Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:50 2009

## 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  * \brief Local Proxy Channel
    00022  *
    00023  * \ingroup channel_drivers
    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: 73318 $")
    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 /* Protect the interface list (of sip_pvt's) */
    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 /* PBX interface structure for channel registration */
    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;       /* Channel private lock */
    00104    char context[AST_MAX_CONTEXT];      /* Context to call */
    00105    char exten[AST_MAX_EXTENSION];      /* Extension to call */
    00106    int reqformat;          /* Requested format */
    00107    int glaredetect;        /* Detect glare on hangup */
    00108    int cancelqueue;        /* Cancel queue */
    00109    int alreadymasqed;         /* Already masqueraded */
    00110    int launchedpbx;        /* Did we launch the PBX */
    00111    int nooptimization;        /* Don't leave masq state */
    00112    struct ast_channel *owner;    /* Master Channel */
    00113    struct ast_channel *chan;     /* Outbound channel */
    00114    struct local_pvt *next;       /* Next entity */
    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    /* Recalculate outbound channel */
    00122    if (isoutbound) {
    00123       other = p->owner;
    00124    } else {
    00125       other = p->chan;
    00126    }
    00127    /* Set glare detection */
    00128    p->glaredetect = 1;
    00129    if (p->cancelqueue) {
    00130       /* We had a glare on the hangup.  Forget all this business,
    00131       return and destroy p.  */
    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       /* Failed to lock.  Release main lock and try again */
    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       /* Wait just a bit */
    00152       usleep(1);
    00153       /* Only we can destroy ourselves, so we can't disappear here */
    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    if (!p)
    00172       return -1;
    00173
    00174    ast_mutex_lock(&p->lock);
    00175    isoutbound = IS_OUTBOUND(ast, p);
    00176    if (isoutbound) {
    00177       /* Pass along answer since somebody answered us */
    00178       struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
    00179       res = local_queue_frame(p, isoutbound, &answer, ast);
    00180    } else
    00181       ast_log(LOG_WARNING, "Huh?  Local is being asked to answer?\n");
    00182    if (!res)
    00183       ast_mutex_unlock(&p->lock);
    00184    return res;
    00185 }
    00186
    00187 static void check_bridge(struct local_pvt *p, int isoutbound)
    00188 {
    00189    if (p->alreadymasqed || p->nooptimization)
    00190       return;
    00191    if (!p->chan || !p->owner || (p->chan->_bridge != ast_bridged_channel(p->chan)))
    00192       return;
    00193
    00194    /* only do the masquerade if we are being called on the outbound channel,
    00195       if it has been bridged to another channel and if there are no pending
    00196       frames on the owner channel (because they would be transferred to the
    00197       outbound channel during the masquerade)
    00198    */
    00199    if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel!  Only go one step! */ && !p->owner->readq) {
    00200       /* Masquerade bridged channel into owner */
    00201       /* Lock everything we need, one by one, and give up if
    00202          we can't get everything.  Remember, we'll get another
    00203          chance in just a little bit */
    00204       if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) {
    00205          if (!p->chan->_bridge->_softhangup) {
    00206             if (!ast_mutex_trylock(&p->owner->lock)) {
    00207                if (!p->owner->_softhangup) {
    00208                   ast_channel_masquerade(p->owner, p->chan->_bridge);
    00209                   p->alreadymasqed = 1;
    00210                }
    00211                ast_mutex_unlock(&p->owner->lock);
    00212             }
    00213             ast_mutex_unlock(&(p->chan->_bridge)->lock);
    00214          }
    00215       }
    00216    /* We only allow masquerading in one 'direction'... it's important to preserve the state
    00217       (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan)
    00218       when the local channels go away.
    00219    */
    00220 #if 0
    00221    } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && !p->chan->readq) {
    00222       /* Masquerade bridged channel into chan */
    00223       if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) {
    00224          if (!p->owner->_bridge->_softhangup) {
    00225             if (!ast_mutex_trylock(&p->chan->lock)) {
    00226                if (!p->chan->_softhangup) {
    00227                   ast_channel_masquerade(p->chan, p->owner->_bridge);
    00228                   p->alreadymasqed = 1;
    00229                }
    00230                ast_mutex_unlock(&p->chan->lock);
    00231             }
    00232          }
    00233          ast_mutex_unlock(&(p->owner->_bridge)->lock);
    00234       }
    00235 #endif
    00236    }
    00237 }
    00238
    00239 static struct ast_frame  *local_read(struct ast_channel *ast)
    00240 {
    00241    static struct ast_frame null = { AST_FRAME_NULL, };
    00242
    00243    return &null;
    00244 }
    00245
    00246 static int local_write(struct ast_channel *ast, struct ast_frame *f)
    00247 {
    00248    struct local_pvt *p = ast->tech_pvt;
    00249    int res = -1;
    00250    int isoutbound;
    00251
    00252    if (!p)
    00253       return -1;
    00254
    00255    /* Just queue for delivery to the other side */
    00256    ast_mutex_lock(&p->lock);
    00257    isoutbound = IS_OUTBOUND(ast, p);
    00258    if (f && (f->frametype == AST_FRAME_VOICE))
    00259       check_bridge(p, isoutbound);
    00260    if (!p->alreadymasqed)
    00261       res = local_queue_frame(p, isoutbound, f, ast);
    00262    else {
    00263       ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name);
    00264       res = 0;
    00265    }
    00266    if (!res)
    00267       ast_mutex_unlock(&p->lock);
    00268    return res;
    00269 }
    00270
    00271 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
    00272 {
    00273    struct local_pvt *p = newchan->tech_pvt;
    00274
    00275    if (!p)
    00276       return -1;
    00277
    00278    ast_mutex_lock(&p->lock);
    00279
    00280    if ((p->owner != oldchan) && (p->chan != oldchan)) {
    00281       ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
    00282       ast_mutex_unlock(&p->lock);
    00283       return -1;
    00284    }
    00285    if (p->owner == oldchan)
    00286       p->owner = newchan;
    00287    else
    00288       p->chan = newchan;
    00289    ast_mutex_unlock(&p->lock);
    00290    return 0;
    00291 }
    00292
    00293 static int local_indicate(struct ast_channel *ast, int condition)
    00294 {
    00295    struct local_pvt *p = ast->tech_pvt;
    00296    int res = -1;
    00297    struct ast_frame f = { AST_FRAME_CONTROL, };
    00298    int isoutbound;
    00299
    00300    if (!p)
    00301       return -1;
    00302
    00303    /* Queue up a frame representing the indication as a control frame */
    00304    ast_mutex_lock(&p->lock);
    00305    isoutbound = IS_OUTBOUND(ast, p);
    00306    f.subclass = condition;
    00307    if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
    00308       ast_mutex_unlock(&p->lock);
    00309    return res;
    00310 }
    00311
    00312 static int local_digit(struct ast_channel *ast, char digit)
    00313 {
    00314    struct local_pvt *p = ast->tech_pvt;
    00315    int res = -1;
    00316    struct ast_frame f = { AST_FRAME_DTMF, };
    00317    int isoutbound;
    00318
    00319    if (!p)
    00320       return -1;
    00321
    00322    ast_mutex_lock(&p->lock);
    00323    isoutbound = IS_OUTBOUND(ast, p);
    00324    f.subclass = digit;
    00325    if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
    00326       ast_mutex_unlock(&p->lock);
    00327    return res;
    00328 }
    00329
    00330 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
    00331 {
    00332    struct local_pvt *p = ast->tech_pvt;
    00333    int res = -1;
    00334    struct ast_frame f = { AST_FRAME_HTML, };
    00335    int isoutbound;
    00336
    00337    if (!p)
    00338       return -1;
    00339
    00340    ast_mutex_lock(&p->lock);
    00341    isoutbound = IS_OUTBOUND(ast, p);
    00342    f.subclass = subclass;
    00343    f.data = (char *)data;
    00344    f.datalen = datalen;
    00345    if (!(res = local_queue_frame(p, isoutbound, &f, ast)))
    00346       ast_mutex_unlock(&p->lock);
    00347    return res;
    00348 }
    00349
    00350 /*--- local_call: Initiate new call, part of PBX interface */
    00351 /*    dest is the dial string */
    00352 static int local_call(struct ast_channel *ast, char *dest, int timeout)
    00353 {
    00354    struct local_pvt *p = ast->tech_pvt;
    00355    int res;
    00356    struct ast_var_t *varptr = NULL, *new;
    00357    size_t len, namelen;
    00358
    00359    if (!p)
    00360       return -1;
    00361
    00362    ast_mutex_lock(&p->lock);
    00363
    00364    ast_set_callerid(p->chan,
    00365       p->owner->cid.cid_num, p->owner->cid.cid_name,
    00366       p->owner->cid.cid_ani);
    00367
    00368    if (p->owner->cid.cid_rdnis)
    00369       p->chan->cid.cid_rdnis = strdup(p->owner->cid.cid_rdnis);
    00370    else
    00371       p->chan->cid.cid_rdnis = NULL;
    00372
    00373    p->chan->cid.cid_pres = p->owner->cid.cid_pres;
    00374
    00375    strncpy(p->chan->language, p->owner->language, sizeof(p->chan->language) - 1);
    00376    strncpy(p->chan->accountcode, p->owner->accountcode, sizeof(p->chan->accountcode) - 1);
    00377    p->chan->cdrflags = p->owner->cdrflags;
    00378
    00379    /* copy the channel variables from the incoming channel to the outgoing channel */
    00380    /* Note that due to certain assumptions, they MUST be in the same order */
    00381    AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
    00382       namelen = strlen(varptr->name);
    00383       len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
    00384       new = malloc(len);
    00385       if (new) {
    00386          memcpy(new, varptr, len);
    00387          new->value = &(new->name[0]) + namelen + 1;
    00388          AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
    00389       } else {
    00390          ast_log(LOG_ERROR, "Out of memory!\n");
    00391       }
    00392    }
    00393
    00394    /* Start switch on sub channel */
    00395    if (!(res = ast_pbx_start(p->chan)))
    00396       p->launchedpbx = 1;
    00397
    00398    ast_mutex_unlock(&p->lock);
    00399    return res;
    00400 }
    00401
    00402 #if 0
    00403 static void local_destroy(struct local_pvt *p)
    00404 {
    00405    struct local_pvt *cur, *prev = NULL;
    00406    ast_mutex_lock(&locallock);
    00407    cur = locals;
    00408    while(cur) {
    00409       if (cur == p) {
    00410          if (prev)
    00411             prev->next = cur->next;
    00412          else
    00413             locals = cur->next;
    00414          ast_mutex_destroy(cur);
    00415          free(cur);
    00416          break;
    00417       }
    00418       prev = cur;
    00419       cur = cur->next;
    00420    }
    00421    ast_mutex_unlock(&locallock);
    00422    if (!cur)
    00423       ast_log(LOG_WARNING, "Unable ot find local '%s@%s' in local list\n", p->exten, p->context);
    00424 }
    00425 #endif
    00426
    00427 /*--- local_hangup: Hangup a call through the local proxy channel */
    00428 static int local_hangup(struct ast_channel *ast)
    00429 {
    00430    struct local_pvt *p = ast->tech_pvt;
    00431    int isoutbound;
    00432    struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP };
    00433    struct local_pvt *cur, *prev=NULL;
    00434    struct ast_channel *ochan = NULL;
    00435    int glaredetect, res = 0;
    00436
    00437    if (!p)
    00438       return -1;
    00439
    00440    ast_mutex_lock(&p->lock);
    00441    isoutbound = IS_OUTBOUND(ast, p);
    00442    if (isoutbound) {
    00443       p->chan = NULL;
    00444       p->launchedpbx = 0;
    00445    } else
    00446       p->owner = NULL;
    00447    ast->tech_pvt = NULL;
    00448
    00449    ast_mutex_lock(&usecnt_lock);
    00450    usecnt--;
    00451    ast_mutex_unlock(&usecnt_lock);
    00452
    00453    if (!p->owner && !p->chan) {
    00454       /* Okay, done with the private part now, too. */
    00455       glaredetect = p->glaredetect;
    00456       /* If we have a queue holding, don't actually destroy p yet, but
    00457          let local_queue do it. */
    00458       if (p->glaredetect)
    00459          p->cancelqueue = 1;
    00460       ast_mutex_unlock(&p->lock);
    00461       /* Remove from list */
    00462       ast_mutex_lock(&locallock);
    00463       cur = locals;
    00464       while(cur) {
    00465          if (cur == p) {
    00466             if (prev)
    00467                prev->next = cur->next;
    00468             else
    00469                locals = cur->next;
    00470             break;
    00471          }
    00472          prev = cur;
    00473          cur = cur->next;
    00474       }
    00475       ast_mutex_unlock(&locallock);
    00476       /* Grab / release lock just in case */
    00477       ast_mutex_lock(&p->lock);
    00478       ast_mutex_unlock(&p->lock);
    00479       /* And destroy */
    00480       if (!glaredetect) {
    00481          ast_mutex_destroy(&p->lock);
    00482          free(p);
    00483       }
    00484       return 0;
    00485    }
    00486    if (p->chan && !p->launchedpbx)
    00487       /* Need to actually hangup since there is no PBX */
    00488       ochan = p->chan;
    00489    else
    00490       res = local_queue_frame(p, isoutbound, &f, NULL);
    00491    if (!res)
    00492       ast_mutex_unlock(&p->lock);
    00493    if (ochan)
    00494       ast_hangup(ochan);
    00495    return 0;
    00496 }
    00497
    00498 /*--- local_alloc: Create a call structure */
    00499 static struct local_pvt *local_alloc(char *data, int format)
    00500 {
    00501    struct local_pvt *tmp;
    00502    char *c;
    00503    char *opts;
    00504
    00505    tmp = malloc(sizeof(struct local_pvt));
    00506    if (tmp) {
    00507       memset(tmp, 0, sizeof(struct local_pvt));
    00508       ast_mutex_init(&tmp->lock);
    00509       strncpy(tmp->exten, data, sizeof(tmp->exten) - 1);
    00510       opts = strchr(tmp->exten, '/');
    00511       if (opts) {
    00512          *opts='\0';
    00513          opts++;
    00514          if (strchr(opts, 'n'))
    00515             tmp->nooptimization = 1;
    00516       }
    00517       c = strchr(tmp->exten, '@');
    00518       if (c) {
    00519          *c = '\0';
    00520          c++;
    00521          strncpy(tmp->context, c, sizeof(tmp->context) - 1);
    00522       } else
    00523          strncpy(tmp->context, "default", sizeof(tmp->context) - 1);
    00524       tmp->reqformat = format;
    00525       if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
    00526          ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
    00527          ast_mutex_destroy(&tmp->lock);
    00528          free(tmp);
    00529          tmp = NULL;
    00530       } else {
    00531          /* Add to list */
    00532          ast_mutex_lock(&locallock);
    00533          tmp->next = locals;
    00534          locals = tmp;
    00535          ast_mutex_unlock(&locallock);
    00536       }
    00537
    00538    }
    00539    return tmp;
    00540 }
    00541
    00542 /*--- local_new: Start new local channel */
    00543 static struct ast_channel *local_new(struct local_pvt *p, int state)
    00544 {
    00545    struct ast_channel *tmp, *tmp2;
    00546    int randnum = rand() & 0xffff, fmt = 0;
    00547
    00548    tmp = ast_channel_alloc(1);
    00549    tmp2 = ast_channel_alloc(1);
    00550    if (!tmp || !tmp2) {
    00551       if (tmp)
    00552          ast_channel_free(tmp);
    00553       if (tmp2)
    00554          ast_channel_free(tmp2);
    00555       ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
    00556       return NULL;
    00557    }
    00558
    00559    tmp2->tech = tmp->tech = &local_tech;
    00560    tmp->nativeformats = p->reqformat;
    00561    tmp2->nativeformats = p->reqformat;
    00562    snprintf(tmp->name, sizeof(tmp->name), "Local/%s@%s-%04x,1", p->exten, p->context, randnum);
    00563    snprintf(tmp2->name, sizeof(tmp2->name), "Local/%s@%s-%04x,2", p->exten, p->context, randnum);
    00564    tmp->type = type;
    00565    tmp2->type = type;
    00566    ast_setstate(tmp, state);
    00567    ast_setstate(tmp2, AST_STATE_RING);
    00568    fmt = ast_best_codec(p->reqformat);
    00569    tmp->writeformat = fmt;
    00570    tmp2->writeformat = fmt;
    00571    tmp->rawwriteformat = fmt;
    00572    tmp2->rawwriteformat = fmt;
    00573    tmp->readformat = fmt;
    00574    tmp2->readformat = fmt;
    00575    tmp->rawreadformat = fmt;
    00576    tmp2->rawreadformat = fmt;
    00577    tmp->tech_pvt = p;
    00578    tmp2->tech_pvt = p;
    00579    p->owner = tmp;
    00580    p->chan = tmp2;
    00581    ast_mutex_lock(&usecnt_lock);
    00582    usecnt++;
    00583    usecnt++;
    00584    ast_mutex_unlock(&usecnt_lock);
    00585    ast_update_use_count();
    00586    ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
    00587    ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
    00588    ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
    00589    tmp->priority = 1;
    00590    tmp2->priority = 1;
    00591
    00592    return tmp;
    00593 }
    00594
    00595
    00596 /*--- local_request: Part of PBX interface */
    00597 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
    00598 {
    00599    struct local_pvt *p;
    00600    struct ast_channel *chan = NULL;
    00601
    00602    p = local_alloc(data, format);
    00603    if (p)
    00604       chan = local_new(p, AST_STATE_DOWN);
    00605    return chan;
    00606 }
    00607
    00608 /*--- locals_show: CLI command "local show channels" */
    00609 static int locals_show(int fd, int argc, char **argv)
    00610 {
    00611    struct local_pvt *p;
    00612
    00613    if (argc != 3)
    00614       return RESULT_SHOWUSAGE;
    00615    ast_mutex_lock(&locallock);
    00616    p = locals;
    00617    while(p) {
    00618       ast_mutex_lock(&p->lock);
    00619       ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
    00620       ast_mutex_unlock(&p->lock);
    00621       p = p->next;
    00622    }
    00623    if (!locals)
    00624       ast_cli(fd, "No local channels in use\n");
    00625    ast_mutex_unlock(&locallock);
    00626    return RESULT_SUCCESS;
    00627 }
    00628
    00629 static char show_locals_usage[] =
    00630 "Usage: local show channels\n"
    00631 "       Provides summary information on active local proxy channels.\n";
    00632
    00633 static struct ast_cli_entry cli_show_locals = {
    00634    { "local", "show", "channels", NULL }, locals_show,
    00635    "Show status of local channels", show_locals_usage, NULL };
    00636
    00637 /*--- load_module: Load module into PBX, register channel */
    00638 int load_module()
    00639 {
    00640    /* Make sure we can register our channel type */
    00641    if (ast_channel_register(&local_tech)) {
    00642       ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
    00643       return -1;
    00644    }
    00645    ast_cli_register(&cli_show_locals);
    00646    return 0;
    00647 }
    00648
    00649 /*--- reload: Reload module */
    00650 int reload()
    00651 {
    00652    return 0;
    00653 }
    00654
    00655 /*--- unload_module: Unload the local proxy channel from Asterisk */
    00656 int unload_module()
    00657 {
    00658    struct local_pvt *p;
    00659
    00660    /* First, take us out of the channel loop */
    00661    ast_cli_unregister(&cli_show_locals);
    00662    ast_channel_unregister(&local_tech);
    00663    if (!ast_mutex_lock(&locallock)) {
    00664       /* Hangup all interfaces if they have an owner */
    00665       p = locals;
    00666       while(p) {
    00667          if (p->owner)
    00668             ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
    00669          p = p->next;
    00670       }
    00671       locals = NULL;
    00672       ast_mutex_unlock(&locallock);
    00673    } else {
    00674       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
    00675       return -1;
    00676    }
    00677    return 0;
    00678 }
    00679
    00680 int usecount()
    00681 {
    00682    return usecnt;
    00683 }
    00684
    00685 char *key()
    00686 {
    00687    return ASTERISK_GPL_KEY;
    00688 }
    00689
    00690 char *description()
    00691 {
    00692    return (char *) desc;
    00693 }
    00694