Wed Oct 28 13:32:05 2009

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_engine.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 "asterisk/chanvars.h"

Include dependency graph for chan_mgcp.c:

Go to the source code of this file.

Data Structures

struct  mgcp_endpoint
struct  mgcp_gateway
struct  mgcp_message
 mgcp_message: MGCP message for queuing up More...
struct  mgcp_request
struct  mgcp_response
struct  mgcp_subchannel

Defines

#define DEFAULT_EXPIRY   120
#define DEFAULT_MGCP_CA_PORT   2727
#define DEFAULT_MGCP_GW_PORT   2427
#define DEFAULT_RETRANS   1000
#define DIRECTMEDIA   1
#define INADDR_NONE   (in_addr_t)(-1)
#define MAX_EXPIRY   3600
#define MAX_RETRANS   5
#define MAX_SUBS   2
#define MGCP_CX_CONF   3
#define MGCP_CX_CONFERENCE   3
#define MGCP_CX_INACTIVE   4
#define MGCP_CX_MUTE   4
#define MGCP_CX_RECVONLY   1
#define MGCP_CX_SENDONLY   0
#define MGCP_CX_SENDRECV   2
#define MGCP_DTMF_HYBRID   (1 << 2)
#define MGCP_DTMF_INBAND   (1 << 1)
#define MGCP_DTMF_RFC2833   (1 << 0)
#define MGCP_MAX_HEADERS   64
#define MGCP_MAX_LINES   64
#define MGCP_MAX_PACKET   1500
#define MGCP_OFFHOOK   2
#define MGCP_ONHOOK   1
#define MGCP_SUBCHANNEL_MAGIC   "!978!"
#define MGCPDUMPER
#define RESPONSE_TIMEOUT   30
#define SUB_ALT   1
#define SUB_REAL   0
#define TYPE_LINE   2
#define TYPE_TRUNK   1

Enumerations

enum  {
  MGCP_CMD_EPCF, MGCP_CMD_CRCX, MGCP_CMD_MDCX, MGCP_CMD_DLCX,
  MGCP_CMD_RQNT, MGCP_CMD_NTFY, MGCP_CMD_AUEP, MGCP_CMD_AUCX,
  MGCP_CMD_RSIP
}

Functions

static char * __get_header (struct mgcp_request *req, char *name, int *start)
static int __mgcp_xmit (struct mgcp_gateway *gw, char *data, int len)
static void __reg_module (void)
static void __unreg_module (void)
static int add_header (struct mgcp_request *req, const char *var, const 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_instance *rtp)
static struct ast_variableadd_var (const char *buf, struct ast_variable *list)
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 struct ast_variablecopy_vars (struct ast_variable *src)
 duplicate a list of channel variables,
static void destroy_endpoint (struct mgcp_endpoint *e)
static void destroy_gateway (struct mgcp_gateway *g)
static void * do_monitor (void *data)
static void dump_cmd_queues (struct mgcp_endpoint *p, struct mgcp_subchannel *sub)
 dump_cmd_queues: (SC:) cleanup pending commands
static void dump_queue (struct mgcp_gateway *gw, struct mgcp_endpoint *p)
static int find_and_retrans (struct mgcp_subchannel *sub, struct mgcp_request *req)
static struct mgcp_requestfind_command (struct mgcp_endpoint *p, struct mgcp_subchannel *sub, struct mgcp_request **queue, ast_mutex_t *l, int ident)
 find_command: (SC:) remove command transaction from queue
static struct mgcp_subchannelfind_subchannel_and_lock (char *name, int msgid, struct sockaddr_in *sin)
static char * get_csv (char *c, int *len, char **next)
 get_csv: (SC:) get comma separated value
static char * get_header (struct mgcp_request *req, char *name)
static char * get_sdp (struct mgcp_request *req, char *name)
static char * get_sdp_by_line (char *line, char *name, int nameLen)
static char * get_sdp_iterate (int *iterator, struct mgcp_request *req, char *name)
static void handle_hd_hf (struct mgcp_subchannel *sub, char *ev)
static char * handle_mgcp_audit_endpoint (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_mgcp_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_mgcp_show_endpoints (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int handle_request (struct mgcp_subchannel *sub, struct mgcp_request *req, struct sockaddr_in *sin)
static void handle_response (struct mgcp_endpoint *p, struct mgcp_subchannel *sub, int result, unsigned int ident, struct mgcp_request *resp)
static int has_voicemail (struct mgcp_endpoint *p)
static int init_req (struct mgcp_endpoint *p, struct mgcp_request *req, char *verb)
static int init_resp (struct mgcp_request *req, char *resp, struct mgcp_request *orig, char *resprest)
static int load_module (void)
 load_module: PBX load module - initialization ---
static int mgcp_answer (struct ast_channel *ast)
static int mgcp_call (struct ast_channel *ast, char *dest, int timeout)
static int mgcp_devicestate (void *data)
 mgcp_devicestate: channel callback for device status monitoring
static int mgcp_fixup (struct ast_channel *oldchan, struct ast_channel *newchan)
static enum ast_rtp_glue_result mgcp_get_rtp_peer (struct ast_channel *chan, struct ast_rtp_instance **instance)
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, const char *linkedid)
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, const struct ast_channel *requestor, 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_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *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_instance *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_instance *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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static struct in_addr __ourip
static char accountcode [AST_MAX_ACCOUNT_CODE] = ""
static int adsi = 0
static int amaflags = 0
static struct ast_module_infoast_module_info = &__mod_info
static struct sockaddr_in bindaddr
static int callreturn = 0
static int callwaiting = 0
static int cancallforward = 0
static int capability = AST_FORMAT_ULAW
static char cid_name [AST_MAX_EXTENSION] = ""
static char cid_num [AST_MAX_EXTENSION] = ""
static struct ast_cli_entry cli_mgcp []
static const char config [] = "mgcp.conf"
static char context [AST_MAX_EXTENSION] = "default"
static ast_group_t cur_callergroup = 0
static ast_group_t cur_pickupgroup = 0
static struct ast_jb_conf default_jbconf
static int directmedia = DIRECTMEDIA
static int dtmfmode = 0
static int firstdigittimeout = 16000
static ast_mutex_t gatelock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER )
 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 const char *const mgcp_cxmodes []
static ast_mutex_t mgcp_reload_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER )
static int mgcp_reloading = 0
static struct ast_rtp_glue mgcp_rtp_glue
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_MUTEX_INITIALIZER )
static char musicclass [MAX_MUSICCLASS] = ""
static int nat = 0
static ast_mutex_t netlock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER )
static int nonCodecCapability = AST_RTP_DTMF
static unsigned int oseq
static char ourhost [MAXHOSTNAMELEN]
static int ourport
static char parkinglot [AST_MAX_CONTEXT]
struct {
   unsigned int   cos
   unsigned int   cos_audio
   unsigned int   tos
   unsigned int   tos_audio
qos
static struct sched_contextsched
static int singlepath = 0
static int slowsequence = 0
static const char tdesc [] = "Media Gateway Control Protocol (MGCP)"
static int threewaycalling = 0
static int transfer = 0


Detailed Description

Implementation of Media Gateway Control Protocol.

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

Definition in file chan_mgcp.c.


Define Documentation

#define DEFAULT_EXPIRY   120

Definition at line 82 of file chan_mgcp.c.

#define DEFAULT_MGCP_CA_PORT   2727

From RFC 2705

Definition at line 108 of file chan_mgcp.c.

Referenced by reload_config().

#define DEFAULT_MGCP_GW_PORT   2427

From RFC 2705

Definition at line 107 of file chan_mgcp.c.

Referenced by build_gateway().

#define DEFAULT_RETRANS   1000

How frequently to retransmit

Definition at line 110 of file chan_mgcp.c.

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

#define DIRECTMEDIA   1

Definition at line 84 of file chan_mgcp.c.

Referenced by build_gateway().

#define INADDR_NONE   (in_addr_t)(-1)

Definition at line 87 of file chan_mgcp.c.

Referenced by build_gateway().

#define MAX_EXPIRY   3600

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

#define RESPONSE_TIMEOUT   30

in seconds

Definition at line 259 of file chan_mgcp.c.

Referenced by find_and_retrans().

#define SUB_ALT   1

Definition at line 272 of file chan_mgcp.c.

#define SUB_REAL   0

Definition at line 271 of file chan_mgcp.c.

#define TYPE_LINE   2

#define TYPE_TRUNK   1

Definition at line 305 of file chan_mgcp.c.

Referenced by build_gateway().


Enumeration Type Documentation

anonymous enum

Enumerator:
MGCP_CMD_EPCF 
MGCP_CMD_CRCX 
MGCP_CMD_MDCX 
MGCP_CMD_DLCX 
MGCP_CMD_RQNT 
MGCP_CMD_NTFY 
MGCP_CMD_AUEP 
MGCP_CMD_AUCX 
MGCP_CMD_RSIP 

Definition at line 131 of file chan_mgcp.c.

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


Function Documentation

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

Definition at line 1594 of file chan_mgcp.c.

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

Referenced by build_route(), copy_all_header(), copy_via_headers(), func_header_read(), get_header(), and handle_response_register().

01595 {
01596    int x;
01597    int len = strlen(name);
01598    char *r;
01599    for (x=*start;x<req->headers;x++) {
01600       if (!strncasecmp(req->header[x], name, len) && 
01601           (req->header[x][len] == ':')) {
01602          r = req->header[x] + len + 1;
01603          while(*r && (*r < 33))
01604             r++;
01605          *start = x+1;
01606          return r;
01607       }
01608    }
01609    /* Don't return NULL, so get_header is always a valid pointer */
01610    return "";
01611 }

static int __mgcp_xmit ( struct mgcp_gateway gw,
char *  data,
int  len 
) [static]

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

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

static void __reg_module ( void   )  [static]

Definition at line 4473 of file chan_mgcp.c.

static void __unreg_module ( void   )  [static]

Definition at line 4473 of file chan_mgcp.c.

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

Definition at line 1940 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 __transmit_response(), add_digit(), add_diversion_header(), add_header_contentLength(), add_header_offhook(), add_route(), add_rpid(), add_sdp(), add_text(), add_vidupdate(), append_date(), copy_all_header(), copy_header(), copy_via_headers(), initreqprep(), reqprep(), respprep(), transmit_audit_endpoint(), transmit_connect_with_sdp(), transmit_connection_del(), transmit_connection_del_w_params(), transmit_invite(), transmit_modify_request(), transmit_modify_with_sdp(), transmit_notify_request(), transmit_notify_request_with_callerid(), transmit_notify_with_mwi(), transmit_notify_with_sipfrag(), transmit_refer(), transmit_register(), transmit_reinvite_with_sdp(), transmit_request(), transmit_request_with_auth(), transmit_response_with_allow(), transmit_response_with_auth(), transmit_response_with_minse(), transmit_response_with_unsupported(), transmit_state_notify(), and update_connectedline().

01941 {
01942    if (req->len >= sizeof(req->data) - 4) {
01943       ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
01944       return -1;
01945    }
01946    if (req->lines) {
01947       ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n");
01948       return -1;
01949    }
01950    req->header[req->headers] = req->data + req->len;
01951    snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s: %s\r\n", var, value);
01952    req->len += strlen(req->header[req->headers]);
01953    if (req->headers < MGCP_MAX_HEADERS)
01954       req->headers++;
01955    else {
01956       ast_log(LOG_WARNING, "Out of header space\n");
01957       return -1;
01958    }
01959    return 0;   
01960 }

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

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

02336 {
02337    struct mgcp_endpoint *p = sub->parent;
02338 
02339    if (p && p->sub && p->sub->owner && p->sub->owner->_state >= AST_STATE_RINGING && (p->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)))
02340       add_header(resp, "R", "L/hu(N),L/hf(N)");
02341    else
02342       add_header(resp, "R", "L/hu(N),L/hf(N),D/[0-9#*](N)");
02343 }

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

Definition at line 1962 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_digit(), add_sdp(), add_text(), add_vidupdate(), transmit_invite(), transmit_notify_with_mwi(), transmit_notify_with_sipfrag(), and transmit_state_notify().

01963 {
01964    if (req->len >= sizeof(req->data) - 4) {
01965       ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
01966       return -1;
01967    }
01968    if (!req->lines) {
01969       /* Add extra empty return */
01970       ast_copy_string(req->data + req->len, "\r\n", sizeof(req->data) - req->len);
01971       req->len += strlen(req->data + req->len);
01972    }
01973    req->line[req->lines] = req->data + req->len;
01974    snprintf(req->line[req->lines], sizeof(req->data) - req->len, "%s", line);
01975    req->len += strlen(req->line[req->lines]);
01976    if (req->lines < MGCP_MAX_LINES)
01977       req->lines++;
01978    else {
01979       ast_log(LOG_WARNING, "Out of line space\n");
01980       return -1;
01981    }
01982    return 0;   
01983 }

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

Definition at line 2063 of file chan_mgcp.c.

References add_line(), ast_copy_string(), AST_FORMAT_AUDIO_MASK, ast_inet_ntoa(), ast_log(), ast_rtp_codecs_payload_code(), AST_RTP_DTMF, ast_rtp_instance_get_codecs(), ast_rtp_instance_get_local_address(), ast_rtp_instance_get_remote_address(), ast_rtp_lookup_mime_subtype2(), 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(), transmit_invite(), transmit_modify_with_sdp(), transmit_reinvite_with_sdp(), transmit_response_with_sdp(), transmit_response_with_t38_sdp(), and update_connectedline().

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

static struct ast_variable * add_var ( const char *  buf,
struct ast_variable list 
) [static, read]

Definition at line 4123 of file chan_mgcp.c.

References ast_strdupa, ast_variable_new(), and ast_variable::next.

Referenced by build_gateway(), build_peer(), and config_parse_variables().

04124 {
04125    struct ast_variable *tmpvar = NULL;
04126    char *varname = ast_strdupa(buf), *varval = NULL;
04127 
04128    if ((varval = strchr(varname, '='))) {
04129       *varval++ = '\0';
04130       if ((tmpvar = ast_variable_new(varname, varval, ""))) {
04131          tmpvar->next = list;
04132          list = tmpvar;
04133       }
04134    }
04135    return list;
04136 }

static int attempt_transfer ( struct mgcp_endpoint p  )  [static]

Definition at line 2896 of file chan_mgcp.c.

References ast_channel::_softhangup, ast_channel::_state, mgcp_subchannel::alreadygone, ast_bridged_channel(), ast_channel_masquerade(), AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_debug, ast_indicate(), ast_log(), ast_queue_control(), AST_SOFTHANGUP_DEV, AST_STATE_RINGING, ast_verb, mgcp_subchannel::id, LOG_WARNING, mgcp_queue_hangup(), mgcp_gateway::name, mgcp_endpoint::name, ast_channel::name, mgcp_subchannel::next, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_endpoint::sub, and unalloc_sub().

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

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

References __ourip, mgcp_endpoint::accountcode, add_var(), 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_variables_destroy(), ast_verb, mgcp_endpoint::callgroup, mgcp_endpoint::callreturn, mgcp_endpoint::callwaiting, mgcp_endpoint::cancallforward, mgcp_endpoint::capability, mgcp_endpoint::chanvars, mgcp_endpoint::cid_name, mgcp_endpoint::cid_num, mgcp_endpoint::cmd_queue_lock, mgcp_endpoint::context, copy_vars(), mgcp_subchannel::cx_queue_lock, mgcp_subchannel::cxmode, mgcp_gateway::defaddr, DEFAULT_MGCP_GW_PORT, mgcp_endpoint::delme, mgcp_gateway::delme, mgcp_endpoint::directmedia, DIRECTMEDIA, mgcp_endpoint::dtmfmode, mgcp_gateway::dynamic, mgcp_gateway::endpoints, mgcp_gateway::expire, gateways, mgcp_gateway::ha, mgcp_endpoint::hascallwaiting, mgcp_endpoint::hookstate, mgcp_subchannel::id, mgcp_endpoint::immediate, INADDR_NONE, mgcp_gateway::isnamedottedip, mgcp_endpoint::language, ast_variable::lineno, mgcp_subchannel::lock, mgcp_endpoint::lock, LOG_WARNING, mgcp_subchannel::magic, mgcp_endpoint::mailbox, MAX_SUBS, mbox(), MGCP_CX_INACTIVE, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, MGCP_DTMF_RFC2833, MGCP_ONHOOK, MGCP_SUBCHANNEL_MAGIC, mgcp_gateway::msgs_lock, mgcp_endpoint::msgstate, mgcp_endpoint::musicclass, mwi_event_cb(), mgcp_endpoint::mwi_event_sub, mgcp_endpoint::name, ast_variable::name, mgcp_gateway::name, mgcp_subchannel::nat, mgcp_endpoint::needaudit, ast_variable::next, mgcp_subchannel::next, mgcp_endpoint::next, mgcp_gateway::next, mgcp_endpoint::onhooktime, mgcp_gateway::ourip, mgcp_subchannel::parent, mgcp_endpoint::parent, mgcp_endpoint::parkinglot, mgcp_endpoint::pickupgroup, mgcp_gateway::retransid, mgcp_endpoint::rqnt_ident, mgcp_endpoint::rqnt_queue_lock, mgcp_subchannel::rtp, mgcp_endpoint::singlepath, mgcp_endpoint::slowsequence, 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().

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

static char* control2str ( int  ind  )  [static]

Definition at line 1403 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(), skinny_indicate(), and unistim_indicate().

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

static struct ast_variable * copy_vars ( struct ast_variable src  )  [static, read]

duplicate a list of channel variables,

Returns:
the copy.

Definition at line 4141 of file chan_mgcp.c.

References ast_variable_new(), and ast_variable::next.

Referenced by build_gateway(), check_peer_ok(), and create_addr_from_peer().

04142 {
04143    struct ast_variable *res = NULL, *tmp, *v = NULL;
04144 
04145    for (v = src ; v ; v = v->next) {
04146       if ((tmp = ast_variable_new(v->name, v->value, v->file))) {
04147          tmp->next = res;
04148          res = tmp;
04149       }
04150    }
04151    return res;
04152 }

static void destroy_endpoint ( struct mgcp_endpoint e  )  [static]

Definition at line 4019 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_instance_destroy(), ast_strlen_zero(), ast_variables_destroy(), mgcp_endpoint::chanvars, 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().

04020 {
04021    struct mgcp_subchannel *sub = e->sub->next, *s;
04022    int i;
04023 
04024    for (i = 0; i < MAX_SUBS; i++) {
04025       ast_mutex_lock(&sub->lock);
04026       if (!ast_strlen_zero(sub->cxident)) {
04027          transmit_connection_del(sub);
04028       }
04029       if (sub->rtp) {
04030          ast_rtp_instance_destroy(sub->rtp);
04031          sub->rtp = NULL;
04032       }
04033       memset(sub->magic, 0, sizeof(sub->magic));
04034       mgcp_queue_hangup(sub);
04035       dump_cmd_queues(NULL, sub);
04036       ast_mutex_unlock(&sub->lock);
04037       sub = sub->next;
04038    }
04039 
04040    if (e->dsp) {
04041       ast_dsp_free(e->dsp);
04042    }
04043 
04044    dump_queue(e->parent, e);
04045    dump_cmd_queues(e, NULL);
04046 
04047    sub = e->sub;
04048    for (i = 0; (i < MAX_SUBS) && sub; i++) {
04049       s = sub;
04050       sub = sub->next;
04051       ast_mutex_destroy(&s->lock);
04052       ast_mutex_destroy(&s->cx_queue_lock);
04053       ast_free(s);
04054    }
04055 
04056    if (e->mwi_event_sub)
04057       ast_event_unsubscribe(e->mwi_event_sub);
04058 
04059    if (e->chanvars) {
04060       ast_variables_destroy(e->chanvars);
04061       e->chanvars = NULL;
04062    }
04063 
04064    ast_mutex_destroy(&e->lock);
04065    ast_mutex_destroy(&e->rqnt_queue_lock);
04066    ast_mutex_destroy(&e->cmd_queue_lock);
04067    ast_free(e);
04068 }

static void destroy_gateway ( struct mgcp_gateway g  )  [static]

Definition at line 4070 of file chan_mgcp.c.

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

Referenced by prune_gateways().

04071 {
04072    if (g->ha)
04073       ast_free_ha(g->ha);
04074 
04075    dump_queue(g, NULL);
04076 
04077    ast_free(g);
04078 }

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

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

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

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

dump_cmd_queues: (SC:) cleanup pending commands

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

02405 {
02406    struct mgcp_request *t, *q;
02407 
02408    if (p) {
02409       ast_mutex_lock(&p->rqnt_queue_lock);
02410       for (q = p->rqnt_queue; q; t = q->next, ast_free(q), q=t);
02411       p->rqnt_queue = NULL;
02412       ast_mutex_unlock(&p->rqnt_queue_lock);
02413 
02414       ast_mutex_lock(&p->cmd_queue_lock);
02415       for (q = p->cmd_queue; q; t = q->next, ast_free(q), q=t);
02416       p->cmd_queue = NULL;
02417       ast_mutex_unlock(&p->cmd_queue_lock);
02418 
02419       ast_mutex_lock(&p->sub->cx_queue_lock);
02420       for (q = p->sub->cx_queue; q; t = q->next, ast_free(q), q=t);
02421       p->sub->cx_queue = NULL;
02422       ast_mutex_unlock(&p->sub->cx_queue_lock);
02423 
02424       ast_mutex_lock(&p->sub->next->cx_queue_lock);
02425       for (q = p->sub->next->cx_queue; q; t = q->next, ast_free(q), q=t);
02426       p->sub->next->cx_queue = NULL;
02427       ast_mutex_unlock(&p->sub->next->cx_queue_lock);
02428    } else if (sub) {
02429       ast_mutex_lock(&sub->cx_queue_lock);
02430       for (q = sub->cx_queue; q; t = q->next, ast_free(q), q=t);
02431       sub->cx_queue = NULL;
02432       ast_mutex_unlock(&sub->cx_queue_lock);
02433    }
02434 }

static void dump_queue ( struct mgcp_gateway gw,
struct mgcp_endpoint p 
) [static]

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

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

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

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

03275 {
03276    int seqno=0;
03277    time_t now;
03278    struct mgcp_response *prev = NULL, *cur, *next, *answer=NULL;
03279    time(&now);
03280    if (sscanf(req->identifier, "%30d", &seqno) != 1) 
03281       seqno = 0;
03282    cur = sub->parent->parent->responses;
03283    while(cur) {
03284       next = cur->next;
03285       if (now - cur->whensent > RESPONSE_TIMEOUT) {
03286          /* Delete this entry */
03287          if (prev)
03288             prev->next = next;
03289          else
03290             sub->parent->parent->responses = next;
03291          ast_free(cur);
03292       } else {
03293          if (seqno == cur->seqno)
03294             answer = cur;
03295          prev = cur;
03296       }
03297       cur = next;
03298    }
03299    if (answer) {
03300       resend_response(sub, answer);
03301       return 1;
03302    }
03303    return 0;
03304 }

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 2438 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 agi_handle_command(), ast_agi_register(), handle_cli_agi_show(), and handle_response().

02440 {
02441    struct mgcp_request *prev, *req;
02442 
02443    ast_mutex_lock(l);
02444    for (prev = NULL, req = *queue; req; prev = req, req = req->next) {
02445       if (req->trid == ident) {
02446          /* remove from queue */
02447          if (!prev)
02448             *queue = req->next;
02449          else
02450             prev->next = req->next;
02451 
02452          /* send next pending command */
02453          if (*queue) {
02454             if (mgcpdebug) {
02455                ast_verbose("Posting Queued Request:\n%s to %s:%d\n", (*queue)->data, 
02456                   ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
02457             }
02458 
02459             mgcp_postrequest(p, sub, (*queue)->data, (*queue)->len, (*queue)->trid);
02460          }
02461          break;
02462       }
02463    }
02464    ast_mutex_unlock(l);
02465    return req;
02466 }

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

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

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

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

get_csv: (SC:) get comma separated value

Definition at line 1620 of file chan_mgcp.c.

References s.

Referenced by handle_response().

01621 {
01622    char *s;
01623 
01624    *next = NULL, *len = 0;
01625    if (!c) return NULL;
01626 
01627    while (*c && (*c < 33 || *c == ','))
01628       c++;
01629 
01630    s = c;
01631    while (*c && (*c >= 33 && *c != ','))
01632       c++, (*len)++;
01633    *next = c;
01634 
01635    if (*len == 0)
01636       s = NULL, *next = NULL;
01637 
01638    return s;
01639 }

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

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

Definition at line 1565 of file chan_mgcp.c.

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

Referenced by process_sdp().

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

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

Definition at line 1555 of file chan_mgcp.c.

Referenced by get_sdp(), and get_sdp_iterate().

01556 {
01557    if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') {
01558       char* r = line + nameLen + 1;
01559       while (*r && (*r < 33)) ++r;
01560       return r;
01561    }
01562    return "";
01563 }

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

Definition at line 1583 of file chan_mgcp.c.

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

Referenced by get_ip_and_port_from_sdp(), get_sdp(), and process_sdp().

01584 {
01585    int len = strlen(name);
01586    char *r;
01587    while (*iterator < req->lines) {
01588       r = get_sdp_by_line(req->line[(*iterator)++], name, len);
01589       if (r[0] != '\0') return r;
01590    }
01591    return "";
01592 }

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

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

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

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

Definition at line 1086 of file chan_mgcp.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, mgcp_gateway::endpoints, ast_cli_args::fd, gatelock, gateways, mgcp_endpoint::name, mgcp_gateway::name, mgcp_gateway::next, mgcp_endpoint::next, transmit_audit_endpoint(), and ast_cli_entry::usage.

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

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

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

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

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

Definition at line 1040 of file chan_mgcp.c.

References mgcp_gateway::addr, ast_cli_args::argc, ast_cli(), ast_inet_ntoa(), ast_mutex_lock(), ast_mutex_unlock(), mgcp_endpoint::chanvars, 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, ast_variable::name, mgcp_endpoint::name, mgcp_gateway::name, mgcp_gateway::next, mgcp_endpoint::next, ast_variable::next, mgcp_subchannel::owner, mgcp_endpoint::sub, ast_cli_entry::usage, and ast_variable::value.

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

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

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

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

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 2469 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 handle_incoming(), mgcpsock_read(), and retrans_pkt().

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

static int has_voicemail ( struct mgcp_endpoint p  )  [static]

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

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

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

Definition at line 2002 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 initreqprep(), reqprep(), and transmit_register().

02003 {
02004    /* Initialize a response */
02005    if (req->headers || req->len) {
02006       ast_log(LOG_WARNING, "Request already initialized?!?\n");
02007       return -1;
02008    }
02009    req->header[req->headers] = req->data + req->len;
02010    /* check if we need brackets around the gw name */
02011    if (p->parent->isnamedottedip)
02012       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);
02013    else
02014       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);
02015    req->len += strlen(req->header[req->headers]);
02016    if (req->headers < MGCP_MAX_HEADERS)
02017       req->headers++;
02018    else
02019       ast_log(LOG_WARNING, "Out of header space\n");
02020    return 0;
02021 }

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

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

01986 {
01987    /* Initialize a response */
01988    if (req->headers || req->len) {
01989       ast_log(LOG_WARNING, "Request already initialized?!?\n");
01990       return -1;
01991    }
01992    req->header[req->headers] = req->data + req->len;
01993    snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %s %s\r\n", resp, orig->identifier, resprest);
01994    req->len += strlen(req->header[req->headers]);
01995    if (req->headers < MGCP_MAX_HEADERS)
01996       req->headers++;
01997    else
01998       ast_log(LOG_WARNING, "Out of header space\n");
01999    return 0;
02000 }

static int load_module ( void   )  [static]

load_module: PBX load module - initialization ---

Definition at line 4335 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_glue_register, io_context_create(), io_context_destroy(), LOG_ERROR, LOG_WARNING, reload_config(), restart_monitor(), sched_context_create(), and sched_context_destroy().

04336 {
04337    if (!(sched = sched_context_create())) {
04338       ast_log(LOG_WARNING, "Unable to create schedule context\n");
04339       return AST_MODULE_LOAD_FAILURE;
04340    }
04341 
04342    if (!(io = io_context_create())) {
04343       ast_log(LOG_WARNING, "Unable to create I/O context\n");
04344       sched_context_destroy(sched);
04345       return AST_MODULE_LOAD_FAILURE;
04346    }
04347 
04348    if (reload_config(0))
04349       return AST_MODULE_LOAD_DECLINE;
04350 
04351    /* Make sure we can register our mgcp channel type */
04352    if (ast_channel_register(&mgcp_tech)) {
04353       ast_log(LOG_ERROR, "Unable to register channel class 'MGCP'\n");
04354       io_context_destroy(io);
04355       sched_context_destroy(sched);
04356       return AST_MODULE_LOAD_FAILURE;
04357    }
04358 
04359    ast_rtp_glue_register(&mgcp_rtp_glue);
04360    ast_cli_register_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
04361    
04362    /* And start the monitor for the first time */
04363    restart_monitor();
04364 
04365    return AST_MODULE_LOAD_SUCCESS;
04366 }

static int mgcp_answer ( struct ast_channel ast  )  [static]

Definition at line 1186 of file chan_mgcp.c.

References ast_channel::_state, ast_debug, ast_mutex_lock(), ast_mutex_unlock(), ast_setstate(), AST_STATE_UP, ast_verb, mgcp_subchannel::cxmode, mgcp_subchannel::id, mgcp_subchannel::lock, MGCP_CX_SENDRECV, mgcp_gateway::name, mgcp_endpoint::name, ast_channel::name, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_subchannel::rtp, start_rtp(), ast_channel::tech_pvt, transmit_modify_request(), and transmit_notify_request().

01187 {
01188    int res = 0;
01189    struct mgcp_subchannel *sub = ast->tech_pvt;
01190    struct mgcp_endpoint *p = sub->parent;
01191 
01192    ast_mutex_lock(&sub->lock);
01193    sub->cxmode = MGCP_CX_SENDRECV;
01194    if (!sub->rtp) {
01195       start_rtp(sub);
01196    } else {
01197       transmit_modify_request(sub);
01198    }
01199    ast_verb(3, "MGCP mgcp_answer(%s) on %s@%s-%d\n",
01200          ast->name, p->name, p->parent->name, sub->id);
01201    if (ast->_state != AST_STATE_UP) {
01202       ast_setstate(ast, AST_STATE_UP);
01203       ast_debug(1, "mgcp_answer(%s)\n", ast->name);
01204       transmit_notify_request(sub, "");
01205       transmit_modify_request(sub);
01206    }
01207    ast_mutex_unlock(&sub->lock);
01208    return res;
01209 }

static int mgcp_call ( struct ast_channel ast,
char *  dest,
int  timeout 
) [static]

Definition at line 846 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::connected, mgcp_subchannel::cxident, mgcp_subchannel::cxmode, ast_var_t::entries, mgcp_endpoint::hookstate, ast_party_connected_line::id, mgcp_subchannel::lock, LOG_NOTICE, LOG_WARNING, MGCP_CX_RECVONLY, MGCP_CX_SENDRECV, MGCP_OFFHOOK, MGCP_ONHOOK, ast_party_id::name, ast_channel::name, mgcp_subchannel::next, ast_party_id::number, 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.

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

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

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

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

Definition at line 1282 of file chan_mgcp.c.

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

01283 {
01284    struct mgcp_subchannel *sub = newchan->tech_pvt;
01285 
01286    ast_mutex_lock(&sub->lock);
01287    ast_log(LOG_NOTICE, "mgcp_fixup(%s, %s)\n", oldchan->name, newchan->name);
01288    if (sub->owner != oldchan) {
01289       ast_mutex_unlock(&sub->lock);
01290       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
01291       return -1;
01292    }
01293    sub->owner = newchan;
01294    ast_mutex_unlock(&sub->lock);
01295    return 0;
01296 }

static enum ast_rtp_glue_result mgcp_get_rtp_peer ( struct ast_channel chan,
struct ast_rtp_instance **  instance 
) [static]

Definition at line 3986 of file chan_mgcp.c.

References ao2_ref, AST_RTP_GLUE_RESULT_FORBID, AST_RTP_GLUE_RESULT_LOCAL, AST_RTP_GLUE_RESULT_REMOTE, mgcp_endpoint::directmedia, mgcp_subchannel::parent, mgcp_subchannel::rtp, and ast_channel::tech_pvt.

03987 {
03988    struct mgcp_subchannel *sub = NULL;
03989 
03990    if (!(sub = chan->tech_pvt) || !(sub->rtp))
03991       return AST_RTP_GLUE_RESULT_FORBID;
03992 
03993    *instance = sub->rtp ? ao2_ref(sub->rtp, +1), sub->rtp : NULL;
03994 
03995    if (sub->parent->directmedia)
03996       return AST_RTP_GLUE_RESULT_REMOTE;
03997    else
03998       return AST_RTP_GLUE_RESULT_LOCAL;
03999 }

static int mgcp_hangup ( struct ast_channel ast  )  [static]

Definition at line 939 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_instance_destroy(), ast_strlen_zero(), ast_verb, mgcp_subchannel::callid, mgcp_endpoint::callwaiting, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, mgcp_subchannel::cxident, mgcp_subchannel::cxmode, mgcp_endpoint::dsp, mgcp_endpoint::dtmf_buf, mgcp_endpoint::dtmfmode, has_voicemail(), mgcp_endpoint::hascallwaiting, mgcp_endpoint::hidecallerid, mgcp_endpoint::hookstate, mgcp_subchannel::lock, mgcp_subchannel::magic, MGCP_CX_INACTIVE, MGCP_CX_RECVONLY, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, MGCP_OFFHOOK, MGCP_ONHOOK, MGCP_SUBCHANNEL_MAGIC, mgcp_gateway::name, mgcp_endpoint::name, ast_channel::name, mgcp_subchannel::next, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_subchannel::rtp, mgcp_endpoint::sub, ast_channel::tech_pvt, mgcp_subchannel::tmpdest, transmit_connection_del(), transmit_modify_request(), transmit_notify_request(), and transmit_notify_request_with_callerid().

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

static int mgcp_indicate ( struct ast_channel ast,
int  ind,
const void *  data,
size_t  datalen 
) [static]

Definition at line 1435 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_instance_new_source(), ast_verb, control2str(), mgcp_subchannel::lock, LOG_WARNING, ast_channel::name, mgcp_subchannel::rtp, ast_channel::tech_pvt, and transmit_notify_request().

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

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

Definition at line 1479 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_get_encoded_str(), ast_hangup(), ast_jb_configure(), ast_log(), ast_module_ref(), ast_pbx_start(), ast_rtp_instance_fd(), ast_state2str(), AST_STATE_DOWN, AST_STATE_RING, ast_strdup, ast_string_field_set, ast_strlen_zero(), ast_verb, mgcp_endpoint::call_forward, mgcp_endpoint::callgroup, ast_channel::callgroup, mgcp_endpoint::capability, mgcp_endpoint::chanvars, ast_channel::cid, ast_callerid::cid_ani, mgcp_endpoint::cid_name, mgcp_endpoint::cid_num, ast_channel::context, mgcp_endpoint::context, mgcp_endpoint::dsp, DSP_DIGITMODE_NOQUELCH, DSP_FEATURE_DIGIT_DETECT, mgcp_endpoint::dtmfmode, ast_channel::exten, mgcp_endpoint::exten, global_jbconf, mgcp_subchannel::id, mgcp_endpoint::language, LOG_WARNING, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, ast_channel::name, ast_variable::name, mgcp_gateway::name, mgcp_endpoint::name, ast_channel::nativeformats, ast_variable::next, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_subchannel::parent, pbx_builtin_setvar_helper(), 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, ast_variable::value, and ast_channel::writeformat.

Referenced by handle_hd_hf(), and mgcp_request().

01480 {
01481    struct ast_channel *tmp;
01482    struct ast_variable *v = NULL;
01483    struct mgcp_endpoint *i = sub->parent;
01484    int fmt;
01485 
01486    tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, linkedid, i->accountcode, i->exten, i->context, i->amaflags, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id);
01487    if (tmp) {
01488       tmp->tech = &mgcp_tech;
01489       tmp->nativeformats = i->capability;
01490       if (!tmp->nativeformats)
01491          tmp->nativeformats = capability;
01492       fmt = ast_best_codec(tmp->nativeformats);
01493       if (sub->rtp)
01494          ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0));
01495       if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) {
01496          i->dsp = ast_dsp_new();
01497          ast_dsp_set_features(i->dsp, DSP_FEATURE_DIGIT_DETECT);
01498          /* this is to prevent clipping of dtmf tones during dsp processing */
01499          ast_dsp_set_digitmode(i->dsp, DSP_DIGITMODE_NOQUELCH);
01500       } else {
01501          i->dsp = NULL;
01502       }
01503       if (state == AST_STATE_RING)
01504          tmp->rings = 1;
01505       tmp->writeformat = fmt;
01506       tmp->rawwriteformat = fmt;
01507       tmp->readformat = fmt;
01508       tmp->rawreadformat = fmt;
01509       tmp->tech_pvt = sub;
01510       if (!ast_strlen_zero(i->language))
01511          ast_string_field_set(tmp, language, i->language);
01512       if (!ast_strlen_zero(i->accountcode))
01513          ast_string_field_set(tmp, accountcode, i->accountcode);
01514       if (i->amaflags)
01515          tmp->amaflags = i->amaflags;
01516       sub->owner = tmp;
01517       ast_module_ref(ast_module_info->self);
01518       tmp->callgroup = i->callgroup;
01519       tmp->pickupgroup = i->pickupgroup;
01520       ast_string_field_set(tmp, call_forward, i->call_forward);
01521       ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
01522       ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
01523 
01524       /* Don't use ast_set_callerid() here because it will
01525        * generate a needless NewCallerID event */
01526       tmp->cid.cid_ani = ast_strdup(i->cid_num);
01527       
01528       if (!i->adsi)
01529          tmp->adsicpe = AST_ADSI_UNAVAILABLE;
01530       tmp->priority = 1;
01531 
01532       /* Set channel variables for this call from configuration */
01533       for (v = i->chanvars ; v ; v = v->next) {
01534          char valuebuf[1024];
01535          pbx_builtin_setvar_helper(tmp, v->name, ast_get_encoded_str(v->value, valuebuf, sizeof(valuebuf)));
01536       }
01537 
01538       if (sub->rtp)
01539          ast_jb_configure(tmp, &global_jbconf);
01540       if (state != AST_STATE_DOWN) {
01541          if (ast_pbx_start(tmp)) {
01542             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
01543             ast_hangup(tmp);
01544             tmp = NULL;
01545          }
01546       }
01547       ast_verb(3, "MGCP mgcp_new(%s) created in state: %s\n",
01548             tmp->name, ast_state2str(state));
01549    } else {
01550       ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
01551    }
01552    return tmp;
01553 }

static int mgcp_postrequest ( struct mgcp_endpoint p,
struct mgcp_subchannel sub,
char *  data,
int  len,
unsigned int  seqno 
) [static]

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

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

static void mgcp_queue_control ( struct mgcp_subchannel sub,
int  control 
) [static]

Definition at line 627 of file chan_mgcp.c.

References AST_FRAME_CONTROL, mgcp_queue_frame(), and ast_frame::subclass.

Referenced by handle_hd_hf().

00628 {
00629    struct ast_frame f = { AST_FRAME_CONTROL, };
00630    f.subclass = control;
00631    return mgcp_queue_frame(sub, &f);
00632 }

static void mgcp_queue_frame ( struct mgcp_subchannel sub,
struct ast_frame f 
) [static]

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

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

static void mgcp_queue_hangup ( struct mgcp_subchannel sub  )  [static]

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

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

static struct ast_frame * mgcp_read ( struct ast_channel ast  )  [static, read]

Definition at line 1242 of file chan_mgcp.c.

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

01243 {
01244    struct ast_frame *f;
01245    struct mgcp_subchannel *sub = ast->tech_pvt;
01246    ast_mutex_lock(&sub->lock);
01247    f = mgcp_rtp_read(sub);
01248    ast_mutex_unlock(&sub->lock);
01249    return f;
01250 }

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

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

04369 {
04370    static int deprecated = 0;
04371 
04372    if (e) {
04373       switch (cmd) {
04374       case CLI_INIT:
04375          e->command = "mgcp reload";
04376          e->usage =
04377             "Usage: mgcp reload\n"
04378             "       'mgcp reload' is deprecated.  Please use 'reload chan_mgcp.so' instead.\n";
04379          return NULL;
04380       case CLI_GENERATE:
04381          return NULL;
04382       }
04383    }
04384 
04385    if (!deprecated && a && a->argc > 0) {
04386       ast_log(LOG_WARNING, "'mgcp reload' is deprecated.  Please use 'reload chan_mgcp.so' instead.\n");
04387       deprecated = 1;
04388    }
04389 
04390    ast_mutex_lock(&mgcp_reload_lock);
04391    if (mgcp_reloading) {
04392       ast_verbose("Previous mgcp reload not yet done\n");
04393    } else
04394       mgcp_reloading = 1;
04395    ast_mutex_unlock(&mgcp_reload_lock);
04396    restart_monitor();
04397    return CLI_SUCCESS;
04398 }

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

Definition at line 3510 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, ast_channel::linkedid, 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().

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

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

Definition at line 1211 of file chan_mgcp.c.

References ast_debug, ast_dsp_process(), AST_FRAME_DTMF, AST_FRAME_VOICE, ast_log(), ast_null_frame, ast_rtp_instance_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().

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

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

Definition at line 1298 of file chan_mgcp.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_rtp_instance_dtmf_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.

01299 {
01300    struct mgcp_subchannel *sub = ast->tech_pvt;
01301    struct mgcp_endpoint *p = sub->parent;
01302    int res = 0;
01303 
01304    ast_mutex_lock(&sub->lock);
01305    if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
01306       ast_log(LOG_DEBUG, "Sending DTMF using inband/hybrid\n");
01307       res = -1; /* Let asterisk play inband indications */
01308    } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
01309       ast_log(LOG_DEBUG, "Sending DTMF using RFC2833");
01310       ast_rtp_instance_dtmf_begin(sub->rtp, digit);
01311    } else {
01312       ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
01313    }
01314    ast_mutex_unlock(&sub->lock);
01315 
01316    return res;
01317 }

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

Definition at line 1319 of file chan_mgcp.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_rtp_instance_dtmf_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().

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

static int mgcp_set_rtp_peer ( struct ast_channel chan,
struct ast_rtp_instance rtp,
struct ast_rtp_instance vrtp,
struct ast_rtp_instance trtp,
int  codecs,
int  nat_active 
) [static]

Definition at line 4001 of file chan_mgcp.c.

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

04002 {
04003    /* XXX Is there such thing as video support with MGCP? XXX */
04004    struct mgcp_subchannel *sub;
04005    sub = chan->tech_pvt;
04006    if (sub && !sub->alreadygone) {
04007       transmit_modify_with_sdp(sub, rtp, codecs);
04008       return 0;
04009    }
04010    return -1;
04011 }

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

Definition at line 2649 of file chan_mgcp.c.

References ast_bridged_channel(), ast_canmatch_extension(), ast_copy_string(), ast_db_put(), ast_debug, ast_exists_extension(), ast_hangup(), ast_ignore_pattern(), ast_indicate(), ast_log(), ast_masq_park_call(), ast_matchmore_extension(), AST_MAX_EXTENSION, ast_parking_ext(), ast_pbx_run(), ast_pickup_call(), ast_pickup_ext(), ast_safe_sleep(), ast_say_digit_str(), ast_set_callerid(), ast_setstate(), AST_STATE_RING, ast_strlen_zero(), ast_verb, ast_waitfordigit(), mgcp_endpoint::call_forward, mgcp_endpoint::callreturn, mgcp_endpoint::callwaiting, mgcp_endpoint::cancallforward, chan, ast_channel::cid, ast_callerid::cid_ani, mgcp_endpoint::cid_name, ast_callerid::cid_num, mgcp_endpoint::cid_num, ast_channel::context, mgcp_endpoint::dnd, mgcp_endpoint::dtmf_buf, mgcp_endpoint::dtmfmode, exten, ast_channel::exten, mgcp_endpoint::hascallwaiting, mgcp_endpoint::hidecallerid, ast_channel::language, mgcp_endpoint::lastcallerid, len(), LOG_WARNING, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, ast_channel::name, mgcp_subchannel::next, mgcp_subchannel::owner, mgcp_subchannel::parent, ast_channel::rings, start_rtp(), ast_channel::tech_pvt, and transmit_notify_request().

Referenced by handle_hd_hf().

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

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

Definition at line 1252 of file chan_mgcp.c.

References AST_FRAME_IMAGE, AST_FRAME_VOICE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_rtp_instance_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.

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

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

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

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

static void mwi_event_cb ( const struct ast_event event,
void *  userdata 
) [static]

Definition at line 457 of file chan_mgcp.c.

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

static void parse ( struct mgcp_request req  )  [static]

Definition at line 1753 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_jabberreceive_read(), acf_meetme_info(), add_agent(), app_exec(), aqm_exec(), ast_parse_allow_disallow(), astman_get_variables(), celgenuserevent_exec(), chanspy_exec(), conf_run(), confbridge_exec(), config_function_read(), cut_internal(), dial_exec_full(), dictate_exec(), directory_exec(), dundi_query_read(), dundi_result_read(), dundifunc_read(), enum_query_read(), enum_result_read(), execif_exec(), extenspy_exec(), find_conf(), function_agent(), get_in_brackets(), handle_statechange(), iconv_read(), isAnsweringMachine(), isexten_function_read(), log_exec(), login_exec(), mgcpsock_read(), mixmonitor_exec(), originate_exec(), oss_call(), oss_request(), page_exec(), park_call_exec(), pbx_builtin_answer(), pbx_builtin_background(), pbx_builtin_waitexten(), play_moh_exec(), pqm_exec(), privacy_exec(), ql_exec(), queue_exec(), rcvfax_exec(), record_exec(), reload_single_member(), retrydial_exec(), rqm_exec(), sayunixtime_exec(), sendtext_exec(), sla_trunk_exec(), smdi_msg_read(), smdi_msg_retrieve_read(), sms_exec(), sndfax_exec(), softhangup_exec(), speech_background(), start_moh_exec(), start_monitor_exec(), transfer_exec(), upqm_exec(), userevent_exec(), verbose_exec(), vm_execmain(), and zapateller_exec().

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

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

Definition at line 1854 of file chan_mgcp.c.

References ast_gethostbyname(), ast_inet_ntoa(), ast_log(), ast_rtp_codecs_payload_formats(), ast_rtp_codecs_payloads_clear(), ast_rtp_codecs_payloads_set_m_type(), ast_rtp_codecs_payloads_set_rtpmap_type(), ast_rtp_instance_get_codecs(), ast_rtp_instance_set_remote_address(), 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_incoming(), handle_request_invite(), handle_response(), and handle_response_invite().

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

static void prune_gateways ( void   )  [static]

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

04081 {
04082    struct mgcp_gateway *g, *z, *r;
04083    struct mgcp_endpoint *e, *p, *t;
04084 
04085    ast_mutex_lock(&gatelock);
04086 
04087    /* prune gateways */
04088    for (z = NULL, g = gateways; g;) {
04089       /* prune endpoints */
04090       for (p = NULL, e = g->endpoints; e; ) {
04091          if (e->delme || g->delme) {
04092             t = e;
04093             e = e->next;
04094             if (!p)
04095                g->endpoints = e;
04096             else
04097                p->next = e;
04098             destroy_endpoint(t);
04099          } else {
04100             p = e;
04101             e = e->next;
04102          }
04103       }
04104 
04105       if (g->delme) {
04106          r = g;
04107          g = g->next;
04108          if (!z)
04109             gateways = g;
04110          else
04111             z->next = g;
04112 
04113          destroy_gateway(r);
04114       } else {
04115          z = g;
04116          g = g->next;
04117       }
04118    }
04119 
04120    ast_mutex_unlock(&gatelock);
04121 }

static int reload ( void   )  [static]

Definition at line 4400 of file chan_mgcp.c.

References mgcp_reload().

04401 {
04402    mgcp_reload(NULL, 0, NULL);
04403    return 0;
04404 }

static int reload_config ( int  reload  )  [static]

Definition at line 4155 of file chan_mgcp.c.

References __ourip, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_getformatbyname(), ast_gethostbyname(), ast_inet_ntoa(), ast_io_remove(), ast_io_wait(), ast_jb_read_conf(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_netsock_set_qos(), ast_sched_runq(), ast_str2cos(), ast_str2tos(), ast_variable_browse(), ast_verb, bindaddr, build_gateway(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_MGCP_CA_PORT, mgcp_endpoint::delme, mgcp_gateway::delme, mgcp_gateway::endpoints, errno, format, gatelock, gateways, global_jbconf, hp, ast_variable::lineno, LOG_ERROR, LOG_NOTICE, LOG_WARNING, mgcp_endpoint::name, mgcp_gateway::name, ast_variable::name, mgcp_endpoint::needaudit, netlock, mgcp_gateway::next, mgcp_endpoint::next, ast_variable::next, prune_gateways(), qos, transmit_audit_endpoint(), and ast_variable::value.

04156 {
04157    struct ast_config *cfg;
04158    struct ast_variable *v;
04159    struct mgcp_gateway *g;
04160    struct mgcp_endpoint *e;
04161    char *cat;
04162    struct ast_hostent ahp;
04163    struct hostent *hp;
04164    int format;
04165    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
04166    
04167    if (gethostname(ourhost, sizeof(ourhost)-1)) {
04168       ast_log(LOG_WARNING, "Unable to get hostname, MGCP disabled\n");
04169       return 0;
04170    }
04171    cfg = ast_config_load(config, config_flags);
04172 
04173    /* We *must* have a config file otherwise stop immediately */
04174    if (!cfg) {
04175       ast_log(LOG_NOTICE, "Unable to load config %s, MGCP disabled\n", config);
04176       return 0;
04177    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
04178       return 0;
04179    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
04180       ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", config);
04181       return 0;
04182    }
04183 
04184    memset(&bindaddr, 0, sizeof(bindaddr));
04185    dtmfmode = 0;
04186 
04187    /* Copy the default jb config over global_jbconf */
04188    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
04189 
04190    v = ast_variable_browse(cfg, "general");
04191    while (v) {
04192       /* handle jb conf */
04193       if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
04194          v = v->next;
04195          continue;
04196       }
04197 
04198       /* Create the interface list */
04199       if (!strcasecmp(v->name, "bindaddr")) {
04200          if (!(hp = ast_gethostbyname(v->value, &ahp))) {
04201             ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
04202          } else {
04203             memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
04204          }
04205       } else if (!strcasecmp(v->name, "allow")) {
04206          format = ast_getformatbyname(v->value);
04207          if (format < 1) 
04208             ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
04209          else
04210             capability |= format;
04211       } else if (!strcasecmp(v->name, "disallow")) {
04212          format = ast_getformatbyname(v->value);
04213          if (format < 1) 
04214             ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
04215          else
04216             capability &= ~format;
04217       } else if (!strcasecmp(v->name, "tos")) {
04218          if (ast_str2tos(v->value, &qos.tos))
04219              ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
04220       } else if (!strcasecmp(v->name, "tos_audio")) {
04221          if (ast_str2tos(v->value, &qos.tos_audio))
04222              ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);
04223       } else if (!strcasecmp(v->name, "cos")) {          
04224          if (ast_str2cos(v->value, &qos.cos))
04225              ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno);
04226       } else if (!strcasecmp(v->name, "cos_audio")) {          
04227          if (ast_str2cos(v->value, &qos.cos_audio))
04228              ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);
04229       } else if (!strcasecmp(v->name, "port")) {
04230          if (sscanf(v->value, "%5d", &ourport) == 1) {
04231             bindaddr.sin_port = htons(ourport);
04232          } else {
04233             ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
04234          }
04235       }
04236       v = v->next;
04237    }
04238 
04239    /* mark existing entries for deletion */
04240    ast_mutex_lock(&gatelock);
04241    g = gateways;
04242    while (g) {
04243       g->delme = 1;
04244       e = g->endpoints;
04245       while (e) {
04246          e->delme = 1;
04247          e = e->next;
04248       }
04249       g = g->next;
04250    }
04251    ast_mutex_unlock(&gatelock);
04252    
04253    cat = ast_category_browse(cfg, NULL);
04254    while(cat) {
04255       if (strcasecmp(cat, "general")) {
04256          ast_mutex_lock(&gatelock);
04257          g = build_gateway(cat, ast_variable_browse(cfg, cat));
04258          if (g) {
04259             ast_verb(3, "Added gateway '%s'\n", g->name);
04260             g->next = gateways;
04261             gateways = g;
04262          }
04263          ast_mutex_unlock(&gatelock);
04264 
04265          /* FS: process queue and IO */
04266          if (monitor_thread == pthread_self()) {
04267             if (sched) ast_sched_runq(sched);
04268             if (io) ast_io_wait(io, 10);
04269          }
04270       }
04271       cat = ast_category_browse(cfg, cat);
04272    }
04273 
04274       /* prune deleted entries etc. */
04275       prune_gateways();
04276 
04277    if (ntohl(bindaddr.sin_addr.s_addr)) {
04278       memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
04279    } else {
04280       hp = ast_gethostbyname(ourhost, &ahp);
04281       if (!hp) {
04282          ast_log(LOG_WARNING, "Unable to get our IP address, MGCP disabled\n");
04283          ast_config_destroy(cfg);
04284          return 0;
04285       }
04286       memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
04287    }
04288    if (!ntohs(bindaddr.sin_port))
04289       bindaddr.sin_port = ntohs(DEFAULT_MGCP_CA_PORT);
04290    bindaddr.sin_family = AF_INET;
04291    ast_mutex_lock(&netlock);
04292    if (mgcpsock > -1)
04293       close(mgcpsock);
04294 
04295    if (mgcpsock_read_id != NULL)
04296       ast_io_remove(io, mgcpsock_read_id);
04297    mgcpsock_read_id = NULL;
04298 
04299    mgcpsock = socket(AF_INET, SOCK_DGRAM, 0);
04300    if (mgcpsock < 0) {
04301       ast_log(LOG_WARNING, "Unable to create MGCP socket: %s\n", strerror(errno));
04302    } else {
04303       if (bind(mgcpsock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
04304          ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
04305             ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
04306                strerror(errno));
04307          close(mgcpsock);
04308          mgcpsock = -1;
04309       } else {
04310          ast_verb(2, "MGCP Listening on %s:%d\n",
04311                ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
04312          ast_netsock_set_qos(mgcpsock, qos.tos, qos.cos, "MGCP");
04313       }
04314    }
04315    ast_mutex_unlock(&netlock);
04316    ast_config_destroy(cfg);
04317 
04318    /* send audit only to the new endpoints */
04319    g = gateways;
04320    while (g) {
04321       e = g->endpoints;
04322       while (e && e->needaudit) {
04323          e->needaudit = 0;
04324          transmit_audit_endpoint(e);
04325          ast_verb(3, "MGCP Auditing endpoint %s@%s for hookstate\n", e->name, g->name);
04326          e = e->next;
04327       }
04328       g = g->next;
04329    }
04330 
04331    return 0;
04332 }

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

static int resend_response ( struct mgcp_subchannel sub,
struct mgcp_response resp 
) [static]

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

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

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

static int restart_monitor ( void   )  [static]

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

03482 {
03483    /* If we're supposed to be stopped -- stay stopped */
03484    if (monitor_thread == AST_PTHREADT_STOP)
03485       return 0;
03486    if (ast_mutex_lock(&monlock)) {
03487       ast_log(LOG_WARNING, "Unable to lock monitor\n");
03488       return -1;
03489    }
03490    if (monitor_thread == pthread_self()) {
03491       ast_mutex_unlock(&monlock);
03492       ast_log(LOG_WARNING, "Cannot kill myself\n");
03493       return -1;
03494    }
03495    if (monitor_thread != AST_PTHREADT_NULL) {
03496       /* Wake up the thread */
03497       pthread_kill(monitor_thread, SIGURG);
03498    } else {
03499       /* Start a new monitor */
03500       if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
03501          ast_mutex_unlock(&monlock);
03502          ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
03503          return -1;
03504       }
03505    }
03506    ast_mutex_unlock(&monlock);
03507    return 0;
03508 }

static int retrans_pkt ( const void *  data  )  [static]

Definition at line 634 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 __sip_reliable_xmit(), mgcp_postrequest(), and sip_show_sched().

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

static void sdpLineNum_iterator_init ( int *  iterator  )  [static]

Definition at line 1578 of file chan_mgcp.c.

Referenced by process_sdp().

01579 {
01580    *iterator = 0;
01581 }

static int send_request ( struct mgcp_endpoint p,
struct mgcp_subchannel sub,
struct mgcp_request req,
unsigned int  seqno 
) [static]

Definition at line 761 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_info_with_digit(), transmit_info_with_vidupdate(), transmit_invite(), transmit_message_with_text(), transmit_modify_request(), transmit_modify_with_sdp(), transmit_notify_request(), transmit_notify_request_with_callerid(), transmit_notify_with_mwi(), transmit_notify_with_sipfrag(), transmit_refer(), transmit_register(), transmit_reinvite_with_sdp(), transmit_request(), transmit_request_with_auth(), transmit_state_notify(), and update_connectedline().

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

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

static void start_rtp ( struct mgcp_subchannel sub  )  [static]

Definition at line 2626 of file chan_mgcp.c.

References ast_channel_set_fd(), ast_mutex_lock(), ast_mutex_unlock(), ast_random(), ast_rtp_instance_destroy(), ast_rtp_instance_fd(), ast_rtp_instance_new(), ast_rtp_instance_set_prop(), ast_rtp_instance_set_qos(), AST_RTP_PROPERTY_NAT, 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_offhook_message(), handle_response(), handle_soft_key_event_message(), handle_stimulus_message(), HandleCallIncoming(), HandleCallOutgoing(), mgcp_answer(), mgcp_call(), mgcp_ss(), skinny_answer(), skinny_newcall(), and unistim_answer().

02627 {
02628    ast_mutex_lock(&sub->lock);
02629    /* check again to be on the safe side */
02630    if (sub->rtp) {
02631       ast_rtp_instance_destroy(sub->rtp);
02632       sub->rtp = NULL;
02633    }
02634    /* Allocate the RTP now */
02635    sub->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr, NULL);
02636    if (sub->rtp && sub->owner)
02637       ast_channel_set_fd(sub->owner, 0, ast_rtp_instance_fd(sub->rtp, 0));
02638    if (sub->rtp) {
02639       ast_rtp_instance_set_qos(sub->rtp, qos.tos_audio, qos.cos_audio, "MGCP RTP");
02640       ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_NAT, sub->nat);
02641    }
02642    /* Make a call*ID */
02643         snprintf(sub->callid, sizeof(sub->callid), "%08lx%s", ast_random(), sub->txident);
02644    /* Transmit the connection create */
02645    transmit_connect_with_sdp(sub, NULL);
02646    ast_mutex_unlock(&sub->lock);
02647 }

static int transmit_audit_endpoint ( struct mgcp_endpoint p  )  [static]

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

02346 {
02347    struct mgcp_request resp;
02348    reqprep(&resp, p, "AUEP");
02349    /* removed unknown param VS */
02350    /*add_header(&resp, "F", "A,R,D,S,X,N,I,T,O,ES,E,MD,M");*/
02351    add_header(&resp, "F", "A");
02352    /* fill in new fields */
02353    resp.cmd = MGCP_CMD_AUEP;
02354    resp.trid = oseq;
02355    return send_request(p, NULL, &resp, oseq);  /* SC */
02356 }

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

Definition at line 2192 of file chan_mgcp.c.

References add_header(), add_sdp(), ast_copy_string(), AST_FORMAT_AUDIO_MASK, ast_rtp_lookup_mime_subtype2(), 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().

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

static int transmit_connection_del ( struct mgcp_subchannel sub  )  [static]

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

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

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

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

02383 {
02384    struct mgcp_request resp;
02385 
02386    if (mgcpdebug) {
02387       ast_verb(3, "Delete connection %s %s@%s on callid: %s\n",
02388          cxident ? cxident : "", p->name, p->parent->name, callid ? callid : "");
02389    }
02390    reqprep(&resp, p, "DLCX");
02391    /* check if call id is avail */
02392    if (callid && *callid)
02393       add_header(&resp, "C", callid);
02394    /* check if cxident is avail */
02395    if (cxident && *cxident)
02396       add_header(&resp, "I", cxident);
02397    /* fill in new fields */
02398    resp.cmd = MGCP_CMD_DLCX;
02399    resp.trid = oseq;
02400    return send_request(p, p->sub, &resp, oseq);
02401 }

static int transmit_modify_request ( struct mgcp_subchannel sub  )  [static]

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

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

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

Definition at line 2156 of file chan_mgcp.c.

References add_header(), add_sdp(), ast_copy_string(), AST_FORMAT_AUDIO_MASK, ast_rtp_instance_get_remote_address(), ast_rtp_lookup_mime_subtype2(), 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().

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

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

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

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

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

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

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

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

Definition at line 2041 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_button_template_req_message(), handle_incoming(), handle_invite_replaces(), handle_keep_alive_message(), handle_line_state_req_message(), handle_open_receive_channel_ack_message(), handle_register_message(), handle_request(), handle_request_bye(), handle_request_cancel(), handle_request_do(), handle_request_info(), handle_request_invite(), handle_request_message(), handle_request_notify(), handle_request_refer(), handle_request_subscribe(), handle_request_update(), handle_server_request_message(), handle_skinny_reset(), handle_soft_key_set_req_message(), handle_soft_key_template_req_message(), handle_speed_dial_stat_req_message(), handle_time_date_req_message(), handle_version_req_message(), local_attended_transfer(), receive_message(), register_verify(), send_provisional_keepalive_full(), sip_indicate(), sip_park_thread(), sip_sendhtml(), skinny_reload(), skinny_set_rtp_peer(), transmit_activatecallplane(), transmit_callinfo(), transmit_callstate(), transmit_callstateonly(), transmit_cfwdstate(), transmit_closereceivechannel(), transmit_connect(), transmit_dialednumber(), transmit_displaymessage(), transmit_displaynotify(), transmit_displaypromptstatus(), transmit_fake_auth_response(), transmit_lamp_indication(), transmit_provisional_response(), transmit_ringer_mode(), transmit_selectsoftkeys(), transmit_speaker_mode(), transmit_stopmediatransmission(), and transmit_tone().

02042 {
02043    struct mgcp_request resp;
02044    struct mgcp_endpoint *p = sub->parent;
02045    struct mgcp_response *mgr;
02046 
02047    respprep(&resp, p, msg, req, msgrest);
02048    mgr = ast_calloc(1, sizeof(*mgr) + resp.len + 1);
02049    if (mgr) {
02050       /* Store MGCP response in case we have to retransmit */
02051       sscanf(req->identifier, "%30d", &mgr->seqno);
02052       time(&mgr->whensent);
02053       mgr->len = resp.len;
02054       memcpy(mgr->buf, resp.data, resp.len);
02055       mgr->buf[resp.len] = '\0';
02056       mgr->next = p->parent->responses;
02057       p->parent->responses = mgr;
02058    }
02059    return send_response(sub, &resp);
02060 }

static int unalloc_sub ( struct mgcp_subchannel sub  )  [static]

Definition at line 490 of file chan_mgcp.c.

References mgcp_subchannel::alreadygone, ast_debug, ast_log(), ast_rtp_instance_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().

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

static int unload_module ( void   )  [static]

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

04407 {
04408    struct mgcp_endpoint *e;
04409    struct mgcp_gateway *g;
04410 
04411    /* Check to see if we're reloading */
04412    if (ast_mutex_trylock(&mgcp_reload_lock)) {
04413       ast_log(LOG_WARNING, "MGCP is currently reloading.  Unable to remove module.\n");
04414       return -1;
04415    } else {
04416       mgcp_reloading = 1;
04417       ast_mutex_unlock(&mgcp_reload_lock);
04418    }
04419 
04420    /* First, take us out of the channel loop */
04421    ast_channel_unregister(&mgcp_tech);
04422 
04423    /* Shut down the monitoring thread */
04424    if (!ast_mutex_lock(&monlock)) {
04425       if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
04426          pthread_cancel(monitor_thread);
04427          pthread_kill(monitor_thread, SIGURG);
04428          pthread_join(monitor_thread, NULL);
04429       }
04430       monitor_thread = AST_PTHREADT_STOP;
04431       ast_mutex_unlock(&monlock);
04432    } else {
04433       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
04434       /* We always want to leave this in a consistent state */
04435       ast_channel_register(&mgcp_tech);
04436       mgcp_reloading = 0;
04437       mgcp_reload(NULL, 0, NULL);
04438       return -1;
04439    }
04440 
04441    if (!ast_mutex_lock(&gatelock)) {
04442       for (g = gateways; g; g = g->next) {
04443          g->delme = 1;
04444          for (e = g->endpoints; e; e = e->next)
04445             e->delme = 1;
04446       }
04447 
04448       prune_gateways();
04449       ast_mutex_unlock(&gatelock);
04450    } else {
04451       ast_log(LOG_WARNING, "Unable to lock the gateways list.\n");
04452       /* We always want to leave this in a consistent state */
04453       ast_channel_register(&mgcp_tech);
04454       /* Allow the monitor to restart */
04455       monitor_thread = AST_PTHREADT_NULL;
04456       mgcp_reloading = 0;
04457       mgcp_reload(NULL, 0, NULL);
04458       return -1;
04459    }
04460 
04461    close(mgcpsock);
04462    ast_rtp_glue_unregister(&mgcp_rtp_glue);
04463    ast_cli_unregister_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
04464    sched_context_destroy(sched);
04465 
04466    return 0;
04467 }


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

Definition at line 4473 of file chan_mgcp.c.

struct in_addr __ourip [static]

Definition at line 218 of file chan_mgcp.c.

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

struct sockaddr_in bindaddr [static]

Definition at line 406 of file chan_mgcp.c.

int callreturn = 0 [static]

Definition at line 168 of file chan_mgcp.c.

int callwaiting = 0 [static]

Definition at line 166 of file chan_mgcp.c.

int cancallforward = 0 [static]

Definition at line 177 of file chan_mgcp.c.

int capability = AST_FORMAT_ULAW [static]

Definition at line 214 of file chan_mgcp.c.

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

char cid_name[AST_MAX_EXTENSION] = "" [static]

char cid_num[AST_MAX_EXTENSION] = "" [static]

struct ast_cli_entry cli_mgcp[] [static]

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

int directmedia = DIRECTMEDIA [static]

Definition at line 181 of file chan_mgcp.c.

int dtmfmode = 0 [static]

Definition at line 151 of file chan_mgcp.c.

Referenced by set_local_capabilities().

int firstdigittimeout = 16000 [static]

Wait up to 16 seconds for first digit (FXO logic)

Definition at line 194 of file chan_mgcp.c.

ast_mutex_t gatelock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [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.

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.

const char* const mgcp_cxmodes[] [static]

}

Definition at line 123 of file chan_mgcp.c.

ast_mutex_t mgcp_reload_lock = ((ast_mutex_t) PTHREAD_MUTEX_INITIALIZER ) [static]

Definition at line 398 of file chan_mgcp.c.

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

int mgcp_reloading = 0 [static]

Definition at line 399 of file chan_mgcp.c.

struct ast_rtp_glue mgcp_rtp_glue [static]

Initial value:

 {
   .type = "MGCP",
   .get_rtp_info = mgcp_get_rtp_peer,
   .update_peer = mgcp_set_rtp_peer,
}

Definition at line 4013 of file chan_mgcp.c.

struct ast_channel_tech mgcp_tech [static]

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

int* mgcpsock_read_id = NULL [static]

Definition at line 3393 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_MUTEX_INITIALIZER ) [static]

Definition at line 206 of file chan_mgcp.c.

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_MUTEX_INITIALIZER ) [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 config_load(), do_monitor(), handle_request_do(), reload_config(), and unload_module().

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]

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 Wed Oct 28 13:32:06 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6