[asterisk-commits] oej: branch oej/pinefrog-1.4 r286266 - in /team/oej/pinefrog-1.4: ./ channels...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Sat Sep 11 10:15:50 CDT 2010


Author: oej
Date: Sat Sep 11 10:15:44 2010
New Revision: 286266

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=286266
Log:
Reset automerge

Modified:
    team/oej/pinefrog-1.4/   (props changed)
    team/oej/pinefrog-1.4/channels/chan_dahdi.c
    team/oej/pinefrog-1.4/channels/chan_iax2.c
    team/oej/pinefrog-1.4/channels/chan_local.c
    team/oej/pinefrog-1.4/channels/chan_sip.c
    team/oej/pinefrog-1.4/funcs/func_channel.c
    team/oej/pinefrog-1.4/include/asterisk/channel.h
    team/oej/pinefrog-1.4/include/asterisk/frame.h
    team/oej/pinefrog-1.4/include/asterisk/pbx.h

Propchange: team/oej/pinefrog-1.4/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Sat Sep 11 10:15:44 2010
@@ -1,1 +1,1 @@
-/branches/1.4:1-286049
+/branches/1.4:1-286265

Modified: team/oej/pinefrog-1.4/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinefrog-1.4/channels/chan_dahdi.c?view=diff&rev=286266&r1=286265&r2=286266
==============================================================================
--- team/oej/pinefrog-1.4/channels/chan_dahdi.c (original)
+++ team/oej/pinefrog-1.4/channels/chan_dahdi.c Sat Sep 11 10:15:44 2010
@@ -9911,6 +9911,14 @@
 									pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
 									break;
 								default:
+									if (!pri->pvts[chanpos]->outgoing) {
+										/*
+										 * The incoming call leg hung up before getting
+										 * connected so just hangup the call.
+										 */
+										pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+										break;
+									}
 									switch (e->hangup.cause) {
 										case PRI_CAUSE_USER_BUSY:
 											pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1;
@@ -9986,6 +9994,14 @@
 								pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
 								break;
 							default:
+								if (!pri->pvts[chanpos]->outgoing) {
+									/*
+									 * The incoming call leg hung up before getting
+									 * connected so just hangup the call.
+									 */
+									pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+									break;
+								}
 								switch (e->hangup.cause) {
 									case PRI_CAUSE_USER_BUSY:
 										pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1;

Modified: team/oej/pinefrog-1.4/channels/chan_iax2.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinefrog-1.4/channels/chan_iax2.c?view=diff&rev=286266&r1=286265&r2=286266
==============================================================================
--- team/oej/pinefrog-1.4/channels/chan_iax2.c (original)
+++ team/oej/pinefrog-1.4/channels/chan_iax2.c Sat Sep 11 10:15:44 2010
@@ -12713,13 +12713,6 @@
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
-	randomcalltokendata = ast_random();
-	ast_custom_function_register(&iaxpeer_function);
-
-	iax_set_output(iax_debug_output);
-	iax_set_error(iax_error_output);
-	jb_setoutput(jb_error_output, jb_warning_output, NULL);
-	
 #ifdef HAVE_DAHDI
 #ifdef DAHDI_TIMERACK
 	timingfd = open(DAHDI_FILE_TIMER, O_RDWR);
@@ -12735,12 +12728,12 @@
 	for (x = 0; x < ARRAY_LEN(iaxsl); x++) {
 		ast_mutex_init(&iaxsl[x]);
 	}
-	
+
 	ast_cond_init(&sched_cond, NULL);
 
 	io = io_context_create();
 	sched = sched_context_create();
-	
+
 	if (!io || !sched) {
 		ast_log(LOG_ERROR, "Out of memory\n");
 		return -1;
@@ -12760,33 +12753,44 @@
 	}
 	ast_netsock_init(outsock);
 
+	randomcalltokendata = ast_random();
+
+	iax_set_output(iax_debug_output);
+	iax_set_error(iax_error_output);
+	jb_setoutput(jb_error_output, jb_warning_output, NULL);
+
 	ast_mutex_init(&waresl.lock);
 
 	AST_LIST_HEAD_INIT(&iaxq.queue);
-	
+
+	if (set_config(config, 0) == -1) {
+		return AST_MODULE_LOAD_DECLINE;
+	}
+
 	ast_cli_register_multiple(cli_iax2, sizeof(cli_iax2) / sizeof(struct ast_cli_entry));
 
 	ast_register_application(papp, iax2_prov_app, psyn, pdescrip);
-	
+
+	ast_custom_function_register(&iaxpeer_function);
+
 	ast_manager_register( "IAXpeers", 0, manager_iax2_show_peers, "List IAX Peers" );
 	ast_manager_register( "IAXnetstats", 0, manager_iax2_show_netstats, "Show IAX Netstats" );
 
-	if(set_config(config, 0) == -1)
-		return AST_MODULE_LOAD_DECLINE;
-
- 	if (ast_channel_register(&iax2_tech)) {
+	if (ast_channel_register(&iax2_tech)) {
 		ast_log(LOG_ERROR, "Unable to register channel class %s\n", "IAX2");
 		__unload_module();
 		return -1;
 	}
 
-	if (ast_register_switch(&iax2_switch)) 
+	if (ast_register_switch(&iax2_switch)) {
 		ast_log(LOG_ERROR, "Unable to register IAX switch\n");
+	}
 
 	res = start_network_thread();
 	if (!res) {
-		if (option_verbose > 1) 
+		if (option_verbose > 1) {
 			ast_verbose(VERBOSE_PREFIX_2 "IAX Ready and Listening\n");
+		}
 	} else {
 		ast_log(LOG_ERROR, "Unable to start network thread\n");
 		ast_netsock_release(netsock);

Modified: team/oej/pinefrog-1.4/channels/chan_local.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinefrog-1.4/channels/chan_local.c?view=diff&rev=286266&r1=286265&r2=286266
==============================================================================
--- team/oej/pinefrog-1.4/channels/chan_local.c (original)
+++ team/oej/pinefrog-1.4/channels/chan_local.c Sat Sep 11 10:15:44 2010
@@ -79,6 +79,7 @@
 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
 static int local_sendtext(struct ast_channel *ast, const char *text);
 static int local_devicestate(void *data);
+static int local_setoption(struct ast_channel *chan, int option, void *data, int datalen);
 
 /* PBX interface structure for channel registration */
 static const struct ast_channel_tech local_tech = {
@@ -100,6 +101,7 @@
 	.send_html = local_sendhtml,
 	.send_text = local_sendtext,
 	.devicestate = local_devicestate,
+	.setoption = local_setoption,
 };
 
 struct local_pvt {
@@ -123,6 +125,71 @@
 #define LOCAL_MOH_PASSTHRU    (1 << 5) /*!< Pass through music on hold start/stop frames */
 
 static AST_LIST_HEAD_STATIC(locals, local_pvt);
+
+static int local_setoption(struct ast_channel *chan, int option, void * data, int datalen)
+{
+	int res;
+	struct local_pvt *p;
+	struct ast_channel *otherchan;
+	ast_chan_write_info_t *write_info;
+
+	if (option != AST_OPTION_CHANNEL_WRITE) {
+		return -1;
+	}
+
+	write_info = data;
+
+	if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) {
+		ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n");
+		return -1;
+	}
+
+
+startover:
+	ast_channel_lock(chan);
+
+	p = chan->tech_pvt;
+	if (!p) {
+		ast_channel_unlock(chan);
+		ast_log(LOG_WARNING, "Could not update other side of %s, local_pvt went away.\n", chan->name);
+		return -1;
+	}
+
+	while (ast_mutex_trylock(&p->lock)) {
+		ast_channel_unlock(chan);
+		sched_yield();
+		ast_channel_lock(chan);
+		p = chan->tech_pvt;
+		if (!p) {
+			ast_channel_unlock(chan);
+			ast_log(LOG_WARNING, "Could not update other side of %s, local_pvt went away.\n", chan->name);
+			return -1;
+		}
+	}
+
+	otherchan = (write_info->chan == p->owner) ? p->chan : p->owner;
+
+	if (!otherchan || otherchan == write_info->chan) {
+		ast_mutex_unlock(&p->lock);
+		ast_channel_unlock(chan);
+		ast_log(LOG_WARNING, "Could not update other side of %s, other side went away.\n", chan->name);
+		return 0;
+	}
+
+	if (ast_channel_trylock(otherchan)) {
+		ast_mutex_unlock(&p->lock);
+		ast_channel_unlock(chan);
+		goto startover;
+	}
+
+	res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value);
+
+	ast_channel_unlock(otherchan);
+	ast_mutex_unlock(&p->lock);
+	ast_channel_unlock(chan);
+
+	return res;
+}
 
 /*! \brief Adds devicestate to local channels */
 static int local_devicestate(void *data)

Modified: team/oej/pinefrog-1.4/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinefrog-1.4/channels/chan_sip.c?view=diff&rev=286266&r1=286265&r2=286266
==============================================================================
--- team/oej/pinefrog-1.4/channels/chan_sip.c (original)
+++ team/oej/pinefrog-1.4/channels/chan_sip.c Sat Sep 11 10:15:44 2010
@@ -1263,6 +1263,39 @@
 AST_THREADSTORAGE_CUSTOM(ts_video_rtp, ts_video_rtp_init, ts_ast_rtp_destroy);
 #endif
 
+struct sip_extenstate_update {
+	struct sip_pvt *pvt;
+	int state;
+	int marked;
+	AST_LIST_ENTRY(sip_extenstate_update) list;	/*!< Pointer to next update in list */
+	char *context;
+	char exten[0];
+};
+
+
+/*!
+ * \brief list of extension state updates for the dialog list.
+ *
+ * \note This list deserves a detailed explanation as to why it was
+ * created and why it is necessary...  So here it is.
+ *
+ * When an endpoint SUBSCRIBES to the state of a hint a callback function
+ * is registered with the Asterisk core.  That callback is used to notify
+ * chan_sip every time that hint's state changes and what endpoint we need
+ * to update.  The problem occurs with the locking order used during that
+ * callback function.  When the function is used by the Asterisk core, the
+ * global contexts lock is held.  Then within the callback the sip_pvt lock
+ * is held.  That completely invalidates the locking order used everywhere
+ * else in chan_sip regarding these two locks.  Typically the pvt lock is
+ * held while we ask the Asterisk core about an extension and context which
+ * results in the context being locked.  In order to avoid the possible deadlock
+ * that could occur in the callback function due to improper locking, this
+ * list was created to queue those state changes for the sip_pvt to read outside
+ * of that thread.  This way the context lock never has to be held before the
+ * pvt lock is held.
+ */
+static AST_LIST_HEAD_STATIC(sip_extenstate_updates, sip_extenstate_update);
+
 /*! \todo Move the sip_auth list to AST_LIST */
 static struct sip_auth *authl = NULL;		/*!< Authentication list for realm authentication */
 
@@ -1420,7 +1453,8 @@
 static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target);
 
 /*--- Device monitoring and Device/extension state handling */
-static int cb_extensionstate(char *context, char* exten, int state, void *data);
+static int notify_extenstate_update(char *context, char* exten, int state, void *data);
+static void clear_extenstate_updates(struct sip_pvt *pvt);
 static int sip_devicestate(void *data);
 static int sip_poke_noanswer(const void *data);
 static int sip_poke_peer(struct sip_peer *peer);
@@ -3402,6 +3436,11 @@
 	if (p->stateid > -1)
 		ast_extension_state_del(p->stateid, NULL);
 	AST_SCHED_DEL(sched, p->rtcpeventid);
+
+	/* remove any pending extension notify that could be left in
+	 * the extension update queue relating to this dialog. */
+	clear_extenstate_updates(p);
+
 	AST_SCHED_DEL(sched, p->initid);
 	AST_SCHED_DEL(sched, p->waitid);
 	AST_SCHED_DEL(sched, p->autokillid);
@@ -9278,10 +9317,166 @@
 	return;
 }
 
+static int add_extensionstate_update(char *context, char *exten, int state, void *data)
+{
+	struct sip_extenstate_update *update;
+	size_t exten_len = strlen(exten);
+	size_t context_len = strlen(context);
+
+	if (!(update = ast_calloc(1, sizeof(*update) + exten_len + context_len + 2))) {
+		return -1;
+	}
+
+	strcpy(update->exten, exten);
+
+	update->context = (char *) (update->exten + exten_len + 1);
+	strcpy(update->context, context);
+
+	update->state = state;
+	update->pvt = data;
+
+	AST_LIST_LOCK(&sip_extenstate_updates);
+	AST_LIST_INSERT_TAIL(&sip_extenstate_updates, update, list);
+	AST_LIST_UNLOCK(&sip_extenstate_updates);
+
+	/* Tell the do_monitor thread it has to do stuff! That thread is so lazy :( */
+	if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
+		pthread_kill(monitor_thread, SIGURG);
+	}
+
+	return 0;
+}
+
+/*!
+ * \internal 
+ * \brief Check to see if there are any extension state updates
+ * for this pvt.  If so send them and remove from queue */
+static void check_extenstate_updates(struct sip_pvt *pvt)
+{
+	struct sip_extenstate_update *update = NULL;
+
+	if (AST_LIST_EMPTY(&sip_extenstate_updates)) {
+		/* avoid holding the lock if possible */
+		return;
+	}
+
+	do {
+		if (update) {
+			/* The notify can not happen while the list lock is held. */
+			notify_extenstate_update(update->context, update->exten, update->state, pvt);
+			ast_free(update);
+		}
+
+		AST_LIST_LOCK(&sip_extenstate_updates);
+		AST_LIST_TRAVERSE_SAFE_BEGIN(&sip_extenstate_updates, update, list) {
+			if (update->pvt == pvt) {
+				AST_LIST_REMOVE_CURRENT(&sip_extenstate_updates, list);
+				break;
+			}
+		}
+		AST_LIST_TRAVERSE_SAFE_END
+		AST_LIST_UNLOCK(&sip_extenstate_updates);
+	} while (update);
+}
+
+/*!
+ * \internal 
+ * \brief clear all marked extenstate updates left in the queue.
+ */
+static void clearmarked_extenstate_updates(void)
+{
+	struct sip_extenstate_update *update = NULL;
+
+	if (AST_LIST_EMPTY(&sip_extenstate_updates)) {
+		/* avoid holding the lock if possible */
+		return;
+	}
+
+	AST_LIST_LOCK(&sip_extenstate_updates);
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&sip_extenstate_updates, update, list) {
+		if (update->marked) {
+			AST_LIST_REMOVE_CURRENT(&sip_extenstate_updates, list);
+			ast_free(update);
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END
+	AST_LIST_UNLOCK(&sip_extenstate_updates);
+
+}
+
+/*!
+ * \internal 
+ * \brief unmark for destruction all the extension updates for a specific dialog.
+ *
+ * \note this is used to remove updates pertaining to a dialog from destruction because
+ * they need to be sent out at a later time.
+ */
+static void unmark_extenstate_update(struct sip_pvt *pvt)
+{
+	struct sip_extenstate_update *update = NULL;
+
+	if (AST_LIST_EMPTY(&sip_extenstate_updates)) {
+		/* avoid holding the lock if possible */
+		return;
+	}
+
+	AST_LIST_LOCK(&sip_extenstate_updates);
+	AST_LIST_TRAVERSE(&sip_extenstate_updates, update, list) {
+		if (update->pvt == pvt) {
+			update->marked = 0;
+		}
+	}
+	AST_LIST_UNLOCK(&sip_extenstate_updates);
+}
+
+/*!
+ * \internal 
+ * \brief mark all the current extenstate updates for removal.
+ */
+static void markall_extenstate_updates(void)
+{
+	struct sip_extenstate_update *update = NULL;
+
+	if (AST_LIST_EMPTY(&sip_extenstate_updates)) {
+		/* avoid holding the lock if possible */
+		return;
+	}
+
+	AST_LIST_LOCK(&sip_extenstate_updates);
+	AST_LIST_TRAVERSE(&sip_extenstate_updates, update, list) {
+		update->marked = 1;
+	}
+	AST_LIST_UNLOCK(&sip_extenstate_updates);
+}
+
+/*!
+ * \internal 
+ * \brief clear out all extension state updates for a pvt.
+ */
+static void clear_extenstate_updates(struct sip_pvt *pvt)
+{
+	struct sip_extenstate_update *update = NULL;
+
+	if (AST_LIST_EMPTY(&sip_extenstate_updates)) {
+		/* avoid holding the lock if possible */
+		return;
+	}
+
+	AST_LIST_LOCK(&sip_extenstate_updates);
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&sip_extenstate_updates, update, list) {
+		if (update->pvt == pvt) {
+			AST_LIST_REMOVE_CURRENT(&sip_extenstate_updates, list);
+			ast_free(update);
+		}
+	}
+	AST_LIST_TRAVERSE_SAFE_END
+	AST_LIST_UNLOCK(&sip_extenstate_updates);
+}
+
 /*! \brief Callback for the devicestate notification (SUBSCRIBE) support subsystem
 \note	If you add an "hint" priority to the extension in the dial plan,
 	you will get notifications on device state changes */
-static int cb_extensionstate(char *context, char* exten, int state, void *data)
+static int notify_extenstate_update(char *context, char* exten, int state, void *data)
 {
 	struct sip_pvt *p = data;
 
@@ -13573,7 +13768,7 @@
 	reporttype = 0  means report during call (if configured)
 	reporttype = 1  means endof-call (hangup) report
 	reporttype = 2  means report at closure of SIP pvt (used only for realtime reports. We might get 
-			an incoming final RTCP after we send BYE */
+			an incoming final RTCP after we send BYE 
 	reporttype = 10  means report at end of call leg (like transfer)
 */
 static void sip_rtcp_report(struct sip_pvt *p, struct ast_rtp *rtp, enum media_type type, int reporttype)
@@ -13908,7 +14103,7 @@
 					if (ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE)) {
 						/* Ready to send the next state we have on queue */
 						ast_clear_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE);
-						cb_extensionstate((char *)p->context, (char *)p->exten, p->laststate, (void *) p);
+						notify_extenstate_update((char *)p->context, (char *)p->exten, p->laststate, (void *) p);
 					}
 				}
 			} else if (sipmethod == SIP_REGISTER) 
@@ -14168,7 +14363,7 @@
 					if (ast_test_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE)) {
 						/* Ready to send the next state we have on queue */
 						ast_clear_flag(&p->flags[1], SIP_PAGE2_STATECHANGEQUEUE);
-						cb_extensionstate((char *)p->context, (char *)p->exten, p->laststate, (void *) p);
+						notify_extenstate_update((char *)p->context, (char *)p->exten, p->laststate, (void *) p);
 					}
 				}
 			} else if (sipmethod == SIP_BYE)
@@ -16664,8 +16859,8 @@
 
 	if (p->subscribed != MWI_NOTIFICATION && !resubscribe) {
 		if (p->stateid > -1)
-			ast_extension_state_del(p->stateid, cb_extensionstate);
-		p->stateid = ast_extension_state_add(p->context, p->exten, cb_extensionstate, p);
+			ast_extension_state_del(p->stateid, add_extensionstate_update);
+		p->stateid = ast_extension_state_add(p->context, p->exten, add_extensionstate_update, p);
 	}
 
 	if (!ast_test_flag(req, SIP_PKT_IGNORE) && p)
@@ -17342,8 +17537,15 @@
 				sipsock_read_id = NULL;
 			}
 		}
-restartsearch:		
-		/* Check for interfaces needing to be killed */
+
+		/* we only want to mark the extenstate updates for destruction
+		 * if the dialog list is being traversed */
+		if (!fastrestart) {
+			markall_extenstate_updates();
+		}
+
+restartsearch:
+		/* Check for interfaces needing to be killed and for pending extension state notifications. */
 		ast_mutex_lock(&iflock);
 		t = time(NULL);
 		/* don't scan the interface list if it hasn't been a reasonable period
@@ -17356,8 +17558,16 @@
 			 * sip_hangup otherwise, because sip_hangup is called with the channel
 			 * locked first, and the iface lock is attempted second.
 			 */
-			if (ast_mutex_trylock(&sip->lock))
+			if (ast_mutex_trylock(&sip->lock)) {
+				/* make sure to unmark any extension state updates for this pvt so
+				 * they can be sent out when we come back to it. */
+				unmark_extenstate_update(sip);
 				continue;
+			}
+
+			/* since we are iterating through all the sip_pvts here, this is a good place
+			 * to send out extension state updates. */
+			check_extenstate_updates(sip);
 
 			/* Check RTP timeouts and kill calls if we have a timeout set and do not get RTP */
 			if (sip->rtp && sip->owner &&
@@ -17420,6 +17630,11 @@
 			ast_mutex_unlock(&sip->lock);
 		}
 		ast_mutex_unlock(&iflock);
+
+		/* we only want to clear the extension state updates if the dialog list was traversed */
+		if (!fastrestart) {
+			clearmarked_extenstate_updates();
+		}
 
 		/* XXX TODO The scheduler usage in this module does not have sufficient 
 		 * synchronization being done between running the scheduler and places 
@@ -20002,7 +20217,8 @@
 static int unload_module(void)
 {
 	struct sip_pvt *p, *pl;
-	
+	struct sip_extenstate_update *update;
+
 	/* First, take us out of the channel type list */
 	ast_channel_unregister(&sip_tech);
 
@@ -20074,6 +20290,14 @@
 	ASTOBJ_CONTAINER_DESTROYALL(&regl, sip_registry_destroy);
 	ASTOBJ_CONTAINER_DESTROY(&regl);
 
+	AST_LIST_LOCK(&sip_extenstate_updates);
+	AST_LIST_TRAVERSE_SAFE_BEGIN(&sip_extenstate_updates, update, list) {
+		AST_LIST_REMOVE_CURRENT(&sip_extenstate_updates, list);
+		ast_free(update);
+	}
+	AST_LIST_TRAVERSE_SAFE_END
+	AST_LIST_UNLOCK(&sip_extenstate_updates);
+
 	clear_realm_authentication(authl);
 	clear_sip_domains();
 	ast_free_ha(global_contact_ha);

Modified: team/oej/pinefrog-1.4/funcs/func_channel.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinefrog-1.4/funcs/func_channel.c?view=diff&rev=286266&r1=286265&r2=286266
==============================================================================
--- team/oej/pinefrog-1.4/funcs/func_channel.c (original)
+++ team/oej/pinefrog-1.4/funcs/func_channel.c Sat Sep 11 10:15:44 2010
@@ -96,7 +96,7 @@
 	return ret;
 }
 
-static int func_channel_write(struct ast_channel *chan, char *function,
+static int func_channel_write_real(struct ast_channel *chan, char *function,
 			      char *data, const char *value)
 {
 	int ret = 0;
@@ -137,6 +137,24 @@
 	}
 
 	return ret;
+}
+
+static int func_channel_write(struct ast_channel *chan, char *function, char *data, const char *value)
+{
+	int res;
+	ast_chan_write_info_t write_info = {
+		.version = AST_CHAN_WRITE_INFO_T_VERSION,
+		.write_fn = func_channel_write_real,
+		.chan = chan,
+		.function = function,
+		.data = data,
+		.value = value,
+	};
+
+	res = func_channel_write_real(chan, function, data, value);
+	ast_channel_setoption(chan, AST_OPTION_CHANNEL_WRITE, &write_info, sizeof(write_info), 0);
+
+	return res;
 }
 
 static struct ast_custom_function channel_function = {

Modified: team/oej/pinefrog-1.4/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinefrog-1.4/include/asterisk/channel.h?view=diff&rev=286266&r1=286265&r2=286266
==============================================================================
--- team/oej/pinefrog-1.4/include/asterisk/channel.h (original)
+++ team/oej/pinefrog-1.4/include/asterisk/channel.h Sat Sep 11 10:15:44 2010
@@ -193,6 +193,24 @@
 	int cid_ton;		/*!< Callerid Type of Number */
 	int cid_tns;		/*!< Callerid Transit Network Select */
 };
+
+/*! \brief Typedef for a custom read function */
+typedef int (*ast_acf_read_fn_t)(struct ast_channel *, char *, char *, char *, size_t);
+
+/*! \brief Typedef for a custom write function */
+typedef int (*ast_acf_write_fn_t)(struct ast_channel *, char *, char *, const char *);
+
+/*! \brief Structure to handle passing func_channel_write info to channels via setoption */
+typedef struct {
+	/*! \brief ast_chan_write_info_t version. Must be incremented if structure is changed */
+	#define AST_CHAN_WRITE_INFO_T_VERSION 1
+	uint32_t version;
+	ast_acf_write_fn_t write_fn;
+	struct ast_channel *chan;
+	char *function;
+	char *data;
+	const char *value;
+} ast_chan_write_info_t;
 
 /*! \brief 
 	Structure to describe a channel "technology", ie a channel driver 

Modified: team/oej/pinefrog-1.4/include/asterisk/frame.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinefrog-1.4/include/asterisk/frame.h?view=diff&rev=286266&r1=286265&r2=286266
==============================================================================
--- team/oej/pinefrog-1.4/include/asterisk/frame.h (original)
+++ team/oej/pinefrog-1.4/include/asterisk/frame.h Sat Sep 11 10:15:44 2010
@@ -340,6 +340,13 @@
 /*! Explicitly enable or disable echo cancelation for the given channel */
 #define	AST_OPTION_ECHOCAN		8
 
+/*! \brief Handle channel write data
+ * If a channel needs to process the data from a func_channel write operation
+ * after func_channel_write executes, it can define the setoption callback
+ * and process this option. A pointer to an ast_chan_write_info_t will be passed.
+ * */
+#define AST_OPTION_CHANNEL_WRITE 9
+
 struct oprmode {
 	struct ast_channel *peer;
 	int mode;

Modified: team/oej/pinefrog-1.4/include/asterisk/pbx.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinefrog-1.4/include/asterisk/pbx.h?view=diff&rev=286266&r1=286265&r2=286266
==============================================================================
--- team/oej/pinefrog-1.4/include/asterisk/pbx.h (original)
+++ team/oej/pinefrog-1.4/include/asterisk/pbx.h Sat Sep 11 10:15:44 2010
@@ -71,8 +71,8 @@
 	const char *synopsis;		/*!< Short description for "show functions" */
 	const char *desc;		/*!< Help text that explains it all */
 	const char *syntax;		/*!< Syntax description */
-	int (*read)(struct ast_channel *, char *, char *, char *, size_t);	/*!< Read function, if read is supported */
-	int (*write)(struct ast_channel *, char *, char *, const char *);	/*!< Write function, if write is supported */
+	ast_acf_read_fn_t read;		/*!< Read function, if read is supported */
+	ast_acf_write_fn_t write;	/*!< Write function, if write is supported */
 	AST_LIST_ENTRY(ast_custom_function) acflist;
 };
 




More information about the asterisk-commits mailing list