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