00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 281391 $")
00031
00032 #include <fcntl.h>
00033 #include <sys/signal.h>
00034
00035 #include "asterisk/lock.h"
00036 #include "asterisk/channel.h"
00037 #include "asterisk/config.h"
00038 #include "asterisk/module.h"
00039 #include "asterisk/pbx.h"
00040 #include "asterisk/sched.h"
00041 #include "asterisk/io.h"
00042 #include "asterisk/rtp.h"
00043 #include "asterisk/acl.h"
00044 #include "asterisk/callerid.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/cli.h"
00047 #include "asterisk/app.h"
00048 #include "asterisk/musiconhold.h"
00049 #include "asterisk/manager.h"
00050 #include "asterisk/stringfields.h"
00051 #include "asterisk/devicestate.h"
00052
00053 static const char tdesc[] = "Local Proxy Channel Driver";
00054
00055 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
00056
00057 static struct ast_jb_conf g_jb_conf = {
00058 .flags = 0,
00059 .max_size = -1,
00060 .resync_threshold = -1,
00061 .impl = "",
00062 .target_extra = -1,
00063 };
00064
00065 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause);
00066 static int local_digit_begin(struct ast_channel *ast, char digit);
00067 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
00068 static int local_call(struct ast_channel *ast, char *dest, int timeout);
00069 static int local_hangup(struct ast_channel *ast);
00070 static int local_answer(struct ast_channel *ast);
00071 static struct ast_frame *local_read(struct ast_channel *ast);
00072 static int local_write(struct ast_channel *ast, struct ast_frame *f);
00073 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
00074 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00075 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
00076 static int local_sendtext(struct ast_channel *ast, const char *text);
00077 static int local_devicestate(void *data);
00078 static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
00079 static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen);
00080
00081
00082 static const struct ast_channel_tech local_tech = {
00083 .type = "Local",
00084 .description = tdesc,
00085 .capabilities = -1,
00086 .requester = local_request,
00087 .send_digit_begin = local_digit_begin,
00088 .send_digit_end = local_digit_end,
00089 .call = local_call,
00090 .hangup = local_hangup,
00091 .answer = local_answer,
00092 .read = local_read,
00093 .write = local_write,
00094 .write_video = local_write,
00095 .exception = local_read,
00096 .indicate = local_indicate,
00097 .fixup = local_fixup,
00098 .send_html = local_sendhtml,
00099 .send_text = local_sendtext,
00100 .devicestate = local_devicestate,
00101 .bridged_channel = local_bridgedchannel,
00102 .queryoption = local_queryoption,
00103 };
00104
00105 struct local_pvt {
00106 ast_mutex_t lock;
00107 unsigned int flags;
00108 char context[AST_MAX_CONTEXT];
00109 char exten[AST_MAX_EXTENSION];
00110 int reqformat;
00111 struct ast_jb_conf jb_conf;
00112 struct ast_channel *owner;
00113 struct ast_channel *chan;
00114 struct ast_module_user *u_owner;
00115 struct ast_module_user *u_chan;
00116 AST_LIST_ENTRY(local_pvt) list;
00117 };
00118
00119 #define LOCAL_GLARE_DETECT (1 << 0)
00120 #define LOCAL_CANCEL_QUEUE (1 << 1)
00121 #define LOCAL_ALREADY_MASQED (1 << 2)
00122 #define LOCAL_LAUNCHED_PBX (1 << 3)
00123 #define LOCAL_NO_OPTIMIZATION (1 << 4)
00124 #define LOCAL_BRIDGE (1 << 5)
00125 #define LOCAL_MOH_PASSTHRU (1 << 6)
00126
00127 static AST_LIST_HEAD_STATIC(locals, local_pvt);
00128
00129
00130 static int local_devicestate(void *data)
00131 {
00132 char *exten = ast_strdupa(data);
00133 char *context = NULL, *opts = NULL;
00134 int res;
00135 struct local_pvt *lp;
00136
00137 if (!(context = strchr(exten, '@'))) {
00138 ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
00139 return AST_DEVICE_INVALID;
00140 }
00141
00142 *context++ = '\0';
00143
00144
00145 if ((opts = strchr(context, '/')))
00146 *opts = '\0';
00147
00148 ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
00149
00150 res = ast_exists_extension(NULL, context, exten, 1, NULL);
00151 if (!res)
00152 return AST_DEVICE_INVALID;
00153
00154 res = AST_DEVICE_NOT_INUSE;
00155 AST_LIST_LOCK(&locals);
00156 AST_LIST_TRAVERSE(&locals, lp, list) {
00157 if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) {
00158 res = AST_DEVICE_INUSE;
00159 break;
00160 }
00161 }
00162 AST_LIST_UNLOCK(&locals);
00163
00164 return res;
00165 }
00166
00167
00168
00169
00170 static struct local_pvt *local_pvt_destroy(struct local_pvt *pvt)
00171 {
00172 ast_mutex_destroy(&pvt->lock);
00173 ast_free(pvt);
00174 return NULL;
00175 }
00176
00177
00178 static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
00179 {
00180 struct local_pvt *p = bridge->tech_pvt;
00181 struct ast_channel *bridged = bridge;
00182
00183 if (!p) {
00184 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n",
00185 chan->name, bridge->name);
00186 return NULL;
00187 }
00188
00189 ast_mutex_lock(&p->lock);
00190
00191 if (ast_test_flag(p, LOCAL_BRIDGE)) {
00192
00193 bridged = (bridge == p->owner ? p->chan : p->owner);
00194
00195
00196 if (!bridged) {
00197 bridged = bridge;
00198 } else if (bridged->_bridge) {
00199 bridged = bridged->_bridge;
00200 }
00201 }
00202
00203 ast_mutex_unlock(&p->lock);
00204
00205 return bridged;
00206 }
00207
00208 static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
00209 {
00210 struct local_pvt *p = ast->tech_pvt;
00211 struct ast_channel *chan, *bridged;
00212 int res;
00213
00214 if (!p) {
00215 return -1;
00216 }
00217
00218 if (option != AST_OPTION_T38_STATE) {
00219
00220 return -1;
00221 }
00222
00223 ast_mutex_lock(&p->lock);
00224 chan = IS_OUTBOUND(ast, p) ? p->owner : p->chan;
00225
00226 try_again:
00227 if (!chan) {
00228 ast_mutex_unlock(&p->lock);
00229 return -1;
00230 }
00231
00232 if (ast_channel_trylock(chan)) {
00233 DEADLOCK_AVOIDANCE(&p->lock);
00234 chan = IS_OUTBOUND(ast, p) ? p->owner : p->chan;
00235 goto try_again;
00236 }
00237
00238 bridged = ast_bridged_channel(chan);
00239 if (!bridged) {
00240
00241 ast_mutex_unlock(&p->lock);
00242 ast_channel_unlock(chan);
00243 return -1;
00244 }
00245
00246 if (ast_channel_trylock(bridged)) {
00247 ast_channel_unlock(chan);
00248 DEADLOCK_AVOIDANCE(&p->lock);
00249 chan = IS_OUTBOUND(ast, p) ? p->owner : p->chan;
00250 goto try_again;
00251 }
00252
00253 res = ast_channel_queryoption(bridged, option, data, datalen, 0);
00254 ast_mutex_unlock(&p->lock);
00255 ast_channel_unlock(chan);
00256 ast_channel_unlock(bridged);
00257 return res;
00258 }
00259
00260 static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f,
00261 struct ast_channel *us, int us_locked)
00262 {
00263 struct ast_channel *other = NULL;
00264
00265
00266 other = isoutbound ? p->owner : p->chan;
00267
00268 if (!other) {
00269 return 0;
00270 }
00271
00272
00273 if (us && us->generator && other->generator) {
00274 return 0;
00275 }
00276
00277
00278 ast_set_flag(p, LOCAL_GLARE_DETECT);
00279
00280
00281 while (other && ast_channel_trylock(other)) {
00282 int res;
00283 if ((res = ast_mutex_unlock(&p->lock))) {
00284 ast_log(LOG_ERROR, "chan_local bug! '&p->lock' was not locked when entering local_queue_frame! (%s)\n", strerror(res));
00285 return -1;
00286 }
00287 if (us && us_locked) {
00288 do {
00289 CHANNEL_DEADLOCK_AVOIDANCE(us);
00290 } while (ast_mutex_trylock(&p->lock));
00291 } else {
00292 usleep(1);
00293 ast_mutex_lock(&p->lock);
00294 }
00295 other = isoutbound ? p->owner : p->chan;
00296 }
00297
00298
00299
00300
00301 if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) {
00302
00303
00304 ast_mutex_unlock(&p->lock);
00305 p = local_pvt_destroy(p);
00306 if (other) {
00307 ast_channel_unlock(other);
00308 }
00309 return -1;
00310 }
00311
00312 if (other) {
00313 if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_RINGING) {
00314 ast_setstate(other, AST_STATE_RINGING);
00315 }
00316 ast_queue_frame(other, f);
00317 ast_channel_unlock(other);
00318 }
00319
00320 ast_clear_flag(p, LOCAL_GLARE_DETECT);
00321
00322 return 0;
00323 }
00324
00325 static int local_answer(struct ast_channel *ast)
00326 {
00327 struct local_pvt *p = ast->tech_pvt;
00328 int isoutbound;
00329 int res = -1;
00330
00331 if (!p)
00332 return -1;
00333
00334 ast_mutex_lock(&p->lock);
00335 isoutbound = IS_OUTBOUND(ast, p);
00336 if (isoutbound) {
00337
00338 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00339 res = local_queue_frame(p, isoutbound, &answer, ast, 1);
00340 } else
00341 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n");
00342 if (!res)
00343 ast_mutex_unlock(&p->lock);
00344 return res;
00345 }
00346
00347
00348
00349
00350
00351 static void check_bridge(struct local_pvt *p)
00352 {
00353 struct ast_channel_monitor *tmp;
00354 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)))
00355 return;
00356
00357
00358
00359
00360
00361
00362 if (p->chan->_bridge && AST_LIST_EMPTY(&p->owner->readq)) {
00363
00364
00365
00366
00367 if (!ast_channel_trylock(p->chan->_bridge)) {
00368 if (!ast_check_hangup(p->chan->_bridge)) {
00369 if (!ast_channel_trylock(p->owner)) {
00370 if (!ast_check_hangup(p->owner)) {
00371 if (p->owner->monitor && !p->chan->_bridge->monitor) {
00372
00373
00374
00375
00376
00377 tmp = p->owner->monitor;
00378 p->owner->monitor = p->chan->_bridge->monitor;
00379 p->chan->_bridge->monitor = tmp;
00380 }
00381 if (p->chan->audiohooks) {
00382 struct ast_audiohook_list *audiohooks_swapper;
00383 audiohooks_swapper = p->chan->audiohooks;
00384 p->chan->audiohooks = p->owner->audiohooks;
00385 p->owner->audiohooks = audiohooks_swapper;
00386 }
00387
00388
00389
00390
00391
00392
00393
00394
00395 if (p->owner->cid.cid_dnid || p->owner->cid.cid_num ||
00396 p->owner->cid.cid_name || p->owner->cid.cid_ani ||
00397 p->owner->cid.cid_rdnis || p->owner->cid.cid_pres ||
00398 p->owner->cid.cid_ani2 || p->owner->cid.cid_ton ||
00399 p->owner->cid.cid_tns) {
00400
00401 struct ast_callerid tmpcid;
00402 tmpcid = p->owner->cid;
00403 p->owner->cid = p->chan->_bridge->cid;
00404 p->chan->_bridge->cid = tmpcid;
00405 }
00406
00407 ast_app_group_update(p->chan, p->owner);
00408 ast_channel_masquerade(p->owner, p->chan->_bridge);
00409 ast_set_flag(p, LOCAL_ALREADY_MASQED);
00410 }
00411 ast_channel_unlock(p->owner);
00412 }
00413 ast_channel_unlock(p->chan->_bridge);
00414 }
00415 }
00416 }
00417 }
00418
00419 static struct ast_frame *local_read(struct ast_channel *ast)
00420 {
00421 return &ast_null_frame;
00422 }
00423
00424 static int local_write(struct ast_channel *ast, struct ast_frame *f)
00425 {
00426 struct local_pvt *p = ast->tech_pvt;
00427 int res = -1;
00428 int isoutbound;
00429
00430 if (!p)
00431 return -1;
00432
00433
00434 ast_mutex_lock(&p->lock);
00435 isoutbound = IS_OUTBOUND(ast, p);
00436 if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
00437 check_bridge(p);
00438 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
00439 res = local_queue_frame(p, isoutbound, f, ast, 1);
00440 else {
00441 ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name);
00442 res = 0;
00443 }
00444 if (!res)
00445 ast_mutex_unlock(&p->lock);
00446 return res;
00447 }
00448
00449 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00450 {
00451 struct local_pvt *p = newchan->tech_pvt;
00452
00453 if (!p)
00454 return -1;
00455
00456 ast_mutex_lock(&p->lock);
00457
00458 if ((p->owner != oldchan) && (p->chan != oldchan)) {
00459 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00460 ast_mutex_unlock(&p->lock);
00461 return -1;
00462 }
00463 if (p->owner == oldchan)
00464 p->owner = newchan;
00465 else
00466 p->chan = newchan;
00467 ast_mutex_unlock(&p->lock);
00468 return 0;
00469 }
00470
00471 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
00472 {
00473 struct local_pvt *p = ast->tech_pvt;
00474 int res = 0;
00475 struct ast_frame f = { AST_FRAME_CONTROL, };
00476 int isoutbound;
00477
00478 if (!p)
00479 return -1;
00480
00481
00482 if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
00483 ast_moh_start(ast, data, NULL);
00484 } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
00485 ast_moh_stop(ast);
00486 } else {
00487
00488 ast_mutex_lock(&p->lock);
00489 isoutbound = IS_OUTBOUND(ast, p);
00490 f.subclass = condition;
00491 f.data.ptr = (void*)data;
00492 f.datalen = datalen;
00493 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1)))
00494 ast_mutex_unlock(&p->lock);
00495 }
00496
00497 return res;
00498 }
00499
00500 static int local_digit_begin(struct ast_channel *ast, char digit)
00501 {
00502 struct local_pvt *p = ast->tech_pvt;
00503 int res = -1;
00504 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00505 int isoutbound;
00506
00507 if (!p)
00508 return -1;
00509
00510 ast_mutex_lock(&p->lock);
00511 isoutbound = IS_OUTBOUND(ast, p);
00512 f.subclass = digit;
00513 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00514 ast_mutex_unlock(&p->lock);
00515
00516 return res;
00517 }
00518
00519 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
00520 {
00521 struct local_pvt *p = ast->tech_pvt;
00522 int res = -1;
00523 struct ast_frame f = { AST_FRAME_DTMF_END, };
00524 int isoutbound;
00525
00526 if (!p)
00527 return -1;
00528
00529 ast_mutex_lock(&p->lock);
00530 isoutbound = IS_OUTBOUND(ast, p);
00531 f.subclass = digit;
00532 f.len = duration;
00533 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00534 ast_mutex_unlock(&p->lock);
00535
00536 return res;
00537 }
00538
00539 static int local_sendtext(struct ast_channel *ast, const char *text)
00540 {
00541 struct local_pvt *p = ast->tech_pvt;
00542 int res = -1;
00543 struct ast_frame f = { AST_FRAME_TEXT, };
00544 int isoutbound;
00545
00546 if (!p)
00547 return -1;
00548
00549 ast_mutex_lock(&p->lock);
00550 isoutbound = IS_OUTBOUND(ast, p);
00551 f.data.ptr = (char *) text;
00552 f.datalen = strlen(text) + 1;
00553 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00554 ast_mutex_unlock(&p->lock);
00555 return res;
00556 }
00557
00558 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
00559 {
00560 struct local_pvt *p = ast->tech_pvt;
00561 int res = -1;
00562 struct ast_frame f = { AST_FRAME_HTML, };
00563 int isoutbound;
00564
00565 if (!p)
00566 return -1;
00567
00568 ast_mutex_lock(&p->lock);
00569 isoutbound = IS_OUTBOUND(ast, p);
00570 f.subclass = subclass;
00571 f.data.ptr = (char *)data;
00572 f.datalen = datalen;
00573 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00574 ast_mutex_unlock(&p->lock);
00575 return res;
00576 }
00577
00578
00579
00580 static int local_call(struct ast_channel *ast, char *dest, int timeout)
00581 {
00582 struct local_pvt *p = ast->tech_pvt;
00583 int res;
00584 struct ast_var_t *varptr = NULL, *new;
00585 size_t len, namelen;
00586
00587 if (!p)
00588 return -1;
00589
00590 ast_mutex_lock(&p->lock);
00591
00592
00593
00594
00595
00596 p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid);
00597 p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
00598 p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
00599 p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
00600 p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
00601 p->chan->cid.cid_pres = p->owner->cid.cid_pres;
00602 p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2;
00603 p->chan->cid.cid_ton = p->owner->cid.cid_ton;
00604 p->chan->cid.cid_tns = p->owner->cid.cid_tns;
00605 ast_string_field_set(p->chan, language, p->owner->language);
00606 ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
00607 ast_string_field_set(p->chan, musicclass, p->owner->musicclass);
00608 ast_cdr_update(p->chan);
00609 p->chan->cdrflags = p->owner->cdrflags;
00610
00611 if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) {
00612 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context);
00613 ast_mutex_unlock(&p->lock);
00614 return -1;
00615 }
00616
00617
00618 if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00619 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00620 }
00621
00622
00623
00624 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
00625 namelen = strlen(varptr->name);
00626 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00627 if ((new = ast_calloc(1, len))) {
00628 memcpy(new, varptr, len);
00629 new->value = &(new->name[0]) + namelen + 1;
00630 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
00631 }
00632 }
00633 ast_channel_datastore_inherit(p->owner, p->chan);
00634
00635
00636 if (!(res = ast_pbx_start(p->chan)))
00637 ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00638
00639 ast_mutex_unlock(&p->lock);
00640 return res;
00641 }
00642
00643
00644 static int local_hangup(struct ast_channel *ast)
00645 {
00646 struct local_pvt *p = ast->tech_pvt;
00647 int isoutbound;
00648 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP, .data.uint32 = ast->hangupcause };
00649 struct ast_channel *ochan = NULL;
00650 int glaredetect = 0, res = 0;
00651
00652 if (!p)
00653 return -1;
00654
00655 ast_mutex_lock(&p->lock);
00656
00657 isoutbound = IS_OUTBOUND(ast, p);
00658
00659 if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00660 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00661 ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n");
00662 }
00663
00664 if (isoutbound) {
00665 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00666 if ((status) && (p->owner)) {
00667
00668 while (p->owner && ast_channel_trylock(p->owner)) {
00669 ast_mutex_unlock(&p->lock);
00670 if (p->chan) {
00671 ast_channel_unlock(p->chan);
00672 }
00673 usleep(1);
00674 if (p->chan) {
00675 ast_channel_lock(p->chan);
00676 }
00677 ast_mutex_lock(&p->lock);
00678 }
00679 if (p->owner) {
00680 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00681 ast_channel_unlock(p->owner);
00682 }
00683 }
00684 p->chan = NULL;
00685 ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
00686 ast_module_user_remove(p->u_chan);
00687 } else {
00688 ast_module_user_remove(p->u_owner);
00689 while (p->chan && ast_channel_trylock(p->chan)) {
00690 ast_mutex_unlock(&p->lock);
00691 if (p->owner) {
00692 ast_channel_unlock(p->owner);
00693 }
00694 usleep(1);
00695 if (p->owner) {
00696 ast_channel_lock(p->owner);
00697 }
00698 ast_mutex_lock(&p->lock);
00699 }
00700
00701 p->owner = NULL;
00702 if (p->chan) {
00703 ast_queue_hangup(p->chan);
00704 ast_channel_unlock(p->chan);
00705 }
00706 }
00707
00708 ast->tech_pvt = NULL;
00709
00710 if (!p->owner && !p->chan) {
00711
00712 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
00713
00714
00715 if (glaredetect)
00716 ast_set_flag(p, LOCAL_CANCEL_QUEUE);
00717
00718 AST_LIST_LOCK(&locals);
00719 AST_LIST_REMOVE(&locals, p, list);
00720 AST_LIST_UNLOCK(&locals);
00721 ast_mutex_unlock(&p->lock);
00722
00723 if (!glaredetect) {
00724 p = local_pvt_destroy(p);
00725 }
00726 return 0;
00727 }
00728 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
00729
00730 ochan = p->chan;
00731 else
00732 res = local_queue_frame(p, isoutbound, &f, NULL, 1);
00733 if (!res)
00734 ast_mutex_unlock(&p->lock);
00735 if (ochan)
00736 ast_hangup(ochan);
00737 return 0;
00738 }
00739
00740
00741 static struct local_pvt *local_alloc(const char *data, int format)
00742 {
00743 struct local_pvt *tmp = NULL;
00744 char *c = NULL, *opts = NULL;
00745
00746 if (!(tmp = ast_calloc(1, sizeof(*tmp))))
00747 return NULL;
00748
00749
00750 ast_mutex_init(&tmp->lock);
00751 ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
00752
00753 memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
00754
00755
00756 if ((opts = strchr(tmp->exten, '/'))) {
00757 *opts++ = '\0';
00758 if (strchr(opts, 'n'))
00759 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
00760 if (strchr(opts, 'j')) {
00761 if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
00762 ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
00763 else {
00764 ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
00765 "to use the 'j' option to enable the jitterbuffer\n");
00766 }
00767 }
00768 if (strchr(opts, 'b')) {
00769 ast_set_flag(tmp, LOCAL_BRIDGE);
00770 }
00771 if (strchr(opts, 'm')) {
00772 ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
00773 }
00774 }
00775
00776
00777 if ((c = strchr(tmp->exten, '@')))
00778 *c++ = '\0';
00779
00780 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
00781
00782 tmp->reqformat = format;
00783
00784 #if 0
00785
00786
00787
00788 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
00789 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
00790 tmp = local_pvt_destroy(tmp);
00791 } else {
00792 #endif
00793
00794 AST_LIST_LOCK(&locals);
00795 AST_LIST_INSERT_HEAD(&locals, tmp, list);
00796 AST_LIST_UNLOCK(&locals);
00797 #if 0
00798 }
00799 #endif
00800
00801 return tmp;
00802 }
00803
00804
00805 static struct ast_channel *local_new(struct local_pvt *p, int state)
00806 {
00807 struct ast_channel *tmp = NULL, *tmp2 = NULL;
00808 int randnum = ast_random() & 0xffff, fmt = 0;
00809 const char *t;
00810 int ama;
00811
00812
00813
00814 if (p->owner && p->owner->accountcode)
00815 t = p->owner->accountcode;
00816 else
00817 t = "";
00818
00819 if (p->owner)
00820 ama = p->owner->amaflags;
00821 else
00822 ama = 0;
00823 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))
00824 || !(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))) {
00825 if (tmp)
00826 ast_channel_free(tmp);
00827 if (tmp2)
00828 ast_channel_free(tmp2);
00829 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
00830 return NULL;
00831 }
00832
00833 tmp2->tech = tmp->tech = &local_tech;
00834
00835 tmp->nativeformats = p->reqformat;
00836 tmp2->nativeformats = p->reqformat;
00837
00838
00839 fmt = ast_best_codec(p->reqformat);
00840 tmp->writeformat = fmt;
00841 tmp2->writeformat = fmt;
00842 tmp->rawwriteformat = fmt;
00843 tmp2->rawwriteformat = fmt;
00844 tmp->readformat = fmt;
00845 tmp2->readformat = fmt;
00846 tmp->rawreadformat = fmt;
00847 tmp2->rawreadformat = fmt;
00848
00849 tmp->tech_pvt = p;
00850 tmp2->tech_pvt = p;
00851
00852 p->owner = tmp;
00853 p->chan = tmp2;
00854 p->u_owner = ast_module_user_add(p->owner);
00855 p->u_chan = ast_module_user_add(p->chan);
00856
00857 ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
00858 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
00859 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
00860 tmp->priority = 1;
00861 tmp2->priority = 1;
00862
00863 ast_jb_configure(tmp, &p->jb_conf);
00864
00865 return tmp;
00866 }
00867
00868
00869 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
00870 {
00871 struct local_pvt *p = NULL;
00872 struct ast_channel *chan = NULL;
00873
00874
00875 if ((p = local_alloc(data, format))) {
00876 if (!(chan = local_new(p, AST_STATE_DOWN))) {
00877 AST_LIST_LOCK(&locals);
00878 AST_LIST_REMOVE(&locals, p, list);
00879 AST_LIST_UNLOCK(&locals);
00880 p = local_pvt_destroy(p);
00881 }
00882 }
00883
00884 return chan;
00885 }
00886
00887
00888 static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00889 {
00890 struct local_pvt *p = NULL;
00891
00892 switch (cmd) {
00893 case CLI_INIT:
00894 e->command = "local show channels";
00895 e->usage =
00896 "Usage: local show channels\n"
00897 " Provides summary information on active local proxy channels.\n";
00898 return NULL;
00899 case CLI_GENERATE:
00900 return NULL;
00901 }
00902
00903 if (a->argc != 3)
00904 return CLI_SHOWUSAGE;
00905
00906 AST_LIST_LOCK(&locals);
00907 if (!AST_LIST_EMPTY(&locals)) {
00908 AST_LIST_TRAVERSE(&locals, p, list) {
00909 ast_mutex_lock(&p->lock);
00910 ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
00911 ast_mutex_unlock(&p->lock);
00912 }
00913 } else
00914 ast_cli(a->fd, "No local channels in use\n");
00915 AST_LIST_UNLOCK(&locals);
00916
00917 return CLI_SUCCESS;
00918 }
00919
00920 static struct ast_cli_entry cli_local[] = {
00921 AST_CLI_DEFINE(locals_show, "List status of local channels"),
00922 };
00923
00924
00925 static int load_module(void)
00926 {
00927
00928 if (ast_channel_register(&local_tech)) {
00929 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
00930 return AST_MODULE_LOAD_FAILURE;
00931 }
00932 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00933 return AST_MODULE_LOAD_SUCCESS;
00934 }
00935
00936
00937 static int unload_module(void)
00938 {
00939 struct local_pvt *p = NULL;
00940
00941
00942 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00943 ast_channel_unregister(&local_tech);
00944 if (!AST_LIST_LOCK(&locals)) {
00945
00946 AST_LIST_TRAVERSE(&locals, p, list) {
00947 if (p->owner)
00948 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
00949 }
00950 AST_LIST_UNLOCK(&locals);
00951 } else {
00952 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
00953 return -1;
00954 }
00955 return 0;
00956 }
00957
00958 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Local Proxy Channel (Note: used internally by other modules)");