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.
21 * \brief Implementation of Media Gateway Control Protocol
23 * \author Mark Spencer <markster@digium.com>
26 * \arg \ref Config_mgcp
28 * \ingroup channel_drivers
31 <depend>res_features</depend>
36 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
41 #include <sys/socket.h>
42 #include <sys/ioctl.h>
48 #include <sys/signal.h>
50 #include <netinet/in.h>
51 #include <netinet/in_systm.h>
52 #include <netinet/ip.h>
53 #include <arpa/inet.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"
84 #define IPTOS_MINCOST 0x02
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 */
94 #define DEFAULT_EXPIRY 120
95 #define MAX_EXPIRY 3600
99 #define INADDR_NONE (in_addr_t)(-1)
102 /*! Global jitterbuffer configuration - by default, jb is disabled */
103 static struct ast_jb_conf default_jbconf
=
107 .resync_threshold
= -1,
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
135 static char *mgcp_cxmodes
[] = {
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;
165 static ast_group_t cur_callergroup
= 0;
166 static ast_group_t cur_pickupgroup
= 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;
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
;
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
{
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
;
258 unsigned long expire
;
261 struct mgcp_message
*next
;
265 #define RESPONSE_TIMEOUT 30 /*!< in seconds */
267 struct mgcp_response
{
271 struct mgcp_response
*next
;
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!"
290 struct ast_channel
*owner
;
291 struct mgcp_endpoint
*parent
;
293 struct sockaddr_in tmpdest
;
294 char txident
[80]; /*! \todo FIXME txident is replaced by rqnt_ident in endpoint.
295 This should be obsoleted */
299 struct mgcp_request
*cx_queue
; /*!< pending CX commands */
300 ast_mutex_t cx_queue_lock
; /*!< CX queue lock */
302 int iseq
; /*!< Not used? RTP? */
305 struct mgcp_subchannel
*next
; /*!< for out circular linked list */
308 #define MGCP_ONHOOK 1
309 #define MGCP_OFFHOOK 2
314 struct mgcp_endpoint
{
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
;
340 int dnd
; /* How does this affect callwait? Do we just deny a mgcp_request if we're dnd? */
346 int slowsequence
; /*!< MS: Sequence the endpoint as a whole */
348 int iseq
; /*!< Not used? */
349 int lastout
; /*!< tracking this on the subchannels. Is it needed here? */
350 int needdestroy
; /*!< Not used? */
352 int nonCodecCapability
;
354 int msgstate
; /*!< voicemail message state */
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 */
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
;
383 int expire
; /*!< XXX Should we ever expire dynamic registrations? XXX */
384 struct mgcp_endpoint
*endpoints
;
391 /* Wildcard endpoint name */
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
;
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
= {
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
,
447 .hangup
= mgcp_hangup
,
448 .answer
= mgcp_answer
,
451 .indicate
= mgcp_indicate
,
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
;
467 ast_log(LOG_WARNING
, "Trying to unalloc the real channel %s@%s?!?\n", p
->name
, p
->parent
->name
);
470 ast_log(LOG_DEBUG
, "Released sub %d of channel %s@%s\n", sub
->id
, p
->name
, p
->parent
->name
);
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
;
480 sub
->alreadygone
= 0;
481 memset(&sub
->tmpdest
, 0, sizeof(sub
->tmpdest
));
483 ast_rtp_destroy(sub
->rtp
);
486 dump_cmd_queues(NULL
, sub
); /* SC */
490 /* modified for new transport mechanism */
491 static int __mgcp_xmit(struct mgcp_gateway
*gw
, char *data
, int len
)
494 if (gw
->addr
.sin_addr
.s_addr
)
495 res
=sendto(mgcpsock
, data
, len
, 0, (struct sockaddr
*)&gw
->addr
, sizeof(struct sockaddr_in
));
497 res
=sendto(mgcpsock
, data
, len
, 0, (struct sockaddr
*)&gw
->defaddr
, sizeof(struct sockaddr_in
));
499 ast_log(LOG_WARNING
, "mgcp_xmit returned %d: %s\n", res
, strerror(errno
));
504 static int resend_response(struct mgcp_subchannel
*sub
, struct mgcp_response
*resp
)
506 struct mgcp_endpoint
*p
= sub
->parent
;
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
);
517 static int send_response(struct mgcp_subchannel
*sub
, struct mgcp_request
*req
)
519 struct mgcp_endpoint
*p
= sub
->parent
;
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
);
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
;
538 if (!p
|| cur
->owner_ep
== p
) {
540 prev
->next
= cur
->next
;
542 gw
->msgs
= cur
->next
;
544 ast_log(LOG_NOTICE
, "Removing message from %s transaction %u\n",
545 gw
->name
, cur
->seqno
);
556 prev
= cur
, cur
=cur
->next
;
559 ast_mutex_unlock(&gw
->msgs_lock
);
568 static void mgcp_queue_frame(struct mgcp_subchannel
*sub
, struct ast_frame
*f
)
572 if (!ast_mutex_trylock(&sub
->owner
->lock
)) {
573 ast_queue_frame(sub
->owner
, f
);
574 ast_mutex_unlock(&sub
->owner
->lock
);
577 ast_mutex_unlock(&sub
->lock
);
579 ast_mutex_lock(&sub
->lock
);
586 static void mgcp_queue_hangup(struct mgcp_subchannel
*sub
)
590 if (!ast_mutex_trylock(&sub
->owner
->lock
)) {
591 ast_queue_hangup(sub
->owner
);
592 ast_mutex_unlock(&sub
->owner
->lock
);
595 ast_mutex_unlock(&sub
->lock
);
597 ast_mutex_lock(&sub
->lock
);
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
;
617 /* find out expired msgs */
618 ast_mutex_lock(&gw
->msgs_lock
);
620 prev
= NULL
, cur
= gw
->msgs
;
622 if (cur
->retrans
< MAX_RETRANS
) {
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
);
634 prev
->next
= cur
->next
;
636 gw
->msgs
= cur
->next
;
638 ast_log(LOG_WARNING
, "Maximum retries exceeded for transaction %u on [%s]\n",
639 cur
->seqno
, gw
->name
);
659 ast_mutex_unlock(&gw
->msgs_lock
);
663 /* time-out transaction */
664 handle_response(cur
->owner_ep
, cur
->owner_sub
, 406, cur
->seqno
, NULL
);
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
);
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
;
701 memcpy(msg
->buf
, data
, msg
->len
);
703 ast_mutex_lock(&gw
->msgs_lock
);
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");
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
);
724 if (!gw->messagepending) {
725 gw->messagepending = 1;
729 __mgcp_xmit(gw
, msg
->buf
, msg
->len
);
730 /* XXX Should schedule retransmission XXX */
733 ast_log(LOG_DEBUG, "Deferring transmission of transaction %d\n", seqno);
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
)
743 struct mgcp_request
**queue
, *q
, *r
, *t
;
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
;
754 queue
= &sub
->cx_queue
;
755 l
= &sub
->cx_queue_lock
;
758 /* delete pending cx cmds */
769 queue
= &sub
->cx_queue
;
770 l
= &sub
->cx_queue_lock
;
775 queue
= &p
->rqnt_queue
;
776 l
= &p
->rqnt_queue_lock
;
781 queue
= &p
->cmd_queue
;
782 l
= &p
->cmd_queue_lock
;
788 r
= (struct mgcp_request
*) malloc (sizeof(struct mgcp_request
));
790 ast_log(LOG_WARNING
, "Cannot post MGCP request: insufficient memory\n");
794 memcpy(r
, req
, sizeof(struct mgcp_request
));
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
);
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
);
824 static int mgcp_call(struct ast_channel
*ast
, char *dest
, int timeout
)
827 struct mgcp_endpoint
*p
;
828 struct mgcp_subchannel
*sub
;
830 const char *distinctive_ring
= NULL
;
831 struct varshead
*headp
;
832 struct ast_var_t
*current
;
835 ast_verbose(VERBOSE_PREFIX_3
"MGCP mgcp_call(%s)\n", ast
->name
);
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
) {
850 if (!ast_strlen_zero(distinctive_ring
)) {
851 snprintf(tone
, sizeof(tone
), "L/wt%s", distinctive_ring
);
853 ast_verbose(VERBOSE_PREFIX_3
"MGCP distinctive callwait %s\n", tone
);
856 snprintf(tone
, sizeof(tone
), "L/wt");
858 ast_verbose(VERBOSE_PREFIX_3
"MGCP normal callwait %s\n", tone
);
864 if (!ast_strlen_zero(distinctive_ring
)) {
865 snprintf(tone
, sizeof(tone
), "L/r%s", distinctive_ring
);
867 ast_verbose(VERBOSE_PREFIX_3
"MGCP distinctive ring %s\n", tone
);
870 snprintf(tone
, sizeof(tone
), "L/rg");
872 ast_verbose(VERBOSE_PREFIX_3
"MGCP default ring\n");
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
);
886 sub
->cxmode
= MGCP_CX_RECVONLY
;
887 if (p
->type
== TYPE_LINE
) {
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
);
909 ast_log(LOG_NOTICE
, "Don't know how to dial on trunks yet\n");
912 ast_mutex_unlock(&sub
->lock
);
913 ast_queue_control(ast
, AST_CONTROL_RINGING
);
917 static int mgcp_hangup(struct ast_channel
*ast
)
919 struct mgcp_subchannel
*sub
= ast
->tech_pvt
;
920 struct mgcp_endpoint
*p
= sub
->parent
;
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");
929 if (strcmp(sub
->magic
, MGCP_SUBCHANNEL_MAGIC
)) {
930 ast_log(LOG_DEBUG
, "Invalid magic. MGCP subchannel freed up already.\n");
933 ast_mutex_lock(&sub
->lock
);
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
;
944 ast_verbose(VERBOSE_PREFIX_2
"MGCP free dsp on %s@%s\n", p
->name
, p
->parent
->name
);
946 ast_dsp_free(p
->dsp
);
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
);
962 /* set our other connection as the primary and swith over to it */
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");
976 transmit_notify_request(sub
, "");
979 ast
->tech_pvt
= NULL
;
980 sub
->alreadygone
= 0;
982 sub
->cxmode
= MGCP_CX_INACTIVE
;
983 sub
->callid
[0] = '\0';
985 memset(p
->dtmf_buf
, 0, sizeof(p
->dtmf_buf
));
987 /* Reset temporary destination */
988 memset(&sub
->tmpdest
, 0, sizeof(sub
->tmpdest
));
990 ast_rtp_destroy(sub
->rtp
);
994 ast_module_unref(ast_module_info
->self
);
996 if ((p
->hookstate
== MGCP_ONHOOK
) && (!sub
->next
->rtp
)) {
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
)) {
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(+)");
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
);
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;
1028 return RESULT_SHOWUSAGE
;
1029 ast_mutex_lock(&gatelock
);
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");
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");
1041 if (!hasendpoints
) {
1042 ast_cli(fd
, " << No Endpoints Defined >> ");
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
;
1077 char *ename
,*gname
, *c
;
1080 return RESULT_SHOWUSAGE
;
1083 return RESULT_SHOWUSAGE
;
1084 /* split the name into parts by null */
1088 if (*gname
== '@') {
1095 if (gname
[0] == '[')
1097 if ((c
= strrchr(gname
, ']')))
1099 ast_mutex_lock(&gatelock
);
1102 if (!strcasecmp(g
->name
, gname
)) {
1105 if (!strcasecmp(e
->name
, ename
)) {
1107 transmit_audit_endpoint(e
);
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
[])
1128 return RESULT_SHOWUSAGE
;
1130 ast_cli(fd
, "MGCP Debugging Enabled\n");
1131 return RESULT_SUCCESS
;
1134 static int mgcp_no_debug(int fd
, int argc
, char *argv
[])
1137 return RESULT_SHOWUSAGE
;
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",
1156 { { "mgcp", "set", "debug", "off", NULL
},
1157 mgcp_no_debug
, "Disable MGCP debugging",
1160 { { "mgcp", "reload", NULL
},
1161 mgcp_reload
, "Reload MGCP configuration",
1162 mgcp_reload_usage
},
1165 static int mgcp_answer(struct ast_channel
*ast
)
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
;
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
);
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
);
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
;
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
)) {
1215 ast_log(LOG_NOTICE
, "MGCP ast_dsp_process\n");
1217 f
= ast_dsp_process(sub
->owner
, sub
->parent
->dsp
, 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
);
1235 static int mgcp_write(struct ast_channel
*ast
, struct ast_frame
*frame
)
1237 struct mgcp_subchannel
*sub
= ast
->tech_pvt
;
1239 if (frame
->frametype
!= AST_FRAME_VOICE
) {
1240 if (frame
->frametype
== AST_FRAME_IMAGE
)
1243 ast_log(LOG_WARNING
, "Can't send %d type frames with MGCP write\n", frame
->frametype
);
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
);
1254 ast_mutex_lock(&sub
->lock
);
1255 if ((sub
->parent
->sub
== sub
) || !sub
->parent
->singlepath
) {
1257 res
= ast_rtp_write(sub
->rtp
, frame
);
1260 ast_mutex_unlock(&sub
->lock
);
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
);
1276 sub
->owner
= newchan
;
1277 ast_mutex_unlock(&sub
->lock
);
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
;
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
);
1295 ast_log(LOG_ERROR
, "Don't know about DTMF_MODE %d\n", p
->dtmfmode
);
1297 ast_mutex_unlock(&sub
->lock
);
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
;
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");
1319 transmit_notify_request(sub
, tmp
);
1320 ast_rtp_senddigit_end(sub
->rtp
, digit
);
1322 ast_log(LOG_ERROR
, "Don't know about DTMF_MODE %d\n", p
->dtmfmode
);
1324 ast_mutex_unlock(&sub
->lock
);
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
, '@'))) {
1352 ast_mutex_lock(&gatelock
);
1355 if (strcasecmp(g
->name
, gw
) == 0) {
1366 if (strcasecmp(e
->name
, endpt
) == 0)
1375 * As long as the gateway/endpoint is valid, we'll
1376 * assume that the device is available and its state
1379 ret
= AST_DEVICE_UNKNOWN
;
1382 ast_mutex_unlock(&gatelock
);
1386 static char *control2str(int 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
:
1408 case AST_CONTROL_OPTION
:
1409 return "Set a low-level option";
1410 case AST_CONTROL_RADIO_KEY
:
1412 case AST_CONTROL_RADIO_UNKEY
:
1413 return "Un-Key Radio";
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
;
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
);
1429 case AST_CONTROL_RINGING
:
1430 #ifdef DLINK_BUGGY_FIRMWARE
1431 transmit_notify_request(sub
, "rt");
1433 transmit_notify_request(sub
, "G/rt");
1436 case AST_CONTROL_BUSY
:
1437 transmit_notify_request(sub
, "L/bz");
1439 case AST_CONTROL_CONGESTION
:
1440 transmit_notify_request(sub
, "G/cg");
1442 case AST_CONTROL_HOLD
:
1443 ast_moh_start(ast
, data
, NULL
);
1445 case AST_CONTROL_UNHOLD
:
1448 case AST_CONTROL_SRCUPDATE
:
1449 ast_rtp_new_source(sub
->rtp
);
1452 transmit_notify_request(sub
, "");
1455 ast_log(LOG_WARNING
, "Don't know how to indicate condition %d\n", ind
);
1458 ast_mutex_unlock(&sub
->lock
);
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
;
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
);
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
);
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
);
1486 if (state
== AST_STATE_RING
)
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
);
1498 tmp
->amaflags
= i
->amaflags
;
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
);
1512 tmp
->adsicpe
= AST_ADSI_UNAVAILABLE
;
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
);
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
));
1529 ast_log(LOG_WARNING
, "Unable to allocate channel structure\n");
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
;
1544 static char *get_sdp(struct mgcp_request
*req
, char *name
)
1547 int len
= strlen(name
);
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
;
1557 static void sdpLineNum_iterator_init(int* iterator
)
1562 static char* get_sdp_iterate(int* iterator
, struct mgcp_request
*req
, char *name
)
1564 int len
= strlen(name
);
1566 while (*iterator
< req
->lines
) {
1567 r
= get_sdp_by_line(req
->line
[(*iterator
)++], name
, len
);
1568 if (r
[0] != '\0') return r
;
1573 static char *__get_header(struct mgcp_request
*req
, char *name
, int *start
)
1576 int len
= strlen(name
);
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))
1588 /* Don't return NULL, so get_header is always a valid pointer */
1592 static char *get_header(struct mgcp_request
*req
, char *name
)
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
)
1603 *next
= NULL
, *len
= 0;
1604 if (!c
) return NULL
;
1606 while (*c
&& (*c
< 33 || *c
== ','))
1610 while (*c
&& (*c
>= 33 && *c
!= ','))
1615 s
= NULL
, *next
= NULL
;
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
;
1626 char *at
= NULL
, *c
;
1629 ast_copy_string(tmp
, name
, sizeof(tmp
));
1630 at
= strchr(tmp
, '@');
1632 ast_log(LOG_NOTICE
, "Endpoint '%s' has no at sign!\n", name
);
1637 ast_mutex_lock(&gatelock
);
1638 if (at
&& (at
[0] == '[')) {
1640 c
= strrchr(at
, ']');
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 */
1661 if (strcasecmp(g
->name
, at
)) {
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
)) {
1681 ast_log(LOG_DEBUG
, "Searching on %s@%s for subchannel\n",
1684 #if 0 /* new transport mech */
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
) {
1692 ast_log(LOG_DEBUG
, "Found subchannel sub%d to handle request %d sub->lastout: %d\n",
1693 sub
->id
, msgid
, sub
->lastout
);
1698 } while (sub
!= p
->sub
);
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
);
1718 ast_mutex_lock(&sub
->lock
);
1724 ast_mutex_unlock(&gatelock
);
1728 ast_log(LOG_NOTICE
, "Endpoint '%s' not found on gateway '%s'\n", tmp
, at
);
1730 ast_log(LOG_NOTICE
, "Gateway '%s' (and thus its endpoint '%s') does not exist\n", at
, tmp
);
1736 static void parse(struct mgcp_request
*req
)
1738 /* Divide fields by NULL's */
1743 /* First header starts immediately */
1747 /* We've got a new header */
1750 printf("Header: %s (%d)\n", req
->header
[f
], strlen(req
->header
[f
]));
1752 if (ast_strlen_zero(req
->header
[f
])) {
1753 /* Line by itself means we're now in content */
1757 if (f
>= MGCP_MAX_HEADERS
- 1) {
1758 ast_log(LOG_WARNING
, "Too many MGCP headers...\n");
1761 req
->header
[f
] = c
+ 1;
1762 } else if (*c
== '\r') {
1763 /* Ignore but eliminate \r's */
1768 /* Check for last header */
1769 if (!ast_strlen_zero(req
->header
[f
]))
1772 /* Now we process any mime content */
1777 /* We've got a new line */
1780 printf("Line: %s (%d)\n", req
->line
[f
], strlen(req
->line
[f
]));
1782 if (f
>= MGCP_MAX_LINES
- 1) {
1783 ast_log(LOG_WARNING
, "Too many SDP lines...\n");
1786 req
->line
[f
] = c
+ 1;
1787 } else if (*c
== '\r') {
1788 /* Ignore and eliminate \r's */
1793 /* Check for last line */
1794 if (!ast_strlen_zero(req
->line
[f
]))
1797 /* Parse up the initial header */
1799 while(*c
&& *c
< 33) c
++;
1800 /* First the verb */
1802 while(*c
&& (*c
> 32)) c
++;
1806 while(*c
&& (*c
< 33)) c
++;
1807 req
->identifier
= c
;
1808 while(*c
&& (*c
> 32)) c
++;
1812 while(*c
&& (*c
< 33)) c
++;
1814 while(*c
&& (*c
> 32)) c
++;
1818 while(*c
&& (*c
< 33)) c
++;
1820 while(*c
&& (*c
> 32)) c
++;
1821 while(*c
&& (*c
< 33)) c
++;
1822 while(*c
&& (*c
> 32)) c
++;
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
);
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
)
1845 int peercapability
, peerNonCodecCapability
;
1846 struct sockaddr_in sin
;
1848 struct ast_hostent ahp
; struct hostent
*hp
;
1849 int codec
, codec_count
=0;
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
);
1860 if (sscanf(c
, "IN IP4 %256s", host
) != 1) {
1861 ast_log(LOG_WARNING
, "Invalid host in c= line, '%s'\n", c
);
1864 /* XXX This could block for a long time, and block the main thread! XXX */
1865 hp
= ast_gethostbyname(host
, &ahp
);
1867 ast_log(LOG_WARNING
, "Unable to lookup host in c= line, '%s'\n", c
);
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
);
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
);
1879 printf("Peer RTP is at port %s:%d\n", ast_inet_ntoa(sin
.sin_addr
), ntohs(sin
.sin_port
));
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) {
1888 ast_log(LOG_WARNING
, "Error in codec string '%s' at '%s'\n", m
, codecs
);
1891 ast_rtp_set_m_type(sub
->rtp
, codec
);
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)
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
;
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");
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");
1930 ast_log(LOG_WARNING
, "Can't add more headers when lines have been added\n");
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
)
1939 ast_log(LOG_WARNING
, "Out of header space\n");
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");
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
)
1962 ast_log(LOG_WARNING
, "Out of line space\n");
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");
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
)
1981 ast_log(LOG_WARNING
, "Out of header space\n");
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");
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
);
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
)
2002 ast_log(LOG_WARNING
, "Out of header space\n");
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
);
2014 static int reqprep(struct mgcp_request
*req
, struct mgcp_endpoint
*p
, char *verb
)
2016 memset(req
, 0, sizeof(struct mgcp_request
));
2018 if (oseq
> 999999999)
2020 init_req(p
, req
, verb
);
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);
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
)
2052 struct sockaddr_in sin
;
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 */
2067 ast_log(LOG_WARNING
, "No way to add SDP without an RTP structure\n");
2070 ast_rtp_get_us(sub
->rtp
, &sin
);
2072 ast_rtp_get_peer(rtp
, &dest
);
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
));
2080 dest
.sin_addr
= p
->parent
->ourip
;
2081 dest
.sin_port
= sin
.sin_port
;
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
) {
2096 ast_verbose("Answering with capability %d\n", x
);
2098 codec
= ast_rtp_lookup_code(sub
->rtp
, 1, x
);
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
) {
2110 ast_verbose("Answering with non-codec capability %d\n", x
);
2112 codec
= ast_rtp_lookup_code(sub
->rtp
, 0, x
);
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
);
2140 static int transmit_modify_with_sdp(struct mgcp_subchannel
*sub
, struct ast_rtp
*rtp
, int codecs
)
2142 struct mgcp_request resp
;
2147 struct mgcp_endpoint
*p
= sub
->parent
;
2149 capability
= p
->capability
;
2151 capability
= codecs
;
2152 if (ast_strlen_zero(sub
->cxident
) && rtp
) {
2153 /* We don't have a CXident yet, store the destination and
2155 ast_rtp_get_peer(rtp
, &sub
->tmpdest
);
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
;
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
;
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);
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
;
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
;
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
) {
2227 add_header(&resp
, "R", "L/hd(N)");
2230 add_header_offhook(sub
, &resp
);
2233 if (!ast_strlen_zero(tone
)) {
2234 add_header(&resp
, "S", tone
);
2236 /* fill in new fields */
2237 resp
.cmd
= MGCP_CMD_RQNT
;
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
;
2249 struct mgcp_endpoint
*p
= sub
->parent
;
2252 ast_localtime(&t
, &tm
, NULL
);
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
) {
2270 add_header(&resp
, "R", "L/hd(N)");
2273 add_header_offhook(sub
, &resp
);
2276 if (!ast_strlen_zero(tone2
)) {
2277 add_header(&resp
, "S", tone2
);
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
;
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
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
) {
2311 add_header(&resp
, "R", "L/hd(N)");
2314 add_header_offhook(sub
, &resp
);
2317 /* fill in new fields */
2318 resp
.cmd
= MGCP_CMD_MDCX
;
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)");
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
;
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
;
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 */
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
;
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
;
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
;
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
;
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
);
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
;
2433 for (prev
= NULL
, req
= *queue
; req
; prev
= req
, req
= req
->next
) {
2434 if (req
->trid
== ident
) {
2435 /* remove from queue */
2439 prev
->next
= req
->next
;
2441 /* send next pending command */
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
);
2453 ast_mutex_unlock(l
);
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
)
2462 struct mgcp_request
*req
;
2463 struct mgcp_gateway
*gw
= p
->parent
;
2466 /* provisional response */
2470 if (p
->slowsequence
)
2471 req
= find_command(p
, sub
, &p
->cmd_queue
, &p
->cmd_queue_lock
, ident
);
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
);
2478 if (option_verbose
> 2) {
2479 ast_verbose(VERBOSE_PREFIX_3
"No command found on [%s] for transaction %d. Ignoring...\n",
2485 if (p
&& (result
>= 400) && (result
<= 599)) {
2488 p
->hookstate
= MGCP_OFFHOOK
;
2491 p
->hookstate
= MGCP_ONHOOK
;
2494 ast_log(LOG_NOTICE
, "Transaction %d timed out\n", ident
);
2497 ast_log(LOG_NOTICE
, "Transaction %d aborted\n", ident
);
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
);
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
);
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. */
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);
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"))) {
2554 while ((v
= get_csv(c
, &len
, &n
))) {
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
);
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
) {
2617 process_sdp(sub
, resp
);
2625 static void start_rtp(struct mgcp_subchannel
*sub
)
2627 ast_mutex_lock(&sub
->lock
);
2628 /* check again to be on the safe side */
2630 ast_rtp_destroy(sub
->rtp
);
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
);
2638 ast_rtp_setnat(sub
->rtp
, sub
->nat
);
2640 ast_rtp_set_callback(p
->rtp
, rtpready
);
2641 ast_rtp_set_data(p
->rtp
, p
);
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] = ""; */
2657 int timeout
= firstdigittimeout
;
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
;
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);
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
)) {
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");
2701 /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
2702 ast_indicate(chan
, -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");
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
);
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");
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);*/
2744 memset(p
->dtmf_buf
, 0, sizeof(p
->dtmf_buf
));
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 */
2752 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
2753 transmit_notify_request(sub
, "L/sl");
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
));
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");
2780 memset(p
->dtmf_buf
, 0, sizeof(p
->dtmf_buf
));
2781 timeout
= firstdigittimeout
;
2782 } else if (p
->callreturn
&& !strcmp(p
->dtmf_buf
, "*69")) {
2784 if (!ast_strlen_zero(p
->lastcallerid
)) {
2785 res
= ast_say_digit_str(chan
, p
->lastcallerid
, "", chan
->language
);
2788 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/
2789 transmit_notify_request(sub
, "L/sl");
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");
2800 memset(p
->dtmf_buf
, 0, sizeof(p
->dtmf_buf
));
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");
2811 memset(p
->dtmf_buf
, 0, sizeof(p
->dtmf_buf
));
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");
2817 memset(p
->dtmf_buf
, 0, sizeof(p
->dtmf_buf
));
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
));
2827 memset(p
->dtmf_buf
, 0, sizeof(p
->dtmf_buf
));
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
);
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");
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
));
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");
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))) {
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
);
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);
2875 res
= ast_waitfordigit(chan
, to
);
2877 ast_log(LOG_DEBUG
, "Timeout...\n");
2881 ast_log(LOG_DEBUG
, "Got hangup...\n");
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
))
2896 if (ast_exists_extension(chan
, chan
->context
, exten
, 1, chan
->callerid
)) {
2897 ast_copy_string(chan
->exten
, exten
, sizeof(chan
->exten
)1);
2901 ast_setstate(chan
, AST_STATE_RING
);
2903 if (ast_pbx_run(chan
)) {
2904 ast_log(LOG_WARNING
, "Unable to launch PBX on %s\n", chan
->name
);
2906 memset(p
->dtmf_buf
, 0, sizeof(p
->dtmf_buf
));
2912 memset(p
->dtmf_buf
, 0, sizeof(p
->dtmf_buf
));
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
);
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
);
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 */
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
);
2972 static void handle_hd_hf(struct mgcp_subchannel
*sub
, char *ev
)
2974 struct mgcp_endpoint
*p
= sub
->parent
;
2975 struct ast_channel
*c
;
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
) {
2985 if (ast_bridged_channel(sub
->owner
))
2986 ast_queue_control(sub
->owner
, AST_CONTROL_UNHOLD
);
2987 sub
->cxmode
= MGCP_CX_SENDRECV
;
2991 transmit_modify_request(sub
);
2993 /*transmit_notify_request(sub, "aw");*/
2994 transmit_notify_request(sub
, "");
2995 mgcp_queue_control(sub
, AST_CONTROL_ANSWER
);
2999 /*sub->cxmode = MGCP_CX_SENDRECV;*/
3004 transmit_modify_request(sub
);
3007 /* The channel is immediately up. Start right away */
3008 #ifdef DLINK_BUGGY_FIRMWARE
3009 transmit_notify_request(sub
, "rt");
3011 transmit_notify_request(sub
, "G/rt");
3013 c
= mgcp_new(sub
, AST_STATE_RING
);
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");
3020 if (has_voicemail(p
)) {
3021 transmit_notify_request(sub
, "L/sl");
3023 transmit_notify_request(sub
, "L/dl");
3025 c
= mgcp_new(sub
, AST_STATE_DOWN
);
3027 if (ast_pthread_create(&t
, &attr
, mgcp_ss
, c
)) {
3028 ast_log(LOG_WARNING
, "Unable to create switch thread: %s\n", strerror(errno
));
3032 ast_log(LOG_WARNING
, "Unable to create channel for %s@%s\n", p
->name
, p
->parent
->name
);
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
);
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
;
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
)
3061 struct ast_frame f
= { 0, };
3062 struct mgcp_endpoint
*p
= sub
->parent
;
3063 struct mgcp_gateway
*g
= NULL
;
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");
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
;
3089 tmp_ep
= g
->endpoints
;
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
;
3101 mgcp_queue_hangup(tmp_sub
);
3102 tmp_sub
= tmp_sub
->next
;
3103 if (tmp_sub
== first_sub
)
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
, "");
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
, '/');
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 */
3147 /* do not let * conference two down channels */
3148 if (sub
->owner
&& sub
->owner
->_state
== AST_STATE_DOWN
&& !sub
->next
->owner
)
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
);
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
);
3205 /* We've most likely lost one of our calls find an active call and bring it up */
3208 } else if (sub
->next
->owner
) {
3211 /* We seem to have lost both our calls */
3212 /* XXX - What do we do now? */
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
);
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 ?
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
);
3239 if (p
->sub
->next
->owner
) {
3240 sub
->next
->alreadygone
= 1;
3241 mgcp_queue_hangup(sub
->next
);
3244 ast_log(LOG_WARNING
, "Transfer attempt failed\n");
3245 ast_mutex_unlock(&p
->sub
->next
->lock
);
3248 ast_mutex_unlock(&p
->sub
->next
->lock
);
3250 /* Hangup the current call */
3251 /* If there is another active call, mgcp_hangup will ring the phone with the other call */
3253 sub
->alreadygone
= 1;
3254 mgcp_queue_hangup(sub
);
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(+)");
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
;
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
));
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 */
3312 ast_log(LOG_NOTICE
, "Received unknown event '%s' from %s@%s\n", ev
, p
->name
, p
->parent
->name
);
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");
3321 static int find_and_retrans(struct mgcp_subchannel
*sub
, struct mgcp_request
*req
)
3325 struct mgcp_response
*prev
= NULL
, *cur
, *next
, *answer
=NULL
;
3327 if (sscanf(req
->identifier
, "%d", &seqno
) != 1)
3329 cur
= sub
->parent
->parent
->responses
;
3332 if (now
- cur
->whensent
> RESPONSE_TIMEOUT
) {
3333 /* Delete this entry */
3337 sub
->parent
->parent
->responses
= next
;
3340 if (seqno
== cur
->seqno
)
3347 resend_response(sub
, answer
);
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
;
3363 memset(&req
, 0, sizeof(req
));
3364 res
= recvfrom(mgcpsock
, req
.data
, sizeof(req
.data
) - 1, 0, (struct sockaddr
*)&sin
, &len
);
3366 if (errno
!= ECONNREFUSED
)
3367 ast_log(LOG_WARNING
, "Recv error: %s\n", strerror(errno
));
3370 req
.data
[res
] = '\0';
3373 ast_verbose("MGCP read: \n%s\nfrom %s:%d\n", req
.data
, ast_inet_ntoa(sin
.sin_addr
), ntohs(sin
.sin_port
));
3376 if (req
.headers
< 1) {
3377 /* Must have at least one header */
3380 if (ast_strlen_zero(req
.identifier
)) {
3381 ast_log(LOG_NOTICE
, "Message from %s missing identifier\n", ast_inet_ntoa(sin
.sin_addr
));
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
);
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
);
3398 prev
->next
= cur
->next
;
3400 gw
->msgs
= cur
->next
;
3405 /* stop retrans timer if the queue is empty */
3407 AST_SCHED_DEL(sched
, gw
->retransid
);
3410 ast_mutex_unlock(&gw
->msgs_lock
);
3412 handle_response(cur
->owner_ep
, cur
->owner_sub
, result
, ident
, &req
);
3417 ast_log(LOG_NOTICE
, "Got response back on [%s] for transaction %d we aren't sending?\n",
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");
3427 /* Process request, with iflock held */
3428 sub
= find_subchannel_and_lock(req
.endpoint
, 0, &sin
);
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
);
3440 static int *mgcpsock_read_id
= NULL
;
3442 static void *do_monitor(void *data
)
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 */
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 */
3458 /* Check for a reload request */
3459 ast_mutex_lock(&mgcp_reload_lock
);
3460 reloading
= mgcp_reloading
;
3462 ast_mutex_unlock(&mgcp_reload_lock
);
3464 if (option_verbose
> 0)
3465 ast_verbose(VERBOSE_PREFIX_1
"Reloading MGCP\n");
3467 /* Add an I/O event to our UDP socket */
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
);
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
);
3487 if (thispass
!= lastpass
) {
3490 if (e
->type
== TYPE_LINE
) {
3491 res
= has_voicemail(e
);
3492 if ((e
->msgstate
!= res
) && (e
->hookstate
== MGCP_ONHOOK
) && (!e
->rtp
)){
3494 transmit_notify_request(e
, "L/vmwi(+)");
3496 transmit_notify_request(e
, "L/vmwi(-)");
3499 e
->onhooktime
= thispass
;
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))
3518 res
= ast_io_wait(io
, res
);
3519 ast_mutex_lock(&monlock
);
3521 ast_sched_runq(sched
);
3522 ast_mutex_unlock(&monlock
);
3528 static int restart_monitor(void)
3530 /* If we're supposed to be stopped -- stay stopped */
3531 if (monitor_thread
== AST_PTHREADT_STOP
)
3533 if (ast_mutex_lock(&monlock
)) {
3534 ast_log(LOG_WARNING
, "Unable to lock monitor\n");
3537 if (monitor_thread
== pthread_self()) {
3538 ast_mutex_unlock(&monlock
);
3539 ast_log(LOG_WARNING
, "Cannot kill myself\n");
3542 if (monitor_thread
!= AST_PTHREADT_NULL
) {
3543 /* Wake up the thread */
3544 pthread_kill(monitor_thread
, SIGURG
);
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");
3553 ast_mutex_unlock(&monlock
);
3557 static struct ast_channel
*mgcp_request(const char *type
, int format
, void *data
, int *cause
)
3560 struct mgcp_subchannel
*sub
;
3561 struct ast_channel
*tmpc
= NULL
;
3566 format
&= capability
;
3568 ast_log(LOG_NOTICE
, "Asked to get a channel of unsupported format '%d'\n", format
);
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");
3576 sub
= find_subchannel_and_lock(tmp
, 0, NULL
);
3578 ast_log(LOG_WARNING
, "Unable to find MGCP endpoint '%s'\n", tmp
);
3579 *cause
= AST_CAUSE_UNREGISTERED
;
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);
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(+)");
3596 transmit_notify_request(sub
,"L/vmwi(-)");
3599 *cause
= AST_CAUSE_BUSY
;
3600 ast_mutex_unlock(&sub
->lock
);
3603 tmpc
= mgcp_new(sub
->owner
? sub
->next
: sub
, AST_STATE_DOWN
);
3604 ast_mutex_unlock(&sub
->lock
);
3606 ast_log(LOG_WARNING
, "Unable to make channel for '%s'\n", tmp
);
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];*/
3622 canreinvite
= CANREINVITE
;
3624 /* locate existing gateway */
3627 if (!strcasecmp(cat
, gw
->name
)) {
3628 /* gateway already exists */
3637 gw
= malloc(sizeof(struct mgcp_gateway
));
3641 memset(gw
, 0, sizeof(struct mgcp_gateway
));
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;
3651 if (!strcasecmp(v
->name
, "host")) {
3652 if (!strcasecmp(v
->value
, "dynamic")) {
3653 /* They'll register with us */
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;
3662 /* Non-dynamic. Make sure we become that way if we're not */
3663 AST_SCHED_DEL(sched
, gw
->expire
);
3665 if (ast_get_ip(&gw
->addr
, v
->value
)) {
3667 ast_mutex_destroy(&gw
->msgs_lock
);
3673 } else if (!strcasecmp(v
->name
, "defaultip")) {
3674 if (ast_get_ip(&gw
->defaddr
, v
->value
)) {
3676 ast_mutex_destroy(&gw
->msgs_lock
);
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"))
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")) {
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
);
3715 ast_log(LOG_WARNING
, "Invalid AMA flags: %s at line %d\n", v
->value
, v
->lineno
);
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 */
3751 if (!strcasecmp(v
->value
, e
->name
)) {
3752 /* endpoint already exists */
3761 /* Allocate wildcard endpoint */
3762 e
= malloc(sizeof(struct mgcp_endpoint
));
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
));
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());
3786 e
->amaflags
= amaflags
;
3787 e
->capability
= capability
;
3789 e
->dtmfmode
= dtmfmode
;
3790 if (!ep_reload
&& e
->sub
&& e
->sub
->rtp
)
3791 e
->dtmfmode
|= MGCP_DTMF_INBAND
;
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
;
3810 /*snprintf(txident, sizeof(txident), "%08lx", ast_random());*/
3811 for (i
= 0; i
< MAX_SUBS
; i
++) {
3812 sub
= malloc(sizeof(struct mgcp_subchannel
));
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
);
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
;
3827 /* XXX Should find a way to clean up our memory */
3828 ast_log(LOG_WARNING
, "Out of memory allocating subchannel\n");
3832 /* Make out subs a circular linked list so we can always sping through the whole bunch */
3834 /* find the end of the list */
3838 /* set the last sub->next to the first sub */
3841 e
->next
= gw
->endpoints
;
3845 } else if (!strcasecmp(v
->name
, "trunk") ||
3846 !strcasecmp(v
->name
, "line")) {
3848 /* locate existing endpoint */
3851 if (!strcasecmp(v
->value
, e
->name
)) {
3852 /* endpoint already exists */
3861 e
= malloc(sizeof(struct mgcp_endpoint
));
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
));
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
);
3886 /* XXX potential issue due to reload */
3890 e
->amaflags
= amaflags
;
3891 e
->capability
= capability
;
3892 e
->dtmfmode
= dtmfmode
;
3894 if (!strcasecmp(v
->name
, "trunk"))
3895 e
->type
= TYPE_TRUNK
;
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
;
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
++) {
3920 sub
= malloc(sizeof(struct mgcp_subchannel
));
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
));
3937 snprintf(sub
->txident
, sizeof(sub
->txident
), "%08lx", ast_random());
3938 sub
->cxmode
= MGCP_CX_INACTIVE
;
3944 /* XXX Should find a way to clean up our memory */
3945 ast_log(LOG_WARNING
, "Out of memory allocating subchannel\n");
3950 /* Make out subs a circular linked list so we can always sping through the whole bunch */
3952 /* find the end of the list */
3956 /* set the last sub->next to the first sub */
3959 e
->next
= gw
->endpoints
;
3964 ast_log(LOG_WARNING
, "Don't know keyword '%s' at line %d\n", v
->name
, v
->lineno
);
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
);
3971 ast_mutex_destroy(&gw
->msgs_lock
);
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
;
3998 if (sub
->parent
->canreinvite
)
3999 return AST_RTP_TRY_NATIVE
;
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
);
4016 static struct ast_rtp_protocol mgcp_rtp
= {
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
;
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
);
4033 ast_rtp_destroy(sub
->rtp
);
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
);
4044 ast_dsp_free(e
->dsp
);
4047 dump_queue(e
->parent
, e
);
4048 dump_cmd_queues(e
, NULL
);
4051 for (i
= 0; (i
< MAX_SUBS
) && sub
; i
++) {
4054 ast_mutex_destroy(&s
->lock
);
4055 ast_mutex_destroy(&s
->cx_queue_lock
);
4058 ast_mutex_destroy(&e
->lock
);
4059 ast_mutex_destroy(&e
->rqnt_queue_lock
);
4060 ast_mutex_destroy(&e
->cmd_queue_lock
);
4064 static void destroy_gateway(struct mgcp_gateway
*g
)
4069 dump_queue(g
, NULL
);
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
) {
4092 destroy_endpoint(t
);
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
;
4124 struct ast_hostent ahp
;
4128 if (gethostname(ourhost
, sizeof(ourhost
)-1)) {
4129 ast_log(LOG_WARNING
, "Unable to get hostname, MGCP disabled\n");
4132 cfg
= ast_config_load(config
);
4134 /* We *must* have a config file otherwise stop immediately */
4136 ast_log(LOG_NOTICE
, "Unable to load config %s, MGCP disabled\n", config
);
4139 memset(&bindaddr
, 0, sizeof(bindaddr
));
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");
4147 /* handle jb conf */
4148 if (!ast_jb_read_conf(&global_jbconf
, v
->name
, v
->value
)) {
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
);
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
);
4163 ast_log(LOG_WARNING
, "Cannot allow unknown format '%s'\n", v
->value
);
4165 capability
|= format
;
4166 } else if (!strcasecmp(v
->name
, "disallow")) {
4167 format
= ast_getformatbyname(v
->value
);
4169 ast_log(LOG_WARNING
, "Cannot disallow unknown format '%s'\n", v
->value
);
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"))
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
);
4191 ast_log(LOG_WARNING
, "Invalid port number '%s' at line %d of %s\n", v
->value
, v
->lineno
, config
);
4197 /* mark existing entries for deletion */
4198 ast_mutex_lock(&gatelock
);
4209 ast_mutex_unlock(&gatelock
);
4211 cat
= ast_category_browse(cfg
, NULL
);
4213 if (strcasecmp(cat
, "general")) {
4214 ast_mutex_lock(&gatelock
);
4215 g
= build_gateway(cat
, ast_variable_browse(cfg
, cat
));
4217 if (option_verbose
> 2) {
4218 ast_verbose(VERBOSE_PREFIX_3
"Added gateway '%s'\n", g
->name
);
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. */
4237 if (ntohl(bindaddr
.sin_addr
.s_addr
)) {
4238 memcpy(&__ourip
, &bindaddr
.sin_addr
, sizeof(__ourip
));
4240 hp
= ast_gethostbyname(ourhost
, &ahp
);
4242 ast_log(LOG_WARNING
, "Unable to get our IP address, MGCP disabled\n");
4243 ast_config_destroy(cfg
);
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
);
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);
4261 ast_log(LOG_WARNING
, "Unable to create MGCP socket: %s\n", strerror(errno
));
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
),
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 */
4286 while (e
&& e
->needaudit
) {
4288 transmit_audit_endpoint(e
);
4289 ast_verbose(VERBOSE_PREFIX_3
"MGCP Auditing endpoint %s@%s for hookstate\n", e
->name
, g
->name
);
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 */
4329 return AST_MODULE_LOAD_SUCCESS
;
4332 /*! \brief mgcp_do_reload: Reload module */
4333 static int mgcp_do_reload(void)
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");
4347 ast_mutex_lock(&mgcp_reload_lock
);
4348 if (mgcp_reloading
) {
4349 ast_verbose("Previous mgcp reload not yet done\n");
4352 ast_mutex_unlock(&mgcp_reload_lock
);
4357 static int reload(void)
4359 mgcp_reload(0, 0, NULL
);
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");
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
);
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
);
4394 mgcp_reload(0, 0, NULL
);
4398 if (!ast_mutex_lock(&gatelock
)) {
4399 for (g
= gateways
; g
; g
= g
->next
) {
4401 for (e
= g
->endpoints
; e
; e
= e
->next
)
4406 ast_mutex_unlock(&gatelock
);
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
;
4414 mgcp_reload(0, 0, NULL
);
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
);
4426 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "Media Gateway Control Protocol (MGCP)",
4427 .load
= load_module
,
4428 .unload
= unload_module
,