[asterisk-commits] murf: branch murf/cdr-debug-1.4 r173843 - in /team/murf/cdr-debug-1.4: ./ app...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Feb 6 00:24:34 CST 2009


Author: murf
Date: Fri Feb  6 00:24:34 2009
New Revision: 173843

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=173843
Log:
Merged revisions 173211,173248,173392,173396,173559,173592,173692,173696,173770 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
r173211 | jpeeler | 2009-02-03 14:57:01 -0700 (Tue, 03 Feb 2009) | 17 lines

Parking attempts made to one end of a bridge no longer will hang up due to a
parking failure.

Parking attempts made using either one-touch, or doing either a blind or 
assisted transfer to the parking extension now keep up the bridge instead of
hanging up the attempted parked party. Normal causes for the parking attempt
to fail includes the specific specified extension (via PARKINGEXTEN) not being 
available or if all the parking spaces are currently in use. To avoid having
to reverse a masquerade park_space_reserve was made to provide foresight if
a parking attempt will succeed and if so reserve the parking space.

(closes issue #13494)
Reported by: mdu113

Reviewed by Russell: http://reviewboard.digium.com/r/133/


........
r173248 | dvossel | 2009-02-03 16:35:55 -0700 (Tue, 03 Feb 2009) | 7 lines

Fixes issue with IAX2 transfer not handing off calls. 

Fixes issue with IAX2 transfers not taking place.  As it was, a call that was being transfered would never be handed off correctly to the call ends because of how call numbers were stored in a hash table.  The hash table, "iax_peercallno_pvt", storing all the current call numbers did not take into account the complications associated with transferring a call, so a separate hash table was required.  This second hash table "iax_transfercallno_pvt" handles calls being transfered, once the call transfer is complete the call is removed from the transfer hash table and added to the peer hash table resuming normal operations. Addition functions were created to handle storing, removing, and comparing items in the iax_transfercallno_pvt table. 

(issue #13468)
Review: http://reviewboard.digium.com/r/140/

........
r173392 | mmichelson | 2009-02-04 10:40:29 -0700 (Wed, 04 Feb 2009) | 3 lines

Add a missing unlock. Extremely unlikely to ever matter, but it's needed.


........
r173396 | mmichelson | 2009-02-04 10:44:48 -0700 (Wed, 04 Feb 2009) | 3 lines

Revert my previous change because it was stupid


........
r173559 | mmichelson | 2009-02-05 10:34:33 -0700 (Thu, 05 Feb 2009) | 25 lines

Fix a problem where a channel pointer becomes invalid due to masquerading or hanging up.

app_mixmonitor runs its own thread to monitor the channel's activity and write the mixed
audio to a file. Since this thread runs independently of the channel, it is possible that
the mixmonitor thread's channel pointer will point to freed memory when the channel either
is masqueraded or hangs up (technically, both cases are hangups, but we need to handle the
cases slightly differently).

The solution for this is to employ a datastore, which has the nice benefit of allowing us 
to hook into channel masquerades and hangups and update our pointer as necessary. If this
looks familiar, this same technique is employed in app_chanspy. app_chanspy is a bit more
involved since it does a lot more operations on the channel that is being spied upon.

app_mixmonitor does have an extra touch that app_chanspy doesn't have, though. Since there
is a thread race between the channel's thread and the mixmonitor thread on a hangup, we em-
ploy a condition-and-boolean combination to ensure that the channel thread finishes with
our structure before the mixmonitor thread attempts to free it. No crashes!

(closes issue #14374)
Reported by: aragon
Patches:
	  14374.patch uploaded by putnopvut (license 60)
Tested by: aragon, putnopvut


........
r173592 | mmichelson | 2009-02-05 11:47:24 -0700 (Thu, 05 Feb 2009) | 3 lines

Add some missing cleanup to app_mixmonitor


........
r173692 | mmichelson | 2009-02-05 13:29:09 -0700 (Thu, 05 Feb 2009) | 12 lines

Fix situations where queue members could be autopaused unexpectedly

Specifically, this patch prevents us from autopausing members when
we receive a busy or congestion frame from them.

(closes issue #14376)
Reported by: fiddur
Patches:
      14376.patch uploaded by putnopvut (license 60)
Tested by: fiddur


........
r173696 | jpeeler | 2009-02-05 13:47:51 -0700 (Thu, 05 Feb 2009) | 12 lines

Add new configuration option to make shared IMAP mailboxes function as expected.

The new option is "imapvmshareid" which is an ID to tag multiple mailboxes
using the same IMAP storage location to function as one mailbox. This allows
all messages to be retrieved for any user in the group. The patch alters the
'X-Asterisk-VM-Extension' header that is responsible for matching voicemails
for a given user.

(closes issue #13673)
Reported by: howardwilkinson


........
r173770 | mmichelson | 2009-02-05 16:19:16 -0700 (Thu, 05 Feb 2009) | 20 lines

Fix logic regarding when to perform an SRV lookup for outgoing REGISTER requests

With this fix, we only will perform an SRV lookup at the following times:

* The first time we register with a remote registrar
* If we send a REGISTER but do not receive a response
* If the sendto() function returns an error

While I wrote the patch that fixes this issue, a huge amount of credit is due
to Brett Bryant, who wrote the initial patch on which I based this one.

(closes issue #12312)
Reported by: jrast
Patches:
      12312.patch uploaded by putnopvut (license 60)
Tested by: blitzrage

Review: http://reviewboard.digium.com/r/132/


........

Modified:
    team/murf/cdr-debug-1.4/   (props changed)
    team/murf/cdr-debug-1.4/apps/app_mixmonitor.c
    team/murf/cdr-debug-1.4/apps/app_queue.c
    team/murf/cdr-debug-1.4/apps/app_voicemail.c
    team/murf/cdr-debug-1.4/channels/chan_iax2.c
    team/murf/cdr-debug-1.4/channels/chan_sip.c
    team/murf/cdr-debug-1.4/res/res_features.c

Propchange: team/murf/cdr-debug-1.4/
------------------------------------------------------------------------------
    automerge = yep

Propchange: team/murf/cdr-debug-1.4/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Fri Feb  6 00:24:34 2009
@@ -1,1 +1,1 @@
-/branches/1.4:1-173200
+/branches/1.4:1-173842

Modified: team/murf/cdr-debug-1.4/apps/app_mixmonitor.c
URL: http://svn.digium.com/svn-view/asterisk/team/murf/cdr-debug-1.4/apps/app_mixmonitor.c?view=diff&rev=173843&r1=173842&r2=173843
==============================================================================
--- team/murf/cdr-debug-1.4/apps/app_mixmonitor.c (original)
+++ team/murf/cdr-debug-1.4/apps/app_mixmonitor.c Fri Feb  6 00:24:34 2009
@@ -98,7 +98,7 @@
 	char *post_process;
 	char *name;
 	unsigned int flags;
-	struct ast_channel *chan;
+	struct mixmonitor_ds *mixmonitor_ds;
 };
 
 enum {
@@ -123,6 +123,50 @@
 	AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME),
 	AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
 });
+
+/* This structure is used as a means of making sure that our pointer to
+ * the channel we are monitoring remains valid. This is very similar to 
+ * what is used in app_chanspy.c.
+ */
+struct mixmonitor_ds {
+	struct ast_channel *chan;
+	/* These condition variables are used to be sure that the channel
+	 * hangup code completes before the mixmonitor thread attempts to
+	 * free this structure. The combination of a bookean flag and a
+	 * ast_cond_t ensure that no matter what order the threads run in,
+	 * we are guaranteed to never have the waiting thread block forever
+	 * in the case that the signaling thread runs first.
+	 */
+	unsigned int destruction_ok;
+	ast_cond_t destruction_condition;
+	ast_mutex_t lock;
+};
+
+static void mixmonitor_ds_destroy(void *data)
+{
+	struct mixmonitor_ds *mixmonitor_ds = data;
+
+	ast_mutex_lock(&mixmonitor_ds->lock);
+	mixmonitor_ds->chan = NULL;
+	mixmonitor_ds->destruction_ok = 1;
+	ast_cond_signal(&mixmonitor_ds->destruction_condition);
+	ast_mutex_unlock(&mixmonitor_ds->lock);
+}
+
+static void mixmonitor_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
+{
+	struct mixmonitor_ds *mixmonitor_ds = data;
+
+	ast_mutex_lock(&mixmonitor_ds->lock);
+	mixmonitor_ds->chan = new_chan;
+	ast_mutex_unlock(&mixmonitor_ds->lock);
+}
+
+static struct ast_datastore_info mixmonitor_ds_info = {
+	.type = "mixmonitor",
+	.destroy = mixmonitor_ds_destroy,
+	.chan_fixup = mixmonitor_ds_chan_fixup,
+};
 
 static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook) 
 {
@@ -165,8 +209,10 @@
 		
 		if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR)))
 			continue;
-		
-		if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || ast_bridged_channel(mixmonitor->chan)) {
+
+		ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
+		if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) {
+			ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
 			/* Initialize the file if not already done so */
 			if (!fs && !errflag) {
 				oflags = O_CREAT | O_WRONLY;
@@ -186,6 +232,8 @@
 			/* Write out the frame */
 			if (fs)
 				ast_writestream(fs, fr);
+		} else {
+			ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
 		}
 
 		/* All done! free it. */
@@ -208,10 +256,46 @@
 		ast_safe_system(mixmonitor->post_process);
 	}
 
+	ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
+	if (!mixmonitor->mixmonitor_ds->destruction_ok) {
+		ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
+	}
+	ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
+	ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
+	ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
+	ast_free(mixmonitor->mixmonitor_ds);
 	free(mixmonitor);
 
-
 	return NULL;
+}
+
+static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan)
+{
+	struct ast_datastore *datastore = NULL;
+	struct mixmonitor_ds *mixmonitor_ds;
+
+	if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
+		return -1;
+	}
+	
+	ast_mutex_init(&mixmonitor_ds->lock);
+	ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
+
+	if (!(datastore = ast_channel_datastore_alloc(&mixmonitor_ds_info, NULL))) {
+		ast_free(mixmonitor_ds);
+		return -1;
+	}
+
+	/* No need to lock mixmonitor_ds since this is still operating in the channel's thread */
+	mixmonitor_ds->chan = chan;
+	datastore->data = mixmonitor_ds;
+
+	ast_channel_lock(chan);
+	ast_channel_datastore_add(chan, datastore);
+	ast_channel_unlock(chan);
+
+	mixmonitor->mixmonitor_ds = mixmonitor_ds;
+	return 0;
 }
 
 static void launch_monitor_thread(struct ast_channel *chan, const char *filename, unsigned int flags,
@@ -248,7 +332,9 @@
 
 	/* Copy over flags and channel name */
 	mixmonitor->flags = flags;
-	mixmonitor->chan = chan;
+	if (setup_mixmonitor_ds(mixmonitor, chan)) {
+		return;
+	}
 	mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor);
 	strcpy(mixmonitor->name, chan->name);
 	if (!ast_strlen_zero(postprocess2)) {
@@ -285,7 +371,6 @@
 	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 	ast_pthread_create_background(&thread, &attr, mixmonitor_thread, mixmonitor);
 	pthread_attr_destroy(&attr);
-
 }
 
 static int mixmonitor_exec(struct ast_channel *chan, void *data)

Modified: team/murf/cdr-debug-1.4/apps/app_queue.c
URL: http://svn.digium.com/svn-view/asterisk/team/murf/cdr-debug-1.4/apps/app_queue.c?view=diff&rev=173843&r1=173842&r2=173843
==============================================================================
--- team/murf/cdr-debug-1.4/apps/app_queue.c (original)
+++ team/murf/cdr-debug-1.4/apps/app_queue.c Fri Feb  6 00:24:34 2009
@@ -2069,12 +2069,12 @@
 }
 
 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
-static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername)
+static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername, int pause)
 {
 	if (option_verbose > 2)
 		ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime);
 	ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
-	if (qe->parent->autopause) {
+	if (qe->parent->autopause && pause) {
 		if (!set_member_paused(qe->parent->name, interface, 1)) {
 			if (option_verbose > 2)
 				ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
@@ -2251,7 +2251,7 @@
 							do_hang(o);
 							endtime = (long)time(NULL);
 							endtime -= starttime;
-							rna(endtime*1000, qe, on, membername);
+							rna(endtime * 1000, qe, on, membername, 0);
 							if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
 								if (qe->parent->timeoutrestart)
 									*to = orig;
@@ -2266,7 +2266,7 @@
 								ast_cdr_busy(in->cdr);
 							endtime = (long)time(NULL);
 							endtime -= starttime;
-							rna(endtime*1000, qe, on, membername);
+							rna(endtime * 1000, qe, on, membername, 0);
 							do_hang(o);
 							if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
 								if (qe->parent->timeoutrestart)
@@ -2289,7 +2289,7 @@
 					ast_frfree(f);
 				} else {
 					endtime = (long) time(NULL) - starttime;
-					rna(endtime * 1000, qe, on, membername);
+					rna(endtime * 1000, qe, on, membername, 1);
 					do_hang(o);
 					if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
 						if (qe->parent->timeoutrestart)
@@ -2327,7 +2327,7 @@
 		}
 		if (!*to) {
 			for (o = start; o; o = o->call_next)
-				rna(orig, qe, o->interface, o->member->membername);
+				rna(orig, qe, o->interface, o->member->membername, 1);
 		}
 	}
 

Modified: team/murf/cdr-debug-1.4/apps/app_voicemail.c
URL: http://svn.digium.com/svn-view/asterisk/team/murf/cdr-debug-1.4/apps/app_voicemail.c?view=diff&rev=173843&r1=173842&r2=173843
==============================================================================
--- team/murf/cdr-debug-1.4/apps/app_voicemail.c (original)
+++ team/murf/cdr-debug-1.4/apps/app_voicemail.c Fri Feb  6 00:24:34 2009
@@ -350,6 +350,7 @@
 #ifdef IMAP_STORAGE
 	char imapuser[80];	/* IMAP server login */
 	char imappassword[80];	/* IMAP server password if authpassword not defined */
+	char imapvmshareid[80]; /* Shared mailbox ID to use rather than the dialed one */
 #endif
 	double volgain;		/*!< Volume gain for voicemails sent via email */
 	AST_LIST_ENTRY(ast_vm_user) list;
@@ -627,6 +628,8 @@
 		ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
 	} else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
 		ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
+	} else if (!strcasecmp(var, "imapvmshareid")) {
+		ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
 #endif
 	} else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
 		ast_set2_flag(vmu, ast_true(value), VM_DELETE);	
@@ -731,6 +734,8 @@
 			ast_copy_string(retval->imapuser, tmp->value, sizeof(retval->imapuser));
 		} else if (!strcasecmp(tmp->name, "imappassword") || !strcasecmp(tmp->name, "imapsecret")) {
 			ast_copy_string(retval->imappassword, tmp->value, sizeof(retval->imappassword));
+		} else if (!strcasecmp(tmp->name, "imapvmshareid")) {
+			ast_copy_string(retval->imapvmshareid, tmp->value, sizeof(retval->imapvmshareid));
 #endif
 		} else
 			apply_option(retval, tmp->name, tmp->value);
@@ -1219,7 +1224,7 @@
 	if (ret == 0) {
 		ast_mutex_lock(&vms_p->lock);
 		pgm = mail_newsearchpgm ();
-		hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)mailbox);
+		hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
 		pgm->header = hdr;
 		if (fold != 1) {
 			pgm->unseen = 1;
@@ -1563,7 +1568,7 @@
 	pgm = mail_newsearchpgm();
 
 	/* Check IMAP folder for Asterisk messages only... */
-	hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", vmu->mailbox);
+	hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
 	pgm->header = hdr;
 	pgm->deleted = 0;
 	pgm->undeleted = 1;
@@ -3214,7 +3219,11 @@
 		/* fprintf(p, "X-Asterisk-VM-Orig-Mailbox: %s" ENDL, ext); */
 		fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
 		fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
+#ifdef IMAP_STORAGE
+		fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
+#else
 		fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
+#endif
 		fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
 		fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
 		fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);

Modified: team/murf/cdr-debug-1.4/channels/chan_iax2.c
URL: http://svn.digium.com/svn-view/asterisk/team/murf/cdr-debug-1.4/channels/chan_iax2.c?view=diff&rev=173843&r1=173842&r2=173843
==============================================================================
--- team/murf/cdr-debug-1.4/channels/chan_iax2.c (original)
+++ team/murf/cdr-debug-1.4/channels/chan_iax2.c Fri Feb  6 00:24:34 2009
@@ -823,6 +823,13 @@
  */
 static struct ao2_container *iax_peercallno_pvts;
 
+/*!
+ *  * \brief Another container of iax2_pvt structures
+ *  
+ *  Active IAX2 pvt stucts used during transfering a call are stored here.  
+ */
+static struct ao2_container *iax_transfercallno_pvts;
+
 /* Flag to use with trunk calls, keeping these calls high up.  It halves our effective use
    but keeps the division between trunked and non-trunked better. */
 #define TRUNK_CALL_START	ARRAY_LEN(iaxs) / 2
@@ -1247,6 +1254,25 @@
 	AST_SCHED_DEL(sched, pvt->jbid);
 }
 
+static void store_by_transfercallno(struct chan_iax2_pvt *pvt)
+{
+	if (!pvt->transfercallno) {
+		ast_log(LOG_ERROR, "This should not be called without a transfer call number.\n");
+		return;
+	}
+
+	ao2_link(iax_transfercallno_pvts, pvt);
+}
+
+static void remove_by_transfercallno(struct chan_iax2_pvt *pvt)
+{
+	if (!pvt->transfercallno) {
+		ast_log(LOG_ERROR, "This should not be called without a transfer call number.\n");
+		return;
+	}
+
+	ao2_unlink(iax_transfercallno_pvts, pvt);
+}
 static void store_by_peercallno(struct chan_iax2_pvt *pvt)
 {
 	if (!pvt->peercallno) {
@@ -1327,6 +1353,10 @@
 
 		if (pvt->peercallno) {
 			remove_by_peercallno(pvt);
+		}
+
+		if (pvt->transfercallno) {
+			remove_by_transfercallno(pvt);
 		}
 
 		if (!owner) {
@@ -1551,28 +1581,40 @@
 	char host[80];
 
 	if (new <= NEW_ALLOW) {
- 		if (callno) {
- 			struct chan_iax2_pvt *pvt;
- 			struct chan_iax2_pvt tmp_pvt = {
- 				.callno = dcallno,
- 				.peercallno = callno,
- 				/* hack!! */
- 				.frames_received = check_dcallno,
- 			};
- 
- 			memcpy(&tmp_pvt.addr, sin, sizeof(tmp_pvt.addr));
- 
- 			if ((pvt = ao2_find(iax_peercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
- 				if (return_locked) {
- 					ast_mutex_lock(&iaxsl[pvt->callno]);
- 				}
- 				res = pvt->callno;
- 				ao2_ref(pvt, -1);
- 				pvt = NULL;
- 				return res;
- 			}
- 		}
-
+		if (callno) {
+			struct chan_iax2_pvt *pvt;
+			struct chan_iax2_pvt tmp_pvt = {
+				.callno = dcallno,
+				.peercallno = callno,
+				.transfercallno = callno,
+				/* hack!! */
+				.frames_received = check_dcallno,
+			};
+
+			memcpy(&tmp_pvt.addr, sin, sizeof(tmp_pvt.addr));
+			/* this works for finding normal call numbers not involving transfering */ 
+			if ((pvt = ao2_find(iax_peercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
+				if (return_locked) {
+					ast_mutex_lock(&iaxsl[pvt->callno]);
+				}
+				res = pvt->callno;
+				ao2_ref(pvt, -1);
+				pvt = NULL;
+				return res;
+			}
+			/* this searches for transfer call numbers that might not get caught otherwise */
+			memset(&tmp_pvt.addr, 0, sizeof(tmp_pvt.addr));
+			memcpy(&tmp_pvt.transfer, sin, sizeof(tmp_pvt.addr));
+			if ((pvt = ao2_find(iax_transfercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
+				if (return_locked) {
+					ast_mutex_lock(&iaxsl[pvt->callno]);
+				}
+				res = pvt->callno;
+				ao2_ref(pvt, -1);
+				pvt = NULL;
+				return res;
+			}
+		}
 		/* This will occur on the first response to a message that we initiated,
 		 * such as a PING. */
 		if (dcallno) {
@@ -1590,7 +1632,6 @@
 		if (dcallno) {
 			ast_mutex_unlock(&iaxsl[dcallno]);
 		}
-
 #ifdef IAX_OLD_FIND
 		/* If we get here, we SHOULD NOT find a call structure for this
 		   callno; if we do, it means that there is a call structure that
@@ -5885,10 +5926,11 @@
 	pvt->transfer.sin_family = AF_INET;
 	pvt->transferring = TRANSFER_BEGIN;
 	pvt->transferid = ies->transferid;
+	store_by_transfercallno(pvt);
 	if (ies->transferid)
 		iax_ie_append_int(&ied, IAX_IE_TRANSFERID, ies->transferid);
 	send_command_transfer(pvt, AST_FRAME_IAX, IAX_COMMAND_TXCNT, 0, ied.buf, ied.pos);
-	return 0; 
+	return 0;
 }
 
 static int complete_dpreply(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
@@ -5965,6 +6007,7 @@
 		ast_log(LOG_WARNING, "Invalid transfer request\n");
 		return -1;
 	}
+	remove_by_transfercallno(pvt);
 	memcpy(&pvt->addr, &pvt->transfer, sizeof(pvt->addr));
 	memset(&pvt->transfer, 0, sizeof(pvt->transfer));
 	/* Reset sequence numbers */
@@ -5977,8 +6020,8 @@
 		remove_by_peercallno(pvt);
 	}
 	pvt->peercallno = peercallno;
+	/*this is where the transfering call swiches hash tables */
 	store_by_peercallno(pvt);
-
 	pvt->transferring = TRANSFER_NONE;
 	pvt->svoiceformat = -1;
 	pvt->voiceformat = 0;
@@ -11187,6 +11230,7 @@
 	ao2_ref(peers, -1);
 	ao2_ref(users, -1);
 	ao2_ref(iax_peercallno_pvts, -1);
+	ao2_ref(iax_transfercallno_pvts, -1);	
 
 	return 0;
 }
@@ -11225,6 +11269,23 @@
 		pvt2->frames_received) ? CMP_MATCH | CMP_STOP : 0;
 }
 
+static int transfercallno_pvt_hash_cb(const void *obj, const int flags)
+{
+	const struct chan_iax2_pvt *pvt = obj;
+
+	return pvt->transfercallno;
+}
+
+static int transfercallno_pvt_cmp_cb(void *obj, void *arg, int flags)
+{
+	struct chan_iax2_pvt *pvt = obj, *pvt2 = arg;
+
+	/* The frames_received field is used to hold whether we're matching
+	 * against a full frame or not ... */
+
+	return match(&pvt2->transfer, pvt2->transfercallno, pvt2->callno, pvt,
+		pvt2->frames_received) ? CMP_MATCH | CMP_STOP : 0;
+}
 /*! \brief Load IAX2 module, load configuraiton ---*/
 static int load_module(void)
 {
@@ -11247,7 +11308,13 @@
 		ao2_ref(users, -1);
 		return AST_MODULE_LOAD_FAILURE;
 	}
-
+	iax_transfercallno_pvts = ao2_container_alloc(IAX_MAX_CALLS, transfercallno_pvt_hash_cb, transfercallno_pvt_cmp_cb);
+	if (!iax_transfercallno_pvts) {
+		ao2_ref(peers, -1);
+		ao2_ref(users, -1);
+		ao2_ref(iax_peercallno_pvts, -1);
+		return AST_MODULE_LOAD_FAILURE;
+	}
 	ast_custom_function_register(&iaxpeer_function);
 
 	iax_set_output(iax_debug_output);

Modified: team/murf/cdr-debug-1.4/channels/chan_sip.c
URL: http://svn.digium.com/svn-view/asterisk/team/murf/cdr-debug-1.4/channels/chan_sip.c?view=diff&rev=173843&r1=173842&r2=173843
==============================================================================
--- team/murf/cdr-debug-1.4/channels/chan_sip.c (original)
+++ team/murf/cdr-debug-1.4/channels/chan_sip.c Fri Feb  6 00:24:34 2009
@@ -1174,6 +1174,7 @@
 	int refresh;			/*!< How often to refresh */
 	struct sip_pvt *call;		/*!< create a sip_pvt structure for each outbound "registration dialog" in progress */
 	enum sipregistrystate regstate;	/*!< Registration state (see above) */
+	unsigned int needdns:1; /*!< Set if we need a new dns lookup before we try to transmit */
 	time_t regtime;		/*!< Last succesful registration time */
 	int callid_valid;		/*!< 0 means we haven't chosen callid for this registry yet. */
 	unsigned int ocseq;		/*!< Sequence number we got to for REGISTERs for this registry */
@@ -1512,7 +1513,7 @@
 static const struct sockaddr_in *sip_real_dst(const struct sip_pvt *p);
 static void build_via(struct sip_pvt *p);
 static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer);
-static int create_addr(struct sip_pvt *dialog, const char *opeer);
+static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockaddr_in *sin);
 static char *generate_random_string(char *buf, size_t size);
 static void build_callid_pvt(struct sip_pvt *pvt);
 static void build_callid_registry(struct sip_registry *reg, struct in_addr ourip, const char *fromdomain);
@@ -1800,7 +1801,14 @@
 		case ECONNREFUSED:      /* ICMP port unreachable */ 
 			res = XMIT_ERROR;	/* Don't bother with trying to transmit again */
 		}
-	}
+
+		if (p->registry && p->registry->regstate < REG_STATE_REGISTERED) {
+			AST_SCHED_DEL(sched, p->registry->timeout);
+			p->registry->needdns = TRUE;
+			p->registry->timeout = ast_sched_add(sched, 1, sip_reg_timeout, p->registry);
+		}
+	}
+
 	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));
 	return res;
@@ -2907,7 +2915,7 @@
 /*! \brief create address structure from peer name
  *      Or, if peer not found, find it in the global DNS 
  *      returns TRUE (-1) on failure, FALSE on success */
-static int create_addr(struct sip_pvt *dialog, const char *opeer)
+static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockaddr_in *sin)
 {
 	struct hostent *hp;
 	struct ast_hostent ahp;
@@ -2934,27 +2942,40 @@
 		ASTOBJ_UNREF(p, sip_destroy_peer);
 		return res;
 	}
-	hostn = peer;
-	portno = port ? atoi(port) : STANDARD_SIP_PORT;
-	if (srvlookup) {
-		char service[MAXHOSTNAMELEN];
-		int tportno;
-		int ret;
-
-		snprintf(service, sizeof(service), "_sip._udp.%s", peer);
-		ret = ast_get_srv(NULL, host, sizeof(host), &tportno, service);
-		if (ret > 0) {
-			hostn = host;
-			portno = tportno;
-		}
-	}
-	hp = ast_gethostbyname(hostn, &ahp);
-	if (!hp) {
-		ast_log(LOG_WARNING, "No such host: %s\n", peer);
-		return -1;
-	}
+	
 	ast_string_field_set(dialog, tohost, peer);
-	memcpy(&dialog->sa.sin_addr, hp->h_addr, sizeof(dialog->sa.sin_addr));
+
+	if (sin) {
+		memcpy(&dialog->sa.sin_addr, &sin->sin_addr, sizeof(dialog->sa.sin_addr));
+		if (!sin->sin_port) {
+			if (ast_strlen_zero(port) || sscanf(port, "%u", &portno) != 1) {
+				portno = STANDARD_SIP_PORT;
+			}
+		} else {
+			portno = ntohs(sin->sin_port);
+		}
+	} else {
+		hostn = peer;
+		portno = port ? atoi(port) : STANDARD_SIP_PORT;
+		if (srvlookup) {
+			char service[MAXHOSTNAMELEN];
+			int tportno;
+			int ret;
+
+			snprintf(service, sizeof(service), "_sip._udp.%s", peer);
+			ret = ast_get_srv(NULL, host, sizeof(host), &tportno, service);
+			if (ret > 0) {
+				hostn = host;
+				portno = tportno;
+			}
+		}
+		hp = ast_gethostbyname(hostn, &ahp);
+		if (!hp) {
+			ast_log(LOG_WARNING, "No such host: %s\n", peer);
+			return -1;
+		}
+		memcpy(&dialog->sa.sin_addr, hp->h_addr, sizeof(dialog->sa.sin_addr));
+	}
 	dialog->sa.sin_port = htons(portno);
 	dialog->recv = dialog->sa;
 	return 0;
@@ -4815,6 +4836,7 @@
 	reg->portno = portnum;
 	reg->callid_valid = FALSE;
 	reg->ocseq = INITIAL_CSEQ;
+	reg->needdns = TRUE;
 	ASTOBJ_CONTAINER_LINK(&regl, reg);	/* Add the new registry entry to the list */
 	ASTOBJ_UNREF(reg,sip_registry_destroy);
 	return 0;
@@ -7645,6 +7667,7 @@
 	} else {
 		r->regstate = REG_STATE_UNREGISTERED;
 		r->timeout = -1;
+		r->needdns = TRUE;
 		res=transmit_register(r, SIP_REGISTER, NULL, NULL);
 	}
 	manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelDriver: SIP\r\nUsername: %s\r\nDomain: %s\r\nStatus: %s\r\n", r->username, r->hostname, regstate2str(r->regstate));
@@ -7693,8 +7716,9 @@
 		}
 		if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY))
 			append_history(p, "RegistryInit", "Account: %s@%s", r->username, r->hostname);
-		/* Find address to hostname */
-		if (create_addr(p, r->hostname)) {
+		/* Find address to hostname if we haven't tried to connect
+		 * or a connection error has occurred */
+		if (create_addr(p, r->hostname, r->needdns ? NULL : &r->us)) {
 			/* we have what we hope is a temporary network error,
 			 * probably DNS.  We need to reschedule a registration try */
 			sip_destroy(p);
@@ -7709,6 +7733,10 @@
 			r->regattempts++;
 			return 0;
 		}
+		if (r->needdns) {
+			memcpy(&r->us, &p->sa, sizeof(r->us));
+		}
+		r->needdns = FALSE;
 		/* Copy back Call-ID in case create_addr changed it */
 		ast_string_field_set(r, callid, p->callid);
 		if (r->portno) {
@@ -11568,7 +11596,7 @@
 			return RESULT_FAILURE;
 		}
 
-		if (create_addr(p, argv[i])) {
+		if (create_addr(p, argv[i], NULL)) {
 			/* Maybe they're not registered, etc. */
 			sip_destroy(p);
 			ast_cli(fd, "Could not create address for '%s'\n", argv[i]);
@@ -16687,7 +16715,7 @@
 		host = tmp;
 	}
 
-	if (create_addr(p, host)) {
+	if (create_addr(p, host, NULL)) {
 		*cause = AST_CAUSE_UNREGISTERED;
 		if (option_debug > 2)
 			ast_log(LOG_DEBUG, "Cant create SIP call - target device not registred\n");

Modified: team/murf/cdr-debug-1.4/res/res_features.c
URL: http://svn.digium.com/svn-view/asterisk/team/murf/cdr-debug-1.4/res/res_features.c?view=diff&rev=173843&r1=173842&r2=173843
==============================================================================
--- team/murf/cdr-debug-1.4/res/res_features.c (original)
+++ team/murf/cdr-debug-1.4/res/res_features.c Fri Feb  6 00:24:34 2009
@@ -72,6 +72,14 @@
 #define AST_MAX_WATCHERS 256
 #define MAX_DIAL_FEATURE_OPTIONS 30
 
+#define FEATURE_RETURN_HANGUP                  -1
+#define FEATURE_RETURN_SUCCESSBREAK             0
+#define FEATURE_RETURN_PASSDIGITS               21
+#define FEATURE_RETURN_STOREDIGITS              22
+#define FEATURE_RETURN_SUCCESS                  23
+#define FEATURE_RETURN_KEEPTRYING               24
+#define FEATURE_RETURN_PARKFAILED               25
+
 enum {
 	AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
 	AST_FEATURE_FLAG_ONPEER =    (1 << 1),
@@ -338,16 +346,15 @@
 		return AST_DEVICE_INUSE;
 }
 
-static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name)
+static struct parkeduser *park_space_reserve(struct ast_channel *chan)
 {
 	struct parkeduser *pu, *cur;
-	int i, x = -1, parking_range, parkingnum_copy;
-	struct ast_context *con;
+	int i, parking_space = -1, parking_range;
 	const char *parkingexten;
-	
+
 	/* Allocate memory for parking data */
 	if (!(pu = ast_calloc(1, sizeof(*pu)))) 
-		return -1;
+		return NULL;
 
 	/* Lock parking lot */
 	ast_mutex_lock(&parking_lock);
@@ -360,28 +367,28 @@
 		 * limitation here.  If extout was not numeric, we could permit
 		 * arbitrary non-numeric extensions.
 		 */
-		if (sscanf(parkingexten, "%d", &x) != 1 || x < 0) {
+		if (sscanf(parkingexten, "%d", &parking_space) != 1 || parking_space < 0) {
 			ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
 			ast_mutex_unlock(&parking_lock);
 			free(pu);
-			return 1;	/* Continue execution if possible */
-		}
-		snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
+			return NULL;
+		}
+		snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
 
 		if (ast_exists_extension(NULL, parking_con, pu->parkingexten, 1, NULL)) {
 			ast_mutex_unlock(&parking_lock);
+			ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
 			free(pu);
-			ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
-			return 1;	/* Continue execution if possible */
+			return NULL;
 		}
 	} else {
 		/* Select parking space within range */
 		parking_range = parking_stop - parking_start+1;
 		for (i = 0; i < parking_range; i++) {
-			x = (i + parking_offset) % parking_range + parking_start;
+			parking_space = (i + parking_offset) % parking_range + parking_start;
 			cur = parkinglot;
 			while(cur) {
-				if (cur->parkingnum == x) 
+				if (cur->parkingnum == parking_space) 
 					break;
 				cur = cur->next;
 			}
@@ -391,15 +398,37 @@
 
 		if (!(i < parking_range)) {
 			ast_log(LOG_WARNING, "No more parking spaces\n");
+			ast_mutex_unlock(&parking_lock);
 			free(pu);
-			ast_mutex_unlock(&parking_lock);
-			return -1;
+			return NULL;
 		}
 		/* Set pointer for next parking */
 		if (parkfindnext) 
-			parking_offset = x - parking_start + 1;
-		snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
-	}
+			parking_offset = parking_space - parking_start + 1;
+		snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
+	}
+	
+	pu->notquiteyet = 1;
+	pu->parkingnum = parking_space;
+	pu->next = parkinglot;
+	parkinglot = pu;
+	ast_mutex_unlock(&parking_lock);
+
+	return pu;
+}
+
+static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, const char *orig_chan_name, struct parkeduser *pu)
+{
+	struct ast_context *con;
+	int parkingnum_copy;
+	
+	/* Get a valid space if not already done */
+	if (pu == NULL)
+		pu = park_space_reserve(chan);
+	if (pu == NULL)
+		return 1; /* Continue execution if possible */
+
+	snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum);
 	
 	chan->appl = "Parked Call";
 	chan->data = NULL; 
@@ -414,10 +443,9 @@
 	}
 	
 	pu->start = ast_tvnow();
-	pu->parkingnum = x;
 	pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
 	if (extout)
-		*extout = x;
+		*extout = pu->parkingnum;
 
 	if (peer) { 
 		/* This is so ugly that it hurts, but implementing get_base_channel() on local channels
@@ -449,12 +477,12 @@
 	ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
 	ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
 	pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
-	pu->next = parkinglot;
-	parkinglot = pu;
 	parkingnum_copy = pu->parkingnum;
-	/* If parking a channel directly, don't quite yet get parking running on it */
-	if (peer == chan) 
-		pu->notquiteyet = 1;
+
+	/* If parking a channel directly (peer == chan), don't quite yet get parking running on it.
+     * All parking lot entires are put into the parking lot with notquiteyet on. */
+	if (peer != chan) 
+		pu->notquiteyet = 0;
 
 	if (option_verbose > 1) 
 		ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parking_con, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
@@ -488,7 +516,6 @@
 		}
 	}
 
-	ast_mutex_unlock(&parking_lock);
 	/* Wake up the (presumably select()ing) thread */
 	pthread_kill(parking_thread, SIGURG);
 
@@ -517,14 +544,20 @@
 	after these channels too */
 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
 {
-	return park_call_full(chan, peer, timeout, extout, NULL);
+	return park_call_full(chan, peer, timeout, extout, NULL, NULL);
 }
 
 static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, const char *orig_chan_name)
 {
 	struct ast_channel *chan;
 	struct ast_frame *f;
+	struct parkeduser *pu;
 	int park_status;
+
+	if ((pu = park_space_reserve(rchan)) == NULL) {
+		ast_stream_and_wait(peer, "beeperr", peer->language, "");
+		return FEATURE_RETURN_PARKFAILED;
+	}
 
 	/* Make a new, fake channel that we'll use to masquerade in the real one */
 	if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
@@ -553,7 +586,7 @@
 		orig_chan_name = ast_strdupa(chan->name);
 	}
 
-	park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name);
+	park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name, pu);
 	if (park_status == 1) {
 		/* would be nice to play: "invalid parking extension" */
 		ast_hangup(chan);
@@ -572,12 +605,6 @@
 {
 	return masq_park_call(rchan, peer, timeout, extout, 1, orig_chan_name);
 }
-#define FEATURE_RETURN_HANGUP                  -1
-#define FEATURE_RETURN_SUCCESSBREAK             0
-#define FEATURE_RETURN_PASSDIGITS               21
-#define FEATURE_RETURN_STOREDIGITS              22
-#define FEATURE_RETURN_SUCCESS                  23
-#define FEATURE_RETURN_KEEPTRYING               24
 
 #define FEATURE_SENSE_CHAN	(1 << 0)
 #define FEATURE_SENSE_PEER	(1 << 1)
@@ -624,8 +651,8 @@
 		res = ast_safe_sleep(chan, 1000);
 
 	if (!res) { /* one direction used to call park_call.... */
-		masq_park_call_announce(parkee, parker, 0, NULL, orig_chan_name);
-		res = 0; /* PBX should hangup zombie channel */
+		res = masq_park_call_announce(parkee, parker, 0, NULL, orig_chan_name);
+		/* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */
 	}
 
 	ast_module_user_remove(u);
@@ -751,6 +778,7 @@
 	char xferto[256];
 	int res;
 	const char *orig_chan_name;
+	int parkstatus = 0;
 
 	set_peers(&transferer, &transferee, peer, chan, sense);
 	orig_chan_name = ast_strdupa(transferer->name);
@@ -780,13 +808,13 @@
 		res = finishup(transferee);
 		if (res)
 			res = -1;
-		else if (!masq_park_call_announce(transferee, transferer, 0, NULL, orig_chan_name)) {	/* success */
+		else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL, orig_chan_name))) {	/* success */
 			/* We return non-zero, but tell the PBX not to hang the channel when
 			   the thread dies -- We have to be careful now though.  We are responsible for 
 			   hanging up the channel, else it will never be hung up! */
 			return 0;
 		} else {
-			ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
+			ast_log(LOG_WARNING, "Unable to park call %s, parkstatus=%d\n", transferee->name, parkstatus);
 		}
 		/*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
 	} else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
@@ -827,7 +855,7 @@
 		if (option_verbose > 2)	
 			ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
 	}
-	if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
+	if (parkstatus != FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
 		finishup(transferee);
 		return -1;
 	}
@@ -1215,6 +1243,9 @@
 		    !ast_strlen_zero(builtin_features[x].exten)) {
 			/* Feature is up for consideration */
 			if (!strcmp(builtin_features[x].exten, code)) {
+				if (option_debug > 2) {
+					ast_log(LOG_DEBUG, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
+				}
 				res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
 				feature_detected = 1;
 				break;




More information about the asterisk-commits mailing list