Thu Apr 8 01:22:02 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 CANREINVITE   1
#define DEFAULT_EXPIRY   120
#define DEFAULT_MGCP_CA_PORT   2727
#define DEFAULT_MGCP_GW_PORT   2427
#define DEFAULT_RETRANS   1000
#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_set_debug_deprecated (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 = "a9c98e5d177805051735cb5b0b16b0a0" , .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 canreinvite = CANREINVITE
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 struct ast_cli_entry cli_mgcp_set_debug_deprecated = AST_CLI_DEFINE(handle_mgcp_set_debug_deprecated, "Enable/Disable MGCP debugging")
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 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 CANREINVITE   1

Definition at line 83 of file chan_mgcp.c.

Referenced by build_gateway().

#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 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

Definition at line 306 of file chan_mgcp.c.

Referenced by build_device(), build_gateway(), do_monitor(), and mgcp_call().

#define TYPE_TRUNK   1

Definition at line 305 of file chan_mgcp.c.

Referenced by build_device(), and 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 1604 of file chan_mgcp.c.

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

Referenced by get_header().

01605 {
01606    int x;
01607    int len = strlen(name);
01608    char *r;
01609    for (x=*start;x<req->headers;x++) {
01610       if (!strncasecmp(req->header[x], name, len) && 
01611           (req->header[x][len] == ':')) {
01612          r = req->header[x] + len + 1;
01613          while(*r && (*r < 33))
01614             r++;
01615          *start = x+1;
01616          return r;
01617       }
01618    }
01619    /* Don't return NULL, so get_header is always a valid pointer */
01620    return "";
01621 }

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

static void __unreg_module ( void   )  [static]

Definition at line 4416 of file chan_mgcp.c.

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

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

01951 {
01952    if (req->len >= sizeof(req->data) - 4) {
01953       ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
01954       return -1;
01955    }
01956    if (req->lines) {
01957       ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n");
01958       return -1;
01959    }
01960    req->header[req->headers] = req->data + req->len;
01961    snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s: %s\r\n", var, value);
01962    req->len += strlen(req->header[req->headers]);
01963    if (req->headers < MGCP_MAX_HEADERS)
01964       req->headers++;
01965    else {
01966       ast_log(LOG_WARNING, "Out of header space\n");
01967       return -1;
01968    }
01969    return 0;   
01970 }

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

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

02346 {
02347    struct mgcp_endpoint *p = sub->parent;
02348 
02349    if (p && p->sub && p->sub->owner && p->sub->owner->_state >= AST_STATE_RINGING && (p->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)))
02350       add_header(resp, "R", "L/hu(N),L/hf(N)");
02351    else
02352       add_header(resp, "R", "L/hu(N),L/hf(N),D/[0-9#*](N)");
02353 }

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

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

01973 {
01974    if (req->len >= sizeof(req->data) - 4) {
01975       ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
01976       return -1;
01977    }
01978    if (!req->lines) {
01979       /* Add extra empty return */
01980       ast_copy_string(req->data + req->len, "\r\n", sizeof(req->data) - req->len);
01981       req->len += strlen(req->data + req->len);
01982    }
01983    req->line[req->lines] = req->data + req->len;
01984    snprintf(req->line[req->lines], sizeof(req->data) - req->len, "%s", line);
01985    req->len += strlen(req->line[req->lines]);
01986    if (req->lines < MGCP_MAX_LINES)
01987       req->lines++;
01988    else {
01989       ast_log(LOG_WARNING, "Out of line space\n");
01990       return -1;
01991    }
01992    return 0;   
01993 }

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

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

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

static int attempt_transfer ( struct mgcp_endpoint p  )  [static]

Definition at line 2910 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, mgcp_subchannel::next, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_endpoint::sub, and unalloc_sub().

Referenced by handle_request().

02911 {
02912    /* *************************
02913     * I hope this works.
02914     * Copied out of chan_zap
02915     * Cross your fingers
02916     * *************************/
02917 
02918    /* In order to transfer, we need at least one of the channels to
02919       actually be in a call bridge.  We can't conference two applications
02920       together (but then, why would we want to?) */
02921    if (ast_bridged_channel(p->sub->owner)) {
02922       /* The three-way person we're about to transfer to could still be in MOH, so
02923          stop if now if appropriate */
02924       if (ast_bridged_channel(p->sub->next->owner))
02925          ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
02926       if (p->sub->owner->_state == AST_STATE_RINGING) {
02927          ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
02928       }
02929       if (ast_channel_masquerade(p->sub->next->owner, ast_bridged_channel(p->sub->owner))) {
02930          ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
02931             ast_bridged_channel(p->sub->owner)->name, p->sub->next->owner->name);
02932          return -1;
02933       }
02934       /* Orphan the channel */
02935       unalloc_sub(p->sub->next);
02936    } else if (ast_bridged_channel(p->sub->next->owner)) {
02937       if (p->sub->owner->_state == AST_STATE_RINGING) {
02938          ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
02939       }
02940       ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
02941       if (ast_channel_masquerade(p->sub->owner, ast_bridged_channel(p->sub->next->owner))) {
02942          ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
02943             ast_bridged_channel(p->sub->next->owner)->name, p->sub->owner->name);
02944          return -1;
02945       }
02946       /*swap_subs(p, SUB_THREEWAY, SUB_REAL);*/
02947       ast_verb(3, "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name);
02948       p->sub = p->sub->next;
02949       unalloc_sub(p->sub->next);
02950       /* Tell the caller not to hangup */
02951       return 1;
02952    } else {
02953       ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
02954          p->sub->owner->name, p->sub->next->owner->name);
02955       p->sub->next->owner->_softhangup |= AST_SOFTHANGUP_DEV;
02956       if (p->sub->next->owner) {
02957          p->sub->next->alreadygone = 1;
02958          mgcp_queue_hangup(p->sub->next);
02959       }
02960    }
02961    return 0;
02962 }

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 3578 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_strdupa, ast_strlen_zero(), ast_true(), ast_verb, mgcp_endpoint::callgroup, mgcp_endpoint::callreturn, mgcp_endpoint::callwaiting, mgcp_endpoint::cancallforward, mgcp_endpoint::canreinvite, CANREINVITE, 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::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, strsep(), 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().

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

static char* control2str ( int  ind  )  [static]

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

01420                                   {
01421    switch (ind) {
01422    case AST_CONTROL_HANGUP:
01423       return "Other end has hungup";
01424    case AST_CONTROL_RING:
01425       return "Local ring";
01426    case AST_CONTROL_RINGING:
01427       return "Remote end is ringing";
01428    case AST_CONTROL_ANSWER:
01429       return "Remote end has answered";
01430    case AST_CONTROL_BUSY:
01431       return "Remote end is busy";
01432    case AST_CONTROL_TAKEOFFHOOK:
01433       return "Make it go off hook";
01434    case AST_CONTROL_OFFHOOK:
01435       return "Line is off hook";
01436    case AST_CONTROL_CONGESTION:
01437       return "Congestion (circuits busy)";
01438    case AST_CONTROL_FLASH:
01439       return "Flash hook";
01440    case AST_CONTROL_WINK:
01441       return "Wink";
01442    case AST_CONTROL_OPTION:
01443       return "Set a low-level option";
01444    case AST_CONTROL_RADIO_KEY:
01445       return "Key Radio";
01446    case AST_CONTROL_RADIO_UNKEY:
01447       return "Un-Key Radio";
01448    }
01449    return "UNKNOWN";
01450 }

static void destroy_endpoint ( struct mgcp_endpoint e  )  [static]

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

04004 {
04005    struct mgcp_subchannel *sub = e->sub->next, *s;
04006    int i;
04007 
04008    for (i = 0; i < MAX_SUBS; i++) {
04009       ast_mutex_lock(&sub->lock);
04010       if (!ast_strlen_zero(sub->cxident)) {
04011          transmit_connection_del(sub);
04012       }
04013       if (sub->rtp) {
04014          ast_rtp_destroy(sub->rtp);
04015          sub->rtp = NULL;
04016       }
04017       memset(sub->magic, 0, sizeof(sub->magic));
04018       mgcp_queue_hangup(sub);
04019       dump_cmd_queues(NULL, sub);
04020       ast_mutex_unlock(&sub->lock);
04021       sub = sub->next;
04022    }
04023 
04024    if (e->dsp) {
04025       ast_dsp_free(e->dsp);
04026    }
04027 
04028    dump_queue(e->parent, e);
04029    dump_cmd_queues(e, NULL);
04030 
04031    sub = e->sub;
04032    for (i = 0; (i < MAX_SUBS) && sub; i++) {
04033       s = sub;
04034       sub = sub->next;
04035       ast_mutex_destroy(&s->lock);
04036       ast_mutex_destroy(&s->cx_queue_lock);
04037       ast_free(s);
04038    }
04039 
04040    if (e->mwi_event_sub)
04041       ast_event_unsubscribe(e->mwi_event_sub);
04042 
04043    ast_mutex_destroy(&e->lock);
04044    ast_mutex_destroy(&e->rqnt_queue_lock);
04045    ast_mutex_destroy(&e->cmd_queue_lock);
04046    ast_free(e);
04047 }

static void destroy_gateway ( struct mgcp_gateway g  )  [static]

Definition at line 4049 of file chan_mgcp.c.

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

Referenced by prune_gateways().

04050 {
04051    if (g->ha)
04052       ast_free_ha(g->ha);
04053 
04054    dump_queue(g, NULL);
04055 
04056    ast_free(g);
04057 }

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

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

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

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

dump_cmd_queues: (SC:) cleanup pending commands

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

02415 {
02416    struct mgcp_request *t, *q;
02417 
02418    if (p) {
02419       ast_mutex_lock(&p->rqnt_queue_lock);
02420       for (q = p->rqnt_queue; q; t = q->next, ast_free(q), q=t);
02421       p->rqnt_queue = NULL;
02422       ast_mutex_unlock(&p->rqnt_queue_lock);
02423 
02424       ast_mutex_lock(&p->cmd_queue_lock);
02425       for (q = p->cmd_queue; q; t = q->next, ast_free(q), q=t);
02426       p->cmd_queue = NULL;
02427       ast_mutex_unlock(&p->cmd_queue_lock);
02428 
02429       ast_mutex_lock(&p->sub->cx_queue_lock);
02430       for (q = p->sub->cx_queue; q; t = q->next, ast_free(q), q=t);
02431       p->sub->cx_queue = NULL;
02432       ast_mutex_unlock(&p->sub->cx_queue_lock);
02433 
02434       ast_mutex_lock(&p->sub->next->cx_queue_lock);
02435       for (q = p->sub->next->cx_queue; q; t = q->next, ast_free(q), q=t);
02436       p->sub->next->cx_queue = NULL;
02437       ast_mutex_unlock(&p->sub->next->cx_queue_lock);
02438    } else if (sub) {
02439       ast_mutex_lock(&sub->cx_queue_lock);
02440       for (q = sub->cx_queue; q; t = q->next, ast_free(q), q=t);
02441       sub->cx_queue = NULL;
02442       ast_mutex_unlock(&sub->cx_queue_lock);
02443    }
02444 }

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

03289 {
03290    int seqno=0;
03291    time_t now;
03292    struct mgcp_response *prev = NULL, *cur, *next, *answer=NULL;
03293    time(&now);
03294    if (sscanf(req->identifier, "%30d", &seqno) != 1) 
03295       seqno = 0;
03296    cur = sub->parent->parent->responses;
03297    while(cur) {
03298       next = cur->next;
03299       if (now - cur->whensent > RESPONSE_TIMEOUT) {
03300          /* Delete this entry */
03301          if (prev)
03302             prev->next = next;
03303          else
03304             sub->parent->parent->responses = next;
03305          ast_free(cur);
03306       } else {
03307          if (seqno == cur->seqno)
03308             answer = cur;
03309          prev = cur;
03310       }
03311       cur = next;
03312    }
03313    if (answer) {
03314       resend_response(sub, answer);
03315       return 1;
03316    }
03317    return 0;
03318 }

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

02450 {
02451    struct mgcp_request *prev, *req;
02452 
02453    ast_mutex_lock(l);
02454    for (prev = NULL, req = *queue; req; prev = req, req = req->next) {
02455       if (req->trid == ident) {
02456          /* remove from queue */
02457          if (!prev)
02458             *queue = req->next;
02459          else
02460             prev->next = req->next;
02461 
02462          /* send next pending command */
02463          if (*queue) {
02464             if (mgcpdebug) {
02465                ast_verbose("Posting Queued Request:\n%s to %s:%d\n", (*queue)->data, 
02466                   ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
02467             }
02468 
02469             mgcp_postrequest(p, sub, (*queue)->data, (*queue)->len, (*queue)->trid);
02470          }
02471          break;
02472       }
02473    }
02474    ast_mutex_unlock(l);
02475    return req;
02476 }

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

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

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

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

get_csv: (SC:) get comma separated value

Definition at line 1630 of file chan_mgcp.c.

References s.

Referenced by handle_response().

01631 {
01632    char *s;
01633 
01634    *next = NULL, *len = 0;
01635    if (!c) return NULL;
01636 
01637    while (*c && (*c < 33 || *c == ','))
01638       c++;
01639 
01640    s = c;
01641    while (*c && (*c >= 33 && *c != ','))
01642       c++, (*len)++;
01643    *next = c;
01644 
01645    if (*len == 0)
01646       s = NULL, *next = NULL;
01647 
01648    return s;
01649 }

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

Definition at line 1623 of file chan_mgcp.c.

References __get_header().

Referenced by handle_request(), and handle_response().

01624 {
01625    int start = 0;
01626    return __get_header(req, name, &start);
01627 }

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

Definition at line 1575 of file chan_mgcp.c.

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

Referenced by process_sdp().

01576 {
01577    int x;
01578    int len = strlen(name);
01579    char *r;
01580 
01581    for (x=0; x<req->lines; x++) {
01582       r = get_sdp_by_line(req->line[x], name, len);
01583       if (r[0] != '\0') return r;
01584    }
01585    return "";
01586 }

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

Definition at line 1565 of file chan_mgcp.c.

Referenced by get_sdp(), and get_sdp_iterate().

01566 {
01567    if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') {
01568       char* r = line + nameLen + 1;
01569       while (*r && (*r < 33)) ++r;
01570       return r;
01571    }
01572    return "";
01573 }

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

Definition at line 1593 of file chan_mgcp.c.

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

Referenced by process_sdp().

01594 {
01595    int len = strlen(name);
01596    char *r;
01597    while (*iterator < req->lines) {
01598       r = get_sdp_by_line(req->line[(*iterator)++], name, len);
01599       if (r[0] != '\0') return r;
01600    }
01601    return "";
01602 }

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

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

02965 {
02966    struct mgcp_endpoint *p = sub->parent;
02967    struct ast_channel *c;
02968    pthread_t t;
02969 
02970    /* Off hook / answer */
02971    if (sub->outgoing) {
02972       /* Answered */
02973       if (sub->owner) {
02974          if (ast_bridged_channel(sub->owner))
02975             ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
02976          sub->cxmode = MGCP_CX_SENDRECV;
02977          if (!sub->rtp) {
02978             start_rtp(sub);
02979          } else {
02980             transmit_modify_request(sub);
02981          }
02982          /*transmit_notify_request(sub, "aw");*/
02983          transmit_notify_request(sub, "");
02984          mgcp_queue_control(sub, AST_CONTROL_ANSWER);
02985       }
02986    } else {
02987       /* Start switch */
02988       /*sub->cxmode = MGCP_CX_SENDRECV;*/
02989       if (!sub->owner) {
02990          if (!sub->rtp) {
02991             start_rtp(sub);
02992          } else {
02993             transmit_modify_request(sub);
02994          }
02995          if (p->immediate) {
02996             /* The channel is immediately up. Start right away */
02997 #ifdef DLINK_BUGGY_FIRMWARE   
02998             transmit_notify_request(sub, "rt");
02999 #else
03000             transmit_notify_request(sub, "G/rt");
03001 #endif      
03002             c = mgcp_new(sub, AST_STATE_RING);
03003             if (!c) {
03004                ast_log(LOG_WARNING, "Unable to start PBX on channel %s@%s\n", p->name, p->parent->name);
03005                transmit_notify_request(sub, "G/cg");
03006                ast_hangup(c);
03007             }
03008          } else {
03009             if (has_voicemail(p)) {
03010                transmit_notify_request(sub, "L/sl");
03011             } else {
03012                transmit_notify_request(sub, "L/dl");
03013             }
03014             c = mgcp_new(sub, AST_STATE_DOWN);
03015             if (c) {
03016                if (ast_pthread_create_detached(&t, NULL, mgcp_ss, c)) {
03017                   ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
03018                   ast_hangup(c);
03019                }
03020             } else {
03021                ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", p->name, p->parent->name);
03022             }
03023          }
03024       } else {
03025          if (p->hookstate == MGCP_OFFHOOK) {
03026             ast_log(LOG_WARNING, "Off hook, but already have owner on %s@%s\n", p->name, p->parent->name);
03027          } else {
03028             ast_log(LOG_WARNING, "On hook, but already have owner on %s@%s\n", p->name, p->parent->name);
03029             ast_log(LOG_WARNING, "If we're onhook why are we here trying to handle a hd or hf?\n");
03030          }
03031          if (ast_bridged_channel(sub->owner))
03032             ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
03033          sub->cxmode = MGCP_CX_SENDRECV;
03034          if (!sub->rtp) {
03035             start_rtp(sub);
03036          } else {
03037             transmit_modify_request(sub);
03038          }
03039          /*transmit_notify_request(sub, "aw");*/
03040          transmit_notify_request(sub, "");
03041          /*ast_queue_control(sub->owner, AST_CONTROL_ANSWER);*/
03042       }
03043    }
03044 }

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

01168 {
01169    switch (cmd) {
01170    case CLI_INIT:
01171       e->command = "mgcp set debug {on|off}";
01172       e->usage =
01173          "Usage: mgcp set debug {on|off}\n"
01174          "       Enables/Disables dumping of MGCP packets for debugging purposes\n";   
01175       return NULL;
01176    case CLI_GENERATE:
01177       return NULL;
01178    }
01179 
01180    if (a->argc != e->args)
01181       return CLI_SHOWUSAGE;
01182 
01183    if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
01184       mgcpdebug = 1;
01185       ast_cli(a->fd, "MGCP Debugging Enabled\n");
01186    } else if (!strncasecmp(a->argv[3], "off", 3)) {
01187       mgcpdebug = 0;
01188       ast_cli(a->fd, "MGCP Debugging Disabled\n");
01189    } else {
01190       return CLI_SHOWUSAGE;
01191    }
01192    return CLI_SUCCESS;
01193 }

static char* handle_mgcp_set_debug_deprecated ( 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_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 [off]";
01147       e->usage =
01148          "Usage: mgcp set debug [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 < 3 || a->argc > 4)
01156       return CLI_SHOWUSAGE;
01157    if (a->argc == 3) {
01158       mgcpdebug = 1;
01159       ast_cli(a->fd, "MGCP Debugging Enabled\n");
01160    } else if (!strncasecmp(a->argv[3], "off", 3)) {
01161       mgcpdebug = 0;
01162       ast_cli(a->fd, "MGCP Debugging Disabled\n");
01163    }
01164    return CLI_SUCCESS;
01165 }

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

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

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

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

static int has_voicemail ( struct mgcp_endpoint p  )  [static]

Definition at line 462 of file chan_mgcp.c.

References ast_app_has_voicemail(), ast_event_destroy(), ast_event_get_cached(), ast_event_get_ie_uint(), AST_EVENT_IE_CONTEXT, AST_EVENT_IE_END, AST_EVENT_IE_MAILBOX, AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_STR, AST_EVENT_MWI, ast_strdupa, ast_strlen_zero(), mgcp_endpoint::mailbox, mbox(), and strsep().

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

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

02013 {
02014    /* Initialize a response */
02015    if (req->headers || req->len) {
02016       ast_log(LOG_WARNING, "Request already initialized?!?\n");
02017       return -1;
02018    }
02019    req->header[req->headers] = req->data + req->len;
02020    /* check if we need brackets around the gw name */
02021    if (p->parent->isnamedottedip)
02022       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);
02023    else
02024       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);
02025    req->len += strlen(req->header[req->headers]);
02026    if (req->headers < MGCP_MAX_HEADERS)
02027       req->headers++;
02028    else
02029       ast_log(LOG_WARNING, "Out of header space\n");
02030    return 0;
02031 }

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

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

01996 {
01997    /* Initialize a response */
01998    if (req->headers || req->len) {
01999       ast_log(LOG_WARNING, "Request already initialized?!?\n");
02000       return -1;
02001    }
02002    req->header[req->headers] = req->data + req->len;
02003    snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %s %s\r\n", resp, orig->identifier, resprest);
02004    req->len += strlen(req->header[req->headers]);
02005    if (req->headers < MGCP_MAX_HEADERS)
02006       req->headers++;
02007    else
02008       ast_log(LOG_WARNING, "Out of header space\n");
02009    return 0;
02010 }

static int load_module ( void   )  [static]

load_module: PBX load module - initialization ---

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

04279 {
04280    if (!(sched = sched_context_create())) {
04281       ast_log(LOG_WARNING, "Unable to create schedule context\n");
04282       return AST_MODULE_LOAD_FAILURE;
04283    }
04284 
04285    if (!(io = io_context_create())) {
04286       ast_log(LOG_WARNING, "Unable to create I/O context\n");
04287       sched_context_destroy(sched);
04288       return AST_MODULE_LOAD_FAILURE;
04289    }
04290 
04291    if (reload_config(0))
04292       return AST_MODULE_LOAD_DECLINE;
04293 
04294    /* Make sure we can register our mgcp channel type */
04295    if (ast_channel_register(&mgcp_tech)) {
04296       ast_log(LOG_ERROR, "Unable to register channel class 'MGCP'\n");
04297       io_context_destroy(io);
04298       sched_context_destroy(sched);
04299       return AST_MODULE_LOAD_FAILURE;
04300    }
04301 
04302    ast_rtp_proto_register(&mgcp_rtp);
04303    ast_cli_register_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
04304    
04305    /* And start the monitor for the first time */
04306    restart_monitor();
04307 
04308    return AST_MODULE_LOAD_SUCCESS;
04309 }

static int mgcp_answer ( struct ast_channel ast  )  [static]

Definition at line 1203 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, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_subchannel::rtp, start_rtp(), ast_channel::tech_pvt, transmit_modify_request(), and transmit_notify_request().

01204 {
01205    int res = 0;
01206    struct mgcp_subchannel *sub = ast->tech_pvt;
01207    struct mgcp_endpoint *p = sub->parent;
01208 
01209    ast_mutex_lock(&sub->lock);
01210    sub->cxmode = MGCP_CX_SENDRECV;
01211    if (!sub->rtp) {
01212       start_rtp(sub);
01213    } else {
01214       transmit_modify_request(sub);
01215    }
01216    ast_verb(3, "MGCP mgcp_answer(%s) on %s@%s-%d\n",
01217          ast->name, p->name, p->parent->name, sub->id);
01218    if (ast->_state != AST_STATE_UP) {
01219       ast_setstate(ast, AST_STATE_UP);
01220       ast_debug(1, "mgcp_answer(%s)\n", ast->name);
01221       transmit_notify_request(sub, "");
01222       transmit_modify_request(sub);
01223    }
01224    ast_mutex_unlock(&sub->lock);
01225    return res;
01226 }

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, mgcp_endpoint::hookstate, mgcp_subchannel::lock, LOG_NOTICE, LOG_WARNING, MGCP_CX_RECVONLY, MGCP_CX_SENDRECV, MGCP_OFFHOOK, MGCP_ONHOOK, 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 1372 of file chan_mgcp.c.

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

01373 {
01374    struct mgcp_gateway  *g;
01375    struct mgcp_endpoint *e = NULL;
01376    char *tmp, *endpt, *gw;
01377    int ret = AST_DEVICE_INVALID;
01378 
01379    endpt = ast_strdupa(data);
01380    if ((tmp = strchr(endpt, '@'))) {
01381       *tmp++ = '\0';
01382       gw = tmp;
01383    } else
01384       goto error;
01385 
01386    ast_mutex_lock(&gatelock);
01387    g = gateways;
01388    while (g) {
01389       if (strcasecmp(g->name, gw) == 0) {
01390          e = g->endpoints;
01391          break;
01392       }
01393       g = g->next;
01394    }
01395 
01396    if (!e)
01397       goto error;
01398 
01399    while (e) {
01400       if (strcasecmp(e->name, endpt) == 0)
01401          break;
01402       e = e->next;
01403    }
01404 
01405    if (!e)
01406       goto error;
01407 
01408    /*
01409     * As long as the gateway/endpoint is valid, we'll
01410     * assume that the device is available and its state
01411     * can be tracked.
01412     */
01413    ret = AST_DEVICE_UNKNOWN;
01414 
01415 error:
01416    ast_mutex_unlock(&gatelock);
01417    return ret;
01418 }

static int mgcp_fixup ( struct ast_channel oldchan,
struct ast_channel newchan 
) [static]

Definition at line 1299 of file chan_mgcp.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), mgcp_subchannel::lock, LOG_NOTICE, LOG_WARNING, mgcp_subchannel::owner, and ast_channel::tech_pvt.

01300 {
01301    struct mgcp_subchannel *sub = newchan->tech_pvt;
01302 
01303    ast_mutex_lock(&sub->lock);
01304    ast_log(LOG_NOTICE, "mgcp_fixup(%s, %s)\n", oldchan->name, newchan->name);
01305    if (sub->owner != oldchan) {
01306       ast_mutex_unlock(&sub->lock);
01307       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
01308       return -1;
01309    }
01310    sub->owner = newchan;
01311    ast_mutex_unlock(&sub->lock);
01312    return 0;
01313 }

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

Definition at line 3970 of file chan_mgcp.c.

References AST_RTP_GET_FAILED, AST_RTP_TRY_NATIVE, AST_RTP_TRY_PARTIAL, mgcp_endpoint::canreinvite, mgcp_subchannel::parent, mgcp_subchannel::rtp, and ast_channel::tech_pvt.

03971 {
03972    struct mgcp_subchannel *sub = NULL;
03973 
03974    if (!(sub = chan->tech_pvt) || !(sub->rtp))
03975       return AST_RTP_GET_FAILED;
03976 
03977    *rtp = sub->rtp;
03978 
03979    if (sub->parent->canreinvite)
03980       return AST_RTP_TRY_NATIVE;
03981    else
03982       return AST_RTP_TRY_PARTIAL;
03983 }

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, 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 1452 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, mgcp_subchannel::rtp, ast_channel::tech_pvt, and transmit_notify_request().

01453 {
01454    struct mgcp_subchannel *sub = ast->tech_pvt;
01455    int res = 0;
01456 
01457    if (mgcpdebug) {
01458       ast_verb(3, "MGCP asked to indicate %d '%s' condition on channel %s\n",
01459          ind, control2str(ind), ast->name);
01460    }
01461    ast_mutex_lock(&sub->lock);
01462    switch(ind) {
01463    case AST_CONTROL_RINGING:
01464 #ifdef DLINK_BUGGY_FIRMWARE   
01465       transmit_notify_request(sub, "rt");
01466 #else
01467       transmit_notify_request(sub, "G/rt");
01468 #endif      
01469       break;
01470    case AST_CONTROL_BUSY:
01471       transmit_notify_request(sub, "L/bz");
01472       break;
01473    case AST_CONTROL_CONGESTION:
01474       transmit_notify_request(sub, "G/cg");
01475       break;
01476    case AST_CONTROL_HOLD:
01477       ast_moh_start(ast, data, NULL);
01478       break;
01479    case AST_CONTROL_UNHOLD:
01480       ast_moh_stop(ast);
01481       break;
01482    case AST_CONTROL_SRCUPDATE:
01483       ast_rtp_new_source(sub->rtp);
01484       break;
01485    case -1:
01486       transmit_notify_request(sub, "");
01487       break;
01488    default:
01489       ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
01490       res = -1;
01491    }
01492    ast_mutex_unlock(&sub->lock);
01493    return res;
01494 }

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

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

01497 {
01498    struct ast_channel *tmp;
01499    struct mgcp_endpoint *i = sub->parent;
01500    int fmt;
01501 
01502    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);
01503    if (tmp) {
01504       tmp->tech = &mgcp_tech;
01505       tmp->nativeformats = i->capability;
01506       if (!tmp->nativeformats)
01507          tmp->nativeformats = capability;
01508       fmt = ast_best_codec(tmp->nativeformats);
01509       ast_string_field_build(tmp, name, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id);
01510       if (sub->rtp)
01511          ast_channel_set_fd(tmp, 0, ast_rtp_fd(sub->rtp));
01512       if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) {
01513          i->dsp = ast_dsp_new();
01514          ast_dsp_set_features(i->dsp, DSP_FEATURE_DIGIT_DETECT);
01515          /* this is to prevent clipping of dtmf tones during dsp processing */
01516          ast_dsp_set_digitmode(i->dsp, DSP_DIGITMODE_NOQUELCH);
01517       } else {
01518          i->dsp = NULL;
01519       }
01520       if (state == AST_STATE_RING)
01521          tmp->rings = 1;
01522       tmp->writeformat = fmt;
01523       tmp->rawwriteformat = fmt;
01524       tmp->readformat = fmt;
01525       tmp->rawreadformat = fmt;
01526       tmp->tech_pvt = sub;
01527       if (!ast_strlen_zero(i->language))
01528          ast_string_field_set(tmp, language, i->language);
01529       if (!ast_strlen_zero(i->accountcode))
01530          ast_string_field_set(tmp, accountcode, i->accountcode);
01531       if (i->amaflags)
01532          tmp->amaflags = i->amaflags;
01533       sub->owner = tmp;
01534       ast_module_ref(ast_module_info->self);
01535       tmp->callgroup = i->callgroup;
01536       tmp->pickupgroup = i->pickupgroup;
01537       ast_string_field_set(tmp, call_forward, i->call_forward);
01538       ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
01539       ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
01540 
01541       /* Don't use ast_set_callerid() here because it will
01542        * generate a needless NewCallerID event */
01543       tmp->cid.cid_ani = ast_strdup(i->cid_num);
01544       
01545       if (!i->adsi)
01546          tmp->adsicpe = AST_ADSI_UNAVAILABLE;
01547       tmp->priority = 1;
01548       if (sub->rtp)
01549          ast_jb_configure(tmp, &global_jbconf);
01550       if (state != AST_STATE_DOWN) {
01551          if (ast_pbx_start(tmp)) {
01552             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
01553             ast_hangup(tmp);
01554             tmp = NULL;
01555          }
01556       }
01557       ast_verb(3, "MGCP mgcp_new(%s) created in state: %s\n",
01558             tmp->name, ast_state2str(state));
01559    } else {
01560       ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
01561    }
01562    return tmp;
01563 }

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

References ast_mutex_lock(), ast_mutex_unlock(), f, mgcp_subchannel::lock, mgcp_rtp_read(), and ast_channel::tech_pvt.

01260 {
01261    struct ast_frame *f;
01262    struct mgcp_subchannel *sub = ast->tech_pvt;
01263    ast_mutex_lock(&sub->lock);
01264    f = mgcp_rtp_read(sub);
01265    ast_mutex_unlock(&sub->lock);
01266    return f;
01267 }

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

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

04312 {
04313    static int deprecated = 0;
04314 
04315    if (e) {
04316       switch (cmd) {
04317       case CLI_INIT:
04318          e->command = "mgcp reload";
04319          e->usage =
04320             "Usage: mgcp reload\n"
04321             "       'mgcp reload' is deprecated.  Please use 'reload chan_mgcp.so' instead.\n";
04322          return NULL;
04323       case CLI_GENERATE:
04324          return NULL;
04325       }
04326    }
04327 
04328    if (!deprecated && a && a->argc > 0) {
04329       ast_log(LOG_WARNING, "'mgcp reload' is deprecated.  Please use 'reload chan_mgcp.so' instead.\n");
04330       deprecated = 1;
04331    }
04332 
04333    ast_mutex_lock(&mgcp_reload_lock);
04334    if (mgcp_reloading) {
04335       ast_verbose("Previous mgcp reload not yet done\n");
04336    } else
04337       mgcp_reloading = 1;
04338    ast_mutex_unlock(&mgcp_reload_lock);
04339    restart_monitor();
04340    return CLI_SUCCESS;
04341 }

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

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

03525 {
03526    int oldformat;
03527    struct mgcp_subchannel *sub;
03528    struct ast_channel *tmpc = NULL;
03529    char tmp[256];
03530    char *dest = data;
03531 
03532    oldformat = format;
03533    format &= capability;
03534    if (!format) {
03535       ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", format);
03536       return NULL;
03537    }
03538    ast_copy_string(tmp, dest, sizeof(tmp));
03539    if (ast_strlen_zero(tmp)) {
03540       ast_log(LOG_NOTICE, "MGCP Channels require an endpoint\n");
03541       return NULL;
03542    }
03543    sub = find_subchannel_and_lock(tmp, 0, NULL);
03544    if (!sub) {
03545       ast_log(LOG_WARNING, "Unable to find MGCP endpoint '%s'\n", tmp);
03546       *cause = AST_CAUSE_UNREGISTERED;
03547       return NULL;
03548    }
03549    
03550    ast_verb(3, "MGCP mgcp_request(%s)\n", tmp);
03551    ast_verb(3, "MGCP cw: %d, dnd: %d, so: %d, sno: %d\n",
03552          sub->parent->callwaiting, sub->parent->dnd, sub->owner ? 1 : 0, sub->next->owner ? 1: 0);
03553    /* Must be busy */
03554    if (((sub->parent->callwaiting) && ((sub->owner) && (sub->next->owner))) ||
03555       ((!sub->parent->callwaiting) && (sub->owner)) ||
03556        (sub->parent->dnd && (ast_strlen_zero(sub->parent->call_forward)))) {
03557       if (sub->parent->hookstate == MGCP_ONHOOK) {
03558          if (has_voicemail(sub->parent)) {
03559             transmit_notify_request(sub,"L/vmwi(+)");
03560          } else {
03561             transmit_notify_request(sub,"L/vmwi(-)");
03562          }
03563       }
03564       *cause = AST_CAUSE_BUSY;
03565       ast_mutex_unlock(&sub->lock);
03566       return NULL;
03567    }
03568    tmpc = mgcp_new(sub->owner ? sub->next : sub, AST_STATE_DOWN);
03569    ast_mutex_unlock(&sub->lock);
03570    if (!tmpc)
03571       ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
03572    restart_monitor();
03573    return tmpc;
03574 }

static struct ast_frame* mgcp_rtp_read ( struct mgcp_subchannel sub  )  [static, read]

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

01229 {
01230    /* Retrieve audio/etc from channel.  Assumes sub->lock is already held. */
01231    struct ast_frame *f;
01232 
01233    f = ast_rtp_read(sub->rtp);
01234    /* Don't send RFC2833 if we're not supposed to */
01235    if (f && (f->frametype == AST_FRAME_DTMF) && !(sub->parent->dtmfmode & MGCP_DTMF_RFC2833))
01236       return &ast_null_frame;
01237    if (sub->owner) {
01238       /* We already hold the channel lock */
01239       if (f->frametype == AST_FRAME_VOICE) {
01240          if (f->subclass != sub->owner->nativeformats) {
01241             ast_debug(1, "Oooh, format changed to %d\n", f->subclass);
01242             sub->owner->nativeformats = f->subclass;
01243             ast_set_read_format(sub->owner, sub->owner->readformat);
01244             ast_set_write_format(sub->owner, sub->owner->writeformat);
01245          }
01246          /* Courtesy fearnor aka alex@pilosoft.com */
01247          if ((sub->parent->dtmfmode & MGCP_DTMF_INBAND) && (sub->parent->dsp)) {
01248 #if 0
01249             ast_log(LOG_NOTICE, "MGCP ast_dsp_process\n");
01250 #endif
01251             f = ast_dsp_process(sub->owner, sub->parent->dsp, f);
01252          }
01253       }
01254    }
01255    return f;
01256 }

static int mgcp_senddigit_begin ( struct ast_channel ast,
char  digit 
) [static]

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

01316 {
01317    struct mgcp_subchannel *sub = ast->tech_pvt;
01318    struct mgcp_endpoint *p = sub->parent;
01319    int res = 0;
01320 
01321    ast_mutex_lock(&sub->lock);
01322    if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
01323       ast_log(LOG_DEBUG, "Sending DTMF using inband/hybrid\n");
01324       res = -1; /* Let asterisk play inband indications */
01325    } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
01326       ast_log(LOG_DEBUG, "Sending DTMF using RFC2833");
01327       ast_rtp_senddigit_begin(sub->rtp, digit);
01328    } else {
01329       ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
01330    }
01331    ast_mutex_unlock(&sub->lock);
01332 
01333    return res;
01334 }

static int mgcp_senddigit_end ( struct ast_channel ast,
char  digit,
unsigned int  duration 
) [static]

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

01337 {
01338    struct mgcp_subchannel *sub = ast->tech_pvt;
01339    struct mgcp_endpoint *p = sub->parent;
01340    int res = 0;
01341    char tmp[4];
01342 
01343    ast_mutex_lock(&sub->lock);
01344    if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
01345       ast_log(LOG_DEBUG, "Stopping DTMF using inband/hybrid\n");
01346       res = -1; /* Tell Asterisk to stop inband indications */
01347    } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
01348       ast_log(LOG_DEBUG, "Stopping DTMF using RFC2833\n");
01349       tmp[0] = 'D';
01350       tmp[1] = '/';
01351       tmp[2] = digit;
01352       tmp[3] = '\0';
01353       transmit_notify_request(sub, tmp);
01354                 ast_rtp_senddigit_end(sub->rtp, digit);
01355    } else {
01356       ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
01357    }
01358    ast_mutex_unlock(&sub->lock);
01359 
01360    return res;
01361 }

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

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

03986 {
03987    /* XXX Is there such thing as video support with MGCP? XXX */
03988    struct mgcp_subchannel *sub;
03989    sub = chan->tech_pvt;
03990    if (sub && !sub->alreadygone) {
03991       transmit_modify_with_sdp(sub, rtp, codecs);
03992       return 0;
03993    }
03994    return -1;
03995 }

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

Definition at line 2663 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, mgcp_endpoint::lastcallerid, len(), LOG_WARNING, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, 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().

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

static int mgcp_write ( struct ast_channel ast,
struct ast_frame frame 
) [static]

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

01270 {
01271    struct mgcp_subchannel *sub = ast->tech_pvt;
01272    int res = 0;
01273    if (frame->frametype != AST_FRAME_VOICE) {
01274       if (frame->frametype == AST_FRAME_IMAGE)
01275          return 0;
01276       else {
01277          ast_log(LOG_WARNING, "Can't send %d type frames with MGCP write\n", frame->frametype);
01278          return 0;
01279       }
01280    } else {
01281       if (!(frame->subclass & ast->nativeformats)) {
01282          ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
01283             frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat);
01284          return -1;
01285       }
01286    }
01287    if (sub) {
01288       ast_mutex_lock(&sub->lock);
01289       if ((sub->parent->sub == sub) || !sub->parent->singlepath) {
01290          if (sub->rtp) {
01291             res =  ast_rtp_write(sub->rtp, frame);
01292          }
01293       }
01294       ast_mutex_unlock(&sub->lock);
01295    }
01296    return res;
01297 }

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

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

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

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 1763 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(), 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(), oss_call(), oss_request(), park_call_exec(), pbx_builtin_background(), pbx_builtin_waitexten(), play_moh_exec(), pqm_exec(), privacy_exec(), process_echocancel(), ql_exec(), queue_exec(), rcvfax_exec(), record_exec(), reload_agents(), reload_queues(), 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().

01764 {
01765    /* Divide fields by NULL's */
01766    char *c;
01767    int f = 0;
01768    c = req->data;
01769 
01770    /* First header starts immediately */
01771    req->header[f] = c;
01772    while(*c) {
01773       if (*c == '\n') {
01774          /* We've got a new header */
01775          *c = 0;
01776 #if 0
01777          printf("Header: %s (%d)\n", req->header[f], strlen(req->header[f]));
01778 #endif         
01779          if (ast_strlen_zero(req->header[f])) {
01780             /* Line by itself means we're now in content */
01781             c++;
01782             break;
01783          }
01784          if (f >= MGCP_MAX_HEADERS - 1) {
01785             ast_log(LOG_WARNING, "Too many MGCP headers...\n");
01786          } else
01787             f++;
01788          req->header[f] = c + 1;
01789       } else if (*c == '\r') {
01790          /* Ignore but eliminate \r's */
01791          *c = 0;
01792       }
01793       c++;
01794    }
01795    /* Check for last header */
01796    if (!ast_strlen_zero(req->header[f])) 
01797       f++;
01798    req->headers = f;
01799    /* Now we process any mime content */
01800    f = 0;
01801    req->line[f] = c;
01802    while(*c) {
01803       if (*c == '\n') {
01804          /* We've got a new line */
01805          *c = 0;
01806 #if 0
01807          printf("Line: %s (%d)\n", req->line[f], strlen(req->line[f]));
01808 #endif         
01809          if (f >= MGCP_MAX_LINES - 1) {
01810             ast_log(LOG_WARNING, "Too many SDP lines...\n");
01811          } else
01812             f++;
01813          req->line[f] = c + 1;
01814       } else if (*c == '\r') {
01815          /* Ignore and eliminate \r's */
01816          *c = 0;
01817       }
01818       c++;
01819    }
01820    /* Check for last line */
01821    if (!ast_strlen_zero(req->line[f])) 
01822       f++;
01823    req->lines = f;
01824    /* Parse up the initial header */
01825    c = req->header[0];
01826    while(*c && *c < 33) c++;
01827    /* First the verb */
01828    req->verb = c;
01829    while(*c && (*c > 32)) c++;
01830    if (*c) {
01831       *c = '\0';
01832       c++;
01833       while(*c && (*c < 33)) c++;
01834       req->identifier = c;
01835       while(*c && (*c > 32)) c++;
01836       if (*c) {
01837          *c = '\0';
01838          c++;
01839          while(*c && (*c < 33)) c++;
01840          req->endpoint = c;
01841          while(*c && (*c > 32)) c++;
01842          if (*c) {
01843             *c = '\0';
01844             c++;
01845             while(*c && (*c < 33)) c++;
01846             req->version = c;
01847             while(*c && (*c > 32)) c++;
01848             while(*c && (*c < 33)) c++;
01849             while(*c && (*c > 32)) c++;
01850             *c = '\0';
01851          }
01852       }
01853    }
01854       
01855    if (mgcpdebug) {
01856       ast_verbose("Verb: '%s', Identifier: '%s', Endpoint: '%s', Version: '%s'\n",
01857          req->verb, req->identifier, req->endpoint, req->version);
01858       ast_verbose("%d headers, %d lines\n", req->headers, req->lines);
01859    }
01860    if (*c) 
01861       ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c);
01862 }

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

Definition at line 1864 of file chan_mgcp.c.

References ast_gethostbyname(), ast_inet_ntoa(), ast_log(), ast_rtp_get_current_formats(), ast_rtp_pt_clear(), ast_rtp_set_m_type(), ast_rtp_set_peer(), ast_rtp_set_rtpmap_type(), ast_strdupa, ast_strlen_zero(), ast_verbose, mgcp_endpoint::capability, get_sdp(), get_sdp_iterate(), hp, len(), LOG_WARNING, mgcp_endpoint::nonCodecCapability, mgcp_subchannel::parent, mgcp_subchannel::rtp, and sdpLineNum_iterator_init().

Referenced by handle_response().

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

static void prune_gateways ( void   )  [static]

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

04060 {
04061    struct mgcp_gateway *g, *z, *r;
04062    struct mgcp_endpoint *e, *p, *t;
04063 
04064    ast_mutex_lock(&gatelock);
04065 
04066    /* prune gateways */
04067    for (z = NULL, g = gateways; g;) {
04068       /* prune endpoints */
04069       for (p = NULL, e = g->endpoints; e; ) {
04070          if (e->delme || g->delme) {
04071             t = e;
04072             e = e->next;
04073             if (!p)
04074                g->endpoints = e;
04075             else
04076                p->next = e;
04077             destroy_endpoint(t);
04078          } else {
04079             p = e;
04080             e = e->next;
04081          }
04082       }
04083 
04084       if (g->delme) {
04085          r = g;
04086          g = g->next;
04087          if (!z)
04088             gateways = g;
04089          else
04090             z->next = g;
04091 
04092          destroy_gateway(r);
04093       } else {
04094          z = g;
04095          g = g->next;
04096       }
04097    }
04098 
04099    ast_mutex_unlock(&gatelock);
04100 }

static int reload ( void   )  [static]

Definition at line 4343 of file chan_mgcp.c.

References mgcp_reload().

04344 {
04345    mgcp_reload(NULL, 0, NULL);
04346    return 0;
04347 }

static int reload_config ( int  reload  )  [static]

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

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

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

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

02042 {
02043    memset(req, 0, sizeof(struct mgcp_request));
02044    oseq++;
02045    if (oseq > 999999999)
02046       oseq = 1;
02047    init_req(p, req, verb);
02048    return 0;
02049 }

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

References init_resp().

Referenced by transmit_response().

02035 {
02036    memset(resp, 0, sizeof(*resp));
02037    init_resp(resp, msg, req, msgrest);
02038    return 0;
02039 }

static int restart_monitor ( void   )  [static]

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

03496 {
03497    /* If we're supposed to be stopped -- stay stopped */
03498    if (monitor_thread == AST_PTHREADT_STOP)
03499       return 0;
03500    if (ast_mutex_lock(&monlock)) {
03501       ast_log(LOG_WARNING, "Unable to lock monitor\n");
03502       return -1;
03503    }
03504    if (monitor_thread == pthread_self()) {
03505       ast_mutex_unlock(&monlock);
03506       ast_log(LOG_WARNING, "Cannot kill myself\n");
03507       return -1;
03508    }
03509    if (monitor_thread != AST_PTHREADT_NULL) {
03510       /* Wake up the thread */
03511       pthread_kill(monitor_thread, SIGURG);
03512    } else {
03513       /* Start a new monitor */
03514       if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
03515          ast_mutex_unlock(&monlock);
03516          ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
03517          return -1;
03518       }
03519    }
03520    ast_mutex_unlock(&monlock);
03521    return 0;
03522 }

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

Referenced by process_sdp().

01589 {
01590    *iterator = 0;
01591 }

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

02637 {
02638    ast_mutex_lock(&sub->lock);
02639    /* check again to be on the safe side */
02640    if (sub->rtp) {
02641       ast_rtp_destroy(sub->rtp);
02642       sub->rtp = NULL;
02643    }
02644    /* Allocate the RTP now */
02645    sub->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
02646    if (sub->rtp && sub->owner)
02647       ast_channel_set_fd(sub->owner, 0, ast_rtp_fd(sub->rtp));
02648    if (sub->rtp) {
02649       ast_rtp_setqos(sub->rtp, qos.tos_audio, qos.cos_audio, "MGCP RTP");
02650       ast_rtp_setnat(sub->rtp, sub->nat);
02651    }
02652 #if 0
02653    ast_rtp_set_callback(p->rtp, rtpready);
02654    ast_rtp_set_data(p->rtp, p);
02655 #endif      
02656    /* Make a call*ID */
02657         snprintf(sub->callid, sizeof(sub->callid), "%08lx%s", ast_random(), sub->txident);
02658    /* Transmit the connection create */
02659    transmit_connect_with_sdp(sub, NULL);
02660    ast_mutex_unlock(&sub->lock);
02661 }

static int transmit_audit_endpoint ( struct mgcp_endpoint p  )  [static]

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

02356 {
02357    struct mgcp_request resp;
02358    reqprep(&resp, p, "AUEP");
02359    /* removed unknown param VS */
02360    /*add_header(&resp, "F", "A,R,D,S,X,N,I,T,O,ES,E,MD,M");*/
02361    add_header(&resp, "F", "A");
02362    /* fill in new fields */
02363    resp.cmd = MGCP_CMD_AUEP;
02364    resp.trid = oseq;
02365    return send_request(p, NULL, &resp, oseq);  /* SC */
02366 }

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

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

02203 {
02204    struct mgcp_request resp;
02205    char local[256];
02206    char tmp[80];
02207    int x;
02208    struct mgcp_endpoint *p = sub->parent;
02209 
02210    ast_copy_string(local, "p:20", sizeof(local));
02211    for (x = 1; x <= AST_FORMAT_AUDIO_MASK; x <<= 1) {
02212       if (p->capability & x) {
02213          snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0));
02214          strncat(local, tmp, sizeof(local) - strlen(local) - 1);
02215       }
02216    }
02217    if (mgcpdebug) {
02218       ast_verb(3, "Creating connection for %s@%s-%d in cxmode: %s callid: %s\n",
02219          p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
02220    }
02221    reqprep(&resp, p, "CRCX");
02222    add_header(&resp, "C", sub->callid);
02223    add_header(&resp, "L", local);
02224    add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
02225    /* X header should not be sent. kept for compatibility */
02226    add_header(&resp, "X", sub->txident);
02227    /*add_header(&resp, "S", "");*/
02228    add_sdp(&resp, sub, rtp);
02229    /* fill in new fields */
02230    resp.cmd = MGCP_CMD_CRCX;
02231    resp.trid = oseq;
02232    return send_request(p, sub, &resp, oseq);  /* SC */
02233 }

static int transmit_connection_del ( struct mgcp_subchannel sub  )  [static]

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

02369 {
02370    struct mgcp_endpoint *p = sub->parent;
02371    struct mgcp_request resp;
02372 
02373    if (mgcpdebug) {
02374       ast_verb(3, "Delete connection %s %s@%s-%d with new mode: %s on callid: %s\n",
02375          sub->cxident, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
02376    }
02377    reqprep(&resp, p, "DLCX");
02378    /* check if call id is avail */
02379    if (sub->callid[0])
02380       add_header(&resp, "C", sub->callid);
02381    /* X header should not be sent. kept for compatibility */
02382    add_header(&resp, "X", sub->txident);
02383    /* check if cxident is avail */
02384    if (sub->cxident[0])
02385       add_header(&resp, "I", sub->cxident);
02386    /* fill in new fields */
02387    resp.cmd = MGCP_CMD_DLCX;
02388    resp.trid = oseq;
02389    return send_request(p, sub, &resp, oseq);  /* SC */
02390 }

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

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

02393 {
02394    struct mgcp_request resp;
02395 
02396    if (mgcpdebug) {
02397       ast_verb(3, "Delete connection %s %s@%s on callid: %s\n",
02398          cxident ? cxident : "", p->name, p->parent->name, callid ? callid : "");
02399    }
02400    reqprep(&resp, p, "DLCX");
02401    /* check if call id is avail */
02402    if (callid && *callid)
02403       add_header(&resp, "C", callid);
02404    /* check if cxident is avail */
02405    if (cxident && *cxident)
02406       add_header(&resp, "I", cxident);
02407    /* fill in new fields */
02408    resp.cmd = MGCP_CMD_DLCX;
02409    resp.trid = oseq;
02410    return send_request(p, p->sub, &resp, oseq);
02411 }

static int transmit_modify_request ( struct mgcp_subchannel sub  )  [static]

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

02311 {
02312    struct mgcp_request resp;
02313    struct mgcp_endpoint *p = sub->parent;
02314 
02315    if (ast_strlen_zero(sub->cxident)) {
02316       /* We don't have a CXident yet, store the destination and
02317          wait a bit */
02318       return 0;
02319    }
02320    if (mgcpdebug) {
02321       ast_verb(3, "Modified %s@%s-%d with new mode: %s on callid: %s\n",
02322          p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
02323    }
02324    reqprep(&resp, p, "MDCX");
02325    add_header(&resp, "C", sub->callid);
02326    add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
02327    /* X header should not be sent. kept for compatibility */
02328    add_header(&resp, "X", sub->txident);
02329    add_header(&resp, "I", sub->cxident);
02330    switch (sub->parent->hookstate) {
02331    case MGCP_ONHOOK:
02332       add_header(&resp, "R", "L/hd(N)");
02333       break;
02334    case MGCP_OFFHOOK:
02335       add_header_offhook(sub, &resp);
02336       break;
02337    }
02338    /* fill in new fields */
02339    resp.cmd = MGCP_CMD_MDCX;
02340    resp.trid = oseq;
02341    return send_request(p, sub, &resp, oseq); /* SC */
02342 }

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

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

02167 {
02168    struct mgcp_request resp;
02169    char local[256];
02170    char tmp[80];
02171    int x;
02172    struct mgcp_endpoint *p = sub->parent;
02173 
02174    if (ast_strlen_zero(sub->cxident) && rtp) {
02175       /* We don't have a CXident yet, store the destination and
02176          wait a bit */
02177       ast_rtp_get_peer(rtp, &sub->tmpdest);
02178       return 0;
02179    }
02180    ast_copy_string(local, "p:20", sizeof(local));
02181    for (x = 1; x <= AST_FORMAT_AUDIO_MASK; x <<= 1) {
02182       if (p->capability & x) {
02183          snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0));
02184          strncat(local, tmp, sizeof(local) - strlen(local) - 1);
02185       }
02186    }
02187    reqprep(&resp, p, "MDCX");
02188    add_header(&resp, "C", sub->callid);
02189    add_header(&resp, "L", local);
02190    add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
02191    /* X header should not be sent. kept for compatibility */
02192    add_header(&resp, "X", sub->txident);
02193    add_header(&resp, "I", sub->cxident);
02194    /*add_header(&resp, "S", "");*/
02195    add_sdp(&resp, sub, rtp);
02196    /* fill in new fields */
02197    resp.cmd = MGCP_CMD_MDCX;
02198    resp.trid = oseq;
02199    return send_request(p, sub, &resp, oseq); /* SC */
02200 }

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

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

02236 {
02237    struct mgcp_request resp;
02238    struct mgcp_endpoint *p = sub->parent;
02239 
02240    if (mgcpdebug) {
02241       ast_verb(3, "MGCP Asked to indicate tone: %s on  %s@%s-%d in cxmode: %s\n",
02242          tone, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]);
02243    }
02244    ast_copy_string(p->curtone, tone, sizeof(p->curtone));
02245    reqprep(&resp, p, "RQNT");
02246    add_header(&resp, "X", p->rqnt_ident); /* SC */
02247    switch (p->hookstate) {
02248    case MGCP_ONHOOK:
02249       add_header(&resp, "R", "L/hd(N)");
02250       break;
02251    case MGCP_OFFHOOK:
02252       add_header_offhook(sub, &resp);
02253       break;
02254    }
02255    if (!ast_strlen_zero(tone)) {
02256       add_header(&resp, "S", tone);
02257    }
02258    /* fill in new fields */
02259    resp.cmd = MGCP_CMD_RQNT;
02260    resp.trid = oseq;
02261    return send_request(p, NULL, &resp, oseq); /* SC */
02262 }

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

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

02265 {
02266    struct mgcp_request resp;
02267    char tone2[256];
02268    char *l, *n;
02269    struct timeval t = ast_tvnow();
02270    struct ast_tm tm;
02271    struct mgcp_endpoint *p = sub->parent;
02272    
02273    ast_localtime(&t, &tm, NULL);
02274    n = callername;
02275    l = callernum;
02276    if (!n)
02277       n = "";
02278    if (!l)
02279       l = "";
02280 
02281    /* Keep track of last callerid for blacklist and callreturn */
02282    ast_copy_string(p->lastcallerid, l, sizeof(p->lastcallerid));
02283 
02284    snprintf(tone2, sizeof(tone2), "%s,L/ci(%02d/%02d/%02d/%02d,%s,%s)", tone, 
02285       tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, l, n);
02286    ast_copy_string(p->curtone, tone, sizeof(p->curtone));
02287    reqprep(&resp, p, "RQNT");
02288    add_header(&resp, "X", p->rqnt_ident); /* SC */
02289    switch (p->hookstate) {
02290    case MGCP_ONHOOK:
02291       add_header(&resp, "R", "L/hd(N)");
02292       break;
02293    case MGCP_OFFHOOK:
02294       add_header_offhook(sub, &resp);
02295       break;
02296    }
02297    if (!ast_strlen_zero(tone2)) {
02298       add_header(&resp, "S", tone2);
02299    }
02300    if (mgcpdebug) {
02301       ast_verb(3, "MGCP Asked to indicate tone: %s on  %s@%s-%d in cxmode: %s\n",
02302          tone2, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]);
02303    }
02304    /* fill in new fields */
02305    resp.cmd = MGCP_CMD_RQNT;
02306    resp.trid = oseq;
02307    return send_request(p, NULL, &resp, oseq);  /* SC */
02308 }

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

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

02052 {
02053    struct mgcp_request resp;
02054    struct mgcp_endpoint *p = sub->parent;
02055    struct mgcp_response *mgr;
02056 
02057    respprep(&resp, p, msg, req, msgrest);
02058    mgr = ast_calloc(1, sizeof(*mgr) + resp.len + 1);
02059    if (mgr) {
02060       /* Store MGCP response in case we have to retransmit */
02061       sscanf(req->identifier, "%30d", &mgr->seqno);
02062       time(&mgr->whensent);
02063       mgr->len = resp.len;
02064       memcpy(mgr->buf, resp.data, resp.len);
02065       mgr->buf[resp.len] = '\0';
02066       mgr->next = p->parent->responses;
02067       p->parent->responses = mgr;
02068    }
02069    return send_response(sub, &resp);
02070 }

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

04350 {
04351    struct mgcp_endpoint *e;
04352    struct mgcp_gateway *g;
04353 
04354    /* Check to see if we're reloading */
04355    if (ast_mutex_trylock(&mgcp_reload_lock)) {
04356       ast_log(LOG_WARNING, "MGCP is currently reloading.  Unable to remove module.\n");
04357       return -1;
04358    } else {
04359       mgcp_reloading = 1;
04360       ast_mutex_unlock(&mgcp_reload_lock);
04361    }
04362 
04363    /* First, take us out of the channel loop */
04364    ast_channel_unregister(&mgcp_tech);
04365 
04366    /* Shut down the monitoring thread */
04367    if (!ast_mutex_lock(&monlock)) {
04368       if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
04369          pthread_cancel(monitor_thread);
04370          pthread_kill(monitor_thread, SIGURG);
04371          pthread_join(monitor_thread, NULL);
04372       }
04373       monitor_thread = AST_PTHREADT_STOP;
04374       ast_mutex_unlock(&monlock);
04375    } else {
04376       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
04377       /* We always want to leave this in a consistent state */
04378       ast_channel_register(&mgcp_tech);
04379       mgcp_reloading = 0;
04380       mgcp_reload(NULL, 0, NULL);
04381       return -1;
04382    }
04383 
04384    if (!ast_mutex_lock(&gatelock)) {
04385       for (g = gateways; g; g = g->next) {
04386          g->delme = 1;
04387          for (e = g->endpoints; e; e = e->next)
04388             e->delme = 1;
04389       }
04390 
04391       prune_gateways();
04392       ast_mutex_unlock(&gatelock);
04393    } else {
04394       ast_log(LOG_WARNING, "Unable to lock the gateways list.\n");
04395       /* We always want to leave this in a consistent state */
04396       ast_channel_register(&mgcp_tech);
04397       /* Allow the monitor to restart */
04398       monitor_thread = AST_PTHREADT_NULL;
04399       mgcp_reloading = 0;
04400       mgcp_reload(NULL, 0, NULL);
04401       return -1;
04402    }
04403 
04404    close(mgcpsock);
04405    ast_rtp_proto_unregister(&mgcp_rtp);
04406    ast_cli_unregister_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
04407    sched_context_destroy(sched);
04408 
04409    return 0;
04410 }


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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 4416 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 4416 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 canreinvite = CANREINVITE [static]

Definition at line 181 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 1196 of file chan_mgcp.c.

struct ast_cli_entry cli_mgcp_set_debug_deprecated = AST_CLI_DEFINE(handle_mgcp_set_debug_deprecated, "Enable/Disable MGCP debugging") [static]

Definition at line 1195 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 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 3997 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 3407 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 on 8 Apr 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1