[svn-commits] branch crichter/0.3.0 - r8478 in /team/crichter/0.3.0: ./ apps/ channels/

svn-commits at lists.digium.com svn-commits at lists.digium.com
Mon Jan 23 08:35:26 MST 2006


Author: crichter
Date: Mon Jan 23 09:35:19 2006
New Revision: 8478

URL: http://svn.digium.com/view/asterisk?rev=8478&view=rev
Log:
Merged revisions 8394,8412,8414,8418,8429,8433,8437,8445 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/branches/1.2

........
r8394 | tilghman | 2006-01-21 19:29:39 +0100 (Sa, 21 Jan 2006) | 2 lines

Bug 5936 - AddQueueMember fails on realtime queue, if queue not yet loaded

........
r8412 | russell | 2006-01-22 00:17:06 +0100 (So, 22 Jan 2006) | 2 lines

prevent the possibility of writing outside of the available workspace (issue #6271)

........
r8414 | russell | 2006-01-22 00:43:14 +0100 (So, 22 Jan 2006) | 2 lines

temporarily revert substring fix pending the result of the discussion in issue #6271

........
r8418 | russell | 2006-01-22 03:05:41 +0100 (So, 22 Jan 2006) | 3 lines

add a modified fix to prevent writing outside of the provided workspace when 
calculating a substring (issue #6271)

........
r8429 | tilghman | 2006-01-22 09:52:49 +0100 (So, 22 Jan 2006) | 2 lines

Bug 6281 - Cannot set more than a single header with SIPAddHeader

........
r8433 | bweschke | 2006-01-22 16:13:41 +0100 (So, 22 Jan 2006) | 3 lines

 Bug fix: Correct some scenarios where CALL_LIMIT could not be getting adjusted properly allowing chan_sip to send calls when it really shouldn't. Bug #6111


........
r8437 | russell | 2006-01-22 18:47:13 +0100 (So, 22 Jan 2006) | 2 lines

fix MixMonitor crash (issue #6321, probably others)

........
r8445 | russell | 2006-01-22 20:03:53 +0100 (So, 22 Jan 2006) | 2 lines

fix memory leak from not freeing the queue member list when freeing an old queue

........

Modified:
    team/crichter/0.3.0/   (props changed)
    team/crichter/0.3.0/apps/app_queue.c
    team/crichter/0.3.0/channel.c
    team/crichter/0.3.0/channels/chan_sip.c
    team/crichter/0.3.0/pbx.c

Propchange: team/crichter/0.3.0/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Mon Jan 23 09:35:19 2006
@@ -1,1 +1,1 @@
-/branches/1.2:1-7496,7498-7914,7916-7959,7961-7964,7966-7969,7971-7975,7977-8350
+/branches/1.2:1-7496,7498-7914,7916-7959,7961-7964,7966-7969,7971-7975,7977-8477

Modified: team/crichter/0.3.0/apps/app_queue.c
URL: http://svn.digium.com/view/asterisk/team/crichter/0.3.0/apps/app_queue.c?rev=8478&r1=8477&r2=8478&view=diff
==============================================================================
--- team/crichter/0.3.0/apps/app_queue.c (original)
+++ team/crichter/0.3.0/apps/app_queue.c Mon Jan 23 09:35:19 2006
@@ -19,8 +19,6 @@
 /*! \file
  *
  * \brief True call queues with optional send URL on answer
- *
- * \author Mark Spencer <markster at digium.com>
  *
  * \arg Config in \ref Config_qu queues.conf
  * 
@@ -286,7 +284,6 @@
 	time_t last_pos;                /*!< Last time we told the user their position */
 	int opos;			/*!< Where we started in the queue */
 	int handled;			/*!< Whether our call was handled */
-	int max_penalty;		/*!< Limit the members that can take this call to this penalty or lower */
 	time_t start;			/*!< When we started holding */
 	time_t expire;			/*!< When this entry should expire (time out of queue) */
 	struct ast_channel *chan;	/*!< Our channel */
@@ -427,15 +424,12 @@
 	QUEUE_NORMAL
 };
 
-static enum queue_member_status get_member_status(const struct ast_call_queue *q, int max_penalty)
+static enum queue_member_status get_member_status(const struct ast_call_queue *q)
 {
 	struct member *member;
 	enum queue_member_status result = QUEUE_NO_MEMBERS;
 
 	for (member = q->members; member; member = member->next) {
-		if (max_penalty && (member->penalty > max_penalty))
-			continue;
-
 		switch (member->status) {
 		case AST_DEVICE_INVALID:
 			/* nothing to do */
@@ -761,11 +755,52 @@
 	}
 }
 
+static void free_members(struct ast_call_queue *q, int all)
+{
+	/* Free non-dynamic members */
+	struct member *curm, *next, *prev = NULL;
+
+	for (curm = q->members; curm; curm = next) {
+		next = curm->next;
+		if (all || !curm->dynamic) {
+			if (prev)
+				prev->next = next;
+			else
+				q->members = next;
+			free(curm);
+		} else 
+			prev = curm;
+	}
+}
+
+static void destroy_queue(struct ast_call_queue *q)
+{
+	free_members(q, 1);
+	ast_mutex_destroy(&q->lock);
+	free(q);
+}
+
+static void remove_queue(struct ast_call_queue *q)
+{
+	struct ast_call_queue *cur, *prev = NULL;
+
+	ast_mutex_lock(&qlock);
+	for (cur = queues; cur; cur = cur->next) {
+		if (cur == q) {
+			if (prev)
+				prev->next = cur->next;
+			else
+				queues = cur->next;
+		} else {
+			prev = cur;
+		}
+	}
+	ast_mutex_unlock(&qlock);
+}
 
 /*!\brief Reload a single queue via realtime.
    \return Return the queue, or NULL if it doesn't exist.
-   \note Should be called with the global qlock locked.
-   When found, the queue is returned with q->lock locked. */
+   \note Should be called with the global qlock locked. */
 static struct ast_call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
 {
 	struct ast_variable *v;
@@ -791,6 +826,7 @@
 				ast_mutex_unlock(&q->lock);
 				return NULL;
 			} else {
+				ast_mutex_unlock(&q->lock);
 				return q;
 			}
 		}
@@ -817,7 +853,7 @@
 					prev_q->next = q->next;
 				}
 				ast_mutex_unlock(&q->lock);
-				free(q);
+				destroy_queue(q);
 			} else
 				ast_mutex_unlock(&q->lock);
 		}
@@ -885,13 +921,60 @@
 		m = next_m;
 	}
 
+	ast_mutex_unlock(&q->lock);
+
 	return q;
 }
 
-static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
+static struct ast_call_queue *load_realtime_queue(char *queuename)
 {
 	struct ast_variable *queue_vars = NULL;
 	struct ast_config *member_config = NULL;
+	struct ast_call_queue *q;
+
+	/* Find the queue in the in-core list first. */
+	ast_mutex_lock(&qlock);
+	for (q = queues; q; q = q->next) {
+		if (!strcasecmp(q->name, queuename)) {
+			break;
+		}
+	}
+	ast_mutex_unlock(&qlock);
+
+	if (!q) {
+		/*! \note Load from realtime before taking the global qlock, to avoid blocking all
+		   queue operations while waiting for the DB.
+
+		   This will be two separate database transactions, so we might
+		   see queue parameters as they were before another process
+		   changed the queue and member list as it was after the change.
+		   Thus we might see an empty member list when a queue is
+		   deleted. In practise, this is unlikely to cause a problem. */
+
+		queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
+		if (queue_vars) {
+			member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
+			if (!member_config) {
+				ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
+				return NULL;
+			}
+		}
+
+		ast_mutex_lock(&qlock);
+
+		q = find_queue_by_name_rt(queuename, queue_vars, member_config);
+		if (member_config)
+			ast_config_destroy(member_config);
+		if (queue_vars)
+			ast_variables_destroy(queue_vars);
+
+		ast_mutex_unlock(&qlock);
+	}
+	return q;
+}
+
+static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
+{
 	struct ast_call_queue *q;
 	struct queue_ent *cur, *prev = NULL;
 	int res = -1;
@@ -899,38 +982,15 @@
 	int inserted = 0;
 	enum queue_member_status stat;
 
-	/*! \note Load from realtime before taking the global qlock, to avoid blocking all
-	   queue operations while waiting for the DB.
-
-	   This will be two separate database transactions, so we might
-	   see queue parameters as they were before another process
-	   changed the queue and member list as it was after the change.
-	   Thus we might see an empty member list when a queue is
-	   deleted. In practise, this is unlikely to cause a problem. */
-	queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
-	if (queue_vars) {
-		member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
-		if (!member_config) {
-			ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
-			return res;
-		}
-	}
+	q = load_realtime_queue(queuename);
+	if (!q)
+		return res;
 
 	ast_mutex_lock(&qlock);
-	q = find_queue_by_name_rt(queuename, queue_vars, member_config);
-	/* Note: If found, find_queue_by_name_rt() returns with q->lock locked. */
-	if(member_config)
-		ast_config_destroy(member_config);
-	if(queue_vars)
-		ast_variables_destroy(queue_vars);
-
-	if (!q) {
-		ast_mutex_unlock(&qlock);
-		return res;
-	}
+	ast_mutex_lock(&q->lock);
 
 	/* This is our one */
-	stat = get_member_status(q, qe->max_penalty);
+	stat = get_member_status(q);
 	if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
 		*reason = QUEUE_JOINEMPTY;
 	else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
@@ -979,48 +1039,6 @@
 	return res;
 }
 
-static void free_members(struct ast_call_queue *q, int all)
-{
-	/* Free non-dynamic members */
-	struct member *curm, *next, *prev;
-
-	curm = q->members;
-	prev = NULL;
-	while(curm) {
-		next = curm->next;
-		if (all || !curm->dynamic) {
-			if (prev)
-				prev->next = next;
-			else
-				q->members = next;
-			free(curm);
-		} else 
-			prev = curm;
-		curm = next;
-	}
-}
-
-static void destroy_queue(struct ast_call_queue *q)
-{
-	struct ast_call_queue *cur, *prev = NULL;
-
-	ast_mutex_lock(&qlock);
-	for (cur = queues; cur; cur = cur->next) {
-		if (cur == q) {
-			if (prev)
-				prev->next = cur->next;
-			else
-				queues = cur->next;
-		} else {
-			prev = cur;
-		}
-	}
-	ast_mutex_unlock(&qlock);
-	free_members(q, 1);
-        ast_mutex_destroy(&q->lock);
-	free(q);
-}
-
 static int play_file(struct ast_channel *chan, char *filename)
 {
 	int res;
@@ -1228,6 +1246,7 @@
 	ast_mutex_unlock(&q->lock);
 	if (q->dead && !q->count) {	
 		/* It's dead and nobody is in it, so kill it */
+		remove_queue(q);
 		destroy_queue(q);
 	}
 }
@@ -1879,7 +1898,7 @@
 			break;
 		}
 
-		stat = get_member_status(qe->parent, qe->max_penalty);
+		stat = get_member_status(qe->parent);
 
 		/* leave the queue if no agents, if enabled */
 		if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
@@ -1936,9 +1955,6 @@
 
 static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
 {
-	if (mem->penalty > qe->max_penalty)
-		return -1;
-
 	switch (q->strategy) {
 	case QUEUE_STRATEGY_RINGALL:
 		/* Everyone equal, except for penalty */
@@ -1999,6 +2015,7 @@
 	char oldcontext[AST_MAX_CONTEXT]="";
 	char queuename[256]="";
 	char *newnum;
+	char *monitorfilename;
 	struct ast_channel *peer;
 	struct ast_channel *which;
 	struct localuser *lpeer;
@@ -2091,18 +2108,15 @@
 		}
 		/* Special case: If we ring everyone, go ahead and ring them, otherwise
 		   just calculate their metric for the appropriate strategy */
-		if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
-			/* Put them in the list of outgoing thingies...  We're ready now. 
-			   XXX If we're forcibly removed, these outgoing calls won't get
-			   hung up XXX */
-			tmp->next = outgoing;
-			outgoing = tmp;		
-			/* If this line is up, don't try anybody else */
-			if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
-				break;
-		} else {
-			free(tmp);
-		}
+		calc_metric(qe->parent, cur, x++, qe, tmp);
+		/* Put them in the list of outgoing thingies...  We're ready now. 
+		   XXX If we're forcibly removed, these outgoing calls won't get
+		   hung up XXX */
+		tmp->next = outgoing;
+		outgoing = tmp;		
+		/* If this line is up, don't try anybody else */
+		if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
+			break;
 
 		cur = cur->next;
 	}
@@ -2218,7 +2232,7 @@
 		}
 		/* Begin Monitoring */
 		if (qe->parent->monfmt && *qe->parent->monfmt) {
-			const char *monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
+			monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
 			if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
 				which = qe->chan;
 			else
@@ -2413,41 +2427,42 @@
 	struct member *new_member;
 	int res = RES_NOSUCHQUEUE;
 
+	/* \note Ensure the appropriate realtime queue is loaded.  Note that this
+	 * short-circuits if the queue is already in memory. */
+	q = load_realtime_queue(queuename);
+
 	ast_mutex_lock(&qlock);
-	for (q = queues ; q ; q = q->next) {
+
+	if (q) {
 		ast_mutex_lock(&q->lock);
-		if (!strcmp(q->name, queuename)) {
-			if (interface_exists(q, interface) == NULL) {
-				new_member = create_queue_member(interface, penalty, paused);
-
-				if (new_member != NULL) {
-					new_member->dynamic = 1;
-					new_member->next = q->members;
-					q->members = new_member;
-					manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
-						"Queue: %s\r\n"
-						"Location: %s\r\n"
-						"Membership: %s\r\n"
-						"Penalty: %d\r\n"
-						"CallsTaken: %d\r\n"
-						"LastCall: %d\r\n"
-						"Status: %d\r\n"
-						"Paused: %d\r\n",
-					q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
-					new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused);
+		if (interface_exists(q, interface) == NULL) {
+			new_member = create_queue_member(interface, penalty, paused);
+
+			if (new_member != NULL) {
+				new_member->dynamic = 1;
+				new_member->next = q->members;
+				q->members = new_member;
+				manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
+					"Queue: %s\r\n"
+					"Location: %s\r\n"
+					"Membership: %s\r\n"
+					"Penalty: %d\r\n"
+					"CallsTaken: %d\r\n"
+					"LastCall: %d\r\n"
+					"Status: %d\r\n"
+					"Paused: %d\r\n",
+				q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
+				new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused);
 					
-					if (dump)
-						dump_queue_members(q);
-
-					res = RES_OKAY;
-				} else {
-					res = RES_OUTOFMEMORY;
-				}
+				if (dump)
+					dump_queue_members(q);
+
+				res = RES_OKAY;
 			} else {
-				res = RES_EXISTS;
-			}
-			ast_mutex_unlock(&q->lock);
-			break;
+				res = RES_OUTOFMEMORY;
+			}
+		} else {
+			res = RES_EXISTS;
 		}
 		ast_mutex_unlock(&q->lock);
 	}
@@ -2627,7 +2642,7 @@
 
 	if (set_member_paused(args.queuename, args.interface, 1)) {
 		ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
-		if (priority_jump || ast_opt_priority_jumping) {
+		if (priority_jump || option_priority_jumping) {
 			if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
 				pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
 				LOCAL_USER_REMOVE(u);
@@ -2683,7 +2698,7 @@
 
 	if (set_member_paused(args.queuename, args.interface, 0)) {
 		ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
-		if (priority_jump || ast_opt_priority_jumping) {
+		if (priority_jump || option_priority_jumping) {
 			if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
 				pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
 				LOCAL_USER_REMOVE(u);
@@ -2748,7 +2763,7 @@
 		break;
 	case RES_EXISTS:
 		ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
-		if (priority_jump || ast_opt_priority_jumping) 
+		if (priority_jump || option_priority_jumping) 
 			ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
 		pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
 		res = 0;
@@ -2824,7 +2839,7 @@
 		break;
 	case RES_EXISTS:
 		ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
-		if (priority_jump || ast_opt_priority_jumping) 
+		if (priority_jump || option_priority_jumping) 
 			ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
 		pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
 		res = 0;
@@ -2854,10 +2869,8 @@
 	char *options = NULL;
 	char *url = NULL;
 	char *announceoverride = NULL;
-	const char *user_priority;
-	const char *max_penalty_str;
+	char *user_priority;
 	int prio;
-	int max_penalty;
 	char *queuetimeoutstr = NULL;
 	enum queue_result reason = QUEUE_UNKNOWN;
 
@@ -2910,31 +2923,15 @@
 		prio = 0;
 	}
 
-	/* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
-	if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
-		if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) {
-			if (option_debug)
-				ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
-					chan->name, max_penalty);
-		} else {
-			ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
-				max_penalty_str, chan->name);
-			max_penalty = 0;
-		}
-	} else {
-		max_penalty = 0;
-	}
-
 	if (options && (strchr(options, 'r')))
 		ringing = 1;
 
 	if (option_debug)  
 		ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
-			queuename, options, url, announceoverride, (long)qe.expire, prio);
+			queuename, options, url, announceoverride, (long)qe.expire, (int)prio);
 
 	qe.chan = chan;
-	qe.prio = prio;
-	qe.max_penalty = max_penalty;
+	qe.prio = (int)prio;
 	qe.last_pos_said = 0;
 	qe.last_pos = 0;
 	qe.last_periodic_announce_time = time(NULL);
@@ -3022,7 +3019,7 @@
 					break;
 				}
 
-				stat = get_member_status(qe.parent, qe.max_penalty);
+				stat = get_member_status(qe.parent);
 
 				/* leave the queue if no agents, if enabled */
 				if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
@@ -3270,7 +3267,7 @@
 			else
 				queues = q->next;
 			if (!q->count) {
-				free(q);
+				destroy_queue(q);
 			} else
 				ast_log(LOG_WARNING, "XXX Leaking a little memory :( XXX\n");
 		} else {
@@ -3299,7 +3296,13 @@
 	time(&now);
 	if ((!queue_show && argc != 2) || (queue_show && argc != 3))
 		return RESULT_SHOWUSAGE;
+
+	/* We only want to load realtime queues when a specific queue is asked for. */
+	if (queue_show)
+		load_realtime_queue(argv[2]);
+
 	ast_mutex_lock(&qlock);
+
 	q = queues;
 	if (!q) {	
 		ast_mutex_unlock(&qlock);
@@ -3387,22 +3390,17 @@
 static char *complete_queue(char *line, char *word, int pos, int state)
 {
 	struct ast_call_queue *q;
-	char *ret = NULL;
-	int which = 0;
-	int wordlen = strlen(word);
+	int which=0;
 	
 	ast_mutex_lock(&qlock);
 	for (q = queues; q; q = q->next) {
-		if (!strncasecmp(word, q->name, wordlen)) {
-			if (++which > state) {
-				ret = strdup(q->name);	
+		if (!strncasecmp(word, q->name, strlen(word))) {
+			if (++which > state)
 				break;
-			}
 		}
 	}
 	ast_mutex_unlock(&qlock);
-
-	return ret;
+	return q ? strdup(q->name) : NULL;
 }
 
 /*!\brief callback to display queues status in manager 

Modified: team/crichter/0.3.0/channel.c
URL: http://svn.digium.com/view/asterisk/team/crichter/0.3.0/channel.c?rev=8478&r1=8477&r2=8478&view=diff
==============================================================================
--- team/crichter/0.3.0/channel.c (original)
+++ team/crichter/0.3.0/channel.c Mon Jan 23 09:35:19 2006
@@ -3826,7 +3826,7 @@
 		}
 
 		tocopy = (f->samples > samples) ? samples : f->samples;
-		bytestocopy = ast_codec_get_len(queue->format, samples);
+		bytestocopy = ast_codec_get_len(queue->format, tocopy);
 		memcpy(buf, f->data, bytestocopy);
 		samples -= tocopy;
 		buf += tocopy;

Modified: team/crichter/0.3.0/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/crichter/0.3.0/channels/chan_sip.c?rev=8478&r1=8477&r2=8478&view=diff
==============================================================================
--- team/crichter/0.3.0/channels/chan_sip.c (original)
+++ team/crichter/0.3.0/channels/chan_sip.c Mon Jan 23 09:35:19 2006
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 1999 - 2006, Digium, Inc.
+ * Copyright (C) 1999 - 2005, Digium, Inc.
  *
  * Mark Spencer <markster at digium.com>
  *
@@ -19,12 +19,7 @@
 /*!
  * \file
  * \brief Implementation of Session Initiation Protocol
- *
- * \author Mark Spencer <markster at digium.com>
- *
- * See Also:
- * \arg \ref AstCREDITS
- *
+ * 
  * Implementation of RFC 3261 - without S/MIME, TCP and TLS support
  * Configuration file \link Config_sip sip.conf \endlink
  *
@@ -86,7 +81,6 @@
 #include "asterisk/dnsmgr.h"
 #include "asterisk/devicestate.h"
 #include "asterisk/linkedlists.h"
-#include "asterisk/stringfields.h"
 
 #ifdef OSP_SUPPORT
 #include "asterisk/astosp.h"
@@ -105,7 +99,6 @@
 
 #define SIPDUMPER
 #define DEFAULT_DEFAULT_EXPIRY  120
-#define DEFAULT_MIN_EXPIRY	60
 #define DEFAULT_MAX_EXPIRY	3600
 #define DEFAULT_REGISTRATION_TIMEOUT	20
 #define DEFAULT_MAX_FORWARDS	"70"
@@ -122,7 +115,6 @@
 #define EXPIRY_GUARD_PCT	0.20	/* Percentage of expires timeout to use when 
 					   below EXPIRY_GUARD_LIMIT */
 
-static int min_expiry = DEFAULT_MIN_EXPIRY;
 static int max_expiry = DEFAULT_MAX_EXPIRY;
 static int default_expiry = DEFAULT_DEFAULT_EXPIRY;
 
@@ -418,6 +410,9 @@
 static struct sockaddr_in outboundproxyip;
 static int ourport;
 
+#define SIP_DEBUG_CONFIG 1 << 0
+#define SIP_DEBUG_CONSOLE 1 << 1
+static int sipdebug = 0;
 static struct sockaddr_in debugaddr;
 
 static int tos = 0;
@@ -468,11 +463,11 @@
 
 /*! \brief Parameters to the transmit_invite function */
 struct sip_invite_param {
-	const char *distinctive_ring;	/*!< Distinctive ring header */
+	char *distinctive_ring;	/*!< Distinctive ring header */
 	char *osptoken;		/*!< OSP token for this call */
 	int addsipheaders;	/*!< Add extra SIP headers */
-	const char *uri_options;	/*!< URI options to add to the URI */
-	const char *vxml_url;		/*!< VXML url for Cisco phones */
+	char *uri_options;	/*!< URI options to add to the URI */
+	char *vxml_url;		/*!< VXML url for Cisco phones */
 	char *auth;		/*!< Authentication */
 	char *authheader;	/*!< Auth header */
 	enum sip_auth_type auth_type;	/*!< Authentication type */
@@ -501,11 +496,9 @@
 
 /*! \brief sip_history: Structure for saving transactions within a SIP dialog */
 struct sip_history {
-	AST_LIST_ENTRY(sip_history) list;
-	char event[0];	/* actually more, depending on needs */
+	char event[80];
+	struct sip_history *next;
 };
-
-AST_LIST_HEAD_NOLOCK(sip_history_head, sip_history); /*!< history list, entry in sip_pvt */
 
 /*! \brief sip_auth: Creadentials for authentication to other SIP services */
 struct sip_auth {
@@ -567,6 +560,8 @@
 #define SIP_CALL_LIMIT		(1 << 29)
 /* Remote Party-ID Support */
 #define SIP_SENDRPID		(1 << 30)
+/* Did this connection increment the counter of in-use calls? */
+#define SIP_INC_COUNT (1 << 31)
 
 #define SIP_FLAGS_TO_COPY \
 	(SIP_PROMISCREDIR | SIP_TRUSTRPID | SIP_SENDRPID | SIP_DTMF | SIP_REINVITE | \
@@ -579,17 +574,10 @@
 #define SIP_PAGE2_RTAUTOCLEAR		(1 << 2)
 #define SIP_PAGE2_IGNOREREGEXPIRE	(1 << 3)
 #define SIP_PAGE2_RT_FROMCONTACT 	(1 << 4)
-#define SIP_PAGE2_DEBUG			(3 << 5)
-#define SIP_PAGE2_DEBUG_CONFIG 		(1 << 5)
-#define SIP_PAGE2_DEBUG_CONSOLE 	(1 << 6)
 
 /* SIP packet flags */
 #define SIP_PKT_DEBUG		(1 << 0)	/*!< Debug this packet */
 #define SIP_PKT_WITH_TOTAG	(1 << 1)	/*!< This packet has a to-tag */
-
-#define sipdebug		ast_test_flag(&global_flags_page2, SIP_PAGE2_DEBUG)
-#define sipdebug_config		ast_test_flag(&global_flags_page2, SIP_PAGE2_DEBUG_CONFIG)
-#define sipdebug_console	ast_test_flag(&global_flags_page2, SIP_PAGE2_DEBUG_CONSOLE)
 
 static int global_rtautoclear = 120;
 
@@ -597,46 +585,8 @@
 static struct sip_pvt {
 	ast_mutex_t lock;			/*!< Channel private lock */
 	int method;				/*!< SIP method of this packet */
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(callid);	/*!< Global CallID */
-		AST_STRING_FIELD(randdata);	/*!< Random data */
-		AST_STRING_FIELD(accountcode);	/*!< Account code */
-		AST_STRING_FIELD(realm);	/*!< Authorization realm */
-		AST_STRING_FIELD(nonce);	/*!< Authorization nonce */
-		AST_STRING_FIELD(opaque);	/*!< Opaque nonsense */
-		AST_STRING_FIELD(qop);		/*!< Quality of Protection, since SIP wasn't complicated enough yet. */
-		AST_STRING_FIELD(domain);	/*!< Authorization domain */
-		AST_STRING_FIELD(refer_to);	/*!< Place to store REFER-TO extension */
-		AST_STRING_FIELD(referred_by);	/*!< Place to store REFERRED-BY extension */
-		AST_STRING_FIELD(refer_contact);/*!< Place to store Contact info from a REFER extension */
-		AST_STRING_FIELD(from);		/*!< The From: header */
-		AST_STRING_FIELD(useragent);	/*!< User agent in SIP request */
-		AST_STRING_FIELD(exten);	/*!< Extension where to start */
-		AST_STRING_FIELD(context);	/*!< Context for this call */
-		AST_STRING_FIELD(subscribecontext); /*!< Subscribecontext */
-		AST_STRING_FIELD(fromdomain);	/*!< Domain to show in the from field */
-		AST_STRING_FIELD(fromuser);	/*!< User to show in the user field */
-		AST_STRING_FIELD(fromname);	/*!< Name to show in the user field */
-		AST_STRING_FIELD(tohost);	/*!< Host we should put in the "to" field */
-		AST_STRING_FIELD(language);	/*!< Default language for this call */
-		AST_STRING_FIELD(musicclass);	/*!< Music on Hold class */
-		AST_STRING_FIELD(rdnis);	/*!< Referring DNIS */
-		AST_STRING_FIELD(theirtag);	/*!< Their tag */
-		AST_STRING_FIELD(username);	/*!< [user] name */
-		AST_STRING_FIELD(peername);	/*!< [peer] name, not set if [user] */
-		AST_STRING_FIELD(authname);	/*!< Who we use for authentication */
-		AST_STRING_FIELD(uri);		/*!< Original requested URI */
-		AST_STRING_FIELD(okcontacturi);	/*!< URI from the 200 OK on INVITE */
-		AST_STRING_FIELD(peersecret);	/*!< Password */
-		AST_STRING_FIELD(peermd5secret);
-		AST_STRING_FIELD(cid_num);	/*!< Caller*ID */
-		AST_STRING_FIELD(cid_name);	/*!< Caller*ID */
-		AST_STRING_FIELD(via);		/*!< Via: header */
-		AST_STRING_FIELD(fullcontact);	/*!< The Contact: that the UA registers with us */
-		AST_STRING_FIELD(our_contact);	/*!< Our contact header */
-		AST_STRING_FIELD(rpid);		/*!< Our RPID header */
-		AST_STRING_FIELD(rpid_from);	/*!< Our RPID From header */
-	);
+	char callid[80];			/*!< Global CallID */
+	char randdata[80];			/*!< Random data */
 	struct ast_codec_pref prefs;		/*!< codec prefs */
 	unsigned int ocseq;			/*!< Current outgoing seqno */
 	unsigned int icseq;			/*!< Current incoming seqno */
@@ -665,11 +615,47 @@
 	struct sockaddr_in recv;		/*!< Received as */
 	struct in_addr ourip;			/*!< Our IP */
 	struct ast_channel *owner;		/*!< Who owns us */
+	char exten[AST_MAX_EXTENSION];		/*!< Extension where to start */
+	char refer_to[AST_MAX_EXTENSION];	/*!< Place to store REFER-TO extension */
+	char referred_by[AST_MAX_EXTENSION];	/*!< Place to store REFERRED-BY extension */
+	char refer_contact[AST_MAX_EXTENSION];	/*!< Place to store Contact info from a REFER extension */
 	struct sip_pvt *refer_call;		/*!< Call we are referring */
 	struct sip_route *route;		/*!< Head of linked list of routing steps (fm Record-Route) */
 	int route_persistant;			/*!< Is this the "real" route? */
+	char from[256];				/*!< The From: header */
+	char useragent[256];			/*!< User agent in SIP request */
+	char context[AST_MAX_CONTEXT];		/*!< Context for this call */
+	char subscribecontext[AST_MAX_CONTEXT];	/*!< Subscribecontext */
+	char fromdomain[MAXHOSTNAMELEN];	/*!< Domain to show in the from field */
+	char fromuser[AST_MAX_EXTENSION];	/*!< User to show in the user field */
+	char fromname[AST_MAX_EXTENSION];	/*!< Name to show in the user field */
+	char tohost[MAXHOSTNAMELEN];		/*!< Host we should put in the "to" field */
+	char language[MAX_LANGUAGE];		/*!< Default language for this call */
+	char musicclass[MAX_MUSICCLASS];	/*!< Music on Hold class */
+	char rdnis[256];			/*!< Referring DNIS */
+	char theirtag[256];			/*!< Their tag */
+	char username[256];			/*!< [user] name */
+	char peername[256];			/*!< [peer] name, not set if [user] */
+	char authname[256];			/*!< Who we use for authentication */
+	char uri[256];				/*!< Original requested URI */
+	char okcontacturi[256];			/*!< URI from the 200 OK on INVITE */
+	char peersecret[256];			/*!< Password */
+	char peermd5secret[256];
 	struct sip_auth *peerauth;		/*!< Realm authentication */
+	char cid_num[256];			/*!< Caller*ID */
+	char cid_name[256];			/*!< Caller*ID */
+	char via[256];				/*!< Via: header */
+	char fullcontact[128];			/*!< The Contact: that the UA registers with us */
+	char accountcode[AST_MAX_ACCOUNT_CODE];	/*!< Account code */
+	char our_contact[256];			/*!< Our contact header */
+	char *rpid;				/*!< Our RPID header */
+	char *rpid_from;			/*!< Our RPID From header */
+	char realm[MAXHOSTNAMELEN];		/*!< Authorization realm */
+	char nonce[256];			/*!< Authorization nonce */
 	int noncecount;				/*!< Nonce-count */
+	char opaque[256];			/*!< Opaque nonsense */
+	char qop[80];				/*!< Quality of Protection, since SIP wasn't complicated enough yet. */
+	char domain[MAXHOSTNAMELEN];		/*!< Authorization domain */
 	char lastmsg[256];			/*!< Last Message sent/received */
 	int amaflags;				/*!< AMA Flags */
 	int pendinginvite;			/*!< Any pending invite */
@@ -700,7 +686,7 @@
 	struct ast_rtp *rtp;			/*!< RTP Session */
 	struct ast_rtp *vrtp;			/*!< Video RTP session */
 	struct sip_pkt *packets;		/*!< Packets scheduled for re-transmission */
-	struct sip_history_head *history;	/*!< History of this SIP dialog */
+	struct sip_history *history;		/*!< History of this SIP dialog */
 	struct ast_variable *chanvars;		/*!< Channel variables to set for call */
 	struct sip_pvt *next;			/*!< Next call in chain */
 	struct sip_invite_param *options;	/*!< Options for INVITE */
@@ -826,22 +812,14 @@
 /*! \brief sip_registry: Registrations with other SIP proxies */
 struct sip_registry {
 	ASTOBJ_COMPONENTS_FULL(struct sip_registry,1,1);
-	AST_DECLARE_STRING_FIELDS(
-		AST_STRING_FIELD(callid);	/*!< Global Call-ID */
-		AST_STRING_FIELD(realm);	/*!< Authorization realm */
-		AST_STRING_FIELD(nonce);	/*!< Authorization nonce */
-		AST_STRING_FIELD(opaque);	/*!< Opaque nonsense */
-		AST_STRING_FIELD(qop);		/*!< Quality of Protection, since SIP wasn't complicated enough yet. */
-		AST_STRING_FIELD(domain);	/*!< Authorization domain */
-		AST_STRING_FIELD(username);	/*!< Who we are registering as */
-		AST_STRING_FIELD(authuser);	/*!< Who we *authenticate* as */
-		AST_STRING_FIELD(hostname);	/*!< Domain or host we register to */
-		AST_STRING_FIELD(secret);	/*!< Password in clear text */	
-		AST_STRING_FIELD(md5secret);	/*!< Password in md5 */
-		AST_STRING_FIELD(contact);	/*!< Contact extension */
-		AST_STRING_FIELD(random);
-	);
 	int portno;			/*!<  Optional port override */
+	char username[80];		/*!<  Who we are registering as */
+	char authuser[80];		/*!< Who we *authenticate* as */
+	char hostname[MAXHOSTNAMELEN];	/*!< Domain or host we register to */
+	char secret[80];		/*!< Password in clear text */	
+	char md5secret[80];		/*!< Password in md5 */
+	char contact[256];		/*!< Contact extension */
+	char random[80];
 	int expire;			/*!< Sched ID of expiration */
 	int regattempts;		/*!< Number of attempts (since the last success) */
 	int timeout; 			/*!< sched id of sip_reg_timeout */
@@ -849,10 +827,19 @@
 	struct sip_pvt *call;		/*!< create a sip_pvt structure for each outbound "registration call" in progress */
 	int regstate;			/*!< Registration state (see above) */
 	int callid_valid;		/*!< 0 means we haven't chosen callid for this registry yet. */
+	char callid[80];		/*!< Global CallID for this registry */
 	unsigned int ocseq;		/*!< Sequence number we got to for REGISTERs for this registry */
 	struct sockaddr_in us;		/*!< Who the server thinks we are */
+ 	
+ 					/* Saved headers */
+ 	char realm[MAXHOSTNAMELEN];	/*!< Authorization realm */
+ 	char nonce[256];		/*!< Authorization nonce */
+ 	char domain[MAXHOSTNAMELEN];	/*!< Authorization domain */
+ 	char opaque[256];		/*!< Opaque nonsense */
+ 	char qop[80];			/*!< Quality of Protection. */
 	int noncecount;			/*!< Nonce-count */
-	char lastmsg[256];		/*!< Last Message sent/received */
+ 
+ 	char lastmsg[256];		/*!< Last Message sent/received */
 };
 
 /*! \brief  The user list: Users and friends ---*/
@@ -883,18 +870,17 @@
 static time_t externexpire = 0;
 static int externrefresh = 10;
 static struct ast_ha *localaddr;
-static int callevents;				/*!< Whether we send manager events or not */
 
 /* The list of manual NOTIFY types we know how to send */
 struct ast_config *notify_types;
 
-static struct sip_auth *authl = NULL;          /*!< Authentication list */
+static struct sip_auth *authl;          /*!< Authentication list */
 
 
 static int transmit_response(struct sip_pvt *p, char *msg, struct sip_request *req);
 static int transmit_response_with_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
 static int transmit_response_with_unsupported(struct sip_pvt *p, char *msg, struct sip_request *req, char *unsupported);
-static int transmit_response_with_auth(struct sip_pvt *p, char *msg, struct sip_request *req, const char *rand, int reliable, char *header, int stale);
+static int transmit_response_with_auth(struct sip_pvt *p, char *msg, struct sip_request *req, char *rand, int reliable, char *header, int stale);
 static int transmit_request(struct sip_pvt *p, int sipmethod, int inc, int reliable, int newbranch);
 static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, int inc, int reliable, int newbranch);
 static int transmit_invite(struct sip_pvt *p, int sipmethod, int sendsdp, int init);
@@ -913,6 +899,7 @@
 static struct sip_user *build_user(const char *name, struct ast_variable *v, int realtime);
 static int sip_do_reload(void);
 static int expire_register(void *data);
+static int callevents = 0;
 
 static struct ast_channel *sip_request_call(const char *type, int format, void *data, int *cause);
 static int sip_devicestate(void *data);
@@ -928,7 +915,7 @@
 static int sip_senddigit(struct ast_channel *ast, char digit);
 static int clear_realm_authentication(struct sip_auth *authlist);                            /* Clear realm authentication list (at reload) */
 static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, char *configuration, int lineno);   /* Add realm authentication in list */
-static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, const char *realm);         /* Find authentication for a specific realm */
+static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, char *realm);         /* Find authentication for a specific realm */
 static int check_sip_domain(const char *domain, char *context, size_t len); /* Check if domain is one of our local domains */
 static void append_date(struct sip_request *req);	/* Append date to SIP packet */
 static int determine_firstline_parts(struct sip_request *req);
@@ -936,8 +923,6 @@
 static const struct cfsubscription_types *find_subscription_type(enum subscriptiontype subtype);
 static int transmit_state_notify(struct sip_pvt *p, int state, int full, int substate);
 static char *gettag(struct sip_request *req, char *header, char *tagbuf, int tagbufsize);
-int find_sip_method(char *msg);
-unsigned int parse_sip_options(struct sip_pvt *pvt, char *supported);
 
 /*! \brief Definition of this channel for PBX channel registration */
 static const struct ast_channel_tech sip_tech = {
@@ -1046,7 +1031,7 @@
 /*! \brief  sip_debug_test_addr: See if we pass debug IP filter */
 static inline int sip_debug_test_addr(struct sockaddr_in *addr) 
 {
-	if (!sipdebug)
+	if (sipdebug == 0)
 		return 0;
 	if (debugaddr.sin_addr.s_addr) {
 		if (((ntohs(debugaddr.sin_port) != 0)
@@ -1060,7 +1045,7 @@
 /*! \brief  sip_debug_test_pvt: Test PVT for debugging output */
 static inline int sip_debug_test_pvt(struct sip_pvt *p) 
 {
-	if (!sipdebug)
+	if (sipdebug == 0)
 		return 0;
 	return sip_debug_test_addr(((ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE) ? &p->recv : &p->sa));
 }
@@ -1086,15 +1071,15 @@
 static void sip_destroy(struct sip_pvt *p);
 
 /*! \brief  build_via: Build a Via header for a request ---*/
-static void build_via(struct sip_pvt *p)
+static void build_via(struct sip_pvt *p, char *buf, int len)
 {
 	char iabuf[INET_ADDRSTRLEN];
-	/* Work around buggy UNIDEN UIP200 firmware */
-	const char *rport = ast_test_flag(p, SIP_NAT) & SIP_NAT_RFC3581 ? ";rport" : "";
 
 	/* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
-	ast_string_field_build(p, via, "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x%s",
-			       ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch, rport);
+	if (ast_test_flag(p, SIP_NAT) & SIP_NAT_RFC3581)
+		snprintf(buf, len, "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
+	else /* Work around buggy UNIDEN UIP200 firmware */
+		snprintf(buf, len, "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
 }
 
 /*! \brief  ast_sip_ouraddrfor: NAT fix - decide which IP address to use for ASterisk server? ---*/
@@ -1132,45 +1117,40 @@
 	return 0;
 }
 
-/*! \brief  append_history: Append to SIP dialog history 
-	\return Always returns 0 */
-#define append_history(p, event, fmt , args... )	append_history_full(p, "%-15s " fmt, event, ## args)
-
-static int append_history_full(struct sip_pvt *p, const char *fmt, ...)
-	__attribute__ ((format (printf, 2, 3)));
-
-/*! \brief  Append to SIP dialog history with arg list  */
-static void append_history_va(struct sip_pvt *p, const char *fmt, va_list ap)
-{
-	char buf[80], *c = buf; /* max history length */
-	struct sip_history *hist;
-	int l;
-
-	vsnprintf(buf, sizeof(buf), fmt, ap);
-	strsep(&c, "\r\n"); /* Trim up everything after \r or \n */
-	l = strlen(buf) + 1;
-	if (!(hist = ast_calloc(1, sizeof(*hist) + l)))
-		return;
-	if (!p->history && !(p->history = ast_calloc(1, sizeof(*p->history)))) {
-		free(hist);
-		return;
-	}
-	memcpy(hist->event, buf, l);
-	AST_LIST_INSERT_TAIL(p->history, hist, list);
-}
-
-/*! \brief  Append to SIP dialog history with arg list  */
-static int append_history_full(struct sip_pvt *p, const char *fmt, ...)
-{
-        va_list ap;
+/*! \brief  append_history: Append to SIP dialog history */
+/*	Always returns 0 */
+static int append_history(struct sip_pvt *p, const char *event, const char *data)
+{
+	struct sip_history *hist, *prev;
+	char *c;
 
 	if (!recordhistory || !p)
 		return 0;
-        va_start(ap, fmt);
-        append_history_va(p, fmt, ap);
-        va_end(ap);
-
-        return 0;
+	if(!(hist = malloc(sizeof(struct sip_history)))) {
+		ast_log(LOG_WARNING, "Can't allocate memory for history");
+		return 0;
+	}
+	memset(hist, 0, sizeof(struct sip_history));
+	snprintf(hist->event, sizeof(hist->event), "%-15s %s", event, data);
+	/* Trim up nicely */
+	c = hist->event;
+	while(*c) {
+		if ((*c == '\r') || (*c == '\n')) {
+			*c = '\0';
+			break;
+		}
+		c++;
+	}
+	/* Enqueue into history */
+	prev = p->history;
+	if (prev) {
+		while(prev->next)
+			prev = prev->next;
+		prev->next = hist;
+	} else {
+		p->history = hist;
+	}
+	return 0;
 }
 
 /*! \brief  retrans_pkt: Retransmit SIP message if no answer ---*/
@@ -1184,6 +1164,8 @@
 	ast_mutex_lock(&pkt->owner->lock);
 
 	if (pkt->retrans < MAX_RETRANS) {
+		char buf[80];
+
 		pkt->retrans++;
  		if (!pkt->timer_t1) {	/* Re-schedule using timer_a and timer_t1 */
 			if (sipdebug && option_debug > 3)
@@ -1215,19 +1197,22 @@
 			else
 				ast_verbose("Retransmitting #%d (no NAT) to %s:%d:\n%s\n---\n", pkt->retrans, ast_inet_ntoa(iabuf, sizeof(iabuf), pkt->owner->sa.sin_addr), ntohs(pkt->owner->sa.sin_port), pkt->data);
 		}
-
-		append_history(pkt->owner, "ReTx", "%d %s", reschedule, pkt->data);
+		snprintf(buf, sizeof(buf), "ReTx %d", reschedule);
+
+		append_history(pkt->owner, buf, pkt->data);
 		__sip_xmit(pkt->owner, pkt->data, pkt->packetlen);

[... 5224 lines stripped ...]


More information about the svn-commits mailing list