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