#include "asterisk.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/signal.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/rtp.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 |
Defines | |
#define | IS_OUTBOUND(a, b) (a == b->chan ? 1 : 0) |
#define | LOCAL_ALREADY_MASQED (1 << 2) |
#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 | AST_LIST_HEAD_STATIC (locals, local_pvt) |
AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Local Proxy Channel (Note: used internally by other modules)") | |
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 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) |
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, 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 int | locals_show (int fd, int argc, char **argv) |
CLI command "local show channels". | |
static int | unload_module (void) |
Unload the local proxy channel from Asterisk. | |
Variables | |
static struct ast_cli_entry | cli_local [] |
static struct ast_channel_tech | local_tech |
static char | show_locals_usage [] |
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 67 of file chan_local.c.
#define LOCAL_ALREADY_MASQED (1 << 2) |
Already masqueraded
Definition at line 120 of file chan_local.c.
Referenced by check_bridge(), and local_write().
#define LOCAL_CANCEL_QUEUE (1 << 1) |
Cancel queue
Definition at line 119 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 118 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 121 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 122 of file chan_local.c.
Referenced by check_bridge(), and local_alloc().
static AST_LIST_HEAD_STATIC | ( | locals | , | |
local_pvt | ||||
) | [static] |
AST_MODULE_INFO_STANDARD | ( | ASTERISK_GPL_KEY | , | |
"Local Proxy Channel (Note: used internally by other modules)" | ||||
) |
static void check_bridge | ( | struct local_pvt * | p, | |
int | isoutbound | |||
) | [static] |
Definition at line 231 of file chan_local.c.
References ast_channel::_bridge, ast_channel::_softhangup, ast_bridged_channel(), ast_channel_masquerade(), AST_LIST_EMPTY, ast_mutex_trylock(), ast_mutex_unlock(), ast_set_flag, ast_test_flag, local_pvt::chan, LOCAL_ALREADY_MASQED, LOCAL_NO_OPTIMIZATION, ast_channel::lock, ast_channel::monitor, and local_pvt::owner.
Referenced by local_write().
00232 { 00233 struct ast_channel_monitor *tmp; 00234 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))) 00235 return; 00236 00237 /* only do the masquerade if we are being called on the outbound channel, 00238 if it has been bridged to another channel and if there are no pending 00239 frames on the owner channel (because they would be transferred to the 00240 outbound channel during the masquerade) 00241 */ 00242 if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) { 00243 /* Masquerade bridged channel into owner */ 00244 /* Lock everything we need, one by one, and give up if 00245 we can't get everything. Remember, we'll get another 00246 chance in just a little bit */ 00247 if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) { 00248 if (!p->chan->_bridge->_softhangup) { 00249 if (!ast_mutex_trylock(&p->owner->lock)) { 00250 if (!p->owner->_softhangup) { 00251 if(p->owner->monitor && !p->chan->_bridge->monitor) { 00252 /* If a local channel is being monitored, we don't want a masquerade 00253 * to cause the monitor to go away. Since the masquerade swaps the monitors, 00254 * pre-swapping the monitors before the masquerade will ensure that the monitor 00255 * ends up where it is expected. 00256 */ 00257 tmp = p->owner->monitor; 00258 p->owner->monitor = p->chan->_bridge->monitor; 00259 p->chan->_bridge->monitor = tmp; 00260 } 00261 ast_channel_masquerade(p->owner, p->chan->_bridge); 00262 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00263 } 00264 ast_mutex_unlock(&p->owner->lock); 00265 } 00266 ast_mutex_unlock(&(p->chan->_bridge)->lock); 00267 } 00268 } 00269 /* We only allow masquerading in one 'direction'... it's important to preserve the state 00270 (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan) 00271 when the local channels go away. 00272 */ 00273 #if 0 00274 } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) { 00275 /* Masquerade bridged channel into chan */ 00276 if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) { 00277 if (!p->owner->_bridge->_softhangup) { 00278 if (!ast_mutex_trylock(&p->chan->lock)) { 00279 if (!p->chan->_softhangup) { 00280 ast_channel_masquerade(p->chan, p->owner->_bridge); 00281 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00282 } 00283 ast_mutex_unlock(&p->chan->lock); 00284 } 00285 } 00286 ast_mutex_unlock(&(p->owner->_bridge)->lock); 00287 } 00288 #endif 00289 } 00290 }
static int load_module | ( | void | ) | [static] |
Load module into PBX, register channel.
Definition at line 733 of file chan_local.c.
References ast_channel_register(), ast_cli_register_multiple(), ast_log(), cli_local, and LOG_ERROR.
00734 { 00735 /* Make sure we can register our channel type */ 00736 if (ast_channel_register(&local_tech)) { 00737 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); 00738 return -1; 00739 } 00740 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00741 return 0; 00742 }
static struct local_pvt* local_alloc | ( | const char * | data, | |
int | format | |||
) | [static, read] |
Create a call structure.
Definition at line 579 of file chan_local.c.
References ast_calloc, ast_exists_extension(), AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_mutex_init(), ast_set_flag, local_pvt::context, local_pvt::exten, LOCAL_NO_OPTIMIZATION, local_pvt_destroy(), locals, local_pvt::lock, LOG_NOTICE, and local_pvt::reqformat.
Referenced by local_request().
00580 { 00581 struct local_pvt *tmp = NULL; 00582 char *c = NULL, *opts = NULL; 00583 00584 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) 00585 return NULL; 00586 00587 /* Initialize private structure information */ 00588 ast_mutex_init(&tmp->lock); 00589 ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); 00590 00591 /* Look for options */ 00592 if ((opts = strchr(tmp->exten, '/'))) { 00593 *opts++ = '\0'; 00594 if (strchr(opts, 'n')) 00595 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); 00596 } 00597 00598 /* Look for a context */ 00599 if ((c = strchr(tmp->exten, '@'))) 00600 *c++ = '\0'; 00601 00602 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context)); 00603 00604 tmp->reqformat = format; 00605 00606 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { 00607 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); 00608 tmp = local_pvt_destroy(tmp); 00609 } else { 00610 /* Add to list */ 00611 AST_LIST_LOCK(&locals); 00612 AST_LIST_INSERT_HEAD(&locals, tmp, list); 00613 AST_LIST_UNLOCK(&locals); 00614 } 00615 00616 return tmp; 00617 }
static int local_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 209 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.
00210 { 00211 struct local_pvt *p = ast->tech_pvt; 00212 int isoutbound; 00213 int res = -1; 00214 00215 if (!p) 00216 return -1; 00217 00218 ast_mutex_lock(&p->lock); 00219 isoutbound = IS_OUTBOUND(ast, p); 00220 if (isoutbound) { 00221 /* Pass along answer since somebody answered us */ 00222 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00223 res = local_queue_frame(p, isoutbound, &answer, ast, 1); 00224 } else 00225 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n"); 00226 if (!res) 00227 ast_mutex_unlock(&p->lock); 00228 return res; 00229 }
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 454 of file chan_local.c.
References accountcode, ast_calloc, ast_cdr_update(), ast_channel_datastore_inherit(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_mutex_lock(), ast_mutex_unlock(), ast_pbx_start(), ast_set_flag, ast_strdup, ast_string_field_set, ast_channel::cdrflags, local_pvt::chan, ast_channel::cid, ast_callerid::cid_ani, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_pres, ast_callerid::cid_rdnis, language, len, LOCAL_LAUNCHED_PBX, local_pvt::lock, ast_var_t::name, local_pvt::owner, ast_channel::tech_pvt, and ast_channel::varshead.
00455 { 00456 struct local_pvt *p = ast->tech_pvt; 00457 int res; 00458 struct ast_var_t *varptr = NULL, *new; 00459 size_t len, namelen; 00460 00461 if (!p) 00462 return -1; 00463 00464 ast_mutex_lock(&p->lock); 00465 00466 /* 00467 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc 00468 * call, so it's done here instead. 00469 */ 00470 p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num); 00471 p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name); 00472 p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis); 00473 p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani); 00474 p->chan->cid.cid_pres = p->owner->cid.cid_pres; 00475 ast_string_field_set(p->chan, language, p->owner->language); 00476 ast_string_field_set(p->chan, accountcode, p->owner->accountcode); 00477 ast_cdr_update(p->chan); 00478 p->chan->cdrflags = p->owner->cdrflags; 00479 00480 /* copy the channel variables from the incoming channel to the outgoing channel */ 00481 /* Note that due to certain assumptions, they MUST be in the same order */ 00482 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) { 00483 namelen = strlen(varptr->name); 00484 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; 00485 if ((new = ast_calloc(1, len))) { 00486 memcpy(new, varptr, len); 00487 new->value = &(new->name[0]) + namelen + 1; 00488 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries); 00489 } 00490 } 00491 ast_channel_datastore_inherit(p->owner, p->chan); 00492 00493 /* Start switch on sub channel */ 00494 if (!(res = ast_pbx_start(p->chan))) 00495 ast_set_flag(p, LOCAL_LAUNCHED_PBX); 00496 00497 ast_mutex_unlock(&p->lock); 00498 return res; 00499 }
static int local_devicestate | ( | void * | data | ) | [static] |
Adds devicestate to local channels.
Definition at line 127 of file chan_local.c.
References AST_DEVICE_INVALID, AST_DEVICE_UNKNOWN, ast_exists_extension(), ast_log(), ast_strdupa, local_pvt::context, local_pvt::exten, LOG_DEBUG, LOG_WARNING, and option_debug.
00128 { 00129 char *exten = ast_strdupa(data); 00130 char *context = NULL, *opts = NULL; 00131 int res; 00132 00133 if (!(context = strchr(exten, '@'))) { 00134 ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten); 00135 return AST_DEVICE_INVALID; 00136 } 00137 00138 *context++ = '\0'; 00139 00140 /* Strip options if they exist */ 00141 if ((opts = strchr(context, '/'))) 00142 *opts = '\0'; 00143 00144 if (option_debug > 2) 00145 ast_log(LOG_DEBUG, "Checking if extension %s@%s exists (devicestate)\n", exten, context); 00146 res = ast_exists_extension(NULL, context, exten, 1, NULL); 00147 if (!res) 00148 return AST_DEVICE_INVALID; 00149 else 00150 return AST_DEVICE_UNKNOWN; 00151 }
static int local_digit_begin | ( | struct ast_channel * | ast, | |
char | digit | |||
) | [static] |
Definition at line 374 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.
00375 { 00376 struct local_pvt *p = ast->tech_pvt; 00377 int res = -1; 00378 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; 00379 int isoutbound; 00380 00381 if (!p) 00382 return -1; 00383 00384 ast_mutex_lock(&p->lock); 00385 isoutbound = IS_OUTBOUND(ast, p); 00386 f.subclass = digit; 00387 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00388 ast_mutex_unlock(&p->lock); 00389 00390 return res; 00391 }
static int local_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 393 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.
00394 { 00395 struct local_pvt *p = ast->tech_pvt; 00396 int res = -1; 00397 struct ast_frame f = { AST_FRAME_DTMF_END, }; 00398 int isoutbound; 00399 00400 if (!p) 00401 return -1; 00402 00403 ast_mutex_lock(&p->lock); 00404 isoutbound = IS_OUTBOUND(ast, p); 00405 f.subclass = digit; 00406 f.len = duration; 00407 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00408 ast_mutex_unlock(&p->lock); 00409 00410 return res; 00411 }
static int local_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 323 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.
00324 { 00325 struct local_pvt *p = newchan->tech_pvt; 00326 00327 if (!p) 00328 return -1; 00329 00330 ast_mutex_lock(&p->lock); 00331 00332 if ((p->owner != oldchan) && (p->chan != oldchan)) { 00333 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); 00334 ast_mutex_unlock(&p->lock); 00335 return -1; 00336 } 00337 if (p->owner == oldchan) 00338 p->owner = newchan; 00339 else 00340 p->chan = newchan; 00341 ast_mutex_unlock(&p->lock); 00342 return 0; 00343 }
static int local_hangup | ( | struct ast_channel * | ast | ) | [static] |
Hangup a call through the local proxy channel.
Definition at line 502 of file chan_local.c.
References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_clear_flag, AST_CONTROL_HANGUP, 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_set_flag, ast_test_flag, local_pvt::chan, IS_OUTBOUND, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, LOCAL_LAUNCHED_PBX, local_pvt_destroy(), local_queue_frame(), locals, local_pvt::lock, local_pvt::owner, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), ast_channel::tech_pvt, local_pvt::u_chan, and local_pvt::u_owner.
00503 { 00504 struct local_pvt *p = ast->tech_pvt; 00505 int isoutbound; 00506 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP }; 00507 struct ast_channel *ochan = NULL; 00508 int glaredetect = 0, res = 0; 00509 00510 if (!p) 00511 return -1; 00512 00513 ast_mutex_lock(&p->lock); 00514 isoutbound = IS_OUTBOUND(ast, p); 00515 if (isoutbound) { 00516 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); 00517 if ((status) && (p->owner)) { 00518 /* Deadlock avoidance */ 00519 while (p->owner && ast_channel_trylock(p->owner)) { 00520 ast_mutex_unlock(&p->lock); 00521 if (ast) { 00522 ast_channel_unlock(ast); 00523 } 00524 usleep(1); 00525 if (ast) { 00526 ast_channel_lock(ast); 00527 } 00528 ast_mutex_lock(&p->lock); 00529 } 00530 if (p->owner) { 00531 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); 00532 ast_channel_unlock(p->owner); 00533 } 00534 } 00535 p->chan = NULL; 00536 ast_clear_flag(p, LOCAL_LAUNCHED_PBX); 00537 ast_module_user_remove(p->u_chan); 00538 } else { 00539 p->owner = NULL; 00540 ast_module_user_remove(p->u_owner); 00541 } 00542 00543 ast->tech_pvt = NULL; 00544 00545 if (!p->owner && !p->chan) { 00546 /* Okay, done with the private part now, too. */ 00547 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT); 00548 /* If we have a queue holding, don't actually destroy p yet, but 00549 let local_queue do it. */ 00550 if (glaredetect) 00551 ast_set_flag(p, LOCAL_CANCEL_QUEUE); 00552 ast_mutex_unlock(&p->lock); 00553 /* Remove from list */ 00554 AST_LIST_LOCK(&locals); 00555 AST_LIST_REMOVE(&locals, p, list); 00556 AST_LIST_UNLOCK(&locals); 00557 /* Grab / release lock just in case */ 00558 ast_mutex_lock(&p->lock); 00559 ast_mutex_unlock(&p->lock); 00560 /* And destroy */ 00561 if (!glaredetect) { 00562 p = local_pvt_destroy(p); 00563 } 00564 return 0; 00565 } 00566 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) 00567 /* Need to actually hangup since there is no PBX */ 00568 ochan = p->chan; 00569 else 00570 res = local_queue_frame(p, isoutbound, &f, NULL, 1); 00571 if (!res) 00572 ast_mutex_unlock(&p->lock); 00573 if (ochan) 00574 ast_hangup(ochan); 00575 return 0; 00576 }
static int local_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 345 of file chan_local.c.
References AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_FRAME_CONTROL, ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_frame::data, ast_frame::datalen, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, ast_frame::subclass, and ast_channel::tech_pvt.
00346 { 00347 struct local_pvt *p = ast->tech_pvt; 00348 int res = 0; 00349 struct ast_frame f = { AST_FRAME_CONTROL, }; 00350 int isoutbound; 00351 00352 if (!p) 00353 return -1; 00354 00355 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */ 00356 if (condition == AST_CONTROL_HOLD) { 00357 ast_moh_start(ast, data, NULL); 00358 } else if (condition == AST_CONTROL_UNHOLD) { 00359 ast_moh_stop(ast); 00360 } else { 00361 /* Queue up a frame representing the indication as a control frame */ 00362 ast_mutex_lock(&p->lock); 00363 isoutbound = IS_OUTBOUND(ast, p); 00364 f.subclass = condition; 00365 f.data = (void*)data; 00366 f.datalen = datalen; 00367 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1))) 00368 ast_mutex_unlock(&p->lock); 00369 } 00370 00371 return res; 00372 }
static struct ast_channel* local_new | ( | struct local_pvt * | p, | |
int | state | |||
) | [static, read] |
Start new local channel.
Definition at line 620 of file chan_local.c.
References ast_channel::amaflags, ast_best_codec(), ast_channel_alloc(), ast_channel_free(), 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, fmt, LOG_WARNING, ast_channel::nativeformats, local_pvt::owner, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, local_pvt::reqformat, t, ast_channel::tech, ast_channel::tech_pvt, local_pvt::u_chan, local_pvt::u_owner, and ast_channel::writeformat.
Referenced by local_request().
00621 { 00622 struct ast_channel *tmp = NULL, *tmp2 = NULL; 00623 int randnum = ast_random() & 0xffff, fmt = 0; 00624 const char *t; 00625 int ama; 00626 00627 /* Allocate two new Asterisk channels */ 00628 /* safe accountcode */ 00629 if (p->owner && p->owner->accountcode) 00630 t = p->owner->accountcode; 00631 else 00632 t = ""; 00633 00634 if (p->owner) 00635 ama = p->owner->amaflags; 00636 else 00637 ama = 0; 00638 if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x,1", p->exten, p->context, randnum)) 00639 || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x,2", p->exten, p->context, randnum))) { 00640 if (tmp) 00641 ast_channel_free(tmp); 00642 if (tmp2) 00643 ast_channel_free(tmp2); 00644 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); 00645 return NULL; 00646 } 00647 00648 tmp2->tech = tmp->tech = &local_tech; 00649 00650 tmp->nativeformats = p->reqformat; 00651 tmp2->nativeformats = p->reqformat; 00652 00653 /* Determine our read/write format and set it on each channel */ 00654 fmt = ast_best_codec(p->reqformat); 00655 tmp->writeformat = fmt; 00656 tmp2->writeformat = fmt; 00657 tmp->rawwriteformat = fmt; 00658 tmp2->rawwriteformat = fmt; 00659 tmp->readformat = fmt; 00660 tmp2->readformat = fmt; 00661 tmp->rawreadformat = fmt; 00662 tmp2->rawreadformat = fmt; 00663 00664 tmp->tech_pvt = p; 00665 tmp2->tech_pvt = p; 00666 00667 p->owner = tmp; 00668 p->chan = tmp2; 00669 p->u_owner = ast_module_user_add(p->owner); 00670 p->u_chan = ast_module_user_add(p->chan); 00671 00672 ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); 00673 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); 00674 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); 00675 tmp->priority = 1; 00676 tmp2->priority = 1; 00677 00678 return tmp; 00679 }
Definition at line 156 of file chan_local.c.
References ast_mutex_destroy(), free, and local_pvt::lock.
Referenced by local_alloc(), local_hangup(), local_queue_frame(), and local_request().
00157 { 00158 ast_mutex_destroy(&pvt->lock); 00159 free(pvt); 00160 return NULL; 00161 }
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 163 of file chan_local.c.
References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_clear_flag, ast_mutex_lock(), ast_mutex_unlock(), ast_queue_frame(), ast_set_flag, ast_test_flag, local_pvt::chan, 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().
00165 { 00166 struct ast_channel *other = NULL; 00167 00168 /* Recalculate outbound channel */ 00169 other = isoutbound ? p->owner : p->chan; 00170 00171 /* Set glare detection */ 00172 ast_set_flag(p, LOCAL_GLARE_DETECT); 00173 if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) { 00174 /* We had a glare on the hangup. Forget all this business, 00175 return and destroy p. */ 00176 ast_mutex_unlock(&p->lock); 00177 p = local_pvt_destroy(p); 00178 return -1; 00179 } 00180 if (!other) { 00181 ast_clear_flag(p, LOCAL_GLARE_DETECT); 00182 return 0; 00183 } 00184 00185 /* Ensure that we have both channels locked */ 00186 while (other && ast_channel_trylock(other)) { 00187 ast_mutex_unlock(&p->lock); 00188 if (us && us_locked) { 00189 ast_channel_unlock(us); 00190 } 00191 usleep(1); 00192 if (us && us_locked) { 00193 ast_channel_lock(us); 00194 } 00195 ast_mutex_lock(&p->lock); 00196 other = isoutbound ? p->owner : p->chan; 00197 } 00198 00199 if (other) { 00200 ast_queue_frame(other, f); 00201 ast_channel_unlock(other); 00202 } 00203 00204 ast_clear_flag(p, LOCAL_GLARE_DETECT); 00205 00206 return 0; 00207 }
static struct ast_frame * local_read | ( | struct ast_channel * | ast | ) | [static, read] |
Definition at line 292 of file chan_local.c.
References ast_null_frame.
00293 { 00294 return &ast_null_frame; 00295 }
static struct ast_channel * local_request | ( | const char * | type, | |
int | format, | |||
void * | data, | |||
int * | cause | |||
) | [static, read] |
Part of PBX interface.
Definition at line 682 of file chan_local.c.
References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, AST_STATE_DOWN, local_pvt::chan, local_alloc(), local_new(), local_pvt_destroy(), and locals.
00683 { 00684 struct local_pvt *p = NULL; 00685 struct ast_channel *chan = NULL; 00686 00687 /* Allocate a new private structure and then Asterisk channel */ 00688 if ((p = local_alloc(data, format))) { 00689 if (!(chan = local_new(p, AST_STATE_DOWN))) { 00690 AST_LIST_LOCK(&locals); 00691 AST_LIST_REMOVE(&locals, p, list); 00692 AST_LIST_UNLOCK(&locals); 00693 p = local_pvt_destroy(p); 00694 } 00695 } 00696 00697 return chan; 00698 }
static int local_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 432 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::subclass, and ast_channel::tech_pvt.
00433 { 00434 struct local_pvt *p = ast->tech_pvt; 00435 int res = -1; 00436 struct ast_frame f = { AST_FRAME_HTML, }; 00437 int isoutbound; 00438 00439 if (!p) 00440 return -1; 00441 00442 ast_mutex_lock(&p->lock); 00443 isoutbound = IS_OUTBOUND(ast, p); 00444 f.subclass = subclass; 00445 f.data = (char *)data; 00446 f.datalen = datalen; 00447 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00448 ast_mutex_unlock(&p->lock); 00449 return res; 00450 }
static int local_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 413 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, and ast_channel::tech_pvt.
00414 { 00415 struct local_pvt *p = ast->tech_pvt; 00416 int res = -1; 00417 struct ast_frame f = { AST_FRAME_TEXT, }; 00418 int isoutbound; 00419 00420 if (!p) 00421 return -1; 00422 00423 ast_mutex_lock(&p->lock); 00424 isoutbound = IS_OUTBOUND(ast, p); 00425 f.data = (char *) text; 00426 f.datalen = strlen(text) + 1; 00427 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00428 ast_mutex_unlock(&p->lock); 00429 return res; 00430 }
static int local_write | ( | struct ast_channel * | ast, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 297 of file chan_local.c.
References AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_log(), 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, LOG_DEBUG, option_debug, and ast_channel::tech_pvt.
00298 { 00299 struct local_pvt *p = ast->tech_pvt; 00300 int res = -1; 00301 int isoutbound; 00302 00303 if (!p) 00304 return -1; 00305 00306 /* Just queue for delivery to the other side */ 00307 ast_mutex_lock(&p->lock); 00308 isoutbound = IS_OUTBOUND(ast, p); 00309 if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) 00310 check_bridge(p, isoutbound); 00311 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) 00312 res = local_queue_frame(p, isoutbound, f, ast, 1); 00313 else { 00314 if (option_debug) 00315 ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name); 00316 res = 0; 00317 } 00318 if (!res) 00319 ast_mutex_unlock(&p->lock); 00320 return res; 00321 }
static int locals_show | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
CLI command "local show channels".
Definition at line 701 of file chan_local.c.
References ast_cli(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), local_pvt::context, local_pvt::exten, locals, local_pvt::lock, local_pvt::owner, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00702 { 00703 struct local_pvt *p = NULL; 00704 00705 if (argc != 3) 00706 return RESULT_SHOWUSAGE; 00707 00708 AST_LIST_LOCK(&locals); 00709 if (!AST_LIST_EMPTY(&locals)) { 00710 AST_LIST_TRAVERSE(&locals, p, list) { 00711 ast_mutex_lock(&p->lock); 00712 ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context); 00713 ast_mutex_unlock(&p->lock); 00714 } 00715 } else 00716 ast_cli(fd, "No local channels in use\n"); 00717 AST_LIST_UNLOCK(&locals); 00718 00719 return RESULT_SUCCESS; 00720 }
static int unload_module | ( | void | ) | [static] |
Unload the local proxy channel from Asterisk.
Definition at line 745 of file chan_local.c.
References ast_channel_unregister(), ast_cli_unregister_multiple(), AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, cli_local, locals, LOG_WARNING, and local_pvt::owner.
00746 { 00747 struct local_pvt *p = NULL; 00748 00749 /* First, take us out of the channel loop */ 00750 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00751 ast_channel_unregister(&local_tech); 00752 if (!AST_LIST_LOCK(&locals)) { 00753 /* Hangup all interfaces if they have an owner */ 00754 AST_LIST_TRAVERSE(&locals, p, list) { 00755 if (p->owner) 00756 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 00757 } 00758 AST_LIST_UNLOCK(&locals); 00759 AST_LIST_HEAD_DESTROY(&locals); 00760 } else { 00761 ast_log(LOG_WARNING, "Unable to lock the monitor\n"); 00762 return -1; 00763 } 00764 return 0; 00765 }
struct ast_cli_entry cli_local[] [static] |
Initial value:
{ { { "local", "show", "channels", NULL }, locals_show, "List status of local channels", show_locals_usage }, }
Definition at line 726 of file chan_local.c.
Referenced by load_module(), and unload_module().
struct ast_channel_tech local_tech [static] |
Definition at line 84 of file chan_local.c.
char show_locals_usage[] [static] |
Initial value:
"Usage: local show channels\n" " Provides summary information on active local proxy channels.\n"
Definition at line 722 of file chan_local.c.
const char tdesc[] = "Local Proxy Channel Driver" [static] |
Definition at line 65 of file chan_local.c.