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: 353685 $")
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, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *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, const 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(const char *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 struct ast_channel_tech local_tech = {
00114 .type = "Local",
00115 .description = tdesc,
00116 .requester = local_request,
00117 .send_digit_begin = local_digit_begin,
00118 .send_digit_end = local_digit_end,
00119 .call = local_call,
00120 .hangup = local_hangup,
00121 .answer = local_answer,
00122 .read = local_read,
00123 .write = local_write,
00124 .write_video = local_write,
00125 .exception = local_read,
00126 .indicate = local_indicate,
00127 .fixup = local_fixup,
00128 .send_html = local_sendhtml,
00129 .send_text = local_sendtext,
00130 .devicestate = local_devicestate,
00131 .bridged_channel = local_bridgedchannel,
00132 .queryoption = local_queryoption,
00133 .setoption = local_setoption,
00134 };
00135
00136
00137
00138
00139
00140
00141
00142
00143 struct local_pvt {
00144 unsigned int flags;
00145 char context[AST_MAX_CONTEXT];
00146 char exten[AST_MAX_EXTENSION];
00147 struct ast_format_cap *reqcap;
00148 struct ast_jb_conf jb_conf;
00149 struct ast_channel *owner;
00150 struct ast_channel *chan;
00151 struct ast_module_user *u_owner;
00152 struct ast_module_user *u_chan;
00153 };
00154
00155 #define LOCAL_ALREADY_MASQED (1 << 0)
00156 #define LOCAL_LAUNCHED_PBX (1 << 1)
00157 #define LOCAL_NO_OPTIMIZATION (1 << 2)
00158 #define LOCAL_BRIDGE (1 << 3)
00159 #define LOCAL_MOH_PASSTHRU (1 << 4)
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170 static void awesome_locking(struct local_pvt *p, struct ast_channel **outchan, struct ast_channel **outowner)
00171 {
00172 struct ast_channel *chan = NULL;
00173 struct ast_channel *owner = NULL;
00174
00175 for (;;) {
00176 ao2_lock(p);
00177 if (p->chan) {
00178 chan = p->chan;
00179 ast_channel_ref(chan);
00180 }
00181 if (p->owner) {
00182 owner = p->owner;
00183 ast_channel_ref(owner);
00184 }
00185 ao2_unlock(p);
00186
00187
00188 if (!owner || !chan) {
00189 if (owner) {
00190 ast_channel_lock(owner);
00191 } else if(chan) {
00192 ast_channel_lock(chan);
00193 }
00194 ao2_lock(p);
00195 } else {
00196
00197 ast_channel_lock(chan);
00198 while (ast_channel_trylock(owner)) {
00199 CHANNEL_DEADLOCK_AVOIDANCE(chan);
00200 }
00201 ao2_lock(p);
00202 }
00203
00204
00205 if (p->owner != owner || p->chan != chan) {
00206 if (owner) {
00207 ast_channel_unlock(owner);
00208 owner = ast_channel_unref(owner);
00209 }
00210 if (chan) {
00211 ast_channel_unlock(chan);
00212 chan = ast_channel_unref(chan);
00213 }
00214 ao2_unlock(p);
00215 continue;
00216 }
00217
00218 break;
00219 }
00220 *outowner = p->owner;
00221 *outchan = p->chan;
00222 }
00223
00224
00225 static int local_setoption(struct ast_channel *ast, int option, void * data, int datalen)
00226 {
00227 int res = 0;
00228 struct local_pvt *p = NULL;
00229 struct ast_channel *otherchan = NULL;
00230 ast_chan_write_info_t *write_info;
00231
00232 if (option != AST_OPTION_CHANNEL_WRITE) {
00233 return -1;
00234 }
00235
00236 write_info = data;
00237
00238 if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) {
00239 ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n");
00240 return -1;
00241 }
00242
00243
00244 if (!(p = ast->tech_pvt)) {
00245 return -1;
00246 }
00247 ao2_ref(p, 1);
00248 ast_channel_unlock(ast);
00249
00250
00251 ao2_lock(p);
00252 otherchan = (write_info->chan == p->owner) ? p->chan : p->owner;
00253 if (!otherchan || otherchan == write_info->chan) {
00254 res = -1;
00255 otherchan = NULL;
00256 ao2_unlock(p);
00257 goto setoption_cleanup;
00258 }
00259 ast_channel_ref(otherchan);
00260
00261
00262 ao2_unlock(p);
00263
00264 ast_channel_lock(otherchan);
00265 res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value);
00266 ast_channel_unlock(otherchan);
00267
00268 setoption_cleanup:
00269 if (p) {
00270 ao2_ref(p, -1);
00271 }
00272 if (otherchan) {
00273 ast_channel_unref(otherchan);
00274 }
00275 ast_channel_lock(ast);
00276 return res;
00277 }
00278
00279
00280 static int local_devicestate(const char *data)
00281 {
00282 char *exten = ast_strdupa(data);
00283 char *context = NULL, *opts = NULL;
00284 int res;
00285 struct local_pvt *lp;
00286 struct ao2_iterator it;
00287
00288 if (!(context = strchr(exten, '@'))) {
00289 ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
00290 return AST_DEVICE_INVALID;
00291 }
00292
00293 *context++ = '\0';
00294
00295
00296 if ((opts = strchr(context, '/')))
00297 *opts = '\0';
00298
00299 ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
00300
00301 res = ast_exists_extension(NULL, context, exten, 1, NULL);
00302 if (!res)
00303 return AST_DEVICE_INVALID;
00304
00305 res = AST_DEVICE_NOT_INUSE;
00306
00307 it = ao2_iterator_init(locals, 0);
00308 while ((lp = ao2_iterator_next(&it))) {
00309 if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) {
00310 res = AST_DEVICE_INUSE;
00311 ao2_ref(lp, -1);
00312 break;
00313 }
00314 ao2_ref(lp, -1);
00315 }
00316 ao2_iterator_destroy(&it);
00317
00318 return res;
00319 }
00320
00321
00322 static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
00323 {
00324 struct local_pvt *p = bridge->tech_pvt;
00325 struct ast_channel *bridged = bridge;
00326
00327 if (!p) {
00328 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n",
00329 ast_channel_name(chan), ast_channel_name(bridge));
00330 return NULL;
00331 }
00332
00333 ao2_lock(p);
00334
00335 if (ast_test_flag(p, LOCAL_BRIDGE)) {
00336
00337 bridged = (bridge == p->owner ? p->chan : p->owner);
00338
00339
00340 if (!bridged) {
00341 bridged = bridge;
00342 } else if (bridged->_bridge) {
00343 bridged = bridged->_bridge;
00344 }
00345 }
00346
00347 ao2_unlock(p);
00348
00349 return bridged;
00350 }
00351
00352
00353 static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
00354 {
00355 struct local_pvt *p;
00356 struct ast_channel *bridged = NULL;
00357 struct ast_channel *tmp = NULL;
00358 int res = 0;
00359
00360 if (option != AST_OPTION_T38_STATE) {
00361
00362 return -1;
00363 }
00364
00365
00366 if (!(p = ast->tech_pvt)) {
00367 return -1;
00368 }
00369
00370 ao2_lock(p);
00371 if (!(tmp = IS_OUTBOUND(ast, p) ? p->owner : p->chan)) {
00372 ao2_unlock(p);
00373 return -1;
00374 }
00375 ast_channel_ref(tmp);
00376 ao2_unlock(p);
00377 ast_channel_unlock(ast);
00378
00379 ast_channel_lock(tmp);
00380 if (!(bridged = ast_bridged_channel(tmp))) {
00381 res = -1;
00382 ast_channel_unlock(tmp);
00383 goto query_cleanup;
00384 }
00385 ast_channel_ref(bridged);
00386 ast_channel_unlock(tmp);
00387
00388 query_cleanup:
00389 if (bridged) {
00390 res = ast_channel_queryoption(bridged, option, data, datalen, 0);
00391 bridged = ast_channel_unref(bridged);
00392 }
00393 if (tmp) {
00394 tmp = ast_channel_unref(tmp);
00395 }
00396 ast_channel_lock(ast);
00397
00398 return res;
00399 }
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409 static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f,
00410 struct ast_channel *us, int us_locked)
00411 {
00412 struct ast_channel *other = NULL;
00413
00414
00415 other = isoutbound ? p->owner : p->chan;
00416
00417 if (!other) {
00418 return 0;
00419 }
00420
00421
00422 if (us && us->generator && other->generator) {
00423 return 0;
00424 }
00425
00426
00427
00428 ast_channel_ref(other);
00429 if (us && us_locked) {
00430 ast_channel_unlock(us);
00431 }
00432 ao2_unlock(p);
00433
00434 if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_RINGING) {
00435 ast_setstate(other, AST_STATE_RINGING);
00436 }
00437 ast_queue_frame(other, f);
00438
00439 other = ast_channel_unref(other);
00440 if (us && us_locked) {
00441 ast_channel_lock(us);
00442 }
00443 ao2_lock(p);
00444
00445 return 0;
00446 }
00447
00448 static int local_answer(struct ast_channel *ast)
00449 {
00450 struct local_pvt *p = ast->tech_pvt;
00451 int isoutbound;
00452 int res = -1;
00453
00454 if (!p) {
00455 return -1;
00456 }
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_channel_name(ast));
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
00627 ao2_lock(p);
00628
00629 if ((p->owner != oldchan) && (p->chan != oldchan)) {
00630 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00631 ao2_unlock(p);
00632 return -1;
00633 }
00634 if (p->owner == oldchan) {
00635 p->owner = newchan;
00636 } else {
00637 p->chan = newchan;
00638 }
00639
00640
00641 if (!ast_check_hangup(newchan) && ((p->owner && p->owner->_bridge == p->chan) || (p->chan && p->chan->_bridge == p->owner))) {
00642 ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n");
00643 ao2_unlock(p);
00644 ast_queue_hangup(newchan);
00645 return -1;
00646 }
00647
00648 ao2_unlock(p);
00649 return 0;
00650 }
00651
00652 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
00653 {
00654 struct local_pvt *p = ast->tech_pvt;
00655 int res = 0;
00656 struct ast_frame f = { AST_FRAME_CONTROL, };
00657 int isoutbound;
00658
00659 if (!p) {
00660 return -1;
00661 }
00662
00663 ao2_ref(p, 1);
00664
00665
00666 if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
00667 ast_moh_start(ast, data, NULL);
00668 } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
00669 ast_moh_stop(ast);
00670 } else if (condition == AST_CONTROL_CONNECTED_LINE || condition == AST_CONTROL_REDIRECTING) {
00671 struct ast_channel *this_channel;
00672 struct ast_channel *the_other_channel;
00673
00674
00675
00676
00677
00678
00679
00680 ao2_lock(p);
00681 isoutbound = IS_OUTBOUND(ast, p);
00682 if (isoutbound) {
00683 this_channel = p->chan;
00684 the_other_channel = p->owner;
00685 } else {
00686 this_channel = p->owner;
00687 the_other_channel = p->chan;
00688 }
00689 if (the_other_channel) {
00690 unsigned char frame_data[1024];
00691 if (condition == AST_CONTROL_CONNECTED_LINE) {
00692 if (isoutbound) {
00693 ast_connected_line_copy_to_caller(&the_other_channel->caller, &this_channel->connected);
00694 }
00695 f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data), &this_channel->connected, NULL);
00696 } else {
00697 f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data), &this_channel->redirecting, NULL);
00698 }
00699 f.subclass.integer = condition;
00700 f.data.ptr = frame_data;
00701 res = local_queue_frame(p, isoutbound, &f, ast, 1);
00702 }
00703 ao2_unlock(p);
00704 } else {
00705
00706 ao2_lock(p);
00707 isoutbound = IS_OUTBOUND(ast, p);
00708 f.subclass.integer = condition;
00709 f.data.ptr = (void*)data;
00710 f.datalen = datalen;
00711 res = local_queue_frame(p, isoutbound, &f, ast, 1);
00712 ao2_unlock(p);
00713 }
00714
00715 ao2_ref(p, -1);
00716 return res;
00717 }
00718
00719 static int local_digit_begin(struct ast_channel *ast, char digit)
00720 {
00721 struct local_pvt *p = ast->tech_pvt;
00722 int res = -1;
00723 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00724 int isoutbound;
00725
00726 if (!p) {
00727 return -1;
00728 }
00729
00730 ao2_ref(p, 1);
00731 ao2_lock(p);
00732 isoutbound = IS_OUTBOUND(ast, p);
00733 f.subclass.integer = digit;
00734 res = local_queue_frame(p, isoutbound, &f, ast, 0);
00735 ao2_unlock(p);
00736 ao2_ref(p, -1);
00737
00738 return res;
00739 }
00740
00741 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
00742 {
00743 struct local_pvt *p = ast->tech_pvt;
00744 int res = -1;
00745 struct ast_frame f = { AST_FRAME_DTMF_END, };
00746 int isoutbound;
00747
00748 if (!p) {
00749 return -1;
00750 }
00751
00752 ao2_ref(p, 1);
00753 ao2_lock(p);
00754 isoutbound = IS_OUTBOUND(ast, p);
00755 f.subclass.integer = digit;
00756 f.len = duration;
00757 res = local_queue_frame(p, isoutbound, &f, ast, 0);
00758 ao2_unlock(p);
00759 ao2_ref(p, -1);
00760
00761 return res;
00762 }
00763
00764 static int local_sendtext(struct ast_channel *ast, const char *text)
00765 {
00766 struct local_pvt *p = ast->tech_pvt;
00767 int res = -1;
00768 struct ast_frame f = { AST_FRAME_TEXT, };
00769 int isoutbound;
00770
00771 if (!p) {
00772 return -1;
00773 }
00774
00775 ao2_lock(p);
00776 ao2_ref(p, 1);
00777 isoutbound = IS_OUTBOUND(ast, p);
00778 f.data.ptr = (char *) text;
00779 f.datalen = strlen(text) + 1;
00780 res = local_queue_frame(p, isoutbound, &f, ast, 0);
00781 ao2_unlock(p);
00782 ao2_ref(p, -1);
00783 return res;
00784 }
00785
00786 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
00787 {
00788 struct local_pvt *p = ast->tech_pvt;
00789 int res = -1;
00790 struct ast_frame f = { AST_FRAME_HTML, };
00791 int isoutbound;
00792
00793 if (!p) {
00794 return -1;
00795 }
00796
00797 ao2_lock(p);
00798 ao2_ref(p, 1);
00799 isoutbound = IS_OUTBOUND(ast, p);
00800 f.subclass.integer = subclass;
00801 f.data.ptr = (char *)data;
00802 f.datalen = datalen;
00803 res = local_queue_frame(p, isoutbound, &f, ast, 0);
00804 ao2_unlock(p);
00805 ao2_ref(p, -1);
00806
00807 return res;
00808 }
00809
00810
00811
00812 static int local_call(struct ast_channel *ast, const char *dest, int timeout)
00813 {
00814 struct local_pvt *p = ast->tech_pvt;
00815 int pvt_locked = 0;
00816
00817 struct ast_channel *owner = NULL;
00818 struct ast_channel *chan = NULL;
00819 int res;
00820 struct ast_var_t *varptr = NULL, *new;
00821 size_t len, namelen;
00822 char *reduced_dest = ast_strdupa(dest);
00823 char *slash;
00824 const char *exten;
00825 const char *context;
00826
00827 if (!p) {
00828 return -1;
00829 }
00830
00831
00832
00833 ao2_ref(p, 1);
00834 ast_channel_unlock(ast);
00835
00836 awesome_locking(p, &chan, &owner);
00837 pvt_locked = 1;
00838
00839 if (owner != ast) {
00840 res = -1;
00841 goto return_cleanup;
00842 }
00843
00844 if (!owner || !chan) {
00845 res = -1;
00846 goto return_cleanup;
00847 }
00848
00849
00850
00851
00852
00853
00854
00855
00856 ast_party_redirecting_copy(&chan->redirecting, &owner->redirecting);
00857
00858 ast_party_dialed_copy(&chan->dialed, &owner->dialed);
00859
00860 ast_connected_line_copy_to_caller(&chan->caller, &owner->connected);
00861 ast_connected_line_copy_from_caller(&chan->connected, &owner->caller);
00862
00863 ast_channel_language_set(chan, ast_channel_language(owner));
00864 ast_channel_accountcode_set(chan, ast_channel_accountcode(owner));
00865 ast_channel_musicclass_set(chan, ast_channel_musicclass(owner));
00866 ast_cdr_update(chan);
00867
00868 ast_channel_cc_params_init(chan, ast_channel_get_cc_config_params(owner));
00869
00870
00871 if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00872 ast_set_flag(chan, AST_FLAG_ANSWERED_ELSEWHERE);
00873 }
00874
00875
00876
00877 AST_LIST_TRAVERSE(&owner->varshead, varptr, entries) {
00878 namelen = strlen(varptr->name);
00879 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00880 if ((new = ast_calloc(1, len))) {
00881 memcpy(new, varptr, len);
00882 new->value = &(new->name[0]) + namelen + 1;
00883 AST_LIST_INSERT_TAIL(&chan->varshead, new, entries);
00884 }
00885 }
00886 ast_channel_datastore_inherit(owner, chan);
00887
00888
00889
00890
00891 if ((slash = strrchr(reduced_dest, '/'))) {
00892 *slash = '\0';
00893 }
00894 ast_set_cc_interfaces_chanvar(chan, reduced_dest);
00895
00896 exten = ast_strdupa(chan->exten);
00897 context = ast_strdupa(chan->context);
00898
00899 ao2_unlock(p);
00900 pvt_locked = 0;
00901
00902 ast_channel_unlock(chan);
00903
00904 if (!ast_exists_extension(chan, context, exten, 1,
00905 S_COR(owner->caller.id.number.valid, owner->caller.id.number.str, NULL))) {
00906 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", exten, context);
00907 res = -1;
00908 chan = ast_channel_unref(chan);
00909 goto return_cleanup;
00910 }
00911
00912 manager_event(EVENT_FLAG_CALL, "LocalBridge",
00913 "Channel1: %s\r\n"
00914 "Channel2: %s\r\n"
00915 "Uniqueid1: %s\r\n"
00916 "Uniqueid2: %s\r\n"
00917 "Context: %s\r\n"
00918 "Exten: %s\r\n"
00919 "LocalOptimization: %s\r\n",
00920 ast_channel_name(p->owner), ast_channel_name(p->chan), ast_channel_uniqueid(p->owner), ast_channel_uniqueid(p->chan),
00921 p->context, p->exten,
00922 ast_test_flag(p, LOCAL_NO_OPTIMIZATION) ? "Yes" : "No");
00923
00924
00925
00926 if (!(res = ast_pbx_start(chan))) {
00927 ao2_lock(p);
00928 ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00929 ao2_unlock(p);
00930 }
00931 chan = ast_channel_unref(chan);
00932
00933 return_cleanup:
00934 if (p) {
00935 if (pvt_locked) {
00936 ao2_unlock(p);
00937 }
00938 ao2_ref(p, -1);
00939 }
00940 if (chan) {
00941 ast_channel_unlock(chan);
00942 chan = ast_channel_unref(chan);
00943 }
00944
00945
00946
00947 if (owner) {
00948 if (owner != ast) {
00949 ast_channel_unlock(owner);
00950 ast_channel_lock(ast);
00951 }
00952 owner = ast_channel_unref(owner);
00953 } else {
00954
00955 ast_channel_lock(ast);
00956 }
00957
00958 return res;
00959 }
00960
00961
00962 static int local_hangup(struct ast_channel *ast)
00963 {
00964 struct local_pvt *p = ast->tech_pvt;
00965 int isoutbound;
00966 int hangup_chan = 0;
00967 int res = 0;
00968 struct ast_frame f = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = ast->hangupcause };
00969 struct ast_channel *owner = NULL;
00970 struct ast_channel *chan = NULL;
00971
00972 if (!p) {
00973 return -1;
00974 }
00975
00976
00977 ao2_ref(p, 1);
00978
00979
00980 ast_channel_unlock(ast);
00981
00982
00983 awesome_locking(p, &chan, &owner);
00984
00985 if (ast != chan && ast != owner) {
00986 res = -1;
00987 goto local_hangup_cleanup;
00988 }
00989
00990 isoutbound = IS_OUTBOUND(ast, p);
00991
00992 if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
00993 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00994 ast_debug(2, "This local call has the ANSWERED_ELSEWHERE flag set.\n");
00995 }
00996
00997 if (isoutbound) {
00998 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00999 if ((status) && (p->owner)) {
01000 p->owner->hangupcause = p->chan->hangupcause;
01001 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
01002 }
01003
01004 ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
01005 ast_module_user_remove(p->u_chan);
01006 p->chan = NULL;
01007 } else {
01008 ast_module_user_remove(p->u_owner);
01009 if (p->chan) {
01010 ast_queue_hangup(p->chan);
01011 }
01012 p->owner = NULL;
01013 }
01014
01015 ast->tech_pvt = NULL;
01016
01017 if (!p->owner && !p->chan) {
01018 ao2_unlock(p);
01019
01020 ao2_unlink(locals, p);
01021 ao2_ref(p, -1);
01022 p = NULL;
01023 res = 0;
01024 goto local_hangup_cleanup;
01025 }
01026 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) {
01027
01028 hangup_chan = 1;
01029 } else {
01030 local_queue_frame(p, isoutbound, &f, NULL, 0);
01031 }
01032
01033 local_hangup_cleanup:
01034 if (p) {
01035 ao2_unlock(p);
01036 ao2_ref(p, -1);
01037 }
01038 if (chan) {
01039 ast_channel_unlock(chan);
01040 if (hangup_chan) {
01041 ast_hangup(chan);
01042 }
01043 chan = ast_channel_unref(chan);
01044 }
01045 if (owner) {
01046 ast_channel_unlock(owner);
01047 owner = ast_channel_unref(owner);
01048 }
01049
01050
01051 ast_channel_lock(ast);
01052 return res;
01053 }
01054
01055 static void local_destroy(void *obj)
01056 {
01057 struct local_pvt *pvt = obj;
01058 pvt->reqcap = ast_format_cap_destroy(pvt->reqcap);
01059 }
01060
01061
01062 static struct local_pvt *local_alloc(const char *data, struct ast_format_cap *cap)
01063 {
01064 struct local_pvt *tmp = NULL;
01065 char *c = NULL, *opts = NULL;
01066
01067 if (!(tmp = ao2_alloc(sizeof(*tmp), local_destroy))) {
01068 return NULL;
01069 }
01070 if (!(tmp->reqcap = ast_format_cap_dup(cap))) {
01071 ao2_ref(tmp, -1);
01072 return NULL;
01073 }
01074
01075
01076 ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
01077
01078 memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
01079
01080
01081 if ((opts = strchr(tmp->exten, '/'))) {
01082 *opts++ = '\0';
01083 if (strchr(opts, 'n'))
01084 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
01085 if (strchr(opts, 'j')) {
01086 if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
01087 ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
01088 else {
01089 ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
01090 "to use the 'j' option to enable the jitterbuffer\n");
01091 }
01092 }
01093 if (strchr(opts, 'b')) {
01094 ast_set_flag(tmp, LOCAL_BRIDGE);
01095 }
01096 if (strchr(opts, 'm')) {
01097 ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
01098 }
01099 }
01100
01101
01102 if ((c = strchr(tmp->exten, '@')))
01103 *c++ = '\0';
01104
01105 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
01106 #if 0
01107
01108
01109
01110 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
01111 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
01112 tmp = local_pvt_destroy(tmp);
01113 } else {
01114 #endif
01115
01116 ao2_link(locals, tmp);
01117 #if 0
01118 }
01119 #endif
01120 return tmp;
01121 }
01122
01123
01124 static struct ast_channel *local_new(struct local_pvt *p, int state, const char *linkedid)
01125 {
01126 struct ast_channel *tmp = NULL, *tmp2 = NULL;
01127 int randnum = ast_random() & 0xffff;
01128 struct ast_format fmt;
01129 const char *t;
01130 int ama;
01131
01132
01133
01134 if (p->owner && ast_channel_accountcode(p->owner))
01135 t = ast_channel_accountcode(p->owner);
01136 else
01137 t = "";
01138
01139 if (p->owner)
01140 ama = p->owner->amaflags;
01141 else
01142 ama = 0;
01143 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))
01144 || !(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))) {
01145 if (tmp) {
01146 tmp = ast_channel_release(tmp);
01147 }
01148 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
01149 return NULL;
01150 }
01151
01152 tmp2->tech = tmp->tech = &local_tech;
01153
01154 ast_format_cap_copy(tmp->nativeformats, p->reqcap);
01155 ast_format_cap_copy(tmp2->nativeformats, p->reqcap);
01156
01157
01158 ast_best_codec(p->reqcap, &fmt);
01159 ast_format_copy(&tmp->writeformat, &fmt);
01160 ast_format_copy(&tmp2->writeformat, &fmt);
01161 ast_format_copy(&tmp->rawwriteformat, &fmt);
01162 ast_format_copy(&tmp2->rawwriteformat, &fmt);
01163 ast_format_copy(&tmp->readformat, &fmt);
01164 ast_format_copy(&tmp2->readformat, &fmt);
01165 ast_format_copy(&tmp->rawreadformat, &fmt);
01166 ast_format_copy(&tmp2->rawreadformat, &fmt);
01167
01168 tmp->tech_pvt = p;
01169 tmp2->tech_pvt = p;
01170
01171 p->owner = tmp;
01172 p->chan = tmp2;
01173 p->u_owner = ast_module_user_add(p->owner);
01174 p->u_chan = ast_module_user_add(p->chan);
01175
01176 ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
01177 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
01178 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
01179 tmp->priority = 1;
01180 tmp2->priority = 1;
01181
01182 ast_jb_configure(tmp, &p->jb_conf);
01183
01184 return tmp;
01185 }
01186
01187
01188 static struct ast_channel *local_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
01189 {
01190 struct local_pvt *p = NULL;
01191 struct ast_channel *chan = NULL;
01192
01193
01194 if ((p = local_alloc(data, cap))) {
01195 if (!(chan = local_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL))) {
01196 ao2_unlink(locals, p);
01197 }
01198 if (chan && ast_channel_cc_params_init(chan, requestor ? ast_channel_get_cc_config_params((struct ast_channel *)requestor) : NULL)) {
01199 chan = ast_channel_release(chan);
01200 ao2_unlink(locals, p);
01201 }
01202 ao2_ref(p, -1);
01203 }
01204
01205 return chan;
01206 }
01207
01208
01209 static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01210 {
01211 struct local_pvt *p = NULL;
01212 struct ao2_iterator it;
01213
01214 switch (cmd) {
01215 case CLI_INIT:
01216 e->command = "local show channels";
01217 e->usage =
01218 "Usage: local show channels\n"
01219 " Provides summary information on active local proxy channels.\n";
01220 return NULL;
01221 case CLI_GENERATE:
01222 return NULL;
01223 }
01224
01225 if (a->argc != 3) {
01226 return CLI_SHOWUSAGE;
01227 }
01228
01229 if (ao2_container_count(locals) == 0) {
01230 ast_cli(a->fd, "No local channels in use\n");
01231 return RESULT_SUCCESS;
01232 }
01233
01234 it = ao2_iterator_init(locals, 0);
01235 while ((p = ao2_iterator_next(&it))) {
01236 ao2_lock(p);
01237 ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? ast_channel_name(p->owner) : "<unowned>", p->exten, p->context);
01238 ao2_unlock(p);
01239 ao2_ref(p, -1);
01240 }
01241 ao2_iterator_destroy(&it);
01242
01243 return CLI_SUCCESS;
01244 }
01245
01246 static struct ast_cli_entry cli_local[] = {
01247 AST_CLI_DEFINE(locals_show, "List status of local channels"),
01248 };
01249
01250 static int manager_optimize_away(struct mansession *s, const struct message *m)
01251 {
01252 const char *channel;
01253 struct local_pvt *p, *tmp = NULL;
01254 struct ast_channel *c;
01255 int found = 0;
01256 struct ao2_iterator it;
01257
01258 channel = astman_get_header(m, "Channel");
01259
01260 if (ast_strlen_zero(channel)) {
01261 astman_send_error(s, m, "'Channel' not specified.");
01262 return 0;
01263 }
01264
01265 c = ast_channel_get_by_name(channel);
01266 if (!c) {
01267 astman_send_error(s, m, "Channel does not exist.");
01268 return 0;
01269 }
01270
01271 p = c->tech_pvt;
01272 ast_channel_unref(c);
01273 c = NULL;
01274
01275 it = ao2_iterator_init(locals, 0);
01276 while ((tmp = ao2_iterator_next(&it))) {
01277 if (tmp == p) {
01278 ao2_lock(tmp);
01279 found = 1;
01280 ast_clear_flag(tmp, LOCAL_NO_OPTIMIZATION);
01281 ao2_unlock(tmp);
01282 ao2_ref(tmp, -1);
01283 break;
01284 }
01285 ao2_ref(tmp, -1);
01286 }
01287 ao2_iterator_destroy(&it);
01288
01289 if (found) {
01290 astman_send_ack(s, m, "Queued channel to be optimized away");
01291 } else {
01292 astman_send_error(s, m, "Unable to find channel");
01293 }
01294
01295 return 0;
01296 }
01297
01298
01299 static int locals_cmp_cb(void *obj, void *arg, int flags)
01300 {
01301 return (obj == arg) ? CMP_MATCH : 0;
01302 }
01303
01304
01305 static int load_module(void)
01306 {
01307 if (!(local_tech.capabilities = ast_format_cap_alloc())) {
01308 return AST_MODULE_LOAD_FAILURE;
01309 }
01310 ast_format_cap_add_all(local_tech.capabilities);
01311
01312 if (!(locals = ao2_container_alloc(BUCKET_SIZE, NULL, locals_cmp_cb))) {
01313 ast_format_cap_destroy(local_tech.capabilities);
01314 return AST_MODULE_LOAD_FAILURE;
01315 }
01316
01317
01318 if (ast_channel_register(&local_tech)) {
01319 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
01320 ao2_ref(locals, -1);
01321 ast_format_cap_destroy(local_tech.capabilities);
01322 return AST_MODULE_LOAD_FAILURE;
01323 }
01324 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
01325 ast_manager_register_xml("LocalOptimizeAway", EVENT_FLAG_SYSTEM|EVENT_FLAG_CALL, manager_optimize_away);
01326
01327 return AST_MODULE_LOAD_SUCCESS;
01328 }
01329
01330
01331 static int unload_module(void)
01332 {
01333 struct local_pvt *p = NULL;
01334 struct ao2_iterator it;
01335
01336
01337 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
01338 ast_manager_unregister("LocalOptimizeAway");
01339 ast_channel_unregister(&local_tech);
01340
01341 it = ao2_iterator_init(locals, 0);
01342 while ((p = ao2_iterator_next(&it))) {
01343 if (p->owner) {
01344 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
01345 }
01346 ao2_ref(p, -1);
01347 }
01348 ao2_iterator_destroy(&it);
01349 ao2_ref(locals, -1);
01350
01351 ast_format_cap_destroy(local_tech.capabilities);
01352 return 0;
01353 }
01354
01355 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Local Proxy Channel (Note: used internally by other modules)",
01356 .load = load_module,
01357 .unload = unload_module,
01358 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
01359 );