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: 259930 $")
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/rtp.h"
00043 #include "asterisk/acl.h"
00044 #include "asterisk/callerid.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/cli.h"
00047 #include "asterisk/app.h"
00048 #include "asterisk/musiconhold.h"
00049 #include "asterisk/manager.h"
00050 #include "asterisk/stringfields.h"
00051 #include "asterisk/devicestate.h"
00052
00053 static const char tdesc[] = "Local Proxy Channel Driver";
00054
00055 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
00056
00057 static struct ast_jb_conf g_jb_conf = {
00058 .flags = 0,
00059 .max_size = -1,
00060 .resync_threshold = -1,
00061 .impl = "",
00062 .target_extra = -1,
00063 };
00064
00065 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause);
00066 static int local_digit_begin(struct ast_channel *ast, char digit);
00067 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
00068 static int local_call(struct ast_channel *ast, char *dest, int timeout);
00069 static int local_hangup(struct ast_channel *ast);
00070 static int local_answer(struct ast_channel *ast);
00071 static struct ast_frame *local_read(struct ast_channel *ast);
00072 static int local_write(struct ast_channel *ast, struct ast_frame *f);
00073 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
00074 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00075 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
00076 static int local_sendtext(struct ast_channel *ast, const char *text);
00077 static int local_devicestate(void *data);
00078 static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
00079
00080
00081 static const struct ast_channel_tech local_tech = {
00082 .type = "Local",
00083 .description = tdesc,
00084 .capabilities = -1,
00085 .requester = local_request,
00086 .send_digit_begin = local_digit_begin,
00087 .send_digit_end = local_digit_end,
00088 .call = local_call,
00089 .hangup = local_hangup,
00090 .answer = local_answer,
00091 .read = local_read,
00092 .write = local_write,
00093 .write_video = local_write,
00094 .exception = local_read,
00095 .indicate = local_indicate,
00096 .fixup = local_fixup,
00097 .send_html = local_sendhtml,
00098 .send_text = local_sendtext,
00099 .devicestate = local_devicestate,
00100 .bridged_channel = local_bridgedchannel,
00101 };
00102
00103 struct local_pvt {
00104 ast_mutex_t lock;
00105 unsigned int flags;
00106 char context[AST_MAX_CONTEXT];
00107 char exten[AST_MAX_EXTENSION];
00108 int reqformat;
00109 struct ast_jb_conf jb_conf;
00110 struct ast_channel *owner;
00111 struct ast_channel *chan;
00112 struct ast_module_user *u_owner;
00113 struct ast_module_user *u_chan;
00114 AST_LIST_ENTRY(local_pvt) list;
00115 };
00116
00117 #define LOCAL_GLARE_DETECT (1 << 0)
00118 #define LOCAL_CANCEL_QUEUE (1 << 1)
00119 #define LOCAL_ALREADY_MASQED (1 << 2)
00120 #define LOCAL_LAUNCHED_PBX (1 << 3)
00121 #define LOCAL_NO_OPTIMIZATION (1 << 4)
00122 #define LOCAL_BRIDGE (1 << 5)
00123 #define LOCAL_MOH_PASSTHRU (1 << 6)
00124
00125 static AST_LIST_HEAD_STATIC(locals, local_pvt);
00126
00127
00128 static int local_devicestate(void *data)
00129 {
00130 char *exten = ast_strdupa(data);
00131 char *context = NULL, *opts = NULL;
00132 int res;
00133 struct local_pvt *lp;
00134
00135 if (!(context = strchr(exten, '@'))) {
00136 ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
00137 return AST_DEVICE_INVALID;
00138 }
00139
00140 *context++ = '\0';
00141
00142
00143 if ((opts = strchr(context, '/')))
00144 *opts = '\0';
00145
00146 ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
00147
00148 res = ast_exists_extension(NULL, context, exten, 1, NULL);
00149 if (!res)
00150 return AST_DEVICE_INVALID;
00151
00152 res = AST_DEVICE_NOT_INUSE;
00153 AST_LIST_LOCK(&locals);
00154 AST_LIST_TRAVERSE(&locals, lp, list) {
00155 if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) {
00156 res = AST_DEVICE_INUSE;
00157 break;
00158 }
00159 }
00160 AST_LIST_UNLOCK(&locals);
00161
00162 return res;
00163 }
00164
00165
00166
00167
00168 static struct local_pvt *local_pvt_destroy(struct local_pvt *pvt)
00169 {
00170 ast_mutex_destroy(&pvt->lock);
00171 ast_free(pvt);
00172 return NULL;
00173 }
00174
00175
00176 static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
00177 {
00178 struct local_pvt *p = bridge->tech_pvt;
00179 struct ast_channel *bridged = bridge;
00180
00181 if (!p) {
00182 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning <none>\n",
00183 chan->name, bridge->name);
00184 return NULL;
00185 }
00186
00187 ast_mutex_lock(&p->lock);
00188
00189 if (ast_test_flag(p, LOCAL_BRIDGE)) {
00190
00191 bridged = (bridge == p->owner ? p->chan : p->owner);
00192
00193
00194 if (!bridged) {
00195 bridged = bridge;
00196 } else if (bridged->_bridge) {
00197 bridged = bridged->_bridge;
00198 }
00199 }
00200
00201 ast_mutex_unlock(&p->lock);
00202
00203 return bridged;
00204 }
00205
00206 static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f,
00207 struct ast_channel *us, int us_locked)
00208 {
00209 struct ast_channel *other = NULL;
00210
00211
00212 other = isoutbound ? p->owner : p->chan;
00213
00214 if (!other) {
00215 return 0;
00216 }
00217
00218
00219 if (us && us->generator && other->generator) {
00220 return 0;
00221 }
00222
00223
00224 ast_set_flag(p, LOCAL_GLARE_DETECT);
00225
00226
00227 while (other && ast_channel_trylock(other)) {
00228 ast_mutex_unlock(&p->lock);
00229 if (us && us_locked) {
00230 do {
00231 CHANNEL_DEADLOCK_AVOIDANCE(us);
00232 } while (ast_mutex_trylock(&p->lock));
00233 } else {
00234 usleep(1);
00235 ast_mutex_lock(&p->lock);
00236 }
00237 other = isoutbound ? p->owner : p->chan;
00238 }
00239
00240
00241
00242
00243 if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) {
00244
00245
00246 ast_mutex_unlock(&p->lock);
00247 p = local_pvt_destroy(p);
00248 if (other) {
00249 ast_channel_unlock(other);
00250 }
00251 return -1;
00252 }
00253
00254 if (other) {
00255 if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_RINGING) {
00256 ast_setstate(other, AST_STATE_RINGING);
00257 }
00258 ast_queue_frame(other, f);
00259 ast_channel_unlock(other);
00260 }
00261
00262 ast_clear_flag(p, LOCAL_GLARE_DETECT);
00263
00264 return 0;
00265 }
00266
00267 static int local_answer(struct ast_channel *ast)
00268 {
00269 struct local_pvt *p = ast->tech_pvt;
00270 int isoutbound;
00271 int res = -1;
00272
00273 if (!p)
00274 return -1;
00275
00276 ast_mutex_lock(&p->lock);
00277 isoutbound = IS_OUTBOUND(ast, p);
00278 if (isoutbound) {
00279
00280 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00281 res = local_queue_frame(p, isoutbound, &answer, ast, 1);
00282 } else
00283 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n");
00284 if (!res)
00285 ast_mutex_unlock(&p->lock);
00286 return res;
00287 }
00288
00289
00290
00291
00292
00293 static void check_bridge(struct local_pvt *p)
00294 {
00295 struct ast_channel_monitor *tmp;
00296 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)))
00297 return;
00298
00299
00300
00301
00302
00303
00304 if (p->chan->_bridge && AST_LIST_EMPTY(&p->owner->readq)) {
00305
00306
00307
00308
00309 if (!ast_channel_trylock(p->chan->_bridge)) {
00310 if (!ast_check_hangup(p->chan->_bridge)) {
00311 if (!ast_channel_trylock(p->owner)) {
00312 if (!ast_check_hangup(p->owner)) {
00313 if (p->owner->monitor && !p->chan->_bridge->monitor) {
00314
00315
00316
00317
00318
00319 tmp = p->owner->monitor;
00320 p->owner->monitor = p->chan->_bridge->monitor;
00321 p->chan->_bridge->monitor = tmp;
00322 }
00323 if (p->chan->audiohooks) {
00324 struct ast_audiohook_list *audiohooks_swapper;
00325 audiohooks_swapper = p->chan->audiohooks;
00326 p->chan->audiohooks = p->owner->audiohooks;
00327 p->owner->audiohooks = audiohooks_swapper;
00328 }
00329 ast_app_group_update(p->chan, p->owner);
00330 ast_channel_masquerade(p->owner, p->chan->_bridge);
00331 ast_set_flag(p, LOCAL_ALREADY_MASQED);
00332 }
00333 ast_channel_unlock(p->owner);
00334 }
00335 ast_channel_unlock(p->chan->_bridge);
00336 }
00337 }
00338 }
00339 }
00340
00341 static struct ast_frame *local_read(struct ast_channel *ast)
00342 {
00343 return &ast_null_frame;
00344 }
00345
00346 static int local_write(struct ast_channel *ast, struct ast_frame *f)
00347 {
00348 struct local_pvt *p = ast->tech_pvt;
00349 int res = -1;
00350 int isoutbound;
00351
00352 if (!p)
00353 return -1;
00354
00355
00356 ast_mutex_lock(&p->lock);
00357 isoutbound = IS_OUTBOUND(ast, p);
00358 if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
00359 check_bridge(p);
00360 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
00361 res = local_queue_frame(p, isoutbound, f, ast, 1);
00362 else {
00363 ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name);
00364 res = 0;
00365 }
00366 if (!res)
00367 ast_mutex_unlock(&p->lock);
00368 return res;
00369 }
00370
00371 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00372 {
00373 struct local_pvt *p = newchan->tech_pvt;
00374
00375 if (!p)
00376 return -1;
00377
00378 ast_mutex_lock(&p->lock);
00379
00380 if ((p->owner != oldchan) && (p->chan != oldchan)) {
00381 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00382 ast_mutex_unlock(&p->lock);
00383 return -1;
00384 }
00385 if (p->owner == oldchan)
00386 p->owner = newchan;
00387 else
00388 p->chan = newchan;
00389 ast_mutex_unlock(&p->lock);
00390 return 0;
00391 }
00392
00393 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
00394 {
00395 struct local_pvt *p = ast->tech_pvt;
00396 int res = 0;
00397 struct ast_frame f = { AST_FRAME_CONTROL, };
00398 int isoutbound;
00399
00400 if (!p)
00401 return -1;
00402
00403
00404 if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
00405 ast_moh_start(ast, data, NULL);
00406 } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
00407 ast_moh_stop(ast);
00408 } else {
00409
00410 ast_mutex_lock(&p->lock);
00411 isoutbound = IS_OUTBOUND(ast, p);
00412 f.subclass = condition;
00413 f.data.ptr = (void*)data;
00414 f.datalen = datalen;
00415 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1)))
00416 ast_mutex_unlock(&p->lock);
00417 }
00418
00419 return res;
00420 }
00421
00422 static int local_digit_begin(struct ast_channel *ast, char digit)
00423 {
00424 struct local_pvt *p = ast->tech_pvt;
00425 int res = -1;
00426 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00427 int isoutbound;
00428
00429 if (!p)
00430 return -1;
00431
00432 ast_mutex_lock(&p->lock);
00433 isoutbound = IS_OUTBOUND(ast, p);
00434 f.subclass = digit;
00435 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00436 ast_mutex_unlock(&p->lock);
00437
00438 return res;
00439 }
00440
00441 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
00442 {
00443 struct local_pvt *p = ast->tech_pvt;
00444 int res = -1;
00445 struct ast_frame f = { AST_FRAME_DTMF_END, };
00446 int isoutbound;
00447
00448 if (!p)
00449 return -1;
00450
00451 ast_mutex_lock(&p->lock);
00452 isoutbound = IS_OUTBOUND(ast, p);
00453 f.subclass = digit;
00454 f.len = duration;
00455 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00456 ast_mutex_unlock(&p->lock);
00457
00458 return res;
00459 }
00460
00461 static int local_sendtext(struct ast_channel *ast, const char *text)
00462 {
00463 struct local_pvt *p = ast->tech_pvt;
00464 int res = -1;
00465 struct ast_frame f = { AST_FRAME_TEXT, };
00466 int isoutbound;
00467
00468 if (!p)
00469 return -1;
00470
00471 ast_mutex_lock(&p->lock);
00472 isoutbound = IS_OUTBOUND(ast, p);
00473 f.data.ptr = (char *) text;
00474 f.datalen = strlen(text) + 1;
00475 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00476 ast_mutex_unlock(&p->lock);
00477 return res;
00478 }
00479
00480 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
00481 {
00482 struct local_pvt *p = ast->tech_pvt;
00483 int res = -1;
00484 struct ast_frame f = { AST_FRAME_HTML, };
00485 int isoutbound;
00486
00487 if (!p)
00488 return -1;
00489
00490 ast_mutex_lock(&p->lock);
00491 isoutbound = IS_OUTBOUND(ast, p);
00492 f.subclass = subclass;
00493 f.data.ptr = (char *)data;
00494 f.datalen = datalen;
00495 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
00496 ast_mutex_unlock(&p->lock);
00497 return res;
00498 }
00499
00500
00501
00502 static int local_call(struct ast_channel *ast, char *dest, int timeout)
00503 {
00504 struct local_pvt *p = ast->tech_pvt;
00505 int res;
00506 struct ast_var_t *varptr = NULL, *new;
00507 size_t len, namelen;
00508
00509 if (!p)
00510 return -1;
00511
00512 ast_mutex_lock(&p->lock);
00513
00514
00515
00516
00517
00518 p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid);
00519 p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
00520 p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
00521 p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
00522 p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
00523 p->chan->cid.cid_pres = p->owner->cid.cid_pres;
00524 p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2;
00525 p->chan->cid.cid_ton = p->owner->cid.cid_ton;
00526 p->chan->cid.cid_tns = p->owner->cid.cid_tns;
00527 ast_string_field_set(p->chan, language, p->owner->language);
00528 ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
00529 ast_string_field_set(p->chan, musicclass, p->owner->musicclass);
00530 ast_cdr_update(p->chan);
00531 p->chan->cdrflags = p->owner->cdrflags;
00532
00533 if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) {
00534 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context);
00535 ast_mutex_unlock(&p->lock);
00536 return -1;
00537 }
00538
00539
00540
00541 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
00542 namelen = strlen(varptr->name);
00543 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00544 if ((new = ast_calloc(1, len))) {
00545 memcpy(new, varptr, len);
00546 new->value = &(new->name[0]) + namelen + 1;
00547 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
00548 }
00549 }
00550 ast_channel_datastore_inherit(p->owner, p->chan);
00551
00552
00553 if (!(res = ast_pbx_start(p->chan)))
00554 ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00555
00556 ast_mutex_unlock(&p->lock);
00557 return res;
00558 }
00559
00560
00561 static int local_hangup(struct ast_channel *ast)
00562 {
00563 struct local_pvt *p = ast->tech_pvt;
00564 int isoutbound;
00565 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP, .data.uint32 = ast->hangupcause };
00566 struct ast_channel *ochan = NULL;
00567 int glaredetect = 0, res = 0;
00568
00569 if (!p)
00570 return -1;
00571
00572 ast_mutex_lock(&p->lock);
00573
00574 if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE))
00575 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
00576 isoutbound = IS_OUTBOUND(ast, p);
00577 if (isoutbound) {
00578 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00579 if ((status) && (p->owner)) {
00580
00581 while (p->owner && ast_channel_trylock(p->owner)) {
00582 ast_mutex_unlock(&p->lock);
00583 if (p->chan) {
00584 ast_channel_unlock(p->chan);
00585 }
00586 usleep(1);
00587 if (p->chan) {
00588 ast_channel_lock(p->chan);
00589 }
00590 ast_mutex_lock(&p->lock);
00591 }
00592 if (p->owner) {
00593 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00594 ast_channel_unlock(p->owner);
00595 }
00596 }
00597 p->chan = NULL;
00598 ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
00599 ast_module_user_remove(p->u_chan);
00600 } else {
00601 ast_module_user_remove(p->u_owner);
00602 while (p->chan && ast_channel_trylock(p->chan)) {
00603 ast_mutex_unlock(&p->lock);
00604 if (p->owner) {
00605 ast_channel_unlock(p->owner);
00606 }
00607 usleep(1);
00608 if (p->owner) {
00609 ast_channel_lock(p->owner);
00610 }
00611 ast_mutex_lock(&p->lock);
00612 }
00613
00614 p->owner = NULL;
00615 if (p->chan) {
00616 ast_queue_hangup(p->chan);
00617 ast_channel_unlock(p->chan);
00618 }
00619 }
00620
00621 ast->tech_pvt = NULL;
00622
00623 if (!p->owner && !p->chan) {
00624
00625 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
00626
00627
00628 if (glaredetect)
00629 ast_set_flag(p, LOCAL_CANCEL_QUEUE);
00630
00631 AST_LIST_LOCK(&locals);
00632 AST_LIST_REMOVE(&locals, p, list);
00633 AST_LIST_UNLOCK(&locals);
00634 ast_mutex_unlock(&p->lock);
00635
00636 if (!glaredetect) {
00637 p = local_pvt_destroy(p);
00638 }
00639 return 0;
00640 }
00641 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
00642
00643 ochan = p->chan;
00644 else
00645 res = local_queue_frame(p, isoutbound, &f, NULL, 1);
00646 if (!res)
00647 ast_mutex_unlock(&p->lock);
00648 if (ochan)
00649 ast_hangup(ochan);
00650 return 0;
00651 }
00652
00653
00654 static struct local_pvt *local_alloc(const char *data, int format)
00655 {
00656 struct local_pvt *tmp = NULL;
00657 char *c = NULL, *opts = NULL;
00658
00659 if (!(tmp = ast_calloc(1, sizeof(*tmp))))
00660 return NULL;
00661
00662
00663 ast_mutex_init(&tmp->lock);
00664 ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
00665
00666 memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
00667
00668
00669 if ((opts = strchr(tmp->exten, '/'))) {
00670 *opts++ = '\0';
00671 if (strchr(opts, 'n'))
00672 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
00673 if (strchr(opts, 'j')) {
00674 if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
00675 ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
00676 else {
00677 ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
00678 "to use the 'j' option to enable the jitterbuffer\n");
00679 }
00680 }
00681 if (strchr(opts, 'b')) {
00682 ast_set_flag(tmp, LOCAL_BRIDGE);
00683 }
00684 if (strchr(opts, 'm')) {
00685 ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
00686 }
00687 }
00688
00689
00690 if ((c = strchr(tmp->exten, '@')))
00691 *c++ = '\0';
00692
00693 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
00694
00695 tmp->reqformat = format;
00696
00697 #if 0
00698
00699
00700
00701 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
00702 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
00703 tmp = local_pvt_destroy(tmp);
00704 } else {
00705 #endif
00706
00707 AST_LIST_LOCK(&locals);
00708 AST_LIST_INSERT_HEAD(&locals, tmp, list);
00709 AST_LIST_UNLOCK(&locals);
00710 #if 0
00711 }
00712 #endif
00713
00714 return tmp;
00715 }
00716
00717
00718 static struct ast_channel *local_new(struct local_pvt *p, int state)
00719 {
00720 struct ast_channel *tmp = NULL, *tmp2 = NULL;
00721 int randnum = ast_random() & 0xffff, fmt = 0;
00722 const char *t;
00723 int ama;
00724
00725
00726
00727 if (p->owner && p->owner->accountcode)
00728 t = p->owner->accountcode;
00729 else
00730 t = "";
00731
00732 if (p->owner)
00733 ama = p->owner->amaflags;
00734 else
00735 ama = 0;
00736 if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x;1", p->exten, p->context, randnum))
00737 || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x;2", p->exten, p->context, randnum))) {
00738 if (tmp)
00739 ast_channel_free(tmp);
00740 if (tmp2)
00741 ast_channel_free(tmp2);
00742 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
00743 return NULL;
00744 }
00745
00746 tmp2->tech = tmp->tech = &local_tech;
00747
00748 tmp->nativeformats = p->reqformat;
00749 tmp2->nativeformats = p->reqformat;
00750
00751
00752 fmt = ast_best_codec(p->reqformat);
00753 tmp->writeformat = fmt;
00754 tmp2->writeformat = fmt;
00755 tmp->rawwriteformat = fmt;
00756 tmp2->rawwriteformat = fmt;
00757 tmp->readformat = fmt;
00758 tmp2->readformat = fmt;
00759 tmp->rawreadformat = fmt;
00760 tmp2->rawreadformat = fmt;
00761
00762 tmp->tech_pvt = p;
00763 tmp2->tech_pvt = p;
00764
00765 p->owner = tmp;
00766 p->chan = tmp2;
00767 p->u_owner = ast_module_user_add(p->owner);
00768 p->u_chan = ast_module_user_add(p->chan);
00769
00770 ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
00771 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
00772 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
00773 tmp->priority = 1;
00774 tmp2->priority = 1;
00775
00776 ast_jb_configure(tmp, &p->jb_conf);
00777
00778 return tmp;
00779 }
00780
00781
00782 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
00783 {
00784 struct local_pvt *p = NULL;
00785 struct ast_channel *chan = NULL;
00786
00787
00788 if ((p = local_alloc(data, format))) {
00789 if (!(chan = local_new(p, AST_STATE_DOWN))) {
00790 AST_LIST_LOCK(&locals);
00791 AST_LIST_REMOVE(&locals, p, list);
00792 AST_LIST_UNLOCK(&locals);
00793 p = local_pvt_destroy(p);
00794 }
00795 }
00796
00797 return chan;
00798 }
00799
00800
00801 static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00802 {
00803 struct local_pvt *p = NULL;
00804
00805 switch (cmd) {
00806 case CLI_INIT:
00807 e->command = "local show channels";
00808 e->usage =
00809 "Usage: local show channels\n"
00810 " Provides summary information on active local proxy channels.\n";
00811 return NULL;
00812 case CLI_GENERATE:
00813 return NULL;
00814 }
00815
00816 if (a->argc != 3)
00817 return CLI_SHOWUSAGE;
00818
00819 AST_LIST_LOCK(&locals);
00820 if (!AST_LIST_EMPTY(&locals)) {
00821 AST_LIST_TRAVERSE(&locals, p, list) {
00822 ast_mutex_lock(&p->lock);
00823 ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
00824 ast_mutex_unlock(&p->lock);
00825 }
00826 } else
00827 ast_cli(a->fd, "No local channels in use\n");
00828 AST_LIST_UNLOCK(&locals);
00829
00830 return CLI_SUCCESS;
00831 }
00832
00833 static struct ast_cli_entry cli_local[] = {
00834 AST_CLI_DEFINE(locals_show, "List status of local channels"),
00835 };
00836
00837
00838 static int load_module(void)
00839 {
00840
00841 if (ast_channel_register(&local_tech)) {
00842 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
00843 return AST_MODULE_LOAD_FAILURE;
00844 }
00845 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00846 return AST_MODULE_LOAD_SUCCESS;
00847 }
00848
00849
00850 static int unload_module(void)
00851 {
00852 struct local_pvt *p = NULL;
00853
00854
00855 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00856 ast_channel_unregister(&local_tech);
00857 if (!AST_LIST_LOCK(&locals)) {
00858
00859 AST_LIST_TRAVERSE(&locals, p, list) {
00860 if (p->owner)
00861 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
00862 }
00863 AST_LIST_UNLOCK(&locals);
00864 } else {
00865 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
00866 return -1;
00867 }
00868 return 0;
00869 }
00870
00871 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Local Proxy Channel (Note: used internally by other modules)");