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: 328209 $")
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 local_pvt *p)
00480 {
00481 struct ast_channel_monitor *tmp;
00482 struct ast_channel *chan = NULL;
00483 struct ast_channel *bridged_chan = NULL;
00484
00485
00486 if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION)) {
00487 return;
00488 }
00489 if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || !p->chan || !p->owner) {
00490 return;
00491 }
00492
00493
00494 chan = ast_channel_ref(p->chan);
00495
00496 ao2_unlock(p);
00497 bridged_chan = ast_bridged_channel(chan);
00498 ao2_lock(p);
00499
00500 chan = ast_channel_unref(chan);
00501
00502
00503
00504
00505 if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || !p->owner || !p->chan || (p->chan->_bridge != bridged_chan)) {
00506 return;
00507 }
00508
00509
00510
00511
00512
00513
00514 if (p->chan->_bridge && AST_LIST_EMPTY(&p->owner->readq)) {
00515
00516
00517
00518
00519 if (!ast_channel_trylock(p->chan->_bridge)) {
00520 if (!ast_check_hangup(p->chan->_bridge)) {
00521 if (!ast_channel_trylock(p->owner)) {
00522 if (!ast_check_hangup(p->owner)) {
00523 if (p->owner->monitor && !p->chan->_bridge->monitor) {
00524
00525
00526
00527
00528
00529 tmp = p->owner->monitor;
00530 p->owner->monitor = p->chan->_bridge->monitor;
00531 p->chan->_bridge->monitor = tmp;
00532 }
00533 if (p->chan->audiohooks) {
00534 struct ast_audiohook_list *audiohooks_swapper;
00535 audiohooks_swapper = p->chan->audiohooks;
00536 p->chan->audiohooks = p->owner->audiohooks;
00537 p->owner->audiohooks = audiohooks_swapper;
00538 }
00539
00540
00541
00542
00543
00544
00545
00546
00547 if (p->owner->caller.id.name.valid || p->owner->caller.id.number.valid
00548 || p->owner->caller.id.subaddress.valid || p->owner->caller.ani.name.valid
00549 || p->owner->caller.ani.number.valid || p->owner->caller.ani.subaddress.valid) {
00550 struct ast_party_caller tmp;
00551 tmp = p->owner->caller;
00552 p->owner->caller = p->chan->_bridge->caller;
00553 p->chan->_bridge->caller = tmp;
00554 }
00555 if (p->owner->redirecting.from.name.valid || p->owner->redirecting.from.number.valid
00556 || p->owner->redirecting.from.subaddress.valid || p->owner->redirecting.to.name.valid
00557 || p->owner->redirecting.to.number.valid || p->owner->redirecting.to.subaddress.valid) {
00558 struct ast_party_redirecting tmp;
00559 tmp = p->owner->redirecting;
00560 p->owner->redirecting = p->chan->_bridge->redirecting;
00561 p->chan->_bridge->redirecting = tmp;
00562 }
00563 if (p->owner->dialed.number.str || p->owner->dialed.subaddress.valid) {
00564 struct ast_party_dialed tmp;
00565 tmp = p->owner->dialed;
00566 p->owner->dialed = p->chan->_bridge->dialed;
00567 p->chan->_bridge->dialed = tmp;
00568 }
00569
00570
00571 ast_app_group_update(p->chan, p->owner);
00572 ast_channel_masquerade(p->owner, p->chan->_bridge);
00573 ast_set_flag(p, LOCAL_ALREADY_MASQED);
00574 }
00575 ast_channel_unlock(p->owner);
00576 }
00577 }
00578 ast_channel_unlock(p->chan->_bridge);
00579 }
00580 }
00581 }
00582
00583 static struct ast_frame *local_read(struct ast_channel *ast)
00584 {
00585 return &ast_null_frame;
00586 }
00587
00588 static int local_write(struct ast_channel *ast, struct ast_frame *f)
00589 {
00590 struct local_pvt *p = ast->tech_pvt;
00591 int res = -1;
00592 int isoutbound;
00593
00594 if (!p) {
00595 return -1;
00596 }
00597
00598
00599 ao2_ref(p, 1);
00600 ao2_lock(p);
00601 isoutbound = IS_OUTBOUND(ast, p);
00602
00603 if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
00604 check_bridge(p);
00605 }
00606
00607 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) {
00608 res = local_queue_frame(p, isoutbound, f, ast, 1);
00609 } else {
00610 ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name);
00611 res = 0;
00612 }
00613 ao2_unlock(p);
00614 ao2_ref(p, -1);
00615
00616 return res;
00617 }
00618
00619 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00620 {
00621 struct local_pvt *p = newchan->tech_pvt;
00622
00623 if (!p)
00624 return -1;
00625
00626 ao2_lock(p);
00627
00628 if ((p->owner != oldchan) && (p->chan != oldchan)) {
00629 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00630 ao2_unlock(p);
00631 return -1;
00632 }
00633 if (p->owner == oldchan)
00634 p->owner = newchan;
00635 else
00636 p->chan = newchan;
00637
00638
00639 if (!ast_check_hangup(newchan) && ((p->owner && p->owner->_bridge == p->chan) || (p->chan && p->chan->_bridge == p->owner))) {
00640 ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n");
00641 ao2_unlock(p);
00642 ast_queue_hangup(newchan);
00643 return -1;
00644 }
00645
00646 ao2_unlock(p);
00647 return 0;
00648 }
00649
00650 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
00651 {
00652 struct local_pvt *p = ast->tech_pvt;
00653 int res = 0;
00654 struct ast_frame f = { AST_FRAME_CONTROL, };
00655 int isoutbound;
00656
00657 if (!p)
00658 return -1;
00659
00660 ao2_ref(p, 1);
00661
00662
00663 if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
00664 ast_moh_start(ast, data, NULL);
00665 } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
00666 ast_moh_stop(ast);
00667 } else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) {
00668 struct ast_channel *this_channel;
00669 struct ast_channel *the_other_channel;
00670
00671
00672
00673
00674
00675
00676
00677 ao2_lock(p);
00678 isoutbound = IS_OUTBOUND(ast, p);
00679 if (isoutbound) {
00680 this_channel = p->chan;
00681 the_other_channel = p->owner;
00682 } else {
00683 this_channel = p->owner;
00684 the_other_channel = p->chan;
00685 }
00686 if (the_other_channel) {
00687 unsigned char frame_data[1024];
00688 if (condition == AST_CONTROL_CONNECTED_LINE) {
00689 if (isoutbound) {
00690 ast_connected_line_copy_to_caller(&the_other_channel->caller, &this_channel->connected);
00691 }
00692 f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected, NULL);
00693 } else {
00694 f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting, NULL);
00695 }
00696 f.subclass.integer = condition;
00697 f.data.ptr = frame_data;
00698 res = local_queue_frame(p, isoutbound, &f, ast, 1);
00699 }
00700 ao2_unlock(p);
00701 } else {
00702
00703 ao2_lock(p);
00704 isoutbound = IS_OUTBOUND(ast, p);
00705 f.subclass.integer = condition;
00706 f.data.ptr = (void*)data;
00707 f.datalen = datalen;
00708 res = local_queue_frame(p, isoutbound, &f, ast, 1);
00709 ao2_unlock(p);
00710 }
00711
00712 ao2_ref(p, -1);
00713 return res;
00714 }
00715
00716 static int local_digit_begin(struct ast_channel *ast, char digit)
00717 {
00718 struct local_pvt *p = ast->tech_pvt;
00719 int res = -1;
00720 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00721 int isoutbound;
00722
00723 if (!p)
00724 return -1;
00725
00726 ao2_ref(p, 1);
00727 ao2_lock(p);
00728 isoutbound = IS_OUTBOUND(ast, p);
00729 f.subclass.integer = digit;
00730 res = local_queue_frame(p, isoutbound, &f, ast, 0);
00731 ao2_unlock(p);
00732 ao2_ref(p, -1);
00733
00734 return res;
00735 }
00736
00737 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
00738 {
00739 struct local_pvt *p = ast->tech_pvt;
00740 int res = -1;
00741 struct ast_frame f = { AST_FRAME_DTMF_END, };
00742 int isoutbound;
00743
00744 if (!p)
00745 return -1;
00746
00747 ao2_ref(p, 1);
00748 ao2_lock(p);
00749 isoutbound = IS_OUTBOUND(ast, p);
00750 f.subclass.integer = digit;
00751 f.len = duration;
00752 res = local_queue_frame(p, isoutbound, &f, ast, 0);
00753 ao2_unlock(p);
00754 ao2_ref(p, -1);
00755
00756 return res;
00757 }
00758
00759 static int local_sendtext(struct ast_channel *ast, const char *text)
00760 {
00761 struct local_pvt *p = ast->tech_pvt;
00762 int res = -1;
00763 struct ast_frame f = { AST_FRAME_TEXT, };
00764 int isoutbound;
00765
00766 if (!p)
00767 return -1;
00768
00769 ao2_lock(p);
00770 ao2_ref(p, 1);
00771 isoutbound = IS_OUTBOUND(ast, p);
00772 f.data.ptr = (char *) text;
00773 f.datalen = strlen(text) + 1;
00774 res = local_queue_frame(p, isoutbound, &f, ast, 0);
00775 ao2_unlock(p);
00776 ao2_ref(p, -1);
00777 return res;
00778 }
00779
00780 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
00781 {
00782 struct local_pvt *p = ast->tech_pvt;
00783 int res = -1;
00784 struct ast_frame f = { AST_FRAME_HTML, };
00785 int isoutbound;
00786
00787 if (!p)
00788 return -1;
00789
00790 ao2_lock(p);
00791 ao2_ref(p, 1);
00792 isoutbound = IS_OUTBOUND(ast, p);
00793 f.subclass.integer = subclass;
00794 f.data.ptr = (char *)data;
00795 f.datalen = datalen;
00796 res = local_queue_frame(p, isoutbound, &f, ast, 0);
00797 ao2_unlock(p);
00798 ao2_ref(p, -1);
00799
00800 return res;
00801 }
00802
00803
00804
00805 static int local_call(struct ast_channel *ast, char *dest, int timeout)
00806 {
00807 struct local_pvt *p = ast->tech_pvt;
00808 int pvt_locked = 0;
00809
00810 struct ast_channel *owner = NULL;
00811 struct ast_channel *chan = NULL;
00812 int res;
00813 struct ast_var_t *varptr = NULL, *new;
00814 size_t len, namelen;
00815 char *reduced_dest = ast_strdupa(dest);
00816 char *slash;
00817 const char *exten;
00818 const char *context;
00819
00820 if (!p) {
00821 return -1;
00822 }
00823
00824
00825
00826 ao2_ref(p, 1);
00827 ast_channel_unlock(ast);
00828
00829 awesome_locking(p, &chan, &owner);
00830 pvt_locked = 1;
00831
00832 if (owner != ast) {
00833 res = -1;
00834 goto return_cleanup;
00835 }
00836
00837 if (!owner || !chan) {
00838 res = -1;
00839 goto return_cleanup;
00840 }
00841
00842
00843
00844
00845
00846
00847
00848
00849 ast_party_redirecting_copy(&chan->redirecting, &owner->redirecting);
00850
00851 ast_party_dialed_copy(&chan->dialed, &owner->dialed);
00852
00853 ast_connected_line_copy_to_caller(&chan->caller, &owner->connected);
00854 ast_connected_line_copy_from_caller(&chan->connected, &owner->caller);
00855
00856 ast_string_field_set(chan, language, owner->language);
00857 ast_string_field_set(chan, accountcode, owner->accountcode);
00858 ast_string_field_set(chan, musicclass, owner->musicclass);
00859 ast_cdr_update(chan);
00860
00861 ast_channel_cc_params_init(chan, ast_channel_get_cc_config_params(owner));
00862
00863
00864 if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00865 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
00866 }
00867
00868
00869
00870 AST_LIST_TRAVERSE(&owner->varshead, varptr, entries) {
00871 namelen = strlen(varptr->name);
00872 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00873 if ((new = ast_calloc(1, len))) {
00874 memcpy(new, varptr, len);
00875 new->value = &(new->name[0]) + namelen + 1;
00876 AST_LIST_INSERT_TAIL(&chan->varshead, new, entries);
00877 }
00878 }
00879 ast_channel_datastore_inherit(owner, chan);
00880
00881
00882
00883
00884 if ((slash = strrchr(reduced_dest, '/'))) {
00885 *slash = '\0';
00886 }
00887 ast_set_cc_interfaces_chanvar(chan, reduced_dest);
00888
00889 exten = ast_strdupa(chan->exten);
00890 context = ast_strdupa(chan->context);
00891
00892 ao2_unlock(p);
00893 pvt_locked = 0;
00894
00895 ast_channel_unlock(chan);
00896
00897 if (!ast_exists_extension(chan, context, exten, 1,
00898 S_COR(owner->caller.id.number.valid, owner->caller.id.number.str, NULL))) {
00899 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", exten, context);
00900 res = -1;
00901 chan = ast_channel_unref(chan);
00902 goto return_cleanup;
00903 }
00904
00905
00906 if (!(res = ast_pbx_start(chan))) {
00907 ao2_lock(p);
00908 ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00909 ao2_unlock(p);
00910 }
00911 chan = ast_channel_unref(chan);
00912
00913 return_cleanup:
00914 if (p) {
00915 if (pvt_locked) {
00916 ao2_unlock(p);
00917 }
00918 ao2_ref(p, -1);
00919 }
00920 if (chan) {
00921 ast_channel_unlock(chan);
00922 chan = ast_channel_unref(chan);
00923 }
00924
00925
00926
00927 if (owner) {
00928 if (owner != ast) {
00929 ast_channel_unlock(owner);
00930 ast_channel_lock(ast);
00931 }
00932 owner = ast_channel_unref(owner);
00933 } else {
00934
00935 ast_channel_lock(ast);
00936 }
00937
00938 return res;
00939 }
00940
00941
00942 static int local_hangup(struct ast_channel *ast)
00943 {
00944 struct local_pvt *p = ast->tech_pvt;
00945 int isoutbound;
00946 int hangup_chan = 0;
00947 int res = 0;
00948 struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = ast->hangupcause };
00949 struct ast_channel *owner = NULL;
00950 struct ast_channel *chan = NULL;
00951
00952 if (!p) {
00953 return -1;
00954 }
00955
00956
00957 ao2_ref(p, 1);
00958
00959
00960 ast_channel_unlock(ast);
00961
00962
00963 awesome_locking(p, &chan, &owner);
00964
00965 if (ast != chan && ast != owner) {
00966 res = -1;
00967 goto local_hangup_cleanup;
00968 }
00969
00970 isoutbound = IS_OUTBOUND(ast, p);
00971
00972 if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00973 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00974 ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n");
00975 }
00976
00977 if (isoutbound) {
00978 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00979 if ((status) && (p->owner)) {
00980 p->owner->hangupcause = p->chan->hangupcause;
00981 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00982 }
00983
00984 ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
00985 ast_module_user_remove(p->u_chan);
00986 p->chan = NULL;
00987 } else {
00988 ast_module_user_remove(p->u_owner);
00989 if (p->chan) {
00990 ast_queue_hangup(p->chan);
00991 }
00992 p->owner = NULL;
00993 }
00994
00995 ast->tech_pvt = NULL;
00996
00997 if (!p->owner && !p->chan) {
00998 ao2_unlock(p);
00999
01000 ao2_unlink(locals, p);
01001 ao2_ref(p, -1);
01002 p = NULL;
01003 res = 0;
01004 goto local_hangup_cleanup;
01005 }
01006 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) {
01007
01008 hangup_chan = 1;
01009 } else {
01010 local_queue_frame(p, isoutbound, &f, NULL, 0);
01011 }
01012
01013 local_hangup_cleanup:
01014 if (p) {
01015 ao2_unlock(p);
01016 ao2_ref(p, -1);
01017 }
01018 if (chan) {
01019 ast_channel_unlock(chan);
01020 if (hangup_chan) {
01021 ast_hangup(chan);
01022 }
01023 chan = ast_channel_unref(chan);
01024 }
01025 if (owner) {
01026 ast_channel_unlock(owner);
01027 owner = ast_channel_unref(owner);
01028 }
01029
01030
01031 ast_channel_lock(ast);
01032 return res;
01033 }
01034
01035
01036 static struct local_pvt *local_alloc(const char *data, format_t format)
01037 {
01038 struct local_pvt *tmp = NULL;
01039 char *c = NULL, *opts = NULL;
01040
01041 if (!(tmp = ao2_alloc(sizeof(*tmp), NULL))) {
01042 return NULL;
01043 }
01044
01045
01046 ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
01047
01048 memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
01049
01050
01051 if ((opts = strchr(tmp->exten, '/'))) {
01052 *opts++ = '\0';
01053 if (strchr(opts, 'n'))
01054 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
01055 if (strchr(opts, 'j')) {
01056 if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
01057 ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
01058 else {
01059 ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
01060 "to use the 'j' option to enable the jitterbuffer\n");
01061 }
01062 }
01063 if (strchr(opts, 'b')) {
01064 ast_set_flag(tmp, LOCAL_BRIDGE);
01065 }
01066 if (strchr(opts, 'm')) {
01067 ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
01068 }
01069 }
01070
01071
01072 if ((c = strchr(tmp->exten, '@')))
01073 *c++ = '\0';
01074
01075 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
01076
01077 tmp->reqformat = format;
01078
01079 #if 0
01080
01081
01082
01083 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
01084 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
01085 tmp = local_pvt_destroy(tmp);
01086 } else {
01087 #endif
01088
01089 ao2_link(locals, tmp);
01090 #if 0
01091 }
01092 #endif
01093 return tmp;
01094 }
01095
01096
01097 static struct ast_channel *local_new(struct local_pvt *p, int state, const char *linkedid)
01098 {
01099 struct ast_channel *tmp = NULL, *tmp2 = NULL;
01100 int randnum = ast_random() & 0xffff, fmt = 0;
01101 const char *t;
01102 int ama;
01103
01104
01105
01106 if (p->owner && p->owner->accountcode)
01107 t = p->owner->accountcode;
01108 else
01109 t = "";
01110
01111 if (p->owner)
01112 ama = p->owner->amaflags;
01113 else
01114 ama = 0;
01115 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))
01116 || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, linkedid, ama, "Local/%s@%s-%04x;2", p->exten, p->context, randnum))) {
01117 if (tmp) {
01118 tmp = ast_channel_release(tmp);
01119 }
01120 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
01121 return NULL;
01122 }
01123
01124 tmp2->tech = tmp->tech = &local_tech;
01125
01126 tmp->nativeformats = p->reqformat;
01127 tmp2->nativeformats = p->reqformat;
01128
01129
01130 fmt = ast_best_codec(p->reqformat);
01131 tmp->writeformat = fmt;
01132 tmp2->writeformat = fmt;
01133 tmp->rawwriteformat = fmt;
01134 tmp2->rawwriteformat = fmt;
01135 tmp->readformat = fmt;
01136 tmp2->readformat = fmt;
01137 tmp->rawreadformat = fmt;
01138 tmp2->rawreadformat = fmt;
01139
01140 tmp->tech_pvt = p;
01141 tmp2->tech_pvt = p;
01142
01143 p->owner = tmp;
01144 p->chan = tmp2;
01145 p->u_owner = ast_module_user_add(p->owner);
01146 p->u_chan = ast_module_user_add(p->chan);
01147
01148 ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
01149 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
01150 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
01151 tmp->priority = 1;
01152 tmp2->priority = 1;
01153
01154 ast_jb_configure(tmp, &p->jb_conf);
01155
01156 return tmp;
01157 }
01158
01159
01160 static struct ast_channel *local_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
01161 {
01162 struct local_pvt *p = NULL;
01163 struct ast_channel *chan = NULL;
01164
01165
01166 if ((p = local_alloc(data, format))) {
01167 if (!(chan = local_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL))) {
01168 ao2_unlink(locals, p);
01169 }
01170 if (chan && ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) {
01171 chan = ast_channel_release(chan);
01172 ao2_unlink(locals, p);
01173 }
01174 ao2_ref(p, -1);
01175 }
01176
01177 return chan;
01178 }
01179
01180
01181 static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01182 {
01183 struct local_pvt *p = NULL;
01184 struct ao2_iterator it;
01185
01186 switch (cmd) {
01187 case CLI_INIT:
01188 e->command = "local show channels";
01189 e->usage =
01190 "Usage: local show channels\n"
01191 " Provides summary information on active local proxy channels.\n";
01192 return NULL;
01193 case CLI_GENERATE:
01194 return NULL;
01195 }
01196
01197 if (a->argc != 3)
01198 return CLI_SHOWUSAGE;
01199
01200 if (ao2_container_count(locals) == 0) {
01201 ast_cli(a->fd, "No local channels in use\n");
01202 return RESULT_SUCCESS;
01203 }
01204
01205 it = ao2_iterator_init(locals, 0);
01206 while ((p = ao2_iterator_next(&it))) {
01207 ao2_lock(p);
01208 ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
01209 ao2_unlock(p);
01210 ao2_ref(p, -1);
01211 }
01212 ao2_iterator_destroy(&it);
01213
01214 return CLI_SUCCESS;
01215 }
01216
01217 static struct ast_cli_entry cli_local[] = {
01218 AST_CLI_DEFINE(locals_show, "List status of local channels"),
01219 };
01220
01221 static int manager_optimize_away(struct mansession *s, const struct message *m)
01222 {
01223 const char *channel;
01224 struct local_pvt *p, *tmp = NULL;
01225 struct ast_channel *c;
01226 int found = 0;
01227 struct ao2_iterator it;
01228
01229 channel = astman_get_header(m, "Channel");
01230
01231 if (ast_strlen_zero(channel)) {
01232 astman_send_error(s, m, "'Channel' not specified.");
01233 return 0;
01234 }
01235
01236 c = ast_channel_get_by_name(channel);
01237 if (!c) {
01238 astman_send_error(s, m, "Channel does not exist.");
01239 return 0;
01240 }
01241
01242 p = c->tech_pvt;
01243 ast_channel_unref(c);
01244 c = NULL;
01245
01246 it = ao2_iterator_init(locals, 0);
01247 while ((tmp = ao2_iterator_next(&it))) {
01248 if (tmp == p) {
01249 ao2_lock(tmp);
01250 found = 1;
01251 ast_clear_flag(tmp, LOCAL_NO_OPTIMIZATION);
01252 ao2_unlock(tmp);
01253 ao2_ref(tmp, -1);
01254 break;
01255 }
01256 ao2_ref(tmp, -1);
01257 }
01258 ao2_iterator_destroy(&it);
01259
01260 if (found) {
01261 astman_send_ack(s, m, "Queued channel to be optimized away");
01262 } else {
01263 astman_send_error(s, m, "Unable to find channel");
01264 }
01265
01266 return 0;
01267 }
01268
01269
01270 static int locals_cmp_cb(void *obj, void *arg, int flags)
01271 {
01272 return (obj == arg) ? CMP_MATCH : 0;
01273 }
01274
01275
01276 static int load_module(void)
01277 {
01278 if (!(locals = ao2_container_alloc(BUCKET_SIZE, NULL, locals_cmp_cb))) {
01279 return AST_MODULE_LOAD_FAILURE;
01280 }
01281
01282
01283 if (ast_channel_register(&local_tech)) {
01284 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
01285 ao2_ref(locals, -1);
01286 return AST_MODULE_LOAD_FAILURE;
01287 }
01288 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
01289 ast_manager_register_xml("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away);
01290
01291 return AST_MODULE_LOAD_SUCCESS;
01292 }
01293
01294
01295 static int unload_module(void)
01296 {
01297 struct local_pvt *p = NULL;
01298 struct ao2_iterator it;
01299
01300
01301 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
01302 ast_manager_unregister("LocalOptimizeAway");
01303 ast_channel_unregister(&local_tech);
01304
01305 it = ao2_iterator_init(locals, 0);
01306 while ((p = ao2_iterator_next(&it))) {
01307 if (p->owner) {
01308 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
01309 }
01310 ao2_ref(p, -1);
01311 }
01312 ao2_iterator_destroy(&it);
01313 ao2_ref(locals, -1);
01314
01315 return 0;
01316 }
01317
01318 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Local Proxy Channel (Note: used internally by other modules)",
01319 .load = load_module,
01320 .unload = unload_module,
01321 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
01322 );