Remove debug output.
[asterisk-bristuff.git] / channels / chan_mgcp.c
blobbd57e54f3f49932ae55638b8ea195d6e35d8ac35
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
19 /*! \file
21 * \brief Implementation of Media Gateway Control Protocol
23 * \author Mark Spencer <markster@digium.com>
25 * \par See also
26 * \arg \ref Config_mgcp
28 * \ingroup channel_drivers
30 /*** MODULEINFO
31 <depend>res_features</depend>
32 ***/
34 #include "asterisk.h"
36 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
38 #include <stdio.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <sys/socket.h>
42 #include <sys/ioctl.h>
43 #include <net/if.h>
44 #include <errno.h>
45 #include <stdlib.h>
46 #include <fcntl.h>
47 #include <netdb.h>
48 #include <sys/signal.h>
49 #include <signal.h>
50 #include <netinet/in.h>
51 #include <netinet/in_systm.h>
52 #include <netinet/ip.h>
53 #include <arpa/inet.h>
54 #include <ctype.h>
56 #include "asterisk/lock.h"
57 #include "asterisk/channel.h"
58 #include "asterisk/config.h"
59 #include "asterisk/logger.h"
60 #include "asterisk/module.h"
61 #include "asterisk/pbx.h"
62 #include "asterisk/options.h"
63 #include "asterisk/lock.h"
64 #include "asterisk/sched.h"
65 #include "asterisk/io.h"
66 #include "asterisk/rtp.h"
67 #include "asterisk/acl.h"
68 #include "asterisk/callerid.h"
69 #include "asterisk/cli.h"
70 #include "asterisk/say.h"
71 #include "asterisk/cdr.h"
72 #include "asterisk/astdb.h"
73 #include "asterisk/features.h"
74 #include "asterisk/app.h"
75 #include "asterisk/musiconhold.h"
76 #include "asterisk/utils.h"
77 #include "asterisk/causes.h"
78 #include "asterisk/dsp.h"
79 #include "asterisk/devicestate.h"
80 #include "asterisk/stringfields.h"
81 #include "asterisk/abstract_jb.h"
83 #ifndef IPTOS_MINCOST
84 #define IPTOS_MINCOST 0x02
85 #endif
88 * Define to work around buggy dlink MGCP phone firmware which
89 * appears not to know that "rt" is part of the "G" package.
91 /* #define DLINK_BUGGY_FIRMWARE */
93 #define MGCPDUMPER
94 #define DEFAULT_EXPIRY 120
95 #define MAX_EXPIRY 3600
96 #define CANREINVITE 1
98 #ifndef INADDR_NONE
99 #define INADDR_NONE (in_addr_t)(-1)
100 #endif
102 /*! Global jitterbuffer configuration - by default, jb is disabled */
103 static struct ast_jb_conf default_jbconf =
105 .flags = 0,
106 .max_size = -1,
107 .resync_threshold = -1,
108 .impl = ""
110 static struct ast_jb_conf global_jbconf;
112 static const char tdesc[] = "Media Gateway Control Protocol (MGCP)";
113 static const char config[] = "mgcp.conf";
115 #define MGCP_DTMF_RFC2833 (1 << 0)
116 #define MGCP_DTMF_INBAND (1 << 1)
117 #define MGCP_DTMF_HYBRID (1 << 2)
119 #define DEFAULT_MGCP_GW_PORT 2427 /*!< From RFC 2705 */
120 #define DEFAULT_MGCP_CA_PORT 2727 /*!< From RFC 2705 */
121 #define MGCP_MAX_PACKET 1500 /*!< Also from RFC 2543, should sub headers tho */
122 #define DEFAULT_RETRANS 1000 /*!< How frequently to retransmit */
123 #define MAX_RETRANS 5 /*!< Try only 5 times for retransmissions */
125 /*! MGCP rtp stream modes { */
126 #define MGCP_CX_SENDONLY 0
127 #define MGCP_CX_RECVONLY 1
128 #define MGCP_CX_SENDRECV 2
129 #define MGCP_CX_CONF 3
130 #define MGCP_CX_CONFERENCE 3
131 #define MGCP_CX_MUTE 4
132 #define MGCP_CX_INACTIVE 4
133 /*! } */
135 static char *mgcp_cxmodes[] = {
136 "sendonly",
137 "recvonly",
138 "sendrecv",
139 "confrnce",
140 "inactive"
143 enum {
144 MGCP_CMD_EPCF,
145 MGCP_CMD_CRCX,
146 MGCP_CMD_MDCX,
147 MGCP_CMD_DLCX,
148 MGCP_CMD_RQNT,
149 MGCP_CMD_NTFY,
150 MGCP_CMD_AUEP,
151 MGCP_CMD_AUCX,
152 MGCP_CMD_RSIP
155 static char context[AST_MAX_EXTENSION] = "default";
157 static char language[MAX_LANGUAGE] = "";
158 static char musicclass[MAX_MUSICCLASS] = "";
159 static char cid_num[AST_MAX_EXTENSION] = "";
160 static char cid_name[AST_MAX_EXTENSION] = "";
162 static int dtmfmode = 0;
163 static int nat = 0;
165 static ast_group_t cur_callergroup = 0;
166 static ast_group_t cur_pickupgroup = 0;
168 static int tos = 0;
170 static int immediate = 0;
172 static int callwaiting = 0;
174 static int callreturn = 0;
176 static int slowsequence = 0;
178 static int threewaycalling = 0;
180 /*! This is for flashhook transfers */
181 static int transfer = 0;
183 static int cancallforward = 0;
185 static int singlepath = 0;
187 static int canreinvite = CANREINVITE;
189 static char accountcode[AST_MAX_ACCOUNT_CODE] = "";
191 static char mailbox[AST_MAX_EXTENSION];
193 static int amaflags = 0;
195 static int adsi = 0;
197 static unsigned int oseq;
199 /*! Wait up to 16 seconds for first digit (FXO logic) */
200 static int firstdigittimeout = 16000;
202 /*! How long to wait for following digits (FXO logic) */
203 static int gendigittimeout = 8000;
205 /*! How long to wait for an extra digit, if there is an ambiguous match */
206 static int matchdigittimeout = 3000;
208 /*! Protect the monitoring thread, so only one process can kill or start it, and not
209 when it's doing something critical. */
210 AST_MUTEX_DEFINE_STATIC(netlock);
212 AST_MUTEX_DEFINE_STATIC(monlock);
214 /*! This is the thread for the monitor which checks for input on the channels
215 which are not currently in use. */
216 static pthread_t monitor_thread = AST_PTHREADT_NULL;
218 static int restart_monitor(void);
220 static int capability = AST_FORMAT_ULAW;
221 static int nonCodecCapability = AST_RTP_DTMF;
223 static char ourhost[MAXHOSTNAMELEN];
224 static struct in_addr __ourip;
225 static int ourport;
227 static int mgcpdebug = 0;
229 static struct sched_context *sched;
230 static struct io_context *io;
231 /*! The private structures of the mgcp channels are linked for
232 ! selecting outgoing channels */
234 #define MGCP_MAX_HEADERS 64
235 #define MGCP_MAX_LINES 64
237 struct mgcp_request {
238 int len;
239 char *verb;
240 char *identifier;
241 char *endpoint;
242 char *version;
243 int headers; /*!< MGCP Headers */
244 char *header[MGCP_MAX_HEADERS];
245 int lines; /*!< SDP Content */
246 char *line[MGCP_MAX_LINES];
247 char data[MGCP_MAX_PACKET];
248 int cmd; /*!< int version of verb = command */
249 unsigned int trid; /*!< int version of identifier = transaction id */
250 struct mgcp_request *next; /*!< next in the queue */
253 /*! \brief mgcp_message: MGCP message for queuing up */
254 struct mgcp_message {
255 struct mgcp_endpoint *owner_ep;
256 struct mgcp_subchannel *owner_sub;
257 int retrans;
258 unsigned long expire;
259 unsigned int seqno;
260 int len;
261 struct mgcp_message *next;
262 char buf[0];
265 #define RESPONSE_TIMEOUT 30 /*!< in seconds */
267 struct mgcp_response {
268 time_t whensent;
269 int len;
270 int seqno;
271 struct mgcp_response *next;
272 char buf[0];
275 #define MAX_SUBS 2
277 #define SUB_REAL 0
278 #define SUB_ALT 1
280 struct mgcp_subchannel {
281 /*! subchannel magic string.
282 Needed to prove that any subchannel pointer passed by asterisk
283 really points to a valid subchannel memory area.
284 Ugly.. But serves the purpose for the time being.
286 #define MGCP_SUBCHANNEL_MAGIC "!978!"
287 char magic[6];
288 ast_mutex_t lock;
289 int id;
290 struct ast_channel *owner;
291 struct mgcp_endpoint *parent;
292 struct ast_rtp *rtp;
293 struct sockaddr_in tmpdest;
294 char txident[80]; /*! \todo FIXME txident is replaced by rqnt_ident in endpoint.
295 This should be obsoleted */
296 char cxident[80];
297 char callid[80];
298 int cxmode;
299 struct mgcp_request *cx_queue; /*!< pending CX commands */
300 ast_mutex_t cx_queue_lock; /*!< CX queue lock */
301 int nat;
302 int iseq; /*!< Not used? RTP? */
303 int outgoing;
304 int alreadygone;
305 struct mgcp_subchannel *next; /*!< for out circular linked list */
308 #define MGCP_ONHOOK 1
309 #define MGCP_OFFHOOK 2
311 #define TYPE_TRUNK 1
312 #define TYPE_LINE 2
314 struct mgcp_endpoint {
315 ast_mutex_t lock;
316 char name[80];
317 struct mgcp_subchannel *sub; /*!< Pointer to our current connection, channel and stuff */
318 char accountcode[AST_MAX_ACCOUNT_CODE];
319 char exten[AST_MAX_EXTENSION]; /*!< Extention where to start */
320 char context[AST_MAX_EXTENSION];
321 char language[MAX_LANGUAGE];
322 char cid_num[AST_MAX_EXTENSION]; /*!< Caller*ID number */
323 char cid_name[AST_MAX_EXTENSION]; /*!< Caller*ID name */
324 char lastcallerid[AST_MAX_EXTENSION]; /*!< Last Caller*ID */
325 char call_forward[AST_MAX_EXTENSION]; /*!< Last Caller*ID */
326 char mailbox[AST_MAX_EXTENSION];
327 char musicclass[MAX_MUSICCLASS];
328 char curtone[80]; /*!< Current tone */
329 char dtmf_buf[AST_MAX_EXTENSION]; /*!< place to collect digits be */
330 ast_group_t callgroup;
331 ast_group_t pickupgroup;
332 int callwaiting;
333 int hascallwaiting;
334 int transfer;
335 int threewaycalling;
336 int singlepath;
337 int cancallforward;
338 int canreinvite;
339 int callreturn;
340 int dnd; /* How does this affect callwait? Do we just deny a mgcp_request if we're dnd? */
341 int hascallerid;
342 int hidecallerid;
343 int dtmfmode;
344 int amaflags;
345 int type;
346 int slowsequence; /*!< MS: Sequence the endpoint as a whole */
347 int group;
348 int iseq; /*!< Not used? */
349 int lastout; /*!< tracking this on the subchannels. Is it needed here? */
350 int needdestroy; /*!< Not used? */
351 int capability;
352 int nonCodecCapability;
353 int onhooktime;
354 int msgstate; /*!< voicemail message state */
355 int immediate;
356 int hookstate;
357 int adsi;
358 char rqnt_ident[80]; /*!< request identifier */
359 struct mgcp_request *rqnt_queue; /*!< pending RQNT commands */
360 ast_mutex_t rqnt_queue_lock;
361 struct mgcp_request *cmd_queue; /*!< pending commands other than RQNT */
362 ast_mutex_t cmd_queue_lock;
363 int delme; /*!< needed for reload */
364 int needaudit; /*!< needed for reload */
365 struct ast_dsp *dsp; /*!< XXX Should there be a dsp/subchannel? XXX */
366 /* owner is tracked on the subchannels, and the *sub indicates whos in charge */
367 /* struct ast_channel *owner; */
368 /* struct ast_rtp *rtp; */
369 /* struct sockaddr_in tmpdest; */
370 /* message go the the endpoint and not the channel so they stay here */
371 struct mgcp_endpoint *next;
372 struct mgcp_gateway *parent;
375 static struct mgcp_gateway {
376 /* A gateway containing one or more endpoints */
377 char name[80];
378 int isnamedottedip; /*!< is the name FQDN or dotted ip */
379 struct sockaddr_in addr;
380 struct sockaddr_in defaddr;
381 struct in_addr ourip;
382 int dynamic;
383 int expire; /*!< XXX Should we ever expire dynamic registrations? XXX */
384 struct mgcp_endpoint *endpoints;
385 struct ast_ha *ha;
386 /* obsolete
387 time_t lastouttime;
388 int lastout;
389 int messagepending;
391 /* Wildcard endpoint name */
392 char wcardep[30];
393 struct mgcp_message *msgs; /*!< gw msg queue */
394 ast_mutex_t msgs_lock; /*!< queue lock */
395 int retransid; /*!< retrans timer id */
396 int delme; /*!< needed for reload */
397 struct mgcp_response *responses;
398 struct mgcp_gateway *next;
399 } *gateways;
401 AST_MUTEX_DEFINE_STATIC(mgcp_reload_lock);
402 static int mgcp_reloading = 0;
404 /*! \brief gatelock: mutex for gateway/endpoint lists */
405 AST_MUTEX_DEFINE_STATIC(gatelock);
407 static int mgcpsock = -1;
409 static struct sockaddr_in bindaddr;
411 static struct ast_frame *mgcp_read(struct ast_channel *ast);
412 static int transmit_response(struct mgcp_subchannel *sub, char *msg, struct mgcp_request *req, char *msgrest);
413 static int transmit_notify_request(struct mgcp_subchannel *sub, char *tone);
414 static int transmit_modify_request(struct mgcp_subchannel *sub);
415 static int transmit_notify_request_with_callerid(struct mgcp_subchannel *sub, char *tone, char *callernum, char *callername);
416 static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp, int codecs);
417 static int transmit_connection_del(struct mgcp_subchannel *sub);
418 static int transmit_audit_endpoint(struct mgcp_endpoint *p);
419 static void start_rtp(struct mgcp_subchannel *sub);
420 static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,
421 int result, unsigned int ident, struct mgcp_request *resp);
422 static void dump_cmd_queues(struct mgcp_endpoint *p, struct mgcp_subchannel *sub);
423 static int mgcp_do_reload(void);
424 static int mgcp_reload(int fd, int argc, char *argv[]);
426 static struct ast_channel *mgcp_request(const char *type, int format, void *data, int *cause);
427 static int mgcp_call(struct ast_channel *ast, char *dest, int timeout);
428 static int mgcp_hangup(struct ast_channel *ast);
429 static int mgcp_answer(struct ast_channel *ast);
430 static struct ast_frame *mgcp_read(struct ast_channel *ast);
431 static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame);
432 static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen);
433 static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
434 static int mgcp_senddigit_begin(struct ast_channel *ast, char digit);
435 static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
436 static int mgcp_devicestate(void *data);
437 static void add_header_offhook(struct mgcp_subchannel *sub, struct mgcp_request *resp);
439 static const struct ast_channel_tech mgcp_tech = {
440 .type = "MGCP",
441 .description = tdesc,
442 .capabilities = AST_FORMAT_ULAW,
443 .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
444 .requester = mgcp_request,
445 .devicestate = mgcp_devicestate,
446 .call = mgcp_call,
447 .hangup = mgcp_hangup,
448 .answer = mgcp_answer,
449 .read = mgcp_read,
450 .write = mgcp_write,
451 .indicate = mgcp_indicate,
452 .fixup = mgcp_fixup,
453 .send_digit_begin = mgcp_senddigit_begin,
454 .send_digit_end = mgcp_senddigit_end,
455 .bridge = ast_rtp_bridge,
458 static int has_voicemail(struct mgcp_endpoint *p)
460 return ast_app_has_voicemail(p->mailbox, NULL);
463 static int unalloc_sub(struct mgcp_subchannel *sub)
465 struct mgcp_endpoint *p = sub->parent;
466 if (p->sub == sub) {
467 ast_log(LOG_WARNING, "Trying to unalloc the real channel %s@%s?!?\n", p->name, p->parent->name);
468 return -1;
470 ast_log(LOG_DEBUG, "Released sub %d of channel %s@%s\n", sub->id, p->name, p->parent->name);
472 sub->owner = NULL;
473 if (!ast_strlen_zero(sub->cxident)) {
474 transmit_connection_del(sub);
476 sub->cxident[0] = '\0';
477 sub->callid[0] = '\0';
478 sub->cxmode = MGCP_CX_INACTIVE;
479 sub->outgoing = 0;
480 sub->alreadygone = 0;
481 memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
482 if (sub->rtp) {
483 ast_rtp_destroy(sub->rtp);
484 sub->rtp = NULL;
486 dump_cmd_queues(NULL, sub); /* SC */
487 return 0;
490 /* modified for new transport mechanism */
491 static int __mgcp_xmit(struct mgcp_gateway *gw, char *data, int len)
493 int res;
494 if (gw->addr.sin_addr.s_addr)
495 res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->addr, sizeof(struct sockaddr_in));
496 else
497 res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->defaddr, sizeof(struct sockaddr_in));
498 if (res != len) {
499 ast_log(LOG_WARNING, "mgcp_xmit returned %d: %s\n", res, strerror(errno));
501 return res;
504 static int resend_response(struct mgcp_subchannel *sub, struct mgcp_response *resp)
506 struct mgcp_endpoint *p = sub->parent;
507 int res;
508 if (mgcpdebug) {
509 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));
511 res = __mgcp_xmit(p->parent, resp->buf, resp->len);
512 if (res > 0)
513 res = 0;
514 return res;
517 static int send_response(struct mgcp_subchannel *sub, struct mgcp_request *req)
519 struct mgcp_endpoint *p = sub->parent;
520 int res;
521 if (mgcpdebug) {
522 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));
524 res = __mgcp_xmit(p->parent, req->data, req->len);
525 if (res > 0)
526 res = 0;
527 return res;
530 /* modified for new transport framework */
531 static void dump_queue(struct mgcp_gateway *gw, struct mgcp_endpoint *p)
533 struct mgcp_message *cur, *q = NULL, *w, *prev;
535 ast_mutex_lock(&gw->msgs_lock);
536 prev = NULL, cur = gw->msgs;
537 while (cur) {
538 if (!p || cur->owner_ep == p) {
539 if (prev)
540 prev->next = cur->next;
541 else
542 gw->msgs = cur->next;
544 ast_log(LOG_NOTICE, "Removing message from %s transaction %u\n",
545 gw->name, cur->seqno);
547 w = cur;
548 cur = cur->next;
549 if (q) {
550 w->next = q;
551 } else {
552 w->next = NULL;
554 q = w;
555 } else {
556 prev = cur, cur=cur->next;
559 ast_mutex_unlock(&gw->msgs_lock);
561 while (q) {
562 cur = q;
563 q = q->next;
564 free(cur);
568 static void mgcp_queue_frame(struct mgcp_subchannel *sub, struct ast_frame *f)
570 for(;;) {
571 if (sub->owner) {
572 if (!ast_mutex_trylock(&sub->owner->lock)) {
573 ast_queue_frame(sub->owner, f);
574 ast_mutex_unlock(&sub->owner->lock);
575 break;
576 } else {
577 ast_mutex_unlock(&sub->lock);
578 usleep(1);
579 ast_mutex_lock(&sub->lock);
581 } else
582 break;
586 static void mgcp_queue_hangup(struct mgcp_subchannel *sub)
588 for(;;) {
589 if (sub->owner) {
590 if (!ast_mutex_trylock(&sub->owner->lock)) {
591 ast_queue_hangup(sub->owner);
592 ast_mutex_unlock(&sub->owner->lock);
593 break;
594 } else {
595 ast_mutex_unlock(&sub->lock);
596 usleep(1);
597 ast_mutex_lock(&sub->lock);
599 } else
600 break;
604 static void mgcp_queue_control(struct mgcp_subchannel *sub, int control)
606 struct ast_frame f = { AST_FRAME_CONTROL, };
607 f.subclass = control;
608 return mgcp_queue_frame(sub, &f);
611 static int retrans_pkt(const void *data)
613 struct mgcp_gateway *gw = (struct mgcp_gateway *)data;
614 struct mgcp_message *cur, *exq = NULL, *w, *prev;
615 int res = 0;
617 /* find out expired msgs */
618 ast_mutex_lock(&gw->msgs_lock);
620 prev = NULL, cur = gw->msgs;
621 while (cur) {
622 if (cur->retrans < MAX_RETRANS) {
623 cur->retrans++;
624 if (mgcpdebug) {
625 ast_verbose("Retransmitting #%d transaction %u on [%s]\n",
626 cur->retrans, cur->seqno, gw->name);
628 __mgcp_xmit(gw, cur->buf, cur->len);
630 prev = cur;
631 cur = cur->next;
632 } else {
633 if (prev)
634 prev->next = cur->next;
635 else
636 gw->msgs = cur->next;
638 ast_log(LOG_WARNING, "Maximum retries exceeded for transaction %u on [%s]\n",
639 cur->seqno, gw->name);
641 w = cur;
642 cur = cur->next;
644 if (exq) {
645 w->next = exq;
646 } else {
647 w->next = NULL;
649 exq = w;
653 if (!gw->msgs) {
654 gw->retransid = -1;
655 res = 0;
656 } else {
657 res = 1;
659 ast_mutex_unlock(&gw->msgs_lock);
661 while (exq) {
662 cur = exq;
663 /* time-out transaction */
664 handle_response(cur->owner_ep, cur->owner_sub, 406, cur->seqno, NULL);
665 exq = exq->next;
666 free(cur);
669 return res;
672 /* modified for the new transaction mechanism */
673 static int mgcp_postrequest(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,
674 char *data, int len, unsigned int seqno)
676 struct mgcp_message *msg = malloc(sizeof(struct mgcp_message) + len);
677 struct mgcp_message *cur;
678 struct mgcp_gateway *gw = ((p && p->parent) ? p->parent : NULL);
679 struct timeval tv;
681 if (!msg) {
682 return -1;
684 if (!gw) {
685 return -1;
687 /* SC
688 time(&t);
689 if (gw->messagepending && (gw->lastouttime + 20 < t)) {
690 ast_log(LOG_NOTICE, "Timeout waiting for response to message:%d, lastouttime: %ld, now: %ld. Dumping pending queue\n",
691 gw->msgs ? gw->msgs->seqno : -1, (long) gw->lastouttime, (long) t);
692 dump_queue(sub->parent);
695 msg->owner_sub = sub;
696 msg->owner_ep = p;
697 msg->seqno = seqno;
698 msg->next = NULL;
699 msg->len = len;
700 msg->retrans = 0;
701 memcpy(msg->buf, data, msg->len);
703 ast_mutex_lock(&gw->msgs_lock);
704 cur = gw->msgs;
705 if (cur) {
706 while(cur->next)
707 cur = cur->next;
708 cur->next = msg;
709 } else {
710 gw->msgs = msg;
713 if (gettimeofday(&tv, NULL) < 0) {
714 /* This shouldn't ever happen, but let's be sure */
715 ast_log(LOG_NOTICE, "gettimeofday() failed!\n");
716 } else {
717 msg->expire = tv.tv_sec * 1000 + tv.tv_usec / 1000 + DEFAULT_RETRANS;
719 if (gw->retransid == -1)
720 gw->retransid = ast_sched_add(sched, DEFAULT_RETRANS, retrans_pkt, (void *)gw);
722 ast_mutex_unlock(&gw->msgs_lock);
723 /* SC
724 if (!gw->messagepending) {
725 gw->messagepending = 1;
726 gw->lastout = seqno;
727 gw->lastouttime = t;
729 __mgcp_xmit(gw, msg->buf, msg->len);
730 /* XXX Should schedule retransmission XXX */
731 /* SC
732 } else
733 ast_log(LOG_DEBUG, "Deferring transmission of transaction %d\n", seqno);
735 return 0;
738 /* modified for new transport */
739 static int send_request(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,
740 struct mgcp_request *req, unsigned int seqno)
742 int res = 0;
743 struct mgcp_request **queue, *q, *r, *t;
744 ast_mutex_t *l;
746 ast_log(LOG_DEBUG, "Slow sequence is %d\n", p->slowsequence);
747 if (p->slowsequence) {
748 queue = &p->cmd_queue;
749 l = &p->cmd_queue_lock;
750 ast_mutex_lock(l);
751 } else {
752 switch (req->cmd) {
753 case MGCP_CMD_DLCX:
754 queue = &sub->cx_queue;
755 l = &sub->cx_queue_lock;
756 ast_mutex_lock(l);
757 q = sub->cx_queue;
758 /* delete pending cx cmds */
759 while (q) {
760 r = q->next;
761 free(q);
762 q = r;
764 *queue = NULL;
765 break;
767 case MGCP_CMD_CRCX:
768 case MGCP_CMD_MDCX:
769 queue = &sub->cx_queue;
770 l = &sub->cx_queue_lock;
771 ast_mutex_lock(l);
772 break;
774 case MGCP_CMD_RQNT:
775 queue = &p->rqnt_queue;
776 l = &p->rqnt_queue_lock;
777 ast_mutex_lock(l);
778 break;
780 default:
781 queue = &p->cmd_queue;
782 l = &p->cmd_queue_lock;
783 ast_mutex_lock(l);
784 break;
788 r = (struct mgcp_request *) malloc (sizeof(struct mgcp_request));
789 if (!r) {
790 ast_log(LOG_WARNING, "Cannot post MGCP request: insufficient memory\n");
791 ast_mutex_unlock(l);
792 return -1;
794 memcpy(r, req, sizeof(struct mgcp_request));
796 if (!(*queue)) {
797 if (mgcpdebug) {
798 ast_verbose("Posting Request:\n%s to %s:%d\n", req->data,
799 ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
802 res = mgcp_postrequest(p, sub, req->data, req->len, seqno);
803 } else {
804 if (mgcpdebug) {
805 ast_verbose("Queueing Request:\n%s to %s:%d\n", req->data,
806 ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
810 /* XXX find tail. We could also keep tail in the data struct for faster access */
811 for (t = *queue; t && t->next; t = t->next);
813 r->next = NULL;
814 if (t)
815 t->next = r;
816 else
817 *queue = r;
819 ast_mutex_unlock(l);
821 return res;
824 static int mgcp_call(struct ast_channel *ast, char *dest, int timeout)
826 int res;
827 struct mgcp_endpoint *p;
828 struct mgcp_subchannel *sub;
829 char tone[50] = "";
830 const char *distinctive_ring = NULL;
831 struct varshead *headp;
832 struct ast_var_t *current;
834 if (mgcpdebug) {
835 ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_call(%s)\n", ast->name);
837 sub = ast->tech_pvt;
838 p = sub->parent;
839 headp = &ast->varshead;
840 AST_LIST_TRAVERSE(headp,current,entries) {
841 /* Check whether there is an ALERT_INFO variable */
842 if (strcasecmp(ast_var_name(current),"ALERT_INFO") == 0) {
843 distinctive_ring = ast_var_value(current);
847 ast_mutex_lock(&sub->lock);
848 switch (p->hookstate) {
849 case MGCP_OFFHOOK:
850 if (!ast_strlen_zero(distinctive_ring)) {
851 snprintf(tone, sizeof(tone), "L/wt%s", distinctive_ring);
852 if (mgcpdebug) {
853 ast_verbose(VERBOSE_PREFIX_3 "MGCP distinctive callwait %s\n", tone);
855 } else {
856 snprintf(tone, sizeof(tone), "L/wt");
857 if (mgcpdebug) {
858 ast_verbose(VERBOSE_PREFIX_3 "MGCP normal callwait %s\n", tone);
861 break;
862 case MGCP_ONHOOK:
863 default:
864 if (!ast_strlen_zero(distinctive_ring)) {
865 snprintf(tone, sizeof(tone), "L/r%s", distinctive_ring);
866 if (mgcpdebug) {
867 ast_verbose(VERBOSE_PREFIX_3 "MGCP distinctive ring %s\n", tone);
869 } else {
870 snprintf(tone, sizeof(tone), "L/rg");
871 if (mgcpdebug) {
872 ast_verbose(VERBOSE_PREFIX_3 "MGCP default ring\n");
875 break;
878 if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
879 ast_log(LOG_WARNING, "mgcp_call called on %s, neither down nor reserved\n", ast->name);
880 ast_mutex_unlock(&sub->lock);
881 return -1;
884 res = 0;
885 sub->outgoing = 1;
886 sub->cxmode = MGCP_CX_RECVONLY;
887 if (p->type == TYPE_LINE) {
888 if (!sub->rtp) {
889 start_rtp(sub);
890 } else {
891 transmit_modify_request(sub);
894 if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) {
895 /* try to prevent a callwait from disturbing the other connection */
896 sub->next->cxmode = MGCP_CX_RECVONLY;
897 transmit_modify_request(sub->next);
900 transmit_notify_request_with_callerid(sub, tone, ast->cid.cid_num, ast->cid.cid_name);
901 ast_setstate(ast, AST_STATE_RINGING);
903 if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) {
904 /* Put the connection back in sendrecv */
905 sub->next->cxmode = MGCP_CX_SENDRECV;
906 transmit_modify_request(sub->next);
908 } else {
909 ast_log(LOG_NOTICE, "Don't know how to dial on trunks yet\n");
910 res = -1;
912 ast_mutex_unlock(&sub->lock);
913 ast_queue_control(ast, AST_CONTROL_RINGING);
914 return res;
917 static int mgcp_hangup(struct ast_channel *ast)
919 struct mgcp_subchannel *sub = ast->tech_pvt;
920 struct mgcp_endpoint *p = sub->parent;
922 if (option_debug) {
923 ast_log(LOG_DEBUG, "mgcp_hangup(%s)\n", ast->name);
925 if (!ast->tech_pvt) {
926 ast_log(LOG_DEBUG, "Asked to hangup channel not connected\n");
927 return 0;
929 if (strcmp(sub->magic, MGCP_SUBCHANNEL_MAGIC)) {
930 ast_log(LOG_DEBUG, "Invalid magic. MGCP subchannel freed up already.\n");
931 return 0;
933 ast_mutex_lock(&sub->lock);
934 if (mgcpdebug) {
935 ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s\n", ast->name, p->name, p->parent->name);
938 if ((p->dtmfmode & MGCP_DTMF_INBAND) && p->dsp) {
939 /* check whether other channel is active. */
940 if (!sub->next->owner) {
941 if (p->dtmfmode & MGCP_DTMF_HYBRID)
942 p->dtmfmode &= ~MGCP_DTMF_INBAND;
943 if (mgcpdebug) {
944 ast_verbose(VERBOSE_PREFIX_2 "MGCP free dsp on %s@%s\n", p->name, p->parent->name);
946 ast_dsp_free(p->dsp);
947 p->dsp = NULL;
951 sub->owner = NULL;
952 if (!ast_strlen_zero(sub->cxident)) {
953 transmit_connection_del(sub);
955 sub->cxident[0] = '\0';
956 if ((sub == p->sub) && sub->next->owner) {
957 if (p->hookstate == MGCP_OFFHOOK) {
958 if (sub->next->owner && ast_bridged_channel(sub->next->owner)) {
959 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);
961 } else {
962 /* set our other connection as the primary and swith over to it */
963 p->sub = sub->next;
964 p->sub->cxmode = MGCP_CX_RECVONLY;
965 transmit_modify_request(p->sub);
966 if (sub->next->owner && ast_bridged_channel(sub->next->owner)) {
967 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);
971 } else if ((sub == p->sub->next) && p->hookstate == MGCP_OFFHOOK) {
972 transmit_notify_request(sub, "L/v");
973 } else if (p->hookstate == MGCP_OFFHOOK) {
974 transmit_notify_request(sub, "L/ro");
975 } else {
976 transmit_notify_request(sub, "");
979 ast->tech_pvt = NULL;
980 sub->alreadygone = 0;
981 sub->outgoing = 0;
982 sub->cxmode = MGCP_CX_INACTIVE;
983 sub->callid[0] = '\0';
984 if (p) {
985 memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
987 /* Reset temporary destination */
988 memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
989 if (sub->rtp) {
990 ast_rtp_destroy(sub->rtp);
991 sub->rtp = NULL;
994 ast_module_unref(ast_module_info->self);
996 if ((p->hookstate == MGCP_ONHOOK) && (!sub->next->rtp)) {
997 p->hidecallerid = 0;
998 if (p->hascallwaiting && !p->callwaiting) {
999 if (option_verbose > 2)
1000 ast_verbose(VERBOSE_PREFIX_3 "Enabling call waiting on %s\n", ast->name);
1001 p->callwaiting = -1;
1003 if (has_voicemail(p)) {
1004 if (mgcpdebug) {
1005 ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s set vmwi(+)\n",
1006 ast->name, p->name, p->parent->name);
1008 transmit_notify_request(sub, "L/vmwi(+)");
1009 } else {
1010 if (mgcpdebug) {
1011 ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s set vmwi(-)\n",
1012 ast->name, p->name, p->parent->name);
1014 transmit_notify_request(sub, "L/vmwi(-)");
1017 ast_mutex_unlock(&sub->lock);
1018 return 0;
1021 static int mgcp_show_endpoints(int fd, int argc, char *argv[])
1023 struct mgcp_gateway *g;
1024 struct mgcp_endpoint *e;
1025 int hasendpoints = 0;
1027 if (argc != 3)
1028 return RESULT_SHOWUSAGE;
1029 ast_mutex_lock(&gatelock);
1030 g = gateways;
1031 while(g) {
1032 e = g->endpoints;
1033 ast_cli(fd, "Gateway '%s' at %s (%s)\n", g->name, g->addr.sin_addr.s_addr ? ast_inet_ntoa(g->addr.sin_addr) : ast_inet_ntoa(g->defaddr.sin_addr), g->dynamic ? "Dynamic" : "Static");
1034 while(e) {
1035 /* Don't show wilcard endpoint */
1036 if (strcmp(e->name, g->wcardep) !=0)
1037 ast_cli(fd, " -- '%s@%s in '%s' is %s\n", e->name, g->name, e->context, e->sub->owner ? "active" : "idle");
1038 hasendpoints = 1;
1039 e = e->next;
1041 if (!hasendpoints) {
1042 ast_cli(fd, " << No Endpoints Defined >> ");
1044 g = g->next;
1046 ast_mutex_unlock(&gatelock);
1047 return RESULT_SUCCESS;
1050 static char show_endpoints_usage[] =
1051 "Usage: mgcp show endpoints\n"
1052 " Lists all endpoints known to the MGCP (Media Gateway Control Protocol) subsystem.\n";
1054 static char audit_endpoint_usage[] =
1055 "Usage: mgcp audit endpoint <endpointid>\n"
1056 " Lists the capabilities of an endpoint in the MGCP (Media Gateway Control Protocol) subsystem.\n"
1057 " mgcp debug MUST be on to see the results of this command.\n";
1059 static char debug_usage[] =
1060 "Usage: mgcp set debug\n"
1061 " Enables dumping of MGCP packets for debugging purposes\n";
1063 static char no_debug_usage[] =
1064 "Usage: mgcp set debug off\n"
1065 " Disables dumping of MGCP packets for debugging purposes\n";
1067 static char mgcp_reload_usage[] =
1068 "Usage: mgcp reload\n"
1069 " Reloads MGCP configuration from mgcp.conf\n"
1070 " Deprecated: please use 'reload chan_mgcp.so' instead.\n";
1072 static int mgcp_audit_endpoint(int fd, int argc, char *argv[])
1074 struct mgcp_gateway *g;
1075 struct mgcp_endpoint *e;
1076 int found = 0;
1077 char *ename,*gname, *c;
1079 if (!mgcpdebug) {
1080 return RESULT_SHOWUSAGE;
1082 if (argc != 4)
1083 return RESULT_SHOWUSAGE;
1084 /* split the name into parts by null */
1085 ename = argv[3];
1086 gname = ename;
1087 while (*gname) {
1088 if (*gname == '@') {
1089 *gname = 0;
1090 gname++;
1091 break;
1093 gname++;
1095 if (gname[0] == '[')
1096 gname++;
1097 if ((c = strrchr(gname, ']')))
1098 *c = '\0';
1099 ast_mutex_lock(&gatelock);
1100 g = gateways;
1101 while(g) {
1102 if (!strcasecmp(g->name, gname)) {
1103 e = g->endpoints;
1104 while(e) {
1105 if (!strcasecmp(e->name, ename)) {
1106 found = 1;
1107 transmit_audit_endpoint(e);
1108 break;
1110 e = e->next;
1112 if (found) {
1113 break;
1116 g = g->next;
1118 if (!found) {
1119 ast_cli(fd, " << Could not find endpoint >> ");
1121 ast_mutex_unlock(&gatelock);
1122 return RESULT_SUCCESS;
1125 static int mgcp_do_debug(int fd, int argc, char *argv[])
1127 if (argc != 3)
1128 return RESULT_SHOWUSAGE;
1129 mgcpdebug = 1;
1130 ast_cli(fd, "MGCP Debugging Enabled\n");
1131 return RESULT_SUCCESS;
1134 static int mgcp_no_debug(int fd, int argc, char *argv[])
1136 if (argc != 4)
1137 return RESULT_SHOWUSAGE;
1138 mgcpdebug = 0;
1139 ast_cli(fd, "MGCP Debugging Disabled\n");
1140 return RESULT_SUCCESS;
1143 static struct ast_cli_entry cli_mgcp[] = {
1144 { { "mgcp", "audit", "endpoint", NULL },
1145 mgcp_audit_endpoint, "Audit specified MGCP endpoint",
1146 audit_endpoint_usage },
1148 { { "mgcp", "show", "endpoints", NULL },
1149 mgcp_show_endpoints, "List defined MGCP endpoints",
1150 show_endpoints_usage },
1152 { { "mgcp", "set", "debug", NULL },
1153 mgcp_do_debug, "Enable MGCP debugging",
1154 debug_usage },
1156 { { "mgcp", "set", "debug", "off", NULL },
1157 mgcp_no_debug, "Disable MGCP debugging",
1158 no_debug_usage },
1160 { { "mgcp", "reload", NULL },
1161 mgcp_reload, "Reload MGCP configuration",
1162 mgcp_reload_usage },
1165 static int mgcp_answer(struct ast_channel *ast)
1167 int res = 0;
1168 struct mgcp_subchannel *sub = ast->tech_pvt;
1169 struct mgcp_endpoint *p = sub->parent;
1171 ast_mutex_lock(&sub->lock);
1172 sub->cxmode = MGCP_CX_SENDRECV;
1173 if (!sub->rtp) {
1174 start_rtp(sub);
1175 } else {
1176 transmit_modify_request(sub);
1178 /* verbose level check */
1179 if (option_verbose > 2) {
1180 ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_answer(%s) on %s@%s-%d\n",
1181 ast->name, p->name, p->parent->name, sub->id);
1183 if (ast->_state != AST_STATE_UP) {
1184 ast_setstate(ast, AST_STATE_UP);
1185 if (option_debug)
1186 ast_log(LOG_DEBUG, "mgcp_answer(%s)\n", ast->name);
1187 transmit_notify_request(sub, "");
1188 transmit_modify_request(sub);
1190 ast_mutex_unlock(&sub->lock);
1191 return res;
1194 static struct ast_frame *mgcp_rtp_read(struct mgcp_subchannel *sub)
1196 /* Retrieve audio/etc from channel. Assumes sub->lock is already held. */
1197 struct ast_frame *f;
1199 f = ast_rtp_read(sub->rtp);
1200 /* Don't send RFC2833 if we're not supposed to */
1201 if (f && (f->frametype == AST_FRAME_DTMF) && !(sub->parent->dtmfmode & MGCP_DTMF_RFC2833))
1202 return &ast_null_frame;
1203 if (sub->owner) {
1204 /* We already hold the channel lock */
1205 if (f->frametype == AST_FRAME_VOICE) {
1206 if (f->subclass != sub->owner->nativeformats) {
1207 ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
1208 sub->owner->nativeformats = f->subclass;
1209 ast_set_read_format(sub->owner, sub->owner->readformat);
1210 ast_set_write_format(sub->owner, sub->owner->writeformat);
1212 /* Courtesy fearnor aka alex@pilosoft.com */
1213 if ((sub->parent->dtmfmode & MGCP_DTMF_INBAND) && (sub->parent->dsp)) {
1214 #if 0
1215 ast_log(LOG_NOTICE, "MGCP ast_dsp_process\n");
1216 #endif
1217 f = ast_dsp_process(sub->owner, sub->parent->dsp, f);
1221 return f;
1225 static struct ast_frame *mgcp_read(struct ast_channel *ast)
1227 struct ast_frame *f;
1228 struct mgcp_subchannel *sub = ast->tech_pvt;
1229 ast_mutex_lock(&sub->lock);
1230 f = mgcp_rtp_read(sub);
1231 ast_mutex_unlock(&sub->lock);
1232 return f;
1235 static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame)
1237 struct mgcp_subchannel *sub = ast->tech_pvt;
1238 int res = 0;
1239 if (frame->frametype != AST_FRAME_VOICE) {
1240 if (frame->frametype == AST_FRAME_IMAGE)
1241 return 0;
1242 else {
1243 ast_log(LOG_WARNING, "Can't send %d type frames with MGCP write\n", frame->frametype);
1244 return 0;
1246 } else {
1247 if (!(frame->subclass & ast->nativeformats)) {
1248 ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
1249 frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat);
1250 return -1;
1253 if (sub) {
1254 ast_mutex_lock(&sub->lock);
1255 if ((sub->parent->sub == sub) || !sub->parent->singlepath) {
1256 if (sub->rtp) {
1257 res = ast_rtp_write(sub->rtp, frame);
1260 ast_mutex_unlock(&sub->lock);
1262 return res;
1265 static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
1267 struct mgcp_subchannel *sub = newchan->tech_pvt;
1269 ast_mutex_lock(&sub->lock);
1270 ast_log(LOG_NOTICE, "mgcp_fixup(%s, %s)\n", oldchan->name, newchan->name);
1271 if (sub->owner != oldchan) {
1272 ast_mutex_unlock(&sub->lock);
1273 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
1274 return -1;
1276 sub->owner = newchan;
1277 ast_mutex_unlock(&sub->lock);
1278 return 0;
1281 static int mgcp_senddigit_begin(struct ast_channel *ast, char digit)
1283 struct mgcp_subchannel *sub = ast->tech_pvt;
1284 struct mgcp_endpoint *p = sub->parent;
1285 int res = 0;
1287 ast_mutex_lock(&sub->lock);
1288 if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
1289 ast_log(LOG_DEBUG, "Sending DTMF using inband/hybrid\n");
1290 res = -1; /* Let asterisk play inband indications */
1291 } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
1292 ast_log(LOG_DEBUG, "Sending DTMF using RFC2833");
1293 ast_rtp_senddigit_begin(sub->rtp, digit);
1294 } else {
1295 ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
1297 ast_mutex_unlock(&sub->lock);
1299 return res;
1302 static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
1304 struct mgcp_subchannel *sub = ast->tech_pvt;
1305 struct mgcp_endpoint *p = sub->parent;
1306 int res = 0;
1307 char tmp[4];
1309 ast_mutex_lock(&sub->lock);
1310 if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
1311 ast_log(LOG_DEBUG, "Stopping DTMF using inband/hybrid\n");
1312 res = -1; /* Tell Asterisk to stop inband indications */
1313 } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
1314 ast_log(LOG_DEBUG, "Stopping DTMF using RFC2833\n");
1315 tmp[0] = 'D';
1316 tmp[1] = '/';
1317 tmp[2] = digit;
1318 tmp[3] = '\0';
1319 transmit_notify_request(sub, tmp);
1320 ast_rtp_senddigit_end(sub->rtp, digit);
1321 } else {
1322 ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
1324 ast_mutex_unlock(&sub->lock);
1326 return res;
1330 * \brief mgcp_devicestate: channel callback for device status monitoring
1331 * \param data tech/resource name of MGCP device to query
1333 * Callback for device state management in channel subsystem
1334 * to obtain device status (up/down) of a specific MGCP endpoint
1336 * \return device status result (from devicestate.h) AST_DEVICE_INVALID (not available) or AST_DEVICE_UNKNOWN (available but unknown state)
1338 static int mgcp_devicestate(void *data)
1340 struct mgcp_gateway *g;
1341 struct mgcp_endpoint *e = NULL;
1342 char *tmp, *endpt, *gw;
1343 int ret = AST_DEVICE_INVALID;
1345 endpt = ast_strdupa(data);
1346 if ((tmp = strchr(endpt, '@'))) {
1347 *tmp++ = '\0';
1348 gw = tmp;
1349 } else
1350 goto error;
1352 ast_mutex_lock(&gatelock);
1353 g = gateways;
1354 while (g) {
1355 if (strcasecmp(g->name, gw) == 0) {
1356 e = g->endpoints;
1357 break;
1359 g = g->next;
1362 if (!e)
1363 goto error;
1365 while (e) {
1366 if (strcasecmp(e->name, endpt) == 0)
1367 break;
1368 e = e->next;
1371 if (!e)
1372 goto error;
1375 * As long as the gateway/endpoint is valid, we'll
1376 * assume that the device is available and its state
1377 * can be tracked.
1379 ret = AST_DEVICE_UNKNOWN;
1381 error:
1382 ast_mutex_unlock(&gatelock);
1383 return ret;
1386 static char *control2str(int ind) {
1387 switch (ind) {
1388 case AST_CONTROL_HANGUP:
1389 return "Other end has hungup";
1390 case AST_CONTROL_RING:
1391 return "Local ring";
1392 case AST_CONTROL_RINGING:
1393 return "Remote end is ringing";
1394 case AST_CONTROL_ANSWER:
1395 return "Remote end has answered";
1396 case AST_CONTROL_BUSY:
1397 return "Remote end is busy";
1398 case AST_CONTROL_TAKEOFFHOOK:
1399 return "Make it go off hook";
1400 case AST_CONTROL_OFFHOOK:
1401 return "Line is off hook";
1402 case AST_CONTROL_CONGESTION:
1403 return "Congestion (circuits busy)";
1404 case AST_CONTROL_FLASH:
1405 return "Flash hook";
1406 case AST_CONTROL_WINK:
1407 return "Wink";
1408 case AST_CONTROL_OPTION:
1409 return "Set a low-level option";
1410 case AST_CONTROL_RADIO_KEY:
1411 return "Key Radio";
1412 case AST_CONTROL_RADIO_UNKEY:
1413 return "Un-Key Radio";
1415 return "UNKNOWN";
1418 static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen)
1420 struct mgcp_subchannel *sub = ast->tech_pvt;
1421 int res = 0;
1423 if (mgcpdebug) {
1424 ast_verbose(VERBOSE_PREFIX_3 "MGCP asked to indicate %d '%s' condition on channel %s\n",
1425 ind, control2str(ind), ast->name);
1427 ast_mutex_lock(&sub->lock);
1428 switch(ind) {
1429 case AST_CONTROL_RINGING:
1430 #ifdef DLINK_BUGGY_FIRMWARE
1431 transmit_notify_request(sub, "rt");
1432 #else
1433 transmit_notify_request(sub, "G/rt");
1434 #endif
1435 break;
1436 case AST_CONTROL_BUSY:
1437 transmit_notify_request(sub, "L/bz");
1438 break;
1439 case AST_CONTROL_CONGESTION:
1440 transmit_notify_request(sub, "G/cg");
1441 break;
1442 case AST_CONTROL_HOLD:
1443 ast_moh_start(ast, data, NULL);
1444 break;
1445 case AST_CONTROL_UNHOLD:
1446 ast_moh_stop(ast);
1447 break;
1448 case AST_CONTROL_SRCUPDATE:
1449 ast_rtp_new_source(sub->rtp);
1450 break;
1451 case -1:
1452 transmit_notify_request(sub, "");
1453 break;
1454 default:
1455 ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
1456 res = -1;
1458 ast_mutex_unlock(&sub->lock);
1459 return res;
1462 static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state)
1464 struct ast_channel *tmp;
1465 struct mgcp_endpoint *i = sub->parent;
1466 int fmt;
1468 tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id);
1469 if (tmp) {
1470 tmp->tech = &mgcp_tech;
1471 tmp->nativeformats = i->capability;
1472 if (!tmp->nativeformats)
1473 tmp->nativeformats = capability;
1474 fmt = ast_best_codec(tmp->nativeformats);
1475 ast_string_field_build(tmp, name, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id);
1476 if (sub->rtp)
1477 tmp->fds[0] = ast_rtp_fd(sub->rtp);
1478 if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) {
1479 i->dsp = ast_dsp_new();
1480 ast_dsp_set_features(i->dsp,DSP_FEATURE_DTMF_DETECT);
1481 /* this is to prevent clipping of dtmf tones during dsp processing */
1482 ast_dsp_digitmode(i->dsp, DSP_DIGITMODE_NOQUELCH);
1483 } else {
1484 i->dsp = NULL;
1486 if (state == AST_STATE_RING)
1487 tmp->rings = 1;
1488 tmp->writeformat = fmt;
1489 tmp->rawwriteformat = fmt;
1490 tmp->readformat = fmt;
1491 tmp->rawreadformat = fmt;
1492 tmp->tech_pvt = sub;
1493 if (!ast_strlen_zero(i->language))
1494 ast_string_field_set(tmp, language, i->language);
1495 if (!ast_strlen_zero(i->accountcode))
1496 ast_string_field_set(tmp, accountcode, i->accountcode);
1497 if (i->amaflags)
1498 tmp->amaflags = i->amaflags;
1499 sub->owner = tmp;
1500 ast_module_ref(ast_module_info->self);
1501 tmp->callgroup = i->callgroup;
1502 tmp->pickupgroup = i->pickupgroup;
1503 ast_string_field_set(tmp, call_forward, i->call_forward);
1504 ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
1505 ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
1507 /* Don't use ast_set_callerid() here because it will
1508 * generate a needless NewCallerID event */
1509 tmp->cid.cid_ani = ast_strdup(i->cid_num);
1511 if (!i->adsi)
1512 tmp->adsicpe = AST_ADSI_UNAVAILABLE;
1513 tmp->priority = 1;
1514 if (sub->rtp)
1515 ast_jb_configure(tmp, &global_jbconf);
1516 if (state != AST_STATE_DOWN) {
1517 if (ast_pbx_start(tmp)) {
1518 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
1519 ast_hangup(tmp);
1520 tmp = NULL;
1523 /* verbose level check */
1524 if (option_verbose > 2) {
1525 ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_new(%s) created in state: %s\n",
1526 tmp->name, ast_state2str(state));
1528 } else {
1529 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
1531 return tmp;
1534 static char* get_sdp_by_line(char* line, char *name, int nameLen)
1536 if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') {
1537 char* r = line + nameLen + 1;
1538 while (*r && (*r < 33)) ++r;
1539 return r;
1541 return "";
1544 static char *get_sdp(struct mgcp_request *req, char *name)
1546 int x;
1547 int len = strlen(name);
1548 char *r;
1550 for (x=0; x<req->lines; x++) {
1551 r = get_sdp_by_line(req->line[x], name, len);
1552 if (r[0] != '\0') return r;
1554 return "";
1557 static void sdpLineNum_iterator_init(int* iterator)
1559 *iterator = 0;
1562 static char* get_sdp_iterate(int* iterator, struct mgcp_request *req, char *name)
1564 int len = strlen(name);
1565 char *r;
1566 while (*iterator < req->lines) {
1567 r = get_sdp_by_line(req->line[(*iterator)++], name, len);
1568 if (r[0] != '\0') return r;
1570 return "";
1573 static char *__get_header(struct mgcp_request *req, char *name, int *start)
1575 int x;
1576 int len = strlen(name);
1577 char *r;
1578 for (x=*start;x<req->headers;x++) {
1579 if (!strncasecmp(req->header[x], name, len) &&
1580 (req->header[x][len] == ':')) {
1581 r = req->header[x] + len + 1;
1582 while(*r && (*r < 33))
1583 r++;
1584 *start = x+1;
1585 return r;
1588 /* Don't return NULL, so get_header is always a valid pointer */
1589 return "";
1592 static char *get_header(struct mgcp_request *req, char *name)
1594 int start = 0;
1595 return __get_header(req, name, &start);
1598 /*! \brief get_csv: (SC:) get comma separated value */
1599 static char *get_csv(char *c, int *len, char **next)
1601 char *s;
1603 *next = NULL, *len = 0;
1604 if (!c) return NULL;
1606 while (*c && (*c < 33 || *c == ','))
1607 c++;
1609 s = c;
1610 while (*c && (*c >= 33 && *c != ','))
1611 c++, (*len)++;
1612 *next = c;
1614 if (*len == 0)
1615 s = NULL, *next = NULL;
1617 return s;
1620 static struct mgcp_subchannel *find_subchannel_and_lock(char *name, int msgid, struct sockaddr_in *sin)
1622 struct mgcp_endpoint *p = NULL;
1623 struct mgcp_subchannel *sub = NULL;
1624 struct mgcp_gateway *g;
1625 char tmp[256] = "";
1626 char *at = NULL, *c;
1627 int found = 0;
1628 if (name) {
1629 ast_copy_string(tmp, name, sizeof(tmp));
1630 at = strchr(tmp, '@');
1631 if (!at) {
1632 ast_log(LOG_NOTICE, "Endpoint '%s' has no at sign!\n", name);
1633 return NULL;
1635 *at++ = '\0';
1637 ast_mutex_lock(&gatelock);
1638 if (at && (at[0] == '[')) {
1639 at++;
1640 c = strrchr(at, ']');
1641 if (c)
1642 *c = '\0';
1644 g = gateways;
1645 while(g) {
1646 if ((!name || !strcasecmp(g->name, at)) &&
1647 (sin || g->addr.sin_addr.s_addr || g->defaddr.sin_addr.s_addr)) {
1648 /* Found the gateway. If it's dynamic, save it's address -- now for the endpoint */
1649 if (sin && g->dynamic && name) {
1650 if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
1651 (g->addr.sin_port != sin->sin_port)) {
1652 memcpy(&g->addr, sin, sizeof(g->addr));
1653 if (ast_ouraddrfor(&g->addr.sin_addr, &g->ourip))
1654 memcpy(&g->ourip, &__ourip, sizeof(g->ourip));
1655 if (option_verbose > 2)
1656 ast_verbose(VERBOSE_PREFIX_3 "Registered MGCP gateway '%s' at %s port %d\n", g->name, ast_inet_ntoa(g->addr.sin_addr), ntohs(g->addr.sin_port));
1659 /* not dynamic, check if the name matches */
1660 else if (name) {
1661 if (strcasecmp(g->name, at)) {
1662 g = g->next;
1663 continue;
1666 /* not dynamic, no name, check if the addr matches */
1667 else if (!name && sin) {
1668 if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
1669 (g->addr.sin_port != sin->sin_port)) {
1670 g = g->next;
1671 continue;
1673 } else {
1674 g = g->next;
1675 continue;
1677 /* SC */
1678 p = g->endpoints;
1679 while(p) {
1680 if (option_debug)
1681 ast_log(LOG_DEBUG, "Searching on %s@%s for subchannel\n",
1682 p->name, g->name);
1683 if (msgid) {
1684 #if 0 /* new transport mech */
1685 sub = p->sub;
1686 do {
1687 if (option_debug)
1688 ast_log(LOG_DEBUG, "Searching on %s@%s-%d for subchannel with lastout: %d\n",
1689 p->name, g->name, sub->id, msgid);
1690 if (sub->lastout == msgid) {
1691 if (option_debug)
1692 ast_log(LOG_DEBUG, "Found subchannel sub%d to handle request %d sub->lastout: %d\n",
1693 sub->id, msgid, sub->lastout);
1694 found = 1;
1695 break;
1697 sub = sub->next;
1698 } while (sub != p->sub);
1699 if (found) {
1700 break;
1702 #endif
1703 /* SC */
1704 sub = p->sub;
1705 found = 1;
1706 /* SC */
1707 break;
1708 } else if (name && !strcasecmp(p->name, tmp)) {
1709 ast_log(LOG_DEBUG, "Coundn't determine subchannel, assuming current master %s@%s-%d\n",
1710 p->name, g->name, p->sub->id);
1711 sub = p->sub;
1712 found = 1;
1713 break;
1715 p = p->next;
1717 if (sub && found) {
1718 ast_mutex_lock(&sub->lock);
1719 break;
1722 g = g->next;
1724 ast_mutex_unlock(&gatelock);
1725 if (!sub) {
1726 if (name) {
1727 if (g)
1728 ast_log(LOG_NOTICE, "Endpoint '%s' not found on gateway '%s'\n", tmp, at);
1729 else
1730 ast_log(LOG_NOTICE, "Gateway '%s' (and thus its endpoint '%s') does not exist\n", at, tmp);
1733 return sub;
1736 static void parse(struct mgcp_request *req)
1738 /* Divide fields by NULL's */
1739 char *c;
1740 int f = 0;
1741 c = req->data;
1743 /* First header starts immediately */
1744 req->header[f] = c;
1745 while(*c) {
1746 if (*c == '\n') {
1747 /* We've got a new header */
1748 *c = 0;
1749 #if 0
1750 printf("Header: %s (%d)\n", req->header[f], strlen(req->header[f]));
1751 #endif
1752 if (ast_strlen_zero(req->header[f])) {
1753 /* Line by itself means we're now in content */
1754 c++;
1755 break;
1757 if (f >= MGCP_MAX_HEADERS - 1) {
1758 ast_log(LOG_WARNING, "Too many MGCP headers...\n");
1759 } else
1760 f++;
1761 req->header[f] = c + 1;
1762 } else if (*c == '\r') {
1763 /* Ignore but eliminate \r's */
1764 *c = 0;
1766 c++;
1768 /* Check for last header */
1769 if (!ast_strlen_zero(req->header[f]))
1770 f++;
1771 req->headers = f;
1772 /* Now we process any mime content */
1773 f = 0;
1774 req->line[f] = c;
1775 while(*c) {
1776 if (*c == '\n') {
1777 /* We've got a new line */
1778 *c = 0;
1779 #if 0
1780 printf("Line: %s (%d)\n", req->line[f], strlen(req->line[f]));
1781 #endif
1782 if (f >= MGCP_MAX_LINES - 1) {
1783 ast_log(LOG_WARNING, "Too many SDP lines...\n");
1784 } else
1785 f++;
1786 req->line[f] = c + 1;
1787 } else if (*c == '\r') {
1788 /* Ignore and eliminate \r's */
1789 *c = 0;
1791 c++;
1793 /* Check for last line */
1794 if (!ast_strlen_zero(req->line[f]))
1795 f++;
1796 req->lines = f;
1797 /* Parse up the initial header */
1798 c = req->header[0];
1799 while(*c && *c < 33) c++;
1800 /* First the verb */
1801 req->verb = c;
1802 while(*c && (*c > 32)) c++;
1803 if (*c) {
1804 *c = '\0';
1805 c++;
1806 while(*c && (*c < 33)) c++;
1807 req->identifier = c;
1808 while(*c && (*c > 32)) c++;
1809 if (*c) {
1810 *c = '\0';
1811 c++;
1812 while(*c && (*c < 33)) c++;
1813 req->endpoint = c;
1814 while(*c && (*c > 32)) c++;
1815 if (*c) {
1816 *c = '\0';
1817 c++;
1818 while(*c && (*c < 33)) c++;
1819 req->version = c;
1820 while(*c && (*c > 32)) c++;
1821 while(*c && (*c < 33)) c++;
1822 while(*c && (*c > 32)) c++;
1823 *c = '\0';
1828 if (mgcpdebug) {
1829 ast_verbose("Verb: '%s', Identifier: '%s', Endpoint: '%s', Version: '%s'\n",
1830 req->verb, req->identifier, req->endpoint, req->version);
1831 ast_verbose("%d headers, %d lines\n", req->headers, req->lines);
1833 if (*c)
1834 ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c);
1837 static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req)
1839 char *m;
1840 char *c;
1841 char *a;
1842 char host[258];
1843 int len;
1844 int portno;
1845 int peercapability, peerNonCodecCapability;
1846 struct sockaddr_in sin;
1847 char *codecs;
1848 struct ast_hostent ahp; struct hostent *hp;
1849 int codec, codec_count=0;
1850 int iterator;
1851 struct mgcp_endpoint *p = sub->parent;
1853 /* Get codec and RTP info from SDP */
1854 m = get_sdp(req, "m");
1855 c = get_sdp(req, "c");
1856 if (ast_strlen_zero(m) || ast_strlen_zero(c)) {
1857 ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s', c = '%s')\n", m, c);
1858 return -1;
1860 if (sscanf(c, "IN IP4 %256s", host) != 1) {
1861 ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
1862 return -1;
1864 /* XXX This could block for a long time, and block the main thread! XXX */
1865 hp = ast_gethostbyname(host, &ahp);
1866 if (!hp) {
1867 ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c);
1868 return -1;
1870 if (sscanf(m, "audio %d RTP/AVP %n", &portno, &len) != 1) {
1871 ast_log(LOG_WARNING, "Unable to determine port number for RTP in '%s'\n", m);
1872 return -1;
1874 sin.sin_family = AF_INET;
1875 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
1876 sin.sin_port = htons(portno);
1877 ast_rtp_set_peer(sub->rtp, &sin);
1878 #if 0
1879 printf("Peer RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
1880 #endif
1881 /* Scan through the RTP payload types specified in a "m=" line: */
1882 ast_rtp_pt_clear(sub->rtp);
1883 codecs = ast_strdupa(m + len);
1884 while (!ast_strlen_zero(codecs)) {
1885 if (sscanf(codecs, "%d%n", &codec, &len) != 1) {
1886 if (codec_count)
1887 break;
1888 ast_log(LOG_WARNING, "Error in codec string '%s' at '%s'\n", m, codecs);
1889 return -1;
1891 ast_rtp_set_m_type(sub->rtp, codec);
1892 codec_count++;
1893 codecs += len;
1896 /* Next, scan through each "a=rtpmap:" line, noting each */
1897 /* specified RTP payload type (with corresponding MIME subtype): */
1898 sdpLineNum_iterator_init(&iterator);
1899 while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
1900 char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
1901 if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2)
1902 continue;
1903 /* Note: should really look at the 'freq' and '#chans' params too */
1904 ast_rtp_set_rtpmap_type(sub->rtp, codec, "audio", mimeSubtype, 0);
1907 /* Now gather all of the codecs that were asked for: */
1908 ast_rtp_get_current_formats(sub->rtp, &peercapability, &peerNonCodecCapability);
1909 p->capability = capability & peercapability;
1910 if (mgcpdebug) {
1911 ast_verbose("Capabilities: us - %d, them - %d, combined - %d\n",
1912 capability, peercapability, p->capability);
1913 ast_verbose("Non-codec capabilities: us - %d, them - %d, combined - %d\n",
1914 nonCodecCapability, peerNonCodecCapability, p->nonCodecCapability);
1916 if (!p->capability) {
1917 ast_log(LOG_WARNING, "No compatible codecs!\n");
1918 return -1;
1920 return 0;
1923 static int add_header(struct mgcp_request *req, char *var, char *value)
1925 if (req->len >= sizeof(req->data) - 4) {
1926 ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
1927 return -1;
1929 if (req->lines) {
1930 ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n");
1931 return -1;
1933 req->header[req->headers] = req->data + req->len;
1934 snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s: %s\r\n", var, value);
1935 req->len += strlen(req->header[req->headers]);
1936 if (req->headers < MGCP_MAX_HEADERS)
1937 req->headers++;
1938 else {
1939 ast_log(LOG_WARNING, "Out of header space\n");
1940 return -1;
1942 return 0;
1945 static int add_line(struct mgcp_request *req, char *line)
1947 if (req->len >= sizeof(req->data) - 4) {
1948 ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
1949 return -1;
1951 if (!req->lines) {
1952 /* Add extra empty return */
1953 snprintf(req->data + req->len, sizeof(req->data) - req->len, "\r\n");
1954 req->len += strlen(req->data + req->len);
1956 req->line[req->lines] = req->data + req->len;
1957 snprintf(req->line[req->lines], sizeof(req->data) - req->len, "%s", line);
1958 req->len += strlen(req->line[req->lines]);
1959 if (req->lines < MGCP_MAX_LINES)
1960 req->lines++;
1961 else {
1962 ast_log(LOG_WARNING, "Out of line space\n");
1963 return -1;
1965 return 0;
1968 static int init_resp(struct mgcp_request *req, char *resp, struct mgcp_request *orig, char *resprest)
1970 /* Initialize a response */
1971 if (req->headers || req->len) {
1972 ast_log(LOG_WARNING, "Request already initialized?!?\n");
1973 return -1;
1975 req->header[req->headers] = req->data + req->len;
1976 snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %s %s\r\n", resp, orig->identifier, resprest);
1977 req->len += strlen(req->header[req->headers]);
1978 if (req->headers < MGCP_MAX_HEADERS)
1979 req->headers++;
1980 else
1981 ast_log(LOG_WARNING, "Out of header space\n");
1982 return 0;
1985 static int init_req(struct mgcp_endpoint *p, struct mgcp_request *req, char *verb)
1987 /* Initialize a response */
1988 if (req->headers || req->len) {
1989 ast_log(LOG_WARNING, "Request already initialized?!?\n");
1990 return -1;
1992 req->header[req->headers] = req->data + req->len;
1993 /* check if we need brackets around the gw name */
1994 if (p->parent->isnamedottedip)
1995 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);
1996 else
1997 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);
1998 req->len += strlen(req->header[req->headers]);
1999 if (req->headers < MGCP_MAX_HEADERS)
2000 req->headers++;
2001 else
2002 ast_log(LOG_WARNING, "Out of header space\n");
2003 return 0;
2007 static int respprep(struct mgcp_request *resp, struct mgcp_endpoint *p, char *msg, struct mgcp_request *req, char *msgrest)
2009 memset(resp, 0, sizeof(*resp));
2010 init_resp(resp, msg, req, msgrest);
2011 return 0;
2014 static int reqprep(struct mgcp_request *req, struct mgcp_endpoint *p, char *verb)
2016 memset(req, 0, sizeof(struct mgcp_request));
2017 oseq++;
2018 if (oseq > 999999999)
2019 oseq = 1;
2020 init_req(p, req, verb);
2021 return 0;
2024 static int transmit_response(struct mgcp_subchannel *sub, char *msg, struct mgcp_request *req, char *msgrest)
2026 struct mgcp_request resp;
2027 struct mgcp_endpoint *p = sub->parent;
2028 struct mgcp_response *mgr;
2030 respprep(&resp, p, msg, req, msgrest);
2031 mgr = malloc(sizeof(struct mgcp_response) + resp.len + 1);
2032 if (mgr) {
2033 /* Store MGCP response in case we have to retransmit */
2034 memset(mgr, 0, sizeof(struct mgcp_response));
2035 sscanf(req->identifier, "%d", &mgr->seqno);
2036 time(&mgr->whensent);
2037 mgr->len = resp.len;
2038 memcpy(mgr->buf, resp.data, resp.len);
2039 mgr->buf[resp.len] = '\0';
2040 mgr->next = p->parent->responses;
2041 p->parent->responses = mgr;
2043 return send_response(sub, &resp);
2047 static int add_sdp(struct mgcp_request *resp, struct mgcp_subchannel *sub, struct ast_rtp *rtp)
2049 int len;
2050 int codec;
2051 char costr[80];
2052 struct sockaddr_in sin;
2053 char v[256];
2054 char s[256];
2055 char o[256];
2056 char c[256];
2057 char t[256];
2058 char m[256] = "";
2059 char a[1024] = "";
2060 int x;
2061 struct sockaddr_in dest;
2062 struct mgcp_endpoint *p = sub->parent;
2063 /* XXX We break with the "recommendation" and send our IP, in order that our
2064 peer doesn't have to ast_gethostbyname() us XXX */
2065 len = 0;
2066 if (!sub->rtp) {
2067 ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n");
2068 return -1;
2070 ast_rtp_get_us(sub->rtp, &sin);
2071 if (rtp) {
2072 ast_rtp_get_peer(rtp, &dest);
2073 } else {
2074 if (sub->tmpdest.sin_addr.s_addr) {
2075 dest.sin_addr = sub->tmpdest.sin_addr;
2076 dest.sin_port = sub->tmpdest.sin_port;
2077 /* Reset temporary destination */
2078 memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
2079 } else {
2080 dest.sin_addr = p->parent->ourip;
2081 dest.sin_port = sin.sin_port;
2084 if (mgcpdebug) {
2085 ast_verbose("We're at %s port %d\n", ast_inet_ntoa(p->parent->ourip), ntohs(sin.sin_port));
2087 snprintf(v, sizeof(v), "v=0\r\n");
2088 snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", (int)getpid(), (int)getpid(), ast_inet_ntoa(dest.sin_addr));
2089 snprintf(s, sizeof(s), "s=session\r\n");
2090 snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr));
2091 snprintf(t, sizeof(t), "t=0 0\r\n");
2092 snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port));
2093 for (x = 1; x <= AST_FORMAT_MAX_AUDIO; x <<= 1) {
2094 if (p->capability & x) {
2095 if (mgcpdebug) {
2096 ast_verbose("Answering with capability %d\n", x);
2098 codec = ast_rtp_lookup_code(sub->rtp, 1, x);
2099 if (codec > -1) {
2100 snprintf(costr, sizeof(costr), " %d", codec);
2101 strncat(m, costr, sizeof(m) - strlen(m) - 1);
2102 snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(1, x, 0));
2103 strncat(a, costr, sizeof(a) - strlen(a) - 1);
2107 for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
2108 if (p->nonCodecCapability & x) {
2109 if (mgcpdebug) {
2110 ast_verbose("Answering with non-codec capability %d\n", x);
2112 codec = ast_rtp_lookup_code(sub->rtp, 0, x);
2113 if (codec > -1) {
2114 snprintf(costr, sizeof(costr), " %d", codec);
2115 strncat(m, costr, sizeof(m) - strlen(m) - 1);
2116 snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(0, x, 0));
2117 strncat(a, costr, sizeof(a) - strlen(a) - 1);
2118 if (x == AST_RTP_DTMF) {
2119 /* Indicate we support DTMF... Not sure about 16,
2120 but MSN supports it so dang it, we will too... */
2121 snprintf(costr, sizeof costr, "a=fmtp:%d 0-16\r\n", codec);
2122 strncat(a, costr, sizeof(a) - strlen(a) - 1);
2127 strncat(m, "\r\n", sizeof(m) - strlen(m) - 1);
2128 len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a);
2129 snprintf(costr, sizeof(costr), "%d", len);
2130 add_line(resp, v);
2131 add_line(resp, o);
2132 add_line(resp, s);
2133 add_line(resp, c);
2134 add_line(resp, t);
2135 add_line(resp, m);
2136 add_line(resp, a);
2137 return 0;
2140 static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp, int codecs)
2142 struct mgcp_request resp;
2143 char local[256];
2144 char tmp[80];
2145 int x;
2146 int capability;
2147 struct mgcp_endpoint *p = sub->parent;
2149 capability = p->capability;
2150 if (codecs)
2151 capability = codecs;
2152 if (ast_strlen_zero(sub->cxident) && rtp) {
2153 /* We don't have a CXident yet, store the destination and
2154 wait a bit */
2155 ast_rtp_get_peer(rtp, &sub->tmpdest);
2156 return 0;
2158 snprintf(local, sizeof(local), "p:20");
2159 for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
2160 if (p->capability & x) {
2161 snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0));
2162 strncat(local, tmp, sizeof(local) - strlen(local) - 1);
2165 reqprep(&resp, p, "MDCX");
2166 add_header(&resp, "C", sub->callid);
2167 add_header(&resp, "L", local);
2168 add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
2169 /* X header should not be sent. kept for compatibility */
2170 add_header(&resp, "X", sub->txident);
2171 add_header(&resp, "I", sub->cxident);
2172 /*add_header(&resp, "S", "");*/
2173 add_sdp(&resp, sub, rtp);
2174 /* fill in new fields */
2175 resp.cmd = MGCP_CMD_MDCX;
2176 resp.trid = oseq;
2177 return send_request(p, sub, &resp, oseq); /* SC */
2180 static int transmit_connect_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp)
2182 struct mgcp_request resp;
2183 char local[256];
2184 char tmp[80];
2185 int x;
2186 struct mgcp_endpoint *p = sub->parent;
2188 snprintf(local, sizeof(local), "p:20");
2189 for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) {
2190 if (p->capability & x) {
2191 snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0));
2192 strncat(local, tmp, sizeof(local) - strlen(local) - 1);
2195 if (mgcpdebug) {
2196 ast_verbose(VERBOSE_PREFIX_3 "Creating connection for %s@%s-%d in cxmode: %s callid: %s\n",
2197 p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
2199 reqprep(&resp, p, "CRCX");
2200 add_header(&resp, "C", sub->callid);
2201 add_header(&resp, "L", local);
2202 add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
2203 /* X header should not be sent. kept for compatibility */
2204 add_header(&resp, "X", sub->txident);
2205 /*add_header(&resp, "S", "");*/
2206 add_sdp(&resp, sub, rtp);
2207 /* fill in new fields */
2208 resp.cmd = MGCP_CMD_CRCX;
2209 resp.trid = oseq;
2210 return send_request(p, sub, &resp, oseq); /* SC */
2213 static int transmit_notify_request(struct mgcp_subchannel *sub, char *tone)
2215 struct mgcp_request resp;
2216 struct mgcp_endpoint *p = sub->parent;
2218 if (mgcpdebug) {
2219 ast_verbose(VERBOSE_PREFIX_3 "MGCP Asked to indicate tone: %s on %s@%s-%d in cxmode: %s\n",
2220 tone, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]);
2222 ast_copy_string(p->curtone, tone, sizeof(p->curtone));
2223 reqprep(&resp, p, "RQNT");
2224 add_header(&resp, "X", p->rqnt_ident); /* SC */
2225 switch (p->hookstate) {
2226 case MGCP_ONHOOK:
2227 add_header(&resp, "R", "L/hd(N)");
2228 break;
2229 case MGCP_OFFHOOK:
2230 add_header_offhook(sub, &resp);
2231 break;
2233 if (!ast_strlen_zero(tone)) {
2234 add_header(&resp, "S", tone);
2236 /* fill in new fields */
2237 resp.cmd = MGCP_CMD_RQNT;
2238 resp.trid = oseq;
2239 return send_request(p, NULL, &resp, oseq); /* SC */
2242 static int transmit_notify_request_with_callerid(struct mgcp_subchannel *sub, char *tone, char *callernum, char *callername)
2244 struct mgcp_request resp;
2245 char tone2[256];
2246 char *l, *n;
2247 time_t t;
2248 struct tm tm;
2249 struct mgcp_endpoint *p = sub->parent;
2251 time(&t);
2252 ast_localtime(&t, &tm, NULL);
2253 n = callername;
2254 l = callernum;
2255 if (!n)
2256 n = "";
2257 if (!l)
2258 l = "";
2260 /* Keep track of last callerid for blacklist and callreturn */
2261 ast_copy_string(p->lastcallerid, l, sizeof(p->lastcallerid));
2263 snprintf(tone2, sizeof(tone2), "%s,L/ci(%02d/%02d/%02d/%02d,%s,%s)", tone,
2264 tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, l, n);
2265 ast_copy_string(p->curtone, tone, sizeof(p->curtone));
2266 reqprep(&resp, p, "RQNT");
2267 add_header(&resp, "X", p->rqnt_ident); /* SC */
2268 switch (p->hookstate) {
2269 case MGCP_ONHOOK:
2270 add_header(&resp, "R", "L/hd(N)");
2271 break;
2272 case MGCP_OFFHOOK:
2273 add_header_offhook(sub, &resp);
2274 break;
2276 if (!ast_strlen_zero(tone2)) {
2277 add_header(&resp, "S", tone2);
2279 if (mgcpdebug) {
2280 ast_verbose(VERBOSE_PREFIX_3 "MGCP Asked to indicate tone: %s on %s@%s-%d in cxmode: %s\n",
2281 tone2, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]);
2283 /* fill in new fields */
2284 resp.cmd = MGCP_CMD_RQNT;
2285 resp.trid = oseq;
2286 return send_request(p, NULL, &resp, oseq); /* SC */
2289 static int transmit_modify_request(struct mgcp_subchannel *sub)
2291 struct mgcp_request resp;
2292 struct mgcp_endpoint *p = sub->parent;
2294 if (ast_strlen_zero(sub->cxident)) {
2295 /* We don't have a CXident yet, store the destination and
2296 wait a bit */
2297 return 0;
2299 if (mgcpdebug) {
2300 ast_verbose(VERBOSE_PREFIX_3 "Modified %s@%s-%d with new mode: %s on callid: %s\n",
2301 p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
2303 reqprep(&resp, p, "MDCX");
2304 add_header(&resp, "C", sub->callid);
2305 add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
2306 /* X header should not be sent. kept for compatibility */
2307 add_header(&resp, "X", sub->txident);
2308 add_header(&resp, "I", sub->cxident);
2309 switch (sub->parent->hookstate) {
2310 case MGCP_ONHOOK:
2311 add_header(&resp, "R", "L/hd(N)");
2312 break;
2313 case MGCP_OFFHOOK:
2314 add_header_offhook(sub, &resp);
2315 break;
2317 /* fill in new fields */
2318 resp.cmd = MGCP_CMD_MDCX;
2319 resp.trid = oseq;
2320 return send_request(p, sub, &resp, oseq); /* SC */
2324 static void add_header_offhook(struct mgcp_subchannel *sub, struct mgcp_request *resp)
2326 struct mgcp_endpoint *p = sub->parent;
2328 if (p && p->sub && p->sub->owner && p->sub->owner->_state >= AST_STATE_RINGING && (p->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)))
2329 add_header(resp, "R", "L/hu(N),L/hf(N)");
2330 else
2331 add_header(resp, "R", "L/hu(N),L/hf(N),D/[0-9#*](N)");
2334 static int transmit_audit_endpoint(struct mgcp_endpoint *p)
2336 struct mgcp_request resp;
2337 reqprep(&resp, p, "AUEP");
2338 /* removed unknown param VS */
2339 /*add_header(&resp, "F", "A,R,D,S,X,N,I,T,O,ES,E,MD,M");*/
2340 add_header(&resp, "F", "A");
2341 /* fill in new fields */
2342 resp.cmd = MGCP_CMD_AUEP;
2343 resp.trid = oseq;
2344 return send_request(p, NULL, &resp, oseq); /* SC */
2347 static int transmit_connection_del(struct mgcp_subchannel *sub)
2349 struct mgcp_endpoint *p = sub->parent;
2350 struct mgcp_request resp;
2352 if (mgcpdebug) {
2353 ast_verbose(VERBOSE_PREFIX_3 "Delete connection %s %s@%s-%d with new mode: %s on callid: %s\n",
2354 sub->cxident, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
2356 reqprep(&resp, p, "DLCX");
2357 /* check if call id is avail */
2358 if (sub->callid[0])
2359 add_header(&resp, "C", sub->callid);
2360 /* X header should not be sent. kept for compatibility */
2361 add_header(&resp, "X", sub->txident);
2362 /* check if cxident is avail */
2363 if (sub->cxident[0])
2364 add_header(&resp, "I", sub->cxident);
2365 /* fill in new fields */
2366 resp.cmd = MGCP_CMD_DLCX;
2367 resp.trid = oseq;
2368 return send_request(p, sub, &resp, oseq); /* SC */
2371 static int transmit_connection_del_w_params(struct mgcp_endpoint *p, char *callid, char *cxident)
2373 struct mgcp_request resp;
2375 if (mgcpdebug) {
2376 ast_verbose(VERBOSE_PREFIX_3 "Delete connection %s %s@%s on callid: %s\n",
2377 cxident ? cxident : "", p->name, p->parent->name, callid ? callid : "");
2379 reqprep(&resp, p, "DLCX");
2380 /* check if call id is avail */
2381 if (callid && *callid)
2382 add_header(&resp, "C", callid);
2383 /* check if cxident is avail */
2384 if (cxident && *cxident)
2385 add_header(&resp, "I", cxident);
2386 /* fill in new fields */
2387 resp.cmd = MGCP_CMD_DLCX;
2388 resp.trid = oseq;
2389 return send_request(p, p->sub, &resp, oseq);
2392 /*! \brief dump_cmd_queues: (SC:) cleanup pending commands */
2393 static void dump_cmd_queues(struct mgcp_endpoint *p, struct mgcp_subchannel *sub)
2395 struct mgcp_request *t, *q;
2397 if (p) {
2398 ast_mutex_lock(&p->rqnt_queue_lock);
2399 for (q = p->rqnt_queue; q; t = q->next, free(q), q=t);
2400 p->rqnt_queue = NULL;
2401 ast_mutex_unlock(&p->rqnt_queue_lock);
2403 ast_mutex_lock(&p->cmd_queue_lock);
2404 for (q = p->cmd_queue; q; t = q->next, free(q), q=t);
2405 p->cmd_queue = NULL;
2406 ast_mutex_unlock(&p->cmd_queue_lock);
2408 ast_mutex_lock(&p->sub->cx_queue_lock);
2409 for (q = p->sub->cx_queue; q; t = q->next, free(q), q=t);
2410 p->sub->cx_queue = NULL;
2411 ast_mutex_unlock(&p->sub->cx_queue_lock);
2413 ast_mutex_lock(&p->sub->next->cx_queue_lock);
2414 for (q = p->sub->next->cx_queue; q; t = q->next, free(q), q=t);
2415 p->sub->next->cx_queue = NULL;
2416 ast_mutex_unlock(&p->sub->next->cx_queue_lock);
2417 } else if (sub) {
2418 ast_mutex_lock(&sub->cx_queue_lock);
2419 for (q = sub->cx_queue; q; t = q->next, free(q), q=t);
2420 sub->cx_queue = NULL;
2421 ast_mutex_unlock(&sub->cx_queue_lock);
2426 /*! \brief find_command: (SC:) remove command transaction from queue */
2427 static struct mgcp_request *find_command(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,
2428 struct mgcp_request **queue, ast_mutex_t *l, int ident)
2430 struct mgcp_request *prev, *req;
2432 ast_mutex_lock(l);
2433 for (prev = NULL, req = *queue; req; prev = req, req = req->next) {
2434 if (req->trid == ident) {
2435 /* remove from queue */
2436 if (!prev)
2437 *queue = req->next;
2438 else
2439 prev->next = req->next;
2441 /* send next pending command */
2442 if (*queue) {
2443 if (mgcpdebug) {
2444 ast_verbose("Posting Queued Request:\n%s to %s:%d\n", (*queue)->data,
2445 ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
2448 mgcp_postrequest(p, sub, (*queue)->data, (*queue)->len, (*queue)->trid);
2450 break;
2453 ast_mutex_unlock(l);
2454 return req;
2457 /* modified for new transport mechanism */
2458 static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,
2459 int result, unsigned int ident, struct mgcp_request *resp)
2461 char *c;
2462 struct mgcp_request *req;
2463 struct mgcp_gateway *gw = p->parent;
2465 if (result < 200) {
2466 /* provisional response */
2467 return;
2470 if (p->slowsequence)
2471 req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident);
2472 else if (sub)
2473 req = find_command(p, sub, &sub->cx_queue, &sub->cx_queue_lock, ident);
2474 else if (!(req = find_command(p, sub, &p->rqnt_queue, &p->rqnt_queue_lock, ident)))
2475 req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident);
2477 if (!req) {
2478 if (option_verbose > 2) {
2479 ast_verbose(VERBOSE_PREFIX_3 "No command found on [%s] for transaction %d. Ignoring...\n",
2480 gw->name, ident);
2482 return;
2485 if (p && (result >= 400) && (result <= 599)) {
2486 switch (result) {
2487 case 401:
2488 p->hookstate = MGCP_OFFHOOK;
2489 break;
2490 case 402:
2491 p->hookstate = MGCP_ONHOOK;
2492 break;
2493 case 406:
2494 ast_log(LOG_NOTICE, "Transaction %d timed out\n", ident);
2495 break;
2496 case 407:
2497 ast_log(LOG_NOTICE, "Transaction %d aborted\n", ident);
2498 break;
2500 if (sub) {
2501 if (sub->owner) {
2502 ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
2503 result, p->name, p->parent->name, sub ? sub->id:-1);
2504 mgcp_queue_hangup(sub);
2506 } else {
2507 if (p->sub->next->owner) {
2508 ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
2509 result, p->name, p->parent->name, sub ? sub->id:-1);
2510 mgcp_queue_hangup(p->sub);
2513 if (p->sub->owner) {
2514 ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
2515 result, p->name, p->parent->name, sub ? sub->id:-1);
2516 mgcp_queue_hangup(p->sub);
2519 dump_cmd_queues(p, NULL);
2523 if (resp) {
2524 if (req->cmd == MGCP_CMD_CRCX) {
2525 if ((c = get_header(resp, "I"))) {
2526 if (!ast_strlen_zero(c) && sub) {
2527 /* if we are hanging up do not process this conn. */
2528 if (sub->owner) {
2529 if (!ast_strlen_zero(sub->cxident)) {
2530 if (strcasecmp(c, sub->cxident)) {
2531 ast_log(LOG_WARNING, "Subchannel already has a cxident. sub->cxident: %s requested %s\n", sub->cxident, c);
2534 ast_copy_string(sub->cxident, c, sizeof(sub->cxident));
2535 if (sub->tmpdest.sin_addr.s_addr) {
2536 transmit_modify_with_sdp(sub, NULL, 0);
2538 } else {
2539 /* XXX delete this one
2540 callid and conn id may already be lost.
2541 so the following del conn may have a side effect of
2542 cleaning up the next subchannel */
2543 transmit_connection_del(sub);
2549 if (req->cmd == MGCP_CMD_AUEP) {
2550 /* check stale connection ids */
2551 if ((c = get_header(resp, "I"))) {
2552 char *v, *n;
2553 int len;
2554 while ((v = get_csv(c, &len, &n))) {
2555 if (len) {
2556 if (strncasecmp(v, p->sub->cxident, len) &&
2557 strncasecmp(v, p->sub->next->cxident, len)) {
2558 /* connection id not found. delete it */
2559 char cxident[80] = "";
2561 if (len > (sizeof(cxident) - 1))
2562 len = sizeof(cxident) - 1;
2563 ast_copy_string(cxident, v, len);
2564 if (option_verbose > 2) {
2565 ast_verbose(VERBOSE_PREFIX_3 "Non existing connection id %s on %s@%s \n",
2566 cxident, p->name, gw->name);
2568 transmit_connection_del_w_params(p, NULL, cxident);
2571 c = n;
2575 /* Try to determine the hookstate returned from an audit endpoint command */
2576 if ((c = get_header(resp, "ES"))) {
2577 if (!ast_strlen_zero(c)) {
2578 if (strstr(c, "hu")) {
2579 if (p->hookstate != MGCP_ONHOOK) {
2580 /* XXX cleanup if we think we are offhook XXX */
2581 if ((p->sub->owner || p->sub->next->owner ) &&
2582 p->hookstate == MGCP_OFFHOOK)
2583 mgcp_queue_hangup(sub);
2584 p->hookstate = MGCP_ONHOOK;
2586 /* update the requested events according to the new hookstate */
2587 transmit_notify_request(p->sub, "");
2589 /* verbose level check */
2590 if (option_verbose > 2) {
2591 ast_verbose(VERBOSE_PREFIX_3 "Setting hookstate of %s@%s to ONHOOK\n", p->name, gw->name);
2594 } else if (strstr(c, "hd")) {
2595 if (p->hookstate != MGCP_OFFHOOK) {
2596 p->hookstate = MGCP_OFFHOOK;
2598 /* update the requested events according to the new hookstate */
2599 transmit_notify_request(p->sub, "");
2601 /* verbose level check */
2602 if (option_verbose > 2) {
2603 ast_verbose(VERBOSE_PREFIX_3 "Setting hookstate of %s@%s to OFFHOOK\n", p->name, gw->name);
2611 if (resp && resp->lines) {
2612 /* do not process sdp if we are hanging up. this may be a late response */
2613 if (sub && sub->owner) {
2614 if (!sub->rtp)
2615 start_rtp(sub);
2616 if (sub->rtp)
2617 process_sdp(sub, resp);
2622 free(req);
2625 static void start_rtp(struct mgcp_subchannel *sub)
2627 ast_mutex_lock(&sub->lock);
2628 /* check again to be on the safe side */
2629 if (sub->rtp) {
2630 ast_rtp_destroy(sub->rtp);
2631 sub->rtp = NULL;
2633 /* Allocate the RTP now */
2634 sub->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
2635 if (sub->rtp && sub->owner)
2636 sub->owner->fds[0] = ast_rtp_fd(sub->rtp);
2637 if (sub->rtp)
2638 ast_rtp_setnat(sub->rtp, sub->nat);
2639 #if 0
2640 ast_rtp_set_callback(p->rtp, rtpready);
2641 ast_rtp_set_data(p->rtp, p);
2642 #endif
2643 /* Make a call*ID */
2644 snprintf(sub->callid, sizeof(sub->callid), "%08lx%s", ast_random(), sub->txident);
2645 /* Transmit the connection create */
2646 transmit_connect_with_sdp(sub, NULL);
2647 ast_mutex_unlock(&sub->lock);
2650 static void *mgcp_ss(void *data)
2652 struct ast_channel *chan = data;
2653 struct mgcp_subchannel *sub = chan->tech_pvt;
2654 struct mgcp_endpoint *p = sub->parent;
2655 /* char exten[AST_MAX_EXTENSION] = ""; */
2656 int len = 0;
2657 int timeout = firstdigittimeout;
2658 int res= 0;
2659 int getforward = 0;
2660 int loop_pause = 100;
2662 len = strlen(p->dtmf_buf);
2664 while(len < AST_MAX_EXTENSION-1) {
2665 res = 1; /* Assume that we will get a digit */
2666 while (strlen(p->dtmf_buf) == len){
2667 ast_safe_sleep(chan, loop_pause);
2668 timeout -= loop_pause;
2669 if (timeout <= 0){
2670 res = 0;
2671 break;
2673 res = 1;
2676 timeout = 0;
2677 len = strlen(p->dtmf_buf);
2679 if (!ast_ignore_pattern(chan->context, p->dtmf_buf)) {
2680 /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
2681 ast_indicate(chan, -1);
2682 } else {
2683 /* XXX Redundant? We should already be playing dialtone */
2684 /*tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALTONE);*/
2685 transmit_notify_request(sub, "L/dl");
2687 if (ast_exists_extension(chan, chan->context, p->dtmf_buf, 1, p->cid_num)) {
2688 if (!res || !ast_matchmore_extension(chan, chan->context, p->dtmf_buf, 1, p->cid_num)) {
2689 if (getforward) {
2690 /* Record this as the forwarding extension */
2691 ast_copy_string(p->call_forward, p->dtmf_buf, sizeof(p->call_forward));
2692 if (option_verbose > 2) {
2693 ast_verbose(VERBOSE_PREFIX_3 "Setting call forward to '%s' on channel %s\n",
2694 p->call_forward, chan->name);
2696 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
2697 transmit_notify_request(sub, "L/sl");
2698 if (res)
2699 break;
2700 usleep(500000);
2701 /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
2702 ast_indicate(chan, -1);
2703 sleep(1);
2704 memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
2705 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALTONE);*/
2706 transmit_notify_request(sub, "L/dl");
2707 len = 0;
2708 getforward = 0;
2709 } else {
2710 /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
2711 ast_indicate(chan, -1);
2712 ast_copy_string(chan->exten, p->dtmf_buf, sizeof(chan->exten));
2713 memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
2714 ast_set_callerid(chan,
2715 p->hidecallerid ? "" : p->cid_num,
2716 p->hidecallerid ? "" : p->cid_name,
2717 chan->cid.cid_ani ? NULL : p->cid_num);
2718 ast_setstate(chan, AST_STATE_RING);
2719 /*zt_enable_ec(p);*/
2720 if (p->dtmfmode & MGCP_DTMF_HYBRID) {
2721 p->dtmfmode |= MGCP_DTMF_INBAND;
2722 ast_indicate(chan, -1);
2724 res = ast_pbx_run(chan);
2725 if (res) {
2726 ast_log(LOG_WARNING, "PBX exited non-zero\n");
2727 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);*/
2728 /*transmit_notify_request(p, "nbz", 1);*/
2729 transmit_notify_request(sub, "G/cg");
2731 return NULL;
2733 } else {
2734 /* It's a match, but they just typed a digit, and there is an ambiguous match,
2735 so just set the timeout to matchdigittimeout and wait some more */
2736 timeout = matchdigittimeout;
2738 } else if (res == 0) {
2739 ast_log(LOG_DEBUG, "not enough digits (and no ambiguous match)...\n");
2740 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);*/
2741 transmit_notify_request(sub, "G/cg");
2742 /*zt_wait_event(p->subs[index].zfd);*/
2743 ast_hangup(chan);
2744 memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
2745 return NULL;
2746 } else if (p->hascallwaiting && p->callwaiting && !strcmp(p->dtmf_buf, "*70")) {
2747 if (option_verbose > 2) {
2748 ast_verbose(VERBOSE_PREFIX_3 "Disabling call waiting on %s\n", chan->name);
2750 /* Disable call waiting if enabled */
2751 p->callwaiting = 0;
2752 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
2753 transmit_notify_request(sub, "L/sl");
2754 len = 0;
2755 memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
2756 timeout = firstdigittimeout;
2757 } else if (!strcmp(p->dtmf_buf,ast_pickup_ext())) {
2758 /* Scan all channels and see if any there
2759 * ringing channqels with that have call groups
2760 * that equal this channels pickup group
2762 if (ast_pickup_call(chan)) {
2763 ast_log(LOG_WARNING, "No call pickup possible...\n");
2764 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);*/
2765 transmit_notify_request(sub, "G/cg");
2767 memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
2768 ast_hangup(chan);
2769 return NULL;
2770 } else if (!p->hidecallerid && !strcmp(p->dtmf_buf, "*67")) {
2771 if (option_verbose > 2) {
2772 ast_verbose(VERBOSE_PREFIX_3 "Disabling Caller*ID on %s\n", chan->name);
2774 /* Disable Caller*ID if enabled */
2775 p->hidecallerid = 1;
2776 ast_set_callerid(chan, "", "", NULL);
2777 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
2778 transmit_notify_request(sub, "L/sl");
2779 len = 0;
2780 memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
2781 timeout = firstdigittimeout;
2782 } else if (p->callreturn && !strcmp(p->dtmf_buf, "*69")) {
2783 res = 0;
2784 if (!ast_strlen_zero(p->lastcallerid)) {
2785 res = ast_say_digit_str(chan, p->lastcallerid, "", chan->language);
2787 if (!res)
2788 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
2789 transmit_notify_request(sub, "L/sl");
2790 break;
2791 } else if (!strcmp(p->dtmf_buf, "*78")) {
2792 /* Do not disturb */
2793 if (option_verbose > 2) {
2794 ast_verbose(VERBOSE_PREFIX_3 "Enabled DND on channel %s\n", chan->name);
2796 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
2797 transmit_notify_request(sub, "L/sl");
2798 p->dnd = 1;
2799 getforward = 0;
2800 memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
2801 len = 0;
2802 } else if (!strcmp(p->dtmf_buf, "*79")) {
2803 /* Do not disturb */
2804 if (option_verbose > 2) {
2805 ast_verbose(VERBOSE_PREFIX_3 "Disabled DND on channel %s\n", chan->name);
2807 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
2808 transmit_notify_request(sub, "L/sl");
2809 p->dnd = 0;
2810 getforward = 0;
2811 memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
2812 len = 0;
2813 } else if (p->cancallforward && !strcmp(p->dtmf_buf, "*72")) {
2814 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
2815 transmit_notify_request(sub, "L/sl");
2816 getforward = 1;
2817 memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
2818 len = 0;
2819 } else if (p->cancallforward && !strcmp(p->dtmf_buf, "*73")) {
2820 if (option_verbose > 2) {
2821 ast_verbose(VERBOSE_PREFIX_3 "Cancelling call forwarding on channel %s\n", chan->name);
2823 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
2824 transmit_notify_request(sub, "L/sl");
2825 memset(p->call_forward, 0, sizeof(p->call_forward));
2826 getforward = 0;
2827 memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
2828 len = 0;
2829 } else if (!strcmp(p->dtmf_buf, ast_parking_ext()) &&
2830 sub->next->owner && ast_bridged_channel(sub->next->owner)) {
2831 /* This is a three way call, the main call being a real channel,
2832 and we're parking the first call. */
2833 ast_masq_park_call(ast_bridged_channel(sub->next->owner), chan, 0, NULL);
2834 if (option_verbose > 2) {
2835 ast_verbose(VERBOSE_PREFIX_3 "Parking call to '%s'\n", chan->name);
2837 break;
2838 } else if (!ast_strlen_zero(p->lastcallerid) && !strcmp(p->dtmf_buf, "*60")) {
2839 if (option_verbose > 2) {
2840 ast_verbose(VERBOSE_PREFIX_3 "Blacklisting number %s\n", p->lastcallerid);
2842 res = ast_db_put("blacklist", p->lastcallerid, "1");
2843 if (!res) {
2844 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
2845 transmit_notify_request(sub, "L/sl");
2846 memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
2847 len = 0;
2849 } else if (p->hidecallerid && !strcmp(p->dtmf_buf, "*82")) {
2850 if (option_verbose > 2) {
2851 ast_verbose(VERBOSE_PREFIX_3 "Enabling Caller*ID on %s\n", chan->name);
2853 /* Enable Caller*ID if enabled */
2854 p->hidecallerid = 0;
2855 ast_set_callerid(chan, p->cid_num, p->cid_name, NULL);
2856 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
2857 transmit_notify_request(sub, "L/sl");
2858 len = 0;
2859 memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
2860 timeout = firstdigittimeout;
2861 } else if (!ast_canmatch_extension(chan, chan->context, p->dtmf_buf, 1, chan->cid.cid_num) &&
2862 ((p->dtmf_buf[0] != '*') || (strlen(p->dtmf_buf) > 2))) {
2863 if (option_debug)
2864 ast_log(LOG_DEBUG, "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);
2865 break;
2867 if (!timeout)
2868 timeout = gendigittimeout;
2869 if (len && !ast_ignore_pattern(chan->context, p->dtmf_buf))
2870 /*tone_zone_play_tone(p->subs[index].zfd, -1);*/
2871 ast_indicate(chan, -1);
2873 #if 0
2874 for (;;) {
2875 res = ast_waitfordigit(chan, to);
2876 if (!res) {
2877 ast_log(LOG_DEBUG, "Timeout...\n");
2878 break;
2880 if (res < 0) {
2881 ast_log(LOG_DEBUG, "Got hangup...\n");
2882 ast_hangup(chan);
2883 break;
2885 exten[pos++] = res;
2886 if (!ast_ignore_pattern(chan->context, exten))
2887 ast_indicate(chan, -1);
2888 if (ast_matchmore_extension(chan, chan->context, exten, 1, chan->callerid)) {
2889 if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid))
2890 to = 3000;
2891 else
2892 to = 8000;
2893 } else
2894 break;
2896 if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid)) {
2897 ast_copy_string(chan->exten, exten, sizeof(chan->exten)1);
2898 if (!p->rtp) {
2899 start_rtp(p);
2901 ast_setstate(chan, AST_STATE_RING);
2902 chan->rings = 1;
2903 if (ast_pbx_run(chan)) {
2904 ast_log(LOG_WARNING, "Unable to launch PBX on %s\n", chan->name);
2905 } else {
2906 memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
2907 return NULL;
2910 #endif
2911 ast_hangup(chan);
2912 memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
2913 return NULL;
2916 static int attempt_transfer(struct mgcp_endpoint *p)
2918 /* *************************
2919 * I hope this works.
2920 * Copied out of chan_zap
2921 * Cross your fingers
2922 * *************************/
2924 /* In order to transfer, we need at least one of the channels to
2925 actually be in a call bridge. We can't conference two applications
2926 together (but then, why would we want to?) */
2927 if (ast_bridged_channel(p->sub->owner)) {
2928 /* The three-way person we're about to transfer to could still be in MOH, so
2929 stop if now if appropriate */
2930 if (ast_bridged_channel(p->sub->next->owner))
2931 ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
2932 if (p->sub->owner->_state == AST_STATE_RINGING) {
2933 ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
2935 if (ast_channel_masquerade(p->sub->next->owner, ast_bridged_channel(p->sub->owner))) {
2936 ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
2937 ast_bridged_channel(p->sub->owner)->name, p->sub->next->owner->name);
2938 return -1;
2940 /* Orphan the channel */
2941 unalloc_sub(p->sub->next);
2942 } else if (ast_bridged_channel(p->sub->next->owner)) {
2943 if (p->sub->owner->_state == AST_STATE_RINGING) {
2944 ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
2946 ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
2947 if (ast_channel_masquerade(p->sub->owner, ast_bridged_channel(p->sub->next->owner))) {
2948 ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
2949 ast_bridged_channel(p->sub->next->owner)->name, p->sub->owner->name);
2950 return -1;
2952 /*swap_subs(p, SUB_THREEWAY, SUB_REAL);*/
2953 if (option_verbose > 2) {
2954 ast_verbose(VERBOSE_PREFIX_3 "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name);
2956 p->sub = p->sub->next;
2957 unalloc_sub(p->sub->next);
2958 /* Tell the caller not to hangup */
2959 return 1;
2960 } else {
2961 ast_log(LOG_DEBUG, "Neither %s nor %s are in a bridge, nothing to transfer\n",
2962 p->sub->owner->name, p->sub->next->owner->name);
2963 p->sub->next->owner->_softhangup |= AST_SOFTHANGUP_DEV;
2964 if (p->sub->next->owner) {
2965 p->sub->next->alreadygone = 1;
2966 mgcp_queue_hangup(p->sub->next);
2969 return 0;
2972 static void handle_hd_hf(struct mgcp_subchannel *sub, char *ev)
2974 struct mgcp_endpoint *p = sub->parent;
2975 struct ast_channel *c;
2976 pthread_t t;
2977 pthread_attr_t attr;
2978 pthread_attr_init(&attr);
2979 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
2981 /* Off hook / answer */
2982 if (sub->outgoing) {
2983 /* Answered */
2984 if (sub->owner) {
2985 if (ast_bridged_channel(sub->owner))
2986 ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
2987 sub->cxmode = MGCP_CX_SENDRECV;
2988 if (!sub->rtp) {
2989 start_rtp(sub);
2990 } else {
2991 transmit_modify_request(sub);
2993 /*transmit_notify_request(sub, "aw");*/
2994 transmit_notify_request(sub, "");
2995 mgcp_queue_control(sub, AST_CONTROL_ANSWER);
2997 } else {
2998 /* Start switch */
2999 /*sub->cxmode = MGCP_CX_SENDRECV;*/
3000 if (!sub->owner) {
3001 if (!sub->rtp) {
3002 start_rtp(sub);
3003 } else {
3004 transmit_modify_request(sub);
3006 if (p->immediate) {
3007 /* The channel is immediately up. Start right away */
3008 #ifdef DLINK_BUGGY_FIRMWARE
3009 transmit_notify_request(sub, "rt");
3010 #else
3011 transmit_notify_request(sub, "G/rt");
3012 #endif
3013 c = mgcp_new(sub, AST_STATE_RING);
3014 if (!c) {
3015 ast_log(LOG_WARNING, "Unable to start PBX on channel %s@%s\n", p->name, p->parent->name);
3016 transmit_notify_request(sub, "G/cg");
3017 ast_hangup(c);
3019 } else {
3020 if (has_voicemail(p)) {
3021 transmit_notify_request(sub, "L/sl");
3022 } else {
3023 transmit_notify_request(sub, "L/dl");
3025 c = mgcp_new(sub, AST_STATE_DOWN);
3026 if (c) {
3027 if (ast_pthread_create(&t, &attr, mgcp_ss, c)) {
3028 ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
3029 ast_hangup(c);
3031 } else {
3032 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", p->name, p->parent->name);
3035 } else {
3036 if (p->hookstate == MGCP_OFFHOOK) {
3037 ast_log(LOG_WARNING, "Off hook, but already have owner on %s@%s\n", p->name, p->parent->name);
3038 } else {
3039 ast_log(LOG_WARNING, "On hook, but already have owner on %s@%s\n", p->name, p->parent->name);
3040 ast_log(LOG_WARNING, "If we're onhook why are we here trying to handle a hd or hf?\n");
3042 if (ast_bridged_channel(sub->owner))
3043 ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
3044 sub->cxmode = MGCP_CX_SENDRECV;
3045 if (!sub->rtp) {
3046 start_rtp(sub);
3047 } else {
3048 transmit_modify_request(sub);
3050 /*transmit_notify_request(sub, "aw");*/
3051 transmit_notify_request(sub, "");
3052 /*ast_queue_control(sub->owner, AST_CONTROL_ANSWER);*/
3055 pthread_attr_destroy(&attr);
3058 static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req, struct sockaddr_in *sin)
3060 char *ev, *s;
3061 struct ast_frame f = { 0, };
3062 struct mgcp_endpoint *p = sub->parent;
3063 struct mgcp_gateway *g = NULL;
3064 int res;
3066 if (mgcpdebug) {
3067 ast_verbose("Handling request '%s' on %s@%s\n", req->verb, p->name, p->parent->name);
3069 /* Clear out potential response */
3070 if (!strcasecmp(req->verb, "RSIP")) {
3071 /* Test if this RSIP request is just a keepalive */
3072 if(!strcasecmp( get_header(req, "RM"), "X-keepalive")) {
3073 if (option_verbose > 2)
3074 ast_verbose(VERBOSE_PREFIX_3 "Received keepalive request from %s@%s\n", p->name, p->parent->name);
3075 transmit_response(sub, "200", req, "OK");
3076 } else {
3077 dump_queue(p->parent, p);
3078 dump_cmd_queues(p, NULL);
3080 if (option_verbose > 2 && (strcmp(p->name, p->parent->wcardep) != 0)) {
3081 ast_verbose(VERBOSE_PREFIX_3 "Resetting interface %s@%s\n", p->name, p->parent->name);
3083 /* For RSIP on wildcard we reset all endpoints */
3084 if (!strcmp(p->name, p->parent->wcardep)) {
3085 /* Reset all endpoints */
3086 struct mgcp_endpoint *tmp_ep;
3088 g = p->parent;
3089 tmp_ep = g->endpoints;
3090 while (tmp_ep) {
3091 /*if ((strcmp(tmp_ep->name, "*") != 0) && (strcmp(tmp_ep->name, "aaln/" "*") != 0)) {*/
3092 if (strcmp(tmp_ep->name, g->wcardep) != 0) {
3093 struct mgcp_subchannel *tmp_sub, *first_sub;
3094 if (option_verbose > 2) {
3095 ast_verbose(VERBOSE_PREFIX_3 "Resetting interface %s@%s\n", tmp_ep->name, p->parent->name);
3098 first_sub = tmp_ep->sub;
3099 tmp_sub = tmp_ep->sub;
3100 while (tmp_sub) {
3101 mgcp_queue_hangup(tmp_sub);
3102 tmp_sub = tmp_sub->next;
3103 if (tmp_sub == first_sub)
3104 break;
3107 tmp_ep = tmp_ep->next;
3109 } else if (sub->owner) {
3110 mgcp_queue_hangup(sub);
3112 transmit_response(sub, "200", req, "OK");
3113 /* We dont send NTFY or AUEP to wildcard ep */
3114 if (strcmp(p->name, p->parent->wcardep) != 0) {
3115 transmit_notify_request(sub, "");
3116 /* Audit endpoint.
3117 Idea is to prevent lost lines due to race conditions
3119 transmit_audit_endpoint(p);
3122 } else if (!strcasecmp(req->verb, "NTFY")) {
3123 /* Acknowledge and be sure we keep looking for the same things */
3124 transmit_response(sub, "200", req, "OK");
3125 /* Notified of an event */
3126 ev = get_header(req, "O");
3127 s = strchr(ev, '/');
3128 if (s) ev = s + 1;
3129 ast_log(LOG_DEBUG, "Endpoint '%s@%s-%d' observed '%s'\n", p->name, p->parent->name, sub->id, ev);
3130 /* Keep looking for events unless this was a hangup */
3131 if (strcasecmp(ev, "hu") && strcasecmp(ev, "hd") && strcasecmp(ev, "ping")) {
3132 transmit_notify_request(sub, p->curtone);
3134 if (!strcasecmp(ev, "hd")) {
3135 p->hookstate = MGCP_OFFHOOK;
3136 sub->cxmode = MGCP_CX_SENDRECV;
3137 handle_hd_hf(sub, ev);
3138 } else if (!strcasecmp(ev, "hf")) {
3139 /* We can assume we are offhook if we received a hookflash */
3140 /* First let's just do call wait and ignore threeway */
3141 /* We're currently in charge */
3142 if (p->hookstate != MGCP_OFFHOOK) {
3143 /* Cisco c7940 sends hf even if the phone is onhook */
3144 /* Thanks to point on IRC for pointing this out */
3145 return -1;
3147 /* do not let * conference two down channels */
3148 if (sub->owner && sub->owner->_state == AST_STATE_DOWN && !sub->next->owner)
3149 return -1;
3151 if (p->callwaiting || p->transfer || p->threewaycalling) {
3152 if (option_verbose > 2) {
3153 ast_verbose(VERBOSE_PREFIX_3 "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name);
3155 p->sub = p->sub->next;
3157 /* transfer control to our next subchannel */
3158 if (!sub->next->owner) {
3159 /* plave the first call on hold and start up a new call */
3160 sub->cxmode = MGCP_CX_MUTE;
3161 if (option_verbose > 2) {
3162 ast_verbose(VERBOSE_PREFIX_3 "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
3164 transmit_modify_request(sub);
3165 if (sub->owner && ast_bridged_channel(sub->owner))
3166 ast_queue_control(sub->owner, AST_CONTROL_HOLD);
3167 sub->next->cxmode = MGCP_CX_RECVONLY;
3168 handle_hd_hf(sub->next, ev);
3169 } else if (sub->owner && sub->next->owner) {
3170 /* We've got two active calls lets decide whether or not to conference or just flip flop */
3171 if ((!sub->outgoing) && (!sub->next->outgoing)) {
3172 /* We made both calls lets conferenct */
3173 if (option_verbose > 2) {
3174 ast_verbose(VERBOSE_PREFIX_3 "MGCP Conferencing %d and %d on %s@%s\n",
3175 sub->id, sub->next->id, p->name, p->parent->name);
3177 sub->cxmode = MGCP_CX_CONF;
3178 sub->next->cxmode = MGCP_CX_CONF;
3179 if (ast_bridged_channel(sub->next->owner))
3180 ast_queue_control(sub->next->owner, AST_CONTROL_UNHOLD);
3181 transmit_modify_request(sub);
3182 transmit_modify_request(sub->next);
3183 } else {
3184 /* Let's flipflop between calls */
3185 /* XXX Need to check for state up ??? */
3186 /* XXX Need a way to indicate the current call, or maybe the call that's waiting */
3187 if (option_verbose > 2) {
3188 ast_verbose(VERBOSE_PREFIX_3 "We didn't make one of the calls FLIPFLOP %d and %d on %s@%s\n",
3189 sub->id, sub->next->id, p->name, p->parent->name);
3191 sub->cxmode = MGCP_CX_MUTE;
3192 if (option_verbose > 2) {
3193 ast_verbose(VERBOSE_PREFIX_3 "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
3195 transmit_modify_request(sub);
3196 if (ast_bridged_channel(sub->owner))
3197 ast_queue_control(sub->owner, AST_CONTROL_HOLD);
3199 if (ast_bridged_channel(sub->next->owner))
3200 ast_queue_control(sub->next->owner, AST_CONTROL_HOLD);
3202 handle_hd_hf(sub->next, ev);
3204 } else {
3205 /* We've most likely lost one of our calls find an active call and bring it up */
3206 if (sub->owner) {
3207 p->sub = sub;
3208 } else if (sub->next->owner) {
3209 p->sub = sub->next;
3210 } else {
3211 /* We seem to have lost both our calls */
3212 /* XXX - What do we do now? */
3213 return -1;
3215 if (ast_bridged_channel(p->sub->owner))
3216 ast_queue_control(p->sub->owner, AST_CONTROL_UNHOLD);
3217 p->sub->cxmode = MGCP_CX_SENDRECV;
3218 transmit_modify_request(p->sub);
3220 } else {
3221 ast_log(LOG_WARNING, "Callwaiting, call transfer or threeway calling not enabled on endpoint %s@%s\n",
3222 p->name, p->parent->name);
3224 } else if (!strcasecmp(ev, "hu")) {
3225 p->hookstate = MGCP_ONHOOK;
3226 sub->cxmode = MGCP_CX_RECVONLY;
3227 ast_log(LOG_DEBUG, "MGCP %s@%s Went on hook\n", p->name, p->parent->name);
3228 /* Do we need to send MDCX before a DLCX ?
3229 if (sub->rtp) {
3230 transmit_modify_request(sub);
3233 if (p->transfer && (sub->owner && sub->next->owner) && ((!sub->outgoing) || (!sub->next->outgoing))) {
3234 /* We're allowed to transfer, we have two avtive calls and */
3235 /* we made at least one of the calls. Let's try and transfer */
3236 ast_mutex_lock(&p->sub->next->lock);
3237 res = attempt_transfer(p);
3238 if (res < 0) {
3239 if (p->sub->next->owner) {
3240 sub->next->alreadygone = 1;
3241 mgcp_queue_hangup(sub->next);
3243 } else if (res) {
3244 ast_log(LOG_WARNING, "Transfer attempt failed\n");
3245 ast_mutex_unlock(&p->sub->next->lock);
3246 return -1;
3248 ast_mutex_unlock(&p->sub->next->lock);
3249 } else {
3250 /* Hangup the current call */
3251 /* If there is another active call, mgcp_hangup will ring the phone with the other call */
3252 if (sub->owner) {
3253 sub->alreadygone = 1;
3254 mgcp_queue_hangup(sub);
3255 } else {
3256 /* verbose level check */
3257 if (option_verbose > 2) {
3258 ast_verbose(VERBOSE_PREFIX_3 "MGCP handle_request(%s@%s-%d) ast_channel already destroyed, resending DLCX.\n",
3259 p->name, p->parent->name, sub->id);
3261 /* Instruct the other side to remove the connection since it apparently *
3262 * still thinks the channel is active. *
3263 * For Cisco IAD2421 /BAK/ */
3264 transmit_connection_del(sub);
3267 if ((p->hookstate == MGCP_ONHOOK) && (!sub->rtp) && (!sub->next->rtp)) {
3268 p->hidecallerid = 0;
3269 if (p->hascallwaiting && !p->callwaiting) {
3270 if (option_verbose > 2)
3271 ast_verbose(VERBOSE_PREFIX_3 "Enabling call waiting on MGCP/%s@%s-%d\n", p->name, p->parent->name, sub->id);
3272 p->callwaiting = -1;
3274 if (has_voicemail(p)) {
3275 if (option_verbose > 2) {
3276 ast_verbose(VERBOSE_PREFIX_3 "MGCP handle_request(%s@%s) set vmwi(+)\n", p->name, p->parent->name);
3278 transmit_notify_request(sub, "L/vmwi(+)");
3279 } else {
3280 if (option_verbose > 2) {
3281 ast_verbose(VERBOSE_PREFIX_3 "MGCP handle_request(%s@%s) set vmwi(-)\n", p->name, p->parent->name);
3283 transmit_notify_request(sub, "L/vmwi(-)");
3286 } else if ((strlen(ev) == 1) &&
3287 (((ev[0] >= '0') && (ev[0] <= '9')) ||
3288 ((ev[0] >= 'A') && (ev[0] <= 'D')) ||
3289 (ev[0] == '*') || (ev[0] == '#'))) {
3290 if (sub && sub->owner && (sub->owner->_state >= AST_STATE_UP)) {
3291 f.frametype = AST_FRAME_DTMF;
3292 f.subclass = ev[0];
3293 f.src = "mgcp";
3294 /* XXX MUST queue this frame to all subs in threeway call if threeway call is active */
3295 mgcp_queue_frame(sub, &f);
3296 ast_mutex_lock(&sub->next->lock);
3297 if (sub->next->owner)
3298 mgcp_queue_frame(sub->next, &f);
3299 ast_mutex_unlock(&sub->next->lock);
3300 if (strstr(p->curtone, "wt") && (ev[0] == 'A')) {
3301 memset(p->curtone, 0, sizeof(p->curtone));
3303 } else {
3304 p->dtmf_buf[strlen(p->dtmf_buf)] = ev[0];
3305 p->dtmf_buf[strlen(p->dtmf_buf)] = '\0';
3307 } else if (!strcasecmp(ev, "T")) {
3308 /* Digit timeout -- unimportant */
3309 } else if (!strcasecmp(ev, "ping")) {
3310 /* ping -- unimportant */
3311 } else {
3312 ast_log(LOG_NOTICE, "Received unknown event '%s' from %s@%s\n", ev, p->name, p->parent->name);
3314 } else {
3315 ast_log(LOG_WARNING, "Unknown verb '%s' received from %s\n", req->verb, ast_inet_ntoa(sin->sin_addr));
3316 transmit_response(sub, "510", req, "Unknown verb");
3318 return 0;
3321 static int find_and_retrans(struct mgcp_subchannel *sub, struct mgcp_request *req)
3323 int seqno=0;
3324 time_t now;
3325 struct mgcp_response *prev = NULL, *cur, *next, *answer=NULL;
3326 time(&now);
3327 if (sscanf(req->identifier, "%d", &seqno) != 1)
3328 seqno = 0;
3329 cur = sub->parent->parent->responses;
3330 while(cur) {
3331 next = cur->next;
3332 if (now - cur->whensent > RESPONSE_TIMEOUT) {
3333 /* Delete this entry */
3334 if (prev)
3335 prev->next = next;
3336 else
3337 sub->parent->parent->responses = next;
3338 free(cur);
3339 } else {
3340 if (seqno == cur->seqno)
3341 answer = cur;
3342 prev = cur;
3344 cur = next;
3346 if (answer) {
3347 resend_response(sub, answer);
3348 return 1;
3350 return 0;
3353 static int mgcpsock_read(int *id, int fd, short events, void *ignore)
3355 struct mgcp_request req;
3356 struct sockaddr_in sin;
3357 struct mgcp_subchannel *sub;
3358 int res;
3359 socklen_t len;
3360 int result;
3361 int ident;
3362 len = sizeof(sin);
3363 memset(&req, 0, sizeof(req));
3364 res = recvfrom(mgcpsock, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len);
3365 if (res < 0) {
3366 if (errno != ECONNREFUSED)
3367 ast_log(LOG_WARNING, "Recv error: %s\n", strerror(errno));
3368 return 1;
3370 req.data[res] = '\0';
3371 req.len = res;
3372 if (mgcpdebug) {
3373 ast_verbose("MGCP read: \n%s\nfrom %s:%d\n", req.data, ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
3375 parse(&req);
3376 if (req.headers < 1) {
3377 /* Must have at least one header */
3378 return 1;
3380 if (ast_strlen_zero(req.identifier)) {
3381 ast_log(LOG_NOTICE, "Message from %s missing identifier\n", ast_inet_ntoa(sin.sin_addr));
3382 return 1;
3385 if (sscanf(req.verb, "%d", &result) && sscanf(req.identifier, "%d", &ident)) {
3386 /* Try to find who this message is for, if it's important */
3387 sub = find_subchannel_and_lock(NULL, ident, &sin);
3388 if (sub) {
3389 struct mgcp_gateway *gw = sub->parent->parent;
3390 struct mgcp_message *cur, *prev;
3392 ast_mutex_unlock(&sub->lock);
3393 ast_mutex_lock(&gw->msgs_lock);
3394 for (prev = NULL, cur = gw->msgs; cur; prev = cur, cur = cur->next) {
3395 if (cur->seqno == ident) {
3396 ast_log(LOG_DEBUG, "Got response back on transaction %d\n", ident);
3397 if (prev)
3398 prev->next = cur->next;
3399 else
3400 gw->msgs = cur->next;
3401 break;
3405 /* stop retrans timer if the queue is empty */
3406 if (!gw->msgs) {
3407 AST_SCHED_DEL(sched, gw->retransid);
3410 ast_mutex_unlock(&gw->msgs_lock);
3411 if (cur) {
3412 handle_response(cur->owner_ep, cur->owner_sub, result, ident, &req);
3413 free(cur);
3414 return 1;
3417 ast_log(LOG_NOTICE, "Got response back on [%s] for transaction %d we aren't sending?\n",
3418 gw->name, ident);
3420 } else {
3421 if (ast_strlen_zero(req.endpoint) ||
3422 ast_strlen_zero(req.version) ||
3423 ast_strlen_zero(req.verb)) {
3424 ast_log(LOG_NOTICE, "Message must have a verb, an idenitifier, version, and endpoint\n");
3425 return 1;
3427 /* Process request, with iflock held */
3428 sub = find_subchannel_and_lock(req.endpoint, 0, &sin);
3429 if (sub) {
3430 /* look first to find a matching response in the queue */
3431 if (!find_and_retrans(sub, &req))
3432 /* pass the request off to the currently mastering subchannel */
3433 handle_request(sub, &req, &sin);
3434 ast_mutex_unlock(&sub->lock);
3437 return 1;
3440 static int *mgcpsock_read_id = NULL;
3442 static void *do_monitor(void *data)
3444 int res;
3445 int reloading;
3446 /*struct mgcp_gateway *g;*/
3447 /*struct mgcp_endpoint *e;*/
3448 /*time_t thispass = 0, lastpass = 0;*/
3450 /* Add an I/O event to our UDP socket */
3451 if (mgcpsock > -1)
3452 mgcpsock_read_id = ast_io_add(io, mgcpsock, mgcpsock_read, AST_IO_IN, NULL);
3454 /* This thread monitors all the frame relay interfaces which are not yet in use
3455 (and thus do not have a separate thread) indefinitely */
3456 /* From here on out, we die whenever asked */
3457 for(;;) {
3458 /* Check for a reload request */
3459 ast_mutex_lock(&mgcp_reload_lock);
3460 reloading = mgcp_reloading;
3461 mgcp_reloading = 0;
3462 ast_mutex_unlock(&mgcp_reload_lock);
3463 if (reloading) {
3464 if (option_verbose > 0)
3465 ast_verbose(VERBOSE_PREFIX_1 "Reloading MGCP\n");
3466 mgcp_do_reload();
3467 /* Add an I/O event to our UDP socket */
3468 if (mgcpsock > -1)
3469 mgcpsock_read_id = ast_io_add(io, mgcpsock, mgcpsock_read, AST_IO_IN, NULL);
3472 /* Check for interfaces needing to be killed */
3473 /* Don't let anybody kill us right away. Nobody should lock the interface list
3474 and wait for the monitor list, but the other way around is okay. */
3475 ast_mutex_lock(&monlock);
3476 /* Lock the network interface */
3477 ast_mutex_lock(&netlock);
3479 #if 0
3480 /* XXX THIS IS COMPLETELY HOSED */
3481 /* The gateway goes into a state of panic */
3482 /* If the vmwi indicator is sent while it is reseting interfaces */
3483 lastpass = thispass;
3484 thispass = time(NULL);
3485 g = gateways;
3486 while(g) {
3487 if (thispass != lastpass) {
3488 e = g->endpoints;
3489 while(e) {
3490 if (e->type == TYPE_LINE) {
3491 res = has_voicemail(e);
3492 if ((e->msgstate != res) && (e->hookstate == MGCP_ONHOOK) && (!e->rtp)){
3493 if (res) {
3494 transmit_notify_request(e, "L/vmwi(+)");
3495 } else {
3496 transmit_notify_request(e, "L/vmwi(-)");
3498 e->msgstate = res;
3499 e->onhooktime = thispass;
3502 e = e->next;
3505 g = g->next;
3507 #endif
3508 /* Okay, now that we know what to do, release the network lock */
3509 ast_mutex_unlock(&netlock);
3510 /* And from now on, we're okay to be killed, so release the monitor lock as well */
3511 ast_mutex_unlock(&monlock);
3512 pthread_testcancel();
3513 /* Wait for sched or io */
3514 res = ast_sched_wait(sched);
3515 /* copied from chan_sip.c */
3516 if ((res < 0) || (res > 1000))
3517 res = 1000;
3518 res = ast_io_wait(io, res);
3519 ast_mutex_lock(&monlock);
3520 if (res >= 0)
3521 ast_sched_runq(sched);
3522 ast_mutex_unlock(&monlock);
3524 /* Never reached */
3525 return NULL;
3528 static int restart_monitor(void)
3530 /* If we're supposed to be stopped -- stay stopped */
3531 if (monitor_thread == AST_PTHREADT_STOP)
3532 return 0;
3533 if (ast_mutex_lock(&monlock)) {
3534 ast_log(LOG_WARNING, "Unable to lock monitor\n");
3535 return -1;
3537 if (monitor_thread == pthread_self()) {
3538 ast_mutex_unlock(&monlock);
3539 ast_log(LOG_WARNING, "Cannot kill myself\n");
3540 return -1;
3542 if (monitor_thread != AST_PTHREADT_NULL) {
3543 /* Wake up the thread */
3544 pthread_kill(monitor_thread, SIGURG);
3545 } else {
3546 /* Start a new monitor */
3547 if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
3548 ast_mutex_unlock(&monlock);
3549 ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
3550 return -1;
3553 ast_mutex_unlock(&monlock);
3554 return 0;
3557 static struct ast_channel *mgcp_request(const char *type, int format, void *data, int *cause)
3559 int oldformat;
3560 struct mgcp_subchannel *sub;
3561 struct ast_channel *tmpc = NULL;
3562 char tmp[256];
3563 char *dest = data;
3565 oldformat = format;
3566 format &= capability;
3567 if (!format) {
3568 ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
3569 return NULL;
3571 ast_copy_string(tmp, dest, sizeof(tmp));
3572 if (ast_strlen_zero(tmp)) {
3573 ast_log(LOG_NOTICE, "MGCP Channels require an endpoint\n");
3574 return NULL;
3576 sub = find_subchannel_and_lock(tmp, 0, NULL);
3577 if (!sub) {
3578 ast_log(LOG_WARNING, "Unable to find MGCP endpoint '%s'\n", tmp);
3579 *cause = AST_CAUSE_UNREGISTERED;
3580 return NULL;
3583 if (option_verbose > 2) {
3584 ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_request(%s)\n", tmp);
3585 ast_verbose(VERBOSE_PREFIX_3 "MGCP cw: %d, dnd: %d, so: %d, sno: %d\n",
3586 sub->parent->callwaiting, sub->parent->dnd, sub->owner ? 1 : 0, sub->next->owner ? 1: 0);
3588 /* Must be busy */
3589 if (((sub->parent->callwaiting) && ((sub->owner) && (sub->next->owner))) ||
3590 ((!sub->parent->callwaiting) && (sub->owner)) ||
3591 (sub->parent->dnd && (ast_strlen_zero(sub->parent->call_forward)))) {
3592 if (sub->parent->hookstate == MGCP_ONHOOK) {
3593 if (has_voicemail(sub->parent)) {
3594 transmit_notify_request(sub,"L/vmwi(+)");
3595 } else {
3596 transmit_notify_request(sub,"L/vmwi(-)");
3599 *cause = AST_CAUSE_BUSY;
3600 ast_mutex_unlock(&sub->lock);
3601 return NULL;
3603 tmpc = mgcp_new(sub->owner ? sub->next : sub, AST_STATE_DOWN);
3604 ast_mutex_unlock(&sub->lock);
3605 if (!tmpc)
3606 ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
3607 restart_monitor();
3608 return tmpc;
3611 /* modified for reload support */
3612 /*! \brief build_gateway: parse mgcp.conf and create gateway/endpoint structures */
3613 static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
3615 struct mgcp_gateway *gw;
3616 struct mgcp_endpoint *e;
3617 struct mgcp_subchannel *sub;
3618 /*char txident[80];*/
3619 int i=0, y=0;
3620 int gw_reload = 0;
3621 int ep_reload = 0;
3622 canreinvite = CANREINVITE;
3624 /* locate existing gateway */
3625 gw = gateways;
3626 while (gw) {
3627 if (!strcasecmp(cat, gw->name)) {
3628 /* gateway already exists */
3629 gw->delme = 0;
3630 gw_reload = 1;
3631 break;
3633 gw = gw->next;
3636 if (!gw)
3637 gw = malloc(sizeof(struct mgcp_gateway));
3639 if (gw) {
3640 if (!gw_reload) {
3641 memset(gw, 0, sizeof(struct mgcp_gateway));
3642 gw->expire = -1;
3643 gw->retransid = -1; /* SC */
3644 ast_mutex_init(&gw->msgs_lock);
3645 ast_copy_string(gw->name, cat, sizeof(gw->name));
3646 /* check if the name is numeric ip */
3647 if ((strchr(gw->name, '.')) && inet_addr(gw->name) != INADDR_NONE)
3648 gw->isnamedottedip = 1;
3650 while(v) {
3651 if (!strcasecmp(v->name, "host")) {
3652 if (!strcasecmp(v->value, "dynamic")) {
3653 /* They'll register with us */
3654 gw->dynamic = 1;
3655 memset(&gw->addr.sin_addr, 0, 4);
3656 if (gw->addr.sin_port) {
3657 /* If we've already got a port, make it the default rather than absolute */
3658 gw->defaddr.sin_port = gw->addr.sin_port;
3659 gw->addr.sin_port = 0;
3661 } else {
3662 /* Non-dynamic. Make sure we become that way if we're not */
3663 AST_SCHED_DEL(sched, gw->expire);
3664 gw->dynamic = 0;
3665 if (ast_get_ip(&gw->addr, v->value)) {
3666 if (!gw_reload) {
3667 ast_mutex_destroy(&gw->msgs_lock);
3668 free(gw);
3670 return NULL;
3673 } else if (!strcasecmp(v->name, "defaultip")) {
3674 if (ast_get_ip(&gw->defaddr, v->value)) {
3675 if (!gw_reload) {
3676 ast_mutex_destroy(&gw->msgs_lock);
3677 free(gw);
3679 return NULL;
3681 } else if (!strcasecmp(v->name, "permit") ||
3682 !strcasecmp(v->name, "deny")) {
3683 gw->ha = ast_append_ha(v->name, v->value, gw->ha);
3684 } else if (!strcasecmp(v->name, "port")) {
3685 gw->addr.sin_port = htons(atoi(v->value));
3686 } else if (!strcasecmp(v->name, "context")) {
3687 ast_copy_string(context, v->value, sizeof(context));
3688 } else if (!strcasecmp(v->name, "dtmfmode")) {
3689 if (!strcasecmp(v->value, "inband"))
3690 dtmfmode = MGCP_DTMF_INBAND;
3691 else if (!strcasecmp(v->value, "rfc2833"))
3692 dtmfmode = MGCP_DTMF_RFC2833;
3693 else if (!strcasecmp(v->value, "hybrid"))
3694 dtmfmode = MGCP_DTMF_HYBRID;
3695 else if (!strcasecmp(v->value, "none"))
3696 dtmfmode = 0;
3697 else
3698 ast_log(LOG_WARNING, "'%s' is not a valid DTMF mode at line %d\n", v->value, v->lineno);
3699 } else if (!strcasecmp(v->name, "nat")) {
3700 nat = ast_true(v->value);
3701 } else if (!strcasecmp(v->name, "callerid")) {
3702 if (!strcasecmp(v->value, "asreceived")) {
3703 cid_num[0] = '\0';
3704 cid_name[0] = '\0';
3705 } else {
3706 ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
3708 } else if (!strcasecmp(v->name, "language")) {
3709 ast_copy_string(language, v->value, sizeof(language));
3710 } else if (!strcasecmp(v->name, "accountcode")) {
3711 ast_copy_string(accountcode, v->value, sizeof(accountcode));
3712 } else if (!strcasecmp(v->name, "amaflags")) {
3713 y = ast_cdr_amaflags2int(v->value);
3714 if (y < 0) {
3715 ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
3716 } else {
3717 amaflags = y;
3719 } else if (!strcasecmp(v->name, "musiconhold")) {
3720 ast_copy_string(musicclass, v->value, sizeof(musicclass));
3721 } else if (!strcasecmp(v->name, "callgroup")) {
3722 cur_callergroup = ast_get_group(v->value);
3723 } else if (!strcasecmp(v->name, "pickupgroup")) {
3724 cur_pickupgroup = ast_get_group(v->value);
3725 } else if (!strcasecmp(v->name, "immediate")) {
3726 immediate = ast_true(v->value);
3727 } else if (!strcasecmp(v->name, "cancallforward")) {
3728 cancallforward = ast_true(v->value);
3729 } else if (!strcasecmp(v->name, "singlepath")) {
3730 singlepath = ast_true(v->value);
3731 } else if (!strcasecmp(v->name, "canreinvite")) {
3732 canreinvite = ast_true(v->value);
3733 } else if (!strcasecmp(v->name, "mailbox")) {
3734 ast_copy_string(mailbox, v->value, sizeof(mailbox));
3735 } else if (!strcasecmp(v->name, "adsi")) {
3736 adsi = ast_true(v->value);
3737 } else if (!strcasecmp(v->name, "callreturn")) {
3738 callreturn = ast_true(v->value);
3739 } else if (!strcasecmp(v->name, "callwaiting")) {
3740 callwaiting = ast_true(v->value);
3741 } else if (!strcasecmp(v->name, "slowsequence")) {
3742 slowsequence = ast_true(v->value);
3743 } else if (!strcasecmp(v->name, "transfer")) {
3744 transfer = ast_true(v->value);
3745 } else if (!strcasecmp(v->name, "threewaycalling")) {
3746 threewaycalling = ast_true(v->value);
3747 } else if (!strcasecmp(v->name, "wcardep")) {
3748 /* locate existing endpoint */
3749 e = gw->endpoints;
3750 while (e) {
3751 if (!strcasecmp(v->value, e->name)) {
3752 /* endpoint already exists */
3753 e->delme = 0;
3754 ep_reload = 1;
3755 break;
3757 e = e->next;
3760 if (!e) {
3761 /* Allocate wildcard endpoint */
3762 e = malloc(sizeof(struct mgcp_endpoint));
3763 ep_reload = 0;
3766 if (e) {
3767 if (!ep_reload) {
3768 memset(e, 0, sizeof(struct mgcp_endpoint));
3769 ast_mutex_init(&e->lock);
3770 ast_mutex_init(&e->rqnt_queue_lock);
3771 ast_mutex_init(&e->cmd_queue_lock);
3772 ast_copy_string(e->name, v->value, sizeof(e->name));
3773 e->needaudit = 1;
3775 ast_copy_string(gw->wcardep, v->value, sizeof(gw->wcardep));
3776 /* XXX Should we really check for uniqueness?? XXX */
3777 ast_copy_string(e->accountcode, accountcode, sizeof(e->accountcode));
3778 ast_copy_string(e->context, context, sizeof(e->context));
3779 ast_copy_string(e->cid_num, cid_num, sizeof(e->cid_num));
3780 ast_copy_string(e->cid_name, cid_name, sizeof(e->cid_name));
3781 ast_copy_string(e->language, language, sizeof(e->language));
3782 ast_copy_string(e->musicclass, musicclass, sizeof(e->musicclass));
3783 ast_copy_string(e->mailbox, mailbox, sizeof(e->mailbox));
3784 snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", ast_random());
3785 e->msgstate = -1;
3786 e->amaflags = amaflags;
3787 e->capability = capability;
3788 e->parent = gw;
3789 e->dtmfmode = dtmfmode;
3790 if (!ep_reload && e->sub && e->sub->rtp)
3791 e->dtmfmode |= MGCP_DTMF_INBAND;
3792 e->adsi = adsi;
3793 e->type = TYPE_LINE;
3794 e->immediate = immediate;
3795 e->callgroup=cur_callergroup;
3796 e->pickupgroup=cur_pickupgroup;
3797 e->callreturn = callreturn;
3798 e->cancallforward = cancallforward;
3799 e->singlepath = singlepath;
3800 e->canreinvite = canreinvite;
3801 e->callwaiting = callwaiting;
3802 e->hascallwaiting = callwaiting;
3803 e->slowsequence = slowsequence;
3804 e->transfer = transfer;
3805 e->threewaycalling = threewaycalling;
3806 e->onhooktime = time(NULL);
3807 /* ASSUME we're onhook */
3808 e->hookstate = MGCP_ONHOOK;
3809 if (!ep_reload) {
3810 /*snprintf(txident, sizeof(txident), "%08lx", ast_random());*/
3811 for (i = 0; i < MAX_SUBS; i++) {
3812 sub = malloc(sizeof(struct mgcp_subchannel));
3813 if (sub) {
3814 ast_verbose(VERBOSE_PREFIX_3 "Allocating subchannel '%d' on %s@%s\n", i, e->name, gw->name);
3815 memset(sub, 0, sizeof(struct mgcp_subchannel));
3816 ast_mutex_init(&sub->lock);
3817 ast_mutex_init(&sub->cx_queue_lock);
3818 sub->parent = e;
3819 sub->id = i;
3820 snprintf(sub->txident, sizeof(sub->txident), "%08lx", ast_random());
3821 /*stnrcpy(sub->txident, txident, sizeof(sub->txident) - 1);*/
3822 sub->cxmode = MGCP_CX_INACTIVE;
3823 sub->nat = nat;
3824 sub->next = e->sub;
3825 e->sub = sub;
3826 } else {
3827 /* XXX Should find a way to clean up our memory */
3828 ast_log(LOG_WARNING, "Out of memory allocating subchannel\n");
3829 return NULL;
3832 /* Make out subs a circular linked list so we can always sping through the whole bunch */
3833 sub = e->sub;
3834 /* find the end of the list */
3835 while(sub->next){
3836 sub = sub->next;
3838 /* set the last sub->next to the first sub */
3839 sub->next = e->sub;
3841 e->next = gw->endpoints;
3842 gw->endpoints = e;
3845 } else if (!strcasecmp(v->name, "trunk") ||
3846 !strcasecmp(v->name, "line")) {
3848 /* locate existing endpoint */
3849 e = gw->endpoints;
3850 while (e) {
3851 if (!strcasecmp(v->value, e->name)) {
3852 /* endpoint already exists */
3853 e->delme = 0;
3854 ep_reload = 1;
3855 break;
3857 e = e->next;
3860 if (!e) {
3861 e = malloc(sizeof(struct mgcp_endpoint));
3862 ep_reload = 0;
3865 if (e) {
3866 if (!ep_reload) {
3867 memset(e, 0, sizeof(struct mgcp_endpoint));
3868 ast_mutex_init(&e->lock);
3869 ast_mutex_init(&e->rqnt_queue_lock);
3870 ast_mutex_init(&e->cmd_queue_lock);
3871 ast_copy_string(e->name, v->value, sizeof(e->name));
3872 e->needaudit = 1;
3874 /* XXX Should we really check for uniqueness?? XXX */
3875 ast_copy_string(e->accountcode, accountcode, sizeof(e->accountcode));
3876 ast_copy_string(e->context, context, sizeof(e->context));
3877 ast_copy_string(e->cid_num, cid_num, sizeof(e->cid_num));
3878 ast_copy_string(e->cid_name, cid_name, sizeof(e->cid_name));
3879 ast_copy_string(e->language, language, sizeof(e->language));
3880 ast_copy_string(e->musicclass, musicclass, sizeof(e->musicclass));
3881 ast_copy_string(e->mailbox, mailbox, sizeof(e->mailbox));
3882 if (!ast_strlen_zero(mailbox)) {
3883 ast_verbose(VERBOSE_PREFIX_3 "Setting mailbox '%s' on %s@%s\n", mailbox, gw->name, e->name);
3885 if (!ep_reload) {
3886 /* XXX potential issue due to reload */
3887 e->msgstate = -1;
3888 e->parent = gw;
3890 e->amaflags = amaflags;
3891 e->capability = capability;
3892 e->dtmfmode = dtmfmode;
3893 e->adsi = adsi;
3894 if (!strcasecmp(v->name, "trunk"))
3895 e->type = TYPE_TRUNK;
3896 else
3897 e->type = TYPE_LINE;
3899 e->immediate = immediate;
3900 e->callgroup=cur_callergroup;
3901 e->pickupgroup=cur_pickupgroup;
3902 e->callreturn = callreturn;
3903 e->cancallforward = cancallforward;
3904 e->canreinvite = canreinvite;
3905 e->singlepath = singlepath;
3906 e->callwaiting = callwaiting;
3907 e->hascallwaiting = callwaiting;
3908 e->slowsequence = slowsequence;
3909 e->transfer = transfer;
3910 e->threewaycalling = threewaycalling;
3911 if (!ep_reload) {
3912 e->onhooktime = time(NULL);
3913 /* ASSUME we're onhook */
3914 e->hookstate = MGCP_ONHOOK;
3915 snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", ast_random());
3918 for (i = 0, sub = NULL; i < MAX_SUBS; i++) {
3919 if (!ep_reload) {
3920 sub = malloc(sizeof(struct mgcp_subchannel));
3921 } else {
3922 if (!sub)
3923 sub = e->sub;
3924 else
3925 sub = sub->next;
3928 if (sub) {
3929 if (!ep_reload) {
3930 ast_verbose(VERBOSE_PREFIX_3 "Allocating subchannel '%d' on %s@%s\n", i, e->name, gw->name);
3931 memset(sub, 0, sizeof(struct mgcp_subchannel));
3932 ast_mutex_init(&sub->lock);
3933 ast_mutex_init(&sub->cx_queue_lock);
3934 ast_copy_string(sub->magic, MGCP_SUBCHANNEL_MAGIC, sizeof(sub->magic));
3935 sub->parent = e;
3936 sub->id = i;
3937 snprintf(sub->txident, sizeof(sub->txident), "%08lx", ast_random());
3938 sub->cxmode = MGCP_CX_INACTIVE;
3939 sub->next = e->sub;
3940 e->sub = sub;
3942 sub->nat = nat;
3943 } else {
3944 /* XXX Should find a way to clean up our memory */
3945 ast_log(LOG_WARNING, "Out of memory allocating subchannel\n");
3946 return NULL;
3949 if (!ep_reload) {
3950 /* Make out subs a circular linked list so we can always sping through the whole bunch */
3951 sub = e->sub;
3952 /* find the end of the list */
3953 while (sub->next) {
3954 sub = sub->next;
3956 /* set the last sub->next to the first sub */
3957 sub->next = e->sub;
3959 e->next = gw->endpoints;
3960 gw->endpoints = e;
3963 } else
3964 ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
3965 v = v->next;
3968 if (!ntohl(gw->addr.sin_addr.s_addr) && !gw->dynamic) {
3969 ast_log(LOG_WARNING, "Gateway '%s' lacks IP address and isn't dynamic\n", gw->name);
3970 if (!gw_reload) {
3971 ast_mutex_destroy(&gw->msgs_lock);
3972 free(gw);
3974 return NULL;
3976 gw->defaddr.sin_family = AF_INET;
3977 gw->addr.sin_family = AF_INET;
3978 if (gw->defaddr.sin_addr.s_addr && !ntohs(gw->defaddr.sin_port))
3979 gw->defaddr.sin_port = htons(DEFAULT_MGCP_GW_PORT);
3980 if (gw->addr.sin_addr.s_addr && !ntohs(gw->addr.sin_port))
3981 gw->addr.sin_port = htons(DEFAULT_MGCP_GW_PORT);
3982 if (gw->addr.sin_addr.s_addr)
3983 if (ast_ouraddrfor(&gw->addr.sin_addr, &gw->ourip))
3984 memcpy(&gw->ourip, &__ourip, sizeof(gw->ourip));
3986 return (gw_reload ? NULL : gw);
3989 static enum ast_rtp_get_result mgcp_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
3991 struct mgcp_subchannel *sub = NULL;
3993 if (!(sub = chan->tech_pvt) || !(sub->rtp))
3994 return AST_RTP_GET_FAILED;
3996 *rtp = sub->rtp;
3998 if (sub->parent->canreinvite)
3999 return AST_RTP_TRY_NATIVE;
4000 else
4001 return AST_RTP_TRY_PARTIAL;
4004 static int mgcp_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
4006 /* XXX Is there such thing as video support with MGCP? XXX */
4007 struct mgcp_subchannel *sub;
4008 sub = chan->tech_pvt;
4009 if (sub && !sub->alreadygone) {
4010 transmit_modify_with_sdp(sub, rtp, codecs);
4011 return 0;
4013 return -1;
4016 static struct ast_rtp_protocol mgcp_rtp = {
4017 .type = "MGCP",
4018 .get_rtp_info = mgcp_get_rtp_peer,
4019 .set_rtp_peer = mgcp_set_rtp_peer,
4022 static void destroy_endpoint(struct mgcp_endpoint *e)
4024 struct mgcp_subchannel *sub = e->sub->next, *s;
4025 int i;
4027 for (i = 0; i < MAX_SUBS; i++) {
4028 ast_mutex_lock(&sub->lock);
4029 if (!ast_strlen_zero(sub->cxident)) {
4030 transmit_connection_del(sub);
4032 if (sub->rtp) {
4033 ast_rtp_destroy(sub->rtp);
4034 sub->rtp = NULL;
4036 memset(sub->magic, 0, sizeof(sub->magic));
4037 mgcp_queue_hangup(sub);
4038 dump_cmd_queues(NULL, sub);
4039 ast_mutex_unlock(&sub->lock);
4040 sub = sub->next;
4043 if (e->dsp) {
4044 ast_dsp_free(e->dsp);
4047 dump_queue(e->parent, e);
4048 dump_cmd_queues(e, NULL);
4050 sub = e->sub;
4051 for (i = 0; (i < MAX_SUBS) && sub; i++) {
4052 s = sub;
4053 sub = sub->next;
4054 ast_mutex_destroy(&s->lock);
4055 ast_mutex_destroy(&s->cx_queue_lock);
4056 free(s);
4058 ast_mutex_destroy(&e->lock);
4059 ast_mutex_destroy(&e->rqnt_queue_lock);
4060 ast_mutex_destroy(&e->cmd_queue_lock);
4061 free(e);
4064 static void destroy_gateway(struct mgcp_gateway *g)
4066 if (g->ha)
4067 ast_free_ha(g->ha);
4069 dump_queue(g, NULL);
4071 free (g);
4074 static void prune_gateways(void)
4076 struct mgcp_gateway *g, *z, *r;
4077 struct mgcp_endpoint *e, *p, *t;
4079 ast_mutex_lock(&gatelock);
4081 /* prune gateways */
4082 for (z = NULL, g = gateways; g;) {
4083 /* prune endpoints */
4084 for (p = NULL, e = g->endpoints; e; ) {
4085 if (e->delme || g->delme) {
4086 t = e;
4087 e = e->next;
4088 if (!p)
4089 g->endpoints = e;
4090 else
4091 p->next = e;
4092 destroy_endpoint(t);
4093 } else {
4094 p = e;
4095 e = e->next;
4099 if (g->delme) {
4100 r = g;
4101 g = g->next;
4102 if (!z)
4103 gateways = g;
4104 else
4105 z->next = g;
4107 destroy_gateway(r);
4108 } else {
4109 z = g;
4110 g = g->next;
4114 ast_mutex_unlock(&gatelock);
4117 static int reload_config(void)
4119 struct ast_config *cfg;
4120 struct ast_variable *v;
4121 struct mgcp_gateway *g;
4122 struct mgcp_endpoint *e;
4123 char *cat;
4124 struct ast_hostent ahp;
4125 struct hostent *hp;
4126 int format;
4128 if (gethostname(ourhost, sizeof(ourhost)-1)) {
4129 ast_log(LOG_WARNING, "Unable to get hostname, MGCP disabled\n");
4130 return 0;
4132 cfg = ast_config_load(config);
4134 /* We *must* have a config file otherwise stop immediately */
4135 if (!cfg) {
4136 ast_log(LOG_NOTICE, "Unable to load config %s, MGCP disabled\n", config);
4137 return 0;
4139 memset(&bindaddr, 0, sizeof(bindaddr));
4140 dtmfmode = 0;
4142 /* Copy the default jb config over global_jbconf */
4143 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
4145 v = ast_variable_browse(cfg, "general");
4146 while (v) {
4147 /* handle jb conf */
4148 if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
4149 v = v->next;
4150 continue;
4153 /* Create the interface list */
4154 if (!strcasecmp(v->name, "bindaddr")) {
4155 if (!(hp = ast_gethostbyname(v->value, &ahp))) {
4156 ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
4157 } else {
4158 memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
4160 } else if (!strcasecmp(v->name, "allow")) {
4161 format = ast_getformatbyname(v->value);
4162 if (format < 1)
4163 ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
4164 else
4165 capability |= format;
4166 } else if (!strcasecmp(v->name, "disallow")) {
4167 format = ast_getformatbyname(v->value);
4168 if (format < 1)
4169 ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
4170 else
4171 capability &= ~format;
4172 } else if (!strcasecmp(v->name, "tos")) {
4173 if (sscanf(v->value, "%d", &format) == 1)
4174 tos = format & 0xff;
4175 else if (!strcasecmp(v->value, "lowdelay"))
4176 tos = IPTOS_LOWDELAY;
4177 else if (!strcasecmp(v->value, "throughput"))
4178 tos = IPTOS_THROUGHPUT;
4179 else if (!strcasecmp(v->value, "reliability"))
4180 tos = IPTOS_RELIABILITY;
4181 else if (!strcasecmp(v->value, "mincost"))
4182 tos = IPTOS_MINCOST;
4183 else if (!strcasecmp(v->value, "none"))
4184 tos = 0;
4185 else
4186 ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none'\n", v->lineno);
4187 } else if (!strcasecmp(v->name, "port")) {
4188 if (sscanf(v->value, "%d", &ourport) == 1) {
4189 bindaddr.sin_port = htons(ourport);
4190 } else {
4191 ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
4194 v = v->next;
4197 /* mark existing entries for deletion */
4198 ast_mutex_lock(&gatelock);
4199 g = gateways;
4200 while (g) {
4201 g->delme = 1;
4202 e = g->endpoints;
4203 while (e) {
4204 e->delme = 1;
4205 e = e->next;
4207 g = g->next;
4209 ast_mutex_unlock(&gatelock);
4211 cat = ast_category_browse(cfg, NULL);
4212 while(cat) {
4213 if (strcasecmp(cat, "general")) {
4214 ast_mutex_lock(&gatelock);
4215 g = build_gateway(cat, ast_variable_browse(cfg, cat));
4216 if (g) {
4217 if (option_verbose > 2) {
4218 ast_verbose(VERBOSE_PREFIX_3 "Added gateway '%s'\n", g->name);
4220 g->next = gateways;
4221 gateways = g;
4223 ast_mutex_unlock(&gatelock);
4225 /* FS: process queue and IO */
4226 if (monitor_thread == pthread_self()) {
4227 if (sched) ast_sched_runq(sched);
4228 if (io) ast_io_wait(io, 10);
4231 cat = ast_category_browse(cfg, cat);
4234 /* prune deleted entries etc. */
4235 prune_gateways();
4237 if (ntohl(bindaddr.sin_addr.s_addr)) {
4238 memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
4239 } else {
4240 hp = ast_gethostbyname(ourhost, &ahp);
4241 if (!hp) {
4242 ast_log(LOG_WARNING, "Unable to get our IP address, MGCP disabled\n");
4243 ast_config_destroy(cfg);
4244 return 0;
4246 memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
4248 if (!ntohs(bindaddr.sin_port))
4249 bindaddr.sin_port = ntohs(DEFAULT_MGCP_CA_PORT);
4250 bindaddr.sin_family = AF_INET;
4251 ast_mutex_lock(&netlock);
4252 if (mgcpsock > -1)
4253 close(mgcpsock);
4255 if (mgcpsock_read_id != NULL)
4256 ast_io_remove(io, mgcpsock_read_id);
4257 mgcpsock_read_id = NULL;
4259 mgcpsock = socket(AF_INET, SOCK_DGRAM, 0);
4260 if (mgcpsock < 0) {
4261 ast_log(LOG_WARNING, "Unable to create MGCP socket: %s\n", strerror(errno));
4262 } else {
4263 if (bind(mgcpsock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
4264 ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
4265 ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
4266 strerror(errno));
4267 close(mgcpsock);
4268 mgcpsock = -1;
4269 } else {
4270 if (option_verbose > 1) {
4271 ast_verbose(VERBOSE_PREFIX_2 "MGCP Listening on %s:%d\n",
4272 ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
4273 ast_verbose(VERBOSE_PREFIX_2 "Using TOS bits %d\n", tos);
4275 if (setsockopt(mgcpsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)))
4276 ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos);
4279 ast_mutex_unlock(&netlock);
4280 ast_config_destroy(cfg);
4282 /* send audit only to the new endpoints */
4283 g = gateways;
4284 while (g) {
4285 e = g->endpoints;
4286 while (e && e->needaudit) {
4287 e->needaudit = 0;
4288 transmit_audit_endpoint(e);
4289 ast_verbose(VERBOSE_PREFIX_3 "MGCP Auditing endpoint %s@%s for hookstate\n", e->name, g->name);
4290 e = e->next;
4292 g = g->next;
4295 return 0;
4298 /*! \brief load_module: PBX load module - initialization ---*/
4299 static int load_module(void)
4301 if (!(sched = sched_context_create())) {
4302 ast_log(LOG_WARNING, "Unable to create schedule context\n");
4303 return AST_MODULE_LOAD_FAILURE;
4306 if (!(io = io_context_create())) {
4307 ast_log(LOG_WARNING, "Unable to create I/O context\n");
4308 sched_context_destroy(sched);
4309 return AST_MODULE_LOAD_FAILURE;
4312 if (reload_config())
4313 return AST_MODULE_LOAD_DECLINE;
4315 /* Make sure we can register our mgcp channel type */
4316 if (ast_channel_register(&mgcp_tech)) {
4317 ast_log(LOG_ERROR, "Unable to register channel class 'MGCP'\n");
4318 io_context_destroy(io);
4319 sched_context_destroy(sched);
4320 return AST_MODULE_LOAD_FAILURE;
4323 ast_rtp_proto_register(&mgcp_rtp);
4324 ast_cli_register_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
4326 /* And start the monitor for the first time */
4327 restart_monitor();
4329 return AST_MODULE_LOAD_SUCCESS;
4332 /*! \brief mgcp_do_reload: Reload module */
4333 static int mgcp_do_reload(void)
4335 reload_config();
4336 return 0;
4339 static int mgcp_reload(int fd, int argc, char *argv[])
4341 static int deprecated = 0;
4342 if (!deprecated && argc > 0) {
4343 ast_log(LOG_WARNING, "'mgcp reload' is deprecated. Please use 'reload chan_mgcp.so' instead.\n");
4344 deprecated = 1;
4347 ast_mutex_lock(&mgcp_reload_lock);
4348 if (mgcp_reloading) {
4349 ast_verbose("Previous mgcp reload not yet done\n");
4350 } else
4351 mgcp_reloading = 1;
4352 ast_mutex_unlock(&mgcp_reload_lock);
4353 restart_monitor();
4354 return 0;
4357 static int reload(void)
4359 mgcp_reload(0, 0, NULL);
4360 return 0;
4363 static int unload_module(void)
4365 struct mgcp_endpoint *e;
4366 struct mgcp_gateway *g;
4368 /* Check to see if we're reloading */
4369 if (ast_mutex_trylock(&mgcp_reload_lock)) {
4370 ast_log(LOG_WARNING, "MGCP is currently reloading. Unable to remove module.\n");
4371 return -1;
4372 } else {
4373 mgcp_reloading = 1;
4374 ast_mutex_unlock(&mgcp_reload_lock);
4377 /* First, take us out of the channel loop */
4378 ast_channel_unregister(&mgcp_tech);
4380 /* Shut down the monitoring thread */
4381 if (!ast_mutex_lock(&monlock)) {
4382 if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
4383 pthread_cancel(monitor_thread);
4384 pthread_kill(monitor_thread, SIGURG);
4385 pthread_join(monitor_thread, NULL);
4387 monitor_thread = AST_PTHREADT_STOP;
4388 ast_mutex_unlock(&monlock);
4389 } else {
4390 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
4391 /* We always want to leave this in a consistent state */
4392 ast_channel_register(&mgcp_tech);
4393 mgcp_reloading = 0;
4394 mgcp_reload(0, 0, NULL);
4395 return -1;
4398 if (!ast_mutex_lock(&gatelock)) {
4399 for (g = gateways; g; g = g->next) {
4400 g->delme = 1;
4401 for (e = g->endpoints; e; e = e->next)
4402 e->delme = 1;
4405 prune_gateways();
4406 ast_mutex_unlock(&gatelock);
4407 } else {
4408 ast_log(LOG_WARNING, "Unable to lock the gateways list.\n");
4409 /* We always want to leave this in a consistent state */
4410 ast_channel_register(&mgcp_tech);
4411 /* Allow the monitor to restart */
4412 monitor_thread = AST_PTHREADT_NULL;
4413 mgcp_reloading = 0;
4414 mgcp_reload(0, 0, NULL);
4415 return -1;
4418 close(mgcpsock);
4419 ast_rtp_proto_unregister(&mgcp_rtp);
4420 ast_cli_unregister_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
4421 sched_context_destroy(sched);
4423 return 0;
4426 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Media Gateway Control Protocol (MGCP)",
4427 .load = load_module,
4428 .unload = unload_module,
4429 .reload = reload,