Thu Oct 11 06:42:03 2012

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: 316328 $")
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 #include "asterisk/astobj2.h"
00065 
00066 static const char tdesc[] = "Local Proxy Channel Driver";
00067 
00068 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
00069 
00070 /* right now we are treating the locals astobj2 container as a
00071  * list.  If there is ever a reason to make this more efficient
00072  * increasing the bucket size would help. */
00073 static const int BUCKET_SIZE = 1;
00074 
00075 static struct ao2_container *locals;
00076 
00077 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause);
00078 static int local_digit_begin(struct ast_channel *ast, char digit);
00079 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
00080 static int local_call(struct ast_channel *ast, char *dest, int timeout);
00081 static int local_hangup(struct ast_channel *ast);
00082 static int local_answer(struct ast_channel *ast);
00083 static struct ast_frame *local_read(struct ast_channel *ast);
00084 static int local_write(struct ast_channel *ast, struct ast_frame *f);
00085 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
00086 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00087 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
00088 static int local_sendtext(struct ast_channel *ast, const char *text);
00089 static int local_devicestate(void *data);
00090 static int local_setoption(struct ast_channel *chan, int option, void *data, int datalen);
00091 
00092 /* PBX interface structure for channel registration */
00093 static const struct ast_channel_tech local_tech = {
00094    .type = "Local",
00095    .description = tdesc,
00096    .capabilities = -1,
00097    .requester = local_request,
00098    .send_digit_begin = local_digit_begin,
00099    .send_digit_end = local_digit_end,
00100    .call = local_call,
00101    .hangup = local_hangup,
00102    .answer = local_answer,
00103    .read = local_read,
00104    .write = local_write,
00105    .write_video = local_write,
00106    .exception = local_read,
00107    .indicate = local_indicate,
00108    .fixup = local_fixup,
00109    .send_html = local_sendhtml,
00110    .send_text = local_sendtext,
00111    .devicestate = local_devicestate,
00112    .setoption = local_setoption,
00113 };
00114 
00115 struct local_pvt {
00116    unsigned int flags;                     /* Private flags */
00117    char context[AST_MAX_CONTEXT];      /* Context to call */
00118    char exten[AST_MAX_EXTENSION];      /* Extension to call */
00119    int reqformat;          /* Requested format */
00120    struct ast_channel *owner;    /* Master Channel */
00121    struct ast_channel *chan;     /* Outbound channel */
00122    struct ast_module_user *u_owner; /*! reference to keep the module loaded while in use */
00123    struct ast_module_user *u_chan;     /*! reference to keep the module loaded while in use */
00124    AST_LIST_ENTRY(local_pvt) list;     /* Next entity */
00125 };
00126 
00127 #define LOCAL_ALREADY_MASQED  (1 << 1) /*!< Already masqueraded */
00128 #define LOCAL_LAUNCHED_PBX    (1 << 2) /*!< PBX was launched */
00129 #define LOCAL_NO_OPTIMIZATION (1 << 3) /*!< Do not optimize using masquerading */
00130 #define LOCAL_MOH_PASSTHRU    (1 << 4) /*!< Pass through music on hold start/stop frames */
00131 
00132 static int local_setoption(struct ast_channel *chan, int option, void * data, int datalen)
00133 {
00134    int res;
00135    struct local_pvt *p;
00136    struct ast_channel *otherchan;
00137    ast_chan_write_info_t *write_info;
00138 
00139    if (option != AST_OPTION_CHANNEL_WRITE) {
00140       return -1;
00141    }
00142 
00143    write_info = data;
00144 
00145    if (write_info->version != AST_CHAN_WRITE_INFO_T_VERSION) {
00146       ast_log(LOG_ERROR, "The chan_write_info_t type has changed, and this channel hasn't been updated!\n");
00147       return -1;
00148    }
00149 
00150 
00151 startover:
00152    ast_channel_lock(chan);
00153 
00154    p = chan->tech_pvt;
00155    if (!p) {
00156       ast_channel_unlock(chan);
00157       ast_log(LOG_WARNING, "Could not update other side of %s, local_pvt went away.\n", chan->name);
00158       return -1;
00159    }
00160 
00161    while (ao2_trylock(p)) {
00162       ast_channel_unlock(chan);
00163       sched_yield();
00164       ast_channel_lock(chan);
00165       p = chan->tech_pvt;
00166       if (!p) {
00167          ast_channel_unlock(chan);
00168          ast_log(LOG_WARNING, "Could not update other side of %s, local_pvt went away.\n", chan->name);
00169          return -1;
00170       }
00171    }
00172 
00173    otherchan = (write_info->chan == p->owner) ? p->chan : p->owner;
00174 
00175    if (!otherchan || otherchan == write_info->chan) {
00176       ao2_unlock(p);
00177       ast_channel_unlock(chan);
00178       ast_log(LOG_WARNING, "Could not update other side of %s, other side went away.\n", chan->name);
00179       return 0;
00180    }
00181 
00182    if (ast_channel_trylock(otherchan)) {
00183       ao2_unlock(p);
00184       ast_channel_unlock(chan);
00185       goto startover;
00186    }
00187 
00188    res = write_info->write_fn(otherchan, write_info->function, write_info->data, write_info->value);
00189 
00190    ast_channel_unlock(otherchan);
00191    ao2_unlock(p);
00192    ast_channel_unlock(chan);
00193 
00194    return res;
00195 }
00196 
00197 /*! \brief Adds devicestate to local channels */
00198 static int local_devicestate(void *data)
00199 {
00200    char *exten = ast_strdupa(data);
00201    char *context = NULL, *opts = NULL;
00202    int res;
00203 
00204    if (!(context = strchr(exten, '@'))) {
00205       ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
00206       return AST_DEVICE_INVALID; 
00207    }
00208 
00209    *context++ = '\0';
00210 
00211    /* Strip options if they exist */
00212    if ((opts = strchr(context, '/')))
00213       *opts = '\0';
00214 
00215    if (option_debug > 2)
00216       ast_log(LOG_DEBUG, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
00217    res = ast_exists_extension(NULL, context, exten, 1, NULL);
00218    if (!res)      
00219       return AST_DEVICE_INVALID;
00220    else
00221       return AST_DEVICE_UNKNOWN;
00222 }
00223 
00224 /*! \brief queue a frame on a to either the p->owner or p->chan
00225  *
00226  * \note the local_pvt MUST have it's ref count bumped before entering this function and
00227  * decremented after this function is called.  This is a side effect of the deadlock
00228  * avoidance that is necessary to lock 2 channels and a tech_pvt.  Without a ref counted
00229  * local_pvt, it is impossible to guarantee it will not be destroyed by another thread
00230  * during deadlock avoidance.
00231  */
00232 static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f, 
00233    struct ast_channel *us, int us_locked)
00234 {
00235    struct ast_channel *other = NULL;
00236 
00237    /* Recalculate outbound channel */
00238    other = isoutbound ? p->owner : p->chan;
00239 
00240    if (!other) {
00241       return 0;
00242    }
00243 
00244    /* do not queue frame if generator is on both local channels */
00245    if (us && us->generator && other->generator) {
00246       return 0;
00247    }
00248 
00249    /* Ensure that we have both channels locked */
00250    while (other && ast_channel_trylock(other)) {
00251       int res;
00252       if ((res = ao2_unlock(p))) {
00253          ast_log(LOG_ERROR, "chan_local bug! '&p->lock' was not locked when entering local_queue_frame! (%s)\n", strerror(res));
00254          return -1;
00255       }
00256       if (us && us_locked) {
00257          do {
00258             if (ast_channel_unlock(us)) {
00259                ast_log(LOG_ERROR, "chan_local bug! Our channel was not locked, yet arguments indicated that it was!!\n");
00260                ao2_lock(p);
00261                return -1;
00262             }
00263             usleep(1);
00264             ast_channel_lock(us);
00265          } while (ao2_trylock(p));
00266       } else {
00267          usleep(1);
00268          ao2_lock(p);
00269       }
00270       other = isoutbound ? p->owner : p->chan;
00271    }
00272 
00273    if (other) {
00274       if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_RINGING) {
00275             ast_setstate(other, AST_STATE_RINGING);
00276       }
00277       ast_queue_frame(other, f);
00278       ast_channel_unlock(other);
00279    }
00280 
00281    return 0;
00282 }
00283 
00284 static int local_answer(struct ast_channel *ast)
00285 {
00286    struct local_pvt *p = ast->tech_pvt;
00287    int isoutbound;
00288    int res = -1;
00289 
00290    if (!p)
00291       return -1;
00292 
00293    ao2_lock(p);
00294    ao2_ref(p, 1);
00295    isoutbound = IS_OUTBOUND(ast, p);
00296    if (isoutbound) {
00297       /* Pass along answer since somebody answered us */
00298       struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00299       res = local_queue_frame(p, isoutbound, &answer, ast, 1);
00300    } else {
00301       ast_log(LOG_WARNING, "Huh?  Local is being asked to answer?\n");
00302    }
00303    ao2_unlock(p);
00304    ao2_ref(p, -1);
00305    return res;
00306 }
00307 
00308 /*!
00309  * \internal
00310  * \note This function assumes that we're only called from the "outbound" local channel side
00311  */
00312 static void check_bridge(struct local_pvt *p)
00313 {
00314    struct ast_channel_monitor *tmp;
00315    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)))
00316       return;
00317 
00318    /* only do the masquerade if we are being called on the outbound channel,
00319       if it has been bridged to another channel and if there are no pending
00320       frames on the owner channel (because they would be transferred to the
00321       outbound channel during the masquerade)
00322    */
00323    if (p->chan->_bridge /* Not ast_bridged_channel!  Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) {
00324       /* Masquerade bridged channel into owner */
00325       /* Lock everything we need, one by one, and give up if
00326          we can't get everything.  Remember, we'll get another
00327          chance in just a little bit */
00328       if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) {
00329          if (!p->chan->_bridge->_softhangup) {
00330             if (!ast_mutex_trylock(&p->owner->lock)) {
00331                if (!p->owner->_softhangup) {
00332                   if (p->owner->monitor && !p->chan->_bridge->monitor) {
00333                      /* If a local channel is being monitored, we don't want a masquerade
00334                       * to cause the monitor to go away. Since the masquerade swaps the monitors,
00335                       * pre-swapping the monitors before the masquerade will ensure that the monitor
00336                       * ends up where it is expected.
00337                       */
00338                      tmp = p->owner->monitor;
00339                      p->owner->monitor = p->chan->_bridge->monitor;
00340                      p->chan->_bridge->monitor = tmp;
00341                   }
00342                   if (p->chan->audiohooks) {
00343                      struct ast_audiohook_list *audiohooks_swapper;
00344                      audiohooks_swapper = p->chan->audiohooks;
00345                      p->chan->audiohooks = p->owner->audiohooks;
00346                      p->owner->audiohooks = audiohooks_swapper;
00347                   }
00348 
00349                   /* If any Caller ID was set, preserve it after masquerade like above. We must check
00350                    * to see if Caller ID was set because otherwise we'll mistakingly copy info not
00351                    * set from the dialplan and will overwrite the real channel Caller ID. The reason
00352                    * for this whole preswapping action is because the Caller ID is set on the channel
00353                    * thread (which is the to be masqueraded away local channel) before both local
00354                    * channels are optimized away.
00355                    */
00356                   if (p->owner->cid.cid_dnid || p->owner->cid.cid_num ||
00357                      p->owner->cid.cid_name || p->owner->cid.cid_ani ||
00358                      p->owner->cid.cid_rdnis || p->owner->cid.cid_pres ||  
00359                      p->owner->cid.cid_ani2 || p->owner->cid.cid_ton ||  
00360                      p->owner->cid.cid_tns) {
00361 
00362                      struct ast_callerid tmpcid;
00363                      tmpcid = p->owner->cid;
00364                      p->owner->cid = p->chan->_bridge->cid;
00365                      p->chan->_bridge->cid = tmpcid;
00366                   }
00367 
00368                   ast_app_group_update(p->chan, p->owner);
00369                   ast_channel_masquerade(p->owner, p->chan->_bridge);
00370                   ast_set_flag(p, LOCAL_ALREADY_MASQED);
00371                }
00372                ast_mutex_unlock(&p->owner->lock);
00373             }
00374          }
00375          ast_mutex_unlock(&(p->chan->_bridge)->lock);
00376       }
00377    }
00378 }
00379 
00380 static struct ast_frame  *local_read(struct ast_channel *ast)
00381 {
00382    return &ast_null_frame;
00383 }
00384 
00385 static int local_write(struct ast_channel *ast, struct ast_frame *f)
00386 {
00387    struct local_pvt *p = ast->tech_pvt;
00388    int res = -1;
00389    int isoutbound;
00390 
00391    if (!p)
00392       return -1;
00393 
00394    /* Just queue for delivery to the other side */
00395    ao2_lock(p);
00396    ao2_ref(p, 1); /* ref for local_queue_frame */
00397    isoutbound = IS_OUTBOUND(ast, p);
00398    if (isoutbound && f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
00399       check_bridge(p);
00400    if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
00401       res = local_queue_frame(p, isoutbound, f, ast, 1);
00402    else {
00403       if (option_debug)
00404          ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name);
00405       res = 0;
00406    }
00407    ao2_unlock(p);
00408    ao2_ref(p, -1);
00409 
00410    return res;
00411 }
00412 
00413 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00414 {
00415    struct local_pvt *p = newchan->tech_pvt;
00416 
00417    if (!p)
00418       return -1;
00419 
00420    ao2_lock(p);
00421 
00422    if ((p->owner != oldchan) && (p->chan != oldchan)) {
00423       ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
00424       ao2_unlock(p);
00425       return -1;
00426    }
00427    if (p->owner == oldchan)
00428       p->owner = newchan;
00429    else
00430       p->chan = newchan;
00431 
00432    /* Do not let a masquerade cause a Local channel to be bridged to itself! */
00433    if (!ast_check_hangup(newchan) && ((p->owner && p->owner->_bridge == p->chan) || (p->chan && p->chan->_bridge == p->owner))) {
00434       ast_log(LOG_WARNING, "You can not bridge a Local channel to itself!\n");
00435       ao2_unlock(p);
00436       ast_queue_hangup(newchan);
00437       return -1;
00438    }
00439 
00440    ao2_unlock(p);
00441    return 0;
00442 }
00443 
00444 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
00445 {
00446    struct local_pvt *p = ast->tech_pvt;
00447    int res = 0;
00448    struct ast_frame f = { AST_FRAME_CONTROL, };
00449    int isoutbound;
00450 
00451    if (!p)
00452       return -1;
00453 
00454    ao2_ref(p, 1); /* ref for local_queue_frame */
00455 
00456    /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
00457    if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_HOLD) {
00458       ast_moh_start(ast, data, NULL);
00459    } else if (!ast_test_flag(p, LOCAL_MOH_PASSTHRU) && condition == AST_CONTROL_UNHOLD) {
00460       ast_moh_stop(ast);
00461    } else {
00462       /* Queue up a frame representing the indication as a control frame */
00463       ao2_lock(p);
00464       isoutbound = IS_OUTBOUND(ast, p);
00465       f.subclass = condition;
00466       f.data = (void*)data;
00467       f.datalen = datalen;
00468       res = local_queue_frame(p, isoutbound, &f, ast, 1);
00469       ao2_unlock(p);
00470    }
00471    ao2_ref(p, -1);
00472 
00473    return res;
00474 }
00475 
00476 static int local_digit_begin(struct ast_channel *ast, char digit)
00477 {
00478    struct local_pvt *p = ast->tech_pvt;
00479    int res = -1;
00480    struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
00481    int isoutbound;
00482 
00483    if (!p)
00484       return -1;
00485 
00486    ao2_ref(p, 1); /* ref for local_queue_frame */
00487    ao2_lock(p);
00488    isoutbound = IS_OUTBOUND(ast, p);
00489    f.subclass = digit;
00490    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00491    ao2_unlock(p);
00492    ao2_ref(p, -1);
00493 
00494    return res;
00495 }
00496 
00497 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
00498 {
00499    struct local_pvt *p = ast->tech_pvt;
00500    int res = -1;
00501    struct ast_frame f = { AST_FRAME_DTMF_END, };
00502    int isoutbound;
00503 
00504    if (!p)
00505       return -1;
00506 
00507    ao2_lock(p);
00508    ao2_ref(p, 1); /* ref for local_queue_frame */
00509    isoutbound = IS_OUTBOUND(ast, p);
00510    f.subclass = digit;
00511    f.len = duration;
00512    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00513    ao2_unlock(p);
00514    ao2_ref(p, -1);
00515 
00516    return res;
00517 }
00518 
00519 static int local_sendtext(struct ast_channel *ast, const char *text)
00520 {
00521    struct local_pvt *p = ast->tech_pvt;
00522    int res = -1;
00523    struct ast_frame f = { AST_FRAME_TEXT, };
00524    int isoutbound;
00525 
00526    if (!p)
00527       return -1;
00528 
00529    ao2_lock(p);
00530    ao2_ref(p, 1); /* ref for local_queue_frame */
00531    isoutbound = IS_OUTBOUND(ast, p);
00532    f.data = (char *) text;
00533    f.datalen = strlen(text) + 1;
00534    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00535    ao2_unlock(p);
00536    ao2_ref(p, -1);
00537    return res;
00538 }
00539 
00540 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
00541 {
00542    struct local_pvt *p = ast->tech_pvt;
00543    int res = -1;
00544    struct ast_frame f = { AST_FRAME_HTML, };
00545    int isoutbound;
00546 
00547    if (!p)
00548       return -1;
00549    
00550    ao2_lock(p);
00551    ao2_ref(p, 1); /* ref for local_queue_frame */
00552 
00553    isoutbound = IS_OUTBOUND(ast, p);
00554    f.subclass = subclass;
00555    f.data = (char *)data;
00556    f.datalen = datalen;
00557    res = local_queue_frame(p, isoutbound, &f, ast, 0);
00558 
00559    ao2_unlock(p);
00560    ao2_ref(p, -1);
00561 
00562    return res;
00563 }
00564 
00565 /*! \brief Initiate new call, part of PBX interface 
00566  *    dest is the dial string */
00567 static int local_call(struct ast_channel *ast, char *dest, int timeout)
00568 {
00569    struct local_pvt *p = ast->tech_pvt;
00570    int res = 0;
00571    struct ast_var_t *varptr = NULL, *new;
00572    size_t len, namelen;
00573 
00574    if (!p)
00575       return -1;
00576 
00577    ao2_lock(p);
00578 
00579    /*
00580     * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
00581     * call, so it's done here instead.
00582     */
00583    p->chan->cid.cid_dnid = ast_strdup(p->owner->cid.cid_dnid);
00584    p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
00585    p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
00586    p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
00587    p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
00588    p->chan->cid.cid_pres = p->owner->cid.cid_pres;
00589    p->chan->cid.cid_ani2 = p->owner->cid.cid_ani2;
00590    p->chan->cid.cid_ton = p->owner->cid.cid_ton;
00591    p->chan->cid.cid_tns = p->owner->cid.cid_tns;
00592    ast_string_field_set(p->chan, language, p->owner->language);
00593    ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
00594    ast_string_field_set(p->chan, musicclass, p->owner->musicclass);
00595    ast_cdr_update(p->chan);
00596    p->chan->cdrflags = p->owner->cdrflags;
00597 
00598    /* copy the channel variables from the incoming channel to the outgoing channel */
00599    /* Note that due to certain assumptions, they MUST be in the same order */
00600    AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
00601       namelen = strlen(varptr->name);
00602       len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
00603       if ((new = ast_calloc(1, len))) {
00604          memcpy(new, varptr, len);
00605          new->value = &(new->name[0]) + namelen + 1;
00606          AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
00607       }
00608    }
00609    ast_channel_datastore_inherit(p->owner, p->chan);
00610 
00611    if (!ast_exists_extension(p->chan, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) {
00612       ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context);
00613       ao2_unlock(p);
00614       return -1;
00615    }
00616 
00617    /* Start switch on sub channel */
00618    if (!(res = ast_pbx_start(p->chan)))
00619       ast_set_flag(p, LOCAL_LAUNCHED_PBX);
00620 
00621    ao2_unlock(p);
00622    return res;
00623 }
00624 
00625 /*! \brief Hangup a call through the local proxy channel */
00626 static int local_hangup(struct ast_channel *ast)
00627 {
00628    struct local_pvt *p = ast->tech_pvt;
00629    int isoutbound;
00630    struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP };
00631    struct ast_channel *ochan = NULL;
00632 
00633    if (!p)
00634       return -1;
00635 
00636    /* we MUST give the tech_pvt a ref here since we are unlocking the
00637     * channel during deadlock avoidance. */
00638    ao2_ref(p, 1);
00639 
00640    while (ao2_trylock(p)) {
00641       ast_channel_unlock(ast);
00642       sched_yield();
00643       ast_channel_lock(ast);
00644    }
00645 
00646    isoutbound = IS_OUTBOUND(ast, p);
00647    if (isoutbound) {
00648       const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
00649       if ((status) && (p->owner)) {
00650          /* Deadlock avoidance */
00651          while (p->owner && ast_channel_trylock(p->owner)) {
00652             ao2_unlock(p);
00653             if (p->chan) {
00654                ast_channel_unlock(p->chan);
00655             }
00656             sched_yield();
00657             if (p->chan) {
00658                ast_channel_lock(p->chan);
00659             }
00660             ao2_lock(p);
00661          }
00662          if (p->owner) {
00663             p->owner->hangupcause = p->chan->hangupcause;
00664             pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
00665             ast_channel_unlock(p->owner);
00666          }
00667       }
00668       if (!p->chan) {
00669          /* chan was == to ast and was !NULL before deadlock avoidance started, if chan
00670           * is NULL now, then we should bail because that channel
00671           * hungup already. This is possible because we let go of the
00672           * lock given to the ast channel passed to this function during
00673           * deadlock avoidance. */
00674          ao2_unlock(p);
00675          ao2_ref(p, -1);
00676          return 0;
00677       }
00678       p->chan = NULL;
00679       ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
00680       ast_module_user_remove(p->u_chan);
00681    } else {
00682       ast_module_user_remove(p->u_owner);
00683       while (p->chan && ast_channel_trylock(p->chan)) {
00684             ao2_unlock(p);
00685             if (p->owner) {
00686                ast_channel_unlock(p->owner);
00687             }
00688             sched_yield();
00689             if (p->owner) {
00690                ast_channel_lock(p->owner);
00691             }
00692             ao2_lock(p);
00693       }
00694       if (p->chan) {
00695          ast_queue_hangup(p->chan);
00696          ast_channel_unlock(p->chan);
00697       }
00698 
00699       if (!p->owner) {
00700          /* owner was == to ast and was !NULL before deadlock avoidance started, if
00701           * owner is NULL now, then we should bail because that channel
00702           * hungup already. This is possible because we let go of the
00703           * lock given to the ast channel passed to this function during
00704           * deadlock avoidance. */
00705          ao2_unlock(p);
00706          ao2_ref(p, -1);
00707          return 0;
00708       }
00709       p->owner = NULL;
00710    }
00711 
00712    ast->tech_pvt = NULL;
00713 
00714    if (!p->owner && !p->chan) {
00715       ao2_unlock(p);
00716 
00717       /* Remove from list */
00718       ao2_unlink(locals, p);
00719       ao2_ref(p, -1);
00720       return 0;
00721    }
00722    if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) {
00723       /* Need to actually hangup since there is no PBX */
00724       ochan = p->chan;
00725    } else {
00726       local_queue_frame(p, isoutbound, &f, NULL, 1);
00727    }
00728 
00729    ao2_unlock(p);
00730    if (ochan) {
00731       ast_hangup(ochan);
00732    }
00733 
00734    ao2_ref(p, -1);
00735    return 0;
00736 }
00737 
00738 /*! \brief Create a call structure */
00739 static struct local_pvt *local_alloc(const char *data, int format)
00740 {
00741    struct local_pvt *tmp = NULL;
00742    char *c = NULL, *opts = NULL;
00743 
00744    if (!(tmp = ao2_alloc(sizeof(*tmp), NULL))) {
00745       return NULL;
00746    }
00747 
00748    /* Initialize private structure information */
00749    ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
00750 
00751    /* Look for options */
00752    if ((opts = strchr(tmp->exten, '/'))) {
00753       *opts++ = '\0';
00754       if (strchr(opts, 'n'))
00755          ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
00756       if (strchr(opts, 'm'))
00757          ast_set_flag(tmp, LOCAL_MOH_PASSTHRU);
00758    }
00759 
00760    /* Look for a context */
00761    if ((c = strchr(tmp->exten, '@')))
00762       *c++ = '\0';
00763 
00764    ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
00765 
00766    tmp->reqformat = format;
00767 
00768 #if 0
00769    /* We can't do this check here, because we don't know the CallerID yet, and
00770     * the CallerID could potentially affect what step is actually taken (or
00771     * even if that step exists). */
00772    if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
00773       ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
00774       tmp = local_pvt_destroy(tmp);
00775    } else {
00776 #endif
00777       /* Add to list */
00778       ao2_link(locals, tmp);
00779 #if 0
00780    }
00781 #endif
00782    return tmp; /* this is returned with a ref */
00783 }
00784 
00785 /*! \brief Start new local channel */
00786 static struct ast_channel *local_new(struct local_pvt *p, int state)
00787 {
00788    struct ast_channel *tmp = NULL, *tmp2 = NULL;
00789    int randnum = ast_random() & 0xffff, fmt = 0;
00790    const char *t;
00791    int ama;
00792 
00793    /* Allocate two new Asterisk channels */
00794    /* safe accountcode */
00795    if (p->owner && p->owner->accountcode)
00796       t = p->owner->accountcode;
00797    else
00798       t = "";
00799 
00800    if (p->owner)
00801       ama = p->owner->amaflags;
00802    else
00803       ama = 0;
00804    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)) 
00805          || !(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))) {
00806       if (tmp)
00807          ast_channel_free(tmp);
00808       if (tmp2)
00809          ast_channel_free(tmp2);
00810       ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
00811       return NULL;
00812    } 
00813 
00814    tmp2->tech = tmp->tech = &local_tech;
00815 
00816    tmp->nativeformats = p->reqformat;
00817    tmp2->nativeformats = p->reqformat;
00818 
00819    /* Determine our read/write format and set it on each channel */
00820    fmt = ast_best_codec(p->reqformat);
00821    tmp->writeformat = fmt;
00822    tmp2->writeformat = fmt;
00823    tmp->rawwriteformat = fmt;
00824    tmp2->rawwriteformat = fmt;
00825    tmp->readformat = fmt;
00826    tmp2->readformat = fmt;
00827    tmp->rawreadformat = fmt;
00828    tmp2->rawreadformat = fmt;
00829 
00830    tmp->tech_pvt = p;
00831    tmp2->tech_pvt = p;
00832 
00833    p->owner = tmp;
00834    p->chan = tmp2;
00835    p->u_owner = ast_module_user_add(p->owner);
00836    p->u_chan = ast_module_user_add(p->chan);
00837 
00838    ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
00839    ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
00840    ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
00841    tmp->priority = 1;
00842    tmp2->priority = 1;
00843 
00844    return tmp;
00845 }
00846 
00847 /*! \brief Part of PBX interface */
00848 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
00849 {
00850    struct local_pvt *p = NULL;
00851    struct ast_channel *chan = NULL;
00852 
00853    /* Allocate a new private structure and then Asterisk channel */
00854    if ((p = local_alloc(data, format))) {
00855       if (!(chan = local_new(p, AST_STATE_DOWN))) {
00856          ao2_unlink(locals, p);
00857       }
00858       ao2_ref(p, -1); /* kill the ref from the alloc */
00859    }
00860 
00861    return chan;
00862 }
00863 
00864 /*! \brief CLI command "local show channels" */
00865 static int locals_show(int fd, int argc, char **argv)
00866 {
00867    struct local_pvt *p = NULL;
00868    struct ao2_iterator it;
00869 
00870    if (argc != 3)
00871       return RESULT_SHOWUSAGE;
00872 
00873 
00874    if (ao2_container_count(locals) == 0) {
00875       ast_cli(fd, "No local channels in use\n");
00876       return RESULT_SUCCESS;
00877    }
00878 
00879    it = ao2_iterator_init(locals, 0);
00880    while ((p = ao2_iterator_next(&it))) {
00881       ao2_lock(p);
00882       ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
00883       ao2_unlock(p);
00884       ao2_ref(p, -1);
00885    }
00886    ao2_iterator_destroy(&it);
00887 
00888    return RESULT_SUCCESS;
00889 }
00890 
00891 static char show_locals_usage[] = 
00892 "Usage: local show channels\n"
00893 "       Provides summary information on active local proxy channels.\n";
00894 
00895 static struct ast_cli_entry cli_local[] = {
00896    { { "local", "show", "channels", NULL },
00897    locals_show, "List status of local channels",
00898    show_locals_usage },
00899 };
00900 
00901 static int locals_cmp_cb(void *obj, void *arg, int flags)
00902 {
00903    return (obj == arg) ? CMP_MATCH : 0;
00904 }
00905 
00906 /*! \brief Load module into PBX, register channel */
00907 static int load_module(void)
00908 {
00909    if (!(locals = ao2_container_alloc(BUCKET_SIZE, NULL, locals_cmp_cb))) {
00910       return -1;
00911    }
00912 
00913    /* Make sure we can register our channel type */
00914    if (ast_channel_register(&local_tech)) {
00915       ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
00916       ao2_ref(locals, -1);
00917       return -1;
00918    }
00919 
00920    ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00921    return 0;
00922 }
00923 
00924 /*! \brief Unload the local proxy channel from Asterisk */
00925 static int unload_module(void)
00926 {
00927    struct local_pvt *p = NULL;
00928    struct ao2_iterator it;
00929 
00930    /* First, take us out of the channel loop */
00931    ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
00932    ast_channel_unregister(&local_tech);
00933 
00934    it = ao2_iterator_init(locals, 0);
00935    while ((p = ao2_iterator_next(&it))) {
00936       if (p->owner) {
00937          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
00938       }
00939       ao2_ref(p, -1);
00940    }
00941    ao2_iterator_destroy(&it);
00942    ao2_ref(locals, -1);
00943    return 0;
00944 }
00945 
00946 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Local Proxy Channel (Note: used internally by other modules)");

Generated on Thu Oct 11 06:42:03 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6