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