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