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