Fri Nov 12 11:56:09 2010

Asterisk developer's documentation


chan_mgcp.c File Reference

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"
Include dependency graph for chan_mgcp.c:

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_gatewaybuild_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_requestfind_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_subchannelfind_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_channelmgcp_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_framemgcp_read (struct ast_channel *ast)
static char * mgcp_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct ast_channelmgcp_request (const char *type, int format, void *data, int *cause)
static struct ast_framemgcp_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 __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Media Gateway Control Protocol (MGCP)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "0901e4e500243c855563a2d78b0c03e4" , .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_infoast_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_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP )
 gatelock: mutex for gateway/endpoint lists
static struct mgcp_gatewaygateways
static int gendigittimeout = 8000
static struct ast_jb_conf global_jbconf
static int immediate = 0
static struct io_contextio
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_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP )
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_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP )
static char musicclass [MAX_MUSICCLASS] = ""
static int nat = 0
static ast_mutex_t netlock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP )
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_contextsched
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

Detailed Description

Implementation of Media Gateway Control Protocol.

Author:
Mark Spencer <markster@digium.com>
See also

Definition in file chan_mgcp.c.


Define Documentation

#define DEFAULT_EXPIRY   120

Definition at line 81 of file chan_mgcp.c.

#define DEFAULT_MGCP_CA_PORT   2727

From RFC 2705

Definition at line 108 of file chan_mgcp.c.

Referenced by reload_config().

#define DEFAULT_MGCP_GW_PORT   2427

From RFC 2705

Definition at line 107 of file chan_mgcp.c.

Referenced by build_gateway().

#define DEFAULT_RETRANS   1000

How frequently to retransmit

Definition at line 110 of file chan_mgcp.c.

Referenced by __sip_reliable_xmit(), mgcp_postrequest(), and retrans_pkt().

#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(), destroy_endpoint(), reload_config(), and unistim_info().

#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)
#define MGCP_DTMF_INBAND   (1 << 1)
#define MGCP_DTMF_RFC2833   (1 << 0)
#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
#define MGCP_ONHOOK   1
#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

in seconds

Definition at line 259 of file chan_mgcp.c.

Referenced by find_and_retrans().

#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
#define TYPE_TRUNK   1

Definition at line 305 of file chan_mgcp.c.

Referenced by build_gateway().


Enumeration Type Documentation

anonymous enum
Enumerator:
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.

00131      {
00132    MGCP_CMD_EPCF,
00133    MGCP_CMD_CRCX,
00134    MGCP_CMD_MDCX,
00135    MGCP_CMD_DLCX,
00136    MGCP_CMD_RQNT,
00137    MGCP_CMD_NTFY,
00138    MGCP_CMD_AUEP,
00139    MGCP_CMD_AUCX,
00140    MGCP_CMD_RSIP
00141 };


Function Documentation

static char* __get_header ( struct mgcp_request req,
char *  name,
int *  start 
) [static]

Definition at line 1578 of file chan_mgcp.c.

References mgcp_request::header, mgcp_request::headers, and len().

Referenced by get_header().

01579 {
01580    int x;
01581    int len = strlen(name);
01582    char *r;
01583    for (x=*start;x<req->headers;x++) {
01584       if (!strncasecmp(req->header[x], name, len) && 
01585           (req->header[x][len] == ':')) {
01586          r = req->header[x] + len + 1;
01587          while(*r && (*r < 33))
01588             r++;
01589          *start = x+1;
01590          return r;
01591       }
01592    }
01593    /* Don't return NULL, so get_header is always a valid pointer */
01594    return "";
01595 }

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().

00516 {
00517    int res;
00518    if (gw->addr.sin_addr.s_addr)
00519       res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->addr, sizeof(struct sockaddr_in));
00520    else 
00521       res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->defaddr, sizeof(struct sockaddr_in));
00522    if (res != len) {
00523       ast_log(LOG_WARNING, "mgcp_xmit returned %d: %s\n", res, strerror(errno));
00524    }
00525    return res;
00526 }

static void __reg_module ( void   )  [static]

Definition at line 4394 of file chan_mgcp.c.

static void __unreg_module ( void   )  [static]

Definition at line 4394 of file chan_mgcp.c.

static int add_header ( struct mgcp_request req,
char *  var,
char *  value 
) [static]

Definition at line 1924 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().

01925 {
01926    if (req->len >= sizeof(req->data) - 4) {
01927       ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
01928       return -1;
01929    }
01930    if (req->lines) {
01931       ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n");
01932       return -1;
01933    }
01934    req->header[req->headers] = req->data + req->len;
01935    snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s: %s\r\n", var, value);
01936    req->len += strlen(req->header[req->headers]);
01937    if (req->headers < MGCP_MAX_HEADERS)
01938       req->headers++;
01939    else {
01940       ast_log(LOG_WARNING, "Out of header space\n");
01941       return -1;
01942    }
01943    return 0;   
01944 }

static void add_header_offhook ( struct mgcp_subchannel sub,
struct mgcp_request resp 
) [static]

Definition at line 2319 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().

02320 {
02321    struct mgcp_endpoint *p = sub->parent;
02322 
02323    if (p && p->sub && p->sub->owner && p->sub->owner->_state >= AST_STATE_RINGING && (p->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)))
02324       add_header(resp, "R", "L/hu(N),L/hf(N)");
02325    else
02326       add_header(resp, "R", "L/hu(N),L/hf(N),D/[0-9#*](N)");
02327 }

static int add_line ( struct mgcp_request req,
char *  line 
) [static]

Definition at line 1946 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().

01947 {
01948    if (req->len >= sizeof(req->data) - 4) {
01949       ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
01950       return -1;
01951    }
01952    if (!req->lines) {
01953       /* Add extra empty return */
01954       ast_copy_string(req->data + req->len, "\r\n", sizeof(req->data) - req->len);
01955       req->len += strlen(req->data + req->len);
01956    }
01957    req->line[req->lines] = req->data + req->len;
01958    snprintf(req->line[req->lines], sizeof(req->data) - req->len, "%s", line);
01959    req->len += strlen(req->line[req->lines]);
01960    if (req->lines < MGCP_MAX_LINES)
01961       req->lines++;
01962    else {
01963       ast_log(LOG_WARNING, "Out of line space\n");
01964       return -1;
01965    }
01966    return 0;   
01967 }

static int add_sdp ( struct mgcp_request resp,
struct mgcp_subchannel sub,
struct ast_rtp rtp 
) [static]

Definition at line 2047 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().

02048 {
02049    int len;
02050    int codec;
02051    char costr[80];
02052    struct sockaddr_in sin;
02053    char v[256];
02054    char s[256];
02055    char o[256];
02056    char c[256];
02057    char t[256];
02058    char m[256] = "";
02059    char a[1024] = "";
02060    int x;
02061    struct sockaddr_in dest;
02062    struct mgcp_endpoint *p = sub->parent;
02063    /* XXX We break with the "recommendation" and send our IP, in order that our
02064           peer doesn't have to ast_gethostbyname() us XXX */
02065    len = 0;
02066    if (!sub->rtp) {
02067       ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n");
02068       return -1;
02069    }
02070    ast_rtp_get_us(sub->rtp, &sin);
02071    if (rtp) {
02072       ast_rtp_get_peer(rtp, &dest);
02073    } else {
02074       if (sub->tmpdest.sin_addr.s_addr) {
02075          dest.sin_addr = sub->tmpdest.sin_addr;
02076          dest.sin_port = sub->tmpdest.sin_port;
02077          /* Reset temporary destination */
02078          memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
02079       } else {
02080          dest.sin_addr = p->parent->ourip;
02081          dest.sin_port = sin.sin_port;
02082       }
02083    }
02084    if (mgcpdebug) {
02085       ast_verbose("We're at %s port %d\n", ast_inet_ntoa(p->parent->ourip), ntohs(sin.sin_port));
02086    }
02087    ast_copy_string(v, "v=0\r\n", sizeof(v));
02088    snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", (int)getpid(), (int)getpid(), ast_inet_ntoa(dest.sin_addr));
02089    ast_copy_string(s, "s=session\r\n", sizeof(s));
02090    snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr));
02091    ast_copy_string(t, "t=0 0\r\n", sizeof(t));
02092    snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port));
02093    for (x = 1; x <= AST_FORMAT_AUDIO_MASK; x <<= 1) {
02094       if (p->capability & x) {
02095          if (mgcpdebug) {
02096             ast_verbose("Answering with capability %d\n", x);
02097          }
02098          codec = ast_rtp_lookup_code(sub->rtp, 1, x);
02099          if (codec > -1) {
02100             snprintf(costr, sizeof(costr), " %d", codec);
02101             strncat(m, costr, sizeof(m) - strlen(m) - 1);
02102             snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(1, x, 0));
02103             strncat(a, costr, sizeof(a) - strlen(a) - 1);
02104          }
02105       }
02106    }
02107    for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
02108       if (p->nonCodecCapability & x) {
02109          if (mgcpdebug) {
02110             ast_verbose("Answering with non-codec capability %d\n", x);
02111          }
02112          codec = ast_rtp_lookup_code(sub->rtp, 0, x);
02113          if (codec > -1) {
02114             snprintf(costr, sizeof(costr), " %d", codec);
02115             strncat(m, costr, sizeof(m) - strlen(m) - 1);
02116             snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(0, x, 0));
02117             strncat(a, costr, sizeof(a) - strlen(a) - 1);
02118             if (x == AST_RTP_DTMF) {
02119                /* Indicate we support DTMF...  Not sure about 16,
02120                   but MSN supports it so dang it, we will too... */
02121                snprintf(costr, sizeof costr, "a=fmtp:%d 0-16\r\n", codec);
02122                strncat(a, costr, sizeof(a) - strlen(a) - 1);
02123             }
02124          }
02125       }
02126    }
02127    strncat(m, "\r\n", sizeof(m) - strlen(m) - 1);
02128    len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a);
02129    snprintf(costr, sizeof(costr), "%d", len);
02130    add_line(resp, v);
02131    add_line(resp, o);
02132    add_line(resp, s);
02133    add_line(resp, c);
02134    add_line(resp, t);
02135    add_line(resp, m);
02136    add_line(resp, a);
02137    return 0;
02138 }

static int attempt_transfer ( struct mgcp_endpoint p  )  [static]

Definition at line 2884 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().

02885 {
02886    /* *************************
02887     * I hope this works.
02888     * Copied out of chan_zap
02889     * Cross your fingers
02890     * *************************/
02891 
02892    /* In order to transfer, we need at least one of the channels to
02893       actually be in a call bridge.  We can't conference two applications
02894       together (but then, why would we want to?) */
02895    if (ast_bridged_channel(p->sub->owner)) {
02896       /* The three-way person we're about to transfer to could still be in MOH, so
02897          stop if now if appropriate */
02898       if (ast_bridged_channel(p->sub->next->owner))
02899          ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
02900       if (p->sub->owner->_state == AST_STATE_RINGING) {
02901          ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
02902       }
02903       if (ast_channel_masquerade(p->sub->next->owner, ast_bridged_channel(p->sub->owner))) {
02904          ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
02905             ast_bridged_channel(p->sub->owner)->name, p->sub->next->owner->name);
02906          return -1;
02907       }
02908       /* Orphan the channel */
02909       unalloc_sub(p->sub->next);
02910    } else if (ast_bridged_channel(p->sub->next->owner)) {
02911       if (p->sub->owner->_state == AST_STATE_RINGING) {
02912          ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
02913       }
02914       ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
02915       if (ast_channel_masquerade(p->sub->owner, ast_bridged_channel(p->sub->next->owner))) {
02916          ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
02917             ast_bridged_channel(p->sub->next->owner)->name, p->sub->owner->name);
02918          return -1;
02919       }
02920       /*swap_subs(p, SUB_THREEWAY, SUB_REAL);*/
02921       ast_verb(3, "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name);
02922       p->sub = p->sub->next;
02923       unalloc_sub(p->sub->next);
02924       /* Tell the caller not to hangup */
02925       return 1;
02926    } else {
02927       ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
02928          p->sub->owner->name, p->sub->next->owner->name);
02929       p->sub->next->owner->_softhangup |= AST_SOFTHANGUP_DEV;
02930       if (p->sub->next->owner) {
02931          p->sub->next->alreadygone = 1;
02932          mgcp_queue_hangup(p->sub->next);
02933       }
02934    }
02935    return 0;
02936 }

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 3552 of file chan_mgcp.c.

References __ourip, mgcp_endpoint::accountcode, mgcp_gateway::addr, mgcp_endpoint::adsi, 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_strlen_zero(), ast_true(), ast_verb, mgcp_endpoint::callgroup, mgcp_endpoint::callreturn, mgcp_endpoint::callwaiting, mgcp_endpoint::cancallforward, mgcp_endpoint::capability, mgcp_endpoint::cid_name, mgcp_endpoint::cid_num, mgcp_endpoint::cmd_queue_lock, mgcp_endpoint::context, mgcp_subchannel::cx_queue_lock, mgcp_subchannel::cxmode, mgcp_gateway::defaddr, DEFAULT_MGCP_GW_PORT, mgcp_endpoint::delme, mgcp_gateway::delme, mgcp_endpoint::directmedia, DIRECTMEDIA, 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, 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, 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, mgcp_endpoint::singlepath, mgcp_endpoint::slowsequence, mgcp_endpoint::sub, mgcp_endpoint::threewaycalling, mgcp_endpoint::transfer, mgcp_subchannel::txident, mgcp_endpoint::type, TYPE_LINE, TYPE_TRUNK, ast_variable::value, and mgcp_gateway::wcardep.

Referenced by reload_config().

03553 {
03554    struct mgcp_gateway *gw;
03555    struct mgcp_endpoint *e;
03556    struct mgcp_subchannel *sub;
03557    /*char txident[80];*/
03558    int i=0, y=0;
03559    int gw_reload = 0;
03560    int ep_reload = 0;
03561    directmedia = DIRECTMEDIA;
03562 
03563    /* locate existing gateway */
03564    gw = gateways;
03565    while (gw) {
03566       if (!strcasecmp(cat, gw->name)) {
03567          /* gateway already exists */
03568          gw->delme = 0;
03569          gw_reload = 1;
03570          break;
03571       }
03572       gw = gw->next;
03573    }
03574 
03575    if (!gw)
03576       gw = ast_calloc(1, sizeof(*gw));
03577 
03578    if (gw) {
03579       if (!gw_reload) {
03580          gw->expire = -1;
03581          gw->retransid = -1; /* SC */
03582          ast_mutex_init(&gw->msgs_lock);
03583          ast_copy_string(gw->name, cat, sizeof(gw->name));
03584          /* check if the name is numeric ip */
03585          if ((strchr(gw->name, '.')) && inet_addr(gw->name) != INADDR_NONE)
03586             gw->isnamedottedip = 1;
03587       }
03588       while(v) {
03589          if (!strcasecmp(v->name, "host")) {
03590             if (!strcasecmp(v->value, "dynamic")) {
03591                /* They'll register with us */
03592                gw->dynamic = 1;
03593                memset(&gw->addr.sin_addr, 0, 4);
03594                if (gw->addr.sin_port) {
03595                   /* If we've already got a port, make it the default rather than absolute */
03596                   gw->defaddr.sin_port = gw->addr.sin_port;
03597                   gw->addr.sin_port = 0;
03598                }
03599             } else {
03600                /* Non-dynamic.  Make sure we become that way if we're not */
03601                AST_SCHED_DEL(sched, gw->expire);
03602                gw->dynamic = 0;
03603                if (ast_get_ip(&gw->addr, v->value)) {
03604                   if (!gw_reload) {
03605                      ast_mutex_destroy(&gw->msgs_lock);
03606                      ast_free(gw);
03607                   }
03608                   return NULL;
03609                }
03610             }
03611          } else if (!strcasecmp(v->name, "defaultip")) {
03612             if (ast_get_ip(&gw->defaddr, v->value)) {
03613                if (!gw_reload) {
03614                   ast_mutex_destroy(&gw->msgs_lock);
03615                   ast_free(gw);
03616                }
03617                return NULL;
03618             }
03619          } else if (!strcasecmp(v->name, "permit") ||
03620             !strcasecmp(v->name, "deny")) {
03621             gw->ha = ast_append_ha(v->name, v->value, gw->ha, NULL);
03622          } else if (!strcasecmp(v->name, "port")) {
03623             gw->addr.sin_port = htons(atoi(v->value));
03624          } else if (!strcasecmp(v->name, "context")) {
03625             ast_copy_string(context, v->value, sizeof(context));
03626          } else if (!strcasecmp(v->name, "dtmfmode")) {
03627             if (!strcasecmp(v->value, "inband"))
03628                dtmfmode = MGCP_DTMF_INBAND;
03629             else if (!strcasecmp(v->value, "rfc2833")) 
03630                dtmfmode = MGCP_DTMF_RFC2833;
03631             else if (!strcasecmp(v->value, "hybrid"))
03632                dtmfmode = MGCP_DTMF_HYBRID;
03633             else if (!strcasecmp(v->value, "none")) 
03634                dtmfmode = 0;
03635             else
03636                ast_log(LOG_WARNING, "'%s' is not a valid DTMF mode at line %d\n", v->value, v->lineno);
03637          } else if (!strcasecmp(v->name, "nat")) {
03638             nat = ast_true(v->value);
03639          } else if (!strcasecmp(v->name, "callerid")) {
03640             if (!strcasecmp(v->value, "asreceived")) {
03641                cid_num[0] = '\0';
03642                cid_name[0] = '\0';
03643             } else {
03644                ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
03645             }
03646          } else if (!strcasecmp(v->name, "language")) {
03647             ast_copy_string(language, v->value, sizeof(language));
03648          } else if (!strcasecmp(v->name, "accountcode")) {
03649             ast_copy_string(accountcode, v->value, sizeof(accountcode));
03650          } else if (!strcasecmp(v->name, "amaflags")) {
03651             y = ast_cdr_amaflags2int(v->value);
03652             if (y < 0) {
03653                ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
03654             } else {
03655                amaflags = y;
03656             }
03657          } else if (!strcasecmp(v->name, "musiconhold")) {
03658             ast_copy_string(musicclass, v->value, sizeof(musicclass));
03659          } else if (!strcasecmp(v->name, "parkinglot")) {
03660             ast_copy_string(parkinglot, v->value, sizeof(parkinglot));
03661          } else if (!strcasecmp(v->name, "callgroup")) {
03662             cur_callergroup = ast_get_group(v->value);
03663          } else if (!strcasecmp(v->name, "pickupgroup")) {
03664             cur_pickupgroup = ast_get_group(v->value);
03665          } else if (!strcasecmp(v->name, "immediate")) {
03666             immediate = ast_true(v->value);
03667          } else if (!strcasecmp(v->name, "cancallforward")) {
03668             cancallforward = ast_true(v->value);
03669          } else if (!strcasecmp(v->name, "singlepath")) {
03670             singlepath = ast_true(v->value);
03671          } else if (!strcasecmp(v->name, "directmedia") || !strcasecmp(v->name, "canreinvite")) {
03672             directmedia = ast_true(v->value);
03673          } else if (!strcasecmp(v->name, "mailbox")) {
03674             ast_copy_string(mailbox, v->value, sizeof(mailbox));
03675          } else if (!strcasecmp(v->name, "hasvoicemail")) {
03676             if (ast_true(v->value) && ast_strlen_zero(mailbox)) {
03677                ast_copy_string(mailbox, gw->name, sizeof(mailbox));
03678             }
03679          } else if (!strcasecmp(v->name, "adsi")) {
03680             adsi = ast_true(v->value);
03681          } else if (!strcasecmp(v->name, "callreturn")) {
03682             callreturn = ast_true(v->value);
03683          } else if (!strcasecmp(v->name, "callwaiting")) {
03684             callwaiting = ast_true(v->value);
03685          } else if (!strcasecmp(v->name, "slowsequence")) {
03686             slowsequence = ast_true(v->value);
03687          } else if (!strcasecmp(v->name, "transfer")) {
03688             transfer = ast_true(v->value);
03689          } else if (!strcasecmp(v->name, "threewaycalling")) {
03690             threewaycalling = ast_true(v->value);
03691          } else if (!strcasecmp(v->name, "wcardep")) {
03692             /* locate existing endpoint */
03693             e = gw->endpoints;
03694             while (e) {
03695                if (!strcasecmp(v->value, e->name)) {
03696                   /* endpoint already exists */
03697                   e->delme = 0;
03698                   ep_reload = 1;
03699                   break;
03700                }
03701                e = e->next;
03702             }
03703 
03704             if (!e) {
03705                /* Allocate wildcard endpoint */
03706                e = ast_calloc(1, sizeof(*e));
03707                ep_reload = 0;
03708             }
03709 
03710             if (e) {
03711                if (!ep_reload) {
03712                   memset(e, 0, sizeof(struct mgcp_endpoint));
03713                   ast_mutex_init(&e->lock);
03714                   ast_mutex_init(&e->rqnt_queue_lock);
03715                   ast_mutex_init(&e->cmd_queue_lock);
03716                   ast_copy_string(e->name, v->value, sizeof(e->name));
03717                   e->needaudit = 1;
03718                }
03719                ast_copy_string(gw->wcardep, v->value, sizeof(gw->wcardep));
03720                /* XXX Should we really check for uniqueness?? XXX */
03721                ast_copy_string(e->accountcode, accountcode, sizeof(e->accountcode));
03722                ast_copy_string(e->context, context, sizeof(e->context));
03723                ast_copy_string(e->cid_num, cid_num, sizeof(e->cid_num));
03724                ast_copy_string(e->cid_name, cid_name, sizeof(e->cid_name));
03725                ast_copy_string(e->language, language, sizeof(e->language));
03726                ast_copy_string(e->musicclass, musicclass, sizeof(e->musicclass));
03727                ast_copy_string(e->mailbox, mailbox, sizeof(e->mailbox));
03728                ast_copy_string(e->parkinglot, parkinglot, sizeof(e->parkinglot));
03729                if (!ast_strlen_zero(e->mailbox)) {
03730                   char *mbox, *cntx;
03731                   cntx = mbox = ast_strdupa(e->mailbox);
03732                   strsep(&cntx, "@");
03733                   if (ast_strlen_zero(cntx))
03734                      cntx = "default";
03735                   e->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, NULL,
03736                      AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mbox,
03737                      AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, cntx,
03738                      AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
03739                      AST_EVENT_IE_END);
03740                }
03741                snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", ast_random());
03742                e->msgstate = -1;
03743                e->amaflags = amaflags;
03744                e->capability = capability;
03745                e->parent = gw;
03746                e->dtmfmode = dtmfmode;
03747                if (!ep_reload && e->sub && e->sub->rtp)
03748                   e->dtmfmode |= MGCP_DTMF_INBAND;
03749                e->adsi = adsi;
03750                e->type = TYPE_LINE;
03751                e->immediate = immediate;
03752                e->callgroup=cur_callergroup;
03753                e->pickupgroup=cur_pickupgroup;
03754                e->callreturn = callreturn;
03755                e->cancallforward = cancallforward;
03756                e->singlepath = singlepath;
03757                e->directmedia = directmedia;
03758                e->callwaiting = callwaiting;
03759                e->hascallwaiting = callwaiting;
03760                e->slowsequence = slowsequence;
03761                e->transfer = transfer;
03762                e->threewaycalling = threewaycalling;
03763                e->onhooktime = time(NULL);
03764                /* ASSUME we're onhook */
03765                e->hookstate = MGCP_ONHOOK;
03766                if (!ep_reload) {
03767                   /*snprintf(txident, sizeof(txident), "%08lx", ast_random());*/
03768                   for (i = 0; i < MAX_SUBS; i++) {
03769                      sub = ast_calloc(1, sizeof(*sub));
03770                      if (sub) {
03771                         ast_verb(3, "Allocating subchannel '%d' on %s@%s\n", i, e->name, gw->name);
03772                         ast_mutex_init(&sub->lock);
03773                         ast_mutex_init(&sub->cx_queue_lock);
03774                         sub->parent = e;
03775                         sub->id = i;
03776                         snprintf(sub->txident, sizeof(sub->txident), "%08lx", ast_random());
03777                         /*stnrcpy(sub->txident, txident, sizeof(sub->txident) - 1);*/
03778                         sub->cxmode = MGCP_CX_INACTIVE;
03779                         sub->nat = nat;
03780                         sub->next = e->sub;
03781                         e->sub = sub;
03782                      } else {
03783                         /* XXX Should find a way to clean up our memory */
03784                         ast_log(LOG_WARNING, "Out of memory allocating subchannel\n");
03785                         return NULL;
03786                      }
03787                   }
03788                   /* Make out subs a circular linked list so we can always sping through the whole bunch */
03789                   sub = e->sub;
03790                   /* find the end of the list */
03791                   while(sub->next){
03792                      sub = sub->next;
03793                   }
03794                   /* set the last sub->next to the first sub */
03795                   sub->next = e->sub;
03796 
03797                   e->next = gw->endpoints;
03798                   gw->endpoints = e;
03799                }
03800             }
03801          } else if (!strcasecmp(v->name, "trunk") ||
03802                     !strcasecmp(v->name, "line")) {
03803 
03804             /* locate existing endpoint */
03805             e = gw->endpoints;
03806             while (e) {
03807                if (!strcasecmp(v->value, e->name)) {
03808                   /* endpoint already exists */
03809                   e->delme = 0;
03810                   ep_reload = 1;
03811                   break;
03812                }
03813                e = e->next;
03814             }
03815 
03816             if (!e) {
03817                e = ast_calloc(1, sizeof(*e));
03818                ep_reload = 0;
03819             }
03820 
03821             if (e) {
03822                if (!ep_reload) {
03823                   ast_mutex_init(&e->lock);
03824                   ast_mutex_init(&e->rqnt_queue_lock);
03825                   ast_mutex_init(&e->cmd_queue_lock);
03826                   ast_copy_string(e->name, v->value, sizeof(e->name));
03827                   e->needaudit = 1;
03828                }
03829                /* XXX Should we really check for uniqueness?? XXX */
03830                ast_copy_string(e->accountcode, accountcode, sizeof(e->accountcode));
03831                ast_copy_string(e->context, context, sizeof(e->context));
03832                ast_copy_string(e->cid_num, cid_num, sizeof(e->cid_num));
03833                ast_copy_string(e->cid_name, cid_name, sizeof(e->cid_name));
03834                ast_copy_string(e->language, language, sizeof(e->language));
03835                ast_copy_string(e->musicclass, musicclass, sizeof(e->musicclass));
03836                ast_copy_string(e->mailbox, mailbox, sizeof(e->mailbox));
03837                ast_copy_string(e->parkinglot, parkinglot, sizeof(e->parkinglot));
03838                if (!ast_strlen_zero(mailbox)) {
03839                   ast_verb(3, "Setting mailbox '%s' on %s@%s\n", mailbox, gw->name, e->name);
03840                }
03841                if (!ep_reload) {
03842                   /* XXX potential issue due to reload */
03843                   e->msgstate = -1;
03844                   e->parent = gw;
03845                }
03846                e->amaflags = amaflags;
03847                e->capability = capability;
03848                e->dtmfmode = dtmfmode;
03849                e->adsi = adsi;
03850                if (!strcasecmp(v->name, "trunk"))
03851                   e->type = TYPE_TRUNK;
03852                else
03853                   e->type = TYPE_LINE;
03854 
03855                e->immediate = immediate;
03856                e->callgroup=cur_callergroup;
03857                e->pickupgroup=cur_pickupgroup;
03858                e->callreturn = callreturn;
03859                e->cancallforward = cancallforward;
03860                e->directmedia = directmedia;
03861                e->singlepath = singlepath;
03862                e->callwaiting = callwaiting;
03863                e->hascallwaiting = callwaiting;
03864                e->slowsequence = slowsequence;
03865                e->transfer = transfer;
03866                e->threewaycalling = threewaycalling;
03867                if (!ep_reload) {
03868                   e->onhooktime = time(NULL);
03869                   /* ASSUME we're onhook */
03870                   e->hookstate = MGCP_ONHOOK;
03871                   snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", ast_random());
03872                }
03873 
03874                for (i = 0, sub = NULL; i < MAX_SUBS; i++) {
03875                   if (!ep_reload) {
03876                      sub = ast_calloc(1, sizeof(*sub));
03877                   } else {
03878                      if (!sub)
03879                         sub = e->sub;
03880                      else
03881                         sub = sub->next;
03882                   }
03883 
03884                   if (sub) {
03885                      if (!ep_reload) {
03886                         ast_verb(3, "Allocating subchannel '%d' on %s@%s\n", i, e->name, gw->name);
03887                         ast_mutex_init(&sub->lock);
03888                         ast_mutex_init(&sub->cx_queue_lock);
03889                         ast_copy_string(sub->magic, MGCP_SUBCHANNEL_MAGIC, sizeof(sub->magic));
03890                         sub->parent = e;
03891                         sub->id = i;
03892                         snprintf(sub->txident, sizeof(sub->txident), "%08lx", ast_random());
03893                         sub->cxmode = MGCP_CX_INACTIVE;
03894                         sub->next = e->sub;
03895                         e->sub = sub;
03896                      }
03897                      sub->nat = nat;
03898                   } else {
03899                      /* XXX Should find a way to clean up our memory */
03900                      ast_log(LOG_WARNING, "Out of memory allocating subchannel\n");
03901                      return NULL;
03902                   }
03903                }
03904                if (!ep_reload) {
03905                   /* Make out subs a circular linked list so we can always sping through the whole bunch */
03906                   sub = e->sub;
03907                   /* find the end of the list */
03908                   while (sub->next) {
03909                      sub = sub->next;
03910                   }
03911                   /* set the last sub->next to the first sub */
03912                   sub->next = e->sub;
03913 
03914                   e->next = gw->endpoints;
03915                   gw->endpoints = e;
03916                }
03917             }
03918          } else
03919             ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
03920          v = v->next;
03921       }
03922    }
03923    if (!ntohl(gw->addr.sin_addr.s_addr) && !gw->dynamic) {
03924       ast_log(LOG_WARNING, "Gateway '%s' lacks IP address and isn't dynamic\n", gw->name);
03925       if (!gw_reload) {
03926          ast_mutex_destroy(&gw->msgs_lock);
03927          ast_free(gw);
03928       }
03929       return NULL;
03930    }
03931    gw->defaddr.sin_family = AF_INET;
03932    gw->addr.sin_family = AF_INET;
03933    if (gw->defaddr.sin_addr.s_addr && !ntohs(gw->defaddr.sin_port)) 
03934       gw->defaddr.sin_port = htons(DEFAULT_MGCP_GW_PORT);
03935    if (gw->addr.sin_addr.s_addr && !ntohs(gw->addr.sin_port))
03936       gw->addr.sin_port = htons(DEFAULT_MGCP_GW_PORT);
03937    if (gw->addr.sin_addr.s_addr)
03938       if (ast_ouraddrfor(&gw->addr.sin_addr, &gw->ourip))
03939          memcpy(&gw->ourip, &__ourip, sizeof(gw->ourip));
03940 
03941    return (gw_reload ? NULL : gw);
03942 }

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().

01394                                   {
01395    switch (ind) {
01396    case AST_CONTROL_HANGUP:
01397       return "Other end has hungup";
01398    case AST_CONTROL_RING:
01399       return "Local ring";
01400    case AST_CONTROL_RINGING:
01401       return "Remote end is ringing";
01402    case AST_CONTROL_ANSWER:
01403       return "Remote end has answered";
01404    case AST_CONTROL_BUSY:
01405       return "Remote end is busy";
01406    case AST_CONTROL_TAKEOFFHOOK:
01407       return "Make it go off hook";
01408    case AST_CONTROL_OFFHOOK:
01409       return "Line is off hook";
01410    case AST_CONTROL_CONGESTION:
01411       return "Congestion (circuits busy)";
01412    case AST_CONTROL_FLASH:
01413       return "Flash hook";
01414    case AST_CONTROL_WINK:
01415       return "Wink";
01416    case AST_CONTROL_OPTION:
01417       return "Set a low-level option";
01418    case AST_CONTROL_RADIO_KEY:
01419       return "Key Radio";
01420    case AST_CONTROL_RADIO_UNKEY:
01421       return "Un-Key Radio";
01422    }
01423    return "UNKNOWN";
01424 }

static void destroy_endpoint ( struct mgcp_endpoint e  )  [static]

Definition at line 3977 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().

03978 {
03979    struct mgcp_subchannel *sub = e->sub->next, *s;
03980    int i;
03981 
03982    for (i = 0; i < MAX_SUBS; i++) {
03983       ast_mutex_lock(&sub->lock);
03984       if (!ast_strlen_zero(sub->cxident)) {
03985          transmit_connection_del(sub);
03986       }
03987       if (sub->rtp) {
03988          ast_rtp_destroy(sub->rtp);
03989          sub->rtp = NULL;
03990       }
03991       memset(sub->magic, 0, sizeof(sub->magic));
03992       mgcp_queue_hangup(sub);
03993       dump_cmd_queues(NULL, sub);
03994       ast_mutex_unlock(&sub->lock);
03995       sub = sub->next;
03996    }
03997 
03998    if (e->dsp) {
03999       ast_dsp_free(e->dsp);
04000    }
04001 
04002    dump_queue(e->parent, e);
04003    dump_cmd_queues(e, NULL);
04004 
04005    sub = e->sub;
04006    for (i = 0; (i < MAX_SUBS) && sub; i++) {
04007       s = sub;
04008       sub = sub->next;
04009       ast_mutex_destroy(&s->lock);
04010       ast_mutex_destroy(&s->cx_queue_lock);
04011       ast_free(s);
04012    }
04013 
04014    if (e->mwi_event_sub)
04015       ast_event_unsubscribe(e->mwi_event_sub);
04016 
04017    ast_mutex_destroy(&e->lock);
04018    ast_mutex_destroy(&e->rqnt_queue_lock);
04019    ast_mutex_destroy(&e->cmd_queue_lock);
04020    ast_free(e);
04021 }

static void destroy_gateway ( struct mgcp_gateway g  )  [static]

Definition at line 4023 of file chan_mgcp.c.

References ast_free, ast_free_ha(), dump_queue(), and mgcp_gateway::ha.

Referenced by prune_gateways().

04024 {
04025    if (g->ha)
04026       ast_free_ha(g->ha);
04027 
04028    dump_queue(g, NULL);
04029 
04030    ast_free(g);
04031 }

static void* do_monitor ( void *  data  )  [static]

Definition at line 3383 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, mgcpsock_read(), monlock, netlock, reload_config(), transmit_notify_request(), and TYPE_LINE.

Referenced by restart_monitor().

03384 {
03385    int res;
03386    int reloading;
03387    /*struct mgcp_gateway *g;*/
03388    /*struct mgcp_endpoint *e;*/
03389    /*time_t thispass = 0, lastpass = 0;*/
03390 
03391    /* Add an I/O event to our UDP socket */
03392    if (mgcpsock > -1) 
03393       mgcpsock_read_id = ast_io_add(io, mgcpsock, mgcpsock_read, AST_IO_IN, NULL);
03394    
03395    /* This thread monitors all the frame relay interfaces which are not yet in use
03396       (and thus do not have a separate thread) indefinitely */
03397    /* From here on out, we die whenever asked */
03398    for(;;) {
03399       /* Check for a reload request */
03400       ast_mutex_lock(&mgcp_reload_lock);
03401       reloading = mgcp_reloading;
03402       mgcp_reloading = 0;
03403       ast_mutex_unlock(&mgcp_reload_lock);
03404       if (reloading) {
03405          ast_verb(1, "Reloading MGCP\n");
03406          reload_config(1);
03407          /* Add an I/O event to our UDP socket */
03408          if (mgcpsock > -1 && !mgcpsock_read_id) {
03409             mgcpsock_read_id = ast_io_add(io, mgcpsock, mgcpsock_read, AST_IO_IN, NULL);
03410          }
03411       }
03412 
03413       /* Check for interfaces needing to be killed */
03414       /* Don't let anybody kill us right away.  Nobody should lock the interface list
03415          and wait for the monitor list, but the other way around is okay. */
03416       ast_mutex_lock(&monlock);
03417       /* Lock the network interface */
03418       ast_mutex_lock(&netlock);
03419 
03420 #if 0
03421       /* XXX THIS IS COMPLETELY HOSED */
03422       /* The gateway goes into a state of panic */
03423       /* If the vmwi indicator is sent while it is reseting interfaces */
03424       lastpass = thispass;
03425       thispass = time(NULL);
03426       g = gateways;
03427       while(g) {
03428          if (thispass != lastpass) {
03429             e = g->endpoints;
03430             while(e) {
03431                if (e->type == TYPE_LINE) {
03432                   res = has_voicemail(e);
03433                   if ((e->msgstate != res) && (e->hookstate == MGCP_ONHOOK) && (!e->rtp)){
03434                      if (res) {
03435                         transmit_notify_request(e, "L/vmwi(+)");
03436                      } else {
03437                         transmit_notify_request(e, "L/vmwi(-)");
03438                      }
03439                      e->msgstate = res;
03440                      e->onhooktime = thispass;
03441                   }
03442                }
03443                e = e->next;
03444             }
03445          }
03446          g = g->next;
03447       }
03448 #endif
03449       /* Okay, now that we know what to do, release the network lock */
03450       ast_mutex_unlock(&netlock);
03451       /* And from now on, we're okay to be killed, so release the monitor lock as well */
03452       ast_mutex_unlock(&monlock);
03453       pthread_testcancel();
03454       /* Wait for sched or io */
03455       res = ast_sched_wait(sched);
03456       /* copied from chan_sip.c */
03457       if ((res < 0) || (res > 1000))
03458          res = 1000;
03459       res = ast_io_wait(io, res);
03460       ast_mutex_lock(&monlock);
03461       if (res >= 0) 
03462          ast_sched_runq(sched);
03463       ast_mutex_unlock(&monlock);
03464    }
03465    /* Never reached */
03466    return NULL;
03467 }

static void dump_cmd_queues ( struct mgcp_endpoint p,
struct mgcp_subchannel sub 
) [static]

dump_cmd_queues: (SC:) cleanup pending commands

Definition at line 2388 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().

02389 {
02390    struct mgcp_request *t, *q;
02391 
02392    if (p) {
02393       ast_mutex_lock(&p->rqnt_queue_lock);
02394       for (q = p->rqnt_queue; q; t = q->next, ast_free(q), q=t);
02395       p->rqnt_queue = NULL;
02396       ast_mutex_unlock(&p->rqnt_queue_lock);
02397 
02398       ast_mutex_lock(&p->cmd_queue_lock);
02399       for (q = p->cmd_queue; q; t = q->next, ast_free(q), q=t);
02400       p->cmd_queue = NULL;
02401       ast_mutex_unlock(&p->cmd_queue_lock);
02402 
02403       ast_mutex_lock(&p->sub->cx_queue_lock);
02404       for (q = p->sub->cx_queue; q; t = q->next, ast_free(q), q=t);
02405       p->sub->cx_queue = NULL;
02406       ast_mutex_unlock(&p->sub->cx_queue_lock);
02407 
02408       ast_mutex_lock(&p->sub->next->cx_queue_lock);
02409       for (q = p->sub->next->cx_queue; q; t = q->next, ast_free(q), q=t);
02410       p->sub->next->cx_queue = NULL;
02411       ast_mutex_unlock(&p->sub->next->cx_queue_lock);
02412    } else if (sub) {
02413       ast_mutex_lock(&sub->cx_queue_lock);
02414       for (q = sub->cx_queue; q; t = q->next, ast_free(q), q=t);
02415       sub->cx_queue = NULL;
02416       ast_mutex_unlock(&sub->cx_queue_lock);
02417    }
02418 }

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().

00556 {
00557    struct mgcp_message *cur, *q = NULL, *w, *prev;
00558 
00559    ast_mutex_lock(&gw->msgs_lock);
00560    prev = NULL, cur = gw->msgs;
00561    while (cur) {
00562       if (!p || cur->owner_ep == p) {
00563          if (prev)
00564             prev->next = cur->next;
00565          else
00566             gw->msgs = cur->next;
00567 
00568          ast_log(LOG_NOTICE, "Removing message from %s transaction %u\n", 
00569             gw->name, cur->seqno);
00570 
00571          w = cur;
00572          cur = cur->next;
00573          if (q) {
00574             w->next = q;
00575          } else {
00576             w->next = NULL;
00577          }
00578          q = w;
00579       } else {
00580          prev = cur, cur=cur->next;
00581       }
00582    }
00583    ast_mutex_unlock(&gw->msgs_lock);
00584 
00585    while (q) {
00586       cur = q;
00587       q = q->next;
00588       ast_free(cur);
00589    }
00590 }

static int find_and_retrans ( struct mgcp_subchannel sub,
struct mgcp_request req 
) [static]

Definition at line 3262 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().

03263 {
03264    int seqno=0;
03265    time_t now;
03266    struct mgcp_response *prev = NULL, *cur, *next, *answer=NULL;
03267    time(&now);
03268    if (sscanf(req->identifier, "%30d", &seqno) != 1) 
03269       seqno = 0;
03270    cur = sub->parent->parent->responses;
03271    while(cur) {
03272       next = cur->next;
03273       if (now - cur->whensent > RESPONSE_TIMEOUT) {
03274          /* Delete this entry */
03275          if (prev)
03276             prev->next = next;
03277          else
03278             sub->parent->parent->responses = next;
03279          ast_free(cur);
03280       } else {
03281          if (seqno == cur->seqno)
03282             answer = cur;
03283          prev = cur;
03284       }
03285       cur = next;
03286    }
03287    if (answer) {
03288       resend_response(sub, answer);
03289       return 1;
03290    }
03291    return 0;
03292 }

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 2422 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().

02424 {
02425    struct mgcp_request *prev, *req;
02426 
02427    ast_mutex_lock(l);
02428    for (prev = NULL, req = *queue; req; prev = req, req = req->next) {
02429       if (req->trid == ident) {
02430          /* remove from queue */
02431          if (!prev)
02432             *queue = req->next;
02433          else
02434             prev->next = req->next;
02435 
02436          /* send next pending command */
02437          if (*queue) {
02438             if (mgcpdebug) {
02439                ast_verbose("Posting Queued Request:\n%s to %s:%d\n", (*queue)->data, 
02440                   ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
02441             }
02442 
02443             mgcp_postrequest(p, sub, (*queue)->data, (*queue)->len, (*queue)->trid);
02444          }
02445          break;
02446       }
02447    }
02448    ast_mutex_unlock(l);
02449    return req;
02450 }

static struct mgcp_subchannel* find_subchannel_and_lock ( char *  name,
int  msgid,
struct sockaddr_in *  sin 
) [static, read]

Definition at line 1625 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().

01626 {
01627    struct mgcp_endpoint *p = NULL;
01628    struct mgcp_subchannel *sub = NULL;
01629    struct mgcp_gateway *g;
01630    char tmp[256] = "";
01631    char *at = NULL, *c;
01632    int found = 0;
01633    if (name) {
01634       ast_copy_string(tmp, name, sizeof(tmp));
01635       at = strchr(tmp, '@');
01636       if (!at) {
01637          ast_log(LOG_NOTICE, "Endpoint '%s' has no at sign!\n", name);
01638          return NULL;
01639       }
01640       *at++ = '\0';
01641    }
01642    ast_mutex_lock(&gatelock);
01643    if (at && (at[0] == '[')) {
01644       at++;
01645       c = strrchr(at, ']');
01646       if (c)
01647          *c = '\0';
01648    }
01649    g = gateways;
01650    while(g) {
01651       if ((!name || !strcasecmp(g->name, at)) && 
01652           (sin || g->addr.sin_addr.s_addr || g->defaddr.sin_addr.s_addr)) {
01653          /* Found the gateway.  If it's dynamic, save it's address -- now for the endpoint */
01654          if (sin && g->dynamic && name) {
01655             if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
01656                (g->addr.sin_port != sin->sin_port)) {
01657                memcpy(&g->addr, sin, sizeof(g->addr));
01658                if (ast_ouraddrfor(&g->addr.sin_addr, &g->ourip))
01659                   memcpy(&g->ourip, &__ourip, sizeof(g->ourip));
01660                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));
01661             }
01662          }
01663          /* not dynamic, check if the name matches */
01664          else if (name) {
01665             if (strcasecmp(g->name, at)) {
01666                g = g->next;
01667                continue;
01668             }
01669          }
01670          /* not dynamic, no name, check if the addr matches */
01671          else if (!name && sin) {
01672             if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
01673                 (g->addr.sin_port != sin->sin_port)) {
01674                g = g->next;
01675                continue;
01676             }
01677          } else {
01678             g = g->next;
01679             continue;
01680          }
01681          /* SC */
01682          p = g->endpoints;
01683          while(p) {
01684             ast_debug(1, "Searching on %s@%s for subchannel\n",
01685                p->name, g->name);
01686             if (msgid) {
01687 #if 0 /* new transport mech */
01688                sub = p->sub;
01689                do {
01690                   ast_debug(1, "Searching on %s@%s-%d for subchannel with lastout: %d\n",
01691                      p->name, g->name, sub->id, msgid);
01692                   if (sub->lastout == msgid) {
01693                      ast_debug(1, "Found subchannel sub%d to handle request %d sub->lastout: %d\n",
01694                         sub->id, msgid, sub->lastout);
01695                      found = 1;
01696                      break;
01697                   }
01698                   sub = sub->next;
01699                } while (sub != p->sub);
01700                if (found) {
01701                   break;
01702                }
01703 #endif
01704                /* SC */
01705                sub = p->sub;
01706                found = 1;
01707                /* SC */
01708                break;
01709             } else if (name && !strcasecmp(p->name, tmp)) {
01710                ast_debug(1, "Coundn't determine subchannel, assuming current master %s@%s-%d\n", 
01711                   p->name, g->name, p->sub->id);
01712                sub = p->sub;
01713                found = 1;
01714                break;
01715             }
01716             p = p->next;
01717          }
01718          if (sub && found) {
01719             ast_mutex_lock(&sub->lock);
01720             break;
01721          }
01722       }
01723       g = g->next;
01724    }
01725    ast_mutex_unlock(&gatelock);
01726    if (!sub) {
01727       if (name) {
01728          if (g)
01729             ast_log(LOG_NOTICE, "Endpoint '%s' not found on gateway '%s'\n", tmp, at);
01730          else
01731             ast_log(LOG_NOTICE, "Gateway '%s' (and thus its endpoint '%s') does not exist\n", at, tmp);
01732       } 
01733    }
01734    return sub;
01735 }

static char* get_csv ( char *  c,
int *  len,
char **  next 
) [static]

get_csv: (SC:) get comma separated value

Definition at line 1604 of file chan_mgcp.c.

References s.

Referenced by handle_response().

01605 {
01606    char *s;
01607 
01608    *next = NULL, *len = 0;
01609    if (!c) return NULL;
01610 
01611    while (*c && (*c < 33 || *c == ','))
01612       c++;
01613 
01614    s = c;
01615    while (*c && (*c >= 33 && *c != ','))
01616       c++, (*len)++;
01617    *next = c;
01618 
01619    if (*len == 0)
01620       s = NULL, *next = NULL;
01621 
01622    return s;
01623 }

static char* get_header ( struct mgcp_request req,
char *  name 
) [static]

Definition at line 1597 of file chan_mgcp.c.

References __get_header().

Referenced by handle_request(), and handle_response().

01598 {
01599    int start = 0;
01600    return __get_header(req, name, &start);
01601 }

static char* get_sdp ( struct mgcp_request req,
char *  name 
) [static]

Definition at line 1549 of file chan_mgcp.c.

References get_sdp_by_line(), len(), mgcp_request::line, and mgcp_request::lines.

Referenced by process_sdp().

01550 {
01551    int x;
01552    int len = strlen(name);
01553    char *r;
01554 
01555    for (x=0; x<req->lines; x++) {
01556       r = get_sdp_by_line(req->line[x], name, len);
01557       if (r[0] != '\0') return r;
01558    }
01559    return "";
01560 }

static char* get_sdp_by_line ( char *  line,
char *  name,
int  nameLen 
) [static]

Definition at line 1539 of file chan_mgcp.c.

Referenced by get_sdp(), and get_sdp_iterate().

01540 {
01541    if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') {
01542       char* r = line + nameLen + 1;
01543       while (*r && (*r < 33)) ++r;
01544       return r;
01545    }
01546    return "";
01547 }

static char* get_sdp_iterate ( int *  iterator,
struct mgcp_request req,
char *  name 
) [static]

Definition at line 1567 of file chan_mgcp.c.

References get_sdp_by_line(), len(), and mgcp_request::line.

Referenced by process_sdp().

01568 {
01569    int len = strlen(name);
01570    char *r;
01571    while (*iterator < req->lines) {
01572       r = get_sdp_by_line(req->line[(*iterator)++], name, len);
01573       if (r[0] != '\0') return r;
01574    }
01575    return "";
01576 }

static void handle_hd_hf ( struct mgcp_subchannel sub,
char *  ev 
) [static]

Definition at line 2938 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().

02939 {
02940    struct mgcp_endpoint *p = sub->parent;
02941    struct ast_channel *c;
02942    pthread_t t;
02943 
02944    /* Off hook / answer */
02945    if (sub->outgoing) {
02946       /* Answered */
02947       if (sub->owner) {
02948          if (ast_bridged_channel(sub->owner))
02949             ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
02950          sub->cxmode = MGCP_CX_SENDRECV;
02951          if (!sub->rtp) {
02952             start_rtp(sub);
02953          } else {
02954             transmit_modify_request(sub);
02955          }
02956          /*transmit_notify_request(sub, "aw");*/
02957          transmit_notify_request(sub, "");
02958          mgcp_queue_control(sub, AST_CONTROL_ANSWER);
02959       }
02960    } else {
02961       /* Start switch */
02962       /*sub->cxmode = MGCP_CX_SENDRECV;*/
02963       if (!sub->owner) {
02964          if (!sub->rtp) {
02965             start_rtp(sub);
02966          } else {
02967             transmit_modify_request(sub);
02968          }
02969          if (p->immediate) {
02970             /* The channel is immediately up. Start right away */
02971 #ifdef DLINK_BUGGY_FIRMWARE   
02972             transmit_notify_request(sub, "rt");
02973 #else
02974             transmit_notify_request(sub, "G/rt");
02975 #endif      
02976             c = mgcp_new(sub, AST_STATE_RING);
02977             if (!c) {
02978                ast_log(LOG_WARNING, "Unable to start PBX on channel %s@%s\n", p->name, p->parent->name);
02979                transmit_notify_request(sub, "G/cg");
02980                ast_hangup(c);
02981             }
02982          } else {
02983             if (has_voicemail(p)) {
02984                transmit_notify_request(sub, "L/sl");
02985             } else {
02986                transmit_notify_request(sub, "L/dl");
02987             }
02988             c = mgcp_new(sub, AST_STATE_DOWN);
02989             if (c) {
02990                if (ast_pthread_create_detached(&t, NULL, mgcp_ss, c)) {
02991                   ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
02992                   ast_hangup(c);
02993                }
02994             } else {
02995                ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", p->name, p->parent->name);
02996             }
02997          }
02998       } else {
02999          if (p->hookstate == MGCP_OFFHOOK) {
03000             ast_log(LOG_WARNING, "Off hook, but already have owner on %s@%s\n", p->name, p->parent->name);
03001          } else {
03002             ast_log(LOG_WARNING, "On hook, but already have owner on %s@%s\n", p->name, p->parent->name);
03003             ast_log(LOG_WARNING, "If we're onhook why are we here trying to handle a hd or hf?\n");
03004          }
03005          if (ast_bridged_channel(sub->owner))
03006             ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
03007          sub->cxmode = MGCP_CX_SENDRECV;
03008          if (!sub->rtp) {
03009             start_rtp(sub);
03010          } else {
03011             transmit_modify_request(sub);
03012          }
03013          /*transmit_notify_request(sub, "aw");*/
03014          transmit_notify_request(sub, "");
03015          /*ast_queue_control(sub->owner, AST_CONTROL_ANSWER);*/
03016       }
03017    }
03018 }

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.

01078 {
01079    struct mgcp_gateway  *mg;
01080    struct mgcp_endpoint *me;
01081    int found = 0;
01082    char *ename,*gname, *c;
01083 
01084    switch (cmd) {
01085    case CLI_INIT:
01086       e->command = "mgcp audit endpoint";
01087       e->usage =
01088          "Usage: mgcp audit endpoint <endpointid>\n"
01089          "       Lists the capabilities of an endpoint in the MGCP (Media Gateway Control Protocol) subsystem.\n"
01090          "       mgcp debug MUST be on to see the results of this command.\n";
01091       return NULL;
01092    case CLI_GENERATE:
01093       return NULL;
01094    }
01095 
01096    if (!mgcpdebug) {
01097       return CLI_SHOWUSAGE;
01098    }
01099    if (a->argc != 4)
01100       return CLI_SHOWUSAGE;
01101    /* split the name into parts by null */
01102    ename = a->argv[3];
01103    gname = ename;
01104    while (*gname) {
01105       if (*gname == '@') {
01106          *gname = 0;
01107          gname++;
01108          break;
01109       }
01110       gname++;
01111    }
01112    if (gname[0] == '[')
01113       gname++;
01114    if ((c = strrchr(gname, ']')))
01115       *c = '\0';
01116    ast_mutex_lock(&gatelock);
01117    mg = gateways;
01118    while(mg) {
01119       if (!strcasecmp(mg->name, gname)) {
01120          me = mg->endpoints;
01121          while(me) {
01122             if (!strcasecmp(me->name, ename)) {
01123                found = 1;
01124                transmit_audit_endpoint(me);
01125                break;
01126             }
01127             me = me->next;
01128          }
01129          if (found) {
01130             break;
01131          }
01132       }
01133       mg = mg->next;
01134    }
01135    if (!found) {
01136       ast_cli(a->fd, "   << Could not find endpoint >>     ");
01137    }
01138    ast_mutex_unlock(&gatelock);
01139    return CLI_SUCCESS;
01140 }

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.

01143 {
01144    switch (cmd) {
01145    case CLI_INIT:
01146       e->command = "mgcp set debug {on|off}";
01147       e->usage =
01148          "Usage: mgcp set debug {on|off}\n"
01149          "       Enables/Disables dumping of MGCP packets for debugging purposes\n";   
01150       return NULL;
01151    case CLI_GENERATE:
01152       return NULL;
01153    }
01154 
01155    if (a->argc != e->args)
01156       return CLI_SHOWUSAGE;
01157 
01158    if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
01159       mgcpdebug = 1;
01160       ast_cli(a->fd, "MGCP Debugging Enabled\n");
01161    } else if (!strncasecmp(a->argv[3], "off", 3)) {
01162       mgcpdebug = 0;
01163       ast_cli(a->fd, "MGCP Debugging Disabled\n");
01164    } else {
01165       return CLI_SHOWUSAGE;
01166    }
01167    return CLI_SUCCESS;
01168 }

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.

01038 {
01039    struct mgcp_gateway  *mg;
01040    struct mgcp_endpoint *me;
01041    int hasendpoints = 0;
01042 
01043    switch (cmd) {
01044    case CLI_INIT:
01045       e->command = "mgcp show endpoints";
01046       e->usage =
01047          "Usage: mgcp show endpoints\n"
01048          "       Lists all endpoints known to the MGCP (Media Gateway Control Protocol) subsystem.\n";
01049       return NULL;
01050    case CLI_GENERATE:
01051       return NULL;
01052    }
01053 
01054    if (a->argc != 3) 
01055       return CLI_SHOWUSAGE;
01056    ast_mutex_lock(&gatelock);
01057    mg = gateways;
01058    while(mg) {
01059       me = mg->endpoints;
01060       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");
01061       while(me) {
01062          /* Don't show wilcard endpoint */
01063          if (strcmp(me->name, mg->wcardep) != 0)
01064             ast_cli(a->fd, "   -- '%s@%s in '%s' is %s\n", me->name, mg->name, me->context, me->sub->owner ? "active" : "idle");
01065          hasendpoints = 1;
01066          me = me->next;
01067       }
01068       if (!hasendpoints) {
01069          ast_cli(a->fd, "   << No Endpoints Defined >>     ");
01070       }
01071       mg = mg->next;
01072    }
01073    ast_mutex_unlock(&gatelock);
01074    return CLI_SUCCESS;
01075 }

static int handle_request ( struct mgcp_subchannel sub,
struct mgcp_request req,
struct sockaddr_in *  sin 
) [static]

Definition at line 3020 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().

03021 {
03022    char *ev, *s;
03023    struct ast_frame f = { 0, };
03024    struct mgcp_endpoint *p = sub->parent;
03025    struct mgcp_gateway *g = NULL;
03026    int res;
03027 
03028    if (mgcpdebug) {
03029       ast_verbose("Handling request '%s' on %s@%s\n", req->verb, p->name, p->parent->name);
03030    }
03031    /* Clear out potential response */
03032    if (!strcasecmp(req->verb, "RSIP")) {
03033       /* Test if this RSIP request is just a keepalive */
03034       if(!strcasecmp( get_header(req, "RM"), "X-keepalive")) {
03035          ast_verb(3, "Received keepalive request from %s@%s\n", p->name, p->parent->name);
03036          transmit_response(sub, "200", req, "OK");
03037       } else {
03038          dump_queue(p->parent, p);
03039          dump_cmd_queues(p, NULL);
03040          
03041          if ((strcmp(p->name, p->parent->wcardep) != 0)) {
03042             ast_verb(3, "Resetting interface %s@%s\n", p->name, p->parent->name);
03043          }
03044          /* For RSIP on wildcard we reset all endpoints */
03045          if (!strcmp(p->name, p->parent->wcardep)) {
03046             /* Reset all endpoints */
03047             struct mgcp_endpoint *tmp_ep;
03048             
03049             g = p->parent;
03050             tmp_ep = g->endpoints;
03051             while (tmp_ep) {
03052                /*if ((strcmp(tmp_ep->name, "*") != 0) && (strcmp(tmp_ep->name, "aaln/" "*") != 0)) {*/
03053                if (strcmp(tmp_ep->name, g->wcardep) != 0) {
03054                   struct mgcp_subchannel *tmp_sub, *first_sub;
03055                   ast_verb(3, "Resetting interface %s@%s\n", tmp_ep->name, p->parent->name);
03056                   
03057                   first_sub = tmp_ep->sub;
03058                   tmp_sub = tmp_ep->sub;
03059                   while (tmp_sub) {
03060                      mgcp_queue_hangup(tmp_sub);
03061                      tmp_sub = tmp_sub->next;
03062                      if (tmp_sub == first_sub)
03063                         break;
03064                   }
03065                }
03066                tmp_ep = tmp_ep->next;
03067             }
03068          } else if (sub->owner) {
03069             mgcp_queue_hangup(sub);
03070          }
03071          transmit_response(sub, "200", req, "OK");
03072          /* We dont send NTFY or AUEP to wildcard ep */
03073          if (strcmp(p->name, p->parent->wcardep) != 0) {
03074             transmit_notify_request(sub, "");
03075             /* Audit endpoint. 
03076              Idea is to prevent lost lines due to race conditions 
03077             */
03078             transmit_audit_endpoint(p);
03079          }
03080       }
03081    } else if (!strcasecmp(req->verb, "NTFY")) {
03082       /* Acknowledge and be sure we keep looking for the same things */
03083       transmit_response(sub, "200", req, "OK");
03084       /* Notified of an event */
03085       ev = get_header(req, "O");
03086       s = strchr(ev, '/');
03087       if (s) ev = s + 1;
03088       ast_debug(1, "Endpoint '%s@%s-%d' observed '%s'\n", p->name, p->parent->name, sub->id, ev);
03089       /* Keep looking for events unless this was a hangup */
03090       if (strcasecmp(ev, "hu") && strcasecmp(ev, "hd") && strcasecmp(ev, "ping")) {
03091          transmit_notify_request(sub, p->curtone);
03092       }
03093       if (!strcasecmp(ev, "hd")) {
03094          p->hookstate = MGCP_OFFHOOK;
03095          sub->cxmode = MGCP_CX_SENDRECV;
03096          handle_hd_hf(sub, ev);
03097       } else if (!strcasecmp(ev, "hf")) {
03098          /* We can assume we are offhook if we received a hookflash */
03099          /* First let's just do call wait and ignore threeway */
03100          /* We're currently in charge */
03101          if (p->hookstate != MGCP_OFFHOOK) {
03102             /* Cisco c7940 sends hf even if the phone is onhook */
03103             /* Thanks to point on IRC for pointing this out */
03104             return -1;
03105          }
03106          /* do not let * conference two down channels */  
03107          if (sub->owner && sub->owner->_state == AST_STATE_DOWN && !sub->next->owner)
03108             return -1;
03109 
03110          if (p->callwaiting || p->transfer || p->threewaycalling) {
03111             ast_verb(3, "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name);
03112             p->sub = p->sub->next;
03113 
03114             /* transfer control to our next subchannel */
03115             if (!sub->next->owner) {
03116                /* plave the first call on hold and start up a new call */
03117                sub->cxmode = MGCP_CX_MUTE;
03118                ast_verb(3, "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
03119                transmit_modify_request(sub);
03120                if (sub->owner && ast_bridged_channel(sub->owner))
03121                   ast_queue_control(sub->owner, AST_CONTROL_HOLD);
03122                sub->next->cxmode = MGCP_CX_RECVONLY;
03123                handle_hd_hf(sub->next, ev);
03124             } else if (sub->owner && sub->next->owner) {
03125                /* We've got two active calls lets decide whether or not to conference or just flip flop */
03126                if ((!sub->outgoing) && (!sub->next->outgoing)) {
03127                   /* We made both calls lets conferenct */
03128                   ast_verb(3, "MGCP Conferencing %d and %d on %s@%s\n",
03129                         sub->id, sub->next->id, p->name, p->parent->name);
03130                   sub->cxmode = MGCP_CX_CONF;
03131                   sub->next->cxmode = MGCP_CX_CONF;
03132                   if (ast_bridged_channel(sub->next->owner))
03133                      ast_queue_control(sub->next->owner, AST_CONTROL_UNHOLD);
03134                   transmit_modify_request(sub);
03135                   transmit_modify_request(sub->next);
03136                } else {
03137                   /* Let's flipflop between calls */
03138                   /* XXX Need to check for state up ??? */
03139                   /* XXX Need a way to indicate the current call, or maybe the call that's waiting */
03140                   ast_verb(3, "We didn't make one of the calls FLIPFLOP %d and %d on %s@%s\n",
03141                         sub->id, sub->next->id, p->name, p->parent->name);
03142                   sub->cxmode = MGCP_CX_MUTE;
03143                   ast_verb(3, "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
03144                   transmit_modify_request(sub);
03145                   if (ast_bridged_channel(sub->owner))
03146                      ast_queue_control(sub->owner, AST_CONTROL_HOLD);
03147                         
03148                   if (ast_bridged_channel(sub->next->owner)) 
03149                      ast_queue_control(sub->next->owner, AST_CONTROL_HOLD);
03150                         
03151                   handle_hd_hf(sub->next, ev);
03152                }
03153             } else {
03154                /* We've most likely lost one of our calls find an active call and bring it up */
03155                if (sub->owner) {
03156                   p->sub = sub;
03157                } else if (sub->next->owner) {
03158                   p->sub = sub->next;
03159                } else {
03160                   /* We seem to have lost both our calls */
03161                   /* XXX - What do we do now? */
03162                   return -1;
03163                }
03164                if (ast_bridged_channel(p->sub->owner))
03165                   ast_queue_control(p->sub->owner, AST_CONTROL_UNHOLD);
03166                p->sub->cxmode = MGCP_CX_SENDRECV;
03167                transmit_modify_request(p->sub);
03168             }
03169          } else {
03170             ast_log(LOG_WARNING, "Callwaiting, call transfer or threeway calling not enabled on endpoint %s@%s\n", 
03171                p->name, p->parent->name);
03172          }
03173       } else if (!strcasecmp(ev, "hu")) {
03174          p->hookstate = MGCP_ONHOOK;
03175          sub->cxmode = MGCP_CX_RECVONLY;
03176          ast_debug(1, "MGCP %s@%s Went on hook\n", p->name, p->parent->name);
03177          /* Do we need to send MDCX before a DLCX ?
03178          if (sub->rtp) {
03179             transmit_modify_request(sub);
03180          }
03181          */
03182          if (p->transfer && (sub->owner && sub->next->owner) && ((!sub->outgoing) || (!sub->next->outgoing))) {
03183             /* We're allowed to transfer, we have two avtive calls and */
03184             /* we made at least one of the calls.  Let's try and transfer */
03185             ast_mutex_lock(&p->sub->next->lock);
03186             res = attempt_transfer(p);
03187             if (res < 0) {
03188                if (p->sub->next->owner) {
03189                   sub->next->alreadygone = 1;
03190                   mgcp_queue_hangup(sub->next);
03191                }
03192             } else if (res) {
03193                ast_log(LOG_WARNING, "Transfer attempt failed\n");
03194                ast_mutex_unlock(&p->sub->next->lock);
03195                return -1;
03196             }
03197             ast_mutex_unlock(&p->sub->next->lock);
03198          } else {
03199             /* Hangup the current call */
03200             /* If there is another active call, mgcp_hangup will ring the phone with the other call */
03201             if (sub->owner) {
03202                sub->alreadygone = 1;
03203                mgcp_queue_hangup(sub);
03204             } else {
03205                ast_verb(3, "MGCP handle_request(%s@%s-%d) ast_channel already destroyed, resending DLCX.\n",
03206                      p->name, p->parent->name, sub->id);
03207                /* Instruct the other side to remove the connection since it apparently *
03208                 * still thinks the channel is active. *
03209                 * For Cisco IAD2421 /BAK/ */
03210                transmit_connection_del(sub);
03211             }
03212          }
03213          if ((p->hookstate == MGCP_ONHOOK) && (!sub->rtp) && (!sub->next->rtp)) {
03214             p->hidecallerid = 0;
03215             if (p->hascallwaiting && !p->callwaiting) {
03216                ast_verb(3, "Enabling call waiting on MGCP/%s@%s-%d\n", p->name, p->parent->name, sub->id);
03217                p->callwaiting = -1;
03218             }
03219             if (has_voicemail(p)) {
03220                ast_verb(3, "MGCP handle_request(%s@%s) set vmwi(+)\n", p->name, p->parent->name);
03221                transmit_notify_request(sub, "L/vmwi(+)");
03222             } else {
03223                ast_verb(3, "MGCP handle_request(%s@%s) set vmwi(-)\n", p->name, p->parent->name);
03224                transmit_notify_request(sub, "L/vmwi(-)");
03225             }
03226          }
03227       } else if ((strlen(ev) == 1) && 
03228             (((ev[0] >= '0') && (ev[0] <= '9')) ||
03229              ((ev[0] >= 'A') && (ev[0] <= 'D')) ||
03230               (ev[0] == '*') || (ev[0] == '#'))) {
03231          if (sub && sub->owner && (sub->owner->_state >=  AST_STATE_UP)) {
03232             f.frametype = AST_FRAME_DTMF;
03233             f.subclass = ev[0];
03234             f.src = "mgcp";
03235             /* XXX MUST queue this frame to all subs in threeway call if threeway call is active */
03236             mgcp_queue_frame(sub, &f);
03237             ast_mutex_lock(&sub->next->lock);
03238             if (sub->next->owner)
03239                mgcp_queue_frame(sub->next, &f);
03240             ast_mutex_unlock(&sub->next->lock);
03241             if (strstr(p->curtone, "wt") && (ev[0] == 'A')) {
03242                memset(p->curtone, 0, sizeof(p->curtone));
03243             }
03244          } else {
03245             p->dtmf_buf[strlen(p->dtmf_buf)] = ev[0];
03246             p->dtmf_buf[strlen(p->dtmf_buf)] = '\0';
03247          }
03248       } else if (!strcasecmp(ev, "T")) {
03249          /* Digit timeout -- unimportant */
03250       } else if (!strcasecmp(ev, "ping")) {
03251          /* ping -- unimportant */
03252       } else {
03253          ast_log(LOG_NOTICE, "Received unknown event '%s' from %s@%s\n", ev, p->name, p->parent->name);
03254       }
03255    } else {
03256       ast_log(LOG_WARNING, "Unknown verb '%s' received from %s\n", req->verb, ast_inet_ntoa(sin->sin_addr));
03257       transmit_response(sub, "510", req, "Unknown verb");
03258    }
03259    return 0;
03260 }

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 2453 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().

02455 {
02456    char *c;
02457    struct mgcp_request *req;
02458    struct mgcp_gateway *gw = p->parent;
02459 
02460    if (result < 200) {
02461       /* provisional response */
02462       return;
02463    }
02464 
02465    if (p->slowsequence) 
02466       req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident);
02467    else if (sub)
02468       req = find_command(p, sub, &sub->cx_queue, &sub->cx_queue_lock, ident);
02469    else if (!(req = find_command(p, sub, &p->rqnt_queue, &p->rqnt_queue_lock, ident)))
02470       req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident);
02471 
02472    if (!req) {
02473       ast_verb(3, "No command found on [%s] for transaction %d. Ignoring...\n",
02474             gw->name, ident);
02475       return;
02476    }
02477 
02478    if (p && (result >= 400) && (result <= 599)) {
02479       switch (result) {
02480       case 401:
02481          p->hookstate = MGCP_OFFHOOK;
02482          break;
02483       case 402:
02484          p->hookstate = MGCP_ONHOOK;
02485          break;
02486       case 406:
02487          ast_log(LOG_NOTICE, "Transaction %d timed out\n", ident);
02488          break;
02489       case 407:
02490          ast_log(LOG_NOTICE, "Transaction %d aborted\n", ident);
02491          break;
02492       }
02493       if (sub) {
02494          if (sub->owner) {
02495             ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n", 
02496                result, p->name, p->parent->name, sub ? sub->id:-1);
02497             mgcp_queue_hangup(sub);
02498          }
02499       } else {
02500          if (p->sub->next->owner) {
02501             ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n", 
02502                result, p->name, p->parent->name, sub ? sub->id:-1);
02503             mgcp_queue_hangup(p->sub);
02504          }
02505 
02506          if (p->sub->owner) {
02507             ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n", 
02508                result, p->name, p->parent->name, sub ? sub->id:-1);
02509             mgcp_queue_hangup(p->sub);
02510          }
02511 
02512          dump_cmd_queues(p, NULL);
02513       }
02514    }
02515 
02516    if (resp) {
02517       if (req->cmd == MGCP_CMD_CRCX) {
02518          if ((c = get_header(resp, "I"))) {
02519             if (!ast_strlen_zero(c) && sub) {
02520                /* if we are hanging up do not process this conn. */
02521                if (sub->owner) {
02522                   if (!ast_strlen_zero(sub->cxident)) {
02523                      if (strcasecmp(c, sub->cxident)) {
02524                         ast_log(LOG_WARNING, "Subchannel already has a cxident. sub->cxident: %s requested %s\n", sub->cxident, c);
02525                      }
02526                   }
02527                   ast_copy_string(sub->cxident, c, sizeof(sub->cxident));
02528                   if (sub->tmpdest.sin_addr.s_addr) {
02529                      transmit_modify_with_sdp(sub, NULL, 0);
02530                   }
02531                } else {
02532                   /* XXX delete this one
02533                      callid and conn id may already be lost. 
02534                      so the following del conn may have a side effect of 
02535                      cleaning up the next subchannel */
02536                   transmit_connection_del(sub);
02537                }
02538             }
02539          }
02540       }
02541 
02542       if (req->cmd == MGCP_CMD_AUEP) {
02543          /* check stale connection ids */
02544          if ((c = get_header(resp, "I"))) {
02545             char *v, *n;
02546             int len;
02547             while ((v = get_csv(c, &len, &n))) {
02548                if (len) {
02549                   if (strncasecmp(v, p->sub->cxident, len) &&
02550                       strncasecmp(v, p->sub->next->cxident, len)) {
02551                      /* connection id not found. delete it */
02552                      char cxident[80] = "";
02553 
02554                      if (len > (sizeof(cxident) - 1))
02555                         len = sizeof(cxident) - 1;
02556                      ast_copy_string(cxident, v, len);
02557                      ast_verb(3, "Non existing connection id %s on %s@%s \n",
02558                                cxident, p->name, gw->name);
02559                      transmit_connection_del_w_params(p, NULL, cxident);
02560                   }
02561                }
02562                c = n;
02563             }
02564          }
02565 
02566          /* Try to determine the hookstate returned from an audit endpoint command */
02567          if ((c = get_header(resp, "ES"))) {
02568             if (!ast_strlen_zero(c)) {
02569                if (strstr(c, "hu")) {
02570                   if (p->hookstate != MGCP_ONHOOK) {
02571                      /* XXX cleanup if we think we are offhook XXX */
02572                      if ((p->sub->owner || p->sub->next->owner ) && 
02573                          p->hookstate == MGCP_OFFHOOK)
02574                         mgcp_queue_hangup(sub);
02575                      p->hookstate = MGCP_ONHOOK;
02576 
02577                      /* update the requested events according to the new hookstate */
02578                      transmit_notify_request(p->sub, "");
02579 
02580                      ast_verb(3, "Setting hookstate of %s@%s to ONHOOK\n", p->name, gw->name);
02581                      }
02582                } else if (strstr(c, "hd")) {
02583                   if (p->hookstate != MGCP_OFFHOOK) {
02584                      p->hookstate = MGCP_OFFHOOK;
02585 
02586                      /* update the requested events according to the new hookstate */
02587                      transmit_notify_request(p->sub, "");
02588 
02589                      ast_verb(3, "Setting hookstate of %s@%s to OFFHOOK\n", p->name, gw->name);
02590                      }
02591                   }
02592                }
02593             }
02594          }
02595 
02596       if (resp && resp->lines) {
02597          /* do not process sdp if we are hanging up. this may be a late response */
02598          if (sub && sub->owner) {
02599             if (!sub->rtp)
02600                start_rtp(sub);
02601             if (sub->rtp)
02602                process_sdp(sub, resp);
02603          }
02604       }
02605    }
02606 
02607    ast_free(req);
02608 }

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_strlen_zero(), mgcp_endpoint::mailbox, and mbox().

Referenced by do_monitor(), handle_hd_hf(), handle_request(), mgcp_hangup(), and mgcp_request().

00463 {
00464    int new_msgs;
00465    struct ast_event *event;
00466    char *mbox, *cntx;
00467 
00468    cntx = mbox = ast_strdupa(p->mailbox);
00469    strsep(&cntx, "@");
00470    if (ast_strlen_zero(cntx))
00471       cntx = "default";
00472 
00473    event = ast_event_get_cached(AST_EVENT_MWI,
00474       AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mbox,
00475       AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, cntx,
00476       AST_EVENT_IE_END);
00477 
00478    if (event) {
00479       new_msgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
00480       ast_event_destroy(event);
00481    } else
00482       new_msgs = ast_app_has_voicemail(p->mailbox, NULL);
00483 
00484    return new_msgs;
00485 }

static int init_req ( struct mgcp_endpoint p,
struct mgcp_request req,
char *  verb 
) [static]

Definition at line 1986 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().

01987 {
01988    /* Initialize a response */
01989    if (req->headers || req->len) {
01990       ast_log(LOG_WARNING, "Request already initialized?!?\n");
01991       return -1;
01992    }
01993    req->header[req->headers] = req->data + req->len;
01994    /* check if we need brackets around the gw name */
01995    if (p->parent->isnamedottedip)
01996       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);
01997    else
01998       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);
01999    req->len += strlen(req->header[req->headers]);
02000    if (req->headers < MGCP_MAX_HEADERS)
02001       req->headers++;
02002    else
02003       ast_log(LOG_WARNING, "Out of header space\n");
02004    return 0;
02005 }

static int init_resp ( struct mgcp_request req,
char *  resp,
struct mgcp_request orig,
char *  resprest 
) [static]

Definition at line 1969 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().

01970 {
01971    /* Initialize a response */
01972    if (req->headers || req->len) {
01973       ast_log(LOG_WARNING, "Request already initialized?!?\n");
01974       return -1;
01975    }
01976    req->header[req->headers] = req->data + req->len;
01977    snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %s %s\r\n", resp, orig->identifier, resprest);
01978    req->len += strlen(req->header[req->headers]);
01979    if (req->headers < MGCP_MAX_HEADERS)
01980       req->headers++;
01981    else
01982       ast_log(LOG_WARNING, "Out of header space\n");
01983    return 0;
01984 }

static int load_module ( void   )  [static]

load_module: PBX load module - initialization ---

Definition at line 4256 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().

04257 {
04258    if (!(sched = sched_context_create())) {
04259       ast_log(LOG_WARNING, "Unable to create schedule context\n");
04260       return AST_MODULE_LOAD_FAILURE;
04261    }
04262 
04263    if (!(io = io_context_create())) {
04264       ast_log(LOG_WARNING, "Unable to create I/O context\n");
04265       sched_context_destroy(sched);
04266       return AST_MODULE_LOAD_FAILURE;
04267    }
04268 
04269    if (reload_config(0))
04270       return AST_MODULE_LOAD_DECLINE;
04271 
04272    /* Make sure we can register our mgcp channel type */
04273    if (ast_channel_register(&mgcp_tech)) {
04274       ast_log(LOG_ERROR, "Unable to register channel class 'MGCP'\n");
04275       io_context_destroy(io);
04276       sched_context_destroy(sched);
04277       return AST_MODULE_LOAD_FAILURE;
04278    }
04279 
04280    ast_rtp_proto_register(&mgcp_rtp);
04281    ast_cli_register_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
04282    
04283    /* And start the monitor for the first time */
04284    restart_monitor();
04285 
04286    return AST_MODULE_LOAD_SUCCESS;
04287 }

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().

01178 {
01179    int res = 0;
01180    struct mgcp_subchannel *sub = ast->tech_pvt;
01181    struct mgcp_endpoint *p = sub->parent;
01182 
01183    ast_mutex_lock(&sub->lock);
01184    sub->cxmode = MGCP_CX_SENDRECV;
01185    if (!sub->rtp) {
01186       start_rtp(sub);
01187    } else {
01188       transmit_modify_request(sub);
01189    }
01190    ast_verb(3, "MGCP mgcp_answer(%s) on %s@%s-%d\n",
01191          ast->name, p->name, p->parent->name, sub->id);
01192    if (ast->_state != AST_STATE_UP) {
01193       ast_setstate(ast, AST_STATE_UP);
01194       ast_debug(1, "mgcp_answer(%s)\n", ast->name);
01195       transmit_notify_request(sub, "");
01196       transmit_modify_request(sub);
01197    }
01198    ast_mutex_unlock(&sub->lock);
01199    return res;
01200 }

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.

00844 {
00845    int res;
00846    struct mgcp_endpoint *p;
00847    struct mgcp_subchannel *sub;
00848    char tone[50] = "";
00849    const char *distinctive_ring = NULL;
00850    struct varshead *headp;
00851    struct ast_var_t *current;
00852 
00853    if (mgcpdebug) {
00854       ast_verb(3, "MGCP mgcp_call(%s)\n", ast->name);
00855    }
00856    sub = ast->tech_pvt;
00857    p = sub->parent;
00858    headp = &ast->varshead;
00859    AST_LIST_TRAVERSE(headp,current,entries) {
00860       /* Check whether there is an ALERT_INFO variable */
00861       if (strcasecmp(ast_var_name(current),"ALERT_INFO") == 0) {
00862          distinctive_ring = ast_var_value(current);
00863       }
00864    }
00865 
00866    ast_mutex_lock(&sub->lock);
00867    switch (p->hookstate) {
00868    case MGCP_OFFHOOK:
00869       if (!ast_strlen_zero(distinctive_ring)) {
00870          snprintf(tone, sizeof(tone), "L/wt%s", distinctive_ring);
00871          if (mgcpdebug) {
00872             ast_verb(3, "MGCP distinctive callwait %s\n", tone);
00873          }
00874       } else {
00875          ast_copy_string(tone, "L/wt", sizeof(tone));
00876          if (mgcpdebug) {
00877             ast_verb(3, "MGCP normal callwait %s\n", tone);
00878          }
00879       }
00880       break;
00881    case MGCP_ONHOOK:
00882    default:
00883       if (!ast_strlen_zero(distinctive_ring)) {
00884          snprintf(tone, sizeof(tone), "L/r%s", distinctive_ring);
00885          if (mgcpdebug) {
00886             ast_verb(3, "MGCP distinctive ring %s\n", tone);
00887          }
00888       } else {
00889          ast_copy_string(tone, "L/rg", sizeof(tone));
00890          if (mgcpdebug) {
00891             ast_verb(3, "MGCP default ring\n");
00892          }
00893       }
00894       break;
00895    }
00896 
00897    if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
00898       ast_log(LOG_WARNING, "mgcp_call called on %s, neither down nor reserved\n", ast->name);
00899       ast_mutex_unlock(&sub->lock);
00900       return -1;
00901    }
00902 
00903    res = 0;
00904    sub->outgoing = 1;
00905    sub->cxmode = MGCP_CX_RECVONLY;
00906    if (p->type == TYPE_LINE) {
00907       if (!sub->rtp) {
00908          start_rtp(sub);
00909       } else {
00910          transmit_modify_request(sub);
00911       }
00912 
00913       if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) {
00914          /* try to prevent a callwait from disturbing the other connection */
00915          sub->next->cxmode = MGCP_CX_RECVONLY;
00916          transmit_modify_request(sub->next);
00917       }
00918 
00919       transmit_notify_request_with_callerid(sub, tone, ast->cid.cid_num, ast->cid.cid_name);
00920       ast_setstate(ast, AST_STATE_RINGING);
00921 
00922       if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) {
00923          /* Put the connection back in sendrecv */
00924          sub->next->cxmode = MGCP_CX_SENDRECV;
00925          transmit_modify_request(sub->next);
00926       }
00927    } else {
00928       ast_log(LOG_NOTICE, "Don't know how to dial on trunks yet\n");
00929       res = -1;
00930    }
00931    ast_mutex_unlock(&sub->lock);
00932    ast_queue_control(ast, AST_CONTROL_RINGING);
00933    return res;
00934 }

static int mgcp_devicestate ( void *  data  )  [static]

mgcp_devicestate: channel callback for device status monitoring

Parameters:
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

Returns:
device status result (from devicestate.h) AST_DEVICE_INVALID (not available) or AST_DEVICE_UNKNOWN (available but unknown state)

Definition at line 1346 of file chan_mgcp.c.

References AST_DEVICE_INVALID, AST_DEVICE_UNKNOWN, ast_mutex_lock(), ast_mutex_unlock(), mgcp_gateway::endpoints, gatelock, gateways, mgcp_endpoint::name, mgcp_gateway::name, mgcp_endpoint::next, and mgcp_gateway::next.

01347 {
01348    struct mgcp_gateway  *g;
01349    struct mgcp_endpoint *e = NULL;
01350    char *tmp, *endpt, *gw;
01351    int ret = AST_DEVICE_INVALID;
01352 
01353    endpt = ast_strdupa(data);
01354    if ((tmp = strchr(endpt, '@'))) {
01355       *tmp++ = '\0';
01356       gw = tmp;
01357    } else
01358       goto error;
01359 
01360    ast_mutex_lock(&gatelock);
01361    g = gateways;
01362    while (g) {
01363       if (strcasecmp(g->name, gw) == 0) {
01364          e = g->endpoints;
01365          break;
01366       }
01367       g = g->next;
01368    }
01369 
01370    if (!e)
01371       goto error;
01372 
01373    while (e) {
01374       if (strcasecmp(e->name, endpt) == 0)
01375          break;
01376       e = e->next;
01377    }
01378 
01379    if (!e)
01380       goto error;
01381 
01382    /*
01383     * As long as the gateway/endpoint is valid, we'll
01384     * assume that the device is available and its state
01385     * can be tracked.
01386     */
01387    ret = AST_DEVICE_UNKNOWN;
01388 
01389 error:
01390    ast_mutex_unlock(&gatelock);
01391    return ret;
01392 }

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.

01274 {
01275    struct mgcp_subchannel *sub = newchan->tech_pvt;
01276 
01277    ast_mutex_lock(&sub->lock);
01278    ast_log(LOG_NOTICE, "mgcp_fixup(%s, %s)\n", oldchan->name, newchan->name);
01279    if (sub->owner != oldchan) {
01280       ast_mutex_unlock(&sub->lock);
01281       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
01282       return -1;
01283    }
01284    sub->owner = newchan;
01285    ast_mutex_unlock(&sub->lock);
01286    return 0;
01287 }

static enum ast_rtp_get_result mgcp_get_rtp_peer ( struct ast_channel chan,
struct ast_rtp **  rtp 
) [static]

Definition at line 3944 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.

03945 {
03946    struct mgcp_subchannel *sub = NULL;
03947 
03948    if (!(sub = chan->tech_pvt) || !(sub->rtp))
03949       return AST_RTP_GET_FAILED;
03950 
03951    *rtp = sub->rtp;
03952 
03953    if (sub->parent->directmedia)
03954       return AST_RTP_TRY_NATIVE;
03955    else
03956       return AST_RTP_TRY_PARTIAL;
03957 }

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, 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().

00937 {
00938    struct mgcp_subchannel *sub = ast->tech_pvt;
00939    struct mgcp_endpoint *p = sub->parent;
00940 
00941    ast_debug(1, "mgcp_hangup(%s)\n", ast->name);
00942    if (!ast->tech_pvt) {
00943       ast_debug(1, "Asked to hangup channel not connected\n");
00944       return 0;
00945    }
00946    if (strcmp(sub->magic, MGCP_SUBCHANNEL_MAGIC)) {
00947       ast_debug(1, "Invalid magic. MGCP subchannel freed up already.\n");
00948       return 0;
00949    }
00950    ast_mutex_lock(&sub->lock);
00951    if (mgcpdebug) {
00952       ast_verb(3, "MGCP mgcp_hangup(%s) on %s@%s\n", ast->name, p->name, p->parent->name);
00953    }
00954 
00955    if ((p->dtmfmode & MGCP_DTMF_INBAND) && p->dsp) {
00956       /* check whether other channel is active. */
00957       if (!sub->next->owner) {
00958          if (p->dtmfmode & MGCP_DTMF_HYBRID)
00959             p->dtmfmode &= ~MGCP_DTMF_INBAND;
00960          if (mgcpdebug) {
00961             ast_verb(2, "MGCP free dsp on %s@%s\n", p->name, p->parent->name);
00962          }
00963          ast_dsp_free(p->dsp);
00964          p->dsp = NULL;
00965       }
00966    }
00967 
00968    sub->owner = NULL;
00969    if (!ast_strlen_zero(sub->cxident)) {
00970       transmit_connection_del(sub);
00971    }
00972    sub->cxident[0] = '\0';
00973    if ((sub == p->sub) && sub->next->owner) {
00974       if (p->hookstate == MGCP_OFFHOOK) {
00975          if (sub->next->owner && ast_bridged_channel(sub->next->owner)) {
00976             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);
00977          }
00978       } else {
00979          /* set our other connection as the primary and swith over to it */
00980          p->sub = sub->next;
00981          p->sub->cxmode = MGCP_CX_RECVONLY;
00982          transmit_modify_request(p->sub);
00983          if (sub->next->owner && ast_bridged_channel(sub->next->owner)) {
00984             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);
00985          }
00986       }
00987 
00988    } else if ((sub == p->sub->next) && p->hookstate == MGCP_OFFHOOK) {
00989       transmit_notify_request(sub, "L/v");
00990    } else if (p->hookstate == MGCP_OFFHOOK) {
00991       transmit_notify_request(sub, "L/ro");
00992    } else {
00993       transmit_notify_request(sub, "");
00994    }
00995 
00996    ast->tech_pvt = NULL;
00997    sub->alreadygone = 0;
00998    sub->outgoing = 0;
00999    sub->cxmode = MGCP_CX_INACTIVE;
01000    sub->callid[0] = '\0';
01001    if (p) {
01002       memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
01003    }
01004    /* Reset temporary destination */
01005    memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
01006    if (sub->rtp) {
01007       ast_rtp_destroy(sub->rtp);
01008       sub->rtp = NULL;
01009    }
01010 
01011    ast_module_unref(ast_module_info->self);
01012 
01013    if ((p->hookstate == MGCP_ONHOOK) && (!sub->next->rtp)) {
01014       p->hidecallerid = 0;
01015       if (p->hascallwaiting && !p->callwaiting) {
01016          ast_verb(3, "Enabling call waiting on %s\n", ast->name);
01017          p->callwaiting = -1;
01018       }
01019       if (has_voicemail(p)) {
01020          if (mgcpdebug) {
01021             ast_verb(3, "MGCP mgcp_hangup(%s) on %s@%s set vmwi(+)\n",
01022                ast->name, p->name, p->parent->name);
01023          }
01024          transmit_notify_request(sub, "L/vmwi(+)");
01025       } else {
01026          if (mgcpdebug) {
01027             ast_verb(3, "MGCP mgcp_hangup(%s) on %s@%s set vmwi(-)\n",
01028                ast->name, p->name, p->parent->name);
01029          }
01030          transmit_notify_request(sub, "L/vmwi(-)");
01031       }
01032    }
01033    ast_mutex_unlock(&sub->lock);
01034    return 0;
01035 }

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_SRCUPDATE, AST_CONTROL_UNHOLD, ast_log(), ast_moh_start(), ast_moh_stop(), ast_mutex_lock(), ast_mutex_unlock(), 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().

01427 {
01428    struct mgcp_subchannel *sub = ast->tech_pvt;
01429    int res = 0;
01430 
01431    if (mgcpdebug) {
01432       ast_verb(3, "MGCP asked to indicate %d '%s' condition on channel %s\n",
01433          ind, control2str(ind), ast->name);
01434    }
01435    ast_mutex_lock(&sub->lock);
01436    switch(ind) {
01437    case AST_CONTROL_RINGING:
01438 #ifdef DLINK_BUGGY_FIRMWARE   
01439       transmit_notify_request(sub, "rt");
01440 #else
01441       transmit_notify_request(sub, "G/rt");
01442 #endif      
01443       break;
01444    case AST_CONTROL_BUSY:
01445       transmit_notify_request(sub, "L/bz");
01446       break;
01447    case AST_CONTROL_CONGESTION:
01448       transmit_notify_request(sub, "G/cg");
01449       break;
01450    case AST_CONTROL_HOLD:
01451       ast_moh_start(ast, data, NULL);
01452       break;
01453    case AST_CONTROL_UNHOLD:
01454       ast_moh_stop(ast);
01455       break;
01456    case AST_CONTROL_SRCUPDATE:
01457       ast_rtp_new_source(sub->rtp);
01458       break;
01459    case -1:
01460       transmit_notify_request(sub, "");
01461       break;
01462    default:
01463       ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
01464       res = -1;
01465    }
01466    ast_mutex_unlock(&sub->lock);
01467    return res;
01468 }

static struct ast_channel* mgcp_new ( struct mgcp_subchannel sub,
int  state 
) [static, read]

Definition at line 1470 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, 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, 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_channel::tech, ast_channel::tech_pvt, and ast_channel::writeformat.

Referenced by handle_hd_hf(), and mgcp_request().

01471 {
01472    struct ast_channel *tmp;
01473    struct mgcp_endpoint *i = sub->parent;
01474    int fmt;
01475 
01476    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);
01477    if (tmp) {
01478       tmp->tech = &mgcp_tech;
01479       tmp->nativeformats = i->capability;
01480       if (!tmp->nativeformats)
01481          tmp->nativeformats = capability;
01482       fmt = ast_best_codec(tmp->nativeformats);
01483       ast_string_field_build(tmp, name, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id);
01484       if (sub->rtp)
01485          ast_channel_set_fd(tmp, 0, ast_rtp_fd(sub->rtp));
01486       if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) {
01487          i->dsp = ast_dsp_new();
01488          ast_dsp_set_features(i->dsp, DSP_FEATURE_DIGIT_DETECT);
01489          /* this is to prevent clipping of dtmf tones during dsp processing */
01490          ast_dsp_set_digitmode(i->dsp, DSP_DIGITMODE_NOQUELCH);
01491       } else {
01492          i->dsp = NULL;
01493       }
01494       if (state == AST_STATE_RING)
01495          tmp->rings = 1;
01496       tmp->writeformat = fmt;
01497       tmp->rawwriteformat = fmt;
01498       tmp->readformat = fmt;
01499       tmp->rawreadformat = fmt;
01500       tmp->tech_pvt = sub;
01501       if (!ast_strlen_zero(i->language))
01502          ast_string_field_set(tmp, language, i->language);
01503       if (!ast_strlen_zero(i->accountcode))
01504          ast_string_field_set(tmp, accountcode, i->accountcode);
01505       if (i->amaflags)
01506          tmp->amaflags = i->amaflags;
01507       sub->owner = tmp;
01508       ast_module_ref(ast_module_info->self);
01509       tmp->callgroup = i->callgroup;
01510       tmp->pickupgroup = i->pickupgroup;
01511       ast_string_field_set(tmp, call_forward, i->call_forward);
01512       ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
01513       ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
01514 
01515       /* Don't use ast_set_callerid() here because it will
01516        * generate a needless NewCallerID event */
01517       tmp->cid.cid_ani = ast_strdup(i->cid_num);
01518       
01519       if (!i->adsi)
01520          tmp->adsicpe = AST_ADSI_UNAVAILABLE;
01521       tmp->priority = 1;
01522       if (sub->rtp)
01523          ast_jb_configure(tmp, &global_jbconf);
01524       if (state != AST_STATE_DOWN) {
01525          if (ast_pbx_start(tmp)) {
01526             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
01527             ast_hangup(tmp);
01528             tmp = NULL;
01529          }
01530       }
01531       ast_verb(3, "MGCP mgcp_new(%s) created in state: %s\n",
01532             tmp->name, ast_state2str(state));
01533    } else {
01534       ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
01535    }
01536    return tmp;
01537 }

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, 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().

00695 {
00696    struct mgcp_message *msg;
00697    struct mgcp_message *cur;
00698    struct mgcp_gateway *gw;
00699    struct timeval now;
00700 
00701    msg = ast_malloc(sizeof(*msg) + len);
00702    if (!msg) {
00703       return -1;
00704    }
00705    gw = ((p && p->parent) ? p->parent : NULL);
00706    if (!gw) {
00707       ast_free(msg);
00708       return -1;
00709    }
00710 /* SC
00711    time(&t);
00712    if (gw->messagepending && (gw->lastouttime + 20 < t)) {
00713       ast_log(LOG_NOTICE, "Timeout waiting for response to message:%d,  lastouttime: %ld, now: %ld.  Dumping pending queue\n",
00714          gw->msgs ? gw->msgs->seqno : -1, (long) gw->lastouttime, (long) t);
00715       dump_queue(sub->parent);
00716    }
00717 */
00718    msg->owner_sub = sub;
00719    msg->owner_ep = p;
00720    msg->seqno = seqno;
00721    msg->next = NULL;
00722    msg->len = len;
00723    msg->retrans = 0;
00724    memcpy(msg->buf, data, msg->len);
00725 
00726    ast_mutex_lock(&gw->msgs_lock);
00727    cur = gw->msgs;
00728    if (cur) {
00729       while(cur->next)
00730          cur = cur->next;
00731       cur->next = msg;
00732    } else {
00733       gw->msgs = msg;
00734    }
00735 
00736    now = ast_tvnow();
00737    msg->expire = now.tv_sec * 1000 + now.tv_usec / 1000 + DEFAULT_RETRANS;
00738 
00739    if (gw->retransid == -1)
00740       gw->retransid = ast_sched_add(sched, DEFAULT_RETRANS, retrans_pkt, (void *)gw);
00741    ast_mutex_unlock(&gw->msgs_lock);
00742 /* SC
00743    if (!gw->messagepending) {
00744       gw->messagepending = 1;
00745       gw->lastout = seqno;
00746       gw->lastouttime = t;
00747 */
00748    __mgcp_xmit(gw, msg->buf, msg->len);
00749       /* XXX Should schedule retransmission XXX */
00750 /* SC
00751    } else
00752       ast_debug(1, "Deferring transmission of transaction %d\n", seqno);
00753 */
00754    return 0;
00755 }

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().

00625 {
00626    struct ast_frame f = { AST_FRAME_CONTROL, };
00627    f.subclass = control;
00628    return mgcp_queue_frame(sub, &f);
00629 }

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().

00593 {
00594    for(;;) {
00595       if (sub->owner) {
00596          if (!ast_channel_trylock(sub->owner)) {
00597             ast_queue_frame(sub->owner, f);
00598             ast_channel_unlock(sub->owner);
00599             break;
00600          } else {
00601             DEADLOCK_AVOIDANCE(&sub->lock);
00602          }
00603       } else
00604          break;
00605    }
00606 }

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().

00609 {
00610    for(;;) {
00611       if (sub->owner) {
00612          if (!ast_channel_trylock(sub->owner)) {
00613             ast_queue_hangup(sub->owner);
00614             ast_channel_unlock(sub->owner);
00615             break;
00616          } else {
00617             DEADLOCK_AVOIDANCE(&sub->lock);
00618          }
00619       } else
00620          break;
00621    }
00622 }

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.

01234 {
01235    struct ast_frame *f;
01236    struct mgcp_subchannel *sub = ast->tech_pvt;
01237    ast_mutex_lock(&sub->lock);
01238    f = mgcp_rtp_read(sub);
01239    ast_mutex_unlock(&sub->lock);
01240    return f;
01241 }

static char * mgcp_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 4289 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().

04290 {
04291    static int deprecated = 0;
04292 
04293    if (e) {
04294       switch (cmd) {
04295       case CLI_INIT:
04296          e->command = "mgcp reload";
04297          e->usage =
04298             "Usage: mgcp reload\n"
04299             "       'mgcp reload' is deprecated.  Please use 'reload chan_mgcp.so' instead.\n";
04300          return NULL;
04301       case CLI_GENERATE:
04302          return NULL;
04303       }
04304    }
04305 
04306    if (!deprecated && a && a->argc > 0) {
04307       ast_log(LOG_WARNING, "'mgcp reload' is deprecated.  Please use 'reload chan_mgcp.so' instead.\n");
04308       deprecated = 1;
04309    }
04310 
04311    ast_mutex_lock(&mgcp_reload_lock);
04312    if (mgcp_reloading) {
04313       ast_verbose("Previous mgcp reload not yet done\n");
04314    } else
04315       mgcp_reloading = 1;
04316    ast_mutex_unlock(&mgcp_reload_lock);
04317    restart_monitor();
04318    return CLI_SUCCESS;
04319 }

static struct ast_channel * mgcp_request ( const char *  type,
int  format,
void *  data,
int *  cause 
) [static, read]

Definition at line 3498 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, mgcp_endpoint::dnd, find_subchannel_and_lock(), 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().

03499 {
03500    int oldformat;
03501    struct mgcp_subchannel *sub;
03502    struct ast_channel *tmpc = NULL;
03503    char tmp[256];
03504    char *dest = data;
03505 
03506    oldformat = format;
03507    format &= capability;
03508    if (!format) {
03509       ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
03510       return NULL;
03511    }
03512    ast_copy_string(tmp, dest, sizeof(tmp));
03513    if (ast_strlen_zero(tmp)) {
03514       ast_log(LOG_NOTICE, "MGCP Channels require an endpoint\n");
03515       return NULL;
03516    }
03517    sub = find_subchannel_and_lock(tmp, 0, NULL);
03518    if (!sub) {
03519       ast_log(LOG_WARNING, "Unable to find MGCP endpoint '%s'\n", tmp);
03520       *cause = AST_CAUSE_UNREGISTERED;
03521       return NULL;
03522    }
03523    
03524    ast_verb(3, "MGCP mgcp_request(%s)\n", tmp);
03525    ast_verb(3, "MGCP cw: %d, dnd: %d, so: %d, sno: %d\n",
03526          sub->parent->callwaiting, sub->parent->dnd, sub->owner ? 1 : 0, sub->next->owner ? 1: 0);
03527    /* Must be busy */
03528    if (((sub->parent->callwaiting) && ((sub->owner) && (sub->next->owner))) ||
03529       ((!sub->parent->callwaiting) && (sub->owner)) ||
03530        (sub->parent->dnd && (ast_strlen_zero(sub->parent->call_forward)))) {
03531       if (sub->parent->hookstate == MGCP_ONHOOK) {
03532          if (has_voicemail(sub->parent)) {
03533             transmit_notify_request(sub,"L/vmwi(+)");
03534          } else {
03535             transmit_notify_request(sub,"L/vmwi(-)");
03536          }
03537       }
03538       *cause = AST_CAUSE_BUSY;
03539       ast_mutex_unlock(&sub->lock);
03540       return NULL;
03541    }
03542    tmpc = mgcp_new(sub->owner ? sub->next : sub, AST_STATE_DOWN);
03543    ast_mutex_unlock(&sub->lock);
03544    if (!tmpc)
03545       ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
03546    restart_monitor();
03547    return tmpc;
03548 }

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().

01203 {
01204    /* Retrieve audio/etc from channel.  Assumes sub->lock is already held. */
01205    struct ast_frame *f;
01206 
01207    f = ast_rtp_read(sub->rtp);
01208    /* Don't send RFC2833 if we're not supposed to */
01209    if (f && (f->frametype == AST_FRAME_DTMF) && !(sub->parent->dtmfmode & MGCP_DTMF_RFC2833))
01210       return &ast_null_frame;
01211    if (sub->owner) {
01212       /* We already hold the channel lock */
01213       if (f->frametype == AST_FRAME_VOICE) {
01214          if (f->subclass != sub->owner->nativeformats) {
01215             ast_debug(1, "Oooh, format changed to %d\n", f->subclass);
01216             sub->owner->nativeformats = f->subclass;
01217             ast_set_read_format(sub->owner, sub->owner->readformat);
01218             ast_set_write_format(sub->owner, sub->owner->writeformat);
01219          }
01220          /* Courtesy fearnor aka alex@pilosoft.com */
01221          if ((sub->parent->dtmfmode & MGCP_DTMF_INBAND) && (sub->parent->dsp)) {
01222 #if 0
01223             ast_log(LOG_NOTICE, "MGCP ast_dsp_process\n");
01224 #endif
01225             f = ast_dsp_process(sub->owner, sub->parent->dsp, f);
01226          }
01227       }
01228    }
01229    return f;
01230 }

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.

01290 {
01291    struct mgcp_subchannel *sub = ast->tech_pvt;
01292    struct mgcp_endpoint *p = sub->parent;
01293    int res = 0;
01294 
01295    ast_mutex_lock(&sub->lock);
01296    if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
01297       ast_log(LOG_DEBUG, "Sending DTMF using inband/hybrid\n");
01298       res = -1; /* Let asterisk play inband indications */
01299    } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
01300       ast_log(LOG_DEBUG, "Sending DTMF using RFC2833");
01301       ast_rtp_senddigit_begin(sub->rtp, digit);
01302    } else {
01303       ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
01304    }
01305    ast_mutex_unlock(&sub->lock);
01306 
01307    return res;
01308 }

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().

01311 {
01312    struct mgcp_subchannel *sub = ast->tech_pvt;
01313    struct mgcp_endpoint *p = sub->parent;
01314    int res = 0;
01315    char tmp[4];
01316 
01317    ast_mutex_lock(&sub->lock);
01318    if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
01319       ast_log(LOG_DEBUG, "Stopping DTMF using inband/hybrid\n");
01320       res = -1; /* Tell Asterisk to stop inband indications */
01321    } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
01322       ast_log(LOG_DEBUG, "Stopping DTMF using RFC2833\n");
01323       tmp[0] = 'D';
01324       tmp[1] = '/';
01325       tmp[2] = digit;
01326       tmp[3] = '\0';
01327       transmit_notify_request(sub, tmp);
01328                 ast_rtp_senddigit_end(sub->rtp, digit);
01329    } else {
01330       ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
01331    }
01332    ast_mutex_unlock(&sub->lock);
01333 
01334    return res;
01335 }

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 3959 of file chan_mgcp.c.

References mgcp_subchannel::alreadygone, ast_channel::tech_pvt, and transmit_modify_with_sdp().

03960 {
03961    /* XXX Is there such thing as video support with MGCP? XXX */
03962    struct mgcp_subchannel *sub;
03963    sub = chan->tech_pvt;
03964    if (sub && !sub->alreadygone) {
03965       transmit_modify_with_sdp(sub, rtp, codecs);
03966       return 0;
03967    }
03968    return -1;
03969 }

static void* mgcp_ss ( void *  data  )  [static]

Definition at line 2637 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, mgcp_endpoint::dnd, mgcp_endpoint::dtmf_buf, mgcp_endpoint::dtmfmode, exten, ast_channel::exten, mgcp_endpoint::hascallwaiting, mgcp_endpoint::hidecallerid, ast_channel::language, mgcp_endpoint::lastcallerid, len(), LOG_WARNING, 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().

02638 {
02639    struct ast_channel *chan = data;
02640    struct mgcp_subchannel *sub = chan->tech_pvt;
02641    struct mgcp_endpoint *p = sub->parent;
02642    /* char exten[AST_MAX_EXTENSION] = ""; */
02643    int len = 0;
02644    int timeout = firstdigittimeout;
02645    int res= 0;
02646    int getforward = 0;
02647    int loop_pause = 100;
02648 
02649    len = strlen(p->dtmf_buf);
02650 
02651    while(len < AST_MAX_EXTENSION-1) {
02652       res = 1;  /* Assume that we will get a digit */
02653       while (strlen(p->dtmf_buf) == len){
02654          ast_safe_sleep(chan, loop_pause);
02655          timeout -= loop_pause;
02656          if (timeout <= 0){
02657             res = 0;
02658             break;
02659          }
02660          res = 1;
02661       }
02662 
02663       timeout = 0;
02664       len = strlen(p->dtmf_buf);
02665 
02666       if (!ast_ignore_pattern(chan->context, p->dtmf_buf)) {
02667          /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
02668          ast_indicate(chan, -1);
02669       } else {
02670          /* XXX Redundant?  We should already be playing dialtone */
02671          /*tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALTONE);*/
02672          transmit_notify_request(sub, "L/dl");
02673       }
02674       if (ast_exists_extension(chan, chan->context, p->dtmf_buf, 1, p->cid_num)) {
02675          if (!res || !ast_matchmore_extension(chan, chan->context, p->dtmf_buf, 1, p->cid_num)) {
02676             if (getforward) {
02677                /* Record this as the forwarding extension */
02678                ast_copy_string(p->call_forward, p->dtmf_buf, sizeof(p->call_forward)); 
02679                ast_verb(3, "Setting call forward to '%s' on channel %s\n",
02680                      p->call_forward, chan->name);
02681                /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02682                transmit_notify_request(sub, "L/sl");
02683                if (res)
02684                   break;
02685                usleep(500000);
02686                /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
02687                ast_indicate(chan, -1);
02688                sleep(1);
02689                memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02690                /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALTONE);*/
02691                transmit_notify_request(sub, "L/dl");
02692                len = 0;
02693                getforward = 0;
02694             } else {
02695                /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
02696                ast_indicate(chan, -1);
02697                ast_copy_string(chan->exten, p->dtmf_buf, sizeof(chan->exten));
02698                memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02699                ast_set_callerid(chan,
02700                   p->hidecallerid ? "" : p->cid_num,
02701                   p->hidecallerid ? "" : p->cid_name,
02702                   chan->cid.cid_ani ? NULL : p->cid_num);
02703                ast_setstate(chan, AST_STATE_RING);
02704                /*dahdi_enable_ec(p);*/
02705                if (p->dtmfmode & MGCP_DTMF_HYBRID) {
02706                   p->dtmfmode |= MGCP_DTMF_INBAND;
02707                   ast_indicate(chan, -1);
02708                }
02709                res = ast_pbx_run(chan);
02710                if (res) {
02711                   ast_log(LOG_WARNING, "PBX exited non-zero\n");
02712                   /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
02713                   /*transmit_notify_request(p, "nbz", 1);*/
02714                   transmit_notify_request(sub, "G/cg");
02715                }
02716                return NULL;
02717             }
02718          } else {
02719             /* It's a match, but they just typed a digit, and there is an ambiguous match,
02720                so just set the timeout to matchdigittimeout and wait some more */
02721             timeout = matchdigittimeout;
02722          }
02723       } else if (res == 0) {
02724          ast_debug(1, "not enough digits (and no ambiguous match)...\n");
02725          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
02726          transmit_notify_request(sub, "G/cg");
02727          /*dahdi_wait_event(p->subs[index].zfd);*/
02728          ast_hangup(chan);
02729          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02730          return NULL;
02731       } else if (p->hascallwaiting && p->callwaiting && !strcmp(p->dtmf_buf, "*70")) {
02732          ast_verb(3, "Disabling call waiting on %s\n", chan->name);
02733          /* Disable call waiting if enabled */
02734          p->callwaiting = 0;
02735          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02736          transmit_notify_request(sub, "L/sl");
02737          len = 0;
02738          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02739          timeout = firstdigittimeout;
02740       } else if (!strcmp(p->dtmf_buf,ast_pickup_ext())) {
02741          /* Scan all channels and see if any there
02742           * ringing channqels with that have call groups
02743           * that equal this channels pickup group  
02744           */
02745          if (ast_pickup_call(chan)) {
02746             ast_log(LOG_WARNING, "No call pickup possible...\n");
02747             /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
02748             transmit_notify_request(sub, "G/cg");
02749          }
02750          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02751          ast_hangup(chan);
02752          return NULL;
02753       } else if (!p->hidecallerid && !strcmp(p->dtmf_buf, "*67")) {
02754          ast_verb(3, "Disabling Caller*ID on %s\n", chan->name);
02755          /* Disable Caller*ID if enabled */
02756          p->hidecallerid = 1;
02757          ast_set_callerid(chan, "", "", NULL);
02758          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02759          transmit_notify_request(sub, "L/sl");
02760          len = 0;
02761          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02762          timeout = firstdigittimeout;
02763       } else if (p->callreturn && !strcmp(p->dtmf_buf, "*69")) {
02764          res = 0;
02765          if (!ast_strlen_zero(p->lastcallerid)) {
02766             res = ast_say_digit_str(chan, p->lastcallerid, "", chan->language);
02767          }
02768          if (!res)
02769             /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02770             transmit_notify_request(sub, "L/sl");
02771          break;
02772       } else if (!strcmp(p->dtmf_buf, "*78")) {
02773          /* Do not disturb */
02774          ast_verb(3, "Enabled DND on channel %s\n", chan->name);
02775          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02776          transmit_notify_request(sub, "L/sl");
02777          p->dnd = 1;
02778          getforward = 0;
02779          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02780          len = 0;
02781       } else if (!strcmp(p->dtmf_buf, "*79")) {
02782          /* Do not disturb */
02783          ast_verb(3, "Disabled DND on channel %s\n", chan->name);
02784          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02785          transmit_notify_request(sub, "L/sl");
02786          p->dnd = 0;
02787          getforward = 0;
02788          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02789          len = 0;
02790       } else if (p->cancallforward && !strcmp(p->dtmf_buf, "*72")) {
02791          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02792          transmit_notify_request(sub, "L/sl");
02793          getforward = 1;
02794          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02795          len = 0;
02796       } else if (p->cancallforward && !strcmp(p->dtmf_buf, "*73")) {
02797          ast_verb(3, "Cancelling call forwarding on channel %s\n", chan->name);
02798          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02799          transmit_notify_request(sub, "L/sl");
02800          memset(p->call_forward, 0, sizeof(p->call_forward));
02801          getforward = 0;
02802          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02803          len = 0;
02804       } else if (!strcmp(p->dtmf_buf, ast_parking_ext()) && 
02805          sub->next->owner && ast_bridged_channel(sub->next->owner)) {
02806          /* This is a three way call, the main call being a real channel, 
02807             and we're parking the first call. */
02808          ast_masq_park_call(ast_bridged_channel(sub->next->owner), chan, 0, NULL);
02809          ast_verb(3, "Parking call to '%s'\n", chan->name);
02810          break;
02811       } else if (!ast_strlen_zero(p->lastcallerid) && !strcmp(p->dtmf_buf, "*60")) {
02812          ast_verb(3, "Blacklisting number %s\n", p->lastcallerid);
02813          res = ast_db_put("blacklist", p->lastcallerid, "1");
02814          if (!res) {
02815             /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02816             transmit_notify_request(sub, "L/sl");
02817             memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02818             len = 0;
02819          }
02820       } else if (p->hidecallerid && !strcmp(p->dtmf_buf, "*82")) {
02821          ast_verb(3, "Enabling Caller*ID on %s\n", chan->name);
02822          /* Enable Caller*ID if enabled */
02823          p->hidecallerid = 0;
02824          ast_set_callerid(chan, p->cid_num, p->cid_name, NULL);
02825          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
02826          transmit_notify_request(sub, "L/sl");
02827          len = 0;
02828          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02829          timeout = firstdigittimeout;
02830       } else if (!ast_canmatch_extension(chan, chan->context, p->dtmf_buf, 1, chan->cid.cid_num) &&
02831             ((p->dtmf_buf[0] != '*') || (strlen(p->dtmf_buf) > 2))) {
02832          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);
02833          break;
02834       }
02835       if (!timeout)
02836          timeout = gendigittimeout;
02837       if (len && !ast_ignore_pattern(chan->context, p->dtmf_buf))
02838          /*tone_zone_play_tone(p->subs[index].zfd, -1);*/
02839          ast_indicate(chan, -1);
02840    }
02841 #if 0
02842    for (;;) {
02843       res = ast_waitfordigit(chan, to);
02844       if (!res) {
02845          ast_debug(1, "Timeout...\n");
02846          break;
02847       }
02848       if (res < 0) {
02849          ast_debug(1, "Got hangup...\n");
02850          ast_hangup(chan);
02851          break;
02852       }
02853       exten[pos++] = res;
02854       if (!ast_ignore_pattern(chan->context, exten))
02855          ast_indicate(chan, -1);
02856       if (ast_matchmore_extension(chan, chan->context, exten, 1, chan->callerid)) {
02857          if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid)) 
02858             to = 3000;
02859          else
02860             to = 8000;
02861       } else
02862          break;
02863    }
02864    if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid)) {
02865       ast_copy_string(chan->exten, exten, sizeof(chan->exten)1);
02866       if (!p->rtp) {
02867          start_rtp(p);
02868       }
02869       ast_setstate(chan, AST_STATE_RING);
02870       chan->rings = 1;
02871       if (ast_pbx_run(chan)) {
02872          ast_log(LOG_WARNING, "Unable to launch PBX on %s\n", chan->name);
02873       } else {
02874          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02875          return NULL;
02876       }
02877    }
02878 #endif
02879    ast_hangup(chan);
02880    memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
02881    return NULL;
02882 }

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.

01244 {
01245    struct mgcp_subchannel *sub = ast->tech_pvt;
01246    int res = 0;
01247    if (frame->frametype != AST_FRAME_VOICE) {
01248       if (frame->frametype == AST_FRAME_IMAGE)
01249          return 0;
01250       else {
01251          ast_log(LOG_WARNING, "Can't send %d type frames with MGCP write\n", frame->frametype);
01252          return 0;
01253       }
01254    } else {
01255       if (!(frame->subclass & ast->nativeformats)) {
01256          ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
01257             frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat);
01258          return -1;
01259       }
01260    }
01261    if (sub) {
01262       ast_mutex_lock(&sub->lock);
01263       if ((sub->parent->sub == sub) || !sub->parent->singlepath) {
01264          if (sub->rtp) {
01265             res =  ast_rtp_write(sub->rtp, frame);
01266          }
01267       }
01268       ast_mutex_unlock(&sub->lock);
01269    }
01270    return res;
01271 }

static int mgcpsock_read ( int *  id,
int  fd,
short  events,
void *  ignore 
) [static]

Definition at line 3294 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().

03295 {
03296    struct mgcp_request req;
03297    struct sockaddr_in sin;
03298    struct mgcp_subchannel *sub;
03299    int res;
03300    socklen_t len;
03301    int result;
03302    int ident;
03303    len = sizeof(sin);
03304    memset(&req, 0, sizeof(req));
03305    res = recvfrom(mgcpsock, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len);
03306    if (res < 0) {
03307       if (errno != ECONNREFUSED)
03308          ast_log(LOG_WARNING, "Recv error: %s\n", strerror(errno));
03309       return 1;
03310    }
03311    req.data[res] = '\0';
03312    req.len = res;
03313    if (mgcpdebug) {
03314       ast_verbose("MGCP read: \n%s\nfrom %s:%d\n", req.data, ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
03315    }
03316    parse(&req);
03317    if (req.headers < 1) {
03318       /* Must have at least one header */
03319       return 1;
03320    }
03321    if (ast_strlen_zero(req.identifier)) {
03322       ast_log(LOG_NOTICE, "Message from %s missing identifier\n", ast_inet_ntoa(sin.sin_addr));
03323       return 1;
03324    }
03325 
03326    if (sscanf(req.verb, "%30d", &result) && sscanf(req.identifier, "%30d", &ident)) {
03327       /* Try to find who this message is for, if it's important */
03328       sub = find_subchannel_and_lock(NULL, ident, &sin);
03329       if (sub) {
03330          struct mgcp_gateway *gw = sub->parent->parent;
03331          struct mgcp_message *cur, *prev;
03332 
03333          ast_mutex_unlock(&sub->lock);
03334          ast_mutex_lock(&gw->msgs_lock);
03335          for (prev = NULL, cur = gw->msgs; cur; prev = cur, cur = cur->next) {
03336             if (cur->seqno == ident) {
03337                ast_debug(1, "Got response back on transaction %d\n", ident);
03338                if (prev)
03339                   prev->next = cur->next;
03340                else
03341                   gw->msgs = cur->next;
03342                break;
03343             }
03344          }
03345 
03346          /* stop retrans timer if the queue is empty */
03347          if (!gw->msgs) {
03348             AST_SCHED_DEL(sched, gw->retransid);
03349          }
03350 
03351          ast_mutex_unlock(&gw->msgs_lock);
03352          if (cur) {
03353             handle_response(cur->owner_ep, cur->owner_sub, result, ident, &req);
03354             ast_free(cur);
03355             return 1;
03356          }
03357 
03358          ast_log(LOG_NOTICE, "Got response back on [%s] for transaction %d we aren't sending?\n", 
03359             gw->name, ident);
03360       }
03361    } else {
03362       if (ast_strlen_zero(req.endpoint) || 
03363             ast_strlen_zero(req.version) || 
03364          ast_strlen_zero(req.verb)) {
03365          ast_log(LOG_NOTICE, "Message must have a verb, an idenitifier, version, and endpoint\n");
03366          return 1;
03367       }
03368       /* Process request, with iflock held */
03369       sub = find_subchannel_and_lock(req.endpoint, 0, &sin);
03370       if (sub) {
03371          /* look first to find a matching response in the queue */
03372          if (!find_and_retrans(sub, &req))
03373             /* pass the request off to the currently mastering subchannel */
03374             handle_request(sub, &req, &sin);
03375          ast_mutex_unlock(&sub->lock);
03376       }
03377    }
03378    return 1;
03379 }

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().

00455 {
00456    /* This module does not handle MWI in an event-based manner.  However, it
00457     * subscribes to MWI for each mailbox that is configured so that the core
00458     * knows that we care about it.  Then, chan_mgcp will get the MWI from the
00459     * event cache instead of checking the mailbox directly. */
00460 }

static void parse ( struct mgcp_request req  )  [static]

Definition at line 1737 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().

01738 {
01739    /* Divide fields by NULL's */
01740    char *c;
01741    int f = 0;
01742    c = req->data;
01743 
01744    /* First header starts immediately */
01745    req->header[f] = c;
01746    while(*c) {
01747       if (*c == '\n') {
01748          /* We've got a new header */
01749          *c = 0;
01750 #if 0
01751          printf("Header: %s (%d)\n", req->header[f], strlen(req->header[f]));
01752 #endif         
01753          if (ast_strlen_zero(req->header[f])) {
01754             /* Line by itself means we're now in content */
01755             c++;
01756             break;
01757          }
01758          if (f >= MGCP_MAX_HEADERS - 1) {
01759             ast_log(LOG_WARNING, "Too many MGCP headers...\n");
01760          } else
01761             f++;
01762          req->header[f] = c + 1;
01763       } else if (*c == '\r') {
01764          /* Ignore but eliminate \r's */
01765          *c = 0;
01766       }
01767       c++;
01768    }
01769    /* Check for last header */
01770    if (!ast_strlen_zero(req->header[f])) 
01771       f++;
01772    req->headers = f;
01773    /* Now we process any mime content */
01774    f = 0;
01775    req->line[f] = c;
01776    while(*c) {
01777       if (*c == '\n') {
01778          /* We've got a new line */
01779          *c = 0;
01780 #if 0
01781          printf("Line: %s (%d)\n", req->line[f], strlen(req->line[f]));
01782 #endif         
01783          if (f >= MGCP_MAX_LINES - 1) {
01784             ast_log(LOG_WARNING, "Too many SDP lines...\n");
01785          } else
01786             f++;
01787          req->line[f] = c + 1;
01788       } else if (*c == '\r') {
01789          /* Ignore and eliminate \r's */
01790          *c = 0;
01791       }
01792       c++;
01793    }
01794    /* Check for last line */
01795    if (!ast_strlen_zero(req->line[f])) 
01796       f++;
01797    req->lines = f;
01798    /* Parse up the initial header */
01799    c = req->header[0];
01800    while(*c && *c < 33) c++;
01801    /* First the verb */
01802    req->verb = c;
01803    while(*c && (*c > 32)) c++;
01804    if (*c) {
01805       *c = '\0';
01806       c++;
01807       while(*c && (*c < 33)) c++;
01808       req->identifier = c;
01809       while(*c && (*c > 32)) c++;
01810       if (*c) {
01811          *c = '\0';
01812          c++;
01813          while(*c && (*c < 33)) c++;
01814          req->endpoint = c;
01815          while(*c && (*c > 32)) c++;
01816          if (*c) {
01817             *c = '\0';
01818             c++;
01819             while(*c && (*c < 33)) c++;
01820             req->version = c;
01821             while(*c && (*c > 32)) c++;
01822             while(*c && (*c < 33)) c++;
01823             while(*c && (*c > 32)) c++;
01824             *c = '\0';
01825          }
01826       }
01827    }
01828       
01829    if (mgcpdebug) {
01830       ast_verbose("Verb: '%s', Identifier: '%s', Endpoint: '%s', Version: '%s'\n",
01831          req->verb, req->identifier, req->endpoint, req->version);
01832       ast_verbose("%d headers, %d lines\n", req->headers, req->lines);
01833    }
01834    if (*c) 
01835       ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c);
01836 }

static int process_sdp ( struct mgcp_subchannel sub,
struct mgcp_request req 
) [static]

Definition at line 1838 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_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().

01839 {
01840    char *m;
01841    char *c;
01842    char *a;
01843    char host[258];
01844    int len;
01845    int portno;
01846    int peercapability, peerNonCodecCapability;
01847    struct sockaddr_in sin;
01848    char *codecs;
01849    struct ast_hostent ahp; struct hostent *hp;
01850    int codec, codec_count=0;
01851    int iterator;
01852    struct mgcp_endpoint *p = sub->parent;
01853 
01854    /* Get codec and RTP info from SDP */
01855    m = get_sdp(req, "m");
01856    c = get_sdp(req, "c");
01857    if (ast_strlen_zero(m) || ast_strlen_zero(c)) {
01858       ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s', c = '%s')\n", m, c);
01859       return -1;
01860    }
01861    if (sscanf(c, "IN IP4 %256s", host) != 1) {
01862       ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
01863       return -1;
01864    }
01865    /* XXX This could block for a long time, and block the main thread! XXX */
01866    hp = ast_gethostbyname(host, &ahp);
01867    if (!hp) {
01868       ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c);
01869       return -1;
01870    }
01871    if (sscanf(m, "audio %30d RTP/AVP %n", &portno, &len) != 1) {
01872       ast_log(LOG_WARNING, "Unable to determine port number for RTP in '%s'\n", m); 
01873       return -1;
01874    }
01875    sin.sin_family = AF_INET;
01876    memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
01877    sin.sin_port = htons(portno);
01878    ast_rtp_set_peer(sub->rtp, &sin);
01879 #if 0
01880    printf("Peer RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
01881 #endif   
01882    /* Scan through the RTP payload types specified in a "m=" line: */
01883    ast_rtp_pt_clear(sub->rtp);
01884    codecs = ast_strdupa(m + len);
01885    while (!ast_strlen_zero(codecs)) {
01886       if (sscanf(codecs, "%30d%n", &codec, &len) != 1) {
01887          if (codec_count)
01888             break;
01889          ast_log(LOG_WARNING, "Error in codec string '%s' at '%s'\n", m, codecs);
01890          return -1;
01891       }
01892       ast_rtp_set_m_type(sub->rtp, codec);
01893       codec_count++;
01894       codecs += len;
01895    }
01896 
01897    /* Next, scan through each "a=rtpmap:" line, noting each */
01898    /* specified RTP payload type (with corresponding MIME subtype): */
01899    sdpLineNum_iterator_init(&iterator);
01900    while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
01901       char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
01902       if (sscanf(a, "rtpmap: %30u %127[^/]/", &codec, mimeSubtype) != 2)
01903          continue;
01904       /* Note: should really look at the 'freq' and '#chans' params too */
01905       ast_rtp_set_rtpmap_type(sub->rtp, codec, "audio", mimeSubtype, 0);
01906    }
01907 
01908    /* Now gather all of the codecs that were asked for: */
01909    ast_rtp_get_current_formats(sub->rtp, &peercapability, &peerNonCodecCapability);
01910    p->capability = capability & peercapability;
01911    if (mgcpdebug) {
01912       ast_verbose("Capabilities: us - %d, them - %d, combined - %d\n",
01913          capability, peercapability, p->capability);
01914       ast_verbose("Non-codec capabilities: us - %d, them - %d, combined - %d\n",
01915          nonCodecCapability, peerNonCodecCapability, p->nonCodecCapability);
01916    }
01917    if (!p->capability) {
01918       ast_log(LOG_WARNING, "No compatible codecs!\n");
01919       return -1;
01920    }
01921    return 0;
01922 }

static void prune_gateways ( void   )  [static]

Definition at line 4033 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().

04034 {
04035    struct mgcp_gateway *g, *z, *r;
04036    struct mgcp_endpoint *e, *p, *t;
04037 
04038    ast_mutex_lock(&gatelock);
04039 
04040    /* prune gateways */
04041    for (z = NULL, g = gateways; g;) {
04042       /* prune endpoints */
04043       for (p = NULL, e = g->endpoints; e; ) {
04044          if (e->delme || g->delme) {
04045             t = e;
04046             e = e->next;
04047             if (!p)
04048                g->endpoints = e;
04049             else
04050                p->next = e;
04051             destroy_endpoint(t);
04052          } else {
04053             p = e;
04054             e = e->next;
04055          }
04056       }
04057 
04058       if (g->delme) {
04059          r = g;
04060          g = g->next;
04061          if (!z)
04062             gateways = g;
04063          else
04064             z->next = g;
04065 
04066          destroy_gateway(r);
04067       } else {
04068          z = g;
04069          g = g->next;
04070       }
04071    }
04072 
04073    ast_mutex_unlock(&gatelock);
04074 }

static int reload ( void   )  [static]

Definition at line 4321 of file chan_mgcp.c.

References mgcp_reload().

04322 {
04323    mgcp_reload(NULL, 0, NULL);
04324    return 0;
04325 }

static int reload_config ( int  reload  )  [static]

Definition at line 4076 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().

04077 {
04078    struct ast_config *cfg;
04079    struct ast_variable *v;
04080    struct mgcp_gateway *g;
04081    struct mgcp_endpoint *e;
04082    char *cat;
04083    struct ast_hostent ahp;
04084    struct hostent *hp;
04085    int format;
04086    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
04087    
04088    if (gethostname(ourhost, sizeof(ourhost)-1)) {
04089       ast_log(LOG_WARNING, "Unable to get hostname, MGCP disabled\n");
04090       return 0;
04091    }
04092    cfg = ast_config_load(config, config_flags);
04093 
04094    /* We *must* have a config file otherwise stop immediately */
04095    if (!cfg) {
04096       ast_log(LOG_NOTICE, "Unable to load config %s, MGCP disabled\n", config);
04097       return 0;
04098    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
04099       return 0;
04100    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
04101       ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", config);
04102       return 0;
04103    }
04104 
04105    memset(&bindaddr, 0, sizeof(bindaddr));
04106    dtmfmode = 0;
04107 
04108    /* Copy the default jb config over global_jbconf */
04109    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
04110 
04111    v = ast_variable_browse(cfg, "general");
04112    while (v) {
04113       /* handle jb conf */
04114       if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
04115          v = v->next;
04116          continue;
04117       }
04118 
04119       /* Create the interface list */
04120       if (!strcasecmp(v->name, "bindaddr")) {
04121          if (!(hp = ast_gethostbyname(v->value, &ahp))) {
04122             ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
04123          } else {
04124             memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
04125          }
04126       } else if (!strcasecmp(v->name, "allow")) {
04127          format = ast_getformatbyname(v->value);
04128          if (format < 1) 
04129             ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
04130          else
04131             capability |= format;
04132       } else if (!strcasecmp(v->name, "disallow")) {
04133          format = ast_getformatbyname(v->value);
04134          if (format < 1) 
04135             ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
04136          else
04137             capability &= ~format;
04138       } else if (!strcasecmp(v->name, "tos")) {
04139          if (ast_str2tos(v->value, &qos.tos))
04140              ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
04141       } else if (!strcasecmp(v->name, "tos_audio")) {
04142          if (ast_str2tos(v->value, &qos.tos_audio))
04143              ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);
04144       } else if (!strcasecmp(v->name, "cos")) {          
04145          if (ast_str2cos(v->value, &qos.cos))
04146              ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno);
04147       } else if (!strcasecmp(v->name, "cos_audio")) {          
04148          if (ast_str2cos(v->value, &qos.cos_audio))
04149              ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);
04150       } else if (!strcasecmp(v->name, "port")) {
04151          if (sscanf(v->value, "%5d", &ourport) == 1) {
04152             bindaddr.sin_port = htons(ourport);
04153          } else {
04154             ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
04155          }
04156       }
04157       v = v->next;
04158    }
04159 
04160    /* mark existing entries for deletion */
04161    ast_mutex_lock(&gatelock);
04162    g = gateways;
04163    while (g) {
04164       g->delme = 1;
04165       e = g->endpoints;
04166       while (e) {
04167          e->delme = 1;
04168          e = e->next;
04169       }
04170       g = g->next;
04171    }
04172    ast_mutex_unlock(&gatelock);
04173    
04174    cat = ast_category_browse(cfg, NULL);
04175    while(cat) {
04176       if (strcasecmp(cat, "general")) {
04177          ast_mutex_lock(&gatelock);
04178          g = build_gateway(cat, ast_variable_browse(cfg, cat));
04179          if (g) {
04180             ast_verb(3, "Added gateway '%s'\n", g->name);
04181             g->next = gateways;
04182             gateways = g;
04183          }
04184          ast_mutex_unlock(&gatelock);
04185 
04186          /* FS: process queue and IO */
04187          if (monitor_thread == pthread_self()) {
04188             if (sched) ast_sched_runq(sched);
04189             if (io) ast_io_wait(io, 10);
04190          }
04191       }
04192       cat = ast_category_browse(cfg, cat);
04193    }
04194 
04195       /* prune deleted entries etc. */
04196       prune_gateways();
04197 
04198    if (ntohl(bindaddr.sin_addr.s_addr)) {
04199       memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
04200    } else {
04201       hp = ast_gethostbyname(ourhost, &ahp);
04202       if (!hp) {
04203          ast_log(LOG_WARNING, "Unable to get our IP address, MGCP disabled\n");
04204          ast_config_destroy(cfg);
04205          return 0;
04206       }
04207       memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
04208    }
04209    if (!ntohs(bindaddr.sin_port))
04210       bindaddr.sin_port = ntohs(DEFAULT_MGCP_CA_PORT);
04211    bindaddr.sin_family = AF_INET;
04212    ast_mutex_lock(&netlock);
04213    if (mgcpsock > -1)
04214       close(mgcpsock);
04215 
04216    if (mgcpsock_read_id != NULL)
04217       ast_io_remove(io, mgcpsock_read_id);
04218    mgcpsock_read_id = NULL;
04219 
04220    mgcpsock = socket(AF_INET, SOCK_DGRAM, 0);
04221    if (mgcpsock < 0) {
04222       ast_log(LOG_WARNING, "Unable to create MGCP socket: %s\n", strerror(errno));
04223    } else {
04224       if (bind(mgcpsock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
04225          ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
04226             ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
04227                strerror(errno));
04228          close(mgcpsock);
04229          mgcpsock = -1;
04230       } else {
04231          ast_verb(2, "MGCP Listening on %s:%d\n",
04232                ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
04233          ast_netsock_set_qos(mgcpsock, qos.tos, qos.cos, "MGCP");
04234       }
04235    }
04236    ast_mutex_unlock(&netlock);
04237    ast_config_destroy(cfg);
04238 
04239    /* send audit only to the new endpoints */
04240    g = gateways;
04241    while (g) {
04242       e = g->endpoints;
04243       while (e && e->needaudit) {
04244          e->needaudit = 0;
04245          transmit_audit_endpoint(e);
04246          ast_verb(3, "MGCP Auditing endpoint %s@%s for hookstate\n", e->name, g->name);
04247          e = e->next;
04248       }
04249       g = g->next;
04250    }
04251 
04252    return 0;
04253 }

static int reqprep ( struct mgcp_request req,
struct mgcp_endpoint p,
char *  verb 
) [static]

Definition at line 2015 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().

02016 {
02017    memset(req, 0, sizeof(struct mgcp_request));
02018    oseq++;
02019    if (oseq > 999999999)
02020       oseq = 1;
02021    init_req(p, req, verb);
02022    return 0;
02023 }

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().

00529 {
00530    struct mgcp_endpoint *p = sub->parent;
00531    int res;
00532    if (mgcpdebug) {
00533       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));
00534    }
00535    res = __mgcp_xmit(p->parent, resp->buf, resp->len);
00536    if (res > 0)
00537       res = 0;
00538    return res;
00539 }

static int respprep ( struct mgcp_request resp,
struct mgcp_endpoint p,
char *  msg,
struct mgcp_request req,
char *  msgrest 
) [static]

Definition at line 2008 of file chan_mgcp.c.

References init_resp().

Referenced by transmit_response().

02009 {
02010    memset(resp, 0, sizeof(*resp));
02011    init_resp(resp, msg, req, msgrest);
02012    return 0;
02013 }

static int restart_monitor ( void   )  [static]

Definition at line 3469 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().

03470 {
03471    /* If we're supposed to be stopped -- stay stopped */
03472    if (monitor_thread == AST_PTHREADT_STOP)
03473       return 0;
03474    if (ast_mutex_lock(&monlock)) {
03475       ast_log(LOG_WARNING, "Unable to lock monitor\n");
03476       return -1;
03477    }
03478    if (monitor_thread == pthread_self()) {
03479       ast_mutex_unlock(&monlock);
03480       ast_log(LOG_WARNING, "Cannot kill myself\n");
03481       return -1;
03482    }
03483    if (monitor_thread != AST_PTHREADT_NULL) {
03484       /* Wake up the thread */
03485       pthread_kill(monitor_thread, SIGURG);
03486    } else {
03487       /* Start a new monitor */
03488       if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
03489          ast_mutex_unlock(&monlock);
03490          ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
03491          return -1;
03492       }
03493    }
03494    ast_mutex_unlock(&monlock);
03495    return 0;
03496 }

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().

00632 {
00633    struct mgcp_gateway *gw = (struct mgcp_gateway *)data;
00634    struct mgcp_message *cur, *exq = NULL, *w, *prev;
00635    int res = 0;
00636 
00637    /* find out expired msgs */
00638    ast_mutex_lock(&gw->msgs_lock);
00639 
00640    prev = NULL, cur = gw->msgs;
00641    while (cur) {
00642       if (cur->retrans < MAX_RETRANS) {
00643          cur->retrans++;
00644          if (mgcpdebug) {
00645             ast_verbose("Retransmitting #%d transaction %u on [%s]\n",
00646                cur->retrans, cur->seqno, gw->name);
00647          }
00648          __mgcp_xmit(gw, cur->buf, cur->len);
00649 
00650          prev = cur;
00651          cur = cur->next;
00652       } else {
00653          if (prev)
00654             prev->next = cur->next;
00655          else
00656             gw->msgs = cur->next;
00657 
00658          ast_log(LOG_WARNING, "Maximum retries exceeded for transaction %u on [%s]\n",
00659             cur->seqno, gw->name);
00660 
00661          w = cur;
00662          cur = cur->next;
00663 
00664          if (exq) {
00665             w->next = exq;
00666          } else {
00667             w->next = NULL;
00668          }
00669          exq = w;
00670       }
00671    }
00672 
00673    if (!gw->msgs) {
00674       gw->retransid = -1;
00675       res = 0;
00676    } else {
00677       res = 1;
00678    }
00679    ast_mutex_unlock(&gw->msgs_lock);
00680 
00681    while (exq) {
00682       cur = exq;
00683       /* time-out transaction */
00684       handle_response(cur->owner_ep, cur->owner_sub, 406, cur->seqno, NULL); 
00685       exq = exq->next;
00686       ast_free(cur);
00687    }
00688 
00689    return res;
00690 }

static void sdpLineNum_iterator_init ( int *  iterator  )  [static]

Definition at line 1562 of file chan_mgcp.c.

Referenced by process_sdp().

01563 {
01564    *iterator = 0;
01565 }

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().

00760 {
00761    int res = 0;
00762    struct mgcp_request **queue, *q, *r, *t;
00763    ast_mutex_t *l;
00764 
00765    ast_debug(1, "Slow sequence is %d\n", p->slowsequence);
00766    if (p->slowsequence) {
00767       queue = &p->cmd_queue;
00768       l = &p->cmd_queue_lock;
00769       ast_mutex_lock(l);
00770    } else {
00771       switch (req->cmd) {
00772       case MGCP_CMD_DLCX:
00773          queue = &sub->cx_queue;
00774          l = &sub->cx_queue_lock;
00775          ast_mutex_lock(l);
00776          q = sub->cx_queue;
00777          /* delete pending cx cmds */
00778          while (q) {
00779             r = q->next;
00780             ast_free(q);
00781             q = r;
00782          }
00783          *queue = NULL;
00784          break;
00785 
00786       case MGCP_CMD_CRCX:
00787       case MGCP_CMD_MDCX:
00788          queue = &sub->cx_queue;
00789          l = &sub->cx_queue_lock;
00790          ast_mutex_lock(l);
00791          break;
00792 
00793       case MGCP_CMD_RQNT:
00794          queue = &p->rqnt_queue;
00795          l = &p->rqnt_queue_lock;
00796          ast_mutex_lock(l);
00797          break;
00798 
00799       default:
00800          queue = &p->cmd_queue;
00801          l = &p->cmd_queue_lock;
00802          ast_mutex_lock(l);
00803          break;
00804       }
00805    }
00806 
00807    r = ast_malloc(sizeof(*r));
00808    if (!r) {
00809       ast_log(LOG_WARNING, "Cannot post MGCP request: insufficient memory\n");
00810       ast_mutex_unlock(l);
00811       return -1;
00812    }
00813    memcpy(r, req, sizeof(*r));
00814 
00815    if (!(*queue)) {
00816       if (mgcpdebug) {
00817          ast_verbose("Posting Request:\n%s to %s:%d\n", req->data, 
00818             ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
00819       }
00820 
00821       res = mgcp_postrequest(p, sub, req->data, req->len, seqno);
00822    } else {
00823       if (mgcpdebug) {
00824          ast_verbose("Queueing Request:\n%s to %s:%d\n", req->data, 
00825             ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
00826       }
00827    }
00828 
00829    /* XXX find tail. We could also keep tail in the data struct for faster access */
00830    for (t = *queue; t && t->next; t = t->next);
00831 
00832    r->next = NULL;
00833    if (t)
00834       t->next = r;
00835    else
00836       *queue = r;
00837 
00838    ast_mutex_unlock(l);
00839 
00840    return res;
00841 }

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().

00542 {
00543    struct mgcp_endpoint *p = sub->parent;
00544    int res;
00545    if (mgcpdebug) {
00546       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));
00547    }
00548    res = __mgcp_xmit(p->parent, req->data, req->len);
00549    if (res > 0)
00550       res = 0;
00551    return res;
00552 }

static void start_rtp ( struct mgcp_subchannel sub  )  [static]

Definition at line 2610 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().

02611 {
02612    ast_mutex_lock(&sub->lock);
02613    /* check again to be on the safe side */
02614    if (sub->rtp) {
02615       ast_rtp_destroy(sub->rtp);
02616       sub->rtp = NULL;
02617    }
02618    /* Allocate the RTP now */
02619    sub->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
02620    if (sub->rtp && sub->owner)
02621       ast_channel_set_fd(sub->owner, 0, ast_rtp_fd(sub->rtp));
02622    if (sub->rtp) {
02623       ast_rtp_setqos(sub->rtp, qos.tos_audio, qos.cos_audio, "MGCP RTP");
02624       ast_rtp_setnat(sub->rtp, sub->nat);
02625    }
02626 #if 0
02627    ast_rtp_set_callback(p->rtp, rtpready);
02628    ast_rtp_set_data(p->rtp, p);
02629 #endif      
02630    /* Make a call*ID */
02631         snprintf(sub->callid, sizeof(sub->callid), "%08lx%s", ast_random(), sub->txident);
02632    /* Transmit the connection create */
02633    transmit_connect_with_sdp(sub, NULL);
02634    ast_mutex_unlock(&sub->lock);
02635 }

static int transmit_audit_endpoint ( struct mgcp_endpoint p  )  [static]

Definition at line 2329 of file chan_mgcp.c.

References add_header(), mgcp_request::cmd, MGCP_CMD_AUEP, reqprep(), send_request(), and mgcp_request::trid.

Referenced by handle_mgcp_audit_endpoint(), handle_request(), and reload_config().

02330 {
02331    struct mgcp_request resp;
02332    reqprep(&resp, p, "AUEP");
02333    /* removed unknown param VS */
02334    /*add_header(&resp, "F", "A,R,D,S,X,N,I,T,O,ES,E,MD,M");*/
02335    add_header(&resp, "F", "A");
02336    /* fill in new fields */
02337    resp.cmd = MGCP_CMD_AUEP;
02338    resp.trid = oseq;
02339    return send_request(p, NULL, &resp, oseq);  /* SC */
02340 }

static int transmit_connect_with_sdp ( struct mgcp_subchannel sub,
struct ast_rtp rtp 
) [static]

Definition at line 2176 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, mgcp_endpoint::parent, mgcp_subchannel::parent, reqprep(), send_request(), mgcp_request::trid, and mgcp_subchannel::txident.

Referenced by start_rtp().

02177 {
02178    struct mgcp_request resp;
02179    char local[256];
02180    char tmp[80];
02181    int x;
02182    struct mgcp_endpoint *p = sub->parent;
02183 
02184    ast_copy_string(local, "p:20", sizeof(local));
02185    for (x = 1; x <= AST_FORMAT_AUDIO_MASK; x <<= 1) {
02186       if (p->capability & x) {
02187          snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0));
02188          strncat(local, tmp, sizeof(local) - strlen(local) - 1);
02189       }
02190    }
02191    if (mgcpdebug) {
02192       ast_verb(3, "Creating connection for %s@%s-%d in cxmode: %s callid: %s\n",
02193          p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
02194    }
02195    reqprep(&resp, p, "CRCX");
02196    add_header(&resp, "C", sub->callid);
02197    add_header(&resp, "L", local);
02198    add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
02199    /* X header should not be sent. kept for compatibility */
02200    add_header(&resp, "X", sub->txident);
02201    /*add_header(&resp, "S", "");*/
02202    add_sdp(&resp, sub, rtp);
02203    /* fill in new fields */
02204    resp.cmd = MGCP_CMD_CRCX;
02205    resp.trid = oseq;
02206    return send_request(p, sub, &resp, oseq);  /* SC */
02207 }

static int transmit_connection_del ( struct mgcp_subchannel sub  )  [static]

Definition at line 2342 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, 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().

02343 {
02344    struct mgcp_endpoint *p = sub->parent;
02345    struct mgcp_request resp;
02346 
02347    if (mgcpdebug) {
02348       ast_verb(3, "Delete connection %s %s@%s-%d with new mode: %s on callid: %s\n",
02349          sub->cxident, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
02350    }
02351    reqprep(&resp, p, "DLCX");
02352    /* check if call id is avail */
02353    if (sub->callid[0])
02354       add_header(&resp, "C", sub->callid);
02355    /* X header should not be sent. kept for compatibility */
02356    add_header(&resp, "X", sub->txident);
02357    /* check if cxident is avail */
02358    if (sub->cxident[0])
02359       add_header(&resp, "I", sub->cxident);
02360    /* fill in new fields */
02361    resp.cmd = MGCP_CMD_DLCX;
02362    resp.trid = oseq;
02363    return send_request(p, sub, &resp, oseq);  /* SC */
02364 }

static int transmit_connection_del_w_params ( struct mgcp_endpoint p,
char *  callid,
char *  cxident 
) [static]

Definition at line 2366 of file chan_mgcp.c.

References add_header(), ast_verb, mgcp_request::cmd, MGCP_CMD_DLCX, mgcp_gateway::name, mgcp_endpoint::name, mgcp_endpoint::parent, reqprep(), send_request(), mgcp_endpoint::sub, and mgcp_request::trid.

Referenced by handle_response().

02367 {
02368    struct mgcp_request resp;
02369 
02370    if (mgcpdebug) {
02371       ast_verb(3, "Delete connection %s %s@%s on callid: %s\n",
02372          cxident ? cxident : "", p->name, p->parent->name, callid ? callid : "");
02373    }
02374    reqprep(&resp, p, "DLCX");
02375    /* check if call id is avail */
02376    if (callid && *callid)
02377       add_header(&resp, "C", callid);
02378    /* check if cxident is avail */
02379    if (cxident && *cxident)
02380       add_header(&resp, "I", cxident);
02381    /* fill in new fields */
02382    resp.cmd = MGCP_CMD_DLCX;
02383    resp.trid = oseq;
02384    return send_request(p, p->sub, &resp, oseq);
02385 }

static int transmit_modify_request ( struct mgcp_subchannel sub  )  [static]

Definition at line 2284 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, 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().

02285 {
02286    struct mgcp_request resp;
02287    struct mgcp_endpoint *p = sub->parent;
02288 
02289    if (ast_strlen_zero(sub->cxident)) {
02290       /* We don't have a CXident yet, store the destination and
02291          wait a bit */
02292       return 0;
02293    }
02294    if (mgcpdebug) {
02295       ast_verb(3, "Modified %s@%s-%d with new mode: %s on callid: %s\n",
02296          p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
02297    }
02298    reqprep(&resp, p, "MDCX");
02299    add_header(&resp, "C", sub->callid);
02300    add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
02301    /* X header should not be sent. kept for compatibility */
02302    add_header(&resp, "X", sub->txident);
02303    add_header(&resp, "I", sub->cxident);
02304    switch (sub->parent->hookstate) {
02305    case MGCP_ONHOOK:
02306       add_header(&resp, "R", "L/hd(N)");
02307       break;
02308    case MGCP_OFFHOOK:
02309       add_header_offhook(sub, &resp);
02310       break;
02311    }
02312    /* fill in new fields */
02313    resp.cmd = MGCP_CMD_MDCX;
02314    resp.trid = oseq;
02315    return send_request(p, sub, &resp, oseq); /* SC */
02316 }

static int transmit_modify_with_sdp ( struct mgcp_subchannel sub,
struct ast_rtp rtp,
int  codecs 
) [static]

Definition at line 2140 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, 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().

02141 {
02142    struct mgcp_request resp;
02143    char local[256];
02144    char tmp[80];
02145    int x;
02146    struct mgcp_endpoint *p = sub->parent;
02147 
02148    if (ast_strlen_zero(sub->cxident) && rtp) {
02149       /* We don't have a CXident yet, store the destination and
02150          wait a bit */
02151       ast_rtp_get_peer(rtp, &sub->tmpdest);
02152       return 0;
02153    }
02154    ast_copy_string(local, "p:20", sizeof(local));
02155    for (x = 1; x <= AST_FORMAT_AUDIO_MASK; x <<= 1) {
02156       if (p->capability & x) {
02157          snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0));
02158          strncat(local, tmp, sizeof(local) - strlen(local) - 1);
02159       }
02160    }
02161    reqprep(&resp, p, "MDCX");
02162    add_header(&resp, "C", sub->callid);
02163    add_header(&resp, "L", local);
02164    add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
02165    /* X header should not be sent. kept for compatibility */
02166    add_header(&resp, "X", sub->txident);
02167    add_header(&resp, "I", sub->cxident);
02168    /*add_header(&resp, "S", "");*/
02169    add_sdp(&resp, sub, rtp);
02170    /* fill in new fields */
02171    resp.cmd = MGCP_CMD_MDCX;
02172    resp.trid = oseq;
02173    return send_request(p, sub, &resp, oseq); /* SC */
02174 }

static int transmit_notify_request ( struct mgcp_subchannel sub,
char *  tone 
) [static]

Definition at line 2209 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, 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().

02210 {
02211    struct mgcp_request resp;
02212    struct mgcp_endpoint *p = sub->parent;
02213 
02214    if (mgcpdebug) {
02215       ast_verb(3, "MGCP Asked to indicate tone: %s on  %s@%s-%d in cxmode: %s\n",
02216          tone, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]);
02217    }
02218    ast_copy_string(p->curtone, tone, sizeof(p->curtone));
02219    reqprep(&resp, p, "RQNT");
02220    add_header(&resp, "X", p->rqnt_ident); /* SC */
02221    switch (p->hookstate) {
02222    case MGCP_ONHOOK:
02223       add_header(&resp, "R", "L/hd(N)");
02224       break;
02225    case MGCP_OFFHOOK:
02226       add_header_offhook(sub, &resp);
02227       break;
02228    }
02229    if (!ast_strlen_zero(tone)) {
02230       add_header(&resp, "S", tone);
02231    }
02232    /* fill in new fields */
02233    resp.cmd = MGCP_CMD_RQNT;
02234    resp.trid = oseq;
02235    return send_request(p, NULL, &resp, oseq); /* SC */
02236 }

static int transmit_notify_request_with_callerid ( struct mgcp_subchannel sub,
char *  tone,
char *  callernum,
char *  callername 
) [static]

Definition at line 2238 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, 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().

02239 {
02240    struct mgcp_request resp;
02241    char tone2[256];
02242    char *l, *n;
02243    struct timeval t = ast_tvnow();
02244    struct ast_tm tm;
02245    struct mgcp_endpoint *p = sub->parent;
02246    
02247    ast_localtime(&t, &tm, NULL);
02248    n = callername;
02249    l = callernum;
02250    if (!n)
02251       n = "";
02252    if (!l)
02253       l = "";
02254 
02255    /* Keep track of last callerid for blacklist and callreturn */
02256    ast_copy_string(p->lastcallerid, l, sizeof(p->lastcallerid));
02257 
02258    snprintf(tone2, sizeof(tone2), "%s,L/ci(%02d/%02d/%02d/%02d,%s,%s)", tone, 
02259       tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, l, n);
02260    ast_copy_string(p->curtone, tone, sizeof(p->curtone));
02261    reqprep(&resp, p, "RQNT");
02262    add_header(&resp, "X", p->rqnt_ident); /* SC */
02263    switch (p->hookstate) {
02264    case MGCP_ONHOOK:
02265       add_header(&resp, "R", "L/hd(N)");
02266       break;
02267    case MGCP_OFFHOOK:
02268       add_header_offhook(sub, &resp);
02269       break;
02270    }
02271    if (!ast_strlen_zero(tone2)) {
02272       add_header(&resp, "S", tone2);
02273    }
02274    if (mgcpdebug) {
02275       ast_verb(3, "MGCP Asked to indicate tone: %s on  %s@%s-%d in cxmode: %s\n",
02276          tone2, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]);
02277    }
02278    /* fill in new fields */
02279    resp.cmd = MGCP_CMD_RQNT;
02280    resp.trid = oseq;
02281    return send_request(p, NULL, &resp, oseq);  /* SC */
02282 }

static int transmit_response ( struct mgcp_subchannel sub,
char *  msg,
struct mgcp_request req,
char *  msgrest 
) [static]

Definition at line 2025 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().

02026 {
02027    struct mgcp_request resp;
02028    struct mgcp_endpoint *p = sub->parent;
02029    struct mgcp_response *mgr;
02030 
02031    respprep(&resp, p, msg, req, msgrest);
02032    mgr = ast_calloc(1, sizeof(*mgr) + resp.len + 1);
02033    if (mgr) {
02034       /* Store MGCP response in case we have to retransmit */
02035       sscanf(req->identifier, "%30d", &mgr->seqno);
02036       time(&mgr->whensent);
02037       mgr->len = resp.len;
02038       memcpy(mgr->buf, resp.data, resp.len);
02039       mgr->buf[resp.len] = '\0';
02040       mgr->next = p->parent->responses;
02041       p->parent->responses = mgr;
02042    }
02043    return send_response(sub, &resp);
02044 }

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().

00488 {
00489    struct mgcp_endpoint *p = sub->parent;
00490    if (p->sub == sub) {
00491       ast_log(LOG_WARNING, "Trying to unalloc the real channel %s@%s?!?\n", p->name, p->parent->name);
00492       return -1;
00493    }
00494    ast_debug(1, "Released sub %d of channel %s@%s\n", sub->id, p->name, p->parent->name);
00495 
00496    sub->owner = NULL;
00497    if (!ast_strlen_zero(sub->cxident)) {
00498       transmit_connection_del(sub);
00499    }
00500    sub->cxident[0] = '\0';
00501    sub->callid[0] = '\0';
00502    sub->cxmode = MGCP_CX_INACTIVE;
00503    sub->outgoing = 0;
00504    sub->alreadygone = 0;
00505    memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
00506    if (sub->rtp) {
00507       ast_rtp_destroy(sub->rtp);
00508       sub->rtp = NULL;
00509    }
00510    dump_cmd_queues(NULL, sub); /* SC */
00511    return 0;
00512 }

static int unload_module ( void   )  [static]

Definition at line 4327 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().

04328 {
04329    struct mgcp_endpoint *e;
04330    struct mgcp_gateway *g;
04331 
04332    /* Check to see if we're reloading */
04333    if (ast_mutex_trylock(&mgcp_reload_lock)) {
04334       ast_log(LOG_WARNING, "MGCP is currently reloading.  Unable to remove module.\n");
04335       return -1;
04336    } else {
04337       mgcp_reloading = 1;
04338       ast_mutex_unlock(&mgcp_reload_lock);
04339    }
04340 
04341    /* First, take us out of the channel loop */
04342    ast_channel_unregister(&mgcp_tech);
04343 
04344    /* Shut down the monitoring thread */
04345    if (!ast_mutex_lock(&monlock)) {
04346       if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
04347          pthread_cancel(monitor_thread);
04348          pthread_kill(monitor_thread, SIGURG);
04349          pthread_join(monitor_thread, NULL);
04350       }
04351       monitor_thread = AST_PTHREADT_STOP;
04352       ast_mutex_unlock(&monlock);
04353    } else {
04354       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
04355       /* We always want to leave this in a consistent state */
04356       ast_channel_register(&mgcp_tech);
04357       mgcp_reloading = 0;
04358       mgcp_reload(NULL, 0, NULL);
04359       return -1;
04360    }
04361 
04362    if (!ast_mutex_lock(&gatelock)) {
04363       for (g = gateways; g; g = g->next) {
04364          g->delme = 1;
04365          for (e = g->endpoints; e; e = e->next)
04366             e->delme = 1;
04367       }
04368 
04369       prune_gateways();
04370       ast_mutex_unlock(&gatelock);
04371    } else {
04372       ast_log(LOG_WARNING, "Unable to lock the gateways list.\n");
04373       /* We always want to leave this in a consistent state */
04374       ast_channel_register(&mgcp_tech);
04375       /* Allow the monitor to restart */
04376       monitor_thread = AST_PTHREADT_NULL;
04377       mgcp_reloading = 0;
04378       mgcp_reload(NULL, 0, NULL);
04379       return -1;
04380    }
04381 
04382    close(mgcpsock);
04383    ast_rtp_proto_unregister(&mgcp_rtp);
04384    ast_cli_unregister_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
04385    sched_context_destroy(sched);
04386 
04387    return 0;
04388 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Media Gateway Control Protocol (MGCP)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 4394 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.

int amaflags = 0 [static]

Definition at line 187 of file chan_mgcp.c.

Definition at line 4394 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.

int callwaiting = 0 [static]

Definition at line 166 of file chan_mgcp.c.

int cancallforward = 0 [static]

Definition at line 177 of file chan_mgcp.c.

int capability = AST_FORMAT_ULAW [static]

Definition at line 214 of file chan_mgcp.c.

Referenced by build_setup(), iax2_call(), parse_setup(), set_config(), and set_local_capabilities().

char cid_name[AST_MAX_EXTENSION] = "" [static]
char cid_num[AST_MAX_EXTENSION] = "" [static]
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.

Definition at line 154 of file chan_mgcp.c.

Definition at line 155 of file chan_mgcp.c.

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.

int dtmfmode = 0 [static]

Definition at line 151 of file chan_mgcp.c.

Referenced by 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.

ast_mutex_t gatelock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [static]
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.

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.

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]
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.

char* mgcp_cxmodes[] [static]

}

Definition at line 123 of file chan_mgcp.c.

ast_mutex_t mgcp_reload_lock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [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.

struct ast_rtp_protocol mgcp_rtp [static]
Initial value:
 {
   .type = "MGCP",
   .get_rtp_info = mgcp_get_rtp_peer,
   .set_rtp_peer = mgcp_set_rtp_peer,
}

Definition at line 3971 of file chan_mgcp.c.

struct ast_channel_tech mgcp_tech [static]

Definition at line 435 of file chan_mgcp.c.

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 3381 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_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [static]

Definition at line 206 of file chan_mgcp.c.

Referenced by do_monitor(), restart_monitor(), and unload_module().

char musicclass[MAX_MUSICCLASS] = "" [static]
int nat = 0 [static]

Definition at line 152 of file chan_mgcp.c.

ast_mutex_t netlock = ((ast_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP ) [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.

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.

int slowsequence = 0 [static]

Definition at line 170 of file chan_mgcp.c.

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.

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 leave_voicemail(), and send_packet().


Generated by  doxygen 1.6.2