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