#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 233 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().
00234 { 00235 struct ast_channel_monitor *tmp; 00236 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))) 00237 return; 00238 00239 /* only do the masquerade if we are being called on the outbound channel, 00240 if it has been bridged to another channel and if there are no pending 00241 frames on the owner channel (because they would be transferred to the 00242 outbound channel during the masquerade) 00243 */ 00244 if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) { 00245 /* Masquerade bridged channel into owner */ 00246 /* Lock everything we need, one by one, and give up if 00247 we can't get everything. Remember, we'll get another 00248 chance in just a little bit */ 00249 if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) { 00250 if (!p->chan->_bridge->_softhangup) { 00251 if (!ast_mutex_trylock(&p->owner->lock)) { 00252 if (!p->owner->_softhangup) { 00253 if(p->owner->monitor && !p->chan->_bridge->monitor) { 00254 /* If a local channel is being monitored, we don't want a masquerade 00255 * to cause the monitor to go away. Since the masquerade swaps the monitors, 00256 * pre-swapping the monitors before the masquerade will ensure that the monitor 00257 * ends up where it is expected. 00258 */ 00259 tmp = p->owner->monitor; 00260 p->owner->monitor = p->chan->_bridge->monitor; 00261 p->chan->_bridge->monitor = tmp; 00262 } 00263 ast_channel_masquerade(p->owner, p->chan->_bridge); 00264 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00265 } 00266 ast_mutex_unlock(&p->owner->lock); 00267 } 00268 ast_mutex_unlock(&(p->chan->_bridge)->lock); 00269 } 00270 } 00271 /* We only allow masquerading in one 'direction'... it's important to preserve the state 00272 (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan) 00273 when the local channels go away. 00274 */ 00275 #if 0 00276 } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) { 00277 /* Masquerade bridged channel into chan */ 00278 if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) { 00279 if (!p->owner->_bridge->_softhangup) { 00280 if (!ast_mutex_trylock(&p->chan->lock)) { 00281 if (!p->chan->_softhangup) { 00282 ast_channel_masquerade(p->chan, p->owner->_bridge); 00283 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00284 } 00285 ast_mutex_unlock(&p->chan->lock); 00286 } 00287 } 00288 ast_mutex_unlock(&(p->owner->_bridge)->lock); 00289 } 00290 #endif 00291 } 00292 }
static int load_module | ( | void | ) | [static] |
Load module into PBX, register channel.
Definition at line 743 of file chan_local.c.
References ast_channel_register(), ast_cli_register_multiple(), ast_log(), cli_local, local_tech, and LOG_ERROR.
00744 { 00745 /* Make sure we can register our channel type */ 00746 if (ast_channel_register(&local_tech)) { 00747 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); 00748 return -1; 00749 } 00750 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00751 return 0; 00752 }
static struct local_pvt* local_alloc | ( | const char * | data, | |
int | format | |||
) | [static] |
Create a call structure.
Definition at line 589 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_NO_OPTIMIZATION, local_pvt_destroy(), locals, and LOG_NOTICE.
Referenced by local_request().
00590 { 00591 struct local_pvt *tmp = NULL; 00592 char *c = NULL, *opts = NULL; 00593 00594 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) 00595 return NULL; 00596 00597 /* Initialize private structure information */ 00598 ast_mutex_init(&tmp->lock); 00599 ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); 00600 00601 /* Look for options */ 00602 if ((opts = strchr(tmp->exten, '/'))) { 00603 *opts++ = '\0'; 00604 if (strchr(opts, 'n')) 00605 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); 00606 } 00607 00608 /* Look for a context */ 00609 if ((c = strchr(tmp->exten, '@'))) 00610 *c++ = '\0'; 00611 00612 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context)); 00613 00614 tmp->reqformat = format; 00615 00616 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { 00617 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); 00618 tmp = local_pvt_destroy(tmp); 00619 } else { 00620 /* Add to list */ 00621 AST_LIST_LOCK(&locals); 00622 AST_LIST_INSERT_HEAD(&locals, tmp, list); 00623 AST_LIST_UNLOCK(&locals); 00624 } 00625 00626 return tmp; 00627 }
static int local_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 211 of file chan_local.c.
References answer, 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.
00212 { 00213 struct local_pvt *p = ast->tech_pvt; 00214 int isoutbound; 00215 int res = -1; 00216 00217 if (!p) 00218 return -1; 00219 00220 ast_mutex_lock(&p->lock); 00221 isoutbound = IS_OUTBOUND(ast, p); 00222 if (isoutbound) { 00223 /* Pass along answer since somebody answered us */ 00224 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00225 res = local_queue_frame(p, isoutbound, &answer, ast, 1); 00226 } else 00227 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n"); 00228 if (!res) 00229 ast_mutex_unlock(&p->lock); 00230 return res; 00231 }
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 456 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, ast_var_t::value, and ast_channel::varshead.
00457 { 00458 struct local_pvt *p = ast->tech_pvt; 00459 int res; 00460 struct ast_var_t *varptr = NULL, *new; 00461 size_t len, namelen; 00462 00463 if (!p) 00464 return -1; 00465 00466 ast_mutex_lock(&p->lock); 00467 00468 /* 00469 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc 00470 * call, so it's done here instead. 00471 */ 00472 p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num); 00473 p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name); 00474 p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis); 00475 p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani); 00476 p->chan->cid.cid_pres = p->owner->cid.cid_pres; 00477 ast_string_field_set(p->chan, language, p->owner->language); 00478 ast_string_field_set(p->chan, accountcode, p->owner->accountcode); 00479 ast_cdr_update(p->chan); 00480 p->chan->cdrflags = p->owner->cdrflags; 00481 00482 /* copy the channel variables from the incoming channel to the outgoing channel */ 00483 /* Note that due to certain assumptions, they MUST be in the same order */ 00484 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) { 00485 namelen = strlen(varptr->name); 00486 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; 00487 if ((new = ast_calloc(1, len))) { 00488 memcpy(new, varptr, len); 00489 new->value = &(new->name[0]) + namelen + 1; 00490 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries); 00491 } 00492 } 00493 ast_channel_datastore_inherit(p->owner, p->chan); 00494 00495 /* Start switch on sub channel */ 00496 if (!(res = ast_pbx_start(p->chan))) 00497 ast_set_flag(p, LOCAL_LAUNCHED_PBX); 00498 00499 ast_mutex_unlock(&p->lock); 00500 return res; 00501 }
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 376 of file chan_local.c.
References AST_FRAME_DTMF_BEGIN, ast_mutex_lock(), ast_mutex_unlock(), f, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, and ast_channel::tech_pvt.
00377 { 00378 struct local_pvt *p = ast->tech_pvt; 00379 int res = -1; 00380 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; 00381 int isoutbound; 00382 00383 if (!p) 00384 return -1; 00385 00386 ast_mutex_lock(&p->lock); 00387 isoutbound = IS_OUTBOUND(ast, p); 00388 f.subclass = digit; 00389 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00390 ast_mutex_unlock(&p->lock); 00391 00392 return res; 00393 }
static int local_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 395 of file chan_local.c.
References AST_FRAME_DTMF_END, ast_mutex_lock(), ast_mutex_unlock(), f, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, and ast_channel::tech_pvt.
00396 { 00397 struct local_pvt *p = ast->tech_pvt; 00398 int res = -1; 00399 struct ast_frame f = { AST_FRAME_DTMF_END, }; 00400 int isoutbound; 00401 00402 if (!p) 00403 return -1; 00404 00405 ast_mutex_lock(&p->lock); 00406 isoutbound = IS_OUTBOUND(ast, p); 00407 f.subclass = digit; 00408 f.len = duration; 00409 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00410 ast_mutex_unlock(&p->lock); 00411 00412 return res; 00413 }
static int local_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 325 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.
00326 { 00327 struct local_pvt *p = newchan->tech_pvt; 00328 00329 if (!p) 00330 return -1; 00331 00332 ast_mutex_lock(&p->lock); 00333 00334 if ((p->owner != oldchan) && (p->chan != oldchan)) { 00335 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); 00336 ast_mutex_unlock(&p->lock); 00337 return -1; 00338 } 00339 if (p->owner == oldchan) 00340 p->owner = newchan; 00341 else 00342 p->chan = newchan; 00343 ast_mutex_unlock(&p->lock); 00344 return 0; 00345 }
static int local_hangup | ( | struct ast_channel * | ast | ) | [static] |
Hangup a call through the local proxy channel.
Definition at line 504 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_trylock(), ast_mutex_unlock(), ast_queue_hangup(), ast_set_flag, ast_test_flag, local_pvt::chan, f, 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.
00505 { 00506 struct local_pvt *p = ast->tech_pvt; 00507 int isoutbound; 00508 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP }; 00509 struct ast_channel *ochan = NULL; 00510 int glaredetect = 0, res = 0; 00511 00512 if (!p) 00513 return -1; 00514 00515 while (ast_mutex_trylock(&p->lock)) { 00516 ast_channel_unlock(ast); 00517 usleep(1); 00518 ast_channel_lock(ast); 00519 } 00520 00521 isoutbound = IS_OUTBOUND(ast, p); 00522 if (isoutbound) { 00523 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); 00524 if ((status) && (p->owner)) { 00525 /* Deadlock avoidance */ 00526 while (p->owner && ast_channel_trylock(p->owner)) { 00527 ast_mutex_unlock(&p->lock); 00528 if (ast) { 00529 ast_channel_unlock(ast); 00530 } 00531 usleep(1); 00532 if (ast) { 00533 ast_channel_lock(ast); 00534 } 00535 ast_mutex_lock(&p->lock); 00536 } 00537 if (p->owner) { 00538 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); 00539 ast_channel_unlock(p->owner); 00540 } 00541 } 00542 p->chan = NULL; 00543 ast_clear_flag(p, LOCAL_LAUNCHED_PBX); 00544 ast_module_user_remove(p->u_chan); 00545 } else { 00546 p->owner = NULL; 00547 ast_module_user_remove(p->u_owner); 00548 if (p->chan) { 00549 ast_queue_hangup(p->chan); 00550 } 00551 } 00552 00553 ast->tech_pvt = NULL; 00554 00555 if (!p->owner && !p->chan) { 00556 /* Okay, done with the private part now, too. */ 00557 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT); 00558 /* If we have a queue holding, don't actually destroy p yet, but 00559 let local_queue do it. */ 00560 if (glaredetect) 00561 ast_set_flag(p, LOCAL_CANCEL_QUEUE); 00562 ast_mutex_unlock(&p->lock); 00563 /* Remove from list */ 00564 AST_LIST_LOCK(&locals); 00565 AST_LIST_REMOVE(&locals, p, list); 00566 AST_LIST_UNLOCK(&locals); 00567 /* Grab / release lock just in case */ 00568 ast_mutex_lock(&p->lock); 00569 ast_mutex_unlock(&p->lock); 00570 /* And destroy */ 00571 if (!glaredetect) { 00572 p = local_pvt_destroy(p); 00573 } 00574 return 0; 00575 } 00576 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) 00577 /* Need to actually hangup since there is no PBX */ 00578 ochan = p->chan; 00579 else 00580 res = local_queue_frame(p, isoutbound, &f, NULL, 1); 00581 if (!res) 00582 ast_mutex_unlock(&p->lock); 00583 if (ochan) 00584 ast_hangup(ochan); 00585 return 0; 00586 }
static int local_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 347 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(), f, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, and ast_channel::tech_pvt.
00348 { 00349 struct local_pvt *p = ast->tech_pvt; 00350 int res = 0; 00351 struct ast_frame f = { AST_FRAME_CONTROL, }; 00352 int isoutbound; 00353 00354 if (!p) 00355 return -1; 00356 00357 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */ 00358 if (condition == AST_CONTROL_HOLD) { 00359 ast_moh_start(ast, data, NULL); 00360 } else if (condition == AST_CONTROL_UNHOLD) { 00361 ast_moh_stop(ast); 00362 } else { 00363 /* Queue up a frame representing the indication as a control frame */ 00364 ast_mutex_lock(&p->lock); 00365 isoutbound = IS_OUTBOUND(ast, p); 00366 f.subclass = condition; 00367 f.data = (void*)data; 00368 f.datalen = datalen; 00369 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1))) 00370 ast_mutex_unlock(&p->lock); 00371 } 00372 00373 return res; 00374 }
static struct ast_channel* local_new | ( | struct local_pvt * | p, | |
int | state | |||
) | [static] |
Start new local channel.
Definition at line 630 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, local_tech, 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().
00631 { 00632 struct ast_channel *tmp = NULL, *tmp2 = NULL; 00633 int randnum = ast_random() & 0xffff, fmt = 0; 00634 const char *t; 00635 int ama; 00636 00637 /* Allocate two new Asterisk channels */ 00638 /* safe accountcode */ 00639 if (p->owner && p->owner->accountcode) 00640 t = p->owner->accountcode; 00641 else 00642 t = ""; 00643 00644 if (p->owner) 00645 ama = p->owner->amaflags; 00646 else 00647 ama = 0; 00648 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)) 00649 || !(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))) { 00650 if (tmp) 00651 ast_channel_free(tmp); 00652 if (tmp2) 00653 ast_channel_free(tmp2); 00654 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); 00655 return NULL; 00656 } 00657 00658 tmp2->tech = tmp->tech = &local_tech; 00659 00660 tmp->nativeformats = p->reqformat; 00661 tmp2->nativeformats = p->reqformat; 00662 00663 /* Determine our read/write format and set it on each channel */ 00664 fmt = ast_best_codec(p->reqformat); 00665 tmp->writeformat = fmt; 00666 tmp2->writeformat = fmt; 00667 tmp->rawwriteformat = fmt; 00668 tmp2->rawwriteformat = fmt; 00669 tmp->readformat = fmt; 00670 tmp2->readformat = fmt; 00671 tmp->rawreadformat = fmt; 00672 tmp2->rawreadformat = fmt; 00673 00674 tmp->tech_pvt = p; 00675 tmp2->tech_pvt = p; 00676 00677 p->owner = tmp; 00678 p->chan = tmp2; 00679 p->u_owner = ast_module_user_add(p->owner); 00680 p->u_chan = ast_module_user_add(p->chan); 00681 00682 ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); 00683 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); 00684 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); 00685 tmp->priority = 1; 00686 tmp2->priority = 1; 00687 00688 return tmp; 00689 }
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_trylock(), ast_mutex_unlock(), ast_queue_frame(), ast_set_flag, ast_test_flag, local_pvt::chan, f, 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 do { 00190 ast_channel_unlock(us); 00191 usleep(1); 00192 ast_channel_lock(us); 00193 } while (ast_mutex_trylock(&p->lock)); 00194 } else { 00195 usleep(1); 00196 ast_mutex_lock(&p->lock); 00197 } 00198 other = isoutbound ? p->owner : p->chan; 00199 } 00200 00201 if (other) { 00202 ast_queue_frame(other, f); 00203 ast_channel_unlock(other); 00204 } 00205 00206 ast_clear_flag(p, LOCAL_GLARE_DETECT); 00207 00208 return 0; 00209 }
static struct ast_frame * local_read | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 294 of file chan_local.c.
References ast_null_frame.
00295 { 00296 return &ast_null_frame; 00297 }
static struct ast_channel * local_request | ( | const char * | type, | |
int | format, | |||
void * | data, | |||
int * | cause | |||
) | [static] |
Part of PBX interface.
Definition at line 692 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.
00693 { 00694 struct local_pvt *p = NULL; 00695 struct ast_channel *chan = NULL; 00696 00697 /* Allocate a new private structure and then Asterisk channel */ 00698 if ((p = local_alloc(data, format))) { 00699 if (!(chan = local_new(p, AST_STATE_DOWN))) { 00700 AST_LIST_LOCK(&locals); 00701 AST_LIST_REMOVE(&locals, p, list); 00702 AST_LIST_UNLOCK(&locals); 00703 p = local_pvt_destroy(p); 00704 } 00705 } 00706 00707 return chan; 00708 }
static int local_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 434 of file chan_local.c.
References AST_FRAME_HTML, ast_mutex_lock(), ast_mutex_unlock(), f, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, and ast_channel::tech_pvt.
00435 { 00436 struct local_pvt *p = ast->tech_pvt; 00437 int res = -1; 00438 struct ast_frame f = { AST_FRAME_HTML, }; 00439 int isoutbound; 00440 00441 if (!p) 00442 return -1; 00443 00444 ast_mutex_lock(&p->lock); 00445 isoutbound = IS_OUTBOUND(ast, p); 00446 f.subclass = subclass; 00447 f.data = (char *)data; 00448 f.datalen = datalen; 00449 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00450 ast_mutex_unlock(&p->lock); 00451 return res; 00452 }
static int local_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 415 of file chan_local.c.
References AST_FRAME_TEXT, ast_mutex_lock(), ast_mutex_unlock(), f, IS_OUTBOUND, local_queue_frame(), local_pvt::lock, and ast_channel::tech_pvt.
00416 { 00417 struct local_pvt *p = ast->tech_pvt; 00418 int res = -1; 00419 struct ast_frame f = { AST_FRAME_TEXT, }; 00420 int isoutbound; 00421 00422 if (!p) 00423 return -1; 00424 00425 ast_mutex_lock(&p->lock); 00426 isoutbound = IS_OUTBOUND(ast, p); 00427 f.data = (char *) text; 00428 f.datalen = strlen(text) + 1; 00429 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00430 ast_mutex_unlock(&p->lock); 00431 return res; 00432 }
static int local_write | ( | struct ast_channel * | ast, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 299 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(), f, IS_OUTBOUND, LOCAL_ALREADY_MASQED, local_queue_frame(), local_pvt::lock, LOG_DEBUG, option_debug, and ast_channel::tech_pvt.
00300 { 00301 struct local_pvt *p = ast->tech_pvt; 00302 int res = -1; 00303 int isoutbound; 00304 00305 if (!p) 00306 return -1; 00307 00308 /* Just queue for delivery to the other side */ 00309 ast_mutex_lock(&p->lock); 00310 isoutbound = IS_OUTBOUND(ast, p); 00311 if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) 00312 check_bridge(p, isoutbound); 00313 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) 00314 res = local_queue_frame(p, isoutbound, f, ast, 1); 00315 else { 00316 if (option_debug) 00317 ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name); 00318 res = 0; 00319 } 00320 if (!res) 00321 ast_mutex_unlock(&p->lock); 00322 return res; 00323 }
static int locals_show | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
CLI command "local show channels".
Definition at line 711 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.
00712 { 00713 struct local_pvt *p = NULL; 00714 00715 if (argc != 3) 00716 return RESULT_SHOWUSAGE; 00717 00718 AST_LIST_LOCK(&locals); 00719 if (!AST_LIST_EMPTY(&locals)) { 00720 AST_LIST_TRAVERSE(&locals, p, list) { 00721 ast_mutex_lock(&p->lock); 00722 ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context); 00723 ast_mutex_unlock(&p->lock); 00724 } 00725 } else 00726 ast_cli(fd, "No local channels in use\n"); 00727 AST_LIST_UNLOCK(&locals); 00728 00729 return RESULT_SUCCESS; 00730 }
static int unload_module | ( | void | ) | [static] |
Unload the local proxy channel from Asterisk.
Definition at line 755 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, local_tech, locals, LOG_WARNING, and local_pvt::owner.
00756 { 00757 struct local_pvt *p = NULL; 00758 00759 /* First, take us out of the channel loop */ 00760 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00761 ast_channel_unregister(&local_tech); 00762 if (!AST_LIST_LOCK(&locals)) { 00763 /* Hangup all interfaces if they have an owner */ 00764 AST_LIST_TRAVERSE(&locals, p, list) { 00765 if (p->owner) 00766 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 00767 } 00768 AST_LIST_UNLOCK(&locals); 00769 } else { 00770 ast_log(LOG_WARNING, "Unable to lock the monitor\n"); 00771 return -1; 00772 } 00773 return 0; 00774 }
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 736 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.
Referenced by load_module(), local_new(), and unload_module().
char show_locals_usage[] [static] |
Initial value:
"Usage: local show channels\n" " Provides summary information on active local proxy channels.\n"
Definition at line 732 of file chan_local.c.
const char tdesc[] = "Local Proxy Channel Driver" [static] |
Definition at line 65 of file chan_local.c.