#include "asterisk.h"
#include <fcntl.h>
#include <sys/signal.h>
#include "asterisk/lock.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"

Go to the source code of this file.
Data Structures | |
| struct | local_pvt |
| struct | locals |
Defines | |
| #define | IS_OUTBOUND(a, b) (a == b->chan ? 1 : 0) |
| #define | LOCAL_ALREADY_MASQED (1 << 2) |
| #define | LOCAL_BRIDGE (1 << 5) |
| #define | LOCAL_CANCEL_QUEUE (1 << 1) |
| #define | LOCAL_GLARE_DETECT (1 << 0) |
| #define | LOCAL_LAUNCHED_PBX (1 << 3) |
| #define | LOCAL_NO_OPTIMIZATION (1 << 4) |
Functions | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static void | check_bridge (struct local_pvt *p, int isoutbound) |
| static int | load_module (void) |
| Load module into PBX, register channel. | |
| static struct local_pvt * | local_alloc (const char *data, int format) |
| Create a call structure. | |
| static int | local_answer (struct ast_channel *ast) |
| static struct ast_channel * | local_bridgedchannel (struct ast_channel *chan, struct ast_channel *bridge) |
| Return the bridged channel of a Local channel. | |
| static int | local_call (struct ast_channel *ast, char *dest, int timeout) |
| Initiate new call, part of PBX interface dest is the dial string. | |
| static int | local_devicestate (void *data) |
| Adds devicestate to local channels. | |
| static int | local_digit_begin (struct ast_channel *ast, char digit) |
| static int | local_digit_end (struct ast_channel *ast, char digit, unsigned int duration) |
| static int | local_fixup (struct ast_channel *oldchan, struct ast_channel *newchan) |
| static int | local_hangup (struct ast_channel *ast) |
| Hangup a call through the local proxy channel. | |
| static int | local_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen) |
| static struct ast_channel * | local_new (struct local_pvt *p, int state, const char *linkedid) |
| Start new local channel. | |
| static struct local_pvt * | local_pvt_destroy (struct local_pvt *pvt) |
| static int | local_queue_frame (struct local_pvt *p, int isoutbound, struct ast_frame *f, struct ast_channel *us, int us_locked) |
| static struct ast_frame * | local_read (struct ast_channel *ast) |
| static struct ast_channel * | local_request (const char *type, int format, const struct ast_channel *requestor, void *data, int *cause) |
| Part of PBX interface. | |
| 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_write (struct ast_channel *ast, struct ast_frame *f) |
| static char * | locals_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| CLI command "local show channels". | |
| static int | unload_module (void) |
| Unload the local proxy channel from Asterisk. | |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Local Proxy Channel (Note: used internally by other modules)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_cli_entry | cli_local [] |
| static struct ast_jb_conf | g_jb_conf |
| static struct ast_channel_tech | local_tech |
| static const char | tdesc [] = "Local Proxy Channel Driver" |
Definition in file chan_local.c.
| #define IS_OUTBOUND | ( | a, | |||
| b | ) | (a == b->chan ? 1 : 0) |
Definition at line 54 of file chan_local.c.
Referenced by local_answer(), local_digit_begin(), local_digit_end(), local_hangup(), local_indicate(), local_sendhtml(), local_sendtext(), and local_write().
| #define LOCAL_ALREADY_MASQED (1 << 2) |
Already masqueraded
Definition at line 117 of file chan_local.c.
Referenced by check_bridge(), and local_write().
| #define LOCAL_BRIDGE (1 << 5) |
Report back the "true" channel as being bridged to
Definition at line 120 of file chan_local.c.
Referenced by local_alloc(), and local_bridgedchannel().
| #define LOCAL_CANCEL_QUEUE (1 << 1) |
Cancel queue
Definition at line 116 of file chan_local.c.
Referenced by local_hangup(), and local_queue_frame().
| #define LOCAL_GLARE_DETECT (1 << 0) |
Detect glare on hangup
Definition at line 115 of file chan_local.c.
Referenced by local_hangup(), and local_queue_frame().
| #define LOCAL_LAUNCHED_PBX (1 << 3) |
PBX was launched
Definition at line 118 of file chan_local.c.
Referenced by local_call(), and local_hangup().
| #define LOCAL_NO_OPTIMIZATION (1 << 4) |
Do not optimize using masquerading
Definition at line 119 of file chan_local.c.
Referenced by check_bridge(), and local_alloc().
| static void __reg_module | ( | void | ) | [static] |
| static void __unreg_module | ( | void | ) | [static] |
| static void check_bridge | ( | struct local_pvt * | p, | |
| int | isoutbound | |||
| ) | [static] |
Definition at line 277 of file chan_local.c.
References ast_channel::_bridge, ast_app_group_update(), ast_bridged_channel(), ast_channel_masquerade(), ast_channel_trylock, ast_channel_unlock, ast_check_hangup(), AST_LIST_EMPTY, ast_mutex_trylock(), ast_mutex_unlock(), ast_set_flag, ast_test_flag, ast_channel::audiohooks, local_pvt::chan, LOCAL_ALREADY_MASQED, LOCAL_NO_OPTIMIZATION, ast_channel::monitor, local_pvt::owner, and ast_channel::readq.
Referenced by local_write().
00278 { 00279 struct ast_channel_monitor *tmp; 00280 if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || ast_test_flag(p, LOCAL_NO_OPTIMIZATION) || !p->chan || !p->owner || (p->chan->_bridge != ast_bridged_channel(p->chan))) 00281 return; 00282 00283 /* only do the masquerade if we are being called on the outbound channel, 00284 if it has been bridged to another channel and if there are no pending 00285 frames on the owner channel (because they would be transferred to the 00286 outbound channel during the masquerade) 00287 */ 00288 if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) { 00289 /* Masquerade bridged channel into owner */ 00290 /* Lock everything we need, one by one, and give up if 00291 we can't get everything. Remember, we'll get another 00292 chance in just a little bit */ 00293 if (!ast_channel_trylock(p->chan->_bridge)) { 00294 if (!ast_check_hangup(p->chan->_bridge)) { 00295 if (!ast_channel_trylock(p->owner)) { 00296 if (!ast_check_hangup(p->owner)) { 00297 if (p->owner->monitor && !p->chan->_bridge->monitor) { 00298 /* If a local channel is being monitored, we don't want a masquerade 00299 * to cause the monitor to go away. Since the masquerade swaps the monitors, 00300 * pre-swapping the monitors before the masquerade will ensure that the monitor 00301 * ends up where it is expected. 00302 */ 00303 tmp = p->owner->monitor; 00304 p->owner->monitor = p->chan->_bridge->monitor; 00305 p->chan->_bridge->monitor = tmp; 00306 } 00307 if (p->chan->audiohooks) { 00308 struct ast_audiohook_list *audiohooks_swapper; 00309 audiohooks_swapper = p->chan->audiohooks; 00310 p->chan->audiohooks = p->owner->audiohooks; 00311 p->owner->audiohooks = audiohooks_swapper; 00312 } 00313 ast_app_group_update(p->chan, p->owner); 00314 ast_channel_masquerade(p->owner, p->chan->_bridge); 00315 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00316 } 00317 ast_channel_unlock(p->owner); 00318 } 00319 ast_channel_unlock(p->chan->_bridge); 00320 } 00321 } 00322 /* We only allow masquerading in one 'direction'... it's important to preserve the state 00323 (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan) 00324 when the local channels go away. 00325 */ 00326 #if 0 00327 } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) { 00328 /* Masquerade bridged channel into chan */ 00329 if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) { 00330 if (!ast_check_hangup(p->owner->_bridge)) { 00331 if (!ast_mutex_trylock(&p->chan->lock)) { 00332 if (!ast_check_hangup(p->chan)) { 00333 ast_channel_masquerade(p->chan, p->owner->_bridge); 00334 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00335 } 00336 ast_mutex_unlock(&p->chan->lock); 00337 } 00338 } 00339 ast_mutex_unlock(&(p->owner->_bridge)->lock); 00340 } 00341 #endif 00342 } 00343 }
| static int load_module | ( | void | ) | [static] |
Load module into PBX, register channel.
Definition at line 905 of file chan_local.c.
References ast_channel_register(), ast_cli_register_multiple(), ast_log(), AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, cli_local, and LOG_ERROR.
00906 { 00907 /* Make sure we can register our channel type */ 00908 if (ast_channel_register(&local_tech)) { 00909 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); 00910 return AST_MODULE_LOAD_FAILURE; 00911 } 00912 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00913 return AST_MODULE_LOAD_SUCCESS; 00914 }
| static struct local_pvt* local_alloc | ( | const char * | data, | |
| int | format | |||
| ) | [static, read] |
Create a call structure.
Definition at line 725 of file chan_local.c.
References ast_calloc, ast_copy_string(), ast_exists_extension(), AST_JB_ENABLED, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_init(), ast_set_flag, ast_test_flag, local_pvt::context, local_pvt::exten, local_pvt::jb_conf, LOCAL_BRIDGE, LOCAL_NO_OPTIMIZATION, local_pvt_destroy(), local_pvt::lock, LOG_ERROR, LOG_NOTICE, and local_pvt::reqformat.
Referenced by local_request().
00726 { 00727 struct local_pvt *tmp = NULL; 00728 char *c = NULL, *opts = NULL; 00729 00730 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) 00731 return NULL; 00732 00733 /* Initialize private structure information */ 00734 ast_mutex_init(&tmp->lock); 00735 ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); 00736 00737 memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf)); 00738 00739 /* Look for options */ 00740 if ((opts = strchr(tmp->exten, '/'))) { 00741 *opts++ = '\0'; 00742 if (strchr(opts, 'n')) 00743 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); 00744 if (strchr(opts, 'j')) { 00745 if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION)) 00746 ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED); 00747 else { 00748 ast_log(LOG_ERROR, "You must use the 'n' option for chan_local " 00749 "to use the 'j' option to enable the jitterbuffer\n"); 00750 } 00751 } 00752 if (strchr(opts, 'b')) { 00753 ast_set_flag(tmp, LOCAL_BRIDGE); 00754 } 00755 } 00756 00757 /* Look for a context */ 00758 if ((c = strchr(tmp->exten, '@'))) 00759 *c++ = '\0'; 00760 00761 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context)); 00762 00763 tmp->reqformat = format; 00764 00765 #if 0 00766 /* We can't do this check here, because we don't know the CallerID yet, and 00767 * the CallerID could potentially affect what step is actually taken (or 00768 * even if that step exists). */ 00769 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { 00770 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); 00771 tmp = local_pvt_destroy(tmp); 00772 } else { 00773 #endif 00774 /* Add to list */ 00775 AST_LIST_LOCK(&locals); 00776 AST_LIST_INSERT_HEAD(&locals, tmp, list); 00777 AST_LIST_UNLOCK(&locals); 00778 #if 0 00779 } 00780 #endif 00781 00782 return tmp; 00783 }
| static int local_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 255 of file chan_local.c.
References AST_CONTROL_ANSWER, AST_FRAME_CONTROL, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), IS_OUTBOUND, local_queue_frame(), local_pvt::lock, LOG_WARNING, and ast_channel::tech_pvt.
00256 { 00257 struct local_pvt *p = ast->tech_pvt; 00258 int isoutbound; 00259 int res = -1; 00260 00261 if (!p) 00262 return -1; 00263 00264 ast_mutex_lock(&p->lock); 00265 isoutbound = IS_OUTBOUND(ast, p); 00266 if (isoutbound) { 00267 /* Pass along answer since somebody answered us */ 00268 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00269 res = local_queue_frame(p, isoutbound, &answer, ast, 1); 00270 } else 00271 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n"); 00272 if (!res) 00273 ast_mutex_unlock(&p->lock); 00274 return res; 00275 }
| static struct ast_channel * local_bridgedchannel | ( | struct ast_channel * | chan, | |
| struct ast_channel * | bridge | |||
| ) | [static, read] |
Return the bridged channel of a Local channel.
Definition at line 173 of file chan_local.c.
References ast_channel::_bridge, ast_mutex_lock(), ast_mutex_unlock(), ast_test_flag, local_pvt::chan, LOCAL_BRIDGE, local_pvt::lock, local_pvt::owner, and ast_channel::tech_pvt.
00174 { 00175 struct local_pvt *p = bridge->tech_pvt; 00176 struct ast_channel *bridged = bridge; 00177 00178 ast_mutex_lock(&p->lock); 00179 00180 if (ast_test_flag(p, LOCAL_BRIDGE)) { 00181 /* Find the opposite channel */ 00182 bridged = (bridge == p->owner ? p->chan : p->owner); 00183 00184 /* Now see if the opposite channel is bridged to anything */ 00185 if (!bridged) { 00186 bridged = bridge; 00187 } else if (bridged->_bridge) { 00188 bridged = bridged->_bridge; 00189 } 00190 } 00191 00192 ast_mutex_unlock(&p->lock); 00193 00194 return bridged; 00195 }
| static int local_call | ( | struct ast_channel * | ast, | |
| char * | dest, | |||
| int | timeout | |||
| ) | [static] |
Initiate new call, part of PBX interface dest is the dial string.
Definition at line 540 of file chan_local.c.
References ast_channel::accountcode, accountcode, ast_calloc, ast_cdr_update(), ast_channel_datastore_inherit(), ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_connected_line_copy_from_caller(), ast_connected_line_copy_to_caller(), ast_exists_extension(), AST_FLAG_ANSWERED_ELSEWHERE, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_trylock(), ast_mutex_unlock(), ast_party_redirecting_copy(), ast_pbx_start(), ast_set_flag, ast_strdup, ast_string_field_set, ast_test_flag, ast_channel::cdrflags, local_pvt::chan, ast_channel::cid, ast_callerid::cid_dnid, ast_callerid::cid_num, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_channel::connected, ast_channel::context, ast_var_t::entries, ast_channel::exten, ast_channel::language, language, len(), LOCAL_LAUNCHED_PBX, local_pvt::lock, LOG_NOTICE, ast_channel::musicclass, musicclass, ast_var_t::name, local_pvt::owner, ast_channel::redirecting, ast_channel::tech_pvt, and ast_channel::varshead.
00541 { 00542 struct local_pvt *p = ast->tech_pvt; 00543 int res; 00544 struct ast_var_t *varptr = NULL, *new; 00545 size_t len, namelen; 00546 00547 if (!p) 00548 return -1; 00549 00550 /* If you value your sanity, please don't look at this code */ 00551 start_over: 00552 while (ast_channel_trylock(p->chan)) { 00553 ast_channel_unlock(p->owner); 00554 usleep(1); 00555 ast_channel_lock(p->owner); 00556 } 00557 00558 /* p->owner and p->chan are locked now. Let's get p locked */ 00559 if (ast_mutex_trylock(&p->lock)) { 00560 /* @#$&$@ */ 00561 ast_channel_unlock(p->chan); 00562 ast_channel_unlock(p->owner); 00563 usleep(1); 00564 ast_channel_lock(p->owner); 00565 goto start_over; 00566 } 00567 00568 /* 00569 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc 00570 * call, so it's done here instead. 00571 * 00572 * All these failure points just return -1. The individual strings will 00573 * be cleared when we destroy the channel. 00574 */ 00575 if (p->owner->cid.cid_rdnis) { 00576 if (!(p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis))) { 00577 ast_mutex_unlock(&p->lock); 00578 ast_channel_unlock(p->chan); 00579 return -1; 00580 } 00581 } 00582 ast_party_redirecting_copy(&p->chan->redirecting, &p->owner->redirecting); 00583 00584 if (p->owner->cid.cid_dnid) { 00585 if (!(p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid))) { 00586 ast_mutex_unlock(&p->lock); 00587 ast_channel_unlock(p->chan); 00588 return -1; 00589 } 00590 } 00591 p->chan->cid.cid_tns = p->owner->cid.cid_tns; 00592 00593 ast_connected_line_copy_to_caller(&p->chan->cid, &p->owner->connected); 00594 ast_connected_line_copy_from_caller(&p->chan->connected, &p->owner->cid); 00595 00596 ast_string_field_set(p->chan, language, p->owner->language); 00597 ast_string_field_set(p->chan, accountcode, p->owner->accountcode); 00598 ast_string_field_set(p->chan, musicclass, p->owner->musicclass); 00599 ast_cdr_update(p->chan); 00600 p->chan->cdrflags = p->owner->cdrflags; 00601 00602 if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) { 00603 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context); 00604 ast_mutex_unlock(&p->lock); 00605 ast_channel_unlock(p->chan); 00606 return -1; 00607 } 00608 00609 /* Make sure we inherit the ANSWERED_ELSEWHERE flag if it's set on the queue/dial call request in the dialplan */ 00610 if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) { 00611 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE); 00612 } 00613 00614 /* copy the channel variables from the incoming channel to the outgoing channel */ 00615 /* Note that due to certain assumptions, they MUST be in the same order */ 00616 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) { 00617 namelen = strlen(varptr->name); 00618 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; 00619 if ((new = ast_calloc(1, len))) { 00620 memcpy(new, varptr, len); 00621 new->value = &(new->name[0]) + namelen + 1; 00622 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries); 00623 } 00624 } 00625 ast_channel_datastore_inherit(p->owner, p->chan); 00626 00627 /* Start switch on sub channel */ 00628 if (!(res = ast_pbx_start(p->chan))) 00629 ast_set_flag(p, LOCAL_LAUNCHED_PBX); 00630 00631 ast_mutex_unlock(&p->lock); 00632 ast_channel_unlock(p->chan); 00633 return res; 00634 }
| static int local_devicestate | ( | void * | data | ) | [static] |
Adds devicestate to local channels.
Definition at line 125 of file chan_local.c.
References ast_debug, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, ast_exists_extension(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_strdupa, local_pvt::context, local_pvt::exten, LOG_WARNING, and local_pvt::owner.
00126 { 00127 char *exten = ast_strdupa(data); 00128 char *context = NULL, *opts = NULL; 00129 int res; 00130 struct local_pvt *lp; 00131 00132 if (!(context = strchr(exten, '@'))) { 00133 ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten); 00134 return AST_DEVICE_INVALID; 00135 } 00136 00137 *context++ = '\0'; 00138 00139 /* Strip options if they exist */ 00140 if ((opts = strchr(context, '/'))) 00141 *opts = '\0'; 00142 00143 ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context); 00144 00145 res = ast_exists_extension(NULL, context, exten, 1, NULL); 00146 if (!res) 00147 return AST_DEVICE_INVALID; 00148 00149 res = AST_DEVICE_NOT_INUSE; 00150 AST_LIST_LOCK(&locals); 00151 AST_LIST_TRAVERSE(&locals, lp, list) { 00152 if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) { 00153 res = AST_DEVICE_INUSE; 00154 break; 00155 } 00156 } 00157 AST_LIST_UNLOCK(&locals); 00158 00159 return res; 00160 }
| static int local_digit_begin | ( | struct ast_channel * | ast, | |
| char | digit | |||
| ) | [static] |
Definition at line 460 of file chan_local.c.
References AST_FRAME_DTMF_BEGIN, ast_mutex_lock(), ast_mutex_unlock(), IS_OUTBOUND, local_queue_frame(), local_pvt::lock, ast_frame::subclass, and ast_channel::tech_pvt.
00461 { 00462 struct local_pvt *p = ast->tech_pvt; 00463 int res = -1; 00464 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; 00465 int isoutbound; 00466 00467 if (!p) 00468 return -1; 00469 00470 ast_mutex_lock(&p->lock); 00471 isoutbound = IS_OUTBOUND(ast, p); 00472 f.subclass = digit; 00473 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00474 ast_mutex_unlock(&p->lock); 00475 00476 return res; 00477 }
| static int local_digit_end | ( | struct ast_channel * | ast, | |
| char | digit, | |||
| unsigned int | duration | |||
| ) | [static] |
Definition at line 479 of file chan_local.c.
References AST_FRAME_DTMF_END, ast_mutex_lock(), ast_mutex_unlock(), IS_OUTBOUND, ast_frame::len, local_queue_frame(), local_pvt::lock, ast_frame::subclass, and ast_channel::tech_pvt.
00480 { 00481 struct local_pvt *p = ast->tech_pvt; 00482 int res = -1; 00483 struct ast_frame f = { AST_FRAME_DTMF_END, }; 00484 int isoutbound; 00485 00486 if (!p) 00487 return -1; 00488 00489 ast_mutex_lock(&p->lock); 00490 isoutbound = IS_OUTBOUND(ast, p); 00491 f.subclass = digit; 00492 f.len = duration; 00493 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00494 ast_mutex_unlock(&p->lock); 00495 00496 return res; 00497 }
| static int local_fixup | ( | struct ast_channel * | oldchan, | |
| struct ast_channel * | newchan | |||
| ) | [static] |
Definition at line 375 of file chan_local.c.
References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), local_pvt::chan, local_pvt::lock, LOG_WARNING, local_pvt::owner, and ast_channel::tech_pvt.
00376 { 00377 struct local_pvt *p = newchan->tech_pvt; 00378 00379 if (!p) 00380 return -1; 00381 00382 ast_mutex_lock(&p->lock); 00383 00384 if ((p->owner != oldchan) && (p->chan != oldchan)) { 00385 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); 00386 ast_mutex_unlock(&p->lock); 00387 return -1; 00388 } 00389 if (p->owner == oldchan) 00390 p->owner = newchan; 00391 else 00392 p->chan = newchan; 00393 ast_mutex_unlock(&p->lock); 00394 return 0; 00395 }
| static int local_hangup | ( | struct ast_channel * | ast | ) | [static] |
Hangup a call through the local proxy channel.
Definition at line 637 of file chan_local.c.
References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_clear_flag, AST_CONTROL_HANGUP, ast_debug, AST_FLAG_ANSWERED_ELSEWHERE, AST_FRAME_CONTROL, ast_hangup(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_module_user_remove, ast_mutex_lock(), ast_mutex_unlock(), ast_queue_hangup(), ast_set_flag, ast_test_flag, local_pvt::chan, DEADLOCK_AVOIDANCE, ast_channel::hangupcause, IS_OUTBOUND, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, LOCAL_LAUNCHED_PBX, local_pvt_destroy(), local_queue_frame(), local_pvt::lock, local_pvt::owner, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), status, ast_channel::tech_pvt, local_pvt::u_chan, and local_pvt::u_owner.
00638 { 00639 struct local_pvt *p = ast->tech_pvt; 00640 int isoutbound; 00641 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP, .data.uint32 = ast->hangupcause }; 00642 struct ast_channel *ochan = NULL; 00643 int glaredetect = 0, res = 0; 00644 00645 if (!p) 00646 return -1; 00647 00648 ast_mutex_lock(&p->lock); 00649 00650 isoutbound = IS_OUTBOUND(ast, p); 00651 00652 if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) { 00653 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE); 00654 ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n"); 00655 } 00656 00657 if (isoutbound) { 00658 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); 00659 if ((status) && (p->owner)) { 00660 /* Deadlock avoidance */ 00661 while (p->owner && ast_channel_trylock(p->owner)) { 00662 ast_mutex_unlock(&p->lock); 00663 if (ast) { 00664 ast_channel_unlock(ast); 00665 } 00666 usleep(1); 00667 if (ast) { 00668 ast_channel_lock(ast); 00669 } 00670 ast_mutex_lock(&p->lock); 00671 } 00672 if (p->owner) { 00673 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); 00674 ast_channel_unlock(p->owner); 00675 } 00676 } 00677 p->chan = NULL; 00678 ast_clear_flag(p, LOCAL_LAUNCHED_PBX); 00679 ast_module_user_remove(p->u_chan); 00680 } else { 00681 p->owner = NULL; 00682 ast_module_user_remove(p->u_owner); 00683 while (p->chan && ast_channel_trylock(p->chan)) { 00684 DEADLOCK_AVOIDANCE(&p->lock); 00685 } 00686 if (p->chan) { 00687 ast_queue_hangup(p->chan); 00688 ast_channel_unlock(p->chan); 00689 } 00690 } 00691 00692 ast->tech_pvt = NULL; 00693 00694 if (!p->owner && !p->chan) { 00695 /* Okay, done with the private part now, too. */ 00696 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT); 00697 /* If we have a queue holding, don't actually destroy p yet, but 00698 let local_queue do it. */ 00699 if (glaredetect) 00700 ast_set_flag(p, LOCAL_CANCEL_QUEUE); 00701 /* Remove from list */ 00702 AST_LIST_LOCK(&locals); 00703 AST_LIST_REMOVE(&locals, p, list); 00704 AST_LIST_UNLOCK(&locals); 00705 ast_mutex_unlock(&p->lock); 00706 /* And destroy */ 00707 if (!glaredetect) { 00708 p = local_pvt_destroy(p); 00709 } 00710 return 0; 00711 } 00712 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) 00713 /* Need to actually hangup since there is no PBX */ 00714 ochan = p->chan; 00715 else 00716 res = local_queue_frame(p, isoutbound, &f, NULL, 1); 00717 if (!res) 00718 ast_mutex_unlock(&p->lock); 00719 if (ochan) 00720 ast_hangup(ochan); 00721 return 0; 00722 }
| static int local_indicate | ( | struct ast_channel * | ast, | |
| int | condition, | |||
| const void * | data, | |||
| size_t | datalen | |||
| ) | [static] |
Definition at line 397 of file chan_local.c.
References ast_connected_line_build_data(), AST_CONTROL_CONNECTED_LINE, AST_CONTROL_HOLD, AST_CONTROL_REDIRECTING, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_redirecting_build_data(), local_pvt::chan, ast_channel::connected, ast_frame::data, ast_frame::datalen, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, local_pvt::owner, ast_frame::ptr, ast_channel::redirecting, ast_frame::subclass, and ast_channel::tech_pvt.
00398 { 00399 struct local_pvt *p = ast->tech_pvt; 00400 int res = 0; 00401 struct ast_frame f = { AST_FRAME_CONTROL, }; 00402 int isoutbound; 00403 00404 if (!p) 00405 return -1; 00406 00407 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */ 00408 if (condition == AST_CONTROL_HOLD) { 00409 ast_moh_start(ast, data, NULL); 00410 } else if (condition == AST_CONTROL_UNHOLD) { 00411 ast_moh_stop(ast); 00412 } else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) { 00413 struct ast_channel *this_channel; 00414 struct ast_channel *the_other_channel; 00415 /* A connected line update frame may only contain a partial amount of data, such 00416 * as just a source, or just a ton, and not the full amount of information. However, 00417 * the collected information is all stored in the outgoing channel's connectedline 00418 * structure, so when receiving a connected line update on an outgoing local channel, 00419 * we need to transmit the collected connected line information instead of whatever 00420 * happens to be in this control frame. The same applies for redirecting information, which 00421 * is why it is handled here as well.*/ 00422 ast_mutex_lock(&p->lock); 00423 isoutbound = IS_OUTBOUND(ast, p); 00424 if (isoutbound) { 00425 this_channel = p->chan; 00426 the_other_channel = p->owner; 00427 } else { 00428 this_channel = p->owner; 00429 the_other_channel = p->chan; 00430 } 00431 if (the_other_channel) { 00432 unsigned char frame_data[1024]; 00433 if (condition == AST_CONTROL_CONNECTED_LINE) { 00434 f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected); 00435 } else { 00436 f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting); 00437 } 00438 f.subclass = condition; 00439 f.data.ptr = frame_data; 00440 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1))) { 00441 ast_mutex_unlock(&p->lock); 00442 } 00443 } else { 00444 ast_mutex_unlock(&p->lock); 00445 } 00446 } else { 00447 /* Queue up a frame representing the indication as a control frame */ 00448 ast_mutex_lock(&p->lock); 00449 isoutbound = IS_OUTBOUND(ast, p); 00450 f.subclass = condition; 00451 f.data.ptr = (void*)data; 00452 f.datalen = datalen; 00453 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1))) 00454 ast_mutex_unlock(&p->lock); 00455 } 00456 00457 return res; 00458 }
| static struct ast_channel* local_new | ( | struct local_pvt * | p, | |
| int | state, | |||
| const char * | linkedid | |||
| ) | [static, read] |
Start new local channel.
Definition at line 786 of file chan_local.c.
References ast_channel::accountcode, ast_channel::amaflags, ast_best_codec(), ast_channel_alloc, ast_channel_release(), ast_copy_string(), ast_jb_configure(), ast_log(), ast_module_user_add, ast_random(), AST_STATE_RING, local_pvt::chan, ast_channel::context, local_pvt::context, ast_channel::exten, local_pvt::exten, local_pvt::jb_conf, LOG_WARNING, ast_channel::nativeformats, local_pvt::owner, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, local_pvt::reqformat, ast_channel::tech, ast_channel::tech_pvt, local_pvt::u_chan, local_pvt::u_owner, and ast_channel::writeformat.
Referenced by local_request().
00787 { 00788 struct ast_channel *tmp = NULL, *tmp2 = NULL; 00789 int randnum = ast_random() & 0xffff, fmt = 0; 00790 const char *t; 00791 int ama; 00792 00793 /* Allocate two new Asterisk channels */ 00794 /* safe accountcode */ 00795 if (p->owner && p->owner->accountcode) 00796 t = p->owner->accountcode; 00797 else 00798 t = ""; 00799 00800 if (p->owner) 00801 ama = p->owner->amaflags; 00802 else 00803 ama = 0; 00804 if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, linkedid, ama, "Local/%s@%s-%04x;1", p->exten, p->context, randnum)) 00805 || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, linkedid, ama, "Local/%s@%s-%04x;2", p->exten, p->context, randnum))) { 00806 if (tmp) { 00807 tmp = ast_channel_release(tmp); 00808 } 00809 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); 00810 return NULL; 00811 } 00812 00813 tmp2->tech = tmp->tech = &local_tech; 00814 00815 tmp->nativeformats = p->reqformat; 00816 tmp2->nativeformats = p->reqformat; 00817 00818 /* Determine our read/write format and set it on each channel */ 00819 fmt = ast_best_codec(p->reqformat); 00820 tmp->writeformat = fmt; 00821 tmp2->writeformat = fmt; 00822 tmp->rawwriteformat = fmt; 00823 tmp2->rawwriteformat = fmt; 00824 tmp->readformat = fmt; 00825 tmp2->readformat = fmt; 00826 tmp->rawreadformat = fmt; 00827 tmp2->rawreadformat = fmt; 00828 00829 tmp->tech_pvt = p; 00830 tmp2->tech_pvt = p; 00831 00832 p->owner = tmp; 00833 p->chan = tmp2; 00834 p->u_owner = ast_module_user_add(p->owner); 00835 p->u_chan = ast_module_user_add(p->chan); 00836 00837 ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); 00838 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); 00839 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); 00840 tmp->priority = 1; 00841 tmp2->priority = 1; 00842 00843 ast_jb_configure(tmp, &p->jb_conf); 00844 00845 return tmp; 00846 }
Definition at line 165 of file chan_local.c.
References ast_free, ast_mutex_destroy(), and local_pvt::lock.
Referenced by local_alloc(), local_hangup(), local_queue_frame(), and local_request().
00166 { 00167 ast_mutex_destroy(&pvt->lock); 00168 ast_free(pvt); 00169 return NULL; 00170 }
| static int local_queue_frame | ( | struct local_pvt * | p, | |
| int | isoutbound, | |||
| struct ast_frame * | f, | |||
| struct ast_channel * | us, | |||
| int | us_locked | |||
| ) | [static] |
Definition at line 197 of file chan_local.c.
References ast_channel_trylock, ast_channel_unlock, ast_clear_flag, ast_mutex_lock(), ast_mutex_trylock(), ast_mutex_unlock(), ast_queue_frame(), ast_set_flag, ast_test_flag, local_pvt::chan, CHANNEL_DEADLOCK_AVOIDANCE, ast_channel::generator, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, local_pvt_destroy(), local_pvt::lock, and local_pvt::owner.
Referenced by local_answer(), local_digit_begin(), local_digit_end(), local_hangup(), local_indicate(), local_sendhtml(), local_sendtext(), and local_write().
00199 { 00200 struct ast_channel *other = NULL; 00201 00202 /* Recalculate outbound channel */ 00203 other = isoutbound ? p->owner : p->chan; 00204 00205 if (!other) { 00206 return 0; 00207 } 00208 00209 /* do not queue frame if generator is on both local channels */ 00210 if (us && us->generator && other->generator) { 00211 return 0; 00212 } 00213 00214 /* Set glare detection */ 00215 ast_set_flag(p, LOCAL_GLARE_DETECT); 00216 00217 /* Ensure that we have both channels locked */ 00218 while (other && ast_channel_trylock(other)) { 00219 ast_mutex_unlock(&p->lock); 00220 if (us && us_locked) { 00221 do { 00222 CHANNEL_DEADLOCK_AVOIDANCE(us); 00223 } while (ast_mutex_trylock(&p->lock)); 00224 } else { 00225 usleep(1); 00226 ast_mutex_lock(&p->lock); 00227 } 00228 other = isoutbound ? p->owner : p->chan; 00229 } 00230 00231 /* Since glare detection only occurs within this function, and because 00232 * a pvt flag cannot be set without having the pvt lock, this is the only 00233 * location where we could detect a cancelling of the queue. */ 00234 if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) { 00235 /* We had a glare on the hangup. Forget all this business, 00236 return and destroy p. */ 00237 ast_mutex_unlock(&p->lock); 00238 p = local_pvt_destroy(p); 00239 if (other) { 00240 ast_channel_unlock(other); 00241 } 00242 return -1; 00243 } 00244 00245 if (other) { 00246 ast_queue_frame(other, f); 00247 ast_channel_unlock(other); 00248 } 00249 00250 ast_clear_flag(p, LOCAL_GLARE_DETECT); 00251 00252 return 0; 00253 }
| static struct ast_frame * local_read | ( | struct ast_channel * | ast | ) | [static, read] |
Definition at line 345 of file chan_local.c.
References ast_null_frame.
00346 { 00347 return &ast_null_frame; 00348 }
| static struct ast_channel * local_request | ( | const char * | type, | |
| int | format, | |||
| const struct ast_channel * | requestor, | |||
| void * | data, | |||
| int * | cause | |||
| ) | [static, read] |
Part of PBX interface.
Definition at line 849 of file chan_local.c.
References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, AST_STATE_DOWN, local_pvt::chan, ast_channel::linkedid, local_alloc(), local_new(), and local_pvt_destroy().
00850 { 00851 struct local_pvt *p = NULL; 00852 struct ast_channel *chan = NULL; 00853 00854 /* Allocate a new private structure and then Asterisk channel */ 00855 if ((p = local_alloc(data, format))) { 00856 if (!(chan = local_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL))) { 00857 AST_LIST_LOCK(&locals); 00858 AST_LIST_REMOVE(&locals, p, list); 00859 AST_LIST_UNLOCK(&locals); 00860 p = local_pvt_destroy(p); 00861 } 00862 } 00863 00864 return chan; 00865 }
| static int local_sendhtml | ( | struct ast_channel * | ast, | |
| int | subclass, | |||
| const char * | data, | |||
| int | datalen | |||
| ) | [static] |
Definition at line 518 of file chan_local.c.
References AST_FRAME_HTML, ast_mutex_lock(), ast_mutex_unlock(), ast_frame::data, ast_frame::datalen, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, ast_frame::ptr, ast_frame::subclass, and ast_channel::tech_pvt.
00519 { 00520 struct local_pvt *p = ast->tech_pvt; 00521 int res = -1; 00522 struct ast_frame f = { AST_FRAME_HTML, }; 00523 int isoutbound; 00524 00525 if (!p) 00526 return -1; 00527 00528 ast_mutex_lock(&p->lock); 00529 isoutbound = IS_OUTBOUND(ast, p); 00530 f.subclass = subclass; 00531 f.data.ptr = (char *)data; 00532 f.datalen = datalen; 00533 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00534 ast_mutex_unlock(&p->lock); 00535 return res; 00536 }
| static int local_sendtext | ( | struct ast_channel * | ast, | |
| const char * | text | |||
| ) | [static] |
Definition at line 499 of file chan_local.c.
References AST_FRAME_TEXT, ast_mutex_lock(), ast_mutex_unlock(), ast_frame::data, ast_frame::datalen, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, ast_frame::ptr, and ast_channel::tech_pvt.
00500 { 00501 struct local_pvt *p = ast->tech_pvt; 00502 int res = -1; 00503 struct ast_frame f = { AST_FRAME_TEXT, }; 00504 int isoutbound; 00505 00506 if (!p) 00507 return -1; 00508 00509 ast_mutex_lock(&p->lock); 00510 isoutbound = IS_OUTBOUND(ast, p); 00511 f.data.ptr = (char *) text; 00512 f.datalen = strlen(text) + 1; 00513 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00514 ast_mutex_unlock(&p->lock); 00515 return res; 00516 }
| static int local_write | ( | struct ast_channel * | ast, | |
| struct ast_frame * | f | |||
| ) | [static] |
Definition at line 350 of file chan_local.c.
References ast_debug, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_mutex_lock(), ast_mutex_unlock(), ast_test_flag, check_bridge(), ast_frame::frametype, IS_OUTBOUND, LOCAL_ALREADY_MASQED, local_queue_frame(), local_pvt::lock, ast_channel::name, and ast_channel::tech_pvt.
00351 { 00352 struct local_pvt *p = ast->tech_pvt; 00353 int res = -1; 00354 int isoutbound; 00355 00356 if (!p) 00357 return -1; 00358 00359 /* Just queue for delivery to the other side */ 00360 ast_mutex_lock(&p->lock); 00361 isoutbound = IS_OUTBOUND(ast, p); 00362 if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) 00363 check_bridge(p, isoutbound); 00364 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) 00365 res = local_queue_frame(p, isoutbound, f, ast, 1); 00366 else { 00367 ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name); 00368 res = 0; 00369 } 00370 if (!res) 00371 ast_mutex_unlock(&p->lock); 00372 return res; 00373 }
| static char* locals_show | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
CLI command "local show channels".
Definition at line 868 of file chan_local.c.
References ast_cli_args::argc, ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, local_pvt::context, local_pvt::exten, ast_cli_args::fd, local_pvt::lock, ast_channel::name, local_pvt::owner, and ast_cli_entry::usage.
00869 { 00870 struct local_pvt *p = NULL; 00871 00872 switch (cmd) { 00873 case CLI_INIT: 00874 e->command = "local show channels"; 00875 e->usage = 00876 "Usage: local show channels\n" 00877 " Provides summary information on active local proxy channels.\n"; 00878 return NULL; 00879 case CLI_GENERATE: 00880 return NULL; 00881 } 00882 00883 if (a->argc != 3) 00884 return CLI_SHOWUSAGE; 00885 00886 AST_LIST_LOCK(&locals); 00887 if (!AST_LIST_EMPTY(&locals)) { 00888 AST_LIST_TRAVERSE(&locals, p, list) { 00889 ast_mutex_lock(&p->lock); 00890 ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context); 00891 ast_mutex_unlock(&p->lock); 00892 } 00893 } else 00894 ast_cli(a->fd, "No local channels in use\n"); 00895 AST_LIST_UNLOCK(&locals); 00896 00897 return CLI_SUCCESS; 00898 }
| static int unload_module | ( | void | ) | [static] |
Unload the local proxy channel from Asterisk.
Definition at line 917 of file chan_local.c.
References ast_channel_unregister(), ast_cli_unregister_multiple(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, cli_local, LOG_WARNING, and local_pvt::owner.
00918 { 00919 struct local_pvt *p = NULL; 00920 00921 /* First, take us out of the channel loop */ 00922 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00923 ast_channel_unregister(&local_tech); 00924 if (!AST_LIST_LOCK(&locals)) { 00925 /* Hangup all interfaces if they have an owner */ 00926 AST_LIST_TRAVERSE(&locals, p, list) { 00927 if (p->owner) 00928 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 00929 } 00930 AST_LIST_UNLOCK(&locals); 00931 } else { 00932 ast_log(LOG_WARNING, "Unable to lock the monitor\n"); 00933 return -1; 00934 } 00935 return 0; 00936 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Local Proxy Channel (Note: used internally by other modules)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static] |
Definition at line 938 of file chan_local.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 938 of file chan_local.c.
struct ast_cli_entry cli_local[] [static] |
Initial value:
{
AST_CLI_DEFINE(locals_show, "List status of local channels"),
}
Definition at line 900 of file chan_local.c.
Referenced by load_module(), and unload_module().
struct ast_jb_conf g_jb_conf [static] |
Definition at line 56 of file chan_local.c.
struct ast_channel_tech local_tech [static] |
Definition at line 79 of file chan_local.c.
const char tdesc[] = "Local Proxy Channel Driver" [static] |
Definition at line 52 of file chan_local.c.
1.5.6