#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, 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 237 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().
00238 { 00239 struct ast_channel_monitor *tmp; 00240 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))) 00241 return; 00242 00243 /* only do the masquerade if we are being called on the outbound channel, 00244 if it has been bridged to another channel and if there are no pending 00245 frames on the owner channel (because they would be transferred to the 00246 outbound channel during the masquerade) 00247 */ 00248 if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) { 00249 /* Masquerade bridged channel into owner */ 00250 /* Lock everything we need, one by one, and give up if 00251 we can't get everything. Remember, we'll get another 00252 chance in just a little bit */ 00253 if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) { 00254 if (!p->chan->_bridge->_softhangup) { 00255 if (!ast_mutex_trylock(&p->owner->lock)) { 00256 if (!p->owner->_softhangup) { 00257 if(p->owner->monitor && !p->chan->_bridge->monitor) { 00258 /* If a local channel is being monitored, we don't want a masquerade 00259 * to cause the monitor to go away. Since the masquerade swaps the monitors, 00260 * pre-swapping the monitors before the masquerade will ensure that the monitor 00261 * ends up where it is expected. 00262 */ 00263 tmp = p->owner->monitor; 00264 p->owner->monitor = p->chan->_bridge->monitor; 00265 p->chan->_bridge->monitor = tmp; 00266 } 00267 ast_channel_masquerade(p->owner, p->chan->_bridge); 00268 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00269 } 00270 ast_mutex_unlock(&p->owner->lock); 00271 } 00272 ast_mutex_unlock(&(p->chan->_bridge)->lock); 00273 } 00274 } 00275 /* We only allow masquerading in one 'direction'... it's important to preserve the state 00276 (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan) 00277 when the local channels go away. 00278 */ 00279 #if 0 00280 } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) { 00281 /* Masquerade bridged channel into chan */ 00282 if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) { 00283 if (!p->owner->_bridge->_softhangup) { 00284 if (!ast_mutex_trylock(&p->chan->lock)) { 00285 if (!p->chan->_softhangup) { 00286 ast_channel_masquerade(p->chan, p->owner->_bridge); 00287 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00288 } 00289 ast_mutex_unlock(&p->chan->lock); 00290 } 00291 } 00292 ast_mutex_unlock(&(p->owner->_bridge)->lock); 00293 } 00294 #endif 00295 } 00296 }
| static int load_module | ( | void | ) | [static] |
Load module into PBX, register channel.
Definition at line 768 of file chan_local.c.
References ast_channel_register(), ast_cli_register_multiple(), ast_log(), cli_local, local_tech, and LOG_ERROR.
00769 { 00770 /* Make sure we can register our channel type */ 00771 if (ast_channel_register(&local_tech)) { 00772 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); 00773 return -1; 00774 } 00775 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00776 return 0; 00777 }
| static struct local_pvt* local_alloc | ( | const char * | data, | |
| int | format | |||
| ) | [static] |
Create a call structure.
Definition at line 607 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().
00608 { 00609 struct local_pvt *tmp = NULL; 00610 char *c = NULL, *opts = NULL; 00611 00612 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) 00613 return NULL; 00614 00615 /* Initialize private structure information */ 00616 ast_mutex_init(&tmp->lock); 00617 ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); 00618 00619 /* Look for options */ 00620 if ((opts = strchr(tmp->exten, '/'))) { 00621 *opts++ = '\0'; 00622 if (strchr(opts, 'n')) 00623 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); 00624 } 00625 00626 /* Look for a context */ 00627 if ((c = strchr(tmp->exten, '@'))) 00628 *c++ = '\0'; 00629 00630 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context)); 00631 00632 tmp->reqformat = format; 00633 00634 #if 0 00635 /* We can't do this check here, because we don't know the CallerID yet, and 00636 * the CallerID could potentially affect what step is actually taken (or 00637 * even if that step exists). */ 00638 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { 00639 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); 00640 tmp = local_pvt_destroy(tmp); 00641 } else { 00642 #endif 00643 /* Add to list */ 00644 AST_LIST_LOCK(&locals); 00645 AST_LIST_INSERT_HEAD(&locals, tmp, list); 00646 AST_LIST_UNLOCK(&locals); 00647 #if 0 00648 } 00649 #endif 00650 00651 return tmp; 00652 }
| static int local_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 215 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.
00216 { 00217 struct local_pvt *p = ast->tech_pvt; 00218 int isoutbound; 00219 int res = -1; 00220 00221 if (!p) 00222 return -1; 00223 00224 ast_mutex_lock(&p->lock); 00225 isoutbound = IS_OUTBOUND(ast, p); 00226 if (isoutbound) { 00227 /* Pass along answer since somebody answered us */ 00228 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00229 res = local_queue_frame(p, isoutbound, &answer, ast, 1); 00230 } else 00231 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n"); 00232 if (!res) 00233 ast_mutex_unlock(&p->lock); 00234 return res; 00235 }
| 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 460 of file chan_local.c.
References accountcode, ast_calloc, ast_cdr_update(), ast_channel_datastore_inherit(), ast_exists_extension(), AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), 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_ani2, ast_callerid::cid_dnid, ast_callerid::cid_name, ast_callerid::cid_num, ast_callerid::cid_pres, ast_callerid::cid_rdnis, ast_callerid::cid_tns, ast_callerid::cid_ton, ast_channel::context, ast_channel::exten, language, len, LOCAL_LAUNCHED_PBX, local_pvt::lock, LOG_NOTICE, ast_var_t::name, local_pvt::owner, ast_channel::tech_pvt, ast_var_t::value, and ast_channel::varshead.
00461 { 00462 struct local_pvt *p = ast->tech_pvt; 00463 int res; 00464 struct ast_var_t *varptr = NULL, *new; 00465 size_t len, namelen; 00466 00467 if (!p) 00468 return -1; 00469 00470 ast_mutex_lock(&p->lock); 00471 00472 /* 00473 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc 00474 * call, so it's done here instead. 00475 */ 00476 p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid); 00477 p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num); 00478 p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name); 00479 p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis); 00480 p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani); 00481 p->chan->cid.cid_pres = p->owner->cid.cid_pres; 00482 p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2; 00483 p->chan->cid.cid_ton = p->owner->cid.cid_ton; 00484 p->chan->cid.cid_tns = p->owner->cid.cid_tns; 00485 ast_string_field_set(p->chan, language, p->owner->language); 00486 ast_string_field_set(p->chan, accountcode, p->owner->accountcode); 00487 ast_cdr_update(p->chan); 00488 p->chan->cdrflags = p->owner->cdrflags; 00489 00490 if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) { 00491 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context); 00492 ast_mutex_unlock(&p->lock); 00493 return -1; 00494 } 00495 00496 /* copy the channel variables from the incoming channel to the outgoing channel */ 00497 /* Note that due to certain assumptions, they MUST be in the same order */ 00498 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) { 00499 namelen = strlen(varptr->name); 00500 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; 00501 if ((new = ast_calloc(1, len))) { 00502 memcpy(new, varptr, len); 00503 new->value = &(new->name[0]) + namelen + 1; 00504 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries); 00505 } 00506 } 00507 ast_channel_datastore_inherit(p->owner, p->chan); 00508 00509 /* Start switch on sub channel */ 00510 if (!(res = ast_pbx_start(p->chan))) 00511 ast_set_flag(p, LOCAL_LAUNCHED_PBX); 00512 00513 ast_mutex_unlock(&p->lock); 00514 return res; 00515 }
| 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 380 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.
00381 { 00382 struct local_pvt *p = ast->tech_pvt; 00383 int res = -1; 00384 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; 00385 int isoutbound; 00386 00387 if (!p) 00388 return -1; 00389 00390 ast_mutex_lock(&p->lock); 00391 isoutbound = IS_OUTBOUND(ast, p); 00392 f.subclass = digit; 00393 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00394 ast_mutex_unlock(&p->lock); 00395 00396 return res; 00397 }
| static int local_digit_end | ( | struct ast_channel * | ast, | |
| char | digit, | |||
| unsigned int | duration | |||
| ) | [static] |
Definition at line 399 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.
00400 { 00401 struct local_pvt *p = ast->tech_pvt; 00402 int res = -1; 00403 struct ast_frame f = { AST_FRAME_DTMF_END, }; 00404 int isoutbound; 00405 00406 if (!p) 00407 return -1; 00408 00409 ast_mutex_lock(&p->lock); 00410 isoutbound = IS_OUTBOUND(ast, p); 00411 f.subclass = digit; 00412 f.len = duration; 00413 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) 00414 ast_mutex_unlock(&p->lock); 00415 00416 return res; 00417 }
| static int local_fixup | ( | struct ast_channel * | oldchan, | |
| struct ast_channel * | newchan | |||
| ) | [static] |
Definition at line 329 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.
00330 { 00331 struct local_pvt *p = newchan->tech_pvt; 00332 00333 if (!p) 00334 return -1; 00335 00336 ast_mutex_lock(&p->lock); 00337 00338 if ((p->owner != oldchan) && (p->chan != oldchan)) { 00339 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); 00340 ast_mutex_unlock(&p->lock); 00341 return -1; 00342 } 00343 if (p->owner == oldchan) 00344 p->owner = newchan; 00345 else 00346 p->chan = newchan; 00347 ast_mutex_unlock(&p->lock); 00348 return 0; 00349 }
| static int local_hangup | ( | struct ast_channel * | ast | ) | [static] |
Hangup a call through the local proxy channel.
Definition at line 518 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, DEADLOCK_AVOIDANCE, 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.
00519 { 00520 struct local_pvt *p = ast->tech_pvt; 00521 int isoutbound; 00522 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP }; 00523 struct ast_channel *ochan = NULL; 00524 int glaredetect = 0, res = 0; 00525 00526 if (!p) 00527 return -1; 00528 00529 while (ast_mutex_trylock(&p->lock)) { 00530 ast_channel_unlock(ast); 00531 usleep(1); 00532 ast_channel_lock(ast); 00533 } 00534 00535 isoutbound = IS_OUTBOUND(ast, p); 00536 if (isoutbound) { 00537 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); 00538 if ((status) && (p->owner)) { 00539 /* Deadlock avoidance */ 00540 while (p->owner && ast_channel_trylock(p->owner)) { 00541 ast_mutex_unlock(&p->lock); 00542 if (ast) { 00543 ast_channel_unlock(ast); 00544 } 00545 usleep(1); 00546 if (ast) { 00547 ast_channel_lock(ast); 00548 } 00549 ast_mutex_lock(&p->lock); 00550 } 00551 if (p->owner) { 00552 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); 00553 ast_channel_unlock(p->owner); 00554 } 00555 } 00556 p->chan = NULL; 00557 ast_clear_flag(p, LOCAL_LAUNCHED_PBX); 00558 ast_module_user_remove(p->u_chan); 00559 } else { 00560 p->owner = NULL; 00561 ast_module_user_remove(p->u_owner); 00562 while (p->chan && ast_channel_trylock(p->chan)) { 00563 DEADLOCK_AVOIDANCE(&p->lock); 00564 } 00565 if (p->chan) { 00566 ast_queue_hangup(p->chan); 00567 ast_channel_unlock(p->chan); 00568 } 00569 } 00570 00571 ast->tech_pvt = NULL; 00572 00573 if (!p->owner && !p->chan) { 00574 /* Okay, done with the private part now, too. */ 00575 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT); 00576 /* If we have a queue holding, don't actually destroy p yet, but 00577 let local_queue do it. */ 00578 if (glaredetect) 00579 ast_set_flag(p, LOCAL_CANCEL_QUEUE); 00580 ast_mutex_unlock(&p->lock); 00581 /* Remove from list */ 00582 AST_LIST_LOCK(&locals); 00583 AST_LIST_REMOVE(&locals, p, list); 00584 AST_LIST_UNLOCK(&locals); 00585 /* Grab / release lock just in case */ 00586 ast_mutex_lock(&p->lock); 00587 ast_mutex_unlock(&p->lock); 00588 /* And destroy */ 00589 if (!glaredetect) { 00590 p = local_pvt_destroy(p); 00591 } 00592 return 0; 00593 } 00594 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) 00595 /* Need to actually hangup since there is no PBX */ 00596 ochan = p->chan; 00597 else 00598 res = local_queue_frame(p, isoutbound, &f, NULL, 1); 00599 if (!res) 00600 ast_mutex_unlock(&p->lock); 00601 if (ochan) 00602 ast_hangup(ochan); 00603 return 0; 00604 }
| static int local_indicate | ( | struct ast_channel * | ast, | |
| int | condition, | |||
| const void * | data, | |||
| size_t | datalen | |||
| ) | [static] |
Definition at line 351 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.
00352 { 00353 struct local_pvt *p = ast->tech_pvt; 00354 int res = 0; 00355 struct ast_frame f = { AST_FRAME_CONTROL, }; 00356 int isoutbound; 00357 00358 if (!p) 00359 return -1; 00360 00361 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */ 00362 if (condition == AST_CONTROL_HOLD) { 00363 ast_moh_start(ast, data, NULL); 00364 } else if (condition == AST_CONTROL_UNHOLD) { 00365 ast_moh_stop(ast); 00366 } else { 00367 /* Queue up a frame representing the indication as a control frame */ 00368 ast_mutex_lock(&p->lock); 00369 isoutbound = IS_OUTBOUND(ast, p); 00370 f.subclass = condition; 00371 f.data = (void*)data; 00372 f.datalen = datalen; 00373 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1))) 00374 ast_mutex_unlock(&p->lock); 00375 } 00376 00377 return res; 00378 }
| static struct ast_channel* local_new | ( | struct local_pvt * | p, | |
| int | state | |||
| ) | [static] |
Start new local channel.
Definition at line 655 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().
00656 { 00657 struct ast_channel *tmp = NULL, *tmp2 = NULL; 00658 int randnum = ast_random() & 0xffff, fmt = 0; 00659 const char *t; 00660 int ama; 00661 00662 /* Allocate two new Asterisk channels */ 00663 /* safe accountcode */ 00664 if (p->owner && p->owner->accountcode) 00665 t = p->owner->accountcode; 00666 else 00667 t = ""; 00668 00669 if (p->owner) 00670 ama = p->owner->amaflags; 00671 else 00672 ama = 0; 00673 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)) 00674 || !(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))) { 00675 if (tmp) 00676 ast_channel_free(tmp); 00677 if (tmp2) 00678 ast_channel_free(tmp2); 00679 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); 00680 return NULL; 00681 } 00682 00683 tmp2->tech = tmp->tech = &local_tech; 00684 00685 tmp->nativeformats = p->reqformat; 00686 tmp2->nativeformats = p->reqformat; 00687 00688 /* Determine our read/write format and set it on each channel */ 00689 fmt = ast_best_codec(p->reqformat); 00690 tmp->writeformat = fmt; 00691 tmp2->writeformat = fmt; 00692 tmp->rawwriteformat = fmt; 00693 tmp2->rawwriteformat = fmt; 00694 tmp->readformat = fmt; 00695 tmp2->readformat = fmt; 00696 tmp->rawreadformat = fmt; 00697 tmp2->rawreadformat = fmt; 00698 00699 tmp->tech_pvt = p; 00700 tmp2->tech_pvt = p; 00701 00702 p->owner = tmp; 00703 p->chan = tmp2; 00704 p->u_owner = ast_module_user_add(p->owner); 00705 p->u_chan = ast_module_user_add(p->chan); 00706 00707 ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); 00708 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); 00709 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); 00710 tmp->priority = 1; 00711 tmp2->priority = 1; 00712 00713 return tmp; 00714 }
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, ast_channel::generator, LOCAL_CANCEL_QUEUE, LOCAL_GLARE_DETECT, local_pvt_destroy(), local_pvt::lock, and local_pvt::owner.
Referenced by local_answer(), local_digit_begin(), local_digit_end(), local_hangup(), local_indicate(), local_sendhtml(), local_sendtext(), and local_write().
00165 { 00166 struct ast_channel *other = NULL; 00167 00168 /* Recalculate outbound channel */ 00169 other = isoutbound ? p->owner : p->