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