#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") | |
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 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 *dest, const char *text, int ispdu) |
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" | ||||
) |
static void check_bridge | ( | struct local_pvt * | p, | |
int | isoutbound | |||
) | [static] |
Definition at line 222 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, and local_pvt::owner.
Referenced by local_write().
00223 { 00224 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))) 00225 return; 00226 00227 /* only do the masquerade if we are being called on the outbound channel, 00228 if it has been bridged to another channel and if there are no pending 00229 frames on the owner channel (because they would be transferred to the 00230 outbound channel during the masquerade) 00231 */ 00232 if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) { 00233 /* Masquerade bridged channel into owner */ 00234 /* Lock everything we need, one by one, and give up if 00235 we can't get everything. Remember, we'll get another 00236 chance in just a little bit */ 00237 if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) { 00238 if (!p->chan->_bridge->_softhangup) { 00239 if (!ast_mutex_trylock(&p->owner->lock)) { 00240 if (!p->owner->_softhangup) { 00241 ast_channel_masquerade(p->owner, p->chan->_bridge); 00242 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00243 } 00244 ast_mutex_unlock(&p->owner->lock); 00245 } 00246 ast_mutex_unlock(&(p->chan->_bridge)->lock); 00247 } 00248 } 00249 /* We only allow masquerading in one 'direction'... it's important to preserve the state 00250 (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan) 00251 when the local channels go away. 00252 */ 00253 #if 0 00254 } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) { 00255 /* Masquerade bridged channel into chan */ 00256 if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) { 00257 if (!p->owner->_bridge->_softhangup) { 00258 if (!ast_mutex_trylock(&p->chan->lock)) { 00259 if (!p->chan->_softhangup) { 00260 ast_channel_masquerade(p->chan, p->owner->_bridge); 00261 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00262 } 00263 ast_mutex_unlock(&p->chan->lock); 00264 } 00265 } 00266 ast_mutex_unlock(&(p->owner->_bridge)->lock); 00267 } 00268 #endif 00269 } 00270 }
static int load_module | ( | void | ) | [static] |
Load module into PBX, register channel.
Definition at line 694 of file chan_local.c.
References ast_channel_register(), ast_cli_register_multiple(), ast_log(), cli_local, and LOG_ERROR.
00695 { 00696 /* Make sure we can register our channel type */ 00697 if (ast_channel_register(&local_tech)) { 00698 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); 00699 return -1; 00700 } 00701 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00702 return 0; 00703 }
static struct local_pvt* local_alloc | ( | const char * | data, | |
int | format | |||
) | [static, read] |
Create a call structure.
Definition at line 543 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_destroy(), ast_mutex_init(), ast_set_flag, local_pvt::context, local_pvt::exten, free, LOCAL_NO_OPTIMIZATION, locals, local_pvt::lock, LOG_NOTICE, and local_pvt::reqformat.
Referenced by local_request().
00544 { 00545 struct local_pvt *tmp = NULL; 00546 char *c = NULL, *opts = NULL; 00547 00548 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) 00549 return NULL; 00550 00551 /* Initialize private structure information */ 00552 ast_mutex_init(&tmp->lock); 00553 ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); 00554 00555 /* Look for options */ 00556 if ((opts = strchr(tmp->exten, '/'))) { 00557 *opts++ = '\0'; 00558 if (strchr(opts, 'n')) 00559 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); 00560 } 00561 00562 /* Look for a context */ 00563 if ((c = strchr(tmp->exten, '@'))) 00564 *c++ = '\0'; 00565 00566 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context)); 00567 00568 tmp->reqformat = format; 00569 00570 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { 00571 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); 00572 ast_mutex_destroy(&tmp->lock); 00573 free(tmp); 00574 tmp = NULL; 00575 } else { 00576 /* Add to list */ 00577 AST_LIST_LOCK(&locals); 00578 AST_LIST_INSERT_HEAD(&locals, tmp, list); 00579 AST_LIST_UNLOCK(&locals); 00580 } 00581 00582 return tmp; 00583 }
static int local_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 200 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.
00201 { 00202 struct local_pvt *p = ast->tech_pvt; 00203 int isoutbound; 00204 int res = -1; 00205 00206 if (!p) 00207 return -1; 00208 00209 ast_mutex_lock(&p->lock); 00210 isoutbound = IS_OUTBOUND(ast, p); 00211 if (isoutbound) { 00212 /* Pass along answer since somebody answered us */ 00213 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00214 res = local_queue_frame(p, isoutbound, &answer, ast); 00215 } else 00216 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n"); 00217 if (!res) 00218 ast_mutex_unlock(&p->lock); 00219 return res; 00220 }
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 434 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, and ast_channel::varshead.
00435 { 00436 struct local_pvt *p = ast->tech_pvt; 00437 int res; 00438 struct ast_var_t *varptr = NULL, *new; 00439 size_t len, namelen; 00440 00441 if (!p) 00442 return -1; 00443 00444 ast_mutex_lock(&p->lock); 00445 00446 /* 00447 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc 00448 * call, so it's done here instead. 00449 */ 00450 p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num); 00451 p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name); 00452 p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis); 00453 p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani); 00454 p->chan->cid.cid_pres = p->owner->cid.cid_pres; 00455 ast_string_field_set(p->chan, language, p->owner->language); 00456 ast_string_field_set(p->chan, accountcode, p->owner->accountcode); 00457 p->chan->cdrflags = p->owner->cdrflags; 00458 00459 /* copy the channel variables from the incoming channel to the outgoing channel */ 00460 /* Note that due to certain assumptions, they MUST be in the same order */ 00461 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) { 00462 namelen = strlen(varptr->name); 00463 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; 00464 if ((new = ast_calloc(1, len))) { 00465 memcpy(new, varptr, len); 00466 new->value = &(new->name[0]) + namelen + 1; 00467 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries); 00468 } 00469 } 00470 ast_channel_datastore_inherit(p->owner, p->chan); 00471 00472 /* Start switch on sub channel */ 00473 if (!(res = ast_pbx_start(p->chan))) 00474 ast_set_flag(p, LOCAL_LAUNCHED_PBX); 00475 00476 ast_mutex_unlock(&p->lock); 00477 return res; 00478 }
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 354 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.
00355 { 00356 struct local_pvt *p = ast->tech_pvt; 00357 int res = -1; 00358 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; 00359 int isoutbound; 00360 00361 if (!p) 00362 return -1; 00363 00364 ast_mutex_lock(&p->lock); 00365 isoutbound = IS_OUTBOUND(ast, p); 00366 f.subclass = digit; 00367 if (!(res = local_queue_frame(p, isoutbound, &f, ast))) 00368 ast_mutex_unlock(&p->lock); 00369 00370 return res; 00371 }
static int local_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 373 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.
00374 { 00375 struct local_pvt *p = ast->tech_pvt; 00376 int res = -1; 00377 struct ast_frame f = { AST_FRAME_DTMF_END, }; 00378 int isoutbound; 00379 00380 if (!p) 00381 return -1; 00382 00383 ast_mutex_lock(&p->lock); 00384 isoutbound = IS_OUTBOUND(ast, p); 00385 f.subclass = digit; 00386 f.len = duration; 00387 if (!(res = local_queue_frame(p, isoutbound, &f, ast))) 00388 ast_mutex_unlock(&p->lock); 00389 00390 return res; 00391 }
static int local_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 303 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.
00304 { 00305 struct local_pvt *p = newchan->tech_pvt; 00306 00307 if (!p) 00308 return -1; 00309 00310 ast_mutex_lock(&p->lock); 00311 00312 if ((p->owner != oldchan) && (p->chan != oldchan)) { 00313 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); 00314 ast_mutex_unlock(&p->lock); 00315 return -1; 00316 } 00317 if (p->owner == oldchan) 00318 p->owner = newchan; 00319 else 00320 p->chan = newchan; 00321 ast_mutex_unlock(&p->lock); 00322 return 0; 00323 }
static int local_hangup | ( | struct ast_channel * | ast | ) | [static] |
Hangup a call through the local proxy channel.
Definition at line 481 of file chan_local.c.
References 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_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_test_flag, local_pvt::chan, free, IS_OUTBOUND, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, LOCAL_LAUNCHED_PBX, 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.
00482 { 00483 struct local_pvt *p = ast->tech_pvt; 00484 int isoutbound; 00485 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP }; 00486 struct ast_channel *ochan = NULL; 00487 int glaredetect = 0, res = 0; 00488 00489 if (!p) 00490 return -1; 00491 00492 ast_mutex_lock(&p->lock); 00493 isoutbound = IS_OUTBOUND(ast, p); 00494 if (isoutbound) { 00495 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); 00496 if ((status) && (p->owner)) 00497 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); 00498 p->chan = NULL; 00499 ast_clear_flag(p, LOCAL_LAUNCHED_PBX); 00500 ast_module_user_remove(p->u_chan); 00501 } else { 00502 p->owner = NULL; 00503 ast_module_user_remove(p->u_owner); 00504 } 00505 00506 ast->tech_pvt = NULL; 00507 00508 if (!p->owner && !p->chan) { 00509 /* Okay, done with the private part now, too. */ 00510 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT); 00511 /* If we have a queue holding, don't actually destroy p yet, but 00512 let local_queue do it. */ 00513 if (glaredetect) 00514 ast_set_flag(p, LOCAL_CANCEL_QUEUE); 00515 ast_mutex_unlock(&p->lock); 00516 /* Remove from list */ 00517 AST_LIST_LOCK(&locals); 00518 AST_LIST_REMOVE(&locals, p, list); 00519 AST_LIST_UNLOCK(&locals); 00520 /* Grab / release lock just in case */ 00521 ast_mutex_lock(&p->lock); 00522 ast_mutex_unlock(&p->lock); 00523 /* And destroy */ 00524 if (!glaredetect) { 00525 ast_mutex_destroy(&p->lock); 00526 free(p); 00527 } 00528 return 0; 00529 } 00530 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) 00531 /* Need to actually hangup since there is no PBX */ 00532 ochan = p->chan; 00533 else 00534 res = local_queue_frame(p, isoutbound, &f, NULL); 00535 if (!res) 00536 ast_mutex_unlock(&p->lock); 00537 if (ochan) 00538 ast_hangup(ochan); 00539 return 0; 00540 }
static int local_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 325 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.
00326 { 00327 struct local_pvt *p = ast->tech_pvt; 00328 int res = 0; 00329 struct ast_frame f = { AST_FRAME_CONTROL, }; 00330 int isoutbound; 00331 00332 if (!p) 00333 return -1; 00334 00335 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */ 00336 if (condition == AST_CONTROL_HOLD) { 00337 ast_moh_start(ast, data, NULL); 00338 } else if (condition == AST_CONTROL_UNHOLD) { 00339 ast_moh_stop(ast); 00340 } else { 00341 /* Queue up a frame representing the indication as a control frame */ 00342 ast_mutex_lock(&p->lock); 00343 isoutbound = IS_OUTBOUND(ast, p); 00344 f.subclass = condition; 00345 f.data = (void*)data; 00346 f.datalen = datalen; 00347 if (!(res = local_queue_frame(p, isoutbound, &f, ast))) 00348 ast_mutex_unlock(&p->lock); 00349 } 00350 00351 return res; 00352 }
static struct ast_channel* local_new | ( | struct local_pvt * | p, | |
int | state | |||
) | [static, read] |
Start new local channel.
Definition at line 586 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().
00587 { 00588 struct ast_channel *tmp = NULL, *tmp2 = NULL; 00589 int randnum = ast_random() & 0xffff, fmt = 0; 00590 const char *t; 00591 int ama; 00592 00593 /* Allocate two new Asterisk channels */ 00594 /* safe accountcode */ 00595 if (p->owner && p->owner->accountcode) 00596 t = p->owner->accountcode; 00597 else 00598 t = ""; 00599 00600 if (p->owner) 00601 ama = p->owner->amaflags; 00602 else 00603 ama = 0; 00604 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)) 00605 || !(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))) { 00606 if (tmp) 00607 ast_channel_free(tmp); 00608 if (tmp2) 00609 ast_channel_free(tmp2); 00610 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); 00611 return NULL; 00612 } 00613 00614 tmp2->tech = tmp->tech = &local_tech; 00615 00616 tmp->nativeformats = p->reqformat; 00617 tmp2->nativeformats = p->reqformat; 00618 00619 /* Determine our read/write format and set it on each channel */ 00620 fmt = ast_best_codec(p->reqformat); 00621 tmp->writeformat = fmt; 00622 tmp2->writeformat = fmt; 00623 tmp->rawwriteformat = fmt; 00624 tmp2->rawwriteformat = fmt; 00625 tmp->readformat = fmt; 00626 tmp2->readformat = fmt; 00627 tmp->rawreadformat = fmt; 00628 tmp2->rawreadformat = fmt; 00629 00630 tmp->tech_pvt = p; 00631 tmp2->tech_pvt = p; 00632 00633 p->owner = tmp; 00634 p->chan = tmp2; 00635 p->u_owner = ast_module_user_add(p->owner); 00636 p->u_chan = ast_module_user_add(p->chan); 00637 00638 ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); 00639 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); 00640 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); 00641 tmp->priority = 1; 00642 tmp2->priority = 1; 00643 00644 return tmp; 00645 }
static int local_queue_frame | ( | struct local_pvt * | p, | |
int | isoutbound, | |||
struct ast_frame * | f, | |||
struct ast_channel * | us | |||
) | [static] |
Definition at line 153 of file chan_local.c.
References ast_clear_flag, ast_log(), ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_trylock(), ast_mutex_unlock(), ast_queue_frame(), ast_set_flag, ast_test_flag, local_pvt::chan, ast_frame::frametype, free, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, ast_channel::lock, local_pvt::lock, LOG_WARNING, local_pvt::owner, and ast_frame::subclass.
Referenced by local_answer(), local_digit_begin(), local_digit_end(), local_hangup(), local_indicate(), local_sendhtml(), local_sendtext(), and local_write().
00154 { 00155 struct ast_channel *other = NULL; 00156 00157 retrylock: 00158 00159 /* Recalculate outbound channel */ 00160 other = isoutbound ? p->owner : p->chan; 00161 00162 /* Set glare detection */ 00163 ast_set_flag(p, LOCAL_GLARE_DETECT); 00164 if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) { 00165 /* We had a glare on the hangup. Forget all this business, 00166 return and destroy p. */ 00167 ast_mutex_unlock(&p->lock); 00168 ast_mutex_destroy(&p->lock); 00169 free(p); 00170 return -1; 00171 } 00172 if (!other) { 00173 ast_clear_flag(p, LOCAL_GLARE_DETECT); 00174 return 0; 00175 } 00176 if (ast_mutex_trylock(&other->lock)) { 00177 /* Failed to lock. Release main lock and try again */ 00178 ast_mutex_unlock(&p->lock); 00179 if (us) { 00180 if (ast_mutex_unlock(&us->lock)) { 00181 ast_log(LOG_WARNING, "%s wasn't locked while sending %d/%d\n", 00182 us->name, f->frametype, f->subclass); 00183 us = NULL; 00184 } 00185 } 00186 /* Wait just a bit */ 00187 usleep(1); 00188 /* Only we can destroy ourselves, so we can't disappear here */ 00189 if (us) 00190 ast_mutex_lock(&us->lock); 00191 ast_mutex_lock(&p->lock); 00192 goto retrylock; 00193 } 00194 ast_queue_frame(other, f); 00195 ast_mutex_unlock(&other->lock); 00196 ast_clear_flag(p, LOCAL_GLARE_DETECT); 00197 return 0; 00198 }
static struct ast_frame * local_read | ( | struct ast_channel * | ast | ) | [static, read] |
Definition at line 272 of file chan_local.c.
References ast_null_frame.
00273 { 00274 return &ast_null_frame; 00275 }
static struct ast_channel * local_request | ( | const char * | type, | |
int | format, | |||
void * | data, | |||
int * | cause | |||
) | [static, read] |
Part of PBX interface.
Definition at line 649 of file chan_local.c.
References AST_STATE_DOWN, local_pvt::chan, local_alloc(), and local_new().
00650 { 00651 struct local_pvt *p = NULL; 00652 struct ast_channel *chan = NULL; 00653 00654 /* Allocate a new private structure and then Asterisk channel */ 00655 if ((p = local_alloc(data, format))) 00656 chan = local_new(p, AST_STATE_DOWN); 00657 00658 return chan; 00659 }
static int local_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 412 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.
00413 { 00414 struct local_pvt *p = ast->tech_pvt; 00415 int res = -1; 00416 struct ast_frame f = { AST_FRAME_HTML, }; 00417 int isoutbound; 00418 00419 if (!p) 00420 return -1; 00421 00422 ast_mutex_lock(&p->lock); 00423 isoutbound = IS_OUTBOUND(ast, p); 00424 f.subclass = subclass; 00425 f.data = (char *)data; 00426 f.datalen = datalen; 00427 if (!(res = local_queue_frame(p, isoutbound, &f, ast))) 00428 ast_mutex_unlock(&p->lock); 00429 return res; 00430 }
static int local_sendtext | ( | struct ast_channel * | ast, | |
const char * | dest, | |||
const char * | text, | |||
int | ispdu | |||
) | [static] |
Definition at line 393 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.
00394 { 00395 struct local_pvt *p = ast->tech_pvt; 00396 int res = -1; 00397 struct ast_frame f = { AST_FRAME_TEXT, }; 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.data = (char *) text; 00406 f.datalen = strlen(text) + 1; 00407 if (!(res = local_queue_frame(p, isoutbound, &f, ast))) 00408 ast_mutex_unlock(&p->lock); 00409 return res; 00410 }
static int local_write | ( | struct ast_channel * | ast, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 277 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.
00278 { 00279 struct local_pvt *p = ast->tech_pvt; 00280 int res = -1; 00281 int isoutbound; 00282 00283 if (!p) 00284 return -1; 00285 00286 /* Just queue for delivery to the other side */ 00287 ast_mutex_lock(&p->lock); 00288 isoutbound = IS_OUTBOUND(ast, p); 00289 if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) 00290 check_bridge(p, isoutbound); 00291 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) 00292 res = local_queue_frame(p, isoutbound, f, ast); 00293 else { 00294 if (option_debug) 00295 ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name); 00296 res = 0; 00297 } 00298 if (!res) 00299 ast_mutex_unlock(&p->lock); 00300 return res; 00301 }
static int locals_show | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
CLI command "local show channels".
Definition at line 662 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.
00663 { 00664 struct local_pvt *p = NULL; 00665 00666 if (argc != 3) 00667 return RESULT_SHOWUSAGE; 00668 00669 AST_LIST_LOCK(&locals); 00670 if (!AST_LIST_EMPTY(&locals)) { 00671 AST_LIST_TRAVERSE(&locals, p, list) { 00672 ast_mutex_lock(&p->lock); 00673 ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context); 00674 ast_mutex_unlock(&p->lock); 00675 } 00676 } else 00677 ast_cli(fd, "No local channels in use\n"); 00678 AST_LIST_UNLOCK(&locals); 00679 00680 return RESULT_SUCCESS; 00681 }
static int unload_module | ( | void | ) | [static] |
Unload the local proxy channel from Asterisk.
Definition at line 706 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.
00707 { 00708 struct local_pvt *p = NULL; 00709 00710 /* First, take us out of the channel loop */ 00711 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00712 ast_channel_unregister(&local_tech); 00713 if (!AST_LIST_LOCK(&locals)) { 00714 /* Hangup all interfaces if they have an owner */ 00715 AST_LIST_TRAVERSE(&locals, p, list) { 00716 if (p->owner) 00717 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 00718 } 00719 AST_LIST_UNLOCK(&locals); 00720 AST_LIST_HEAD_DESTROY(&locals); 00721 } else { 00722 ast_log(LOG_WARNING, "Unable to lock the monitor\n"); 00723 return -1; 00724 } 00725 return 0; 00726 }
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 687 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 683 of file chan_local.c.
const char tdesc[] = "Local Proxy Channel Driver" [static] |
Definition at line 65 of file chan_local.c.