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
00029
00030
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 414269 $")
00035
00036 #include <fcntl.h>
00037 #include <sys/signal.h>
00038
00039 #include "asterisk/lock.h"
00040 #include "asterisk/causes.h"
00041 #include "asterisk/channel.h"
00042 #include "asterisk/config.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/pbx.h"
00045 #include "asterisk/sched.h"
00046 #include "asterisk/io.h"
00047 #include "asterisk/acl.h"
00048 #include "asterisk/callerid.h"
00049 #include "asterisk/file.h"
00050 #include "asterisk/cli.h"
00051 #include "asterisk/app.h"
00052 #include "asterisk/musiconhold.h"
00053 #include "asterisk/manager.h"
00054 #include "asterisk/stringfields.h"
00055 #include "asterisk/devicestate.h"
00056 #include "asterisk/astobj2.h"
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 static const char tdesc[] = "Local Proxy Channel Driver";
00078
00079 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
00080
00081
00082
00083
00084 static const int BUCKET_SIZE = 1;
00085
00086 static struct ao2_container *locals;
00087
00088 static unsigned int name_sequence = 0;
00089
00090 static struct ast_jb_conf g_jb_conf = {
00091 .flags = 0,
00092 .max_size = -1,
00093 .resync_threshold = -1,
00094 .impl = "",
00095 .target_extra = -1,
00096 };
00097
00098 static struct ast_channel *local_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause);
00099 static int local_digit_begin(struct ast_channel *ast, char digit);
00100 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
00101 static int local_call(struct ast_channel *ast, char *dest, int timeout);
00102 static int local_hangup(struct ast_channel *ast);
00103 static int local_answer(struct ast_channel *ast);
00104 static struct ast_frame *local_read(struct ast_channel *ast);
00105 static int local_write(struct ast_channel *ast, struct ast_frame *f);
00106 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
00107 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00108 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
00109 static int local_sendtext(struct ast_channel *ast, const char *text);
00110 static int local_devicestate(void *data);
00111 static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
00112 static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen);
00113 static int local_setoption(struct ast_channel *chan, int option, void *data, int datalen);
00114
00115
00116 static const struct ast_channel_tech local_tech = {
00117 .type = "Local",
00118 .description = tdesc,
00119 .capabilities = -1,
00120 .requester = local_request,
00121 .send_digit_begin = local_digit_begin,
00122 .send_digit_end = local_digit_end,
00123 .call = local_call,
00124 .hangup = local_hangup,
00125 .answer = local_answer,
00126 .read = local_read,
00127 .write = local_write,
00128 .write_video = local_write,
00129 .exception = local_read,
00130 .indicate = local_indicate,
00131 .fixup = local_fixup,
00132 .send_html = local_sendhtml,
00133 .send_text = local_sendtext,
00134 .devicestate = local_devicestate,
00135 .bridged_channel = local_bridgedchannel,
00136 .queryoption = local_queryoption,
00137 .setoption = local_setoption,
00138 };
00139
00140
00141
00142
00143
00144
00145
00146
00147 struct local_pvt {
00148 unsigned int flags;
00149 char context[AST_MAX_CONTEXT];
00150 char exten[AST_MAX_EXTENSION];
00151 format_t reqformat;
00152 struct ast_jb_conf jb_conf;
00153 struct ast_channel *owner;
00154 struct ast_channel *chan;
00155 };
00156
00157 #define LOCAL_ALREADY_MASQED (1 << 0)
00158 #define LOCAL_LAUNCHED_PBX (1 << 1)
00159 #define LOCAL_NO_OPTIMIZATION (1 << 2)
00160 #define LOCAL_BRIDGE (1 << 3)
00161 #define LOCAL_MOH_PASSTHRU (1 << 4)
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172 static void awesome_locking(struct local_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
00173 {
00174 struct ast_channel *chan = NULL;
00175 struct ast_channel *owner = NULL;
00176
00177 for (;;) {
00178 ao2_lock(p);
00179 if (p->chan) {
00180 chan = p->chan;
00181 ast_channel_ref(chan);
00182 }
00183 if (p->owner) {
00184 owner = p->owner;
00185 ast_channel_ref(owner);
00186 }
00187 ao2_unlock(p);
00188
00189
00190 if (!owner || !chan) {
00191 if (owner) {
00192 ast_channel_lock(owner);
00193 } else if(chan) {
00194 ast_channel_lock(chan);
00195 }
00196 ao2_lock(p);
00197 } else {
00198
00199 ast_channel_lock(chan);
00200 while (ast_channel_trylock(owner)) {
00201 CHANNEL_DEADLOCK_AVOIDANCE(chan);
00202 }
00203 ao2_lock(p);
00204 }
00205
00206
00207 if (p->owner != owner || p->chan != chan) {
00208 if (owner) {
00209 ast_channel_unlock(owner);
00210 owner = ast_channel_unref(owner);
00211 }
00212 if (chan) {
00213 ast_channel_unlock(chan);
00214 chan = ast_channel_unref(chan);
00215 }
00216 ao2_unlock(p);
00217 continue;
00218 }
00219
00220 break;
00221 }
00222 *outowner = p->owner;
00223 *outchan = p->chan;
00224 }
00225
00226
00227 static int local_setoption(struct ast_channel *ast, int option, void * data, int datalen)
00228 {
00229 int res = 0;
00230 struct local_pvt *p = NULL;
00231 struct ast_channel *otherchan = NULL;
00232 ast_chan_write_info_t *write_info;
00233
00234 if (option != AST_OPTION_CHANNEL_WRITE) {
00235 return -1;
00236 }
00237
00238 write_info = data;
00239
00240 if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) {
00241 ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n");
00242 return -1;
00243 }
00244
00245
00246 if (!(p = ast->tech_pvt)) {
00247 return -1;
00248 }
00249 ao2_ref(p, 1);
00250 ast_channel_unlock(ast);
00251
00252
00253 ao2_lock(p);
00254 otherchan = (write_info->chan == p->owner) ? p->chan : p->owner;
00255 if (!otherchan || otherchan == write_info->chan) {
00256 res = -1;
00257 otherchan = NULL;
00258 ao2_unlock(p);
00259 goto setoption_cleanup;
00260 }
00261 ast_channel_ref(otherchan);
00262
00263
00264 ao2_unlock(p);
00265
00266 ast_channel_lock(otherchan);
00267 res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value);
00268 ast_channel_unlock(otherchan);
00269
00270 setoption_cleanup:
00271 if (p) {
00272 ao2_ref(p, -1);
00273 }
00274 if (otherchan) {
00275 ast_channel_unref(otherchan);
00276 }
00277 ast_channel_lock(ast);
00278 return res;
00279 }
00280
00281
00282 static int local_devicestate(void *data)
00283 {
00284 char *exten = ast_strdupa(data);
00285 char *context = NULL, *opts = NULL;
00286 int res;
00287 struct local_pvt *lp;
00288 struct ao2_iterator it;
00289
00290 if (!(context = strchr(exten, '@'))) {
00291 ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
00292 return AST_DEVICE_INVALID;
00293 }
00294
00295 *context++ = '\0';
00296
00297
00298 if ((opts = strchr(context, '/')))
00299 *opts = '\0';
00300
00301 ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
00302
00303 res = ast_exists_extension(NULL, context, exten, 1, NULL);
00304 if (!res)
00305 return AST_DEVICE_INVALID;
00306
00307 res = AST_DEVICE_NOT_INUSE;
00308
00309 it = ao2_iterator_init(locals, 0);
00310 for (; (lp = ao2_iterator_next(&it)); ao2_ref(lp, -1)) {
00311 int is_inuse;
00312
00313 ao2_lock(lp);
00314 is_inuse = !strcmp(exten, lp->exten)
00315 && !strcmp(context, lp->context)
00316 && lp->owner
00317 && ast_test_flag(lp, LOCAL_LAUNCHED_PBX);
00318 ao2_unlock(lp);
00319 if (is_inuse) {
00320 res = AST_DEVICE_INUSE;
00321 ao2_ref(lp, -1);
00322 break;
00323 }
00324 }
00325 ao2_iterator_destroy(&it);
00326
00327 return res;
00328 }
00329
00330
00331 static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
00332 {
00333 struct local_pvt *p = bridge->tech_pvt;
00334 struct ast_channel *bridged = bridge;
00335
00336 if (!p) {
00337 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n",
00338 chan->name, bridge->name);
00339 return NULL;
00340 }
00341
00342 ao2_lock(p);
00343
00344 if (ast_test_flag(p, LOCAL_BRIDGE)) {
00345
00346 bridged = (bridge == p->owner ? p->chan : p->owner);
00347
00348
00349 if (!bridged) {
00350 bridged = bridge;
00351 } else if (bridged->_bridge) {
00352 bridged = bridged->_bridge;
00353 }
00354 }
00355
00356 ao2_unlock(p);
00357
00358 return bridged;
00359 }
00360
00361
00362 static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
00363 {
00364 struct local_pvt *p;
00365 struct ast_channel *bridged = NULL;
00366 struct ast_channel *tmp = NULL;
00367 int res = 0;
00368
00369 if (option != AST_OPTION_T38_STATE) {
00370
00371 return -1;
00372 }
00373
00374
00375 if (!(p = ast->tech_pvt)) {
00376 return -1;
00377 }
00378
00379 ao2_lock(p);
00380 if (!(tmp = IS_OUTBOUND(ast, p) ? p->owner : p->chan)) {
00381 ao2_unlock(p);
00382 return -1;
00383 }
00384 ast_channel_ref(tmp);
00385 ao2_unlock(p);
00386 ast_channel_unlock(ast);
00387
00388 ast_channel_lock(tmp);
00389 if (!(bridged = ast_bridged_channel(tmp))) {
00390 res = -1;
00391 ast_channel_unlock(tmp);
00392 goto query_cleanup;
00393 }
00394 ast_channel_ref(bridged);
00395 ast_channel_unlock(tmp);
00396
00397 query_cleanup:
00398 if (bridged) {
00399 res = ast_channel_queryoption(bridged, option, data, datalen, 0);
00400 bridged = ast_channel_unref(bridged);
00401 }
00402 if (tmp) {
00403 tmp = ast_channel_unref(tmp);
00404 }
00405 ast_channel_lock(ast);
00406
00407 return res;
00408 }
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418 static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f,
00419 struct ast_channel *us, int us_locked)
00420 {
00421 struct ast_channel *other = NULL;
00422
00423
00424 other = isoutbound ? p->owner : p->chan;
00425
00426 if (!other) {
00427 return 0;
00428 }
00429
00430
00431 if (us
00432 && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)
00433 && us->generator
00434 && other->generator) {
00435 return 0;
00436 }
00437
00438
00439
00440 ast_channel_ref(other);
00441 if (us && us_locked) {
00442 ast_channel_unlock(us);
00443 }
00444 ao2_unlock(p);
00445
00446 if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) {
00447 ast_setstate(other, AST_STATE_RINGING);
00448 }
00449 ast_queue_frame(other, f);
00450
00451 other = ast_channel_unref(other);
00452 if (us && us_locked) {
00453 ast_channel_lock(us);
00454 }
00455 ao2_lock(p);
00456
00457 return 0;
00458 }
00459
00460 static int local_answer(struct ast_channel *ast)
00461 {
00462 struct local_pvt *p = ast->tech_pvt;
00463 int isoutbound;
00464 int res = -1;
00465
00466 if (!p)
00467 return -1;
00468
00469 ao2_lock(p);
00470 ao2_ref(p, 1);
00471 isoutbound = IS_OUTBOUND(ast, p);
00472 if (isoutbound) {
00473
00474 struct ast_frame answer = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
00475 res = local_queue_frame(p, isoutbound, &answer, ast, 1);
00476 } else {
00477 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n");
00478 }
00479 ao2_unlock(p);
00480 ao2_ref(p, -1);
00481 return res;
00482 }
00483
00484
00485
00486
00487
00488
00489
00490 static void check_bridge(struct ast_channel *ast, struct local_pvt *p)
00491 {
00492 struct ast_channel *owner;
00493 struct ast_channel *chan;
00494 struct ast_channel *bridged_chan;
00495 struct ast_frame *f;
00496
00497
00498 if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED)
00499 || !p->chan || !p->owner) {
00500 return;
00501 }
00502
00503
00504 chan = ast_channel_ref(p->chan);
00505
00506 ao2_unlock(p);
00507 bridged_chan = ast_bridged_channel(chan);
00508 ao2_lock(p);
00509
00510 chan = ast_channel_unref(chan);
00511
00512
00513
00514
00515 if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED)
00516 || !p->chan || !p->owner
00517 || (p->chan->_bridge != bridged_chan)) {
00518 return;
00519 }
00520
00521
00522
00523
00524
00525
00526 if (!p->chan->_bridge
00527 || !AST_LIST_EMPTY(&p->owner->readq)
00528 || ast != p->chan ) {
00529 return;
00530 }
00531
00532
00533
00534
00535
00536 if (ast_channel_trylock(p->chan->_bridge)) {
00537 return;
00538 }
00539 if (ast_check_hangup(p->chan->_bridge) || ast_channel_trylock(p->owner)) {
00540 ast_channel_unlock(p->chan->_bridge);
00541 return;
00542 }
00543
00544
00545
00546
00547
00548
00549
00550
00551 f = AST_LIST_FIRST(&p->chan->readq);
00552 if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
00553 AST_LIST_REMOVE_HEAD(&p->chan->readq, frame_list);
00554 ast_frfree(f);
00555 f = AST_LIST_FIRST(&p->chan->readq);
00556 }
00557
00558 if (f
00559 || ast_check_hangup(p->owner)
00560 || ast_channel_masquerade(p->owner, p->chan->_bridge)) {
00561 ast_channel_unlock(p->owner);
00562 ast_channel_unlock(p->chan->_bridge);
00563 return;
00564 }
00565
00566
00567 ast_debug(4, "Masquerading %s <- %s\n",
00568 p->owner->name, p->chan->_bridge->name);
00569 if (p->owner->monitor && !p->chan->_bridge->monitor) {
00570 struct ast_channel_monitor *tmp;
00571
00572
00573
00574
00575
00576
00577 tmp = p->owner->monitor;
00578 p->owner->monitor = p->chan->_bridge->monitor;
00579 p->chan->_bridge->monitor = tmp;
00580 }
00581 if (p->chan->audiohooks) {
00582 struct ast_audiohook_list *audiohooks_swapper;
00583
00584 audiohooks_swapper = p->chan->audiohooks;
00585 p->chan->audiohooks = p->owner->audiohooks;
00586 p->owner->audiohooks = audiohooks_swapper;
00587 }
00588
00589
00590
00591
00592
00593
00594
00595
00596 if (p->owner->caller.id.name.valid || p->owner->caller.id.number.valid
00597 || p->owner->caller.id.subaddress.valid || p->owner->caller.ani.name.valid
00598 || p->owner->caller.ani.number.valid || p->owner->caller.ani.subaddress.valid) {
00599 struct ast_party_caller tmp;
00600
00601 tmp = p->owner->caller;
00602 p->owner->caller = p->chan->_bridge->caller;
00603 p->chan->_bridge->caller = tmp;
00604 }
00605 if (p->owner->redirecting.from.name.valid || p->owner->redirecting.from.number.valid
00606 || p->owner->redirecting.from.subaddress.valid || p->owner->redirecting.to.name.valid
00607 || p->owner->redirecting.to.number.valid || p->owner->redirecting.to.subaddress.valid) {
00608 struct ast_party_redirecting tmp;
00609
00610 tmp = p->owner->redirecting;
00611 p->owner->redirecting = p->chan->_bridge->redirecting;
00612 p->chan->_bridge->redirecting = tmp;
00613 }
00614 if (p->owner->dialed.number.str || p->owner->dialed.subaddress.valid) {
00615 struct ast_party_dialed tmp;
00616
00617 tmp = p->owner->dialed;
00618 p->owner->dialed = p->chan->_bridge->dialed;
00619 p->chan->_bridge->dialed = tmp;
00620 }
00621 ast_app_group_update(p->chan, p->owner);
00622 ast_set_flag(p, LOCAL_ALREADY_MASQED);
00623
00624 ast_channel_unlock(p->owner);
00625 ast_channel_unlock(p->chan->_bridge);
00626
00627
00628 owner = ast_channel_ref(p->owner);
00629 ao2_unlock(p);
00630 ast_channel_unlock(ast);
00631 ast_do_masquerade(owner);
00632 ast_channel_unref(owner);
00633 ast_channel_lock(ast);
00634 ao2_lock(p);
00635 }
00636
00637 static struct ast_frame *local_read(struct ast_channel *ast)
00638 {
00639 return &ast_null_frame;
00640 }
00641
00642 static int local_write(struct ast_channel *ast, struct ast_frame *f)
00643 {
00644 struct local_pvt *p = ast->tech_pvt;
00645 int res = -1;
00646 int isoutbound;
00647
00648 if (!p) {
00649 return -1;
00650 }
00651
00652
00653 ao2_ref(p, 1);
00654 ao2_lock(p);
00655 isoutbound = IS_OUTBOUND(ast, p);
00656
00657 if (isoutbound
00658 && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
00659 check_bridge(ast, p);
00660 }
00661
00662 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) {
00663 res = local_queue_frame(p, isoutbound, f, ast, 1);
00664 } else {
00665 ast_debug(1, "Not posting to '%s' queue since already masqueraded out\n",
00666 ast->name);
00667 res = 0;
00668 }
00669 ao2_unlock(p);
00670 ao2_ref(p, -1);
00671
00672 return res;
00673 }
00674
00675 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00676 {
00677 struct local_pvt *p = newchan->tech_pvt;
00678
00679 if (!p)
00680 return -1;
00681
00682 ao2_lock(p);
00683
00684 if ((p->owner != oldchan) && (p->chan != oldchan)) {
00685 ast_log(LOG_WARNING, "Old channel %p wasn't %p or %p\n", oldchan, p->owner, p->chan);
00686 ao2_unlock(p);
00687 return -1;
00688 }
00689 if (p->owner == oldchan)
00690 p->owner = newchan;
00691 else
00692 p->chan = newchan;
00693
00694
00695 if (!ast_check_hangup(newchan) && ((p->owner && p->owner->_bridge == p->chan) || (p->chan && p->chan->_bridge == p->owner))) {
00696 ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n");
00697 ao2_unlock(p);
00698 ast_queue_hangup(newchan);
00699 return -1;
00700 }
00701
00702 ao2_unlock(p);
00703 return 0;
00704 }
00705
00706 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
00707 {
00708 struct local_pvt *p = ast->tech_pvt;
00709 int res = 0;
00710 struct ast_frame f = { AST_FRAME_CONTROL, };
00711 int isoutbound;
00712
00713 if (!p)
00714 return -1;
00715
00716 ao2_ref(p, 1);
00717
00718
00719 if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
00720 ast_moh_start(ast, data, NULL);
00721 } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
00722 ast_moh_stop(ast);
00723 } else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) {
00724 struct ast_channel *this_channel;
00725 struct ast_channel *the_other_channel;
00726
00727
00728
00729
00730
00731
00732
00733 ao2_lock(p);
00734 isoutbound = IS_OUTBOUND(ast, p);
00735 if (isoutbound) {
00736 this_channel = p->chan;
00737 the_other_channel = p->owner;
00738 } else {
00739 this_channel = p->owner;
00740 the_other_channel = p->chan;
00741 }
00742 if (the_other_channel) {
00743 unsigned char frame_data[1024];
00744 if (condition == AST_CONTROL_CONNECTED_LINE) {
00745 if (isoutbound) {
00746 ast_connected_line_copy_to_caller(&the_other_channel->caller, &this_channel->connected);
00747 }
00748 f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected, NULL);
00749 } else {
00750 f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting, NULL);
00751 }
00752 f.subclass.integer = condition;
00753 f.data.ptr = frame_data;
00754 res = local_queue_frame(p, isoutbound, &f, ast, 1);
00755 }
00756 ao2_unlock(p);
00757 } else {
00758
00759 ao2_lock(p);
00760
00761
00762
00763
00764
00765 if (0 <= condition || ast_test_flag(p, LOCAL_NO_OPTIMIZATION)) {
00766 isoutbound = IS_OUTBOUND(ast, p);
00767 f.subclass.integer = condition;
00768 f.data.ptr = (void *) data;
00769 f.datalen = datalen;
00770 res = local_queue_frame(p, isoutbound, &f, ast, 1);
00771
00772 if (!res && (condition == AST_CONTROL_T38_PARAMETERS) &&
00773 (datalen == sizeof(struct ast_control_t38_parameters))) {
00774 const struct ast_control_t38_parameters *parameters = data;
00775
00776 if (parameters->request_response == AST_T38_REQUEST_PARMS) {
00777 res = AST_T38_REQUEST_PARMS;
00778 }
00779 }
00780 } else {
00781 ast_debug(4, "Blocked indication %d\n", condition);
00782 }
00783 ao2_unlock(p);
00784 }
00785
00786 ao2_ref(p, -1);
00787 return res;
00788 }
00789
00790 static int local_digit_begin(struct ast_channel *ast, char digit)
00791 {
00792 struct local_pvt *p = ast->tech_pvt;
00793 int res = -1;
00794 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00795 int isoutbound;
00796
00797 if (!p)
00798 return -1;
00799
00800 ao2_ref(p, 1);
00801 ao2_lock(p);
00802 isoutbound = IS_OUTBOUND(ast, p);
00803 f.subclass.integer = digit;
00804 res = local_queue_frame(p, isoutbound, &f, ast, 0);
00805 ao2_unlock(p);
00806 ao2_ref(p, -1);
00807
00808 return res;
00809 }
00810
00811 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
00812 {
00813 struct local_pvt *p = ast->tech_pvt;
00814 int res = -1;
00815 struct ast_frame f = { AST_FRAME_DTMF_END, };
00816 int isoutbound;
00817
00818 if (!p)
00819 return -1;
00820
00821 ao2_ref(p, 1);
00822 ao2_lock(p);
00823 isoutbound = IS_OUTBOUND(ast, p);
00824 f.subclass.integer = digit;
00825 f.len = duration;
00826 res = local_queue_frame(p, isoutbound, &f, ast, 0);
00827 ao2_unlock(p);
00828 ao2_ref(p, -1);
00829
00830 return res;
00831 }
00832
00833 static int local_sendtext(struct ast_channel *ast, const char *text)
00834 {
00835 struct local_pvt *p = ast->tech_pvt;
00836 int res = -1;
00837 struct ast_frame f = { AST_FRAME_TEXT, };
00838 int isoutbound;
00839
00840 if (!p)
00841 return -1;
00842
00843 ao2_lock(p);
00844 ao2_ref(p, 1);
00845 isoutbound = IS_OUTBOUND(ast, p);
00846 f.data.ptr = (char *) text;
00847 f.datalen = strlen(text) + 1;
00848 res = local_queue_frame(p, isoutbound, &f, ast, 0);
00849 ao2_unlock(p);
00850 ao2_ref(p, -1);
00851 return res;
00852 }
00853
00854 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
00855 {
00856 struct local_pvt *p = ast->tech_pvt;
00857 int res = -1;
00858 struct ast_frame f = { AST_FRAME_HTML, };
00859 int isoutbound;
00860
00861 if (!p)
00862 return -1;
00863
00864 ao2_lock(p);
00865 ao2_ref(p, 1);
00866 isoutbound = IS_OUTBOUND(ast, p);
00867 f.subclass.integer = subclass;
00868 f.data.ptr = (char *)data;
00869 f.datalen = datalen;
00870 res = local_queue_frame(p, isoutbound, &f, ast, 0);
00871 ao2_unlock(p);
00872 ao2_ref(p, -1);
00873
00874 return res;
00875 }
00876
00877
00878
00879 static int local_call(struct ast_channel *ast, char *dest, int timeout)
00880 {
00881 struct local_pvt *p = ast->tech_pvt;
00882 int pvt_locked = 0;
00883
00884 struct ast_channel *owner = NULL;
00885 struct ast_channel *chan = NULL;
00886 int res;
00887 struct ast_var_t *varptr = NULL, *new;
00888 size_t len, namelen;
00889 char *reduced_dest = ast_strdupa(dest);
00890 char *slash;
00891 const char *exten;
00892 const char *context;
00893
00894 if (!p) {
00895 return -1;
00896 }
00897
00898
00899
00900 ao2_ref(p, 1);
00901 ast_channel_unlock(ast);
00902
00903 awesome_locking(p, &chan, &owner);
00904 pvt_locked = 1;
00905
00906 if (owner != ast) {
00907 res = -1;
00908 goto return_cleanup;
00909 }
00910
00911 if (!owner || !chan) {
00912 res = -1;
00913 goto return_cleanup;
00914 }
00915
00916
00917
00918
00919
00920
00921
00922
00923 ast_party_redirecting_copy(&chan->redirecting, &owner->redirecting);
00924
00925 ast_party_dialed_copy(&chan->dialed, &owner->dialed);
00926
00927 ast_connected_line_copy_to_caller(&chan->caller, &owner->connected);
00928 ast_connected_line_copy_from_caller(&chan->connected, &owner->caller);
00929
00930 ast_string_field_set(chan, language, owner->language);
00931 ast_string_field_set(chan, accountcode, owner->accountcode);
00932 ast_string_field_set(chan, musicclass, owner->musicclass);
00933 ast_cdr_update(chan);
00934
00935 ast_channel_cc_params_init(chan, ast_channel_get_cc_config_params(owner));
00936
00937
00938 if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00939 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
00940 }
00941
00942
00943
00944 AST_LIST_TRAVERSE(&owner->varshead, varptr, entries) {
00945 namelen = strlen(varptr->name);
00946 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00947 if ((new = ast_calloc(1, len))) {
00948 memcpy(new, varptr, len);
00949 new->value = &(new->name[0]) + namelen + 1;
00950 AST_LIST_INSERT_TAIL(&chan->varshead, new, entries);
00951 }
00952 }
00953 ast_channel_datastore_inherit(owner, chan);
00954
00955
00956
00957
00958 if ((slash = strrchr(reduced_dest, '/'))) {
00959 *slash = '\0';
00960 }
00961 ast_set_cc_interfaces_chanvar(chan, reduced_dest);
00962
00963 exten = ast_strdupa(chan->exten);
00964 context = ast_strdupa(chan->context);
00965
00966 ao2_unlock(p);
00967 pvt_locked = 0;
00968
00969 ast_channel_unlock(chan);
00970
00971 if (!ast_exists_extension(chan, context, exten, 1,
00972 S_COR(owner->caller.id.number.valid, owner->caller.id.number.str, NULL))) {
00973 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", exten, context);
00974 res = -1;
00975 chan = ast_channel_unref(chan);
00976 goto return_cleanup;
00977 }
00978
00979
00980 if (!(res = ast_pbx_start(chan))) {
00981 ao2_lock(p);
00982 ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00983 ao2_unlock(p);
00984 }
00985 chan = ast_channel_unref(chan);
00986
00987 return_cleanup:
00988 if (p) {
00989 if (pvt_locked) {
00990 ao2_unlock(p);
00991 }
00992 ao2_ref(p, -1);
00993 }
00994 if (chan) {
00995 ast_channel_unlock(chan);
00996 chan = ast_channel_unref(chan);
00997 }
00998
00999
01000
01001 if (owner) {
01002 if (owner != ast) {
01003 ast_channel_unlock(owner);
01004 ast_channel_lock(ast);
01005 }
01006 owner = ast_channel_unref(owner);
01007 } else {
01008
01009 ast_channel_lock(ast);
01010 }
01011
01012 return res;
01013 }
01014
01015
01016 static int local_hangup(struct ast_channel *ast)
01017 {
01018 struct local_pvt *p = ast->tech_pvt;
01019 int isoutbound;
01020 int hangup_chan = 0;
01021 int res = 0;
01022 struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = ast->hangupcause };
01023 struct ast_channel *owner = NULL;
01024 struct ast_channel *chan = NULL;
01025 int answered_elsewhere = 0;
01026
01027 if (!p) {
01028 return -1;
01029 }
01030
01031
01032 ao2_ref(p, 1);
01033
01034
01035 ast_channel_unlock(ast);
01036
01037
01038 awesome_locking(p, &chan, &owner);
01039
01040 if (ast != chan && ast != owner) {
01041 res = -1;
01042 goto local_hangup_cleanup;
01043 }
01044
01045 isoutbound = IS_OUTBOUND(ast, p);
01046
01047 if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
01048 answered_elsewhere = 1;
01049 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
01050 ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n");
01051 }
01052
01053 if (isoutbound) {
01054 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
01055
01056 if (status && p->owner) {
01057 p->owner->hangupcause = p->chan->hangupcause;
01058 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
01059 }
01060
01061 ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
01062 p->chan = NULL;
01063 } else {
01064 if (p->chan) {
01065
01066
01067 if (answered_elsewhere) {
01068 ast_queue_hangup_with_cause(p->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
01069 } else {
01070 ast_queue_hangup(p->chan);
01071 }
01072 }
01073 p->owner = NULL;
01074 }
01075
01076 ast->tech_pvt = NULL;
01077
01078 if (!p->owner && !p->chan) {
01079 ao2_unlock(p);
01080
01081
01082 ao2_unlink(locals, p);
01083 ao2_ref(p, -1);
01084 p = NULL;
01085 res = 0;
01086 goto local_hangup_cleanup;
01087 }
01088 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) {
01089
01090 hangup_chan = 1;
01091 } else {
01092 local_queue_frame(p, isoutbound, &f, NULL, 0);
01093 }
01094
01095 local_hangup_cleanup:
01096 if (p) {
01097 ao2_unlock(p);
01098 ao2_ref(p, -1);
01099 }
01100 if (owner) {
01101 ast_channel_unlock(owner);
01102 owner = ast_channel_unref(owner);
01103 }
01104 if (chan) {
01105 ast_channel_unlock(chan);
01106 if (hangup_chan) {
01107 ast_hangup(chan);
01108 }
01109 chan = ast_channel_unref(chan);
01110 }
01111
01112
01113 ast_channel_lock(ast);
01114 return res;
01115 }
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125 static void local_pvt_destructor(void *vdoomed)
01126 {
01127 ast_module_unref(ast_module_info->self);
01128 }
01129
01130
01131 static struct local_pvt *local_alloc(const char *data, format_t format)
01132 {
01133 struct local_pvt *tmp = NULL;
01134 char *c = NULL, *opts = NULL;
01135
01136 if (!(tmp = ao2_alloc(sizeof(*tmp), local_pvt_destructor))) {
01137 return NULL;
01138 }
01139
01140 ast_module_ref(ast_module_info->self);
01141
01142
01143 ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
01144
01145 memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
01146
01147
01148 if ((opts = strchr(tmp->exten, '/'))) {
01149 *opts++ = '\0';
01150 if (strchr(opts, 'n'))
01151 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
01152 if (strchr(opts, 'j')) {
01153 if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
01154 ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
01155 else {
01156 ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
01157 "to use the 'j' option to enable the jitterbuffer\n");
01158 }
01159 }
01160 if (strchr(opts, 'b')) {
01161 ast_set_flag(tmp, LOCAL_BRIDGE);
01162 }
01163 if (strchr(opts, 'm')) {
01164 ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
01165 }
01166 }
01167
01168
01169 if ((c = strchr(tmp->exten, '@')))
01170 *c++ = '\0';
01171
01172 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
01173
01174 tmp->reqformat = format;
01175
01176 #if 0
01177
01178
01179
01180 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
01181 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
01182 tmp = local_pvt_destroy(tmp);
01183 } else {
01184 #endif
01185
01186 ao2_link(locals, tmp);
01187 #if 0
01188 }
01189 #endif
01190 return tmp;
01191 }
01192
01193
01194 static struct ast_channel *local_new(struct local_pvt *p, int state, const char *linkedid)
01195 {
01196 struct ast_channel *tmp = NULL, *tmp2 = NULL;
01197 int fmt = 0;
01198 int generated_seqno = ast_atomic_fetchadd_int((int *)&name_sequence, +1);
01199 const char *t;
01200 int ama;
01201
01202
01203
01204 if (p->owner && p->owner->accountcode)
01205 t = p->owner->accountcode;
01206 else
01207 t = "";
01208
01209 if (p->owner)
01210 ama = p->owner->amaflags;
01211 else
01212 ama = 0;
01213
01214
01215
01216 if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, linkedid, ama, "Local/%s@%s-%08x;1", p->exten, p->context, (unsigned)generated_seqno))
01217 || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, tmp->linkedid, ama, "Local/%s@%s-%08x;2", p->exten, p->context, (unsigned)generated_seqno))) {
01218 if (tmp) {
01219 tmp = ast_channel_release(tmp);
01220 }
01221 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
01222 return NULL;
01223 }
01224
01225 tmp2->tech = tmp->tech = &local_tech;
01226
01227 tmp->nativeformats = p->reqformat;
01228 tmp2->nativeformats = p->reqformat;
01229
01230
01231 fmt = ast_best_codec(p->reqformat);
01232 tmp->writeformat = fmt;
01233 tmp2->writeformat = fmt;
01234 tmp->rawwriteformat = fmt;
01235 tmp2->rawwriteformat = fmt;
01236 tmp->readformat = fmt;
01237 tmp2->readformat = fmt;
01238 tmp->rawreadformat = fmt;
01239 tmp2->rawreadformat = fmt;
01240
01241 tmp->tech_pvt = p;
01242 tmp2->tech_pvt = p;
01243
01244 tmp->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE;
01245 tmp2->flags |= AST_FLAG_DISABLE_DEVSTATE_CACHE;
01246
01247 p->owner = tmp;
01248 p->chan = tmp2;
01249
01250 ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
01251 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
01252 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
01253 tmp->priority = 1;
01254 tmp2->priority = 1;
01255
01256 ast_jb_configure(tmp, &p->jb_conf);
01257
01258 return tmp;
01259 }
01260
01261
01262 static struct ast_channel *local_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
01263 {
01264 struct local_pvt *p;
01265 struct ast_channel *chan;
01266
01267
01268 p = local_alloc(data, format);
01269 if (!p) {
01270 return NULL;
01271 }
01272 chan = local_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
01273 if (!chan) {
01274 ao2_unlink(locals, p);
01275 } else if (ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) {
01276 ao2_unlink(locals, p);
01277 p->owner = ast_channel_release(p->owner);
01278 p->chan = ast_channel_release(p->chan);
01279 chan = NULL;
01280 }
01281 ao2_ref(p, -1);
01282
01283 return chan;
01284 }
01285
01286
01287 static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01288 {
01289 struct local_pvt *p = NULL;
01290 struct ao2_iterator it;
01291
01292 switch (cmd) {
01293 case CLI_INIT:
01294 e->command = "local show channels";
01295 e->usage =
01296 "Usage: local show channels\n"
01297 " Provides summary information on active local proxy channels.\n";
01298 return NULL;
01299 case CLI_GENERATE:
01300 return NULL;
01301 }
01302
01303 if (a->argc != 3)
01304 return CLI_SHOWUSAGE;
01305
01306 if (ao2_container_count(locals) == 0) {
01307 ast_cli(a->fd, "No local channels in use\n");
01308 return RESULT_SUCCESS;
01309 }
01310
01311 it = ao2_iterator_init(locals, 0);
01312 while ((p = ao2_iterator_next(&it))) {
01313 ao2_lock(p);
01314 ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
01315 ao2_unlock(p);
01316 ao2_ref(p, -1);
01317 }
01318 ao2_iterator_destroy(&it);
01319
01320 return CLI_SUCCESS;
01321 }
01322
01323 static struct ast_cli_entry cli_local[] = {
01324 AST_CLI_DEFINE(locals_show, "List status of local channels"),
01325 };
01326
01327 static int manager_optimize_away(struct mansession *s, const struct message *m)
01328 {
01329 const char *channel;
01330 struct local_pvt *p, *tmp = NULL;
01331 struct ast_channel *c;
01332 int found = 0;
01333 struct ao2_iterator it;
01334
01335 channel = astman_get_header(m, "Channel");
01336
01337 if (ast_strlen_zero(channel)) {
01338 astman_send_error(s, m, "'Channel' not specified.");
01339 return 0;
01340 }
01341
01342 c = ast_channel_get_by_name(channel);
01343 if (!c) {
01344 astman_send_error(s, m, "Channel does not exist.");
01345 return 0;
01346 }
01347
01348 p = c->tech_pvt;
01349 ast_channel_unref(c);
01350 c = NULL;
01351
01352 it = ao2_iterator_init(locals, 0);
01353 while ((tmp = ao2_iterator_next(&it))) {
01354 if (tmp == p) {
01355 ao2_lock(tmp);
01356 found = 1;
01357 ast_clear_flag(tmp, LOCAL_NO_OPTIMIZATION);
01358 ao2_unlock(tmp);
01359 ao2_ref(tmp, -1);
01360 break;
01361 }
01362 ao2_ref(tmp, -1);
01363 }
01364 ao2_iterator_destroy(&it);
01365
01366 if (found) {
01367 astman_send_ack(s, m, "Queued channel to be optimized away");
01368 } else {
01369 astman_send_error(s, m, "Unable to find channel");
01370 }
01371
01372 return 0;
01373 }
01374
01375
01376 static int locals_cmp_cb(void *obj, void *arg, int flags)
01377 {
01378 return (obj == arg) ? CMP_MATCH : 0;
01379 }
01380
01381
01382 static int load_module(void)
01383 {
01384 if (!(locals = ao2_container_alloc(BUCKET_SIZE, NULL, locals_cmp_cb))) {
01385 return AST_MODULE_LOAD_FAILURE;
01386 }
01387
01388
01389 if (ast_channel_register(&local_tech)) {
01390 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
01391 ao2_ref(locals, -1);
01392 return AST_MODULE_LOAD_FAILURE;
01393 }
01394 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
01395 ast_manager_register_xml("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away);
01396
01397 return AST_MODULE_LOAD_SUCCESS;
01398 }
01399
01400
01401 static int unload_module(void)
01402 {
01403 struct local_pvt *p = NULL;
01404 struct ao2_iterator it;
01405
01406
01407 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
01408 ast_manager_unregister("LocalOptimizeAway");
01409 ast_channel_unregister(&local_tech);
01410
01411 it = ao2_iterator_init(locals, 0);
01412 while ((p = ao2_iterator_next(&it))) {
01413 if (p->owner) {
01414 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
01415 }
01416 ao2_ref(p, -1);
01417 }
01418 ao2_iterator_destroy(&it);
01419 ao2_ref(locals, -1);
01420
01421 return 0;
01422 }
01423
01424 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Local Proxy Channel (Note: used internally by other modules)",
01425 .load = load_module,
01426 .unload = unload_module,
01427 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
01428 );