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