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