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