[asterisk-commits] oej: branch oej/sipregister r44756 - in /team/oej/sipregister: ./ channels/

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Mon Oct 9 04:39:51 MST 2006


Author: oej
Date: Mon Oct  9 06:39:50 2006
New Revision: 44756

URL: http://svn.digium.com/view/asterisk?rev=44756&view=rev
Log:
Update 2

Modified:
    team/oej/sipregister/   (props changed)
    team/oej/sipregister/channels/chan_sip.c

Propchange: team/oej/sipregister/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Mon Oct  9 06:39:50 2006
@@ -1,1 +1,1 @@
-/trunk:1-44726
+/trunk:1-44755

Modified: team/oej/sipregister/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/oej/sipregister/channels/chan_sip.c?rev=44756&r1=44755&r2=44756&view=diff
==============================================================================
--- team/oej/sipregister/channels/chan_sip.c (original)
+++ team/oej/sipregister/channels/chan_sip.c Mon Oct  9 06:39:50 2006
@@ -1581,7 +1581,7 @@
 {
 	int res;
 	const struct sockaddr_in *dst = sip_real_dst(p);
-	res=sendto(sipsock, data, len, 0, (const struct sockaddr *)dst, sizeof(struct sockaddr_in));
+	res = sendto(sipsock, data, len, 0, (const struct sockaddr *)dst, sizeof(struct sockaddr_in));
 
 	if (res != len)
 		ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s:%d returned %d: %s\n", data, len, ast_inet_ntoa(dst->sin_addr), ntohs(dst->sin_port), res, strerror(errno));
@@ -2804,7 +2804,7 @@
 static int update_call_counter(struct sip_pvt *fup, int event)
 {
 	char name[256];
-	int *inuse, *call_limit;
+	int *inuse, *call_limit, *inringing;
 	int outgoing = ast_test_flag(&fup->flags[0], SIP_OUTGOING);
 	struct sip_user *u = NULL;
 	struct sip_peer *p = NULL;
@@ -2818,65 +2818,91 @@
 
 	ast_copy_string(name, fup->username, sizeof(name));
 
-	/* Check the list of users */
-	if (!outgoing)	/* Only check users for incoming calls */
-		u = find_user(name, 1);
-
-	if (u) {
+	/* Check the list of users only for incoming calls */
+	if (!outgoing && (u = find_user(name, 1)) ) {
 		inuse = &u->inUse;
 		call_limit = &u->call_limit;
-		p = NULL;
+		inringing = NULL;
+	} else if ( (p = find_peer(fup->peername, NULL, 1) ) ) { /* Try to find peer */
+		inuse = &p->inUse;
+		call_limit = &p->call_limit;
+		inringing = &p->inRinging;
+		ast_copy_string(name, fup->peername, sizeof(name));
 	} else {
-		/* Try to find peer */
-		if (!p)
-			p = find_peer(fup->peername, NULL, 1);
-		if (p) {
-			inuse = &p->inUse;
-			call_limit = &p->call_limit;
-			ast_copy_string(name, fup->peername, sizeof(name));
+		if (option_debug > 1)
+			ast_log(LOG_DEBUG, "%s is not a local device, no call limit\n", name);
+		return 0;
+	}
+
+	switch(event) {
+	/* incoming and outgoing affects the inUse counter */
+	case DEC_CALL_LIMIT:
+		if ( *inuse > 0 ) {
+			if (ast_test_flag(&fup->flags[0], SIP_INC_COUNT))
+				(*inuse)--;
 		} else {
-			if (option_debug > 1)
-				ast_log(LOG_DEBUG, "%s is not a local user, no call limit\n", name);
-			return 0;
-		}
-	}
-	switch(event) {
-		/* incoming and outgoing affects the inUse counter */
-		case DEC_CALL_LIMIT:
-			if ( *inuse > 0 ) {
-				if (ast_test_flag(&fup->flags[0], SIP_INC_COUNT))
-					(*inuse)--;
-			} else {
-				*inuse = 0;
+			*inuse = 0;
+		}
+		if (inringing) {
+			if (ast_test_flag(&fup->flags[1], SIP_PAGE2_INC_RINGING)) {
+				if (*inringing > 0)
+					(*inringing)--;
+				else
+					ast_log(LOG_WARNING, "Inringing for peer '%s' < 0?\n", fup->peername);
+				ast_clear_flag(&fup->flags[1], SIP_PAGE2_INC_RINGING);
 			}
-			if (option_debug > 1 || sipdebug) {
-				ast_log(LOG_DEBUG, "Call %s %s '%s' removed from call limit %d\n", outgoing ? "to" : "from", u ? "user":"peer", name, *call_limit);
+		}
+		if (option_debug > 1 || sipdebug) {
+			ast_log(LOG_DEBUG, "Call %s %s '%s' removed from call limit %d\n", outgoing ? "to" : "from", u ? "user":"peer", name, *call_limit);
+		}
+		break;
+
+	case INC_CALL_RINGING:
+	case INC_CALL_LIMIT:
+		if (*call_limit > 0 ) {
+			if (*inuse >= *call_limit) {
+				ast_log(LOG_ERROR, "Call %s %s '%s' rejected due to usage limit of %d\n", outgoing ? "to" : "from", u ? "user":"peer", name, *call_limit);
+				if (u)
+					ASTOBJ_UNREF(u, sip_destroy_user);
+				else
+					ASTOBJ_UNREF(p, sip_destroy_peer);
+				return -1; 
 			}
-			break;
-		case INC_CALL_LIMIT:
-			if (*call_limit > 0 ) {
-				if (*inuse >= *call_limit) {
-					ast_log(LOG_ERROR, "Call %s %s '%s' rejected due to usage limit of %d\n", outgoing ? "to" : "from", u ? "user":"peer", name, *call_limit);
-					if (u)
-						ASTOBJ_UNREF(u, sip_destroy_user);
-					else
-						ASTOBJ_UNREF(p, sip_destroy_peer);
-					return -1; 
-				}
+		}
+		if (inringing && (event == INC_CALL_RINGING)) {
+			if (!ast_test_flag(&fup->flags[1], SIP_PAGE2_INC_RINGING)) {
+				(*inringing)++;
+				ast_set_flag(&fup->flags[1], SIP_PAGE2_INC_RINGING);
 			}
-			(*inuse)++;
-			ast_set_flag(&fup->flags[0], SIP_INC_COUNT);
-			if (option_debug > 1 || sipdebug) {
-				ast_log(LOG_DEBUG, "Call %s %s '%s' is %d out of %d\n", outgoing ? "to" : "from", u ? "user":"peer", name, *inuse, *call_limit);
+		}
+		/* Continue */
+		(*inuse)++;
+		ast_set_flag(&fup->flags[0], SIP_INC_COUNT);
+		if (option_debug > 1 || sipdebug) {
+			ast_log(LOG_DEBUG, "Call %s %s '%s' is %d out of %d\n", outgoing ? "to" : "from", u ? "user":"peer", name, *inuse, *call_limit);
+		}
+		break;
+
+	case DEC_CALL_RINGING:
+		if (inringing) {
+			if (ast_test_flag(&fup->flags[1], SIP_PAGE2_INC_RINGING)) {
+				if (*inringing > 0)
+					(*inringing)--;
+				else
+					ast_log(LOG_WARNING, "Inringing for peer '%s' < 0?\n", p->name);
+				ast_clear_flag(&fup->flags[1], SIP_PAGE2_INC_RINGING);
 			}
-			break;
-		default:
-			ast_log(LOG_ERROR, "update_call_counter(%s, %d) called with no event!\n", name, event);
-	}
-	if (u)
+		}
+		break;
+
+	default:
+		ast_log(LOG_ERROR, "update_call_counter(%s, %d) called with no event!\n", name, event);
+	}
+	if (p) {
+		ast_device_state_changed("SIP/%s", p->name);
+		ASTOBJ_UNREF(p, sip_destroy_peer);
+	} else /* u must be set */
 		ASTOBJ_UNREF(u, sip_destroy_user);
-	else
-		ASTOBJ_UNREF(p, sip_destroy_peer);
 	return 0;
 }
 
@@ -4184,70 +4210,43 @@
 */
 static void parse_request(struct sip_request *req)
 {
-	/* Divide fields by NULL's */
-	char *c;
-	int f = 0;
-
-	c = req->data;
-
-	/* First header starts immediately */
-	req->header[f] = c;
-	while(*c) {
-		if (*c == '\n') {
-			/* We've got a new header */
-			*c = 0;
-
+	char *c = req->data, **dst = req->header;
+	int i = 0, lim = SIP_MAX_HEADERS - 1;
+
+	req->header[0] = c;
+	req->headers = -1;	/* mark that we are working on the header */
+	for (; *c; c++) {
+		if (*c == '\r')		/* remove \r */
+			*c = '\0';
+		else if (*c == '\n') { /* end of this line */
+			*c = '\0';
 			if (sipdebug && option_debug > 3)
-				ast_log(LOG_DEBUG, "Header %d: %s (%d)\n", f, req->header[f], (int) strlen(req->header[f]));
-			if (ast_strlen_zero(req->header[f])) {
-				/* Line by itself means we're now in content */
-				c++;
-				break;
+				ast_log(LOG_DEBUG, "%7s %2d [%3d]: %s\n",
+					req->headers < 0 ? "Header" : "Body",
+					i, strlen(dst[i]), dst[i]);
+			if (ast_strlen_zero(dst[i]) && req->headers < 0) {
+				req->headers = i;	/* record number of header lines */
+				dst = req->line;	/* start working on the body */
+				i = 0;
+				lim = SIP_MAX_LINES - 1;
+			} else {	/* move to next line, check for overflows */
+				if (i++ >= lim)
+					break;
 			}
-			if (f >= SIP_MAX_HEADERS - 1) {
-				ast_log(LOG_WARNING, "Too many SIP headers. Ignoring.\n");
-			} else
-				f++;
-			req->header[f] = c + 1;
-		} else if (*c == '\r') {
-			/* Ignore but eliminate \r's */
-			*c = 0;
-		}
-		c++;
-	}
-	/* Check for last header */
-	if (!ast_strlen_zero(req->header[f])) {
-		if (sipdebug && option_debug > 3)
-			ast_log(LOG_DEBUG, "Header %d: %s (%d)\n", f, req->header[f], (int) strlen(req->header[f]));
-		f++;
-	}
-	req->headers = f;
-	/* Now we process any mime content */
-	f = 0;
-	req->line[f] = c;
-	while(*c) {
-		if (*c == '\n') {
-			/* We've got a new line */
-			*c = 0;
-			if (sipdebug && option_debug > 3)
-				ast_log(LOG_DEBUG, "Line: %s (%d)\n", req->line[f], (int) strlen(req->line[f]));
-			if (f >= SIP_MAX_LINES - 1) {
-				ast_log(LOG_WARNING, "Too many SDP lines. Ignoring.\n");
-			} else
-				f++;
-			req->line[f] = c + 1;
-		} else if (*c == '\r') {
-			/* Ignore and eliminate \r's */
-			*c = 0;
-		}
-		c++;
-	}
-	/* Check for last line */
-	if (!ast_strlen_zero(req->line[f])) 
-		f++;
-	req->lines = f;
-	if (*c) 
-		ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c);
+			dst[i] = c + 1; /* record start of next line */
+		}
+        }
+	/* update count of header or body lines */
+	if (req->headers >= 0)	/* we are in the body */
+		req->lines = i;
+	else {			/* no body */
+		req->headers = i;
+		req->lines = 0;
+		req->line[0] = "";
+	}
+
+	if (*c)
+		ast_log(LOG_WARNING, "Too many lines, skipping <%s>\n", c);
 	/* Split up the first line parts */
 	determine_firstline_parts(req);
 }
@@ -6108,31 +6107,25 @@
 	char tmp[BUFSIZ/2];
 	char tmp2[BUFSIZ/2];
 	const char *l = NULL, *n = NULL;
-	int x;
-	char urioptions[256]="";
+	const char *urioptions = "";
 
 	if (ast_test_flag(&p->flags[0], SIP_USEREQPHONE)) {
-	 	char onlydigits = TRUE;
-		x=0;
+	 	const char *s = p->username;	/* being a string field, cannot be NULL */
 
 		/* Test p->username against allowed characters in AST_DIGIT_ANY
 			If it matches the allowed characters list, then sipuser = ";user=phone"
 			If not, then sipuser = ""
 		*/
 		/* + is allowed in first position in a tel: uri */
-        	if (p->username && p->username[0] == '+')
-			x=1;
-
-		for (; x < strlen(p->username); x++) {
-			if (!strchr(AST_DIGIT_ANYNUM, p->username[x])) {
-                		onlydigits = FALSE;
+		if (*s == '+')
+			s++;
+		for (; *s; s++) {
+			if (!strchr(AST_DIGIT_ANYNUM, *s) )
 				break;
-			}
-		}
-
+		}
 		/* If we have only digits, add ;user=phone to the uri */
-		if (onlydigits)
-			strcpy(urioptions, ";user=phone");
+		if (*s)
+			urioptions = ";user=phone";
 	}
 
 
@@ -6276,25 +6269,21 @@
 
 	add_header(&req, "Allow", ALLOWED_METHODS);
 	add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
-	if (p->options && p->options->addsipheaders ) {
-		struct ast_channel *ast;
-		struct varshead *headp = NULL;
-		const struct ast_var_t *current;
-
-		ast = p->owner;	/* The owner channel */
-		if (ast) {
-			char *headdup;
-	 		headp = &ast->varshead;
+	if (p->options && p->options->addsipheaders && p->owner) {
+		struct ast_channel *ast = p->owner; /* The owner channel */
+		struct varshead *headp = &ast->varshead;
+
 			if (!headp)
 				ast_log(LOG_WARNING,"No Headp for the channel...ooops!\n");
 			else {
+				const struct ast_var_t *current;
 				AST_LIST_TRAVERSE(headp, current, entries) {  
 					/* SIPADDHEADER: Add SIP header to outgoing call */
 					if (!strncasecmp(ast_var_name(current), "SIPADDHEADER", strlen("SIPADDHEADER"))) {
 						char *content, *end;
 						const char *header = ast_var_value(current);
-
-						headdup = ast_strdupa(header);
+						char *headdup = ast_strdupa(header);
+
 						/* Strip of the starting " (if it's there) */
 						if (*headdup == '"')
 					 		headdup++;
@@ -6313,7 +6302,6 @@
 					}
 				}
 			}
-		}
 	}
 	if (sdp) {
 		if (p->udptl && p->t38.state == T38_LOCAL_DIRECT) {
@@ -11416,7 +11404,7 @@
 }
 
 /*! \brief Immediately stop RTP, VRTP and UDPTL as applicable */
-static void stop_data_flows(struct sip_pvt *p)
+static void stop_media_flows(struct sip_pvt *p)
 {
 	/* Immediately stop RTP, VRTP and UDPTL as applicable */
 	if (p->rtp)
@@ -11615,7 +11603,7 @@
 					ast_verbose(VERBOSE_PREFIX_3 "Got SIP response %d \"%s\" back from %s\n", resp, rest, ast_inet_ntoa(p->sa.sin_addr));
 				ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
 	
-				stop_data_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */
+				stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */
 
 				/* XXX Locking issues?? XXX */
 				switch(resp) {
@@ -13256,7 +13244,7 @@
 			ast_log(LOG_DEBUG, "Got CANCEL on an answered call. Ignoring... \n");
 		return 0;
 	}
-	stop_data_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */
+	stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */
 
 	if (p->owner)
 		ast_queue_hangup(p->owner);
@@ -13305,7 +13293,7 @@
 		}
 	}
 
-	stop_data_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */
+	stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */
 
 	if (!ast_strlen_zero(get_header(req, "Also"))) {
 		ast_log(LOG_NOTICE, "Client '%s' using deprecated BYE/Also transfer method.  Ask vendor to support REFER instead\n",
@@ -13853,11 +13841,11 @@
 	struct sockaddr_in sin = { 0, };
 	struct sip_pvt *p;
 	int res;
-	socklen_t len;
+	socklen_t len = sizeof(sin);
 	int nounlock;
 	int recount = 0;
-
-	len = sizeof(sin);
+	int lockretry;
+
 	memset(&req, 0, sizeof(req));
 	res = recvfrom(sipsock, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len);
 	if (res < 0) {
@@ -13885,51 +13873,59 @@
 
 	parse_request(&req);
 	req.method = find_sip_method(req.rlPart1);
-	if (ast_test_flag(&req, SIP_PKT_DEBUG)) {
+
+	if (ast_test_flag(&req, SIP_PKT_DEBUG))
 		ast_verbose("--- (%d headers %d lines)%s ---\n", req.headers, req.lines, (req.headers + req.lines == 0) ? " Nat keepalive" : "");
-	}
-
-	if (req.headers < 2) {
-		/* Must have at least two headers */
+
+	if (req.headers < 2)	/* Must have at least two headers */
 		return 1;
-	}
-
-
-	/* Process request, with netlock held */
-retrylock:
-	ast_mutex_lock(&netlock);
-
-	/* Find the active SIP dialog or create a new one */
-	p = find_call(&req, &sin, req.method);	/* returns p locked */
-	if (p) {
+
+	/* Process request, with netlock held, and with usual deadlock avoidance */
+	for (lockretry = 100; lockretry > 0; lockretry--) {
+		ast_mutex_lock(&netlock);
+
+		/* Find the active SIP dialog or create a new one */
+		p = find_call(&req, &sin, req.method);	/* returns p locked */
+		if (p == NULL) {
+			if (option_debug)
+				ast_log(LOG_DEBUG, "Invalid SIP message - rejected , no callid, len %d\n", req.len);
+			ast_mutex_unlock(&netlock);
+			return 1;
+		}
 		/* Go ahead and lock the owner if it has one -- we may need it */
 		/* becaues this is deadlock-prone, we need to try and unlock if failed */
-		if (p->owner && ast_channel_trylock(p->owner)) {
-			if (option_debug)
-				ast_log(LOG_DEBUG, "Failed to grab lock, trying again...\n");
-			ast_mutex_unlock(&p->lock);
-			ast_mutex_unlock(&netlock);
-			/* Sleep infintismly short amount of time */
-			usleep(1);
-			goto retrylock;
-		}
-		p->recv = sin;
-		if (recordhistory) /* This is a request or response, note what it was for */
-			append_history(p, "Rx", "%s / %s / %s", req.data, get_header(&req, "CSeq"), req.rlPart2);
-		nounlock = 0;
-		if (handle_request(p, &req, &sin, &recount, &nounlock) == -1) {
-			/* Request failed */
-			if (option_debug)
-				ast_log(LOG_DEBUG, "SIP message could not be handled, bad request: %-70.70s\n", p->callid[0] ? p->callid : "<no callid>");
-		}
+		if (!p->owner || !ast_channel_trylock(p->owner))
+			break;	/* locking succeeded */
+		if (option_debug)
+			ast_log(LOG_DEBUG, "Failed to grab owner channel lock, trying again. (SIP call %s)\n", p->callid);
+		ast_mutex_unlock(&p->lock);
+		ast_mutex_unlock(&netlock);
+		/* Sleep for a very short amount of time */
+		usleep(1);
+	}
+	p->recv = sin;
+
+	if (recordhistory) /* This is a request or response, note what it was for */
+		append_history(p, "Rx", "%s / %s / %s", req.data, get_header(&req, "CSeq"), req.rlPart2);
+
+	if (!lockretry) {
+		ast_log(LOG_ERROR, "We could NOT get the channel lock for %s! \n", S_OR(p->owner->name, "- no channel name ??? - "));
+		ast_log(LOG_ERROR, "SIP transaction failed: %s \n", p->callid);
+		transmit_response(p, "503 Server error", &req);	/* We must respond according to RFC 3261 sec 12.2 */
+		/* XXX We could add retry-after to make sure they come back */
+		append_history(p, "LockFail", "Owner lock failed, transaction failed.");
+		return 1;
+	}
+	nounlock = 0;
+	if (handle_request(p, &req, &sin, &recount, &nounlock) == -1) {
+		/* Request failed */
+		if (option_debug)
+			ast_log(LOG_DEBUG, "SIP message could not be handled, bad request: %-70.70s\n", p->callid[0] ? p->callid : "<no callid>");
+	}
 		
-		if (p->owner && !nounlock)
-			ast_channel_unlock(p->owner);
-		ast_mutex_unlock(&p->lock);
-	} else {
-		if (option_debug)
-			ast_log(LOG_DEBUG, "Invalid SIP message - rejected , bad request: %-70.70s\n", p->callid[0] ? p->callid : "<no callid>");
-	}
+	if (p->owner && !nounlock)
+		ast_channel_unlock(p->owner);
+	ast_mutex_unlock(&p->lock);
 	ast_mutex_unlock(&netlock);
 	if (recount)
 		ast_update_use_count();
@@ -15631,13 +15627,13 @@
 				close(sipsock);
 				sipsock = -1;
 			} else {
-				if (option_verbose > 1) { 
+				if (option_verbose > 1)
 					ast_verbose(VERBOSE_PREFIX_2 "SIP Listening on %s:%d\n", 
-					ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
-					ast_verbose(VERBOSE_PREFIX_2 "Using SIP TOS: %s\n", ast_tos2str(global_tos_sip));
-				}
+						ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
 				if (setsockopt(sipsock, IPPROTO_IP, IP_TOS, &global_tos_sip, sizeof(global_tos_sip))) 
 					ast_log(LOG_WARNING, "Unable to set SIP TOS to %s\n", ast_tos2str(global_tos_sip));
+				else if (option_verbose > 1)
+					ast_verbose(VERBOSE_PREFIX_2 "Using SIP TOS: %s\n", ast_tos2str(global_tos_sip));
 			}
 		}
 	}



More information about the asterisk-commits mailing list