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

Generated on Wed Oct 28 13:30:56 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6