Wed Aug 15 01:24:17 2007

Asterisk developer's documentation


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: 73319 $")
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    if (!res)
00218       ast_mutex_unlock(&p->lock);
00219    return res;
00220 }
00221 
00222 static void check_bridge(struct local_pvt *p, int isoutbound)
00223 {
00224    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)))
00225       return;
00226 
00227    /* only do the masquerade if we are being called on the outbound channel,
00228       if it has been bridged to another channel and if there are no pending
00229       frames on the owner channel (because they would be transferred to the
00230       outbound channel during the masquerade)
00231    */
00232    if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel!  Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) {
00233       /* Masquerade bridged channel into owner */
00234       /* Lock everything we need, one by one, and give up if
00235          we can't get everything.  Remember, we'll get another
00236          chance in just a little bit */
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                   ast_set_flag(p, LOCAL_ALREADY_MASQED);
00243                }
00244                ast_mutex_unlock(&p->owner->lock);
00245             }
00246             ast_mutex_unlock(&(p->chan->_bridge)->lock);
00247          }
00248       }
00249    /* We only allow masquerading in one 'direction'... it's important to preserve the state
00250       (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan)
00251       when the local channels go away.
00252    */
00253 #if 0
00254    } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) {
00255       /* Masquerade bridged channel into chan */
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                   ast_set_flag(p, LOCAL_ALREADY_MASQED);
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    return &ast_null_frame;
00275 }
00276 
00277 static int local_write(struct ast_channel *ast, struct ast_frame *f)
00278 {
00279    struct local_pvt *p = ast->tech_pvt;
00280    int res = -1;
00281    int isoutbound;
00282 
00283    if (!p)
00284       return -1;
00285 
00286    /* Just queue for delivery to the other side */
00287    ast_mutex_lock(&p->lock);
00288    isoutbound = IS_OUTBOUND(ast, p);
00289    if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
00290       check_bridge(p, isoutbound);
00291    if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
00292       res = local_queue_frame(p, isoutbound, f, ast);
00293    else {
00294       if (option_debug)
00295          ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name);
00296       res = 0;
00297    }
00298    if (!res)
00299       ast_mutex_unlock(&p->lock);
00300    return res;
00301 }
00302 
00303 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00304 {
00305    struct local_pvt *p = newchan->tech_pvt;
00306 
00307    if (!p)
00308       return -1;
00309 
00310    ast_mutex_lock(&p->lock);
00311 
00312    if ((p->owner != oldchan) && (p->chan != oldchan)) {
00313       ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00314       ast_mutex_unlock(&p->lock);
00315       return -1;
00316    }
00317    if (p->owner == oldchan)
00318       p->owner = newchan;
00319    else
00320       p->chan = newchan;
00321    ast_mutex_unlock(&p->lock);
00322    return 0;
00323 }
00324 
00325 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
00326 {
00327    struct local_pvt *p = ast->tech_pvt;
00328    int res = 0;
00329    struct ast_frame f = { AST_FRAME_CONTROL, };
00330    int isoutbound;
00331 
00332    if (!p)
00333       return -1;
00334 
00335    /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
00336    if (condition == AST_CONTROL_HOLD) {
00337       ast_moh_start(ast, data, NULL);
00338    } else if (condition == AST_CONTROL_UNHOLD) {
00339       ast_moh_stop(ast);
00340    } else {
00341       /* Queue up a frame representing the indication as a control frame */
00342       ast_mutex_lock(&p->lock);
00343       isoutbound = IS_OUTBOUND(ast, p);
00344       f.subclass = condition;
00345       f.data = (void*)data;
00346       f.datalen = datalen;
00347       if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
00348          ast_mutex_unlock(&p->lock);
00349    }
00350 
00351    return res;
00352 }
00353 
00354 static int local_digit_begin(struct ast_channel *ast, char digit)
00355 {
00356    struct local_pvt *p = ast->tech_pvt;
00357    int res = -1;
00358    struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00359    int isoutbound;
00360 
00361    if (!p)
00362       return -1;
00363 
00364    ast_mutex_lock(&p->lock);
00365    isoutbound = IS_OUTBOUND(ast, p);
00366    f.subclass = digit;
00367    if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
00368       ast_mutex_unlock(&p->lock);
00369 
00370    return res;
00371 }
00372 
00373 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
00374 {
00375    struct local_pvt *p = ast->tech_pvt;
00376    int res = -1;
00377    struct ast_frame f = { AST_FRAME_DTMF_END, };
00378    int isoutbound;
00379 
00380    if (!p)
00381       return -1;
00382 
00383    ast_mutex_lock(&p->lock);
00384    isoutbound = IS_OUTBOUND(ast, p);
00385    f.subclass = digit;
00386    f.len = duration;
00387    if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
00388       ast_mutex_unlock(&p->lock);
00389 
00390    return res;
00391 }
00392 
00393 static int local_sendtext(struct ast_channel *ast, const char *text)
00394 {
00395    struct local_pvt *p = ast->tech_pvt;
00396    int res = -1;
00397    struct ast_frame f = { AST_FRAME_TEXT, };
00398    int isoutbound;
00399 
00400    if (!p)
00401       return -1;
00402 
00403    ast_mutex_lock(&p->lock);
00404    isoutbound = IS_OUTBOUND(ast, p);
00405    f.data = (char *) text;
00406    f.datalen = strlen(text) + 1;
00407    if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
00408       ast_mutex_unlock(&p->lock);
00409    return res;
00410 }
00411 
00412 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
00413 {
00414    struct local_pvt *p = ast->tech_pvt;
00415    int res = -1;
00416    struct ast_frame f = { AST_FRAME_HTML, };
00417    int isoutbound;
00418 
00419    if (!p)
00420       return -1;
00421    
00422    ast_mutex_lock(&p->lock);
00423    isoutbound = IS_OUTBOUND(ast, p);
00424    f.subclass = subclass;
00425    f.data = (char *)data;
00426    f.datalen = datalen;
00427    if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
00428       ast_mutex_unlock(&p->lock);
00429    return res;
00430 }
00431 
00432 /*! \brief Initiate new call, part of PBX interface 
00433  *    dest is the dial string */
00434 static int local_call(struct ast_channel *ast, char *dest, int timeout)
00435 {
00436    struct local_pvt *p = ast->tech_pvt;
00437    int res;
00438    struct ast_var_t *varptr = NULL, *new;
00439    size_t len, namelen;
00440 
00441    if (!p)
00442       return -1;
00443    
00444    ast_mutex_lock(&p->lock);
00445 
00446    p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
00447    p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
00448    p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
00449    p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
00450    p->chan->cid.cid_pres = p->owner->cid.cid_pres;
00451    ast_string_field_set(p->chan, language, p->owner->language);
00452    ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
00453    p->chan->cdrflags = p->owner->cdrflags;
00454 
00455    /* copy the channel variables from the incoming channel to the outgoing channel */
00456    /* Note that due to certain assumptions, they MUST be in the same order */
00457    AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
00458       namelen = strlen(varptr->name);
00459       len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00460       if ((new = ast_calloc(1, len))) {
00461          memcpy(new, varptr, len);
00462          new->value = &(new->name[0]) + namelen + 1;
00463          AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
00464       }
00465    }
00466 
00467    /* Start switch on sub channel */
00468    if (!(res = ast_pbx_start(p->chan)))
00469       ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00470 
00471    ast_mutex_unlock(&p->lock);
00472    return res;
00473 }
00474 
00475 /*! \brief Hangup a call through the local proxy channel */
00476 static int local_hangup(struct ast_channel *ast)
00477 {
00478    struct local_pvt *p = ast->tech_pvt;
00479    int isoutbound;
00480    struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP };
00481    struct ast_channel *ochan = NULL;
00482    int glaredetect = 0, res = 0;
00483 
00484    if (!p)
00485       return -1;
00486 
00487    ast_mutex_lock(&p->lock);
00488    isoutbound = IS_OUTBOUND(ast, p);
00489    if (isoutbound) {
00490       const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00491       if ((status) && (p->owner))
00492          pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00493       p->chan = NULL;
00494       ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
00495       ast_module_user_remove(p->u_chan);
00496    } else {
00497       p->owner = NULL;
00498       ast_module_user_remove(p->u_owner);
00499    }
00500    
00501    ast->tech_pvt = NULL;
00502    
00503    if (!p->owner && !p->chan) {
00504       /* Okay, done with the private part now, too. */
00505       glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
00506       /* If we have a queue holding, don't actually destroy p yet, but
00507          let local_queue do it. */
00508       if (glaredetect)
00509          ast_set_flag(p, LOCAL_CANCEL_QUEUE);
00510       ast_mutex_unlock(&p->lock);
00511       /* Remove from list */
00512       AST_LIST_LOCK(&locals);
00513       AST_LIST_REMOVE(&locals, p, list);
00514       AST_LIST_UNLOCK(&locals);
00515       /* Grab / release lock just in case */
00516       ast_mutex_lock(&p->lock);
00517       ast_mutex_unlock(&p->lock);
00518       /* And destroy */
00519       if (!glaredetect) {
00520          ast_mutex_destroy(&p->lock);
00521          free(p);
00522       }
00523       return 0;
00524    }
00525    if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
00526       /* Need to actually hangup since there is no PBX */
00527       ochan = p->chan;
00528    else
00529       res = local_queue_frame(p, isoutbound, &f, NULL);
00530    if (!res)
00531       ast_mutex_unlock(&p->lock);
00532    if (ochan)
00533       ast_hangup(ochan);
00534    return 0;
00535 }
00536 
00537 /*! \brief Create a call structure */
00538 static struct local_pvt *local_alloc(const char *data, int format)
00539 {
00540    struct local_pvt *tmp = NULL;
00541    char *c = NULL, *opts = NULL;
00542 
00543    if (!(tmp = ast_calloc(1, sizeof(*tmp))))
00544       return NULL;
00545 
00546    /* Initialize private structure information */
00547    ast_mutex_init(&tmp->lock);
00548    ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
00549 
00550    /* Look for options */
00551    if ((opts = strchr(tmp->exten, '/'))) {
00552       *opts++ = '\0';
00553       if (strchr(opts, 'n'))
00554          ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
00555    }
00556 
00557    /* Look for a context */
00558    if ((c = strchr(tmp->exten, '@')))
00559       *c++ = '\0';
00560 
00561    ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
00562 
00563    tmp->reqformat = format;
00564 
00565    if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
00566       ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
00567       ast_mutex_destroy(&tmp->lock);
00568       free(tmp);
00569       tmp = NULL;
00570    } else {
00571       /* Add to list */
00572       AST_LIST_LOCK(&locals);
00573       AST_LIST_INSERT_HEAD(&locals, tmp, list);
00574       AST_LIST_UNLOCK(&locals);
00575    }
00576    
00577    return tmp;
00578 }
00579 
00580 /*! \brief Start new local channel */
00581 static struct ast_channel *local_new(struct local_pvt *p, int state)
00582 {
00583    struct ast_channel *tmp = NULL, *tmp2 = NULL;
00584    int randnum = ast_random() & 0xffff, fmt = 0;
00585    const char *t;
00586    int ama;
00587 
00588    /* Allocate two new Asterisk channels */
00589    /* safe accountcode */
00590    if (p->owner && p->owner->accountcode)
00591       t = p->owner->accountcode;
00592    else
00593       t = "";
00594 
00595    if (p->owner)
00596       ama = p->owner->amaflags;
00597    else
00598       ama = 0;
00599    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)) 
00600          || !(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))) {
00601       if (tmp)
00602          ast_channel_free(tmp);
00603       if (tmp2)
00604          ast_channel_free(tmp2);
00605       ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
00606       return NULL;
00607    } 
00608 
00609    tmp2->tech = tmp->tech = &local_tech;
00610 
00611    tmp->nativeformats = p->reqformat;
00612    tmp2->nativeformats = p->reqformat;
00613 
00614    /* Determine our read/write format and set it on each channel */
00615    fmt = ast_best_codec(p->reqformat);
00616    tmp->writeformat = fmt;
00617    tmp2->writeformat = fmt;
00618    tmp->rawwriteformat = fmt;
00619    tmp2->rawwriteformat = fmt;
00620    tmp->readformat = fmt;
00621    tmp2->readformat = fmt;
00622    tmp->rawreadformat = fmt;
00623    tmp2->rawreadformat = fmt;
00624 
00625    tmp->tech_pvt = p;
00626    tmp2->tech_pvt = p;
00627 
00628    p->owner = tmp;
00629    p->chan = tmp2;
00630    p->u_owner = ast_module_user_add(p->owner);
00631    p->u_chan = ast_module_user_add(p->chan);
00632 
00633    ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
00634    ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
00635    ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
00636    tmp->priority = 1;
00637    tmp2->priority = 1;
00638 
00639    return tmp;
00640 }
00641 
00642 
00643 /*! \brief Part of PBX interface */
00644 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
00645 {
00646    struct local_pvt *p = NULL;
00647    struct ast_channel *chan = NULL;
00648 
00649    /* Allocate a new private structure and then Asterisk channel */
00650    if ((p = local_alloc(data, format)))
00651       chan = local_new(p, AST_STATE_DOWN);
00652 
00653    return chan;
00654 }
00655 
00656 /*! \brief CLI command "local show channels" */
00657 static int locals_show(int fd, int argc, char **argv)
00658 {
00659    struct local_pvt *p = NULL;
00660 
00661    if (argc != 3)
00662       return RESULT_SHOWUSAGE;
00663 
00664    AST_LIST_LOCK(&locals);
00665    if (!AST_LIST_EMPTY(&locals)) {
00666       AST_LIST_TRAVERSE(&locals, p, list) {
00667          ast_mutex_lock(&p->lock);
00668          ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
00669          ast_mutex_unlock(&p->lock);
00670       }
00671    } else
00672       ast_cli(fd, "No local channels in use\n");
00673    AST_LIST_UNLOCK(&locals);
00674 
00675    return RESULT_SUCCESS;
00676 }
00677 
00678 static char show_locals_usage[] = 
00679 "Usage: local show channels\n"
00680 "       Provides summary information on active local proxy channels.\n";
00681 
00682 static struct ast_cli_entry cli_local[] = {
00683    { { "local", "show", "channels", NULL },
00684    locals_show, "List status of local channels",
00685    show_locals_usage },
00686 };
00687 
00688 /*! \brief Load module into PBX, register channel */
00689 static int load_module(void)
00690 {
00691    /* Make sure we can register our channel type */
00692    if (ast_channel_register(&local_tech)) {
00693       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
00694       return -1;
00695    }
00696    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00697    return 0;
00698 }
00699 
00700 /*! \brief Unload the local proxy channel from Asterisk */
00701 static int unload_module(void)
00702 {
00703    struct local_pvt *p = NULL;
00704 
00705    /* First, take us out of the channel loop */
00706    ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00707    ast_channel_unregister(&local_tech);
00708    if (!AST_LIST_LOCK(&locals)) {
00709       /* Hangup all interfaces if they have an owner */
00710       AST_LIST_TRAVERSE(&locals, p, list) {
00711          if (p->owner)
00712             ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
00713       }
00714       AST_LIST_UNLOCK(&locals);
00715       AST_LIST_HEAD_DESTROY(&locals);
00716    } else {
00717       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
00718       return -1;
00719    }     
00720    return 0;
00721 }
00722 
00723 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Local Proxy Channel");

Generated on Wed Aug 15 01:24:17 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.3