Sat Feb 11 06:34:37 2012

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 "asterisk/pktccops.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, char *def)
static int __mgcp_xmit (struct mgcp_gateway *gw, char *data, int len)
static void __reg_module (void)
static void __unreg_module (void)
static int acf_channel_read (struct ast_channel *chan, const char *funcname, char *preparse, char *buf, size_t buflen)
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, char *tone)
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_gatewayfind_realtime_gw (char *name, char *at, struct sockaddr_in *sin)
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_alloc_pktcgate (struct mgcp_subchannel *sub)
static int mgcp_answer (struct ast_channel *ast)
static int mgcp_call (struct ast_channel *ast, const char *dest, int timeout)
static int mgcp_devicestate (const char *data)
 mgcp_devicestate: channel callback for device status monitoring
static int mgcp_fixup (struct ast_channel *oldchan, struct ast_channel *newchan)
static void mgcp_get_codec (struct ast_channel *chan, struct ast_format_cap *result)
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_pktcgate_open (struct cops_gate *gate)
static int mgcp_pktcgate_remove (struct cops_gate *gate)
static int mgcp_postrequest (struct mgcp_endpoint *p, struct mgcp_subchannel *sub, char *data, int len, unsigned int seqno)
static int mgcp_prune_realtime_gateway (struct mgcp_gateway *g)
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, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *dest, 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, const struct ast_format_cap *cap, 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 (struct mgcp_subchannel *sub)
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, const struct ast_format_cap *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_LOAD_ORDER , .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, .load_pri = AST_MODPRI_CHANNEL_DRIVER, .nonoptreq = "res_pktccops", }
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 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 = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 }
 gatelock: mutex for gateway/endpoint lists
static struct mgcp_gatewaygateways
static int gendigittimeout = 8000
static struct ast_format_capglobal_capability
static struct ast_jb_conf global_jbconf
static int hangupongateremove = 0
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 = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 }
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 = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 }
static char musicclass [MAX_MUSICCLASS] = ""
static int nat = 0
static int ncs = 0
static ast_mutex_t netlock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 }
static int nonCodecCapability = AST_RTP_DTMF
static unsigned int oseq
static char ourhost [MAXHOSTNAMELEN]
static int ourport
static char parkinglot [AST_MAX_CONTEXT]
static int pktcgatealloc = 0
struct {
   unsigned int   cos
   unsigned int   cos_audio
   unsigned int   tos
   unsigned int   tos_audio
qos
static struct ast_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 89 of file chan_mgcp.c.

#define DEFAULT_MGCP_CA_PORT   2727

From RFC 2705

Definition at line 117 of file chan_mgcp.c.

Referenced by reload_config().

#define DEFAULT_MGCP_GW_PORT   2427

From RFC 2705

Definition at line 116 of file chan_mgcp.c.

Referenced by build_gateway().

#define DEFAULT_RETRANS   1000

How frequently to retransmit

Definition at line 119 of file chan_mgcp.c.

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

#define DIRECTMEDIA   1

Definition at line 91 of file chan_mgcp.c.

Referenced by build_gateway().

#define INADDR_NONE   (in_addr_t)(-1)

Definition at line 94 of file chan_mgcp.c.

Referenced by build_gateway().

#define MAX_EXPIRY   3600

Definition at line 90 of file chan_mgcp.c.

#define MAX_RETRANS   5

Try only 5 times for retransmissions

Definition at line 120 of file chan_mgcp.c.

Referenced by retrans_pkt().

#define MAX_SUBS   2

#define MGCP_CX_CONF   3

Definition at line 126 of file chan_mgcp.c.

Referenced by handle_request().

#define MGCP_CX_CONFERENCE   3

Definition at line 127 of file chan_mgcp.c.

#define MGCP_CX_INACTIVE   4

Definition at line 129 of file chan_mgcp.c.

Referenced by build_gateway(), mgcp_hangup(), and unalloc_sub().

#define MGCP_CX_MUTE   4

Definition at line 128 of file chan_mgcp.c.

Referenced by handle_request().

#define MGCP_CX_RECVONLY   1

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

#define MGCP_CX_SENDRECV   2

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

Referenced by add_header(), init_req(), init_resp(), and parse().

#define MGCP_MAX_LINES   64

Definition at line 243 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 118 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 294 of file chan_mgcp.c.

Referenced by build_gateway(), and mgcp_hangup().

#define MGCPDUMPER

Definition at line 88 of file chan_mgcp.c.

#define RESPONSE_TIMEOUT   30

in seconds

Definition at line 273 of file chan_mgcp.c.

Referenced by find_and_retrans().

#define SUB_ALT   1

Definition at line 286 of file chan_mgcp.c.

#define SUB_REAL   0

Definition at line 285 of file chan_mgcp.c.

#define TYPE_LINE   2

#define TYPE_TRUNK   1

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

00140      {
00141    MGCP_CMD_EPCF,
00142    MGCP_CMD_CRCX,
00143    MGCP_CMD_MDCX,
00144    MGCP_CMD_DLCX,
00145    MGCP_CMD_RQNT,
00146    MGCP_CMD_NTFY,
00147    MGCP_CMD_AUEP,
00148    MGCP_CMD_AUCX,
00149    MGCP_CMD_RSIP
00150 };


Function Documentation

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

Definition at line 1615 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(), handle_incoming(), handle_request_subscribe(), handle_response_register(), parse_register_contact(), and sip_get_header().

01616 {
01617    int x;
01618    int len = strlen(name);
01619    char *r;
01620    for (x = *start; x < req->headers; x++) {
01621       if (!strncasecmp(req->header[x], name, len) &&
01622           (req->header[x][len] == ':')) {
01623          r = req->header[x] + len + 1;
01624          while (*r && (*r < 33)) {
01625             r++;
01626          }
01627          *start = x + 1;
01628          return r;
01629       }
01630    }
01631    /* Don't return NULL, so get_header is always a valid pointer */
01632    return def;
01633 }

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

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

00544 {
00545    int res;
00546    if (gw->addr.sin_addr.s_addr)
00547       res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->addr, sizeof(struct sockaddr_in));
00548    else
00549       res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->defaddr, sizeof(struct sockaddr_in));
00550    if (res != len) {
00551       ast_log(LOG_WARNING, "mgcp_xmit returned %d: %s\n", res, strerror(errno));
00552    }
00553    return res;
00554 }

static void __reg_module ( void   )  [static]

Definition at line 4953 of file chan_mgcp.c.

static void __unreg_module ( void   )  [static]

Definition at line 4953 of file chan_mgcp.c.

static int acf_channel_read ( struct ast_channel chan,
const char *  funcname,
char *  preparse,
char *  buf,
size_t  buflen 
) [static]

Definition at line 4459 of file chan_mgcp.c.

References ast_log(), LOG_ERROR, mgcp_endpoint::ncs, mgcp_subchannel::parent, sub, ast_channel::tech, and ast_channel::tech_pvt.

04460 {
04461    struct mgcp_subchannel *sub = chan->tech_pvt;
04462    int res = 0;
04463 
04464    /* Sanity check */
04465    if (!chan || chan->tech != &mgcp_tech) {
04466       ast_log(LOG_ERROR, "This function requires a valid MGCP channel\n");
04467       return -1;
04468    }
04469 
04470    if (!strcasecmp(args, "ncs")) {
04471       snprintf(buf, buflen, "%s", sub->parent->ncs ?  "yes":"no");
04472    } else {
04473       res = -1;
04474    }
04475    return res;
04476 }

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

Definition at line 2049 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_cc_call_info_to_response(), add_digit(), add_diversion_header(), add_header_max_forwards(), add_header_offhook(), add_route(), add_rpid(), add_sdp(), add_supported_header(), add_text(), add_vidupdate(), append_date(), copy_all_header(), copy_header(), copy_via_headers(), finalize_content(), initreqprep(), reqprep(), respprep(), transmit_audit_endpoint(), transmit_cc_notify(), transmit_connect(), transmit_connect_with_sdp(), transmit_connection_del(), transmit_connection_del_w_params(), transmit_info_with_aoc(), 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_minexpires(), transmit_response_with_minse(), transmit_response_with_retry_after(), transmit_response_with_sip_etag(), transmit_response_with_unsupported(), transmit_state_notify(), and update_connectedline().

02050 {
02051    if (req->len >= sizeof(req->data) - 4) {
02052       ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
02053       return -1;
02054    }
02055    if (req->lines) {
02056       ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n");
02057       return -1;
02058    }
02059    req->header[req->headers] = req->data + req->len;
02060    snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s: %s\r\n", var, value);
02061    req->len += strlen(req->header[req->headers]);
02062    if (req->headers < MGCP_MAX_HEADERS) {
02063       req->headers++;
02064    } else {
02065       ast_log(LOG_WARNING, "Out of header space\n");
02066       return -1;
02067    }
02068    return 0;
02069 }

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

Definition at line 2614 of file chan_mgcp.c.

References ast_channel::_state, add_header(), ast_debug, AST_STATE_RINGING, mgcp_endpoint::dtmfmode, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, mgcp_endpoint::ncs, mgcp_subchannel::owner, mgcp_subchannel::parent, and mgcp_endpoint::sub.

Referenced by transmit_modify_request(), transmit_notify_request(), and transmit_notify_request_with_callerid().

02615 {
02616    struct mgcp_endpoint *p = sub->parent;
02617    char tone_indicate_end = 0;
02618 
02619    /* We also should check the tone to indicate, because it have no sense
02620       to request notify D/[0-9#*] (dtmf keys) if we are sending congestion
02621       tone for example G/cg */
02622    if (p && (!strcasecmp(tone, (p->ncs ? "L/ro" : "G/cg")))) {
02623       tone_indicate_end = 1;
02624    }
02625 
02626    if (p && p->sub && p->sub->owner &&
02627          p->sub->owner->_state >= AST_STATE_RINGING &&
02628          (p->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID))) {
02629        add_header(resp, "R", "L/hu(N),L/hf(N)");
02630 
02631    } else if (!tone_indicate_end){
02632        add_header(resp, "R", (p->ncs ? "L/hu(N),L/hf(N),L/[0-9#*](N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)"));
02633    } else {
02634       ast_debug(1, "We don't want more digits if we will end the call\n");
02635       add_header(resp, "R", "L/hu(N),L/hf(N)");
02636    }
02637 }

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

Definition at line 2071 of file chan_mgcp.c.

References ast_copy_string(), ast_log(), mgcp_request::data, mgcp_request::len, mgcp_request::line, mgcp_request::lines, LOG_WARNING, and MGCP_MAX_LINES.

Referenced by add_sdp().

02072 {
02073    if (req->len >= sizeof(req->data) - 4) {
02074       ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
02075       return -1;
02076    }
02077    if (!req->lines) {
02078       /* Add extra empty return */
02079       ast_copy_string(req->data + req->len, "\r\n", sizeof(req->data) - req->len);
02080       req->len += strlen(req->data + req->len);
02081    }
02082    req->line[req->lines] = req->data + req->len;
02083    snprintf(req->line[req->lines], sizeof(req->data) - req->len, "%s", line);
02084    req->len += strlen(req->line[req->lines]);
02085    if (req->lines < MGCP_MAX_LINES) {
02086       req->lines++;
02087    } else {
02088       ast_log(LOG_WARNING, "Out of line space\n");
02089       return -1;
02090    }
02091    return 0;
02092 }

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

Definition at line 2181 of file chan_mgcp.c.

References add_line(), ast_copy_string(), ast_debug, ast_format_cap_iscompatible(), ast_format_cap_iter_end(), ast_format_cap_iter_next(), ast_format_cap_iter_start(), AST_FORMAT_GET_TYPE, AST_FORMAT_TYPE_AUDIO, ast_getformatname(), 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_sockaddr_to_sin, mgcp_endpoint::cap, ast_format::id, len(), LOG_WARNING, mgcp_endpoint::nonCodecCapability, mgcp_gateway::ourip, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_subchannel::rtp, and mgcp_subchannel::tmpdest.

Referenced by transmit_connect_with_sdp(), transmit_invite(), transmit_modify_request(), transmit_modify_with_sdp(), transmit_reinvite_with_sdp(), transmit_response_with_sdp(), transmit_response_with_t38_sdp(), and update_connectedline().

02182 {
02183    int len;
02184    int codec;
02185    char costr[80];
02186    struct sockaddr_in sin;
02187    struct ast_sockaddr sin_tmp;
02188    char v[256];
02189    char s[256];
02190    char o[256];
02191    char c[256];
02192    char t[256];
02193    char m[256] = "";
02194    char a[1024] = "";
02195    int x;
02196    struct ast_format tmpfmt;
02197    struct sockaddr_in dest = { 0, };
02198    struct ast_sockaddr dest_tmp;
02199    struct mgcp_endpoint *p = sub->parent;
02200    /* XXX We break with the "recommendation" and send our IP, in order that our
02201           peer doesn't have to ast_gethostbyname() us XXX */
02202    len = 0;
02203    if (!sub->rtp) {
02204       ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n");
02205       return -1;
02206    }
02207    ast_rtp_instance_get_local_address(sub->rtp, &sin_tmp);
02208    ast_sockaddr_to_sin(&sin_tmp, &sin);
02209    if (rtp) {
02210       ast_rtp_instance_get_remote_address(sub->rtp, &dest_tmp);
02211       ast_sockaddr_to_sin(&dest_tmp, &dest);
02212    } else {
02213       if (sub->tmpdest.sin_addr.s_addr) {
02214          dest.sin_addr = sub->tmpdest.sin_addr;
02215          dest.sin_port = sub->tmpdest.sin_port;
02216          /* Reset temporary destination */
02217          memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
02218       } else {
02219          dest.sin_addr = p->parent->ourip;
02220          dest.sin_port = sin.sin_port;
02221       }
02222    }
02223    ast_debug(1, "We're at %s port %d\n", ast_inet_ntoa(p->parent->ourip), ntohs(sin.sin_port));
02224    ast_copy_string(v, "v=0\r\n", sizeof(v));
02225    snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", (int)getpid(), (int)getpid(), ast_inet_ntoa(dest.sin_addr));
02226    ast_copy_string(s, "s=session\r\n", sizeof(s));
02227    snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr));
02228    ast_copy_string(t, "t=0 0\r\n", sizeof(t));
02229    snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port));
02230 
02231    ast_format_cap_iter_start(p->cap);
02232    while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) {
02233       if (AST_FORMAT_GET_TYPE(tmpfmt.id) != AST_FORMAT_TYPE_AUDIO) {
02234          /* Audio is now discontiguous */
02235          continue;
02236       }
02237       if (ast_format_cap_iscompatible(p->cap, &tmpfmt)) {
02238          ast_debug(1, "Answering with capability %s\n", ast_getformatname(&tmpfmt));
02239          codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 1, &tmpfmt, 0);
02240          if (codec > -1) {
02241             snprintf(costr, sizeof(costr), " %d", codec);
02242             strncat(m, costr, sizeof(m) - strlen(m) - 1);
02243             snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0));
02244             strncat(a, costr, sizeof(a) - strlen(a) - 1);
02245          }
02246       }
02247    }
02248    ast_format_cap_iter_end(p->cap);
02249 
02250    for (x = 1LL; x <= AST_RTP_MAX; x <<= 1) {
02251       if (p->nonCodecCapability & x) {
02252          ast_debug(1, "Answering with non-codec capability %d\n", (int) x);
02253          codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 0, NULL, x);
02254          if (codec > -1) {
02255             snprintf(costr, sizeof(costr), " %d", codec);
02256             strncat(m, costr, sizeof(m) - strlen(m) - 1);
02257             snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype2(0, NULL, x, 0));
02258             strncat(a, costr, sizeof(a) - strlen(a) - 1);
02259             if (x == AST_RTP_DTMF) {
02260                /* Indicate we support DTMF...  Not sure about 16,
02261                   but MSN supports it so dang it, we will too... */
02262                snprintf(costr, sizeof costr, "a=fmtp:%d 0-16\r\n", codec);
02263                strncat(a, costr, sizeof(a) - strlen(a) - 1);
02264             }
02265          }
02266       }
02267    }
02268    strncat(m, "\r\n", sizeof(m) - strlen(m) - 1);
02269    len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a);
02270    snprintf(costr, sizeof(costr), "%d", len);
02271    add_line(resp, v);
02272    add_line(resp, o);
02273    add_line(resp, s);
02274    add_line(resp, c);
02275    add_line(resp, t);
02276    add_line(resp, m);
02277    add_line(resp, a);
02278    return 0;
02279 }

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

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

04591 {
04592    struct ast_variable *tmpvar = NULL;
04593    char *varname = ast_strdupa(buf), *varval = NULL;
04594 
04595    if ((varval = strchr(varname, '='))) {
04596       *varval++ = '\0';
04597       if ((tmpvar = ast_variable_new(varname, varval, ""))) {
04598          tmpvar->next = list;
04599          list = tmpvar;
04600       }
04601    }
04602    return list;
04603 }

static int attempt_transfer ( struct mgcp_endpoint p  )  [static]

Definition at line 3216 of file chan_mgcp.c.

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

03217 {
03218    /* *************************
03219     * I hope this works.
03220     * Copied out of chan_zap
03221     * Cross your fingers
03222     * *************************/
03223 
03224    /* In order to transfer, we need at least one of the channels to
03225       actually be in a call bridge.  We can't conference two applications
03226       together (but then, why would we want to?) */
03227    if (ast_bridged_channel(p->sub->owner)) {
03228       /* The three-way person we're about to transfer to could still be in MOH, so
03229          stop if now if appropriate */
03230       if (ast_bridged_channel(p->sub->next->owner))
03231          ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
03232       if (p->sub->owner->_state == AST_STATE_RINGING) {
03233          ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
03234       }
03235       if (ast_channel_masquerade(p->sub->next->owner, ast_bridged_channel(p->sub->owner))) {
03236          ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
03237             ast_channel_name(ast_bridged_channel(p->sub->owner)), ast_channel_name(p->sub->next->owner));
03238          return -1;
03239       }
03240       /* Orphan the channel */
03241       unalloc_sub(p->sub->next);
03242    } else if (ast_bridged_channel(p->sub->next->owner)) {
03243       if (p->sub->owner->_state == AST_STATE_RINGING) {
03244          ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
03245       }
03246       ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
03247       if (ast_channel_masquerade(p->sub->owner, ast_bridged_channel(p->sub->next->owner))) {
03248          ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
03249             ast_channel_name(ast_bridged_channel(p->sub->next->owner)), ast_channel_name(p->sub->owner));
03250          return -1;
03251       }
03252       /*swap_subs(p, SUB_THREEWAY, SUB_REAL);*/
03253       ast_verb(3, "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name);
03254       p->sub = p->sub->next;
03255       unalloc_sub(p->sub->next);
03256       /* Tell the caller not to hangup */
03257       return 1;
03258    } else {
03259       ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
03260          ast_channel_name(p->sub->owner), ast_channel_name(p->sub->next->owner));
03261       p->sub->next->owner->_softhangup |= AST_SOFTHANGUP_DEV;
03262       if (p->sub->next->owner) {
03263          p->sub->next->alreadygone = 1;
03264          mgcp_queue_hangup(p->sub->next);
03265       }
03266    }
03267    return 0;
03268 }

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 3972 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_format_cap_alloc_nolock(), ast_format_cap_copy(), ast_free, ast_get_group(), ast_get_ip(), ast_log(), ast_mutex_destroy, ast_mutex_init, ast_ouraddrfor(), ast_random(), AST_SCHED_DEL, ast_sockaddr_from_sin, ast_sockaddr_to_sin, 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::cap, 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, mgcp_subchannel::gate, gateways, mgcp_gateway::ha, mgcp_endpoint::hangupongateremove, 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::ncs, mgcp_endpoint::needaudit, mgcp_subchannel::next, mgcp_endpoint::next, ast_variable::next, mgcp_gateway::next, mgcp_endpoint::onhooktime, mgcp_gateway::ourip, mgcp_subchannel::parent, mgcp_endpoint::parent, mgcp_endpoint::parkinglot, mgcp_endpoint::pickupgroup, mgcp_endpoint::pktcgatealloc, mgcp_gateway::realtime, mgcp_gateway::retransid, mgcp_endpoint::rqnt_ident, mgcp_endpoint::rqnt_queue_lock, mgcp_subchannel::rtp, mgcp_subchannel::sdpsent, mgcp_endpoint::singlepath, mgcp_endpoint::slowsequence, strsep(), mgcp_endpoint::sub, 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 find_realtime_gw(), and reload_config().

03973 {
03974    struct mgcp_gateway *gw;
03975    struct mgcp_endpoint *e;
03976    struct mgcp_subchannel *sub;
03977    struct ast_variable *chanvars = NULL;
03978 
03979    /*char txident[80];*/
03980    int i=0, y=0;
03981    int gw_reload = 0;
03982    int ep_reload = 0;
03983    directmedia = DIRECTMEDIA;
03984 
03985    /* locate existing gateway */
03986    for (gw = gateways; gw; gw = gw->next) {
03987       if (!strcasecmp(cat, gw->name)) {
03988          /* gateway already exists */
03989          gw->delme = 0;
03990          gw_reload = 1;
03991          break;
03992       }
03993    }
03994 
03995    if (!gw && !(gw = ast_calloc(1, sizeof(*gw)))) {
03996       return NULL;
03997    }
03998 
03999    if (!gw_reload) {
04000       gw->expire = -1;
04001       gw->realtime = 0;
04002       gw->retransid = -1;
04003       ast_mutex_init(&gw->msgs_lock);
04004       ast_copy_string(gw->name, cat, sizeof(gw->name));
04005       /* check if the name is numeric ip */
04006       if ((strchr(gw->name, '.')) && inet_addr(gw->name) != INADDR_NONE)
04007          gw->isnamedottedip = 1;
04008    }
04009    for (; v; v = v->next) {
04010       if (!strcasecmp(v->name, "host")) {
04011          if (!strcasecmp(v->value, "dynamic")) {
04012             /* They'll register with us */
04013             gw->dynamic = 1;
04014             memset(&gw->addr.sin_addr, 0, 4);
04015             if (gw->addr.sin_port) {
04016                /* If we've already got a port, make it the default rather than absolute */
04017                gw->defaddr.sin_port = gw->addr.sin_port;
04018                gw->addr.sin_port = 0;
04019             }
04020          } else {
04021             /* Non-dynamic.  Make sure we become that way if we're not */
04022             AST_SCHED_DEL(sched, gw->expire);
04023             gw->dynamic = 0;
04024             {
04025                struct ast_sockaddr tmp;
04026 
04027                ast_sockaddr_from_sin(&tmp, &gw->addr);
04028                if (ast_get_ip(&tmp, v->value)) {
04029                   if (!gw_reload) {
04030                      ast_mutex_destroy(&gw->msgs_lock);
04031                      ast_free(gw);
04032                   }
04033                   return NULL;
04034                }
04035                ast_sockaddr_to_sin(&tmp, &gw->addr);
04036             }
04037          }
04038       } else if (!strcasecmp(v->name, "defaultip")) {
04039          struct ast_sockaddr tmp;
04040 
04041          ast_sockaddr_from_sin(&tmp, &gw->defaddr);
04042          if (ast_get_ip(&tmp, v->value)) {
04043             if (!gw_reload) {
04044                ast_mutex_destroy(&gw->msgs_lock);
04045                ast_free(gw);
04046             }
04047             return NULL;
04048          }
04049          ast_sockaddr_to_sin(&tmp, &gw->defaddr);
04050       } else if (!strcasecmp(v->name, "permit") ||
04051          !strcasecmp(v->name, "deny")) {
04052          gw->ha = ast_append_ha(v->name, v->value, gw->ha, NULL);
04053       } else if (!strcasecmp(v->name, "port")) {
04054          gw->addr.sin_port = htons(atoi(v->value));
04055       } else if (!strcasecmp(v->name, "context")) {
04056          ast_copy_string(context, v->value, sizeof(context));
04057       } else if (!strcasecmp(v->name, "dtmfmode")) {
04058          if (!strcasecmp(v->value, "inband"))
04059             dtmfmode = MGCP_DTMF_INBAND;
04060          else if (!strcasecmp(v->value, "rfc2833"))
04061             dtmfmode = MGCP_DTMF_RFC2833;
04062          else if (!strcasecmp(v->value, "hybrid"))
04063             dtmfmode = MGCP_DTMF_HYBRID;
04064          else if (!strcasecmp(v->value, "none"))
04065             dtmfmode = 0;
04066          else
04067             ast_log(LOG_WARNING, "'%s' is not a valid DTMF mode at line %d\n", v->value, v->lineno);
04068       } else if (!strcasecmp(v->name, "nat")) {
04069          nat = ast_true(v->value);
04070       } else if (!strcasecmp(v->name, "ncs")) {
04071          ncs = ast_true(v->value);
04072       } else if (!strcasecmp(v->name, "hangupongateremove")) {
04073          hangupongateremove = ast_true(v->value);
04074       } else if (!strcasecmp(v->name, "pktcgatealloc")) {
04075          pktcgatealloc = ast_true(v->value);
04076       } else if (!strcasecmp(v->name, "callerid")) {
04077          if (!strcasecmp(v->value, "asreceived")) {
04078             cid_num[0] = '\0';
04079             cid_name[0] = '\0';
04080          } else {
04081             ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
04082          }
04083       } else if (!strcasecmp(v->name, "language")) {
04084          ast_copy_string(language, v->value, sizeof(language));
04085       } else if (!strcasecmp(v->name, "accountcode")) {
04086          ast_copy_string(accountcode, v->value, sizeof(accountcode));
04087       } else if (!strcasecmp(v->name, "amaflags")) {
04088          y = ast_cdr_amaflags2int(v->value);
04089          if (y < 0) {
04090             ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
04091          } else {
04092             amaflags = y;
04093          }
04094       } else if (!strcasecmp(v->name, "setvar")) {
04095          chanvars = add_var(v->value, chanvars);
04096       } else if (!strcasecmp(v->name, "clearvars")) {
04097          if (chanvars) {
04098             ast_variables_destroy(chanvars);
04099             chanvars = NULL;
04100          }
04101       } else if (!strcasecmp(v->name, "musiconhold")) {
04102          ast_copy_string(musicclass, v->value, sizeof(musicclass));
04103       } else if (!strcasecmp(v->name, "parkinglot")) {
04104          ast_copy_string(parkinglot, v->value, sizeof(parkinglot));
04105       } else if (!strcasecmp(v->name, "callgroup")) {
04106          cur_callergroup = ast_get_group(v->value);
04107       } else if (!strcasecmp(v->name, "pickupgroup")) {
04108          cur_pickupgroup = ast_get_group(v->value);
04109       } else if (!strcasecmp(v->name, "immediate")) {
04110          immediate = ast_true(v->value);
04111       } else if (!strcasecmp(v->name, "cancallforward")) {
04112          cancallforward = ast_true(v->value);
04113       } else if (!strcasecmp(v->name, "singlepath")) {
04114          singlepath = ast_true(v->value);
04115       } else if (!strcasecmp(v->name, "directmedia") || !strcasecmp(v->name, "canreinvite")) {
04116          directmedia = ast_true(v->value);
04117       } else if (!strcasecmp(v->name, "mailbox")) {
04118          ast_copy_string(mailbox, v->value, sizeof(mailbox));
04119       } else if (!strcasecmp(v->name, "hasvoicemail")) {
04120          if (ast_true(v->value) && ast_strlen_zero(mailbox)) {
04121             ast_copy_string(mailbox, gw->name, sizeof(mailbox));
04122          }
04123       } else if (!strcasecmp(v->name, "adsi")) {
04124          adsi = ast_true(v->value);
04125       } else if (!strcasecmp(v->name, "callreturn")) {
04126          callreturn = ast_true(v->value);
04127       } else if (!strcasecmp(v->name, "callwaiting")) {
04128          callwaiting = ast_true(v->value);
04129       } else if (!strcasecmp(v->name, "slowsequence")) {
04130          slowsequence = ast_true(v->value);
04131       } else if (!strcasecmp(v->name, "transfer")) {
04132          transfer = ast_true(v->value);
04133       } else if (!strcasecmp(v->name, "threewaycalling")) {
04134          threewaycalling = ast_true(v->value);
04135       } else if (!strcasecmp(v->name, "wcardep")) {
04136          /* locate existing endpoint */
04137          for (e = gw->endpoints; e; e = e->next) {
04138             if (!strcasecmp(v->value, e->name)) {
04139                /* endpoint already exists */
04140                e->delme = 0;
04141                ep_reload = 1;
04142                break;
04143             }
04144          }
04145 
04146          if (!e) {
04147             /* Allocate wildcard endpoint */
04148             e = ast_calloc(1, sizeof(*e));
04149             ep_reload = 0;
04150          }
04151 
04152          if (e) {
04153             if (!ep_reload) {
04154                memset(e, 0, sizeof(struct mgcp_endpoint));
04155                ast_mutex_init(&e->lock);
04156                ast_mutex_init(&e->rqnt_queue_lock);
04157                ast_mutex_init(&e->cmd_queue_lock);
04158                e->cap = ast_format_cap_alloc_nolock();
04159                ast_copy_string(e->name, v->value, sizeof(e->name));
04160                e->needaudit = 1;
04161             }
04162             ast_copy_string(gw->wcardep, v->value, sizeof(gw->wcardep));
04163             /* XXX Should we really check for uniqueness?? XXX */
04164             ast_copy_string(e->accountcode, accountcode, sizeof(e->accountcode));
04165             ast_copy_string(e->context, context, sizeof(e->context));
04166             ast_copy_string(e->cid_num, cid_num, sizeof(e->cid_num));
04167             ast_copy_string(e->cid_name, cid_name, sizeof(e->cid_name));
04168             ast_copy_string(e->language, language, sizeof(e->language));
04169             ast_copy_string(e->musicclass, musicclass, sizeof(e->musicclass));
04170             ast_copy_string(e->mailbox, mailbox, sizeof(e->mailbox));
04171             ast_copy_string(e->parkinglot, parkinglot, sizeof(e->parkinglot));
04172             if (!ast_strlen_zero(e->mailbox)) {
04173                char *mbox, *cntx;
04174                cntx = mbox = ast_strdupa(e->mailbox);
04175                strsep(&cntx, "@");
04176                if (ast_strlen_zero(cntx)) {
04177                   cntx = "default";
04178                }
04179                e->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, "MGCP MWI subscription", NULL,
04180                   AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mbox,
04181                   AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, cntx,
04182                   AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
04183                   AST_EVENT_IE_END);
04184             }
04185             snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", ast_random());
04186             e->msgstate = -1;
04187             e->amaflags = amaflags;
04188             ast_format_cap_copy(e->cap, global_capability);
04189             e->parent = gw;
04190             e->ncs = ncs;
04191             e->dtmfmode = dtmfmode;
04192             if (!ep_reload && e->sub && e->sub->rtp) {
04193                e->dtmfmode |= MGCP_DTMF_INBAND;
04194             }
04195             e->adsi = adsi;
04196             e->type = TYPE_LINE;
04197             e->immediate = immediate;
04198             e->callgroup=cur_callergroup;
04199             e->pickupgroup=cur_pickupgroup;
04200             e->callreturn = callreturn;
04201             e->cancallforward = cancallforward;
04202             e->singlepath = singlepath;
04203             e->directmedia = directmedia;
04204             e->callwaiting = callwaiting;
04205             e->hascallwaiting = callwaiting;
04206             e->slowsequence = slowsequence;
04207             e->transfer = transfer;
04208             e->threewaycalling = threewaycalling;
04209             e->onhooktime = time(NULL);
04210             /* ASSUME we're onhook */
04211             e->hookstate = MGCP_ONHOOK;
04212             e->chanvars = copy_vars(chanvars);
04213             if (!ep_reload) {
04214                /*snprintf(txident, sizeof(txident), "%08lx", ast_random());*/
04215                for (i = 0; i < MAX_SUBS; i++) {
04216                   sub = ast_calloc(1, sizeof(*sub));
04217                   if (sub) {
04218                      ast_verb(3, "Allocating subchannel '%d' on %s@%s\n", i, e->name, gw->name);
04219                      ast_mutex_init(&sub->lock);
04220                      ast_mutex_init(&sub->cx_queue_lock);
04221                      sub->parent = e;
04222                      sub->id = i;
04223                      snprintf(sub->txident, sizeof(sub->txident), "%08lx", ast_random());
04224                      /*stnrcpy(sub->txident, txident, sizeof(sub->txident) - 1);*/
04225                      sub->cxmode = MGCP_CX_INACTIVE;
04226                      sub->nat = nat;
04227                      sub->gate = NULL;
04228                      sub->sdpsent = 0;
04229                      sub->next = e->sub;
04230                      e->sub = sub;
04231                   } else {
04232                      /* XXX Should find a way to clean up our memory */
04233                      ast_log(LOG_WARNING, "Out of memory allocating subchannel\n");
04234                      return NULL;
04235                   }
04236                }
04237                /* Make out subs a circular linked list so we can always sping through the whole bunch */
04238                /* find the end of the list */
04239                for (sub = e->sub; sub && sub->next; sub = sub->next);
04240                /* set the last sub->next to the first sub */
04241                sub->next = e->sub;
04242 
04243                e->next = gw->endpoints;
04244                gw->endpoints = e;
04245             }
04246          }
04247       } else if (!strcasecmp(v->name, "trunk") ||
04248                  !strcasecmp(v->name, "line")) {
04249 
04250          /* locate existing endpoint */
04251          for (e = gw->endpoints; e; e = e->next) {
04252             if (!strcasecmp(v->value, e->name)) {
04253                /* endpoint already exists */
04254                e->delme = 0;
04255                ep_reload = 1;
04256                break;
04257             }
04258          }
04259 
04260          if (!e) {
04261             e = ast_calloc(1, sizeof(*e));
04262             ep_reload = 0;
04263          }
04264 
04265          if (e) {
04266             if (!ep_reload) {
04267                ast_mutex_init(&e->lock);
04268                ast_mutex_init(&e->rqnt_queue_lock);
04269                ast_mutex_init(&e->cmd_queue_lock);
04270                e->cap = ast_format_cap_alloc_nolock();
04271                ast_copy_string(e->name, v->value, sizeof(e->name));
04272                e->needaudit = 1;
04273             }
04274             /* XXX Should we really check for uniqueness?? XXX */
04275             ast_copy_string(e->accountcode, accountcode, sizeof(e->accountcode));
04276             ast_copy_string(e->context, context, sizeof(e->context));
04277             ast_copy_string(e->cid_num, cid_num, sizeof(e->cid_num));
04278             ast_copy_string(e->cid_name, cid_name, sizeof(e->cid_name));
04279             ast_copy_string(e->language, language, sizeof(e->language));
04280             ast_copy_string(e->musicclass, musicclass, sizeof(e->musicclass));
04281             ast_copy_string(e->mailbox, mailbox, sizeof(e->mailbox));
04282             ast_copy_string(e->parkinglot, parkinglot, sizeof(e->parkinglot));
04283             if (!ast_strlen_zero(mailbox)) {
04284                ast_verb(3, "Setting mailbox '%s' on %s@%s\n", mailbox, gw->name, e->name);
04285             }
04286             if (!ep_reload) {
04287                /* XXX potential issue due to reload */
04288                e->msgstate = -1;
04289                e->parent = gw;
04290             }
04291             e->amaflags = amaflags;
04292             ast_format_cap_copy(e->cap, global_capability);
04293             e->dtmfmode = dtmfmode;
04294             e->ncs = ncs;
04295             e->pktcgatealloc = pktcgatealloc;
04296             e->hangupongateremove = hangupongateremove;
04297             e->adsi = adsi;
04298             e->type = (!strcasecmp(v->name, "trunk")) ? TYPE_TRUNK : TYPE_LINE;
04299             e->immediate = immediate;
04300             e->callgroup=cur_callergroup;
04301             e->pickupgroup=cur_pickupgroup;
04302             e->callreturn = callreturn;
04303             e->cancallforward = cancallforward;
04304             e->directmedia = directmedia;
04305             e->singlepath = singlepath;
04306             e->callwaiting = callwaiting;
04307             e->hascallwaiting = callwaiting;
04308             e->slowsequence = slowsequence;
04309             e->transfer = transfer;
04310             e->threewaycalling = threewaycalling;
04311 
04312             /* If we already have a valid chanvars, it's not a new endpoint (it's a reload),
04313                so first, free previous mem
04314              */
04315             if (e->chanvars) {
04316                ast_variables_destroy(e->chanvars);
04317                e->chanvars = NULL;
04318             }
04319             e->chanvars = copy_vars(chanvars);
04320 
04321             if (!ep_reload) {
04322                e->onhooktime = time(NULL);
04323                /* ASSUME we're onhook */
04324                e->hookstate = MGCP_ONHOOK;
04325                snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", ast_random());
04326             }
04327 
04328             for (i = 0, sub = NULL; i < MAX_SUBS; i++) {
04329                if (!ep_reload) {
04330                   sub = ast_calloc(1, sizeof(*sub));
04331                } else {
04332                   if (!sub) {
04333                      sub = e->sub;
04334                   } else {
04335                      sub = sub->next;
04336                   }
04337                }
04338 
04339                if (sub) {
04340                   if (!ep_reload) {
04341                      ast_verb(3, "Allocating subchannel '%d' on %s@%s\n", i, e->name, gw->name);
04342                      ast_mutex_init(&sub->lock);
04343                      ast_mutex_init(&sub->cx_queue_lock);
04344                      ast_copy_string(sub->magic, MGCP_SUBCHANNEL_MAGIC, sizeof(sub->magic));
04345                      sub->parent = e;
04346                      sub->id = i;
04347                      snprintf(sub->txident, sizeof(sub->txident), "%08lx", ast_random());
04348                      sub->cxmode = MGCP_CX_INACTIVE;
04349                      sub->next = e->sub;
04350                      e->sub = sub;
04351                   }
04352                   sub->nat = nat;
04353                } else {
04354                   /* XXX Should find a way to clean up our memory */
04355                   ast_log(LOG_WARNING, "Out of memory allocating subchannel\n");
04356                   return NULL;
04357                }
04358             }
04359             if (!ep_reload) {
04360                /* Make out subs a circular linked list so we can always sping through the whole bunch */
04361                /* find the end of the list */
04362                for (sub = e->sub; sub && sub->next; sub = sub->next);
04363                /* set the last sub->next to the first sub */
04364                sub->next = e->sub;
04365 
04366                e->next = gw->endpoints;
04367                gw->endpoints = e;
04368             }
04369          }
04370       } else if (!strcasecmp(v->name, "name") || !strcasecmp(v->name, "lines")) {
04371          /* just eliminate realtime warnings */
04372       } else {
04373          ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
04374       }
04375    }
04376    if (!ntohl(gw->addr.sin_addr.s_addr) && !gw->dynamic) {
04377       ast_log(LOG_WARNING, "Gateway '%s' lacks IP address and isn't dynamic\n", gw->name);
04378       if (!gw_reload) {
04379          ast_mutex_destroy(&gw->msgs_lock);
04380          ast_free(gw);
04381       }
04382 
04383       /* Return NULL */
04384       gw_reload = 1;
04385    } else {
04386       gw->defaddr.sin_family = AF_INET;
04387       gw->addr.sin_family = AF_INET;
04388       if (gw->defaddr.sin_addr.s_addr && !ntohs(gw->defaddr.sin_port)) {
04389          gw->defaddr.sin_port = htons(DEFAULT_MGCP_GW_PORT);
04390       }
04391       if (gw->addr.sin_addr.s_addr && !ntohs(gw->addr.sin_port)) {
04392          gw->addr.sin_port = htons(DEFAULT_MGCP_GW_PORT);
04393       }
04394       {
04395          struct ast_sockaddr tmp1, tmp2;
04396          struct sockaddr_in tmp3 = {0,};
04397 
04398          tmp3.sin_addr = gw->ourip;
04399          ast_sockaddr_from_sin(&tmp1, &gw->addr);
04400          ast_sockaddr_from_sin(&tmp2, &tmp3);
04401          if (gw->addr.sin_addr.s_addr && ast_ouraddrfor(&tmp1, &tmp2)) {
04402             memcpy(&gw->ourip, &__ourip, sizeof(gw->ourip));
04403          } else {
04404             ast_sockaddr_to_sin(&tmp2, &tmp3);
04405             gw->ourip = tmp3.sin_addr;
04406          }
04407       }
04408    }
04409 
04410    if (chanvars) {
04411       ast_variables_destroy(chanvars);
04412       chanvars = NULL;
04413    }
04414    return (gw_reload ? NULL : gw);
04415 }

static char* control2str ( int  ind  )  [static]

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

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

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

duplicate a list of channel variables,

Returns:
the copy.

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

04609 {
04610    struct ast_variable *res = NULL, *tmp, *v = NULL;
04611 
04612    for (v = src ; v ; v = v->next) {
04613       if ((tmp = ast_variable_new(v->name, v->value, v->file))) {
04614          tmp->next = res;
04615          res = tmp;
04616       }
04617    }
04618    return res;
04619 }

static void destroy_endpoint ( struct mgcp_endpoint e  )  [static]

Definition at line 4479 of file chan_mgcp.c.

References ast_dsp_free(), ast_event_unsubscribe(), ast_format_cap_destroy(), ast_free, ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, ast_rtp_instance_destroy(), ast_strlen_zero(), ast_variables_destroy(), mgcp_endpoint::cap, mgcp_endpoint::chanvars, mgcp_endpoint::cmd_queue_lock, mgcp_subchannel::cxident, mgcp_endpoint::dsp, dump_cmd_queues(), dump_queue(), mgcp_subchannel::gate, cops_gate::gate_open, cops_gate::gate_remove, cops_gate::got_dq_gi, 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, mgcp_endpoint::sub, sub, cops_gate::tech_pvt, and transmit_connection_del().

Referenced by prune_gateways().

04480 {
04481    struct mgcp_subchannel *sub = e->sub->next, *s;
04482    int i;
04483 
04484    for (i = 0; i < MAX_SUBS; i++) {
04485       ast_mutex_lock(&sub->lock);
04486       if (!ast_strlen_zero(sub->cxident)) {
04487          transmit_connection_del(sub);
04488       }
04489       if (sub->rtp) {
04490          ast_rtp_instance_destroy(sub->rtp);
04491          sub->rtp = NULL;
04492       }
04493       memset(sub->magic, 0, sizeof(sub->magic));
04494       mgcp_queue_hangup(sub);
04495       dump_cmd_queues(NULL, sub);
04496       if(sub->gate) {
04497          sub->gate->tech_pvt = NULL;
04498          sub->gate->got_dq_gi = NULL;
04499          sub->gate->gate_remove = NULL;
04500          sub->gate->gate_open = NULL;
04501       }
04502       ast_mutex_unlock(&sub->lock);
04503       sub = sub->next;
04504    }
04505 
04506    if (e->dsp) {
04507       ast_dsp_free(e->dsp);
04508    }
04509 
04510    dump_queue(e->parent, e);
04511    dump_cmd_queues(e, NULL);
04512 
04513    sub = e->sub;
04514    for (i = 0; (i < MAX_SUBS) && sub; i++) {
04515       s = sub;
04516       sub = sub->next;
04517       ast_mutex_destroy(&s->lock);
04518       ast_mutex_destroy(&s->cx_queue_lock);
04519       ast_free(s);
04520    }
04521 
04522    if (e->mwi_event_sub)
04523       ast_event_unsubscribe(e->mwi_event_sub);
04524 
04525    if (e->chanvars) {
04526       ast_variables_destroy(e->chanvars);
04527       e->chanvars = NULL;
04528    }
04529 
04530    ast_mutex_destroy(&e->lock);
04531    ast_mutex_destroy(&e->rqnt_queue_lock);
04532    ast_mutex_destroy(&e->cmd_queue_lock);
04533    e->cap = ast_format_cap_destroy(e->cap);
04534    ast_free(e);
04535 }

static void destroy_gateway ( struct mgcp_gateway g  )  [static]

Definition at line 4537 of file chan_mgcp.c.

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

Referenced by fax_gateway_new(), and prune_gateways().

04538 {
04539    if (g->ha)
04540       ast_free_ha(g->ha);
04541 
04542    dump_queue(g, NULL);
04543 
04544    ast_free(g);
04545 }

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

Definition at line 3776 of file chan_mgcp.c.

References ast_io_add(), AST_IO_IN, ast_io_wait(), ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, ast_sched_runq(), ast_sched_wait(), ast_verb, mgcp_gateway::endpoints, free, gatelock, gateways, has_voicemail(), MGCP_ONHOOK, mgcp_prune_realtime_gateway(), mgcp_reload_lock, mgcpsock_read(), monlock, mgcp_gateway::msgs_lock, netlock, mgcp_gateway::next, mgcp_gateway::realtime, reload_config(), transmit_notify_request(), and TYPE_LINE.

03777 {
03778    int res;
03779    int reloading;
03780    struct mgcp_gateway *g, *gprev;
03781    /*struct mgcp_gateway *g;*/
03782    /*struct mgcp_endpoint *e;*/
03783    /*time_t thispass = 0, lastpass = 0;*/
03784    time_t lastrun = 0;
03785 
03786    /* Add an I/O event to our UDP socket */
03787    if (mgcpsock > -1) {
03788       mgcpsock_read_id = ast_io_add(io, mgcpsock, mgcpsock_read, AST_IO_IN, NULL);
03789    }
03790    /* This thread monitors all the frame relay interfaces which are not yet in use
03791       (and thus do not have a separate thread) indefinitely */
03792    /* From here on out, we die whenever asked */
03793    for (;;) {
03794       /* Check for a reload request */
03795       ast_mutex_lock(&mgcp_reload_lock);
03796       reloading = mgcp_reloading;
03797       mgcp_reloading = 0;
03798       ast_mutex_unlock(&mgcp_reload_lock);
03799       if (reloading) {
03800          ast_verb(1, "Reloading MGCP\n");
03801          reload_config(1);
03802          /* Add an I/O event to our UDP socket */
03803          if (mgcpsock > -1 && !mgcpsock_read_id) {
03804             mgcpsock_read_id = ast_io_add(io, mgcpsock, mgcpsock_read, AST_IO_IN, NULL);
03805          }
03806       }
03807 
03808       /* Check for interfaces needing to be killed */
03809       /* Don't let anybody kill us right away.  Nobody should lock the interface list
03810          and wait for the monitor list, but the other way around is okay. */
03811       ast_mutex_lock(&monlock);
03812       /* Lock the network interface */
03813       ast_mutex_lock(&netlock);
03814 
03815 #if 0
03816       /* XXX THIS IS COMPLETELY HOSED */
03817       /* The gateway goes into a state of panic */
03818       /* If the vmwi indicator is sent while it is reseting interfaces */
03819       lastpass = thispass;
03820       thispass = time(NULL);
03821       g = gateways;
03822       while(g) {
03823          if (thispass != lastpass) {
03824             e = g->endpoints;
03825             while(e) {
03826                if (e->type == TYPE_LINE) {
03827                   res = has_voicemail(e);
03828                   if ((e->msgstate != res) && (e->hookstate == MGCP_ONHOOK) && (!e->rtp)){
03829                      if (res) {
03830                         transmit_notify_request(e, "L/vmwi(+)");
03831                      } else {
03832                         transmit_notify_request(e, "L/vmwi(-)");
03833                      }
03834                      e->msgstate = res;
03835                      e->onhooktime = thispass;
03836                   }
03837                }
03838                e = e->next;
03839             }
03840          }
03841          g = g->next;
03842       }
03843 #endif
03844       /* pruning unused realtime gateways, running in every 60 seconds*/
03845       if(time(NULL) > (lastrun + 60)) {
03846          ast_mutex_lock(&gatelock);
03847          g = gateways;
03848          gprev = NULL;
03849          while(g) {
03850             if(g->realtime) {
03851                if(mgcp_prune_realtime_gateway(g)) {
03852                   if(gprev) {
03853                      gprev->next = g->next;
03854                   } else {
03855                      gateways = g->next;
03856                   }
03857                   ast_mutex_unlock(&g->msgs_lock);
03858                   ast_mutex_destroy(&g->msgs_lock);
03859                   free(g);
03860                } else {
03861                   ast_mutex_unlock(&g->msgs_lock);
03862                   gprev = g;
03863                }
03864             } else {
03865                gprev = g;
03866             }
03867             g = g->next;
03868          }
03869          ast_mutex_unlock(&gatelock);
03870          lastrun = time(NULL);
03871       }
03872       /* Okay, now that we know what to do, release the network lock */
03873       ast_mutex_unlock(&netlock);
03874       /* And from now on, we're okay to be killed, so release the monitor lock as well */
03875       ast_mutex_unlock(&monlock);
03876       pthread_testcancel();
03877       /* Wait for sched or io */
03878       res = ast_sched_wait(sched);
03879       /* copied from chan_sip.c */
03880       if ((res < 0) || (res > 1000)) {
03881          res = 1000;
03882       }
03883       res = ast_io_wait(io, res);
03884       ast_mutex_lock(&monlock);
03885       if (res >= 0) {
03886          ast_sched_runq(sched);
03887       }
03888       ast_mutex_unlock(&monlock);
03889    }
03890    /* Never reached */
03891    return NULL;
03892 }

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

dump_cmd_queues: (SC:) cleanup pending commands

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

02698 {
02699    struct mgcp_request *t, *q;
02700 
02701    if (p) {
02702       ast_mutex_lock(&p->rqnt_queue_lock);
02703       for (q = p->rqnt_queue; q; t = q->next, ast_free(q), q=t);
02704       p->rqnt_queue = NULL;
02705       ast_mutex_unlock(&p->rqnt_queue_lock);
02706 
02707       ast_mutex_lock(&p->cmd_queue_lock);
02708       for (q = p->cmd_queue; q; t = q->next, ast_free(q), q=t);
02709       p->cmd_queue = NULL;
02710       ast_mutex_unlock(&p->cmd_queue_lock);
02711 
02712       ast_mutex_lock(&p->sub->cx_queue_lock);
02713       for (q = p->sub->cx_queue; q; t = q->next, ast_free(q), q=t);
02714       p->sub->cx_queue = NULL;
02715       ast_mutex_unlock(&p->sub->cx_queue_lock);
02716 
02717       ast_mutex_lock(&p->sub->next->cx_queue_lock);
02718       for (q = p->sub->next->cx_queue; q; t = q->next, ast_free(q), q=t);
02719       p->sub->next->cx_queue = NULL;
02720       ast_mutex_unlock(&p->sub->next->cx_queue_lock);
02721    } else if (sub) {
02722       ast_mutex_lock(&sub->cx_queue_lock);
02723       for (q = sub->cx_queue; q; t = q->next, ast_free(q), q=t);
02724       sub->cx_queue = NULL;
02725       ast_mutex_unlock(&sub->cx_queue_lock);
02726    }
02727 }

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

Definition at line 579 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, mgcp_message::next, mgcp_message::owner_ep, and mgcp_message::seqno.

Referenced by destroy_endpoint(), destroy_gateway(), and handle_request().

00580 {
00581    struct mgcp_message *cur, *q = NULL, *w, *prev;
00582 
00583    ast_mutex_lock(&gw->msgs_lock);
00584    for (prev = NULL, cur = gw->msgs; cur; prev = cur, cur = cur->next) {
00585       if (!p || cur->owner_ep == p) {
00586          if (prev) {
00587             prev->next = cur->next;
00588          } else {
00589             gw->msgs = cur->next;
00590          }
00591 
00592          ast_log(LOG_NOTICE, "Removing message from %s transaction %u\n",
00593             gw->name, cur->seqno);
00594 
00595          w = cur;
00596          if (q) {
00597             w->next = q;
00598          } else {
00599             w->next = NULL;
00600          }
00601          q = w;
00602       }
00603    }
00604    ast_mutex_unlock(&gw->msgs_lock);
00605 
00606    while (q) {
00607       cur = q;
00608       q = q->next;
00609       ast_free(cur);
00610    }
00611 }

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

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

03598 {
03599    int seqno=0;
03600    time_t now;
03601    struct mgcp_response *prev = NULL, *cur, *next, *answer = NULL;
03602    time(&now);
03603    if (sscanf(req->identifier, "%30d", &seqno) != 1) {
03604       seqno = 0;
03605    }
03606    for (cur = sub->parent->parent->responses, next = cur ? cur->next : NULL; cur; cur = next, next = cur ? cur->next : NULL) {
03607       if (now - cur->whensent > RESPONSE_TIMEOUT) {
03608          /* Delete this entry */
03609          if (prev)
03610             prev->next = next;
03611          else
03612             sub->parent->parent->responses = next;
03613          ast_free(cur);
03614       } else {
03615          if (seqno == cur->seqno)
03616             answer = cur;
03617          prev = cur;
03618       }
03619    }
03620    if (answer) {
03621       resend_response(sub, answer);
03622       return 1;
03623    }
03624    return 0;
03625 }

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

References mgcp_gateway::addr, ast_debug, ast_inet_ntoa(), ast_mutex_lock, ast_mutex_unlock, mgcp_postrequest(), mgcp_request::next, and mgcp_endpoint::parent.

Referenced by agi_handle_command(), ast_agi_register(), handle_cli_agi_show(), and handle_response().

02733 {
02734    struct mgcp_request *prev, *req;
02735 
02736    ast_mutex_lock(l);
02737    for (prev = NULL, req = *queue; req; prev = req, req = req->next) {
02738       if (req->trid == ident) {
02739          /* remove from queue */
02740          if (!prev)
02741             *queue = req->next;
02742          else
02743             prev->next = req->next;
02744 
02745          /* send next pending command */
02746          if (*queue) {
02747             ast_debug(1, "Posting Queued Request:\n%s to %s:%d\n", (*queue)->data,
02748                ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
02749 
02750             mgcp_postrequest(p, sub, (*queue)->data, (*queue)->len, (*queue)->trid);
02751          }
02752          break;
02753       }
02754    }
02755    ast_mutex_unlock(l);
02756    return req;
02757 }

static struct mgcp_gateway* find_realtime_gw ( char *  name,
char *  at,
struct sockaddr_in *  sin 
) [static, read]

Note:
This is a fairly odd way of instantiating lines. Instead of each line created by virtue of being in the database (and loaded via ast_load_realtime_multientry), this code forces a specific order with a "lines" entry in the "mgcpgw" record. This has benefits, because as with chan_dahdi, values are inherited across definitions. The downside is that it's not as clear what the values will be simply by looking at a single row in the database, and it's probable that the sanest configuration should have the first column in the "mgcpep" table be "clearvars", with a static value of "all", if any variables are set at all. It may be worth making this assumption explicit in the code in the future, and then just using ast_load_realtime_multientry for the "mgcpep" records.

Definition at line 1666 of file chan_mgcp.c.

References args, AST_APP_ARG, ast_check_realtime(), ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, ast_load_realtime(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), ast_variables_destroy(), build_gateway(), mgcp_gateway::endpoints, gateways, ast_variable::name, mgcp_endpoint::needaudit, mgcp_endpoint::next, mgcp_gateway::next, ast_variable::next, mgcp_gateway::realtime, transmit_audit_endpoint(), and ast_variable::value.

Referenced by find_subchannel_and_lock().

01667 {
01668    struct mgcp_gateway *g = NULL;
01669    struct ast_variable *mgcpgwconfig = NULL;
01670    struct ast_variable *gwv, *epname = NULL;
01671    struct mgcp_endpoint *e;
01672    char lines[256];
01673    int i, j;
01674 
01675    ast_debug(1, "*** find Realtime MGCPGW\n");
01676 
01677    if (!(i = ast_check_realtime("mgcpgw")) || !(j = ast_check_realtime("mgcpep"))) {
01678       return NULL;
01679    }
01680 
01681    if (ast_strlen_zero(at)) {
01682       ast_debug(1, "null gw name\n");
01683       return NULL;
01684    }
01685 
01686    if (!(mgcpgwconfig = ast_load_realtime("mgcpgw", "name", at, NULL))) {
01687       return NULL;
01688    }
01689 
01690    /*!
01691     * \note This is a fairly odd way of instantiating lines.  Instead of each
01692     * line created by virtue of being in the database (and loaded via
01693     * ast_load_realtime_multientry), this code forces a specific order with a
01694     * "lines" entry in the "mgcpgw" record.  This has benefits, because as with
01695     * chan_dahdi, values are inherited across definitions.  The downside is
01696     * that it's not as clear what the values will be simply by looking at a
01697     * single row in the database, and it's probable that the sanest configuration
01698     * should have the first column in the "mgcpep" table be "clearvars", with a
01699     * static value of "all", if any variables are set at all.  It may be worth
01700     * making this assumption explicit in the code in the future, and then just
01701     * using ast_load_realtime_multientry for the "mgcpep" records.
01702     */
01703    lines[0] = '\0';
01704    for (gwv = mgcpgwconfig; gwv; gwv = gwv->next) {
01705       if (!strcasecmp(gwv->name, "lines")) {
01706          ast_copy_string(lines, gwv->value, sizeof(lines));
01707          break;
01708       }
01709    }
01710    /* Position gwv at the end of the list */
01711    for (gwv = gwv && gwv->next ? gwv : mgcpgwconfig; gwv->next; gwv = gwv->next);
01712 
01713    if (!ast_strlen_zero(lines)) {
01714       AST_DECLARE_APP_ARGS(args,
01715          AST_APP_ARG(line)[100];
01716       );
01717       AST_STANDARD_APP_ARGS(args, lines);
01718       for (i = 0; i < args.argc; i++) {
01719          gwv->next = ast_load_realtime("mgcpep", "name", at, "line", args.line[i], NULL);
01720 
01721          /* Remove "line" AND position gwv at the end of the list. */
01722          for (epname = NULL; gwv->next; gwv = gwv->next) {
01723             if (!strcasecmp(gwv->next->name, "line")) {
01724                /* Remove it from the list */
01725                epname = gwv->next;
01726                gwv->next = gwv->next->next;
01727             }
01728          }
01729          /* Since "line" instantiates the configuration, we have to move it to the end. */
01730          if (epname) {
01731             gwv->next = epname;
01732             epname->next = NULL;
01733             gwv = gwv->next;
01734          }
01735       }
01736    }
01737    for (gwv = mgcpgwconfig; gwv; gwv = gwv->next) {
01738       ast_debug(1, "MGCP Realtime var: %s => %s\n", gwv->name, gwv->value);
01739    }
01740 
01741    if (mgcpgwconfig) {
01742       g = build_gateway(at, mgcpgwconfig);
01743       ast_variables_destroy(mgcpgwconfig);
01744    }
01745    if (g) {
01746       g->next = gateways;
01747       g->realtime = 1;
01748       gateways = g;
01749       for (e = g->endpoints; e; e = e->next) {
01750          transmit_audit_endpoint(e);
01751          e->needaudit = 0;
01752       }
01753    }
01754    return g;
01755 }

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

Definition at line 1757 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_sockaddr_from_sin, ast_sockaddr_to_sin, ast_verb, mgcp_gateway::defaddr, mgcp_gateway::dynamic, mgcp_gateway::endpoints, find_realtime_gw(), gatelock, gateways, mgcp_subchannel::id, mgcp_subchannel::lock, LOG_NOTICE, mgcp_endpoint::name, mgcp_gateway::name, mgcp_endpoint::next, mgcp_gateway::next, mgcp_gateway::ourip, mgcp_endpoint::sub, and sub.

Referenced by mgcp_request(), and mgcpsock_read().

01758 {
01759    struct mgcp_endpoint *p = NULL;
01760    struct mgcp_subchannel *sub = NULL;
01761    struct mgcp_gateway *g;
01762    char tmp[256] = "";
01763    char *at = NULL, *c;
01764    int found = 0;
01765    if (name) {
01766       ast_copy_string(tmp, name, sizeof(tmp));
01767       at = strchr(tmp, '@');
01768       if (!at) {
01769          ast_log(LOG_NOTICE, "Endpoint '%s' has no at sign!\n", name);
01770          return NULL;
01771       }
01772       *at++ = '\0';
01773    }
01774    ast_mutex_lock(&gatelock);
01775    if (at && (at[0] == '[')) {
01776       at++;
01777       c = strrchr(at, ']');
01778       if (c) {
01779          *c = '\0';
01780       }
01781    }
01782    for (g = gateways ? gateways : find_realtime_gw(name, at, sin); g; g = g->next ? g->next : find_realtime_gw(name, at, sin)) {
01783       if ((!name || !strcasecmp(g->name, at)) &&
01784           (sin || g->addr.sin_addr.s_addr || g->defaddr.sin_addr.s_addr)) {
01785          /* Found the gateway.  If it's dynamic, save it's address -- now for the endpoint */
01786          if (sin && g->dynamic && name) {
01787             if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
01788                (g->addr.sin_port != sin->sin_port)) {
01789                memcpy(&g->addr, sin, sizeof(g->addr));
01790                {
01791                   struct ast_sockaddr tmp1, tmp2;
01792                   struct sockaddr_in tmp3 = {0,};
01793 
01794                   tmp3.sin_addr = g->ourip;
01795                   ast_sockaddr_from_sin(&tmp1, &g->addr);
01796                   ast_sockaddr_from_sin(&tmp2, &tmp3);
01797                   if (ast_ouraddrfor(&tmp1, &tmp2)) {
01798                      memcpy(&g->ourip, &__ourip, sizeof(g->ourip));
01799                   }
01800                   ast_sockaddr_to_sin(&tmp2, &tmp3);
01801                   g->ourip = tmp3.sin_addr;
01802                }
01803                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));
01804             }
01805          /* not dynamic, check if the name matches */
01806          } else if (name) {
01807             if (strcasecmp(g->name, at)) {
01808                g = g->next;
01809                continue;
01810             }
01811          /* not dynamic, no name, check if the addr matches */
01812          } else if (!name && sin) {
01813             if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
01814                 (g->addr.sin_port != sin->sin_port)) {
01815                if(!g->next)
01816                   g = find_realtime_gw(name, at, sin);
01817                else
01818                   g = g->next;
01819                continue;
01820             }
01821          } else {
01822             continue;
01823          }
01824          for (p = g->endpoints; p; p = p->next) {
01825             ast_debug(1, "Searching on %s@%s for subchannel\n", p->name, g->name);
01826             if (msgid) {
01827                sub = p->sub;
01828                found = 1;
01829                break;
01830             } else if (name && !strcasecmp(p->name, tmp)) {
01831                ast_debug(1, "Coundn't determine subchannel, assuming current master %s@%s-%d\n",
01832                   p->name, g->name, p->sub->id);
01833                sub = p->sub;
01834                found = 1;
01835                break;
01836             }
01837          }
01838          if (sub && found) {
01839             ast_mutex_lock(&sub->lock);
01840             break;
01841          }
01842       }
01843    }
01844    ast_mutex_unlock(&gatelock);
01845    if (!sub) {
01846       if (name) {
01847          if (g) {
01848             ast_log(LOG_NOTICE, "Endpoint '%s' not found on gateway '%s'\n", tmp, at);
01849          } else {
01850             ast_log(LOG_NOTICE, "Gateway '%s' (and thus its endpoint '%s') does not exist\n", at, tmp);
01851          }
01852       }
01853    }
01854    return sub;
01855 }

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

get_csv: (SC:) get comma separated value

Definition at line 1642 of file chan_mgcp.c.

Referenced by handle_response().

01643 {
01644    char *s;
01645 
01646    *next = NULL, *len = 0;
01647    if (!c) return NULL;
01648 
01649    while (*c && (*c < 33 || *c == ',')) {
01650       c++;
01651    }
01652 
01653    s = c;
01654    while (*c && (*c >= 33 && *c != ',')) {
01655       c++, (*len)++;
01656    }
01657    *next = c;
01658 
01659    if (*len == 0) {
01660       s = NULL, *next = NULL;
01661    }
01662 
01663    return s;
01664 }

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

Definition at line 1635 of file chan_mgcp.c.

References __get_header().

Referenced by handle_request(), and handle_response().

01636 {
01637    int start = 0;
01638    return __get_header(req, name, &start, "");
01639 }

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

Definition at line 1586 of file chan_mgcp.c.

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

Referenced by process_sdp().

01587 {
01588    int x;
01589    int len = strlen(name);
01590    char *r;
01591 
01592    for (x = 0; x < req->lines; x++) {
01593       r = get_sdp_by_line(req->line[x], name, len);
01594       if (r[0] != '\0') return r;
01595    }
01596    return "";
01597 }

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

Definition at line 1576 of file chan_mgcp.c.

Referenced by get_sdp(), and get_sdp_iterate().

01577 {
01578    if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') {
01579       char *r = line + nameLen + 1;
01580       while (*r && (*r < 33)) ++r;
01581       return r;
01582    }
01583    return "";
01584 }

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

Definition at line 1604 of file chan_mgcp.c.

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

Referenced by get_ip_and_port_from_sdp(), and process_sdp().

01605 {
01606    int len = strlen(name);
01607    char *r;
01608    while (*iterator < req->lines) {
01609       r = get_sdp_by_line(req->line[(*iterator)++], name, len);
01610       if (r[0] != '\0') return r;
01611    }
01612    return "";
01613 }

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

Definition at line 3270 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_endpoint::ncs, 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().

03271 {
03272    struct mgcp_endpoint *p = sub->parent;
03273    struct ast_channel *c;
03274    pthread_t t;
03275 
03276    /* Off hook / answer */
03277    if (sub->outgoing) {
03278       /* Answered */
03279       if (sub->owner) {
03280          if (ast_bridged_channel(sub->owner))
03281             ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
03282          sub->cxmode = MGCP_CX_SENDRECV;
03283          if (!sub->rtp) {
03284             start_rtp(sub);
03285          } else {
03286             transmit_modify_request(sub);
03287          }
03288          /*transmit_notify_request(sub, "aw");*/
03289          transmit_notify_request(sub, "");
03290          mgcp_queue_control(sub, AST_CONTROL_ANSWER);
03291       }
03292    } else {
03293       /* Start switch */
03294       /*sub->cxmode = MGCP_CX_SENDRECV;*/
03295       if (!sub->owner) {
03296          if (!sub->rtp) {
03297             start_rtp(sub);
03298          } else {
03299             transmit_modify_request(sub);
03300          }
03301          if (p->immediate) {
03302             /* The channel is immediately up. Start right away */
03303 #ifdef DLINK_BUGGY_FIRMWARE
03304             transmit_notify_request(sub, "rt");
03305 #else
03306             transmit_notify_request(sub, p->ncs ? "L/rt" : "G/rt");
03307 #endif
03308             c = mgcp_new(sub, AST_STATE_RING, NULL);
03309             if (!c) {
03310                ast_log(LOG_WARNING, "Unable to start PBX on channel %s@%s\n", p->name, p->parent->name);
03311                transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
03312                ast_hangup(c);
03313             }
03314          } else {
03315             if (has_voicemail(p)) {
03316                transmit_notify_request(sub, "L/sl");
03317             } else {
03318                transmit_notify_request(sub, "L/dl");
03319             }
03320             c = mgcp_new(sub, AST_STATE_DOWN, NULL);
03321             if (c) {
03322                if (ast_pthread_create_detached(&t, NULL, mgcp_ss, c)) {
03323                   ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
03324                   ast_hangup(c);
03325                }
03326             } else {
03327                ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", p->name, p->parent->name);
03328             }
03329          }
03330       } else {
03331          if (p->hookstate == MGCP_OFFHOOK) {
03332             ast_log(LOG_WARNING, "Off hook, but already have owner on %s@%s\n", p->name, p->parent->name);
03333          } else {
03334             ast_log(LOG_WARNING, "On hook, but already have owner on %s@%s\n", p->name, p->parent->name);
03335             ast_log(LOG_WARNING, "If we're onhook why are we here trying to handle a hd or hf?\n");
03336          }
03337          if (ast_bridged_channel(sub->owner))
03338             ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
03339          sub->cxmode = MGCP_CX_SENDRECV;
03340          if (!sub->rtp) {
03341             start_rtp(sub);
03342          } else {
03343             transmit_modify_request(sub);
03344          }
03345          /*transmit_notify_request(sub, "aw");*/
03346          transmit_notify_request(sub, "");
03347          /*ast_queue_control(sub->owner, AST_CONTROL_ANSWER);*/
03348       }
03349    }
03350 }

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

Definition at line 1079 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_endpoint::next, mgcp_gateway::next, transmit_audit_endpoint(), and ast_cli_entry::usage.

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

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

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

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

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

Definition at line 1037 of file chan_mgcp.c.

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

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

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

Definition at line 3352 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, 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, ast_frame_subclass::integer, 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::ncs, mgcp_subchannel::next, mgcp_endpoint::next, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_subchannel::rtp, 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().

03353 {
03354    char *ev, *s;
03355    struct ast_frame f = { 0, };
03356    struct mgcp_endpoint *p = sub->parent;
03357    struct mgcp_gateway *g = NULL;
03358    int res;
03359 
03360    ast_debug(1, "Handling request '%s' on %s@%s\n", req->verb, p->name, p->parent->name);
03361    /* Clear out potential response */
03362    if (!strcasecmp(req->verb, "RSIP")) {
03363       /* Test if this RSIP request is just a keepalive */
03364       if (!strcasecmp( get_header(req, "RM"), "X-keepalive")) {
03365          ast_verb(3, "Received keepalive request from %s@%s\n", p->name, p->parent->name);
03366          transmit_response(sub, "200", req, "OK");
03367       } else {
03368          dump_queue(p->parent, p);
03369          dump_cmd_queues(p, NULL);
03370 
03371          if ((strcmp(p->name, p->parent->wcardep) != 0)) {
03372             ast_verb(3, "Resetting interface %s@%s\n", p->name, p->parent->name);
03373          }
03374          /* For RSIP on wildcard we reset all endpoints */
03375          if (!strcmp(p->name, p->parent->wcardep)) {
03376             /* Reset all endpoints */
03377             struct mgcp_endpoint *tmp_ep;
03378 
03379             g = p->parent;
03380             for (tmp_ep = g->endpoints; tmp_ep; tmp_ep = tmp_ep->next) {
03381                /*if ((strcmp(tmp_ep->name, "*") != 0) && (strcmp(tmp_ep->name, "aaln/" "*") != 0)) {*/
03382                if (strcmp(tmp_ep->name, g->wcardep) != 0) {
03383                   struct mgcp_subchannel *tmp_sub, *first_sub;
03384                   ast_verb(3, "Resetting interface %s@%s\n", tmp_ep->name, p->parent->name);
03385 
03386                   first_sub = tmp_ep->sub;
03387                   tmp_sub = tmp_ep->sub;
03388                   while (tmp_sub) {
03389                      mgcp_queue_hangup(tmp_sub);
03390                      tmp_sub = tmp_sub->next;
03391                      if (tmp_sub == first_sub)
03392                         break;
03393                   }
03394                }
03395             }
03396          } else if (sub->owner) {
03397             mgcp_queue_hangup(sub);
03398          }
03399          transmit_response(sub, "200", req, "OK");
03400          /* We don't send NTFY or AUEP to wildcard ep */
03401          if (strcmp(p->name, p->parent->wcardep) != 0) {
03402             transmit_notify_request(sub, "");
03403             /* Audit endpoint.
03404              Idea is to prevent lost lines due to race conditions
03405             */
03406             transmit_audit_endpoint(p);
03407          }
03408       }
03409    } else if (!strcasecmp(req->verb, "NTFY")) {
03410       /* Acknowledge and be sure we keep looking for the same things */
03411       transmit_response(sub, "200", req, "OK");
03412       /* Notified of an event */
03413       ev = get_header(req, "O");
03414       s = strchr(ev, '/');
03415       if (s) ev = s + 1;
03416       ast_debug(1, "Endpoint '%s@%s-%d' observed '%s'\n", p->name, p->parent->name, sub->id, ev);
03417       /* Keep looking for events unless this was a hangup */
03418       if (strcasecmp(ev, "hu") && strcasecmp(ev, "hd") && strcasecmp(ev, "ping")) {
03419          transmit_notify_request(sub, p->curtone);
03420       }
03421       if (!strcasecmp(ev, "hd")) {
03422          p->hookstate = MGCP_OFFHOOK;
03423          sub->cxmode = MGCP_CX_SENDRECV;
03424 
03425          if (p) {
03426            /* When the endpoint have a Off hook transition we allways
03427               starts without any previous dtmfs */
03428            memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03429          }
03430 
03431          handle_hd_hf(sub, ev);
03432       } else if (!strcasecmp(ev, "hf")) {
03433          /* We can assume we are offhook if we received a hookflash */
03434          /* First let's just do call wait and ignore threeway */
03435          /* We're currently in charge */
03436          if (p->hookstate != MGCP_OFFHOOK) {
03437             /* Cisco c7940 sends hf even if the phone is onhook */
03438             /* Thanks to point on IRC for pointing this out */
03439             return -1;
03440          }
03441          /* do not let * conference two down channels */
03442          if (sub->owner && sub->owner->_state == AST_STATE_DOWN && !sub->next->owner)
03443             return -1;
03444 
03445          if (p->callwaiting || p->transfer || p->threewaycalling) {
03446             ast_verb(3, "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name);
03447             p->sub = p->sub->next;
03448 
03449             /* transfer control to our next subchannel */
03450             if (!sub->next->owner) {
03451                /* plave the first call on hold and start up a new call */
03452                sub->cxmode = MGCP_CX_MUTE;
03453                ast_verb(3, "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
03454                transmit_modify_request(sub);
03455                if (sub->owner && ast_bridged_channel(sub->owner))
03456                   ast_queue_control(sub->owner, AST_CONTROL_HOLD);
03457                sub->next->cxmode = MGCP_CX_RECVONLY;
03458                handle_hd_hf(sub->next, ev);
03459             } else if (sub->owner && sub->next->owner) {
03460                /* We've got two active calls lets decide whether or not to conference or just flip flop */
03461                if ((!sub->outgoing) && (!sub->next->outgoing)) {
03462                   /* We made both calls lets conferenct */
03463                   ast_verb(3, "MGCP Conferencing %d and %d on %s@%s\n",
03464                         sub->id, sub->next->id, p->name, p->parent->name);
03465                   sub->cxmode = MGCP_CX_CONF;
03466                   sub->next->cxmode = MGCP_CX_CONF;
03467                   if (ast_bridged_channel(sub->next->owner))
03468                      ast_queue_control(sub->next->owner, AST_CONTROL_UNHOLD);
03469                   transmit_modify_request(sub);
03470                   transmit_modify_request(sub->next);
03471                } else {
03472                   /* Let's flipflop between calls */
03473                   /* XXX Need to check for state up ??? */
03474                   /* XXX Need a way to indicate the current call, or maybe the call that's waiting */
03475                   ast_verb(3, "We didn't make one of the calls FLIPFLOP %d and %d on %s@%s\n",
03476                         sub->id, sub->next->id, p->name, p->parent->name);
03477                   sub->cxmode = MGCP_CX_MUTE;
03478                   ast_verb(3, "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
03479                   transmit_modify_request(sub);
03480                   if (ast_bridged_channel(sub->owner))
03481                      ast_queue_control(sub->owner, AST_CONTROL_HOLD);
03482 
03483                   if (ast_bridged_channel(sub->next->owner))
03484                      ast_queue_control(sub->next->owner, AST_CONTROL_HOLD);
03485 
03486                   handle_hd_hf(sub->next, ev);
03487                }
03488             } else {
03489                /* We've most likely lost one of our calls find an active call and bring it up */
03490                if (sub->owner) {
03491                   p->sub = sub;
03492                } else if (sub->next->owner) {
03493                   p->sub = sub->next;
03494                } else {
03495                   /* We seem to have lost both our calls */
03496                   /* XXX - What do we do now? */
03497                   return -1;
03498                }
03499                if (ast_bridged_channel(p->sub->owner))
03500                   ast_queue_control(p->sub->owner, AST_CONTROL_UNHOLD);
03501                p->sub->cxmode = MGCP_CX_SENDRECV;
03502                transmit_modify_request(p->sub);
03503             }
03504          } else {
03505             ast_log(LOG_WARNING, "Callwaiting, call transfer or threeway calling not enabled on endpoint %s@%s\n",
03506                p->name, p->parent->name);
03507          }
03508       } else if (!strcasecmp(ev, "hu")) {
03509          p->hookstate = MGCP_ONHOOK;
03510          sub->cxmode = MGCP_CX_RECVONLY;
03511          ast_debug(1, "MGCP %s@%s Went on hook\n", p->name, p->parent->name);
03512          /* Do we need to send MDCX before a DLCX ?
03513          if (sub->rtp) {
03514             transmit_modify_request(sub);
03515          }
03516          */
03517          if (p->transfer && (sub->owner && sub->next->owner) && ((!sub->outgoing) || (!sub->next->outgoing))) {
03518             /* We're allowed to transfer, we have two avtive calls and */
03519             /* we made at least one of the calls.  Let's try and transfer */
03520             ast_mutex_lock(&p->sub->next->lock);
03521             res = attempt_transfer(p);
03522             if (res < 0) {
03523                if (p->sub->next->owner) {
03524                   sub->next->alreadygone = 1;
03525                   mgcp_queue_hangup(sub->next);
03526                }
03527             } else if (res) {
03528                ast_log(LOG_WARNING, "Transfer attempt failed\n");
03529                ast_mutex_unlock(&p->sub->next->lock);
03530                return -1;
03531             }
03532             ast_mutex_unlock(&p->sub->next->lock);
03533          } else {
03534             /* Hangup the current call */
03535             /* If there is another active call, mgcp_hangup will ring the phone with the other call */
03536             if (sub->owner) {
03537                sub->alreadygone = 1;
03538                mgcp_queue_hangup(sub);
03539             } else {
03540                ast_verb(3, "MGCP handle_request(%s@%s-%d) ast_channel already destroyed, resending DLCX.\n",
03541                      p->name, p->parent->name, sub->id);
03542                /* Instruct the other side to remove the connection since it apparently *
03543                 * still thinks the channel is active. *
03544                 * For Cisco IAD2421 /BAK/ */
03545                transmit_connection_del(sub);
03546             }
03547          }
03548          if ((p->hookstate == MGCP_ONHOOK) && (!sub->rtp) && (!sub->next->rtp)) {
03549             p->hidecallerid = 0;
03550             if (p->hascallwaiting && !p->callwaiting) {
03551                ast_verb(3, "Enabling call waiting on MGCP/%s@%s-%d\n", p->name, p->parent->name, sub->id);
03552                p->callwaiting = -1;
03553             }
03554             if (has_voicemail(p)) {
03555                ast_verb(3, "MGCP handle_request(%s@%s) set vmwi(+)\n", p->name, p->parent->name);
03556                transmit_notify_request(sub, "L/vmwi(+)");
03557             } else {
03558                ast_verb(3, "MGCP handle_request(%s@%s) set vmwi(-)\n", p->name, p->parent->name);
03559                transmit_notify_request(sub, "L/vmwi(-)");
03560             }
03561          }
03562       } else if ((strlen(ev) == 1) &&
03563             (((ev[0] >= '0') && (ev[0] <= '9')) ||
03564              ((ev[0] >= 'A') && (ev[0] <= 'D')) ||
03565               (ev[0] == '*') || (ev[0] == '#'))) {
03566          if (sub && sub->owner && (sub->owner->_state >=  AST_STATE_UP)) {
03567             f.frametype = AST_FRAME_DTMF;
03568             f.subclass.integer = ev[0];
03569             f.src = "mgcp";
03570             /* XXX MUST queue this frame to all subs in threeway call if threeway call is active */
03571             mgcp_queue_frame(sub, &f);
03572             ast_mutex_lock(&sub->next->lock);
03573             if (sub->next->owner)
03574                mgcp_queue_frame(sub->next, &f);
03575             ast_mutex_unlock(&sub->next->lock);
03576             if (strstr(p->curtone, (p->ncs ? "wt1" : "wt")) && (ev[0] == 'A')) {
03577                memset(p->curtone, 0, sizeof(p->curtone));
03578             }
03579          } else {
03580             p->dtmf_buf[strlen(p->dtmf_buf)] = ev[0];
03581             p->dtmf_buf[strlen(p->dtmf_buf)] = '\0';
03582          }
03583       } else if (!strcasecmp(ev, "T")) {
03584          /* Digit timeout -- unimportant */
03585       } else if (!strcasecmp(ev, "ping")) {
03586          /* ping -- unimportant */
03587       } else {
03588          ast_log(LOG_NOTICE, "Received unknown event '%s' from %s@%s\n", ev, p->name, p->parent->name);
03589       }
03590    } else {
03591       ast_log(LOG_WARNING, "Unknown verb '%s' received from %s\n", req->verb, ast_inet_ntoa(sin->sin_addr));
03592       transmit_response(sub, "510", req, "Unknown verb");
03593    }
03594    return 0;
03595 }

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

References ast_channel::_state, AST_CONTROL_RINGING, ast_copy_string(), ast_free, ast_log(), ast_queue_control(), AST_STATE_RINGING, 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_CMD_MDCX, 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(), transmit_notify_request(), and transmit_response().

Referenced by handle_incoming(), mgcpsock_read(), and retrans_pkt().

02762 {
02763    char *c;
02764    struct mgcp_request *req;
02765    struct mgcp_gateway *gw = p->parent;
02766 
02767    if (result < 200) {
02768       /* provisional response */
02769       return;
02770    }
02771 
02772    if (p->slowsequence)
02773       req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident);
02774    else if (sub)
02775       req = find_command(p, sub, &sub->cx_queue, &sub->cx_queue_lock, ident);
02776    else if (!(req = find_command(p, sub, &p->rqnt_queue, &p->rqnt_queue_lock, ident)))
02777       req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident);
02778 
02779    if (!req) {
02780       ast_verb(3, "No command found on [%s] for transaction %d. Ignoring...\n",
02781             gw->name, ident);
02782       return;
02783    }
02784 
02785    if (p && (result >= 400) && (result <= 599)) {
02786       switch (result) {
02787       case 401:
02788          p->hookstate = MGCP_OFFHOOK;
02789          break;
02790       case 402:
02791          p->hookstate = MGCP_ONHOOK;
02792          break;
02793       case 406:
02794          ast_log(LOG_NOTICE, "Transaction %d timed out\n", ident);
02795          break;
02796       case 407:
02797          ast_log(LOG_NOTICE, "Transaction %d aborted\n", ident);
02798          break;
02799       }
02800       if (sub) {
02801          if (!sub->cxident[0] && (req->cmd == MGCP_CMD_CRCX)) {
02802              ast_log(LOG_NOTICE, "DLCX for all connections on %s due to error %d\n", gw->name, result);
02803              transmit_connection_del(sub);
02804          }
02805          if (sub->owner) {
02806             ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
02807                result, p->name, p->parent->name, sub ? sub->id:-1);
02808             mgcp_queue_hangup(sub);
02809          }
02810       } else {
02811          if (p->sub->next->owner) {
02812             ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
02813                result, p->name, p->parent->name, sub ? sub->id:-1);
02814             mgcp_queue_hangup(p->sub);
02815          }
02816 
02817          if (p->sub->owner) {
02818             ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
02819                result, p->name, p->parent->name, sub ? sub->id:-1);
02820             mgcp_queue_hangup(p->sub);
02821          }
02822 
02823          dump_cmd_queues(p, NULL);
02824       }
02825    }
02826 
02827    if (resp) {
02828       /* responseAck: */
02829       if (result == 200 && (req->cmd == MGCP_CMD_CRCX || req->cmd == MGCP_CMD_MDCX)) {
02830             if (sub) {
02831                transmit_response(sub, "000", resp, "OK");
02832                if (sub->owner && sub->owner->_state == AST_STATE_RINGING) {
02833                   ast_queue_control(sub->owner, AST_CONTROL_RINGING);
02834                }
02835             }
02836       }
02837       if (req->cmd == MGCP_CMD_CRCX) {
02838          if ((c = get_header(resp, "I"))) {
02839             if (!ast_strlen_zero(c) && sub) {
02840                /* if we are hanging up do not process this conn. */
02841                if (sub->owner) {
02842                   if (!ast_strlen_zero(sub->cxident)) {
02843                      if (strcasecmp(c, sub->cxident)) {
02844                         ast_log(LOG_WARNING, "Subchannel already has a cxident. sub->cxident: %s requested %s\n", sub->cxident, c);
02845                      }
02846                   }
02847                   ast_copy_string(sub->cxident, c, sizeof(sub->cxident));
02848                   if (sub->tmpdest.sin_addr.s_addr) {
02849                      transmit_modify_with_sdp(sub, NULL, 0);
02850                   }
02851                } else {
02852                   /* XXX delete this one
02853                      callid and conn id may already be lost.
02854                      so the following del conn may have a side effect of
02855                      cleaning up the next subchannel */
02856                   transmit_connection_del(sub);
02857                }
02858             }
02859          }
02860       }
02861 
02862       if (req->cmd == MGCP_CMD_AUEP) {
02863          /* check stale connection ids */
02864          if ((c = get_header(resp, "I"))) {
02865             char *v, *n;
02866             int len;
02867             while ((v = get_csv(c, &len, &n))) {
02868                if (len) {
02869                   if (strncasecmp(v, p->sub->cxident, len) &&
02870                       strncasecmp(v, p->sub->next->cxident, len)) {
02871                      /* connection id not found. delete it */
02872                      char cxident[80] = "";
02873 
02874                      if (len > (sizeof(cxident) - 1))
02875                         len = sizeof(cxident) - 1;
02876                      ast_copy_string(cxident, v, len);
02877                      ast_verb(3, "Non existing connection id %s on %s@%s \n",
02878                                cxident, p->name, gw->name);
02879                      transmit_connection_del_w_params(p, NULL, cxident);
02880                   }
02881                }
02882                c = n;
02883             }
02884          }
02885 
02886          /* Try to determine the hookstate returned from an audit endpoint command */
02887          if ((c = get_header(resp, "ES"))) {
02888             if (!ast_strlen_zero(c)) {
02889                if (strstr(c, "hu")) {
02890                   if (p->hookstate != MGCP_ONHOOK) {
02891                      /* XXX cleanup if we think we are offhook XXX */
02892                      if ((p->sub->owner || p->sub->next->owner ) &&
02893                          p->hookstate == MGCP_OFFHOOK)
02894                         mgcp_queue_hangup(sub);
02895                      p->hookstate = MGCP_ONHOOK;
02896 
02897                      /* update the requested events according to the new hookstate */
02898                      transmit_notify_request(p->sub, "");
02899 
02900                      ast_verb(3, "Setting hookstate of %s@%s to ONHOOK\n", p->name, gw->name);
02901                      }
02902                } else if (strstr(c, "hd")) {
02903                   if (p->hookstate != MGCP_OFFHOOK) {
02904                      p->hookstate = MGCP_OFFHOOK;
02905 
02906                      /* update the requested events according to the new hookstate */
02907                      transmit_notify_request(p->sub, "");
02908 
02909                      ast_verb(3, "Setting hookstate of %s@%s to OFFHOOK\n", p->name, gw->name);
02910                      }
02911                   }
02912                }
02913             }
02914          }
02915 
02916       if (resp && resp->lines) {
02917          /* do not process sdp if we are hanging up. this may be a late response */
02918          if (sub && sub->owner) {
02919             if (!sub->rtp)
02920                start_rtp(sub);
02921             if (sub->rtp)
02922                process_sdp(sub, resp);
02923          }
02924       }
02925    }
02926 
02927    ast_free(req);
02928 }

static int has_voicemail ( struct mgcp_endpoint p  )  [static]

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

00491 {
00492    int new_msgs;
00493    struct ast_event *event;
00494    char *mbox, *cntx;
00495 
00496    cntx = mbox = ast_strdupa(p->mailbox);
00497    strsep(&cntx, "@");
00498    if (ast_strlen_zero(cntx))
00499       cntx = "default";
00500 
00501    event = ast_event_get_cached(AST_EVENT_MWI,
00502       AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mbox,
00503       AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, cntx,
00504       AST_EVENT_IE_END);
00505 
00506    if (event) {
00507       new_msgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
00508       ast_event_destroy(event);
00509    } else
00510       new_msgs = ast_app_has_voicemail(p->mailbox, NULL);
00511 
00512    return new_msgs;
00513 }

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

Definition at line 2112 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, mgcp_endpoint::ncs, and mgcp_endpoint::parent.

Referenced by initreqprep(), reqprep(), and transmit_register().

02113 {
02114    /* Initialize a response */
02115    if (req->headers || req->len) {
02116       ast_log(LOG_WARNING, "Request already initialized?!?\n");
02117       return -1;
02118    }
02119    req->header[req->headers] = req->data + req->len;
02120    /* check if we need brackets around the gw name */
02121    if (p->parent->isnamedottedip) {
02122       snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@[%s] MGCP 1.0%s\r\n", verb, oseq, p->name, p->parent->name, p->ncs ? " NCS 1.0" : "");
02123    } else {
02124 +     snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@%s MGCP 1.0%s\r\n", verb, oseq, p->name, p->parent->name, p->ncs ? " NCS 1.0" : "");
02125    }
02126    req->len += strlen(req->header[req->headers]);
02127    if (req->headers < MGCP_MAX_HEADERS) {
02128       req->headers++;
02129    } else {
02130       ast_log(LOG_WARNING, "Out of header space\n");
02131    }
02132    return 0;
02133 }

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

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

02095 {
02096    /* Initialize a response */
02097    if (req->headers || req->len) {
02098       ast_log(LOG_WARNING, "Request already initialized?!?\n");
02099       return -1;
02100    }
02101    req->header[req->headers] = req->data + req->len;
02102    snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %s %s\r\n", resp, orig->identifier, resprest);
02103    req->len += strlen(req->header[req->headers]);
02104    if (req->headers < MGCP_MAX_HEADERS) {
02105       req->headers++;
02106    } else {
02107       ast_log(LOG_WARNING, "Out of header space\n");
02108    }
02109    return 0;
02110 }

static int load_module ( void   )  [static]

load_module: PBX load module - initialization ---

Definition at line 4797 of file chan_mgcp.c.

References ast_channel_register(), ast_cli_register_multiple(), AST_FORMAT_ALAW, ast_format_cap_add(), ast_format_cap_alloc(), ast_format_set(), AST_FORMAT_ULAW, ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_rtp_glue_register, ast_sched_context_create(), ast_sched_context_destroy(), ast_channel_tech::capabilities, io_context_create(), io_context_destroy(), LOG_ERROR, LOG_WARNING, reload_config(), and restart_monitor().

04798 {
04799    struct ast_format tmpfmt;
04800 
04801    if (!(global_capability = ast_format_cap_alloc())) {
04802       return AST_MODULE_LOAD_FAILURE;
04803    }
04804    if (!(mgcp_tech.capabilities = ast_format_cap_alloc())) {
04805       return AST_MODULE_LOAD_FAILURE;
04806    }
04807    ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
04808    ast_format_cap_add(mgcp_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
04809    ast_format_cap_add(mgcp_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
04810    if (!(sched = ast_sched_context_create())) {
04811       ast_log(LOG_WARNING, "Unable to create schedule context\n");
04812       return AST_MODULE_LOAD_FAILURE;
04813    }
04814 
04815    if (!(io = io_context_create())) {
04816       ast_log(LOG_WARNING, "Unable to create I/O context\n");
04817       ast_sched_context_destroy(sched);
04818       return AST_MODULE_LOAD_FAILURE;
04819    }
04820 
04821    if (reload_config(0))
04822       return AST_MODULE_LOAD_DECLINE;
04823 
04824    /* Make sure we can register our mgcp channel type */
04825    if (ast_channel_register(&mgcp_tech)) {
04826       ast_log(LOG_ERROR, "Unable to register channel class 'MGCP'\n");
04827       io_context_destroy(io);
04828       ast_sched_context_destroy(sched);
04829       return AST_MODULE_LOAD_FAILURE;
04830    }
04831 
04832    ast_rtp_glue_register(&mgcp_rtp_glue);
04833    ast_cli_register_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
04834 
04835    /* And start the monitor for the first time */
04836    restart_monitor();
04837 
04838    return AST_MODULE_LOAD_SUCCESS;
04839 }

static int mgcp_alloc_pktcgate ( struct mgcp_subchannel sub  )  [static]

Definition at line 2423 of file chan_mgcp.c.

References mgcp_gateway::addr, ast_pktccops_gate_alloc(), mgcp_subchannel::gate, cops_gate::gate_open, GATE_SET, mgcp_pktcgate_open(), mgcp_pktcgate_remove(), mgcp_endpoint::parent, mgcp_subchannel::parent, and cops_gate::tech_pvt.

Referenced by start_rtp().

02424 {
02425    struct mgcp_endpoint *p = sub->parent;
02426    sub->gate = ast_pktccops_gate_alloc(GATE_SET, NULL, ntohl(p->parent->addr.sin_addr.s_addr),
02427                8, 128000, 232, 0, 0, NULL, &mgcp_pktcgate_remove);
02428 
02429    if (!sub->gate) {
02430       return 0;
02431    }
02432    sub->gate->tech_pvt = sub;
02433    sub->gate->gate_open = &mgcp_pktcgate_open;
02434    return 1;
02435 }

static int mgcp_answer ( struct ast_channel ast  )  [static]

Definition at line 1175 of file chan_mgcp.c.

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

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

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

Definition at line 835 of file chan_mgcp.c.

References ast_channel::_state, ast_channel_name(), ast_copy_string(), ast_debug, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_setstate(), AST_STATE_DOWN, AST_STATE_RESERVED, AST_STATE_RINGING, ast_strlen_zero(), ast_var_name(), ast_var_value(), 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, mgcp_endpoint::ncs, mgcp_subchannel::next, ast_party_id::number, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_subchannel::parent, mgcp_subchannel::rtp, S_COR, start_rtp(), ast_party_name::str, ast_party_number::str, sub, ast_channel::tech_pvt, transmit_modify_request(), transmit_notify_request_with_callerid(), mgcp_endpoint::type, TYPE_LINE, ast_party_name::valid, ast_party_number::valid, and ast_channel::varshead.

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

static int mgcp_devicestate ( const char *  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 1360 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.

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

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

Definition at line 1282 of file chan_mgcp.c.

References ast_channel_name(), ast_log(), ast_mutex_lock, ast_mutex_unlock, mgcp_subchannel::lock, LOG_NOTICE, LOG_WARNING, mgcp_subchannel::owner, sub, 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", ast_channel_name(oldchan), ast_channel_name(newchan));
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 void mgcp_get_codec ( struct ast_channel chan,
struct ast_format_cap result 
) [static]

Definition at line 4444 of file chan_mgcp.c.

References ast_format_cap_copy(), mgcp_endpoint::cap, mgcp_subchannel::parent, sub, and ast_channel::tech_pvt.

04445 {
04446    struct mgcp_subchannel *sub = chan->tech_pvt;
04447    struct mgcp_endpoint *p = sub->parent;
04448    ast_format_cap_copy(result, p->cap);
04449 }

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

Definition at line 4417 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, sub, and ast_channel::tech_pvt.

04418 {
04419    struct mgcp_subchannel *sub = NULL;
04420 
04421    if (!(sub = chan->tech_pvt) || !(sub->rtp))
04422       return AST_RTP_GLUE_RESULT_FORBID;
04423 
04424    *instance = sub->rtp ? ao2_ref(sub->rtp, +1), sub->rtp : NULL;
04425 
04426    if (sub->parent->directmedia)
04427       return AST_RTP_GLUE_RESULT_REMOTE;
04428    else
04429       return AST_RTP_GLUE_RESULT_LOCAL;
04430 }

static int mgcp_hangup ( struct ast_channel ast  )  [static]

Definition at line 920 of file chan_mgcp.c.

References mgcp_subchannel::alreadygone, ast_bridged_channel(), ast_channel_name(), ast_debug, ast_dsp_free(), ast_module_unref(), ast_mutex_lock, ast_mutex_unlock, ast_pktccops_gate_alloc(), ast_rtp_instance_destroy(), ast_strlen_zero(), ast_verb, ast_channel::caller, mgcp_subchannel::callid, mgcp_endpoint::callwaiting, mgcp_subchannel::cxident, mgcp_subchannel::cxmode, cops_gate::deltimer, mgcp_endpoint::dsp, mgcp_endpoint::dtmf_buf, mgcp_endpoint::dtmfmode, mgcp_subchannel::gate, GATE_ALLOC_PROGRESS, GATE_ALLOCATED, GATE_DEL, cops_gate::gate_open, cops_gate::gate_remove, cops_gate::got_dq_gi, has_voicemail(), mgcp_endpoint::hascallwaiting, mgcp_endpoint::hidecallerid, mgcp_endpoint::hookstate, ast_party_caller::id, 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, ast_party_id::name, mgcp_gateway::name, mgcp_endpoint::name, mgcp_endpoint::ncs, mgcp_subchannel::next, ast_party_id::number, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_endpoint::pktcgatealloc, mgcp_subchannel::rtp, S_COR, cops_gate::state, ast_party_name::str, ast_party_number::str, mgcp_endpoint::sub, sub, cops_gate::tech_pvt, ast_channel::tech_pvt, mgcp_subchannel::tmpdest, transmit_connection_del(), transmit_modify_request(), transmit_notify_request(), transmit_notify_request_with_callerid(), ast_party_name::valid, and ast_party_number::valid.

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

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

Definition at line 1438 of file chan_mgcp.c.

References ast_channel_name(), AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, AST_CONTROL_INCOMPLETE, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_SRCCHANGE, AST_CONTROL_SRCUPDATE, AST_CONTROL_UNHOLD, ast_debug, ast_log(), ast_moh_start(), ast_moh_stop(), ast_mutex_lock, ast_mutex_unlock, ast_rtp_instance_change_source(), ast_rtp_instance_update_source(), control2str(), mgcp_subchannel::lock, LOG_WARNING, mgcp_endpoint::ncs, mgcp_subchannel::parent, mgcp_subchannel::rtp, mgcp_subchannel::sdpsent, sub, ast_channel::tech_pvt, transmit_modify_request(), and transmit_notify_request().

01439 {
01440    struct mgcp_subchannel *sub = ast->tech_pvt;
01441    int res = 0;
01442 
01443    ast_debug(3, "MGCP asked to indicate %d '%s' condition on channel %s\n",
01444       ind, control2str(ind), ast_channel_name(ast));
01445    ast_mutex_lock(&sub->lock);
01446    switch(ind) {
01447    case AST_CONTROL_RINGING:
01448 #ifdef DLINK_BUGGY_FIRMWARE   
01449       transmit_notify_request(sub, "rt");
01450 #else
01451       if (!sub->sdpsent) { /* will hide the inband progress!!! */
01452          transmit_notify_request(sub, sub->parent->ncs ? "L/rt" : "G/rt");
01453       }
01454 #endif
01455       break;
01456    case AST_CONTROL_BUSY:
01457       transmit_notify_request(sub, "L/bz");
01458       break;
01459    case AST_CONTROL_INCOMPLETE:
01460       /* We do not currently support resetting of the Interdigit Timer, so treat
01461        * Incomplete control frames as a congestion response
01462        */
01463    case AST_CONTROL_CONGESTION:
01464       transmit_notify_request(sub, sub->parent->ncs ? "L/cg" : "G/cg");
01465       break;
01466    case AST_CONTROL_HOLD:
01467       ast_moh_start(ast, data, NULL);
01468       break;
01469    case AST_CONTROL_UNHOLD:
01470       ast_moh_stop(ast);
01471       break;
01472    case AST_CONTROL_SRCUPDATE:
01473       ast_rtp_instance_update_source(sub->rtp);
01474       break;
01475    case AST_CONTROL_SRCCHANGE:
01476       ast_rtp_instance_change_source(sub->rtp);
01477       break;
01478    case AST_CONTROL_PROGRESS:
01479    case AST_CONTROL_PROCEEDING:
01480       transmit_modify_request(sub);
01481    case -1:
01482       transmit_notify_request(sub, "");
01483       break;
01484    default:
01485       ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
01486       res = -1;
01487    }
01488    ast_mutex_unlock(&sub->lock);
01489    return res;
01490 }

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

Definition at line 1492 of file chan_mgcp.c.

References mgcp_endpoint::accountcode, mgcp_endpoint::adsi, mgcp_endpoint::amaflags, AST_ADSI_UNAVAILABLE, ast_best_codec(), ast_channel_alloc, ast_channel_name(), ast_channel_set_fd(), ast_copy_string(), ast_dsp_new(), ast_dsp_set_digitmode(), ast_dsp_set_features(), ast_format_cap_copy(), ast_format_cap_is_empty(), ast_format_copy(), 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_strlen_zero(), ast_verb, mgcp_endpoint::call_forward, mgcp_endpoint::callgroup, mgcp_endpoint::cap, mgcp_endpoint::chanvars, mgcp_endpoint::cid_name, mgcp_endpoint::cid_num, mgcp_endpoint::context, mgcp_endpoint::dsp, DSP_DIGITMODE_NOQUELCH, DSP_FEATURE_DIGIT_DETECT, mgcp_endpoint::dtmfmode, mgcp_endpoint::exten, global_jbconf, mgcp_subchannel::id, mgcp_endpoint::language, LOG_WARNING, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, ast_variable::name, mgcp_gateway::name, mgcp_endpoint::name, ast_variable::next, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_subchannel::parent, pbx_builtin_setvar_helper(), mgcp_endpoint::pickupgroup, mgcp_subchannel::rtp, and ast_variable::value.

Referenced by handle_hd_hf(), and mgcp_request().

01493 {
01494    struct ast_channel *tmp;
01495    struct ast_variable *v = NULL;
01496    struct mgcp_endpoint *i = sub->parent;
01497    struct ast_format tmpfmt;
01498 
01499    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);
01500    if (tmp) {
01501       tmp->tech = &mgcp_tech;
01502       ast_format_cap_copy(tmp->nativeformats, i->cap);
01503       if (ast_format_cap_is_empty(tmp->nativeformats)) {
01504          ast_format_cap_copy(tmp->nativeformats, global_capability);
01505       }
01506       if (sub->rtp) {
01507          ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0));
01508       }
01509       if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) {
01510          i->dsp = ast_dsp_new();
01511          ast_dsp_set_features(i->dsp, DSP_FEATURE_DIGIT_DETECT);
01512          /* this is to prevent clipping of dtmf tones during dsp processing */
01513          ast_dsp_set_digitmode(i->dsp, DSP_DIGITMODE_NOQUELCH);
01514       } else {
01515          i->dsp = NULL;
01516       }
01517       if (state == AST_STATE_RING)
01518          tmp->rings = 1;
01519 
01520       ast_best_codec(tmp->nativeformats, &tmpfmt);
01521       ast_format_copy(&tmp->writeformat, &tmpfmt);
01522       ast_format_copy(&tmp->rawwriteformat, &tmpfmt);
01523       ast_format_copy(&tmp->readformat, &tmpfmt);
01524       ast_format_copy(&tmp->rawreadformat, &tmpfmt);
01525       tmp->tech_pvt = sub;
01526       if (!ast_strlen_zero(i->language))
01527          ast_channel_language_set(tmp, i->language);
01528       if (!ast_strlen_zero(i->accountcode))
01529          ast_channel_accountcode_set(tmp, i->accountcode);
01530       if (i->amaflags)
01531          tmp->amaflags = i->amaflags;
01532       sub->owner = tmp;
01533       ast_module_ref(ast_module_info->self);
01534       tmp->callgroup = i->callgroup;
01535       tmp->pickupgroup = i->pickupgroup;
01536       ast_channel_call_forward_set(tmp, i->call_forward);
01537       ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
01538       ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
01539 
01540       /* Don't use ast_set_callerid() here because it will
01541        * generate a needless NewCallerID event */
01542       if (!ast_strlen_zero(i->cid_num)) {
01543          tmp->caller.ani.number.valid = 1;
01544          tmp->caller.ani.number.str = ast_strdup(i->cid_num);
01545       }
01546 
01547       if (!i->adsi) {
01548          tmp->adsicpe = AST_ADSI_UNAVAILABLE;
01549       }
01550       tmp->priority = 1;
01551 
01552       /* Set channel variables for this call from configuration */
01553       for (v = i->chanvars ; v ; v = v->next) {
01554          char valuebuf[1024];
01555          pbx_builtin_setvar_helper(tmp, v->name, ast_get_encoded_str(v->value, valuebuf, sizeof(valuebuf)));
01556       }
01557 
01558       if (sub->rtp) {
01559          ast_jb_configure(tmp, &global_jbconf);
01560       }
01561       if (state != AST_STATE_DOWN) {
01562          if (ast_pbx_start(tmp)) {
01563             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
01564             ast_hangup(tmp);
01565             tmp = NULL;
01566          }
01567       }
01568       ast_verb(3, "MGCP mgcp_new(%s) created in state: %s\n",
01569             ast_channel_name(tmp), ast_state2str(state));
01570    } else {
01571       ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
01572    }
01573    return tmp;
01574 }

static int mgcp_pktcgate_open ( struct cops_gate gate  )  [static]

Definition at line 2410 of file chan_mgcp.c.

References ast_debug, ast_mutex_lock, ast_mutex_unlock, cops_gate::gateid, mgcp_subchannel::lock, mgcp_subchannel::sdpsent, sub, cops_gate::tech_pvt, and transmit_modify_with_sdp().

Referenced by mgcp_alloc_pktcgate().

02411 {
02412    struct mgcp_subchannel *sub = gate->tech_pvt;
02413    if (!sub) {
02414       return 1;
02415    }
02416    ast_mutex_lock(&sub->lock);
02417    ast_debug(1, "Pktc: gate 0x%x open\n", gate->gateid);
02418    if (!sub->sdpsent) transmit_modify_with_sdp(sub, NULL, 0);
02419    ast_mutex_unlock(&sub->lock);
02420    return 1;
02421 }

static int mgcp_pktcgate_remove ( struct cops_gate gate  )  [static]

Definition at line 2387 of file chan_mgcp.c.

References AST_CAUSE_REQUESTED_CHAN_UNAVAIL, ast_channel_unlock, ast_debug, ast_mutex_lock, ast_mutex_unlock, ast_softhangup(), mgcp_subchannel::gate, GATE_CLOSED, cops_gate::gateid, mgcp_endpoint::hangupongateremove, mgcp_subchannel::lock, mgcp_subchannel::owner, mgcp_subchannel::parent, cops_gate::state, sub, and cops_gate::tech_pvt.

Referenced by mgcp_alloc_pktcgate().

02388 {
02389    struct mgcp_subchannel *sub = gate->tech_pvt;
02390 
02391    if (!sub) {
02392       return 1;
02393    }
02394 
02395    ast_mutex_lock(&sub->lock);
02396    ast_debug(1, "Pktc: gate 0x%x deleted\n", gate->gateid);
02397    if (sub->gate->state != GATE_CLOSED && sub->parent->hangupongateremove) {
02398       sub->gate = NULL;
02399       if (sub->owner) {
02400          ast_softhangup(sub->owner, AST_CAUSE_REQUESTED_CHAN_UNAVAIL);
02401          ast_channel_unlock(sub->owner);
02402       }
02403    } else {
02404       sub->gate = NULL;
02405    }
02406    ast_mutex_unlock(&sub->lock);
02407    return 1;
02408 }

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

Definition at line 708 of file chan_mgcp.c.

References __mgcp_xmit(), ast_free, ast_malloc, ast_mutex_lock, ast_mutex_unlock, ast_sched_add(), ast_tvnow(), mgcp_message::buf, DEFAULT_RETRANS, mgcp_message::expire, mgcp_message::len, mgcp_gateway::msgs, mgcp_gateway::msgs_lock, mgcp_message::next, mgcp_message::owner_ep, mgcp_message::owner_sub, mgcp_endpoint::parent, mgcp_message::retrans, retrans_pkt(), mgcp_gateway::retransid, and mgcp_message::seqno.

Referenced by find_command(), and send_request().

00710 {
00711    struct mgcp_message *msg;
00712    struct mgcp_message *cur;
00713    struct mgcp_gateway *gw;
00714    struct timeval now;
00715 
00716    if (!(msg = ast_malloc(sizeof(*msg) + len))) {
00717       return -1;
00718    }
00719    if (!(gw = ((p && p->parent) ? p->parent : NULL))) {
00720       ast_free(msg);
00721       return -1;
00722    }
00723 
00724    msg->owner_sub = sub;
00725    msg->owner_ep = p;
00726    msg->seqno = seqno;
00727    msg->next = NULL;
00728    msg->len = len;
00729    msg->retrans = 0;
00730    memcpy(msg->buf, data, msg->len);
00731 
00732    ast_mutex_lock(&gw->msgs_lock);
00733    for (cur = gw->msgs; cur && cur->next; cur = cur->next);
00734    if (cur) {
00735       cur->next = msg;
00736    } else {
00737       gw->msgs = msg;
00738    }
00739 
00740    now = ast_tvnow();
00741    msg->expire = now.tv_sec * 1000 + now.tv_usec / 1000 + DEFAULT_RETRANS;
00742 
00743    if (gw->retransid == -1)
00744       gw->retransid = ast_sched_add(sched, DEFAULT_RETRANS, retrans_pkt, (void *)gw);
00745    ast_mutex_unlock(&gw->msgs_lock);
00746    __mgcp_xmit(gw, msg->buf, msg->len);
00747    /* XXX Should schedule retransmission XXX */
00748    return 0;
00749 }

static int mgcp_prune_realtime_gateway ( struct mgcp_gateway g  )  [static]

Definition at line 3718 of file chan_mgcp.c.

References ast_debug, ast_mutex_destroy, ast_mutex_lock, ast_mutex_trylock, ast_mutex_unlock, ast_strlen_zero(), mgcp_endpoint::cmd_queue, mgcp_endpoint::cmd_queue_lock, mgcp_subchannel::cx_queue, mgcp_subchannel::cx_queue_lock, mgcp_subchannel::cxident, mgcp_endpoint::dsp, mgcp_gateway::endpoints, free, mgcp_subchannel::gate, mgcp_gateway::ha, mgcp_subchannel::lock, mgcp_endpoint::lock, MAX_SUBS, mgcp_gateway::msgs, mgcp_gateway::msgs_lock, mgcp_gateway::name, mgcp_subchannel::next, mgcp_endpoint::next, mgcp_gateway::realtime, mgcp_endpoint::rqnt_queue, mgcp_endpoint::rqnt_queue_lock, mgcp_subchannel::rtp, mgcp_endpoint::sub, and sub.

Referenced by do_monitor().

03719 {
03720    struct mgcp_endpoint *enext, *e;
03721    struct mgcp_subchannel *s, *sub;
03722    int i, prune = 1;
03723 
03724    if (g->ha || !g->realtime || ast_mutex_trylock(&g->msgs_lock) || g->msgs) {
03725       ast_mutex_unlock(&g->msgs_lock);
03726       return 0;
03727    }
03728 
03729    for (e = g->endpoints; e; e = e->next) {
03730       ast_mutex_lock(&e->lock);
03731       if (e->dsp || ast_mutex_trylock(&e->rqnt_queue_lock) || ast_mutex_trylock(&e->cmd_queue_lock)) {
03732          prune = 0;
03733       } else if (e->rqnt_queue || e->cmd_queue) {
03734          prune = 0;
03735       }
03736       s = e->sub;
03737       for (i = 0; (i < MAX_SUBS) && s; i++) {
03738          ast_mutex_lock(&s->lock);
03739          if (!ast_strlen_zero(s->cxident) || s->rtp || ast_mutex_trylock(&s->cx_queue_lock) || s->gate) {
03740             prune = 0;
03741          } else if (s->cx_queue) {
03742             prune = 0;
03743          }
03744          s = s->next;
03745       }
03746    }
03747 
03748    for (e = g->endpoints, sub = e->sub, enext = e->next; e; e = enext, enext = e->next) {
03749       for (i = 0; (i < MAX_SUBS) && sub; i++) {
03750          s = sub;
03751          sub = sub->next;
03752          ast_mutex_unlock(&s->lock);
03753          ast_mutex_unlock(&s->cx_queue_lock);
03754          if (prune) {
03755             ast_mutex_destroy(&s->lock);
03756             ast_mutex_destroy(&s->cx_queue_lock);
03757             free(s);
03758          }
03759       }
03760       ast_mutex_unlock(&e->lock);
03761       ast_mutex_unlock(&e->rqnt_queue_lock);
03762       ast_mutex_unlock(&e->cmd_queue_lock);
03763       if (prune) {
03764          ast_mutex_destroy(&e->lock);
03765          ast_mutex_destroy(&e->rqnt_queue_lock);
03766          ast_mutex_destroy(&e->cmd_queue_lock);
03767          free(e);
03768       }
03769    }
03770    if (prune) {
03771       ast_debug(1, "***** MGCP REALTIME PRUNE GW: %s\n", g->name);
03772    }
03773    return prune;
03774 }

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

Definition at line 647 of file chan_mgcp.c.

References AST_FRAME_CONTROL, and mgcp_queue_frame().

Referenced by handle_hd_hf().

00648 {
00649    struct ast_frame f = { AST_FRAME_CONTROL, { control } };
00650    return mgcp_queue_frame(sub, &f);
00651 }

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

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

00614 {
00615    for (;;) {
00616       if (sub->owner) {
00617          if (!ast_channel_trylock(sub->owner)) {
00618             ast_queue_frame(sub->owner, f);
00619             ast_channel_unlock(sub->owner);
00620             break;
00621          } else {
00622             DEADLOCK_AVOIDANCE(&sub->lock);
00623          }
00624       } else {
00625          break;
00626       }
00627    }
00628 }

static void mgcp_queue_hangup ( struct mgcp_subchannel sub  )  [static]

Definition at line 630 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(), handle_response(), and start_rtp().

00631 {
00632    for (;;) {
00633       if (sub->owner) {
00634          if (!ast_channel_trylock(sub->owner)) {
00635             ast_queue_hangup(sub->owner);
00636             ast_channel_unlock(sub->owner);
00637             break;
00638          } else {
00639             DEADLOCK_AVOIDANCE(&sub->lock);
00640          }
00641       } else {
00642          break;
00643       }
00644    }
00645 }

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

Definition at line 1231 of file chan_mgcp.c.

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

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

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

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

04842 {
04843    static int deprecated = 0;
04844 
04845    if (e) {
04846       switch (cmd) {
04847       case CLI_INIT:
04848          e->command = "mgcp reload";
04849          e->usage =
04850             "Usage: mgcp reload\n"
04851             "       'mgcp reload' is deprecated.  Please use 'reload chan_mgcp.so' instead.\n";
04852          return NULL;
04853       case CLI_GENERATE:
04854          return NULL;
04855       }
04856    }
04857 
04858    if (!deprecated && a && a->argc > 0) {
04859       ast_log(LOG_WARNING, "'mgcp reload' is deprecated.  Please use 'reload chan_mgcp.so' instead.\n");
04860       deprecated = 1;
04861    }
04862 
04863    ast_mutex_lock(&mgcp_reload_lock);
04864    if (mgcp_reloading) {
04865       ast_verbose("Previous mgcp reload not yet done\n");
04866    } else {
04867       mgcp_reloading = 1;
04868    }
04869    ast_mutex_unlock(&mgcp_reload_lock);
04870    restart_monitor();
04871    return CLI_SUCCESS;
04872 }

static struct ast_channel * mgcp_request ( const char *  type,
struct ast_format_cap cap,
const struct ast_channel requestor,
const char *  dest,
int *  cause 
) [static, read]

Definition at line 3923 of file chan_mgcp.c.

References AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, ast_channel_linkedid(), ast_copy_string(), ast_format_cap_has_joint(), ast_getformatname_multiple(), ast_log(), ast_mutex_unlock, AST_STATE_DOWN, ast_strlen_zero(), ast_verb, mgcp_endpoint::call_forward, mgcp_endpoint::callwaiting, mgcp_endpoint::dnd, find_subchannel_and_lock(), has_voicemail(), mgcp_endpoint::hookstate, mgcp_subchannel::lock, LOG_NOTICE, LOG_WARNING, mgcp_new(), MGCP_ONHOOK, mgcp_subchannel::next, mgcp_subchannel::owner, mgcp_subchannel::parent, restart_monitor(), sub, and transmit_notify_request().

03924 {
03925    struct mgcp_subchannel *sub;
03926    struct ast_channel *tmpc = NULL;
03927    char tmp[256];
03928 
03929    if (!(ast_format_cap_has_joint(cap, global_capability))) {
03930       ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap));
03931       /*return NULL;*/
03932    }
03933    ast_copy_string(tmp, dest, sizeof(tmp));
03934    if (ast_strlen_zero(tmp)) {
03935       ast_log(LOG_NOTICE, "MGCP Channels require an endpoint\n");
03936       return NULL;
03937    }
03938    if (!(sub = find_subchannel_and_lock(tmp, 0, NULL))) {
03939       ast_log(LOG_WARNING, "Unable to find MGCP endpoint '%s'\n", tmp);
03940       *cause = AST_CAUSE_UNREGISTERED;
03941       return NULL;
03942    }
03943 
03944    ast_verb(3, "MGCP mgcp_request(%s)\n", tmp);
03945    ast_verb(3, "MGCP cw: %d, dnd: %d, so: %d, sno: %d\n",
03946          sub->parent->callwaiting, sub->parent->dnd, sub->owner ? 1 : 0, sub->next->owner ? 1: 0);
03947    /* Must be busy */
03948    if (((sub->parent->callwaiting) && ((sub->owner) && (sub->next->owner))) ||
03949       ((!sub->parent->callwaiting) && (sub->owner)) ||
03950        (sub->parent->dnd && (ast_strlen_zero(sub->parent->call_forward)))) {
03951       if (sub->parent->hookstate == MGCP_ONHOOK) {
03952          if (has_voicemail(sub->parent)) {
03953             transmit_notify_request(sub,"L/vmwi(+)");
03954          } else {
03955             transmit_notify_request(sub,"L/vmwi(-)");
03956          }
03957       }
03958       *cause = AST_CAUSE_BUSY;
03959       ast_mutex_unlock(&sub->lock);
03960       return NULL;
03961    }
03962    tmpc = mgcp_new(sub->owner ? sub->next : sub, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL);
03963    ast_mutex_unlock(&sub->lock);
03964    if (!tmpc)
03965       ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
03966    restart_monitor();
03967    return tmpc;
03968 }

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

Definition at line 1200 of file chan_mgcp.c.

References ast_debug, ast_dsp_process(), ast_format_cap_iscompatible(), ast_format_cap_set(), AST_FRAME_DTMF, AST_FRAME_VOICE, ast_getformatname(), 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_subclass::format, 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().

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

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

Definition at line 1298 of file chan_mgcp.c.

References ast_debug, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_rtp_instance_dtmf_begin(), mgcp_endpoint::dtmfmode, mgcp_subchannel::lock, LOG_ERROR, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, MGCP_DTMF_RFC2833, mgcp_subchannel::parent, mgcp_subchannel::rtp, sub, 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_debug(1, "Sending DTMF using inband/hybrid\n");
01307       res = -1; /* Let asterisk play inband indications */
01308    } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
01309       ast_debug(1, "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_debug, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_rtp_instance_dtmf_end(), mgcp_endpoint::dtmfmode, mgcp_subchannel::lock, LOG_ERROR, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, MGCP_DTMF_RFC2833, mgcp_endpoint::ncs, mgcp_subchannel::parent, mgcp_subchannel::rtp, sub, 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_debug(1, "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_debug(1, "Stopping DTMF using RFC2833\n");
01332       if (sub->parent->ncs) {
01333          tmp[0] = digit;
01334          tmp[1] = '\0';
01335       } else {
01336          tmp[0] = 'D';
01337          tmp[1] = '/';
01338          tmp[2] = digit;
01339          tmp[3] = '\0';
01340       }
01341       transmit_notify_request(sub, tmp);
01342       ast_rtp_instance_dtmf_end(sub->rtp, digit);
01343    } else {
01344       ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
01345    }
01346    ast_mutex_unlock(&sub->lock);
01347 
01348    return res;
01349 }

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,
const struct ast_format_cap cap,
int  nat_active 
) [static]

Definition at line 4432 of file chan_mgcp.c.

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

04433 {
04434    /* XXX Is there such thing as video support with MGCP? XXX */
04435    struct mgcp_subchannel *sub;
04436    sub = chan->tech_pvt;
04437    if (sub && !sub->alreadygone) {
04438       transmit_modify_with_sdp(sub, rtp, cap);
04439       return 0;
04440    }
04441    return -1;
04442 }

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

Definition at line 2963 of file chan_mgcp.c.

References ast_party_caller::ani, ast_bridged_channel(), ast_canmatch_extension(), ast_channel_language(), ast_channel_name(), ast_copy_string(), ast_db_put(), ast_debug, ast_exists_extension(), ast_hangup(), ast_ignore_pattern(), ast_indicate(), ast_log(), ast_masq_park_call_exten(), ast_matchmore_extension(), AST_MAX_EXTENSION, ast_parking_ext_valid(), 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_strdup, ast_strlen_zero(), ast_verb, ast_waitfordigit(), mgcp_endpoint::call_forward, ast_channel::caller, mgcp_endpoint::callreturn, mgcp_endpoint::callwaiting, mgcp_endpoint::cancallforward, mgcp_endpoint::cid_name, mgcp_endpoint::cid_num, ast_channel::context, ast_channel::dialed, mgcp_endpoint::dnd, mgcp_endpoint::dtmf_buf, mgcp_endpoint::dtmfmode, exten, ast_channel::exten, mgcp_endpoint::hascallwaiting, mgcp_endpoint::hidecallerid, ast_party_caller::id, mgcp_endpoint::lastcallerid, len(), LOG_WARNING, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, mgcp_gateway::name, mgcp_endpoint::name, mgcp_endpoint::ncs, mgcp_subchannel::next, ast_party_id::number, ast_party_dialed::number, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_subchannel::parent, ast_channel::rings, S_COR, start_rtp(), ast_party_number::str, ast_party_dialed::str, sub, ast_channel::tech_pvt, transmit_notify_request(), and ast_party_number::valid.

Referenced by handle_hd_hf().

02964 {
02965    struct ast_channel *chan = data;
02966    struct mgcp_subchannel *sub = chan->tech_pvt;
02967    struct mgcp_endpoint *p = sub->parent;
02968    /* char exten[AST_MAX_EXTENSION] = ""; */
02969    int len = 0;
02970    int timeout = firstdigittimeout;
02971    int res= 0;
02972    int getforward = 0;
02973    int loop_pause = 100;
02974 
02975    len = strlen(p->dtmf_buf);
02976 
02977    while (len < AST_MAX_EXTENSION - 1) {
02978       ast_debug(1, "Dtmf buffer '%s' for '%s@%s'\n", p->dtmf_buf, p->name, p->parent->name);
02979       res = 1;  /* Assume that we will get a digit */
02980       while (strlen(p->dtmf_buf) == len) {
02981          ast_safe_sleep(chan, loop_pause);
02982          timeout -= loop_pause;
02983          if (timeout <= 0){
02984             res = 0;
02985             break;
02986          }
02987          res = 1;
02988       }
02989 
02990       timeout = 0;
02991       len = strlen(p->dtmf_buf);
02992 
02993       if (!ast_ignore_pattern(chan->context, p->dtmf_buf)) {
02994          /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
02995          ast_indicate(chan, -1);
02996       } else {
02997          /* XXX Redundant?  We should already be playing dialtone */
02998          /*tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALTONE);*/
02999          transmit_notify_request(sub, "L/dl");
03000       }
03001       if (ast_exists_extension(chan, chan->context, p->dtmf_buf, 1, p->cid_num)) {
03002          if (!res || !ast_matchmore_extension(chan, chan->context, p->dtmf_buf, 1, p->cid_num)) {
03003             if (getforward) {
03004                /* Record this as the forwarding extension */
03005                ast_copy_string(p->call_forward, p->dtmf_buf, sizeof(p->call_forward));
03006                ast_verb(3, "Setting call forward to '%s' on channel %s\n",
03007                      p->call_forward, ast_channel_name(chan));
03008                /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03009                transmit_notify_request(sub, "L/sl");
03010                if (res)
03011                   break;
03012                usleep(500000);
03013                /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
03014                ast_indicate(chan, -1);
03015                sleep(1);
03016                memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03017                /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALTONE);*/
03018                transmit_notify_request(sub, "L/dl");
03019                len = 0;
03020                getforward = 0;
03021             } else {
03022                /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
03023                ast_indicate(chan, -1);
03024                ast_copy_string(chan->exten, p->dtmf_buf, sizeof(chan->exten));
03025                chan->dialed.number.str = ast_strdup(p->dtmf_buf);
03026                memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03027                ast_set_callerid(chan,
03028                   p->hidecallerid ? "" : p->cid_num,
03029                   p->hidecallerid ? "" : p->cid_name,
03030                   chan->caller.ani.number.valid ? NULL : p->cid_num);
03031                ast_setstate(chan, AST_STATE_RING);
03032                /*dahdi_enable_ec(p);*/
03033                if (p->dtmfmode & MGCP_DTMF_HYBRID) {
03034                   p->dtmfmode |= MGCP_DTMF_INBAND;
03035                   ast_indicate(chan, -1);
03036                }
03037                res = ast_pbx_run(chan);
03038                if (res) {
03039                   ast_log(LOG_WARNING, "PBX exited non-zero\n");
03040                   /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
03041                   /*transmit_notify_request(p, "nbz", 1);*/
03042                   transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
03043                }
03044                return NULL;
03045             }
03046          } else {
03047             /* It's a match, but they just typed a digit, and there is an ambiguous match,
03048                so just set the timeout to matchdigittimeout and wait some more */
03049             timeout = matchdigittimeout;
03050          }
03051       } else if (res == 0) {
03052          ast_debug(1, "not enough digits (and no ambiguous match)...\n");
03053          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
03054          transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
03055          /*dahdi_wait_event(p->subs[index].zfd);*/
03056          ast_hangup(chan);
03057          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03058          return NULL;
03059       } else if (p->hascallwaiting && p->callwaiting && !strcmp(p->dtmf_buf, "*70")) {
03060          ast_verb(3, "Disabling call waiting on %s\n", ast_channel_name(chan));
03061          /* Disable call waiting if enabled */
03062          p->callwaiting = 0;
03063          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03064          transmit_notify_request(sub, "L/sl");
03065          len = 0;
03066          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03067          timeout = firstdigittimeout;
03068       } else if (!strcmp(p->dtmf_buf,ast_pickup_ext())) {
03069          /* Scan all channels and see if any there
03070           * ringing channqels with that have call groups
03071           * that equal this channels pickup group
03072           */
03073          if (ast_pickup_call(chan)) {
03074             ast_log(LOG_WARNING, "No call pickup possible...\n");
03075             /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
03076             transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
03077          }
03078          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03079          ast_hangup(chan);
03080          return NULL;
03081       } else if (!p->hidecallerid && !strcmp(p->dtmf_buf, "*67")) {
03082          ast_verb(3, "Disabling Caller*ID on %s\n", ast_channel_name(chan));
03083          /* Disable Caller*ID if enabled */
03084          p->hidecallerid = 1;
03085          ast_set_callerid(chan, "", "", NULL);
03086          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03087          transmit_notify_request(sub, "L/sl");
03088          len = 0;
03089          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03090          timeout = firstdigittimeout;
03091       } else if (p->callreturn && !strcmp(p->dtmf_buf, "*69")) {
03092          res = 0;
03093          if (!ast_strlen_zero(p->lastcallerid)) {
03094             res = ast_say_digit_str(chan, p->lastcallerid, "", ast_channel_language(chan));
03095          }
03096          if (!res)
03097             /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03098             transmit_notify_request(sub, "L/sl");
03099          break;
03100       } else if (!strcmp(p->dtmf_buf, "*78")) {
03101          /* Do not disturb */
03102          ast_verb(3, "Enabled DND on channel %s\n", ast_channel_name(chan));
03103          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03104          transmit_notify_request(sub, "L/sl");
03105          p->dnd = 1;
03106          getforward = 0;
03107          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03108          len = 0;
03109       } else if (!strcmp(p->dtmf_buf, "*79")) {
03110          /* Do not disturb */
03111          ast_verb(3, "Disabled DND on channel %s\n", ast_channel_name(chan));
03112          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03113          transmit_notify_request(sub, "L/sl");
03114          p->dnd = 0;
03115          getforward = 0;
03116          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03117          len = 0;
03118       } else if (p->cancallforward && !strcmp(p->dtmf_buf, "*72")) {
03119          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03120          transmit_notify_request(sub, "L/sl");
03121          getforward = 1;
03122          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03123          len = 0;
03124       } else if (p->cancallforward && !strcmp(p->dtmf_buf, "*73")) {
03125          ast_verb(3, "Cancelling call forwarding on channel %s\n", ast_channel_name(chan));
03126          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03127          transmit_notify_request(sub, "L/sl");
03128          memset(p->call_forward, 0, sizeof(p->call_forward));
03129          getforward = 0;
03130          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03131          len = 0;
03132       } else if (ast_parking_ext_valid(p->dtmf_buf, chan, chan->context) &&
03133          sub->next->owner && ast_bridged_channel(sub->next->owner)) {
03134          /* This is a three way call, the main call being a real channel,
03135             and we're parking the first call. */
03136          ast_masq_park_call_exten(ast_bridged_channel(sub->next->owner), chan,
03137             p->dtmf_buf, chan->context, 0, NULL);
03138          ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
03139          break;
03140       } else if (!ast_strlen_zero(p->lastcallerid) && !strcmp(p->dtmf_buf, "*60")) {
03141          ast_verb(3, "Blacklisting number %s\n", p->lastcallerid);
03142          res = ast_db_put("blacklist", p->lastcallerid, "1");
03143          if (!res) {
03144             /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03145             transmit_notify_request(sub, "L/sl");
03146             memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03147             len = 0;
03148          }
03149       } else if (p->hidecallerid && !strcmp(p->dtmf_buf, "*82")) {
03150          ast_verb(3, "Enabling Caller*ID on %s\n", ast_channel_name(chan));
03151          /* Enable Caller*ID if enabled */
03152          p->hidecallerid = 0;
03153          ast_set_callerid(chan, p->cid_num, p->cid_name, NULL);
03154          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03155          transmit_notify_request(sub, "L/sl");
03156          len = 0;
03157          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03158          timeout = firstdigittimeout;
03159       } else if (!ast_canmatch_extension(chan, chan->context, p->dtmf_buf, 1,
03160          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))
03161          && ((p->dtmf_buf[0] != '*') || (strlen(p->dtmf_buf) > 2))) {
03162          ast_debug(1, "Can't match %s from '%s' in context %s\n", p->dtmf_buf,
03163             S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, "<Unknown Caller>"),
03164             chan->context);
03165          break;
03166       }
03167       if (!timeout)
03168          timeout = gendigittimeout;
03169       if (len && !ast_ignore_pattern(chan->context, p->dtmf_buf))
03170          /*tone_zone_play_tone(p->subs[index].zfd, -1);*/
03171          ast_indicate(chan, -1);
03172    }
03173 #if 0
03174    for (;;) {
03175       res = ast_waitfordigit(chan, to);
03176       if (!res) {
03177          ast_debug(1, "Timeout...\n");
03178          break;
03179       }
03180       if (res < 0) {
03181          ast_debug(1, "Got hangup...\n");
03182          ast_hangup(chan);
03183          break;
03184       }
03185       exten[pos++] = res;
03186       if (!ast_ignore_pattern(chan->context, exten))
03187          ast_indicate(chan, -1);
03188       if (ast_matchmore_extension(chan, chan->context, exten, 1, chan->callerid)) {
03189          if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid))
03190             to = 3000;
03191          else
03192             to = 8000;
03193       } else
03194          break;
03195    }
03196    if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid)) {
03197       ast_copy_string(chan->exten, exten, sizeof(chan->exten)1);
03198       if (!p->rtp) {
03199          start_rtp(p);
03200       }
03201       ast_setstate(chan, AST_STATE_RING);
03202       chan->rings = 1;
03203       if (ast_pbx_run(chan)) {
03204          ast_log(LOG_WARNING, "Unable to launch PBX on %s\n", chan->name);
03205       } else {
03206          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03207          return NULL;
03208       }
03209    }
03210 #endif
03211    ast_hangup(chan);
03212    memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03213    return NULL;
03214 }

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

Definition at line 1241 of file chan_mgcp.c.

References ast_debug, ast_format_cap_iscompatible(), AST_FRAME_IMAGE, AST_FRAME_VOICE, ast_getformatname(), ast_getformatname_multiple(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_rtp_instance_write(), ast_frame_subclass::format, ast_frame::frametype, mgcp_subchannel::gate, GATE_ALLOCATED, mgcp_subchannel::lock, LOG_WARNING, ast_channel::nativeformats, mgcp_subchannel::parent, ast_channel::readformat, mgcp_subchannel::rtp, mgcp_subchannel::sdpsent, mgcp_endpoint::singlepath, cops_gate::state, mgcp_endpoint::sub, sub, ast_frame::subclass, ast_channel::tech_pvt, transmit_modify_with_sdp(), and ast_channel::writeformat.

01242 {
01243    struct mgcp_subchannel *sub = ast->tech_pvt;
01244    int res = 0;
01245    char buf[256];
01246 
01247    if (frame->frametype != AST_FRAME_VOICE) {
01248       if (frame->frametype == AST_FRAME_IMAGE)
01249          return 0;
01250       else {
01251          ast_log(LOG_WARNING, "Can't send %d type frames with MGCP write\n", frame->frametype);
01252          return 0;
01253       }
01254    } else {
01255       if (!(ast_format_cap_iscompatible(ast->nativeformats, &frame->subclass.format))) {
01256          ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
01257             ast_getformatname(&frame->subclass.format),
01258             ast_getformatname_multiple(buf, sizeof(buf), ast->nativeformats),
01259             ast_getformatname(&ast->readformat),
01260             ast_getformatname(&ast->writeformat));
01261          /* return -1; */
01262       }
01263    }
01264    if (sub) {
01265       ast_mutex_lock(&sub->lock);
01266       if (!sub->sdpsent && sub->gate) {
01267          if (sub->gate->state == GATE_ALLOCATED) {
01268             ast_debug(1, "GATE ALLOCATED, sending sdp\n");
01269             transmit_modify_with_sdp(sub, NULL, 0);
01270          }
01271       }
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 3627 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(), 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, sub, mgcp_request::verb, and mgcp_request::version.

Referenced by do_monitor().

03628 {
03629    struct mgcp_request req;
03630    struct sockaddr_in sin;
03631    struct mgcp_subchannel *sub;
03632    int res;
03633    socklen_t len;
03634    int result;
03635    int ident;
03636    len = sizeof(sin);
03637    memset(&req, 0, sizeof(req));
03638    res = recvfrom(mgcpsock, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len);
03639    if (res < 0) {
03640       if (errno != ECONNREFUSED)
03641          ast_log(LOG_WARNING, "Recv error: %s\n", strerror(errno));
03642       return 1;
03643    }
03644    req.data[res] = '\0';
03645    req.len = res;
03646    ast_debug(1, "MGCP read: \n%s\nfrom %s:%d\n", req.data, ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
03647    parse(&req);
03648    if (req.headers < 1) {
03649       /* Must have at least one header */
03650       return 1;
03651    }
03652    if (ast_strlen_zero(req.identifier)) {
03653       ast_log(LOG_NOTICE, "Message from %s missing identifier\n", ast_inet_ntoa(sin.sin_addr));
03654       return 1;
03655    }
03656 
03657    if (sscanf(req.verb, "%30d", &result) && sscanf(req.identifier, "%30d", &ident)) {
03658       if (result < 200) {
03659          ast_debug(1, "Ignoring provisional response on transaction %d\n", ident);
03660          return 1;
03661       }
03662       /* Try to find who this message is for, if it's important */
03663       sub = find_subchannel_and_lock(NULL, ident, &sin);
03664       if (sub) {
03665          struct mgcp_gateway *gw = sub->parent->parent;
03666          struct mgcp_message *cur, *prev;
03667 
03668          ast_mutex_unlock(&sub->lock);
03669          ast_mutex_lock(&gw->msgs_lock);
03670          for (prev = NULL, cur = gw->msgs; cur; prev = cur, cur = cur->next) {
03671             if (cur->seqno == ident) {
03672                ast_debug(1, "Got response back on transaction %d\n", ident);
03673                if (prev)
03674                   prev->next = cur->next;
03675                else
03676                   gw->msgs = cur->next;
03677                break;
03678             }
03679          }
03680 
03681          /* stop retrans timer if the queue is empty */
03682          if (!gw->msgs) {
03683             AST_SCHED_DEL(sched, gw->retransid);
03684          }
03685 
03686          ast_mutex_unlock(&gw->msgs_lock);
03687          if (cur) {
03688             handle_response(cur->owner_ep, cur->owner_sub, result, ident, &req);
03689             ast_free(cur);
03690             return 1;
03691          }
03692 
03693          ast_log(LOG_NOTICE, "Got response back on [%s] for transaction %d we aren't sending?\n",
03694             gw->name, ident);
03695       }
03696    } else {
03697       if (ast_strlen_zero(req.endpoint) ||
03698          ast_strlen_zero(req.version) ||
03699          ast_strlen_zero(req.verb)) {
03700          ast_log(LOG_NOTICE, "Message must have a verb, an idenitifier, version, and endpoint\n");
03701          return 1;
03702       }
03703       /* Process request, with iflock held */
03704       sub = find_subchannel_and_lock(req.endpoint, 0, &sin);
03705       if (sub) {
03706          /* look first to find a matching response in the queue */
03707          if (!find_and_retrans(sub, &req))
03708             /* pass the request off to the currently mastering subchannel */
03709             handle_request(sub, &req, &sin);
03710          ast_mutex_unlock(&sub->lock);
03711       }
03712    }
03713    return 1;
03714 }

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

Definition at line 482 of file chan_mgcp.c.

00483 {
00484    /* This module does not handle MWI in an event-based manner.  However, it
00485     * subscribes to MWI for each mailbox that is configured so that the core
00486     * knows that we care about it.  Then, chan_mgcp will get the MWI from the
00487     * event cache instead of checking the mailbox directly. */
00488 }

static void parse ( struct mgcp_request req  )  [static]

Definition at line 1857 of file chan_mgcp.c.

References ast_debug, ast_log(), ast_strlen_zero(), 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_jabberreceive_read(), acf_meetme_info(), acf_vm_info(), add_agent(), add_hintdevice(), app_exec(), aqm_exec(), ast_masq_park_call_exten(), ast_park_call_exten(), ast_parse_allow_disallow(), celgenuserevent_exec(), chanspy_exec(), conf_exec(), conf_run(), confbridge_exec(), config_function_read(), cut_internal(), dial_exec_full(), dictate_exec(), directory_exec(), dundi_query_read(), dundi_result_read(), dundifunc_read(), enum_query_read(), enum_result_read(), execif_exec(), extenspy_exec(), find_conf(), func_confbridge_info(), function_agent(), get_comma(), get_in_brackets_full(), iconv_read(), isAnsweringMachine(), isexten_function_read(), jb_framedata_init(), log_exec(), login_exec(), man_do_variable_value(), mgcpsock_read(), mixmonitor_exec(), msg_send_exec(), originate_exec(), oss_call(), oss_request(), page_exec(), park_call_exec(), parked_call_exec(), pbx_builtin_answer(), pbx_builtin_background(), pbx_builtin_waitexten(), pickupchan_exec(), play_moh_exec(), pqm_exec(), privacy_exec(), ql_exec(), queue_exec(), rcvfax_exec(), receivefax_exec(), record_exec(), reload_single_member(), retrydial_exec(), rqm_exec(), saycountedadj_exec(), saycountednoun_exec(), sayunixtime_exec(), sendfax_exec(), sip_acf_channel_read(), sip_parse_nat_option(), sla_trunk_exec(), smdi_msg_read(), smdi_msg_retrieve_read(), sms_exec(), sndfax_exec(), softhangup_exec(), speech_background(), srv_result_read(), start_moh_exec(), start_monitor_exec(), stop_mixmonitor_exec(), transfer_exec(), upqm_exec(), userevent_exec(), verbose_exec(), vm_execmain(), xfer_park_call_helper(), and zapateller_exec().

01858 {
01859    /* Divide fields by NULL's */
01860    char *c;
01861    int f = 0;
01862    c = req->data;
01863 
01864    /* First header starts immediately */
01865    req->header[f] = c;
01866    for (; *c; c++) {
01867       if (*c == '\n') {
01868          /* We've got a new header */
01869          *c = 0;
01870          ast_debug(3, "Header: %s (%d)\n", req->header[f], (int) strlen(req->header[f]));
01871          if (ast_strlen_zero(req->header[f])) {
01872             /* Line by itself means we're now in content */
01873             c++;
01874             break;
01875          }
01876          if (f >= MGCP_MAX_HEADERS - 1) {
01877             ast_log(LOG_WARNING, "Too many MGCP headers...\n");
01878          } else {
01879             f++;
01880          }
01881          req->header[f] = c + 1;
01882       } else if (*c == '\r') {
01883          /* Ignore but eliminate \r's */
01884          *c = 0;
01885       }
01886    }
01887    /* Check for last header */
01888    if (!ast_strlen_zero(req->header[f])) {
01889       f++;
01890    }
01891    req->headers = f;
01892    /* Now we process any mime content */
01893    f = 0;
01894    req->line[f] = c;
01895    for (; *c; c++) {
01896       if (*c == '\n') {
01897          /* We've got a new line */
01898          *c = 0;
01899          ast_debug(3, "Line: %s (%d)\n", req->line[f], (int) strlen(req->line[f]));
01900          if (f >= MGCP_MAX_LINES - 1) {
01901             ast_log(LOG_WARNING, "Too many SDP lines...\n");
01902          } else {
01903             f++;
01904          }
01905          req->line[f] = c + 1;
01906       } else if (*c == '\r') {
01907          /* Ignore and eliminate \r's */
01908          *c = 0;
01909       }
01910    }
01911    /* Check for last line */
01912    if (!ast_strlen_zero(req->line[f])) {
01913       f++;
01914    }
01915    req->lines = f;
01916    /* Parse up the initial header */
01917    c = req->header[0];
01918    while (*c && *c < 33) c++;
01919    /* First the verb */
01920    req->verb = c;
01921    while (*c && (*c > 32)) c++;
01922    if (*c) {
01923       *c = '\0';
01924       c++;
01925       while (*c && (*c < 33)) c++;
01926       req->identifier = c;
01927       while (*c && (*c > 32)) c++;
01928       if (*c) {
01929          *c = '\0';
01930          c++;
01931          while (*c && (*c < 33)) c++;
01932          req->endpoint = c;
01933          while (*c && (*c > 32)) c++;
01934          if (*c) {
01935             *c = '\0';
01936             c++;
01937             while (*c && (*c < 33)) c++;
01938             req->version = c;
01939             while (*c && (*c > 32)) c++;
01940             while (*c && (*c < 33)) c++;
01941             while (*c && (*c > 32)) c++;
01942             *c = '\0';
01943          }
01944       }
01945    }
01946 
01947    ast_debug(1, "Verb: '%s', Identifier: '%s', Endpoint: '%s', Version: '%s'\n",
01948          req->verb, req->identifier, req->endpoint, req->version);
01949    ast_debug(1, "%d headers, %d lines\n", req->headers, req->lines);
01950    if (*c) {
01951       ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c);
01952    }
01953 }

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

Definition at line 1955 of file chan_mgcp.c.

References ast_debug, ast_format_cap_alloc_nolock(), ast_format_cap_destroy(), ast_format_cap_is_empty(), ast_format_cap_joint_copy(), ast_getformatname_multiple(), 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_sockaddr_from_sin, ast_strdupa, ast_strlen_zero(), mgcp_endpoint::cap, 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().

01956 {
01957    char *m;
01958    char *c;
01959    char *a;
01960    char host[258];
01961    int len;
01962    int portno;
01963    struct ast_format_cap *peercap;
01964    int peerNonCodecCapability;
01965    struct sockaddr_in sin;
01966    struct ast_sockaddr sin_tmp;
01967    char *codecs;
01968    struct ast_hostent ahp; struct hostent *hp;
01969    int codec, codec_count=0;
01970    int iterator;
01971    struct mgcp_endpoint *p = sub->parent;
01972    char tmp1[256], tmp2[256], tmp3[256];
01973 
01974    /* Get codec and RTP info from SDP */
01975    m = get_sdp(req, "m");
01976    c = get_sdp(req, "c");
01977    if (ast_strlen_zero(m) || ast_strlen_zero(c)) {
01978       ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s', c = '%s')\n", m, c);
01979       return -1;
01980    }
01981    if (sscanf(c, "IN IP4 %256s", host) != 1) {
01982       ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
01983       return -1;
01984    }
01985    /* XXX This could block for a long time, and block the main thread! XXX */
01986    hp = ast_gethostbyname(host, &ahp);
01987    if (!hp) {
01988       ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c);
01989       return -1;
01990    }
01991    if (sscanf(m, "audio %30d RTP/AVP %n", &portno, &len) != 1) {
01992       ast_log(LOG_WARNING, "Unable to determine port number for RTP in '%s'\n", m);
01993       return -1;
01994    }
01995    sin.sin_family = AF_INET;
01996    memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
01997    sin.sin_port = htons(portno);
01998    ast_sockaddr_from_sin(&sin_tmp, &sin);
01999    ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp);
02000    ast_debug(3, "Peer RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
02001    /* Scan through the RTP payload types specified in a "m=" line: */
02002    ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp);
02003    codecs = ast_strdupa(m + len);
02004    while (!ast_strlen_zero(codecs)) {
02005       if (sscanf(codecs, "%30d%n", &codec, &len) != 1) {
02006          if (codec_count) {
02007             break;
02008          }
02009          ast_log(LOG_WARNING, "Error in codec string '%s' at '%s'\n", m, codecs);
02010          return -1;
02011       }
02012       ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp, codec);
02013       codec_count++;
02014       codecs += len;
02015    }
02016 
02017    /* Next, scan through each "a=rtpmap:" line, noting each */
02018    /* specified RTP payload type (with corresponding MIME subtype): */
02019    sdpLineNum_iterator_init(&iterator);
02020    while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
02021       char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
02022       if (sscanf(a, "rtpmap: %30u %127[^/]/", &codec, mimeSubtype) != 2)
02023          continue;
02024       /* Note: should really look at the 'freq' and '#chans' params too */
02025       ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp, codec, "audio", mimeSubtype, 0);
02026    }
02027 
02028    /* Now gather all of the codecs that were asked for: */
02029    if (!(peercap = ast_format_cap_alloc_nolock())) {
02030       return -1;
02031    }
02032    ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(sub->rtp), peercap, &peerNonCodecCapability);
02033    ast_format_cap_joint_copy(global_capability, peercap, p->cap);
02034    ast_debug(1, "Capabilities: us - %s, them - %s, combined - %s\n",
02035       ast_getformatname_multiple(tmp1, sizeof(tmp1), global_capability),
02036       ast_getformatname_multiple(tmp2, sizeof(tmp2), peercap),
02037       ast_getformatname_multiple(tmp3, sizeof(tmp3), p->cap));
02038    peercap = ast_format_cap_destroy(peercap);
02039 
02040    ast_debug(1, "Non-codec capabilities: us - %d, them - %d, combined - %d\n",
02041       nonCodecCapability, peerNonCodecCapability, p->nonCodecCapability);
02042    if (ast_format_cap_is_empty(p->cap)) {
02043       ast_log(LOG_WARNING, "No compatible codecs!\n");
02044       return -1;
02045    }
02046    return 0;
02047 }

static void prune_gateways ( void   )  [static]

Definition at line 4547 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, mgcp_endpoint::next, and mgcp_gateway::realtime.

Referenced by reload_config(), and unload_module().

04548 {
04549    struct mgcp_gateway *g, *z, *r;
04550    struct mgcp_endpoint *e, *p, *t;
04551 
04552    ast_mutex_lock(&gatelock);
04553 
04554    /* prune gateways */
04555    for (z = NULL, g = gateways; g;) {
04556       /* prune endpoints */
04557       for (p = NULL, e = g->endpoints; e; ) {
04558          if (!g->realtime && (e->delme || g->delme)) {
04559             t = e;
04560             e = e->next;
04561             if (!p)
04562                g->endpoints = e;
04563             else
04564                p->next = e;
04565             destroy_endpoint(t);
04566          } else {
04567             p = e;
04568             e = e->next;
04569          }
04570       }
04571 
04572       if (g->delme) {
04573          r = g;
04574          g = g->next;
04575          if (!z)
04576             gateways = g;
04577          else
04578             z->next = g;
04579 
04580          destroy_gateway(r);
04581       } else {
04582          z = g;
04583          g = g->next;
04584       }
04585    }
04586 
04587    ast_mutex_unlock(&gatelock);
04588 }

static int reload ( void   )  [static]

Definition at line 4874 of file chan_mgcp.c.

References mgcp_reload().

04875 {
04876    mgcp_reload(NULL, 0, NULL);
04877    return 0;
04878 }

static int reload_config ( int  reload  )  [static]

Definition at line 4622 of file chan_mgcp.c.

References __ourip, ast_category_browse(), ast_config_destroy(), ast_config_load, ast_format_cap_add(), ast_format_cap_remove(), 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, gatelock, gateways, global_jbconf, hp, ast_format::id, ast_variable::lineno, LOG_ERROR, LOG_NOTICE, LOG_WARNING, mgcp_endpoint::name, mgcp_gateway::name, ast_variable::name, mgcp_endpoint::needaudit, netlock, mgcp_endpoint::next, mgcp_gateway::next, ast_variable::next, prune_gateways(), qos, transmit_audit_endpoint(), and ast_variable::value.

04623 {
04624    struct ast_config *cfg;
04625    struct ast_variable *v;
04626    struct mgcp_gateway *g;
04627    struct mgcp_endpoint *e;
04628    char *cat;
04629    struct ast_hostent ahp;
04630    struct hostent *hp;
04631    struct ast_format format;
04632    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
04633    
04634    if (gethostname(ourhost, sizeof(ourhost)-1)) {
04635       ast_log(LOG_WARNING, "Unable to get hostname, MGCP disabled\n");
04636       return 0;
04637    }
04638    cfg = ast_config_load(config, config_flags);
04639 
04640    /* We *must* have a config file otherwise stop immediately */
04641    if (!cfg) {
04642       ast_log(LOG_NOTICE, "Unable to load config %s, MGCP disabled\n", config);
04643       return 0;
04644    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
04645       return 0;
04646    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
04647       ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", config);
04648       return 0;
04649    }
04650 
04651    memset(&bindaddr, 0, sizeof(bindaddr));
04652    dtmfmode = 0;
04653 
04654    /* Copy the default jb config over global_jbconf */
04655    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
04656 
04657    for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
04658       /* handle jb conf */
04659       if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
04660          continue;
04661       }
04662 
04663       /* Create the interface list */
04664       if (!strcasecmp(v->name, "bindaddr")) {
04665          if (!(hp = ast_gethostbyname(v->value, &ahp))) {
04666             ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
04667          } else {
04668             memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
04669          }
04670       } else if (!strcasecmp(v->name, "allow")) {
04671          ast_getformatbyname(v->value, &format);
04672          if (!format.id) {
04673             ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
04674          } else {
04675             ast_format_cap_add(global_capability, &format);
04676          }
04677       } else if (!strcasecmp(v->name, "disallow")) {
04678          ast_getformatbyname(v->value, &format);
04679          if (!format.id) {
04680             ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
04681          } else {
04682             ast_format_cap_remove(global_capability, &format);
04683          }
04684       } else if (!strcasecmp(v->name, "tos")) {
04685          if (ast_str2tos(v->value, &qos.tos)) {
04686              ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
04687          }
04688       } else if (!strcasecmp(v->name, "tos_audio")) {
04689          if (ast_str2tos(v->value, &qos.tos_audio))
04690              ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);
04691       } else if (!strcasecmp(v->name, "cos")) {
04692          if (ast_str2cos(v->value, &qos.cos))
04693              ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno);
04694       } else if (!strcasecmp(v->name, "cos_audio")) {
04695          if (ast_str2cos(v->value, &qos.cos_audio))
04696              ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);
04697       } else if (!strcasecmp(v->name, "port")) {
04698          if (sscanf(v->value, "%5d", &ourport) == 1) {
04699             bindaddr.sin_port = htons(ourport);
04700          } else {
04701             ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
04702          }
04703       } else if (!strcasecmp(v->name, "firstdigittimeout")) {
04704          firstdigittimeout = atoi(v->value);
04705       } else if (!strcasecmp(v->name, "gendigittimeout")) {
04706          gendigittimeout = atoi(v->value);
04707       } else if (!strcasecmp(v->name, "matchdigittimeout")) {
04708          matchdigittimeout = atoi(v->value);
04709       }
04710    }
04711 
04712    /* mark existing entries for deletion */
04713    ast_mutex_lock(&gatelock);
04714    for (g = gateways; g; g = g->next) {
04715       g->delme = 1;
04716       for (e = g->endpoints; e; e = e->next) {
04717          e->delme = 1;
04718       }
04719    }
04720    ast_mutex_unlock(&gatelock);
04721 
04722    for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
04723       if (strcasecmp(cat, "general")) {
04724          ast_mutex_lock(&gatelock);
04725          if ((g = build_gateway(cat, ast_variable_browse(cfg, cat)))) {
04726             ast_verb(3, "Added gateway '%s'\n", g->name);
04727             g->next = gateways;
04728             gateways = g;
04729          }
04730          ast_mutex_unlock(&gatelock);
04731 
04732          /* FS: process queue and IO */
04733          if (monitor_thread == pthread_self()) {
04734             if (sched) ast_sched_runq(sched);
04735             if (io) ast_io_wait(io, 10);
04736          }
04737       }
04738    }
04739 
04740    /* prune deleted entries etc. */
04741    prune_gateways();
04742 
04743    if (ntohl(bindaddr.sin_addr.s_addr)) {
04744       memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
04745    } else {
04746       hp = ast_gethostbyname(ourhost, &ahp);
04747       if (!hp) {
04748          ast_log(LOG_WARNING, "Unable to get our IP address, MGCP disabled\n");
04749          ast_config_destroy(cfg);
04750          return 0;
04751       }
04752       memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
04753    }
04754    if (!ntohs(bindaddr.sin_port))
04755       bindaddr.sin_port = htons(DEFAULT_MGCP_CA_PORT);
04756    bindaddr.sin_family = AF_INET;
04757    ast_mutex_lock(&netlock);
04758    if (mgcpsock > -1)
04759       close(mgcpsock);
04760 
04761    if (mgcpsock_read_id != NULL)
04762       ast_io_remove(io, mgcpsock_read_id);
04763    mgcpsock_read_id = NULL;
04764 
04765    mgcpsock = socket(AF_INET, SOCK_DGRAM, 0);
04766    if (mgcpsock < 0) {
04767       ast_log(LOG_WARNING, "Unable to create MGCP socket: %s\n", strerror(errno));
04768    } else {
04769       if (bind(mgcpsock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
04770          ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
04771             ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
04772                strerror(errno));
04773          close(mgcpsock);
04774          mgcpsock = -1;
04775       } else {
04776          ast_verb(2, "MGCP Listening on %s:%d\n",
04777                ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
04778          ast_netsock_set_qos(mgcpsock, qos.tos, qos.cos, "MGCP");
04779       }
04780    }
04781    ast_mutex_unlock(&netlock);
04782    ast_config_destroy(cfg);
04783 
04784    /* send audit only to the new endpoints */
04785    for (g = gateways; g; g = g->next) {
04786       for (e = g->endpoints; e && e->needaudit; e = e->next) {
04787          e->needaudit = 0;
04788          transmit_audit_endpoint(e);
04789          ast_verb(3, "MGCP Auditing endpoint %s@%s for hookstate\n", e->name, g->name);
04790       }
04791    }
04792 
04793    return 0;
04794 }

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

References __mgcp_xmit(), mgcp_gateway::addr, ast_debug, ast_inet_ntoa(), mgcp_response::buf, mgcp_response::len, mgcp_endpoint::parent, and mgcp_subchannel::parent.

Referenced by find_and_retrans().

00557 {
00558    struct mgcp_endpoint *p = sub->parent;
00559    int res;
00560    ast_debug(1, "Retransmitting:\n%s\n to %s:%d\n", resp->buf, ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
00561    res = __mgcp_xmit(p->parent, resp->buf, resp->len);
00562    if (res > 0)
00563       res = 0;
00564    return res;
00565 }

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

03895 {
03896    /* If we're supposed to be stopped -- stay stopped */
03897    if (monitor_thread == AST_PTHREADT_STOP)
03898       return 0;
03899    if (ast_mutex_lock(&monlock)) {
03900       ast_log(LOG_WARNING, "Unable to lock monitor\n");
03901       return -1;
03902    }
03903    if (monitor_thread == pthread_self()) {
03904       ast_mutex_unlock(&monlock);
03905       ast_log(LOG_WARNING, "Cannot kill myself\n");
03906       return -1;
03907    }
03908    if (monitor_thread != AST_PTHREADT_NULL) {
03909       /* Wake up the thread */
03910       pthread_kill(monitor_thread, SIGURG);
03911    } else {
03912       /* Start a new monitor */
03913       if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
03914          ast_mutex_unlock(&monlock);
03915          ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
03916          return -1;
03917       }
03918    }
03919    ast_mutex_unlock(&monlock);
03920    return 0;
03921 }

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

Definition at line 653 of file chan_mgcp.c.

References __mgcp_xmit(), ast_debug, ast_free, ast_log(), ast_mutex_lock, ast_mutex_unlock, mgcp_message::buf, handle_response(), mgcp_message::len, LOG_WARNING, MAX_RETRANS, mgcp_gateway::msgs, mgcp_gateway::msgs_lock, mgcp_gateway::name, mgcp_message::next, mgcp_message::owner_ep, mgcp_message::owner_sub, mgcp_message::retrans, mgcp_gateway::retransid, and mgcp_message::seqno.

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

00654 {
00655    struct mgcp_gateway *gw = (struct mgcp_gateway *)data;
00656    struct mgcp_message *cur, *exq = NULL, *w, *prev;
00657    int res = 0;
00658 
00659    /* find out expired msgs */
00660    ast_mutex_lock(&gw->msgs_lock);
00661 
00662    for (prev = NULL, cur = gw->msgs; cur; prev = cur, cur = cur->next) {
00663       if (cur->retrans < MAX_RETRANS) {
00664          cur->retrans++;
00665          ast_debug(1, "Retransmitting #%d transaction %u on [%s]\n",
00666             cur->retrans, cur->seqno, gw->name);
00667          __mgcp_xmit(gw, cur->buf, cur->len);
00668       } else {
00669          if (prev)
00670             prev->next = cur->next;
00671          else
00672             gw->msgs = cur->next;
00673 
00674          ast_log(LOG_WARNING, "Maximum retries exceeded for transaction %u on [%s]\n",
00675             cur->seqno, gw->name);
00676 
00677          w = cur;
00678 
00679          if (exq) {
00680             w->next = exq;
00681          } else {
00682             w->next = NULL;
00683          }
00684          exq = w;
00685       }
00686    }
00687 
00688    if (!gw->msgs) {
00689       gw->retransid = -1;
00690       res = 0;
00691    } else {
00692       res = 1;
00693    }
00694    ast_mutex_unlock(&gw->msgs_lock);
00695 
00696    while (exq) {
00697       cur = exq;
00698       /* time-out transaction */
00699       handle_response(cur->owner_ep, cur->owner_sub, 406, cur->seqno, NULL);
00700       exq = exq->next;
00701       ast_free(cur);
00702    }
00703 
00704    return res;
00705 }

static void sdpLineNum_iterator_init ( int *  iterator  )  [static]

Definition at line 1599 of file chan_mgcp.c.

Referenced by process_sdp().

01600 {
01601    *iterator = 0;
01602 }

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

Definition at line 752 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, 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_endpoint::ncs, mgcp_request::next, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_endpoint::rqnt_queue, mgcp_endpoint::rqnt_queue_lock, and mgcp_endpoint::slowsequence.

Referenced by transmit_audit_endpoint(), transmit_cc_notify(), transmit_connect(), transmit_connect_with_sdp(), transmit_connection_del(), transmit_connection_del_w_params(), transmit_info_with_aoc(), transmit_info_with_digit(), transmit_info_with_vidupdate(), transmit_invite(), transmit_message(), 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().

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

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 2930 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, ast_sockaddr_from_sin, bindaddr, mgcp_subchannel::callid, mgcp_subchannel::gate, mgcp_subchannel::lock, mgcp_alloc_pktcgate(), mgcp_queue_hangup(), mgcp_subchannel::nat, mgcp_subchannel::owner, mgcp_subchannel::parent, mgcp_endpoint::pktcgatealloc, qos, mgcp_subchannel::rtp, transmit_connect(), transmit_connect_with_sdp(), and mgcp_subchannel::txident.

Referenced by handle_hd_hf(), handle_response(), HandleCallIncoming(), HandleCallOutgoing(), mgcp_answer(), mgcp_call(), mgcp_ss(), setsubstate(), skinny_newcall(), and unistim_answer().

02931 {
02932    struct ast_sockaddr bindaddr_tmp;
02933 
02934    ast_mutex_lock(&sub->lock);
02935    /* check again to be on the safe side */
02936    if (sub->rtp) {
02937       ast_rtp_instance_destroy(sub->rtp);
02938       sub->rtp = NULL;
02939    }
02940    /* Allocate the RTP now */
02941    ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
02942    sub->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL);
02943    if (sub->rtp && sub->owner)
02944       ast_channel_set_fd(sub->owner, 0, ast_rtp_instance_fd(sub->rtp, 0));
02945    if (sub->rtp) {
02946       ast_rtp_instance_set_qos(sub->rtp, qos.tos_audio, qos.cos_audio, "MGCP RTP");
02947       ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_NAT, sub->nat);
02948    }
02949    /* Make a call*ID */
02950    snprintf(sub->callid, sizeof(sub->callid), "%08lx%s", ast_random(), sub->txident);
02951    /* Transmit the connection create */
02952    if(!sub->parent->pktcgatealloc) {
02953       transmit_connect_with_sdp(sub, NULL);
02954    } else {
02955       transmit_connect(sub);
02956       sub->gate = NULL;
02957       if(!mgcp_alloc_pktcgate(sub))
02958          mgcp_queue_hangup(sub);
02959    }
02960    ast_mutex_unlock(&sub->lock);
02961 }

static int transmit_audit_endpoint ( struct mgcp_endpoint p  )  [static]

Definition at line 2642 of file chan_mgcp.c.

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

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

02643 {
02644    struct mgcp_request resp;
02645    reqprep(&resp, p, "AUEP");
02646    /* removed unknown param VS */
02647    /*add_header(&resp, "F", "A,R,D,S,X,N,I,T,O,ES,E,MD,M");*/
02648    add_header(&resp, "F", "A");
02649    /* fill in new fields */
02650    resp.cmd = MGCP_CMD_AUEP;
02651    resp.trid = oseq;
02652    return send_request(p, NULL, &resp, oseq);
02653 }

static int transmit_connect ( struct mgcp_subchannel sub  )  [static]

Definition at line 2437 of file chan_mgcp.c.

References add_header(), ast_copy_string(), ast_debug, ast_format_cap_iscompatible(), ast_format_cap_iter_end(), ast_format_cap_iter_next(), ast_format_cap_iter_start(), ast_rtp_lookup_mime_subtype2(), mgcp_subchannel::callid, mgcp_endpoint::cap, 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(), mgcp_subchannel::sdpsent, send_request(), mgcp_request::trid, and mgcp_subchannel::txident.

Referenced by setsubstate(), and start_rtp().

02438 {
02439    struct mgcp_request resp;
02440    char local[256];
02441    char tmp[80];
02442    struct ast_format tmpfmt;
02443    struct mgcp_endpoint *p = sub->parent;
02444 
02445    ast_copy_string(local, "p:20, s:off, e:on", sizeof(local));
02446 
02447    ast_format_cap_iter_start(p->cap);
02448    while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) {
02449       if (ast_format_cap_iscompatible(p->cap, &tmpfmt)) {
02450          snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0));
02451          strncat(local, tmp, sizeof(local) - strlen(local) - 1);
02452       }
02453    }
02454    ast_format_cap_iter_end(p->cap);
02455 
02456    ast_debug(3, "Creating connection for %s@%s-%d in cxmode: %s callid: %s\n",
02457           p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
02458    sub->sdpsent = 0;
02459    reqprep(&resp, p, "CRCX");
02460    add_header(&resp, "C", sub->callid);
02461    add_header(&resp, "L", local);
02462    add_header(&resp, "M", "inactive");
02463    /* X header should not be sent. kept for compatibility */
02464    add_header(&resp, "X", sub->txident);
02465    /*add_header(&resp, "S", "");*/
02466    /* fill in new fields */
02467    resp.cmd = MGCP_CMD_CRCX;
02468    resp.trid = oseq;
02469    return send_request(p, sub, &resp, oseq);
02470 }

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

Definition at line 2340 of file chan_mgcp.c.

References add_header(), add_sdp(), ast_copy_string(), ast_debug, ast_format_cap_iscompatible(), ast_format_cap_iter_end(), ast_format_cap_iter_next(), ast_format_cap_iter_start(), AST_FORMAT_GET_TYPE, AST_FORMAT_TYPE_AUDIO, ast_rtp_lookup_mime_subtype2(), mgcp_subchannel::callid, mgcp_endpoint::cap, mgcp_request::cmd, mgcp_subchannel::cxmode, mgcp_subchannel::gate, GATE_ALLOCATED, cops_gate::gateid, ast_format::id, mgcp_subchannel::id, MGCP_CMD_CRCX, mgcp_gateway::name, mgcp_endpoint::name, mgcp_endpoint::parent, mgcp_subchannel::parent, reqprep(), mgcp_subchannel::sdpsent, send_request(), cops_gate::state, mgcp_request::trid, and mgcp_subchannel::txident.

Referenced by start_rtp().

02341 {
02342    struct mgcp_request resp;
02343    char local[256];
02344    char tmp[80];
02345    struct ast_format tmpfmt;
02346    struct mgcp_endpoint *p = sub->parent;
02347 
02348    ast_debug(3, "Creating connection for %s@%s-%d in cxmode: %s callid: %s\n",
02349        p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
02350 
02351    ast_copy_string(local, "e:on, s:off, p:20", sizeof(local));
02352 
02353    ast_format_cap_iter_start(p->cap);
02354    while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) {
02355       if (AST_FORMAT_GET_TYPE(tmpfmt.id) != AST_FORMAT_TYPE_AUDIO) {
02356          /* Audio is now discontiguous */
02357          continue;
02358       }
02359       if (ast_format_cap_iscompatible(p->cap, &tmpfmt)) {
02360          snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0));
02361          strncat(local, tmp, sizeof(local) - strlen(local) - 1);
02362       }
02363    }
02364    ast_format_cap_iter_end(p->cap);
02365 
02366    if (sub->gate) {
02367       if(sub->gate->state == GATE_ALLOCATED) {
02368          snprintf(tmp, sizeof(tmp), ", dq-gi:%x", sub->gate->gateid);
02369          strncat(local, tmp, sizeof(local) - strlen(local) - 1);
02370       }
02371    }
02372    sub->sdpsent = 1;
02373    reqprep(&resp, p, "CRCX");
02374    add_header(&resp, "C", sub->callid);
02375    add_header(&resp, "L", local);
02376    add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
02377    /* X header should not be sent. kept for compatibility */
02378    add_header(&resp, "X", sub->txident);
02379    /*add_header(&resp, "S", "");*/
02380    add_sdp(&resp, sub, rtp);
02381    /* fill in new fields */
02382    resp.cmd = MGCP_CMD_CRCX;
02383    resp.trid = oseq;
02384    return send_request(p, sub, &resp, oseq);
02385 }

static int transmit_connection_del ( struct mgcp_subchannel sub  )  [static]

Definition at line 2655 of file chan_mgcp.c.

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

02656 {
02657    struct mgcp_endpoint *p = sub->parent;
02658    struct mgcp_request resp;
02659 
02660    ast_debug(3, "Delete connection %s %s@%s-%d with new mode: %s on callid: %s\n",
02661       sub->cxident, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
02662    reqprep(&resp, p, "DLCX");
02663    /* check if call id is avail */
02664    if (sub->callid[0])
02665       add_header(&resp, "C", sub->callid);
02666    /* X header should not be sent. kept for compatibility */
02667    add_header(&resp, "X", sub->txident);
02668    /* check if cxident is avail */
02669    if (sub->cxident[0])
02670       add_header(&resp, "I", sub->cxident);
02671    /* fill in new fields */
02672    resp.cmd = MGCP_CMD_DLCX;
02673    resp.trid = oseq;
02674    return send_request(p, sub, &resp, oseq);
02675 }

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

Definition at line 2677 of file chan_mgcp.c.

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

02678 {
02679    struct mgcp_request resp;
02680 
02681    ast_debug(3, "Delete connection %s %s@%s on callid: %s\n",
02682       cxident ? cxident : "", p->name, p->parent->name, callid ? callid : "");
02683    reqprep(&resp, p, "DLCX");
02684    /* check if call id is avail */
02685    if (callid && *callid)
02686       add_header(&resp, "C", callid);
02687    /* check if cxident is avail */
02688    if (cxident && *cxident)
02689       add_header(&resp, "I", cxident);
02690    /* fill in new fields */
02691    resp.cmd = MGCP_CMD_DLCX;
02692    resp.trid = oseq;
02693    return send_request(p, p->sub, &resp, oseq);
02694 }

static int transmit_modify_request ( struct mgcp_subchannel sub  )  [static]

Definition at line 2543 of file chan_mgcp.c.

References add_header(), add_header_offhook(), add_sdp(), ast_copy_string(), ast_debug, ast_format_cap_iter_end(), ast_format_cap_iter_next(), ast_format_cap_iter_start(), ast_format_cap_set(), ast_rtp_lookup_mime_subtype2(), ast_strlen_zero(), mgcp_subchannel::callid, mgcp_endpoint::cap, mgcp_request::cmd, mgcp_subchannel::cxident, mgcp_subchannel::cxmode, mgcp_subchannel::gate, GATE_ALLOCATED, GATE_OPEN, cops_gate::gateid, mgcp_endpoint::hookstate, mgcp_subchannel::id, MGCP_CMD_MDCX, MGCP_OFFHOOK, MGCP_ONHOOK, mgcp_gateway::name, mgcp_endpoint::name, mgcp_endpoint::ncs, mgcp_endpoint::parent, mgcp_subchannel::parent, reqprep(), mgcp_subchannel::sdpsent, send_request(), cops_gate::state, mgcp_request::trid, and mgcp_subchannel::txident.

Referenced by handle_hd_hf(), handle_request(), mgcp_answer(), mgcp_call(), mgcp_hangup(), and mgcp_indicate().

02544 {
02545    struct mgcp_request resp;
02546    struct mgcp_endpoint *p = sub->parent;
02547    struct ast_format tmpfmt;
02548    int fc = 1;
02549    char local[256];
02550    char tmp[80];
02551 
02552    if (ast_strlen_zero(sub->cxident)) {
02553       /* We don't have a CXident yet, store the destination and
02554          wait a bit */
02555       return 0;
02556    }
02557    ast_debug(3, "Modified %s@%s-%d with new mode: %s on callid: %s\n",
02558       p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
02559 
02560    ast_copy_string(local, "", sizeof(local));
02561    ast_format_cap_iter_start(p->cap);
02562    while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) {
02563       if (p->ncs && !fc) {
02564          ast_format_cap_set(p->cap, &tmpfmt); /* sb5120e bug */
02565          break;
02566       } else {
02567          fc = 0;
02568          snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0));
02569       }
02570       strncat(local, tmp, sizeof(local) - strlen(local) - 1);
02571    }
02572    ast_format_cap_iter_end(p->cap);
02573 
02574    if (!sub->sdpsent) {
02575       if (sub->gate) {
02576          if (sub->gate->state == GATE_ALLOCATED || sub->gate->state == GATE_OPEN) {
02577             snprintf(tmp, sizeof(tmp), ", dq-gi:%x", sub->gate->gateid);
02578             strncat(local, tmp, sizeof(local) - strlen(local) - 1);
02579          } else {
02580                /* we still don't have gateid wait */
02581             return 0;
02582          }
02583       }
02584    }
02585 
02586    reqprep(&resp, p, "MDCX");
02587    add_header(&resp, "C", sub->callid);
02588    if (!sub->sdpsent) {
02589       add_header(&resp, "L", local);
02590    }
02591    add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
02592    /* X header should not be sent. kept for compatibility */
02593    add_header(&resp, "X", sub->txident);
02594    add_header(&resp, "I", sub->cxident);
02595    switch (sub->parent->hookstate) {
02596    case MGCP_ONHOOK:
02597       add_header(&resp, "R", "L/hd(N)");
02598       break;
02599    case MGCP_OFFHOOK:
02600       add_header_offhook(sub, &resp, "");
02601       break;
02602    }
02603    if (!sub->sdpsent) {
02604       add_sdp(&resp, sub, NULL);
02605       sub->sdpsent = 1;
02606    }
02607    /* fill in new fields */
02608    resp.cmd = MGCP_CMD_MDCX;
02609    resp.trid = oseq;
02610    return send_request(p, sub, &resp, oseq);
02611 }

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

Definition at line 2281 of file chan_mgcp.c.

References add_header(), add_sdp(), ast_copy_string(), ast_debug, ast_format_cap_iscompatible(), ast_format_cap_iter_end(), ast_format_cap_iter_next(), ast_format_cap_iter_start(), AST_FORMAT_GET_TYPE, AST_FORMAT_TYPE_AUDIO, ast_rtp_instance_get_remote_address(), ast_rtp_lookup_mime_subtype2(), ast_sockaddr_to_sin, ast_strlen_zero(), mgcp_subchannel::callid, mgcp_endpoint::cap, mgcp_request::cmd, mgcp_subchannel::cxident, mgcp_subchannel::cxmode, mgcp_subchannel::gate, GATE_ALLOCATED, GATE_OPEN, cops_gate::gateid, ast_format::id, MGCP_CMD_MDCX, mgcp_subchannel::parent, reqprep(), mgcp_subchannel::sdpsent, send_request(), cops_gate::state, mgcp_subchannel::tmpdest, mgcp_request::trid, and mgcp_subchannel::txident.

Referenced by handle_response(), mgcp_pktcgate_open(), mgcp_set_rtp_peer(), and mgcp_write().

02282 {
02283    struct mgcp_request resp;
02284    char local[256];
02285    char tmp[80];
02286    struct mgcp_endpoint *p = sub->parent;
02287    struct ast_format tmpfmt;
02288    struct ast_sockaddr sub_tmpdest_tmp;
02289 
02290    if (ast_strlen_zero(sub->cxident) && rtp) {
02291       /* We don't have a CXident yet, store the destination and
02292          wait a bit */
02293       ast_rtp_instance_get_remote_address(rtp, &sub_tmpdest_tmp);
02294       ast_sockaddr_to_sin(&sub_tmpdest_tmp, &sub->tmpdest);
02295       return 0;
02296    }
02297    ast_copy_string(local, "e:on, s:off, p:20", sizeof(local));
02298    ast_format_cap_iter_start(p->cap);
02299    while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) {
02300       if (AST_FORMAT_GET_TYPE(tmpfmt.id) != AST_FORMAT_TYPE_AUDIO) {
02301          /* Audio is now discontiguous */
02302          continue;
02303       }
02304       if (ast_format_cap_iscompatible(p->cap, &tmpfmt)) {
02305          snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0));
02306          strncat(local, tmp, sizeof(local) - strlen(local) - 1);
02307       }
02308    }
02309    ast_format_cap_iter_end(p->cap);
02310 
02311    if (sub->gate) {
02312       if (sub->gate->state == GATE_ALLOCATED || sub->gate->state == GATE_OPEN) {
02313          snprintf(tmp, sizeof(tmp), ", dq-gi:%x", sub->gate->gateid);
02314          strncat(local, tmp, sizeof(local) - strlen(local) - 1);
02315          sub->sdpsent = 1;
02316       } else {
02317          /* oops wait */
02318          ast_debug(1, "Waiting for opened gate...\n");
02319          sub->sdpsent = 0;
02320          return 0;
02321       }
02322    }
02323 
02324 
02325    reqprep(&resp, p, "MDCX");
02326    add_header(&resp, "C", sub->callid);
02327    add_header(&resp, "L", local);
02328    add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
02329    /* X header should not be sent. kept for compatibility */
02330    add_header(&resp, "X", sub->txident);
02331    add_header(&resp, "I", sub->cxident);
02332    /*add_header(&resp, "S", "");*/
02333    add_sdp(&resp, sub, rtp);
02334    /* fill in new fields */
02335    resp.cmd = MGCP_CMD_MDCX;
02336    resp.trid = oseq;
02337    return send_request(p, sub, &resp, oseq);
02338 }

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

Definition at line 2472 of file chan_mgcp.c.

References add_header(), add_header_offhook(), ast_copy_string(), ast_debug, ast_strlen_zero(), 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().

02473 {
02474    struct mgcp_request resp;
02475    struct mgcp_endpoint *p = sub->parent;
02476 
02477    ast_debug(3, "MGCP Asked to indicate tone: %s on  %s@%s-%d in cxmode: %s\n",
02478       tone, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]);
02479    ast_copy_string(p->curtone, tone, sizeof(p->curtone));
02480    reqprep(&resp, p, "RQNT");
02481    add_header(&resp, "X", p->rqnt_ident);
02482    switch (p->hookstate) {
02483    case MGCP_ONHOOK:
02484       add_header(&resp, "R", "L/hd(N)");
02485       break;
02486    case MGCP_OFFHOOK:
02487       add_header_offhook(sub, &resp, tone);
02488       break;
02489    }
02490    if (!ast_strlen_zero(tone)) {
02491       add_header(&resp, "S", tone);
02492    }
02493    /* fill in new fields */
02494    resp.cmd = MGCP_CMD_RQNT;
02495    resp.trid = oseq;
02496    return send_request(p, NULL, &resp, oseq);
02497 }

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

Definition at line 2499 of file chan_mgcp.c.

References add_header(), add_header_offhook(), ast_copy_string(), ast_debug, ast_localtime(), ast_strlen_zero(), ast_tvnow(), 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().

02500 {
02501    struct mgcp_request resp;
02502    char tone2[256];
02503    char *l, *n;
02504    struct timeval t = ast_tvnow();
02505    struct ast_tm tm;
02506    struct mgcp_endpoint *p = sub->parent;
02507 
02508    ast_localtime(&t, &tm, NULL);
02509    n = callername;
02510    l = callernum;
02511    if (!n)
02512       n = "";
02513    if (!l)
02514       l = "";
02515 
02516    /* Keep track of last callerid for blacklist and callreturn */
02517    ast_copy_string(p->lastcallerid, l, sizeof(p->lastcallerid));
02518 
02519    snprintf(tone2, sizeof(tone2), "%s,L/ci(%02d/%02d/%02d/%02d,%s,%s)", tone,
02520       tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, l, n);
02521    ast_copy_string(p->curtone, tone, sizeof(p->curtone));
02522    reqprep(&resp, p, "RQNT");
02523    add_header(&resp, "X", p->rqnt_ident);
02524    switch (p->hookstate) {
02525    case MGCP_ONHOOK:
02526       add_header(&resp, "R", "L/hd(N)");
02527       break;
02528    case MGCP_OFFHOOK:
02529       add_header_offhook(sub, &resp, tone);
02530       break;
02531    }
02532    if (!ast_strlen_zero(tone2)) {
02533       add_header(&resp, "S", tone2);
02534    }
02535    ast_debug(3, "MGCP Asked to indicate tone: %s on  %s@%s-%d in cxmode: %s\n",
02536       tone2, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]);
02537    /* fill in new fields */
02538    resp.cmd = MGCP_CMD_RQNT;
02539    resp.trid = oseq;
02540    return send_request(p, NULL, &resp, oseq);
02541 }

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

Definition at line 2154 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_cc_notify(), handle_cc_subscribe(), handle_incoming(), handle_invite_replaces(), handle_request(), handle_request_bye(), handle_request_cancel(), handle_request_info(), handle_request_invite(), handle_request_message(), handle_request_notify(), handle_request_options(), handle_request_publish(), handle_request_refer(), handle_request_subscribe(), handle_request_update(), handle_response(), handle_sip_publish_initial(), handle_sip_publish_modify(), handle_sip_publish_refresh(), handle_sip_publish_remove(), receive_message(), register_verify(), send_provisional_keepalive_full(), sip_cc_agent_destructor(), sip_cc_agent_respond(), sip_indicate(), sip_sendhtml(), skinny_reload(), transmit_activatecallplane(), transmit_callinfo(), transmit_callstate(), transmit_capabilitiesreq(), transmit_cfwdstate(), transmit_clear_display_message(), transmit_clearpromptmessage(), transmit_closereceivechannel(), transmit_connect(), transmit_definetimedate(), transmit_dialednumber(), transmit_displaynotify(), transmit_displaypromptstatus(), transmit_fake_auth_response(), transmit_keepaliveack(), transmit_lamp_indication(), transmit_linestatres(), transmit_microphone_mode(), transmit_provisional_response(), transmit_registerack(), transmit_reset(), transmit_ringer_mode(), transmit_selectsoftkeys(), transmit_serverres(), transmit_softkeysetres(), transmit_softkeytemplateres(), transmit_speaker_mode(), transmit_speeddialstatres(), transmit_start_tone(), transmit_startmediatransmission(), transmit_stop_tone(), transmit_stopmediatransmission(), and transmit_versionres().

02155 {
02156    struct mgcp_request resp;
02157    struct mgcp_endpoint *p = sub->parent;
02158    struct mgcp_response *mgr;
02159 
02160    if (!sub) {
02161       return -1;
02162    }
02163 
02164    respprep(&resp, p, msg, req, msgrest);
02165    if (!(mgr = ast_calloc(1, sizeof(*mgr) + resp.len + 1))) {
02166       return send_response(sub, &resp);
02167    }
02168    /* Store MGCP response in case we have to retransmit */
02169    sscanf(req->identifier, "%30d", &mgr->seqno);
02170    time(&mgr->whensent);
02171    mgr->len = resp.len;
02172    memcpy(mgr->buf, resp.data, resp.len);
02173    mgr->buf[resp.len] = '\0';
02174    mgr->next = p->parent->responses;
02175    p->parent->responses = mgr;
02176 
02177    return send_response(sub, &resp);
02178 }

static int unalloc_sub ( struct mgcp_subchannel sub  )  [static]

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

00516 {
00517    struct mgcp_endpoint *p = sub->parent;
00518    if (p->sub == sub) {
00519       ast_log(LOG_WARNING, "Trying to unalloc the real channel %s@%s?!?\n", p->name, p->parent->name);
00520       return -1;
00521    }
00522    ast_debug(1, "Released sub %d of channel %s@%s\n", sub->id, p->name, p->parent->name);
00523 
00524    sub->owner = NULL;
00525    if (!ast_strlen_zero(sub->cxident)) {
00526       transmit_connection_del(sub);
00527    }
00528    sub->cxident[0] = '\0';
00529    sub->callid[0] = '\0';
00530    sub->cxmode = MGCP_CX_INACTIVE;
00531    sub->outgoing = 0;
00532    sub->alreadygone = 0;
00533    memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
00534    if (sub->rtp) {
00535       ast_rtp_instance_destroy(sub->rtp);
00536       sub->rtp = NULL;
00537    }
00538    dump_cmd_queues(NULL, sub);
00539    return 0;
00540 }

static int unload_module ( void   )  [static]

Definition at line 4880 of file chan_mgcp.c.

References ast_channel_register(), ast_channel_unregister(), ast_cli_unregister_multiple(), ast_format_cap_destroy(), ast_log(), ast_mutex_lock, ast_mutex_trylock, ast_mutex_unlock, AST_PTHREADT_NULL, AST_PTHREADT_STOP, ast_rtp_glue_unregister(), ast_sched_context_destroy(), ast_channel_tech::capabilities, 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, and prune_gateways().

04881 {
04882    struct mgcp_endpoint *e;
04883    struct mgcp_gateway *g;
04884 
04885    /* Check to see if we're reloading */
04886    if (ast_mutex_trylock(&mgcp_reload_lock)) {
04887       ast_log(LOG_WARNING, "MGCP is currently reloading.  Unable to remove module.\n");
04888       return -1;
04889    } else {
04890       mgcp_reloading = 1;
04891       ast_mutex_unlock(&mgcp_reload_lock);
04892    }
04893 
04894    /* First, take us out of the channel loop */
04895    ast_channel_unregister(&mgcp_tech);
04896 
04897    /* Shut down the monitoring thread */
04898    if (!ast_mutex_lock(&monlock)) {
04899       if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
04900          pthread_cancel(monitor_thread);
04901          pthread_kill(monitor_thread, SIGURG);
04902          pthread_join(monitor_thread, NULL);
04903       }
04904       monitor_thread = AST_PTHREADT_STOP;
04905       ast_mutex_unlock(&monlock);
04906    } else {
04907       ast_log(LOG_WARNING, "Unable to lock the monitor\n");
04908       /* We always want to leave this in a consistent state */
04909       ast_channel_register(&mgcp_tech);
04910       mgcp_reloading = 0;
04911       mgcp_reload(NULL, 0, NULL);
04912       return -1;
04913    }
04914 
04915    if (!ast_mutex_lock(&gatelock)) {
04916       for (g = gateways; g; g = g->next) {
04917          g->delme = 1;
04918          for (e = g->endpoints; e; e = e->next) {
04919             e->delme = 1;
04920          }
04921       }
04922 
04923       prune_gateways();
04924       ast_mutex_unlock(&gatelock);
04925    } else {
04926       ast_log(LOG_WARNING, "Unable to lock the gateways list.\n");
04927       /* We always want to leave this in a consistent state */
04928       ast_channel_register(&mgcp_tech);
04929       /* Allow the monitor to restart */
04930       monitor_thread = AST_PTHREADT_NULL;
04931       mgcp_reloading = 0;
04932       mgcp_reload(NULL, 0, NULL);
04933       return -1;
04934    }
04935 
04936    close(mgcpsock);
04937    ast_rtp_glue_unregister(&mgcp_rtp_glue);
04938    ast_cli_unregister_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
04939    ast_sched_context_destroy(sched);
04940 
04941    global_capability = ast_format_cap_destroy(global_capability);
04942    mgcp_tech.capabilities = ast_format_cap_destroy(mgcp_tech.capabilities);
04943 
04944    return 0;
04945 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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, .load_pri = AST_MODPRI_CHANNEL_DRIVER, .nonoptreq = "res_pktccops", } [static]

Definition at line 4953 of file chan_mgcp.c.

struct in_addr __ourip [static]

Definition at line 231 of file chan_mgcp.c.

char accountcode[AST_MAX_ACCOUNT_CODE] = "" [static]

Definition at line 195 of file chan_mgcp.c.

int adsi = 0 [static]

Definition at line 201 of file chan_mgcp.c.

int amaflags = 0 [static]

Definition at line 199 of file chan_mgcp.c.

Definition at line 4953 of file chan_mgcp.c.

struct sockaddr_in bindaddr [static]

Definition at line 426 of file chan_mgcp.c.

int callreturn = 0 [static]

Definition at line 180 of file chan_mgcp.c.

int callwaiting = 0 [static]

Definition at line 178 of file chan_mgcp.c.

int cancallforward = 0 [static]

Definition at line 189 of file chan_mgcp.c.

char cid_name[AST_MAX_EXTENSION] = "" [static]

char cid_num[AST_MAX_EXTENSION] = "" [static]

struct ast_cli_entry cli_mgcp[] [static]

Definition at line 1168 of file chan_mgcp.c.

const char config[] = "mgcp.conf" [static]

Definition at line 110 of file chan_mgcp.c.

char context[AST_MAX_EXTENSION] = "default" [static]

Definition at line 152 of file chan_mgcp.c.

unsigned int cos

Definition at line 172 of file chan_mgcp.c.

unsigned int cos_audio

Definition at line 173 of file chan_mgcp.c.

Definition at line 166 of file chan_mgcp.c.

Definition at line 167 of file chan_mgcp.c.

struct ast_jb_conf default_jbconf [static]

Global jitterbuffer configuration - by default, jb is disabled

Note:
Values shown here match the defaults shown in mgcp.conf.sample

Definition at line 99 of file chan_mgcp.c.

int directmedia = DIRECTMEDIA [static]

Definition at line 193 of file chan_mgcp.c.

int dtmfmode = 0 [static]

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

ast_mutex_t gatelock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static]

struct mgcp_gateway * gateways [static]

int gendigittimeout = 8000 [static]

How long to wait for following digits (FXO logic)

Definition at line 209 of file chan_mgcp.c.

Definition at line 227 of file chan_mgcp.c.

struct ast_jb_conf global_jbconf [static]

Definition at line 107 of file chan_mgcp.c.

int hangupongateremove = 0 [static]

Definition at line 164 of file chan_mgcp.c.

int immediate = 0 [static]

Definition at line 176 of file chan_mgcp.c.

struct io_context* io [static]

Definition at line 237 of file chan_mgcp.c.

char language[MAX_LANGUAGE] = "" [static]

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

const char* const mgcp_cxmodes[] [static]

}

Definition at line 132 of file chan_mgcp.c.

ast_mutex_t mgcp_reload_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static]

Definition at line 418 of file chan_mgcp.c.

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

int mgcp_reloading = 0 [static]

Definition at line 419 of file chan_mgcp.c.

struct ast_rtp_glue mgcp_rtp_glue [static]

Definition at line 4451 of file chan_mgcp.c.

struct ast_channel_tech mgcp_tech [static]

Definition at line 463 of file chan_mgcp.c.

int mgcpdebug = 0 [static]

Definition at line 234 of file chan_mgcp.c.

int mgcpsock = -1 [static]

Definition at line 424 of file chan_mgcp.c.

int* mgcpsock_read_id = NULL [static]

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

ast_mutex_t monlock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [static]

Definition at line 218 of file chan_mgcp.c.

char musicclass[MAX_MUSICCLASS] = "" [static]

Definition at line 155 of file chan_mgcp.c.

Referenced by func_channel_write_real().

int nat = 0 [static]

Definition at line 161 of file chan_mgcp.c.

int ncs = 0 [static]

Definition at line 162 of file chan_mgcp.c.

ast_mutex_t netlock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 } [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 216 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 228 of file chan_mgcp.c.

unsigned int oseq [static]

Definition at line 203 of file chan_mgcp.c.

char ourhost[MAXHOSTNAMELEN] [static]

Definition at line 230 of file chan_mgcp.c.

Referenced by ast_find_ourip().

int ourport [static]

Definition at line 232 of file chan_mgcp.c.

Referenced by initreqprep(), and transmit_notify_with_mwi().

char parkinglot[AST_MAX_CONTEXT] [static]

int pktcgatealloc = 0 [static]

Definition at line 163 of file chan_mgcp.c.

struct { ... } qos [static]

struct ast_sched_context* sched [static]

Definition at line 236 of file chan_mgcp.c.

int singlepath = 0 [static]

Definition at line 191 of file chan_mgcp.c.

int slowsequence = 0 [static]

Definition at line 182 of file chan_mgcp.c.

const char tdesc[] = "Media Gateway Control Protocol (MGCP)" [static]

Definition at line 109 of file chan_mgcp.c.

int threewaycalling = 0 [static]

Definition at line 184 of file chan_mgcp.c.

unsigned int tos

Definition at line 170 of file chan_mgcp.c.

unsigned int tos_audio

Definition at line 171 of file chan_mgcp.c.

int transfer = 0 [static]

This is for flashhook transfers

Definition at line 187 of file chan_mgcp.c.

Referenced by leave_voicemail(), and send_packet().


Generated on Sat Feb 11 06:34:38 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6