Implementation of Media Gateway Control Protocol. More...
#include "asterisk.h"#include <sys/socket.h>#include <sys/ioctl.h>#include <net/if.h>#include <fcntl.h>#include <netdb.h>#include <sys/signal.h>#include <signal.h>#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <arpa/inet.h>#include <ctype.h>#include "asterisk/lock.h"#include "asterisk/channel.h"#include "asterisk/config.h"#include "asterisk/module.h"#include "asterisk/pbx.h"#include "asterisk/sched.h"#include "asterisk/io.h"#include "asterisk/rtp.h"#include "asterisk/acl.h"#include "asterisk/callerid.h"#include "asterisk/cli.h"#include "asterisk/say.h"#include "asterisk/cdr.h"#include "asterisk/astdb.h"#include "asterisk/features.h"#include "asterisk/app.h"#include "asterisk/musiconhold.h"#include "asterisk/utils.h"#include "asterisk/netsock.h"#include "asterisk/causes.h"#include "asterisk/dsp.h"#include "asterisk/devicestate.h"#include "asterisk/stringfields.h"#include "asterisk/abstract_jb.h"#include "asterisk/event.h"
Go to the source code of this file.
Data Structures | |
| struct | mgcp_endpoint |
| struct | mgcp_gateway |
| struct | mgcp_message |
| mgcp_message: MGCP message for queuing up More... | |
| struct | mgcp_request |
| struct | mgcp_response |
| struct | mgcp_subchannel |
Defines | |
| #define | DEFAULT_EXPIRY 120 |
| #define | DEFAULT_MGCP_CA_PORT 2727 |
| #define | DEFAULT_MGCP_GW_PORT 2427 |
| #define | DEFAULT_RETRANS 1000 |
| #define | DIRECTMEDIA 1 |
| #define | INADDR_NONE (in_addr_t)(-1) |
| #define | MAX_EXPIRY 3600 |
| #define | MAX_RETRANS 5 |
| #define | MAX_SUBS 2 |
| #define | MGCP_CX_CONF 3 |
| #define | MGCP_CX_CONFERENCE 3 |
| #define | MGCP_CX_INACTIVE 4 |
| #define | MGCP_CX_MUTE 4 |
| #define | MGCP_CX_RECVONLY 1 |
| #define | MGCP_CX_SENDONLY 0 |
| #define | MGCP_CX_SENDRECV 2 |
| #define | MGCP_DTMF_HYBRID (1 << 2) |
| #define | MGCP_DTMF_INBAND (1 << 1) |
| #define | MGCP_DTMF_RFC2833 (1 << 0) |
| #define | MGCP_MAX_HEADERS 64 |
| #define | MGCP_MAX_LINES 64 |
| #define | MGCP_MAX_PACKET 1500 |
| #define | MGCP_OFFHOOK 2 |
| #define | MGCP_ONHOOK 1 |
| #define | MGCP_SUBCHANNEL_MAGIC "!978!" |
| #define | MGCPDUMPER |
| #define | RESPONSE_TIMEOUT 30 |
| #define | SUB_ALT 1 |
| #define | SUB_REAL 0 |
| #define | TYPE_LINE 2 |
| #define | TYPE_TRUNK 1 |
Enumerations | |
| enum | { MGCP_CMD_EPCF, MGCP_CMD_CRCX, MGCP_CMD_MDCX, MGCP_CMD_DLCX, MGCP_CMD_RQNT, MGCP_CMD_NTFY, MGCP_CMD_AUEP, MGCP_CMD_AUCX, MGCP_CMD_RSIP } |
Functions | |
| static char * | __get_header (struct mgcp_request *req, char *name, int *start) |
| static int | __mgcp_xmit (struct mgcp_gateway *gw, char *data, int len) |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | add_header (struct mgcp_request *req, char *var, char *value) |
| static void | add_header_offhook (struct mgcp_subchannel *sub, struct mgcp_request *resp) |
| static int | add_line (struct mgcp_request *req, char *line) |
| static int | add_sdp (struct mgcp_request *resp, struct mgcp_subchannel *sub, struct ast_rtp *rtp) |
| static int | attempt_transfer (struct mgcp_endpoint *p) |
| static struct mgcp_gateway * | build_gateway (char *cat, struct ast_variable *v) |
| build_gateway: parse mgcp.conf and create gateway/endpoint structures | |
| static char * | control2str (int ind) |
| static void | destroy_endpoint (struct mgcp_endpoint *e) |
| static void | destroy_gateway (struct mgcp_gateway *g) |
| static void * | do_monitor (void *data) |
| static void | dump_cmd_queues (struct mgcp_endpoint *p, struct mgcp_subchannel *sub) |
| dump_cmd_queues: (SC:) cleanup pending commands | |
| static void | dump_queue (struct mgcp_gateway *gw, struct mgcp_endpoint *p) |
| static int | find_and_retrans (struct mgcp_subchannel *sub, struct mgcp_request *req) |
| static struct mgcp_request * | find_command (struct mgcp_endpoint *p, struct mgcp_subchannel *sub, struct mgcp_request **queue, ast_mutex_t *l, int ident) |
| find_command: (SC:) remove command transaction from queue | |
| static struct mgcp_subchannel * | find_subchannel_and_lock (char *name, int msgid, struct sockaddr_in *sin) |
| static char * | get_csv (char *c, int *len, char **next) |
| get_csv: (SC:) get comma separated value | |
| static char * | get_header (struct mgcp_request *req, char *name) |
| static char * | get_sdp (struct mgcp_request *req, char *name) |
| static char * | get_sdp_by_line (char *line, char *name, int nameLen) |
| static char * | get_sdp_iterate (int *iterator, struct mgcp_request *req, char *name) |
| static void | handle_hd_hf (struct mgcp_subchannel *sub, char *ev) |
| static char * | handle_mgcp_audit_endpoint (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_mgcp_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_mgcp_show_endpoints (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static int | handle_request (struct mgcp_subchannel *sub, struct mgcp_request *req, struct sockaddr_in *sin) |
| static void | handle_response (struct mgcp_endpoint *p, struct mgcp_subchannel *sub, int result, unsigned int ident, struct mgcp_request *resp) |
| static int | has_voicemail (struct mgcp_endpoint *p) |
| static int | init_req (struct mgcp_endpoint *p, struct mgcp_request *req, char *verb) |
| static int | init_resp (struct mgcp_request *req, char *resp, struct mgcp_request *orig, char *resprest) |
| static int | load_module (void) |
| load_module: PBX load module - initialization --- | |
| static int | mgcp_answer (struct ast_channel *ast) |
| static int | mgcp_call (struct ast_channel *ast, char *dest, int timeout) |
| static int | mgcp_devicestate (void *data) |
| mgcp_devicestate: channel callback for device status monitoring | |
| static int | mgcp_fixup (struct ast_channel *oldchan, struct ast_channel *newchan) |
| static enum ast_rtp_get_result | mgcp_get_rtp_peer (struct ast_channel *chan, struct ast_rtp **rtp) |
| static int | mgcp_hangup (struct ast_channel *ast) |
| static int | mgcp_indicate (struct ast_channel *ast, int ind, const void *data, size_t datalen) |
| static struct ast_channel * | mgcp_new (struct mgcp_subchannel *sub, int state) |
| static int | mgcp_postrequest (struct mgcp_endpoint *p, struct mgcp_subchannel *sub, char *data, int len, unsigned int seqno) |
| static void | mgcp_queue_control (struct mgcp_subchannel *sub, int control) |
| static void | mgcp_queue_frame (struct mgcp_subchannel *sub, struct ast_frame *f) |
| static void | mgcp_queue_hangup (struct mgcp_subchannel *sub) |
| static struct ast_frame * | mgcp_read (struct ast_channel *ast) |
| static char * | mgcp_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static struct ast_channel * | mgcp_request (const char *type, int format, void *data, int *cause) |
| static struct ast_frame * | mgcp_rtp_read (struct mgcp_subchannel *sub) |
| static int | mgcp_senddigit_begin (struct ast_channel *ast, char digit) |
| static int | mgcp_senddigit_end (struct ast_channel *ast, char digit, unsigned int duration) |
| static int | mgcp_set_rtp_peer (struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active) |
| static void * | mgcp_ss (void *data) |
| static int | mgcp_write (struct ast_channel *ast, struct ast_frame *frame) |
| static int | mgcpsock_read (int *id, int fd, short events, void *ignore) |
| static void | mwi_event_cb (const struct ast_event *event, void *userdata) |
| static void | parse (struct mgcp_request *req) |
| static int | process_sdp (struct mgcp_subchannel *sub, struct mgcp_request *req) |
| static void | prune_gateways (void) |
| static int | reload (void) |
| static int | reload_config (int reload) |
| static int | reqprep (struct mgcp_request *req, struct mgcp_endpoint *p, char *verb) |
| static int | resend_response (struct mgcp_subchannel *sub, struct mgcp_response *resp) |
| static int | respprep (struct mgcp_request *resp, struct mgcp_endpoint *p, char *msg, struct mgcp_request *req, char *msgrest) |
| static int | restart_monitor (void) |
| static int | retrans_pkt (const void *data) |
| static void | sdpLineNum_iterator_init (int *iterator) |
| static int | send_request (struct mgcp_endpoint *p, struct mgcp_subchannel *sub, struct mgcp_request *req, unsigned int seqno) |
| static int | send_response (struct mgcp_subchannel *sub, struct mgcp_request *req) |
| static void | start_rtp (struct mgcp_subchannel *sub) |
| static int | transmit_audit_endpoint (struct mgcp_endpoint *p) |
| static int | transmit_connect_with_sdp (struct mgcp_subchannel *sub, struct ast_rtp *rtp) |
| static int | transmit_connection_del (struct mgcp_subchannel *sub) |
| static int | transmit_connection_del_w_params (struct mgcp_endpoint *p, char *callid, char *cxident) |
| static int | transmit_modify_request (struct mgcp_subchannel *sub) |
| static int | transmit_modify_with_sdp (struct mgcp_subchannel *sub, struct ast_rtp *rtp, int codecs) |
| static int | transmit_notify_request (struct mgcp_subchannel *sub, char *tone) |
| static int | transmit_notify_request_with_callerid (struct mgcp_subchannel *sub, char *tone, char *callernum, char *callername) |
| static int | transmit_response (struct mgcp_subchannel *sub, char *msg, struct mgcp_request *req, char *msgrest) |
| static int | unalloc_sub (struct mgcp_subchannel *sub) |
| static int | unload_module (void) |
Variables | |
| static struct ast_module_info __MODULE_INFO_SECTION | __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Media Gateway Control Protocol (MGCP)" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } |
| static struct in_addr | __ourip |
| static char | accountcode [AST_MAX_ACCOUNT_CODE] = "" |
| static int | adsi = 0 |
| static int | amaflags = 0 |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct sockaddr_in | bindaddr |
| static int | callreturn = 0 |
| static int | callwaiting = 0 |
| static int | cancallforward = 0 |
| static int | capability = AST_FORMAT_ULAW |
| static char | cid_name [AST_MAX_EXTENSION] = "" |
| static char | cid_num [AST_MAX_EXTENSION] = "" |
| static struct ast_cli_entry | cli_mgcp [] |
| static const char | config [] = "mgcp.conf" |
| static char | context [AST_MAX_EXTENSION] = "default" |
| static ast_group_t | cur_callergroup = 0 |
| static ast_group_t | cur_pickupgroup = 0 |
| static struct ast_jb_conf | default_jbconf |
| static int | directmedia = DIRECTMEDIA |
| static int | dtmfmode = 0 |
| static int | firstdigittimeout = 16000 |
| static ast_mutex_t | gatelock = AST_MUTEX_INIT_VALUE |
| gatelock: mutex for gateway/endpoint lists | |
| static struct mgcp_gateway * | gateways |
| static int | gendigittimeout = 8000 |
| static struct ast_jb_conf | global_jbconf |
| static int | immediate = 0 |
| static struct io_context * | io |
| static char | language [MAX_LANGUAGE] = "" |
| static char | mailbox [AST_MAX_EXTENSION] |
| static int | matchdigittimeout = 3000 |
| static char * | mgcp_cxmodes [] |
| static ast_mutex_t | mgcp_reload_lock = AST_MUTEX_INIT_VALUE |
| static int | mgcp_reloading = 0 |
| static struct ast_rtp_protocol | mgcp_rtp |
| static struct ast_channel_tech | mgcp_tech |
| static int | mgcpdebug = 0 |
| static int | mgcpsock = -1 |
| static int * | mgcpsock_read_id = NULL |
| static pthread_t | monitor_thread = AST_PTHREADT_NULL |
| static ast_mutex_t | monlock = AST_MUTEX_INIT_VALUE |
| static char | musicclass [MAX_MUSICCLASS] = "" |
| static int | nat = 0 |
| static ast_mutex_t | netlock = AST_MUTEX_INIT_VALUE |
| static int | nonCodecCapability = AST_RTP_DTMF |
| static unsigned int | oseq |
| static char | ourhost [MAXHOSTNAMELEN] |
| static int | ourport |
| static char | parkinglot [AST_MAX_CONTEXT] |
| struct { | |
| unsigned int cos | |
| unsigned int cos_audio | |
| unsigned int tos | |
| unsigned int tos_audio | |
| } | qos |
| static struct sched_context * | sched |
| static int | singlepath = 0 |
| static int | slowsequence = 0 |
| static const char | tdesc [] = "Media Gateway Control Protocol (MGCP)" |
| static int | threewaycalling = 0 |
| static int | transfer = 0 |
| #define DEFAULT_EXPIRY 120 |
Definition at line 81 of file chan_mgcp.c.
| #define DEFAULT_MGCP_CA_PORT 2727 |
| #define DEFAULT_MGCP_GW_PORT 2427 |
| #define DEFAULT_RETRANS 1000 |
How frequently to retransmit
Definition at line 110 of file chan_mgcp.c.
Referenced by mgcp_postrequest().
| #define DIRECTMEDIA 1 |
Definition at line 83 of file chan_mgcp.c.
Referenced by build_gateway().
| #define INADDR_NONE (in_addr_t)(-1) |
Definition at line 86 of file chan_mgcp.c.
Referenced by build_gateway().
| #define MAX_EXPIRY 3600 |
Definition at line 82 of file chan_mgcp.c.
| #define MAX_RETRANS 5 |
Try only 5 times for retransmissions
Definition at line 111 of file chan_mgcp.c.
Referenced by retrans_pkt().
| #define MAX_SUBS 2 |
Definition at line 269 of file chan_mgcp.c.
Referenced by build_gateway(), and destroy_endpoint().
| #define MGCP_CX_CONF 3 |
Definition at line 117 of file chan_mgcp.c.
Referenced by handle_request().
| #define MGCP_CX_CONFERENCE 3 |
Definition at line 118 of file chan_mgcp.c.
| #define MGCP_CX_INACTIVE 4 |
Definition at line 120 of file chan_mgcp.c.
Referenced by build_gateway(), mgcp_hangup(), and unalloc_sub().
| #define MGCP_CX_MUTE 4 |
Definition at line 119 of file chan_mgcp.c.
Referenced by handle_request().
| #define MGCP_CX_RECVONLY 1 |
Definition at line 115 of file chan_mgcp.c.
Referenced by handle_request(), mgcp_call(), and mgcp_hangup().
| #define MGCP_CX_SENDONLY 0 |
MGCP rtp stream modes {
Definition at line 114 of file chan_mgcp.c.
| #define MGCP_CX_SENDRECV 2 |
Definition at line 116 of file chan_mgcp.c.
Referenced by handle_hd_hf(), handle_request(), mgcp_answer(), and mgcp_call().
| #define MGCP_DTMF_HYBRID (1 << 2) |
Definition at line 105 of file chan_mgcp.c.
Referenced by add_header_offhook(), build_gateway(), mgcp_hangup(), mgcp_new(), mgcp_senddigit_begin(), mgcp_senddigit_end(), and mgcp_ss().
| #define MGCP_DTMF_INBAND (1 << 1) |
Definition at line 104 of file chan_mgcp.c.
Referenced by add_header_offhook(), build_gateway(), mgcp_hangup(), mgcp_new(), mgcp_rtp_read(), mgcp_senddigit_begin(), mgcp_senddigit_end(), and mgcp_ss().
| #define MGCP_DTMF_RFC2833 (1 << 0) |
Definition at line 103 of file chan_mgcp.c.
Referenced by build_gateway(), mgcp_rtp_read(), mgcp_senddigit_begin(), and mgcp_senddigit_end().
| #define MGCP_MAX_HEADERS 64 |
The private structures of the mgcp channels are linked for ! selecting outgoing channels
Definition at line 228 of file chan_mgcp.c.
Referenced by add_header(), init_req(), init_resp(), and parse().
| #define MGCP_MAX_LINES 64 |
Definition at line 229 of file chan_mgcp.c.
Referenced by add_line(), and parse().
| #define MGCP_MAX_PACKET 1500 |
Also from RFC 2543, should sub headers tho
Definition at line 109 of file chan_mgcp.c.
| #define MGCP_OFFHOOK 2 |
Definition at line 303 of file chan_mgcp.c.
Referenced by handle_hd_hf(), handle_request(), handle_response(), mgcp_call(), mgcp_hangup(), transmit_modify_request(), transmit_notify_request(), and transmit_notify_request_with_callerid().
| #define MGCP_ONHOOK 1 |
Definition at line 302 of file chan_mgcp.c.
Referenced by build_gateway(), do_monitor(), handle_request(), handle_response(), mgcp_call(), mgcp_hangup(), mgcp_request(), transmit_modify_request(), transmit_notify_request(), and transmit_notify_request_with_callerid().
| #define MGCP_SUBCHANNEL_MAGIC "!978!" |
subchannel magic string. Needed to prove that any subchannel pointer passed by asterisk really points to a valid subchannel memory area. Ugly.. But serves the purpose for the time being.
Definition at line 280 of file chan_mgcp.c.
Referenced by build_gateway(), and mgcp_hangup().
| #define MGCPDUMPER |
Definition at line 80 of file chan_mgcp.c.
| #define RESPONSE_TIMEOUT 30 |
| #define SUB_ALT 1 |
Definition at line 272 of file chan_mgcp.c.
| #define SUB_REAL 0 |
Definition at line 271 of file chan_mgcp.c.
| #define TYPE_LINE 2 |
Definition at line 306 of file chan_mgcp.c.
Referenced by build_gateway(), do_monitor(), and mgcp_call().
| #define TYPE_TRUNK 1 |
Definition at line 305 of file chan_mgcp.c.
Referenced by build_gateway().
| anonymous enum |
| MGCP_CMD_EPCF | |
| MGCP_CMD_CRCX | |
| MGCP_CMD_MDCX | |
| MGCP_CMD_DLCX | |
| MGCP_CMD_RQNT | |
| MGCP_CMD_NTFY | |
| MGCP_CMD_AUEP | |
| MGCP_CMD_AUCX | |
| MGCP_CMD_RSIP |
Definition at line 131 of file chan_mgcp.c.
| static char* __get_header | ( | struct mgcp_request * | req, |
| char * | name, | ||
| int * | start | ||
| ) | [static] |
Definition at line 1581 of file chan_mgcp.c.
References mgcp_request::header, mgcp_request::headers, and len().
Referenced by get_header().
{
int x;
int len = strlen(name);
char *r;
for (x=*start;x<req->headers;x++) {
if (!strncasecmp(req->header[x], name, len) &&
(req->header[x][len] == ':')) {
r = req->header[x] + len + 1;
while(*r && (*r < 33))
r++;
*start = x+1;
return r;
}
}
/* Don't return NULL, so get_header is always a valid pointer */
return "";
}
| static int __mgcp_xmit | ( | struct mgcp_gateway * | gw, |
| char * | data, | ||
| int | len | ||
| ) | [static] |
Definition at line 515 of file chan_mgcp.c.
References mgcp_gateway::addr, ast_log(), mgcp_gateway::defaddr, errno, and LOG_WARNING.
Referenced by mgcp_postrequest(), resend_response(), retrans_pkt(), and send_response().
{
int res;
if (gw->addr.sin_addr.s_addr)
res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->addr, sizeof(struct sockaddr_in));
else
res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->defaddr, sizeof(struct sockaddr_in));
if (res != len) {
ast_log(LOG_WARNING, "mgcp_xmit returned %d: %s\n", res, strerror(errno));
}
return res;
}
| static void __reg_module | ( | void | ) | [static] |
Definition at line 4397 of file chan_mgcp.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 4397 of file chan_mgcp.c.
| static int add_header | ( | struct mgcp_request * | req, |
| char * | var, | ||
| char * | value | ||
| ) | [static] |
Definition at line 1927 of file chan_mgcp.c.
References ast_log(), mgcp_request::data, mgcp_request::header, mgcp_request::headers, mgcp_request::len, mgcp_request::lines, LOG_WARNING, and MGCP_MAX_HEADERS.
Referenced by add_header_offhook(), transmit_audit_endpoint(), transmit_connect_with_sdp(), transmit_connection_del(), transmit_connection_del_w_params(), transmit_modify_request(), transmit_modify_with_sdp(), transmit_notify_request(), and transmit_notify_request_with_callerid().
{
if (req->len >= sizeof(req->data) - 4) {
ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
return -1;
}
if (req->lines) {
ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n");
return -1;
}
req->header[req->headers] = req->data + req->len;
snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s: %s\r\n", var, value);
req->len += strlen(req->header[req->headers]);
if (req->headers < MGCP_MAX_HEADERS)
req->headers++;
else {
ast_log(LOG_WARNING, "Out of header space\n");
return -1;
}
return 0;
}
| static void add_header_offhook | ( | struct mgcp_subchannel * | sub, |
| struct mgcp_request * | resp | ||
| ) | [static] |
Definition at line 2322 of file chan_mgcp.c.
References ast_channel::_state, add_header(), AST_STATE_RINGING, mgcp_endpoint::dtmfmode, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, mgcp_subchannel::owner, mgcp_subchannel::parent, and mgcp_endpoint::sub.
Referenced by transmit_modify_request(), transmit_notify_request(), and transmit_notify_request_with_callerid().
{
struct mgcp_endpoint *p = sub->parent;
if (p && p->sub && p->sub->owner && p->sub->owner->_state >= AST_STATE_RINGING && (p->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)))
add_header(resp, "R", "L/hu(N),L/hf(N)");
else
add_header(resp, "R", "L/hu(N),L/hf(N),D/[0-9#*](N)");
}
| static int add_line | ( | struct mgcp_request * | req, |
| char * | line | ||
| ) | [static] |
Definition at line 1949 of file chan_mgcp.c.
References ast_copy_string(), ast_log(), mgcp_request::data, mgcp_request::len, mgcp_request::line, mgcp_request::lines, LOG_WARNING, and MGCP_MAX_LINES.
Referenced by add_sdp().
{
if (req->len >= sizeof(req->data) - 4) {
ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
return -1;
}
if (!req->lines) {
/* Add extra empty return */
ast_copy_string(req->data + req->len, "\r\n", sizeof(req->data) - req->len);
req->len += strlen(req->data + req->len);
}
req->line[req->lines] = req->data + req->len;
snprintf(req->line[req->lines], sizeof(req->data) - req->len, "%s", line);
req->len += strlen(req->line[req->lines]);
if (req->lines < MGCP_MAX_LINES)
req->lines++;
else {
ast_log(LOG_WARNING, "Out of line space\n");
return -1;
}
return 0;
}
| static int add_sdp | ( | struct mgcp_request * | resp, |
| struct mgcp_subchannel * | sub, | ||
| struct ast_rtp * | rtp | ||
| ) | [static] |
Definition at line 2050 of file chan_mgcp.c.
References add_line(), ast_copy_string(), AST_FORMAT_AUDIO_MASK, ast_inet_ntoa(), ast_log(), AST_RTP_DTMF, ast_rtp_get_peer(), ast_rtp_get_us(), ast_rtp_lookup_code(), ast_rtp_lookup_mime_subtype(), AST_RTP_MAX, ast_verbose(), mgcp_endpoint::capability, len(), LOG_WARNING, mgcp_endpoint::nonCodecCapability, mgcp_gateway::ourip, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_subchannel::rtp, s, and mgcp_subchannel::tmpdest.
Referenced by transmit_connect_with_sdp(), and transmit_modify_with_sdp().
{
int len;
int codec;
char costr[80];
struct sockaddr_in sin;
char v[256];
char s[256];
char o[256];
char c[256];
char t[256];
char m[256] = "";
char a[1024] = "";
int x;
struct sockaddr_in dest;
struct mgcp_endpoint *p = sub->parent;
/* XXX We break with the "recommendation" and send our IP, in order that our
peer doesn't have to ast_gethostbyname() us XXX */
len = 0;
if (!sub->rtp) {
ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n");
return -1;
}
ast_rtp_get_us(sub->rtp, &sin);
if (rtp) {
ast_rtp_get_peer(rtp, &dest);
} else {
if (sub->tmpdest.sin_addr.s_addr) {
dest.sin_addr = sub->tmpdest.sin_addr;
dest.sin_port = sub->tmpdest.sin_port;
/* Reset temporary destination */
memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
} else {
dest.sin_addr = p->parent->ourip;
dest.sin_port = sin.sin_port;
}
}
if (mgcpdebug) {
ast_verbose("We're at %s port %d\n", ast_inet_ntoa(p->parent->ourip), ntohs(sin.sin_port));
}
ast_copy_string(v, "v=0\r\n", sizeof(v));
snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", (int)getpid(), (int)getpid(), ast_inet_ntoa(dest.sin_addr));
ast_copy_string(s, "s=session\r\n", sizeof(s));
snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr));
ast_copy_string(t, "t=0 0\r\n", sizeof(t));
snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port));
for (x = 1; x <= AST_FORMAT_AUDIO_MASK; x <<= 1) {
if (p->capability & x) {
if (mgcpdebug) {
ast_verbose("Answering with capability %d\n", x);
}
codec = ast_rtp_lookup_code(sub->rtp, 1, x);
if (codec > -1) {
snprintf(costr, sizeof(costr), " %d", codec);
strncat(m, costr, sizeof(m) - strlen(m) - 1);
snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(1, x, 0));
strncat(a, costr, sizeof(a) - strlen(a) - 1);
}
}
}
for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
if (p->nonCodecCapability & x) {
if (mgcpdebug) {
ast_verbose("Answering with non-codec capability %d\n", x);
}
codec = ast_rtp_lookup_code(sub->rtp, 0, x);
if (codec > -1) {
snprintf(costr, sizeof(costr), " %d", codec);
strncat(m, costr, sizeof(m) - strlen(m) - 1);
snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(0, x, 0));
strncat(a, costr, sizeof(a) - strlen(a) - 1);
if (x == AST_RTP_DTMF) {
/* Indicate we support DTMF... Not sure about 16,
but MSN supports it so dang it, we will too... */
snprintf(costr, sizeof costr, "a=fmtp:%d 0-16\r\n", codec);
strncat(a, costr, sizeof(a) - strlen(a) - 1);
}
}
}
}
strncat(m, "\r\n", sizeof(m) - strlen(m) - 1);
len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a);
snprintf(costr, sizeof(costr), "%d", len);
add_line(resp, v);
add_line(resp, o);
add_line(resp, s);
add_line(resp, c);
add_line(resp, t);
add_line(resp, m);
add_line(resp, a);
return 0;
}
| static int attempt_transfer | ( | struct mgcp_endpoint * | p | ) | [static] |
Definition at line 2887 of file chan_mgcp.c.
References ast_channel::_softhangup, ast_channel::_state, mgcp_subchannel::alreadygone, ast_bridged_channel(), ast_channel_masquerade(), AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_debug, ast_indicate(), ast_log(), ast_queue_control(), AST_SOFTHANGUP_DEV, AST_STATE_RINGING, ast_verb, mgcp_subchannel::id, LOG_WARNING, mgcp_queue_hangup(), mgcp_gateway::name, mgcp_endpoint::name, ast_channel::name, mgcp_subchannel::next, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_endpoint::sub, and unalloc_sub().
Referenced by handle_request().
{
/* *************************
* I hope this works.
* Copied out of chan_zap
* Cross your fingers
* *************************/
/* In order to transfer, we need at least one of the channels to
actually be in a call bridge. We can't conference two applications
together (but then, why would we want to?) */
if (ast_bridged_channel(p->sub->owner)) {
/* The three-way person we're about to transfer to could still be in MOH, so
stop if now if appropriate */
if (ast_bridged_channel(p->sub->next->owner))
ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
if (p->sub->owner->_state == AST_STATE_RINGING) {
ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
}
if (ast_channel_masquerade(p->sub->next->owner, ast_bridged_channel(p->sub->owner))) {
ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
ast_bridged_channel(p->sub->owner)->name, p->sub->next->owner->name);
return -1;
}
/* Orphan the channel */
unalloc_sub(p->sub->next);
} else if (ast_bridged_channel(p->sub->next->owner)) {
if (p->sub->owner->_state == AST_STATE_RINGING) {
ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
}
ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
if (ast_channel_masquerade(p->sub->owner, ast_bridged_channel(p->sub->next->owner))) {
ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
ast_bridged_channel(p->sub->next->owner)->name, p->sub->owner->name);
return -1;
}
/*swap_subs(p, SUB_THREEWAY, SUB_REAL);*/
ast_verb(3, "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name);
p->sub = p->sub->next;
unalloc_sub(p->sub->next);
/* Tell the caller not to hangup */
return 1;
} else {
ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
p->sub->owner->name, p->sub->next->owner->name);
p->sub->next->owner->_softhangup |= AST_SOFTHANGUP_DEV;
if (p->sub->next->owner) {
p->sub->next->alreadygone = 1;
mgcp_queue_hangup(p->sub->next);
}
}
return 0;
}
| static struct mgcp_gateway* build_gateway | ( | char * | cat, |
| struct ast_variable * | v | ||
| ) | [static, read] |
build_gateway: parse mgcp.conf and create gateway/endpoint structures
Definition at line 3555 of file chan_mgcp.c.
References __ourip, mgcp_endpoint::accountcode, mgcp_gateway::addr, adsi, mgcp_endpoint::adsi, amaflags, mgcp_endpoint::amaflags, ast_append_ha(), ast_callerid_split(), ast_calloc, ast_cdr_amaflags2int(), ast_copy_string(), AST_EVENT_IE_CONTEXT, AST_EVENT_IE_END, AST_EVENT_IE_MAILBOX, AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS, AST_EVENT_IE_PLTYPE_STR, AST_EVENT_MWI, ast_event_subscribe(), ast_free, ast_get_group(), ast_get_ip(), ast_log(), ast_mutex_destroy(), ast_mutex_init(), ast_ouraddrfor(), ast_random(), AST_SCHED_DEL, ast_strdupa, ast_strlen_zero(), ast_true(), ast_verb, mgcp_endpoint::callgroup, callreturn, mgcp_endpoint::callreturn, callwaiting, mgcp_endpoint::callwaiting, cancallforward, mgcp_endpoint::cancallforward, capability, mgcp_endpoint::capability, mgcp_endpoint::cid_name, mgcp_endpoint::cid_num, mgcp_endpoint::cmd_queue_lock, mgcp_endpoint::context, cur_callergroup, cur_pickupgroup, mgcp_subchannel::cx_queue_lock, mgcp_subchannel::cxmode, mgcp_gateway::defaddr, DEFAULT_MGCP_GW_PORT, mgcp_endpoint::delme, mgcp_gateway::delme, directmedia, mgcp_endpoint::directmedia, DIRECTMEDIA, dtmfmode, mgcp_endpoint::dtmfmode, mgcp_gateway::dynamic, mgcp_gateway::endpoints, mgcp_gateway::expire, gateways, mgcp_gateway::ha, mgcp_endpoint::hascallwaiting, mgcp_endpoint::hookstate, mgcp_subchannel::id, immediate, mgcp_endpoint::immediate, INADDR_NONE, mgcp_gateway::isnamedottedip, mgcp_endpoint::language, ast_variable::lineno, mgcp_subchannel::lock, mgcp_endpoint::lock, LOG_WARNING, mgcp_subchannel::magic, mgcp_endpoint::mailbox, MAX_SUBS, mbox(), MGCP_CX_INACTIVE, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, MGCP_DTMF_RFC2833, MGCP_ONHOOK, MGCP_SUBCHANNEL_MAGIC, mgcp_gateway::msgs_lock, mgcp_endpoint::msgstate, mgcp_endpoint::musicclass, mwi_event_cb(), mgcp_endpoint::mwi_event_sub, mgcp_endpoint::name, ast_variable::name, mgcp_gateway::name, nat, mgcp_subchannel::nat, mgcp_endpoint::needaudit, ast_variable::next, mgcp_subchannel::next, mgcp_endpoint::next, mgcp_gateway::next, mgcp_endpoint::onhooktime, mgcp_gateway::ourip, mgcp_subchannel::parent, mgcp_endpoint::parent, mgcp_endpoint::parkinglot, mgcp_endpoint::pickupgroup, mgcp_gateway::retransid, mgcp_endpoint::rqnt_ident, mgcp_endpoint::rqnt_queue_lock, mgcp_subchannel::rtp, singlepath, mgcp_endpoint::singlepath, slowsequence, mgcp_endpoint::slowsequence, strsep(), mgcp_endpoint::sub, threewaycalling, mgcp_endpoint::threewaycalling, transfer, mgcp_endpoint::transfer, mgcp_subchannel::txident, mgcp_endpoint::type, TYPE_LINE, TYPE_TRUNK, ast_variable::value, and mgcp_gateway::wcardep.
Referenced by reload_config().
{
struct mgcp_gateway *gw;
struct mgcp_endpoint *e;
struct mgcp_subchannel *sub;
/*char txident[80];*/
int i=0, y=0;
int gw_reload = 0;
int ep_reload = 0;
directmedia = DIRECTMEDIA;
/* locate existing gateway */
gw = gateways;
while (gw) {
if (!strcasecmp(cat, gw->name)) {
/* gateway already exists */
gw->delme = 0;
gw_reload = 1;
break;
}
gw = gw->next;
}
if (!gw)
gw = ast_calloc(1, sizeof(*gw));
if (gw) {
if (!gw_reload) {
gw->expire = -1;
gw->retransid = -1; /* SC */
ast_mutex_init(&gw->msgs_lock);
ast_copy_string(gw->name, cat, sizeof(gw->name));
/* check if the name is numeric ip */
if ((strchr(gw->name, '.')) && inet_addr(gw->name) != INADDR_NONE)
gw->isnamedottedip = 1;
}
while(v) {
if (!strcasecmp(v->name, "host")) {
if (!strcasecmp(v->value, "dynamic")) {
/* They'll register with us */
gw->dynamic = 1;
memset(&gw->addr.sin_addr, 0, 4);
if (gw->addr.sin_port) {
/* If we've already got a port, make it the default rather than absolute */
gw->defaddr.sin_port = gw->addr.sin_port;
gw->addr.sin_port = 0;
}
} else {
/* Non-dynamic. Make sure we become that way if we're not */
AST_SCHED_DEL(sched, gw->expire);
gw->dynamic = 0;
if (ast_get_ip(&gw->addr, v->value)) {
if (!gw_reload) {
ast_mutex_destroy(&gw->msgs_lock);
ast_free(gw);
}
return NULL;
}
}
} else if (!strcasecmp(v->name, "defaultip")) {
if (ast_get_ip(&gw->defaddr, v->value)) {
if (!gw_reload) {
ast_mutex_destroy(&gw->msgs_lock);
ast_free(gw);
}
return NULL;
}
} else if (!strcasecmp(v->name, "permit") ||
!strcasecmp(v->name, "deny")) {
gw->ha = ast_append_ha(v->name, v->value, gw->ha, NULL);
} else if (!strcasecmp(v->name, "port")) {
gw->addr.sin_port = htons(atoi(v->value));
} else if (!strcasecmp(v->name, "context")) {
ast_copy_string(context, v->value, sizeof(context));
} else if (!strcasecmp(v->name, "dtmfmode")) {
if (!strcasecmp(v->value, "inband"))
dtmfmode = MGCP_DTMF_INBAND;
else if (!strcasecmp(v->value, "rfc2833"))
dtmfmode = MGCP_DTMF_RFC2833;
else if (!strcasecmp(v->value, "hybrid"))
dtmfmode = MGCP_DTMF_HYBRID;
else if (!strcasecmp(v->value, "none"))
dtmfmode = 0;
else
ast_log(LOG_WARNING, "'%s' is not a valid DTMF mode at line %d\n", v->value, v->lineno);
} else if (!strcasecmp(v->name, "nat")) {
nat = ast_true(v->value);
} else if (!strcasecmp(v->name, "callerid")) {
if (!strcasecmp(v->value, "asreceived")) {
cid_num[0] = '\0';
cid_name[0] = '\0';
} else {
ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
}
} else if (!strcasecmp(v->name, "language")) {
ast_copy_string(language, v->value, sizeof(language));
} else if (!strcasecmp(v->name, "accountcode")) {
ast_copy_string(accountcode, v->value, sizeof(accountcode));
} else if (!strcasecmp(v->name, "amaflags")) {
y = ast_cdr_amaflags2int(v->value);
if (y < 0) {
ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
} else {
amaflags = y;
}
} else if (!strcasecmp(v->name, "musiconhold")) {
ast_copy_string(musicclass, v->value, sizeof(musicclass));
} else if (!strcasecmp(v->name, "parkinglot")) {
ast_copy_string(parkinglot, v->value, sizeof(parkinglot));
} else if (!strcasecmp(v->name, "callgroup")) {
cur_callergroup = ast_get_group(v->value);
} else if (!strcasecmp(v->name, "pickupgroup")) {
cur_pickupgroup = ast_get_group(v->value);
} else if (!strcasecmp(v->name, "immediate")) {
immediate = ast_true(v->value);
} else if (!strcasecmp(v->name, "cancallforward")) {
cancallforward = ast_true(v->value);
} else if (!strcasecmp(v->name, "singlepath")) {
singlepath = ast_true(v->value);
} else if (!strcasecmp(v->name, "directmedia") || !strcasecmp(v->name, "canreinvite")) {
directmedia = ast_true(v->value);
} else if (!strcasecmp(v->name, "mailbox")) {
ast_copy_string(mailbox, v->value, sizeof(mailbox));
} else if (!strcasecmp(v->name, "hasvoicemail")) {
if (ast_true(v->value) && ast_strlen_zero(mailbox)) {
ast_copy_string(mailbox, gw->name, sizeof(mailbox));
}
} else if (!strcasecmp(v->name, "adsi")) {
adsi = ast_true(v->value);
} else if (!strcasecmp(v->name, "callreturn")) {
callreturn = ast_true(v->value);
} else if (!strcasecmp(v->name, "callwaiting")) {
callwaiting = ast_true(v->value);
} else if (!strcasecmp(v->name, "slowsequence")) {
slowsequence = ast_true(v->value);
} else if (!strcasecmp(v->name, "transfer")) {
transfer = ast_true(v->value);
} else if (!strcasecmp(v->name, "threewaycalling")) {
threewaycalling = ast_true(v->value);
} else if (!strcasecmp(v->name, "wcardep")) {
/* locate existing endpoint */
e = gw->endpoints;
while (e) {
if (!strcasecmp(v->value, e->name)) {
/* endpoint already exists */
e->delme = 0;
ep_reload = 1;
break;
}
e = e->next;
}
if (!e) {
/* Allocate wildcard endpoint */
e = ast_calloc(1, sizeof(*e));
ep_reload = 0;
}
if (e) {
if (!ep_reload) {
memset(e, 0, sizeof(struct mgcp_endpoint));
ast_mutex_init(&e->lock);
ast_mutex_init(&e->rqnt_queue_lock);
ast_mutex_init(&e->cmd_queue_lock);
ast_copy_string(e->name, v->value, sizeof(e->name));
e->needaudit = 1;
}
ast_copy_string(gw->wcardep, v->value, sizeof(gw->wcardep));
/* XXX Should we really check for uniqueness?? XXX */
ast_copy_string(e->accountcode, accountcode, sizeof(e->accountcode));
ast_copy_string(e->context, context, sizeof(e->context));
ast_copy_string(e->cid_num, cid_num, sizeof(e->cid_num));
ast_copy_string(e->cid_name, cid_name, sizeof(e->cid_name));
ast_copy_string(e->language, language, sizeof(e->language));
ast_copy_string(e->musicclass, musicclass, sizeof(e->musicclass));
ast_copy_string(e->mailbox, mailbox, sizeof(e->mailbox));
ast_copy_string(e->parkinglot, parkinglot, sizeof(e->parkinglot));
if (!ast_strlen_zero(e->mailbox)) {
char *mbox, *cntx;
cntx = mbox = ast_strdupa(e->mailbox);
strsep(&cntx, "@");
if (ast_strlen_zero(cntx))
cntx = "default";
e->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, NULL,
AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mbox,
AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, cntx,
AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
AST_EVENT_IE_END);
}
snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", ast_random());
e->msgstate = -1;
e->amaflags = amaflags;
e->capability = capability;
e->parent = gw;
e->dtmfmode = dtmfmode;
if (!ep_reload && e->sub && e->sub->rtp)
e->dtmfmode |= MGCP_DTMF_INBAND;
e->adsi = adsi;
e->type = TYPE_LINE;
e->immediate = immediate;
e->callgroup=cur_callergroup;
e->pickupgroup=cur_pickupgroup;
e->callreturn = callreturn;
e->cancallforward = cancallforward;
e->singlepath = singlepath;
e->directmedia = directmedia;
e->callwaiting = callwaiting;
e->hascallwaiting = callwaiting;
e->slowsequence = slowsequence;
e->transfer = transfer;
e->threewaycalling = threewaycalling;
e->onhooktime = time(NULL);
/* ASSUME we're onhook */
e->hookstate = MGCP_ONHOOK;
if (!ep_reload) {
/*snprintf(txident, sizeof(txident), "%08lx", ast_random());*/
for (i = 0; i < MAX_SUBS; i++) {
sub = ast_calloc(1, sizeof(*sub));
if (sub) {
ast_verb(3, "Allocating subchannel '%d' on %s@%s\n", i, e->name, gw->name);
ast_mutex_init(&sub->lock);
ast_mutex_init(&sub->cx_queue_lock);
sub->parent = e;
sub->id = i;
snprintf(sub->txident, sizeof(sub->txident), "%08lx", ast_random());
/*stnrcpy(sub->txident, txident, sizeof(sub->txident) - 1);*/
sub->cxmode = MGCP_CX_INACTIVE;
sub->nat = nat;
sub->next = e->sub;
e->sub = sub;
} else {
/* XXX Should find a way to clean up our memory */
ast_log(LOG_WARNING, "Out of memory allocating subchannel\n");
return NULL;
}
}
/* Make out subs a circular linked list so we can always sping through the whole bunch */
sub = e->sub;
/* find the end of the list */
while(sub->next){
sub = sub->next;
}
/* set the last sub->next to the first sub */
sub->next = e->sub;
e->next = gw->endpoints;
gw->endpoints = e;
}
}
} else if (!strcasecmp(v->name, "trunk") ||
!strcasecmp(v->name, "line")) {
/* locate existing endpoint */
e = gw->endpoints;
while (e) {
if (!strcasecmp(v->value, e->name)) {
/* endpoint already exists */
e->delme = 0;
ep_reload = 1;
break;
}
e = e->next;
}
if (!e) {
e = ast_calloc(1, sizeof(*e));
ep_reload = 0;
}
if (e) {
if (!ep_reload) {
ast_mutex_init(&e->lock);
ast_mutex_init(&e->rqnt_queue_lock);
ast_mutex_init(&e->cmd_queue_lock);
ast_copy_string(e->name, v->value, sizeof(e->name));
e->needaudit = 1;
}
/* XXX Should we really check for uniqueness?? XXX */
ast_copy_string(e->accountcode, accountcode, sizeof(e->accountcode));
ast_copy_string(e->context, context, sizeof(e->context));
ast_copy_string(e->cid_num, cid_num, sizeof(e->cid_num));
ast_copy_string(e->cid_name, cid_name, sizeof(e->cid_name));
ast_copy_string(e->language, language, sizeof(e->language));
ast_copy_string(e->musicclass, musicclass, sizeof(e->musicclass));
ast_copy_string(e->mailbox, mailbox, sizeof(e->mailbox));
ast_copy_string(e->parkinglot, parkinglot, sizeof(e->parkinglot));
if (!ast_strlen_zero(mailbox)) {
ast_verb(3, "Setting mailbox '%s' on %s@%s\n", mailbox, gw->name, e->name);
}
if (!ep_reload) {
/* XXX potential issue due to reload */
e->msgstate = -1;
e->parent = gw;
}
e->amaflags = amaflags;
e->capability = capability;
e->dtmfmode = dtmfmode;
e->adsi = adsi;
if (!strcasecmp(v->name, "trunk"))
e->type = TYPE_TRUNK;
else
e->type = TYPE_LINE;
e->immediate = immediate;
e->callgroup=cur_callergroup;
e->pickupgroup=cur_pickupgroup;
e->callreturn = callreturn;
e->cancallforward = cancallforward;
e->directmedia = directmedia;
e->singlepath = singlepath;
e->callwaiting = callwaiting;
e->hascallwaiting = callwaiting;
e->slowsequence = slowsequence;
e->transfer = transfer;
e->threewaycalling = threewaycalling;
if (!ep_reload) {
e->onhooktime = time(NULL);
/* ASSUME we're onhook */
e->hookstate = MGCP_ONHOOK;
snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", ast_random());
}
for (i = 0, sub = NULL; i < MAX_SUBS; i++) {
if (!ep_reload) {
sub = ast_calloc(1, sizeof(*sub));
} else {
if (!sub)
sub = e->sub;
else
sub = sub->next;
}
if (sub) {
if (!ep_reload) {
ast_verb(3, "Allocating subchannel '%d' on %s@%s\n", i, e->name, gw->name);
ast_mutex_init(&sub->lock);
ast_mutex_init(&sub->cx_queue_lock);
ast_copy_string(sub->magic, MGCP_SUBCHANNEL_MAGIC, sizeof(sub->magic));
sub->parent = e;
sub->id = i;
snprintf(sub->txident, sizeof(sub->txident), "%08lx", ast_random());
sub->cxmode = MGCP_CX_INACTIVE;
sub->next = e->sub;
e->sub = sub;
}
sub->nat = nat;
} else {
/* XXX Should find a way to clean up our memory */
ast_log(LOG_WARNING, "Out of memory allocating subchannel\n");
return NULL;
}
}
if (!ep_reload) {
/* Make out subs a circular linked list so we can always sping through the whole bunch */
sub = e->sub;
/* find the end of the list */
while (sub->next) {
sub = sub->next;
}
/* set the last sub->next to the first sub */
sub->next = e->sub;
e->next = gw->endpoints;
gw->endpoints = e;
}
}
} else
ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
v = v->next;
}
}
if (!ntohl(gw->addr.sin_addr.s_addr) && !gw->dynamic) {
ast_log(LOG_WARNING, "Gateway '%s' lacks IP address and isn't dynamic\n", gw->name);
if (!gw_reload) {
ast_mutex_destroy(&gw->msgs_lock);
ast_free(gw);
}
return NULL;
}
gw->defaddr.sin_family = AF_INET;
gw->addr.sin_family = AF_INET;
if (gw->defaddr.sin_addr.s_addr && !ntohs(gw->defaddr.sin_port))
gw->defaddr.sin_port = htons(DEFAULT_MGCP_GW_PORT);
if (gw->addr.sin_addr.s_addr && !ntohs(gw->addr.sin_port))
gw->addr.sin_port = htons(DEFAULT_MGCP_GW_PORT);
if (gw->addr.sin_addr.s_addr)
if (ast_ouraddrfor(&gw->addr.sin_addr, &gw->ourip))
memcpy(&gw->ourip, &__ourip, sizeof(gw->ourip));
return (gw_reload ? NULL : gw);
}
| static char* control2str | ( | int | ind | ) | [static] |
Definition at line 1394 of file chan_mgcp.c.
References AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_OFFHOOK, AST_CONTROL_OPTION, AST_CONTROL_RADIO_KEY, AST_CONTROL_RADIO_UNKEY, AST_CONTROL_RING, AST_CONTROL_RINGING, AST_CONTROL_TAKEOFFHOOK, and AST_CONTROL_WINK.
Referenced by mgcp_indicate().
{
switch (ind) {
case AST_CONTROL_HANGUP:
return "Other end has hungup";
case AST_CONTROL_RING:
return "Local ring";
case AST_CONTROL_RINGING:
return "Remote end is ringing";
case AST_CONTROL_ANSWER:
return "Remote end has answered";
case AST_CONTROL_BUSY:
return "Remote end is busy";
case AST_CONTROL_TAKEOFFHOOK:
return "Make it go off hook";
case AST_CONTROL_OFFHOOK:
return "Line is off hook";
case AST_CONTROL_CONGESTION:
return "Congestion (circuits busy)";
case AST_CONTROL_FLASH:
return "Flash hook";
case AST_CONTROL_WINK:
return "Wink";
case AST_CONTROL_OPTION:
return "Set a low-level option";
case AST_CONTROL_RADIO_KEY:
return "Key Radio";
case AST_CONTROL_RADIO_UNKEY:
return "Un-Key Radio";
}
return "UNKNOWN";
}
| static void destroy_endpoint | ( | struct mgcp_endpoint * | e | ) | [static] |
Definition at line 3980 of file chan_mgcp.c.
References ast_dsp_free(), ast_event_unsubscribe(), ast_free, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_rtp_destroy(), ast_strlen_zero(), mgcp_endpoint::cmd_queue_lock, mgcp_subchannel::cxident, mgcp_endpoint::dsp, dump_cmd_queues(), dump_queue(), mgcp_endpoint::lock, mgcp_subchannel::lock, mgcp_subchannel::magic, MAX_SUBS, mgcp_queue_hangup(), mgcp_endpoint::mwi_event_sub, mgcp_subchannel::next, mgcp_endpoint::parent, mgcp_endpoint::rqnt_queue_lock, mgcp_subchannel::rtp, s, mgcp_endpoint::sub, and transmit_connection_del().
Referenced by prune_gateways().
{
struct mgcp_subchannel *sub = e->sub->next, *s;
int i;
for (i = 0; i < MAX_SUBS; i++) {
ast_mutex_lock(&sub->lock);
if (!ast_strlen_zero(sub->cxident)) {
transmit_connection_del(sub);
}
if (sub->rtp) {
ast_rtp_destroy(sub->rtp);
sub->rtp = NULL;
}
memset(sub->magic, 0, sizeof(sub->magic));
mgcp_queue_hangup(sub);
dump_cmd_queues(NULL, sub);
ast_mutex_unlock(&sub->lock);
sub = sub->next;
}
if (e->dsp) {
ast_dsp_free(e->dsp);
}
dump_queue(e->parent, e);
dump_cmd_queues(e, NULL);
sub = e->sub;
for (i = 0; (i < MAX_SUBS) && sub; i++) {
s = sub;
sub = sub->next;
ast_mutex_destroy(&s->lock);
ast_mutex_destroy(&s->cx_queue_lock);
ast_free(s);
}
if (e->mwi_event_sub)
ast_event_unsubscribe(e->mwi_event_sub);
ast_mutex_destroy(&e->lock);
ast_mutex_destroy(&e->rqnt_queue_lock);
ast_mutex_destroy(&e->cmd_queue_lock);
ast_free(e);
}
| static void destroy_gateway | ( | struct mgcp_gateway * | g | ) | [static] |
Definition at line 4026 of file chan_mgcp.c.
References ast_free, ast_free_ha(), dump_queue(), and mgcp_gateway::ha.
Referenced by prune_gateways().
{
if (g->ha)
ast_free_ha(g->ha);
dump_queue(g, NULL);
ast_free(g);
}
| static void* do_monitor | ( | void * | data | ) | [static] |
Definition at line 3386 of file chan_mgcp.c.
References ast_io_add(), AST_IO_IN, ast_io_wait(), ast_mutex_lock(), ast_mutex_unlock(), ast_sched_runq(), ast_sched_wait(), ast_verb, mgcp_gateway::endpoints, gateways, has_voicemail(), MGCP_ONHOOK, mgcp_reload_lock, mgcp_reloading, mgcpsock_read(), monlock, netlock, reload_config(), transmit_notify_request(), and TYPE_LINE.
Referenced by restart_monitor().
{
int res;
int reloading;
/*struct mgcp_gateway *g;*/
/*struct mgcp_endpoint *e;*/
/*time_t thispass = 0, lastpass = 0;*/
/* Add an I/O event to our UDP socket */
if (mgcpsock > -1)
mgcpsock_read_id = ast_io_add(io, mgcpsock, mgcpsock_read, AST_IO_IN, NULL);
/* This thread monitors all the frame relay interfaces which are not yet in use
(and thus do not have a separate thread) indefinitely */
/* From here on out, we die whenever asked */
for(;;) {
/* Check for a reload request */
ast_mutex_lock(&mgcp_reload_lock);
reloading = mgcp_reloading;
mgcp_reloading = 0;
ast_mutex_unlock(&mgcp_reload_lock);
if (reloading) {
ast_verb(1, "Reloading MGCP\n");
reload_config(1);
/* Add an I/O event to our UDP socket */
if (mgcpsock > -1 && !mgcpsock_read_id) {
mgcpsock_read_id = ast_io_add(io, mgcpsock, mgcpsock_read, AST_IO_IN, NULL);
}
}
/* Check for interfaces needing to be killed */
/* Don't let anybody kill us right away. Nobody should lock the interface list
and wait for the monitor list, but the other way around is okay. */
ast_mutex_lock(&monlock);
/* Lock the network interface */
ast_mutex_lock(&netlock);
#if 0
/* XXX THIS IS COMPLETELY HOSED */
/* The gateway goes into a state of panic */
/* If the vmwi indicator is sent while it is reseting interfaces */
lastpass = thispass;
thispass = time(NULL);
g = gateways;
while(g) {
if (thispass != lastpass) {
e = g->endpoints;
while(e) {
if (e->type == TYPE_LINE) {
res = has_voicemail(e);
if ((e->msgstate != res) && (e->hookstate == MGCP_ONHOOK) && (!e->rtp)){
if (res) {
transmit_notify_request(e, "L/vmwi(+)");
} else {
transmit_notify_request(e, "L/vmwi(-)");
}
e->msgstate = res;
e->onhooktime = thispass;
}
}
e = e->next;
}
}
g = g->next;
}
#endif
/* Okay, now that we know what to do, release the network lock */
ast_mutex_unlock(&netlock);
/* And from now on, we're okay to be killed, so release the monitor lock as well */
ast_mutex_unlock(&monlock);
pthread_testcancel();
/* Wait for sched or io */
res = ast_sched_wait(sched);
/* copied from chan_sip.c */
if ((res < 0) || (res > 1000))
res = 1000;
res = ast_io_wait(io, res);
ast_mutex_lock(&monlock);
if (res >= 0)
ast_sched_runq(sched);
ast_mutex_unlock(&monlock);
}
/* Never reached */
return NULL;
}
| static void dump_cmd_queues | ( | struct mgcp_endpoint * | p, |
| struct mgcp_subchannel * | sub | ||
| ) | [static] |
dump_cmd_queues: (SC:) cleanup pending commands
Definition at line 2391 of file chan_mgcp.c.
References ast_free, ast_mutex_lock(), ast_mutex_unlock(), mgcp_endpoint::cmd_queue, mgcp_endpoint::cmd_queue_lock, mgcp_subchannel::cx_queue, mgcp_subchannel::cx_queue_lock, mgcp_subchannel::next, mgcp_request::next, mgcp_endpoint::rqnt_queue, mgcp_endpoint::rqnt_queue_lock, and mgcp_endpoint::sub.
Referenced by destroy_endpoint(), handle_request(), handle_response(), and unalloc_sub().
{
struct mgcp_request *t, *q;
if (p) {
ast_mutex_lock(&p->rqnt_queue_lock);
for (q = p->rqnt_queue; q; t = q->next, ast_free(q), q=t);
p->rqnt_queue = NULL;
ast_mutex_unlock(&p->rqnt_queue_lock);
ast_mutex_lock(&p->cmd_queue_lock);
for (q = p->cmd_queue; q; t = q->next, ast_free(q), q=t);
p->cmd_queue = NULL;
ast_mutex_unlock(&p->cmd_queue_lock);
ast_mutex_lock(&p->sub->cx_queue_lock);
for (q = p->sub->cx_queue; q; t = q->next, ast_free(q), q=t);
p->sub->cx_queue = NULL;
ast_mutex_unlock(&p->sub->cx_queue_lock);
ast_mutex_lock(&p->sub->next->cx_queue_lock);
for (q = p->sub->next->cx_queue; q; t = q->next, ast_free(q), q=t);
p->sub->next->cx_queue = NULL;
ast_mutex_unlock(&p->sub->next->cx_queue_lock);
} else if (sub) {
ast_mutex_lock(&sub->cx_queue_lock);
for (q = sub->cx_queue; q; t = q->next, ast_free(q), q=t);
sub->cx_queue = NULL;
ast_mutex_unlock(&sub->cx_queue_lock);
}
}
| static void dump_queue | ( | struct mgcp_gateway * | gw, |
| struct mgcp_endpoint * | p | ||
| ) | [static] |
Definition at line 555 of file chan_mgcp.c.
References ast_free, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), LOG_NOTICE, mgcp_gateway::msgs, mgcp_gateway::msgs_lock, mgcp_gateway::name, and mgcp_message::next.
Referenced by destroy_endpoint(), destroy_gateway(), and handle_request().
{
struct mgcp_message *cur, *q = NULL, *w, *prev;
ast_mutex_lock(&gw->msgs_lock);
prev = NULL, cur = gw->msgs;
while (cur) {
if (!p || cur->owner_ep == p) {
if (prev)
prev->next = cur->next;
else
gw->msgs = cur->next;
ast_log(LOG_NOTICE, "Removing message from %s transaction %u\n",
gw->name, cur->seqno);
w = cur;
cur = cur->next;
if (q) {
w->next = q;
} else {
w->next = NULL;
}
q = w;
} else {
prev = cur, cur=cur->next;
}
}
ast_mutex_unlock(&gw->msgs_lock);
while (q) {
cur = q;
q = q->next;
ast_free(cur);
}
}
| static int find_and_retrans | ( | struct mgcp_subchannel * | sub, |
| struct mgcp_request * | req | ||
| ) | [static] |
Definition at line 3265 of file chan_mgcp.c.
References ast_free, mgcp_request::identifier, mgcp_response::next, mgcp_endpoint::parent, mgcp_subchannel::parent, resend_response(), RESPONSE_TIMEOUT, and mgcp_gateway::responses.
Referenced by mgcpsock_read().
{
int seqno=0;
time_t now;
struct mgcp_response *prev = NULL, *cur, *next, *answer=NULL;
time(&now);
if (sscanf(req->identifier, "%30d", &seqno) != 1)
seqno = 0;
cur = sub->parent->parent->responses;
while(cur) {
next = cur->next;
if (now - cur->whensent > RESPONSE_TIMEOUT) {
/* Delete this entry */
if (prev)
prev->next = next;
else
sub->parent->parent->responses = next;
ast_free(cur);
} else {
if (seqno == cur->seqno)
answer = cur;
prev = cur;
}
cur = next;
}
if (answer) {
resend_response(sub, answer);
return 1;
}
return 0;
}
| static struct mgcp_request* find_command | ( | struct mgcp_endpoint * | p, |
| struct mgcp_subchannel * | sub, | ||
| struct mgcp_request ** | queue, | ||
| ast_mutex_t * | l, | ||
| int | ident | ||
| ) | [static, read] |
find_command: (SC:) remove command transaction from queue
Definition at line 2425 of file chan_mgcp.c.
References mgcp_gateway::addr, ast_inet_ntoa(), ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), mgcp_postrequest(), mgcp_request::next, and mgcp_endpoint::parent.
Referenced by handle_response().
{
struct mgcp_request *prev, *req;
ast_mutex_lock(l);
for (prev = NULL, req = *queue; req; prev = req, req = req->next) {
if (req->trid == ident) {
/* remove from queue */
if (!prev)
*queue = req->next;
else
prev->next = req->next;
/* send next pending command */
if (*queue) {
if (mgcpdebug) {
ast_verbose("Posting Queued Request:\n%s to %s:%d\n", (*queue)->data,
ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
}
mgcp_postrequest(p, sub, (*queue)->data, (*queue)->len, (*queue)->trid);
}
break;
}
}
ast_mutex_unlock(l);
return req;
}
| static struct mgcp_subchannel* find_subchannel_and_lock | ( | char * | name, |
| int | msgid, | ||
| struct sockaddr_in * | sin | ||
| ) | [static, read] |
Definition at line 1628 of file chan_mgcp.c.
References __ourip, mgcp_gateway::addr, ast_copy_string(), ast_debug, ast_inet_ntoa(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_ouraddrfor(), ast_verb, mgcp_gateway::defaddr, mgcp_gateway::dynamic, mgcp_gateway::endpoints, gatelock, gateways, mgcp_subchannel::id, mgcp_subchannel::lock, LOG_NOTICE, mgcp_endpoint::name, mgcp_gateway::name, mgcp_endpoint::next, mgcp_subchannel::next, mgcp_gateway::next, mgcp_gateway::ourip, and mgcp_endpoint::sub.
Referenced by mgcp_request(), and mgcpsock_read().
{
struct mgcp_endpoint *p = NULL;
struct mgcp_subchannel *sub = NULL;
struct mgcp_gateway *g;
char tmp[256] = "";
char *at = NULL, *c;
int found = 0;
if (name) {
ast_copy_string(tmp, name, sizeof(tmp));
at = strchr(tmp, '@');
if (!at) {
ast_log(LOG_NOTICE, "Endpoint '%s' has no at sign!\n", name);
return NULL;
}
*at++ = '\0';
}
ast_mutex_lock(&gatelock);
if (at && (at[0] == '[')) {
at++;
c = strrchr(at, ']');
if (c)
*c = '\0';
}
g = gateways;
while(g) {
if ((!name || !strcasecmp(g->name, at)) &&
(sin || g->addr.sin_addr.s_addr || g->defaddr.sin_addr.s_addr)) {
/* Found the gateway. If it's dynamic, save it's address -- now for the endpoint */
if (sin && g->dynamic && name) {
if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
(g->addr.sin_port != sin->sin_port)) {
memcpy(&g->addr, sin, sizeof(g->addr));
if (ast_ouraddrfor(&g->addr.sin_addr, &g->ourip))
memcpy(&g->ourip, &__ourip, sizeof(g->ourip));
ast_verb(3, "Registered MGCP gateway '%s' at %s port %d\n", g->name, ast_inet_ntoa(g->addr.sin_addr), ntohs(g->addr.sin_port));
}
}
/* not dynamic, check if the name matches */
else if (name) {
if (strcasecmp(g->name, at)) {
g = g->next;
continue;
}
}
/* not dynamic, no name, check if the addr matches */
else if (!name && sin) {
if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
(g->addr.sin_port != sin->sin_port)) {
g = g->next;
continue;
}
} else {
g = g->next;
continue;
}
/* SC */
p = g->endpoints;
while(p) {
ast_debug(1, "Searching on %s@%s for subchannel\n",
p->name, g->name);
if (msgid) {
#if 0 /* new transport mech */
sub = p->sub;
do {
ast_debug(1, "Searching on %s@%s-%d for subchannel with lastout: %d\n",
p->name, g->name, sub->id, msgid);
if (sub->lastout == msgid) {
ast_debug(1, "Found subchannel sub%d to handle request %d sub->lastout: %d\n",
sub->id, msgid, sub->lastout);
found = 1;
break;
}
sub = sub->next;
} while (sub != p->sub);
if (found) {
break;
}
#endif
/* SC */
sub = p->sub;
found = 1;
/* SC */
break;
} else if (name && !strcasecmp(p->name, tmp)) {
ast_debug(1, "Coundn't determine subchannel, assuming current master %s@%s-%d\n",
p->name, g->name, p->sub->id);
sub = p->sub;
found = 1;
break;
}
p = p->next;
}
if (sub && found) {
ast_mutex_lock(&sub->lock);
break;
}
}
g = g->next;
}
ast_mutex_unlock(&gatelock);
if (!sub) {
if (name) {
if (g)
ast_log(LOG_NOTICE, "Endpoint '%s' not found on gateway '%s'\n", tmp, at);
else
ast_log(LOG_NOTICE, "Gateway '%s' (and thus its endpoint '%s') does not exist\n", at, tmp);
}
}
return sub;
}
| static char* get_csv | ( | char * | c, |
| int * | len, | ||
| char ** | next | ||
| ) | [static] |
get_csv: (SC:) get comma separated value
Definition at line 1607 of file chan_mgcp.c.
References s.
Referenced by handle_response().
| static char* get_header | ( | struct mgcp_request * | req, |
| char * | name | ||
| ) | [static] |
Definition at line 1600 of file chan_mgcp.c.
References __get_header().
Referenced by handle_request(), and handle_response().
{
int start = 0;
return __get_header(req, name, &start);
}
| static char* get_sdp | ( | struct mgcp_request * | req, |
| char * | name | ||
| ) | [static] |
Definition at line 1552 of file chan_mgcp.c.
References get_sdp_by_line(), len(), mgcp_request::line, and mgcp_request::lines.
Referenced by process_sdp().
| static char* get_sdp_by_line | ( | char * | line, |
| char * | name, | ||
| int | nameLen | ||
| ) | [static] |
Definition at line 1542 of file chan_mgcp.c.
Referenced by get_sdp(), and get_sdp_iterate().
{
if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') {
char* r = line + nameLen + 1;
while (*r && (*r < 33)) ++r;
return r;
}
return "";
}
| static char* get_sdp_iterate | ( | int * | iterator, |
| struct mgcp_request * | req, | ||
| char * | name | ||
| ) | [static] |
Definition at line 1570 of file chan_mgcp.c.
References get_sdp_by_line(), len(), and mgcp_request::line.
Referenced by process_sdp().
| static void handle_hd_hf | ( | struct mgcp_subchannel * | sub, |
| char * | ev | ||
| ) | [static] |
Definition at line 2941 of file chan_mgcp.c.
References ast_bridged_channel(), AST_CONTROL_ANSWER, AST_CONTROL_UNHOLD, ast_hangup(), ast_log(), ast_pthread_create_detached, ast_queue_control(), AST_STATE_DOWN, AST_STATE_RING, mgcp_subchannel::cxmode, errno, has_voicemail(), mgcp_endpoint::hookstate, mgcp_endpoint::immediate, LOG_WARNING, MGCP_CX_SENDRECV, mgcp_new(), MGCP_OFFHOOK, mgcp_queue_control(), mgcp_ss(), mgcp_gateway::name, mgcp_endpoint::name, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_subchannel::rtp, start_rtp(), transmit_modify_request(), and transmit_notify_request().
Referenced by handle_request().
{
struct mgcp_endpoint *p = sub->parent;
struct ast_channel *c;
pthread_t t;
/* Off hook / answer */
if (sub->outgoing) {
/* Answered */
if (sub->owner) {
if (ast_bridged_channel(sub->owner))
ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
sub->cxmode = MGCP_CX_SENDRECV;
if (!sub->rtp) {
start_rtp(sub);
} else {
transmit_modify_request(sub);
}
/*transmit_notify_request(sub, "aw");*/
transmit_notify_request(sub, "");
mgcp_queue_control(sub, AST_CONTROL_ANSWER);
}
} else {
/* Start switch */
/*sub->cxmode = MGCP_CX_SENDRECV;*/
if (!sub->owner) {
if (!sub->rtp) {
start_rtp(sub);
} else {
transmit_modify_request(sub);
}
if (p->immediate) {
/* The channel is immediately up. Start right away */
#ifdef DLINK_BUGGY_FIRMWARE
transmit_notify_request(sub, "rt");
#else
transmit_notify_request(sub, "G/rt");
#endif
c = mgcp_new(sub, AST_STATE_RING);
if (!c) {
ast_log(LOG_WARNING, "Unable to start PBX on channel %s@%s\n", p->name, p->parent->name);
transmit_notify_request(sub, "G/cg");
ast_hangup(c);
}
} else {
if (has_voicemail(p)) {
transmit_notify_request(sub, "L/sl");
} else {
transmit_notify_request(sub, "L/dl");
}
c = mgcp_new(sub, AST_STATE_DOWN);
if (c) {
if (ast_pthread_create_detached(&t, NULL, mgcp_ss, c)) {
ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
ast_hangup(c);
}
} else {
ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", p->name, p->parent->name);
}
}
} else {
if (p->hookstate == MGCP_OFFHOOK) {
ast_log(LOG_WARNING, "Off hook, but already have owner on %s@%s\n", p->name, p->parent->name);
} else {
ast_log(LOG_WARNING, "On hook, but already have owner on %s@%s\n", p->name, p->parent->name);
ast_log(LOG_WARNING, "If we're onhook why are we here trying to handle a hd or hf?\n");
}
if (ast_bridged_channel(sub->owner))
ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
sub->cxmode = MGCP_CX_SENDRECV;
if (!sub->rtp) {
start_rtp(sub);
} else {
transmit_modify_request(sub);
}
/*transmit_notify_request(sub, "aw");*/
transmit_notify_request(sub, "");
/*ast_queue_control(sub->owner, AST_CONTROL_ANSWER);*/
}
}
}
| static char* handle_mgcp_audit_endpoint | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 1077 of file chan_mgcp.c.
References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, mgcp_gateway::endpoints, ast_cli_args::fd, gatelock, gateways, me, mgcp_endpoint::name, mgcp_gateway::name, mgcp_gateway::next, mgcp_endpoint::next, transmit_audit_endpoint(), and ast_cli_entry::usage.
{
struct mgcp_gateway *mg;
struct mgcp_endpoint *me;
int found = 0;
char *ename,*gname, *c;
switch (cmd) {
case CLI_INIT:
e->command = "mgcp audit endpoint";
e->usage =
"Usage: mgcp audit endpoint <endpointid>\n"
" Lists the capabilities of an endpoint in the MGCP (Media Gateway Control Protocol) subsystem.\n"
" mgcp debug MUST be on to see the results of this command.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (!mgcpdebug) {
return CLI_SHOWUSAGE;
}
if (a->argc != 4)
return CLI_SHOWUSAGE;
/* split the name into parts by null */
ename = a->argv[3];
gname = ename;
while (*gname) {
if (*gname == '@') {
*gname = 0;
gname++;
break;
}
gname++;
}
if (gname[0] == '[')
gname++;
if ((c = strrchr(gname, ']')))
*c = '\0';
ast_mutex_lock(&gatelock);
mg = gateways;
while(mg) {
if (!strcasecmp(mg->name, gname)) {
me = mg->endpoints;
while(me) {
if (!strcasecmp(me->name, ename)) {
found = 1;
transmit_audit_endpoint(me);
break;
}
me = me->next;
}
if (found) {
break;
}
}
mg = mg->next;
}
if (!found) {
ast_cli(a->fd, " << Could not find endpoint >> ");
}
ast_mutex_unlock(&gatelock);
return CLI_SUCCESS;
}
| static char* handle_mgcp_set_debug | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 1142 of file chan_mgcp.c.
References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.
{
switch (cmd) {
case CLI_INIT:
e->command = "mgcp set debug {on|off}";
e->usage =
"Usage: mgcp set debug {on|off}\n"
" Enables/Disables dumping of MGCP packets for debugging purposes\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != e->args)
return CLI_SHOWUSAGE;
if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
mgcpdebug = 1;
ast_cli(a->fd, "MGCP Debugging Enabled\n");
} else if (!strncasecmp(a->argv[3], "off", 3)) {
mgcpdebug = 0;
ast_cli(a->fd, "MGCP Debugging Disabled\n");
} else {
return CLI_SHOWUSAGE;
}
return CLI_SUCCESS;
}
| static char* handle_mgcp_show_endpoints | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 1037 of file chan_mgcp.c.
References mgcp_gateway::addr, ast_cli_args::argc, ast_cli(), ast_inet_ntoa(), ast_mutex_lock(), ast_mutex_unlock(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, mgcp_endpoint::context, mgcp_gateway::defaddr, mgcp_gateway::dynamic, mgcp_gateway::endpoints, ast_cli_args::fd, gatelock, gateways, me, mgcp_endpoint::name, mgcp_gateway::name, mgcp_gateway::next, mgcp_endpoint::next, mgcp_subchannel::owner, mgcp_endpoint::sub, ast_cli_entry::usage, and mgcp_gateway::wcardep.
{
struct mgcp_gateway *mg;
struct mgcp_endpoint *me;
int hasendpoints = 0;
switch (cmd) {
case CLI_INIT:
e->command = "mgcp show endpoints";
e->usage =
"Usage: mgcp show endpoints\n"
" Lists all endpoints known to the MGCP (Media Gateway Control Protocol) subsystem.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 3)
return CLI_SHOWUSAGE;
ast_mutex_lock(&gatelock);
mg = gateways;
while(mg) {
me = mg->endpoints;
ast_cli(a->fd, "Gateway '%s' at %s (%s)\n", mg->name, mg->addr.sin_addr.s_addr ? ast_inet_ntoa(mg->addr.sin_addr) : ast_inet_ntoa(mg->defaddr.sin_addr), mg->dynamic ? "Dynamic" : "Static");
while(me) {
/* Don't show wilcard endpoint */
if (strcmp(me->name, mg->wcardep) != 0)
ast_cli(a->fd, " -- '%s@%s in '%s' is %s\n", me->name, mg->name, me->context, me->sub->owner ? "active" : "idle");
hasendpoints = 1;
me = me->next;
}
if (!hasendpoints) {
ast_cli(a->fd, " << No Endpoints Defined >> ");
}
mg = mg->next;
}
ast_mutex_unlock(&gatelock);
return CLI_SUCCESS;
}
| static int handle_request | ( | struct mgcp_subchannel * | sub, |
| struct mgcp_request * | req, | ||
| struct sockaddr_in * | sin | ||
| ) | [static] |
Definition at line 3023 of file chan_mgcp.c.
References ast_channel::_state, mgcp_subchannel::alreadygone, ast_bridged_channel(), AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, ast_debug, AST_FRAME_DTMF, ast_inet_ntoa(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_control(), AST_STATE_DOWN, AST_STATE_UP, ast_verb, ast_verbose(), attempt_transfer(), mgcp_endpoint::callwaiting, mgcp_endpoint::curtone, mgcp_subchannel::cxmode, mgcp_endpoint::dtmf_buf, dump_cmd_queues(), dump_queue(), mgcp_gateway::endpoints, ast_frame::frametype, get_header(), handle_hd_hf(), has_voicemail(), mgcp_endpoint::hascallwaiting, mgcp_endpoint::hidecallerid, mgcp_endpoint::hookstate, mgcp_subchannel::id, mgcp_subchannel::lock, LOG_NOTICE, LOG_WARNING, MGCP_CX_CONF, MGCP_CX_MUTE, MGCP_CX_RECVONLY, MGCP_CX_SENDRECV, MGCP_OFFHOOK, MGCP_ONHOOK, mgcp_queue_frame(), mgcp_queue_hangup(), mgcp_gateway::name, mgcp_endpoint::name, mgcp_endpoint::next, mgcp_subchannel::next, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_subchannel::rtp, s, ast_frame::src, mgcp_endpoint::sub, ast_frame::subclass, mgcp_endpoint::threewaycalling, mgcp_endpoint::transfer, transmit_audit_endpoint(), transmit_connection_del(), transmit_modify_request(), transmit_notify_request(), transmit_response(), mgcp_request::verb, and mgcp_gateway::wcardep.
Referenced by mgcpsock_read().
{
char *ev, *s;
struct ast_frame f = { 0, };
struct mgcp_endpoint *p = sub->parent;
struct mgcp_gateway *g = NULL;
int res;
if (mgcpdebug) {
ast_verbose("Handling request '%s' on %s@%s\n", req->verb, p->name, p->parent->name);
}
/* Clear out potential response */
if (!strcasecmp(req->verb, "RSIP")) {
/* Test if this RSIP request is just a keepalive */
if(!strcasecmp( get_header(req, "RM"), "X-keepalive")) {
ast_verb(3, "Received keepalive request from %s@%s\n", p->name, p->parent->name);
transmit_response(sub, "200", req, "OK");
} else {
dump_queue(p->parent, p);
dump_cmd_queues(p, NULL);
if ((strcmp(p->name, p->parent->wcardep) != 0)) {
ast_verb(3, "Resetting interface %s@%s\n", p->name, p->parent->name);
}
/* For RSIP on wildcard we reset all endpoints */
if (!strcmp(p->name, p->parent->wcardep)) {
/* Reset all endpoints */
struct mgcp_endpoint *tmp_ep;
g = p->parent;
tmp_ep = g->endpoints;
while (tmp_ep) {
/*if ((strcmp(tmp_ep->name, "*") != 0) && (strcmp(tmp_ep->name, "aaln/" "*") != 0)) {*/
if (strcmp(tmp_ep->name, g->wcardep) != 0) {
struct mgcp_subchannel *tmp_sub, *first_sub;
ast_verb(3, "Resetting interface %s@%s\n", tmp_ep->name, p->parent->name);
first_sub = tmp_ep->sub;
tmp_sub = tmp_ep->sub;
while (tmp_sub) {
mgcp_queue_hangup(tmp_sub);
tmp_sub = tmp_sub->next;
if (tmp_sub == first_sub)
break;
}
}
tmp_ep = tmp_ep->next;
}
} else if (sub->owner) {
mgcp_queue_hangup(sub);
}
transmit_response(sub, "200", req, "OK");
/* We dont send NTFY or AUEP to wildcard ep */
if (strcmp(p->name, p->parent->wcardep) != 0) {
transmit_notify_request(sub, "");
/* Audit endpoint.
Idea is to prevent lost lines due to race conditions
*/
transmit_audit_endpoint(p);
}
}
} else if (!strcasecmp(req->verb, "NTFY")) {
/* Acknowledge and be sure we keep looking for the same things */
transmit_response(sub, "200", req, "OK");
/* Notified of an event */
ev = get_header(req, "O");
s = strchr(ev, '/');
if (s) ev = s + 1;
ast_debug(1, "Endpoint '%s@%s-%d' observed '%s'\n", p->name, p->parent->name, sub->id, ev);
/* Keep looking for events unless this was a hangup */
if (strcasecmp(ev, "hu") && strcasecmp(ev, "hd") && strcasecmp(ev, "ping")) {
transmit_notify_request(sub, p->curtone);
}
if (!strcasecmp(ev, "hd")) {
p->hookstate = MGCP_OFFHOOK;
sub->cxmode = MGCP_CX_SENDRECV;
handle_hd_hf(sub, ev);
} else if (!strcasecmp(ev, "hf")) {
/* We can assume we are offhook if we received a hookflash */
/* First let's just do call wait and ignore threeway */
/* We're currently in charge */
if (p->hookstate != MGCP_OFFHOOK) {
/* Cisco c7940 sends hf even if the phone is onhook */
/* Thanks to point on IRC for pointing this out */
return -1;
}
/* do not let * conference two down channels */
if (sub->owner && sub->owner->_state == AST_STATE_DOWN && !sub->next->owner)
return -1;
if (p->callwaiting || p->transfer || p->threewaycalling) {
ast_verb(3, "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name);
p->sub = p->sub->next;
/* transfer control to our next subchannel */
if (!sub->next->owner) {
/* plave the first call on hold and start up a new call */
sub->cxmode = MGCP_CX_MUTE;
ast_verb(3, "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
transmit_modify_request(sub);
if (sub->owner && ast_bridged_channel(sub->owner))
ast_queue_control(sub->owner, AST_CONTROL_HOLD);
sub->next->cxmode = MGCP_CX_RECVONLY;
handle_hd_hf(sub->next, ev);
} else if (sub->owner && sub->next->owner) {
/* We've got two active calls lets decide whether or not to conference or just flip flop */
if ((!sub->outgoing) && (!sub->next->outgoing)) {
/* We made both calls lets conferenct */
ast_verb(3, "MGCP Conferencing %d and %d on %s@%s\n",
sub->id, sub->next->id, p->name, p->parent->name);
sub->cxmode = MGCP_CX_CONF;
sub->next->cxmode = MGCP_CX_CONF;
if (ast_bridged_channel(sub->next->owner))
ast_queue_control(sub->next->owner, AST_CONTROL_UNHOLD);
transmit_modify_request(sub);
transmit_modify_request(sub->next);
} else {
/* Let's flipflop between calls */
/* XXX Need to check for state up ??? */
/* XXX Need a way to indicate the current call, or maybe the call that's waiting */
ast_verb(3, "We didn't make one of the calls FLIPFLOP %d and %d on %s@%s\n",
sub->id, sub->next->id, p->name, p->parent->name);
sub->cxmode = MGCP_CX_MUTE;
ast_verb(3, "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
transmit_modify_request(sub);
if (ast_bridged_channel(sub->owner))
ast_queue_control(sub->owner, AST_CONTROL_HOLD);
if (ast_bridged_channel(sub->next->owner))
ast_queue_control(sub->next->owner, AST_CONTROL_HOLD);
handle_hd_hf(sub->next, ev);
}
} else {
/* We've most likely lost one of our calls find an active call and bring it up */
if (sub->owner) {
p->sub = sub;
} else if (sub->next->owner) {
p->sub = sub->next;
} else {
/* We seem to have lost both our calls */
/* XXX - What do we do now? */
return -1;
}
if (ast_bridged_channel(p->sub->owner))
ast_queue_control(p->sub->owner, AST_CONTROL_UNHOLD);
p->sub->cxmode = MGCP_CX_SENDRECV;
transmit_modify_request(p->sub);
}
} else {
ast_log(LOG_WARNING, "Callwaiting, call transfer or threeway calling not enabled on endpoint %s@%s\n",
p->name, p->parent->name);
}
} else if (!strcasecmp(ev, "hu")) {
p->hookstate = MGCP_ONHOOK;
sub->cxmode = MGCP_CX_RECVONLY;
ast_debug(1, "MGCP %s@%s Went on hook\n", p->name, p->parent->name);
/* Do we need to send MDCX before a DLCX ?
if (sub->rtp) {
transmit_modify_request(sub);
}
*/
if (p->transfer && (sub->owner && sub->next->owner) && ((!sub->outgoing) || (!sub->next->outgoing))) {
/* We're allowed to transfer, we have two avtive calls and */
/* we made at least one of the calls. Let's try and transfer */
ast_mutex_lock(&p->sub->next->lock);
res = attempt_transfer(p);
if (res < 0) {
if (p->sub->next->owner) {
sub->next->alreadygone = 1;
mgcp_queue_hangup(sub->next);
}
} else if (res) {
ast_log(LOG_WARNING, "Transfer attempt failed\n");
ast_mutex_unlock(&p->sub->next->lock);
return -1;
}
ast_mutex_unlock(&p->sub->next->lock);
} else {
/* Hangup the current call */
/* If there is another active call, mgcp_hangup will ring the phone with the other call */
if (sub->owner) {
sub->alreadygone = 1;
mgcp_queue_hangup(sub);
} else {
ast_verb(3, "MGCP handle_request(%s@%s-%d) ast_channel already destroyed, resending DLCX.\n",
p->name, p->parent->name, sub->id);
/* Instruct the other side to remove the connection since it apparently *
* still thinks the channel is active. *
* For Cisco IAD2421 /BAK/ */
transmit_connection_del(sub);
}
}
if ((p->hookstate == MGCP_ONHOOK) && (!sub->rtp) && (!sub->next->rtp)) {
p->hidecallerid = 0;
if (p->hascallwaiting && !p->callwaiting) {
ast_verb(3, "Enabling call waiting on MGCP/%s@%s-%d\n", p->name, p->parent->name, sub->id);
p->callwaiting = -1;
}
if (has_voicemail(p)) {
ast_verb(3, "MGCP handle_request(%s@%s) set vmwi(+)\n", p->name, p->parent->name);
transmit_notify_request(sub, "L/vmwi(+)");
} else {
ast_verb(3, "MGCP handle_request(%s@%s) set vmwi(-)\n", p->name, p->parent->name);
transmit_notify_request(sub, "L/vmwi(-)");
}
}
} else if ((strlen(ev) == 1) &&
(((ev[0] >= '0') && (ev[0] <= '9')) ||
((ev[0] >= 'A') && (ev[0] <= 'D')) ||
(ev[0] == '*') || (ev[0] == '#'))) {
if (sub && sub->owner && (sub->owner->_state >= AST_STATE_UP)) {
f.frametype = AST_FRAME_DTMF;
f.subclass = ev[0];
f.src = "mgcp";
/* XXX MUST queue this frame to all subs in threeway call if threeway call is active */
mgcp_queue_frame(sub, &f);
ast_mutex_lock(&sub->next->lock);
if (sub->next->owner)
mgcp_queue_frame(sub->next, &f);
ast_mutex_unlock(&sub->next->lock);
if (strstr(p->curtone, "wt") && (ev[0] == 'A')) {
memset(p->curtone, 0, sizeof(p->curtone));
}
} else {
p->dtmf_buf[strlen(p->dtmf_buf)] = ev[0];
p->dtmf_buf[strlen(p->dtmf_buf)] = '\0';
}
} else if (!strcasecmp(ev, "T")) {
/* Digit timeout -- unimportant */
} else if (!strcasecmp(ev, "ping")) {
/* ping -- unimportant */
} else {
ast_log(LOG_NOTICE, "Received unknown event '%s' from %s@%s\n", ev, p->name, p->parent->name);
}
} else {
ast_log(LOG_WARNING, "Unknown verb '%s' received from %s\n", req->verb, ast_inet_ntoa(sin->sin_addr));
transmit_response(sub, "510", req, "Unknown verb");
}
return 0;
}
| static void handle_response | ( | struct mgcp_endpoint * | p, |
| struct mgcp_subchannel * | sub, | ||
| int | result, | ||
| unsigned int | ident, | ||
| struct mgcp_request * | resp | ||
| ) | [static] |
Definition at line 2456 of file chan_mgcp.c.
References ast_copy_string(), ast_free, ast_log(), ast_strlen_zero(), ast_verb, mgcp_request::cmd, mgcp_endpoint::cmd_queue, mgcp_endpoint::cmd_queue_lock, mgcp_subchannel::cx_queue, mgcp_subchannel::cx_queue_lock, mgcp_subchannel::cxident, dump_cmd_queues(), find_command(), get_csv(), get_header(), mgcp_endpoint::hookstate, mgcp_subchannel::id, len(), mgcp_request::lines, LOG_NOTICE, LOG_WARNING, MGCP_CMD_AUEP, MGCP_CMD_CRCX, MGCP_OFFHOOK, MGCP_ONHOOK, mgcp_queue_hangup(), mgcp_endpoint::name, mgcp_gateway::name, mgcp_subchannel::next, mgcp_subchannel::owner, mgcp_endpoint::parent, process_sdp(), mgcp_endpoint::rqnt_queue, mgcp_endpoint::rqnt_queue_lock, mgcp_subchannel::rtp, mgcp_endpoint::slowsequence, start_rtp(), mgcp_endpoint::sub, mgcp_subchannel::tmpdest, transmit_connection_del(), transmit_connection_del_w_params(), transmit_modify_with_sdp(), and transmit_notify_request().
Referenced by mgcpsock_read(), and retrans_pkt().
{
char *c;
struct mgcp_request *req;
struct mgcp_gateway *gw = p->parent;
if (result < 200) {
/* provisional response */
return;
}
if (p->slowsequence)
req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident);
else if (sub)
req = find_command(p, sub, &sub->cx_queue, &sub->cx_queue_lock, ident);
else if (!(req = find_command(p, sub, &p->rqnt_queue, &p->rqnt_queue_lock, ident)))
req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident);
if (!req) {
ast_verb(3, "No command found on [%s] for transaction %d. Ignoring...\n",
gw->name, ident);
return;
}
if (p && (result >= 400) && (result <= 599)) {
switch (result) {
case 401:
p->hookstate = MGCP_OFFHOOK;
break;
case 402:
p->hookstate = MGCP_ONHOOK;
break;
case 406:
ast_log(LOG_NOTICE, "Transaction %d timed out\n", ident);
break;
case 407:
ast_log(LOG_NOTICE, "Transaction %d aborted\n", ident);
break;
}
if (sub) {
if (sub->owner) {
ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
result, p->name, p->parent->name, sub ? sub->id:-1);
mgcp_queue_hangup(sub);
}
} else {
if (p->sub->next->owner) {
ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
result, p->name, p->parent->name, sub ? sub->id:-1);
mgcp_queue_hangup(p->sub);
}
if (p->sub->owner) {
ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
result, p->name, p->parent->name, sub ? sub->id:-1);
mgcp_queue_hangup(p->sub);
}
dump_cmd_queues(p, NULL);
}
}
if (resp) {
if (req->cmd == MGCP_CMD_CRCX) {
if ((c = get_header(resp, "I"))) {
if (!ast_strlen_zero(c) && sub) {
/* if we are hanging up do not process this conn. */
if (sub->owner) {
if (!ast_strlen_zero(sub->cxident)) {
if (strcasecmp(c, sub->cxident)) {
ast_log(LOG_WARNING, "Subchannel already has a cxident. sub->cxident: %s requested %s\n", sub->cxident, c);
}
}
ast_copy_string(sub->cxident, c, sizeof(sub->cxident));
if (sub->tmpdest.sin_addr.s_addr) {
transmit_modify_with_sdp(sub, NULL, 0);
}
} else {
/* XXX delete this one
callid and conn id may already be lost.
so the following del conn may have a side effect of
cleaning up the next subchannel */
transmit_connection_del(sub);
}
}
}
}
if (req->cmd == MGCP_CMD_AUEP) {
/* check stale connection ids */
if ((c = get_header(resp, "I"))) {
char *v, *n;
int len;
while ((v = get_csv(c, &len, &n))) {
if (len) {
if (strncasecmp(v, p->sub->cxident, len) &&
strncasecmp(v, p->sub->next->cxident, len)) {
/* connection id not found. delete it */
char cxident[80] = "";
if (len > (sizeof(cxident) - 1))
len = sizeof(cxident) - 1;
ast_copy_string(cxident, v, len);
ast_verb(3, "Non existing connection id %s on %s@%s \n",
cxident, p->name, gw->name);
transmit_connection_del_w_params(p, NULL, cxident);
}
}
c = n;
}
}
/* Try to determine the hookstate returned from an audit endpoint command */
if ((c = get_header(resp, "ES"))) {
if (!ast_strlen_zero(c)) {
if (strstr(c, "hu")) {
if (p->hookstate != MGCP_ONHOOK) {
/* XXX cleanup if we think we are offhook XXX */
if ((p->sub->owner || p->sub->next->owner ) &&
p->hookstate == MGCP_OFFHOOK)
mgcp_queue_hangup(sub);
p->hookstate = MGCP_ONHOOK;
/* update the requested events according to the new hookstate */
transmit_notify_request(p->sub, "");
ast_verb(3, "Setting hookstate of %s@%s to ONHOOK\n", p->name, gw->name);
}
} else if (strstr(c, "hd")) {
if (p->hookstate != MGCP_OFFHOOK) {
p->hookstate = MGCP_OFFHOOK;
/* update the requested events according to the new hookstate */
transmit_notify_request(p->sub, "");
ast_verb(3, "Setting hookstate of %s@%s to OFFHOOK\n", p->name, gw->name);
}
}
}
}
}
if (resp && resp->lines) {
/* do not process sdp if we are hanging up. this may be a late response */
if (sub && sub->owner) {
if (!sub->rtp)
start_rtp(sub);
if (sub->rtp)
process_sdp(sub, resp);
}
}
}
ast_free(req);
}
| static int has_voicemail | ( | struct mgcp_endpoint * | p | ) | [static] |
Definition at line 462 of file chan_mgcp.c.
References ast_app_has_voicemail(), ast_event_destroy(), ast_event_get_cached(), ast_event_get_ie_uint(), AST_EVENT_IE_CONTEXT, AST_EVENT_IE_END, AST_EVENT_IE_MAILBOX, AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_STR, AST_EVENT_MWI, ast_strdupa, ast_strlen_zero(), mgcp_endpoint::mailbox, mbox(), and strsep().
Referenced by do_monitor(), handle_hd_hf(), handle_request(), mgcp_hangup(), and mgcp_request().
{
int new_msgs;
struct ast_event *event;
char *mbox, *cntx;
cntx = mbox = ast_strdupa(p->mailbox);
strsep(&cntx, "@");
if (ast_strlen_zero(cntx))
cntx = "default";
event = ast_event_get_cached(AST_EVENT_MWI,
AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mbox,
AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, cntx,
AST_EVENT_IE_END);
if (event) {
new_msgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
ast_event_destroy(event);
} else
new_msgs = ast_app_has_voicemail(p->mailbox, NULL);
return new_msgs;
}
| static int init_req | ( | struct mgcp_endpoint * | p, |
| struct mgcp_request * | req, | ||
| char * | verb | ||
| ) | [static] |
Definition at line 1989 of file chan_mgcp.c.
References ast_log(), mgcp_request::data, mgcp_request::header, mgcp_request::headers, mgcp_gateway::isnamedottedip, mgcp_request::len, LOG_WARNING, MGCP_MAX_HEADERS, mgcp_gateway::name, mgcp_endpoint::name, and mgcp_endpoint::parent.
Referenced by reqprep().
{
/* Initialize a response */
if (req->headers || req->len) {
ast_log(LOG_WARNING, "Request already initialized?!?\n");
return -1;
}
req->header[req->headers] = req->data + req->len;
/* check if we need brackets around the gw name */
if (p->parent->isnamedottedip)
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);
else
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);
req->len += strlen(req->header[req->headers]);
if (req->headers < MGCP_MAX_HEADERS)
req->headers++;
else
ast_log(LOG_WARNING, "Out of header space\n");
return 0;
}
| static int init_resp | ( | struct mgcp_request * | req, |
| char * | resp, | ||
| struct mgcp_request * | orig, | ||
| char * | resprest | ||
| ) | [static] |
Definition at line 1972 of file chan_mgcp.c.
References ast_log(), mgcp_request::data, mgcp_request::header, mgcp_request::headers, mgcp_request::identifier, mgcp_request::len, LOG_WARNING, and MGCP_MAX_HEADERS.
Referenced by respprep().
{
/* Initialize a response */
if (req->headers || req->len) {
ast_log(LOG_WARNING, "Request already initialized?!?\n");
return -1;
}
req->header[req->headers] = req->data + req->len;
snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %s %s\r\n", resp, orig->identifier, resprest);
req->len += strlen(req->header[req->headers]);
if (req->headers < MGCP_MAX_HEADERS)
req->headers++;
else
ast_log(LOG_WARNING, "Out of header space\n");
return 0;
}
| static int load_module | ( | void | ) | [static] |
load_module: PBX load module - initialization ---
Definition at line 4259 of file chan_mgcp.c.
References ast_channel_register(), ast_cli_register_multiple(), ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_rtp_proto_register(), io_context_create(), io_context_destroy(), LOG_ERROR, LOG_WARNING, reload_config(), restart_monitor(), sched_context_create(), and sched_context_destroy().
{
if (!(sched = sched_context_create())) {
ast_log(LOG_WARNING, "Unable to create schedule context\n");
return AST_MODULE_LOAD_FAILURE;
}
if (!(io = io_context_create())) {
ast_log(LOG_WARNING, "Unable to create I/O context\n");
sched_context_destroy(sched);
return AST_MODULE_LOAD_FAILURE;
}
if (reload_config(0))
return AST_MODULE_LOAD_DECLINE;
/* Make sure we can register our mgcp channel type */
if (ast_channel_register(&mgcp_tech)) {
ast_log(LOG_ERROR, "Unable to register channel class 'MGCP'\n");
io_context_destroy(io);
sched_context_destroy(sched);
return AST_MODULE_LOAD_FAILURE;
}
ast_rtp_proto_register(&mgcp_rtp);
ast_cli_register_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
/* And start the monitor for the first time */
restart_monitor();
return AST_MODULE_LOAD_SUCCESS;
}
| static int mgcp_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 1177 of file chan_mgcp.c.
References ast_channel::_state, ast_debug, ast_mutex_lock(), ast_mutex_unlock(), ast_setstate(), AST_STATE_UP, ast_verb, mgcp_subchannel::cxmode, mgcp_subchannel::id, mgcp_subchannel::lock, MGCP_CX_SENDRECV, mgcp_gateway::name, mgcp_endpoint::name, ast_channel::name, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_subchannel::rtp, start_rtp(), ast_channel::tech_pvt, transmit_modify_request(), and transmit_notify_request().
{
int res = 0;
struct mgcp_subchannel *sub = ast->tech_pvt;
struct mgcp_endpoint *p = sub->parent;
ast_mutex_lock(&sub->lock);
sub->cxmode = MGCP_CX_SENDRECV;
if (!sub->rtp) {
start_rtp(sub);
} else {
transmit_modify_request(sub);
}
ast_verb(3, "MGCP mgcp_answer(%s) on %s@%s-%d\n",
ast->name, p->name, p->parent->name, sub->id);
if (ast->_state != AST_STATE_UP) {
ast_setstate(ast, AST_STATE_UP);
ast_debug(1, "mgcp_answer(%s)\n", ast->name);
transmit_notify_request(sub, "");
transmit_modify_request(sub);
}
ast_mutex_unlock(&sub->lock);
return res;
}
| static int mgcp_call | ( | struct ast_channel * | ast, |
| char * | dest, | ||
| int | timeout | ||
| ) | [static] |
Definition at line 843 of file chan_mgcp.c.
References ast_channel::_state, AST_CONTROL_RINGING, ast_copy_string(), AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_control(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RESERVED, AST_STATE_RINGING, ast_strlen_zero(), ast_var_name(), ast_var_value(), ast_verb, mgcp_subchannel::callid, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, mgcp_subchannel::cxident, mgcp_subchannel::cxmode, ast_var_t::entries, mgcp_endpoint::hookstate, mgcp_subchannel::lock, LOG_NOTICE, LOG_WARNING, MGCP_CX_RECVONLY, MGCP_CX_SENDRECV, MGCP_OFFHOOK, MGCP_ONHOOK, ast_channel::name, mgcp_subchannel::next, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_subchannel::parent, mgcp_subchannel::rtp, start_rtp(), ast_channel::tech_pvt, transmit_modify_request(), transmit_notify_request_with_callerid(), mgcp_endpoint::type, TYPE_LINE, and ast_channel::varshead.
{
int res;
struct mgcp_endpoint *p;
struct mgcp_subchannel *sub;
char tone[50] = "";
const char *distinctive_ring = NULL;
struct varshead *headp;
struct ast_var_t *current;
if (mgcpdebug) {
ast_verb(3, "MGCP mgcp_call(%s)\n", ast->name);
}
sub = ast->tech_pvt;
p = sub->parent;
headp = &ast->varshead;
AST_LIST_TRAVERSE(headp,current,entries) {
/* Check whether there is an ALERT_INFO variable */
if (strcasecmp(ast_var_name(current),"ALERT_INFO") == 0) {
distinctive_ring = ast_var_value(current);
}
}
ast_mutex_lock(&sub->lock);
switch (p->hookstate) {
case MGCP_OFFHOOK:
if (!ast_strlen_zero(distinctive_ring)) {
snprintf(tone, sizeof(tone), "L/wt%s", distinctive_ring);
if (mgcpdebug) {
ast_verb(3, "MGCP distinctive callwait %s\n", tone);
}
} else {
ast_copy_string(tone, "L/wt", sizeof(tone));
if (mgcpdebug) {
ast_verb(3, "MGCP normal callwait %s\n", tone);
}
}
break;
case MGCP_ONHOOK:
default:
if (!ast_strlen_zero(distinctive_ring)) {
snprintf(tone, sizeof(tone), "L/r%s", distinctive_ring);
if (mgcpdebug) {
ast_verb(3, "MGCP distinctive ring %s\n", tone);
}
} else {
ast_copy_string(tone, "L/rg", sizeof(tone));
if (mgcpdebug) {
ast_verb(3, "MGCP default ring\n");
}
}
break;
}
if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
ast_log(LOG_WARNING, "mgcp_call called on %s, neither down nor reserved\n", ast->name);
ast_mutex_unlock(&sub->lock);
return -1;
}
res = 0;
sub->outgoing = 1;
sub->cxmode = MGCP_CX_RECVONLY;
if (p->type == TYPE_LINE) {
if (!sub->rtp) {
start_rtp(sub);
} else {
transmit_modify_request(sub);
}
if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) {
/* try to prevent a callwait from disturbing the other connection */
sub->next->cxmode = MGCP_CX_RECVONLY;
transmit_modify_request(sub->next);
}
transmit_notify_request_with_callerid(sub, tone, ast->cid.cid_num, ast->cid.cid_name);
ast_setstate(ast, AST_STATE_RINGING);
if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) {
/* Put the connection back in sendrecv */
sub->next->cxmode = MGCP_CX_SENDRECV;
transmit_modify_request(sub->next);
}
} else {
ast_log(LOG_NOTICE, "Don't know how to dial on trunks yet\n");
res = -1;
}
ast_mutex_unlock(&sub->lock);
ast_queue_control(ast, AST_CONTROL_RINGING);
return res;
}
| static int mgcp_devicestate | ( | void * | data | ) | [static] |
mgcp_devicestate: channel callback for device status monitoring
| data | tech/resource name of MGCP device to query |
Callback for device state management in channel subsystem to obtain device status (up/down) of a specific MGCP endpoint
Definition at line 1346 of file chan_mgcp.c.
References AST_DEVICE_INVALID, AST_DEVICE_UNKNOWN, ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, mgcp_gateway::endpoints, gatelock, gateways, mgcp_endpoint::name, mgcp_gateway::name, mgcp_endpoint::next, and mgcp_gateway::next.
{
struct mgcp_gateway *g;
struct mgcp_endpoint *e = NULL;
char *tmp, *endpt, *gw;
int ret = AST_DEVICE_INVALID;
endpt = ast_strdupa(data);
if ((tmp = strchr(endpt, '@'))) {
*tmp++ = '\0';
gw = tmp;
} else
goto error;
ast_mutex_lock(&gatelock);
g = gateways;
while (g) {
if (strcasecmp(g->name, gw) == 0) {
e = g->endpoints;
break;
}
g = g->next;
}
if (!e)
goto error;
while (e) {
if (strcasecmp(e->name, endpt) == 0)
break;
e = e->next;
}
if (!e)
goto error;
/*
* As long as the gateway/endpoint is valid, we'll
* assume that the device is available and its state
* can be tracked.
*/
ret = AST_DEVICE_UNKNOWN;
error:
ast_mutex_unlock(&gatelock);
return ret;
}
| static int mgcp_fixup | ( | struct ast_channel * | oldchan, |
| struct ast_channel * | newchan | ||
| ) | [static] |
Definition at line 1273 of file chan_mgcp.c.
References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), mgcp_subchannel::lock, LOG_NOTICE, LOG_WARNING, ast_channel::name, mgcp_subchannel::owner, and ast_channel::tech_pvt.
{
struct mgcp_subchannel *sub = newchan->tech_pvt;
ast_mutex_lock(&sub->lock);
ast_log(LOG_NOTICE, "mgcp_fixup(%s, %s)\n", oldchan->name, newchan->name);
if (sub->owner != oldchan) {
ast_mutex_unlock(&sub->lock);
ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
return -1;
}
sub->owner = newchan;
ast_mutex_unlock(&sub->lock);
return 0;
}
| static enum ast_rtp_get_result mgcp_get_rtp_peer | ( | struct ast_channel * | chan, |
| struct ast_rtp ** | rtp | ||
| ) | [static] |
Definition at line 3947 of file chan_mgcp.c.
References AST_RTP_GET_FAILED, AST_RTP_TRY_NATIVE, AST_RTP_TRY_PARTIAL, mgcp_endpoint::directmedia, mgcp_subchannel::parent, mgcp_subchannel::rtp, and ast_channel::tech_pvt.
{
struct mgcp_subchannel *sub = NULL;
if (!(sub = chan->tech_pvt) || !(sub->rtp))
return AST_RTP_GET_FAILED;
*rtp = sub->rtp;
if (sub->parent->directmedia)
return AST_RTP_TRY_NATIVE;
else
return AST_RTP_TRY_PARTIAL;
}
| static int mgcp_hangup | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 936 of file chan_mgcp.c.
References mgcp_subchannel::alreadygone, ast_bridged_channel(), ast_debug, ast_dsp_free(), ast_module_unref(), ast_mutex_lock(), ast_mutex_unlock(), ast_rtp_destroy(), ast_strlen_zero(), ast_verb, mgcp_subchannel::callid, mgcp_endpoint::callwaiting, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, mgcp_subchannel::cxident, mgcp_subchannel::cxmode, mgcp_endpoint::dsp, mgcp_endpoint::dtmf_buf, mgcp_endpoint::dtmfmode, has_voicemail(), mgcp_endpoint::hascallwaiting, mgcp_endpoint::hidecallerid, mgcp_endpoint::hookstate, mgcp_subchannel::lock, mgcp_subchannel::magic, MGCP_CX_INACTIVE, MGCP_CX_RECVONLY, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, MGCP_OFFHOOK, MGCP_ONHOOK, MGCP_SUBCHANNEL_MAGIC, mgcp_gateway::name, mgcp_endpoint::name, ast_channel::name, mgcp_subchannel::next, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_subchannel::rtp, ast_module_info::self, mgcp_endpoint::sub, ast_channel::tech_pvt, mgcp_subchannel::tmpdest, transmit_connection_del(), transmit_modify_request(), transmit_notify_request(), and transmit_notify_request_with_callerid().
{
struct mgcp_subchannel *sub = ast->tech_pvt;
struct mgcp_endpoint *p = sub->parent;
ast_debug(1, "mgcp_hangup(%s)\n", ast->name);
if (!ast->tech_pvt) {
ast_debug(1, "Asked to hangup channel not connected\n");
return 0;
}
if (strcmp(sub->magic, MGCP_SUBCHANNEL_MAGIC)) {
ast_debug(1, "Invalid magic. MGCP subchannel freed up already.\n");
return 0;
}
ast_mutex_lock(&sub->lock);
if (mgcpdebug) {
ast_verb(3, "MGCP mgcp_hangup(%s) on %s@%s\n", ast->name, p->name, p->parent->name);
}
if ((p->dtmfmode & MGCP_DTMF_INBAND) && p->dsp) {
/* check whether other channel is active. */
if (!sub->next->owner) {
if (p->dtmfmode & MGCP_DTMF_HYBRID)
p->dtmfmode &= ~MGCP_DTMF_INBAND;
if (mgcpdebug) {
ast_verb(2, "MGCP free dsp on %s@%s\n", p->name, p->parent->name);
}
ast_dsp_free(p->dsp);
p->dsp = NULL;
}
}
sub->owner = NULL;
if (!ast_strlen_zero(sub->cxident)) {
transmit_connection_del(sub);
}
sub->cxident[0] = '\0';
if ((sub == p->sub) && sub->next->owner) {
if (p->hookstate == MGCP_OFFHOOK) {
if (sub->next->owner && ast_bridged_channel(sub->next->owner)) {
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);
}
} else {
/* set our other connection as the primary and swith over to it */
p->sub = sub->next;
p->sub->cxmode = MGCP_CX_RECVONLY;
transmit_modify_request(p->sub);
if (sub->next->owner && ast_bridged_channel(sub->next->owner)) {
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);
}
}
} else if ((sub == p->sub->next) && p->hookstate == MGCP_OFFHOOK) {
transmit_notify_request(sub, "L/v");
} else if (p->hookstate == MGCP_OFFHOOK) {
transmit_notify_request(sub, "L/ro");
} else {
transmit_notify_request(sub, "");
}
ast->tech_pvt = NULL;
sub->alreadygone = 0;
sub->outgoing = 0;
sub->cxmode = MGCP_CX_INACTIVE;
sub->callid[0] = '\0';
if (p) {
memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
}
/* Reset temporary destination */
memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
if (sub->rtp) {
ast_rtp_destroy(sub->rtp);
sub->rtp = NULL;
}
ast_module_unref(ast_module_info->self);
if ((p->hookstate == MGCP_ONHOOK) && (!sub->next->rtp)) {
p->hidecallerid = 0;
if (p->hascallwaiting && !p->callwaiting) {
ast_verb(3, "Enabling call waiting on %s\n", ast->name);
p->callwaiting = -1;
}
if (has_voicemail(p)) {
if (mgcpdebug) {
ast_verb(3, "MGCP mgcp_hangup(%s) on %s@%s set vmwi(+)\n",
ast->name, p->name, p->parent->name);
}
transmit_notify_request(sub, "L/vmwi(+)");
} else {
if (mgcpdebug) {
ast_verb(3, "MGCP mgcp_hangup(%s) on %s@%s set vmwi(-)\n",
ast->name, p->name, p->parent->name);
}
transmit_notify_request(sub, "L/vmwi(-)");
}
}
ast_mutex_unlock(&sub->lock);
return 0;
}
| static int mgcp_indicate | ( | struct ast_channel * | ast, |
| int | ind, | ||
| const void * | data, | ||
| size_t | datalen | ||
| ) | [static] |
Definition at line 1426 of file chan_mgcp.c.
References AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, AST_CONTROL_RINGING, AST_CONTROL_SRCCHANGE, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, ast_log(), ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), ast_rtp_change_source(), ast_rtp_new_source(), ast_verb, control2str(), mgcp_subchannel::lock, LOG_WARNING, ast_channel::name, mgcp_subchannel::rtp, ast_channel::tech_pvt, and transmit_notify_request().
{
struct mgcp_subchannel *sub = ast->tech_pvt;
int res = 0;
if (mgcpdebug) {
ast_verb(3, "MGCP asked to indicate %d '%s' condition on channel %s\n",
ind, control2str(ind), ast->name);
}
ast_mutex_lock(&sub->lock);
switch(ind) {
case AST_CONTROL_RINGING:
#ifdef DLINK_BUGGY_FIRMWARE
transmit_notify_request(sub, "rt");
#else
transmit_notify_request(sub, "G/rt");
#endif
break;
case AST_CONTROL_BUSY:
transmit_notify_request(sub, "L/bz");
break;
case AST_CONTROL_CONGESTION:
transmit_notify_request(sub, "G/cg");
break;
case AST_CONTROL_HOLD:
ast_moh_start(ast, data, NULL);
break;
case AST_CONTROL_UNHOLD:
ast_moh_stop(ast);
break;
case AST_CONTROL_SRCUPDATE:
ast_rtp_new_source(sub->rtp);
break;
case AST_CONTROL_SRCCHANGE:
ast_rtp_change_source(sub->rtp);
break;
case -1:
transmit_notify_request(sub, "");
break;
default:
ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
res = -1;
}
ast_mutex_unlock(&sub->lock);
return res;
}
| static struct ast_channel* mgcp_new | ( | struct mgcp_subchannel * | sub, |
| int | state | ||
| ) | [static, read] |
Definition at line 1473 of file chan_mgcp.c.
References mgcp_endpoint::accountcode, mgcp_endpoint::adsi, ast_channel::adsicpe, ast_channel::amaflags, mgcp_endpoint::amaflags, AST_ADSI_UNAVAILABLE, ast_best_codec(), ast_channel_alloc(), ast_channel_set_fd(), ast_copy_string(), ast_dsp_new(), ast_dsp_set_digitmode(), ast_dsp_set_features(), ast_hangup(), ast_jb_configure(), ast_log(), ast_module_ref(), ast_pbx_start(), ast_rtp_fd(), ast_state2str(), AST_STATE_DOWN, AST_STATE_RING, ast_strdup, ast_string_field_build, ast_string_field_set, ast_strlen_zero(), ast_verb, mgcp_endpoint::call_forward, mgcp_endpoint::callgroup, ast_channel::callgroup, capability, mgcp_endpoint::capability, ast_channel::cid, ast_callerid::cid_ani, mgcp_endpoint::cid_name, mgcp_endpoint::cid_num, ast_channel::context, mgcp_endpoint::context, mgcp_endpoint::dsp, DSP_DIGITMODE_NOQUELCH, DSP_FEATURE_DIGIT_DETECT, mgcp_endpoint::dtmfmode, ast_channel::exten, mgcp_endpoint::exten, global_jbconf, mgcp_subchannel::id, mgcp_endpoint::language, LOG_WARNING, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, mgcp_tech, ast_channel::name, name, mgcp_gateway::name, mgcp_endpoint::name, ast_channel::nativeformats, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_endpoint::pickupgroup, ast_channel::pickupgroup, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::rings, mgcp_subchannel::rtp, ast_module_info::self, mgcp_endpoint::sub, ast_channel::tech, ast_channel::tech_pvt, and ast_channel::writeformat.
Referenced by handle_hd_hf(), and mgcp_request().
{
struct ast_channel *tmp;
struct mgcp_endpoint *i = sub->parent;
int fmt;
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);
if (tmp) {
tmp->tech = &mgcp_tech;
tmp->nativeformats = i->capability;
if (!tmp->nativeformats)
tmp->nativeformats = capability;
fmt = ast_best_codec(tmp->nativeformats);
ast_string_field_build(tmp, name, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id);
if (sub->rtp)
ast_channel_set_fd(tmp, 0, ast_rtp_fd(sub->rtp));
if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) {
i->dsp = ast_dsp_new();
ast_dsp_set_features(i->dsp, DSP_FEATURE_DIGIT_DETECT);
/* this is to prevent clipping of dtmf tones during dsp processing */
ast_dsp_set_digitmode(i->dsp, DSP_DIGITMODE_NOQUELCH);
} else {
i->dsp = NULL;
}
if (state == AST_STATE_RING)
tmp->rings = 1;
tmp->writeformat = fmt;
tmp->rawwriteformat = fmt;
tmp->readformat = fmt;
tmp->rawreadformat = fmt;
tmp->tech_pvt = sub;
if (!ast_strlen_zero(i->language))
ast_string_field_set(tmp, language, i->language);
if (!ast_strlen_zero(i->accountcode))
ast_string_field_set(tmp, accountcode, i->accountcode);
if (i->amaflags)
tmp->amaflags = i->amaflags;
sub->owner = tmp;
ast_module_ref(ast_module_info->self);
tmp->callgroup = i->callgroup;
tmp->pickupgroup = i->pickupgroup;
ast_string_field_set(tmp, call_forward, i->call_forward);
ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
/* Don't use ast_set_callerid() here because it will
* generate a needless NewCallerID event */
tmp->cid.cid_ani = ast_strdup(i->cid_num);
if (!i->adsi)
tmp->adsicpe = AST_ADSI_UNAVAILABLE;
tmp->priority = 1;
if (sub->rtp)
ast_jb_configure(tmp, &global_jbconf);
if (state != AST_STATE_DOWN) {
if (ast_pbx_start(tmp)) {
ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
ast_hangup(tmp);
tmp = NULL;
}
}
ast_verb(3, "MGCP mgcp_new(%s) created in state: %s\n",
tmp->name, ast_state2str(state));
} else {
ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
}
return tmp;
}
| static int mgcp_postrequest | ( | struct mgcp_endpoint * | p, |
| struct mgcp_subchannel * | sub, | ||
| char * | data, | ||
| int | len, | ||
| unsigned int | seqno | ||
| ) | [static] |
Definition at line 693 of file chan_mgcp.c.
References __mgcp_xmit(), ast_free, ast_malloc, ast_mutex_lock(), ast_mutex_unlock(), ast_sched_add(), ast_tvnow(), DEFAULT_RETRANS, len(), msg, mgcp_gateway::msgs, mgcp_gateway::msgs_lock, mgcp_message::next, mgcp_endpoint::next, mgcp_endpoint::parent, retrans_pkt(), and mgcp_gateway::retransid.
Referenced by find_command(), and send_request().
{
struct mgcp_message *msg;
struct mgcp_message *cur;
struct mgcp_gateway *gw;
struct timeval now;
msg = ast_malloc(sizeof(*msg) + len);
if (!msg) {
return -1;
}
gw = ((p && p->parent) ? p->parent : NULL);
if (!gw) {
ast_free(msg);
return -1;
}
/* SC
time(&t);
if (gw->messagepending && (gw->lastouttime + 20 < t)) {
ast_log(LOG_NOTICE, "Timeout waiting for response to message:%d, lastouttime: %ld, now: %ld. Dumping pending queue\n",
gw->msgs ? gw->msgs->seqno : -1, (long) gw->lastouttime, (long) t);
dump_queue(sub->parent);
}
*/
msg->owner_sub = sub;
msg->owner_ep = p;
msg->seqno = seqno;
msg->next = NULL;
msg->len = len;
msg->retrans = 0;
memcpy(msg->buf, data, msg->len);
ast_mutex_lock(&gw->msgs_lock);
cur = gw->msgs;
if (cur) {
while(cur->next)
cur = cur->next;
cur->next = msg;
} else {
gw->msgs = msg;
}
now = ast_tvnow();
msg->expire = now.tv_sec * 1000 + now.tv_usec / 1000 + DEFAULT_RETRANS;
if (gw->retransid == -1)
gw->retransid = ast_sched_add(sched, DEFAULT_RETRANS, retrans_pkt, (void *)gw);
ast_mutex_unlock(&gw->msgs_lock);
/* SC
if (!gw->messagepending) {
gw->messagepending = 1;
gw->lastout = seqno;
gw->lastouttime = t;
*/
__mgcp_xmit(gw, msg->buf, msg->len);
/* XXX Should schedule retransmission XXX */
/* SC
} else
ast_debug(1, "Deferring transmission of transaction %d\n", seqno);
*/
return 0;
}
| static void mgcp_queue_control | ( | struct mgcp_subchannel * | sub, |
| int | control | ||
| ) | [static] |
Definition at line 624 of file chan_mgcp.c.
References AST_FRAME_CONTROL, mgcp_queue_frame(), and ast_frame::subclass.
Referenced by handle_hd_hf().
{
struct ast_frame f = { AST_FRAME_CONTROL, };
f.subclass = control;
return mgcp_queue_frame(sub, &f);
}
| static void mgcp_queue_frame | ( | struct mgcp_subchannel * | sub, |
| struct ast_frame * | f | ||
| ) | [static] |
Definition at line 592 of file chan_mgcp.c.
References ast_channel_trylock, ast_channel_unlock, ast_queue_frame(), DEADLOCK_AVOIDANCE, mgcp_subchannel::lock, and mgcp_subchannel::owner.
Referenced by handle_request(), and mgcp_queue_control().
{
for(;;) {
if (sub->owner) {
if (!ast_channel_trylock(sub->owner)) {
ast_queue_frame(sub->owner, f);
ast_channel_unlock(sub->owner);
break;
} else {
DEADLOCK_AVOIDANCE(&sub->lock);
}
} else
break;
}
}
| static void mgcp_queue_hangup | ( | struct mgcp_subchannel * | sub | ) | [static] |
Definition at line 608 of file chan_mgcp.c.
References ast_channel_trylock, ast_channel_unlock, ast_queue_hangup(), DEADLOCK_AVOIDANCE, mgcp_subchannel::lock, and mgcp_subchannel::owner.
Referenced by attempt_transfer(), destroy_endpoint(), handle_request(), and handle_response().
{
for(;;) {
if (sub->owner) {
if (!ast_channel_trylock(sub->owner)) {
ast_queue_hangup(sub->owner);
ast_channel_unlock(sub->owner);
break;
} else {
DEADLOCK_AVOIDANCE(&sub->lock);
}
} else
break;
}
}
| static struct ast_frame * mgcp_read | ( | struct ast_channel * | ast | ) | [static, read] |
Definition at line 1233 of file chan_mgcp.c.
References ast_mutex_lock(), ast_mutex_unlock(), f, mgcp_subchannel::lock, mgcp_rtp_read(), and ast_channel::tech_pvt.
{
struct ast_frame *f;
struct mgcp_subchannel *sub = ast->tech_pvt;
ast_mutex_lock(&sub->lock);
f = mgcp_rtp_read(sub);
ast_mutex_unlock(&sub->lock);
return f;
}
| static char * mgcp_reload | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 4292 of file chan_mgcp.c.
References ast_cli_args::argc, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, LOG_WARNING, mgcp_reload_lock, restart_monitor(), and ast_cli_entry::usage.
Referenced by reload(), and unload_module().
{
static int deprecated = 0;
if (e) {
switch (cmd) {
case CLI_INIT:
e->command = "mgcp reload";
e->usage =
"Usage: mgcp reload\n"
" 'mgcp reload' is deprecated. Please use 'reload chan_mgcp.so' instead.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
}
if (!deprecated && a && a->argc > 0) {
ast_log(LOG_WARNING, "'mgcp reload' is deprecated. Please use 'reload chan_mgcp.so' instead.\n");
deprecated = 1;
}
ast_mutex_lock(&mgcp_reload_lock);
if (mgcp_reloading) {
ast_verbose("Previous mgcp reload not yet done\n");
} else
mgcp_reloading = 1;
ast_mutex_unlock(&mgcp_reload_lock);
restart_monitor();
return CLI_SUCCESS;
}
| static struct ast_channel * mgcp_request | ( | const char * | type, |
| int | format, | ||
| void * | data, | ||
| int * | cause | ||
| ) | [static, read] |
Definition at line 3501 of file chan_mgcp.c.
References AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, ast_copy_string(), ast_log(), ast_mutex_unlock(), AST_STATE_DOWN, ast_strlen_zero(), ast_verb, mgcp_endpoint::call_forward, mgcp_endpoint::callwaiting, capability, ast_channel::data, mgcp_endpoint::dnd, find_subchannel_and_lock(), format, has_voicemail(), mgcp_endpoint::hookstate, mgcp_subchannel::lock, LOG_NOTICE, LOG_WARNING, mgcp_new(), MGCP_ONHOOK, mgcp_subchannel::next, mgcp_subchannel::owner, mgcp_subchannel::parent, restart_monitor(), and transmit_notify_request().
{
int oldformat;
struct mgcp_subchannel *sub;
struct ast_channel *tmpc = NULL;
char tmp[256];
char *dest = data;
oldformat = format;
format &= capability;
if (!format) {
ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
return NULL;
}
ast_copy_string(tmp, dest, sizeof(tmp));
if (ast_strlen_zero(tmp)) {
ast_log(LOG_NOTICE, "MGCP Channels require an endpoint\n");
return NULL;
}
sub = find_subchannel_and_lock(tmp, 0, NULL);
if (!sub) {
ast_log(LOG_WARNING, "Unable to find MGCP endpoint '%s'\n", tmp);
*cause = AST_CAUSE_UNREGISTERED;
return NULL;
}
ast_verb(3, "MGCP mgcp_request(%s)\n", tmp);
ast_verb(3, "MGCP cw: %d, dnd: %d, so: %d, sno: %d\n",
sub->parent->callwaiting, sub->parent->dnd, sub->owner ? 1 : 0, sub->next->owner ? 1: 0);
/* Must be busy */
if (((sub->parent->callwaiting) && ((sub->owner) && (sub->next->owner))) ||
((!sub->parent->callwaiting) && (sub->owner)) ||
(sub->parent->dnd && (ast_strlen_zero(sub->parent->call_forward)))) {
if (sub->parent->hookstate == MGCP_ONHOOK) {
if (has_voicemail(sub->parent)) {
transmit_notify_request(sub,"L/vmwi(+)");
} else {
transmit_notify_request(sub,"L/vmwi(-)");
}
}
*cause = AST_CAUSE_BUSY;
ast_mutex_unlock(&sub->lock);
return NULL;
}
tmpc = mgcp_new(sub->owner ? sub->next : sub, AST_STATE_DOWN);
ast_mutex_unlock(&sub->lock);
if (!tmpc)
ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
restart_monitor();
return tmpc;
}
| static struct ast_frame* mgcp_rtp_read | ( | struct mgcp_subchannel * | sub | ) | [static, read] |
Definition at line 1202 of file chan_mgcp.c.
References ast_debug, ast_dsp_process(), AST_FRAME_DTMF, AST_FRAME_VOICE, ast_log(), ast_null_frame, ast_rtp_read(), ast_set_read_format(), ast_set_write_format(), mgcp_endpoint::dsp, mgcp_endpoint::dtmfmode, f, ast_frame::frametype, LOG_NOTICE, MGCP_DTMF_INBAND, MGCP_DTMF_RFC2833, ast_channel::nativeformats, mgcp_subchannel::owner, mgcp_subchannel::parent, ast_channel::readformat, mgcp_subchannel::rtp, ast_frame::subclass, and ast_channel::writeformat.
Referenced by mgcp_read().
{
/* Retrieve audio/etc from channel. Assumes sub->lock is already held. */
struct ast_frame *f;
f = ast_rtp_read(sub->rtp);
/* Don't send RFC2833 if we're not supposed to */
if (f && (f->frametype == AST_FRAME_DTMF) && !(sub->parent->dtmfmode & MGCP_DTMF_RFC2833))
return &ast_null_frame;
if (sub->owner) {
/* We already hold the channel lock */
if (f->frametype == AST_FRAME_VOICE) {
if (f->subclass != sub->owner->nativeformats) {
ast_debug(1, "Oooh, format changed to %d\n", f->subclass);
sub->owner->nativeformats = f->subclass;
ast_set_read_format(sub->owner, sub->owner->readformat);
ast_set_write_format(sub->owner, sub->owner->writeformat);
}
/* Courtesy fearnor aka alex@pilosoft.com */
if ((sub->parent->dtmfmode & MGCP_DTMF_INBAND) && (sub->parent->dsp)) {
#if 0
ast_log(LOG_NOTICE, "MGCP ast_dsp_process\n");
#endif
f = ast_dsp_process(sub->owner, sub->parent->dsp, f);
}
}
}
return f;
}
| static int mgcp_senddigit_begin | ( | struct ast_channel * | ast, |
| char | digit | ||
| ) | [static] |
Definition at line 1289 of file chan_mgcp.c.
References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_rtp_senddigit_begin(), mgcp_endpoint::dtmfmode, mgcp_subchannel::lock, LOG_DEBUG, LOG_ERROR, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, MGCP_DTMF_RFC2833, mgcp_subchannel::parent, mgcp_subchannel::rtp, and ast_channel::tech_pvt.
{
struct mgcp_subchannel *sub = ast->tech_pvt;
struct mgcp_endpoint *p = sub->parent;
int res = 0;
ast_mutex_lock(&sub->lock);
if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
ast_log(LOG_DEBUG, "Sending DTMF using inband/hybrid\n");
res = -1; /* Let asterisk play inband indications */
} else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
ast_log(LOG_DEBUG, "Sending DTMF using RFC2833");
ast_rtp_senddigit_begin(sub->rtp, digit);
} else {
ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
}
ast_mutex_unlock(&sub->lock);
return res;
}
| static int mgcp_senddigit_end | ( | struct ast_channel * | ast, |
| char | digit, | ||
| unsigned int | duration | ||
| ) | [static] |
Definition at line 1310 of file chan_mgcp.c.
References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_rtp_senddigit_end(), mgcp_endpoint::dtmfmode, mgcp_subchannel::lock, LOG_DEBUG, LOG_ERROR, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, MGCP_DTMF_RFC2833, mgcp_subchannel::parent, mgcp_subchannel::rtp, ast_channel::tech_pvt, and transmit_notify_request().
{
struct mgcp_subchannel *sub = ast->tech_pvt;
struct mgcp_endpoint *p = sub->parent;
int res = 0;
char tmp[4];
ast_mutex_lock(&sub->lock);
if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
ast_log(LOG_DEBUG, "Stopping DTMF using inband/hybrid\n");
res = -1; /* Tell Asterisk to stop inband indications */
} else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
ast_log(LOG_DEBUG, "Stopping DTMF using RFC2833\n");
tmp[0] = 'D';
tmp[1] = '/';
tmp[2] = digit;
tmp[3] = '\0';
transmit_notify_request(sub, tmp);
ast_rtp_senddigit_end(sub->rtp, digit);
} else {
ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
}
ast_mutex_unlock(&sub->lock);
return res;
}
| static int mgcp_set_rtp_peer | ( | struct ast_channel * | chan, |
| struct ast_rtp * | rtp, | ||
| struct ast_rtp * | vrtp, | ||
| struct ast_rtp * | trtp, | ||
| int | codecs, | ||
| int | nat_active | ||
| ) | [static] |
Definition at line 3962 of file chan_mgcp.c.
References mgcp_subchannel::alreadygone, ast_channel::tech_pvt, and transmit_modify_with_sdp().
{
/* XXX Is there such thing as video support with MGCP? XXX */
struct mgcp_subchannel *sub;
sub = chan->tech_pvt;
if (sub && !sub->alreadygone) {
transmit_modify_with_sdp(sub, rtp, codecs);
return 0;
}
return -1;
}
| static void* mgcp_ss | ( | void * | data | ) | [static] |
Definition at line 2640 of file chan_mgcp.c.
References ast_bridged_channel(), ast_canmatch_extension(), ast_copy_string(), ast_db_put(), ast_debug, ast_exists_extension(), ast_hangup(), ast_ignore_pattern(), ast_indicate(), ast_log(), ast_masq_park_call(), ast_matchmore_extension(), AST_MAX_EXTENSION, ast_parking_ext(), ast_pbx_run(), ast_pickup_call(), ast_pickup_ext(), ast_safe_sleep(), ast_say_digit_str(), ast_set_callerid(), ast_setstate(), AST_STATE_RING, ast_strlen_zero(), ast_verb, ast_waitfordigit(), mgcp_endpoint::call_forward, mgcp_endpoint::callreturn, mgcp_endpoint::callwaiting, mgcp_endpoint::cancallforward, chan, ast_channel::cid, ast_callerid::cid_ani, mgcp_endpoint::cid_name, ast_callerid::cid_num, mgcp_endpoint::cid_num, ast_channel::context, ast_channel::data, mgcp_endpoint::dnd, mgcp_endpoint::dtmf_buf, mgcp_endpoint::dtmfmode, exten, ast_channel::exten, firstdigittimeout, gendigittimeout, mgcp_endpoint::hascallwaiting, mgcp_endpoint::hidecallerid, ast_channel::language, mgcp_endpoint::lastcallerid, len(), LOG_WARNING, matchdigittimeout, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, ast_channel::name, mgcp_subchannel::next, mgcp_subchannel::owner, mgcp_subchannel::parent, ast_channel::rings, start_rtp(), ast_channel::tech_pvt, and transmit_notify_request().
Referenced by handle_hd_hf().
{
struct ast_channel *chan = data;
struct mgcp_subchannel *sub = chan->tech_pvt;
struct mgcp_endpoint *p = sub->parent;
/* char exten[AST_MAX_EXTENSION] = ""; */
int len = 0;
int timeout = firstdigittimeout;
int res= 0;
int getforward = 0;
int loop_pause = 100;
len = strlen(p->dtmf_buf);
while(len < AST_MAX_EXTENSION-1) {
res = 1; /* Assume that we will get a digit */
while (strlen(p->dtmf_buf) == len){
ast_safe_sleep(chan, loop_pause);
timeout -= loop_pause;
if (timeout <= 0){
res = 0;
break;
}
res = 1;
}
timeout = 0;
len = strlen(p->dtmf_buf);
if (!ast_ignore_pattern(chan->context, p->dtmf_buf)) {
/*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
ast_indicate(chan, -1);
} else {
/* XXX Redundant? We should already be playing dialtone */
/*tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALTONE);*/
transmit_notify_request(sub, "L/dl");
}
if (ast_exists_extension(chan, chan->context, p->dtmf_buf, 1, p->cid_num)) {
if (!res || !ast_matchmore_extension(chan, chan->context, p->dtmf_buf, 1, p->cid_num)) {
if (getforward) {
/* Record this as the forwarding extension */
ast_copy_string(p->call_forward, p->dtmf_buf, sizeof(p->call_forward));
ast_verb(3, "Setting call forward to '%s' on channel %s\n",
p->call_forward, chan->name);
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
transmit_notify_request(sub, "L/sl");
if (res)
break;
usleep(500000);
/*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
ast_indicate(chan, -1);
sleep(1);
memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALTONE);*/
transmit_notify_request(sub, "L/dl");
len = 0;
getforward = 0;
} else {
/*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
ast_indicate(chan, -1);
ast_copy_string(chan->exten, p->dtmf_buf, sizeof(chan->exten));
memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
ast_set_callerid(chan,
p->hidecallerid ? "" : p->cid_num,
p->hidecallerid ? "" : p->cid_name,
chan->cid.cid_ani ? NULL : p->cid_num);
ast_setstate(chan, AST_STATE_RING);
/*dahdi_enable_ec(p);*/
if (p->dtmfmode & MGCP_DTMF_HYBRID) {
p->dtmfmode |= MGCP_DTMF_INBAND;
ast_indicate(chan, -1);
}
res = ast_pbx_run(chan);
if (res) {
ast_log(LOG_WARNING, "PBX exited non-zero\n");
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
/*transmit_notify_request(p, "nbz", 1);*/
transmit_notify_request(sub, "G/cg");
}
return NULL;
}
} else {
/* It's a match, but they just typed a digit, and there is an ambiguous match,
so just set the timeout to matchdigittimeout and wait some more */
timeout = matchdigittimeout;
}
} else if (res == 0) {
ast_debug(1, "not enough digits (and no ambiguous match)...\n");
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
transmit_notify_request(sub, "G/cg");
/*dahdi_wait_event(p->subs[index].zfd);*/
ast_hangup(chan);
memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
return NULL;
} else if (p->hascallwaiting && p->callwaiting && !strcmp(p->dtmf_buf, "*70")) {
ast_verb(3, "Disabling call waiting on %s\n", chan->name);
/* Disable call waiting if enabled */
p->callwaiting = 0;
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
transmit_notify_request(sub, "L/sl");
len = 0;
memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
timeout = firstdigittimeout;
} else if (!strcmp(p->dtmf_buf,ast_pickup_ext())) {
/* Scan all channels and see if any there
* ringing channqels with that have call groups
* that equal this channels pickup group
*/
if (ast_pickup_call(chan)) {
ast_log(LOG_WARNING, "No call pickup possible...\n");
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
transmit_notify_request(sub, "G/cg");
}
memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
ast_hangup(chan);
return NULL;
} else if (!p->hidecallerid && !strcmp(p->dtmf_buf, "*67")) {
ast_verb(3, "Disabling Caller*ID on %s\n", chan->name);
/* Disable Caller*ID if enabled */
p->hidecallerid = 1;
ast_set_callerid(chan, "", "", NULL);
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
transmit_notify_request(sub, "L/sl");
len = 0;
memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
timeout = firstdigittimeout;
} else if (p->callreturn && !strcmp(p->dtmf_buf, "*69")) {
res = 0;
if (!ast_strlen_zero(p->lastcallerid)) {
res = ast_say_digit_str(chan, p->lastcallerid, "", chan->language);
}
if (!res)
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
transmit_notify_request(sub, "L/sl");
break;
} else if (!strcmp(p->dtmf_buf, "*78")) {
/* Do not disturb */
ast_verb(3, "Enabled DND on channel %s\n", chan->name);
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
transmit_notify_request(sub, "L/sl");
p->dnd = 1;
getforward = 0;
memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
len = 0;
} else if (!strcmp(p->dtmf_buf, "*79")) {
/* Do not disturb */
ast_verb(3, "Disabled DND on channel %s\n", chan->name);
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
transmit_notify_request(sub, "L/sl");
p->dnd = 0;
getforward = 0;
memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
len = 0;
} else if (p->cancallforward && !strcmp(p->dtmf_buf, "*72")) {
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
transmit_notify_request(sub, "L/sl");
getforward = 1;
memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
len = 0;
} else if (p->cancallforward && !strcmp(p->dtmf_buf, "*73")) {
ast_verb(3, "Cancelling call forwarding on channel %s\n", chan->name);
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
transmit_notify_request(sub, "L/sl");
memset(p->call_forward, 0, sizeof(p->call_forward));
getforward = 0;
memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
len = 0;
} else if (!strcmp(p->dtmf_buf, ast_parking_ext()) &&
sub->next->owner && ast_bridged_channel(sub->next->owner)) {
/* This is a three way call, the main call being a real channel,
and we're parking the first call. */
ast_masq_park_call(ast_bridged_channel(sub->next->owner), chan, 0, NULL);
ast_verb(3, "Parking call to '%s'\n", chan->name);
break;
} else if (!ast_strlen_zero(p->lastcallerid) && !strcmp(p->dtmf_buf, "*60")) {
ast_verb(3, "Blacklisting number %s\n", p->lastcallerid);
res = ast_db_put("blacklist", p->lastcallerid, "1");
if (!res) {
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
transmit_notify_request(sub, "L/sl");
memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
len = 0;
}
} else if (p->hidecallerid && !strcmp(p->dtmf_buf, "*82")) {
ast_verb(3, "Enabling Caller*ID on %s\n", chan->name);
/* Enable Caller*ID if enabled */
p->hidecallerid = 0;
ast_set_callerid(chan, p->cid_num, p->cid_name, NULL);
/*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
transmit_notify_request(sub, "L/sl");
len = 0;
memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
timeout = firstdigittimeout;
} else if (!ast_canmatch_extension(chan, chan->context, p->dtmf_buf, 1, chan->cid.cid_num) &&
((p->dtmf_buf[0] != '*') || (strlen(p->dtmf_buf) > 2))) {
ast_debug(1, "Can't match %s from '%s' in context %s\n", p->dtmf_buf, chan->cid.cid_num ? chan->cid.cid_num : "<Unknown Caller>", chan->context);
break;
}
if (!timeout)
timeout = gendigittimeout;
if (len && !ast_ignore_pattern(chan->context, p->dtmf_buf))
/*tone_zone_play_tone(p->subs[index].zfd, -1);*/
ast_indicate(chan, -1);
}
#if 0
for (;;) {
res = ast_waitfordigit(chan, to);
if (!res) {
ast_debug(1, "Timeout...\n");
break;
}
if (res < 0) {
ast_debug(1, "Got hangup...\n");
ast_hangup(chan);
break;
}
exten[pos++] = res;
if (!ast_ignore_pattern(chan->context, exten))
ast_indicate(chan, -1);
if (ast_matchmore_extension(chan, chan->context, exten, 1, chan->callerid)) {
if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid))
to = 3000;
else
to = 8000;
} else
break;
}
if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid)) {
ast_copy_string(chan->exten, exten, sizeof(chan->exten)1);
if (!p->rtp) {
start_rtp(p);
}
ast_setstate(chan, AST_STATE_RING);
chan->rings = 1;
if (ast_pbx_run(chan)) {
ast_log(LOG_WARNING, "Unable to launch PBX on %s\n", chan->name);
} else {
memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
return NULL;
}
}
#endif
ast_hangup(chan);
memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
return NULL;
}
| static int mgcp_write | ( | struct ast_channel * | ast, |
| struct ast_frame * | frame | ||
| ) | [static] |
Definition at line 1243 of file chan_mgcp.c.
References AST_FRAME_IMAGE, AST_FRAME_VOICE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_rtp_write(), ast_frame::frametype, mgcp_subchannel::lock, LOG_WARNING, ast_channel::nativeformats, mgcp_subchannel::parent, ast_channel::readformat, mgcp_subchannel::rtp, mgcp_endpoint::singlepath, mgcp_endpoint::sub, ast_frame::subclass, ast_channel::tech_pvt, and ast_channel::writeformat.
{
struct mgcp_subchannel *sub = ast->tech_pvt;
int res = 0;
if (frame->frametype != AST_FRAME_VOICE) {
if (frame->frametype == AST_FRAME_IMAGE)
return 0;
else {
ast_log(LOG_WARNING, "Can't send %d type frames with MGCP write\n", frame->frametype);
return 0;
}
} else {
if (!(frame->subclass & ast->nativeformats)) {
ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat);
return -1;
}
}
if (sub) {
ast_mutex_lock(&sub->lock);
if ((sub->parent->sub == sub) || !sub->parent->singlepath) {
if (sub->rtp) {
res = ast_rtp_write(sub->rtp, frame);
}
}
ast_mutex_unlock(&sub->lock);
}
return res;
}
| static int mgcpsock_read | ( | int * | id, |
| int | fd, | ||
| short | events, | ||
| void * | ignore | ||
| ) | [static] |
Definition at line 3297 of file chan_mgcp.c.
References ast_debug, ast_free, ast_inet_ntoa(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_SCHED_DEL, ast_strlen_zero(), ast_verbose(), mgcp_request::data, mgcp_request::endpoint, errno, find_and_retrans(), find_subchannel_and_lock(), handle_request(), handle_response(), mgcp_request::headers, mgcp_request::identifier, mgcp_request::len, len(), mgcp_subchannel::lock, LOG_NOTICE, LOG_WARNING, mgcp_gateway::msgs, mgcp_gateway::msgs_lock, mgcp_gateway::name, mgcp_message::next, mgcp_message::owner_ep, mgcp_message::owner_sub, mgcp_endpoint::parent, mgcp_subchannel::parent, parse(), mgcp_gateway::retransid, mgcp_message::seqno, mgcp_request::verb, and mgcp_request::version.
Referenced by do_monitor().
{
struct mgcp_request req;
struct sockaddr_in sin;
struct mgcp_subchannel *sub;
int res;
socklen_t len;
int result;
int ident;
len = sizeof(sin);
memset(&req, 0, sizeof(req));
res = recvfrom(mgcpsock, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len);
if (res < 0) {
if (errno != ECONNREFUSED)
ast_log(LOG_WARNING, "Recv error: %s\n", strerror(errno));
return 1;
}
req.data[res] = '\0';
req.len = res;
if (mgcpdebug) {
ast_verbose("MGCP read: \n%s\nfrom %s:%d\n", req.data, ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
}
parse(&req);
if (req.headers < 1) {
/* Must have at least one header */
return 1;
}
if (ast_strlen_zero(req.identifier)) {
ast_log(LOG_NOTICE, "Message from %s missing identifier\n", ast_inet_ntoa(sin.sin_addr));
return 1;
}
if (sscanf(req.verb, "%30d", &result) && sscanf(req.identifier, "%30d", &ident)) {
/* Try to find who this message is for, if it's important */
sub = find_subchannel_and_lock(NULL, ident, &sin);
if (sub) {
struct mgcp_gateway *gw = sub->parent->parent;
struct mgcp_message *cur, *prev;
ast_mutex_unlock(&sub->lock);
ast_mutex_lock(&gw->msgs_lock);
for (prev = NULL, cur = gw->msgs; cur; prev = cur, cur = cur->next) {
if (cur->seqno == ident) {
ast_debug(1, "Got response back on transaction %d\n", ident);
if (prev)
prev->next = cur->next;
else
gw->msgs = cur->next;
break;
}
}
/* stop retrans timer if the queue is empty */
if (!gw->msgs) {
AST_SCHED_DEL(sched, gw->retransid);
}
ast_mutex_unlock(&gw->msgs_lock);
if (cur) {
handle_response(cur->owner_ep, cur->owner_sub, result, ident, &req);
ast_free(cur);
return 1;
}
ast_log(LOG_NOTICE, "Got response back on [%s] for transaction %d we aren't sending?\n",
gw->name, ident);
}
} else {
if (ast_strlen_zero(req.endpoint) ||
ast_strlen_zero(req.version) ||
ast_strlen_zero(req.verb)) {
ast_log(LOG_NOTICE, "Message must have a verb, an idenitifier, version, and endpoint\n");
return 1;
}
/* Process request, with iflock held */
sub = find_subchannel_and_lock(req.endpoint, 0, &sin);
if (sub) {
/* look first to find a matching response in the queue */
if (!find_and_retrans(sub, &req))
/* pass the request off to the currently mastering subchannel */
handle_request(sub, &req, &sin);
ast_mutex_unlock(&sub->lock);
}
}
return 1;
}
| static void mwi_event_cb | ( | const struct ast_event * | event, |
| void * | userdata | ||
| ) | [static] |
Definition at line 454 of file chan_mgcp.c.
Referenced by build_gateway().
{
/* This module does not handle MWI in an event-based manner. However, it
* subscribes to MWI for each mailbox that is configured so that the core
* knows that we care about it. Then, chan_mgcp will get the MWI from the
* event cache instead of checking the mailbox directly. */
}
| static void parse | ( | struct mgcp_request * | req | ) | [static] |
Definition at line 1740 of file chan_mgcp.c.
References ast_log(), ast_strlen_zero(), ast_verbose(), mgcp_request::data, mgcp_request::endpoint, f, mgcp_request::header, mgcp_request::headers, mgcp_request::identifier, mgcp_request::line, mgcp_request::lines, LOG_WARNING, MGCP_MAX_HEADERS, MGCP_MAX_LINES, mgcp_request::verb, and mgcp_request::version.
Referenced by acf_channel_read(), acf_meetme_info(), add_agent(), app_exec(), aqm_exec(), ast_parse_allow_disallow(), astman_get_variables(), conf_exec(), conf_run(), confbridge_exec(), config_function_read(), cut_internal(), dial_exec_full(), dictate_exec(), directory_exec(), dundi_query_read(), dundi_result_read(), dundifunc_read(), enum_query_read(), enum_result_read(), execif_exec(), find_conf(), function_agent(), get_in_brackets(), handle_statechange(), iconv_read(), isAnsweringMachine(), isexten_function_read(), log_exec(), login_exec(), mgcpsock_read(), misdn_check_l2l1(), misdn_facility_exec(), misdn_set_opt_exec(), mixmonitor_exec(), originate_exec(), oss_call(), oss_request(), page_exec(), park_call_exec(), pbx_builtin_answer(), pbx_builtin_background(), pbx_builtin_waitexten(), play_moh_exec(), pqm_exec(), privacy_exec(), ql_exec(), queue_exec(), rcvfax_exec(), record_exec(), reload_agents(), reload_single_member(), retrydial_exec(), rqm_exec(), sayunixtime_exec(), sendtext_exec(), sla_trunk_exec(), smdi_msg_read(), smdi_msg_retrieve_read(), sms_exec(), sndfax_exec(), softhangup_exec(), speech_background(), start_moh_exec(), start_monitor_exec(), transfer_exec(), upqm_exec(), userevent_exec(), verbose_exec(), vm_execmain(), and zapateller_exec().
{
/* Divide fields by NULL's */
char *c;
int f = 0;
c = req->data;
/* First header starts immediately */
req->header[f] = c;
while(*c) {
if (*c == '\n') {
/* We've got a new header */
*c = 0;
#if 0
printf("Header: %s (%d)\n", req->header[f], strlen(req->header[f]));
#endif
if (ast_strlen_zero(req->header[f])) {
/* Line by itself means we're now in content */
c++;
break;
}
if (f >= MGCP_MAX_HEADERS - 1) {
ast_log(LOG_WARNING, "Too many MGCP headers...\n");
} else
f++;
req->header[f] = c + 1;
} else if (*c == '\r') {
/* Ignore but eliminate \r's */
*c = 0;
}
c++;
}
/* Check for last header */
if (!ast_strlen_zero(req->header[f]))
f++;
req->headers = f;
/* Now we process any mime content */
f = 0;
req->line[f] = c;
while(*c) {
if (*c == '\n') {
/* We've got a new line */
*c = 0;
#if 0
printf("Line: %s (%d)\n", req->line[f], strlen(req->line[f]));
#endif
if (f >= MGCP_MAX_LINES - 1) {
ast_log(LOG_WARNING, "Too many SDP lines...\n");
} else
f++;
req->line[f] = c + 1;
} else if (*c == '\r') {
/* Ignore and eliminate \r's */
*c = 0;
}
c++;
}
/* Check for last line */
if (!ast_strlen_zero(req->line[f]))
f++;
req->lines = f;
/* Parse up the initial header */
c = req->header[0];
while(*c && *c < 33) c++;
/* First the verb */
req->verb = c;
while(*c && (*c > 32)) c++;
if (*c) {
*c = '\0';
c++;
while(*c && (*c < 33)) c++;
req->identifier = c;
while(*c && (*c > 32)) c++;
if (*c) {
*c = '\0';
c++;
while(*c && (*c < 33)) c++;
req->endpoint = c;
while(*c && (*c > 32)) c++;
if (*c) {
*c = '\0';
c++;
while(*c && (*c < 33)) c++;
req->version = c;
while(*c && (*c > 32)) c++;
while(*c && (*c < 33)) c++;
while(*c && (*c > 32)) c++;
*c = '\0';
}
}
}
if (mgcpdebug) {
ast_verbose("Verb: '%s', Identifier: '%s', Endpoint: '%s', Version: '%s'\n",
req->verb, req->identifier, req->endpoint, req->version);
ast_verbose("%d headers, %d lines\n", req->headers, req->lines);
}
if (*c)
ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c);
}
| static int process_sdp | ( | struct mgcp_subchannel * | sub, |
| struct mgcp_request * | req | ||
| ) | [static] |
Definition at line 1841 of file chan_mgcp.c.
References ast_gethostbyname(), ast_inet_ntoa(), ast_log(), ast_rtp_get_current_formats(), ast_rtp_pt_clear(), ast_rtp_set_m_type(), ast_rtp_set_peer(), ast_rtp_set_rtpmap_type(), ast_strdupa, ast_strlen_zero(), ast_verbose(), mgcp_endpoint::capability, get_sdp(), get_sdp_iterate(), hp, len(), LOG_WARNING, mgcp_endpoint::nonCodecCapability, mgcp_subchannel::parent, mgcp_subchannel::rtp, and sdpLineNum_iterator_init().
Referenced by handle_response().
{
char *m;
char *c;
char *a;
char host[258];
int len;
int portno;
int peercapability, peerNonCodecCapability;
struct sockaddr_in sin;
char *codecs;
struct ast_hostent ahp; struct hostent *hp;
int codec, codec_count=0;
int iterator;
struct mgcp_endpoint *p = sub->parent;
/* Get codec and RTP info from SDP */
m = get_sdp(req, "m");
c = get_sdp(req, "c");
if (ast_strlen_zero(m) || ast_strlen_zero(c)) {
ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s', c = '%s')\n", m, c);
return -1;
}
if (sscanf(c, "IN IP4 %256s", host) != 1) {
ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
return -1;
}
/* XXX This could block for a long time, and block the main thread! XXX */
hp = ast_gethostbyname(host, &ahp);
if (!hp) {
ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c);
return -1;
}
if (sscanf(m, "audio %30d RTP/AVP %n", &portno, &len) != 1) {
ast_log(LOG_WARNING, "Unable to determine port number for RTP in '%s'\n", m);
return -1;
}
sin.sin_family = AF_INET;
memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
sin.sin_port = htons(portno);
ast_rtp_set_peer(sub->rtp, &sin);
#if 0
printf("Peer RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
#endif
/* Scan through the RTP payload types specified in a "m=" line: */
ast_rtp_pt_clear(sub->rtp);
codecs = ast_strdupa(m + len);
while (!ast_strlen_zero(codecs)) {
if (sscanf(codecs, "%30d%n", &codec, &len) != 1) {
if (codec_count)
break;
ast_log(LOG_WARNING, "Error in codec string '%s' at '%s'\n", m, codecs);
return -1;
}
ast_rtp_set_m_type(sub->rtp, codec);
codec_count++;
codecs += len;
}
/* Next, scan through each "a=rtpmap:" line, noting each */
/* specified RTP payload type (with corresponding MIME subtype): */
sdpLineNum_iterator_init(&iterator);
while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
if (sscanf(a, "rtpmap: %30u %127[^/]/", &codec, mimeSubtype) != 2)
continue;
/* Note: should really look at the 'freq' and '#chans' params too */
ast_rtp_set_rtpmap_type(sub->rtp, codec, "audio", mimeSubtype, 0);
}
/* Now gather all of the codecs that were asked for: */
ast_rtp_get_current_formats(sub->rtp, &peercapability, &peerNonCodecCapability);
p->capability = capability & peercapability;
if (mgcpdebug) {
ast_verbose("Capabilities: us - %d, them - %d, combined - %d\n",
capability, peercapability, p->capability);
ast_verbose("Non-codec capabilities: us - %d, them - %d, combined - %d\n",
nonCodecCapability, peerNonCodecCapability, p->nonCodecCapability);
}
if (!p->capability) {
ast_log(LOG_WARNING, "No compatible codecs!\n");
return -1;
}
return 0;
}
| static void prune_gateways | ( | void | ) | [static] |
Definition at line 4036 of file chan_mgcp.c.
References ast_mutex_lock(), ast_mutex_unlock(), mgcp_gateway::delme, mgcp_endpoint::delme, destroy_endpoint(), destroy_gateway(), mgcp_gateway::endpoints, gatelock, gateways, mgcp_gateway::next, and mgcp_endpoint::next.
Referenced by reload_config(), and unload_module().
{
struct mgcp_gateway *g, *z, *r;
struct mgcp_endpoint *e, *p, *t;
ast_mutex_lock(&gatelock);
/* prune gateways */
for (z = NULL, g = gateways; g;) {
/* prune endpoints */
for (p = NULL, e = g->endpoints; e; ) {
if (e->delme || g->delme) {
t = e;
e = e->next;
if (!p)
g->endpoints = e;
else
p->next = e;
destroy_endpoint(t);
} else {
p = e;
e = e->next;
}
}
if (g->delme) {
r = g;
g = g->next;
if (!z)
gateways = g;
else
z->next = g;
destroy_gateway(r);
} else {
z = g;
g = g->next;
}
}
ast_mutex_unlock(&gatelock);
}
| static int reload | ( | void | ) | [static] |
Definition at line 4324 of file chan_mgcp.c.
References mgcp_reload().
{
mgcp_reload(NULL, 0, NULL);
return 0;
}
| static int reload_config | ( | int | reload | ) | [static] |
Definition at line 4079 of file chan_mgcp.c.
References __ourip, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_getformatbyname(), ast_gethostbyname(), ast_inet_ntoa(), ast_io_remove(), ast_io_wait(), ast_jb_read_conf(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_netsock_set_qos(), ast_sched_runq(), ast_str2cos(), ast_str2tos(), ast_variable_browse(), ast_verb, bindaddr, build_gateway(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_MGCP_CA_PORT, mgcp_endpoint::delme, mgcp_gateway::delme, mgcp_gateway::endpoints, errno, format, gatelock, gateways, global_jbconf, hp, ast_variable::lineno, LOG_ERROR, LOG_NOTICE, LOG_WARNING, mgcp_endpoint::name, mgcp_gateway::name, ast_variable::name, mgcp_endpoint::needaudit, netlock, mgcp_gateway::next, mgcp_endpoint::next, ast_variable::next, prune_gateways(), qos, transmit_audit_endpoint(), and ast_variable::value.
Referenced by do_monitor(), and load_module().
{
struct ast_config *cfg;
struct ast_variable *v;
struct mgcp_gateway *g;
struct mgcp_endpoint *e;
char *cat;
struct ast_hostent ahp;
struct hostent *hp;
int format;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
if (gethostname(ourhost, sizeof(ourhost)-1)) {
ast_log(LOG_WARNING, "Unable to get hostname, MGCP disabled\n");
return 0;
}
cfg = ast_config_load(config, config_flags);
/* We *must* have a config file otherwise stop immediately */
if (!cfg) {
ast_log(LOG_NOTICE, "Unable to load config %s, MGCP disabled\n", config);
return 0;
} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
return 0;
} else if (cfg == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", config);
return 0;
}
memset(&bindaddr, 0, sizeof(bindaddr));
dtmfmode = 0;
/* Copy the default jb config over global_jbconf */
memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
v = ast_variable_browse(cfg, "general");
while (v) {
/* handle jb conf */
if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
v = v->next;
continue;
}
/* Create the interface list */
if (!strcasecmp(v->name, "bindaddr")) {
if (!(hp = ast_gethostbyname(v->value, &ahp))) {
ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
} else {
memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
}
} else if (!strcasecmp(v->name, "allow")) {
format = ast_getformatbyname(v->value);
if (format < 1)
ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
else
capability |= format;
} else if (!strcasecmp(v->name, "disallow")) {
format = ast_getformatbyname(v->value);
if (format < 1)
ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
else
capability &= ~format;
} else if (!strcasecmp(v->name, "tos")) {
if (ast_str2tos(v->value, &qos.tos))
ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
} else if (!strcasecmp(v->name, "tos_audio")) {
if (ast_str2tos(v->value, &qos.tos_audio))
ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);
} else if (!strcasecmp(v->name, "cos")) {
if (ast_str2cos(v->value, &qos.cos))
ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno);
} else if (!strcasecmp(v->name, "cos_audio")) {
if (ast_str2cos(v->value, &qos.cos_audio))
ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);
} else if (!strcasecmp(v->name, "port")) {
if (sscanf(v->value, "%5d", &ourport) == 1) {
bindaddr.sin_port = htons(ourport);
} else {
ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
}
}
v = v->next;
}
/* mark existing entries for deletion */
ast_mutex_lock(&gatelock);
g = gateways;
while (g) {
g->delme = 1;
e = g->endpoints;
while (e) {
e->delme = 1;
e = e->next;
}
g = g->next;
}
ast_mutex_unlock(&gatelock);
cat = ast_category_browse(cfg, NULL);
while(cat) {
if (strcasecmp(cat, "general")) {
ast_mutex_lock(&gatelock);
g = build_gateway(cat, ast_variable_browse(cfg, cat));
if (g) {
ast_verb(3, "Added gateway '%s'\n", g->name);
g->next = gateways;
gateways = g;
}
ast_mutex_unlock(&gatelock);
/* FS: process queue and IO */
if (monitor_thread == pthread_self()) {
if (sched) ast_sched_runq(sched);
if (io) ast_io_wait(io, 10);
}
}
cat = ast_category_browse(cfg, cat);
}
/* prune deleted entries etc. */
prune_gateways();
if (ntohl(bindaddr.sin_addr.s_addr)) {
memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
} else {
hp = ast_gethostbyname(ourhost, &ahp);
if (!hp) {
ast_log(LOG_WARNING, "Unable to get our IP address, MGCP disabled\n");
ast_config_destroy(cfg);
return 0;
}
memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
}
if (!ntohs(bindaddr.sin_port))
bindaddr.sin_port = ntohs(DEFAULT_MGCP_CA_PORT);
bindaddr.sin_family = AF_INET;
ast_mutex_lock(&netlock);
if (mgcpsock > -1)
close(mgcpsock);
if (mgcpsock_read_id != NULL)
ast_io_remove(io, mgcpsock_read_id);
mgcpsock_read_id = NULL;
mgcpsock = socket(AF_INET, SOCK_DGRAM, 0);
if (mgcpsock < 0) {
ast_log(LOG_WARNING, "Unable to create MGCP socket: %s\n", strerror(errno));
} else {
if (bind(mgcpsock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
strerror(errno));
close(mgcpsock);
mgcpsock = -1;
} else {
ast_verb(2, "MGCP Listening on %s:%d\n",
ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
ast_netsock_set_qos(mgcpsock, qos.tos, qos.cos, "MGCP");
}
}
ast_mutex_unlock(&netlock);
ast_config_destroy(cfg);
/* send audit only to the new endpoints */
g = gateways;
while (g) {
e = g->endpoints;
while (e && e->needaudit) {
e->needaudit = 0;
transmit_audit_endpoint(e);
ast_verb(3, "MGCP Auditing endpoint %s@%s for hookstate\n", e->name, g->name);
e = e->next;
}
g = g->next;
}
return 0;
}
| static int reqprep | ( | struct mgcp_request * | req, |
| struct mgcp_endpoint * | p, | ||
| char * | verb | ||
| ) | [static] |
Definition at line 2018 of file chan_mgcp.c.
References init_req().
Referenced by transmit_audit_endpoint(), transmit_connect_with_sdp(), transmit_connection_del(), transmit_connection_del_w_params(), transmit_modify_request(), transmit_modify_with_sdp(), transmit_notify_request(), and transmit_notify_request_with_callerid().
| static int resend_response | ( | struct mgcp_subchannel * | sub, |
| struct mgcp_response * | resp | ||
| ) | [static] |
Definition at line 528 of file chan_mgcp.c.
References __mgcp_xmit(), mgcp_gateway::addr, ast_inet_ntoa(), ast_verbose(), mgcp_response::buf, mgcp_response::len, mgcp_endpoint::parent, and mgcp_subchannel::parent.
Referenced by find_and_retrans().
{
struct mgcp_endpoint *p = sub->parent;
int res;
if (mgcpdebug) {
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));
}
res = __mgcp_xmit(p->parent, resp->buf, resp->len);
if (res > 0)
res = 0;
return res;
}
| static int respprep | ( | struct mgcp_request * | resp, |
| struct mgcp_endpoint * | p, | ||
| char * | msg, | ||
| struct mgcp_request * | req, | ||
| char * | msgrest | ||
| ) | [static] |
Definition at line 2011 of file chan_mgcp.c.
References init_resp().
Referenced by transmit_response().
| static int restart_monitor | ( | void | ) | [static] |
Definition at line 3472 of file chan_mgcp.c.
References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create_background, AST_PTHREADT_NULL, AST_PTHREADT_STOP, do_monitor(), LOG_ERROR, LOG_WARNING, and monlock.
Referenced by load_module(), mgcp_reload(), and mgcp_request().
{
/* If we're supposed to be stopped -- stay stopped */
if (monitor_thread == AST_PTHREADT_STOP)
return 0;
if (ast_mutex_lock(&monlock)) {
ast_log(LOG_WARNING, "Unable to lock monitor\n");
return -1;
}
if (monitor_thread == pthread_self()) {
ast_mutex_unlock(&monlock);
ast_log(LOG_WARNING, "Cannot kill myself\n");
return -1;
}
if (monitor_thread != AST_PTHREADT_NULL) {
/* Wake up the thread */
pthread_kill(monitor_thread, SIGURG);
} else {
/* Start a new monitor */
if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
ast_mutex_unlock(&monlock);
ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
return -1;
}
}
ast_mutex_unlock(&monlock);
return 0;
}
| static int retrans_pkt | ( | const void * | data | ) | [static] |
Definition at line 631 of file chan_mgcp.c.
References __mgcp_xmit(), ast_free, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), handle_response(), LOG_WARNING, MAX_RETRANS, mgcp_gateway::msgs, mgcp_gateway::msgs_lock, mgcp_gateway::name, mgcp_message::next, mgcp_message::retrans, and mgcp_gateway::retransid.
Referenced by mgcp_postrequest().
{
struct mgcp_gateway *gw = (struct mgcp_gateway *)data;
struct mgcp_message *cur, *exq = NULL, *w, *prev;
int res = 0;
/* find out expired msgs */
ast_mutex_lock(&gw->msgs_lock);
prev = NULL, cur = gw->msgs;
while (cur) {
if (cur->retrans < MAX_RETRANS) {
cur->retrans++;
if (mgcpdebug) {
ast_verbose("Retransmitting #%d transaction %u on [%s]\n",
cur->retrans, cur->seqno, gw->name);
}
__mgcp_xmit(gw, cur->buf, cur->len);
prev = cur;
cur = cur->next;
} else {
if (prev)
prev->next = cur->next;
else
gw->msgs = cur->next;
ast_log(LOG_WARNING, "Maximum retries exceeded for transaction %u on [%s]\n",
cur->seqno, gw->name);
w = cur;
cur = cur->next;
if (exq) {
w->next = exq;
} else {
w->next = NULL;
}
exq = w;
}
}
if (!gw->msgs) {
gw->retransid = -1;
res = 0;
} else {
res = 1;
}
ast_mutex_unlock(&gw->msgs_lock);
while (exq) {
cur = exq;
/* time-out transaction */
handle_response(cur->owner_ep, cur->owner_sub, 406, cur->seqno, NULL);
exq = exq->next;
ast_free(cur);
}
return res;
}
| static void sdpLineNum_iterator_init | ( | int * | iterator | ) | [static] |
| static int send_request | ( | struct mgcp_endpoint * | p, |
| struct mgcp_subchannel * | sub, | ||
| struct mgcp_request * | req, | ||
| unsigned int | seqno | ||
| ) | [static] |
Definition at line 758 of file chan_mgcp.c.
References mgcp_gateway::addr, ast_debug, ast_free, ast_inet_ntoa(), ast_log(), ast_malloc, ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), mgcp_request::cmd, mgcp_endpoint::cmd_queue, mgcp_endpoint::cmd_queue_lock, mgcp_subchannel::cx_queue, mgcp_subchannel::cx_queue_lock, mgcp_request::data, mgcp_request::len, LOG_WARNING, MGCP_CMD_CRCX, MGCP_CMD_DLCX, MGCP_CMD_MDCX, MGCP_CMD_RQNT, mgcp_postrequest(), mgcp_request::next, mgcp_endpoint::parent, mgcp_endpoint::rqnt_queue, mgcp_endpoint::rqnt_queue_lock, and mgcp_endpoint::slowsequence.
Referenced by transmit_audit_endpoint(), transmit_connect_with_sdp(), transmit_connection_del(), transmit_connection_del_w_params(), transmit_modify_request(), transmit_modify_with_sdp(), transmit_notify_request(), and transmit_notify_request_with_callerid().
{
int res = 0;
struct mgcp_request **queue, *q, *r, *t;
ast_mutex_t *l;
ast_debug(1, "Slow sequence is %d\n", p->slowsequence);
if (p->slowsequence) {
queue = &p->cmd_queue;
l = &p->cmd_queue_lock;
ast_mutex_lock(l);
} else {
switch (req->cmd) {
case MGCP_CMD_DLCX:
queue = &sub->cx_queue;
l = &sub->cx_queue_lock;
ast_mutex_lock(l);
q = sub->cx_queue;
/* delete pending cx cmds */
while (q) {
r = q->next;
ast_free(q);
q = r;
}
*queue = NULL;
break;
case MGCP_CMD_CRCX:
case MGCP_CMD_MDCX:
queue = &sub->cx_queue;
l = &sub->cx_queue_lock;
ast_mutex_lock(l);
break;
case MGCP_CMD_RQNT:
queue = &p->rqnt_queue;
l = &p->rqnt_queue_lock;
ast_mutex_lock(l);
break;
default:
queue = &p->cmd_queue;
l = &p->cmd_queue_lock;
ast_mutex_lock(l);
break;
}
}
r = ast_malloc(sizeof(*r));
if (!r) {
ast_log(LOG_WARNING, "Cannot post MGCP request: insufficient memory\n");
ast_mutex_unlock(l);
return -1;
}
memcpy(r, req, sizeof(*r));
if (!(*queue)) {
if (mgcpdebug) {
ast_verbose("Posting Request:\n%s to %s:%d\n", req->data,
ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
}
res = mgcp_postrequest(p, sub, req->data, req->len, seqno);
} else {
if (mgcpdebug) {
ast_verbose("Queueing Request:\n%s to %s:%d\n", req->data,
ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
}
}
/* XXX find tail. We could also keep tail in the data struct for faster access */
for (t = *queue; t && t->next; t = t->next);
r->next = NULL;
if (t)
t->next = r;
else
*queue = r;
ast_mutex_unlock(l);
return res;
}
| static int send_response | ( | struct mgcp_subchannel * | sub, |
| struct mgcp_request * | req | ||
| ) | [static] |
Definition at line 541 of file chan_mgcp.c.
References __mgcp_xmit(), mgcp_gateway::addr, ast_inet_ntoa(), ast_verbose(), mgcp_request::data, mgcp_request::len, mgcp_endpoint::parent, and mgcp_subchannel::parent.
Referenced by transmit_response().
{
struct mgcp_endpoint *p = sub->parent;
int res;
if (mgcpdebug) {
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));
}
res = __mgcp_xmit(p->parent, req->data, req->len);
if (res > 0)
res = 0;
return res;
}
| static void start_rtp | ( | struct mgcp_subchannel * | sub | ) | [static] |
Definition at line 2613 of file chan_mgcp.c.
References ast_channel_set_fd(), ast_mutex_lock(), ast_mutex_unlock(), ast_random(), ast_rtp_destroy(), ast_rtp_fd(), ast_rtp_new_with_bindaddr(), ast_rtp_set_callback(), ast_rtp_set_data(), ast_rtp_setnat(), ast_rtp_setqos(), bindaddr, mgcp_subchannel::callid, mgcp_subchannel::lock, mgcp_subchannel::nat, mgcp_subchannel::owner, qos, mgcp_subchannel::rtp, transmit_connect_with_sdp(), and mgcp_subchannel::txident.
Referenced by handle_hd_hf(), handle_response(), mgcp_answer(), mgcp_call(), and mgcp_ss().
{
ast_mutex_lock(&sub->lock);
/* check again to be on the safe side */
if (sub->rtp) {
ast_rtp_destroy(sub->rtp);
sub->rtp = NULL;
}
/* Allocate the RTP now */
sub->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
if (sub->rtp && sub->owner)
ast_channel_set_fd(sub->owner, 0, ast_rtp_fd(sub->rtp));
if (sub->rtp) {
ast_rtp_setqos(sub->rtp, qos.tos_audio, qos.cos_audio, "MGCP RTP");
ast_rtp_setnat(sub->rtp, sub->nat);
}
#if 0
ast_rtp_set_callback(p->rtp, rtpready);
ast_rtp_set_data(p->rtp, p);
#endif
/* Make a call*ID */
snprintf(sub->callid, sizeof(sub->callid), "%08lx%s", ast_random(), sub->txident);
/* Transmit the connection create */
transmit_connect_with_sdp(sub, NULL);
ast_mutex_unlock(&sub->lock);
}
| static int transmit_audit_endpoint | ( | struct mgcp_endpoint * | p | ) | [static] |
Definition at line 2332 of file chan_mgcp.c.
References add_header(), mgcp_request::cmd, MGCP_CMD_AUEP, oseq, reqprep(), send_request(), and mgcp_request::trid.
Referenced by handle_mgcp_audit_endpoint(), handle_request(), and reload_config().
{
struct mgcp_request resp;
reqprep(&resp, p, "AUEP");
/* removed unknown param VS */
/*add_header(&resp, "F", "A,R,D,S,X,N,I,T,O,ES,E,MD,M");*/
add_header(&resp, "F", "A");
/* fill in new fields */
resp.cmd = MGCP_CMD_AUEP;
resp.trid = oseq;
return send_request(p, NULL, &resp, oseq); /* SC */
}
| static int transmit_connect_with_sdp | ( | struct mgcp_subchannel * | sub, |
| struct ast_rtp * | rtp | ||
| ) | [static] |
Definition at line 2179 of file chan_mgcp.c.
References add_header(), add_sdp(), ast_copy_string(), AST_FORMAT_AUDIO_MASK, ast_rtp_lookup_mime_subtype(), ast_verb, mgcp_subchannel::callid, mgcp_endpoint::capability, mgcp_request::cmd, mgcp_subchannel::cxmode, mgcp_subchannel::id, MGCP_CMD_CRCX, mgcp_gateway::name, mgcp_endpoint::name, oseq, mgcp_endpoint::parent, mgcp_subchannel::parent, reqprep(), send_request(), mgcp_request::trid, and mgcp_subchannel::txident.
Referenced by start_rtp().
{
struct mgcp_request resp;
char local[256];
char tmp[80];
int x;
struct mgcp_endpoint *p = sub->parent;
ast_copy_string(local, "p:20", sizeof(local));
for (x = 1; x <= AST_FORMAT_AUDIO_MASK; x <<= 1) {
if (p->capability & x) {
snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0));
strncat(local, tmp, sizeof(local) - strlen(local) - 1);
}
}
if (mgcpdebug) {
ast_verb(3, "Creating connection for %s@%s-%d in cxmode: %s callid: %s\n",
p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
}
reqprep(&resp, p, "CRCX");
add_header(&resp, "C", sub->callid);
add_header(&resp, "L", local);
add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
/* X header should not be sent. kept for compatibility */
add_header(&resp, "X", sub->txident);
/*add_header(&resp, "S", "");*/
add_sdp(&resp, sub, rtp);
/* fill in new fields */
resp.cmd = MGCP_CMD_CRCX;
resp.trid = oseq;
return send_request(p, sub, &resp, oseq); /* SC */
}
| static int transmit_connection_del | ( | struct mgcp_subchannel * | sub | ) | [static] |
Definition at line 2345 of file chan_mgcp.c.
References add_header(), ast_verb, mgcp_subchannel::callid, mgcp_request::cmd, mgcp_subchannel::cxident, mgcp_subchannel::cxmode, mgcp_subchannel::id, MGCP_CMD_DLCX, mgcp_gateway::name, mgcp_endpoint::name, oseq, mgcp_endpoint::parent, mgcp_subchannel::parent, reqprep(), send_request(), mgcp_request::trid, and mgcp_subchannel::txident.
Referenced by destroy_endpoint(), handle_request(), handle_response(), mgcp_hangup(), and unalloc_sub().
{
struct mgcp_endpoint *p = sub->parent;
struct mgcp_request resp;
if (mgcpdebug) {
ast_verb(3, "Delete connection %s %s@%s-%d with new mode: %s on callid: %s\n",
sub->cxident, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
}
reqprep(&resp, p, "DLCX");
/* check if call id is avail */
if (sub->callid[0])
add_header(&resp, "C", sub->callid);
/* X header should not be sent. kept for compatibility */
add_header(&resp, "X", sub->txident);
/* check if cxident is avail */
if (sub->cxident[0])
add_header(&resp, "I", sub->cxident);
/* fill in new fields */
resp.cmd = MGCP_CMD_DLCX;
resp.trid = oseq;
return send_request(p, sub, &resp, oseq); /* SC */
}
| static int transmit_connection_del_w_params | ( | struct mgcp_endpoint * | p, |
| char * | callid, | ||
| char * | cxident | ||
| ) | [static] |
Definition at line 2369 of file chan_mgcp.c.
References add_header(), ast_verb, mgcp_request::cmd, MGCP_CMD_DLCX, mgcp_gateway::name, mgcp_endpoint::name, oseq, mgcp_endpoint::parent, reqprep(), send_request(), mgcp_endpoint::sub, and mgcp_request::trid.
Referenced by handle_response().
{
struct mgcp_request resp;
if (mgcpdebug) {
ast_verb(3, "Delete connection %s %s@%s on callid: %s\n",
cxident ? cxident : "", p->name, p->parent->name, callid ? callid : "");
}
reqprep(&resp, p, "DLCX");
/* check if call id is avail */
if (callid && *callid)
add_header(&resp, "C", callid);
/* check if cxident is avail */
if (cxident && *cxident)
add_header(&resp, "I", cxident);
/* fill in new fields */
resp.cmd = MGCP_CMD_DLCX;
resp.trid = oseq;
return send_request(p, p->sub, &resp, oseq);
}
| static int transmit_modify_request | ( | struct mgcp_subchannel * | sub | ) | [static] |
Definition at line 2287 of file chan_mgcp.c.
References add_header(), add_header_offhook(), ast_strlen_zero(), ast_verb, mgcp_subchannel::callid, mgcp_request::cmd, mgcp_subchannel::cxident, mgcp_subchannel::cxmode, mgcp_endpoint::hookstate, mgcp_subchannel::id, MGCP_CMD_MDCX, MGCP_OFFHOOK, MGCP_ONHOOK, mgcp_gateway::name, mgcp_endpoint::name, oseq, mgcp_endpoint::parent, mgcp_subchannel::parent, reqprep(), send_request(), mgcp_request::trid, and mgcp_subchannel::txident.
Referenced by handle_hd_hf(), handle_request(), mgcp_answer(), mgcp_call(), and mgcp_hangup().
{
struct mgcp_request resp;
struct mgcp_endpoint *p = sub->parent;
if (ast_strlen_zero(sub->cxident)) {
/* We don't have a CXident yet, store the destination and
wait a bit */
return 0;
}
if (mgcpdebug) {
ast_verb(3, "Modified %s@%s-%d with new mode: %s on callid: %s\n",
p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
}
reqprep(&resp, p, "MDCX");
add_header(&resp, "C", sub->callid);
add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
/* X header should not be sent. kept for compatibility */
add_header(&resp, "X", sub->txident);
add_header(&resp, "I", sub->cxident);
switch (sub->parent->hookstate) {
case MGCP_ONHOOK:
add_header(&resp, "R", "L/hd(N)");
break;
case MGCP_OFFHOOK:
add_header_offhook(sub, &resp);
break;
}
/* fill in new fields */
resp.cmd = MGCP_CMD_MDCX;
resp.trid = oseq;
return send_request(p, sub, &resp, oseq); /* SC */
}
| static int transmit_modify_with_sdp | ( | struct mgcp_subchannel * | sub, |
| struct ast_rtp * | rtp, | ||
| int | codecs | ||
| ) | [static] |
Definition at line 2143 of file chan_mgcp.c.
References add_header(), add_sdp(), ast_copy_string(), AST_FORMAT_AUDIO_MASK, ast_rtp_get_peer(), ast_rtp_lookup_mime_subtype(), ast_strlen_zero(), mgcp_subchannel::callid, mgcp_endpoint::capability, mgcp_request::cmd, mgcp_subchannel::cxident, mgcp_subchannel::cxmode, MGCP_CMD_MDCX, oseq, mgcp_subchannel::parent, reqprep(), send_request(), mgcp_subchannel::tmpdest, mgcp_request::trid, and mgcp_subchannel::txident.
Referenced by handle_response(), and mgcp_set_rtp_peer().
{
struct mgcp_request resp;
char local[256];
char tmp[80];
int x;
struct mgcp_endpoint *p = sub->parent;
if (ast_strlen_zero(sub->cxident) && rtp) {
/* We don't have a CXident yet, store the destination and
wait a bit */
ast_rtp_get_peer(rtp, &sub->tmpdest);
return 0;
}
ast_copy_string(local, "p:20", sizeof(local));
for (x = 1; x <= AST_FORMAT_AUDIO_MASK; x <<= 1) {
if (p->capability & x) {
snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0));
strncat(local, tmp, sizeof(local) - strlen(local) - 1);
}
}
reqprep(&resp, p, "MDCX");
add_header(&resp, "C", sub->callid);
add_header(&resp, "L", local);
add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
/* X header should not be sent. kept for compatibility */
add_header(&resp, "X", sub->txident);
add_header(&resp, "I", sub->cxident);
/*add_header(&resp, "S", "");*/
add_sdp(&resp, sub, rtp);
/* fill in new fields */
resp.cmd = MGCP_CMD_MDCX;
resp.trid = oseq;
return send_request(p, sub, &resp, oseq); /* SC */
}
| static int transmit_notify_request | ( | struct mgcp_subchannel * | sub, |
| char * | tone | ||
| ) | [static] |
Definition at line 2212 of file chan_mgcp.c.
References add_header(), add_header_offhook(), ast_copy_string(), ast_strlen_zero(), ast_verb, mgcp_request::cmd, mgcp_endpoint::curtone, mgcp_subchannel::cxmode, mgcp_endpoint::hookstate, mgcp_subchannel::id, MGCP_CMD_RQNT, MGCP_OFFHOOK, MGCP_ONHOOK, mgcp_gateway::name, mgcp_endpoint::name, oseq, mgcp_endpoint::parent, mgcp_subchannel::parent, reqprep(), mgcp_endpoint::rqnt_ident, send_request(), and mgcp_request::trid.
Referenced by do_monitor(), handle_hd_hf(), handle_request(), handle_response(), mgcp_answer(), mgcp_hangup(), mgcp_indicate(), mgcp_request(), mgcp_senddigit_end(), and mgcp_ss().
{
struct mgcp_request resp;
struct mgcp_endpoint *p = sub->parent;
if (mgcpdebug) {
ast_verb(3, "MGCP Asked to indicate tone: %s on %s@%s-%d in cxmode: %s\n",
tone, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]);
}
ast_copy_string(p->curtone, tone, sizeof(p->curtone));
reqprep(&resp, p, "RQNT");
add_header(&resp, "X", p->rqnt_ident); /* SC */
switch (p->hookstate) {
case MGCP_ONHOOK:
add_header(&resp, "R", "L/hd(N)");
break;
case MGCP_OFFHOOK:
add_header_offhook(sub, &resp);
break;
}
if (!ast_strlen_zero(tone)) {
add_header(&resp, "S", tone);
}
/* fill in new fields */
resp.cmd = MGCP_CMD_RQNT;
resp.trid = oseq;
return send_request(p, NULL, &resp, oseq); /* SC */
}
| static int transmit_notify_request_with_callerid | ( | struct mgcp_subchannel * | sub, |
| char * | tone, | ||
| char * | callernum, | ||
| char * | callername | ||
| ) | [static] |
Definition at line 2241 of file chan_mgcp.c.
References add_header(), add_header_offhook(), ast_copy_string(), ast_localtime(), ast_strlen_zero(), ast_tvnow(), ast_verb, mgcp_request::cmd, mgcp_endpoint::curtone, mgcp_subchannel::cxmode, mgcp_endpoint::hookstate, mgcp_subchannel::id, mgcp_endpoint::lastcallerid, MGCP_CMD_RQNT, MGCP_OFFHOOK, MGCP_ONHOOK, mgcp_gateway::name, mgcp_endpoint::name, oseq, mgcp_endpoint::parent, mgcp_subchannel::parent, reqprep(), mgcp_endpoint::rqnt_ident, send_request(), ast_tm::tm_hour, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, and mgcp_request::trid.
Referenced by mgcp_call(), and mgcp_hangup().
{
struct mgcp_request resp;
char tone2[256];
char *l, *n;
struct timeval t = ast_tvnow();
struct ast_tm tm;
struct mgcp_endpoint *p = sub->parent;
ast_localtime(&t, &tm, NULL);
n = callername;
l = callernum;
if (!n)
n = "";
if (!l)
l = "";
/* Keep track of last callerid for blacklist and callreturn */
ast_copy_string(p->lastcallerid, l, sizeof(p->lastcallerid));
snprintf(tone2, sizeof(tone2), "%s,L/ci(%02d/%02d/%02d/%02d,%s,%s)", tone,
tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, l, n);
ast_copy_string(p->curtone, tone, sizeof(p->curtone));
reqprep(&resp, p, "RQNT");
add_header(&resp, "X", p->rqnt_ident); /* SC */
switch (p->hookstate) {
case MGCP_ONHOOK:
add_header(&resp, "R", "L/hd(N)");
break;
case MGCP_OFFHOOK:
add_header_offhook(sub, &resp);
break;
}
if (!ast_strlen_zero(tone2)) {
add_header(&resp, "S", tone2);
}
if (mgcpdebug) {
ast_verb(3, "MGCP Asked to indicate tone: %s on %s@%s-%d in cxmode: %s\n",
tone2, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]);
}
/* fill in new fields */
resp.cmd = MGCP_CMD_RQNT;
resp.trid = oseq;
return send_request(p, NULL, &resp, oseq); /* SC */
}
| static int transmit_response | ( | struct mgcp_subchannel * | sub, |
| char * | msg, | ||
| struct mgcp_request * | req, | ||
| char * | msgrest | ||
| ) | [static] |
Definition at line 2028 of file chan_mgcp.c.
References ast_calloc, mgcp_response::buf, mgcp_request::data, mgcp_request::identifier, mgcp_response::len, mgcp_request::len, mgcp_response::next, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_gateway::responses, respprep(), send_response(), mgcp_response::seqno, and mgcp_response::whensent.
Referenced by handle_request().
{
struct mgcp_request resp;
struct mgcp_endpoint *p = sub->parent;
struct mgcp_response *mgr;
respprep(&resp, p, msg, req, msgrest);
mgr = ast_calloc(1, sizeof(*mgr) + resp.len + 1);
if (mgr) {
/* Store MGCP response in case we have to retransmit */
sscanf(req->identifier, "%30d", &mgr->seqno);
time(&mgr->whensent);
mgr->len = resp.len;
memcpy(mgr->buf, resp.data, resp.len);
mgr->buf[resp.len] = '\0';
mgr->next = p->parent->responses;
p->parent->responses = mgr;
}
return send_response(sub, &resp);
}
| static int unalloc_sub | ( | struct mgcp_subchannel * | sub | ) | [static] |
Definition at line 487 of file chan_mgcp.c.
References mgcp_subchannel::alreadygone, ast_debug, ast_log(), ast_rtp_destroy(), ast_strlen_zero(), mgcp_subchannel::callid, mgcp_subchannel::cxident, mgcp_subchannel::cxmode, dump_cmd_queues(), mgcp_subchannel::id, LOG_WARNING, MGCP_CX_INACTIVE, mgcp_gateway::name, mgcp_endpoint::name, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_subchannel::rtp, mgcp_endpoint::sub, mgcp_subchannel::tmpdest, and transmit_connection_del().
Referenced by attempt_transfer().
{
struct mgcp_endpoint *p = sub->parent;
if (p->sub == sub) {
ast_log(LOG_WARNING, "Trying to unalloc the real channel %s@%s?!?\n", p->name, p->parent->name);
return -1;
}
ast_debug(1, "Released sub %d of channel %s@%s\n", sub->id, p->name, p->parent->name);
sub->owner = NULL;
if (!ast_strlen_zero(sub->cxident)) {
transmit_connection_del(sub);
}
sub->cxident[0] = '\0';
sub->callid[0] = '\0';
sub->cxmode = MGCP_CX_INACTIVE;
sub->outgoing = 0;
sub->alreadygone = 0;
memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
if (sub->rtp) {
ast_rtp_destroy(sub->rtp);
sub->rtp = NULL;
}
dump_cmd_queues(NULL, sub); /* SC */
return 0;
}
| static int unload_module | ( | void | ) | [static] |
Definition at line 4330 of file chan_mgcp.c.
References ast_channel_register(), ast_channel_unregister(), ast_cli_unregister_multiple(), ast_log(), ast_mutex_lock(), ast_mutex_trylock(), ast_mutex_unlock(), AST_PTHREADT_NULL, AST_PTHREADT_STOP, ast_rtp_proto_unregister(), mgcp_endpoint::delme, mgcp_gateway::delme, mgcp_gateway::endpoints, gatelock, gateways, LOG_WARNING, mgcp_reload(), mgcp_reload_lock, monlock, mgcp_endpoint::next, mgcp_gateway::next, prune_gateways(), and sched_context_destroy().
{
struct mgcp_endpoint *e;
struct mgcp_gateway *g;
/* Check to see if we're reloading */
if (ast_mutex_trylock(&mgcp_reload_lock)) {
ast_log(LOG_WARNING, "MGCP is currently reloading. Unable to remove module.\n");
return -1;
} else {
mgcp_reloading = 1;
ast_mutex_unlock(&mgcp_reload_lock);
}
/* First, take us out of the channel loop */
ast_channel_unregister(&mgcp_tech);
/* Shut down the monitoring thread */
if (!ast_mutex_lock(&monlock)) {
if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
pthread_cancel(monitor_thread);
pthread_kill(monitor_thread, SIGURG);
pthread_join(monitor_thread, NULL);
}
monitor_thread = AST_PTHREADT_STOP;
ast_mutex_unlock(&monlock);
} else {
ast_log(LOG_WARNING, "Unable to lock the monitor\n");
/* We always want to leave this in a consistent state */
ast_channel_register(&mgcp_tech);
mgcp_reloading = 0;
mgcp_reload(NULL, 0, NULL);
return -1;
}
if (!ast_mutex_lock(&gatelock)) {
for (g = gateways; g; g = g->next) {
g->delme = 1;
for (e = g->endpoints; e; e = e->next)
e->delme = 1;
}
prune_gateways();
ast_mutex_unlock(&gatelock);
} else {
ast_log(LOG_WARNING, "Unable to lock the gateways list.\n");
/* We always want to leave this in a consistent state */
ast_channel_register(&mgcp_tech);
/* Allow the monitor to restart */
monitor_thread = AST_PTHREADT_NULL;
mgcp_reloading = 0;
mgcp_reload(NULL, 0, NULL);
return -1;
}
close(mgcpsock);
ast_rtp_proto_unregister(&mgcp_rtp);
ast_cli_unregister_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
sched_context_destroy(sched);
return 0;
}
struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Media Gateway Control Protocol (MGCP)" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 4397 of file chan_mgcp.c.
struct in_addr __ourip [static] |
Definition at line 218 of file chan_mgcp.c.
Referenced by build_gateway(), find_subchannel_and_lock(), and reload_config().
char accountcode[AST_MAX_ACCOUNT_CODE] = "" [static] |
Definition at line 183 of file chan_mgcp.c.
int adsi = 0 [static] |
Definition at line 189 of file chan_mgcp.c.
Referenced by build_gateway().
int amaflags = 0 [static] |
Definition at line 187 of file chan_mgcp.c.
Referenced by build_gateway().
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 4397 of file chan_mgcp.c.
struct sockaddr_in bindaddr [static] |
Definition at line 405 of file chan_mgcp.c.
Referenced by reload_config(), and start_rtp().
int callreturn = 0 [static] |
Definition at line 168 of file chan_mgcp.c.
Referenced by build_gateway().
int callwaiting = 0 [static] |
Definition at line 166 of file chan_mgcp.c.
Referenced by build_gateway().
int cancallforward = 0 [static] |
Definition at line 177 of file chan_mgcp.c.
Referenced by build_gateway().
int capability = AST_FORMAT_ULAW [static] |
Definition at line 214 of file chan_mgcp.c.
Referenced by ast_iax2_new(), build_gateway(), build_setup(), iax2_call(), mgcp_new(), mgcp_request(), parse_setup(), set_config(), and set_local_capabilities().
char cid_name[AST_MAX_EXTENSION] = "" [static] |
Definition at line 149 of file chan_mgcp.c.
Referenced by __oh323_new(), apply_outgoing(), ast_pbx_outgoing_exten(), build_peer(), build_user(), check_access(), check_peer_ok(), check_user_full(), dahdi_handle_event(), dial_trunk(), misdn_new(), replace_cid(), set_peer_defaults(), set_pvt_defaults(), sip_call(), sla_ring_station(), and store_callerid().
char cid_num[AST_MAX_EXTENSION] = "" [static] |
Definition at line 148 of file chan_mgcp.c.
Referenced by __oh323_new(), apply_outgoing(), ast_pbx_outgoing_exten(), build_peer(), build_user(), check_access(), check_peer_ok(), check_user_full(), dahdi_handle_event(), dial_trunk(), misdn_new(), replace_cid(), set_peer_defaults(), set_pvt_defaults(), sla_ring_station(), socket_process(), and store_callerid().
struct ast_cli_entry cli_mgcp[] [static] |
Definition at line 1170 of file chan_mgcp.c.
const char config[] = "mgcp.conf" [static] |
Definition at line 101 of file chan_mgcp.c.
char context[AST_MAX_EXTENSION] = "default" [static] |
Definition at line 143 of file chan_mgcp.c.
| unsigned int cos |
Definition at line 160 of file chan_mgcp.c.
| unsigned int cos_audio |
Definition at line 161 of file chan_mgcp.c.
ast_group_t cur_callergroup = 0 [static] |
Definition at line 154 of file chan_mgcp.c.
Referenced by build_gateway().
ast_group_t cur_pickupgroup = 0 [static] |
Definition at line 155 of file chan_mgcp.c.
Referenced by build_gateway().
struct ast_jb_conf default_jbconf [static] |
Global jitterbuffer configuration - by default, jb is disabled
Definition at line 90 of file chan_mgcp.c.
int directmedia = DIRECTMEDIA [static] |
Definition at line 181 of file chan_mgcp.c.
Referenced by build_gateway().
int dtmfmode = 0 [static] |
Definition at line 151 of file chan_mgcp.c.
Referenced by build_gateway(), and set_local_capabilities().
int firstdigittimeout = 16000 [static] |
Wait up to 16 seconds for first digit (FXO logic)
Definition at line 194 of file chan_mgcp.c.
Referenced by mgcp_ss().
ast_mutex_t gatelock = AST_MUTEX_INIT_VALUE [static] |
gatelock: mutex for gateway/endpoint lists
Definition at line 401 of file chan_mgcp.c.
Referenced by find_subchannel_and_lock(), handle_mgcp_audit_endpoint(), handle_mgcp_show_endpoints(), mgcp_devicestate(), prune_gateways(), reload_config(), and unload_module().
struct mgcp_gateway * gateways [static] |
int gendigittimeout = 8000 [static] |
How long to wait for following digits (FXO logic)
Definition at line 197 of file chan_mgcp.c.
Referenced by mgcp_ss().
struct ast_jb_conf global_jbconf [static] |
Definition at line 98 of file chan_mgcp.c.
Referenced by mgcp_new(), and reload_config().
int immediate = 0 [static] |
Definition at line 164 of file chan_mgcp.c.
Referenced by build_gateway().
struct io_context* io [static] |
Definition at line 224 of file chan_mgcp.c.
char language[MAX_LANGUAGE] = "" [static] |
Definition at line 145 of file chan_mgcp.c.
char mailbox[AST_MAX_EXTENSION] [static] |
Definition at line 185 of file chan_mgcp.c.
Referenced by action_mailboxcount(), action_mailboxstatus(), add_peer_mailboxes(), add_peer_mwi_subs(), append_mailbox_mapping(), ast_event_hash_mwi(), build_peer(), chanspy_exec(), clear_peer_mailboxes(), disa_exec(), extenspy_exec(), get_cached_mwi(), has_voicemail(), minivm_mwi_exec(), mkintf(), notify_message(), peer_mailboxes_to_str(), queue_mwi_event(), realtime_directory(), sip_subscribe_mwi(), unistim_send_mwi_to_peer(), and update_registry().
int matchdigittimeout = 3000 [static] |
How long to wait for an extra digit, if there is an ambiguous match
Definition at line 200 of file chan_mgcp.c.
Referenced by mgcp_ss().
char* mgcp_cxmodes[] [static] |
}
Definition at line 123 of file chan_mgcp.c.
ast_mutex_t mgcp_reload_lock = AST_MUTEX_INIT_VALUE [static] |
Definition at line 397 of file chan_mgcp.c.
Referenced by do_monitor(), mgcp_reload(), and unload_module().
int mgcp_reloading = 0 [static] |
Definition at line 398 of file chan_mgcp.c.
Referenced by do_monitor().
struct ast_rtp_protocol mgcp_rtp [static] |
{
.type = "MGCP",
.get_rtp_info = mgcp_get_rtp_peer,
.set_rtp_peer = mgcp_set_rtp_peer,
}
Definition at line 3974 of file chan_mgcp.c.
struct ast_channel_tech mgcp_tech [static] |
Definition at line 435 of file chan_mgcp.c.
Referenced by mgcp_new().
int mgcpdebug = 0 [static] |
Definition at line 221 of file chan_mgcp.c.
int mgcpsock = -1 [static] |
Definition at line 403 of file chan_mgcp.c.
int* mgcpsock_read_id = NULL [static] |
Definition at line 3384 of file chan_mgcp.c.
pthread_t monitor_thread = AST_PTHREADT_NULL [static] |
This is the thread for the monitor which checks for input on the channels which are not currently in use.
Definition at line 210 of file chan_mgcp.c.
ast_mutex_t monlock = AST_MUTEX_INIT_VALUE [static] |
Definition at line 206 of file chan_mgcp.c.
Referenced by do_monitor(), restart_monitor(), and unload_module().
char musicclass[MAX_MUSICCLASS] = "" [static] |
Definition at line 146 of file chan_mgcp.c.
Referenced by ast_do_masquerade(), begin_dial_channel(), dial_exec_full(), findmeexec(), func_channel_write_real(), gtalk_new(), jingle_new(), local_call(), moh_handle_digit(), monitor_dial(), and set_moh_exec().
int nat = 0 [static] |
Definition at line 152 of file chan_mgcp.c.
Referenced by ast_rtp_setnat(), ast_udptl_setnat(), and build_gateway().
ast_mutex_t netlock = AST_MUTEX_INIT_VALUE [static] |
Protect the monitoring thread, so only one process can kill or start it, and not when it's doing something critical.
Definition at line 204 of file chan_mgcp.c.
Referenced by do_monitor(), and reload_config().
int nonCodecCapability = AST_RTP_DTMF [static] |
Definition at line 215 of file chan_mgcp.c.
unsigned int oseq [static] |
Definition at line 191 of file chan_mgcp.c.
Referenced by transmit_audit_endpoint(), transmit_connect_with_sdp(), transmit_connection_del(), transmit_connection_del_w_params(), transmit_modify_request(), transmit_modify_with_sdp(), transmit_notify_request(), and transmit_notify_request_with_callerid().
char ourhost[MAXHOSTNAMELEN] [static] |
Definition at line 217 of file chan_mgcp.c.
Referenced by ast_find_ourip().
int ourport [static] |
Definition at line 219 of file chan_mgcp.c.
Referenced by build_contact(), initreqprep(), and transmit_notify_with_mwi().
char parkinglot[AST_MAX_CONTEXT] [static] |
Definition at line 147 of file chan_mgcp.c.
struct { ... } qos [static] |
Referenced by reload_config(), and start_rtp().
struct sched_context* sched [static] |
Definition at line 223 of file chan_mgcp.c.
int singlepath = 0 [static] |
Definition at line 179 of file chan_mgcp.c.
Referenced by build_gateway().
int slowsequence = 0 [static] |
Definition at line 170 of file chan_mgcp.c.
Referenced by build_gateway().
const char tdesc[] = "Media Gateway Control Protocol (MGCP)" [static] |
Definition at line 100 of file chan_mgcp.c.
int threewaycalling = 0 [static] |
Definition at line 172 of file chan_mgcp.c.
Referenced by build_gateway().
| unsigned int tos |
Definition at line 158 of file chan_mgcp.c.
| unsigned int tos_audio |
Definition at line 159 of file chan_mgcp.c.
int transfer = 0 [static] |
This is for flashhook transfers
Definition at line 175 of file chan_mgcp.c.
Referenced by build_gateway(), iax2_send(), leave_voicemail(), and send_packet().