Thu Jul 9 13:40:27 2009

Asterisk developer's documentation


chan_mgcp.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, 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 Implementation of Media Gateway Control Protocol
00022  *
00023  * \author Mark Spencer <markster@digium.com>
00024  *
00025  * \par See also
00026  * \arg \ref Config_mgcp
00027  *
00028  * \ingroup channel_drivers
00029  */
00030 
00031 #include "asterisk.h"
00032 
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 152443 $")
00034 
00035 #include <sys/socket.h>
00036 #include <sys/ioctl.h>
00037 #include <net/if.h>
00038 #include <fcntl.h>
00039 #include <netdb.h>
00040 #include <sys/signal.h>
00041 #include <signal.h>
00042 #include <netinet/in.h>
00043 #include <netinet/in_systm.h>
00044 #include <netinet/ip.h>
00045 #include <arpa/inet.h>
00046 #include <ctype.h>
00047 
00048 #include "asterisk/lock.h"
00049 #include "asterisk/channel.h"
00050 #include "asterisk/config.h"
00051 #include "asterisk/module.h"
00052 #include "asterisk/pbx.h"
00053 #include "asterisk/sched.h"
00054 #include "asterisk/io.h"
00055 #include "asterisk/rtp.h"
00056 #include "asterisk/acl.h"
00057 #include "asterisk/callerid.h"
00058 #include "asterisk/cli.h"
00059 #include "asterisk/say.h"
00060 #include "asterisk/cdr.h"
00061 #include "asterisk/astdb.h"
00062 #include "asterisk/features.h"
00063 #include "asterisk/app.h"
00064 #include "asterisk/musiconhold.h"
00065 #include "asterisk/utils.h"
00066 #include "asterisk/netsock.h"
00067 #include "asterisk/causes.h"
00068 #include "asterisk/dsp.h"
00069 #include "asterisk/devicestate.h"
00070 #include "asterisk/stringfields.h"
00071 #include "asterisk/abstract_jb.h"
00072 #include "asterisk/event.h"
00073 
00074 /*
00075  * Define to work around buggy dlink MGCP phone firmware which
00076  * appears not to know that "rt" is part of the "G" package.
00077  */
00078 /* #define DLINK_BUGGY_FIRMWARE  */
00079 
00080 #define MGCPDUMPER
00081 #define DEFAULT_EXPIRY  120
00082 #define MAX_EXPIRY   3600
00083 #define CANREINVITE  1
00084 
00085 #ifndef INADDR_NONE
00086 #define INADDR_NONE (in_addr_t)(-1)
00087 #endif
00088 
00089 /*! Global jitterbuffer configuration - by default, jb is disabled */
00090 static struct ast_jb_conf default_jbconf =
00091 {
00092    .flags = 0,
00093    .max_size = -1,
00094    .resync_threshold = -1,
00095    .impl = ""
00096 };
00097 static struct ast_jb_conf global_jbconf;
00098 
00099 static const char tdesc[] = "Media Gateway Control Protocol (MGCP)";
00100 static const char config[] = "mgcp.conf";
00101 
00102 #define MGCP_DTMF_RFC2833  (1 << 0)
00103 #define MGCP_DTMF_INBAND   (1 << 1)
00104 #define MGCP_DTMF_HYBRID   (1 << 2)
00105 
00106 #define DEFAULT_MGCP_GW_PORT  2427 /*!< From RFC 2705 */
00107 #define DEFAULT_MGCP_CA_PORT  2727 /*!< From RFC 2705 */
00108 #define MGCP_MAX_PACKET    1500 /*!< Also from RFC 2543, should sub headers tho */
00109 #define DEFAULT_RETRANS    1000 /*!< How frequently to retransmit */
00110 #define MAX_RETRANS     5    /*!< Try only 5 times for retransmissions */
00111 
00112 /*! MGCP rtp stream modes { */
00113 #define MGCP_CX_SENDONLY   0
00114 #define MGCP_CX_RECVONLY   1
00115 #define MGCP_CX_SENDRECV   2
00116 #define MGCP_CX_CONF    3
00117 #define MGCP_CX_CONFERENCE 3
00118 #define MGCP_CX_MUTE    4
00119 #define MGCP_CX_INACTIVE   4
00120 /*! } */
00121 
00122 static char *mgcp_cxmodes[] = {
00123    "sendonly",
00124    "recvonly",
00125    "sendrecv",
00126    "confrnce",
00127    "inactive"
00128 };
00129 
00130 enum {
00131    MGCP_CMD_EPCF,
00132    MGCP_CMD_CRCX,
00133    MGCP_CMD_MDCX,
00134    MGCP_CMD_DLCX,
00135    MGCP_CMD_RQNT,
00136    MGCP_CMD_NTFY,
00137    MGCP_CMD_AUEP,
00138    MGCP_CMD_AUCX,
00139    MGCP_CMD_RSIP
00140 };
00141 
00142 static char context[AST_MAX_EXTENSION] = "default";
00143 
00144 static char language[MAX_LANGUAGE] = "";
00145 static char musicclass[MAX_MUSICCLASS] = "";
00146 static char cid_num[AST_MAX_EXTENSION] = "";
00147 static char cid_name[AST_MAX_EXTENSION] = "";
00148 
00149 static int dtmfmode = 0;
00150 static int nat = 0;
00151 
00152 static ast_group_t cur_callergroup = 0;
00153 static ast_group_t cur_pickupgroup = 0;
00154 
00155 static unsigned int tos = 0;
00156 static unsigned int tos_audio = 0;
00157 static unsigned int cos = 0;
00158 static unsigned int cos_audio = 0;
00159 
00160 static int immediate = 0;
00161 
00162 static int callwaiting = 0;
00163 
00164 static int callreturn = 0;
00165 
00166 static int slowsequence = 0;
00167 
00168 static int threewaycalling = 0;
00169 
00170 /*! This is for flashhook transfers */
00171 static int transfer = 0;
00172 
00173 static int cancallforward = 0;
00174 
00175 static int singlepath = 0;
00176 
00177 static int canreinvite = CANREINVITE;
00178 
00179 static char accountcode[AST_MAX_ACCOUNT_CODE] = "";
00180 
00181 static char mailbox[AST_MAX_EXTENSION];
00182 
00183 static int amaflags = 0;
00184 
00185 static int adsi = 0;
00186 
00187 static unsigned int oseq;
00188 
00189 /*! Wait up to 16 seconds for first digit (FXO logic) */
00190 static int firstdigittimeout = 16000;
00191 
00192 /*! How long to wait for following digits (FXO logic) */
00193 static int gendigittimeout = 8000;
00194 
00195 /*! How long to wait for an extra digit, if there is an ambiguous match */
00196 static int matchdigittimeout = 3000;
00197 
00198 /*! Protect the monitoring thread, so only one process can kill or start it, and not
00199     when it's doing something critical. */
00200 AST_MUTEX_DEFINE_STATIC(netlock);
00201 
00202 AST_MUTEX_DEFINE_STATIC(monlock);
00203 
00204 /*! This is the thread for the monitor which checks for input on the channels
00205     which are not currently in use. */
00206 static pthread_t monitor_thread = AST_PTHREADT_NULL;
00207 
00208 static int restart_monitor(void);
00209 
00210 static int capability = AST_FORMAT_ULAW;
00211 static int nonCodecCapability = AST_RTP_DTMF;
00212 
00213 static char ourhost[MAXHOSTNAMELEN];
00214 static struct in_addr __ourip;
00215 static int ourport;
00216 
00217 static int mgcpdebug = 0;
00218 
00219 static struct sched_context *sched;
00220 static struct io_context *io;
00221 /*! The private structures of the  mgcp channels are linked for
00222   ! selecting outgoing channels */
00223    
00224 #define MGCP_MAX_HEADERS   64
00225 #define MGCP_MAX_LINES     64
00226 
00227 struct mgcp_request {
00228    int len;
00229    char *verb;
00230    char *identifier;
00231    char *endpoint;
00232    char *version;
00233    int headers;         /*!< MGCP Headers */
00234    char *header[MGCP_MAX_HEADERS];
00235    int lines;        /*!< SDP Content */
00236    char *line[MGCP_MAX_LINES];
00237    char data[MGCP_MAX_PACKET];
00238    int cmd;                        /*!< int version of verb = command */
00239    unsigned int trid;              /*!< int version of identifier = transaction id */
00240    struct mgcp_request *next;      /*!< next in the queue */
00241 };
00242 
00243 /*! \brief mgcp_message: MGCP message for queuing up */
00244 struct mgcp_message {
00245    struct mgcp_endpoint *owner_ep;
00246    struct mgcp_subchannel *owner_sub;
00247    int retrans;
00248    unsigned long expire;
00249    unsigned int seqno;
00250    int len;
00251    struct mgcp_message *next;
00252    char buf[0];
00253 };
00254 
00255 #define RESPONSE_TIMEOUT 30   /*!< in seconds */
00256 
00257 struct mgcp_response {
00258    time_t whensent;
00259    int len;
00260    int seqno;
00261    struct mgcp_response *next;
00262    char buf[0];
00263 };
00264 
00265 #define MAX_SUBS 2
00266 
00267 #define SUB_REAL 0
00268 #define SUB_ALT  1
00269 
00270 struct mgcp_subchannel {
00271    /*! subchannel magic string. 
00272       Needed to prove that any subchannel pointer passed by asterisk 
00273       really points to a valid subchannel memory area.
00274       Ugly.. But serves the purpose for the time being.
00275     */
00276 #define MGCP_SUBCHANNEL_MAGIC "!978!"
00277    char magic[6]; 
00278    ast_mutex_t lock;
00279    int id;
00280    struct ast_channel *owner;
00281    struct mgcp_endpoint *parent;
00282    struct ast_rtp *rtp;
00283    struct sockaddr_in tmpdest;
00284    char txident[80]; /*! \todo FIXME txident is replaced by rqnt_ident in endpoint. 
00285          This should be obsoleted */
00286    char cxident[80];
00287    char callid[80];
00288    int cxmode;
00289    struct mgcp_request *cx_queue; /*!< pending CX commands */
00290    ast_mutex_t cx_queue_lock;     /*!< CX queue lock */
00291    int nat;
00292    int iseq;                      /*!< Not used? RTP? */
00293    int outgoing;
00294    int alreadygone;
00295    struct mgcp_subchannel *next;  /*!< for out circular linked list */
00296 };
00297 
00298 #define MGCP_ONHOOK  1
00299 #define MGCP_OFFHOOK 2
00300 
00301 #define TYPE_TRUNK 1
00302 #define TYPE_LINE  2
00303 
00304 struct mgcp_endpoint {
00305    ast_mutex_t lock;
00306    char name[80];
00307    struct mgcp_subchannel *sub;     /*!< Pointer to our current connection, channel and stuff */
00308    char accountcode[AST_MAX_ACCOUNT_CODE];
00309    char exten[AST_MAX_EXTENSION];      /*!< Extention where to start */
00310    char context[AST_MAX_EXTENSION];
00311    char language[MAX_LANGUAGE];
00312    char cid_num[AST_MAX_EXTENSION]; /*!< Caller*ID number */
00313    char cid_name[AST_MAX_EXTENSION];   /*!< Caller*ID name */
00314    char lastcallerid[AST_MAX_EXTENSION];  /*!< Last Caller*ID */
00315    char dtmf_buf[AST_MAX_EXTENSION];   /*!< place to collect digits be */
00316    char call_forward[AST_MAX_EXTENSION];  /*!< Last Caller*ID */
00317    char musicclass[MAX_MUSICCLASS];
00318    char curtone[80];       /*!< Current tone */
00319    char mailbox[AST_MAX_EXTENSION];
00320    struct ast_event_sub *mwi_event_sub;
00321    ast_group_t callgroup;
00322    ast_group_t pickupgroup;
00323    int callwaiting;
00324    int hascallwaiting;
00325    int transfer;
00326    int threewaycalling;
00327    int singlepath;
00328    int cancallforward;
00329    int canreinvite;
00330    int callreturn;
00331    int dnd; /* How does this affect callwait? Do we just deny a mgcp_request if we're dnd? */
00332    int hascallerid;
00333    int hidecallerid;
00334    int dtmfmode;
00335    int amaflags;
00336    int type;
00337    int slowsequence;       /*!< MS: Sequence the endpoint as a whole */
00338    int group;
00339    int iseq; /*!< Not used? */
00340    int lastout; /*!< tracking this on the subchannels.  Is it needed here? */
00341    int needdestroy; /*!< Not used? */
00342    int capability;
00343    int nonCodecCapability;
00344    int onhooktime;
00345    int msgstate; /*!< voicemail message state */
00346    int immediate;
00347    int hookstate;
00348    int adsi;
00349    char rqnt_ident[80];             /*!< request identifier */
00350    struct mgcp_request *rqnt_queue; /*!< pending RQNT commands */
00351    ast_mutex_t rqnt_queue_lock;
00352    struct mgcp_request *cmd_queue;  /*!< pending commands other than RQNT */
00353    ast_mutex_t cmd_queue_lock;
00354    int delme;                       /*!< needed for reload */
00355    int needaudit;                   /*!< needed for reload */
00356    struct ast_dsp *dsp; /*!< XXX Should there be a dsp/subchannel? XXX */
00357    /* owner is tracked on the subchannels, and the *sub indicates whos in charge */
00358    /* struct ast_channel *owner; */
00359    /* struct ast_rtp *rtp; */
00360    /* struct sockaddr_in tmpdest; */
00361    /* message go the the endpoint and not the channel so they stay here */
00362    struct mgcp_endpoint *next;
00363    struct mgcp_gateway *parent;
00364 };
00365 
00366 static struct mgcp_gateway {
00367    /* A gateway containing one or more endpoints */
00368    char name[80];
00369    int isnamedottedip; /*!< is the name FQDN or dotted ip */
00370    struct sockaddr_in addr;
00371    struct sockaddr_in defaddr;
00372    struct in_addr ourip;
00373    int dynamic;
00374    int expire;    /*!< XXX Should we ever expire dynamic registrations? XXX */
00375    struct mgcp_endpoint *endpoints;
00376    struct ast_ha *ha;
00377 /* obsolete
00378    time_t lastouttime;
00379    int lastout;
00380    int messagepending;
00381 */
00382 /* Wildcard endpoint name */
00383    char wcardep[30];
00384    struct mgcp_message *msgs; /*!< gw msg queue */
00385    ast_mutex_t msgs_lock;     /*!< queue lock */  
00386    int retransid;             /*!< retrans timer id */
00387    int delme;                 /*!< needed for reload */
00388    struct mgcp_response *responses;
00389    struct mgcp_gateway *next;
00390 } *gateways;
00391 
00392 AST_MUTEX_DEFINE_STATIC(mgcp_reload_lock);
00393 static int mgcp_reloading = 0;
00394 
00395 /*! \brief gatelock: mutex for gateway/endpoint lists */
00396 AST_MUTEX_DEFINE_STATIC(gatelock);
00397 
00398 static int mgcpsock  = -1;
00399 
00400 static struct sockaddr_in bindaddr;
00401 
00402 static struct ast_frame  *mgcp_read(struct ast_channel *ast);
00403 static int transmit_response(struct mgcp_subchannel *sub, char *msg, struct mgcp_request *req, char *msgrest);
00404 static int transmit_notify_request(struct mgcp_subchannel *sub, char *tone);
00405 static int transmit_modify_request(struct mgcp_subchannel *sub);
00406 static int transmit_notify_request_with_callerid(struct mgcp_subchannel *sub, char *tone, char *callernum, char *callername);
00407 static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp, int codecs);
00408 static int transmit_connection_del(struct mgcp_subchannel *sub);
00409 static int transmit_audit_endpoint(struct mgcp_endpoint *p);
00410 static void start_rtp(struct mgcp_subchannel *sub);
00411 static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,  
00412                             int result, unsigned int ident, struct mgcp_request *resp);
00413 static void dump_cmd_queues(struct mgcp_endpoint *p, struct mgcp_subchannel *sub);
00414 static char *mgcp_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00415 static int reload_config(int reload);
00416 
00417 static struct ast_channel *mgcp_request(const char *type, int format, void *data, int *cause);
00418 static int mgcp_call(struct ast_channel *ast, char *dest, int timeout);
00419 static int mgcp_hangup(struct ast_channel *ast);
00420 static int mgcp_answer(struct ast_channel *ast);
00421 static struct ast_frame *mgcp_read(struct ast_channel *ast);
00422 static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame);
00423 static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen);
00424 static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00425 static int mgcp_senddigit_begin(struct ast_channel *ast, char digit);
00426 static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
00427 static int mgcp_devicestate(void *data);
00428 static void add_header_offhook(struct mgcp_subchannel *sub, struct mgcp_request *resp);
00429 
00430 static const struct ast_channel_tech mgcp_tech = {
00431    .type = "MGCP",
00432    .description = tdesc,
00433    .capabilities = AST_FORMAT_ULAW,
00434    .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
00435    .requester = mgcp_request,
00436    .devicestate = mgcp_devicestate,
00437    .call = mgcp_call,
00438    .hangup = mgcp_hangup,
00439    .answer = mgcp_answer,
00440    .read = mgcp_read,
00441    .write = mgcp_write,
00442    .indicate = mgcp_indicate,
00443    .fixup = mgcp_fixup,
00444    .send_digit_begin = mgcp_senddigit_begin,
00445    .send_digit_end = mgcp_senddigit_end,
00446    .bridge = ast_rtp_bridge,
00447 };
00448 
00449 static void mwi_event_cb(const struct ast_event *event, void *userdata)
00450 {
00451    /* This module does not handle MWI in an event-based manner.  However, it
00452     * subscribes to MWI for each mailbox that is configured so that the core
00453     * knows that we care about it.  Then, chan_mgcp will get the MWI from the
00454     * event cache instead of checking the mailbox directly. */
00455 }
00456 
00457 static int has_voicemail(struct mgcp_endpoint *p)
00458 {
00459    int new_msgs;
00460    struct ast_event *event;
00461    char *mailbox, *context;
00462 
00463    context = mailbox = ast_strdupa(p->mailbox);
00464    strsep(&context, "@");
00465    if (ast_strlen_zero(context))
00466       context = "default";
00467 
00468    event = ast_event_get_cached(AST_EVENT_MWI,
00469       AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
00470       AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
00471       AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
00472       AST_EVENT_IE_END);
00473 
00474    if (event) {
00475       new_msgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
00476       ast_event_destroy(event);
00477    } else
00478       new_msgs = ast_app_has_voicemail(p->mailbox, NULL);
00479 
00480    return new_msgs;
00481 }
00482 
00483 static int unalloc_sub(struct mgcp_subchannel *sub)
00484 {
00485    struct mgcp_endpoint *p = sub->parent;
00486    if (p->sub == sub) {
00487       ast_log(LOG_WARNING, "Trying to unalloc the real channel %s@%s?!?\n", p->name, p->parent->name);
00488       return -1;
00489    }
00490    ast_debug(1, "Released sub %d of channel %s@%s\n", sub->id, p->name, p->parent->name);
00491 
00492    sub->owner = NULL;
00493    if (!ast_strlen_zero(sub->cxident)) {
00494       transmit_connection_del(sub);
00495    }
00496    sub->cxident[0] = '\0';
00497    sub->callid[0] = '\0';
00498    sub->cxmode = MGCP_CX_INACTIVE;
00499    sub->outgoing = 0;
00500    sub->alreadygone = 0;
00501    memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
00502    if (sub->rtp) {
00503       ast_rtp_destroy(sub->rtp);
00504       sub->rtp = NULL;
00505    }
00506    dump_cmd_queues(NULL, sub); /* SC */
00507    return 0;
00508 }
00509 
00510 /* modified for new transport mechanism */
00511 static int __mgcp_xmit(struct mgcp_gateway *gw, char *data, int len)
00512 {
00513    int res;
00514    if (gw->addr.sin_addr.s_addr)
00515       res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->addr, sizeof(struct sockaddr_in));
00516    else 
00517       res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->defaddr, sizeof(struct sockaddr_in));
00518    if (res != len) {
00519       ast_log(LOG_WARNING, "mgcp_xmit returned %d: %s\n", res, strerror(errno));
00520    }
00521    return res;
00522 }
00523 
00524 static int resend_response(struct mgcp_subchannel *sub, struct mgcp_response *resp)
00525 {
00526    struct mgcp_endpoint *p = sub->parent;
00527    int res;
00528    if (mgcpdebug) {
00529       ast_verbose("Retransmitting:\n%s\n to %s:%d\n", resp->buf, ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
00530    }
00531    res = __mgcp_xmit(p->parent, resp->buf, resp->len);
00532    if (res > 0)
00533       res = 0;
00534    return res;
00535 }
00536 
00537 static int send_response(struct mgcp_subchannel *sub, struct mgcp_request *req)
00538 {
00539    struct mgcp_endpoint *p = sub->parent;
00540    int res;
00541    if (mgcpdebug) {
00542       ast_verbose("Transmitting:\n%s\n to %s:%d\n", req->data, ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
00543    }
00544    res = __mgcp_xmit(p->parent, req->data, req->len);
00545    if (res > 0)
00546       res = 0;
00547    return res;
00548 }
00549 
00550 /* modified for new transport framework */
00551 static void dump_queue(struct mgcp_gateway *gw, struct mgcp_endpoint *p)
00552 {
00553    struct mgcp_message *cur, *q = NULL, *w, *prev;
00554 
00555    ast_mutex_lock(&gw->msgs_lock);
00556    prev = NULL, cur = gw->msgs;
00557    while (cur) {
00558       if (!p || cur->owner_ep == p) {
00559          if (prev)
00560             prev->next = cur->next;
00561          else
00562             gw->msgs = cur->next;
00563 
00564          ast_log(LOG_NOTICE, "Removing message from %s transaction %u\n", 
00565             gw->name, cur->seqno);
00566 
00567          w = cur;
00568          cur = cur->next;
00569          if (q) {
00570             w->next = q;
00571          } else {
00572             w->next = NULL;
00573          }
00574          q = w;
00575       } else {
00576          prev = cur, cur=cur->next;
00577       }
00578    }
00579    ast_mutex_unlock(&gw->msgs_lock);
00580 
00581    while (q) {
00582       cur = q;
00583       q = q->next;
00584       ast_free(cur);
00585    }
00586 }
00587 
00588 static void mgcp_queue_frame(struct mgcp_subchannel *sub, struct ast_frame *f)
00589 {
00590    for(;;) {
00591       if (sub->owner) {
00592          if (!ast_channel_trylock(sub->owner)) {
00593             ast_queue_frame(sub->owner, f);
00594             ast_channel_unlock(sub->owner);
00595             break;
00596          } else {
00597             DEADLOCK_AVOIDANCE(&sub->lock);
00598          }
00599       } else
00600          break;
00601    }
00602 }
00603 
00604 static void mgcp_queue_hangup(struct mgcp_subchannel *sub)
00605 {
00606    for(;;) {
00607       if (sub->owner) {
00608          if (!ast_channel_trylock(sub->owner)) {
00609             ast_queue_hangup(sub->owner);
00610             ast_channel_unlock(sub->owner);
00611             break;
00612          } else {
00613             DEADLOCK_AVOIDANCE(&sub->lock);
00614          }
00615       } else
00616          break;
00617    }
00618 }
00619 
00620 static void mgcp_queue_control(struct mgcp_subchannel *sub, int control)
00621 {
00622    struct ast_frame f = { AST_FRAME_CONTROL, };
00623    f.subclass = control;
00624    return mgcp_queue_frame(sub, &f);
00625 }
00626 
00627 static int retrans_pkt(const void *data)
00628 {
00629    struct mgcp_gateway *gw = (struct mgcp_gateway *)data;
00630    struct mgcp_message *cur, *exq = NULL, *w, *prev;
00631    int res = 0;
00632 
00633    /* find out expired msgs */
00634    ast_mutex_lock(&gw->msgs_lock);
00635 
00636    prev = NULL, cur = gw->msgs;
00637    while (cur) {
00638       if (cur->retrans < MAX_RETRANS) {
00639          cur->retrans++;
00640          if (mgcpdebug) {
00641             ast_verbose("Retransmitting #%d transaction %u on [%s]\n",
00642                cur->retrans, cur->seqno, gw->name);
00643          }
00644          __mgcp_xmit(gw, cur->buf, cur->len);
00645 
00646          prev = cur;
00647          cur = cur->next;
00648       } else {
00649          if (prev)
00650             prev->next = cur->next;
00651          else
00652             gw->msgs = cur->next;
00653 
00654          ast_log(LOG_WARNING, "Maximum retries exceeded for transaction %u on [%s]\n",
00655             cur->seqno, gw->name);
00656 
00657          w = cur;
00658          cur = cur->next;
00659 
00660          if (exq) {
00661             w->next = exq;
00662          } else {
00663             w->next = NULL;
00664          }
00665          exq = w;
00666       }
00667    }
00668 
00669    if (!gw->msgs) {
00670       gw->retransid = -1;
00671       res = 0;
00672    } else {
00673       res = 1;
00674    }
00675    ast_mutex_unlock(&gw->msgs_lock);
00676 
00677    while (exq) {
00678       cur = exq;
00679       /* time-out transaction */
00680       handle_response(cur->owner_ep, cur->owner_sub, 406, cur->seqno, NULL); 
00681       exq = exq->next;
00682       ast_free(cur);
00683    }
00684 
00685    return res;
00686 }
00687 
00688 /* modified for the new transaction mechanism */
00689 static int mgcp_postrequest(struct mgcp_endpoint *p, struct mgcp_subchannel *sub, 
00690                             char *data, int len, unsigned int seqno)
00691 {
00692    struct mgcp_message *msg;
00693    struct mgcp_message *cur;
00694    struct mgcp_gateway *gw;
00695    struct timeval tv;
00696 
00697    msg = ast_malloc(sizeof(*msg) + len);
00698    if (!msg) {
00699       return -1;
00700    }
00701    gw = ((p && p->parent) ? p->parent : NULL);
00702    if (!gw) {
00703       ast_free(msg);
00704       return -1;
00705    }
00706 /* SC
00707    time(&t);
00708    if (gw->messagepending && (gw->lastouttime + 20 < t)) {
00709       ast_log(LOG_NOTICE, "Timeout waiting for response to message:%d,  lastouttime: %ld, now: %ld.  Dumping pending queue\n",
00710          gw->msgs ? gw->msgs->seqno : -1, (long) gw->lastouttime, (long) t);
00711       dump_queue(sub->parent);
00712    }
00713 */
00714    msg->owner_sub = sub;
00715    msg->owner_ep = p;
00716    msg->seqno = seqno;
00717    msg->next = NULL;
00718    msg->len = len;
00719    msg->retrans = 0;
00720    memcpy(msg->buf, data, msg->len);
00721 
00722    ast_mutex_lock(&gw->msgs_lock);
00723    cur = gw->msgs;
00724    if (cur) {
00725       while(cur->next)
00726          cur = cur->next;
00727       cur->next = msg;
00728    } else {
00729       gw->msgs = msg;
00730    }
00731 
00732    tv = ast_tvnow();
00733    msg->expire = tv.tv_sec * 1000 + tv.tv_usec / 1000 + DEFAULT_RETRANS;
00734 
00735    if (gw->retransid == -1)
00736       gw->retransid = ast_sched_add(sched, DEFAULT_RETRANS, retrans_pkt, (void *)gw);
00737    ast_mutex_unlock(&gw->msgs_lock);
00738 /* SC
00739    if (!gw->messagepending) {
00740       gw->messagepending = 1;
00741       gw->lastout = seqno;
00742       gw->lastouttime = t;
00743 */
00744    __mgcp_xmit(gw, msg->buf, msg->len);
00745       /* XXX Should schedule retransmission XXX */
00746 /* SC
00747    } else
00748       ast_debug(1, "Deferring transmission of transaction %d\n", seqno);
00749 */
00750    return 0;
00751 }
00752 
00753 /* modified for new transport */
00754 static int send_request(struct mgcp_endpoint *p, struct mgcp_subchannel *sub, 
00755                         struct mgcp_request *req, unsigned int seqno)
00756 {
00757    int res = 0;
00758    struct mgcp_request **queue, *q, *r, *t;
00759    ast_mutex_t *l;
00760 
00761    ast_debug(1, "Slow sequence is %d\n", p->slowsequence);
00762    if (p->slowsequence) {
00763       queue = &p->cmd_queue;
00764       l = &p->cmd_queue_lock;
00765       ast_mutex_lock(l);
00766    } else {
00767       switch (req->cmd) {
00768       case MGCP_CMD_DLCX:
00769          queue = &sub->cx_queue;
00770          l = &sub->cx_queue_lock;
00771          ast_mutex_lock(l);
00772          q = sub->cx_queue;
00773          /* delete pending cx cmds */
00774          while (q) {
00775             r = q->next;
00776             ast_free(q);
00777             q = r;
00778          }
00779          *queue = NULL;
00780          break;
00781 
00782       case MGCP_CMD_CRCX:
00783       case MGCP_CMD_MDCX:
00784          queue = &sub->cx_queue;
00785          l = &sub->cx_queue_lock;
00786          ast_mutex_lock(l);
00787          break;
00788 
00789       case MGCP_CMD_RQNT:
00790          queue = &p->rqnt_queue;
00791          l = &p->rqnt_queue_lock;
00792          ast_mutex_lock(l);
00793          break;
00794 
00795       default:
00796          queue = &p->cmd_queue;
00797          l = &p->cmd_queue_lock;
00798          ast_mutex_lock(l);
00799          break;
00800       }
00801    }
00802 
00803    r = ast_malloc(sizeof(*r));
00804    if (!r) {
00805       ast_log(LOG_WARNING, "Cannot post MGCP request: insufficient memory\n");
00806       ast_mutex_unlock(l);
00807       return -1;
00808    }
00809    memcpy(r, req, sizeof(*r));
00810 
00811    if (!(*queue)) {
00812       if (mgcpdebug) {
00813          ast_verbose("Posting Request:\n%s to %s:%d\n", req->data, 
00814             ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
00815       }
00816 
00817       res = mgcp_postrequest(p, sub, req->data, req->len, seqno);
00818    } else {
00819       if (mgcpdebug) {
00820          ast_verbose("Queueing Request:\n%s to %s:%d\n", req->data, 
00821             ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
00822       }
00823    }
00824 
00825    /* XXX find tail. We could also keep tail in the data struct for faster access */
00826    for (t = *queue; t && t->next; t = t->next);
00827 
00828    r->next = NULL;
00829    if (t)
00830       t->next = r;
00831    else
00832       *queue = r;
00833 
00834    ast_mutex_unlock(l);
00835 
00836    return res;
00837 }
00838 
00839 static int mgcp_call(struct ast_channel *ast, char *dest, int timeout)
00840 {
00841    int res;
00842    struct mgcp_endpoint *p;
00843    struct mgcp_subchannel *sub;
00844    char tone[50] = "";
00845    const char *distinctive_ring = NULL;
00846    struct varshead *headp;
00847    struct ast_var_t *current;
00848 
00849    if (mgcpdebug) {
00850       ast_verb(3, "MGCP mgcp_call(%s)\n", ast->name);
00851    }
00852    sub = ast->tech_pvt;
00853    p = sub->parent;
00854    headp = &ast->varshead;
00855    AST_LIST_TRAVERSE(headp,current,entries) {
00856       /* Check whether there is an ALERT_INFO variable */
00857       if (strcasecmp(ast_var_name(current),"ALERT_INFO") == 0) {
00858          distinctive_ring = ast_var_value(current);
00859       }
00860    }
00861 
00862    ast_mutex_lock(&sub->lock);
00863    switch (p->hookstate) {
00864    case MGCP_OFFHOOK:
00865       if (!ast_strlen_zero(distinctive_ring)) {
00866          snprintf(tone, sizeof(tone), "L/wt%s", distinctive_ring);
00867          if (mgcpdebug) {
00868             ast_verb(3, "MGCP distinctive callwait %s\n", tone);
00869          }
00870       } else {
00871          ast_copy_string(tone, "L/wt", sizeof(tone));
00872          if (mgcpdebug) {
00873             ast_verb(3, "MGCP normal callwait %s\n", tone);
00874          }
00875       }
00876       break;
00877    case MGCP_ONHOOK:
00878    default:
00879       if (!ast_strlen_zero(distinctive_ring)) {
00880          snprintf(tone, sizeof(tone), "L/r%s", distinctive_ring);
00881          if (mgcpdebug) {
00882             ast_verb(3, "MGCP distinctive ring %s\n", tone);
00883          }
00884       } else {
00885          ast_copy_string(tone, "L/rg", sizeof(tone));
00886          if (mgcpdebug) {
00887             ast_verb(3, "MGCP default ring\n");
00888          }
00889       }
00890       break;
00891    }
00892 
00893    if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
00894       ast_log(LOG_WARNING, "mgcp_call called on %s, neither down nor reserved\n", ast->name);
00895       ast_mutex_unlock(&sub->lock);
00896       return -1;
00897    }
00898 
00899    res = 0;
00900    sub->outgoing = 1;
00901    sub->cxmode = MGCP_CX_RECVONLY;
00902    if (p->type == TYPE_LINE) {
00903       if (!sub->rtp) {
00904          start_rtp(sub);
00905       } else {
00906          transmit_modify_request(sub);
00907       }
00908 
00909       if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) {
00910          /* try to prevent a callwait from disturbing the other connection */
00911          sub->next->cxmode = MGCP_CX_RECVONLY;
00912          transmit_modify_request(sub->next);
00913       }
00914 
00915       transmit_notify_request_with_callerid(sub, tone, ast->cid.cid_num, ast->cid.cid_name);
00916       ast_setstate(ast, AST_STATE_RINGING);
00917 
00918       if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) {
00919          /* Put the connection back in sendrecv */
00920          sub->next->cxmode = MGCP_CX_SENDRECV;
00921          transmit_modify_request(sub->next);
00922       }
00923    } else {
00924       ast_log(LOG_NOTICE, "Don't know how to dial on trunks yet\n");
00925       res = -1;
00926    }
00927    ast_mutex_unlock(&sub->lock);
00928    ast_queue_control(ast, AST_CONTROL_RINGING);
00929    return res;
00930 }
00931 
00932 static int mgcp_hangup(struct ast_channel *ast)
00933 {
00934    struct mgcp_subchannel *sub = ast->tech_pvt;
00935    struct mgcp_endpoint *p = sub->parent;
00936 
00937    ast_debug(1, "mgcp_hangup(%s)\n", ast->name);
00938    if (!ast->tech_pvt) {
00939       ast_debug(1, "Asked to hangup channel not connected\n");
00940       return 0;
00941    }
00942    if (strcmp(sub->magic, MGCP_SUBCHANNEL_MAGIC)) {
00943       ast_debug(1, "Invalid magic. MGCP subchannel freed up already.\n");
00944       return 0;
00945    }
00946    ast_mutex_lock(&sub->lock);
00947    if (mgcpdebug) {
00948       ast_verb(3, "MGCP mgcp_hangup(%s) on %s@%s\n", ast->name, p->name, p->parent->name);
00949    }
00950 
00951    if ((p->dtmfmode & MGCP_DTMF_INBAND) && p->dsp) {
00952       /* check whether other channel is active. */
00953       if (!sub->next->owner) {
00954          if (p->dtmfmode & MGCP_DTMF_HYBRID)
00955             p->dtmfmode &= ~MGCP_DTMF_INBAND;
00956          if (mgcpdebug) {
00957             ast_verb(2, "MGCP free dsp on %s@%s\n", p->name, p->parent->name);
00958          }
00959          ast_dsp_free(p->dsp);
00960          p->dsp = NULL;
00961       }
00962    }
00963 
00964    sub->owner = NULL;
00965    if (!ast_strlen_zero(sub->cxident)) {
00966       transmit_connection_del(sub);
00967    }
00968    sub->cxident[0] = '\0';
00969    if ((sub == p->sub) && sub->next->owner) {
00970       if (p->hookstate == MGCP_OFFHOOK) {
00971          if (sub->next->owner && ast_bridged_channel(sub->next->owner)) {
00972             transmit_notify_request_with_callerid(p->sub, "L/wt", ast_bridged_channel(sub->next->owner)->cid.cid_num, ast_bridged_channel(sub->next->owner)->cid.cid_name);
00973          }
00974       } else {
00975          /* set our other connection as the primary and swith over to it */
00976          p->sub = sub->next;
00977          p->sub->cxmode = MGCP_CX_RECVONLY;
00978          transmit_modify_request(p->sub);
00979          if (sub->next->owner && ast_bridged_channel(sub->next->owner)) {
00980             transmit_notify_request_with_callerid(p->sub, "L/rg", ast_bridged_channel(sub->next->owner)->cid.cid_num, ast_bridged_channel(sub->next->owner)->cid.cid_name);
00981          }
00982       }
00983 
00984    } else if ((sub == p->sub->next) && p->hookstate == MGCP_OFFHOOK) {
00985       transmit_notify_request(sub, "L/v");
00986    } else if (p->hookstate == MGCP_OFFHOOK) {
00987       transmit_notify_request(sub, "L/ro");
00988    } else {
00989       transmit_notify_request(sub, "");
00990    }
00991 
00992    ast->tech_pvt = NULL;
00993    sub->alreadygone = 0;
00994    sub->outgoing = 0;
00995    sub->cxmode = MGCP_CX_INACTIVE;
00996    sub->callid[0] = '\0';
00997    if (p) {
00998       memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
00999    }
01000    /* Reset temporary destination */
01001    memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
01002    if (sub->rtp) {
01003       ast_rtp_destroy(sub->rtp);
01004       sub->rtp = NULL;
01005    }
01006 
01007    ast_module_unref(ast_module_info->self);
01008 
01009    if ((p->hookstate == MGCP_ONHOOK) && (!sub->next->rtp)) {
01010       p->hidecallerid = 0;
01011       if (p->hascallwaiting && !p->callwaiting) {
01012          ast_verb(3, "Enabling call waiting on %s\n", ast->name);
01013          p->callwaiting = -1;
01014       }
01015       if (has_voicemail(p)) {
01016          if (mgcpdebug) {
01017             ast_verb(3, "MGCP mgcp_hangup(%s) on %s@%s set vmwi(+)\n",
01018                ast->name, p->name, p->parent->name);
01019          }
01020          transmit_notify_request(sub, "L/vmwi(+)");
01021       } else {
01022          if (mgcpdebug) {
01023             ast_verb(3, "MGCP mgcp_hangup(%s) on %s@%s set vmwi(-)\n",
01024                ast->name, p->name, p->parent->name);
01025          }
01026          transmit_notify_request(sub, "L/vmwi(-)");
01027       }
01028    }
01029    ast_mutex_unlock(&sub->lock);
01030    return 0;
01031 }
01032 
01033 static char *handle_mgcp_show_endpoints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01034 {
01035    struct mgcp_gateway  *mg;
01036    struct mgcp_endpoint *me;
01037    int hasendpoints = 0;
01038 
01039    switch (cmd) {
01040    case CLI_INIT:
01041       e->command = "mgcp show endpoints";
01042       e->usage =
01043          "Usage: mgcp show endpoints\n"
01044          "       Lists all endpoints known to the MGCP (Media Gateway Control Protocol) subsystem.\n";
01045       return NULL;
01046    case CLI_GENERATE:
01047       return NULL;
01048    }
01049 
01050    if (a->argc != 3) 
01051       return CLI_SHOWUSAGE;
01052    ast_mutex_lock(&gatelock);
01053    mg = gateways;
01054    while(mg) {
01055       me = mg->endpoints;
01056       ast_cli(a->fd, "Gateway '%s' at %s (%s)\n", mg->name, mg->addr.sin_addr.s_addr ? ast_inet_ntoa(mg->addr.sin_addr) : ast_inet_ntoa(mg->defaddr.sin_addr), mg->dynamic ? "Dynamic" : "Static");
01057       while(me) {
01058          /* Don't show wilcard endpoint */
01059          if (strcmp(me->name, mg->wcardep) != 0)
01060             ast_cli(a->fd, "   -- '%s@%s in '%s' is %s\n", me->name, mg->name, me->context, me->sub->owner ? "active" : "idle");
01061          hasendpoints = 1;
01062          me = me->next;
01063       }
01064       if (!hasendpoints) {
01065          ast_cli(a->fd, "   << No Endpoints Defined >>     ");
01066       }
01067       mg = mg->next;
01068    }
01069    ast_mutex_unlock(&gatelock);
01070    return CLI_SUCCESS;
01071 }
01072 
01073 static char *handle_mgcp_audit_endpoint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01074 {
01075    struct mgcp_gateway  *mg;
01076    struct mgcp_endpoint *me;
01077    int found = 0;
01078    char *ename,*gname, *c;
01079 
01080    switch (cmd) {
01081    case CLI_INIT:
01082       e->command = "mgcp audit endpoint";
01083       e->usage =
01084          "Usage: mgcp audit endpoint <endpointid>\n"
01085          "       Lists the capabilities of an endpoint in the MGCP (Media Gateway Control Protocol) subsystem.\n"
01086          "       mgcp debug MUST be on to see the results of this command.\n";
01087       return NULL;
01088    case CLI_GENERATE:
01089       return NULL;
01090    }
01091 
01092    if (!mgcpdebug) {
01093       return CLI_SHOWUSAGE;
01094    }
01095    if (a->argc != 4)
01096       return CLI_SHOWUSAGE;
01097    /* split the name into parts by null */
01098    ename = a->argv[3];
01099    gname = ename;
01100    while (*gname) {
01101       if (*gname == '@') {
01102          *gname = 0;
01103          gname++;
01104          break;
01105       }
01106       gname++;
01107    }
01108    if (gname[0] == '[')
01109       gname++;
01110    if ((c = strrchr(gname, ']')))
01111       *c = '\0';
01112    ast_mutex_lock(&gatelock);
01113    mg = gateways;
01114    while(mg) {
01115       if (!strcasecmp(mg->name, gname)) {
01116          me = mg->endpoints;
01117          while(me) {
01118             if (!strcasecmp(me->name, ename)) {
01119                found = 1;
01120                transmit_audit_endpoint(me);
01121                break;
01122             }
01123             me = me->next;
01124          }
01125          if (found) {
01126             break;
01127          }
01128       }
01129       mg = mg->next;
01130    }
01131    if (!found) {
01132       ast_cli(a->fd, "   << Could not find endpoint >>     ");
01133    }
01134    ast_mutex_unlock(&gatelock);
01135    return CLI_SUCCESS;
01136 }
01137 
01138 static char *handle_mgcp_set_debug_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01139 {
01140    switch (cmd) {
01141    case CLI_INIT:
01142       e->command = "mgcp set debug [off]";
01143       e->usage =
01144          "Usage: mgcp set debug [off]\n"
01145          "       Enables/Disables dumping of MGCP packets for debugging purposes\n";   
01146       return NULL;
01147    case CLI_GENERATE:
01148       return NULL;
01149    }
01150 
01151    if (a->argc < 3 || a->argc > 4)
01152       return CLI_SHOWUSAGE;
01153    if (a->argc == 3) {
01154       mgcpdebug = 1;
01155       ast_cli(a->fd, "MGCP Debugging Enabled\n");
01156    } else if (!strncasecmp(a->argv[3], "off", 3)) {
01157       mgcpdebug = 0;
01158       ast_cli(a->fd, "MGCP Debugging Disabled\n");
01159    }
01160    return CLI_SUCCESS;
01161 }
01162 
01163 static char *handle_mgcp_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01164 {
01165    switch (cmd) {
01166    case CLI_INIT:
01167       e->command = "mgcp set debug {on|off}";
01168       e->usage =
01169          "Usage: mgcp set debug {on|off}\n"
01170          "       Enables/Disables dumping of MGCP packets for debugging purposes\n";   
01171       return NULL;
01172    case CLI_GENERATE:
01173       return NULL;
01174    }
01175 
01176    if (a->argc != e->args)
01177       return CLI_SHOWUSAGE;
01178 
01179    if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
01180       mgcpdebug = 1;
01181       ast_cli(a->fd, "MGCP Debugging Enabled\n");
01182    } else if (!strncasecmp(a->argv[3], "off", 3)) {
01183       mgcpdebug = 0;
01184       ast_cli(a->fd, "MGCP Debugging Disabled\n");
01185    } else {
01186       return CLI_SHOWUSAGE;
01187    }
01188    return CLI_SUCCESS;
01189 }
01190 
01191 static struct ast_cli_entry cli_mgcp_set_debug_deprecated = AST_CLI_DEFINE(handle_mgcp_set_debug_deprecated, "Enable/Disable MGCP debugging");
01192 static struct ast_cli_entry cli_mgcp[] = {
01193    AST_CLI_DEFINE(handle_mgcp_audit_endpoint, "Audit specified MGCP endpoint"),
01194    AST_CLI_DEFINE(handle_mgcp_show_endpoints, "List defined MGCP endpoints"),
01195    AST_CLI_DEFINE(handle_mgcp_set_debug, "Enable/Disable MGCP debugging", .deprecate_cmd = &cli_mgcp_set_debug_deprecated),
01196    AST_CLI_DEFINE(mgcp_reload, "Reload MGCP configuration"),
01197 };
01198 
01199 static int mgcp_answer(struct ast_channel *ast)
01200 {
01201    int res = 0;
01202    struct mgcp_subchannel *sub = ast->tech_pvt;
01203    struct mgcp_endpoint *p = sub->parent;
01204 
01205    ast_mutex_lock(&sub->lock);
01206    sub->cxmode = MGCP_CX_SENDRECV;
01207    if (!sub->rtp) {
01208       start_rtp(sub);
01209    } else {
01210       transmit_modify_request(sub);
01211    }
01212    ast_verb(3, "MGCP mgcp_answer(%s) on %s@%s-%d\n",
01213          ast->name, p->name, p->parent->name, sub->id);
01214    if (ast->_state != AST_STATE_UP) {
01215       ast_setstate(ast, AST_STATE_UP);
01216       ast_debug(1, "mgcp_answer(%s)\n", ast->name);
01217       transmit_notify_request(sub, "");
01218       transmit_modify_request(sub);
01219    }
01220    ast_mutex_unlock(&sub->lock);
01221    return res;
01222 }
01223 
01224 static struct ast_frame *mgcp_rtp_read(struct mgcp_subchannel *sub)
01225 {
01226    /* Retrieve audio/etc from channel.  Assumes sub->lock is already held. */
01227    struct ast_frame *f;
01228 
01229    f = ast_rtp_read(sub->rtp);
01230    /* Don't send RFC2833 if we're not supposed to */
01231    if (f && (f->frametype == AST_FRAME_DTMF) && !(sub->parent->dtmfmode & MGCP_DTMF_RFC2833))
01232       return &ast_null_frame;
01233    if (sub->owner) {
01234       /* We already hold the channel lock */
01235       if (f->frametype == AST_FRAME_VOICE) {
01236          if (f->subclass != sub->owner->nativeformats) {
01237             ast_debug(1, "Oooh, format changed to %d\n", f->subclass);
01238             sub->owner->nativeformats = f->subclass;
01239             ast_set_read_format(sub->owner, sub->owner->readformat);
01240             ast_set_write_format(sub->owner, sub->owner->writeformat);
01241          }
01242          /* Courtesy fearnor aka alex@pilosoft.com */
01243          if ((sub->parent->dtmfmode & MGCP_DTMF_INBAND) && (sub->parent->dsp)) {
01244 #if 0
01245             ast_log(LOG_NOTICE, "MGCP ast_dsp_process\n");
01246 #endif
01247             f = ast_dsp_process(sub->owner, sub->parent->dsp, f);
01248          }
01249       }
01250    }
01251    return f;
01252 }
01253 
01254 
01255 static struct ast_frame *mgcp_read(struct ast_channel *ast)
01256 {
01257    struct ast_frame *f;
01258    struct mgcp_subchannel *sub = ast->tech_pvt;
01259    ast_mutex_lock(&sub->lock);
01260    f = mgcp_rtp_read(sub);
01261    ast_mutex_unlock(&sub->lock);
01262    return f;
01263 }
01264 
01265 static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame)
01266 {
01267    struct mgcp_subchannel *sub = ast->tech_pvt;
01268    int res = 0;
01269    if (frame->frametype != AST_FRAME_VOICE) {
01270       if (frame->frametype == AST_FRAME_IMAGE)
01271          return 0;
01272       else {
01273          ast_log(LOG_WARNING, "Can't send %d type frames with MGCP write\n", frame->frametype);
01274          return 0;
01275       }
01276    } else {
01277       if (!(frame->subclass & ast->nativeformats)) {
01278          ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
01279             frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat);
01280          return -1;
01281       }
01282    }
01283    if (sub) {
01284       ast_mutex_lock(&sub->lock);
01285       if ((sub->parent->sub == sub) || !sub->parent->singlepath) {
01286          if (sub->rtp) {
01287             res =  ast_rtp_write(sub->rtp, frame);
01288          }
01289       }
01290       ast_mutex_unlock(&sub->lock);
01291    }
01292    return res;
01293 }
01294 
01295 static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
01296 {
01297    struct mgcp_subchannel *sub = newchan->tech_pvt;
01298 
01299    ast_mutex_lock(&sub->lock);
01300    ast_log(LOG_NOTICE, "mgcp_fixup(%s, %s)\n", oldchan->name, newchan->name);
01301    if (sub->owner != oldchan) {
01302       ast_mutex_unlock(&sub->lock);
01303       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
01304       return -1;
01305    }
01306    sub->owner = newchan;
01307    ast_mutex_unlock(&sub->lock);
01308    return 0;
01309 }
01310 
01311 static int mgcp_senddigit_begin(struct ast_channel *ast, char digit)
01312 {
01313    struct mgcp_subchannel *sub = ast->tech_pvt;
01314    struct mgcp_endpoint *p = sub->parent;
01315    int res = 0;
01316 
01317    ast_mutex_lock(&sub->lock);
01318    if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
01319       ast_log(LOG_DEBUG, "Sending DTMF using inband/hybrid\n");
01320       res = -1; /* Let asterisk play inband indications */
01321    } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
01322       ast_log(LOG_DEBUG, "Sending DTMF using RFC2833");
01323       ast_rtp_senddigit_begin(sub->rtp, digit);
01324    } else {
01325       ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
01326    }
01327    ast_mutex_unlock(&sub->lock);
01328 
01329    return res;
01330 }
01331 
01332 static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
01333 {
01334    struct mgcp_subchannel *sub = ast->tech_pvt;
01335    struct mgcp_endpoint *p = sub->parent;
01336    int res = 0;
01337    char tmp[4];
01338 
01339    ast_mutex_lock(&sub->lock);
01340    if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
01341       ast_log(LOG_DEBUG, "Stopping DTMF using inband/hybrid\n");
01342       res = -1; /* Tell Asterisk to stop inband indications */
01343    } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
01344       ast_log(LOG_DEBUG, "Stopping DTMF using RFC2833\n");
01345       tmp[0] = 'D';
01346       tmp[1] = '/';
01347       tmp[2] = digit;
01348       tmp[3] = '\0';
01349       transmit_notify_request(sub, tmp);
01350                 ast_rtp_senddigit_end(sub->rtp, digit);
01351    } else {
01352       ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
01353    }
01354    ast_mutex_unlock(&sub->lock);
01355 
01356    return res;
01357 }
01358 
01359 /*!
01360  *  \brief  mgcp_devicestate: channel callback for device status monitoring
01361  *  \param  data tech/resource name of MGCP device to query
01362  *
01363  * Callback for device state management in channel subsystem
01364  * to obtain device status (up/down) of a specific MGCP endpoint
01365  *
01366  *  \return device status result (from devicestate.h) AST_DEVICE_INVALID (not available) or AST_DEVICE_UNKNOWN (available but unknown state)
01367  */
01368 static int mgcp_devicestate(void *data)
01369 {
01370    struct mgcp_gateway  *g;
01371    struct mgcp_endpoint *e = NULL;
01372    char *tmp, *endpt, *gw;
01373    int ret = AST_DEVICE_INVALID;
01374 
01375    endpt = ast_strdupa(data);
01376    if ((tmp = strchr(endpt, '@'))) {
01377       *tmp++ = '\0';
01378       gw = tmp;
01379    } else
01380       goto error;
01381 
01382    ast_mutex_lock(&gatelock);
01383    g = gateways;
01384    while (g) {
01385       if (strcasecmp(g->name, gw) == 0) {
01386          e = g->endpoints;
01387          break;
01388       }
01389       g = g->next;
01390    }
01391 
01392    if (!e)
01393       goto error;
01394 
01395    while (e) {
01396       if (strcasecmp(e->name, endpt) == 0)
01397          break;
01398       e = e->next;
01399    }
01400 
01401    if (!e)
01402       goto error;
01403 
01404    /*
01405     * As long as the gateway/endpoint is valid, we'll
01406     * assume that the device is available and its state
01407     * can be tracked.
01408     */
01409    ret = AST_DEVICE_UNKNOWN;
01410 
01411 error:
01412    ast_mutex_unlock(&gatelock);
01413    return ret;
01414 }
01415 
01416 static char *control2str(int ind) {
01417    switch (ind) {
01418    case AST_CONTROL_HANGUP:
01419       return "Other end has hungup";
01420    case AST_CONTROL_RING:
01421       return "Local ring";
01422    case AST_CONTROL_RINGING:
01423       return "Remote end is ringing";
01424    case AST_CONTROL_ANSWER:
01425       return "Remote end has answered";
01426    case AST_CONTROL_BUSY:
01427       return "Remote end is busy";
01428    case AST_CONTROL_TAKEOFFHOOK:
01429       return "Make it go off hook";
01430    case AST_CONTROL_OFFHOOK:
01431       return "Line is off hook";
01432    case AST_CONTROL_CONGESTION:
01433       return "Congestion (circuits busy)";
01434    case AST_CONTROL_FLASH:
01435       return "Flash hook";
01436    case AST_CONTROL_WINK:
01437       return "Wink";
01438    case AST_CONTROL_OPTION:
01439       return "Set a low-level option";
01440    case AST_CONTROL_RADIO_KEY:
01441       return "Key Radio";
01442    case AST_CONTROL_RADIO_UNKEY:
01443       return "Un-Key Radio";
01444    }
01445    return "UNKNOWN";
01446 }
01447 
01448 static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen)
01449 {
01450    struct mgcp_subchannel *sub = ast->tech_pvt;
01451    int res = 0;
01452 
01453    if (mgcpdebug) {
01454       ast_verb(3, "MGCP asked to indicate %d '%s' condition on channel %s\n",
01455          ind, control2str(ind), ast->name);
01456    }
01457    ast_mutex_lock(&sub->lock);
01458    switch(ind) {
01459    case AST_CONTROL_RINGING:
01460 #ifdef DLINK_BUGGY_FIRMWARE   
01461       transmit_notify_request(sub, "rt");
01462 #else
01463       transmit_notify_request(sub, "G/rt");
01464 #endif      
01465       break;
01466    case AST_CONTROL_BUSY:
01467       transmit_notify_request(sub, "L/bz");
01468       break;
01469    case AST_CONTROL_CONGESTION:
01470       transmit_notify_request(sub, "G/cg");
01471       break;
01472    case AST_CONTROL_HOLD:
01473       ast_moh_start(ast, data, NULL);
01474       break;
01475    case AST_CONTROL_UNHOLD:
01476       ast_moh_stop(ast);
01477       break;
01478    case AST_CONTROL_SRCUPDATE:
01479       ast_rtp_new_source(sub->rtp);
01480       break;
01481    case -1:
01482       transmit_notify_request(sub, "");
01483       break;
01484    default:
01485       ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
01486       res = -1;
01487    }
01488    ast_mutex_unlock(&sub->lock);
01489    return res;
01490 }
01491 
01492 static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state)
01493 {
01494    struct ast_channel *tmp;
01495    struct mgcp_endpoint *i = sub->parent;
01496    int fmt;
01497 
01498    tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id);
01499    if (tmp) {
01500       tmp->tech = &mgcp_tech;
01501       tmp->nativeformats = i->capability;
01502       if (!tmp->nativeformats)
01503          tmp->nativeformats = capability;
01504       fmt = ast_best_codec(tmp->nativeformats);
01505       ast_string_field_build(tmp, name, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id);
01506       if (sub->rtp)
01507          ast_channel_set_fd(tmp, 0, ast_rtp_fd(sub->rtp));
01508       if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) {
01509          i->dsp = ast_dsp_new();
01510          ast_dsp_set_features(i->dsp,DSP_FEATURE_DTMF_DETECT);
01511          /* this is to prevent clipping of dtmf tones during dsp processing */
01512          ast_dsp_digitmode(i->dsp, DSP_DIGITMODE_NOQUELCH);
01513       } else {
01514          i->dsp = NULL;
01515       }
01516       if (state == AST_STATE_RING)
01517          tmp->rings = 1;
01518       tmp->writeformat = fmt;
01519       tmp->rawwriteformat = fmt;
01520       tmp->readformat = fmt;
01521       tmp->rawreadformat = fmt;
01522       tmp->tech_pvt = sub;
01523       if (!ast_strlen_zero(i->language))
01524          ast_string_field_set(tmp, language, i->language);
01525       if (!ast_strlen_zero(i->accountcode))
01526          ast_string_field_set(tmp, accountcode, i->accountcode);
01527       if (i->amaflags)
01528          tmp->amaflags = i->amaflags;
01529       sub->owner = tmp;
01530       ast_module_ref(ast_module_info->self);
01531       tmp->callgroup = i->callgroup;
01532       tmp->pickupgroup = i->pickupgroup;
01533       ast_string_field_set(tmp, call_forward, i->call_forward);
01534       ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
01535       ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
01536 
01537       /* Don't use ast_set_callerid() here because it will
01538        * generate a needless NewCallerID event */
01539       tmp->cid.cid_ani = ast_strdup(i->cid_num);
01540       
01541       if (!i->adsi)
01542          tmp->adsicpe = AST_ADSI_UNAVAILABLE;
01543       tmp->priority = 1;
01544       if (sub->rtp)
01545          ast_jb_configure(tmp, &global_jbconf);
01546       if (state != AST_STATE_DOWN) {
01547          if (ast_pbx_start(tmp)) {
01548             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
01549             ast_hangup(tmp);
01550             tmp = NULL;
01551          }
01552       }
01553       ast_verb(3, "MGCP mgcp_new(%s) created in state: %s\n",
01554             tmp->name, ast_state2str(state));
01555    } else {
01556       ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
01557    }
01558    return tmp;
01559 }
01560 
01561 static char* get_sdp_by_line(char* line, char *name, int nameLen)
01562 {
01563    if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') {
01564       char* r = line + nameLen + 1;
01565       while (*r && (*r < 33)) ++r;
01566       return r;
01567    }
01568    return "";
01569 }
01570 
01571 static char *get_sdp(struct mgcp_request *req, char *name)
01572 {
01573    int x;
01574    int len = strlen(name);
01575    char *r;
01576 
01577    for (x=0; x<req->lines; x++) {
01578       r = get_sdp_by_line(req->line[x], name, len);
01579       if (r[0] != '\0') return r;
01580    }
01581    return "";
01582 }
01583 
01584 static void sdpLineNum_iterator_init(int* iterator)
01585 {
01586    *iterator = 0;
01587 }
01588 
01589 static char* get_sdp_iterate(int* iterator, struct mgcp_request *req, char *name)
01590 {
01591    int len = strlen(name);
01592    char *r;
01593    while (*iterator < req->lines) {
01594       r = get_sdp_by_line(req->line[(*iterator)++], name, len);
01595       if (r[0] != '\0') return r;
01596    }
01597    return "";
01598 }
01599 
01600 static char *__get_header(struct mgcp_request *req, char *name, int *start)
01601 {
01602    int x;
01603    int len = strlen(name);
01604    char *r;
01605    for (x=*start;x<req->headers;x++) {
01606       if (!strncasecmp(req->header[x], name, len) && 
01607           (req->header[x][len] == ':')) {
01608          r = req->header[x] + len + 1;
01609          while(*r && (*r < 33))
01610             r++;
01611          *start = x+1;
01612          return r;
01613       }
01614    }
01615    /* Don't return NULL, so get_header is always a valid pointer */
01616    return "";
01617 }
01618 
01619 static char *get_header(struct mgcp_request *req, char *name)
01620 {
01621    int start = 0;
01622    return __get_header(req, name, &start);
01623 }
01624 
01625 /*! \brief get_csv: (SC:) get comma separated value */
01626 static char *get_csv(char *c, int *len, char **next) 
01627 {
01628    char *s;
01629 
01630    *next = NULL, *len = 0;
01631    if (!c) return NULL;
01632 
01633    while (*c && (*c < 33 || *c == ','))
01634       c++;
01635 
01636    s = c;
01637    while (*c && (*c >= 33 && *c != ','))
01638       c++, (*len)++;
01639    *next = c;
01640 
01641    if (*len == 0)
01642       s = NULL, *next = NULL;
01643 
01644    return s;
01645 }
01646 
01647 static struct mgcp_subchannel *find_subchannel_and_lock(char *name, int msgid, struct sockaddr_in *sin)
01648 {
01649    struct mgcp_endpoint *p = NULL;
01650    struct mgcp_subchannel *sub = NULL;
01651    struct mgcp_gateway *g;
01652    char tmp[256] = "";
01653    char *at = NULL, *c;
01654    int found = 0;
01655    if (name) {
01656       ast_copy_string(tmp, name, sizeof(tmp));
01657       at = strchr(tmp, '@');
01658       if (!at) {
01659          ast_log(LOG_NOTICE, "Endpoint '%s' has no at sign!\n", name);
01660          return NULL;
01661       }
01662       *at++ = '\0';
01663    }
01664    ast_mutex_lock(&gatelock);
01665    if (at && (at[0] == '[')) {
01666       at++;
01667       c = strrchr(at, ']');
01668       if (c)
01669          *c = '\0';
01670    }
01671    g = gateways;
01672    while(g) {
01673       if ((!name || !strcasecmp(g->name, at)) && 
01674           (sin || g->addr.sin_addr.s_addr || g->defaddr.sin_addr.s_addr)) {
01675          /* Found the gateway.  If it's dynamic, save it's address -- now for the endpoint */
01676          if (sin && g->dynamic && name) {
01677             if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
01678                (g->addr.sin_port != sin->sin_port)) {
01679                memcpy(&g->addr, sin, sizeof(g->addr));
01680                if (ast_ouraddrfor(&g->addr.sin_addr, &g->ourip))
01681                   memcpy(&g->ourip, &__ourip, sizeof(g->ourip));
01682                ast_verb(3, "Registered MGCP gateway '%s' at %s port %d\n", g->name, ast_inet_ntoa(g->addr.sin_addr), ntohs(g->addr.sin_port));
01683             }
01684          }
01685          /* not dynamic, check if the name matches */
01686          else if (name) {
01687             if (strcasecmp(g->name, at)) {
01688                g = g->next;
01689                continue;
01690             }
01691          }
01692          /* not dynamic, no name, check if the addr matches */
01693          else if (!name && sin) {
01694             if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
01695                 (g->addr.sin_port != sin->sin_port)) {
01696                g = g->next;
01697                continue;
01698             }
01699          } else {
01700             g = g->next;
01701             continue;
01702          }
01703          /* SC */
01704          p = g->endpoints;
01705          while(p) {
01706             ast_debug(1, "Searching on %s@%s for subchannel\n",
01707                p->name, g->name);
01708             if (msgid) {
01709 #if 0 /* new transport mech */
01710                sub = p->sub;
01711                do {
01712                   ast_debug(1, "Searching on %s@%s-%d for subchannel with lastout: %d\n",
01713                      p->name, g->name, sub->id, msgid);
01714                   if (sub->lastout == msgid) {
01715                      ast_debug(1, "Found subchannel sub%d to handle request %d sub->lastout: %d\n",
01716                         sub->id, msgid, sub->lastout);
01717                      found = 1;
01718                      break;
01719                   }
01720                   sub = sub->next;
01721                } while (sub != p->sub);
01722                if (found) {
01723                   break;
01724                }
01725 #endif
01726                /* SC */
01727                sub = p->sub;
01728                found = 1;
01729                /* SC */
01730                break;
01731             } else if (name && !strcasecmp(p->name, tmp)) {
01732                ast_debug(1, "Coundn't determine subchannel, assuming current master %s@%s-%d\n", 
01733                   p->name, g->name, p->sub->id);
01734                sub = p->sub;
01735                found = 1;
01736                break;
01737             }
01738             p = p->next;
01739          }
01740          if (sub && found) {
01741             ast_mutex_lock(&sub->lock);
01742             break;
01743          }
01744       }
01745       g = g->next;
01746    }
01747    ast_mutex_unlock(&gatelock);
01748    if (!sub) {
01749       if (name) {
01750          if (g)
01751             ast_log(LOG_NOTICE, "Endpoint '%s' not found on gateway '%s'\n", tmp, at);
01752          else
01753             ast_log(LOG_NOTICE, "Gateway '%s' (and thus its endpoint '%s') does not exist\n", at, tmp);
01754       } 
01755    }
01756    return sub;
01757 }
01758 
01759 static void parse(struct mgcp_request *req)
01760 {
01761    /* Divide fields by NULL's */
01762    char *c;
01763    int f = 0;
01764    c = req->data;
01765 
01766    /* First header starts immediately */
01767    req->header[f] = c;
01768    while(*c) {
01769       if (*c == '\n') {
01770          /* We've got a new header */
01771          *c = 0;
01772 #if 0
01773          printf("Header: %s (%d)\n", req->header[f], strlen(req->header[f]));
01774 #endif         
01775          if (ast_strlen_zero(req->header[f])) {
01776             /* Line by itself means we're now in content */
01777             c++;
01778             break;
01779          }
01780          if (f >= MGCP_MAX_HEADERS - 1) {
01781             ast_log(LOG_WARNING, "Too many MGCP headers...\n");
01782          } else
01783             f++;
01784          req->header[f] = c + 1;
01785       } else if (*c == '\r') {
01786          /* Ignore but eliminate \r's */
01787          *c = 0;
01788       }
01789       c++;
01790    }
01791    /* Check for last header */
01792    if (!ast_strlen_zero(req->header[f])) 
01793       f++;
01794    req->headers = f;
01795    /* Now we process any mime content */
01796    f = 0;
01797    req->line[f] = c;
01798    while(*c) {
01799       if (*c == '\n') {
01800          /* We've got a new line */
01801          *c = 0;
01802 #if 0
01803          printf("Line: %s (%d)\n", req->line[f], strlen(req->line[f]));
01804 #endif         
01805          if (f >= MGCP_MAX_LINES - 1) {
01806             ast_log(LOG_WARNING, "Too many SDP lines...\n");
01807          } else
01808             f++;
01809          req->line[f] = c + 1;
01810       } else if (*c == '\r') {
01811          /* Ignore and eliminate \r's */
01812          *c = 0;
01813       }
01814       c++;
01815    }
01816    /* Check for last line */
01817    if (!ast_strlen_zero(req->line[f])) 
01818       f++;
01819    req->lines = f;
01820    /* Parse up the initial header */
01821    c = req->header[0];
01822    while(*c && *c < 33) c++;
01823    /* First the verb */
01824    req->verb = c;
01825    while(*c && (*c > 32)) c++;
01826    if (*c) {
01827       *c = '\0';
01828       c++;
01829       while(*c && (*c < 33)) c++;
01830       req->identifier = c;
01831       while(*c && (*c > 32)) c++;
01832       if (*c) {
01833          *c = '\0';
01834          c++;
01835          while(*c && (*c < 33)) c++;
01836          req->endpoint = c;
01837          while(*c && (*c > 32)) c++;
01838          if (*c) {
01839             *c = '\0';
01840             c++;
01841             while(*c && (*c < 33)) c++;
01842             req->version = c;
01843             while(*c && (*c > 32)) c++;
01844             while(*c && (*c < 33)) c++;
01845             while(*c && (*c > 32)) c++;
01846             *c = '\0';
01847          }
01848       }
01849    }
01850       
01851    if (mgcpdebug) {
01852       ast_verbose("Verb: '%s', Identifier: '%s', Endpoint: '%s', Version: '%s'\n",
01853          req->verb, req->identifier, req->endpoint, req->version);
01854       ast_verbose("%d headers, %d lines\n", req->headers, req->lines);
01855    }
01856    if (*c) 
01857       ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c);
01858 }
01859 
01860 static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req)
01861 {
01862    char *m;
01863    char *c;
01864    char *a;
01865    char host[258];
01866    int len;
01867    int portno;
01868    int peercapability, peerNonCodecCapability;
01869    struct sockaddr_in sin;
01870    char *codecs;
01871    struct ast_hostent ahp; struct hostent *hp;
01872    int codec, codec_count=0;
01873    int iterator;
01874    struct mgcp_endpoint *p = sub->parent;
01875 
01876    /* Get codec and RTP info from SDP */
01877    m = get_sdp(req, "m");
01878    c = get_sdp(req, "c");
01879    if (ast_strlen_zero(m) || ast_strlen_zero(c)) {
01880       ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s', c = '%s')\n", m, c);
01881       return -1;
01882    }
01883    if (sscanf(c, "IN IP4 %256s", host) != 1) {
01884       ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
01885       return -1;
01886    }
01887    /* XXX This could block for a long time, and block the main thread! XXX */
01888    hp = ast_gethostbyname(host, &ahp);
01889    if (!hp) {
01890       ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c);
01891       return -1;
01892    }
01893    if (sscanf(m, "audio %d RTP/AVP %n", &portno, &len) != 1) {
01894       ast_log(LOG_WARNING, "Unable to determine port number for RTP in '%s'\n", m); 
01895       return -1;
01896    }
01897    sin.sin_family = AF_INET;
01898    memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
01899    sin.sin_port = htons(portno);
01900    ast_rtp_set_peer(sub->rtp, &sin);
01901 #if 0
01902    printf("Peer RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
01903 #endif   
01904    /* Scan through the RTP payload types specified in a "m=" line: */
01905    ast_rtp_pt_clear(sub->rtp);
01906    codecs = ast_strdupa(m + len);
01907    while (!ast_strlen_zero(codecs)) {
01908       if (sscanf(codecs, "%d%n", &codec, &len) != 1) {
01909          if (codec_count)
01910             break;
01911          ast_log(LOG_WARNING, "Error in codec string '%s' at '%s'\n", m, codecs);
01912          return -1;
01913       }
01914       ast_rtp_set_m_type(sub->rtp, codec);
01915       codec_count++;
01916       codecs += len;
01917    }
01918 
01919    /* Next, scan through each "a=rtpmap:" line, noting each */
01920    /* specified RTP payload type (with corresponding MIME subtype): */
01921    sdpLineNum_iterator_init(&iterator);
01922    while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
01923       char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
01924       if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2)
01925          continue;
01926       /* Note: should really look at the 'freq' and '#chans' params too */
01927       ast_rtp_set_rtpmap_type(sub->rtp, codec, "audio", mimeSubtype, 0);
01928    }
01929 
01930    /* Now gather all of the codecs that were asked for: */
01931    ast_rtp_get_current_formats(sub->rtp, &peercapability, &peerNonCodecCapability);
01932    p->capability = capability & peercapability;
01933    if (mgcpdebug) {
01934       ast_verbose("Capabilities: us - %d, them - %d, combined - %d\n",
01935          capability, peercapability, p->capability);
01936       ast_verbose("Non-codec capabilities: us - %d, them - %d, combined - %d\n",
01937          nonCodecCapability, peerNonCodecCapability, p->nonCodecCapability);
01938    }
01939    if (!p->capability) {
01940       ast_log(LOG_WARNING, "No compatible codecs!\n");
01941       return -1;
01942    }
01943    return 0;
01944 }
01945 
01946 static int add_header(struct mgcp_request *req, char *var, char *value)
01947 {
01948    if (req->len >= sizeof(req->data) - 4) {
01949       ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
01950       return -1;
01951    }
01952    if (req->lines) {
01953       ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n");
01954       return -1;
01955    }
01956    req->header[req->headers] = req->data + req->len;
01957    snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s: %s\r\n", var, value);
01958    req->len += strlen(req->header[req->headers]);
01959    if (req->headers < MGCP_MAX_HEADERS)
01960       req->headers++;
01961    else {
01962       ast_log(LOG_WARNING, "Out of header space\n");
01963       return -1;
01964    }
01965    return 0;   
01966 }
01967 
01968 static int add_line(struct mgcp_request *req, char *line)
01969 {
01970    if (req->len >= sizeof(req->data) - 4) {
01971       ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
01972       return -1;
01973    }
01974    if (!req->lines) {
01975       /* Add extra empty return */
01976       ast_copy_string(req->data + req->len, "\r\n", sizeof(req->data) - req->len);
01977       req->len += strlen(req->data + req->len);
01978    }
01979    req->line[req->lines] = req->data + req->len;
01980    snprintf(req->line[req->lines], sizeof(req->data) - req->len, "%s", line);
01981    req->len += strlen(req->line[req->lines]);
01982    if (req->lines < MGCP_MAX_LINES)
01983       req->lines++;
01984    else {
01985       ast_log(LOG_WARNING, "Out of line space\n");
01986       return -1;
01987    }
01988    return 0;   
01989 }
01990 
01991 static int init_resp(struct mgcp_request *req, char *resp, struct mgcp_request *orig, char *resprest)
01992 {
01993    /* Initialize a response */
01994    if (req->headers || req->len) {
01995       ast_log(LOG_WARNING, "Request already initialized?!?\n");
01996       return -1;
01997    }
01998    req->header[req->headers] = req->data + req->len;
01999    snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %s %s\r\n", resp, orig->identifier, resprest);
02000    req->len += strlen(req->header[req->headers]);
02001    if (req->headers < MGCP_MAX_HEADERS)
02002       req->headers++;
02003    else
02004       ast_log(LOG_WARNING, "Out of header space\n");
02005    return 0;
02006 }
02007 
02008 static int init_req(struct mgcp_endpoint *p, struct mgcp_request *req, char *verb)
02009 {
02010    /* Initialize a response */
02011    if (req->headers || req->len) {
02012       ast_log(LOG_WARNING, "Request already initialized?!?\n");
02013       return -1;
02014    }
02015    req->header[req->headers] = req->data + req->len;
02016    /* check if we need brackets around the gw name */
02017    if (p->parent->isnamedottedip)
02018       snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@[%s] MGCP 1.0\r\n", verb, oseq, p->name, p->parent->name);
02019    else
02020       snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@%s MGCP 1.0\r\n", verb, oseq, p->name, p->parent->name);
02021    req->len += strlen(req->header[req->headers]);
02022    if (req->headers < MGCP_MAX_HEADERS)
02023       req->headers++;
02024    else
02025       ast_log(LOG_WARNING, "Out of header space\n");
02026    return 0;
02027 }
02028 
02029 
02030 static int respprep(struct mgcp_request *resp, struct mgcp_endpoint *p, char *msg, struct mgcp_request *req, char *msgrest)
02031 {
02032    memset(resp, 0, sizeof(*resp));
02033    init_resp(resp, msg, req, msgrest);
02034    return 0;
02035 }
02036 
02037 static int reqprep(struct mgcp_request *req, struct mgcp_endpoint *p, char *verb)
02038 {
02039    memset(req, 0, sizeof(struct mgcp_request));
02040    oseq++;
02041    if (oseq > 999999999)
02042       oseq = 1;
02043    init_req(p, req, verb);
02044    return 0;
02045 }
02046 
02047 static int transmit_response(struct mgcp_subchannel *sub, char *msg, struct mgcp_request *req, char *msgrest)
02048 {
02049    struct mgcp_request resp;
02050    struct mgcp_endpoint *p = sub->parent;
02051    struct mgcp_response *mgr;
02052 
02053    respprep(&resp, p, msg, req, msgrest);
02054    mgr = ast_calloc(1, sizeof(*mgr) + resp.len + 1);
02055    if (mgr) {
02056       /* Store MGCP response in case we have to retransmit */
02057       sscanf(req->identifier, "%d", &mgr->seqno);
02058       time(&mgr->whensent);
02059       mgr->len = resp.len;
02060       memcpy(mgr->buf, resp.data, resp.len);
02061       mgr->buf[resp.len] = '\0';
02062       mgr->next = p->parent->responses;
02063       p->parent->responses = mgr;
02064    }
02065    return send_response(sub, &resp);
02066 }
02067 
02068 
02069 static int add_sdp(struct mgcp_request *resp, struct mgcp_subchannel *sub, struct ast_rtp *rtp)
02070 {
02071    int len;
02072    int codec;
02073    char costr[80];
02074    struct sockaddr_in sin;
02075    char v[256];
02076    char s[256];
02077    char o[256];
02078    char c[256];
02079    char t[256];
02080    char m[256] = "";
02081    char a[1024] = "";
02082    int x;
02083    struct sockaddr_in dest;
02084    struct mgcp_endpoint *p = sub->parent;
02085    /* XXX We break with the "recommendation" and send our IP, in order that our
02086           peer doesn't have to ast_gethostbyname() us XXX */
02087    len = 0;
02088    if (!sub->rtp) {
02089       ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n");
02090       return -1;
02091    }
02092    ast_rtp_get_us(sub->rtp, &sin);
02093    if (rtp) {
02094       ast_rtp_get_peer(rtp, &dest);
02095    } else {
02096       if (sub->tmpdest.sin_addr.s_addr) {
02097          dest.sin_addr = sub->tmpdest.sin_addr;
02098          dest.sin_port = sub->tmpdest.sin_port;
02099          /* Reset temporary destination */
02100          memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
02101       } else {
02102          dest.sin_addr = p->parent->ourip;
02103          dest.sin_port = sin.sin_port;
02104       }
02105    }
02106    if (mgcpdebug) {
02107       ast_verbose("We're at %s port %d\n", ast_inet_ntoa(p->parent->ourip), ntohs(sin.sin_port));
02108    }
02109    ast_copy_string(v, "v=0\r\n", sizeof(v));
02110    snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", (int)getpid(), (int)getpid(), ast_inet_ntoa(dest.sin_addr));
02111    ast_copy_string(s, "s=session\r\n", sizeof(s));
02112    snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr));
02113    ast_copy_string(t, "t=0 0\r\n", sizeof(t));
02114    snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port));
02115    for (x = 1; x <= AST_FORMAT_AUDIO_MASK; x <<= 1) {
02116       if (p->capability & x) {
02117          if (mgcpdebug) {
02118             ast_verbose("Answering with capability %d\n", x);
02119          }
02120          codec = ast_rtp_lookup_code(sub->rtp, 1, x);
02121          if (codec > -1) {
02122             snprintf(costr, sizeof(costr), " %d", codec);
02123             strncat(m, costr, sizeof(m) - strlen(m) - 1);
02124             snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(1, x, 0));
02125             strncat(a, costr, sizeof(a) - strlen(a) - 1);
02126          }
02127       }
02128    }
02129    for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
02130       if (p->nonCodecCapability & x) {
02131          if (mgcpdebug) {
02132             ast_verbose("Answering with non-codec capability %d\n", x);
02133          }
02134          codec = ast_rtp_lookup_code(sub->rtp, 0, x);
02135          if (codec > -1) {
02136             snprintf(costr, sizeof(costr), " %d", codec);
02137             strncat(m, costr, sizeof(m) - strlen(m) - 1);
02138             snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(0, x, 0));
02139             strncat(a, costr, sizeof(a) - strlen(a) - 1);
02140             if (x == AST_RTP_DTMF) {
02141                /* Indicate we support DTMF...  Not sure about 16,
02142                   but MSN supports it so dang it, we will too... */
02143                snprintf(costr, sizeof costr, "a=fmtp:%d 0-16\r\n", codec);
02144                strncat(a, costr, sizeof(a) - strlen(a) - 1);
02145             }
02146          }
02147       }
02148    }
02149    strncat(m, "\r\n", sizeof(m) - strlen(m) - 1);
02150    len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a);
02151    snprintf(costr, sizeof(costr), "%d", len);
02152    add_line(resp, v);
02153    add_line(resp, o);
02154    add_line(resp, s);
02155    add_line(resp, c);
02156    add_line(resp, t);
02157    add_line(resp, m);
02158    add_line(resp, a);
02159    return 0;
02160 }
02161 
02162 static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp, int codecs)
02163 {
02164    struct mgcp_request resp;
02165    char local[256];
02166    char tmp[80];
02167    int x;
02168    struct mgcp_endpoint *p = sub->parent;
02169 
02170    if (ast_strlen_zero(sub->cxident) && rtp) {
02171       /* We don't have a CXident yet, store the destination and
02172          wait a bit */
02173       ast_rtp_get_peer(rtp, &sub->tmpdest);
02174       return 0;
02175    }
02176    ast_copy_string(local, "p:20", sizeof(local));
02177    for (x = 1; x <= AST_FORMAT_AUDIO_MASK; x <<= 1) {
02178       if (p->capability & x) {
02179          snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0));
02180          strncat(local, tmp, sizeof(local) - strlen(local) - 1);
02181       }
02182    }
02183    reqprep(&resp, p, "MDCX");
02184    add_header(&resp, "C", sub->callid);
02185    add_header(&resp, "L", local);
02186    add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
02187    /* X header should not be sent. kept for compatibility */
02188    add_header(&resp, "X", sub->txident);
02189    add_header(&resp, "I", sub->cxident);
02190    /*add_header(&resp, "S", "");*/
02191    add_sdp(&resp, sub, rtp);
02192    /* fill in new fields */
02193    resp.cmd = MGCP_CMD_MDCX;
02194    resp.trid = oseq;
02195    return send_request(p, sub, &resp, oseq); /* SC */
02196 }
02197 
02198 static int transmit_connect_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp)
02199 {
02200    struct mgcp_request resp;
02201    char local[256];
02202    char tmp[80];
02203    int x;
02204    struct mgcp_endpoint *p = sub->parent;
02205 
02206    ast_copy_string(local, "p:20", sizeof(local));
02207    for (x = 1; x <= AST_FORMAT_AUDIO_MASK; x <<= 1) {
02208       if (p->capability & x) {
02209          snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0));
02210          strncat(local, tmp, sizeof(local) - strlen(local) - 1);
02211       }
02212    }
02213    if (mgcpdebug) {
02214       ast_verb(3, "Creating connection for %s@%s-%d in cxmode: %s callid: %s\n",
02215          p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
02216    }
02217    reqprep(&resp, p, "CRCX");
02218    add_header(&resp, "C", sub->callid);
02219    add_header(&resp, "L", local);
02220    add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
02221    /* X header should not be sent. kept for compatibility */
02222    add_header(&resp, "X", sub->txident);
02223    /*add_header(&resp, "S", "");*/
02224    add_sdp(&resp, sub, rtp);
02225    /* fill in new fields */
02226    resp.cmd = MGCP_CMD_CRCX;
02227    resp.trid = oseq;
02228    return send_request(p, sub, &resp, oseq);  /* SC */
02229 }
02230 
02231 static int transmit_notify_request(struct mgcp_subchannel *sub, char *tone)
02232 {
02233    struct mgcp_request resp;
02234    struct mgcp_endpoint *p = sub->parent;
02235 
02236    if (mgcpdebug) {
02237       ast_verb(3, "MGCP Asked to indicate tone: %s on  %s@%s-%d in cxmode: %s\n",
02238          tone, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]);
02239    }
02240    ast_copy_string(p->curtone, tone, sizeof(p->curtone));
02241    reqprep(&resp, p, "RQNT");
02242    add_header(&resp, "X", p->rqnt_ident); /* SC */
02243    switch (p->hookstate) {
02244    case MGCP_ONHOOK:
02245       add_header(&resp, "R", "L/hd(N)");
02246       break;
02247    case MGCP_OFFHOOK:
02248       add_header_offhook(sub, &resp);
02249       break;
02250    }
02251    if (!ast_strlen_zero(tone)) {
02252       add_header(&resp, "S", tone);
02253    }
02254    /* fill in new fields */
02255    resp.cmd = MGCP_CMD_RQNT;
02256    resp.trid = oseq;
02257    return send_request(p, NULL, &resp, oseq); /* SC */
02258 }
02259 
02260 static int transmit_notify_request_with_callerid(struct mgcp_subchannel *sub, char *tone, char *callernum, char *callername)
02261 {
02262    struct mgcp_request resp;
02263    char tone2[256];
02264    char *l, *n;
02265    struct timeval t = ast_tvnow();
02266    struct ast_tm tm;
02267    struct mgcp_endpoint *p = sub->parent;
02268    
02269    ast_localtime(&t, &tm, NULL);
02270    n = callername;
02271    l = callernum;
02272    if (!n)
02273       n = "";
02274    if (!l)
02275       l = "";
02276 
02277    /* Keep track of last callerid for blacklist and callreturn */
02278    ast_copy_string(p->lastcallerid, l, sizeof(p->lastcallerid));
02279 
02280    snprintf(tone2, sizeof(tone2), "%s,L/ci(%02d/%02d/%02d/%02d,%s,%s)", tone, 
02281       tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, l, n);
02282    ast_copy_string(p->curtone, tone, sizeof(p->curtone));
02283    reqprep(&resp, p, "RQNT");
02284    add_header(&resp, "X", p->rqnt_ident); /* SC */
02285    switch (p->hookstate) {
02286    case MGCP_ONHOOK:
02287       add_header(&resp, "R", "L/hd(N)");
02288       break;
02289    case MGCP_OFFHOOK:
02290       add_header_offhook(sub, &resp);
02291       break;
02292    }
02293    if (!ast_strlen_zero(tone2)) {
02294       add_header(&resp, "S", tone2);
02295    }
02296    if (mgcpdebug) {
02297       ast_verb(3, "MGCP Asked to indicate tone: %s on  %s@%s-%d in cxmode: %s\n",
02298          tone2, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]);
02299    }
02300    /* fill in new fields */
02301    resp.cmd = MGCP_CMD_RQNT;
02302    resp.trid = oseq;
02303    return send_request(p, NULL, &resp, oseq);  /* SC */
02304 }
02305 
02306 static int transmit_modify_request(struct mgcp_subchannel *sub)
02307 {
02308    struct mgcp_request resp;
02309    struct mgcp_endpoint *p = sub->parent;
02310 
02311    if (ast_strlen_zero(sub->cxident)) {
02312       /* We don't have a CXident yet, store the destination and
02313          wait a bit */
02314       return 0;
02315    }
02316    if (mgcpdebug) {
02317       ast_verb(3, "Modified %s@%s-%d with new mode: %s on callid: %s\n",
02318          p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
02319    }
02320    reqprep(&resp, p, "MDCX");
02321    add_header(&resp, "C", sub->callid);
02322    add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
02323    /* X header should not be sent. kept for compatibility */
02324    add_header(&resp, "X", sub->txident);
02325    add_header(&resp, "I", sub->cxident);
02326    switch (sub->parent->hookstate) {
02327    case MGCP_ONHOOK:
02328       add_header(&resp, "R", "L/hd(N)");
02329       break;
02330    case MGCP_OFFHOOK:
02331       add_header_offhook(sub, &resp);
02332       break;
02333    }
02334    /* fill in new fields */
02335    resp.cmd = MGCP_CMD_MDCX;
02336    resp.trid = oseq;
02337    return send_request(p, sub, &resp, oseq); /* SC */
02338 }
02339 
02340 
02341 static void add_header_offhook(struct mgcp_subchannel *sub, struct mgcp_request *resp)
02342 {
02343    struct mgcp_endpoint *p = sub->parent;
02344 
02345    if (p && p->sub && p->sub->owner && p->sub->owner->_state >= AST_STATE_RINGING && (p->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)))
02346       add_header(resp, "R", "L/hu(N),L/hf(N)");
02347    else
02348       add_header(resp, "R", "L/hu(N),L/hf(N),D/[0-9#*](N)");
02349 }
02350 
02351 static int transmit_audit_endpoint(struct mgcp_endpoint *p)
02352 {
02353    struct mgcp_request resp;
02354    reqprep(&resp, p, "AUEP");
02355    /* removed unknown param VS */
02356    /*add_header(&resp, "F", "A,R,D,S,X,N,I,T,O,ES,E,MD,M");*/
02357    add_header(&resp, "F", "A");
02358    /* fill in new fields */
02359    resp.cmd = MGCP_CMD_AUEP;
02360    resp.trid = oseq;
02361    return send_request(p, NULL, &resp, oseq);  /* SC */
02362 }
02363 
02364 static int transmit_connection_del(struct mgcp_subchannel *sub)
02365 {
02366    struct mgcp_endpoint *p = sub->parent;
02367    struct mgcp_request resp;
02368 
02369    if (mgcpdebug) {
02370       ast_verb(3, "Delete connection %s %s@%s-%d with new mode: %s on callid: %s\n",
02371          sub->cxident, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
02372    }
02373    reqprep(&resp, p, "DLCX");
02374    /* check if call id is avail */
02375    if (sub->callid[0])
02376       add_header(&resp, "C", sub->callid);
02377    /* X header should not be sent. kept for compatibility */
02378    add_header(&resp, "X", sub->txident);
02379    /* check if cxident is avail */
02380    if (sub->cxident[0])
02381       add_header(&resp, "I", sub->cxident);
02382    /* fill in new fields */
02383    resp.cmd = MGCP_CMD_DLCX;
02384    resp.trid = oseq;
02385    return send_request(p, sub, &resp, oseq);  /* SC */
02386 }
02387 
02388 static int transmit_connection_del_w_params(struct mgcp_endpoint *p, char *callid, char *cxident)
02389 {
02390    struct mgcp_request resp;
02391 
02392    if (mgcpdebug) {
02393       ast_verb(3, "Delete connection %s %s@%s on callid: %s\n",
02394          cxident ? cxident : "", p->name, p->parent->name, callid ? callid : "");
02395    }
02396    reqprep(&resp, p, "DLCX");
02397    /* check if call id is avail */
02398    if (callid && *callid)
02399       add_header(&resp, "C", callid);
02400    /* check if cxident is avail */
02401    if (cxident && *cxident)
02402       add_header(&resp, "I", cxident);
02403    /* fill in new fields */
02404    resp.cmd = MGCP_CMD_DLCX;
02405    resp.trid = oseq;
02406    return send_request(p, p->sub, &resp, oseq);
02407 }
02408 
02409 /*! \brief  dump_cmd_queues: (SC:) cleanup pending commands */
02410 static void dump_cmd_queues(struct mgcp_endpoint *p, struct mgcp_subchannel *sub) 
02411 {
02412    struct mgcp_request *t, *q;
02413 
02414    if (p) {
02415       ast_mutex_lock(&p->rqnt_queue_lock);
02416       for (q = p->rqnt_queue; q; t = q->next, ast_free(q), q=t);
02417       p->rqnt_queue = NULL;
02418       ast_mutex_unlock(&p->rqnt_queue_lock);
02419 
02420       ast_mutex_lock(&p->cmd_queue_lock);
02421       for (q = p->cmd_queue; q; t = q->next, ast_free(q), q=t);
02422       p->cmd_queue = NULL;
02423       ast_mutex_unlock(&p->cmd_queue_lock);
02424 
02425       ast_mutex_lock(&p->sub->cx_queue_lock);
02426       for (q = p->sub->cx_queue; q; t = q->next, ast_free(q), q=t);
02427       p->sub->cx_queue = NULL;
02428       ast_mutex_unlock(&p->sub->cx_queue_lock);
02429 
02430       ast_mutex_lock(&p->sub->next->cx_queue_lock);
02431       for (q = p->sub->next->cx_queue; q; t = q->next, ast_free(q), q=t);
02432       p->sub->next->cx_queue = NULL;
02433       ast_mutex_unlock(&p->sub->next->cx_queue_lock);
02434    } else if (sub) {
02435       ast_mutex_lock(&sub->cx_queue_lock);
02436       for (q = sub->cx_queue; q; t = q->next, ast_free(q), q=t);
02437       sub->cx_queue = NULL;
02438       ast_mutex_unlock(&sub->cx_queue_lock);
02439    }
02440 }
02441 
02442 
02443 /*! \brief  find_command: (SC:) remove command transaction from queue */
02444 static struct mgcp_request *find_command(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,
02445                                          struct mgcp_request **queue, ast_mutex_t *l, int ident)
02446 {
02447    struct mgcp_request *prev, *req;
02448 
02449    ast_mutex_lock(l);
02450    for (prev = NULL, req = *queue; req; prev = req, req = req->next) {
02451       if (req->trid == ident) {
02452          /* remove from queue */
02453          if (!prev)
02454             *queue = req->next;
02455          else
02456             prev->next = req->next;
02457 
02458          /* send next pending command */
02459          if (*queue) {
02460             if (mgcpdebug) {
02461                ast_verbose("Posting Queued Request:\n%s to %s:%d\n", (*queue)->data, 
02462                   ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
02463             }
02464 
02465             mgcp_postrequest(p, sub, (*queue)->data, (*queue)->len, (*queue)->trid);
02466          }
02467          break;
02468       }
02469    }
02470    ast_mutex_unlock(l);
02471    return req;
02472 }
02473 
02474 /* modified for new transport mechanism */
02475 static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,  
02476                             int result, unsigned int ident, struct mgcp_request *resp)
02477 {
02478    char *c;
02479    struct mgcp_request *req;
02480    struct mgcp_gateway *gw = p->parent;
02481 
02482    if (result < 200) {
02483       /* provisional response */
02484       return;
02485    }
02486 
02487    if (p->slowsequence) 
02488       req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident);
02489    else if (sub)
02490       req = find_command(p, sub, &sub->cx_queue, &sub->cx_queue_lock, ident);
02491    else if (!(req = find_command(p, sub, &p->rqnt_queue, &p->rqnt_queue_lock, ident)))
02492       req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident);
02493 
02494    if (!req) {
02495       ast_verb(3, "No command found on [%s] for transaction %d. Ignoring...\n",
02496             gw->name, ident);
02497       return;
02498    }
02499 
02500    if (p && (result >= 400) && (result <= 599)) {
02501       switch (result) {
02502       case 401:
02503          p->hookstate = MGCP_OFFHOOK;
02504          break;
02505       case 402:
02506          p->hookstate = MGCP_ONHOOK;
02507          break;
02508       case 406:
02509          ast_log(LOG_NOTICE, "Transaction %d timed out\n", ident);
02510          break;
02511       case 407:
02512          ast_log(LOG_NOTICE, "Transaction %d aborted\n", ident);
02513          break;
02514       }
02515       if (sub) {
02516          if (sub->owner) {
02517             ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n", 
02518                result, p->name, p->parent->name, sub ? sub->id:-1);
02519             mgcp_queue_hangup(sub);
02520          }
02521       } else {
02522          if (p->sub->next->owner) {
02523             ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n", 
02524                result, p->name, p->parent->name, sub ? sub->id:-1);
02525             mgcp_queue_hangup(p->sub);
02526          }
02527 
02528          if (p->sub->owner) {
02529             ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n", 
02530                result, p->name, p->parent->name, sub ? sub->id:-1);
02531             mgcp_queue_hangup(p->sub);
02532          }
02533 
02534          dump_cmd_queues(p, NULL);
02535       }
02536    }
02537 
02538    if (resp) {
02539       if (req->cmd == MGCP_CMD_CRCX) {
02540          if ((c = get_header(resp, "I"))) {
02541             if (!ast_strlen_zero(c) && sub) {
02542                /* if we are hanging up do not process this conn. */
02543                if (sub->owner) {
02544                   if (!ast_strlen_zero(sub->cxident)) {
02545                      if (strcasecmp(c, sub->cxident)) {
02546                         ast_log(LOG_WARNING, "Subchannel already has a cxident. sub->cxident: %s requested %s\n", sub->cxident, c);
02547                      }
02548                   }
02549                   ast_copy_string(sub->cxident, c, sizeof(sub->cxident));
02550                   if (sub->tmpdest.sin_addr.s_addr) {
02551                      transmit_modify_with_sdp(sub, NULL, 0);
02552                   }
02553                } else {
02554                   /* XXX delete this one
02555                      callid and conn id may already be lost. 
02556                      so the following del conn may have a side effect of 
02557                      cleaning up the next subchannel */
02558                   transmit_connection_del(sub);
02559                }
02560             }
02561          }
02562       }
02563 
02564       if (req->cmd == MGCP_CMD_AUEP) {
02565          /* check stale connection ids */
02566          if ((c = get_header(resp, "I"))) {
02567             char *v, *n;
02568             int len;
02569             while ((v = get_csv(c, &len, &n))) {
02570                if (len) {
02571                   if (strncasecmp(v, p->sub->cxident, len) &&
02572                       strncasecmp(v, p->sub->next->cxident, len)) {
02573                      /* connection id not found. delete it */
02574                      char cxident[80] = "";
02575 
02576                      if (len > (sizeof(cxident) - 1))
02577                         len = sizeof(cxident) - 1;
02578                      ast_copy_string(cxident, v, len);
02579                      ast_verb(3, "Non existing connection id %s on %s@%s \n",
02580                                cxident, p->name, gw->name);
02581                      transmit_connection_del_w_params(p, NULL, cxident);
02582                   }
02583                }
02584                c = n;
02585             }
02586          }
02587 
02588          /* Try to determine the hookstate returned from an audit endpoint command */
02589          if ((c = get_header(resp, "ES"))) {
02590             if (!ast_strlen_zero(c)) {
02591                if (strstr(c, "hu")) {
02592                   if (p->hookstate != MGCP_ONHOOK) {
02593                      /* XXX cleanup if we think we are offhook XXX */
02594                      if ((p->sub->owner || p->sub->next->owner ) && 
02595                          p->hookstate == MGCP_OFFHOOK)
02596                         mgcp_queue_hangup(sub);
02597                      p->hookstate = MGCP_ONHOOK;
02598 
02599                      /* update the requested events according to the new hookstate */
02600                      transmit_notify_request(p->sub, "");
02601 
02602                      ast_verb(3, "Setting hookstate of %s@%s to ONHOOK\n", p->name, gw->name);
02603                      }
02604                } else if (strstr(c, "hd")) {
02605                   if (p->hookstate != MGCP_OFFHOOK) {
02606                      p->hookstate = MGCP_OFFHOOK;
02607 
02608                      /* update the requested events according to the new hookstate */
02609                      transmit_notify_request(p->sub, "");
02610 
02611                      ast_verb(3, "Setting hookstate of %s@%s to OFFHOOK\n", p->name, gw->name);
02612                      }
02613                   }
02614                }
02615             }
02616          }
02617 
02618       if (resp && resp->lines) {
02619          /* do not process sdp if we are hanging up. this may be a late response */
02620          if (sub && sub->owner) {
02621             if (!sub->rtp)
02622                start_rtp(sub);
02623             if (sub->rtp)
02624                process_sdp(sub, resp);
02625          }
02626       }
02627    }
02628 
02629    ast_free(req);
02630 }
02631 
02632 static void start_rtp(struct mgcp_subchannel *sub)
02633 {
02634    ast_mutex_lock(&sub->lock);
02635    /* check again to be on the safe side */
02636    if (sub->rtp) {
02637       ast_rtp_destroy(sub->rtp);
02638       sub->rtp = NULL;
02639    }
02640    /* Allocate the RTP now */
02641    sub->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
02642    if (sub->rtp && sub->owner)
02643       ast_channel_set_fd(sub->owner, 0, ast_rtp_fd(sub->rtp));
02644    if (sub->rtp) {
02645       ast_rtp_setqos(sub->rtp, tos_audio, cos_audio, "MGCP RTP");
02646       ast_rtp_setnat(sub->rtp, sub->nat);
02647    }
02648 #if 0
02649    ast_rtp_set_callback(p->rtp, rtpready);
02650    ast_rtp_set_data(p->rtp, p);
02651 #endif      
02652    /* Make a call*ID */
02653         snprintf(sub->callid, sizeof(sub->callid), "%08lx%s", ast_random(), sub->txident);
02654    /* Transmit the connection create */
02655    transmit_connect_with_sdp(sub, NULL);
02656    ast_mutex_unlock(&sub->lock);
02657 }
02658 
02659 static void *mgcp_ss(void *data)
02660 {
02661    struct ast_channel *chan = data;
02662    struct mgcp_subchannel *sub = chan->tech_pvt;
02663    struct mgcp_endpoint *p = sub->parent;
02664    /* char exten[AST_MAX_EXTENSION] = ""; */
02665    int len = 0;
02666    int timeout = firstdigittimeout;
02667    int res= 0;
02668    int getforward = 0;
02669    int loop_pause = 100;
02670 
02671    len = strlen(p->dtmf_buf);
02672 
02673    while(len < AST_MAX_EXTENSION-1) {
02674       res = 1;  /* Assume that we will get a digit */
02675       while (strlen(p->dtmf_buf) == len){
02676          ast_safe_sleep(chan, loop_pause);
02677          timeout -= loop_pause;
02678          if (timeout <= 0){
02679             res = 0;
02680             break;
02681          }
02682          res = 1;
02683       }
02684 
02685       timeout = 0;
02686       len = strlen(p->dtmf_buf);
02687 
02688       if (!ast_ignore_pattern(chan->context, p->dtmf_buf)) {
02689          /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
02690          ast_indicate(chan, -1);
02691       } else {
02692          /* XXX Redundant?  We should already be playing dialtone */
02693          /*tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALTONE);*/
02694          transmit_notify_request(sub, "L/dl");
02695       }
02696       if (ast_exists_extension(chan, chan->context, p->dtmf_buf, 1, p->cid_num)) {
02697          if (!res || !ast_matchmore_extension(chan, chan->context, p->dtmf_buf, 1, p->cid_num)) {
02698             if (getforward) {
02699                /* Record this as the forwarding extension */
02700                ast_copy_string(p->call_forward, p->dtmf_buf, sizeof(p->call_forward)); 
02701                ast_verb(3, "Setting call forward to '%s' on channel %s\n",
02702                      p->call_forward, chan->name);
02703                /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02704                transmit_notify_request(sub, "L/sl");
02705                if (res)
02706                   break;
02707                usleep(500000);
02708                /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
02709                ast_indicate(chan, -1);
02710                sleep(1);
02711                memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02712                /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALTONE);*/
02713                transmit_notify_request(sub, "L/dl");
02714                len = 0;
02715                getforward = 0;
02716             } else {
02717                /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
02718                ast_indicate(chan, -1);
02719                ast_copy_string(chan->exten, p->dtmf_buf, sizeof(chan->exten));
02720                memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02721                ast_set_callerid(chan,
02722                   p->hidecallerid ? "" : p->cid_num,
02723                   p->hidecallerid ? "" : p->cid_name,
02724                   chan->cid.cid_ani ? NULL : p->cid_num);
02725                ast_setstate(chan, AST_STATE_RING);
02726                /*dahdi_enable_ec(p);*/
02727                if (p->dtmfmode & MGCP_DTMF_HYBRID) {
02728                   p->dtmfmode |= MGCP_DTMF_INBAND;
02729                   ast_indicate(chan, -1);
02730                }
02731                res = ast_pbx_run(chan);
02732                if (res) {
02733                   ast_log(LOG_WARNING, "PBX exited non-zero\n");
02734                   /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
02735                   /*transmit_notify_request(p, "nbz", 1);*/
02736                   transmit_notify_request(sub, "G/cg");
02737                }
02738                return NULL;
02739             }
02740          } else {
02741             /* It's a match, but they just typed a digit, and there is an ambiguous match,
02742                so just set the timeout to matchdigittimeout and wait some more */
02743             timeout = matchdigittimeout;
02744          }
02745       } else if (res == 0) {
02746          ast_debug(1, "not enough digits (and no ambiguous match)...\n");
02747          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
02748          transmit_notify_request(sub, "G/cg");
02749          /*dahdi_wait_event(p->subs[index].zfd);*/
02750          ast_hangup(chan);
02751          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02752          return NULL;
02753       } else if (p->hascallwaiting && p->callwaiting && !strcmp(p->dtmf_buf, "*70")) {
02754          ast_verb(3, "Disabling call waiting on %s\n", chan->name);
02755          /* Disable call waiting if enabled */
02756          p->callwaiting = 0;
02757          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02758          transmit_notify_request(sub, "L/sl");
02759          len = 0;
02760          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02761          timeout = firstdigittimeout;
02762       } else if (!strcmp(p->dtmf_buf,ast_pickup_ext())) {
02763          /* Scan all channels and see if any there
02764           * ringing channqels with that have call groups
02765           * that equal this channels pickup group  
02766           */
02767          if (ast_pickup_call(chan)) {
02768             ast_log(LOG_WARNING, "No call pickup possible...\n");
02769             /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
02770             transmit_notify_request(sub, "G/cg");
02771          }
02772          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02773          ast_hangup(chan);
02774          return NULL;
02775       } else if (!p->hidecallerid && !strcmp(p->dtmf_buf, "*67")) {
02776          ast_verb(3, "Disabling Caller*ID on %s\n", chan->name);
02777          /* Disable Caller*ID if enabled */
02778          p->hidecallerid = 1;
02779          ast_set_callerid(chan, "", "", NULL);
02780          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02781          transmit_notify_request(sub, "L/sl");
02782          len = 0;
02783          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02784          timeout = firstdigittimeout;
02785       } else if (p->callreturn && !strcmp(p->dtmf_buf, "*69")) {
02786          res = 0;
02787          if (!ast_strlen_zero(p->lastcallerid)) {
02788             res = ast_say_digit_str(chan, p->lastcallerid, "", chan->language);
02789          }
02790          if (!res)
02791             /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02792             transmit_notify_request(sub, "L/sl");
02793          break;
02794       } else if (!strcmp(p->dtmf_buf, "*78")) {
02795          /* Do not disturb */
02796          ast_verb(3, "Enabled DND on channel %s\n", chan->name);
02797          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02798          transmit_notify_request(sub, "L/sl");
02799          p->dnd = 1;
02800          getforward = 0;
02801          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02802          len = 0;
02803       } else if (!strcmp(p->dtmf_buf, "*79")) {
02804          /* Do not disturb */
02805          ast_verb(3, "Disabled DND on channel %s\n", chan->name);
02806          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02807          transmit_notify_request(sub, "L/sl");
02808          p->dnd = 0;
02809          getforward = 0;
02810          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02811          len = 0;
02812       } else if (p->cancallforward && !strcmp(p->dtmf_buf, "*72")) {
02813          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02814          transmit_notify_request(sub, "L/sl");
02815          getforward = 1;
02816          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02817          len = 0;
02818       } else if (p->cancallforward && !strcmp(p->dtmf_buf, "*73")) {
02819          ast_verb(3, "Cancelling call forwarding on channel %s\n", chan->name);
02820          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02821          transmit_notify_request(sub, "L/sl");
02822          memset(p->call_forward, 0, sizeof(p->call_forward));
02823          getforward = 0;
02824          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02825          len = 0;
02826       } else if (!strcmp(p->dtmf_buf, ast_parking_ext()) && 
02827          sub->next->owner && ast_bridged_channel(sub->next->owner)) {
02828          /* This is a three way call, the main call being a real channel, 
02829             and we're parking the first call. */
02830          ast_masq_park_call(ast_bridged_channel(sub->next->owner), chan, 0, NULL);
02831          ast_verb(3, "Parking call to '%s'\n", chan->name);
02832          break;
02833       } else if (!ast_strlen_zero(p->lastcallerid) && !strcmp(p->dtmf_buf, "*60")) {
02834          ast_verb(3, "Blacklisting number %s\n", p->lastcallerid);
02835          res = ast_db_put("blacklist", p->lastcallerid, "1");
02836          if (!res) {
02837             /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02838             transmit_notify_request(sub, "L/sl");
02839             memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02840             len = 0;
02841          }
02842       } else if (p->hidecallerid && !strcmp(p->dtmf_buf, "*82")) {
02843          ast_verb(3, "Enabling Caller*ID on %s\n", chan->name);
02844          /* Enable Caller*ID if enabled */
02845          p->hidecallerid = 0;
02846          ast_set_callerid(chan, p->cid_num, p->cid_name, NULL);
02847          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02848          transmit_notify_request(sub, "L/sl");
02849          len = 0;
02850          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02851          timeout = firstdigittimeout;
02852       } else if (!ast_canmatch_extension(chan, chan->context, p->dtmf_buf, 1, chan->cid.cid_num) &&
02853             ((p->dtmf_buf[0] != '*') || (strlen(p->dtmf_buf) > 2))) {
02854          ast_debug(1, "Can't match %s from '%s' in context %s\n", p->dtmf_buf, chan->cid.cid_num ? chan->cid.cid_num : "<Unknown Caller>", chan->context);
02855          break;
02856       }
02857       if (!timeout)
02858          timeout = gendigittimeout;
02859       if (len && !ast_ignore_pattern(chan->context, p->dtmf_buf))
02860          /*tone_zone_play_tone(p->subs[index].zfd, -1);*/
02861          ast_indicate(chan, -1);
02862    }
02863 #if 0
02864    for (;;) {
02865       res = ast_waitfordigit(chan, to);
02866       if (!res) {
02867          ast_debug(1, "Timeout...\n");
02868          break;
02869       }
02870       if (res < 0) {
02871          ast_debug(1, "Got hangup...\n");
02872          ast_hangup(chan);
02873          break;
02874       }
02875       exten[pos++] = res;
02876       if (!ast_ignore_pattern(chan->context, exten))
02877          ast_indicate(chan, -1);
02878       if (ast_matchmore_extension(chan, chan->context, exten, 1, chan->callerid)) {
02879          if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid)) 
02880             to = 3000;
02881          else
02882             to = 8000;
02883       } else
02884          break;
02885    }
02886    if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid)) {
02887       ast_copy_string(chan->exten, exten, sizeof(chan->exten)1);
02888       if (!p->rtp) {
02889          start_rtp(p);
02890       }
02891       ast_setstate(chan, AST_STATE_RING);
02892       chan->rings = 1;
02893       if (ast_pbx_run(chan)) {
02894          ast_log(LOG_WARNING, "Unable to launch PBX on %s\n", chan->name);
02895       } else {
02896          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02897          return NULL;
02898       }
02899    }
02900 #endif
02901    ast_hangup(chan);
02902    memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02903    return NULL;
02904 }
02905 
02906 static int attempt_transfer(struct mgcp_endpoint *p)
02907 {
02908    /* *************************
02909     * I hope this works.
02910     * Copied out of chan_zap
02911     * Cross your fingers
02912     * *************************/
02913 
02914    /* In order to transfer, we need at least one of the channels to
02915       actually be in a call bridge.  We can't conference two applications
02916       together (but then, why would we want to?) */
02917    if (ast_bridged_channel(p->sub->owner)) {
02918       /* The three-way person we're about to transfer to could still be in MOH, so
02919          stop if now if appropriate */
02920       if (ast_bridged_channel(p->sub->next->owner))
02921          ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
02922       if (p->sub->owner->_state == AST_STATE_RINGING) {
02923          ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
02924       }
02925       if (ast_channel_masquerade(p->sub->next->owner, ast_bridged_channel(p->sub->owner))) {
02926          ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
02927             ast_bridged_channel(p->sub->owner)->name, p->sub->next->owner->name);
02928          return -1;
02929       }
02930       /* Orphan the channel */
02931       unalloc_sub(p->sub->next);
02932    } else if (ast_bridged_channel(p->sub->next->owner)) {
02933       if (p->sub->owner->_state == AST_STATE_RINGING) {
02934          ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
02935       }
02936       ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
02937       if (ast_channel_masquerade(p->sub->owner, ast_bridged_channel(p->sub->next->owner))) {
02938          ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
02939             ast_bridged_channel(p->sub->next->owner)->name, p->sub->owner->name);
02940          return -1;
02941       }
02942       /*swap_subs(p, SUB_THREEWAY, SUB_REAL);*/
02943       ast_verb(3, "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name);
02944       p->sub = p->sub->next;
02945       unalloc_sub(p->sub->next);
02946       /* Tell the caller not to hangup */
02947       return 1;
02948    } else {
02949       ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
02950          p->sub->owner->name, p->sub->next->owner->name);
02951       p->sub->next->owner->_softhangup |= AST_SOFTHANGUP_DEV;
02952       if (p->sub->next->owner) {
02953          p->sub->next->alreadygone = 1;
02954          mgcp_queue_hangup(p->sub->next);
02955       }
02956    }
02957    return 0;
02958 }
02959 
02960 static void handle_hd_hf(struct mgcp_subchannel *sub, char *ev) 
02961 {
02962    struct mgcp_endpoint *p = sub->parent;
02963    struct ast_channel *c;
02964    pthread_t t;
02965 
02966    /* Off hook / answer */
02967    if (sub->outgoing) {
02968       /* Answered */
02969       if (sub->owner) {
02970          if (ast_bridged_channel(sub->owner))
02971             ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
02972          sub->cxmode = MGCP_CX_SENDRECV;
02973          if (!sub->rtp) {
02974             start_rtp(sub);
02975          } else {
02976             transmit_modify_request(sub);
02977          }
02978          /*transmit_notify_request(sub, "aw");*/
02979          transmit_notify_request(sub, "");
02980          mgcp_queue_control(sub, AST_CONTROL_ANSWER);
02981       }
02982    } else {
02983       /* Start switch */
02984       /*sub->cxmode = MGCP_CX_SENDRECV;*/
02985       if (!sub->owner) {
02986          if (!sub->rtp) {
02987             start_rtp(sub);
02988          } else {
02989             transmit_modify_request(sub);
02990          }
02991          if (p->immediate) {
02992             /* The channel is immediately up. Start right away */
02993 #ifdef DLINK_BUGGY_FIRMWARE   
02994             transmit_notify_request(sub, "rt");
02995 #else
02996             transmit_notify_request(sub, "G/rt");
02997 #endif      
02998             c = mgcp_new(sub, AST_STATE_RING);
02999             if (!c) {
03000                ast_log(LOG_WARNING, "Unable to start PBX on channel %s@%s\n", p->name, p->parent->name);
03001                transmit_notify_request(sub, "G/cg");
03002                ast_hangup(c);
03003             }
03004          } else {
03005             if (has_voicemail(p)) {
03006                transmit_notify_request(sub, "L/sl");
03007             } else {
03008                transmit_notify_request(sub, "L/dl");
03009             }
03010             c = mgcp_new(sub, AST_STATE_DOWN);
03011             if (c) {
03012                if (ast_pthread_create_detached(&t, NULL, mgcp_ss, c)) {
03013                   ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
03014                   ast_hangup(c);
03015                }
03016             } else {
03017                ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", p->name, p->parent->name);
03018             }
03019          }
03020       } else {
03021          if (p->hookstate == MGCP_OFFHOOK) {
03022             ast_log(LOG_WARNING, "Off hook, but already have owner on %s@%s\n", p->name, p->parent->name);
03023          } else {
03024             ast_log(LOG_WARNING, "On hook, but already have owner on %s@%s\n", p->name, p->parent->name);
03025             ast_log(LOG_WARNING, "If we're onhook why are we here trying to handle a hd or hf?\n");
03026          }
03027          if (ast_bridged_channel(sub->owner))
03028             ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
03029          sub->cxmode = MGCP_CX_SENDRECV;
03030          if (!sub->rtp) {
03031             start_rtp(sub);
03032          } else {
03033             transmit_modify_request(sub);
03034          }
03035          /*transmit_notify_request(sub, "aw");*/
03036          transmit_notify_request(sub, "");
03037          /*ast_queue_control(sub->owner, AST_CONTROL_ANSWER);*/
03038       }
03039    }
03040 }
03041 
03042 static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req, struct sockaddr_in *sin)
03043 {
03044    char *ev, *s;
03045    struct ast_frame f = { 0, };
03046    struct mgcp_endpoint *p = sub->parent;
03047    struct mgcp_gateway *g = NULL;
03048    int res;
03049 
03050    if (mgcpdebug) {
03051       ast_verbose("Handling request '%s' on %s@%s\n", req->verb, p->name, p->parent->name);
03052    }
03053    /* Clear out potential response */
03054    if (!strcasecmp(req->verb, "RSIP")) {
03055       /* Test if this RSIP request is just a keepalive */
03056       if(!strcasecmp( get_header(req, "RM"), "X-keepalive")) {
03057          ast_verb(3, "Received keepalive request from %s@%s\n", p->name, p->parent->name);
03058          transmit_response(sub, "200", req, "OK");
03059       } else {
03060          dump_queue(p->parent, p);
03061          dump_cmd_queues(p, NULL);
03062          
03063          if ((strcmp(p->name, p->parent->wcardep) != 0)) {
03064             ast_verb(3, "Resetting interface %s@%s\n", p->name, p->parent->name);
03065          }
03066          /* For RSIP on wildcard we reset all endpoints */
03067          if (!strcmp(p->name, p->parent->wcardep)) {
03068             /* Reset all endpoints */
03069             struct mgcp_endpoint *tmp_ep;
03070             
03071             g = p->parent;
03072             tmp_ep = g->endpoints;
03073             while (tmp_ep) {
03074                /*if ((strcmp(tmp_ep->name, "*") != 0) && (strcmp(tmp_ep->name, "aaln/" "*") != 0)) {*/
03075                if (strcmp(tmp_ep->name, g->wcardep) != 0) {
03076                   struct mgcp_subchannel *tmp_sub, *first_sub;
03077                   ast_verb(3, "Resetting interface %s@%s\n", tmp_ep->name, p->parent->name);
03078                   
03079                   first_sub = tmp_ep->sub;
03080                   tmp_sub = tmp_ep->sub;
03081                   while (tmp_sub) {
03082                      mgcp_queue_hangup(tmp_sub);
03083                      tmp_sub = tmp_sub->next;
03084                      if (tmp_sub == first_sub)
03085                         break;
03086                   }
03087                }
03088                tmp_ep = tmp_ep->next;
03089             }
03090          } else if (sub->owner) {
03091             mgcp_queue_hangup(sub);
03092          }
03093          transmit_response(sub, "200", req, "OK");
03094          /* We dont send NTFY or AUEP to wildcard ep */
03095          if (strcmp(p->name, p->parent->wcardep) != 0) {
03096             transmit_notify_request(sub, "");
03097             /* Audit endpoint. 
03098              Idea is to prevent lost lines due to race conditions 
03099             */
03100             transmit_audit_endpoint(p);
03101          }
03102       }
03103    } else if (!strcasecmp(req->verb, "NTFY")) {
03104       /* Acknowledge and be sure we keep looking for the same things */
03105       transmit_response(sub, "200", req, "OK");
03106       /* Notified of an event */
03107       ev = get_header(req, "O");
03108       s = strchr(ev, '/');
03109       if (s) ev = s + 1;
03110       ast_debug(1, "Endpoint '%s@%s-%d' observed '%s'\n", p->name, p->parent->name, sub->id, ev);
03111       /* Keep looking for events unless this was a hangup */
03112       if (strcasecmp(ev, "hu") && strcasecmp(ev, "hd") && strcasecmp(ev, "ping")) {
03113          transmit_notify_request(sub, p->curtone);
03114       }
03115       if (!strcasecmp(ev, "hd")) {
03116          p->hookstate = MGCP_OFFHOOK;
03117          sub->cxmode = MGCP_CX_SENDRECV;
03118          handle_hd_hf(sub, ev);
03119       } else if (!strcasecmp(ev, "hf")) {
03120          /* We can assume we are offhook if we received a hookflash */
03121          /* First let's just do call wait and ignore threeway */
03122          /* We're currently in charge */
03123          if (p->hookstate != MGCP_OFFHOOK) {
03124             /* Cisco c7940 sends hf even if the phone is onhook */
03125             /* Thanks to point on IRC for pointing this out */
03126             return -1;
03127          }
03128          /* do not let * conference two down channels */  
03129          if (sub->owner && sub->owner->_state == AST_STATE_DOWN && !sub->next->owner)
03130             return -1;
03131 
03132          if (p->callwaiting || p->transfer || p->threewaycalling) {
03133             ast_verb(3, "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name);
03134             p->sub = p->sub->next;
03135 
03136             /* transfer control to our next subchannel */
03137             if (!sub->next->owner) {
03138                /* plave the first call on hold and start up a new call */
03139                sub->cxmode = MGCP_CX_MUTE;
03140                ast_verb(3, "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
03141                transmit_modify_request(sub);
03142                if (sub->owner && ast_bridged_channel(sub->owner))
03143                   ast_queue_control(sub->owner, AST_CONTROL_HOLD);
03144                sub->next->cxmode = MGCP_CX_RECVONLY;
03145                handle_hd_hf(sub->next, ev);
03146             } else if (sub->owner && sub->next->owner) {
03147                /* We've got two active calls lets decide whether or not to conference or just flip flop */
03148                if ((!sub->outgoing) && (!sub->next->outgoing)) {
03149                   /* We made both calls lets conferenct */
03150                   ast_verb(3, "MGCP Conferencing %d and %d on %s@%s\n",
03151                         sub->id, sub->next->id, p->name, p->parent->name);
03152                   sub->cxmode = MGCP_CX_CONF;
03153                   sub->next->cxmode = MGCP_CX_CONF;
03154                   if (ast_bridged_channel(sub->next->owner))
03155                      ast_queue_control(sub->next->owner, AST_CONTROL_UNHOLD);
03156                   transmit_modify_request(sub);
03157                   transmit_modify_request(sub->next);
03158                } else {
03159                   /* Let's flipflop between calls */
03160                   /* XXX Need to check for state up ??? */
03161                   /* XXX Need a way to indicate the current call, or maybe the call that's waiting */
03162                   ast_verb(3, "We didn't make one of the calls FLIPFLOP %d and %d on %s@%s\n",
03163                         sub->id, sub->next->id, p->name, p->parent->name);
03164                   sub->cxmode = MGCP_CX_MUTE;
03165                   ast_verb(3, "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
03166                   transmit_modify_request(sub);
03167                   if (ast_bridged_channel(sub->owner))
03168                      ast_queue_control(sub->owner, AST_CONTROL_HOLD);
03169                         
03170                   if (ast_bridged_channel(sub->next->owner)) 
03171                      ast_queue_control(sub->next->owner, AST_CONTROL_HOLD);
03172                         
03173                   handle_hd_hf(sub->next, ev);
03174                }
03175             } else {
03176                /* We've most likely lost one of our calls find an active call and bring it up */
03177                if (sub->owner) {
03178                   p->sub = sub;
03179                } else if (sub->next->owner) {
03180                   p->sub = sub->next;
03181                } else {
03182                   /* We seem to have lost both our calls */
03183                   /* XXX - What do we do now? */
03184                   return -1;
03185                }
03186                if (ast_bridged_channel(p->sub->owner))
03187                   ast_queue_control(p->sub->owner, AST_CONTROL_UNHOLD);
03188                p->sub->cxmode = MGCP_CX_SENDRECV;
03189                transmit_modify_request(p->sub);
03190             }
03191          } else {
03192             ast_log(LOG_WARNING, "Callwaiting, call transfer or threeway calling not enabled on endpoint %s@%s\n", 
03193                p->name, p->parent->name);
03194          }
03195       } else if (!strcasecmp(ev, "hu")) {
03196          p->hookstate = MGCP_ONHOOK;
03197          sub->cxmode = MGCP_CX_RECVONLY;
03198          ast_debug(1, "MGCP %s@%s Went on hook\n", p->name, p->parent->name);
03199          /* Do we need to send MDCX before a DLCX ?
03200          if (sub->rtp) {
03201             transmit_modify_request(sub);
03202          }
03203          */
03204          if (p->transfer && (sub->owner && sub->next->owner) && ((!sub->outgoing) || (!sub->next->outgoing))) {
03205             /* We're allowed to transfer, we have two avtive calls and */
03206             /* we made at least one of the calls.  Let's try and transfer */
03207             ast_mutex_lock(&p->sub->next->lock);
03208             res = attempt_transfer(p);
03209             if (res < 0) {
03210                if (p->sub->next->owner) {
03211                   sub->next->alreadygone = 1;
03212                   mgcp_queue_hangup(sub->next);
03213                }
03214             } else if (res) {
03215                ast_log(LOG_WARNING, "Transfer attempt failed\n");
03216                ast_mutex_unlock(&p->sub->next->lock);
03217                return -1;
03218             }
03219             ast_mutex_unlock(&p->sub->next->lock);
03220          } else {
03221             /* Hangup the current call */
03222             /* If there is another active call, mgcp_hangup will ring the phone with the other call */
03223             if (sub->owner) {
03224                sub->alreadygone = 1;
03225                mgcp_queue_hangup(sub);
03226             } else {
03227                ast_verb(3, "MGCP handle_request(%s@%s-%d) ast_channel already destroyed, resending DLCX.\n",
03228                      p->name, p->parent->name, sub->id);
03229                /* Instruct the other side to remove the connection since it apparently *
03230                 * still thinks the channel is active. *
03231                 * For Cisco IAD2421 /BAK/ */
03232                transmit_connection_del(sub);
03233             }
03234          }
03235          if ((p->hookstate == MGCP_ONHOOK) && (!sub->rtp) && (!sub->next->rtp)) {
03236             p->hidecallerid = 0;
03237             if (p->hascallwaiting && !p->callwaiting) {
03238                ast_verb(3, "Enabling call waiting on MGCP/%s@%s-%d\n", p->name, p->parent->name, sub->id);
03239                p->callwaiting = -1;
03240             }
03241             if (has_voicemail(p)) {
03242                ast_verb(3, "MGCP handle_request(%s@%s) set vmwi(+)\n", p->name, p->parent->name);
03243                transmit_notify_request(sub, "L/vmwi(+)");
03244             } else {
03245                ast_verb(3, "MGCP handle_request(%s@%s) set vmwi(-)\n", p->name, p->parent->name);
03246                transmit_notify_request(sub, "L/vmwi(-)");
03247             }
03248          }
03249       } else if ((strlen(ev) == 1) && 
03250             (((ev[0] >= '0') && (ev[0] <= '9')) ||
03251              ((ev[0] >= 'A') && (ev[0] <= 'D')) ||
03252               (ev[0] == '*') || (ev[0] == '#'))) {
03253          if (sub && sub->owner && (sub->owner->_state >=  AST_STATE_UP)) {
03254             f.frametype = AST_FRAME_DTMF;
03255             f.subclass = ev[0];
03256             f.src = "mgcp";
03257             /* XXX MUST queue this frame to all subs in threeway call if threeway call is active */
03258             mgcp_queue_frame(sub, &f);
03259             ast_mutex_lock(&sub->next->lock);
03260             if (sub->next->owner)
03261                mgcp_queue_frame(sub->next, &f);
03262             ast_mutex_unlock(&sub->next->lock);
03263             if (strstr(p->curtone, "wt") && (ev[0] == 'A')) {
03264                memset(p->curtone, 0, sizeof(p->curtone));
03265             }
03266          } else {
03267             p->dtmf_buf[strlen(p->dtmf_buf)] = ev[0];
03268             p->dtmf_buf[strlen(p->dtmf_buf)] = '\0';
03269          }
03270       } else if (!strcasecmp(ev, "T")) {
03271          /* Digit timeout -- unimportant */
03272       } else if (!strcasecmp(ev, "ping")) {
03273          /* ping -- unimportant */
03274       } else {
03275          ast_log(LOG_NOTICE, "Received unknown event '%s' from %s@%s\n", ev, p->name, p->parent->name);
03276       }
03277    } else {
03278       ast_log(LOG_WARNING, "Unknown verb '%s' received from %s\n", req->verb, ast_inet_ntoa(sin->sin_addr));
03279       transmit_response(sub, "510", req, "Unknown verb");
03280    }
03281    return 0;
03282 }
03283 
03284 static int find_and_retrans(struct mgcp_subchannel *sub, struct mgcp_request *req)
03285 {
03286    int seqno=0;
03287    time_t now;
03288    struct mgcp_response *prev = NULL, *cur, *next, *answer=NULL;
03289    time(&now);
03290    if (sscanf(req->identifier, "%d", &seqno) != 1) 
03291       seqno = 0;
03292    cur = sub->parent->parent->responses;
03293    while(cur) {
03294       next = cur->next;
03295       if (now - cur->whensent > RESPONSE_TIMEOUT) {
03296          /* Delete this entry */
03297          if (prev)
03298             prev->next = next;
03299          else
03300             sub->parent->parent->responses = next;
03301          ast_free(cur);
03302       } else {
03303          if (seqno == cur->seqno)
03304             answer = cur;
03305          prev = cur;
03306       }
03307       cur = next;
03308    }
03309    if (answer) {
03310       resend_response(sub, answer);
03311       return 1;
03312    }
03313    return 0;
03314 }
03315 
03316 static int mgcpsock_read(int *id, int fd, short events, void *ignore)
03317 {
03318    struct mgcp_request req;
03319    struct sockaddr_in sin;
03320    struct mgcp_subchannel *sub;
03321    int res;
03322    socklen_t len;
03323    int result;
03324    int ident;
03325    len = sizeof(sin);
03326    memset(&req, 0, sizeof(req));
03327    res = recvfrom(mgcpsock, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len);
03328    if (res < 0) {
03329       if (errno != ECONNREFUSED)
03330          ast_log(LOG_WARNING, "Recv error: %s\n", strerror(errno));
03331       return 1;
03332    }
03333    req.data[res] = '\0';
03334    req.len = res;
03335    if (mgcpdebug) {
03336       ast_verbose("MGCP read: \n%s\nfrom %s:%d\n", req.data, ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
03337    }
03338    parse(&req);
03339    if (req.headers < 1) {
03340       /* Must have at least one header */
03341       return 1;
03342    }
03343    if (ast_strlen_zero(req.identifier)) {
03344       ast_log(LOG_NOTICE, "Message from %s missing identifier\n", ast_inet_ntoa(sin.sin_addr));
03345       return 1;
03346    }
03347 
03348    if (sscanf(req.verb, "%d", &result) && sscanf(req.identifier, "%d", &ident)) {
03349       /* Try to find who this message is for, if it's important */
03350       sub = find_subchannel_and_lock(NULL, ident, &sin);
03351       if (sub) {
03352          struct mgcp_gateway *gw = sub->parent->parent;
03353          struct mgcp_message *cur, *prev;
03354 
03355          ast_mutex_unlock(&sub->lock);
03356          ast_mutex_lock(&gw->msgs_lock);
03357          for (prev = NULL, cur = gw->msgs; cur; prev = cur, cur = cur->next) {
03358             if (cur->seqno == ident) {
03359                ast_debug(1, "Got response back on transaction %d\n", ident);
03360                if (prev)
03361                   prev->next = cur->next;
03362                else
03363                   gw->msgs = cur->next;
03364                break;
03365             }
03366          }
03367 
03368          /* stop retrans timer if the queue is empty */
03369          if (!gw->msgs) {
03370             AST_SCHED_DEL(sched, gw->retransid);
03371          }
03372 
03373          ast_mutex_unlock(&gw->msgs_lock);
03374          if (cur) {
03375             handle_response(cur->owner_ep, cur->owner_sub, result, ident, &req);
03376             ast_free(cur);
03377             return 1;
03378          }
03379 
03380          ast_log(LOG_NOTICE, "Got response back on [%s] for transaction %d we aren't sending?\n", 
03381             gw->name, ident);
03382       }
03383    } else {
03384       if (ast_strlen_zero(req.endpoint) || 
03385             ast_strlen_zero(req.version) || 
03386          ast_strlen_zero(req.verb)) {
03387          ast_log(LOG_NOTICE, "Message must have a verb, an idenitifier, version, and endpoint\n");
03388          return 1;
03389       }
03390       /* Process request, with iflock held */
03391       sub = find_subchannel_and_lock(req.endpoint, 0, &sin);
03392       if (sub) {
03393          /* look first to find a matching response in the queue */
03394          if (!find_and_retrans(sub, &req))
03395             /* pass the request off to the currently mastering subchannel */
03396             handle_request(sub, &req, &sin);
03397          ast_mutex_unlock(&sub->lock);
03398       }
03399    }
03400    return 1;
03401 }
03402 
03403 static int *mgcpsock_read_id = NULL;
03404 
03405 static void *do_monitor(void *data)
03406 {
03407    int res;
03408    int reloading;
03409    /*struct mgcp_gateway *g;*/
03410    /*struct mgcp_endpoint *e;*/
03411    /*time_t thispass = 0, lastpass = 0;*/
03412 
03413    /* Add an I/O event to our UDP socket */
03414    if (mgcpsock > -1) 
03415       mgcpsock_read_id = ast_io_add(io, mgcpsock, mgcpsock_read, AST_IO_IN, NULL);
03416    
03417    /* This thread monitors all the frame relay interfaces which are not yet in use
03418       (and thus do not have a separate thread) indefinitely */
03419    /* From here on out, we die whenever asked */
03420    for(;;) {
03421       /* Check for a reload request */
03422       ast_mutex_lock(&mgcp_reload_lock);
03423       reloading = mgcp_reloading;
03424       mgcp_reloading = 0;
03425       ast_mutex_unlock(&mgcp_reload_lock);
03426       if (reloading) {
03427          ast_verb(1, "Reloading MGCP\n");
03428          reload_config(1);
03429          /* Add an I/O event to our UDP socket */
03430          if (mgcpsock > -1 && !mgcpsock_read_id) {
03431             mgcpsock_read_id = ast_io_add(io, mgcpsock, mgcpsock_read, AST_IO_IN, NULL);
03432          }
03433       }
03434 
03435       /* Check for interfaces needing to be killed */
03436       /* Don't let anybody kill us right away.  Nobody should lock the interface list
03437          and wait for the monitor list, but the other way around is okay. */
03438       ast_mutex_lock(&monlock);
03439       /* Lock the network interface */
03440       ast_mutex_lock(&netlock);
03441 
03442 #if 0
03443       /* XXX THIS IS COMPLETELY HOSED */
03444       /* The gateway goes into a state of panic */
03445       /* If the vmwi indicator is sent while it is reseting interfaces */
03446       lastpass = thispass;
03447       thispass = time(NULL);
03448       g = gateways;
03449       while(g) {
03450          if (thispass != lastpass) {
03451             e = g->endpoints;
03452             while(e) {
03453                if (e->type == TYPE_LINE) {
03454                   res = has_voicemail(e);
03455                   if ((e->msgstate != res) && (e->hookstate == MGCP_ONHOOK) && (!e->rtp)){
03456                      if (res) {
03457                         transmit_notify_request(e, "L/vmwi(+)");
03458                      } else {
03459                         transmit_notify_request(e, "L/vmwi(-)");
03460                      }
03461                      e->msgstate = res;
03462                      e->onhooktime = thispass;
03463                   }
03464                }
03465                e = e->next;
03466             }
03467          }
03468          g = g->next;
03469       }
03470 #endif
03471       /* Okay, now that we know what to do, release the network lock */
03472       ast_mutex_unlock(&netlock);
03473       /* And from now on, we're okay to be killed, so release the monitor lock as well */
03474       ast_mutex_unlock(&monlock);
03475       pthread_testcancel();
03476       /* Wait for sched or io */
03477       res = ast_sched_wait(sched);
03478       /* copied from chan_sip.c */
03479       if ((res < 0) || (res > 1000))
03480          res = 1000;
03481       res = ast_io_wait(io, res);
03482       ast_mutex_lock(&monlock);
03483       if (res >= 0) 
03484          ast_sched_runq(sched);
03485       ast_mutex_unlock(&monlock);
03486    }
03487    /* Never reached */
03488    return NULL;
03489 }
03490 
03491 static int restart_monitor(void)
03492 {
03493    /* If we're supposed to be stopped -- stay stopped */
03494    if (monitor_thread == AST_PTHREADT_STOP)
03495       return 0;
03496    if (ast_mutex_lock(&monlock)) {
03497       ast_log(LOG_WARNING, "Unable to lock monitor\n");
03498       return -1;
03499    }
03500    if (monitor_thread == pthread_self()) {
03501       ast_mutex_unlock(&monlock);
03502       ast_log(LOG_WARNING, "Cannot kill myself\n");
03503       return -1;
03504    }
03505    if (monitor_thread != AST_PTHREADT_NULL) {
03506       /* Wake up the thread */
03507       pthread_kill(monitor_thread, SIGURG);
03508    } else {
03509       /* Start a new monitor */
03510       if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
03511          ast_mutex_unlock(&monlock);
03512          ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
03513          return -1;
03514       }
03515    }
03516    ast_mutex_unlock(&monlock);
03517    return 0;
03518 }
03519 
03520 static struct ast_channel *mgcp_request(const char *type, int format, void *data, int *cause)
03521 {
03522    int oldformat;
03523    struct mgcp_subchannel *sub;
03524    struct ast_channel *tmpc = NULL;
03525    char tmp[256];
03526    char *dest = data;
03527 
03528    oldformat = format;
03529    format &= capability;
03530    if (!format) {
03531       ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
03532       return NULL;
03533    }
03534    ast_copy_string(tmp, dest, sizeof(tmp));
03535    if (ast_strlen_zero(tmp)) {
03536       ast_log(LOG_NOTICE, "MGCP Channels require an endpoint\n");
03537       return NULL;
03538    }
03539    sub = find_subchannel_and_lock(tmp, 0, NULL);
03540    if (!sub) {
03541       ast_log(LOG_WARNING, "Unable to find MGCP endpoint '%s'\n", tmp);
03542       *cause = AST_CAUSE_UNREGISTERED;
03543       return NULL;
03544    }
03545    
03546    ast_verb(3, "MGCP mgcp_request(%s)\n", tmp);
03547    ast_verb(3, "MGCP cw: %d, dnd: %d, so: %d, sno: %d\n",
03548          sub->parent->callwaiting, sub->parent->dnd, sub->owner ? 1 : 0, sub->next->owner ? 1: 0);
03549    /* Must be busy */
03550    if (((sub->parent->callwaiting) && ((sub->owner) && (sub->next->owner))) ||
03551       ((!sub->parent->callwaiting) && (sub->owner)) ||
03552        (sub->parent->dnd && (ast_strlen_zero(sub->parent->call_forward)))) {
03553       if (sub->parent->hookstate == MGCP_ONHOOK) {
03554          if (has_voicemail(sub->parent)) {
03555             transmit_notify_request(sub,"L/vmwi(+)");
03556          } else {
03557             transmit_notify_request(sub,"L/vmwi(-)");
03558          }
03559       }
03560       *cause = AST_CAUSE_BUSY;
03561       ast_mutex_unlock(&sub->lock);
03562       return NULL;
03563    }
03564    tmpc = mgcp_new(sub->owner ? sub->next : sub, AST_STATE_DOWN);
03565    ast_mutex_unlock(&sub->lock);
03566    if (!tmpc)
03567       ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
03568    restart_monitor();
03569    return tmpc;
03570 }
03571 
03572 /* modified for reload support */
03573 /*! \brief  build_gateway: parse mgcp.conf and create gateway/endpoint structures */
03574 static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
03575 {
03576    struct mgcp_gateway *gw;
03577    struct mgcp_endpoint *e;
03578    struct mgcp_subchannel *sub;
03579    /*char txident[80];*/
03580    int i=0, y=0;
03581    int gw_reload = 0;
03582    int ep_reload = 0;
03583    canreinvite = CANREINVITE;
03584 
03585    /* locate existing gateway */
03586    gw = gateways;
03587    while (gw) {
03588       if (!strcasecmp(cat, gw->name)) {
03589          /* gateway already exists */
03590          gw->delme = 0;
03591          gw_reload = 1;
03592          break;
03593       }
03594       gw = gw->next;
03595    }
03596 
03597    if (!gw)
03598       gw = ast_calloc(1, sizeof(*gw));
03599 
03600    if (gw) {
03601       if (!gw_reload) {
03602          gw->expire = -1;
03603          gw->retransid = -1; /* SC */
03604          ast_mutex_init(&gw->msgs_lock);
03605          ast_copy_string(gw->name, cat, sizeof(gw->name));
03606          /* check if the name is numeric ip */
03607          if ((strchr(gw->name, '.')) && inet_addr(gw->name) != INADDR_NONE)
03608             gw->isnamedottedip = 1;
03609       }
03610       while(v) {
03611          if (!strcasecmp(v->name, "host")) {
03612             if (!strcasecmp(v->value, "dynamic")) {
03613                /* They'll register with us */
03614                gw->dynamic = 1;
03615                memset(&gw->addr.sin_addr, 0, 4);
03616                if (gw->addr.sin_port) {
03617                   /* If we've already got a port, make it the default rather than absolute */
03618                   gw->defaddr.sin_port = gw->addr.sin_port;
03619                   gw->addr.sin_port = 0;
03620                }
03621             } else {
03622                /* Non-dynamic.  Make sure we become that way if we're not */
03623                AST_SCHED_DEL(sched, gw->expire);
03624                gw->dynamic = 0;
03625                if (ast_get_ip(&gw->addr, v->value)) {
03626                   if (!gw_reload) {
03627                      ast_mutex_destroy(&gw->msgs_lock);
03628                      ast_free(gw);
03629                   }
03630                   return NULL;
03631                }
03632             }
03633          } else if (!strcasecmp(v->name, "defaultip")) {
03634             if (ast_get_ip(&gw->defaddr, v->value)) {
03635                if (!gw_reload) {
03636                   ast_mutex_destroy(&gw->msgs_lock);
03637                   ast_free(gw);
03638                }
03639                return NULL;
03640             }
03641          } else if (!strcasecmp(v->name, "permit") ||
03642             !strcasecmp(v->name, "deny")) {
03643             gw->ha = ast_append_ha(v->name, v->value, gw->ha, NULL);
03644          } else if (!strcasecmp(v->name, "port")) {
03645             gw->addr.sin_port = htons(atoi(v->value));
03646          } else if (!strcasecmp(v->name, "context")) {
03647             ast_copy_string(context, v->value, sizeof(context));
03648          } else if (!strcasecmp(v->name, "dtmfmode")) {
03649             if (!strcasecmp(v->value, "inband"))
03650                dtmfmode = MGCP_DTMF_INBAND;
03651             else if (!strcasecmp(v->value, "rfc2833")) 
03652                dtmfmode = MGCP_DTMF_RFC2833;
03653             else if (!strcasecmp(v->value, "hybrid"))
03654                dtmfmode = MGCP_DTMF_HYBRID;
03655             else if (!strcasecmp(v->value, "none")) 
03656                dtmfmode = 0;
03657             else
03658                ast_log(LOG_WARNING, "'%s' is not a valid DTMF mode at line %d\n", v->value, v->lineno);
03659          } else if (!strcasecmp(v->name, "nat")) {
03660             nat = ast_true(v->value);
03661          } else if (!strcasecmp(v->name, "callerid")) {
03662             if (!strcasecmp(v->value, "asreceived")) {
03663                cid_num[0] = '\0';
03664                cid_name[0] = '\0';
03665             } else {
03666                ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
03667             }
03668          } else if (!strcasecmp(v->name, "language")) {
03669             ast_copy_string(language, v->value, sizeof(language));
03670          } else if (!strcasecmp(v->name, "accountcode")) {
03671             ast_copy_string(accountcode, v->value, sizeof(accountcode));
03672          } else if (!strcasecmp(v->name, "amaflags")) {
03673             y = ast_cdr_amaflags2int(v->value);
03674             if (y < 0) {
03675                ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
03676             } else {
03677                amaflags = y;
03678             }
03679          } else if (!strcasecmp(v->name, "musiconhold")) {
03680             ast_copy_string(musicclass, v->value, sizeof(musicclass));
03681          } else if (!strcasecmp(v->name, "callgroup")) {
03682             cur_callergroup = ast_get_group(v->value);
03683          } else if (!strcasecmp(v->name, "pickupgroup")) {
03684             cur_pickupgroup = ast_get_group(v->value);
03685          } else if (!strcasecmp(v->name, "immediate")) {
03686             immediate = ast_true(v->value);
03687          } else if (!strcasecmp(v->name, "cancallforward")) {
03688             cancallforward = ast_true(v->value);
03689          } else if (!strcasecmp(v->name, "singlepath")) {
03690             singlepath = ast_true(v->value);
03691          } else if (!strcasecmp(v->name, "canreinvite")) {
03692             canreinvite = ast_true(v->value);
03693          } else if (!strcasecmp(v->name, "mailbox")) {
03694             ast_copy_string(mailbox, v->value, sizeof(mailbox));
03695          } else if (!strcasecmp(v->name, "hasvoicemail")) {
03696             if (ast_true(v->value) && ast_strlen_zero(mailbox)) {
03697                ast_copy_string(mailbox, gw->name, sizeof(mailbox));
03698             }
03699          } else if (!strcasecmp(v->name, "adsi")) {
03700             adsi = ast_true(v->value);
03701          } else if (!strcasecmp(v->name, "callreturn")) {
03702             callreturn = ast_true(v->value);
03703          } else if (!strcasecmp(v->name, "callwaiting")) {
03704             callwaiting = ast_true(v->value);
03705          } else if (!strcasecmp(v->name, "slowsequence")) {
03706             slowsequence = ast_true(v->value);
03707          } else if (!strcasecmp(v->name, "transfer")) {
03708             transfer = ast_true(v->value);
03709          } else if (!strcasecmp(v->name, "threewaycalling")) {
03710             threewaycalling = ast_true(v->value);
03711          } else if (!strcasecmp(v->name, "wcardep")) {
03712             /* locate existing endpoint */
03713             e = gw->endpoints;
03714             while (e) {
03715                if (!strcasecmp(v->value, e->name)) {
03716                   /* endpoint already exists */
03717                   e->delme = 0;
03718                   ep_reload = 1;
03719                   break;
03720                }
03721                e = e->next;
03722             }
03723 
03724             if (!e) {
03725                /* Allocate wildcard endpoint */
03726                e = ast_calloc(1, sizeof(*e));
03727                ep_reload = 0;
03728             }
03729 
03730             if (e) {
03731                if (!ep_reload) {
03732                   memset(e, 0, sizeof(struct mgcp_endpoint));
03733                   ast_mutex_init(&e->lock);
03734                   ast_mutex_init(&e->rqnt_queue_lock);
03735                   ast_mutex_init(&e->cmd_queue_lock);
03736                   ast_copy_string(e->name, v->value, sizeof(e->name));
03737                   e->needaudit = 1;
03738                }
03739                ast_copy_string(gw->wcardep, v->value, sizeof(gw->wcardep));
03740                /* XXX Should we really check for uniqueness?? XXX */
03741                ast_copy_string(e->accountcode, accountcode, sizeof(e->accountcode));
03742                ast_copy_string(e->context, context, sizeof(e->context));
03743                ast_copy_string(e->cid_num, cid_num, sizeof(e->cid_num));
03744                ast_copy_string(e->cid_name, cid_name, sizeof(e->cid_name));
03745                ast_copy_string(e->language, language, sizeof(e->language));
03746                ast_copy_string(e->musicclass, musicclass, sizeof(e->musicclass));
03747                ast_copy_string(e->mailbox, mailbox, sizeof(e->mailbox));
03748                if (!ast_strlen_zero(e->mailbox)) {
03749                   char *mailbox, *context;
03750                   context = mailbox = ast_strdupa(e->mailbox);
03751                   strsep(&context, "@");
03752                   if (ast_strlen_zero(context))
03753                      context = "default";
03754                   e->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, NULL,
03755                      AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
03756                      AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
03757                      AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
03758                      AST_EVENT_IE_END);
03759                }
03760                snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", ast_random());
03761                e->msgstate = -1;
03762                e->amaflags = amaflags;
03763                e->capability = capability;
03764                e->parent = gw;
03765                e->dtmfmode = dtmfmode;
03766                if (!ep_reload && e->sub && e->sub->rtp)
03767                   e->dtmfmode |= MGCP_DTMF_INBAND;
03768                e->adsi = adsi;
03769                e->type = TYPE_LINE;
03770                e->immediate = immediate;
03771                e->callgroup=cur_callergroup;
03772                e->pickupgroup=cur_pickupgroup;
03773                e->callreturn = callreturn;
03774                e->cancallforward = cancallforward;
03775                e->singlepath = singlepath;
03776                e->canreinvite = canreinvite;
03777                e->callwaiting = callwaiting;
03778                e->hascallwaiting = callwaiting;
03779                e->slowsequence = slowsequence;
03780                e->transfer = transfer;
03781                e->threewaycalling = threewaycalling;
03782                e->onhooktime = time(NULL);
03783                /* ASSUME we're onhook */
03784                e->hookstate = MGCP_ONHOOK;
03785                if (!ep_reload) {
03786                   /*snprintf(txident, sizeof(txident), "%08lx", ast_random());*/
03787                   for (i = 0; i < MAX_SUBS; i++) {
03788                      sub = ast_calloc(1, sizeof(*sub));
03789                      if (sub) {
03790                         ast_verb(3, "Allocating subchannel '%d' on %s@%s\n", i, e->name, gw->name);
03791                         ast_mutex_init(&sub->lock);
03792                         ast_mutex_init(&sub->cx_queue_lock);
03793                         sub->parent = e;
03794                         sub->id = i;
03795                         snprintf(sub->txident, sizeof(sub->txident), "%08lx", ast_random());
03796                         /*stnrcpy(sub->txident, txident, sizeof(sub->txident) - 1);*/
03797                         sub->cxmode = MGCP_CX_INACTIVE;
03798                         sub->nat = nat;
03799                         sub->next = e->sub;
03800                         e->sub = sub;
03801                      } else {
03802                         /* XXX Should find a way to clean up our memory */
03803                         ast_log(LOG_WARNING, "Out of memory allocating subchannel\n");
03804                         return NULL;
03805                      }
03806                   }
03807                   /* Make out subs a circular linked list so we can always sping through the whole bunch */
03808                   sub = e->sub;
03809                   /* find the end of the list */
03810                   while(sub->next){
03811                      sub = sub->next;
03812                   }
03813                   /* set the last sub->next to the first sub */
03814                   sub->next = e->sub;
03815 
03816                   e->next = gw->endpoints;
03817                   gw->endpoints = e;
03818                }
03819             }
03820          } else if (!strcasecmp(v->name, "trunk") ||
03821                     !strcasecmp(v->name, "line")) {
03822 
03823             /* locate existing endpoint */
03824             e = gw->endpoints;
03825             while (e) {
03826                if (!strcasecmp(v->value, e->name)) {
03827                   /* endpoint already exists */
03828                   e->delme = 0;
03829                   ep_reload = 1;
03830                   break;
03831                }
03832                e = e->next;
03833             }
03834 
03835             if (!e) {
03836                e = ast_calloc(1, sizeof(*e));
03837                ep_reload = 0;
03838             }
03839 
03840             if (e) {
03841                if (!ep_reload) {
03842                   ast_mutex_init(&e->lock);
03843                   ast_mutex_init(&e->rqnt_queue_lock);
03844                   ast_mutex_init(&e->cmd_queue_lock);
03845                   ast_copy_string(e->name, v->value, sizeof(e->name));
03846                   e->needaudit = 1;
03847                }
03848                /* XXX Should we really check for uniqueness?? XXX */
03849                ast_copy_string(e->accountcode, accountcode, sizeof(e->accountcode));
03850                ast_copy_string(e->context, context, sizeof(e->context));
03851                ast_copy_string(e->cid_num, cid_num, sizeof(e->cid_num));
03852                ast_copy_string(e->cid_name, cid_name, sizeof(e->cid_name));
03853                ast_copy_string(e->language, language, sizeof(e->language));
03854                ast_copy_string(e->musicclass, musicclass, sizeof(e->musicclass));
03855                ast_copy_string(e->mailbox, mailbox, sizeof(e->mailbox));
03856                if (!ast_strlen_zero(mailbox)) {
03857                   ast_verb(3, "Setting mailbox '%s' on %s@%s\n", mailbox, gw->name, e->name);
03858                }
03859                if (!ep_reload) {
03860                   /* XXX potential issue due to reload */
03861                   e->msgstate = -1;
03862                   e->parent = gw;
03863                }
03864                e->amaflags = amaflags;
03865                e->capability = capability;
03866                e->dtmfmode = dtmfmode;
03867                e->adsi = adsi;
03868                if (!strcasecmp(v->name, "trunk"))
03869                   e->type = TYPE_TRUNK;
03870                else
03871                   e->type = TYPE_LINE;
03872 
03873                e->immediate = immediate;
03874                e->callgroup=cur_callergroup;
03875                e->pickupgroup=cur_pickupgroup;
03876                e->callreturn = callreturn;
03877                e->cancallforward = cancallforward;
03878                e->canreinvite = canreinvite;
03879                e->singlepath = singlepath;
03880                e->callwaiting = callwaiting;
03881                e->hascallwaiting = callwaiting;
03882                e->slowsequence = slowsequence;
03883                e->transfer = transfer;
03884                e->threewaycalling = threewaycalling;
03885                if (!ep_reload) {
03886                   e->onhooktime = time(NULL);
03887                   /* ASSUME we're onhook */
03888                   e->hookstate = MGCP_ONHOOK;
03889                   snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", ast_random());
03890                }
03891 
03892                for (i = 0, sub = NULL; i < MAX_SUBS; i++) {
03893                   if (!ep_reload) {
03894                      sub = ast_calloc(1, sizeof(*sub));
03895                   } else {
03896                      if (!sub)
03897                         sub = e->sub;
03898                      else
03899                         sub = sub->next;
03900                   }
03901 
03902                   if (sub) {
03903                      if (!ep_reload) {
03904                         ast_verb(3, "Allocating subchannel '%d' on %s@%s\n", i, e->name, gw->name);
03905                         ast_mutex_init(&sub->lock);
03906                         ast_mutex_init(&sub->cx_queue_lock);
03907                         ast_copy_string(sub->magic, MGCP_SUBCHANNEL_MAGIC, sizeof(sub->magic));
03908                         sub->parent = e;
03909                         sub->id = i;
03910                         snprintf(sub->txident, sizeof(sub->txident), "%08lx", ast_random());
03911                         sub->cxmode = MGCP_CX_INACTIVE;
03912                         sub->next = e->sub;
03913                         e->sub = sub;
03914                      }
03915                      sub->nat = nat;
03916                   } else {
03917                      /* XXX Should find a way to clean up our memory */
03918                      ast_log(LOG_WARNING, "Out of memory allocating subchannel\n");
03919                      return NULL;
03920                   }
03921                }
03922                if (!ep_reload) {
03923                   /* Make out subs a circular linked list so we can always sping through the whole bunch */
03924                   sub = e->sub;
03925                   /* find the end of the list */
03926                   while (sub->next) {
03927                      sub = sub->next;
03928                   }
03929                   /* set the last sub->next to the first sub */
03930                   sub->next = e->sub;
03931 
03932                   e->next = gw->endpoints;
03933                   gw->endpoints = e;
03934                }
03935             }
03936          } else
03937             ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
03938          v = v->next;
03939       }
03940    }
03941    if (!ntohl(gw->addr.sin_addr.s_addr) && !gw->dynamic) {
03942       ast_log(LOG_WARNING, "Gateway '%s' lacks IP address and isn't dynamic\n", gw->name);
03943       if (!gw_reload) {
03944          ast_mutex_destroy(&gw->msgs_lock);
03945          ast_free(gw);
03946       }
03947       return NULL;
03948    }
03949    gw->defaddr.sin_family = AF_INET;
03950    gw->addr.sin_family = AF_INET;
03951    if (gw->defaddr.sin_addr.s_addr && !ntohs(gw->defaddr.sin_port)) 
03952       gw->defaddr.sin_port = htons(DEFAULT_MGCP_GW_PORT);
03953    if (gw->addr.sin_addr.s_addr && !ntohs(gw->addr.sin_port))
03954       gw->addr.sin_port = htons(DEFAULT_MGCP_GW_PORT);
03955    if (gw->addr.sin_addr.s_addr)
03956       if (ast_ouraddrfor(&gw->addr.sin_addr, &gw->ourip))
03957          memcpy(&gw->ourip, &__ourip, sizeof(gw->ourip));
03958 
03959    return (gw_reload ? NULL : gw);
03960 }
03961 
03962 static enum ast_rtp_get_result mgcp_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
03963 {
03964    struct mgcp_subchannel *sub = NULL;
03965 
03966    if (!(sub = chan->tech_pvt) || !(sub->rtp))
03967       return AST_RTP_GET_FAILED;
03968 
03969    *rtp = sub->rtp;
03970 
03971    if (sub->parent->canreinvite)
03972       return AST_RTP_TRY_NATIVE;
03973    else
03974       return AST_RTP_TRY_PARTIAL;
03975 }
03976 
03977 static int mgcp_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active)
03978 {
03979    /* XXX Is there such thing as video support with MGCP? XXX */
03980    struct mgcp_subchannel *sub;
03981    sub = chan->tech_pvt;
03982    if (sub && !sub->alreadygone) {
03983       transmit_modify_with_sdp(sub, rtp, codecs);
03984       return 0;
03985    }
03986    return -1;
03987 }
03988 
03989 static struct ast_rtp_protocol mgcp_rtp = {
03990    .type = "MGCP",
03991    .get_rtp_info = mgcp_get_rtp_peer,
03992    .set_rtp_peer = mgcp_set_rtp_peer,
03993 };
03994 
03995 static void destroy_endpoint(struct mgcp_endpoint *e)
03996 {
03997    struct mgcp_subchannel *sub = e->sub->next, *s;
03998    int i;
03999 
04000    for (i = 0; i < MAX_SUBS; i++) {
04001       ast_mutex_lock(&sub->lock);
04002       if (!ast_strlen_zero(sub->cxident)) {
04003          transmit_connection_del(sub);
04004       }
04005       if (sub->rtp) {
04006          ast_rtp_destroy(sub->rtp);
04007          sub->rtp = NULL;
04008       }
04009       memset(sub->magic, 0, sizeof(sub->magic));
04010       mgcp_queue_hangup(sub);
04011       dump_cmd_queues(NULL, sub);
04012       ast_mutex_unlock(&sub->lock);
04013       sub = sub->next;
04014    }
04015 
04016    if (e->dsp) {
04017       ast_dsp_free(e->dsp);
04018    }
04019 
04020    dump_queue(e->parent, e);
04021    dump_cmd_queues(e, NULL);
04022 
04023    sub = e->sub;
04024    for (i = 0; (i < MAX_SUBS) && sub; i++) {
04025       s = sub;
04026       sub = sub->next;
04027       ast_mutex_destroy(&s->lock);
04028       ast_mutex_destroy(&s->cx_queue_lock);
04029       ast_free(s);
04030    }
04031 
04032    if (e->mwi_event_sub)
04033       ast_event_unsubscribe(e->mwi_event_sub);
04034 
04035    ast_mutex_destroy(&e->lock);
04036    ast_mutex_destroy(&e->rqnt_queue_lock);
04037    ast_mutex_destroy(&e->cmd_queue_lock);
04038    ast_free(e);
04039 }
04040 
04041 static void destroy_gateway(struct mgcp_gateway *g)
04042 {
04043    if (g->ha)
04044       ast_free_ha(g->ha);
04045 
04046    dump_queue(g, NULL);
04047 
04048    ast_free(g);
04049 }
04050 
04051 static void prune_gateways(void)
04052 {
04053    struct mgcp_gateway *g, *z, *r;
04054    struct mgcp_endpoint *e, *p, *t;
04055 
04056    ast_mutex_lock(&gatelock);
04057 
04058    /* prune gateways */
04059    for (z = NULL, g = gateways; g;) {
04060       /* prune endpoints */
04061       for (p = NULL, e = g->endpoints; e; ) {
04062          if (e->delme || g->delme) {
04063             t = e;
04064             e = e->next;
04065             if (!p)
04066                g->endpoints = e;
04067             else
04068                p->next = e;
04069             destroy_endpoint(t);
04070          } else {
04071             p = e;
04072             e = e->next;
04073          }
04074       }
04075 
04076       if (g->delme) {
04077          r = g;
04078          g = g->next;
04079          if (!z)
04080             gateways = g;
04081          else
04082             z->next = g;
04083 
04084          destroy_gateway(r);
04085       } else {
04086          z = g;
04087          g = g->next;
04088       }
04089    }
04090 
04091    ast_mutex_unlock(&gatelock);
04092 }
04093 
04094 static int reload_config(int reload)
04095 {
04096    struct ast_config *cfg;
04097    struct ast_variable *v;
04098    struct mgcp_gateway *g;
04099    struct mgcp_endpoint *e;
04100    char *cat;
04101    struct ast_hostent ahp;
04102    struct hostent *hp;
04103    int format;
04104    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
04105    
04106    if (gethostname(ourhost, sizeof(ourhost)-1)) {
04107       ast_log(LOG_WARNING, "Unable to get hostname, MGCP disabled\n");
04108       return 0;
04109    }
04110    cfg = ast_config_load(config, config_flags);
04111 
04112    /* We *must* have a config file otherwise stop immediately */
04113    if (!cfg) {
04114       ast_log(LOG_NOTICE, "Unable to load config %s, MGCP disabled\n", config);
04115       return 0;
04116    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
04117       return 0;
04118 
04119    memset(&bindaddr, 0, sizeof(bindaddr));
04120    dtmfmode = 0;
04121 
04122    /* Copy the default jb config over global_jbconf */
04123    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
04124 
04125    v = ast_variable_browse(cfg, "general");
04126    while (v) {
04127       /* handle jb conf */
04128       if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
04129          v = v->next;
04130          continue;
04131       }
04132 
04133       /* Create the interface list */
04134       if (!strcasecmp(v->name, "bindaddr")) {
04135          if (!(hp = ast_gethostbyname(v->value, &ahp))) {
04136             ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
04137          } else {
04138             memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
04139          }
04140       } else if (!strcasecmp(v->name, "allow")) {
04141          format = ast_getformatbyname(v->value);
04142          if (format < 1) 
04143             ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
04144          else
04145             capability |= format;
04146       } else if (!strcasecmp(v->name, "disallow")) {
04147          format = ast_getformatbyname(v->value);
04148          if (format < 1) 
04149             ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
04150          else
04151             capability &= ~format;
04152       } else if (!strcasecmp(v->name, "tos")) {
04153          if (ast_str2tos(v->value, &tos))
04154              ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
04155       } else if (!strcasecmp(v->name, "tos_audio")) {
04156          if (ast_str2tos(v->value, &tos_audio))
04157              ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);
04158       } else if (!strcasecmp(v->name, "cos")) {          
04159          if (ast_str2cos(v->value, &cos))
04160              ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno);
04161       } else if (!strcasecmp(v->name, "cos_audio")) {          
04162          if (ast_str2cos(v->value, &cos_audio))
04163              ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);
04164       } else if (!strcasecmp(v->name, "port")) {
04165          if (sscanf(v->value, "%d", &ourport) == 1) {
04166             bindaddr.sin_port = htons(ourport);
04167          } else {
04168             ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
04169          }
04170       }
04171       v = v->next;
04172    }
04173 
04174    /* mark existing entries for deletion */
04175    ast_mutex_lock(&gatelock);
04176    g = gateways;
04177    while (g) {
04178       g->delme = 1;
04179       e = g->endpoints;
04180       while (e) {
04181          e->delme = 1;
04182          e = e->next;
04183       }
04184       g = g->next;
04185    }
04186    ast_mutex_unlock(&gatelock);
04187    
04188    cat = ast_category_browse(cfg, NULL);
04189    while(cat) {
04190       if (strcasecmp(cat, "general")) {
04191          ast_mutex_lock(&gatelock);
04192          g = build_gateway(cat, ast_variable_browse(cfg, cat));
04193          if (g) {
04194             ast_verb(3, "Added gateway '%s'\n", g->name);
04195             g->next = gateways;
04196             gateways = g;
04197          }
04198          ast_mutex_unlock(&gatelock);
04199 
04200          /* FS: process queue and IO */
04201          if (monitor_thread == pthread_self()) {
04202             if (sched) ast_sched_runq(sched);
04203             if (io) ast_io_wait(io, 10);
04204          }
04205       }
04206       cat = ast_category_browse(cfg, cat);
04207    }
04208 
04209       /* prune deleted entries etc. */
04210       prune_gateways();
04211 
04212    if (ntohl(bindaddr.sin_addr.s_addr)) {
04213       memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
04214    } else {
04215       hp = ast_gethostbyname(ourhost, &ahp);
04216       if (!hp) {
04217          ast_log(LOG_WARNING, "Unable to get our IP address, MGCP disabled\n");
04218          ast_config_destroy(cfg);
04219          return 0;
04220       }
04221       memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
04222    }
04223    if (!ntohs(bindaddr.sin_port))
04224       bindaddr.sin_port = ntohs(DEFAULT_MGCP_CA_PORT);
04225    bindaddr.sin_family = AF_INET;
04226    ast_mutex_lock(&netlock);
04227    if (mgcpsock > -1)
04228       close(mgcpsock);
04229 
04230    if (mgcpsock_read_id != NULL)
04231       ast_io_remove(io, mgcpsock_read_id);
04232    mgcpsock_read_id = NULL;
04233 
04234    mgcpsock = socket(AF_INET, SOCK_DGRAM, 0);
04235    if (mgcpsock < 0) {
04236       ast_log(LOG_WARNING, "Unable to create MGCP socket: %s\n", strerror(errno));
04237    } else {
04238       if (bind(mgcpsock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
04239          ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
04240             ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
04241                strerror(errno));
04242          close(mgcpsock);
04243          mgcpsock = -1;
04244       } else {
04245          ast_verb(2, "MGCP Listening on %s:%d\n",
04246                ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
04247          ast_netsock_set_qos(mgcpsock, tos, cos, "MGCP");
04248       }
04249    }
04250    ast_mutex_unlock(&netlock);
04251    ast_config_destroy(cfg);
04252 
04253    /* send audit only to the new endpoints */
04254    g = gateways;
04255    while (g) {
04256       e = g->endpoints;
04257       while (e && e->needaudit) {
04258          e->needaudit = 0;
04259          transmit_audit_endpoint(e);
04260          ast_verb(3, "MGCP Auditing endpoint %s@%s for hookstate\n", e->name, g->name);
04261          e = e->next;
04262       }
04263       g = g->next;
04264    }
04265 
04266    return 0;
04267 }
04268 
04269 /*! \brief  load_module: PBX load module - initialization ---*/
04270 static int load_module(void)
04271 {
04272    if (!(sched = sched_context_create())) {
04273       ast_log(LOG_WARNING, "Unable to create schedule context\n");
04274       return AST_MODULE_LOAD_FAILURE;
04275    }
04276 
04277    if (!(io = io_context_create())) {
04278       ast_log(LOG_WARNING, "Unable to create I/O context\n");
04279       sched_context_destroy(sched);
04280       return AST_MODULE_LOAD_FAILURE;
04281    }
04282 
04283    if (reload_config(0))
04284       return AST_MODULE_LOAD_DECLINE;
04285 
04286    /* Make sure we can register our mgcp channel type */
04287    if (ast_channel_register(&mgcp_tech)) {
04288       ast_log(LOG_ERROR, "Unable to register channel class 'MGCP'\n");
04289       io_context_destroy(io);
04290       sched_context_destroy(sched);
04291       return AST_MODULE_LOAD_FAILURE;
04292    }
04293 
04294    ast_rtp_proto_register(&mgcp_rtp);
04295    ast_cli_register_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
04296    
04297    /* And start the monitor for the first time */
04298    restart_monitor();
04299 
04300    return AST_MODULE_LOAD_SUCCESS;
04301 }
04302 
04303 static char *mgcp_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04304 {
04305    static int deprecated = 0;
04306 
04307    if (e) {
04308       switch (cmd) {
04309       case CLI_INIT:
04310          e->command = "mgcp reload";
04311          e->usage =
04312             "Usage: mgcp reload\n"
04313             "       'mgcp reload' is deprecated.  Please use 'reload chan_mgcp.so' instead.\n";
04314          return NULL;
04315       case CLI_GENERATE:
04316          return NULL;
04317       }
04318    }
04319 
04320    if (!deprecated && a && a->argc > 0) {
04321       ast_log(LOG_WARNING, "'mgcp reload' is deprecated.  Please use 'reload chan_mgcp.so' instead.\n");
04322       deprecated = 1;
04323    }
04324 
04325    ast_mutex_lock(&mgcp_reload_lock);
04326    if (mgcp_reloading) {
04327       ast_verbose("Previous mgcp reload not yet done\n");
04328    } else
04329       mgcp_reloading = 1;
04330    ast_mutex_unlock(&mgcp_reload_lock);
04331    restart_monitor();
04332    return CLI_SUCCESS;
04333 }
04334 
04335 static int reload(void)
04336 {
04337    mgcp_reload(NULL, 0, NULL);
04338    return 0;
04339 }
04340 
04341 static int unload_module(void)
04342 {
04343    struct mgcp_endpoint *e;
04344    struct mgcp_gateway *g;
04345 
04346    /* Check to see if we're reloading */
04347    if (ast_mutex_trylock(&mgcp_reload_lock)) {
04348       ast_log(LOG_WARNING, "MGCP is currently reloading.  Unable to remove module.\n");
04349       return -1;
04350    } else {
04351       mgcp_reloading = 1;
04352       ast_mutex_unlock(&mgcp_reload_lock);
04353    }
04354 
04355    /* First, take us out of the channel loop */
04356    ast_channel_unregister(&mgcp_tech);
04357 
04358    /* Shut down the monitoring thread */
04359    if (!ast_mutex_lock(&monlock)) {
04360       if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
04361          pthread_cancel(monitor_thread);
04362          pthread_kill(monitor_thread, SIGURG);
04363          pthread_join(monitor_thread, NULL);
04364       }
04365       monitor_thread = AST_PTHREADT_STOP;
04366       ast_mutex_unlock(&monlock);
04367    } else {
04368       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
04369       /* We always want to leave this in a consistent state */
04370       ast_channel_register(&mgcp_tech);
04371       mgcp_reloading = 0;
04372       mgcp_reload(NULL, 0, NULL);
04373       return -1;
04374    }
04375 
04376    if (!ast_mutex_lock(&gatelock)) {
04377       for (g = gateways; g; g = g->next) {
04378          g->delme = 1;
04379          for (e = g->endpoints; e; e = e->next)
04380             e->delme = 1;
04381       }
04382 
04383       prune_gateways();
04384       ast_mutex_unlock(&gatelock);
04385    } else {
04386       ast_log(LOG_WARNING, "Unable to lock the gateways list.\n");
04387       /* We always want to leave this in a consistent state */
04388       ast_channel_register(&mgcp_tech);
04389       /* Allow the monitor to restart */
04390       monitor_thread = AST_PTHREADT_NULL;
04391       mgcp_reloading = 0;
04392       mgcp_reload(NULL, 0, NULL);
04393       return -1;
04394    }
04395 
04396    close(mgcpsock);
04397    ast_rtp_proto_unregister(&mgcp_rtp);
04398    ast_cli_unregister_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
04399    sched_context_destroy(sched);
04400 
04401    return 0;
04402 }
04403 
04404 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Media Gateway Control Protocol (MGCP)",
04405       .load = load_module,
04406       .unload = unload_module,
04407       .reload = reload,
04408           );

Generated on Thu Jul 9 13:40:27 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7