[asterisk-commits] rmudgett: branch rmudgett/bridge_phase r388210 - in /team/rmudgett/bridge_pha...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu May 9 13:10:35 CDT 2013


Author: rmudgett
Date: Thu May  9 13:10:33 2013
New Revision: 388210

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=388210
Log:
Separate unreal/local code into their own files.

Added:
    team/rmudgett/bridge_phase/include/asterisk/core_unreal.h   (with props)
    team/rmudgett/bridge_phase/main/core_local.c   (with props)
Modified:
    team/rmudgett/bridge_phase/include/asterisk/_private.h
    team/rmudgett/bridge_phase/include/asterisk/core_local.h
    team/rmudgett/bridge_phase/main/asterisk.c
    team/rmudgett/bridge_phase/main/core_unreal.c

Modified: team/rmudgett/bridge_phase/include/asterisk/_private.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/include/asterisk/_private.h?view=diff&rev=388210&r1=388209&r2=388210
==============================================================================
--- team/rmudgett/bridge_phase/include/asterisk/_private.h (original)
+++ team/rmudgett/bridge_phase/include/asterisk/_private.h Thu May  9 13:10:33 2013
@@ -61,13 +61,13 @@
 int ast_bridging_init(void);
 
 /*!
- * \brief Initialize the local proxy channel and unreal derivative framework system.
+ * \brief Initialize the local proxy channel.
  * \since 12.0.0
  *
  * \retval 0 on success.
  * \retval -1 on error.
  */
-int ast_unreal_init(void);
+int ast_local_init(void);
 
 /*!
  * \brief Reload asterisk modules.

Modified: team/rmudgett/bridge_phase/include/asterisk/core_local.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/include/asterisk/core_local.h?view=diff&rev=388210&r1=388209&r2=388210
==============================================================================
--- team/rmudgett/bridge_phase/include/asterisk/core_local.h (original)
+++ team/rmudgett/bridge_phase/include/asterisk/core_local.h Thu May  9 13:10:33 2013
@@ -18,7 +18,7 @@
 
 /*!
  * \file
- * \brief Local proxy channel and other unreal channel derivatives framework.
+ * \brief Local proxy channel special access.
  *
  * \author Richard Mudgett <rmudgett at digium.com>
  *
@@ -29,128 +29,16 @@
 #ifndef _ASTERISK_CORE_LOCAL_H
 #define _ASTERISK_CORE_LOCAL_H
 
-#include "asterisk/channel.h"
-
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
 
+/* Forward declare some struct names */
+struct ast_channel;
+struct ast_bridge;
+struct ast_bridge_features;
+
 /* ------------------------------------------------------------------- */
-
-/*!
- * \brief The base pvt structure for local channel derivatives.
- *
- * The unreal pvt has two ast_chan objects - the "owner" and the "next channel", the outbound channel
- *
- * ast_chan owner -> ast_unreal_pvt -> ast_chan chan
- */
-struct ast_unreal_pvt {
-	struct ast_channel *owner;      /*!< Master Channel - ;1 side */
-	struct ast_channel *chan;       /*!< Outbound channel - ;2 side */
-	struct ast_format_cap *reqcap;  /*!< Requested format capabilities */
-	struct ast_jb_conf jb_conf;     /*!< jitterbuffer configuration */
-	unsigned int flags;             /*!< Private option flags */
-	/*! Base name of the unreal channels.  exten at context or other name. */
-	char name[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2];
-};
-
-#define AST_UNREAL_IS_OUTBOUND(a, b) ((a) == (b)->chan ? 1 : 0)
-
-#define AST_UNREAL_CARETAKER_THREAD (1 << 0) /*!< The ;2 side launched a PBX, was pushed into a bridge, or was masqueraded into an application. */
-#define AST_UNREAL_NO_OPTIMIZATION  (1 << 1) /*!< Do not optimize out the unreal channels */
-#define AST_UNREAL_MOH_INTERCEPT    (1 << 2) /*!< Intercept and act on hold/unhold control frames */
-
-/*!
- * \brief Send an unreal pvt in with no locks held and get all locks
- *
- * \note NO locks should be held prior to calling this function
- * \note The pvt must have a ref held before calling this function
- * \note if outchan or outowner is set != NULL after calling this function
- *       those channels are locked and reffed.
- * \note Batman.
- */
-void ast_unreal_lock_all(struct ast_unreal_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner);
-
-/*!
- * \brief Hangup one end (maybe both ends) of an unreal channel derivative.
- * \since 12.0.0
- *
- * \param p Private channel struct (reffed)
- * \param ast Channel being hung up.  (locked)
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
-int ast_unreal_hangup(struct ast_unreal_pvt *p, struct ast_channel *ast);
-
-int ast_unreal_digit_begin(struct ast_channel *ast, char digit);
-int ast_unreal_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
-int ast_unreal_answer(struct ast_channel *ast);
-struct ast_frame *ast_unreal_read(struct ast_channel *ast);
-int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f);
-int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
-int ast_unreal_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
-int ast_unreal_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
-int ast_unreal_sendtext(struct ast_channel *ast, const char *text);
-int ast_unreal_queryoption(struct ast_channel *ast, int option, void *data, int *datalen);
-int ast_unreal_setoption(struct ast_channel *chan, int option, void *data, int datalen);
-
-/*!
- * \brief struct ast_unreal_pvt destructor.
- * \since 12.0.0
- *
- * \param vdoomed Object to destroy.
- *
- * \return Nothing
- */
-void ast_unreal_destructor(void *vdoomed);
-
-/*!
- * \brief Allocate the base unreal struct for a derivative.
- * \since 12.0.0
- *
- * \param size Size of the unreal struct to allocate.
- * \param destructor Destructor callback.
- * \param cap Format capabilities to give the unreal private struct.
- *
- * \retval pvt on success.
- * \retval NULL on error.
- */
-struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap);
-
-/*!
- * \brief Create the semi1 and semi2 unreal channels.
- * \since 12.0.0
- *
- * \param p Unreal channel private struct.
- * \param tech Channel technology to use.
- * \param semi1_state State to start the semi1(owner) channel in.
- * \param semi2_state State to start the semi2(outgoing chan) channel in.
- * \param exten Exten to start the chennels in. (NULL if s)
- * \param context Context to start the channels in. (NULL if default)
- * \param requestor Channel requesting creation. (NULL if none)
- * \param callid Thread callid to use.
- *
- * \retval semi1_channel on success.
- * \retval NULL on error.
- */
-struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
-	const struct ast_channel_tech *tech, int semi1_state, int semi2_state,
-	const char *exten, const char *context, struct ast_channel *requestor,
-	struct ast_callid *callid);
-
-/*!
- * \brief Setup unreal owner and chan channels before initiating call.
- * \since 12.0.0
- *
- * \param semi1 Owner channel of unreal channel pair.
- * \param semi2 Outgoing channel of unreal channel pair.
- *
- * \note On entry, the semi1 and semi2 channels are already locked.
- *
- * \return Nothing
- */
-void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2);
 
 /*!
  * \brief Get the other local channel in the pair.

Added: team/rmudgett/bridge_phase/include/asterisk/core_unreal.h
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/include/asterisk/core_unreal.h?view=auto&rev=388210
==============================================================================
--- team/rmudgett/bridge_phase/include/asterisk/core_unreal.h (added)
+++ team/rmudgett/bridge_phase/include/asterisk/core_unreal.h Thu May  9 13:10:33 2013
@@ -1,0 +1,167 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013 Digium, Inc.
+ *
+ * Richard Mudgett <rmudgett at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Unreal channel derivative framework.
+ *
+ * \author Richard Mudgett <rmudgett at digium.com>
+ *
+ * See Also:
+ * \arg \ref AstCREDITS
+ */
+
+#ifndef _ASTERISK_CORE_UNREAL_H
+#define _ASTERISK_CORE_UNREAL_H
+
+#include "asterisk/astobj2.h"
+#include "asterisk/channel.h"
+#include "asterisk/abstract_jb.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+/* Forward declare some struct names */
+struct ast_format_cap;
+struct ast_callid;
+
+/* ------------------------------------------------------------------- */
+
+/*!
+ * \brief The base pvt structure for local channel derivatives.
+ *
+ * The unreal pvt has two ast_chan objects - the "owner" and the "next channel", the outbound channel
+ *
+ * ast_chan owner -> ast_unreal_pvt -> ast_chan chan
+ */
+struct ast_unreal_pvt {
+	struct ast_channel *owner;      /*!< Master Channel - ;1 side */
+	struct ast_channel *chan;       /*!< Outbound channel - ;2 side */
+	struct ast_format_cap *reqcap;  /*!< Requested format capabilities */
+	struct ast_jb_conf jb_conf;     /*!< jitterbuffer configuration */
+	unsigned int flags;             /*!< Private option flags */
+	/*! Base name of the unreal channels.  exten at context or other name. */
+	char name[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 2];
+};
+
+#define AST_UNREAL_IS_OUTBOUND(a, b) ((a) == (b)->chan ? 1 : 0)
+
+#define AST_UNREAL_CARETAKER_THREAD (1 << 0) /*!< The ;2 side launched a PBX, was pushed into a bridge, or was masqueraded into an application. */
+#define AST_UNREAL_NO_OPTIMIZATION  (1 << 1) /*!< Do not optimize out the unreal channels */
+#define AST_UNREAL_MOH_INTERCEPT    (1 << 2) /*!< Intercept and act on hold/unhold control frames */
+
+/*!
+ * \brief Send an unreal pvt in with no locks held and get all locks
+ *
+ * \note NO locks should be held prior to calling this function
+ * \note The pvt must have a ref held before calling this function
+ * \note if outchan or outowner is set != NULL after calling this function
+ *       those channels are locked and reffed.
+ * \note Batman.
+ */
+void ast_unreal_lock_all(struct ast_unreal_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner);
+
+/*!
+ * \brief Hangup one end (maybe both ends) of an unreal channel derivative.
+ * \since 12.0.0
+ *
+ * \param p Private channel struct (reffed)
+ * \param ast Channel being hung up.  (locked)
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int ast_unreal_hangup(struct ast_unreal_pvt *p, struct ast_channel *ast);
+
+int ast_unreal_digit_begin(struct ast_channel *ast, char digit);
+int ast_unreal_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
+int ast_unreal_answer(struct ast_channel *ast);
+struct ast_frame *ast_unreal_read(struct ast_channel *ast);
+int ast_unreal_write(struct ast_channel *ast, struct ast_frame *f);
+int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
+int ast_unreal_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
+int ast_unreal_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
+int ast_unreal_sendtext(struct ast_channel *ast, const char *text);
+int ast_unreal_queryoption(struct ast_channel *ast, int option, void *data, int *datalen);
+int ast_unreal_setoption(struct ast_channel *chan, int option, void *data, int datalen);
+
+/*!
+ * \brief struct ast_unreal_pvt destructor.
+ * \since 12.0.0
+ *
+ * \param vdoomed Object to destroy.
+ *
+ * \return Nothing
+ */
+void ast_unreal_destructor(void *vdoomed);
+
+/*!
+ * \brief Allocate the base unreal struct for a derivative.
+ * \since 12.0.0
+ *
+ * \param size Size of the unreal struct to allocate.
+ * \param destructor Destructor callback.
+ * \param cap Format capabilities to give the unreal private struct.
+ *
+ * \retval pvt on success.
+ * \retval NULL on error.
+ */
+struct ast_unreal_pvt *ast_unreal_alloc(size_t size, ao2_destructor_fn destructor, struct ast_format_cap *cap);
+
+/*!
+ * \brief Create the semi1 and semi2 unreal channels.
+ * \since 12.0.0
+ *
+ * \param p Unreal channel private struct.
+ * \param tech Channel technology to use.
+ * \param semi1_state State to start the semi1(owner) channel in.
+ * \param semi2_state State to start the semi2(outgoing chan) channel in.
+ * \param exten Exten to start the chennels in. (NULL if s)
+ * \param context Context to start the channels in. (NULL if default)
+ * \param requestor Channel requesting creation. (NULL if none)
+ * \param callid Thread callid to use.
+ *
+ * \retval semi1_channel on success.
+ * \retval NULL on error.
+ */
+struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
+	const struct ast_channel_tech *tech, int semi1_state, int semi2_state,
+	const char *exten, const char *context, struct ast_channel *requestor,
+	struct ast_callid *callid);
+
+/*!
+ * \brief Setup unreal owner and chan channels before initiating call.
+ * \since 12.0.0
+ *
+ * \param semi1 Owner channel of unreal channel pair.
+ * \param semi2 Outgoing channel of unreal channel pair.
+ *
+ * \note On entry, the semi1 and semi2 channels are already locked.
+ *
+ * \return Nothing
+ */
+void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2);
+
+/* ------------------------------------------------------------------- */
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif	/* _ASTERISK_CORE_UNREAL_H */

Propchange: team/rmudgett/bridge_phase/include/asterisk/core_unreal.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/rmudgett/bridge_phase/include/asterisk/core_unreal.h
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/rmudgett/bridge_phase/include/asterisk/core_unreal.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: team/rmudgett/bridge_phase/main/asterisk.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/main/asterisk.c?view=diff&rev=388210&r1=388209&r2=388210
==============================================================================
--- team/rmudgett/bridge_phase/main/asterisk.c (original)
+++ team/rmudgett/bridge_phase/main/asterisk.c Thu May  9 13:10:33 2013
@@ -4345,7 +4345,7 @@
 		exit(1);
 	}
 
-	if (ast_unreal_init()) {
+	if (ast_local_init()) {
 		printf("%s", term_quit());
 		exit(1);
 	}

Added: team/rmudgett/bridge_phase/main/core_local.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/main/core_local.c?view=auto&rev=388210
==============================================================================
--- team/rmudgett/bridge_phase/main/core_local.c (added)
+++ team/rmudgett/bridge_phase/main/core_local.c Thu May  9 13:10:33 2013
@@ -1,0 +1,775 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013 Digium, Inc.
+ *
+ * Richard Mudgett <rmudgett at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Local proxy channel driver.
+ *
+ * \author Richard Mudgett <rmudgett at digium.com>
+ *
+ * See Also:
+ * \arg \ref AstCREDITS
+ */
+
+/*** MODULEINFO
+	<support_level>core</support_level>
+ ***/
+
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+/* ------------------------------------------------------------------- */
+
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/cli.h"
+#include "asterisk/manager.h"
+#include "asterisk/devicestate.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/bridging.h"
+#include "asterisk/core_unreal.h"
+#include "asterisk/core_local.h"
+#include "asterisk/_private.h"
+
+/*** DOCUMENTATION
+	<manager name="LocalOptimizeAway" language="en_US">
+		<synopsis>
+			Optimize away a local channel when possible.
+		</synopsis>
+		<syntax>
+			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+			<parameter name="Channel" required="true">
+				<para>The channel name to optimize away.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>A local channel created with "/n" will not automatically optimize away.
+			Calling this command on the local channel will clear that flag and allow
+			it to optimize away if it's bridged or when it becomes bridged.</para>
+		</description>
+	</manager>
+ ***/
+
+static const char tdesc[] = "Local Proxy Channel Driver";
+
+static struct ao2_container *locals;
+
+static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
+static int local_call(struct ast_channel *ast, const char *dest, int timeout);
+static int local_hangup(struct ast_channel *ast);
+static int local_devicestate(const char *data);
+
+/* PBX interface structure for channel registration */
+static struct ast_channel_tech local_tech = {
+	.type = "Local",
+	.description = tdesc,
+	.requester = local_request,
+	.send_digit_begin = ast_unreal_digit_begin,
+	.send_digit_end = ast_unreal_digit_end,
+	.call = local_call,
+	.hangup = local_hangup,
+	.answer = ast_unreal_answer,
+	.read = ast_unreal_read,
+	.write = ast_unreal_write,
+	.write_video = ast_unreal_write,
+	.exception = ast_unreal_read,
+	.indicate = ast_unreal_indicate,
+	.fixup = ast_unreal_fixup,
+	.send_html = ast_unreal_sendhtml,
+	.send_text = ast_unreal_sendtext,
+	.devicestate = local_devicestate,
+	.queryoption = ast_unreal_queryoption,
+	.setoption = ast_unreal_setoption,
+};
+
+/*! What to do with the ;2 channel when ast_call() happens. */
+enum local_call_action {
+	/* The ast_call() will run dialplan on the ;2 channel. */
+	LOCAL_CALL_ACTION_DIALPLAN,
+	/* The ast_call() will impart the ;2 channel into a bridge. */
+	LOCAL_CALL_ACTION_BRIDGE,
+	/* The ast_call() will masquerade the ;2 channel into a channel. */
+	LOCAL_CALL_ACTION_MASQUERADE,
+};
+
+/*! Join a bridge on ast_call() parameters. */
+struct local_bridge {
+	/*! Bridge to join. */
+	struct ast_bridge *join;
+	/*! Channel to swap with when joining bridge. */
+	struct ast_channel *swap;
+	/*! Features that are specific to this channel when pushed into the bridge. */
+	struct ast_bridge_features *features;
+};
+
+/*!
+ * \brief the local pvt structure for all channels
+ *
+ * The local channel pvt has two ast_chan objects - the "owner" and the "next channel", the outbound channel
+ *
+ * ast_chan owner -> local_pvt -> ast_chan chan
+ */
+struct local_pvt {
+	/*! Unreal channel driver base class values. */
+	struct ast_unreal_pvt base;
+	/*! Additional action arguments */
+	union {
+		/*! Make ;2 join a bridge on ast_call(). */
+		struct local_bridge bridge;
+		/*! Make ;2 masquerade into this channel on ast_call(). */
+		struct ast_channel *masq;
+	} action;
+	/*! What to do with the ;2 channel on ast_call(). */
+	enum local_call_action type;
+	/*! Context to call */
+	char context[AST_MAX_CONTEXT];
+	/*! Extension to call */
+	char exten[AST_MAX_EXTENSION];
+};
+
+struct ast_channel *ast_local_get_peer(struct ast_channel *ast)
+{
+	struct local_pvt *p = ast_channel_tech_pvt(ast);
+	struct local_pvt *found;
+	struct ast_channel *peer;
+
+	if (!p) {
+		return NULL;
+	}
+
+	found = p ? ao2_find(locals, p, 0) : NULL;
+	if (!found) {
+		/* ast is either not a local channel or it has alredy been hungup */
+		return NULL;
+	}
+	ao2_lock(found);
+	if (ast == p->base.owner) {
+		peer = p->base.chan;
+	} else if (ast == p->base.chan) {
+		peer = p->base.owner;
+	} else {
+		peer = NULL;
+	}
+	if (peer) {
+		ast_channel_ref(peer);
+	}
+	ao2_unlock(found);
+	ao2_ref(found, -1);
+	return peer;
+}
+
+/*! \brief Adds devicestate to local channels */
+static int local_devicestate(const char *data)
+{
+	int is_inuse = 0;
+	int res = AST_DEVICE_INVALID;
+	char *exten = ast_strdupa(data);
+	char *context;
+	char *opts;
+	struct local_pvt *lp;
+	struct ao2_iterator it;
+
+	/* Strip options if they exist */
+	opts = strchr(exten, '/');
+	if (opts) {
+		*opts = '\0';
+	}
+
+	context = strchr(exten, '@');
+	if (!context) {
+		ast_log(LOG_WARNING,
+			"Someone used Local/%s somewhere without a @context. This is bad.\n", data);
+		return AST_DEVICE_INVALID;
+	}
+	*context++ = '\0';
+
+	it = ao2_iterator_init(locals, 0);
+	for (; (lp = ao2_iterator_next(&it)); ao2_ref(lp, -1)) {
+		ao2_lock(lp);
+		if (!strcmp(exten, lp->exten)
+			&& !strcmp(context, lp->context)) {
+			res = AST_DEVICE_NOT_INUSE;
+			if (lp->base.owner
+				&& ast_test_flag(&lp->base, AST_UNREAL_CARETAKER_THREAD)) {
+				is_inuse = 1;
+			}
+		}
+		ao2_unlock(lp);
+		if (is_inuse) {
+			res = AST_DEVICE_INUSE;
+			ao2_ref(lp, -1);
+			break;
+		}
+	}
+	ao2_iterator_destroy(&it);
+
+	if (res == AST_DEVICE_INVALID) {
+		ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
+		if (ast_exists_extension(NULL, context, exten, 1, NULL)) {
+			res = AST_DEVICE_NOT_INUSE;
+		}
+	}
+
+	return res;
+}
+
+/*!
+ * \internal
+ * \brief Post the LocalBridge AMI event.
+ * \since 12.0.0
+ *
+ * \param p local_pvt to raise the bridge event.
+ *
+ * \return Nothing
+ */
+static void local_bridge_event(struct local_pvt *p)
+{
+	ao2_lock(p);
+	/*** DOCUMENTATION
+		<managerEventInstance>
+			<synopsis>Raised when two halves of a Local Channel form a bridge.</synopsis>
+			<syntax>
+				<parameter name="Channel1">
+					<para>The name of the Local Channel half that bridges to another channel.</para>
+				</parameter>
+				<parameter name="Channel2">
+					<para>The name of the Local Channel half that executes the dialplan.</para>
+				</parameter>
+				<parameter name="Context">
+					<para>The context in the dialplan that Channel2 starts in.</para>
+				</parameter>
+				<parameter name="Exten">
+					<para>The extension in the dialplan that Channel2 starts in.</para>
+				</parameter>
+				<parameter name="LocalOptimization">
+					<enumlist>
+						<enum name="Yes"/>
+						<enum name="No"/>
+					</enumlist>
+				</parameter>
+			</syntax>
+		</managerEventInstance>
+	***/
+	manager_event(EVENT_FLAG_CALL, "LocalBridge",
+		"Channel1: %s\r\n"
+		"Channel2: %s\r\n"
+		"Uniqueid1: %s\r\n"
+		"Uniqueid2: %s\r\n"
+		"Context: %s\r\n"
+		"Exten: %s\r\n"
+		"LocalOptimization: %s\r\n",
+		ast_channel_name(p->base.owner), ast_channel_name(p->base.chan),
+		ast_channel_uniqueid(p->base.owner), ast_channel_uniqueid(p->base.chan),
+		p->context, p->exten,
+		ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION) ? "Yes" : "No");
+	ao2_unlock(p);
+}
+
+int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features)
+{
+	struct local_pvt *p;
+	struct local_pvt *found;
+	int res = -1;
+
+	/* Sanity checks. */
+	if (!ast || !bridge) {
+		ast_bridge_features_destroy(features);
+		return -1;
+	}
+
+	ast_channel_lock(ast);
+	p = ast_channel_tech_pvt(ast);
+	ast_channel_unlock(ast);
+
+	found = p ? ao2_find(locals, p, 0) : NULL;
+	if (found) {
+		ao2_lock(found);
+		if (found->type == LOCAL_CALL_ACTION_DIALPLAN
+			&& found->base.owner
+			&& found->base.chan
+			&& !ast_test_flag(&found->base, AST_UNREAL_CARETAKER_THREAD)) {
+			ao2_ref(bridge, +1);
+			if (swap) {
+				ast_channel_ref(swap);
+			}
+			found->type = LOCAL_CALL_ACTION_BRIDGE;
+			found->action.bridge.join = bridge;
+			found->action.bridge.swap = swap;
+			found->action.bridge.features = features;
+			res = 0;
+		} else {
+			ast_bridge_features_destroy(features);
+		}
+		ao2_unlock(found);
+		ao2_ref(found, -1);
+	}
+
+	return res;
+}
+
+int ast_local_setup_masquerade(struct ast_channel *ast, struct ast_channel *masq)
+{
+	struct local_pvt *p;
+	struct local_pvt *found;
+	int res = -1;
+
+	/* Sanity checks. */
+	if (!ast || !masq) {
+		return -1;
+	}
+
+	ast_channel_lock(ast);
+	p = ast_channel_tech_pvt(ast);
+	ast_channel_unlock(ast);
+
+	found = p ? ao2_find(locals, p, 0) : NULL;
+	if (found) {
+		ao2_lock(found);
+		if (found->type == LOCAL_CALL_ACTION_DIALPLAN
+			&& found->base.owner
+			&& found->base.chan
+			&& !ast_test_flag(&found->base, AST_UNREAL_CARETAKER_THREAD)) {
+			ast_channel_ref(masq);
+			found->type = LOCAL_CALL_ACTION_MASQUERADE;
+			found->action.masq = masq;
+			res = 0;
+		}
+		ao2_unlock(found);
+		ao2_ref(found, -1);
+	}
+
+	return res;
+}
+
+/*! \brief Initiate new call, part of PBX interface
+ *         dest is the dial string */
+static int local_call(struct ast_channel *ast, const char *dest, int timeout)
+{
+	struct local_pvt *p = ast_channel_tech_pvt(ast);
+	int pvt_locked = 0;
+
+	struct ast_channel *owner = NULL;
+	struct ast_channel *chan = NULL;
+	int res;
+	char *reduced_dest = ast_strdupa(dest);
+	char *slash;
+	const char *chan_cid;
+
+	if (!p) {
+		return -1;
+	}
+
+	/* since we are letting go of channel locks that were locked coming into
+	 * this function, then we need to give the tech pvt a ref */
+	ao2_ref(p, 1);
+	ast_channel_unlock(ast);
+
+	ast_unreal_lock_all(&p->base, &chan, &owner);
+	pvt_locked = 1;
+
+	if (owner != ast) {
+		res = -1;
+		goto return_cleanup;
+	}
+
+	if (!owner || !chan) {
+		res = -1;
+		goto return_cleanup;
+	}
+
+	ast_unreal_call_setup(owner, chan);
+
+	/*
+	 * If the local channel has /n on the end of it, we need to lop
+	 * that off for our argument to setting up the CC_INTERFACES
+	 * variable.
+	 */
+	if ((slash = strrchr(reduced_dest, '/'))) {
+		*slash = '\0';
+	}
+	ast_set_cc_interfaces_chanvar(chan, reduced_dest);
+
+	ao2_unlock(p);
+	pvt_locked = 0;
+
+	ast_channel_unlock(owner);
+
+	chan_cid = S_COR(ast_channel_caller(chan)->id.number.valid,
+		ast_channel_caller(chan)->id.number.str, NULL);
+	if (chan_cid) {
+		chan_cid = ast_strdupa(chan_cid);
+	}
+	ast_channel_unlock(chan);
+
+	res = -1;
+	switch (p->type) {
+	case LOCAL_CALL_ACTION_DIALPLAN:
+		if (!ast_exists_extension(NULL, p->context, p->exten, 1, chan_cid)) {
+			ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n",
+				p->exten, p->context);
+		} else {
+			local_bridge_event(p);
+
+			/* Start switch on sub channel */
+			res = ast_pbx_start(chan);
+		}
+		break;
+	case LOCAL_CALL_ACTION_BRIDGE:
+		local_bridge_event(p);
+		ast_answer(chan);
+		res = ast_bridge_impart(p->action.bridge.join, chan, p->action.bridge.swap,
+			p->action.bridge.features, 1);
+		ao2_ref(p->action.bridge.join, -1);
+		p->action.bridge.join = NULL;
+		ao2_cleanup(p->action.bridge.swap);
+		p->action.bridge.swap = NULL;
+		p->action.bridge.features = NULL;
+		break;
+	case LOCAL_CALL_ACTION_MASQUERADE:
+		local_bridge_event(p);
+		ast_answer(chan);
+		res = ast_channel_masquerade(p->action.masq, chan);
+		if (!res) {
+			ast_do_masquerade(p->action.masq);
+			/* Chan is now an orphaned zombie.  Destroy it. */
+			ast_hangup(chan);
+		}
+		p->action.masq = ast_channel_unref(p->action.masq);
+		break;
+	}
+	if (!res) {
+		ao2_lock(p);
+		ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD);
+		ao2_unlock(p);
+	}
+
+	/* we already unlocked them, clear them here so the cleanup label won't touch them. */
+	owner = ast_channel_unref(owner);
+	chan = ast_channel_unref(chan);
+
+return_cleanup:
+	if (p) {
+		if (pvt_locked) {
+			ao2_unlock(p);
+		}
+		ao2_ref(p, -1);
+	}
+	if (chan) {
+		ast_channel_unlock(chan);
+		ast_channel_unref(chan);
+	}
+
+	/*
+	 * owner is supposed to be == to ast, if it is, don't unlock it
+	 * because ast must exit locked
+	 */
+	if (owner) {
+		if (owner != ast) {
+			ast_channel_unlock(owner);
+			ast_channel_lock(ast);
+		}
+		ast_channel_unref(owner);
+	} else {
+		/* we have to exit with ast locked */
+		ast_channel_lock(ast);
+	}
+
+	return res;
+}
+
+/*! \brief Hangup a call through the local proxy channel */
+static int local_hangup(struct ast_channel *ast)
+{
+	struct local_pvt *p = ast_channel_tech_pvt(ast);
+	int res;
+
+	if (!p) {
+		return -1;
+	}
+
+	/* give the pvt a ref to fulfill calling requirements. */
+	ao2_ref(p, +1);
+	res = ast_unreal_hangup(&p->base, ast);
+	if (!res) {
+		int unlink;
+
+		ao2_lock(p);
+		unlink = !p->base.owner && !p->base.chan;
+		ao2_unlock(p);
+		if (unlink) {
+			ao2_unlink(locals, p);
+		}
+	}
+	ao2_ref(p, -1);
+
+	return res;
+}
+
+/*!
+ * \internal
+ * \brief struct local_pvt destructor.
+ *
+ * \param vdoomed Object to destroy.
+ *
+ * \return Nothing
+ */
+static void local_pvt_destructor(void *vdoomed)
+{
+	struct local_pvt *doomed = vdoomed;
+
+	switch (doomed->type) {
+	case LOCAL_CALL_ACTION_DIALPLAN:
+		break;
+	case LOCAL_CALL_ACTION_BRIDGE:
+		ao2_cleanup(doomed->action.bridge.join);
+		ao2_cleanup(doomed->action.bridge.swap);
+		ast_bridge_features_destroy(doomed->action.bridge.features);
+		break;
+	case LOCAL_CALL_ACTION_MASQUERADE:
+		ao2_cleanup(doomed->action.masq);
+		break;
+	}
+	ast_unreal_destructor(&doomed->base);
+}
+
+/*! \brief Create a call structure */
+static struct local_pvt *local_alloc(const char *data, struct ast_format_cap *cap)
+{
+	struct local_pvt *pvt;
+	char *parse;
+	char *context;
+	char *opts;
+
+	pvt = (struct local_pvt *) ast_unreal_alloc(sizeof(*pvt), local_pvt_destructor, cap);
+	if (!pvt) {
+		return NULL;
+	}
+
+	parse = ast_strdupa(data);
+
+	/*
+	 * Local channels intercept MOH by default.
+	 *
+	 * This is a silly default because it represents state held by
+	 * the local channels.  Unless local channel optimization is
+	 * disabled, the state will dissapear when the local channels
+	 * optimize out.
+	 */
+	ast_set_flag(&pvt->base, AST_UNREAL_MOH_INTERCEPT);
+
+	/* Look for options */
+	if ((opts = strchr(parse, '/'))) {
+		*opts++ = '\0';
+		if (strchr(opts, 'n')) {
+			ast_set_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION);
+		}
+		if (strchr(opts, 'j')) {
+			if (ast_test_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION)) {
+				ast_set_flag(&pvt->base.jb_conf, AST_JB_ENABLED);
+			} else {
+				ast_log(LOG_ERROR, "You must use the 'n' option with the 'j' option to enable the jitter buffer\n");
+			}
+		}
+		if (strchr(opts, 'm')) {
+			ast_clear_flag(&pvt->base, AST_UNREAL_MOH_INTERCEPT);
+		}
+	}
+
+	/* Look for a context */
+	if ((context = strchr(parse, '@'))) {
+		*context++ = '\0';
+	}
+
+	ast_copy_string(pvt->context, S_OR(context, "default"), sizeof(pvt->context));
+	ast_copy_string(pvt->exten, parse, sizeof(pvt->exten));
+	snprintf(pvt->base.name, sizeof(pvt->base.name), "%s@%s", pvt->exten, pvt->context);
+
+	return pvt; /* this is returned with a ref */
+}
+
+/*! \brief Part of PBX interface */
+static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
+{
+	struct local_pvt *p;
+	struct ast_channel *chan;
+	struct ast_callid *callid;
+
+	/* Allocate a new private structure and then Asterisk channels */
+	p = local_alloc(data, cap);
+	if (!p) {
+		return NULL;
+	}
+	callid = ast_read_threadstorage_callid();
+	chan = ast_unreal_new_channels(&p->base, &local_tech, AST_STATE_DOWN, AST_STATE_RING,
+		p->exten, p->context, (struct ast_channel *) requestor, callid);
+	if (chan) {
+		ao2_link(locals, p);
+	}
+	if (callid) {
+		ast_callid_unref(callid);
+	}
+	ao2_ref(p, -1); /* kill the ref from the alloc */
+
+	return chan;
+}
+
+/*! \brief CLI command "local show channels" */
+static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct local_pvt *p;
+	struct ao2_iterator it;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "local show channels";
+		e->usage =
+			"Usage: local show channels\n"
+			"       Provides summary information on active local proxy channels.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 3) {
+		return CLI_SHOWUSAGE;
+	}
+
+	if (ao2_container_count(locals) == 0) {
+		ast_cli(a->fd, "No local channels in use\n");
+		return RESULT_SUCCESS;
+	}
+
+	it = ao2_iterator_init(locals, 0);
+	while ((p = ao2_iterator_next(&it))) {
+		ao2_lock(p);
+		ast_cli(a->fd, "%s -- %s\n",
+			p->base.owner ? ast_channel_name(p->base.owner) : "<unowned>",
+			p->base.name);
+		ao2_unlock(p);
+		ao2_ref(p, -1);
+	}
+	ao2_iterator_destroy(&it);
+
+	return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry cli_local[] = {
+	AST_CLI_DEFINE(locals_show, "List status of local channels"),
+};
+
+static int manager_optimize_away(struct mansession *s, const struct message *m)
+{
+	const char *channel;
+	struct local_pvt *p;
+	struct local_pvt *found;
+	struct ast_channel *chan;
+
+	channel = astman_get_header(m, "Channel");
+	if (ast_strlen_zero(channel)) {
+		astman_send_error(s, m, "'Channel' not specified.");
+		return 0;
+	}
+
+	chan = ast_channel_get_by_name(channel);
+	if (!chan) {
+		astman_send_error(s, m, "Channel does not exist.");
+		return 0;
+	}
+
+	p = ast_channel_tech_pvt(chan);
+	ast_channel_unref(chan);
+
+	found = p ? ao2_find(locals, p, 0) : NULL;
+	if (found) {
+		ao2_lock(found);
+		ast_clear_flag(&found->base, AST_UNREAL_NO_OPTIMIZATION);
+		ao2_unlock(found);
+		ao2_ref(found, -1);
+		astman_send_ack(s, m, "Queued channel to be optimized away");
+	} else {
+		astman_send_error(s, m, "Unable to find channel");
+	}
+
+	return 0;
+}
+
+
+static int locals_cmp_cb(void *obj, void *arg, int flags)
+{
+	return (obj == arg) ? CMP_MATCH : 0;
+}
+
+/*!
+ * \internal
+ * \brief Shutdown the local proxy channel.
+ * \since 12.0.0
+ *
+ * \return Nothing
+ */
+static void local_shutdown(void)
+{
+	struct local_pvt *p;
+	struct ao2_iterator it;
+
+	/* First, take us out of the channel loop */
+	ast_cli_unregister_multiple(cli_local, ARRAY_LEN(cli_local));
+	ast_manager_unregister("LocalOptimizeAway");
+	ast_channel_unregister(&local_tech);
+
+	it = ao2_iterator_init(locals, 0);
+	while ((p = ao2_iterator_next(&it))) {
+		if (p->base.owner) {
+			ast_softhangup(p->base.owner, AST_SOFTHANGUP_APPUNLOAD);
+		}
+		ao2_ref(p, -1);
+	}
+	ao2_iterator_destroy(&it);
+	ao2_ref(locals, -1);
+	locals = NULL;
+
+	ast_format_cap_destroy(local_tech.capabilities);
+}
+
+int ast_local_init(void)
+{
+	if (!(local_tech.capabilities = ast_format_cap_alloc())) {
+		return -1;
+	}
+	ast_format_cap_add_all(local_tech.capabilities);
+
+	locals = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, locals_cmp_cb);
+	if (!locals) {
+		ast_format_cap_destroy(local_tech.capabilities);
+		return -1;
+	}
+
+	/* Make sure we can register our channel type */
+	if (ast_channel_register(&local_tech)) {
+		ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
+		ao2_ref(locals, -1);
+		ast_format_cap_destroy(local_tech.capabilities);
+		return -1;
+	}
+	ast_cli_register_multiple(cli_local, ARRAY_LEN(cli_local));
+	ast_manager_register_xml_core("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away);
+
+	ast_register_atexit(local_shutdown);
+	return 0;
+}

Propchange: team/rmudgett/bridge_phase/main/core_local.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/rmudgett/bridge_phase/main/core_local.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/rmudgett/bridge_phase/main/core_local.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: team/rmudgett/bridge_phase/main/core_unreal.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/bridge_phase/main/core_unreal.c?view=diff&rev=388210&r1=388209&r2=388210
==============================================================================
--- team/rmudgett/bridge_phase/main/core_unreal.c (original)
+++ team/rmudgett/bridge_phase/main/core_unreal.c Thu May  9 13:10:33 2013
@@ -1,9 +1,9 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 1999 - 2005, 2013, Digium, Inc.
- *
- * Mark Spencer <markster at digium.com>
+ * Copyright (C) 2013 Digium, Inc.
+ *
+ * Richard Mudgett <rmudgett at digium.com>
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk project. Please do not directly contact
@@ -16,12 +16,14 @@
  * at the top of the source tree.
  */
 
-/*! \file
- *
- * \author Mark Spencer <markster at digium.com>
+/*!
+ * \file
+ * \brief Unreal channel derivatives framework for channel drivers like local channels.
+ *
  * \author Richard Mudgett <rmudgett at digium.com>
  *
- * \brief Local proxy channel and other unreal channel derivatives framework.
+ * See Also:
+ * \arg \ref AstCREDITS
  */
 
 /*** MODULEINFO
@@ -32,128 +34,15 @@
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
-#include <fcntl.h>
-#include <sys/signal.h>
-
-#include "asterisk/lock.h"
 #include "asterisk/causes.h"
 #include "asterisk/channel.h"
-#include "asterisk/config.h"
-#include "asterisk/module.h"
 #include "asterisk/pbx.h"
-#include "asterisk/sched.h"
-#include "asterisk/io.h"
-#include "asterisk/acl.h"
-#include "asterisk/callerid.h"
-#include "asterisk/file.h"
-#include "asterisk/cli.h"
-#include "asterisk/app.h"
 #include "asterisk/musiconhold.h"
-#include "asterisk/manager.h"
-#include "asterisk/stringfields.h"
-#include "asterisk/devicestate.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/bridging.h"
-#include "asterisk/core_local.h"
-#include "asterisk/_private.h"
-
-/*** DOCUMENTATION
-	<manager name="LocalOptimizeAway" language="en_US">
-		<synopsis>
-			Optimize away a local channel when possible.
-		</synopsis>
-		<syntax>
-			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
-			<parameter name="Channel" required="true">
-				<para>The channel name to optimize away.</para>
-			</parameter>
-		</syntax>
-		<description>
-			<para>A local channel created with "/n" will not automatically optimize away.
-			Calling this command on the local channel will clear that flag and allow
-			it to optimize away if it's bridged or when it becomes bridged.</para>
-		</description>
-	</manager>
- ***/
-
-static const char tdesc[] = "Local Proxy Channel Driver";
-
-static struct ao2_container *locals;
+#include "asterisk/core_unreal.h"
 
 static unsigned int name_sequence = 0;
-
-static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
-static int local_call(struct ast_channel *ast, const char *dest, int timeout);
-static int local_hangup(struct ast_channel *ast);
-static int local_devicestate(const char *data);
-
-/* PBX interface structure for channel registration */
-static struct ast_channel_tech local_tech = {
-	.type = "Local",
-	.description = tdesc,
-	.requester = local_request,
-	.send_digit_begin = ast_unreal_digit_begin,
-	.send_digit_end = ast_unreal_digit_end,
-	.call = local_call,
-	.hangup = local_hangup,
-	.answer = ast_unreal_answer,
-	.read = ast_unreal_read,
-	.write = ast_unreal_write,
-	.write_video = ast_unreal_write,
-	.exception = ast_unreal_read,
-	.indicate = ast_unreal_indicate,
-	.fixup = ast_unreal_fixup,
-	.send_html = ast_unreal_sendhtml,
-	.send_text = ast_unreal_sendtext,
-	.devicestate = local_devicestate,
-	.queryoption = ast_unreal_queryoption,
-	.setoption = ast_unreal_setoption,
-};
-
-/*! What to do with the ;2 channel when ast_call() happens. */
-enum local_call_action {

[... 724 lines stripped ...]



More information about the asterisk-commits mailing list