Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:00:36 2007

Asterisk developer's documentation :: Codename Pineapple


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: 51385 $")
00034 
00035 #include <stdio.h>
00036 #include <string.h>
00037 #include <unistd.h>
00038 #include <sys/socket.h>
00039 #include <sys/ioctl.h>
00040 #include <net/if.h>
00041 #include <errno.h>
00042 #include <stdlib.h>
00043 #include <fcntl.h>
00044 #include <netdb.h>
00045 #include <sys/signal.h>
00046 #include <signal.h>
00047 #include <netinet/in.h>
00048 #include <netinet/in_systm.h>
00049 #include <netinet/ip.h>
00050 #include <arpa/inet.h>
00051 #include <ctype.h>
00052 
00053 #include "asterisk/lock.h"
00054 #include "asterisk/channel.h"
00055 #include "asterisk/config.h"
00056 #include "asterisk/logger.h"
00057 #include "asterisk/module.h"
00058 #include "asterisk/pbx.h"
00059 #include "asterisk/options.h"
00060 #include "asterisk/lock.h"
00061 #include "asterisk/sched.h"
00062 #include "asterisk/io.h"
00063 #include "asterisk/rtp.h"
00064 #include "asterisk/acl.h"
00065 #include "asterisk/callerid.h"
00066 #include "asterisk/cli.h"
00067 #include "asterisk/say.h"
00068 #include "asterisk/cdr.h"
00069 #include "asterisk/astdb.h"
00070 #include "asterisk/features.h"
00071 #include "asterisk/app.h"
00072 #include "asterisk/musiconhold.h"
00073 #include "asterisk/utils.h"
00074 #include "asterisk/causes.h"
00075 #include "asterisk/dsp.h"
00076 #include "asterisk/devicestate.h"
00077 #include "asterisk/stringfields.h"
00078 #include "asterisk/abstract_jb.h"
00079 
00080 #ifndef IPTOS_MINCOST
00081 #define IPTOS_MINCOST 0x02
00082 #endif
00083 
00084 /*
00085  * Define to work around buggy dlink MGCP phone firmware which
00086  * appears not to know that "rt" is part of the "G" package.
00087  */
00088 /* #define DLINK_BUGGY_FIRMWARE  */
00089 
00090 #define MGCPDUMPER
00091 #define DEFAULT_EXPIRY  120
00092 #define MAX_EXPIRY   3600
00093 #define CANREINVITE  1
00094 
00095 #ifndef INADDR_NONE
00096 #define INADDR_NONE (in_addr_t)(-1)
00097 #endif
00098 
00099 /*! Global jitterbuffer configuration - by default, jb is disabled */
00100 static struct ast_jb_conf default_jbconf =
00101 {
00102    .flags = 0,
00103    .max_size = -1,
00104    .resync_threshold = -1,
00105    .impl = ""
00106 };
00107 static struct ast_jb_conf global_jbconf;
00108 
00109 static const char tdesc[] = "Media Gateway Control Protocol (MGCP)";
00110 static const char config[] = "mgcp.conf";
00111 
00112 #define MGCP_DTMF_RFC2833  (1 << 0)
00113 #define MGCP_DTMF_INBAND   (1 << 1)
00114 #define MGCP_DTMF_HYBRID   (1 << 2)
00115 
00116 #define DEFAULT_MGCP_GW_PORT  2427 /*!< From RFC 2705 */
00117 #define DEFAULT_MGCP_CA_PORT  2727 /*!< From RFC 2705 */
00118 #define MGCP_MAX_PACKET    1500 /*!< Also from RFC 2543, should sub headers tho */
00119 #define DEFAULT_RETRANS    1000 /*!< How frequently to retransmit */
00120 #define MAX_RETRANS     5    /*!< Try only 5 times for retransmissions */
00121 
00122 /*! MGCP rtp stream modes { */
00123 #define MGCP_CX_SENDONLY   0
00124 #define MGCP_CX_RECVONLY   1
00125 #define MGCP_CX_SENDRECV   2
00126 #define MGCP_CX_CONF    3
00127 #define MGCP_CX_CONFERENCE 3
00128 #define MGCP_CX_MUTE    4
00129 #define MGCP_CX_INACTIVE   4
00130 /*! } */
00131 
00132 static char *mgcp_cxmodes[] = {
00133    "sendonly",
00134    "recvonly",
00135    "sendrecv",
00136    "confrnce",
00137    "inactive"
00138 };
00139 
00140 enum {
00141    MGCP_CMD_EPCF,
00142    MGCP_CMD_CRCX,
00143    MGCP_CMD_MDCX,
00144    MGCP_CMD_DLCX,
00145    MGCP_CMD_RQNT,
00146    MGCP_CMD_NTFY,
00147    MGCP_CMD_AUEP,
00148    MGCP_CMD_AUCX,
00149    MGCP_CMD_RSIP
00150 };
00151 
00152 static char context[AST_MAX_EXTENSION] = "default";
00153 
00154 static char language[MAX_LANGUAGE] = "";
00155 static char musicclass[MAX_MUSICCLASS] = "";
00156 static char cid_num[AST_MAX_EXTENSION] = "";
00157 static char cid_name[AST_MAX_EXTENSION] = "";
00158 
00159 static int dtmfmode = 0;
00160 static int nat = 0;
00161 
00162 static ast_group_t cur_callergroup = 0;
00163 static ast_group_t cur_pickupgroup = 0;
00164 
00165 static int tos = 0;
00166 
00167 static int immediate = 0;
00168 
00169 static int callwaiting = 0;
00170 
00171 static int callreturn = 0;
00172 
00173 static int slowsequence = 0;
00174 
00175 static int threewaycalling = 0;
00176 
00177 /*! This is for flashhook transfers */
00178 static int transfer = 0;
00179 
00180 static int cancallforward = 0;
00181 
00182 static int singlepath = 0;
00183 
00184 static int canreinvite = CANREINVITE;
00185 
00186 static char accountcode[AST_MAX_ACCOUNT_CODE] = "";
00187 
00188 static char mailbox[AST_MAX_EXTENSION];
00189 
00190 static int amaflags = 0;
00191 
00192 static int adsi = 0;
00193 
00194 static unsigned int oseq;
00195 
00196 /*! Wait up to 16 seconds for first digit (FXO logic) */
00197 static int firstdigittimeout = 16000;
00198 
00199 /*! How long to wait for following digits (FXO logic) */
00200 static int gendigittimeout = 8000;
00201 
00202 /*! How long to wait for an extra digit, if there is an ambiguous match */
00203 static int matchdigittimeout = 3000;
00204 
00205 /*! Protect the monitoring thread, so only one process can kill or start it, and not
00206     when it's doing something critical. */
00207 AST_MUTEX_DEFINE_STATIC(netlock);
00208 
00209 AST_MUTEX_DEFINE_STATIC(monlock);
00210 
00211 /*! This is the thread for the monitor which checks for input on the channels
00212     which are not currently in use. */
00213 static pthread_t monitor_thread = AST_PTHREADT_NULL;
00214 
00215 static int restart_monitor(void);
00216 
00217 static int capability = AST_FORMAT_ULAW;
00218 static int nonCodecCapability = AST_RTP_DTMF;
00219 
00220 static char ourhost[MAXHOSTNAMELEN];
00221 static struct in_addr __ourip;
00222 static int ourport;
00223 
00224 static int mgcpdebug = 0;
00225 
00226 static struct sched_context *sched;
00227 static struct io_context *io;
00228 /*! The private structures of the  mgcp channels are linked for
00229   ! selecting outgoing channels */
00230    
00231 #define MGCP_MAX_HEADERS   64
00232 #define MGCP_MAX_LINES     64
00233 
00234 struct mgcp_request {
00235    int len;
00236    char *verb;
00237    char *identifier;
00238    char *endpoint;
00239    char *version;
00240    int headers;         /*!< MGCP Headers */
00241    char *header[MGCP_MAX_HEADERS];
00242    int lines;        /*!< SDP Content */
00243    char *line[MGCP_MAX_LINES];
00244    char data[MGCP_MAX_PACKET];
00245    int cmd;                        /*!< int version of verb = command */
00246    unsigned int trid;              /*!< int version of identifier = transaction id */
00247    struct mgcp_request *next;      /*!< next in the queue */
00248 };
00249 
00250 /*! \brief mgcp_message: MGCP message for queuing up */
00251 struct mgcp_message {
00252    struct mgcp_endpoint *owner_ep;
00253    struct mgcp_subchannel *owner_sub;
00254    int retrans;
00255    unsigned long expire;
00256    unsigned int seqno;
00257    int len;
00258    struct mgcp_message *next;
00259    char buf[0];
00260 };
00261 
00262 #define RESPONSE_TIMEOUT 30   /*!< in seconds */
00263 
00264 struct mgcp_response {
00265    time_t whensent;
00266    int len;
00267    int seqno;
00268    struct mgcp_response *next;
00269    char buf[0];
00270 };
00271 
00272 #define MAX_SUBS 2
00273 
00274 #define SUB_REAL 0
00275 #define SUB_ALT  1
00276 
00277 struct mgcp_subchannel {
00278    /*! subchannel magic string. 
00279       Needed to prove that any subchannel pointer passed by asterisk 
00280       really points to a valid subchannel memory area.
00281       Ugly.. But serves the purpose for the time being.
00282     */
00283 #define MGCP_SUBCHANNEL_MAGIC "!978!"
00284    char magic[6]; 
00285    ast_mutex_t lock;
00286    int id;
00287    struct ast_channel *owner;
00288    struct mgcp_endpoint *parent;
00289    struct ast_rtp *rtp;
00290    struct sockaddr_in tmpdest;
00291    char txident[80]; /*! \todo FIXME txident is replaced by rqnt_ident in endpoint. 
00292          This should be obsoleted */
00293    char cxident[80];
00294    char callid[80];
00295    int cxmode;
00296    struct mgcp_request *cx_queue; /*!< pending CX commands */
00297    ast_mutex_t cx_queue_lock;     /*!< CX queue lock */
00298    int nat;
00299    int iseq;                      /*!< Not used? RTP? */
00300    int outgoing;
00301    int alreadygone;
00302    struct mgcp_subchannel *next;  /*!< for out circular linked list */
00303 };
00304 
00305 #define MGCP_ONHOOK  1
00306 #define MGCP_OFFHOOK 2
00307 
00308 #define TYPE_TRUNK 1
00309 #define TYPE_LINE  2
00310 
00311 struct mgcp_endpoint {
00312    ast_mutex_t lock;
00313    char name[80];
00314    struct mgcp_subchannel *sub;     /*!< Pointer to our current connection, channel and stuff */
00315    char accountcode[AST_MAX_ACCOUNT_CODE];
00316    char exten[AST_MAX_EXTENSION];      /*!< Extention where to start */
00317    char context[AST_MAX_EXTENSION];
00318    char language[MAX_LANGUAGE];
00319    char cid_num[AST_MAX_EXTENSION]; /*!< Caller*ID number */
00320    char cid_name[AST_MAX_EXTENSION];   /*!< Caller*ID name */
00321    char lastcallerid[AST_MAX_EXTENSION];  /*!< Last Caller*ID */
00322    char call_forward[AST_MAX_EXTENSION];  /*!< Last Caller*ID */
00323    char mailbox[AST_MAX_EXTENSION];
00324    char musicclass[MAX_MUSICCLASS];
00325    char curtone[80];       /*!< Current tone */
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 canreinvite;
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 mgcp_endpoint *next;
00368    struct mgcp_gateway *parent;
00369 };
00370 
00371 static struct mgcp_gateway {
00372    /* A gateway containing one or more endpoints */
00373    char name[80];
00374    int isnamedottedip; /*!< is the name FQDN or dotted ip */
00375    struct sockaddr_in addr;
00376    struct sockaddr_in defaddr;
00377    struct in_addr ourip;
00378    int dynamic;
00379    int expire;    /*!< XXX Should we ever expire dynamic registrations? XXX */
00380    struct mgcp_endpoint *endpoints;
00381    struct ast_ha *ha;
00382 /* obsolete
00383    time_t lastouttime;
00384    int lastout;
00385    int messagepending;
00386 */
00387 /* Wildcard endpoint name */
00388    char wcardep[30];
00389    struct mgcp_message *msgs; /*!< gw msg queue */
00390    ast_mutex_t msgs_lock;     /*!< queue lock */  
00391    int retransid;             /*!< retrans timer id */
00392    int delme;                 /*!< needed for reload */
00393    struct mgcp_response *responses;
00394    struct mgcp_gateway *next;
00395 } *gateways;
00396 
00397 AST_MUTEX_DEFINE_STATIC(mgcp_reload_lock);
00398 static int mgcp_reloading = 0;
00399 
00400 /*! \brief gatelock: mutex for gateway/endpoint lists */
00401 AST_MUTEX_DEFINE_STATIC(gatelock);
00402 
00403 static int mgcpsock  = -1;
00404 
00405 static struct sockaddr_in bindaddr;
00406 
00407 static struct ast_frame  *mgcp_read(struct ast_channel *ast);
00408 static int transmit_response(struct mgcp_subchannel *sub, char *msg, struct mgcp_request *req, char *msgrest);
00409 static int transmit_notify_request(struct mgcp_subchannel *sub, char *tone);
00410 static int transmit_modify_request(struct mgcp_subchannel *sub);
00411 static int transmit_notify_request_with_callerid(struct mgcp_subchannel *sub, char *tone, char *callernum, char *callername);
00412 static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp, int codecs);
00413 static int transmit_connection_del(struct mgcp_subchannel *sub);
00414 static int transmit_audit_endpoint(struct mgcp_endpoint *p);
00415 static void start_rtp(struct mgcp_subchannel *sub);
00416 static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,  
00417                             int result, unsigned int ident, struct mgcp_request *resp);
00418 static void dump_cmd_queues(struct mgcp_endpoint *p, struct mgcp_subchannel *sub);
00419 static int mgcp_do_reload(void);
00420 static int mgcp_reload(int fd, int argc, char *argv[]);
00421 
00422 static struct ast_channel *mgcp_request(const char *type, int format, void *data, int *cause);
00423 static int mgcp_call(struct ast_channel *ast, char *dest, int timeout);
00424 static int mgcp_hangup(struct ast_channel *ast);
00425 static int mgcp_answer(struct ast_channel *ast);
00426 static struct ast_frame *mgcp_read(struct ast_channel *ast);
00427 static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame);
00428 static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen);
00429 static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00430 static int mgcp_senddigit_begin(struct ast_channel *ast, char digit);
00431 static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
00432 static int mgcp_devicestate(void *data);
00433 
00434 static const struct ast_channel_tech mgcp_tech = {
00435    .type = "MGCP",
00436    .description = tdesc,
00437    .capabilities = AST_FORMAT_ULAW,
00438    .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
00439    .requester = mgcp_request,
00440    .devicestate = mgcp_devicestate,
00441    .call = mgcp_call,
00442    .hangup = mgcp_hangup,
00443    .answer = mgcp_answer,
00444    .read = mgcp_read,
00445    .write = mgcp_write,
00446    .indicate = mgcp_indicate,
00447    .fixup = mgcp_fixup,
00448    .send_digit_begin = mgcp_senddigit_begin,
00449    .send_digit_end = mgcp_senddigit_end,
00450    .bridge = ast_rtp_bridge,
00451 };
00452 
00453 static int has_voicemail(struct mgcp_endpoint *p)
00454 {
00455    return ast_app_has_voicemail(p->mailbox, NULL);
00456 }
00457 
00458 static int unalloc_sub(struct mgcp_subchannel *sub)
00459 {
00460    struct mgcp_endpoint *p = sub->parent;
00461    if (p->sub == sub) {
00462       ast_log(LOG_WARNING, "Trying to unalloc the real channel %s@%s?!?\n", p->name, p->parent->name);
00463       return -1;
00464    }
00465    if (option_debug)
00466       ast_log(LOG_DEBUG, "Released sub %d of channel %s@%s\n", sub->id, p->name, p->parent->name);
00467 
00468    sub->owner = NULL;
00469    if (!ast_strlen_zero(sub->cxident)) {
00470       transmit_connection_del(sub);
00471    }
00472    sub->cxident[0] = '\0';
00473    sub->callid[0] = '\0';
00474    sub->cxmode = MGCP_CX_INACTIVE;
00475    sub->outgoing = 0;
00476    sub->alreadygone = 0;
00477    memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
00478    if (sub->rtp) {
00479       ast_rtp_destroy(sub->rtp);
00480       sub->rtp = NULL;
00481    }
00482    dump_cmd_queues(NULL, sub); /* SC */
00483    return 0;
00484 }
00485 
00486 /* modified for new transport mechanism */
00487 static int __mgcp_xmit(struct mgcp_gateway *gw, char *data, int len)
00488 {
00489    int res;
00490    if (gw->addr.sin_addr.s_addr)
00491       res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->addr, sizeof(struct sockaddr_in));
00492    else 
00493       res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->defaddr, sizeof(struct sockaddr_in));
00494    if (res != len) {
00495       ast_log(LOG_WARNING, "mgcp_xmit returned %d: %s\n", res, strerror(errno));
00496    }
00497    return res;
00498 }
00499 
00500 static int resend_response(struct mgcp_subchannel *sub, struct mgcp_response *resp)
00501 {
00502    struct mgcp_endpoint *p = sub->parent;
00503    int res;
00504    if (mgcpdebug) {
00505       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));
00506    }
00507    res = __mgcp_xmit(p->parent, resp->buf, resp->len);
00508    if (res > 0)
00509       res = 0;
00510    return res;
00511 }
00512 
00513 static int send_response(struct mgcp_subchannel *sub, struct mgcp_request *req)
00514 {
00515    struct mgcp_endpoint *p = sub->parent;
00516    int res;
00517    if (mgcpdebug) {
00518       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));
00519    }
00520    res = __mgcp_xmit(p->parent, req->data, req->len);
00521    if (res > 0)
00522       res = 0;
00523    return res;
00524 }
00525 
00526 /* modified for new transport framework */
00527 static void dump_queue(struct mgcp_gateway *gw, struct mgcp_endpoint *p)
00528 {
00529    struct mgcp_message *cur, *q = NULL, *w, *prev;
00530 
00531    ast_mutex_lock(&gw->msgs_lock);
00532    prev = NULL, cur = gw->msgs;
00533    while (cur) {
00534       if (!p || cur->owner_ep == p) {
00535          if (prev)
00536             prev->next = cur->next;
00537          else
00538             gw->msgs = cur->next;
00539 
00540          ast_log(LOG_NOTICE, "Removing message from %s transaction %u\n", 
00541             gw->name, cur->seqno);
00542 
00543          w = cur;
00544          cur = cur->next;
00545          if (q) {
00546             w->next = q;
00547          } else {
00548             w->next = NULL;
00549          }
00550          q = w;
00551       } else {
00552          prev = cur, cur=cur->next;
00553       }
00554    }
00555    ast_mutex_unlock(&gw->msgs_lock);
00556 
00557    while (q) {
00558       cur = q;
00559       q = q->next;
00560       free(cur);
00561    }
00562 }
00563 
00564 static void mgcp_queue_frame(struct mgcp_subchannel *sub, struct ast_frame *f)
00565 {
00566    for(;;) {
00567       if (sub->owner) {
00568          if (!ast_mutex_trylock(&sub->owner->lock)) {
00569             ast_queue_frame(sub->owner, f);
00570             ast_mutex_unlock(&sub->owner->lock);
00571             break;
00572          } else {
00573             ast_mutex_unlock(&sub->lock);
00574             usleep(1);
00575             ast_mutex_lock(&sub->lock);
00576          }
00577       } else
00578          break;
00579    }
00580 }
00581 
00582 static void mgcp_queue_hangup(struct mgcp_subchannel *sub)
00583 {
00584    for(;;) {
00585       if (sub->owner) {
00586          if (!ast_mutex_trylock(&sub->owner->lock)) {
00587             ast_queue_hangup(sub->owner);
00588             ast_mutex_unlock(&sub->owner->lock);
00589             break;
00590          } else {
00591             ast_mutex_unlock(&sub->lock);
00592             usleep(1);
00593             ast_mutex_lock(&sub->lock);
00594          }
00595       } else
00596          break;
00597    }
00598 }
00599 
00600 static void mgcp_queue_control(struct mgcp_subchannel *sub, int control)
00601 {
00602    struct ast_frame f = { AST_FRAME_CONTROL, };
00603    f.subclass = control;
00604    return mgcp_queue_frame(sub, &f);
00605 }
00606 
00607 static int retrans_pkt(void *data)
00608 {
00609    struct mgcp_gateway *gw = (struct mgcp_gateway *)data;
00610    struct mgcp_message *cur, *exq = NULL, *w, *prev;
00611    int res = 0;
00612 
00613    /* find out expired msgs */
00614    ast_mutex_lock(&gw->msgs_lock);
00615 
00616    prev = NULL, cur = gw->msgs;
00617    while (cur) {
00618       if (cur->retrans < MAX_RETRANS) {
00619          cur->retrans++;
00620          if (mgcpdebug) {
00621             ast_verbose("Retransmitting #%d transaction %u on [%s]\n",
00622                cur->retrans, cur->seqno, gw->name);
00623          }
00624          __mgcp_xmit(gw, cur->buf, cur->len);
00625 
00626          prev = cur;
00627          cur = cur->next;
00628       } else {
00629          if (prev)
00630             prev->next = cur->next;
00631          else
00632             gw->msgs = cur->next;
00633 
00634          ast_log(LOG_WARNING, "Maximum retries exceeded for transaction %u on [%s]\n",
00635             cur->seqno, gw->name);
00636 
00637          w = cur;
00638          cur = cur->next;
00639 
00640          if (exq) {
00641             w->next = exq;
00642          } else {
00643             w->next = NULL;
00644          }
00645          exq = w;
00646       }
00647    }
00648 
00649    if (!gw->msgs) {
00650       gw->retransid = -1;
00651       res = 0;
00652    } else {
00653       res = 1;
00654    }
00655    ast_mutex_unlock(&gw->msgs_lock);
00656 
00657    while (exq) {
00658       cur = exq;
00659       /* time-out transaction */
00660       handle_response(cur->owner_ep, cur->owner_sub, 406, cur->seqno, NULL); 
00661       exq = exq->next;
00662       free(cur);
00663    }
00664 
00665    return res;
00666 }
00667 
00668 /* modified for the new transaction mechanism */
00669 static int mgcp_postrequest(struct mgcp_endpoint *p, struct mgcp_subchannel *sub, 
00670                             char *data, int len, unsigned int seqno)
00671 {
00672    struct mgcp_message *msg = malloc(sizeof(struct mgcp_message) + len);
00673    struct mgcp_message *cur;
00674    struct mgcp_gateway *gw = ((p && p->parent) ? p->parent : NULL);
00675    struct timeval tv;
00676 
00677    if (!msg) {
00678       return -1;
00679    }
00680    if (!gw) {
00681       return -1;
00682    }
00683 /* SC
00684    time(&t);
00685    if (gw->messagepending && (gw->lastouttime + 20 < t)) {
00686       ast_log(LOG_NOTICE, "Timeout waiting for response to message:%d,  lastouttime: %ld, now: %ld.  Dumping pending queue\n",
00687          gw->msgs ? gw->msgs->seqno : -1, (long) gw->lastouttime, (long) t);
00688       dump_queue(sub->parent);
00689    }
00690 */
00691    msg->owner_sub = sub;
00692    msg->owner_ep = p;
00693    msg->seqno = seqno;
00694    msg->next = NULL;
00695    msg->len = len;
00696    msg->retrans = 0;
00697    memcpy(msg->buf, data, msg->len);
00698 
00699    ast_mutex_lock(&gw->msgs_lock);
00700    cur = gw->msgs;
00701    if (cur) {
00702       while(cur->next)
00703          cur = cur->next;
00704       cur->next = msg;
00705    } else {
00706       gw->msgs = msg;
00707    }
00708 
00709    if (gettimeofday(&tv, NULL) < 0) {
00710       /* This shouldn't ever happen, but let's be sure */
00711       ast_log(LOG_NOTICE, "gettimeofday() failed!\n");
00712    } else {
00713       msg->expire = tv.tv_sec * 1000 + tv.tv_usec / 1000 + DEFAULT_RETRANS;
00714 
00715       if (gw->retransid == -1)
00716          gw->retransid = ast_sched_add(sched, DEFAULT_RETRANS, retrans_pkt, (void *)gw);
00717    }
00718    ast_mutex_unlock(&gw->msgs_lock);
00719 /* SC
00720    if (!gw->messagepending) {
00721       gw->messagepending = 1;
00722       gw->lastout = seqno;
00723       gw->lastouttime = t;
00724 */
00725    __mgcp_xmit(gw, msg->buf, msg->len);
00726       /* XXX Should schedule retransmission XXX */
00727 /* SC
00728    } else
00729       if (option_debug)
00730          ast_log(LOG_DEBUG, "Deferring transmission of transaction %d\n", seqno);
00731 */
00732    return 0;
00733 }
00734 
00735 /* modified for new transport */
00736 static int send_request(struct mgcp_endpoint *p, struct mgcp_subchannel *sub, 
00737                         struct mgcp_request *req, unsigned int seqno)
00738 {
00739    int res = 0;
00740    struct mgcp_request **queue, *q, *r, *t;
00741    ast_mutex_t *l;
00742 
00743    if (option_debug)
00744       ast_log(LOG_DEBUG, "Slow sequence is %d\n", p->slowsequence);
00745    if (p->slowsequence) {
00746       queue = &p->cmd_queue;
00747       l = &p->cmd_queue_lock;
00748       ast_mutex_lock(l);
00749    } else {
00750       switch (req->cmd) {
00751       case MGCP_CMD_DLCX:
00752          queue = &sub->cx_queue;
00753          l = &sub->cx_queue_lock;
00754          ast_mutex_lock(l);
00755          q = sub->cx_queue;
00756          /* delete pending cx cmds */
00757          while (q) {
00758             r = q->next;
00759             free(q);
00760             q = r;
00761          }
00762          *queue = NULL;
00763          break;
00764 
00765       case MGCP_CMD_CRCX:
00766       case MGCP_CMD_MDCX:
00767          queue = &sub->cx_queue;
00768          l = &sub->cx_queue_lock;
00769          ast_mutex_lock(l);
00770          break;
00771 
00772       case MGCP_CMD_RQNT:
00773          queue = &p->rqnt_queue;
00774          l = &p->rqnt_queue_lock;
00775          ast_mutex_lock(l);
00776          break;
00777 
00778       default:
00779          queue = &p->cmd_queue;
00780          l = &p->cmd_queue_lock;
00781          ast_mutex_lock(l);
00782          break;
00783       }
00784    }
00785 
00786    r = (struct mgcp_request *) malloc (sizeof(struct mgcp_request));
00787    if (!r) {
00788       ast_log(LOG_WARNING, "Cannot post MGCP request: insufficient memory\n");
00789       ast_mutex_unlock(l);
00790       return -1;
00791    }
00792    memcpy(r, req, sizeof(