![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
chan_local.c
Go to the documentation of this file.
00001 /* 00002 * Asterisk -- An open source telephony toolkit. 00003 * 00004 * Copyright (C) 1999 - 2005, Digium, Inc. 00005 * 00006 * Mark Spencer <markster@digium.com> 00007 * 00008 * See http://www.asterisk.org for more information about 00009 * the Asterisk project. Please do not directly contact 00010 * any of the maintainers of this project for assistance; 00011 * the project provides a web site, mailing lists and IRC 00012 * channels for your use. 00013 * 00014 * This program is free software, distributed under the terms of 00015 * the GNU General Public License Version 2. See the LICENSE file 00016 * at the top of the source tree. 00017 */ 00018 00019 /*! \file 00020 * 00021 * \author Mark Spencer <markster@digium.com> 00022 * 00023 * \brief Local Proxy Channel 00024 * 00025 * \ingroup channel_drivers 00026 */ 00027 00028 #include "asterisk.h" 00029 00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 51385 $") 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 /* PBX interface structure for channel registration */ 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; /* Channel private lock */ 00107 unsigned int flags; /* Private flags */ 00108 char context[AST_MAX_CONTEXT]; /* Context to call */ 00109 char exten[AST_MAX_EXTENSION]; /* Extension to call */ 00110 int reqformat; /* Requested format */ 00111 struct ast_channel *owner; /* Master Channel */ 00112 struct ast_channel *chan; /* Outbound channel */ 00113 struct ast_module_user *u_owner; /*! reference to keep the module loaded while in use */ 00114 struct ast_module_user *u_chan; /*! reference to keep the module loaded while in use */ 00115 AST_LIST_ENTRY(local_pvt) list; /* Next entity */ 00116 }; 00117 00118 #define LOCAL_GLARE_DETECT (1 << 0) /*!< Detect glare on hangup */ 00119 #define LOCAL_CANCEL_QUEUE (1 << 1) /*!< Cancel queue */ 00120 #define LOCAL_ALREADY_MASQED (1 << 2) /*!< Already masqueraded */ 00121 #define LOCAL_LAUNCHED_PBX (1 << 3) /*!< PBX was launched */ 00122 #define LOCAL_NO_OPTIMIZATION (1 << 4) /*!< Do not optimize using masquerading */ 00123 00124 static AST_LIST_HEAD_STATIC(locals, local_pvt); 00125 00126 /*! \brief Adds devicestate to local channels */ 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 /* Strip options if they exist */ 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 static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f, struct ast_channel *us) 00154 { 00155 struct ast_channel *other = NULL; 00156 00157 retrylock: 00158 00159 /* Recalculate outbound channel */ 00160 other = isoutbound ? p->owner : p->chan; 00161 00162 /* Set glare detection */ 00163 ast_set_flag(p, LOCAL_GLARE_DETECT); 00164 if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) { 00165 /* We had a glare on the hangup. Forget all this business, 00166 return and destroy p. */ 00167 ast_mutex_unlock(&p->lock); 00168 ast_mutex_destroy(&p->lock); 00169 free(p); 00170 return -1; 00171 } 00172 if (!other) { 00173 ast_clear_flag(p, LOCAL_GLARE_DETECT); 00174 return 0; 00175 } 00176 if (ast_mutex_trylock(&other->lock)) { 00177 /* Failed to lock. Release main lock and try again */ 00178 ast_mutex_unlock(&p->lock); 00179 if (us) { 00180 if (ast_mutex_unlock(&us->lock)) { 00181 ast_log(LOG_WARNING, "%s wasn't locked while sending %d/%d\n", 00182 us->name, f->frametype, f->subclass); 00183 us = NULL; 00184 } 00185 } 00186 /* Wait just a bit */ 00187 usleep(1); 00188 /* Only we can destroy ourselves, so we can't disappear here */ 00189 if (us) 00190 ast_mutex_lock(&us->lock); 00191 ast_mutex_lock(&p->lock); 00192 goto retrylock; 00193 } 00194 ast_queue_frame(other, f); 00195 ast_mutex_unlock(&other->lock); 00196 ast_clear_flag(p, LOCAL_GLARE_DETECT); 00197 return 0; 00198 } 00199 00200 static int local_answer(struct ast_channel *ast) 00201 { 00202 struct local_pvt *p = ast->tech_pvt; 00203 int isoutbound; 00204 int res = -1; 00205 00206 if (!p) 00207 return -1; 00208 00209 ast_mutex_lock(&p->lock); 00210 isoutbound = IS_OUTBOUND(ast, p); 00211 if (isoutbound) { 00212 /* Pass along answer since somebody answered us */ 00213 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00214 res = local_queue_frame(p, isoutbound, &answer, ast); 00215 } else 00216 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n"); 00217 ast_mutex_unlock(&p->lock); 00218 return res; 00219 } 00220 00221 static void check_bridge(struct local_pvt *p, int isoutbound) 00222 { 00223 if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || ast_test_flag(p, LOCAL_NO_OPTIMIZATION) || !p->chan || !p->owner) 00224 return; 00225 00226 /* only do the masquerade if we are being called on the outbound channel, 00227 if it has been bridged to another channel and if there are no pending 00228 frames on the owner channel (because they would be transferred to the 00229 outbound channel during the masquerade) 00230 */ 00231 if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) { 00232 /* Masquerade bridged channel into owner */ 00233 /* Lock everything we need, one by one, and give up if 00234 we can't get everything. Remember, we'll get another 00235 chance in just a little bit */ 00236 if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) { 00237 if (!p->chan->_bridge->_softhangup) { 00238 if (!ast_mutex_trylock(&p->owner->lock)) { 00239 if (!p->owner->_softhangup) { 00240 ast_channel_masquerade(p->owner, p->chan->_bridge); 00241 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00242 } 00243 ast_mutex_unlock(&p->owner->lock); 00244 } 00245 ast_mutex_unlock(&(p->chan->_bridge)->lock); 00246 } 00247 } 00248 /* We only allow masquerading in one 'direction'... it's important to preserve the state 00249 (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan) 00250 when the local channels go away. 00251 */ 00252 #if 0 00253 } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) { 00254 /* Masquerade bridged channel into chan */ 00255 if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) { 00256 if (!p->owner->_bridge->_softhangup) { 00257 if (!ast_mutex_trylock(&p->chan->lock)) { 00258 if (!p->chan->_softhangup) { 00259 ast_channel_masquerade(p->chan, p->owner->_bridge); 00260 ast_set_flag(p, LOCAL_ALREADY_MASQED); 00261 } 00262 ast_mutex_unlock(&p->chan->lock); 00263 } 00264 } 00265 ast_mutex_unlock(&(p->owner->_bridge)->lock); 00266 } 00267 #endif 00268 } 00269 } 00270 00271 static struct ast_frame *local_read(struct ast_channel *ast) 00272 { 00273 return &ast_null_frame; 00274 } 00275 00276 static int local_write(struct ast_channel *ast, struct ast_frame *f) 00277 { 00278 struct local_pvt *p = ast->tech_pvt; 00279 int res = -1; 00280 int isoutbound; 00281 00282 if (!p) 00283 return -1; 00284 00285 /* Just queue for delivery to the other side */ 00286 ast_mutex_lock(&p->lock); 00287 isoutbound = IS_OUTBOUND(ast, p); 00288 if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) 00289 check_bridge(p, isoutbound); 00290 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED)) 00291 res = local_queue_frame(p, isoutbound, f, ast); 00292 else { 00293 if (option_debug) 00294 ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name); 00295 res = 0; 00296 } 00297 ast_mutex_unlock(&p->lock); 00298 return res; 00299 } 00300 00301 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) 00302 { 00303 struct local_pvt *p = newchan->tech_pvt; 00304 00305 if (!p) 00306 return -1; 00307 00308 ast_mutex_lock(&p->lock); 00309 00310 if ((p->owner != oldchan) && (p->chan != oldchan)) { 00311 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan); 00312 ast_mutex_unlock(&p->lock); 00313 return -1; 00314 } 00315 if (p->owner == oldchan) 00316 p->owner = newchan; 00317 else 00318 p->chan = newchan; 00319 ast_mutex_unlock(&p->lock); 00320 return 0; 00321 } 00322 00323 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen) 00324 { 00325 struct local_pvt *p = ast->tech_pvt; 00326 int res = 0; 00327 struct ast_frame f = { AST_FRAME_CONTROL, }; 00328 int isoutbound; 00329 00330 if (!p) 00331 return -1; 00332 00333 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */ 00334 if (condition == AST_CONTROL_HOLD) { 00335 ast_moh_start(ast, data, NULL); 00336 } else if (condition == AST_CONTROL_UNHOLD) { 00337 ast_moh_stop(ast); 00338 } else { 00339 /* Queue up a frame representing the indication as a control frame */ 00340 ast_mutex_lock(&p->lock); 00341 isoutbound = IS_OUTBOUND(ast, p); 00342 f.subclass = condition; 00343 f.data = (void*)data; 00344 f.datalen = datalen; 00345 res = local_queue_frame(p, isoutbound, &f, ast); 00346 ast_mutex_unlock(&p->lock); 00347 } 00348 00349 return res; 00350 } 00351 00352 static int local_digit_begin(struct ast_channel *ast, char digit) 00353 { 00354 struct local_pvt *p = ast->tech_pvt; 00355 int res = -1; 00356 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, }; 00357 int isoutbound; 00358 00359 if (!p) 00360 return -1; 00361 00362 ast_mutex_lock(&p->lock); 00363 isoutbound = IS_OUTBOUND(ast, p); 00364 f.subclass = digit; 00365 res = local_queue_frame(p, isoutbound, &f, ast); 00366 ast_mutex_unlock(&p->lock); 00367 00368 return res; 00369 } 00370 00371 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration) 00372 { 00373 struct local_pvt *p = ast->tech_pvt; 00374 int res = -1; 00375 struct ast_frame f = { AST_FRAME_DTMF_END, }; 00376 int isoutbound; 00377 00378 if (!p) 00379 return -1; 00380 00381 ast_mutex_lock(&p->lock); 00382 isoutbound = IS_OUTBOUND(ast, p); 00383 f.subclass = digit; 00384 f.len = duration; 00385 res = local_queue_frame(p, isoutbound, &f, ast); 00386 ast_mutex_unlock(&p->lock); 00387 00388 return res; 00389 } 00390 00391 static int local_sendtext(struct ast_channel *ast, const char *text) 00392 { 00393 struct local_pvt *p = ast->tech_pvt; 00394 int res = -1; 00395 struct ast_frame f = { AST_FRAME_TEXT, }; 00396 int isoutbound; 00397 00398 if (!p) 00399 return -1; 00400 00401 ast_mutex_lock(&p->lock); 00402 isoutbound = IS_OUTBOUND(ast, p); 00403 f.data = (char *) text; 00404 f.datalen = strlen(text) + 1; 00405 res = local_queue_frame(p, isoutbound, &f, ast); 00406 ast_mutex_unlock(&p->lock); 00407 return res; 00408 } 00409 00410 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen) 00411 { 00412 struct local_pvt *p = ast->tech_pvt; 00413 int res = -1; 00414 struct ast_frame f = { AST_FRAME_HTML, }; 00415 int isoutbound; 00416 00417 if (!p) 00418 return -1; 00419 00420 ast_mutex_lock(&p->lock); 00421 isoutbound = IS_OUTBOUND(ast, p); 00422 f.subclass = subclass; 00423 f.data = (char *)data; 00424 f.datalen = datalen; 00425 res = local_queue_frame(p, isoutbound, &f, ast); 00426 ast_mutex_unlock(&p->lock); 00427 return res; 00428 } 00429 00430 /*! \brief Initiate new call, part of PBX interface 00431 * dest is the dial string */ 00432 static int local_call(struct ast_channel *ast, char *dest, int timeout) 00433 { 00434 struct local_pvt *p = ast->tech_pvt; 00435 int res; 00436 struct ast_var_t *varptr = NULL, *new; 00437 size_t len, namelen; 00438 00439 if (!p) 00440 return -1; 00441 00442 ast_mutex_lock(&p->lock); 00443 00444 p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num); 00445 p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name); 00446 p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis); 00447 p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani); 00448 p->chan->cid.cid_pres = p->owner->cid.cid_pres; 00449 ast_string_field_set(p->chan, language, p->owner->language); 00450 ast_string_field_set(p->chan, accountcode, p->owner->accountcode); 00451 p->chan->cdrflags = p->owner->cdrflags; 00452 00453 /* copy the channel variables from the incoming channel to the outgoing channel */ 00454 /* Note that due to certain assumptions, they MUST be in the same order */ 00455 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) { 00456 namelen = strlen(varptr->name); 00457 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; 00458 if ((new = ast_calloc(1, len))) { 00459 memcpy(new, varptr, len); 00460 new->value = &(new->name[0]) + namelen + 1; 00461 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries); 00462 } 00463 } 00464 00465 ast_set_flag(p, LOCAL_LAUNCHED_PBX); 00466 00467 /* Start switch on sub channel */ 00468 res = ast_pbx_start(p->chan); 00469 ast_mutex_unlock(&p->lock); 00470 return res; 00471 } 00472 00473 /*! \brief Hangup a call through the local proxy channel */ 00474 static int local_hangup(struct ast_channel *ast) 00475 { 00476 struct local_pvt *p = ast->tech_pvt; 00477 int isoutbound; 00478 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP }; 00479 struct ast_channel *ochan = NULL; 00480 int glaredetect = 0; 00481 00482 if (!p) 00483 return -1; 00484 00485 ast_mutex_lock(&p->lock); 00486 isoutbound = IS_OUTBOUND(ast, p); 00487 if (isoutbound) { 00488 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); 00489 if ((status) && (p->owner)) 00490 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); 00491 p->chan = NULL; 00492 ast_clear_flag(p, LOCAL_LAUNCHED_PBX); 00493 ast_module_user_remove(p->u_chan); 00494 } else { 00495 p->owner = NULL; 00496 ast_module_user_remove(p->u_owner); 00497 } 00498 00499 ast->tech_pvt = NULL; 00500 00501 if (!p->owner && !p->chan) { 00502 /* Okay, done with the private part now, too. */ 00503 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT); 00504 /* If we have a queue holding, don't actually destroy p yet, but 00505 let local_queue do it. */ 00506 if (glaredetect) 00507 ast_set_flag(p, LOCAL_CANCEL_QUEUE); 00508 ast_mutex_unlock(&p->lock); 00509 /* Remove from list */ 00510 AST_LIST_LOCK(&locals); 00511 AST_LIST_REMOVE(&locals, p, list); 00512 AST_LIST_UNLOCK(&locals); 00513 /* Grab / release lock just in case */ 00514 ast_mutex_lock(&p->lock); 00515 ast_mutex_unlock(&p->lock); 00516 /* And destroy */ 00517 if (!glaredetect) { 00518 ast_mutex_destroy(&p->lock); 00519 free(p); 00520 } 00521 return 0; 00522 } 00523 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) 00524 /* Need to actually hangup since there is no PBX */ 00525 ochan = p->chan; 00526 else 00527 local_queue_frame(p, isoutbound, &f, NULL); 00528 ast_mutex_unlock(&p->lock); 00529 if (ochan) 00530 ast_hangup(ochan); 00531 return 0; 00532 } 00533 00534 /*! \brief Create a call structure */ 00535 static struct local_pvt *local_alloc(const char *data, int format) 00536 { 00537 struct local_pvt *tmp = NULL; 00538 char *c = NULL, *opts = NULL; 00539 00540 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) 00541 return NULL; 00542 00543 /* Initialize private structure information */ 00544 ast_mutex_init(&tmp->lock); 00545 ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); 00546 00547 /* Look for options */ 00548 if ((opts = strchr(tmp->exten, '/'))) { 00549 *opts++ = '\0'; 00550 if (strchr(opts, 'n')) 00551 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); 00552 } 00553 00554 /* Look for a context */ 00555 if ((c = strchr(tmp->exten, '@'))) 00556 *c++ = '\0'; 00557 00558 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context)); 00559 00560 tmp->reqformat = format; 00561 00562 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { 00563 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); 00564 ast_mutex_destroy(&tmp->lock); 00565 free(tmp); 00566 tmp = NULL; 00567 } else { 00568 /* Add to list */ 00569 AST_LIST_LOCK(&locals); 00570 AST_LIST_INSERT_HEAD(&locals, tmp, list); 00571 AST_LIST_UNLOCK(&locals); 00572 } 00573 00574 return tmp; 00575 } 00576 00577 /*! \brief Start new local channel */ 00578 static struct ast_channel *local_new(struct local_pvt *p, int state) 00579 { 00580 struct ast_channel *tmp = NULL, *tmp2 = NULL; 00581 int randnum = ast_random() & 0xffff, fmt = 0; 00582 00583 /* Allocate two new Asterisk channels */ 00584 if (!(tmp = ast_channel_alloc(1, state, 0, 0, "Local/%s@%s-%04x,1", p->exten, p->context, randnum)) 00585 || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, "Local/%s@%s-%04x,2", p->exten, p->context, randnum))) { 00586 if (tmp) 00587 ast_channel_free(tmp); 00588 if (tmp2) 00589 ast_channel_free(tmp2); 00590 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); 00591 return NULL; 00592 } 00593 00594 tmp2->tech = tmp->tech = &local_tech; 00595 00596 tmp->nativeformats = p->reqformat; 00597 tmp2->nativeformats = p->reqformat; 00598 00599 /* Determine our read/write format and set it on each channel */ 00600 fmt = ast_best_codec(p->reqformat); 00601 tmp->writeformat = fmt; 00602 tmp2->writeformat = fmt; 00603 tmp->rawwriteformat = fmt; 00604 tmp2->rawwriteformat = fmt; 00605 tmp->readformat = fmt; 00606 tmp2->readformat = fmt; 00607 tmp->rawreadformat = fmt; 00608 tmp2->rawreadformat = fmt; 00609 00610 tmp->tech_pvt = p; 00611 tmp2->tech_pvt = p; 00612 00613 p->owner = tmp; 00614 p->chan = tmp2; 00615 p->u_owner = ast_module_user_add(p->owner); 00616 p->u_chan = ast_module_user_add(p->chan); 00617 00618 ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); 00619 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); 00620 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); 00621 tmp->priority = 1; 00622 tmp2->priority = 1; 00623 00624 return tmp; 00625 } 00626 00627 00628 /*! \brief Part of PBX interface */ 00629 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause) 00630 { 00631 struct local_pvt *p = NULL; 00632 struct ast_channel *chan = NULL; 00633 00634 /* Allocate a new private structure and then Asterisk channel */ 00635 if ((p = local_alloc(data, format))) 00636 chan = local_new(p, AST_STATE_DOWN); 00637 00638 return chan; 00639 } 00640 00641 /*! \brief CLI command "local show channels" */ 00642 static int locals_show(int fd, int argc, char **argv) 00643 { 00644 struct local_pvt *p = NULL; 00645 00646 if (argc != 3) 00647 return RESULT_SHOWUSAGE; 00648 00649 AST_LIST_LOCK(&locals); 00650 if (!AST_LIST_EMPTY(&locals)) { 00651 AST_LIST_TRAVERSE(&locals, p, list) { 00652 ast_mutex_lock(&p->lock); 00653 ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context); 00654 ast_mutex_unlock(&p->lock); 00655 } 00656 } else 00657 ast_cli(fd, "No local channels in use\n"); 00658 AST_LIST_UNLOCK(&locals); 00659 00660 return RESULT_SUCCESS; 00661 } 00662 00663 static const char show_locals_usage[] = 00664 "Usage: local show channels\n" 00665 " Provides summary information on active local proxy channels.\n"; 00666 00667 static struct ast_cli_entry cli_local[] = { 00668 { { "local", "show", "channels", NULL }, 00669 locals_show, "List status of local channels", 00670 show_locals_usage }, 00671 }; 00672 00673 /*! \brief Load module into PBX, register channel */ 00674 static int load_module(void) 00675 { 00676 /* Make sure we can register our channel type */ 00677 if (ast_channel_register(&local_tech)) { 00678 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); 00679 return -1; 00680 } 00681 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00682 return 0; 00683 } 00684 00685 /*! \brief Unload the local proxy channel from Asterisk */ 00686 static int unload_module(void) 00687 { 00688 struct local_pvt *p = NULL; 00689 00690 /* First, take us out of the channel loop */ 00691 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); 00692 ast_channel_unregister(&local_tech); 00693 if (!AST_LIST_LOCK(&locals)) { 00694 /* Hangup all interfaces if they have an owner */ 00695 AST_LIST_TRAVERSE(&locals, p, list) { 00696 if (p->owner) 00697 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 00698 } 00699 AST_LIST_UNLOCK(&locals); 00700 AST_LIST_HEAD_DESTROY(&locals); 00701 } else { 00702 ast_log(LOG_WARNING, "Unable to lock the monitor\n"); 00703 return -1; 00704 } 00705 return 0; 00706 } 00707 00708 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Local Proxy Channel");