[asterisk-commits] dlee: branch dlee/ari-async-bridge r396561 - in /team/dlee/ari-async-bridge: ...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Aug 13 10:16:17 CDT 2013


Author: dlee
Date: Tue Aug 13 10:16:15 2013
New Revision: 396561

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=396561
Log:
Merged revisions 396474-396560 from http://svn.asterisk.org/svn/asterisk/trunk

Modified:
    team/dlee/ari-async-bridge/   (props changed)
    team/dlee/ari-async-bridge/apps/confbridge/conf_config_parser.c
    team/dlee/ari-async-bridge/bridges/bridge_native_rtp.c
    team/dlee/ari-async-bridge/channels/chan_dahdi.c
    team/dlee/ari-async-bridge/channels/chan_sip.c
    team/dlee/ari-async-bridge/include/asterisk/bridge.h
    team/dlee/ari-async-bridge/include/asterisk/core_unreal.h
    team/dlee/ari-async-bridge/main/autoservice.c
    team/dlee/ari-async-bridge/main/bridge.c
    team/dlee/ari-async-bridge/main/bridge_channel.c
    team/dlee/ari-async-bridge/main/core_unreal.c
    team/dlee/ari-async-bridge/main/features.c
    team/dlee/ari-async-bridge/main/pbx.c
    team/dlee/ari-async-bridge/res/ari/resource_bridges.c
    team/dlee/ari-async-bridge/res/res_pjsip_registrar.c
    team/dlee/ari-async-bridge/tests/test_hashtab_thrash.c
    team/dlee/ari-async-bridge/tests/test_stasis.c

Propchange: team/dlee/ari-async-bridge/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Tue Aug 13 10:16:15 2013
@@ -1,1 +1,1 @@
-/trunk:1-396465
+/trunk:1-396560

Modified: team/dlee/ari-async-bridge/apps/confbridge/conf_config_parser.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-async-bridge/apps/confbridge/conf_config_parser.c?view=diff&rev=396561&r1=396560&r2=396561
==============================================================================
--- team/dlee/ari-async-bridge/apps/confbridge/conf_config_parser.c (original)
+++ team/dlee/ari-async-bridge/apps/confbridge/conf_config_parser.c Tue Aug 13 10:16:15 2013
@@ -123,8 +123,8 @@
 					<synopsis>Apply a denoise filter to the audio before mixing</synopsis>
 					<description><para>Sets whether or not a denoise filter should be applied
 					to the audio before mixing or not.  Off by default. Requires
-					codec_speex to be built and installed.  Do not confuse this option
-					with drop_silence.  Denoise is useful if there is a lot of background
+					<literal>codec_speex</literal> to be built and installed.  Do not confuse this option
+					with <replaceable>drop_silence</replaceable>.  Denoise is useful if there is a lot of background
 					noise for a user as it attempts to remove the noise while preserving
 					the speech.  This option does NOT remove silence from being mixed into
 					the conference and does come at the cost of a slight performance hit.
@@ -158,7 +158,7 @@
 						during mid sentence.
 					</para>
 					<para>
-						2. The drop_silence option depends on this value to
+						2. The <replaceable>drop_silence</replaceable> option depends on this value to
 						determine when the user's audio should begin to be
 						dropped from the conference bridge after the user
 						stops talking.  If this value is set too low the user's
@@ -200,7 +200,7 @@
 						room noise.
 						</para>
 						<para>
-						3. The drop_silence option depends on this value to determine
+						3. The <replaceable>drop_silence</replaceable> option depends on this value to determine
 						when the user's audio should be mixed into the bridge
 						after periods of silence.  If this value is too loose
 						the beginning of a user's speech will get cut off as they
@@ -274,15 +274,15 @@
 						Records the conference call starting when the first user
 						enters the room, and ending when the last user exits the room.
 						The default recorded filename is
-						<filename>'confbridge-${name of conference bridge}-${start time}.wav</filename>
+						<filename>'confbridge-${name of conference bridge}-${start time}.wav'</filename>
 						and the default format is 8khz slinear.  This file will be
-						located in the configured monitoring directory in asterisk.conf.
+						located in the configured monitoring directory in <filename>asterisk.conf</filename>.
 					</para></description>
 				</configOption>
 				<configOption name="record_file" default="confbridge-${name of conference bridge}-${start time}.wav">
 					<synopsis>The filename of the conference recording</synopsis>
 					<description><para>
-						When record_conference is set to yes, the specific name of the
+						When <replaceable>record_conference</replaceable> is set to yes, the specific name of the
 						record file can be set using this option.  Note that since multiple
 						conferences may use the same bridge profile, this may cause issues
 						depending on the configuration.  It is recommended to only use this
@@ -295,9 +295,9 @@
 				<configOption name="record_file_append" default="yes">
 					<synopsis>Append record file when starting/stopping on same conference recording</synopsis>
 					<description><para>
-						When record_file_append is set to yes, stopping and starting recording on a
+						When <replaceable>record_file_append</replaceable> is set to yes, stopping and starting recording on a
 						conference adds the new portion to end of current record_file. When this is
-						set to no, a new record_file is generated every time you start then stop recording
+						set to no, a new <replaceable>record_file</replaceable> is generated every time you start then stop recording
 						on a conference.
 					</para></description>
 				</configOption>
@@ -306,7 +306,7 @@
 					<description><para>
 						Sets how confbridge handles video distribution to the conference participants.
 						Note that participants wanting to view and be the source of a video feed
-						_MUST_ be sharing the same video codec.  Also, using video in conjunction with
+						<emphasis>MUST</emphasis> be sharing the same video codec.  Also, using video in conjunction with
 						with the jitterbuffer currently results in the audio being slightly out of sync
 						with the video.  This is a result of the jitterbuffer only working on the audio
 						stream.  It is recommended to disable the jitterbuffer when video is used.</para>
@@ -395,7 +395,7 @@
 			<configObject name="menu">
 				<synopsis>A conference user menu</synopsis>
 				<description>
-					<para>Conference users, as defined by a <literal>conf_user</literal>,
+					<para>Conference users, as defined by a <replaceable>conf_user</replaceable>,
 					can have a DTMF menu assigned to their profile when they enter the
 					<literal>ConfBridge</literal> application.</para>
 				</description>
@@ -412,7 +412,7 @@
 				</configOption>
 				<configOption name="^[0-9A-D*#]+$">
 					<synopsis>DTMF sequences to assign various confbridge actions to</synopsis>
-					<description><para>--- ConfBridge Menu Options ---</para>
+					<description>
 					<para>The ConfBridge application also has the ability to apply custom DTMF menus to
 					each channel using the application.  Like the User and Bridge profiles a menu
 					is passed in to ConfBridge as an argument in the dialplan.</para>

Modified: team/dlee/ari-async-bridge/bridges/bridge_native_rtp.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-async-bridge/bridges/bridge_native_rtp.c?view=diff&rev=396561&r1=396560&r2=396561
==============================================================================
--- team/dlee/ari-async-bridge/bridges/bridge_native_rtp.c (original)
+++ team/dlee/ari-async-bridge/bridges/bridge_native_rtp.c Tue Aug 13 10:16:15 2013
@@ -57,21 +57,21 @@
 	struct ast_rtp_glue **glue1, struct ast_rtp_instance **instance0, struct ast_rtp_instance **instance1,
 	struct ast_rtp_instance **vinstance0, struct ast_rtp_instance **vinstance1)
 {
-	enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID, video_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
-	enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID, video_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
+	enum ast_rtp_glue_result audio_glue0_res;
+	enum ast_rtp_glue_result video_glue0_res;
+	enum ast_rtp_glue_result audio_glue1_res;
+	enum ast_rtp_glue_result video_glue1_res;
 
 	if (!(*glue0 = ast_rtp_instance_get_glue(ast_channel_tech(c0)->type)) ||
-		(c1 && !(*glue1 = ast_rtp_instance_get_glue(ast_channel_tech(c1)->type)))) {
+		!(*glue1 = ast_rtp_instance_get_glue(ast_channel_tech(c1)->type))) {
 		return AST_RTP_GLUE_RESULT_FORBID;
 	}
 
 	audio_glue0_res = (*glue0)->get_rtp_info(c0, instance0);
 	video_glue0_res = (*glue0)->get_vrtp_info ? (*glue0)->get_vrtp_info(c0, vinstance0) : AST_RTP_GLUE_RESULT_FORBID;
 
-	if (c1) {
-		audio_glue1_res = (*glue1)->get_rtp_info(c1, instance1);
-		video_glue1_res = (*glue1)->get_vrtp_info ? (*glue1)->get_vrtp_info(c1, vinstance1) : AST_RTP_GLUE_RESULT_FORBID;
-	}
+	audio_glue1_res = (*glue1)->get_rtp_info(c1, instance1);
+	video_glue1_res = (*glue1)->get_vrtp_info ? (*glue1)->get_vrtp_info(c1, vinstance1) : AST_RTP_GLUE_RESULT_FORBID;
 
 	/* Apply any limitations on direct media bridging that may be present */
 	if (audio_glue0_res == audio_glue1_res && audio_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) {
@@ -82,7 +82,7 @@
 			audio_glue0_res = audio_glue1_res = AST_RTP_GLUE_RESULT_LOCAL;
 		}
 	}
-	if (c1 && video_glue0_res == video_glue1_res && video_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) {
+	if (video_glue0_res == video_glue1_res && video_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) {
 		if ((*glue0)->allow_vrtp_remote && !((*glue0)->allow_vrtp_remote(c0, *instance1))) {
 			/* if the allow_vrtp_remote indicates that remote isn't allowed, revert to local bridge */
 			video_glue0_res = video_glue1_res = AST_RTP_GLUE_RESULT_LOCAL;
@@ -92,15 +92,20 @@
 	}
 
 	/* If we are carrying video, and both sides are not going to remotely bridge... fail the native bridge */
-	if (video_glue0_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue0_res != AST_RTP_GLUE_RESULT_REMOTE)) {
+	if (video_glue0_res != AST_RTP_GLUE_RESULT_FORBID
+		&& (audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE
+			|| video_glue0_res != AST_RTP_GLUE_RESULT_REMOTE)) {
 		audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID;
 	}
-	if (c1 && video_glue1_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue1_res != AST_RTP_GLUE_RESULT_REMOTE)) {
+	if (video_glue1_res != AST_RTP_GLUE_RESULT_FORBID
+		&& (audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE
+			|| video_glue1_res != AST_RTP_GLUE_RESULT_REMOTE)) {
 		audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID;
 	}
 
 	/* If any sort of bridge is forbidden just completely bail out and go back to generic bridging */
-	if (audio_glue0_res == AST_RTP_GLUE_RESULT_FORBID || (c1 && audio_glue1_res == AST_RTP_GLUE_RESULT_FORBID)) {
+	if (audio_glue0_res == AST_RTP_GLUE_RESULT_FORBID
+		|| audio_glue1_res == AST_RTP_GLUE_RESULT_FORBID) {
 		return AST_RTP_GLUE_RESULT_FORBID;
 	}
 
@@ -172,7 +177,7 @@
 		return;
 	}
 
-	native_type = native_rtp_bridge_get(c0->chan, c1 ? c1->chan : NULL, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1);
+	native_type = native_rtp_bridge_get(c0->chan, c1->chan, &glue0, &glue1, &instance0, &instance1, &vinstance0, &vinstance1);
 
 	switch (native_type) {
 	case AST_RTP_GLUE_RESULT_LOCAL:

Modified: team/dlee/ari-async-bridge/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-async-bridge/channels/chan_dahdi.c?view=diff&rev=396561&r1=396560&r2=396561
==============================================================================
--- team/dlee/ari-async-bridge/channels/chan_dahdi.c (original)
+++ team/dlee/ari-async-bridge/channels/chan_dahdi.c Tue Aug 13 10:16:15 2013
@@ -461,6 +461,8 @@
 static int num_cadence = 4;
 static int user_has_defined_cadences = 0;
 
+static int has_pseudo;
+
 static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
 	{ { 125, 125, 2000, 4000 } },			/*!< Quick chirp followed by normal ring */
 	{ { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
@@ -817,6 +819,18 @@
 	 * \note Set from the "smdiport" string read in from chan_dahdi.conf
 	 */
 	char smdi_port[SMDI_MAX_FILENAME_LEN];
+
+	/*!
+	 * \brief Don't create channels below this number
+	 * \note by default is 0 (no limit)
+	 */
+	int wanted_channels_start;
+
+	/*!
+	 * \brief Don't create channels above this number (infinity by default)
+	 * \note by default is 0 (special value that means "no limit").
+	 */
+	int wanted_channels_end;
 };
 
 /*! returns a new dahdi_chan_conf with default values (by-value) */
@@ -2633,7 +2647,7 @@
 #endif	/* defined(HAVE_PRI) */
 
 #if defined(HAVE_PRI)
-static int pri_destroy_dchan(struct sig_pri_span *pri);
+static void pri_destroy_span(struct sig_pri_span *pri);
 
 static void my_handle_dchan_exception(struct sig_pri_span *pri, int index)
 {
@@ -2663,7 +2677,7 @@
 		pri_event_noalarm(pri, index, 0);
 		break;
 	case DAHDI_EVENT_REMOVED:
-		pri_destroy_dchan(pri);
+		pri_destroy_span(pri);
 		break;
 	default:
 		break;
@@ -10736,28 +10750,120 @@
 	return handled;
 }
 
-/* destroy a DAHDI channel, identified by its number */
-static int dahdi_destroy_channel_bynum(int channel)
+/* destroy a range DAHDI channels, identified by their number */
+static void dahdi_destroy_channel_range(int start, int end)
 {
 	struct dahdi_pvt *cur;
-
+	struct dahdi_pvt *next;
+	int destroyed_first = 0;
+	int destroyed_last = 0;
+
+	ast_mutex_lock(&iflock);
+	ast_debug(1, "range: %d-%d\n", start, end);
+	for (cur = iflist; cur; cur = next) {
+		next = cur->next;
+		if (cur->channel >= start && cur->channel <= end) {
+			int x = DAHDI_FLASH;
+
+			if (cur->channel > destroyed_last) {
+				destroyed_last = cur->channel;
+			}
+			if (destroyed_first < 1 || cur->channel < destroyed_first) {
+				destroyed_first = cur->channel;
+			}
+			ast_debug(3, "Destroying %d\n", cur->channel);
+			/* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
+			ioctl(cur->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
+
+			destroy_channel(cur, 1);
+			ast_module_unref(ast_module_info->self);
+		}
+	}
+	ast_mutex_unlock(&iflock);
+	if (destroyed_first > start || destroyed_last < end) {
+		ast_debug(1, "Asked to destroy %d-%d, destroyed %d-%d,\n",
+			start, end, destroyed_first, destroyed_last);
+	}
+}
+
+static int setup_dahdi(int reload);
+static int setup_dahdi_int(int reload, struct dahdi_chan_conf *default_conf, struct dahdi_chan_conf *base_conf, struct dahdi_chan_conf *conf);
+
+/*!
+ * \internal
+ * \brief create a range of new DAHDI channels
+ *
+ * \param start first channel in the range
+ * \param end last channel in the range
+ *
+ * \retval RESULT_SUCCESS on success.
+ * \retval RESULT_FAILURE on error.
+ */
+static int dahdi_create_channel_range(int start, int end)
+{
+	struct dahdi_pvt *cur;
+	struct dahdi_chan_conf default_conf = dahdi_chan_conf_default();
+	struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
+	struct dahdi_chan_conf conf = dahdi_chan_conf_default();
+	int i, x;
+	int ret = RESULT_FAILURE; /* be pessimistic */
+
+	ast_debug(1, "channel range caps: %d - %d\n", start, end);
 	ast_mutex_lock(&iflock);
 	for (cur = iflist; cur; cur = cur->next) {
-		if (cur->channel == channel) {
-			int x = DAHDI_FLASH;
-
-			/* important to create an event for dahdi_wait_event to register so that all analog_ss_threads terminate */
-			ioctl(cur->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
-
-			destroy_channel(cur, 1);
-			ast_mutex_unlock(&iflock);
-			ast_module_unref(ast_module_info->self);
-			return RESULT_SUCCESS;
-		}
-	}
+		if (cur->channel >= start && cur->channel <= end) {
+			ast_log(LOG_ERROR,
+				"channel range %d-%d is occupied\n",
+				start, end);
+			goto out;
+		}
+	}
+	for (x = 0; x < NUM_SPANS; x++) {
+#ifdef HAVE_PRI
+		struct dahdi_pri *pri = pris + x;
+
+		if (!pris[x].pri.pvts[0]) {
+			break;
+		}
+		for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
+			int channo = pri->dchannels[i];
+
+			if (!channo) {
+				break;
+			}
+			if (!pri->pri.fds[i]) {
+				break;
+			}
+			if (channo >= start && channo <= end) {
+				ast_log(LOG_ERROR,
+						"channel range %d-%d is occupied by span %d\n",
+						start, end, x + 1);
+				goto out;
+			}
+		}
+#endif
+	}
+	if (!default_conf.chan.cc_params || !base_conf.chan.cc_params ||
+		!conf.chan.cc_params) {
+		goto out;
+	}
+	default_conf.wanted_channels_start = start;
+	base_conf.wanted_channels_start = start;
+	conf.wanted_channels_start = start;
+	default_conf.wanted_channels_end = end;
+	base_conf.wanted_channels_end = end;
+	conf.wanted_channels_end = end;
+	if (setup_dahdi_int(0, &default_conf, &base_conf, &conf) == 0) {
+		ret = RESULT_SUCCESS;
+	}
+out:
+	ast_cc_config_params_destroy(default_conf.chan.cc_params);
+	ast_cc_config_params_destroy(base_conf.chan.cc_params);
+	ast_cc_config_params_destroy(conf.chan.cc_params);
 	ast_mutex_unlock(&iflock);
-	return RESULT_FAILURE;
-}
+	return ret;
+}
+
 
 static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
 {
@@ -11124,11 +11230,7 @@
 		doomed = NULL;
 		for (i = iflist;; i = i->next) {
 			if (doomed) {
-				int res;
-				res = dahdi_destroy_channel_bynum(doomed->channel);
-				if (res != RESULT_SUCCESS) {
-					ast_log(LOG_WARNING, "Couldn't find channel to destroy, hopefully another destroy operation just happened.\n");
-				}
+				dahdi_destroy_channel_range(doomed->channel, doomed->channel);
 				doomed = NULL;
 			}
 			if (!i) {
@@ -13574,10 +13676,21 @@
 	for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
 		if (!pri->dchannels[i])
 			break;
+		if (pri->pri.fds[i] >= 0) {
+			/* A partial range addition. Not a complete setup. */
+			break;
+		}
 		pri->pri.fds[i] = open("/dev/dahdi/channel", O_RDWR);
+		if ((pri->pri.fds[i] < 0)) {
+			ast_log(LOG_ERROR, "Unable to open D-channel (fd=%d) (%s)\n",
+				pri->pri.fds[i], strerror(errno));
+			return -1;
+		}
 		x = pri->dchannels[i];
-		if ((pri->pri.fds[i] < 0) || (ioctl(pri->pri.fds[i],DAHDI_SPECIFY,&x) == -1)) {
-			ast_log(LOG_ERROR, "Unable to open D-channel %d (%s)\n", x, strerror(errno));
+		res = ioctl(pri->pri.fds[i], DAHDI_SPECIFY, &x);
+		if (res) {
+			dahdi_close_pri_fd(pri, i);
+			ast_log(LOG_ERROR, "Unable to SPECIFY channel %d (%s)\n", x, strerror(errno));
 			return -1;
 		}
 		memset(&p, 0, sizeof(p));
@@ -13978,22 +14091,44 @@
  *
  * \param pri the pri span
  *
- * \return TRUE if the span was valid and we attempted destroying.
- *
  * Shuts down a span and destroys its D-Channel. Further destruction
  * of the B-channels using dahdi_destroy_channel() would probably be required
  * for the B-Channels.
  */
-static int pri_destroy_dchan(struct sig_pri_span *pri)
+static void pri_destroy_span(struct sig_pri_span *pri)
 {
 	int i;
+	int res;
+	int cancel_code;
 	struct dahdi_pri* dahdi_pri;
-
-	if (!pri->master || (pri->master == AST_PTHREADT_NULL)) {
-		return 0;
-	}
-	pthread_cancel(pri->master);
-	pthread_join(pri->master, NULL);
+	pthread_t master = pri->master;
+
+	if (!master || (master == AST_PTHREADT_NULL)) {
+		return;
+	}
+	ast_debug(2, "About to destroy DAHDI channels of span %d.\n", pri->span);
+	for (i = 0; i < pri->numchans; i++) {
+		int channel;
+		struct sig_pri_chan *pvt = pri->pvts[i];
+
+		if (!pvt) {
+			continue;
+		}
+		channel = pvt->channel;
+		ast_debug(2, "About to destroy B-channel %d.\n", channel);
+		dahdi_destroy_channel_range(channel, channel);
+	}
+
+	cancel_code = pthread_cancel(master);
+	ast_debug(4,
+		"Waiting to join thread of span %d "
+		"with pid=%p cancel_code=%d\n",
+		pri->span, (void *)master, cancel_code);
+	res = pthread_join(master, NULL);
+	if (res != 0) {
+		ast_log(LOG_NOTICE, "pthread_join failed: %d\n", res);
+	}
+	pri->master = AST_PTHREADT_NULL;
 
 	/* The 'struct dahdi_pri' that contains our 'struct sig_pri_span' */
 	dahdi_pri = container_of(pri, struct dahdi_pri, pri);
@@ -14001,17 +14136,16 @@
 		ast_debug(4, "closing pri_fd %d\n", i);
 		dahdi_close_pri_fd(dahdi_pri, i);
 	}
-	pri->pri = NULL;
+	sig_pri_init_pri(pri);
 	ast_debug(1, "PRI span %d destroyed\n", pri->span);
-	return 1;
 }
 
 static char *handle_pri_destroy_span(struct ast_cli_entry *e, int cmd,
 		struct ast_cli_args *a)
 {
 	int span;
-	int i;
 	int res;
+	struct sig_pri_span *pri;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -14035,25 +14169,13 @@
 			a->argv[3], 1, NUM_SPANS);
 		return CLI_SUCCESS;
 	}
-	if (!pris[span - 1].pri.pri) {
+	pri = &pris[span - 1].pri;
+	if (!pri->pri) {
 		ast_cli(a->fd, "No PRI running on span %d\n", span);
 		return CLI_SUCCESS;
 	}
 
-	for (i = 0; i < pris[span - 1].pri.numchans; i++) {
-		int channel;
-		struct sig_pri_chan *pvt = pris[span - 1].pri.pvts[i];
-
-		if (!pvt) {
-			continue;
-		}
-		channel = pvt->channel;
-		ast_debug(2, "About to destroy B-channel %d.\n", channel);
-		dahdi_destroy_channel_bynum(channel);
-	}
-	ast_debug(2, "About to destroy D-channel of span %d.\n", span);
-	pri_destroy_dchan(&pris[span - 1].pri);
-
+	pri_destroy_span(pri);
 	return CLI_SUCCESS;
 }
 
@@ -14505,26 +14627,97 @@
 
 #endif /* HAVE_OPENR2 */
 
-static char *dahdi_destroy_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	int channel;
-	int ret;
+static char *dahdi_destroy_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	int start;
+	int end;
 	switch (cmd) {
 	case CLI_INIT:
-		e->command = "dahdi destroy channel";
+		e->command = "dahdi destroy channels";
 		e->usage =
-			"Usage: dahdi destroy channel <chan num>\n"
+			"Usage: dahdi destroy channels <from_channel> [<to_channel>]\n"
 			"	DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.  Immediately removes a given channel, whether it is in use or not\n";
 		return NULL;
 	case CLI_GENERATE:
 		return NULL;
 	}
-	if (a->argc != 4)
+	if ((a->argc < 4) || a->argc > 5) {
 		return CLI_SHOWUSAGE;
-
-	channel = atoi(a->argv[3]);
-	ret = dahdi_destroy_channel_bynum(channel);
-	return ( RESULT_SUCCESS == ret ) ? CLI_SUCCESS : CLI_FAILURE;
+	}
+	start = atoi(a->argv[3]);
+	if (start < 1) {
+		ast_cli(a->fd, "Invalid starting channel number %s.\n",
+				a->argv[4]);
+		return CLI_FAILURE;
+	}
+	if (a->argc == 5) {
+		end = atoi(a->argv[4]);
+		if (end < 1) {
+			ast_cli(a->fd, "Invalid ending channel number %s.\n",
+					a->argv[4]);
+			return CLI_FAILURE;
+		}
+	} else {
+		end = start;
+	}
+
+	if (end < start) {
+		ast_cli(a->fd,
+			"range end (%d) is smaller than range start (%d)\n",
+			end, start);
+		return CLI_FAILURE;
+	}
+	dahdi_destroy_channel_range(start, end);
+	return CLI_SUCCESS;
+}
+
+static char *dahdi_create_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	int start;
+	int end;
+	int ret;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "dahdi create channels";
+		e->usage = "Usage: dahdi create channels <from> [<to>] - a range of channels\n"
+			   "       dahdi create channels new           - add channels not yet created\n"
+			   "For ISDN  and SS7 the range should include complete spans.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+	if ((a->argc < 4) || a->argc > 5) {
+		return CLI_SHOWUSAGE;
+	}
+	if (a->argc == 4 && !strcmp(a->argv[3], "new")) {
+		ret = dahdi_create_channel_range(0, 0);
+		return (RESULT_SUCCESS == ret) ? CLI_SUCCESS : CLI_FAILURE;
+	}
+	start = atoi(a->argv[3]);
+	if (start <= 0) {
+		ast_cli(a->fd, "Invalid starting channel number '%s'.\n",
+				a->argv[3]);
+		return CLI_FAILURE;
+	}
+	if (a->argc == 5) {
+		end = atoi(a->argv[4]);
+		if (end <= 0) {
+			ast_cli(a->fd, "Invalid ending channel number '%s'.\n",
+					a->argv[4]);
+			return CLI_FAILURE;
+		}
+	} else {
+		end = start;
+	}
+	if (end < start) {
+		ast_cli(a->fd,
+			"range end (%d) is smaller than range start (%d)\n",
+			end, start);
+		return CLI_FAILURE;
+	}
+	ret = dahdi_create_channel_range(start, end);
+	return (RESULT_SUCCESS == ret) ? CLI_SUCCESS : CLI_FAILURE;
 }
 
 static void dahdi_softhangup_all(void)
@@ -14555,7 +14748,6 @@
 	ast_mutex_unlock(&iflock);
 }
 
-static int setup_dahdi(int reload);
 static int dahdi_restart(void)
 {
 #if defined(HAVE_PRI) || defined(HAVE_SS7)
@@ -15332,7 +15524,8 @@
 	AST_CLI_DEFINE(handle_dahdi_show_cadences, "List cadences"),
 	AST_CLI_DEFINE(dahdi_show_channels, "Show active DAHDI channels"),
 	AST_CLI_DEFINE(dahdi_show_channel, "Show information on a channel"),
-	AST_CLI_DEFINE(dahdi_destroy_channel, "Destroy a channel"),
+	AST_CLI_DEFINE(dahdi_destroy_channels, "Destroy channels"),
+	AST_CLI_DEFINE(dahdi_create_channels, "Create channels"),
 	AST_CLI_DEFINE(dahdi_restart_cmd, "Fully restart DAHDI channels"),
 	AST_CLI_DEFINE(dahdi_show_status, "Show all DAHDI cards status"),
 	AST_CLI_DEFINE(dahdi_show_version, "Show the DAHDI version in use"),
@@ -16359,7 +16552,7 @@
 	return p;
 }
 
-static int build_channels(struct dahdi_chan_conf *conf, const char *value, int reload, int lineno, int *found_pseudo)
+static int build_channels(struct dahdi_chan_conf *conf, const char *value, int reload, int lineno)
 {
 	char *c, *chan;
 	char *subdir;
@@ -16382,8 +16575,6 @@
 			finish = start;
 		} else if (!strcasecmp(chan, "pseudo")) {
 			finish = start = CHAN_PSEUDO;
-			if (found_pseudo)
-				*found_pseudo = 1;
 		} else {
 			ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'\n", value, chan);
 			return -1;
@@ -16413,6 +16604,12 @@
 					}
 				}
 			}
+			if (conf->wanted_channels_start &&
+				(real_channel < conf->wanted_channels_start ||
+				 real_channel > conf->wanted_channels_end)
+			   ) {
+				continue;
+			}
 			tmp = mkintf(real_channel, conf, reload);
 
 			if (tmp) {
@@ -16421,6 +16618,9 @@
 				ast_log(LOG_ERROR, "Unable to %s channel '%s'\n",
 						(reload == 1) ? "reconfigure" : "register", value);
 				return -1;
+			}
+			if (real_channel == CHAN_PSEUDO) {
+				has_pseudo = 1;
 			}
 		}
 	}
@@ -16608,7 +16808,6 @@
 {
 	struct dahdi_pvt *tmp;
 	int y;
-	int found_pseudo = 0;
 	struct ast_variable *dahdichan = NULL;
 
 	for (; v; v = v->next) {
@@ -16621,7 +16820,7 @@
 				ast_log(LOG_WARNING, "Channel '%s' ignored.\n", v->value);
 				continue;
 			}
-			if (build_channels(confp, v->value, reload, v->lineno, &found_pseudo)) {
+			if (build_channels(confp, v->value, reload, v->lineno)) {
 				if (confp->ignore_failed_channels) {
 					ast_log(LOG_WARNING, "Channel '%s' failure ignored: ignore_failed_channels.\n", v->value);
 					continue;
@@ -17754,8 +17953,7 @@
 
 	if (dahdichan) {
 		/* Process the deferred dahdichan value. */
-		if (build_channels(confp, dahdichan->value, reload, dahdichan->lineno,
-			&found_pseudo)) {
+		if (build_channels(confp, dahdichan->value, reload, dahdichan->lineno)) {
 			if (confp->ignore_failed_channels) {
 				ast_log(LOG_WARNING,
 					"Dahdichan '%s' failure ignored: ignore_failed_channels.\n",
@@ -17778,7 +17976,7 @@
 
 	/*< \todo why check for the pseudo in the per-channel section.
 	 * Any actual use for manual setup of the pseudo channel? */
-	if (!found_pseudo && reload != 1 && !(options & PROC_DAHDI_OPT_NOCHAN)) {
+	if (!has_pseudo && reload != 1 && !(options & PROC_DAHDI_OPT_NOCHAN)) {
 		/* use the default configuration for a channel, so
 		   that any settings from real configured channels
 		   don't "leak" into the pseudo channel config
@@ -17792,6 +17990,7 @@
 		}
 		if (tmp) {
 			ast_verb(3, "Automatically generated pseudo channel\n");
+			has_pseudo = 1;
 		} else {
 			ast_log(LOG_WARNING, "Unable to register pseudo channel!\n");
 		}
@@ -18071,7 +18270,8 @@
 	if (reload != 1) {
 		int x;
 		for (x = 0; x < NUM_SPANS; x++) {
-			if (pris[x].pri.pvts[0]) {
+			if (pris[x].pri.pvts[0] &&
+					pris[x].pri.master == AST_PTHREADT_NULL) {
 				prepare_pri(pris + x);
 				if (sig_pri_start_pri(&pris[x].pri)) {
 					ast_log(LOG_ERROR, "Unable to start D-channel on span %d\n", x + 1);

Modified: team/dlee/ari-async-bridge/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-async-bridge/channels/chan_sip.c?view=diff&rev=396561&r1=396560&r2=396561
==============================================================================
--- team/dlee/ari-async-bridge/channels/chan_sip.c (original)
+++ team/dlee/ari-async-bridge/channels/chan_sip.c Tue Aug 13 10:16:15 2013
@@ -17345,7 +17345,7 @@
 			break;
 		}
 
-		if (peer->endpoint) {
+		if (peer && peer->endpoint) {
 			ast_endpoint_blob_publish(peer->endpoint, ast_endpoint_state_type(), blob);
 		}
 	}

Modified: team/dlee/ari-async-bridge/include/asterisk/bridge.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-async-bridge/include/asterisk/bridge.h?view=diff&rev=396561&r1=396560&r2=396561
==============================================================================
--- team/dlee/ari-async-bridge/include/asterisk/bridge.h (original)
+++ team/dlee/ari-async-bridge/include/asterisk/bridge.h Tue Aug 13 10:16:15 2013
@@ -295,6 +295,8 @@
 	unsigned int num_channels;
 	/*! Number of active channels in the bridge. */
 	unsigned int num_active;
+	/*! Number of channels with AST_BRIDGE_CHANNEL_FLAG_LONELY in the bridge. */
+	unsigned int num_lonely;
 	/*!
 	 * \brief Count of the active temporary requests to inhibit bridge merges.
 	 * Zero if merges are allowed.

Modified: team/dlee/ari-async-bridge/include/asterisk/core_unreal.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-async-bridge/include/asterisk/core_unreal.h?view=diff&rev=396561&r1=396560&r2=396561
==============================================================================
--- team/dlee/ari-async-bridge/include/asterisk/core_unreal.h (original)
+++ team/dlee/ari-async-bridge/include/asterisk/core_unreal.h Tue Aug 13 10:16:15 2013
@@ -215,13 +215,14 @@
  *
  * \param ast A member of the unreal channel being pushed
  * \param bridge Which bridge we want to push the channel to
+ * \param flags Feature flags to be set on the bridge channel.
  *
  * \retval 0 if the channel is successfully imparted onto the bridge
  * \retval -1 on failure
  *
  * \note This is equivalent to ast_call() on unreal based channel drivers that are designed to use it instead.
  */
-int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge *bridge);
+int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge *bridge, unsigned int flags);
 
 /* ------------------------------------------------------------------- */
 

Modified: team/dlee/ari-async-bridge/main/autoservice.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-async-bridge/main/autoservice.c?view=diff&rev=396561&r1=396560&r2=396561
==============================================================================
--- team/dlee/ari-async-bridge/main/autoservice.c (original)
+++ team/dlee/ari-async-bridge/main/autoservice.c Tue Aug 13 10:16:15 2013
@@ -144,34 +144,40 @@
 			defer_frame = &hangup_frame;
 		} else if (ast_is_deferrable_frame(f)) {
 			defer_frame = f;
-		}
-
-		if (defer_frame) {
-			for (i = 0; i < x; i++) {
-				struct ast_frame *dup_f;
-
-				if (mons[i] != chan) {
-					continue;
+		} else {
+			/* Can't defer. Discard and continue with next. */
+			ast_frfree(f);
+			continue;
+		}
+
+		for (i = 0; i < x; i++) {
+			struct ast_frame *dup_f;
+
+			if (mons[i] != chan) {
+				continue;
+			}
+
+			if (!f) { /* defer_frame == &hangup_frame */
+				if ((dup_f = ast_frdup(defer_frame))) {
+					AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
 				}
-
-				if (defer_frame != f) {
-					if ((dup_f = ast_frdup(defer_frame))) {
-						AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
-					}
-				} else {
-					if ((dup_f = ast_frisolate(defer_frame))) {
-						if (dup_f != defer_frame) {
-							ast_frfree(defer_frame);
-						}
-						AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
-					}
+			} else {
+				if ((dup_f = ast_frisolate(defer_frame))) {
+					AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
 				}
-
-				break;
+				if (dup_f != defer_frame) {
+					ast_frfree(defer_frame);
+				}
 			}
-		} else if (f) {
-			ast_frfree(f);
-		}
+
+			break;
+		}
+		/* The ast_waitfor_n() call will only read frames from
+		 * the channels' file descriptors. If ast_waitfor_n()
+		 * returns non-NULL, then one of the channels in the
+		 * mons array must have triggered the return. It's
+		 * therefore impossible that we got here while (i >= x).
+		 * If we did, we'd need to ast_frfree(f) if (f). */
 	}
 
 	if (callid) {

Modified: team/dlee/ari-async-bridge/main/bridge.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-async-bridge/main/bridge.c?view=diff&rev=396561&r1=396560&r2=396561
==============================================================================
--- team/dlee/ari-async-bridge/main/bridge.c (original)
+++ team/dlee/ari-async-bridge/main/bridge.c Tue Aug 13 10:16:15 2013
@@ -1439,7 +1439,7 @@
 	int pass_reference)
 {
 	struct ast_bridge_channel *bridge_channel;
-	int res;
+	int res = 0;
 
 	bridge_channel = bridge_channel_internal_alloc(bridge);
 	if (pass_reference) {
@@ -1460,16 +1460,21 @@
 		bridge_channel->tech_args = *tech_args;
 	}
 
-	/* Initialize various other elements of the bridge channel structure that we can't do above */
 	ast_channel_lock(chan);
-	ast_channel_internal_bridge_channel_set(chan, bridge_channel);
+	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)) {
+		res = -1;
+	} else {
+		ast_channel_internal_bridge_channel_set(chan, bridge_channel);
+	}
 	ast_channel_unlock(chan);
 	bridge_channel->thread = pthread_self();
 	bridge_channel->chan = chan;
 	bridge_channel->swap = swap;
 	bridge_channel->features = features;
 
-	res = bridge_channel_internal_join(bridge_channel);
+	if (!res) {
+		res = bridge_channel_internal_join(bridge_channel);
+	}
 
 	/* Cleanup all the data in the bridge channel after it leaves the bridge. */
 	ast_channel_lock(chan);
@@ -1546,8 +1551,15 @@
 
 int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, int independent)
 {
-	int res;
+	int res = 0;
 	struct ast_bridge_channel *bridge_channel;
+
+	/* Imparted channels cannot have a PBX. */
+	if (ast_channel_pbx(chan)) {
+		ast_log(AST_LOG_WARNING, "Channel %s has a PBX thread and cannot be imparted into bridge %s\n",
+			ast_channel_name(chan), bridge->uniqueid);
+		return -1;
+	}
 
 	/* Supply an empty features structure if the caller did not. */
 	if (!features) {
@@ -1564,9 +1576,14 @@
 		return -1;
 	}
 
-	/* Setup various parameters */
 	ast_channel_lock(chan);
-	ast_channel_internal_bridge_channel_set(chan, bridge_channel);
+	if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)) {
+		ast_log(AST_LOG_NOTICE, "Channel %s is a zombie and cannot be imparted into bridge %s\n",
+			ast_channel_name(chan), bridge->uniqueid);
+		res = -1;
+	} else {
+		ast_channel_internal_bridge_channel_set(chan, bridge_channel);
+	}
 	ast_channel_unlock(chan);
 	bridge_channel->chan = chan;
 	bridge_channel->swap = swap;
@@ -1575,18 +1592,14 @@
 	bridge_channel->callid = ast_read_threadstorage_callid();
 
 	/* Actually create the thread that will handle the channel */
-	if (independent) {
-		/* Independently imparted channels cannot have a PBX. */
-		ast_assert(!ast_channel_pbx(chan));
-
-		res = ast_pthread_create_detached(&bridge_channel->thread, NULL,
-			bridge_channel_ind_thread, bridge_channel);
-	} else {
-		/* Imparted channels to be departed should not have a PBX either. */
-		ast_assert(!ast_channel_pbx(chan));
-
-		res = ast_pthread_create(&bridge_channel->thread, NULL,
-			bridge_channel_depart_thread, bridge_channel);
+	if (!res) {
+		if (independent) {
+			res = ast_pthread_create_detached(&bridge_channel->thread, NULL,
+				bridge_channel_ind_thread, bridge_channel);
+		} else {
+			res = ast_pthread_create(&bridge_channel->thread, NULL,
+				bridge_channel_depart_thread, bridge_channel);
+		}
 	}
 
 	if (res) {
@@ -2105,10 +2118,11 @@
 	ast_channel_unlock(chan);
 
 	if (chan_bridge) {
-		RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
+		struct ast_bridge_channel *bridge_channel;
 
 		ast_bridge_lock_both(bridge, chan_bridge);
 		bridge_channel = bridge_find_channel(chan_bridge, chan);
+
 		if (bridge_move_locked(bridge, chan_bridge, chan, NULL, 1)) {
 			ast_bridge_unlock(chan_bridge);
 			ast_bridge_unlock(bridge);
@@ -2145,8 +2159,17 @@
 		}
 		ast_channel_ref(yanked_chan);
 		if (ast_bridge_impart(bridge, yanked_chan, NULL, features, 1)) {
-			ast_log(LOG_WARNING, "Could not add %s to the bridge\n", ast_channel_name(chan));
-			ast_hangup(yanked_chan);
+			/* It is possible for us to yank a channel and have some other
+			 * thread start a PBX on the channl after we yanked it. In particular,
+			 * this can theoretically happen on the ;2 of a Local channel if we
+			 * yank it prior to the ;1 being answered. Make sure that it isn't
+			 * executing a PBX before hanging it up.
+			 */
+			if (ast_channel_pbx(yanked_chan)) {
+				ast_channel_unref(yanked_chan);
+			} else {
+				ast_hangup(yanked_chan);
+			}
 			return -1;
 		}
 	}

Modified: team/dlee/ari-async-bridge/main/bridge_channel.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-async-bridge/main/bridge_channel.c?view=diff&rev=396561&r1=396560&r2=396561
==============================================================================
--- team/dlee/ari-async-bridge/main/bridge_channel.c (original)
+++ team/dlee/ari-async-bridge/main/bridge_channel.c Tue Aug 13 10:16:15 2013
@@ -1324,7 +1324,12 @@
 	default:
 		break;
 	}
-/* BUGBUG need to implement AST_BRIDGE_CHANNEL_FLAG_LONELY support here */
+
+	if (bridge->num_lonely && bridge->num_lonely == bridge->num_channels) {
+		/* This will start a chain reaction where each channel leaving enters this function and causes
+		 * the next to leave as long as there aren't non-lonely channels in the bridge. */
+		ast_bridge_channel_leave_bridge(AST_LIST_FIRST(&bridge->channels), BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+	}
 }
 
 void bridge_channel_internal_pull(struct ast_bridge_channel *bridge_channel)
@@ -1360,6 +1365,9 @@
 	/* Remove channel from the bridge */
 	if (!bridge_channel->suspended) {
 		--bridge->num_active;
+	}
+	if (ast_test_flag(&bridge_channel->features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
+		--bridge->num_lonely;
 	}
 	--bridge->num_channels;
 	AST_LIST_REMOVE(&bridge->channels, bridge_channel, entry);
@@ -1416,6 +1424,9 @@
 	bridge_channel->just_joined = 1;
 	AST_LIST_INSERT_TAIL(&bridge->channels, bridge_channel, entry);
 	++bridge->num_channels;
+	if (ast_test_flag(&bridge_channel->features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
+		++bridge->num_lonely;
+	}
 	if (!bridge_channel->suspended) {
 		++bridge->num_active;
 	}
@@ -1816,21 +1827,29 @@
 		bridge_channel, ast_channel_name(bridge_channel->chan));
 
 	/*
-	 * Get "in the bridge" before pushing the channel for any
-	 * masquerades on the channel to happen before bridging.
-	 */
-	ast_channel_lock(bridge_channel->chan);
-	ast_channel_internal_bridge_set(bridge_channel->chan, bridge_channel->bridge);
-	ast_channel_unlock(bridge_channel->chan);
-
-	/* Add the jitterbuffer if the channel requires it */
-	ast_jb_enable_for_channel(bridge_channel->chan);
-
-	/*
 	 * Directly locking the bridge is safe here because nobody else
 	 * knows about this bridge_channel yet.
 	 */
 	ast_bridge_lock(bridge_channel->bridge);
+
+	/* Make sure we're still good to be put into a bridge
+	 */
+	ast_channel_lock(bridge_channel->chan);
+	if (ast_channel_internal_bridge(bridge_channel->chan)
+		|| ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_ZOMBIE)) {
+		ast_channel_unlock(bridge_channel->chan);
+		ast_bridge_unlock(bridge_channel->bridge);
+		ast_debug(1, "Bridge %s: %p(%s) failed to join Bridge\n",
+			bridge_channel->bridge->uniqueid,
+			bridge_channel,
+			ast_channel_name(bridge_channel->chan));
+		return -1;
+	}
+	ast_channel_internal_bridge_set(bridge_channel->chan, bridge_channel->bridge);

[... 246 lines stripped ...]



More information about the asterisk-commits mailing list