Sat Apr 26 2014 22:02:12

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/netsock2.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, unsigned int oseq)
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_RECURSIVE_MUTEX_INITIALIZER_NP , 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_RECURSIVE_MUTEX_INITIALIZER_NP , 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_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
static char musicclass [MAX_MUSICCLASS] = ""
static int nat = 0
static int ncs = 0
static ast_mutex_t netlock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
static int nonCodecCapability = AST_RTP_DTMF
static unsigned int oseq_global = 0
static ast_mutex_t oseq_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 }
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

Definition at line 284 of file chan_mgcp.c.

Referenced by build_gateway(), destroy_endpoint(), and mgcp_prune_realtime_gateway().

#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_RFC2833   (1 << 0)
#define MGCP_MAX_HEADERS   64

The private structures of the mgcp channels are linked for selecting outgoing channels

Definition at line 243 of file chan_mgcp.c.

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

#define MGCP_MAX_LINES   64

Definition at line 244 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_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 295 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 274 of file chan_mgcp.c.

Referenced by find_and_retrans().

#define SUB_ALT   1

Definition at line 287 of file chan_mgcp.c.

#define SUB_REAL   0

Definition at line 286 of file chan_mgcp.c.

#define TYPE_LINE   2

Definition at line 323 of file chan_mgcp.c.

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

#define TYPE_TRUNK   1

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


Function Documentation

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

Definition at line 1618 of file chan_mgcp.c.

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

Referenced by get_header().

{
   int x;
   int len = strlen(name);
   char *r;
   for (x = *start; x < req->headers; x++) {
      if (!strncasecmp(req->header[x], name, len) &&
          (req->header[x][len] == ':')) {
         r = req->header[x] + len + 1;
         while (*r && (*r < 33)) {
            r++;
         }
         *start = x + 1;
         return r;
      }
   }
   /* Don't return NULL, so get_header is always a valid pointer */
   return def;
}
static int __mgcp_xmit ( struct mgcp_gateway gw,
char *  data,
int  len 
) [static]

Definition at line 544 of file chan_mgcp.c.

References mgcp_gateway::addr, ast_log(), mgcp_gateway::defaddr, errno, and LOG_WARNING.

Referenced by mgcp_postrequest(), resend_response(), retrans_pkt(), and send_response().

{
   int res;
   if (gw->addr.sin_addr.s_addr)
      res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->addr, sizeof(struct sockaddr_in));
   else
      res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->defaddr, sizeof(struct sockaddr_in));
   if (res != len) {
      ast_log(LOG_WARNING, "mgcp_xmit returned %d: %s\n", res, strerror(errno));
   }
   return res;
}
static void __reg_module ( void  ) [static]

Definition at line 4969 of file chan_mgcp.c.

static void __unreg_module ( void  ) [static]

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

References ast_channel_tech(), ast_channel_tech_pvt(), ast_log(), LOG_ERROR, mgcp_endpoint::ncs, mgcp_subchannel::parent, and sub.

{
   struct mgcp_subchannel *sub = ast_channel_tech_pvt(chan);
   int res = 0;

   /* Sanity check */
   if (!chan || ast_channel_tech(chan) != &mgcp_tech) {
      ast_log(LOG_ERROR, "This function requires a valid MGCP channel\n");
      return -1;
   }

   if (!strcasecmp(args, "ncs")) {
      snprintf(buf, buflen, "%s", sub->parent->ncs ?  "yes":"no");
   } else {
      res = -1;
   }
   return res;
}
static int add_header ( struct mgcp_request req,
const char *  var,
const char *  value 
) [static]

Definition at line 2052 of file chan_mgcp.c.

References ast_log(), mgcp_request::data, mgcp_request::header, mgcp_request::headers, mgcp_request::len, mgcp_request::lines, LOG_WARNING, and MGCP_MAX_HEADERS.

Referenced by add_header_offhook(), transmit_audit_endpoint(), transmit_connect(), transmit_connect_with_sdp(), transmit_connection_del(), transmit_connection_del_w_params(), transmit_modify_request(), transmit_modify_with_sdp(), transmit_notify_request(), and transmit_notify_request_with_callerid().

{
   if (req->len >= sizeof(req->data) - 4) {
      ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
      return -1;
   }
   if (req->lines) {
      ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n");
      return -1;
   }
   req->header[req->headers] = req->data + req->len;
   snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s: %s\r\n", var, value);
   req->len += strlen(req->header[req->headers]);
   if (req->headers < MGCP_MAX_HEADERS) {
      req->headers++;
   } else {
      ast_log(LOG_WARNING, "Out of header space\n");
      return -1;
   }
   return 0;
}
static void add_header_offhook ( struct mgcp_subchannel sub,
struct mgcp_request resp,
char *  tone 
) [static]

Definition at line 2627 of file chan_mgcp.c.

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

{
   struct mgcp_endpoint *p = sub->parent;
   char tone_indicate_end = 0;

   /* We also should check the tone to indicate, because it have no sense
      to request notify D/[0-9#*] (dtmf keys) if we are sending congestion
      tone for example G/cg */
   if (p && (!strcasecmp(tone, (p->ncs ? "L/ro" : "G/cg")))) {
      tone_indicate_end = 1;
   }

   if (p && p->sub && p->sub->owner &&
         ast_channel_state(p->sub->owner) >= AST_STATE_RINGING &&
         (p->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID))) {
       add_header(resp, "R", "L/hu(N),L/hf(N)");

   } else if (!tone_indicate_end){
       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)"));
   } else {
      ast_debug(1, "We don't want more digits if we will end the call\n");
      add_header(resp, "R", "L/hu(N),L/hf(N)");
   }
}
static int add_line ( struct mgcp_request req,
char *  line 
) [static]

Definition at line 2074 of file chan_mgcp.c.

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

Referenced by add_sdp().

{
   if (req->len >= sizeof(req->data) - 4) {
      ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
      return -1;
   }
   if (!req->lines) {
      /* Add extra empty return */
      ast_copy_string(req->data + req->len, "\r\n", sizeof(req->data) - req->len);
      req->len += strlen(req->data + req->len);
   }
   req->line[req->lines] = req->data + req->len;
   snprintf(req->line[req->lines], sizeof(req->data) - req->len, "%s", line);
   req->len += strlen(req->line[req->lines]);
   if (req->lines < MGCP_MAX_LINES) {
      req->lines++;
   } else {
      ast_log(LOG_WARNING, "Out of line space\n");
      return -1;
   }
   return 0;
}
static int add_sdp ( struct mgcp_request resp,
struct mgcp_subchannel sub,
struct ast_rtp_instance rtp 
) [static]

Definition at line 2188 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_subchannel::parent, mgcp_endpoint::parent, mgcp_subchannel::rtp, and mgcp_subchannel::tmpdest.

Referenced by transmit_connect_with_sdp(), transmit_modify_request(), and transmit_modify_with_sdp().

{
   int len;
   int codec;
   char costr[80];
   struct sockaddr_in sin;
   struct ast_sockaddr sin_tmp;
   char v[256];
   char s[256];
   char o[256];
   char c[256];
   char t[256];
   char m[256] = "";
   char a[1024] = "";
   int x;
   struct ast_format tmpfmt;
   struct sockaddr_in dest = { 0, };
   struct ast_sockaddr dest_tmp;
   struct mgcp_endpoint *p = sub->parent;
   /* XXX We break with the "recommendation" and send our IP, in order that our
          peer doesn't have to ast_gethostbyname() us XXX */
   len = 0;
   if (!sub->rtp) {
      ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n");
      return -1;
   }
   ast_rtp_instance_get_local_address(sub->rtp, &sin_tmp);
   ast_sockaddr_to_sin(&sin_tmp, &sin);
   if (rtp) {
      ast_rtp_instance_get_remote_address(sub->rtp, &dest_tmp);
      ast_sockaddr_to_sin(&dest_tmp, &dest);
   } else {
      if (sub->tmpdest.sin_addr.s_addr) {
         dest.sin_addr = sub->tmpdest.sin_addr;
         dest.sin_port = sub->tmpdest.sin_port;
         /* Reset temporary destination */
         memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
      } else {
         dest.sin_addr = p->parent->ourip;
         dest.sin_port = sin.sin_port;
      }
   }
   ast_debug(1, "We're at %s port %d\n", ast_inet_ntoa(p->parent->ourip), ntohs(sin.sin_port));
   ast_copy_string(v, "v=0\r\n", sizeof(v));
   snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", (int)getpid(), (int)getpid(), ast_inet_ntoa(dest.sin_addr));
   ast_copy_string(s, "s=session\r\n", sizeof(s));
   snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr));
   ast_copy_string(t, "t=0 0\r\n", sizeof(t));
   snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port));

   ast_format_cap_iter_start(p->cap);
   while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) {
      if (AST_FORMAT_GET_TYPE(tmpfmt.id) != AST_FORMAT_TYPE_AUDIO) {
         /* Audio is now discontiguous */
         continue;
      }
      if (ast_format_cap_iscompatible(p->cap, &tmpfmt)) {
         ast_debug(1, "Answering with capability %s\n", ast_getformatname(&tmpfmt));
         codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 1, &tmpfmt, 0);
         if (codec > -1) {
            snprintf(costr, sizeof(costr), " %d", codec);
            strncat(m, costr, sizeof(m) - strlen(m) - 1);
            snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0));
            strncat(a, costr, sizeof(a) - strlen(a) - 1);
         }
      }
   }
   ast_format_cap_iter_end(p->cap);

   for (x = 1LL; x <= AST_RTP_MAX; x <<= 1) {
      if (p->nonCodecCapability & x) {
         ast_debug(1, "Answering with non-codec capability %d\n", (int) x);
         codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 0, NULL, x);
         if (codec > -1) {
            snprintf(costr, sizeof(costr), " %d", codec);
            strncat(m, costr, sizeof(m) - strlen(m) - 1);
            snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype2(0, NULL, x, 0));
            strncat(a, costr, sizeof(a) - strlen(a) - 1);
            if (x == AST_RTP_DTMF) {
               /* Indicate we support DTMF...  Not sure about 16,
                  but MSN supports it so dang it, we will too... */
               snprintf(costr, sizeof costr, "a=fmtp:%d 0-16\r\n", codec);
               strncat(a, costr, sizeof(a) - strlen(a) - 1);
            }
         }
      }
   }
   strncat(m, "\r\n", sizeof(m) - strlen(m) - 1);
   len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a);
   snprintf(costr, sizeof(costr), "%d", len);
   add_line(resp, v);
   add_line(resp, o);
   add_line(resp, s);
   add_line(resp, c);
   add_line(resp, t);
   add_line(resp, m);
   add_line(resp, a);
   return 0;
}
static struct ast_variable * add_var ( const char *  buf,
struct ast_variable list 
) [static, read]

Definition at line 4606 of file chan_mgcp.c.

References ast_variable_new(), and ast_variable::next.

Referenced by build_gateway().

{
   struct ast_variable *tmpvar = NULL;
   char *varname = ast_strdupa(buf), *varval = NULL;

   if ((varval = strchr(varname, '='))) {
      *varval++ = '\0';
      if ((tmpvar = ast_variable_new(varname, varval, ""))) {
         tmpvar->next = list;
         list = tmpvar;
      }
   }
   return list;
}
static int attempt_transfer ( struct mgcp_endpoint p) [static]

Definition at line 3232 of file chan_mgcp.c.

References mgcp_subchannel::alreadygone, ast_bridged_channel(), ast_channel_masquerade(), ast_channel_name(), ast_channel_softhangup_internal_flag_add(), 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_endpoint::name, mgcp_gateway::name, mgcp_subchannel::next, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_endpoint::sub, and unalloc_sub().

Referenced by handle_request().

{
   /* *************************
    * I hope this works.
    * Copied out of chan_zap
    * Cross your fingers
    * *************************/

   /* In order to transfer, we need at least one of the channels to
      actually be in a call bridge.  We can't conference two applications
      together (but then, why would we want to?) */
   if (ast_bridged_channel(p->sub->owner)) {
      /* The three-way person we're about to transfer to could still be in MOH, so
         stop if now if appropriate */
      if (ast_bridged_channel(p->sub->next->owner))
         ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
      if (ast_channel_state(p->sub->owner) == AST_STATE_RINGING) {
         ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
      }
      if (ast_channel_masquerade(p->sub->next->owner, ast_bridged_channel(p->sub->owner))) {
         ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
            ast_channel_name(ast_bridged_channel(p->sub->owner)), ast_channel_name(p->sub->next->owner));
         return -1;
      }
      /* Orphan the channel */
      unalloc_sub(p->sub->next);
   } else if (ast_bridged_channel(p->sub->next->owner)) {
      if (ast_channel_state(p->sub->owner) == AST_STATE_RINGING) {
         ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING);
      }
      ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD);
      if (ast_channel_masquerade(p->sub->owner, ast_bridged_channel(p->sub->next->owner))) {
         ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
            ast_channel_name(ast_bridged_channel(p->sub->next->owner)), ast_channel_name(p->sub->owner));
         return -1;
      }
      /*swap_subs(p, SUB_THREEWAY, SUB_REAL);*/
      ast_verb(3, "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name);
      p->sub = p->sub->next;
      unalloc_sub(p->sub->next);
      /* Tell the caller not to hangup */
      return 1;
   } else {
      ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
         ast_channel_name(p->sub->owner), ast_channel_name(p->sub->next->owner));
      ast_channel_softhangup_internal_flag_add(p->sub->next->owner, AST_SOFTHANGUP_DEV);
      if (p->sub->next->owner) {
         p->sub->next->alreadygone = 1;
         mgcp_queue_hangup(p->sub->next);
      }
   }
   return 0;
}
static struct mgcp_gateway * build_gateway ( char *  cat,
struct ast_variable v 
) [static, read]

build_gateway: parse mgcp.conf and create gateway/endpoint structures

Definition at line 3988 of file chan_mgcp.c.

References __ourip, mgcp_endpoint::accountcode, add_var(), mgcp_gateway::addr, adsi, mgcp_endpoint::adsi, amaflags, mgcp_endpoint::amaflags, ast_append_ha(), ast_callerid_split(), ast_calloc, ast_cdr_amaflags2int(), ast_copy_string(), AST_EVENT_IE_CONTEXT, AST_EVENT_IE_END, AST_EVENT_IE_MAILBOX, AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS, AST_EVENT_IE_PLTYPE_STR, AST_EVENT_MWI, ast_event_subscribe(), ast_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_strlen_zero(), ast_true(), ast_variables_destroy(), ast_verb, mgcp_endpoint::callgroup, callreturn, mgcp_endpoint::callreturn, callwaiting, mgcp_endpoint::callwaiting, cancallforward, 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(), cur_callergroup, cur_pickupgroup, mgcp_subchannel::cx_queue_lock, mgcp_subchannel::cxmode, mgcp_gateway::defaddr, DEFAULT_MGCP_GW_PORT, mgcp_endpoint::delme, mgcp_gateway::delme, DIRECTMEDIA, directmedia, mgcp_endpoint::directmedia, dtmfmode, mgcp_endpoint::dtmfmode, mgcp_gateway::dynamic, mgcp_gateway::endpoints, mgcp_gateway::expire, mgcp_subchannel::gate, gateways, mgcp_gateway::ha, hangupongateremove, mgcp_endpoint::hangupongateremove, mgcp_endpoint::hascallwaiting, mgcp_endpoint::hookstate, mgcp_subchannel::id, immediate, mgcp_endpoint::immediate, INADDR_NONE, mgcp_gateway::isnamedottedip, mgcp_endpoint::language, ast_variable::lineno, mgcp_subchannel::lock, mgcp_endpoint::lock, LOG_WARNING, mgcp_subchannel::magic, mgcp_endpoint::mailbox, MAX_SUBS, mbox(), MGCP_CX_INACTIVE, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, MGCP_DTMF_RFC2833, MGCP_ONHOOK, MGCP_SUBCHANNEL_MAGIC, mgcp_gateway::msgs_lock, mgcp_endpoint::msgstate, mgcp_endpoint::musicclass, mwi_event_cb(), mgcp_endpoint::mwi_event_sub, ast_variable::name, mgcp_endpoint::name, mgcp_gateway::name, nat, mgcp_subchannel::nat, ncs, mgcp_endpoint::ncs, mgcp_endpoint::needaudit, ast_variable::next, mgcp_subchannel::next, mgcp_endpoint::next, mgcp_gateway::next, mgcp_endpoint::onhooktime, mgcp_gateway::ourip, mgcp_subchannel::parent, mgcp_endpoint::parent, mgcp_endpoint::parkinglot, mgcp_endpoint::pickupgroup, pktcgatealloc, mgcp_endpoint::pktcgatealloc, mgcp_gateway::realtime, mgcp_gateway::retransid, mgcp_endpoint::rqnt_ident, mgcp_endpoint::rqnt_queue_lock, mgcp_subchannel::rtp, mgcp_subchannel::sdpsent, singlepath, mgcp_endpoint::singlepath, slowsequence, mgcp_endpoint::slowsequence, sub, mgcp_endpoint::sub, threewaycalling, mgcp_endpoint::threewaycalling, transfer, mgcp_endpoint::transfer, mgcp_subchannel::txident, mgcp_endpoint::type, TYPE_LINE, TYPE_TRUNK, ast_variable::value, and mgcp_gateway::wcardep.

Referenced by find_realtime_gw(), and reload_config().

{
   struct mgcp_gateway *gw;
   struct mgcp_endpoint *e;
   struct mgcp_subchannel *sub;
   struct ast_variable *chanvars = NULL;

   /*char txident[80];*/
   int i=0, y=0;
   int gw_reload = 0;
   int ep_reload = 0;
   directmedia = DIRECTMEDIA;

   /* locate existing gateway */
   for (gw = gateways; gw; gw = gw->next) {
      if (!strcasecmp(cat, gw->name)) {
         /* gateway already exists */
         gw->delme = 0;
         gw_reload = 1;
         break;
      }
   }

   if (!gw && !(gw = ast_calloc(1, sizeof(*gw)))) {
      return NULL;
   }

   if (!gw_reload) {
      gw->expire = -1;
      gw->realtime = 0;
      gw->retransid = -1;
      ast_mutex_init(&gw->msgs_lock);
      ast_copy_string(gw->name, cat, sizeof(gw->name));
      /* check if the name is numeric ip */
      if ((strchr(gw->name, '.')) && inet_addr(gw->name) != INADDR_NONE)
         gw->isnamedottedip = 1;
   }
   for (; v; v = v->next) {
      if (!strcasecmp(v->name, "host")) {
         if (!strcasecmp(v->value, "dynamic")) {
            /* They'll register with us */
            gw->dynamic = 1;
            memset(&gw->addr.sin_addr, 0, 4);
            if (gw->addr.sin_port) {
               /* If we've already got a port, make it the default rather than absolute */
               gw->defaddr.sin_port = gw->addr.sin_port;
               gw->addr.sin_port = 0;
            }
         } else {
            /* Non-dynamic.  Make sure we become that way if we're not */
            AST_SCHED_DEL(sched, gw->expire);
            gw->dynamic = 0;
            {
               struct ast_sockaddr tmp;

               ast_sockaddr_from_sin(&tmp, &gw->addr);
               if (ast_get_ip(&tmp, v->value)) {
                  if (!gw_reload) {
                     ast_mutex_destroy(&gw->msgs_lock);
                     ast_free(gw);
                  }
                  return NULL;
               }
               ast_sockaddr_to_sin(&tmp, &gw->addr);
            }
         }
      } else if (!strcasecmp(v->name, "defaultip")) {
         struct ast_sockaddr tmp;

         ast_sockaddr_from_sin(&tmp, &gw->defaddr);
         if (ast_get_ip(&tmp, v->value)) {
            if (!gw_reload) {
               ast_mutex_destroy(&gw->msgs_lock);
               ast_free(gw);
            }
            return NULL;
         }
         ast_sockaddr_to_sin(&tmp, &gw->defaddr);
      } else if (!strcasecmp(v->name, "permit") ||
         !strcasecmp(v->name, "deny")) {
         gw->ha = ast_append_ha(v->name, v->value, gw->ha, NULL);
      } else if (!strcasecmp(v->name, "port")) {
         gw->addr.sin_port = htons(atoi(v->value));
      } else if (!strcasecmp(v->name, "context")) {
         ast_copy_string(context, v->value, sizeof(context));
      } else if (!strcasecmp(v->name, "dtmfmode")) {
         if (!strcasecmp(v->value, "inband"))
            dtmfmode = MGCP_DTMF_INBAND;
         else if (!strcasecmp(v->value, "rfc2833"))
            dtmfmode = MGCP_DTMF_RFC2833;
         else if (!strcasecmp(v->value, "hybrid"))
            dtmfmode = MGCP_DTMF_HYBRID;
         else if (!strcasecmp(v->value, "none"))
            dtmfmode = 0;
         else
            ast_log(LOG_WARNING, "'%s' is not a valid DTMF mode at line %d\n", v->value, v->lineno);
      } else if (!strcasecmp(v->name, "nat")) {
         nat = ast_true(v->value);
      } else if (!strcasecmp(v->name, "ncs")) {
         ncs = ast_true(v->value);
      } else if (!strcasecmp(v->name, "hangupongateremove")) {
         hangupongateremove = ast_true(v->value);
      } else if (!strcasecmp(v->name, "pktcgatealloc")) {
         pktcgatealloc = ast_true(v->value);
      } else if (!strcasecmp(v->name, "callerid")) {
         if (!strcasecmp(v->value, "asreceived")) {
            cid_num[0] = '\0';
            cid_name[0] = '\0';
         } else {
            ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
         }
      } else if (!strcasecmp(v->name, "language")) {
         ast_copy_string(language, v->value, sizeof(language));
      } else if (!strcasecmp(v->name, "accountcode")) {
         ast_copy_string(accountcode, v->value, sizeof(accountcode));
      } else if (!strcasecmp(v->name, "amaflags")) {
         y = ast_cdr_amaflags2int(v->value);
         if (y < 0) {
            ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
         } else {
            amaflags = y;
         }
      } else if (!strcasecmp(v->name, "setvar")) {
         chanvars = add_var(v->value, chanvars);
      } else if (!strcasecmp(v->name, "clearvars")) {
         if (chanvars) {
            ast_variables_destroy(chanvars);
            chanvars = NULL;
         }
      } else if (!strcasecmp(v->name, "musiconhold")) {
         ast_copy_string(musicclass, v->value, sizeof(musicclass));
      } else if (!strcasecmp(v->name, "parkinglot")) {
         ast_copy_string(parkinglot, v->value, sizeof(parkinglot));
      } else if (!strcasecmp(v->name, "callgroup")) {
         cur_callergroup = ast_get_group(v->value);
      } else if (!strcasecmp(v->name, "pickupgroup")) {
         cur_pickupgroup = ast_get_group(v->value);
      } else if (!strcasecmp(v->name, "immediate")) {
         immediate = ast_true(v->value);
      } else if (!strcasecmp(v->name, "cancallforward")) {
         cancallforward = ast_true(v->value);
      } else if (!strcasecmp(v->name, "singlepath")) {
         singlepath = ast_true(v->value);
      } else if (!strcasecmp(v->name, "directmedia") || !strcasecmp(v->name, "canreinvite")) {
         directmedia = ast_true(v->value);
      } else if (!strcasecmp(v->name, "mailbox")) {
         ast_copy_string(mailbox, v->value, sizeof(mailbox));
      } else if (!strcasecmp(v->name, "hasvoicemail")) {
         if (ast_true(v->value) && ast_strlen_zero(mailbox)) {
            ast_copy_string(mailbox, gw->name, sizeof(mailbox));
         }
      } else if (!strcasecmp(v->name, "adsi")) {
         adsi = ast_true(v->value);
      } else if (!strcasecmp(v->name, "callreturn")) {
         callreturn = ast_true(v->value);
      } else if (!strcasecmp(v->name, "callwaiting")) {
         callwaiting = ast_true(v->value);
      } else if (!strcasecmp(v->name, "slowsequence")) {
         slowsequence = ast_true(v->value);
      } else if (!strcasecmp(v->name, "transfer")) {
         transfer = ast_true(v->value);
      } else if (!strcasecmp(v->name, "threewaycalling")) {
         threewaycalling = ast_true(v->value);
      } else if (!strcasecmp(v->name, "wcardep")) {
         /* locate existing endpoint */
         for (e = gw->endpoints; e; e = e->next) {
            if (!strcasecmp(v->value, e->name)) {
               /* endpoint already exists */
               e->delme = 0;
               ep_reload = 1;
               break;
            }
         }

         if (!e) {
            /* Allocate wildcard endpoint */
            e = ast_calloc(1, sizeof(*e));
            ep_reload = 0;
         }

         if (e) {
            if (!ep_reload) {
               memset(e, 0, sizeof(struct mgcp_endpoint));
               ast_mutex_init(&e->lock);
               ast_mutex_init(&e->rqnt_queue_lock);
               ast_mutex_init(&e->cmd_queue_lock);
               e->cap = ast_format_cap_alloc_nolock();
               ast_copy_string(e->name, v->value, sizeof(e->name));
               e->needaudit = 1;
            }
            ast_copy_string(gw->wcardep, v->value, sizeof(gw->wcardep));
            /* XXX Should we really check for uniqueness?? XXX */
            ast_copy_string(e->accountcode, accountcode, sizeof(e->accountcode));
            ast_copy_string(e->context, context, sizeof(e->context));
            ast_copy_string(e->cid_num, cid_num, sizeof(e->cid_num));
            ast_copy_string(e->cid_name, cid_name, sizeof(e->cid_name));
            ast_copy_string(e->language, language, sizeof(e->language));
            ast_copy_string(e->musicclass, musicclass, sizeof(e->musicclass));
            ast_copy_string(e->mailbox, mailbox, sizeof(e->mailbox));
            ast_copy_string(e->parkinglot, parkinglot, sizeof(e->parkinglot));
            if (!ast_strlen_zero(e->mailbox)) {
               char *mbox, *cntx;
               cntx = mbox = ast_strdupa(e->mailbox);
               strsep(&cntx, "@");
               if (ast_strlen_zero(cntx)) {
                  cntx = "default";
               }
               e->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, "MGCP MWI subscription", NULL,
                  AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mbox,
                  AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, cntx,
                  AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
                  AST_EVENT_IE_END);
            }
            snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", ast_random());
            e->msgstate = -1;
            e->amaflags = amaflags;
            ast_format_cap_copy(e->cap, global_capability);
            e->parent = gw;
            e->ncs = ncs;
            e->dtmfmode = dtmfmode;
            if (!ep_reload && e->sub && e->sub->rtp) {
               e->dtmfmode |= MGCP_DTMF_INBAND;
            }
            e->adsi = adsi;
            e->type = TYPE_LINE;
            e->immediate = immediate;
            e->callgroup=cur_callergroup;
            e->pickupgroup=cur_pickupgroup;
            e->callreturn = callreturn;
            e->cancallforward = cancallforward;
            e->singlepath = singlepath;
            e->directmedia = directmedia;
            e->callwaiting = callwaiting;
            e->hascallwaiting = callwaiting;
            e->slowsequence = slowsequence;
            e->transfer = transfer;
            e->threewaycalling = threewaycalling;
            e->onhooktime = time(NULL);
            /* ASSUME we're onhook */
            e->hookstate = MGCP_ONHOOK;
            e->chanvars = copy_vars(chanvars);
            if (!ep_reload) {
               /*snprintf(txident, sizeof(txident), "%08lx", ast_random());*/
               for (i = 0; i < MAX_SUBS; i++) {
                  sub = ast_calloc(1, sizeof(*sub));
                  if (sub) {
                     ast_verb(3, "Allocating subchannel '%d' on %s@%s\n", i, e->name, gw->name);
                     ast_mutex_init(&sub->lock);
                     ast_mutex_init(&sub->cx_queue_lock);
                     sub->parent = e;
                     sub->id = i;
                     snprintf(sub->txident, sizeof(sub->txident), "%08lx", ast_random());
                     /*stnrcpy(sub->txident, txident, sizeof(sub->txident) - 1);*/
                     sub->cxmode = MGCP_CX_INACTIVE;
                     sub->nat = nat;
                     sub->gate = NULL;
                     sub->sdpsent = 0;
                     sub->next = e->sub;
                     e->sub = sub;
                  } else {
                     /* XXX Should find a way to clean up our memory */
                     ast_log(LOG_WARNING, "Out of memory allocating subchannel\n");
                     return NULL;
                  }
               }
               /* Make out subs a circular linked list so we can always sping through the whole bunch */
               /* find the end of the list */
               for (sub = e->sub; sub && sub->next; sub = sub->next);
               /* set the last sub->next to the first sub */
               sub->next = e->sub;

               e->next = gw->endpoints;
               gw->endpoints = e;
            }
         }
      } else if (!strcasecmp(v->name, "trunk") ||
                 !strcasecmp(v->name, "line")) {

         /* locate existing endpoint */
         for (e = gw->endpoints; e; e = e->next) {
            if (!strcasecmp(v->value, e->name)) {
               /* endpoint already exists */
               e->delme = 0;
               ep_reload = 1;
               break;
            }
         }

         if (!e) {
            e = ast_calloc(1, sizeof(*e));
            ep_reload = 0;
         }

         if (e) {
            if (!ep_reload) {
               ast_mutex_init(&e->lock);
               ast_mutex_init(&e->rqnt_queue_lock);
               ast_mutex_init(&e->cmd_queue_lock);
               e->cap = ast_format_cap_alloc_nolock();
               ast_copy_string(e->name, v->value, sizeof(e->name));
               e->needaudit = 1;
            }
            /* XXX Should we really check for uniqueness?? XXX */
            ast_copy_string(e->accountcode, accountcode, sizeof(e->accountcode));
            ast_copy_string(e->context, context, sizeof(e->context));
            ast_copy_string(e->cid_num, cid_num, sizeof(e->cid_num));
            ast_copy_string(e->cid_name, cid_name, sizeof(e->cid_name));
            ast_copy_string(e->language, language, sizeof(e->language));
            ast_copy_string(e->musicclass, musicclass, sizeof(e->musicclass));
            ast_copy_string(e->mailbox, mailbox, sizeof(e->mailbox));
            ast_copy_string(e->parkinglot, parkinglot, sizeof(e->parkinglot));
            if (!ast_strlen_zero(mailbox)) {
               ast_verb(3, "Setting mailbox '%s' on %s@%s\n", mailbox, gw->name, e->name);
            }
            if (!ep_reload) {
               /* XXX potential issue due to reload */
               e->msgstate = -1;
               e->parent = gw;
            }
            e->amaflags = amaflags;
            ast_format_cap_copy(e->cap, global_capability);
            e->dtmfmode = dtmfmode;
            e->ncs = ncs;
            e->pktcgatealloc = pktcgatealloc;
            e->hangupongateremove = hangupongateremove;
            e->adsi = adsi;
            e->type = (!strcasecmp(v->name, "trunk")) ? TYPE_TRUNK : TYPE_LINE;
            e->immediate = immediate;
            e->callgroup=cur_callergroup;
            e->pickupgroup=cur_pickupgroup;
            e->callreturn = callreturn;
            e->cancallforward = cancallforward;
            e->directmedia = directmedia;
            e->singlepath = singlepath;
            e->callwaiting = callwaiting;
            e->hascallwaiting = callwaiting;
            e->slowsequence = slowsequence;
            e->transfer = transfer;
            e->threewaycalling = threewaycalling;

            /* If we already have a valid chanvars, it's not a new endpoint (it's a reload),
               so first, free previous mem
             */
            if (e->chanvars) {
               ast_variables_destroy(e->chanvars);
               e->chanvars = NULL;
            }
            e->chanvars = copy_vars(chanvars);

            if (!ep_reload) {
               e->onhooktime = time(NULL);
               /* ASSUME we're onhook */
               e->hookstate = MGCP_ONHOOK;
               snprintf(e->rqnt_ident, sizeof(e->rqnt_ident), "%08lx", ast_random());
            }

            for (i = 0, sub = NULL; i < MAX_SUBS; i++) {
               if (!ep_reload) {
                  sub = ast_calloc(1, sizeof(*sub));
               } else {
                  if (!sub) {
                     sub = e->sub;
                  } else {
                     sub = sub->next;
                  }
               }

               if (sub) {
                  if (!ep_reload) {
                     ast_verb(3, "Allocating subchannel '%d' on %s@%s\n", i, e->name, gw->name);
                     ast_mutex_init(&sub->lock);
                     ast_mutex_init(&sub->cx_queue_lock);
                     ast_copy_string(sub->magic, MGCP_SUBCHANNEL_MAGIC, sizeof(sub->magic));
                     sub->parent = e;
                     sub->id = i;
                     snprintf(sub->txident, sizeof(sub->txident), "%08lx", ast_random());
                     sub->cxmode = MGCP_CX_INACTIVE;
                     sub->next = e->sub;
                     e->sub = sub;
                  }
                  sub->nat = nat;
               } else {
                  /* XXX Should find a way to clean up our memory */
                  ast_log(LOG_WARNING, "Out of memory allocating subchannel\n");
                  return NULL;
               }
            }
            if (!ep_reload) {
               /* Make out subs a circular linked list so we can always sping through the whole bunch */
               /* find the end of the list */
               for (sub = e->sub; sub && sub->next; sub = sub->next);
               /* set the last sub->next to the first sub */
               sub->next = e->sub;

               e->next = gw->endpoints;
               gw->endpoints = e;
            }
         }
      } else if (!strcasecmp(v->name, "name") || !strcasecmp(v->name, "lines")) {
         /* just eliminate realtime warnings */
      } else {
         ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
      }
   }
   if (!ntohl(gw->addr.sin_addr.s_addr) && !gw->dynamic) {
      ast_log(LOG_WARNING, "Gateway '%s' lacks IP address and isn't dynamic\n", gw->name);
      if (!gw_reload) {
         ast_mutex_destroy(&gw->msgs_lock);
         ast_free(gw);
      }

      /* Return NULL */
      gw_reload = 1;
   } else {
      gw->defaddr.sin_family = AF_INET;
      gw->addr.sin_family = AF_INET;
      if (gw->defaddr.sin_addr.s_addr && !ntohs(gw->defaddr.sin_port)) {
         gw->defaddr.sin_port = htons(DEFAULT_MGCP_GW_PORT);
      }
      if (gw->addr.sin_addr.s_addr && !ntohs(gw->addr.sin_port)) {
         gw->addr.sin_port = htons(DEFAULT_MGCP_GW_PORT);
      }
      {
         struct ast_sockaddr tmp1, tmp2;
         struct sockaddr_in tmp3 = {0,};

         tmp3.sin_addr = gw->ourip;
         ast_sockaddr_from_sin(&tmp1, &gw->addr);
         ast_sockaddr_from_sin(&tmp2, &tmp3);
         if (gw->addr.sin_addr.s_addr && ast_ouraddrfor(&tmp1, &tmp2)) {
            memcpy(&gw->ourip, &__ourip, sizeof(gw->ourip));
         } else {
            ast_sockaddr_to_sin(&tmp2, &tmp3);
            gw->ourip = tmp3.sin_addr;
         }
      }
   }

   if (chanvars) {
      ast_variables_destroy(chanvars);
      chanvars = NULL;
   }
   return (gw_reload ? NULL : gw);
}
static char* control2str ( int  ind) [static]

Definition at line 1407 of file chan_mgcp.c.

References AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_OFFHOOK, AST_CONTROL_OPTION, AST_CONTROL_RADIO_KEY, AST_CONTROL_RADIO_UNKEY, AST_CONTROL_RING, AST_CONTROL_RINGING, AST_CONTROL_TAKEOFFHOOK, and AST_CONTROL_WINK.

Referenced by mgcp_indicate().

                                  {
   switch (ind) {
   case AST_CONTROL_HANGUP:
      return "Other end has hungup";
   case AST_CONTROL_RING:
      return "Local ring";
   case AST_CONTROL_RINGING:
      return "Remote end is ringing";
   case AST_CONTROL_ANSWER:
      return "Remote end has answered";
   case AST_CONTROL_BUSY:
      return "Remote end is busy";
   case AST_CONTROL_TAKEOFFHOOK:
      return "Make it go off hook";
   case AST_CONTROL_OFFHOOK:
      return "Line is off hook";
   case AST_CONTROL_CONGESTION:
      return "Congestion (circuits busy)";
   case AST_CONTROL_FLASH:
      return "Flash hook";
   case AST_CONTROL_WINK:
      return "Wink";
   case AST_CONTROL_OPTION:
      return "Set a low-level option";
   case AST_CONTROL_RADIO_KEY:
      return "Key Radio";
   case AST_CONTROL_RADIO_UNKEY:
      return "Un-Key Radio";
   }
   return "UNKNOWN";
}
static struct ast_variable * copy_vars ( struct ast_variable src) [static, read]

duplicate a list of channel variables,

Returns:
the copy.

Definition at line 4624 of file chan_mgcp.c.

References ast_variable_new(), and ast_variable::next.

Referenced by build_gateway().

{
   struct ast_variable *res = NULL, *tmp, *v = NULL;

   for (v = src ; v ; v = v->next) {
      if ((tmp = ast_variable_new(v->name, v->value, v->file))) {
         tmp->next = res;
         res = tmp;
      }
   }
   return res;
}
static void destroy_endpoint ( struct mgcp_endpoint e) [static]

Definition at line 4495 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_subchannel::lock, mgcp_endpoint::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, sub, mgcp_endpoint::sub, cops_gate::tech_pvt, and transmit_connection_del().

Referenced by prune_gateways().

{
   struct mgcp_subchannel *sub = e->sub->next, *s;
   int i;

   for (i = 0; i < MAX_SUBS; i++) {
      ast_mutex_lock(&sub->lock);
      if (!ast_strlen_zero(sub->cxident)) {
         transmit_connection_del(sub);
      }
      if (sub->rtp) {
         ast_rtp_instance_destroy(sub->rtp);
         sub->rtp = NULL;
      }
      memset(sub->magic, 0, sizeof(sub->magic));
      mgcp_queue_hangup(sub);
      dump_cmd_queues(NULL, sub);
      if(sub->gate) {
         sub->gate->tech_pvt = NULL;
         sub->gate->got_dq_gi = NULL;
         sub->gate->gate_remove = NULL;
         sub->gate->gate_open = NULL;
      }
      ast_mutex_unlock(&sub->lock);
      sub = sub->next;
   }

   if (e->dsp) {
      ast_dsp_free(e->dsp);
   }

   dump_queue(e->parent, e);
   dump_cmd_queues(e, NULL);

   sub = e->sub;
   for (i = 0; (i < MAX_SUBS) && sub; i++) {
      s = sub;
      sub = sub->next;
      ast_mutex_destroy(&s->lock);
      ast_mutex_destroy(&s->cx_queue_lock);
      ast_free(s);
   }

   if (e->mwi_event_sub)
      ast_event_unsubscribe(e->mwi_event_sub);

   if (e->chanvars) {
      ast_variables_destroy(e->chanvars);
      e->chanvars = NULL;
   }

   ast_mutex_destroy(&e->lock);
   ast_mutex_destroy(&e->rqnt_queue_lock);
   ast_mutex_destroy(&e->cmd_queue_lock);
   e->cap = ast_format_cap_destroy(e->cap);
   ast_free(e);
}
static void destroy_gateway ( struct mgcp_gateway g) [static]

Definition at line 4553 of file chan_mgcp.c.

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

Referenced by prune_gateways().

{
   if (g->ha)
      ast_free_ha(g->ha);

   dump_queue(g, NULL);

   ast_free(g);
}
static void* do_monitor ( void *  data) [static]

Definition at line 3792 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, mgcp_reloading, mgcpsock_read(), monlock, mgcp_gateway::msgs_lock, netlock, mgcp_gateway::next, mgcp_gateway::realtime, reload_config(), transmit_notify_request(), and TYPE_LINE.

Referenced by restart_monitor().

{
   int res;
   int reloading;
   struct mgcp_gateway *g, *gprev;
   /*struct mgcp_gateway *g;*/
   /*struct mgcp_endpoint *e;*/
   /*time_t thispass = 0, lastpass = 0;*/
   time_t lastrun = 0;

   /* Add an I/O event to our UDP socket */
   if (mgcpsock > -1) {
      mgcpsock_read_id = ast_io_add(io, mgcpsock, mgcpsock_read, AST_IO_IN, NULL);
   }
   /* This thread monitors all the frame relay interfaces which are not yet in use
      (and thus do not have a separate thread) indefinitely */
   /* From here on out, we die whenever asked */
   for (;;) {
      /* Check for a reload request */
      ast_mutex_lock(&mgcp_reload_lock);
      reloading = mgcp_reloading;
      mgcp_reloading = 0;
      ast_mutex_unlock(&mgcp_reload_lock);
      if (reloading) {
         ast_verb(1, "Reloading MGCP\n");
         reload_config(1);
         /* Add an I/O event to our UDP socket */
         if (mgcpsock > -1 && !mgcpsock_read_id) {
            mgcpsock_read_id = ast_io_add(io, mgcpsock, mgcpsock_read, AST_IO_IN, NULL);
         }
      }

      /* Check for interfaces needing to be killed */
      /* Don't let anybody kill us right away.  Nobody should lock the interface list
         and wait for the monitor list, but the other way around is okay. */
      ast_mutex_lock(&monlock);
      /* Lock the network interface */
      ast_mutex_lock(&netlock);

#if 0
      /* XXX THIS IS COMPLETELY HOSED */
      /* The gateway goes into a state of panic */
      /* If the vmwi indicator is sent while it is reseting interfaces */
      lastpass = thispass;
      thispass = time(NULL);
      g = gateways;
      while(g) {
         if (thispass != lastpass) {
            e = g->endpoints;
            while(e) {
               if (e->type == TYPE_LINE) {
                  res = has_voicemail(e);
                  if ((e->msgstate != res) && (e->hookstate == MGCP_ONHOOK) && (!e->rtp)){
                     if (res) {
                        transmit_notify_request(e, "L/vmwi(+)");
                     } else {
                        transmit_notify_request(e, "L/vmwi(-)");
                     }
                     e->msgstate = res;
                     e->onhooktime = thispass;
                  }
               }
               e = e->next;
            }
         }
         g = g->next;
      }
#endif
      /* pruning unused realtime gateways, running in every 60 seconds*/
      if(time(NULL) > (lastrun + 60)) {
         ast_mutex_lock(&gatelock);
         g = gateways;
         gprev = NULL;
         while(g) {
            if(g->realtime) {
               if(mgcp_prune_realtime_gateway(g)) {
                  if(gprev) {
                     gprev->next = g->next;
                  } else {
                     gateways = g->next;
                  }
                  ast_mutex_unlock(&g->msgs_lock);
                  ast_mutex_destroy(&g->msgs_lock);
                  free(g);
               } else {
                  ast_mutex_unlock(&g->msgs_lock);
                  gprev = g;
               }
            } else {
               gprev = g;
            }
            g = g->next;
         }
         ast_mutex_unlock(&gatelock);
         lastrun = time(NULL);
      }
      /* Okay, now that we know what to do, release the network lock */
      ast_mutex_unlock(&netlock);
      /* And from now on, we're okay to be killed, so release the monitor lock as well */
      ast_mutex_unlock(&monlock);
      pthread_testcancel();
      /* Wait for sched or io */
      res = ast_sched_wait(sched);
      /* copied from chan_sip.c */
      if ((res < 0) || (res > 1000)) {
         res = 1000;
      }
      res = ast_io_wait(io, res);
      ast_mutex_lock(&monlock);
      if (res >= 0) {
         ast_sched_runq(sched);
      }
      ast_mutex_unlock(&monlock);
   }
   /* Never reached */
   return NULL;
}
static void dump_cmd_queues ( struct mgcp_endpoint p,
struct mgcp_subchannel sub 
) [static]

dump_cmd_queues: (SC:) cleanup pending commands

Definition at line 2713 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_request::next, mgcp_subchannel::next, mgcp_endpoint::rqnt_queue, mgcp_endpoint::rqnt_queue_lock, and mgcp_endpoint::sub.

Referenced by destroy_endpoint(), handle_request(), handle_response(), and unalloc_sub().

{
   struct mgcp_request *t, *q;

   if (p) {
      ast_mutex_lock(&p->rqnt_queue_lock);
      for (q = p->rqnt_queue; q; t = q->next, ast_free(q), q=t);
      p->rqnt_queue = NULL;
      ast_mutex_unlock(&p->rqnt_queue_lock);

      ast_mutex_lock(&p->cmd_queue_lock);
      for (q = p->cmd_queue; q; t = q->next, ast_free(q), q=t);
      p->cmd_queue = NULL;
      ast_mutex_unlock(&p->cmd_queue_lock);

      ast_mutex_lock(&p->sub->cx_queue_lock);
      for (q = p->sub->cx_queue; q; t = q->next, ast_free(q), q=t);
      p->sub->cx_queue = NULL;
      ast_mutex_unlock(&p->sub->cx_queue_lock);

      ast_mutex_lock(&p->sub->next->cx_queue_lock);
      for (q = p->sub->next->cx_queue; q; t = q->next, ast_free(q), q=t);
      p->sub->next->cx_queue = NULL;
      ast_mutex_unlock(&p->sub->next->cx_queue_lock);
   } else if (sub) {
      ast_mutex_lock(&sub->cx_queue_lock);
      for (q = sub->cx_queue; q; t = q->next, ast_free(q), q=t);
      sub->cx_queue = NULL;
      ast_mutex_unlock(&sub->cx_queue_lock);
   }
}
static void dump_queue ( struct mgcp_gateway gw,
struct mgcp_endpoint p 
) [static]

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

{
   struct mgcp_message *cur, *q = NULL, *w, *prev;

   ast_mutex_lock(&gw->msgs_lock);
   for (prev = NULL, cur = gw->msgs; cur; prev = cur, cur = cur->next) {
      if (!p || cur->owner_ep == p) {
         if (prev) {
            prev->next = cur->next;
         } else {
            gw->msgs = cur->next;
         }

         ast_log(LOG_NOTICE, "Removing message from %s transaction %u\n",
            gw->name, cur->seqno);

         w = cur;
         if (q) {
            w->next = q;
         } else {
            w->next = NULL;
         }
         q = w;
      }
   }
   ast_mutex_unlock(&gw->msgs_lock);

   while (q) {
      cur = q;
      q = q->next;
      ast_free(cur);
   }
}
static int find_and_retrans ( struct mgcp_subchannel sub,
struct mgcp_request req 
) [static]

Definition at line 3613 of file chan_mgcp.c.

References ast_free, mgcp_request::identifier, mgcp_response::next, mgcp_subchannel::parent, mgcp_endpoint::parent, resend_response(), RESPONSE_TIMEOUT, and mgcp_gateway::responses.

Referenced by mgcpsock_read().

{
   int seqno=0;
   time_t now;
   struct mgcp_response *prev = NULL, *cur, *next, *answer = NULL;
   time(&now);
   if (sscanf(req->identifier, "%30d", &seqno) != 1) {
      seqno = 0;
   }
   for (cur = sub->parent->parent->responses, next = cur ? cur->next : NULL; cur; cur = next, next = cur ? cur->next : NULL) {
      if (now - cur->whensent > RESPONSE_TIMEOUT) {
         /* Delete this entry */
         if (prev)
            prev->next = next;
         else
            sub->parent->parent->responses = next;
         ast_free(cur);
      } else {
         if (seqno == cur->seqno)
            answer = cur;
         prev = cur;
      }
   }
   if (answer) {
      resend_response(sub, answer);
      return 1;
   }
   return 0;
}
static struct mgcp_request* find_command ( struct mgcp_endpoint p,
struct mgcp_subchannel sub,
struct mgcp_request **  queue,
ast_mutex_t l,
int  ident 
) [static, read]

find_command: (SC:) remove command transaction from queue

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

{
   struct mgcp_request *prev, *req;

   ast_mutex_lock(l);
   for (prev = NULL, req = *queue; req; prev = req, req = req->next) {
      if (req->trid == ident) {
         /* remove from queue */
         if (!prev)
            *queue = req->next;
         else
            prev->next = req->next;

         /* send next pending command */
         if (*queue) {
            ast_debug(1, "Posting Queued Request:\n%s to %s:%d\n", (*queue)->data,
               ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));

            mgcp_postrequest(p, sub, (*queue)->data, (*queue)->len, (*queue)->trid);
         }
         break;
      }
   }
   ast_mutex_unlock(l);
   return req;
}
static struct mgcp_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 1669 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, ast_variable::next, mgcp_endpoint::next, mgcp_gateway::next, mgcp_gateway::realtime, transmit_audit_endpoint(), and ast_variable::value.

Referenced by find_subchannel_and_lock().

{
   struct mgcp_gateway *g = NULL;
   struct ast_variable *mgcpgwconfig = NULL;
   struct ast_variable *gwv, *epname = NULL;
   struct mgcp_endpoint *e;
   char lines[256];
   int i, j;

   ast_debug(1, "*** find Realtime MGCPGW\n");

   if (!(i = ast_check_realtime("mgcpgw")) || !(j = ast_check_realtime("mgcpep"))) {
      return NULL;
   }

   if (ast_strlen_zero(at)) {
      ast_debug(1, "null gw name\n");
      return NULL;
   }

   if (!(mgcpgwconfig = ast_load_realtime("mgcpgw", "name", at, NULL))) {
      return NULL;
   }

   /*!
    * \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.
    */
   lines[0] = '\0';
   for (gwv = mgcpgwconfig; gwv; gwv = gwv->next) {
      if (!strcasecmp(gwv->name, "lines")) {
         ast_copy_string(lines, gwv->value, sizeof(lines));
         break;
      }
   }
   /* Position gwv at the end of the list */
   for (gwv = gwv && gwv->next ? gwv : mgcpgwconfig; gwv->next; gwv = gwv->next);

   if (!ast_strlen_zero(lines)) {
      AST_DECLARE_APP_ARGS(args,
         AST_APP_ARG(line)[100];
      );
      AST_STANDARD_APP_ARGS(args, lines);
      for (i = 0; i < args.argc; i++) {
         gwv->next = ast_load_realtime("mgcpep", "name", at, "line", args.line[i], NULL);

         /* Remove "line" AND position gwv at the end of the list. */
         for (epname = NULL; gwv->next; gwv = gwv->next) {
            if (!strcasecmp(gwv->next->name, "line")) {
               /* Remove it from the list */
               epname = gwv->next;
               gwv->next = gwv->next->next;
            }
         }
         /* Since "line" instantiates the configuration, we have to move it to the end. */
         if (epname) {
            gwv->next = epname;
            epname->next = NULL;
            gwv = gwv->next;
         }
      }
   }
   for (gwv = mgcpgwconfig; gwv; gwv = gwv->next) {
      ast_debug(1, "MGCP Realtime var: %s => %s\n", gwv->name, gwv->value);
   }

   if (mgcpgwconfig) {
      g = build_gateway(at, mgcpgwconfig);
      ast_variables_destroy(mgcpgwconfig);
   }
   if (g) {
      g->next = gateways;
      g->realtime = 1;
      gateways = g;
      for (e = g->endpoints; e; e = e->next) {
         transmit_audit_endpoint(e);
         e->needaudit = 0;
      }
   }
   return g;
}
static struct mgcp_subchannel* find_subchannel_and_lock ( char *  name,
int  msgid,
struct sockaddr_in *  sin 
) [static, read]

Definition at line 1760 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, sub, and mgcp_endpoint::sub.

Referenced by mgcp_request(), and mgcpsock_read().

{
   struct mgcp_endpoint *p = NULL;
   struct mgcp_subchannel *sub = NULL;
   struct mgcp_gateway *g;
   char tmp[256] = "";
   char *at = NULL, *c;
   int found = 0;
   if (name) {
      ast_copy_string(tmp, name, sizeof(tmp));
      at = strchr(tmp, '@');
      if (!at) {
         ast_log(LOG_NOTICE, "Endpoint '%s' has no at sign!\n", name);
         return NULL;
      }
      *at++ = '\0';
   }
   ast_mutex_lock(&gatelock);
   if (at && (at[0] == '[')) {
      at++;
      c = strrchr(at, ']');
      if (c) {
         *c = '\0';
      }
   }
   for (g = gateways ? gateways : find_realtime_gw(name, at, sin); g; g = g->next ? g->next : find_realtime_gw(name, at, sin)) {
      if ((!name || !strcasecmp(g->name, at)) &&
          (sin || g->addr.sin_addr.s_addr || g->defaddr.sin_addr.s_addr)) {
         /* Found the gateway.  If it's dynamic, save it's address -- now for the endpoint */
         if (sin && g->dynamic && name) {
            if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
               (g->addr.sin_port != sin->sin_port)) {
               memcpy(&g->addr, sin, sizeof(g->addr));
               {
                  struct ast_sockaddr tmp1, tmp2;
                  struct sockaddr_in tmp3 = {0,};

                  tmp3.sin_addr = g->ourip;
                  ast_sockaddr_from_sin(&tmp1, &g->addr);
                  ast_sockaddr_from_sin(&tmp2, &tmp3);
                  if (ast_ouraddrfor(&tmp1, &tmp2)) {
                     memcpy(&g->ourip, &__ourip, sizeof(g->ourip));
                  }
                  ast_sockaddr_to_sin(&tmp2, &tmp3);
                  g->ourip = tmp3.sin_addr;
               }
               ast_verb(3, "Registered MGCP gateway '%s' at %s port %d\n", g->name, ast_inet_ntoa(g->addr.sin_addr), ntohs(g->addr.sin_port));
            }
         /* not dynamic, check if the name matches */
         } else if (name) {
            if (strcasecmp(g->name, at)) {
               g = g->next;
               continue;
            }
         /* not dynamic, no name, check if the addr matches */
         } else if (!name && sin) {
            if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
                (g->addr.sin_port != sin->sin_port)) {
               if(!g->next)
                  g = find_realtime_gw(name, at, sin);
               else
                  g = g->next;
               continue;
            }
         } else {
            continue;
         }
         for (p = g->endpoints; p; p = p->next) {
            ast_debug(1, "Searching on %s@%s for subchannel\n", p->name, g->name);
            if (msgid) {
               sub = p->sub;
               found = 1;
               break;
            } else if (name && !strcasecmp(p->name, tmp)) {
               ast_debug(1, "Coundn't determine subchannel, assuming current master %s@%s-%d\n",
                  p->name, g->name, p->sub->id);
               sub = p->sub;
               found = 1;
               break;
            }
         }
         if (sub && found) {
            ast_mutex_lock(&sub->lock);
            break;
         }
      }
   }
   ast_mutex_unlock(&gatelock);
   if (!sub) {
      if (name) {
         if (g) {
            ast_log(LOG_NOTICE, "Endpoint '%s' not found on gateway '%s'\n", tmp, at);
         } else {
            ast_log(LOG_NOTICE, "Gateway '%s' (and thus its endpoint '%s') does not exist\n", at, tmp);
         }
      }
   }
   return sub;
}
static char* get_csv ( char *  c,
int *  len,
char **  next 
) [static]

get_csv: (SC:) get comma separated value

Definition at line 1645 of file chan_mgcp.c.

Referenced by handle_response().

{
   char *s;

   *next = NULL, *len = 0;
   if (!c) return NULL;

   while (*c && (*c < 33 || *c == ',')) {
      c++;
   }

   s = c;
   while (*c && (*c >= 33 && *c != ',')) {
      c++, (*len)++;
   }
   *next = c;

   if (*len == 0) {
      s = NULL, *next = NULL;
   }

   return s;
}
static char* get_header ( struct mgcp_request req,
char *  name 
) [static]

Definition at line 1638 of file chan_mgcp.c.

References __get_header().

Referenced by handle_request(), and handle_response().

{
   int start = 0;
   return __get_header(req, name, &start, "");
}
static char* get_sdp ( struct mgcp_request req,
char *  name 
) [static]

Definition at line 1589 of file chan_mgcp.c.

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

Referenced by process_sdp().

{
   int x;
   int len = strlen(name);
   char *r;

   for (x = 0; x < req->lines; x++) {
      r = get_sdp_by_line(req->line[x], name, len);
      if (r[0] != '\0') return r;
   }
   return "";
}
static char* get_sdp_by_line ( char *  line,
char *  name,
int  nameLen 
) [static]

Definition at line 1579 of file chan_mgcp.c.

Referenced by get_sdp(), and get_sdp_iterate().

{
   if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') {
      char *r = line + nameLen + 1;
      while (*r && (*r < 33)) ++r;
      return r;
   }
   return "";
}
static char* get_sdp_iterate ( int *  iterator,
struct mgcp_request req,
char *  name 
) [static]

Definition at line 1607 of file chan_mgcp.c.

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

Referenced by process_sdp().

{
   int len = strlen(name);
   char *r;
   while (*iterator < req->lines) {
      r = get_sdp_by_line(req->line[(*iterator)++], name, len);
      if (r[0] != '\0') return r;
   }
   return "";
}
static void handle_hd_hf ( struct mgcp_subchannel sub,
char *  ev 
) [static]

Definition at line 3286 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_endpoint::name, mgcp_gateway::name, mgcp_endpoint::ncs, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_subchannel::parent, mgcp_endpoint::parent, mgcp_subchannel::rtp, start_rtp(), transmit_modify_request(), and transmit_notify_request().

Referenced by handle_request().

{
   struct mgcp_endpoint *p = sub->parent;
   struct ast_channel *c;
   pthread_t t;

   /* Off hook / answer */
   if (sub->outgoing) {
      /* Answered */
      if (sub->owner) {
         if (ast_bridged_channel(sub->owner))
            ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
         sub->cxmode = MGCP_CX_SENDRECV;
         if (!sub->rtp) {
            start_rtp(sub);
         } else {
            transmit_modify_request(sub);
         }
         /*transmit_notify_request(sub, "aw");*/
         transmit_notify_request(sub, "");
         mgcp_queue_control(sub, AST_CONTROL_ANSWER);
      }
   } else {
      /* Start switch */
      /*sub->cxmode = MGCP_CX_SENDRECV;*/
      if (!sub->owner) {
         if (!sub->rtp) {
            start_rtp(sub);
         } else {
            transmit_modify_request(sub);
         }
         if (p->immediate) {
            /* The channel is immediately up. Start right away */
#ifdef DLINK_BUGGY_FIRMWARE
            transmit_notify_request(sub, "rt");
#else
            transmit_notify_request(sub, p->ncs ? "L/rt" : "G/rt");
#endif
            c = mgcp_new(sub, AST_STATE_RING, NULL);
            if (!c) {
               ast_log(LOG_WARNING, "Unable to start PBX on channel %s@%s\n", p->name, p->parent->name);
               transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
               ast_hangup(c);
            }
         } else {
            if (has_voicemail(p)) {
               transmit_notify_request(sub, "L/sl");
            } else {
               transmit_notify_request(sub, "L/dl");
            }
            c = mgcp_new(sub, AST_STATE_DOWN, NULL);
            if (c) {
               if (ast_pthread_create_detached(&t, NULL, mgcp_ss, c)) {
                  ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
                  ast_hangup(c);
               }
            } else {
               ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", p->name, p->parent->name);
            }
         }
      } else {
         if (p->hookstate == MGCP_OFFHOOK) {
            ast_log(LOG_WARNING, "Off hook, but already have owner on %s@%s\n", p->name, p->parent->name);
         } else {
            ast_log(LOG_WARNING, "On hook, but already have owner on %s@%s\n", p->name, p->parent->name);
            ast_log(LOG_WARNING, "If we're onhook why are we here trying to handle a hd or hf?\n");
         }
         if (ast_bridged_channel(sub->owner))
            ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
         sub->cxmode = MGCP_CX_SENDRECV;
         if (!sub->rtp) {
            start_rtp(sub);
         } else {
            transmit_modify_request(sub);
         }
         /*transmit_notify_request(sub, "aw");*/
         transmit_notify_request(sub, "");
         /*ast_queue_control(sub->owner, AST_CONTROL_ANSWER);*/
      }
   }
}
static char* handle_mgcp_audit_endpoint ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1080 of file chan_mgcp.c.

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

{
   struct mgcp_gateway  *mg;
   struct mgcp_endpoint *me;
   int found = 0;
   char *ename,*gname, *c;

   switch (cmd) {
   case CLI_INIT:
      e->command = "mgcp audit endpoint";
      e->usage =
         "Usage: mgcp audit endpoint <endpointid>\n"
         "       Lists the capabilities of an endpoint in the MGCP (Media Gateway Control Protocol) subsystem.\n"
         "       mgcp debug MUST be on to see the results of this command.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (!mgcpdebug) {
      return CLI_SHOWUSAGE;
   }
   if (a->argc != 4)
      return CLI_SHOWUSAGE;
   /* split the name into parts by null */
   ename = ast_strdupa(a->argv[3]);
   for (gname = ename; *gname; gname++) {
      if (*gname == '@') {
         *gname = 0;
         gname++;
         break;
      }
   }
   if (gname[0] == '[') {
      gname++;
   }
   if ((c = strrchr(gname, ']'))) {
      *c = '\0';
   }
   ast_mutex_lock(&gatelock);
   for (mg = gateways; mg; mg = mg->next) {
      if (!strcasecmp(mg->name, gname)) {
         for (me = mg->endpoints; me; me = me->next) {
            if (!strcasecmp(me->name, ename)) {
               found = 1;
               transmit_audit_endpoint(me);
               break;
            }
         }
         if (found) {
            break;
         }
      }
   }
   if (!found) {
      ast_cli(a->fd, "   << Could not find endpoint >>     ");
   }
   ast_mutex_unlock(&gatelock);
   return CLI_SUCCESS;
}
static char* handle_mgcp_set_debug ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1141 of file chan_mgcp.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "mgcp set debug {on|off}";
      e->usage =
         "Usage: mgcp set debug {on|off}\n"
         "       Enables/Disables dumping of MGCP packets for debugging purposes\n";   
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != e->args)
      return CLI_SHOWUSAGE;

   if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
      mgcpdebug = 1;
      ast_cli(a->fd, "MGCP Debugging Enabled\n");
   } else if (!strncasecmp(a->argv[3], "off", 3)) {
      mgcpdebug = 0;
      ast_cli(a->fd, "MGCP Debugging Disabled\n");
   } else {
      return CLI_SHOWUSAGE;
   }
   return CLI_SUCCESS;
}
static char* handle_mgcp_show_endpoints ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

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

{
   struct mgcp_gateway  *mg;
   struct mgcp_endpoint *me;
   int hasendpoints = 0;
   struct ast_variable * v = NULL;

   switch (cmd) {
   case CLI_INIT:
      e->command = "mgcp show endpoints";
      e->usage =
         "Usage: mgcp show endpoints\n"
         "       Lists all endpoints known to the MGCP (Media Gateway Control Protocol) subsystem.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 3) {
      return CLI_SHOWUSAGE;
   }
   ast_mutex_lock(&gatelock);
   for (mg = gateways; mg; mg = mg->next) {
      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");
      for (me = mg->endpoints; me; me = me->next) {
         ast_cli(a->fd, "   -- '%s@%s in '%s' is %s\n", me->name, mg->name, me->context, me->sub->owner ? "active" : "idle");
         if (me->chanvars) {
            ast_cli(a->fd, "  Variables:\n");
            for (v = me->chanvars ; v ; v = v->next) {
               ast_cli(a->fd, "    %s = '%s'\n", v->name, v->value);
            }
         }
         hasendpoints = 1;
      }
      if (!hasendpoints) {
         ast_cli(a->fd, "   << No Endpoints Defined >>     ");
      }
   }
   ast_mutex_unlock(&gatelock);
   return CLI_SUCCESS;
}
static int handle_request ( struct mgcp_subchannel sub,
struct mgcp_request req,
struct sockaddr_in *  sin 
) [static]

Definition at line 3368 of file chan_mgcp.c.

References 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_endpoint::name, mgcp_gateway::name, mgcp_endpoint::ncs, mgcp_subchannel::next, mgcp_endpoint::next, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_subchannel::parent, mgcp_endpoint::parent, mgcp_subchannel::rtp, ast_frame::src, sub, mgcp_endpoint::sub, ast_frame::subclass, mgcp_endpoint::threewaycalling, mgcp_endpoint::transfer, transmit_audit_endpoint(), transmit_connection_del(), transmit_modify_request(), transmit_notify_request(), transmit_response(), mgcp_request::verb, and mgcp_gateway::wcardep.

Referenced by mgcpsock_read().

{
   char *ev, *s;
   struct ast_frame f = { 0, };
   struct mgcp_endpoint *p = sub->parent;
   struct mgcp_gateway *g = NULL;
   int res;

   ast_debug(1, "Handling request '%s' on %s@%s\n", req->verb, p->name, p->parent->name);
   /* Clear out potential response */
   if (!strcasecmp(req->verb, "RSIP")) {
      /* Test if this RSIP request is just a keepalive */
      if (!strcasecmp( get_header(req, "RM"), "X-keepalive")) {
         ast_verb(3, "Received keepalive request from %s@%s\n", p->name, p->parent->name);
         transmit_response(sub, "200", req, "OK");
      } else {
         dump_queue(p->parent, p);
         dump_cmd_queues(p, NULL);

         if ((strcmp(p->name, p->parent->wcardep) != 0)) {
            ast_verb(3, "Resetting interface %s@%s\n", p->name, p->parent->name);
         }
         /* For RSIP on wildcard we reset all endpoints */
         if (!strcmp(p->name, p->parent->wcardep)) {
            /* Reset all endpoints */
            struct mgcp_endpoint *tmp_ep;

            g = p->parent;
            for (tmp_ep = g->endpoints; tmp_ep; tmp_ep = tmp_ep->next) {
               /*if ((strcmp(tmp_ep->name, "*") != 0) && (strcmp(tmp_ep->name, "aaln/" "*") != 0)) {*/
               if (strcmp(tmp_ep->name, g->wcardep) != 0) {
                  struct mgcp_subchannel *tmp_sub, *first_sub;
                  ast_verb(3, "Resetting interface %s@%s\n", tmp_ep->name, p->parent->name);

                  first_sub = tmp_ep->sub;
                  tmp_sub = tmp_ep->sub;
                  while (tmp_sub) {
                     mgcp_queue_hangup(tmp_sub);
                     tmp_sub = tmp_sub->next;
                     if (tmp_sub == first_sub)
                        break;
                  }
               }
            }
         } else if (sub->owner) {
            mgcp_queue_hangup(sub);
         }
         transmit_response(sub, "200", req, "OK");
         /* We don't send NTFY or AUEP to wildcard ep */
         if (strcmp(p->name, p->parent->wcardep) != 0) {
            transmit_notify_request(sub, "");
            /* Audit endpoint.
             Idea is to prevent lost lines due to race conditions
            */
            transmit_audit_endpoint(p);
         }
      }
   } else if (!strcasecmp(req->verb, "NTFY")) {
      /* Acknowledge and be sure we keep looking for the same things */
      transmit_response(sub, "200", req, "OK");
      /* Notified of an event */
      ev = get_header(req, "O");
      s = strchr(ev, '/');
      if (s) ev = s + 1;
      ast_debug(1, "Endpoint '%s@%s-%d' observed '%s'\n", p->name, p->parent->name, sub->id, ev);
      /* Keep looking for events unless this was a hangup */
      if (strcasecmp(ev, "hu") && strcasecmp(ev, "hd") && strcasecmp(ev, "ping")) {
         transmit_notify_request(sub, p->curtone);
      }
      if (!strcasecmp(ev, "hd")) {
         p->hookstate = MGCP_OFFHOOK;
         sub->cxmode = MGCP_CX_SENDRECV;

         if (p) {
           /* When the endpoint have a Off hook transition we allways
              starts without any previous dtmfs */
           memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
         }

         handle_hd_hf(sub, ev);
      } else if (!strcasecmp(ev, "hf")) {
         /* We can assume we are offhook if we received a hookflash */
         /* First let's just do call wait and ignore threeway */
         /* We're currently in charge */
         if (p->hookstate != MGCP_OFFHOOK) {
            /* Cisco c7940 sends hf even if the phone is onhook */
            /* Thanks to point on IRC for pointing this out */
            return -1;
         }
         /* do not let * conference two down channels */
         if (sub->owner && ast_channel_state(sub->owner) == AST_STATE_DOWN && !sub->next->owner)
            return -1;

         if (p->callwaiting || p->transfer || p->threewaycalling) {
            ast_verb(3, "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name);
            p->sub = p->sub->next;

            /* transfer control to our next subchannel */
            if (!sub->next->owner) {
               /* plave the first call on hold and start up a new call */
               sub->cxmode = MGCP_CX_MUTE;
               ast_verb(3, "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
               transmit_modify_request(sub);
               if (sub->owner && ast_bridged_channel(sub->owner))
                  ast_queue_control(sub->owner, AST_CONTROL_HOLD);
               sub->next->cxmode = MGCP_CX_RECVONLY;
               handle_hd_hf(sub->next, ev);
            } else if (sub->owner && sub->next->owner) {
               /* We've got two active calls lets decide whether or not to conference or just flip flop */
               if ((!sub->outgoing) && (!sub->next->outgoing)) {
                  /* We made both calls lets conferenct */
                  ast_verb(3, "MGCP Conferencing %d and %d on %s@%s\n",
                        sub->id, sub->next->id, p->name, p->parent->name);
                  sub->cxmode = MGCP_CX_CONF;
                  sub->next->cxmode = MGCP_CX_CONF;
                  if (ast_bridged_channel(sub->next->owner))
                     ast_queue_control(sub->next->owner, AST_CONTROL_UNHOLD);
                  transmit_modify_request(sub);
                  transmit_modify_request(sub->next);
               } else {
                  /* Let's flipflop between calls */
                  /* XXX Need to check for state up ??? */
                  /* XXX Need a way to indicate the current call, or maybe the call that's waiting */
                  ast_verb(3, "We didn't make one of the calls FLIPFLOP %d and %d on %s@%s\n",
                        sub->id, sub->next->id, p->name, p->parent->name);
                  sub->cxmode = MGCP_CX_MUTE;
                  ast_verb(3, "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name);
                  transmit_modify_request(sub);
                  if (ast_bridged_channel(sub->owner))
                     ast_queue_control(sub->owner, AST_CONTROL_HOLD);

                  if (ast_bridged_channel(sub->next->owner))
                     ast_queue_control(sub->next->owner, AST_CONTROL_HOLD);

                  handle_hd_hf(sub->next, ev);
               }
            } else {
               /* We've most likely lost one of our calls find an active call and bring it up */
               if (sub->owner) {
                  p->sub = sub;
               } else if (sub->next->owner) {
                  p->sub = sub->next;
               } else {
                  /* We seem to have lost both our calls */
                  /* XXX - What do we do now? */
                  return -1;
               }
               if (ast_bridged_channel(p->sub->owner))
                  ast_queue_control(p->sub->owner, AST_CONTROL_UNHOLD);
               p->sub->cxmode = MGCP_CX_SENDRECV;
               transmit_modify_request(p->sub);
            }
         } else {
            ast_log(LOG_WARNING, "Callwaiting, call transfer or threeway calling not enabled on endpoint %s@%s\n",
               p->name, p->parent->name);
         }
      } else if (!strcasecmp(ev, "hu")) {
         p->hookstate = MGCP_ONHOOK;
         sub->cxmode = MGCP_CX_RECVONLY;
         ast_debug(1, "MGCP %s@%s Went on hook\n", p->name, p->parent->name);
         /* Do we need to send MDCX before a DLCX ?
         if (sub->rtp) {
            transmit_modify_request(sub);
         }
         */
         if (p->transfer && (sub->owner && sub->next->owner) && ((!sub->outgoing) || (!sub->next->outgoing))) {
            /* We're allowed to transfer, we have two avtive calls and */
            /* we made at least one of the calls.  Let's try and transfer */
            ast_mutex_lock(&p->sub->next->lock);
            res = attempt_transfer(p);
            if (res < 0) {
               if (p->sub->next->owner) {
                  sub->next->alreadygone = 1;
                  mgcp_queue_hangup(sub->next);
               }
            } else if (res) {
               ast_log(LOG_WARNING, "Transfer attempt failed\n");
               ast_mutex_unlock(&p->sub->next->lock);
               return -1;
            }
            ast_mutex_unlock(&p->sub->next->lock);
         } else {
            /* Hangup the current call */
            /* If there is another active call, mgcp_hangup will ring the phone with the other call */
            if (sub->owner) {
               sub->alreadygone = 1;
               mgcp_queue_hangup(sub);
            } else {
               ast_verb(3, "MGCP handle_request(%s@%s-%d) ast_channel already destroyed, resending DLCX.\n",
                     p->name, p->parent->name, sub->id);
               /* Instruct the other side to remove the connection since it apparently *
                * still thinks the channel is active. *
                * For Cisco IAD2421 /BAK/ */
               transmit_connection_del(sub);
            }
         }
         if ((p->hookstate == MGCP_ONHOOK) && (!sub->rtp) && (!sub->next->rtp)) {
            p->hidecallerid = 0;
            if (p->hascallwaiting && !p->callwaiting) {
               ast_verb(3, "Enabling call waiting on MGCP/%s@%s-%d\n", p->name, p->parent->name, sub->id);
               p->callwaiting = -1;
            }
            if (has_voicemail(p)) {
               ast_verb(3, "MGCP handle_request(%s@%s) set vmwi(+)\n", p->name, p->parent->name);
               transmit_notify_request(sub, "L/vmwi(+)");
            } else {
               ast_verb(3, "MGCP handle_request(%s@%s) set vmwi(-)\n", p->name, p->parent->name);
               transmit_notify_request(sub, "L/vmwi(-)");
            }
         }
      } else if ((strlen(ev) == 1) &&
            (((ev[0] >= '0') && (ev[0] <= '9')) ||
             ((ev[0] >= 'A') && (ev[0] <= 'D')) ||
              (ev[0] == '*') || (ev[0] == '#'))) {
         if (sub && sub->owner && (ast_channel_state(sub->owner) >=  AST_STATE_UP)) {
            f.frametype = AST_FRAME_DTMF;
            f.subclass.integer = ev[0];
            f.src = "mgcp";
            /* XXX MUST queue this frame to all subs in threeway call if threeway call is active */
            mgcp_queue_frame(sub, &f);
            ast_mutex_lock(&sub->next->lock);
            if (sub->next->owner)
               mgcp_queue_frame(sub->next, &f);
            ast_mutex_unlock(&sub->next->lock);
            if (strstr(p->curtone, (p->ncs ? "wt1" : "wt")) && (ev[0] == 'A')) {
               memset(p->curtone, 0, sizeof(p->curtone));
            }
         } else {
            p->dtmf_buf[strlen(p->dtmf_buf)] = ev[0];
            p->dtmf_buf[strlen(p->dtmf_buf)] = '\0';
         }
      } else if (!strcasecmp(ev, "T")) {
         /* Digit timeout -- unimportant */
      } else if (!strcasecmp(ev, "ping")) {
         /* ping -- unimportant */
      } else {
         ast_log(LOG_NOTICE, "Received unknown event '%s' from %s@%s\n", ev, p->name, p->parent->name);
      }
   } else {
      ast_log(LOG_WARNING, "Unknown verb '%s' received from %s\n", req->verb, ast_inet_ntoa(sin->sin_addr));
      transmit_response(sub, "510", req, "Unknown verb");
   }
   return 0;
}
static void handle_response ( struct mgcp_endpoint p,
struct mgcp_subchannel sub,
int  result,
unsigned int  ident,
struct mgcp_request resp 
) [static]

Definition at line 2776 of file chan_mgcp.c.

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

{
   char *c;
   struct mgcp_request *req;
   struct mgcp_gateway *gw = p->parent;

   if (result < 200) {
      /* provisional response */
      return;
   }

   if (p->slowsequence)
      req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident);
   else if (sub)
      req = find_command(p, sub, &sub->cx_queue, &sub->cx_queue_lock, ident);
   else if (!(req = find_command(p, sub, &p->rqnt_queue, &p->rqnt_queue_lock, ident)))
      req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident);

   if (!req) {
      ast_verb(3, "No command found on [%s] for transaction %d. Ignoring...\n",
            gw->name, ident);
      return;
   }

   if (p && (result >= 400) && (result <= 599)) {
      switch (result) {
      case 401:
         p->hookstate = MGCP_OFFHOOK;
         break;
      case 402:
         p->hookstate = MGCP_ONHOOK;
         break;
      case 406:
         ast_log(LOG_NOTICE, "Transaction %d timed out\n", ident);
         break;
      case 407:
         ast_log(LOG_NOTICE, "Transaction %d aborted\n", ident);
         break;
      }
      if (sub) {
         if (!sub->cxident[0] && (req->cmd == MGCP_CMD_CRCX)) {
             ast_log(LOG_NOTICE, "DLCX for all connections on %s due to error %d\n", gw->name, result);
             transmit_connection_del(sub);
         }
         if (sub->owner) {
            ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
               result, p->name, p->parent->name, sub ? sub->id:-1);
            mgcp_queue_hangup(sub);
         }
      } else {
         if (p->sub->next->owner) {
            ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
               result, p->name, p->parent->name, sub ? sub->id:-1);
            mgcp_queue_hangup(p->sub);
         }

         if (p->sub->owner) {
            ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
               result, p->name, p->parent->name, sub ? sub->id:-1);
            mgcp_queue_hangup(p->sub);
         }

         dump_cmd_queues(p, NULL);
      }
   }

   if (resp) {
      /* responseAck: */
      if (result == 200 && (req->cmd == MGCP_CMD_CRCX || req->cmd == MGCP_CMD_MDCX)) {
            if (sub) {
               transmit_response(sub, "000", resp, "OK");
               if (sub->owner && ast_channel_state(sub->owner) == AST_STATE_RINGING) {
                  ast_queue_control(sub->owner, AST_CONTROL_RINGING);
               }
            }
      }
      if (req->cmd == MGCP_CMD_CRCX) {
         if ((c = get_header(resp, "I"))) {
            if (!ast_strlen_zero(c) && sub) {
               /* if we are hanging up do not process this conn. */
               if (sub->owner) {
                  if (!ast_strlen_zero(sub->cxident)) {
                     if (strcasecmp(c, sub->cxident)) {
                        ast_log(LOG_WARNING, "Subchannel already has a cxident. sub->cxident: %s requested %s\n", sub->cxident, c);
                     }
                  }
                  ast_copy_string(sub->cxident, c, sizeof(sub->cxident));
                  if (sub->tmpdest.sin_addr.s_addr) {
                     transmit_modify_with_sdp(sub, NULL, 0);
                  }
               } else {
                  /* XXX delete this one
                     callid and conn id may already be lost.
                     so the following del conn may have a side effect of
                     cleaning up the next subchannel */
                  transmit_connection_del(sub);
               }
            }
         }
      }

      if (req->cmd == MGCP_CMD_AUEP) {
         /* check stale connection ids */
         if ((c = get_header(resp, "I"))) {
            char *v, *n;
            int len;
            while ((v = get_csv(c, &len, &n))) {
               if (len) {
                  if (strncasecmp(v, p->sub->cxident, len) &&
                      strncasecmp(v, p->sub->next->cxident, len)) {
                     /* connection id not found. delete it */
                     char cxident[80] = "";

                     if (len > (sizeof(cxident) - 1))
                        len = sizeof(cxident) - 1;
                     ast_copy_string(cxident, v, len);
                     ast_verb(3, "Non existing connection id %s on %s@%s \n",
                               cxident, p->name, gw->name);
                     transmit_connection_del_w_params(p, NULL, cxident);
                  }
               }
               c = n;
            }
         }

         /* Try to determine the hookstate returned from an audit endpoint command */
         if ((c = get_header(resp, "ES"))) {
            if (!ast_strlen_zero(c)) {
               if (strstr(c, "hu")) {
                  if (p->hookstate != MGCP_ONHOOK) {
                     /* XXX cleanup if we think we are offhook XXX */
                     if ((p->sub->owner || p->sub->next->owner ) &&
                         p->hookstate == MGCP_OFFHOOK)
                        mgcp_queue_hangup(sub);
                     p->hookstate = MGCP_ONHOOK;

                     /* update the requested events according to the new hookstate */
                     transmit_notify_request(p->sub, "");

                     ast_verb(3, "Setting hookstate of %s@%s to ONHOOK\n", p->name, gw->name);
                     }
               } else if (strstr(c, "hd")) {
                  if (p->hookstate != MGCP_OFFHOOK) {
                     p->hookstate = MGCP_OFFHOOK;

                     /* update the requested events according to the new hookstate */
                     transmit_notify_request(p->sub, "");

                     ast_verb(3, "Setting hookstate of %s@%s to OFFHOOK\n", p->name, gw->name);
                     }
                  }
               }
            }
         }

      if (resp && resp->lines) {
         /* do not process sdp if we are hanging up. this may be a late response */
         if (sub && sub->owner) {
            if (!sub->rtp)
               start_rtp(sub);
            if (sub->rtp)
               process_sdp(sub, resp);
         }
      }
   }

   ast_free(req);
}
static int init_req ( struct mgcp_endpoint p,
struct mgcp_request req,
char *  verb,
unsigned int  oseq 
) [static]

Definition at line 2115 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_endpoint::name, mgcp_gateway::name, mgcp_endpoint::ncs, and mgcp_endpoint::parent.

Referenced by reqprep().

{
   /* Initialize a response */
   if (req->headers || req->len) {
      ast_log(LOG_WARNING, "Request already initialized?!?\n");
      return -1;
   }
   req->header[req->headers] = req->data + req->len;
   /* check if we need brackets around the gw name */
   if (p->parent->isnamedottedip) {
      snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@[%s] MGCP 1.0%s\r\n", verb, oseq, p->name, p->parent->name, p->ncs ? " NCS 1.0" : "");
   } else {
+     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" : "");
   }
   req->len += strlen(req->header[req->headers]);
   if (req->headers < MGCP_MAX_HEADERS) {
      req->headers++;
   } else {
      ast_log(LOG_WARNING, "Out of header space\n");
   }
   return 0;
}
static int init_resp ( struct mgcp_request req,
char *  resp,
struct mgcp_request orig,
char *  resprest 
) [static]

Definition at line 2097 of file chan_mgcp.c.

References ast_log(), mgcp_request::data, mgcp_request::header, mgcp_request::headers, mgcp_request::identifier, mgcp_request::len, LOG_WARNING, and MGCP_MAX_HEADERS.

Referenced by respprep().

{
   /* Initialize a response */
   if (req->headers || req->len) {
      ast_log(LOG_WARNING, "Request already initialized?!?\n");
      return -1;
   }
   req->header[req->headers] = req->data + req->len;
   snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %s %s\r\n", resp, orig->identifier, resprest);
   req->len += strlen(req->header[req->headers]);
   if (req->headers < MGCP_MAX_HEADERS) {
      req->headers++;
   } else {
      ast_log(LOG_WARNING, "Out of header space\n");
   }
   return 0;
}
static int load_module ( void  ) [static]

load_module: PBX load module - initialization ---

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

{
   struct ast_format tmpfmt;

   if (!(global_capability = ast_format_cap_alloc())) {
      return AST_MODULE_LOAD_FAILURE;
   }
   if (!(mgcp_tech.capabilities = ast_format_cap_alloc())) {
      return AST_MODULE_LOAD_FAILURE;
   }
   ast_format_cap_add(global_capability, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
   ast_format_cap_add(mgcp_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0));
   ast_format_cap_add(mgcp_tech.capabilities, ast_format_set(&tmpfmt, AST_FORMAT_ALAW, 0));
   if (!(sched = ast_sched_context_create())) {
      ast_log(LOG_WARNING, "Unable to create schedule context\n");
      return AST_MODULE_LOAD_FAILURE;
   }

   if (!(io = io_context_create())) {
      ast_log(LOG_WARNING, "Unable to create I/O context\n");
      ast_sched_context_destroy(sched);
      return AST_MODULE_LOAD_FAILURE;
   }

   if (reload_config(0))
      return AST_MODULE_LOAD_DECLINE;

   /* Make sure we can register our mgcp channel type */
   if (ast_channel_register(&mgcp_tech)) {
      ast_log(LOG_ERROR, "Unable to register channel class 'MGCP'\n");
      io_context_destroy(io);
      ast_sched_context_destroy(sched);
      return AST_MODULE_LOAD_FAILURE;
   }

   ast_rtp_glue_register(&mgcp_rtp_glue);
   ast_cli_register_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));

   /* And start the monitor for the first time */
   restart_monitor();

   return AST_MODULE_LOAD_SUCCESS;
}
static int mgcp_alloc_pktcgate ( struct mgcp_subchannel sub) [static]

Definition at line 2432 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_subchannel::parent, mgcp_endpoint::parent, sub, and cops_gate::tech_pvt.

Referenced by start_rtp().

{
   struct mgcp_endpoint *p = sub->parent;
   sub->gate = ast_pktccops_gate_alloc(GATE_SET, NULL, ntohl(p->parent->addr.sin_addr.s_addr),
               8, 128000, 232, 0, 0, NULL, &mgcp_pktcgate_remove);

   if (!sub->gate) {
      return 0;
   }
   sub->gate->tech_pvt = sub;
   sub->gate->gate_open = &mgcp_pktcgate_open;
   return 1;
}
static int mgcp_call ( struct ast_channel ast,
const char *  dest,
int  timeout 
) [static]

Definition at line 836 of file chan_mgcp.c.

References ast_channel_connected(), ast_channel_name(), ast_channel_tech_pvt(), ast_channel_varshead(), 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, mgcp_subchannel::cxident, mgcp_subchannel::cxmode, ast_var_t::entries, mgcp_endpoint::hookstate, mgcp_subchannel::lock, LOG_NOTICE, LOG_WARNING, MGCP_CX_RECVONLY, MGCP_CX_SENDRECV, MGCP_OFFHOOK, MGCP_ONHOOK, name, mgcp_endpoint::ncs, mgcp_subchannel::next, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_subchannel::parent, mgcp_subchannel::rtp, S_COR, start_rtp(), sub, transmit_modify_request(), transmit_notify_request_with_callerid(), mgcp_endpoint::type, and TYPE_LINE.

{
   int res;
   struct mgcp_endpoint *p;
   struct mgcp_subchannel *sub;
   char tone[50] = "";
   const char *distinctive_ring = NULL;
   struct varshead *headp;
   struct ast_var_t *current;

   ast_debug(3, "MGCP mgcp_call(%s)\n", ast_channel_name(ast));
   sub = ast_channel_tech_pvt(ast);
   p = sub->parent;
   headp = ast_channel_varshead(ast);
   AST_LIST_TRAVERSE(headp,current,entries) {
      /* Check whether there is an ALERT_INFO variable */
      if (strcasecmp(ast_var_name(current),"ALERT_INFO") == 0) {
         distinctive_ring = ast_var_value(current);
      }
   }

   ast_mutex_lock(&sub->lock);
   switch (p->hookstate) {
   case MGCP_OFFHOOK:
      if (!ast_strlen_zero(distinctive_ring)) {
         snprintf(tone, sizeof(tone), "L/wt%s", distinctive_ring);
         ast_debug(3, "MGCP distinctive callwait %s\n", tone);
      } else {
         ast_copy_string(tone, (p->ncs ? "L/wt1" : "L/wt"), sizeof(tone));
         ast_debug(3, "MGCP normal callwait %s\n", tone);
      }
      break;
   case MGCP_ONHOOK:
   default:
      if (!ast_strlen_zero(distinctive_ring)) {
         snprintf(tone, sizeof(tone), "L/r%s", distinctive_ring);
         ast_debug(3, "MGCP distinctive ring %s\n", tone);
      } else {
         ast_copy_string(tone, "L/rg", sizeof(tone));
         ast_debug(3, "MGCP default ring\n");
      }
      break;
   }

   if ((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) {
      ast_log(LOG_WARNING, "mgcp_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
      ast_mutex_unlock(&sub->lock);
      return -1;
   }

   res = 0;
   sub->outgoing = 1;
   sub->cxmode = MGCP_CX_RECVONLY;
   ast_setstate(ast, AST_STATE_RINGING);
   if (p->type == TYPE_LINE) {
      if (!sub->rtp) {
         start_rtp(sub);
      } else {
         transmit_modify_request(sub);
      }

      if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) {
         /* try to prevent a callwait from disturbing the other connection */
         sub->next->cxmode = MGCP_CX_RECVONLY;
         transmit_modify_request(sub->next);
      }

      transmit_notify_request_with_callerid(sub, tone,
         S_COR(ast_channel_connected(ast)->id.number.valid, ast_channel_connected(ast)->id.number.str, ""),
         S_COR(ast_channel_connected(ast)->id.name.valid, ast_channel_connected(ast)->id.name.str, ""));
      ast_setstate(ast, AST_STATE_RINGING);

      if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) {
         /* Put the connection back in sendrecv */
         sub->next->cxmode = MGCP_CX_SENDRECV;
         transmit_modify_request(sub->next);
      }
   } else {
      ast_log(LOG_NOTICE, "Don't know how to dial on trunks yet\n");
      res = -1;
   }
   ast_mutex_unlock(&sub->lock);
   return res;
}
static int mgcp_devicestate ( const char *  data) [static]

mgcp_devicestate: channel callback for device status monitoring

Parameters:
datatech/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 1361 of file chan_mgcp.c.

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

{
   struct mgcp_gateway  *g;
   struct mgcp_endpoint *e = NULL;
   char *tmp, *endpt, *gw;
   int ret = AST_DEVICE_INVALID;

   endpt = ast_strdupa(data);
   if ((tmp = strchr(endpt, '@'))) {
      *tmp++ = '\0';
      gw = tmp;
   } else
      goto error;

   ast_mutex_lock(&gatelock);
   for (g = gateways; g; g = g->next) {
      if (strcasecmp(g->name, gw) == 0) {
         e = g->endpoints;
         break;
      }
   }

   if (!e)
      goto error;

   for (; e; e = e->next) {
      if (strcasecmp(e->name, endpt) == 0) {
         break;
      }
   }

   if (!e)
      goto error;

   /*
    * As long as the gateway/endpoint is valid, we'll
    * assume that the device is available and its state
    * can be tracked.
    */
   ret = AST_DEVICE_UNKNOWN;

error:
   ast_mutex_unlock(&gatelock);
   return ret;
}
static int mgcp_fixup ( struct ast_channel oldchan,
struct ast_channel newchan 
) [static]

Definition at line 1283 of file chan_mgcp.c.

References ast_channel_name(), ast_channel_tech_pvt(), ast_log(), ast_mutex_lock, ast_mutex_unlock, mgcp_subchannel::lock, LOG_NOTICE, LOG_WARNING, mgcp_subchannel::owner, and sub.

{
   struct mgcp_subchannel *sub = ast_channel_tech_pvt(newchan);

   ast_mutex_lock(&sub->lock);
   ast_log(LOG_NOTICE, "mgcp_fixup(%s, %s)\n", ast_channel_name(oldchan), ast_channel_name(newchan));
   if (sub->owner != oldchan) {
      ast_mutex_unlock(&sub->lock);
      ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
      return -1;
   }
   sub->owner = newchan;
   ast_mutex_unlock(&sub->lock);
   return 0;
}
static void mgcp_get_codec ( struct ast_channel chan,
struct ast_format_cap result 
) [static]
static enum ast_rtp_glue_result mgcp_get_rtp_peer ( struct ast_channel chan,
struct ast_rtp_instance **  instance 
) [static]
static int mgcp_hangup ( struct ast_channel ast) [static]

Definition at line 921 of file chan_mgcp.c.

References mgcp_subchannel::alreadygone, ast_bridged_channel(), ast_channel_caller(), ast_channel_name(), ast_channel_tech_pvt(), ast_channel_tech_pvt_set(), 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, 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, 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, name, mgcp_endpoint::name, mgcp_gateway::name, mgcp_endpoint::ncs, mgcp_subchannel::next, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_subchannel::parent, mgcp_endpoint::parent, mgcp_endpoint::pktcgatealloc, mgcp_subchannel::rtp, S_COR, ast_module_info::self, cops_gate::state, sub, mgcp_endpoint::sub, cops_gate::tech_pvt, mgcp_subchannel::tmpdest, transmit_connection_del(), transmit_modify_request(), transmit_notify_request(), and transmit_notify_request_with_callerid().

{
   struct mgcp_subchannel *sub = ast_channel_tech_pvt(ast);
   struct mgcp_endpoint *p = sub->parent;
   struct ast_channel *bridged;

   ast_debug(1, "mgcp_hangup(%s)\n", ast_channel_name(ast));
   if (!ast_channel_tech_pvt(ast)) {
      ast_debug(1, "Asked to hangup channel not connected\n");
      return 0;
   }
   if (strcmp(sub->magic, MGCP_SUBCHANNEL_MAGIC)) {
      ast_debug(1, "Invalid magic. MGCP subchannel freed up already.\n");
      return 0;
   }
   ast_mutex_lock(&sub->lock);
   ast_debug(3, "MGCP mgcp_hangup(%s) on %s@%s\n", ast_channel_name(ast), p->name, p->parent->name);

   if ((p->dtmfmode & MGCP_DTMF_INBAND) && p->dsp) {
      /* check whether other channel is active. */
      if (!sub->next->owner) {
         if (p->dtmfmode & MGCP_DTMF_HYBRID) {
            p->dtmfmode &= ~MGCP_DTMF_INBAND;
         }
         ast_debug(2, "MGCP free dsp on %s@%s\n", p->name, p->parent->name);
         ast_dsp_free(p->dsp);
         p->dsp = NULL;
      }
   }

   sub->owner = NULL;

   /* for deleting gate */
   if (p->pktcgatealloc && sub->gate) {
      sub->gate->gate_open = NULL;
      sub->gate->gate_remove = NULL;
      sub->gate->got_dq_gi = NULL;
      sub->gate->tech_pvt = NULL;
      if (sub->gate->state == GATE_ALLOC_PROGRESS || sub->gate->state == GATE_ALLOCATED) {
         ast_pktccops_gate_alloc(GATE_DEL, sub->gate, 0, 0, 0, 0, 0, 0, NULL, NULL);
      } else {
         sub->gate->deltimer = time(NULL) + 5;
      }
      sub->gate = NULL;
   }

   if (!ast_strlen_zero(sub->cxident)) {
      transmit_connection_del(sub);
   }
   sub->cxident[0] = '\0';
   if ((sub == p->sub) && sub->next->owner) {
      if (p->hookstate == MGCP_OFFHOOK) {
         if (sub->next->owner && ast_bridged_channel(sub->next->owner)) {
            /* ncs fix! */
            bridged = ast_bridged_channel(sub->next->owner);
            transmit_notify_request_with_callerid(p->sub, (p->ncs ? "L/wt1" : "L/wt"),
               S_COR(ast_channel_caller(bridged)->id.number.valid, ast_channel_caller(bridged)->id.number.str, ""),
               S_COR(ast_channel_caller(bridged)->id.name.valid, ast_channel_caller(bridged)->id.name.str, ""));
         }
      } else {
         /* set our other connection as the primary and swith over to it */
         p->sub = sub->next;
         p->sub->cxmode = MGCP_CX_RECVONLY;
         transmit_modify_request(p->sub);
         if (sub->next->owner && ast_bridged_channel(sub->next->owner)) {
            bridged = ast_bridged_channel(sub->next->owner);
            transmit_notify_request_with_callerid(p->sub, "L/rg",
               S_COR(ast_channel_caller(bridged)->id.number.valid, ast_channel_caller(bridged)->id.number.str, ""),
               S_COR(ast_channel_caller(bridged)->id.name.valid, ast_channel_caller(bridged)->id.name.str, ""));
         }
      }

   } else if ((sub == p->sub->next) && p->hookstate == MGCP_OFFHOOK) {
      transmit_notify_request(sub, p->ncs ? "" : "L/v");
   } else if (p->hookstate == MGCP_OFFHOOK) {
      transmit_notify_request(sub, "L/ro");
   } else {
      transmit_notify_request(sub, "");
   }

   ast_channel_tech_pvt_set(ast, NULL);
   sub->alreadygone = 0;
   sub->outgoing = 0;
   sub->cxmode = MGCP_CX_INACTIVE;
   sub->callid[0] = '\0';
   if (p) {
      memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
   }
   /* Reset temporary destination */
   memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
   if (sub->rtp) {
      ast_rtp_instance_destroy(sub->rtp);
      sub->rtp = NULL;
   }

   ast_module_unref(ast_module_info->self);

   if ((p->hookstate == MGCP_ONHOOK) && (!sub->next->rtp)) {
      p->hidecallerid = 0;
      if (p->hascallwaiting && !p->callwaiting) {
         ast_verb(3, "Enabling call waiting on %s\n", ast_channel_name(ast));
         p->callwaiting = -1;
      }
      if (has_voicemail(p)) {
         ast_debug(3, "MGCP mgcp_hangup(%s) on %s@%s set vmwi(+)\n",
            ast_channel_name(ast), p->name, p->parent->name);
         transmit_notify_request(sub, "L/vmwi(+)");
      } else {
         ast_debug(3, "MGCP mgcp_hangup(%s) on %s@%s set vmwi(-)\n",
            ast_channel_name(ast), p->name, p->parent->name);
         transmit_notify_request(sub, "L/vmwi(-)");
      }
   }
   ast_mutex_unlock(&sub->lock);
   return 0;
}
static int mgcp_indicate ( struct ast_channel ast,
int  ind,
const void *  data,
size_t  datalen 
) [static]

Definition at line 1439 of file chan_mgcp.c.

References ast_channel_name(), ast_channel_tech_pvt(), AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_HOLD, AST_CONTROL_INCOMPLETE, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_PVT_CAUSE_CODE, 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, transmit_modify_request(), and transmit_notify_request().

{
   struct mgcp_subchannel *sub = ast_channel_tech_pvt(ast);
   int res = 0;

   ast_debug(3, "MGCP asked to indicate %d '%s' condition on channel %s\n",
      ind, control2str(ind), ast_channel_name(ast));
   ast_mutex_lock(&sub->lock);
   switch(ind) {
   case AST_CONTROL_RINGING:
#ifdef DLINK_BUGGY_FIRMWARE   
      transmit_notify_request(sub, "rt");
#else
      if (!sub->sdpsent) { /* will hide the inband progress!!! */
         transmit_notify_request(sub, sub->parent->ncs ? "L/rt" : "G/rt");
      }
#endif
      break;
   case AST_CONTROL_BUSY:
      transmit_notify_request(sub, "L/bz");
      break;
   case AST_CONTROL_INCOMPLETE:
      /* We do not currently support resetting of the Interdigit Timer, so treat
       * Incomplete control frames as a congestion response
       */
   case AST_CONTROL_CONGESTION:
      transmit_notify_request(sub, sub->parent->ncs ? "L/cg" : "G/cg");
      break;
   case AST_CONTROL_HOLD:
      ast_moh_start(ast, data, NULL);
      break;
   case AST_CONTROL_UNHOLD:
      ast_moh_stop(ast);
      break;
   case AST_CONTROL_SRCUPDATE:
      ast_rtp_instance_update_source(sub->rtp);
      break;
   case AST_CONTROL_SRCCHANGE:
      ast_rtp_instance_change_source(sub->rtp);
      break;
   case AST_CONTROL_PROGRESS:
   case AST_CONTROL_PROCEEDING:
      transmit_modify_request(sub);
   case -1:
      transmit_notify_request(sub, "");
      break;
   default:
      ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
      /* fallthrough */
   case AST_CONTROL_PVT_CAUSE_CODE:
      res = -1;
   }
   ast_mutex_unlock(&sub->lock);
   return res;
}
static struct ast_channel* mgcp_new ( struct mgcp_subchannel sub,
int  state,
const char *  linkedid 
) [static, read]

Definition at line 1495 of file chan_mgcp.c.

References mgcp_endpoint::accountcode, mgcp_endpoint::adsi, mgcp_endpoint::amaflags, ast_party_caller::ani, AST_ADSI_UNAVAILABLE, ast_best_codec(), ast_channel_adsicpe_set(), ast_channel_alloc(), ast_channel_amaflags_set(), ast_channel_caller(), ast_channel_callgroup_set(), ast_channel_context_set(), ast_channel_exten_set(), ast_channel_name(), ast_channel_nativeformats(), ast_channel_pickupgroup_set(), ast_channel_priority_set(), ast_channel_rawreadformat(), ast_channel_rawwriteformat(), ast_channel_readformat(), ast_channel_rings_set(), ast_channel_set_fd(), ast_channel_tech_pvt_set(), ast_channel_tech_set(), ast_channel_writeformat(), 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_endpoint::name, mgcp_gateway::name, ast_variable::next, ast_party_id::number, mgcp_subchannel::owner, mgcp_subchannel::parent, mgcp_endpoint::parent, pbx_builtin_setvar_helper(), mgcp_endpoint::pickupgroup, mgcp_subchannel::rtp, ast_module_info::self, ast_party_number::str, ast_party_number::valid, and ast_variable::value.

Referenced by handle_hd_hf(), and mgcp_request().

{
   struct ast_channel *tmp;
   struct ast_variable *v = NULL;
   struct mgcp_endpoint *i = sub->parent;
   struct ast_format tmpfmt;

   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);
   if (tmp) {
      ast_channel_tech_set(tmp, &mgcp_tech);
      ast_format_cap_copy(ast_channel_nativeformats(tmp), i->cap);
      if (ast_format_cap_is_empty(ast_channel_nativeformats(tmp))) {
         ast_format_cap_copy(ast_channel_nativeformats(tmp), global_capability);
      }
      if (sub->rtp) {
         ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0));
      }
      if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) {
         i->dsp = ast_dsp_new();
         ast_dsp_set_features(i->dsp, DSP_FEATURE_DIGIT_DETECT);
         /* this is to prevent clipping of dtmf tones during dsp processing */
         ast_dsp_set_digitmode(i->dsp, DSP_DIGITMODE_NOQUELCH);
      } else {
         i->dsp = NULL;
      }
      if (state == AST_STATE_RING)
         ast_channel_rings_set(tmp, 1);

      ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt);
      ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt);
      ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
      ast_format_copy(ast_channel_readformat(tmp), &tmpfmt);
      ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
      ast_channel_tech_pvt_set(tmp, sub);
      if (!ast_strlen_zero(i->language))
         ast_channel_language_set(tmp, i->language);
      if (!ast_strlen_zero(i->accountcode))
         ast_channel_accountcode_set(tmp, i->accountcode);
      if (i->amaflags)
         ast_channel_amaflags_set(tmp, i->amaflags);
      sub->owner = tmp;
      ast_module_ref(ast_module_info->self);
      ast_channel_callgroup_set(tmp, i->callgroup);
      ast_channel_pickupgroup_set(tmp, i->pickupgroup);
      ast_channel_call_forward_set(tmp, i->call_forward);
      ast_channel_context_set(tmp, i->context);
      ast_channel_exten_set(tmp, i->exten);

      /* Don't use ast_set_callerid() here because it will
       * generate a needless NewCallerID event */
      if (!ast_strlen_zero(i->cid_num)) {
         ast_channel_caller(tmp)->ani.number.valid = 1;
         ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_num);
      }

      if (!i->adsi) {
         ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE);
      }
      ast_channel_priority_set(tmp, 1);

      /* Set channel variables for this call from configuration */
      for (v = i->chanvars ; v ; v = v->next) {
         char valuebuf[1024];
         pbx_builtin_setvar_helper(tmp, v->name, ast_get_encoded_str(v->value, valuebuf, sizeof(valuebuf)));
      }

      if (sub->rtp) {
         ast_jb_configure(tmp, &global_jbconf);
      }
      if (state != AST_STATE_DOWN) {
         if (ast_pbx_start(tmp)) {
            ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
            ast_hangup(tmp);
            tmp = NULL;
         }
      }
      ast_verb(3, "MGCP mgcp_new(%s) created in state: %s\n",
            ast_channel_name(tmp), ast_state2str(state));
   } else {
      ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
   }
   return tmp;
}
static int mgcp_pktcgate_open ( struct cops_gate gate) [static]

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

{
   struct mgcp_subchannel *sub = gate->tech_pvt;
   if (!sub) {
      return 1;
   }
   ast_mutex_lock(&sub->lock);
   ast_debug(1, "Pktc: gate 0x%x open\n", gate->gateid);
   if (!sub->sdpsent) transmit_modify_with_sdp(sub, NULL, 0);
   ast_mutex_unlock(&sub->lock);
   return 1;
}
static int mgcp_postrequest ( struct mgcp_endpoint p,
struct mgcp_subchannel sub,
char *  data,
int  len,
unsigned int  seqno 
) [static]

Definition at line 709 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, 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, mgcp_message::seqno, and sub.

Referenced by find_command(), and send_request().

{
   struct mgcp_message *msg;
   struct mgcp_message *cur;
   struct mgcp_gateway *gw;
   struct timeval now;

   if (!(msg = ast_malloc(sizeof(*msg) + len))) {
      return -1;
   }
   if (!(gw = ((p && p->parent) ? p->parent : NULL))) {
      ast_free(msg);
      return -1;
   }

   msg->owner_sub = sub;
   msg->owner_ep = p;
   msg->seqno = seqno;
   msg->next = NULL;
   msg->len = len;
   msg->retrans = 0;
   memcpy(msg->buf, data, msg->len);

   ast_mutex_lock(&gw->msgs_lock);
   for (cur = gw->msgs; cur && cur->next; cur = cur->next);
   if (cur) {
      cur->next = msg;
   } else {
      gw->msgs = msg;
   }

   now = ast_tvnow();
   msg->expire = now.tv_sec * 1000 + now.tv_usec / 1000 + DEFAULT_RETRANS;

   if (gw->retransid == -1)
      gw->retransid = ast_sched_add(sched, DEFAULT_RETRANS, retrans_pkt, (void *)gw);
   ast_mutex_unlock(&gw->msgs_lock);
   __mgcp_xmit(gw, msg->buf, msg->len);
   /* XXX Should schedule retransmission XXX */
   return 0;
}
static int mgcp_prune_realtime_gateway ( struct mgcp_gateway g) [static]

Definition at line 3734 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, sub, and mgcp_endpoint::sub.

Referenced by do_monitor().

{
   struct mgcp_endpoint *enext, *e;
   struct mgcp_subchannel *s, *sub;
   int i, prune = 1;

   if (g->ha || !g->realtime || ast_mutex_trylock(&g->msgs_lock) || g->msgs) {
      ast_mutex_unlock(&g->msgs_lock);
      return 0;
   }

   for (e = g->endpoints; e; e = e->next) {
      ast_mutex_lock(&e->lock);
      if (e->dsp || ast_mutex_trylock(&e->rqnt_queue_lock) || ast_mutex_trylock(&e->cmd_queue_lock)) {
         prune = 0;
      } else if (e->rqnt_queue || e->cmd_queue) {
         prune = 0;
      }
      s = e->sub;
      for (i = 0; (i < MAX_SUBS) && s; i++) {
         ast_mutex_lock(&s->lock);
         if (!ast_strlen_zero(s->cxident) || s->rtp || ast_mutex_trylock(&s->cx_queue_lock) || s->gate) {
            prune = 0;
         } else if (s->cx_queue) {
            prune = 0;
         }
         s = s->next;
      }
   }

   for (e = g->endpoints, sub = e->sub, enext = e->next; e; e = enext, enext = e->next) {
      for (i = 0; (i < MAX_SUBS) && sub; i++) {
         s = sub;
         sub = sub->next;
         ast_mutex_unlock(&s->lock);
         ast_mutex_unlock(&s->cx_queue_lock);
         if (prune) {
            ast_mutex_destroy(&s->lock);
            ast_mutex_destroy(&s->cx_queue_lock);
            free(s);
         }
      }
      ast_mutex_unlock(&e->lock);
      ast_mutex_unlock(&e->rqnt_queue_lock);
      ast_mutex_unlock(&e->cmd_queue_lock);
      if (prune) {
         ast_mutex_destroy(&e->lock);
         ast_mutex_destroy(&e->rqnt_queue_lock);
         ast_mutex_destroy(&e->cmd_queue_lock);
         free(e);
      }
   }
   if (prune) {
      ast_debug(1, "***** MGCP REALTIME PRUNE GW: %s\n", g->name);
   }
   return prune;
}
static void mgcp_queue_control ( struct mgcp_subchannel sub,
int  control 
) [static]

Definition at line 648 of file chan_mgcp.c.

References AST_FRAME_CONTROL, and mgcp_queue_frame().

Referenced by handle_hd_hf().

{
   struct ast_frame f = { AST_FRAME_CONTROL, { control } };
   return mgcp_queue_frame(sub, &f);
}
static void mgcp_queue_frame ( struct mgcp_subchannel sub,
struct ast_frame f 
) [static]

Definition at line 614 of file chan_mgcp.c.

References ast_channel_trylock, ast_channel_unlock, ast_queue_frame(), DEADLOCK_AVOIDANCE, mgcp_subchannel::lock, and mgcp_subchannel::owner.

Referenced by handle_request(), and mgcp_queue_control().

{
   for (;;) {
      if (sub->owner) {
         if (!ast_channel_trylock(sub->owner)) {
            ast_queue_frame(sub->owner, f);
            ast_channel_unlock(sub->owner);
            break;
         } else {
            DEADLOCK_AVOIDANCE(&sub->lock);
         }
      } else {
         break;
      }
   }
}
static void mgcp_queue_hangup ( struct mgcp_subchannel sub) [static]
static struct ast_frame * mgcp_read ( struct ast_channel ast) [static, read]
static char * mgcp_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 4857 of file chan_mgcp.c.

References ast_cli_args::argc, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_verbose(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, LOG_WARNING, mgcp_reload_lock, restart_monitor(), and ast_cli_entry::usage.

Referenced by reload(), and unload_module().

{
   static int deprecated = 0;

   if (e) {
      switch (cmd) {
      case CLI_INIT:
         e->command = "mgcp reload";
         e->usage =
            "Usage: mgcp reload\n"
            "       'mgcp reload' is deprecated.  Please use 'reload chan_mgcp.so' instead.\n";
         return NULL;
      case CLI_GENERATE:
         return NULL;
      }
   }

   if (!deprecated && a && a->argc > 0) {
      ast_log(LOG_WARNING, "'mgcp reload' is deprecated.  Please use 'reload chan_mgcp.so' instead.\n");
      deprecated = 1;
   }

   ast_mutex_lock(&mgcp_reload_lock);
   if (mgcp_reloading) {
      ast_verbose("Previous mgcp reload not yet done\n");
   } else {
      mgcp_reloading = 1;
   }
   ast_mutex_unlock(&mgcp_reload_lock);
   restart_monitor();
   return CLI_SUCCESS;
}
static struct ast_channel * mgcp_request ( const char *  type,
struct ast_format_cap cap,
const struct ast_channel requestor,
const char *  dest,
int *  cause 
) [static, read]

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

{
   struct mgcp_subchannel *sub;
   struct ast_channel *tmpc = NULL;
   char tmp[256];

   if (!(ast_format_cap_has_joint(cap, global_capability))) {
      ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), cap));
      /*return NULL;*/
   }
   ast_copy_string(tmp, dest, sizeof(tmp));
   if (ast_strlen_zero(tmp)) {
      ast_log(LOG_NOTICE, "MGCP Channels require an endpoint\n");
      return NULL;
   }
   if (!(sub = find_subchannel_and_lock(tmp, 0, NULL))) {
      ast_log(LOG_WARNING, "Unable to find MGCP endpoint '%s'\n", tmp);
      *cause = AST_CAUSE_UNREGISTERED;
      return NULL;
   }

   ast_verb(3, "MGCP mgcp_request(%s)\n", tmp);
   ast_verb(3, "MGCP cw: %d, dnd: %d, so: %d, sno: %d\n",
         sub->parent->callwaiting, sub->parent->dnd, sub->owner ? 1 : 0, sub->next->owner ? 1: 0);
   /* Must be busy */
   if (((sub->parent->callwaiting) && ((sub->owner) && (sub->next->owner))) ||
      ((!sub->parent->callwaiting) && (sub->owner)) ||
       (sub->parent->dnd && (ast_strlen_zero(sub->parent->call_forward)))) {
      if (sub->parent->hookstate == MGCP_ONHOOK) {
         if (has_voicemail(sub->parent)) {
            transmit_notify_request(sub,"L/vmwi(+)");
         } else {
            transmit_notify_request(sub,"L/vmwi(-)");
         }
      }
      *cause = AST_CAUSE_BUSY;
      ast_mutex_unlock(&sub->lock);
      return NULL;
   }
   tmpc = mgcp_new(sub->owner ? sub->next : sub, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL);
   ast_mutex_unlock(&sub->lock);
   if (!tmpc)
      ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
   restart_monitor();
   return tmpc;
}
static struct ast_frame* mgcp_rtp_read ( struct mgcp_subchannel sub) [static, read]

Definition at line 1201 of file chan_mgcp.c.

References ast_channel_nativeformats(), ast_channel_readformat(), ast_channel_writeformat(), 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, mgcp_subchannel::owner, mgcp_subchannel::parent, mgcp_subchannel::rtp, and ast_frame::subclass.

Referenced by mgcp_read().

{
   /* Retrieve audio/etc from channel.  Assumes sub->lock is already held. */
   struct ast_frame *f;

   f = ast_rtp_instance_read(sub->rtp, 0);
   /* Don't send RFC2833 if we're not supposed to */
   if (f && (f->frametype == AST_FRAME_DTMF) && !(sub->parent->dtmfmode & MGCP_DTMF_RFC2833))
      return &ast_null_frame;
   if (sub->owner) {
      /* We already hold the channel lock */
      if (f->frametype == AST_FRAME_VOICE) {
         if (!ast_format_cap_iscompatible(ast_channel_nativeformats(sub->owner), &f->subclass.format)) {
            ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(&f->subclass.format));
            ast_format_cap_set(ast_channel_nativeformats(sub->owner), &f->subclass.format);
            ast_set_read_format(sub->owner, ast_channel_readformat(sub->owner));
            ast_set_write_format(sub->owner, ast_channel_writeformat(sub->owner));
         }
         /* Courtesy fearnor aka alex@pilosoft.com */
         if ((sub->parent->dtmfmode & MGCP_DTMF_INBAND) && (sub->parent->dsp)) {
#if 0
            ast_log(LOG_NOTICE, "MGCP ast_dsp_process\n");
#endif
            f = ast_dsp_process(sub->owner, sub->parent->dsp, f);
         }
      }
   }
   return f;
}
static int mgcp_senddigit_begin ( struct ast_channel ast,
char  digit 
) [static]

Definition at line 1299 of file chan_mgcp.c.

References ast_channel_tech_pvt(), 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, and sub.

{
   struct mgcp_subchannel *sub = ast_channel_tech_pvt(ast);
   struct mgcp_endpoint *p = sub->parent;
   int res = 0;

   ast_mutex_lock(&sub->lock);
   if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
      ast_debug(1, "Sending DTMF using inband/hybrid\n");
      res = -1; /* Let asterisk play inband indications */
   } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
      ast_debug(1, "Sending DTMF using RFC2833\n");
      ast_rtp_instance_dtmf_begin(sub->rtp, digit);
   } else {
      ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
   }
   ast_mutex_unlock(&sub->lock);

   return res;
}
static int mgcp_senddigit_end ( struct ast_channel ast,
char  digit,
unsigned int  duration 
) [static]

Definition at line 1320 of file chan_mgcp.c.

References ast_channel_tech_pvt(), 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, and transmit_notify_request().

{
   struct mgcp_subchannel *sub = ast_channel_tech_pvt(ast);
   struct mgcp_endpoint *p = sub->parent;
   int res = 0;
   char tmp[4];

   ast_mutex_lock(&sub->lock);
   if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
      ast_debug(1, "Stopping DTMF using inband/hybrid\n");
      res = -1; /* Tell Asterisk to stop inband indications */
   } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
      ast_debug(1, "Stopping DTMF using RFC2833\n");
      if (sub->parent->ncs) {
         tmp[0] = digit;
         tmp[1] = '\0';
      } else {
         tmp[0] = 'D';
         tmp[1] = '/';
         tmp[2] = digit;
         tmp[3] = '\0';
      }
      transmit_notify_request(sub, tmp);
      ast_rtp_instance_dtmf_end(sub->rtp, digit);
   } else {
      ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
   }
   ast_mutex_unlock(&sub->lock);

   return res;
}
static int mgcp_set_rtp_peer ( struct ast_channel chan,
struct ast_rtp_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 4448 of file chan_mgcp.c.

References mgcp_subchannel::alreadygone, ast_channel_tech_pvt(), sub, and transmit_modify_with_sdp().

{
   /* XXX Is there such thing as video support with MGCP? XXX */
   struct mgcp_subchannel *sub;
   sub = ast_channel_tech_pvt(chan);
   if (sub && !sub->alreadygone) {
      transmit_modify_with_sdp(sub, rtp, cap);
      return 0;
   }
   return -1;
}
static void* mgcp_ss ( void *  data) [static]

Definition at line 2979 of file chan_mgcp.c.

References ast_bridged_channel(), ast_canmatch_extension(), ast_channel_caller(), ast_channel_context(), ast_channel_dialed(), ast_channel_exten_set(), ast_channel_language(), ast_channel_name(), ast_channel_tech_pvt(), 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, mgcp_endpoint::callreturn, mgcp_endpoint::callwaiting, mgcp_endpoint::cancallforward, mgcp_endpoint::cid_name, mgcp_endpoint::cid_num, ast_channel::context, ast_channel::data, mgcp_endpoint::dnd, mgcp_endpoint::dtmf_buf, mgcp_endpoint::dtmfmode, exten, ast_channel::exten, firstdigittimeout, gendigittimeout, mgcp_endpoint::hascallwaiting, mgcp_endpoint::hidecallerid, mgcp_endpoint::lastcallerid, len(), LOG_WARNING, matchdigittimeout, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, ast_channel::name, mgcp_endpoint::name, mgcp_gateway::name, mgcp_endpoint::ncs, mgcp_subchannel::next, ast_party_dialed::number, mgcp_subchannel::owner, mgcp_subchannel::parent, mgcp_endpoint::parent, ast_channel::rings, S_COR, start_rtp(), ast_party_dialed::str, sub, and transmit_notify_request().

Referenced by handle_hd_hf().

{
   struct ast_channel *chan = data;
   struct mgcp_subchannel *sub = ast_channel_tech_pvt(chan);
   struct mgcp_endpoint *p = sub->parent;
   /* char exten[AST_MAX_EXTENSION] = ""; */
   int len = 0;
   int timeout = firstdigittimeout;
   int res= 0;
   int getforward = 0;
   int loop_pause = 100;

   len = strlen(p->dtmf_buf);

   while (len < AST_MAX_EXTENSION - 1) {
      ast_debug(1, "Dtmf buffer '%s' for '%s@%s'\n", p->dtmf_buf, p->name, p->parent->name);
      res = 1;  /* Assume that we will get a digit */
      while (strlen(p->dtmf_buf) == len) {
         ast_safe_sleep(chan, loop_pause);
         timeout -= loop_pause;
         if (timeout <= 0){
            res = 0;
            break;
         }
         res = 1;
      }

      timeout = 0;
      len = strlen(p->dtmf_buf);

      if (!ast_ignore_pattern(ast_channel_context(chan), p->dtmf_buf)) {
         /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
         ast_indicate(chan, -1);
      } else {
         /* XXX Redundant?  We should already be playing dialtone */
         /*tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALTONE);*/
         transmit_notify_request(sub, "L/dl");
      }
      if (ast_exists_extension(chan, ast_channel_context(chan), p->dtmf_buf, 1, p->cid_num)) {
         if (!res || !ast_matchmore_extension(chan, ast_channel_context(chan), p->dtmf_buf, 1, p->cid_num)) {
            if (getforward) {
               /* Record this as the forwarding extension */
               ast_copy_string(p->call_forward, p->dtmf_buf, sizeof(p->call_forward));
               ast_verb(3, "Setting call forward to '%s' on channel %s\n",
                     p->call_forward, ast_channel_name(chan));
               /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
               transmit_notify_request(sub, "L/sl");
               if (res)
                  break;
               usleep(500000);
               /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
               ast_indicate(chan, -1);
               sleep(1);
               memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
               /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALTONE);*/
               transmit_notify_request(sub, "L/dl");
               len = 0;
               getforward = 0;
            } else {
               /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
               ast_indicate(chan, -1);
               ast_channel_exten_set(chan, p->dtmf_buf);
               ast_channel_dialed(chan)->number.str = ast_strdup(p->dtmf_buf);
               memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
               ast_set_callerid(chan,
                  p->hidecallerid ? "" : p->cid_num,
                  p->hidecallerid ? "" : p->cid_name,
                  ast_channel_caller(chan)->ani.number.valid ? NULL : p->cid_num);
               ast_setstate(chan, AST_STATE_RING);
               /*dahdi_enable_ec(p);*/
               if (p->dtmfmode & MGCP_DTMF_HYBRID) {
                  p->dtmfmode |= MGCP_DTMF_INBAND;
                  ast_indicate(chan, -1);
               }
               res = ast_pbx_run(chan);
               if (res) {
                  ast_log(LOG_WARNING, "PBX exited non-zero\n");
                  /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
                  /*transmit_notify_request(p, "nbz", 1);*/
                  transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
               }
               return NULL;
            }
         } else {
            /* It's a match, but they just typed a digit, and there is an ambiguous match,
               so just set the timeout to matchdigittimeout and wait some more */
            timeout = matchdigittimeout;
         }
      } else if (res == 0) {
         ast_debug(1, "not enough digits (and no ambiguous match)...\n");
         /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
         transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
         /*dahdi_wait_event(p->subs[index].zfd);*/
         ast_hangup(chan);
         memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
         return NULL;
      } else if (p->hascallwaiting && p->callwaiting && !strcmp(p->dtmf_buf, "*70")) {
         ast_verb(3, "Disabling call waiting on %s\n", ast_channel_name(chan));
         /* Disable call waiting if enabled */
         p->callwaiting = 0;
         /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
         transmit_notify_request(sub, "L/sl");
         len = 0;
         memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
         timeout = firstdigittimeout;
      } else if (!strcmp(p->dtmf_buf,ast_pickup_ext())) {
         /* Scan all channels and see if any there
          * ringing channqels with that have call groups
          * that equal this channels pickup group
          */
         if (ast_pickup_call(chan)) {
            ast_log(LOG_WARNING, "No call pickup possible...\n");
            /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
            transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
         }
         memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
         ast_hangup(chan);
         return NULL;
      } else if (!p->hidecallerid && !strcmp(p->dtmf_buf, "*67")) {
         ast_verb(3, "Disabling Caller*ID on %s\n", ast_channel_name(chan));
         /* Disable Caller*ID if enabled */
         p->hidecallerid = 1;
         ast_set_callerid(chan, "", "", NULL);
         /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
         transmit_notify_request(sub, "L/sl");
         len = 0;
         memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
         timeout = firstdigittimeout;
      } else if (p->callreturn && !strcmp(p->dtmf_buf, "*69")) {
         res = 0;
         if (!ast_strlen_zero(p->lastcallerid)) {
            res = ast_say_digit_str(chan, p->lastcallerid, "", ast_channel_language(chan));
         }
         if (!res)
            /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
            transmit_notify_request(sub, "L/sl");
         break;
      } else if (!strcmp(p->dtmf_buf, "*78")) {
         /* Do not disturb */
         ast_verb(3, "Enabled DND on channel %s\n", ast_channel_name(chan));
         /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
         transmit_notify_request(sub, "L/sl");
         p->dnd = 1;
         getforward = 0;
         memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
         len = 0;
      } else if (!strcmp(p->dtmf_buf, "*79")) {
         /* Do not disturb */
         ast_verb(3, "Disabled DND on channel %s\n", ast_channel_name(chan));
         /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
         transmit_notify_request(sub, "L/sl");
         p->dnd = 0;
         getforward = 0;
         memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
         len = 0;
      } else if (p->cancallforward && !strcmp(p->dtmf_buf, "*72")) {
         /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
         transmit_notify_request(sub, "L/sl");
         getforward = 1;
         memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
         len = 0;
      } else if (p->cancallforward && !strcmp(p->dtmf_buf, "*73")) {
         ast_verb(3, "Cancelling call forwarding on channel %s\n", ast_channel_name(chan));
         /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
         transmit_notify_request(sub, "L/sl");
         memset(p->call_forward, 0, sizeof(p->call_forward));
         getforward = 0;
         memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
         len = 0;
      } else if (ast_parking_ext_valid(p->dtmf_buf, chan, ast_channel_context(chan)) &&
         sub->next->owner && ast_bridged_channel(sub->next->owner)) {
         /* This is a three way call, the main call being a real channel,
            and we're parking the first call. */
         ast_masq_park_call_exten(ast_bridged_channel(sub->next->owner), chan,
            p->dtmf_buf, ast_channel_context(chan), 0, NULL);
         ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
         break;
      } else if (!ast_strlen_zero(p->lastcallerid) && !strcmp(p->dtmf_buf, "*60")) {
         ast_verb(3, "Blacklisting number %s\n", p->lastcallerid);
         res = ast_db_put("blacklist", p->lastcallerid, "1");
         if (!res) {
            /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
            transmit_notify_request(sub, "L/sl");
            memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
            len = 0;
         }
      } else if (p->hidecallerid && !strcmp(p->dtmf_buf, "*82")) {
         ast_verb(3, "Enabling Caller*ID on %s\n", ast_channel_name(chan));
         /* Enable Caller*ID if enabled */
         p->hidecallerid = 0;
         ast_set_callerid(chan, p->cid_num, p->cid_name, NULL);
         /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
         transmit_notify_request(sub, "L/sl");
         len = 0;
         memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
         timeout = firstdigittimeout;
      } else if (!ast_canmatch_extension(chan, ast_channel_context(chan), p->dtmf_buf, 1,
         S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))
         && ((p->dtmf_buf[0] != '*') || (strlen(p->dtmf_buf) > 2))) {
         ast_debug(1, "Can't match %s from '%s' in context %s\n", p->dtmf_buf,
            S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<Unknown Caller>"),
            ast_channel_context(chan));
         break;
      }
      if (!timeout)
         timeout = gendigittimeout;
      if (len && !ast_ignore_pattern(ast_channel_context(chan), p->dtmf_buf))
         /*tone_zone_play_tone(p->subs[index].zfd, -1);*/
         ast_indicate(chan, -1);
   }
#if 0
   for (;;) {
      res = ast_waitfordigit(chan, to);
      if (!res) {
         ast_debug(1, "Timeout...\n");
         break;
      }
      if (res < 0) {
         ast_debug(1, "Got hangup...\n");
         ast_hangup(chan);
         break;
      }
      exten[pos++] = res;
      if (!ast_ignore_pattern(chan->context, exten))
         ast_indicate(chan, -1);
      if (ast_matchmore_extension(chan, chan->context, exten, 1, chan->callerid)) {
         if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid))
            to = 3000;
         else
            to = 8000;
      } else
         break;
   }
   if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid)) {
      ast_copy_string(chan->exten, exten, sizeof(chan->exten)1);
      if (!p->rtp) {
         start_rtp(p);
      }
      ast_setstate(chan, AST_STATE_RING);
      chan->rings = 1;
      if (ast_pbx_run(chan)) {
         ast_log(LOG_WARNING, "Unable to launch PBX on %s\n", chan->name);
      } else {
         memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
         return NULL;
      }
   }
#endif
   ast_hangup(chan);
   memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
   return NULL;
}
static int mgcp_write ( struct ast_channel ast,
struct ast_frame frame 
) [static]

Definition at line 1242 of file chan_mgcp.c.

References ast_channel_nativeformats(), ast_channel_readformat(), ast_channel_tech_pvt(), ast_channel_writeformat(), 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, mgcp_subchannel::parent, mgcp_subchannel::rtp, mgcp_subchannel::sdpsent, mgcp_endpoint::singlepath, cops_gate::state, sub, mgcp_endpoint::sub, ast_frame::subclass, and transmit_modify_with_sdp().

{
   struct mgcp_subchannel *sub = ast_channel_tech_pvt(ast);
   int res = 0;
   char buf[256];

   if (frame->frametype != AST_FRAME_VOICE) {
      if (frame->frametype == AST_FRAME_IMAGE)
         return 0;
      else {
         ast_log(LOG_WARNING, "Can't send %d type frames with MGCP write\n", frame->frametype);
         return 0;
      }
   } else {
      if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
         ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
            ast_getformatname(&frame->subclass.format),
            ast_getformatname_multiple(buf, sizeof(buf), ast_channel_nativeformats(ast)),
            ast_getformatname(ast_channel_readformat(ast)),
            ast_getformatname(ast_channel_writeformat(ast)));
         /* return -1; */
      }
   }
   if (sub) {
      ast_mutex_lock(&sub->lock);
      if (!sub->sdpsent && sub->gate) {
         if (sub->gate->state == GATE_ALLOCATED) {
            ast_debug(1, "GATE ALLOCATED, sending sdp\n");
            transmit_modify_with_sdp(sub, NULL, 0);
         }
      }
      if ((sub->parent->sub == sub) || !sub->parent->singlepath) {
         if (sub->rtp) {
            res =  ast_rtp_instance_write(sub->rtp, frame);
         }
      }
      ast_mutex_unlock(&sub->lock);
   }
   return res;
}
static int mgcpsock_read ( int *  id,
int  fd,
short  events,
void *  ignore 
) [static]

Definition at line 3643 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_subchannel::parent, mgcp_endpoint::parent, parse(), mgcp_gateway::retransid, mgcp_message::seqno, sub, mgcp_request::verb, and mgcp_request::version.

Referenced by do_monitor().

{
   struct mgcp_request req;
   struct sockaddr_in sin;
   struct mgcp_subchannel *sub;
   int res;
   socklen_t len;
   int result;
   int ident;
   len = sizeof(sin);
   memset(&req, 0, sizeof(req));
   res = recvfrom(mgcpsock, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len);
   if (res < 0) {
      if (errno != ECONNREFUSED)
         ast_log(LOG_WARNING, "Recv error: %s\n", strerror(errno));
      return 1;
   }
   req.data[res] = '\0';
   req.len = res;
   ast_debug(1, "MGCP read: \n%s\nfrom %s:%d\n", req.data, ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
   parse(&req);
   if (req.headers < 1) {
      /* Must have at least one header */
      return 1;
   }
   if (ast_strlen_zero(req.identifier)) {
      ast_log(LOG_NOTICE, "Message from %s missing identifier\n", ast_inet_ntoa(sin.sin_addr));
      return 1;
   }

   if (sscanf(req.verb, "%30d", &result) && sscanf(req.identifier, "%30d", &ident)) {
      if (result < 200) {
         ast_debug(1, "Ignoring provisional response on transaction %d\n", ident);
         return 1;
      }
      /* Try to find who this message is for, if it's important */
      sub = find_subchannel_and_lock(NULL, ident, &sin);
      if (sub) {
         struct mgcp_gateway *gw = sub->parent->parent;
         struct mgcp_message *cur, *prev;

         ast_mutex_unlock(&sub->lock);
         ast_mutex_lock(&gw->msgs_lock);
         for (prev = NULL, cur = gw->msgs; cur; prev = cur, cur = cur->next) {
            if (cur->seqno == ident) {
               ast_debug(1, "Got response back on transaction %d\n", ident);
               if (prev)
                  prev->next = cur->next;
               else
                  gw->msgs = cur->next;
               break;
            }
         }

         /* stop retrans timer if the queue is empty */
         if (!gw->msgs) {
            AST_SCHED_DEL(sched, gw->retransid);
         }

         ast_mutex_unlock(&gw->msgs_lock);
         if (cur) {
            handle_response(cur->owner_ep, cur->owner_sub, result, ident, &req);
            ast_free(cur);
            return 1;
         }

         ast_log(LOG_NOTICE, "Got response back on [%s] for transaction %d we aren't sending?\n",
            gw->name, ident);
      }
   } else {
      if (ast_strlen_zero(req.endpoint) ||
         ast_strlen_zero(req.version) ||
         ast_strlen_zero(req.verb)) {
         ast_log(LOG_NOTICE, "Message must have a verb, an idenitifier, version, and endpoint\n");
         return 1;
      }
      /* Process request, with iflock held */
      sub = find_subchannel_and_lock(req.endpoint, 0, &sin);
      if (sub) {
         /* look first to find a matching response in the queue */
         if (!find_and_retrans(sub, &req))
            /* pass the request off to the currently mastering subchannel */
            handle_request(sub, &req, &sin);
         ast_mutex_unlock(&sub->lock);
      }
   }
   return 1;
}
static void mwi_event_cb ( const struct ast_event event,
void *  userdata 
) [static]

Definition at line 483 of file chan_mgcp.c.

Referenced by build_gateway().

{
   /* This module does not handle MWI in an event-based manner.  However, it
    * subscribes to MWI for each mailbox that is configured so that the core
    * knows that we care about it.  Then, chan_mgcp will get the MWI from the
    * event cache instead of checking the mailbox directly. */
}
static void parse ( struct mgcp_request req) [static]

Definition at line 1860 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(), dahdi_accept_r2_call_exec(), dahdi_send_callrerouting_facility_exec(), dial_exec_full(), dictate_exec(), directory_exec(), dundi_query_read(), dundi_result_read(), dundifunc_read(), enum_query_read(), enum_result_read(), execif_exec(), expand_gosub_args(), extenspy_exec(), find_conf(), func_confbridge_info(), function_agent(), get_comma(), get_in_brackets_const(), get_in_brackets_full(), gosub_exec(), handle_presencechange(), iconv_read(), isAnsweringMachine(), isexten_function_read(), jb_framedata_init(), log_exec(), login_exec(), man_do_variable_value(), mgcpsock_read(), misdn_check_l2l1(), misdn_facility_exec(), misdn_set_opt_exec(), mixmonitor_exec(), msg_send_exec(), originate_exec(), oss_call(), oss_request(), page_exec(), park_call_exec(), parked_call_exec(), parse_cookies(), pbx_builtin_answer(), pbx_builtin_background(), pbx_builtin_waitexten(), pickupchan_exec(), play_moh_exec(), pqm_exec(), presence_read(), privacy_exec(), process_echocancel(), 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_full(), transfer_exec(), upqm_exec(), userevent_exec(), verbose_exec(), vm_execmain(), vm_playmsgexec(), xfer_park_call_helper(), and zapateller_exec().

{
   /* Divide fields by NULL's */
   char *c;
   int f = 0;
   c = req->data;

   /* First header starts immediately */
   req->header[f] = c;
   for (; *c; c++) {
      if (*c == '\n') {
         /* We've got a new header */
         *c = 0;
         ast_debug(3, "Header: %s (%d)\n", req->header[f], (int) strlen(req->header[f]));
         if (ast_strlen_zero(req->header[f])) {
            /* Line by itself means we're now in content */
            c++;
            break;
         }
         if (f >= MGCP_MAX_HEADERS - 1) {
            ast_log(LOG_WARNING, "Too many MGCP headers...\n");
         } else {
            f++;
         }
         req->header[f] = c + 1;
      } else if (*c == '\r') {
         /* Ignore but eliminate \r's */
         *c = 0;
      }
   }
   /* Check for last header */
   if (!ast_strlen_zero(req->header[f])) {
      f++;
   }
   req->headers = f;
   /* Now we process any mime content */
   f = 0;
   req->line[f] = c;
   for (; *c; c++) {
      if (*c == '\n') {
         /* We've got a new line */
         *c = 0;
         ast_debug(3, "Line: %s (%d)\n", req->line[f], (int) strlen(req->line[f]));
         if (f >= MGCP_MAX_LINES - 1) {
            ast_log(LOG_WARNING, "Too many SDP lines...\n");
         } else {
            f++;
         }
         req->line[f] = c + 1;
      } else if (*c == '\r') {
         /* Ignore and eliminate \r's */
         *c = 0;
      }
   }
   /* Check for last line */
   if (!ast_strlen_zero(req->line[f])) {
      f++;
   }
   req->lines = f;
   /* Parse up the initial header */
   c = req->header[0];
   while (*c && *c < 33) c++;
   /* First the verb */
   req->verb = c;
   while (*c && (*c > 32)) c++;
   if (*c) {
      *c = '\0';
      c++;
      while (*c && (*c < 33)) c++;
      req->identifier = c;
      while (*c && (*c > 32)) c++;
      if (*c) {
         *c = '\0';
         c++;
         while (*c && (*c < 33)) c++;
         req->endpoint = c;
         while (*c && (*c > 32)) c++;
         if (*c) {
            *c = '\0';
            c++;
            while (*c && (*c < 33)) c++;
            req->version = c;
            while (*c && (*c > 32)) c++;
            while (*c && (*c < 33)) c++;
            while (*c && (*c > 32)) c++;
            *c = '\0';
         }
      }
   }

   ast_debug(1, "Verb: '%s', Identifier: '%s', Endpoint: '%s', Version: '%s'\n",
         req->verb, req->identifier, req->endpoint, req->version);
   ast_debug(1, "%d headers, %d lines\n", req->headers, req->lines);
   if (*c) {
      ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c);
   }
}
static int process_sdp ( struct mgcp_subchannel sub,
struct mgcp_request req 
) [static]

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

{
   char *m;
   char *c;
   char *a;
   char host[258];
   int len = 0;
   int portno;
   struct ast_format_cap *peercap;
   int peerNonCodecCapability;
   struct sockaddr_in sin;
   struct ast_sockaddr sin_tmp;
   char *codecs;
   struct ast_hostent ahp; struct hostent *hp;
   int codec, codec_count=0;
   int iterator;
   struct mgcp_endpoint *p = sub->parent;
   char tmp1[256], tmp2[256], tmp3[256];

   /* Get codec and RTP info from SDP */
   m = get_sdp(req, "m");
   c = get_sdp(req, "c");
   if (ast_strlen_zero(m) || ast_strlen_zero(c)) {
      ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s', c = '%s')\n", m, c);
      return -1;
   }
   if (sscanf(c, "IN IP4 %256s", host) != 1) {
      ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
      return -1;
   }
   /* XXX This could block for a long time, and block the main thread! XXX */
   hp = ast_gethostbyname(host, &ahp);
   if (!hp) {
      ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c);
      return -1;
   }
   if (sscanf(m, "audio %30d RTP/AVP %n", &portno, &len) != 1 || !len) {
      ast_log(LOG_WARNING, "Malformed media stream descriptor: %s\n", m);
      return -1;
   }
   sin.sin_family = AF_INET;
   memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
   sin.sin_port = htons(portno);
   ast_sockaddr_from_sin(&sin_tmp, &sin);
   ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp);
   ast_debug(3, "Peer RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
   /* Scan through the RTP payload types specified in a "m=" line: */
   ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp);
   codecs = ast_strdupa(m + len);
   while (!ast_strlen_zero(codecs)) {
      if (sscanf(codecs, "%30d%n", &codec, &len) != 1) {
         if (codec_count) {
            break;
         }
         ast_log(LOG_WARNING, "Error in codec string '%s' at '%s'\n", m, codecs);
         return -1;
      }
      ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp, codec);
      codec_count++;
      codecs += len;
   }

   /* Next, scan through each "a=rtpmap:" line, noting each */
   /* specified RTP payload type (with corresponding MIME subtype): */
   sdpLineNum_iterator_init(&iterator);
   while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
      char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
      if (sscanf(a, "rtpmap: %30u %127[^/]/", &codec, mimeSubtype) != 2)
         continue;
      /* Note: should really look at the 'freq' and '#chans' params too */
      ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp, codec, "audio", mimeSubtype, 0);
   }

   /* Now gather all of the codecs that were asked for: */
   if (!(peercap = ast_format_cap_alloc_nolock())) {
      return -1;
   }
   ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(sub->rtp), peercap, &peerNonCodecCapability);
   ast_format_cap_joint_copy(global_capability, peercap, p->cap);
   ast_debug(1, "Capabilities: us - %s, them - %s, combined - %s\n",
      ast_getformatname_multiple(tmp1, sizeof(tmp1), global_capability),
      ast_getformatname_multiple(tmp2, sizeof(tmp2), peercap),
      ast_getformatname_multiple(tmp3, sizeof(tmp3), p->cap));
   peercap = ast_format_cap_destroy(peercap);

   ast_debug(1, "Non-codec capabilities: us - %d, them - %d, combined - %d\n",
      nonCodecCapability, peerNonCodecCapability, p->nonCodecCapability);
   if (ast_format_cap_is_empty(p->cap)) {
      ast_log(LOG_WARNING, "No compatible codecs!\n");
      return -1;
   }
   return 0;
}
static void prune_gateways ( void  ) [static]

Definition at line 4563 of file chan_mgcp.c.

References ast_mutex_lock, ast_mutex_unlock, mgcp_endpoint::delme, mgcp_gateway::delme, destroy_endpoint(), destroy_gateway(), mgcp_gateway::endpoints, gatelock, gateways, mgcp_endpoint::next, mgcp_gateway::next, and mgcp_gateway::realtime.

Referenced by reload_config(), and unload_module().

{
   struct mgcp_gateway *g, *z, *r;
   struct mgcp_endpoint *e, *p, *t;

   ast_mutex_lock(&gatelock);

   /* prune gateways */
   for (z = NULL, g = gateways; g;) {
      /* prune endpoints */
      for (p = NULL, e = g->endpoints; e; ) {
         if (!g->realtime && (e->delme || g->delme)) {
            t = e;
            e = e->next;
            if (!p)
               g->endpoints = e;
            else
               p->next = e;
            destroy_endpoint(t);
         } else {
            p = e;
            e = e->next;
         }
      }

      if (g->delme) {
         r = g;
         g = g->next;
         if (!z)
            gateways = g;
         else
            z->next = g;

         destroy_gateway(r);
      } else {
         z = g;
         g = g->next;
      }
   }

   ast_mutex_unlock(&gatelock);
}
static int reload ( void  ) [static]

Definition at line 4890 of file chan_mgcp.c.

References mgcp_reload().

{
   mgcp_reload(NULL, 0, NULL);
   return 0;
}
static int reload_config ( int  reload) [static]

Definition at line 4638 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_sched_runq(), ast_set_qos(), 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, ast_variable::name, mgcp_endpoint::name, mgcp_gateway::name, mgcp_endpoint::needaudit, netlock, ast_variable::next, mgcp_endpoint::next, mgcp_gateway::next, prune_gateways(), qos, transmit_audit_endpoint(), and ast_variable::value.

Referenced by do_monitor(), and load_module().

{
   struct ast_config *cfg;
   struct ast_variable *v;
   struct mgcp_gateway *g;
   struct mgcp_endpoint *e;
   char *cat;
   struct ast_hostent ahp;
   struct hostent *hp;
   struct ast_format format;
   struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
   
   if (gethostname(ourhost, sizeof(ourhost)-1)) {
      ast_log(LOG_WARNING, "Unable to get hostname, MGCP disabled\n");
      return 0;
   }
   cfg = ast_config_load(config, config_flags);

   /* We *must* have a config file otherwise stop immediately */
   if (!cfg) {
      ast_log(LOG_NOTICE, "Unable to load config %s, MGCP disabled\n", config);
      return 0;
   } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
      return 0;
   } else if (cfg == CONFIG_STATUS_FILEINVALID) {
      ast_log(LOG_ERROR, "Config file %s is in an invalid format.  Aborting.\n", config);
      return 0;
   }

   memset(&bindaddr, 0, sizeof(bindaddr));
   dtmfmode = 0;

   /* Copy the default jb config over global_jbconf */
   memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));

   for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
      /* handle jb conf */
      if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
         continue;
      }

      /* Create the interface list */
      if (!strcasecmp(v->name, "bindaddr")) {
         if (!(hp = ast_gethostbyname(v->value, &ahp))) {
            ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
         } else {
            memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
         }
      } else if (!strcasecmp(v->name, "allow")) {
         ast_getformatbyname(v->value, &format);
         if (!format.id) {
            ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
         } else {
            ast_format_cap_add(global_capability, &format);
         }
      } else if (!strcasecmp(v->name, "disallow")) {
         ast_getformatbyname(v->value, &format);
         if (!format.id) {
            ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
         } else {
            ast_format_cap_remove(global_capability, &format);
         }
      } else if (!strcasecmp(v->name, "tos")) {
         if (ast_str2tos(v->value, &qos.tos)) {
             ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
         }
      } else if (!strcasecmp(v->name, "tos_audio")) {
         if (ast_str2tos(v->value, &qos.tos_audio))
             ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);
      } else if (!strcasecmp(v->name, "cos")) {
         if (ast_str2cos(v->value, &qos.cos))
             ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno);
      } else if (!strcasecmp(v->name, "cos_audio")) {
         if (ast_str2cos(v->value, &qos.cos_audio))
             ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);
      } else if (!strcasecmp(v->name, "port")) {
         if (sscanf(v->value, "%5d", &ourport) == 1) {
            bindaddr.sin_port = htons(ourport);
         } else {
            ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s\n", v->value, v->lineno, config);
         }
      } else if (!strcasecmp(v->name, "firstdigittimeout")) {
         firstdigittimeout = atoi(v->value);
      } else if (!strcasecmp(v->name, "gendigittimeout")) {
         gendigittimeout = atoi(v->value);
      } else if (!strcasecmp(v->name, "matchdigittimeout")) {
         matchdigittimeout = atoi(v->value);
      }
   }

   /* mark existing entries for deletion */
   ast_mutex_lock(&gatelock);
   for (g = gateways; g; g = g->next) {
      g->delme = 1;
      for (e = g->endpoints; e; e = e->next) {
         e->delme = 1;
      }
   }
   ast_mutex_unlock(&gatelock);

   for (cat = ast_category_browse(cfg, NULL); cat; cat = ast_category_browse(cfg, cat)) {
      if (strcasecmp(cat, "general")) {
         ast_mutex_lock(&gatelock);
         if ((g = build_gateway(cat, ast_variable_browse(cfg, cat)))) {
            ast_verb(3, "Added gateway '%s'\n", g->name);
            g->next = gateways;
            gateways = g;
         }
         ast_mutex_unlock(&gatelock);

         /* FS: process queue and IO */
         if (monitor_thread == pthread_self()) {
            if (sched) ast_sched_runq(sched);
            if (io) ast_io_wait(io, 10);
         }
      }
   }

   /* prune deleted entries etc. */
   prune_gateways();

   if (ntohl(bindaddr.sin_addr.s_addr)) {
      memcpy(&__ourip, &bindaddr.sin_addr, sizeof(__ourip));
   } else {
      hp = ast_gethostbyname(ourhost, &ahp);
      if (!hp) {
         ast_log(LOG_WARNING, "Unable to get our IP address, MGCP disabled\n");
         ast_config_destroy(cfg);
         return 0;
      }
      memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
   }
   if (!ntohs(bindaddr.sin_port))
      bindaddr.sin_port = htons(DEFAULT_MGCP_CA_PORT);
   bindaddr.sin_family = AF_INET;
   ast_mutex_lock(&netlock);
   if (mgcpsock > -1)
      close(mgcpsock);

   if (mgcpsock_read_id != NULL)
      ast_io_remove(io, mgcpsock_read_id);
   mgcpsock_read_id = NULL;

   mgcpsock = socket(AF_INET, SOCK_DGRAM, 0);
   if (mgcpsock < 0) {
      ast_log(LOG_WARNING, "Unable to create MGCP socket: %s\n", strerror(errno));
   } else {
      if (bind(mgcpsock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
         ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
            ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
               strerror(errno));
         close(mgcpsock);
         mgcpsock = -1;
      } else {
         ast_verb(2, "MGCP Listening on %s:%d\n",
               ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
         ast_set_qos(mgcpsock, qos.tos, qos.cos, "MGCP");
      }
   }
   ast_mutex_unlock(&netlock);
   ast_config_destroy(cfg);

   /* send audit only to the new endpoints */
   for (g = gateways; g; g = g->next) {
      for (e = g->endpoints; e && e->needaudit; e = e->next) {
         e->needaudit = 0;
         transmit_audit_endpoint(e);
         ast_verb(3, "MGCP Auditing endpoint %s@%s for hookstate\n", e->name, g->name);
      }
   }

   return 0;
}
static int resend_response ( struct mgcp_subchannel sub,
struct mgcp_response resp 
) [static]

Definition at line 557 of file chan_mgcp.c.

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

Referenced by find_and_retrans().

{
   struct mgcp_endpoint *p = sub->parent;
   int res;
   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));
   res = __mgcp_xmit(p->parent, resp->buf, resp->len);
   if (res > 0)
      res = 0;
   return res;
}
static int respprep ( struct mgcp_request resp,
struct mgcp_endpoint p,
char *  msg,
struct mgcp_request req,
char *  msgrest 
) [static]

Definition at line 2139 of file chan_mgcp.c.

References init_resp().

Referenced by transmit_response().

{
   memset(resp, 0, sizeof(*resp));
   init_resp(resp, msg, req, msgrest);
   return 0;
}
static int restart_monitor ( void  ) [static]

Definition at line 3910 of file chan_mgcp.c.

References ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_pthread_create_background, AST_PTHREADT_NULL, AST_PTHREADT_STOP, do_monitor(), LOG_ERROR, LOG_WARNING, and monlock.

Referenced by load_module(), mgcp_reload(), and mgcp_request().

{
   /* If we're supposed to be stopped -- stay stopped */
   if (monitor_thread == AST_PTHREADT_STOP)
      return 0;
   if (ast_mutex_lock(&monlock)) {
      ast_log(LOG_WARNING, "Unable to lock monitor\n");
      return -1;
   }
   if (monitor_thread == pthread_self()) {
      ast_mutex_unlock(&monlock);
      ast_log(LOG_WARNING, "Cannot kill myself\n");
      return -1;
   }
   if (monitor_thread != AST_PTHREADT_NULL) {
      /* Wake up the thread */
      pthread_kill(monitor_thread, SIGURG);
   } else {
      /* Start a new monitor */
      if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
         ast_mutex_unlock(&monlock);
         ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
         return -1;
      }
   }
   ast_mutex_unlock(&monlock);
   return 0;
}
static int retrans_pkt ( const void *  data) [static]

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

{
   struct mgcp_gateway *gw = (struct mgcp_gateway *)data;
   struct mgcp_message *cur, *exq = NULL, *w, *prev;
   int res = 0;

   /* find out expired msgs */
   ast_mutex_lock(&gw->msgs_lock);

   for (prev = NULL, cur = gw->msgs; cur; prev = cur, cur = cur->next) {
      if (cur->retrans < MAX_RETRANS) {
         cur->retrans++;
         ast_debug(1, "Retransmitting #%d transaction %u on [%s]\n",
            cur->retrans, cur->seqno, gw->name);
         __mgcp_xmit(gw, cur->buf, cur->len);
      } else {
         if (prev)
            prev->next = cur->next;
         else
            gw->msgs = cur->next;

         ast_log(LOG_WARNING, "Maximum retries exceeded for transaction %u on [%s]\n",
            cur->seqno, gw->name);

         w = cur;

         if (exq) {
            w->next = exq;
         } else {
            w->next = NULL;
         }
         exq = w;
      }
   }

   if (!gw->msgs) {
      gw->retransid = -1;
      res = 0;
   } else {
      res = 1;
   }
   ast_mutex_unlock(&gw->msgs_lock);

   while (exq) {
      cur = exq;
      /* time-out transaction */
      handle_response(cur->owner_ep, cur->owner_sub, 406, cur->seqno, NULL);
      exq = exq->next;
      ast_free(cur);
   }

   return res;
}
static void sdpLineNum_iterator_init ( int *  iterator) [static]

Definition at line 1602 of file chan_mgcp.c.

Referenced by process_sdp().

{
   *iterator = 0;
}
static int send_request ( struct mgcp_endpoint p,
struct mgcp_subchannel sub,
struct mgcp_request req,
unsigned int  seqno 
) [static]

Definition at line 753 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_subchannel::parent, mgcp_endpoint::parent, mgcp_endpoint::rqnt_queue, mgcp_endpoint::rqnt_queue_lock, and mgcp_endpoint::slowsequence.

Referenced by transmit_audit_endpoint(), transmit_connect(), transmit_connect_with_sdp(), transmit_connection_del(), transmit_connection_del_w_params(), transmit_modify_request(), transmit_modify_with_sdp(), transmit_notify_request(), and transmit_notify_request_with_callerid().

{
   int res = 0;
   struct mgcp_request **queue, *q, *r, *t;
   ast_mutex_t *l;

   ast_debug(1, "Slow sequence is %d\n", p->slowsequence);
   if (p->slowsequence) {
      queue = &p->cmd_queue;
      l = &p->cmd_queue_lock;
      ast_mutex_lock(l);
   } else {
      switch (req->cmd) {
      case MGCP_CMD_DLCX:
         queue = &sub->cx_queue;
         l = &sub->cx_queue_lock;
         ast_mutex_lock(l);
         q = sub->cx_queue;
         /* delete pending cx cmds */
         /* buggy sb5120 */
         if (!sub->parent->ncs) {
            while (q) {
               r = q->next;
               ast_free(q);
               q = r;
            }
            *queue = NULL;
         }
         break;

      case MGCP_CMD_CRCX:
      case MGCP_CMD_MDCX:
         queue = &sub->cx_queue;
         l = &sub->cx_queue_lock;
         ast_mutex_lock(l);
         break;

      case MGCP_CMD_RQNT:
         queue = &p->rqnt_queue;
         l = &p->rqnt_queue_lock;
         ast_mutex_lock(l);
         break;

      default:
         queue = &p->cmd_queue;
         l = &p->cmd_queue_lock;
         ast_mutex_lock(l);
         break;
      }
   }

   if (!(r = ast_malloc(sizeof(*r)))) {
      ast_log(LOG_WARNING, "Cannot post MGCP request: insufficient memory\n");
      ast_mutex_unlock(l);
      return -1;
   }
   memcpy(r, req, sizeof(*r));

   if (!(*queue)) {
      ast_debug(1, "Posting Request:\n%s to %s:%d\n", req->data,
         ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));

      res = mgcp_postrequest(p, sub, req->data, req->len, seqno);
   } else {
      ast_debug(1, "Queueing Request:\n%s to %s:%d\n", req->data,
         ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
   }

   /* XXX find tail. We could also keep tail in the data struct for faster access */
   for (t = *queue; t && t->next; t = t->next);

   r->next = NULL;
   if (t)
      t->next = r;
   else
      *queue = r;

   ast_mutex_unlock(l);

   return res;
}
static int send_response ( struct mgcp_subchannel sub,
struct mgcp_request req 
) [static]

Definition at line 568 of file chan_mgcp.c.

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

Referenced by transmit_response().

{
   struct mgcp_endpoint *p = sub->parent;
   int res;
   ast_debug(1, "Transmitting:\n%s\n to %s:%d\n", req->data, ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
   res = __mgcp_xmit(p->parent, req->data, req->len);
   if (res > 0)
      res = 0;
   return res;
}
static void start_rtp ( struct mgcp_subchannel sub) [static]

Definition at line 2946 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(), mgcp_answer(), mgcp_call(), and mgcp_ss().

{
   struct ast_sockaddr bindaddr_tmp;

   ast_mutex_lock(&sub->lock);
   /* check again to be on the safe side */
   if (sub->rtp) {
      ast_rtp_instance_destroy(sub->rtp);
      sub->rtp = NULL;
   }
   /* Allocate the RTP now */
   ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
   sub->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL);
   if (sub->rtp && sub->owner)
      ast_channel_set_fd(sub->owner, 0, ast_rtp_instance_fd(sub->rtp, 0));
   if (sub->rtp) {
      ast_rtp_instance_set_qos(sub->rtp, qos.tos_audio, qos.cos_audio, "MGCP RTP");
      ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_NAT, sub->nat);
   }
   /* Make a call*ID */
   snprintf(sub->callid, sizeof(sub->callid), "%08lx%s", ast_random(), sub->txident);
   /* Transmit the connection create */
   if(!sub->parent->pktcgatealloc) {
      transmit_connect_with_sdp(sub, NULL);
   } else {
      transmit_connect(sub);
      sub->gate = NULL;
      if(!mgcp_alloc_pktcgate(sub))
         mgcp_queue_hangup(sub);
   }
   ast_mutex_unlock(&sub->lock);
}
static int transmit_audit_endpoint ( struct mgcp_endpoint p) [static]

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

{
   struct mgcp_request resp;
   unsigned int oseq;
   oseq = reqprep(&resp, p, "AUEP");
   /* removed unknown param VS */
   /*add_header(&resp, "F", "A,R,D,S,X,N,I,T,O,ES,E,MD,M");*/
   add_header(&resp, "F", "A");
   /* fill in new fields */
   resp.cmd = MGCP_CMD_AUEP;
   resp.trid = oseq;
   return send_request(p, NULL, &resp, oseq);
}
static int transmit_connect ( struct mgcp_subchannel sub) [static]

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

Referenced by start_rtp().

{
   struct mgcp_request resp;
   char local[256];
   char tmp[80];
   struct ast_format tmpfmt;
   struct mgcp_endpoint *p = sub->parent;
   unsigned int oseq;

   ast_copy_string(local, "p:20, s:off, e:on", sizeof(local));

   ast_format_cap_iter_start(p->cap);
   while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) {
      if (ast_format_cap_iscompatible(p->cap, &tmpfmt)) {
         snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0));
         strncat(local, tmp, sizeof(local) - strlen(local) - 1);
      }
   }
   ast_format_cap_iter_end(p->cap);

   ast_debug(3, "Creating connection for %s@%s-%d in cxmode: %s callid: %s\n",
          p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
   sub->sdpsent = 0;
   oseq = reqprep(&resp, p, "CRCX");
   add_header(&resp, "C", sub->callid);
   add_header(&resp, "L", local);
   add_header(&resp, "M", "inactive");
   /* X header should not be sent. kept for compatibility */
   add_header(&resp, "X", sub->txident);
   /*add_header(&resp, "S", "");*/
   /* fill in new fields */
   resp.cmd = MGCP_CMD_CRCX;
   resp.trid = oseq;
   return send_request(p, sub, &resp, oseq);
}
static int transmit_connect_with_sdp ( struct mgcp_subchannel sub,
struct ast_rtp_instance rtp 
) [static]

Definition at line 2348 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_endpoint::name, mgcp_gateway::name, mgcp_subchannel::parent, mgcp_endpoint::parent, reqprep(), mgcp_subchannel::sdpsent, send_request(), cops_gate::state, mgcp_request::trid, and mgcp_subchannel::txident.

Referenced by start_rtp().

{
   struct mgcp_request resp;
   char local[256];
   char tmp[80];
   struct ast_format tmpfmt;
   struct mgcp_endpoint *p = sub->parent;
   unsigned int oseq;

   ast_debug(3, "Creating connection for %s@%s-%d in cxmode: %s callid: %s\n",
       p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);

   ast_copy_string(local, "e:on, s:off, p:20", sizeof(local));

   ast_format_cap_iter_start(p->cap);
   while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) {
      if (AST_FORMAT_GET_TYPE(tmpfmt.id) != AST_FORMAT_TYPE_AUDIO) {
         /* Audio is now discontiguous */
         continue;
      }
      if (ast_format_cap_iscompatible(p->cap, &tmpfmt)) {
         snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0));
         strncat(local, tmp, sizeof(local) - strlen(local) - 1);
      }
   }
   ast_format_cap_iter_end(p->cap);

   if (sub->gate) {
      if(sub->gate->state == GATE_ALLOCATED) {
         snprintf(tmp, sizeof(tmp), ", dq-gi:%x", sub->gate->gateid);
         strncat(local, tmp, sizeof(local) - strlen(local) - 1);
      }
   }
   sub->sdpsent = 1;
   oseq = reqprep(&resp, p, "CRCX");
   add_header(&resp, "C", sub->callid);
   add_header(&resp, "L", local);
   add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
   /* X header should not be sent. kept for compatibility */
   add_header(&resp, "X", sub->txident);
   /*add_header(&resp, "S", "");*/
   add_sdp(&resp, sub, rtp);
   /* fill in new fields */
   resp.cmd = MGCP_CMD_CRCX;
   resp.trid = oseq;
   return send_request(p, sub, &resp, oseq);
}
static int transmit_connection_del ( struct mgcp_subchannel sub) [static]

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

Referenced by destroy_endpoint(), handle_request(), handle_response(), mgcp_hangup(), and unalloc_sub().

{
   struct mgcp_endpoint *p = sub->parent;
   struct mgcp_request resp;
   unsigned int oseq;

   ast_debug(3, "Delete connection %s %s@%s-%d with new mode: %s on callid: %s\n",
      sub->cxident, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);
   oseq = reqprep(&resp, p, "DLCX");
   /* check if call id is avail */
   if (sub->callid[0])
      add_header(&resp, "C", sub->callid);
   /* X header should not be sent. kept for compatibility */
   add_header(&resp, "X", sub->txident);
   /* check if cxident is avail */
   if (sub->cxident[0])
      add_header(&resp, "I", sub->cxident);
   /* fill in new fields */
   resp.cmd = MGCP_CMD_DLCX;
   resp.trid = oseq;
   return send_request(p, sub, &resp, oseq);
}
static int transmit_connection_del_w_params ( struct mgcp_endpoint p,
char *  callid,
char *  cxident 
) [static]

Definition at line 2692 of file chan_mgcp.c.

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

Referenced by handle_response().

{
   struct mgcp_request resp;
   unsigned int oseq;

   ast_debug(3, "Delete connection %s %s@%s on callid: %s\n",
      cxident ? cxident : "", p->name, p->parent->name, callid ? callid : "");
   oseq = reqprep(&resp, p, "DLCX");
   /* check if call id is avail */
   if (callid && *callid)
      add_header(&resp, "C", callid);
   /* check if cxident is avail */
   if (cxident && *cxident)
      add_header(&resp, "I", cxident);
   /* fill in new fields */
   resp.cmd = MGCP_CMD_DLCX;
   resp.trid = oseq;
   return send_request(p, p->sub, &resp, oseq);
}
static int transmit_modify_request ( struct mgcp_subchannel sub) [static]

Definition at line 2555 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_endpoint::name, mgcp_gateway::name, mgcp_endpoint::ncs, mgcp_subchannel::parent, mgcp_endpoint::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().

{
   struct mgcp_request resp;
   struct mgcp_endpoint *p = sub->parent;
   struct ast_format tmpfmt;
   int fc = 1;
   char local[256];
   char tmp[80];
   unsigned int oseq;

   if (ast_strlen_zero(sub->cxident)) {
      /* We don't have a CXident yet, store the destination and
         wait a bit */
      return 0;
   }
   ast_debug(3, "Modified %s@%s-%d with new mode: %s on callid: %s\n",
      p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid);

   ast_copy_string(local, "", sizeof(local));
   ast_format_cap_iter_start(p->cap);
   while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) {
      if (p->ncs && !fc) {
         ast_format_cap_set(p->cap, &tmpfmt); /* sb5120e bug */
         break;
      } else {
         fc = 0;
         snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0));
      }
      strncat(local, tmp, sizeof(local) - strlen(local) - 1);
   }
   ast_format_cap_iter_end(p->cap);

   if (!sub->sdpsent) {
      if (sub->gate) {
         if (sub->gate->state == GATE_ALLOCATED || sub->gate->state == GATE_OPEN) {
            snprintf(tmp, sizeof(tmp), ", dq-gi:%x", sub->gate->gateid);
            strncat(local, tmp, sizeof(local) - strlen(local) - 1);
         } else {
               /* we still don't have gateid wait */
            return 0;
         }
      }
   }

   oseq = reqprep(&resp, p, "MDCX");
   add_header(&resp, "C", sub->callid);
   if (!sub->sdpsent) {
      add_header(&resp, "L", local);
   }
   add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
   /* X header should not be sent. kept for compatibility */
   add_header(&resp, "X", sub->txident);
   add_header(&resp, "I", sub->cxident);
   switch (sub->parent->hookstate) {
   case MGCP_ONHOOK:
      add_header(&resp, "R", "L/hd(N)");
      break;
   case MGCP_OFFHOOK:
      add_header_offhook(sub, &resp, "");
      break;
   }
   if (!sub->sdpsent) {
      add_sdp(&resp, sub, NULL);
      sub->sdpsent = 1;
   }
   /* fill in new fields */
   resp.cmd = MGCP_CMD_MDCX;
   resp.trid = oseq;
   return send_request(p, sub, &resp, oseq);
}
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 2288 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().

{
   struct mgcp_request resp;
   char local[256];
   char tmp[80];
   struct mgcp_endpoint *p = sub->parent;
   struct ast_format tmpfmt;
   struct ast_sockaddr sub_tmpdest_tmp;
   unsigned int oseq;

   if (ast_strlen_zero(sub->cxident) && rtp) {
      /* We don't have a CXident yet, store the destination and
         wait a bit */
      ast_rtp_instance_get_remote_address(rtp, &sub_tmpdest_tmp);
      ast_sockaddr_to_sin(&sub_tmpdest_tmp, &sub->tmpdest);
      return 0;
   }
   ast_copy_string(local, "e:on, s:off, p:20", sizeof(local));
   ast_format_cap_iter_start(p->cap);
   while (!(ast_format_cap_iter_next(p->cap, &tmpfmt))) {
      if (AST_FORMAT_GET_TYPE(tmpfmt.id) != AST_FORMAT_TYPE_AUDIO) {
         /* Audio is now discontiguous */
         continue;
      }
      if (ast_format_cap_iscompatible(p->cap, &tmpfmt)) {
         snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype2(1, &tmpfmt, 0, 0));
         strncat(local, tmp, sizeof(local) - strlen(local) - 1);
      }
   }
   ast_format_cap_iter_end(p->cap);

   if (sub->gate) {
      if (sub->gate->state == GATE_ALLOCATED || sub->gate->state == GATE_OPEN) {
         snprintf(tmp, sizeof(tmp), ", dq-gi:%x", sub->gate->gateid);
         strncat(local, tmp, sizeof(local) - strlen(local) - 1);
         sub->sdpsent = 1;
      } else {
         /* oops wait */
         ast_debug(1, "Waiting for opened gate...\n");
         sub->sdpsent = 0;
         return 0;
      }
   }


   oseq = reqprep(&resp, p, "MDCX");
   add_header(&resp, "C", sub->callid);
   add_header(&resp, "L", local);
   add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]);
   /* X header should not be sent. kept for compatibility */
   add_header(&resp, "X", sub->txident);
   add_header(&resp, "I", sub->cxident);
   /*add_header(&resp, "S", "");*/
   add_sdp(&resp, sub, rtp);
   /* fill in new fields */
   resp.cmd = MGCP_CMD_MDCX;
   resp.trid = oseq;
   return send_request(p, sub, &resp, oseq);
}
static int transmit_notify_request ( struct mgcp_subchannel sub,
char *  tone 
) [static]

Definition at line 2482 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_endpoint::name, mgcp_gateway::name, mgcp_subchannel::parent, mgcp_endpoint::parent, reqprep(), mgcp_endpoint::rqnt_ident, send_request(), and mgcp_request::trid.

Referenced by do_monitor(), handle_hd_hf(), handle_request(), handle_response(), mgcp_answer(), mgcp_hangup(), mgcp_indicate(), mgcp_request(), mgcp_senddigit_end(), and mgcp_ss().

{
   struct mgcp_request resp;
   struct mgcp_endpoint *p = sub->parent;
   unsigned int oseq;

   ast_debug(3, "MGCP Asked to indicate tone: %s on  %s@%s-%d in cxmode: %s\n",
      tone, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]);
   ast_copy_string(p->curtone, tone, sizeof(p->curtone));
   oseq = reqprep(&resp, p, "RQNT");
   add_header(&resp, "X", p->rqnt_ident);
   switch (p->hookstate) {
   case MGCP_ONHOOK:
      add_header(&resp, "R", "L/hd(N)");
      break;
   case MGCP_OFFHOOK:
      add_header_offhook(sub, &resp, tone);
      break;
   }
   if (!ast_strlen_zero(tone)) {
      add_header(&resp, "S", tone);
   }
   /* fill in new fields */
   resp.cmd = MGCP_CMD_RQNT;
   resp.trid = oseq;
   return send_request(p, NULL, &resp, oseq);
}
static int transmit_notify_request_with_callerid ( struct mgcp_subchannel sub,
char *  tone,
char *  callernum,
char *  callername 
) [static]

Definition at line 2510 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_endpoint::name, mgcp_gateway::name, mgcp_subchannel::parent, mgcp_endpoint::parent, reqprep(), mgcp_endpoint::rqnt_ident, send_request(), ast_tm::tm_hour, ast_tm::tm_mday, ast_tm::tm_min, ast_tm::tm_mon, and mgcp_request::trid.

Referenced by mgcp_call(), and mgcp_hangup().

{
   struct mgcp_request resp;
   char tone2[256];
   char *l, *n;
   struct timeval t = ast_tvnow();
   struct ast_tm tm;
   struct mgcp_endpoint *p = sub->parent;
   unsigned int oseq;

   ast_localtime(&t, &tm, NULL);
   n = callername;
   l = callernum;
   if (!n)
      n = "";
   if (!l)
      l = "";

   /* Keep track of last callerid for blacklist and callreturn */
   ast_copy_string(p->lastcallerid, l, sizeof(p->lastcallerid));

   snprintf(tone2, sizeof(tone2), "%s,L/ci(%02d/%02d/%02d/%02d,%s,%s)", tone,
      tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, l, n);
   ast_copy_string(p->curtone, tone, sizeof(p->curtone));
   oseq = reqprep(&resp, p, "RQNT");
   add_header(&resp, "X", p->rqnt_ident);
   switch (p->hookstate) {
   case MGCP_ONHOOK:
      add_header(&resp, "R", "L/hd(N)");
      break;
   case MGCP_OFFHOOK:
      add_header_offhook(sub, &resp, tone);
      break;
   }
   if (!ast_strlen_zero(tone2)) {
      add_header(&resp, "S", tone2);
   }
   ast_debug(3, "MGCP Asked to indicate tone: %s on  %s@%s-%d in cxmode: %s\n",
      tone2, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]);
   /* fill in new fields */
   resp.cmd = MGCP_CMD_RQNT;
   resp.trid = oseq;
   return send_request(p, NULL, &resp, oseq);
}
static int transmit_response ( struct mgcp_subchannel sub,
char *  msg,
struct mgcp_request req,
char *  msgrest 
) [static]

Definition at line 2161 of file chan_mgcp.c.

References ast_calloc, mgcp_response::buf, mgcp_request::data, mgcp_request::identifier, mgcp_request::len, mgcp_response::len, mgcp_response::next, mgcp_subchannel::parent, mgcp_endpoint::parent, mgcp_gateway::responses, respprep(), send_response(), mgcp_response::seqno, and mgcp_response::whensent.

Referenced by handle_request(), and handle_response().

{
   struct mgcp_request resp;
   struct mgcp_endpoint *p = sub->parent;
   struct mgcp_response *mgr;

   if (!sub) {
      return -1;
   }

   respprep(&resp, p, msg, req, msgrest);
   if (!(mgr = ast_calloc(1, sizeof(*mgr) + resp.len + 1))) {
      return send_response(sub, &resp);
   }
   /* Store MGCP response in case we have to retransmit */
   sscanf(req->identifier, "%30d", &mgr->seqno);
   time(&mgr->whensent);
   mgr->len = resp.len;
   memcpy(mgr->buf, resp.data, resp.len);
   mgr->buf[resp.len] = '\0';
   mgr->next = p->parent->responses;
   p->parent->responses = mgr;

   return send_response(sub, &resp);
}
static int unalloc_sub ( struct mgcp_subchannel sub) [static]

Definition at line 516 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_endpoint::name, mgcp_gateway::name, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_subchannel::parent, mgcp_endpoint::parent, mgcp_subchannel::rtp, mgcp_endpoint::sub, mgcp_subchannel::tmpdest, and transmit_connection_del().

Referenced by attempt_transfer().

{
   struct mgcp_endpoint *p = sub->parent;
   if (p->sub == sub) {
      ast_log(LOG_WARNING, "Trying to unalloc the real channel %s@%s?!?\n", p->name, p->parent->name);
      return -1;
   }
   ast_debug(1, "Released sub %d of channel %s@%s\n", sub->id, p->name, p->parent->name);

   sub->owner = NULL;
   if (!ast_strlen_zero(sub->cxident)) {
      transmit_connection_del(sub);
   }
   sub->cxident[0] = '\0';
   sub->callid[0] = '\0';
   sub->cxmode = MGCP_CX_INACTIVE;
   sub->outgoing = 0;
   sub->alreadygone = 0;
   memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
   if (sub->rtp) {
      ast_rtp_instance_destroy(sub->rtp);
      sub->rtp = NULL;
   }
   dump_cmd_queues(NULL, sub);
   return 0;
}
static int unload_module ( void  ) [static]

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

{
   struct mgcp_endpoint *e;
   struct mgcp_gateway *g;

   /* Check to see if we're reloading */
   if (ast_mutex_trylock(&mgcp_reload_lock)) {
      ast_log(LOG_WARNING, "MGCP is currently reloading.  Unable to remove module.\n");
      return -1;
   } else {
      mgcp_reloading = 1;
      ast_mutex_unlock(&mgcp_reload_lock);
   }

   /* First, take us out of the channel loop */
   ast_channel_unregister(&mgcp_tech);

   /* Shut down the monitoring thread */
   if (!ast_mutex_lock(&monlock)) {
      if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP)) {
         pthread_cancel(monitor_thread);
         pthread_kill(monitor_thread, SIGURG);
         pthread_join(monitor_thread, NULL);
      }
      monitor_thread = AST_PTHREADT_STOP;
      ast_mutex_unlock(&monlock);
   } else {
      ast_log(LOG_WARNING, "Unable to lock the monitor\n");
      /* We always want to leave this in a consistent state */
      ast_channel_register(&mgcp_tech);
      mgcp_reloading = 0;
      mgcp_reload(NULL, 0, NULL);
      return -1;
   }

   if (!ast_mutex_lock(&gatelock)) {
      for (g = gateways; g; g = g->next) {
         g->delme = 1;
         for (e = g->endpoints; e; e = e->next) {
            e->delme = 1;
         }
      }

      prune_gateways();
      ast_mutex_unlock(&gatelock);
   } else {
      ast_log(LOG_WARNING, "Unable to lock the gateways list.\n");
      /* We always want to leave this in a consistent state */
      ast_channel_register(&mgcp_tech);
      /* Allow the monitor to restart */
      monitor_thread = AST_PTHREADT_NULL;
      mgcp_reloading = 0;
      mgcp_reload(NULL, 0, NULL);
      return -1;
   }

   close(mgcpsock);
   ast_rtp_glue_unregister(&mgcp_rtp_glue);
   ast_cli_unregister_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
   ast_sched_context_destroy(sched);

   global_capability = ast_format_cap_destroy(global_capability);
   mgcp_tech.capabilities = ast_format_cap_destroy(mgcp_tech.capabilities);

   return 0;
}

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

struct in_addr __ourip [static]

Definition at line 232 of file chan_mgcp.c.

Referenced by build_gateway(), find_subchannel_and_lock(), and reload_config().

char accountcode[AST_MAX_ACCOUNT_CODE] = "" [static]

Definition at line 195 of file chan_mgcp.c.

int adsi = 0 [static]

Definition at line 201 of file chan_mgcp.c.

Referenced by build_gateway().

int amaflags = 0 [static]

Definition at line 199 of file chan_mgcp.c.

Referenced by build_gateway().

Definition at line 4969 of file chan_mgcp.c.

struct sockaddr_in bindaddr [static]

Definition at line 427 of file chan_mgcp.c.

int callreturn = 0 [static]

Definition at line 180 of file chan_mgcp.c.

Referenced by build_gateway().

int callwaiting = 0 [static]

Definition at line 178 of file chan_mgcp.c.

Referenced by build_gateway().

int cancallforward = 0 [static]

Definition at line 189 of file chan_mgcp.c.

Referenced by build_gateway().

struct ast_cli_entry cli_mgcp[] [static]

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

Referenced by build_gateway().

Definition at line 167 of file chan_mgcp.c.

Referenced by build_gateway().

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.

Referenced by build_gateway().

int dtmfmode = 0 [static]

Definition at line 160 of file chan_mgcp.c.

Referenced by build_gateway(), and set_local_capabilities().

int firstdigittimeout = 16000 [static]

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

Definition at line 207 of file chan_mgcp.c.

Referenced by mgcp_ss().

ast_mutex_t gatelock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static]
int gendigittimeout = 8000 [static]

How long to wait for following digits (FXO logic)

Definition at line 210 of file chan_mgcp.c.

Referenced by mgcp_ss().

Definition at line 228 of file chan_mgcp.c.

struct ast_jb_conf global_jbconf [static]

Definition at line 107 of file chan_mgcp.c.

Referenced by mgcp_new(), and reload_config().

int hangupongateremove = 0 [static]

Definition at line 164 of file chan_mgcp.c.

Referenced by build_gateway().

int immediate = 0 [static]

Definition at line 176 of file chan_mgcp.c.

Referenced by build_gateway().

struct io_context* io [static]

Definition at line 238 of file chan_mgcp.c.

char language[MAX_LANGUAGE] = "" [static]

Definition at line 154 of file chan_mgcp.c.

int matchdigittimeout = 3000 [static]

How long to wait for an extra digit, if there is an ambiguous match

Definition at line 213 of file chan_mgcp.c.

Referenced by mgcp_ss().

const char* const mgcp_cxmodes[] [static]

}

Definition at line 132 of file chan_mgcp.c.

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

Definition at line 419 of file chan_mgcp.c.

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

int mgcp_reloading = 0 [static]

Definition at line 420 of file chan_mgcp.c.

Referenced by do_monitor().

struct ast_rtp_glue mgcp_rtp_glue [static]

Definition at line 4467 of file chan_mgcp.c.

struct ast_channel_tech mgcp_tech [static]

Definition at line 464 of file chan_mgcp.c.

int mgcpdebug = 0 [static]

Definition at line 235 of file chan_mgcp.c.

int mgcpsock = -1 [static]

Definition at line 425 of file chan_mgcp.c.

int* mgcpsock_read_id = NULL [static]

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

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

Definition at line 219 of file chan_mgcp.c.

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

char musicclass[MAX_MUSICCLASS] = "" [static]

Definition at line 155 of file chan_mgcp.c.

Referenced by func_channel_write_real(), and load_module().

int nat = 0 [static]

Definition at line 161 of file chan_mgcp.c.

Referenced by ast_udptl_setnat(), and build_gateway().

int ncs = 0 [static]

Definition at line 162 of file chan_mgcp.c.

Referenced by build_gateway().

ast_mutex_t netlock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , 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 217 of file chan_mgcp.c.

Referenced by do_monitor(), and reload_config().

Definition at line 229 of file chan_mgcp.c.

unsigned int oseq_global = 0 [static]

Definition at line 203 of file chan_mgcp.c.

Referenced by reqprep().

ast_mutex_t oseq_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, 1 } [static]

Definition at line 204 of file chan_mgcp.c.

Referenced by reqprep().

char ourhost[MAXHOSTNAMELEN] [static]

Definition at line 231 of file chan_mgcp.c.

Referenced by ast_find_ourip().

int ourport [static]

Definition at line 233 of file chan_mgcp.c.

Referenced by initreqprep(), and transmit_notify_with_mwi().

int pktcgatealloc = 0 [static]

Definition at line 163 of file chan_mgcp.c.

Referenced by build_gateway().

struct { ... } qos [static]

Referenced by reload_config(), and start_rtp().

struct ast_sched_context* sched [static]

Definition at line 237 of file chan_mgcp.c.

int singlepath = 0 [static]

Definition at line 191 of file chan_mgcp.c.

Referenced by build_gateway().

int slowsequence = 0 [static]

Definition at line 182 of file chan_mgcp.c.

Referenced by build_gateway().

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.

Referenced by build_gateway().

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 ast_transfer(), build_gateway(), iax2_send(), leave_voicemail(), send_packet(), and transfer_exec().