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 #include <stdio.h>
00027 #include <string.h>
00028 #include <unistd.h>
00029 #include <sys/socket.h>
00030 #include <errno.h>
00031 #include <stdlib.h>
00032 #include <fcntl.h>
00033 #include <netdb.h>
00034 #include <netinet/in.h>
00035 #include <arpa/inet.h>
00036 #include <sys/signal.h>
00037
00038 #include "asterisk.h"
00039
00040 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 42402 $")
00041
00042 #include "asterisk/lock.h"
00043 #include "asterisk/channel.h"
00044 #include "asterisk/config.h"
00045 #include "asterisk/logger.h"
00046 #include "asterisk/module.h"
00047 #include "asterisk/pbx.h"
00048 #include "asterisk/options.h"
00049 #include "asterisk/lock.h"
00050 #include "asterisk/sched.h"
00051 #include "asterisk/io.h"
00052 #include "asterisk/rtp.h"
00053 #include "asterisk/acl.h"
00054 #include "asterisk/callerid.h"
00055 #include "asterisk/file.h"
00056 #include "asterisk/cli.h"
00057 #include "asterisk/app.h"
00058 #include "asterisk/musiconhold.h"
00059 #include "asterisk/manager.h"
00060 #include "asterisk/devicestate.h"
00061 #include "asterisk/features.h"
00062
00063 static const char desc[] = "Local Proxy Channel";
00064 static const char type[] = "Local";
00065 static const char tdesc[] = "Local Proxy Channel Driver";
00066
00067 static int watchid;
00068
00069 static int usecnt =0;
00070 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
00071
00072 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
00073
00074
00075 AST_MUTEX_DEFINE_STATIC(locallock);
00076
00077 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause);
00078 static int local_digit(struct ast_channel *ast, char digit);
00079 static int local_call(struct ast_channel *ast, char *dest, int timeout);
00080 static int local_hangup(struct ast_channel *ast);
00081 static int local_answer(struct ast_channel *ast);
00082 static struct ast_frame *local_read(struct ast_channel *ast);
00083 static int local_write(struct ast_channel *ast, struct ast_frame *f);
00084 static int local_indicate(struct ast_channel *ast, int condition);
00085 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00086 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
00087 static int local_devicestate(void *data);
00088
00089
00090 static const struct ast_channel_tech local_tech = {
00091 .type = type,
00092 .description = tdesc,
00093 .capabilities = -1,
00094 .requester = local_request,
00095 .send_digit = local_digit,
00096 .call = local_call,
00097 .hangup = local_hangup,
00098 .answer = local_answer,
00099 .read = local_read,
00100 .write = local_write,
00101 .exception = local_read,
00102 .indicate = local_indicate,
00103 .fixup = local_fixup,
00104 .send_html = local_sendhtml,
00105 .devicestate = local_devicestate,
00106 };
00107
00108 static struct local_pvt {
00109 ast_mutex_t lock;
00110 char context[AST_MAX_CONTEXT];
00111 char exten[AST_MAX_EXTENSION];
00112 int reqformat;
00113 int glaredetect;
00114 int cancelqueue;
00115 int alreadymasqed;
00116 int launchedpbx;
00117 int nooptimization;
00118 struct ast_channel *owner;
00119 struct ast_channel *chan;
00120 struct local_pvt *next;
00121 } *locals = NULL;
00122
00123
00124 void local_watcher(char *exten, char *context) {
00125 if (option_debug > 1)
00126 ast_log(LOG_DEBUG, "Got notification of state change for %s@%s\n", exten, context);
00127 ast_device_state_changed("Local/%s@%s", exten, context);
00128 return;
00129 }
00130
00131
00132
00133 static int local_devicestate(void *data)
00134 {
00135 char *exten;
00136 char *context;
00137
00138 int res = AST_DEVICE_INVALID;
00139
00140 exten = ast_strdupa(data);
00141 if ((context = strchr(exten, '@'))) {
00142 *context = '\0';
00143 context = context + 1;
00144 }
00145 if (option_debug > 2)
00146 ast_log(LOG_DEBUG, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
00147 res = ast_exists_extension(NULL, context, exten, 1, NULL);
00148 if (!res)
00149 return AST_DEVICE_NOT_INUSE;
00150 else
00151 return AST_DEVICE_INUSE;
00152 }
00153
00154 static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f, struct ast_channel *us)
00155 {
00156 struct ast_channel *other;
00157 retrylock:
00158
00159 if (isoutbound) {
00160 other = p->owner;
00161 } else {
00162 other = p->chan;
00163 }
00164
00165 p->glaredetect = 1;
00166 if (p->cancelqueue) {
00167
00168
00169 ast_mutex_unlock(&p->lock);
00170 ast_mutex_destroy(&p->lock);
00171 free(p);
00172 return -1;
00173 }
00174 if (!other) {
00175 p->glaredetect = 0;
00176 return 0;
00177 }
00178 if (ast_mutex_trylock(&other->lock)) {
00179
00180 ast_mutex_unlock(&p->lock);
00181 if (us) {
00182 if (ast_mutex_unlock(&us->lock)) {
00183 ast_log(LOG_WARNING, "%s wasn't locked while sending %d/%d\n",
00184 us->name, f->frametype, f->subclass);
00185 us = NULL;
00186 }
00187 }
00188
00189 usleep(1);
00190
00191 if (us)
00192 ast_mutex_lock(&us->lock);
00193 ast_mutex_lock(&p->lock);
00194 goto retrylock;
00195 }
00196 ast_queue_frame(other, f);
00197 ast_mutex_unlock(&other->lock);
00198 p->glaredetect = 0;
00199 return 0;
00200 }
00201
00202 static int local_answer(struct ast_channel *ast)
00203 {
00204 struct local_pvt *p = ast->tech_pvt;
00205 int isoutbound;
00206 int res = -1;
00207
00208 ast_mutex_lock(&p->lock);
00209 isoutbound = IS_OUTBOUND(ast, p);
00210 if (isoutbound) {
00211
00212 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00213 res = local_queue_frame(p, isoutbound, &answer, ast);
00214 } else
00215 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n");
00216 ast_mutex_unlock(&p->lock);
00217 return res;
00218 }
00219
00220 static void check_bridge(struct local_pvt *p, int isoutbound)
00221 {
00222 if (p->alreadymasqed || p->nooptimization)
00223 return;
00224 if (!p->chan || !p->owner)
00225 return;
00226
00227
00228
00229
00230
00231
00232 if (isoutbound && p->chan->_bridge && !p->owner->readq) {
00233
00234
00235
00236
00237 if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) {
00238 if (!p->chan->_bridge->_softhangup) {
00239 if (!ast_mutex_trylock(&p->owner->lock)) {
00240 if (!p->owner->_softhangup) {
00241 ast_channel_masquerade(p->owner, p->chan->_bridge);
00242 p->alreadymasqed = 1;
00243 }
00244 ast_mutex_unlock(&p->owner->lock);
00245 }
00246 ast_mutex_unlock(&(p->chan->_bridge)->lock);
00247 }
00248 }
00249
00250
00251
00252
00253 #if 0
00254 } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && !p->chan->readq) {
00255
00256 if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) {
00257 if (!p->owner->_bridge->_softhangup) {
00258 if (!ast_mutex_trylock(&p->chan->lock)) {
00259 if (!p->chan->_softhangup) {
00260 ast_channel_masquerade(p->chan, p->owner->_bridge);
00261 p->alreadymasqed = 1;
00262 }
00263 ast_mutex_unlock(&p->chan->lock);
00264 }
00265 }
00266 ast_mutex_unlock(&(p->owner->_bridge)->lock);
00267 }
00268 #endif
00269 }
00270 }
00271
00272 static struct ast_frame *local_read(struct ast_channel *ast)
00273 {
00274 static struct ast_frame null = { AST_FRAME_NULL, };
00275
00276 return &null;
00277 }
00278
00279 static int local_write(struct ast_channel *ast, struct ast_frame *f)
00280 {
00281 struct local_pvt *p = ast->tech_pvt;
00282 int res = -1;
00283 int isoutbound;
00284
00285
00286 ast_mutex_lock(&p->lock);
00287 isoutbound = IS_OUTBOUND(ast, p);
00288 if (f && (f->frametype == AST_FRAME_VOICE))
00289 check_bridge(p, isoutbound);
00290 if (!p->alreadymasqed)
00291 res = local_queue_frame(p, isoutbound, f, ast);
00292 else {
00293 ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name);
00294 res = 0;
00295 }
00296 ast_mutex_unlock(&p->lock);
00297 return res;
00298 }
00299
00300 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00301 {
00302 struct local_pvt *p = newchan->tech_pvt;
00303 ast_mutex_lock(&p->lock);
00304
00305 if ((p->owner != oldchan) && (p->chan != oldchan)) {
00306 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00307 ast_mutex_unlock(&p->lock);
00308 return -1;
00309 }
00310 if (p->owner == oldchan)
00311 p->owner = newchan;
00312 else
00313 p->chan = newchan;
00314 ast_mutex_unlock(&p->lock);
00315 return 0;
00316 }
00317
00318 static int local_indicate(struct ast_channel *ast, int condition)
00319 {
00320 struct local_pvt *p = ast->tech_pvt;
00321 int res = -1;
00322 struct ast_frame f = { AST_FRAME_CONTROL, };
00323 int isoutbound;
00324
00325
00326 ast_mutex_lock(&p->lock);
00327 isoutbound = IS_OUTBOUND(ast, p);
00328 f.subclass = condition;
00329 res = local_queue_frame(p, isoutbound, &f, ast);
00330 ast_mutex_unlock(&p->lock);
00331 return res;
00332 }
00333
00334 static int local_digit(struct ast_channel *ast, char digit)
00335 {
00336 struct local_pvt *p = ast->tech_pvt;
00337 int res = -1;
00338 struct ast_frame f = { AST_FRAME_DTMF, };
00339 int isoutbound;
00340
00341 ast_mutex_lock(&p->lock);
00342 isoutbound = IS_OUTBOUND(ast, p);
00343 f.subclass = digit;
00344 res = local_queue_frame(p, isoutbound, &f, ast);
00345 ast_mutex_unlock(&p->lock);
00346 return res;
00347 }
00348
00349 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
00350 {
00351 struct local_pvt *p = ast->tech_pvt;
00352 int res = -1;
00353 struct ast_frame f = { AST_FRAME_HTML, };
00354 int isoutbound;
00355
00356 ast_mutex_lock(&p->lock);
00357 isoutbound = IS_OUTBOUND(ast, p);
00358 f.subclass = subclass;
00359 f.data = (char *)data;
00360 f.datalen = datalen;
00361 res = local_queue_frame(p, isoutbound, &f, ast);
00362 ast_mutex_unlock(&p->lock);
00363 return res;
00364 }
00365
00366
00367
00368 static int local_call(struct ast_channel *ast, char *dest, int timeout)
00369 {
00370 struct local_pvt *p = ast->tech_pvt;
00371 int res;
00372 struct ast_var_t *varptr = NULL, *new;
00373 size_t len, namelen;
00374
00375 ast_mutex_lock(&p->lock);
00376
00377 ast_set_callerid(p->chan,
00378 p->owner->cid.cid_num, p->owner->cid.cid_name,
00379 p->owner->cid.cid_ani);
00380
00381 if (p->owner->cid.cid_rdnis)
00382 p->chan->cid.cid_rdnis = strdup(p->owner->cid.cid_rdnis);
00383 else
00384 p->chan->cid.cid_rdnis = NULL;
00385
00386 p->chan->cid.cid_pres = p->owner->cid.cid_pres;
00387
00388 strncpy(p->chan->language, p->owner->language, sizeof(p->chan->language) - 1);
00389 strncpy(p->chan->accountcode, p->owner->accountcode, sizeof(p->chan->accountcode) - 1);
00390 p->chan->cdrflags = p->owner->cdrflags;
00391
00392
00393
00394 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
00395 namelen = strlen(varptr->name);
00396 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00397 new = malloc(len);
00398 if (new) {
00399 memcpy(new, varptr, len);
00400 new->value = &(new->name[0]) + namelen + 1;
00401 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
00402 } else {
00403 ast_log(LOG_ERROR, "Out of memory!\n");
00404 }
00405 }
00406
00407 p->launchedpbx = 1;
00408
00409
00410 res = ast_pbx_start(p->chan);
00411 ast_mutex_unlock(&p->lock);
00412 return res;
00413 }
00414
00415 #if 0
00416 static void local_destroy(struct local_pvt *p)
00417 {
00418 struct local_pvt *cur, *prev = NULL;
00419 ast_mutex_lock(&locallock);
00420 cur = locals;
00421 while(cur) {
00422 if (cur == p) {
00423 if (prev)
00424 prev->next = cur->next;
00425 else
00426 locals = cur->next;
00427 ast_mutex_destroy(cur);
00428 free(cur);
00429 break;
00430 }
00431 prev = cur;
00432 cur = cur->next;
00433 }
00434 ast_mutex_unlock(&locallock);
00435 if (!cur)
00436 ast_log(LOG_WARNING, "Unable ot find local '%s@%s' in local list\n", p->exten, p->context);
00437 }
00438 #endif
00439
00440
00441 static int local_hangup(struct ast_channel *ast)
00442 {
00443 struct local_pvt *p = ast->tech_pvt;
00444 int isoutbound;
00445 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP };
00446 struct local_pvt *cur, *prev=NULL;
00447 struct ast_channel *ochan = NULL;
00448 int glaredetect;
00449
00450 ast_mutex_lock(&p->lock);
00451 isoutbound = IS_OUTBOUND(ast, p);
00452 if (isoutbound) {
00453 p->chan = NULL;
00454 p->launchedpbx = 0;
00455 } else
00456 p->owner = NULL;
00457 ast->tech_pvt = NULL;
00458
00459 ast_mutex_lock(&usecnt_lock);
00460 usecnt--;
00461 ast_mutex_unlock(&usecnt_lock);
00462
00463 if (!p->owner && !p->chan) {
00464
00465 glaredetect = p->glaredetect;
00466
00467
00468 if (p->glaredetect)
00469 p->cancelqueue = 1;
00470 ast_mutex_unlock(&p->lock);
00471
00472 ast_mutex_lock(&locallock);
00473 cur = locals;
00474 while(cur) {
00475 if (cur == p) {
00476 if (prev)
00477 prev->next = cur->next;
00478 else
00479 locals = cur->next;
00480 break;
00481 }
00482 prev = cur;
00483 cur = cur->next;
00484 }
00485 ast_mutex_unlock(&locallock);
00486
00487 ast_mutex_lock(&p->lock);
00488 ast_mutex_unlock(&p->lock);
00489
00490 if (!glaredetect) {
00491 ast_mutex_destroy(&p->lock);
00492 free(p);
00493 }
00494 return 0;
00495 }
00496 if (p->chan && !p->launchedpbx)
00497
00498 ochan = p->chan;
00499 else
00500 local_queue_frame(p, isoutbound, &f, NULL);
00501 ast_mutex_unlock(&p->lock);
00502 if (ochan)
00503 ast_hangup(ochan);
00504 return 0;
00505 }
00506
00507
00508 static struct local_pvt *local_alloc(char *data, int format)
00509 {
00510 struct local_pvt *tmp;
00511 char *c;
00512 char *opts;
00513
00514 tmp = malloc(sizeof(struct local_pvt));
00515 if (tmp) {
00516 memset(tmp, 0, sizeof(struct local_pvt));
00517 ast_mutex_init(&tmp->lock);
00518 strncpy(tmp->exten, data, sizeof(tmp->exten) - 1);
00519 opts = strchr(tmp->exten, '/');
00520 if (opts) {
00521 *opts='\0';
00522 opts++;
00523 if (strchr(opts, 'n'))
00524 tmp->nooptimization = 1;
00525 }
00526 c = strchr(tmp->exten, '@');
00527 if (c) {
00528 *c = '\0';
00529 c++;
00530 strncpy(tmp->context, c, sizeof(tmp->context) - 1);
00531 } else
00532 strncpy(tmp->context, "default", sizeof(tmp->context) - 1);
00533 tmp->reqformat = format;
00534 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
00535 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
00536 ast_mutex_destroy(&tmp->lock);
00537 free(tmp);
00538 tmp = NULL;
00539 } else {
00540
00541 ast_mutex_lock(&locallock);
00542 tmp->next = locals;
00543 locals = tmp;
00544 ast_mutex_unlock(&locallock);
00545 }
00546
00547 }
00548 return tmp;
00549 }
00550
00551
00552 static struct ast_channel *local_new(struct local_pvt *p, int state)
00553 {
00554 struct ast_channel *tmp, *tmp2;
00555 int randnum = rand() & 0xffff, fmt = 0;
00556
00557 tmp = ast_channel_alloc(1);
00558 tmp2 = ast_channel_alloc(1);
00559 if (!tmp || !tmp2) {
00560 if (tmp)
00561 ast_channel_free(tmp);
00562 if (tmp2)
00563 ast_channel_free(tmp2);
00564 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
00565 return NULL;
00566 }
00567
00568 tmp2->tech = tmp->tech = &local_tech;
00569 tmp->nativeformats = p->reqformat;
00570 tmp2->nativeformats = p->reqformat;
00571 snprintf(tmp->name, sizeof(tmp->name), "Local/%s@%s-%04x,1", p->exten, p->context, randnum);
00572 snprintf(tmp2->name, sizeof(tmp2->name), "Local/%s@%s-%04x,2", p->exten, p->context, randnum);
00573 tmp->type = type;
00574 tmp2->type = type;
00575 ast_setstate(tmp, state);
00576 ast_setstate(tmp2, AST_STATE_RING);
00577 fmt = ast_best_codec(p->reqformat);
00578 tmp->writeformat = fmt;
00579 tmp2->writeformat = fmt;
00580 tmp->rawwriteformat = fmt;
00581 tmp2->rawwriteformat = fmt;
00582 tmp->readformat = fmt;
00583 tmp2->readformat = fmt;
00584 tmp->rawreadformat = fmt;
00585 tmp2->rawreadformat = fmt;
00586 tmp->tech_pvt = p;
00587 tmp2->tech_pvt = p;
00588 p->owner = tmp;
00589 p->chan = tmp2;
00590 ast_mutex_lock(&usecnt_lock);
00591 usecnt++;
00592 usecnt++;
00593 ast_mutex_unlock(&usecnt_lock);
00594 ast_update_use_count();
00595 ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
00596 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
00597 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
00598 tmp->priority = 1;
00599 tmp2->priority = 1;
00600
00601 return tmp;
00602 }
00603
00604
00605
00606 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
00607 {
00608 struct local_pvt *p;
00609 struct ast_channel *chan = NULL;
00610
00611 p = local_alloc(data, format);
00612 if (p)
00613 chan = local_new(p, AST_STATE_DOWN);
00614 return chan;
00615 }
00616
00617
00618 static int locals_show(int fd, int argc, char **argv)
00619 {
00620 struct local_pvt *p;
00621
00622 if (argc != 3)
00623 return RESULT_SHOWUSAGE;
00624 ast_mutex_lock(&locallock);
00625 p = locals;
00626 while(p) {
00627 ast_mutex_lock(&p->lock);
00628 ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
00629 ast_mutex_unlock(&p->lock);
00630 p = p->next;
00631 }
00632 if (!locals)
00633 ast_cli(fd, "No local channels in use\n");
00634 ast_mutex_unlock(&locallock);
00635 return RESULT_SUCCESS;
00636 }
00637
00638 static char show_locals_usage[] =
00639 "Usage: local show channels\n"
00640 " Provides summary information on active local proxy channels.\n";
00641
00642 static struct ast_cli_entry cli_show_locals = {
00643 { "local", "show", "channels", NULL }, locals_show,
00644 "Show status of local channels", show_locals_usage, NULL };
00645
00646
00647 int load_module()
00648 {
00649
00650 if (ast_channel_register(&local_tech)) {
00651 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
00652 return -1;
00653 }
00654 ast_cli_register(&cli_show_locals);
00655
00656
00657 ast_log(LOG_DEBUG, "Adding metermaid watcher...\n");
00658 watchid = ast_park_metermaid_add(&local_watcher, NULL);
00659 return 0;
00660 }
00661
00662
00663 int reload()
00664 {
00665 return 0;
00666 }
00667
00668
00669 int unload_module()
00670 {
00671 struct local_pvt *p;
00672
00673
00674 ast_cli_unregister(&cli_show_locals);
00675 ast_park_metermaid_remove(watchid);
00676 ast_channel_unregister(&local_tech);
00677 if (!ast_mutex_lock(&locallock)) {
00678
00679 p = locals;
00680 while(p) {
00681 if (p->owner)
00682 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
00683 p = p->next;
00684 }
00685 locals = NULL;
00686 ast_mutex_unlock(&locallock);
00687 } else {
00688 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
00689 return -1;
00690 }
00691 return 0;
00692 }
00693
00694 int usecount()
00695 {
00696 return usecnt;
00697 }
00698
00699 char *key()
00700 {
00701 return ASTERISK_GPL_KEY;
00702 }
00703
00704 char *description()
00705 {
00706 return (char *) desc;
00707 }
00708