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