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/pickup.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/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/chanvars.h"
#include "asterisk/pktccops.h"
#include "asterisk/stasis.h"
#include "asterisk/bridge.h"
#include "asterisk/features_config.h"
#include "asterisk/parking.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/format_cache.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, struct mgcp_subchannel *sub)
 Complete an attended transfer.
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 the module.
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 struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
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_assigned_ids *assignedids, 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 void mgcp_set_owner (struct mgcp_subchannel *sub, struct ast_channel *chan)
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 (void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
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)
 Start the channel monitor thread.
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, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DRIVER, .nonoptreq = "res_pktccops", }
static struct in_addr __ourip
static char accountcode [AST_MAX_ACCOUNT_CODE] = ""
static int adsi = 0
static int amaflags = 0
static struct ast_module_infoast_module_info = &__mod_info
static struct sockaddr_in bindaddr
static int callreturn = 0
static int callwaiting = 0
static int cancallforward = 0
static char cid_name [AST_MAX_EXTENSION] = ""
static char cid_num [AST_MAX_EXTENSION] = ""
static struct ast_cli_entry cli_mgcp []
static const char config [] = "mgcp.conf"
static char context [AST_MAX_EXTENSION] = "default"
static ast_group_t cur_callergroup = 0
static ast_group_t cur_pickupgroup = 0
static struct ast_jb_conf default_jbconf
static int directmedia = DIRECTMEDIA
static int dtmfmode = 0
static int firstdigittimeout = 16000
static ast_mutex_t gatelock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 }
 gatelock: mutex for gateway/endpoint lists
static struct mgcp_gatewaygateways
static int gendigittimeout = 8000
static struct ast_format_capglobal_capability
static struct ast_jb_conf global_jbconf
static int hangupongateremove = 0
static int immediate = 0
static struct io_contextio
static char language [MAX_LANGUAGE] = ""
static char mailbox [AST_MAX_MAILBOX_UNIQUEID]
static int matchdigittimeout = 3000
static const char *const mgcp_cxmodes []
static ast_mutex_t mgcp_reload_lock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 }
static int mgcp_reloading = 0
static struct ast_rtp_glue mgcp_rtp_glue
static struct ast_channel_tech mgcp_tech
static int mgcpdebug = 0
static int mgcpsock = -1
static int * mgcpsock_read_id = NULL
static pthread_t monitor_thread = AST_PTHREADT_NULL
static ast_mutex_t monlock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 }
static char musicclass [MAX_MUSICCLASS] = ""
static int nat = 0
static int ncs = 0
static ast_mutex_t netlock = { PTHREAD_MUTEX_INITIALIZER , NULL, 1 }
static int nonCodecCapability = AST_RTP_DTMF
static unsigned int oseq_global = 0
static ast_mutex_t oseq_lock = { PTHREAD_MUTEX_INITIALIZER , 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>

Definition in file chan_mgcp.c.


Define Documentation

#define DEFAULT_EXPIRY   120

Definition at line 98 of file chan_mgcp.c.

#define DEFAULT_MGCP_CA_PORT   2727

From RFC 2705

Definition at line 126 of file chan_mgcp.c.

#define DEFAULT_MGCP_GW_PORT   2427

From RFC 2705

Definition at line 125 of file chan_mgcp.c.

Referenced by build_gateway().

#define DEFAULT_RETRANS   1000

How frequently to retransmit

Definition at line 128 of file chan_mgcp.c.

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

#define DIRECTMEDIA   1

Definition at line 100 of file chan_mgcp.c.

Referenced by build_gateway().

#define INADDR_NONE   (in_addr_t)(-1)

Definition at line 103 of file chan_mgcp.c.

Referenced by build_gateway().

#define MAX_EXPIRY   3600

Definition at line 99 of file chan_mgcp.c.

#define MAX_RETRANS   5

Try only 5 times for retransmissions

Definition at line 129 of file chan_mgcp.c.

Referenced by retrans_pkt().

#define MAX_SUBS   2

Definition at line 293 of file chan_mgcp.c.

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

#define MGCP_CX_CONF   3

Definition at line 135 of file chan_mgcp.c.

Referenced by handle_request().

#define MGCP_CX_CONFERENCE   3

Definition at line 136 of file chan_mgcp.c.

#define MGCP_CX_INACTIVE   4

Definition at line 138 of file chan_mgcp.c.

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

#define MGCP_CX_MUTE   4

Definition at line 137 of file chan_mgcp.c.

Referenced by handle_request().

#define MGCP_CX_RECVONLY   1

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

#define MGCP_CX_SENDRECV   2

Definition at line 134 of file chan_mgcp.c.

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

#define MGCP_DTMF_HYBRID   (1 << 2)

#define MGCP_DTMF_INBAND   (1 << 1)

#define MGCP_DTMF_RFC2833   (1 << 0)

#define MGCP_MAX_HEADERS   64

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

Definition at line 252 of file chan_mgcp.c.

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

#define MGCP_MAX_LINES   64

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

#define MGCP_OFFHOOK   2

#define MGCP_ONHOOK   1

#define MGCP_SUBCHANNEL_MAGIC   "!978!"

subchannel magic string. Needed to prove that any subchannel pointer passed by asterisk really points to a valid subchannel memory area. Ugly.. But serves the purpose for the time being.

Definition at line 304 of file chan_mgcp.c.

Referenced by build_gateway(), and mgcp_hangup().

#define MGCPDUMPER

Definition at line 97 of file chan_mgcp.c.

#define RESPONSE_TIMEOUT   30

in seconds

Definition at line 283 of file chan_mgcp.c.

Referenced by find_and_retrans().

#define SUB_ALT   1

Definition at line 296 of file chan_mgcp.c.

#define SUB_REAL   0

Definition at line 295 of file chan_mgcp.c.

#define TYPE_LINE   2

#define TYPE_TRUNK   1

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

00149      {
00150    MGCP_CMD_EPCF,
00151    MGCP_CMD_CRCX,
00152    MGCP_CMD_MDCX,
00153    MGCP_CMD_DLCX,
00154    MGCP_CMD_RQNT,
00155    MGCP_CMD_NTFY,
00156    MGCP_CMD_AUEP,
00157    MGCP_CMD_AUCX,
00158    MGCP_CMD_RSIP
00159 };


Function Documentation

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

Definition at line 1645 of file chan_mgcp.c.

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

Referenced by build_path(), build_route(), copy_all_header(), copy_via_headers(), func_header_read(), get_header(), handle_incoming(), handle_request_invite(), handle_request_subscribe(), handle_response_register(), parse_register_contact(), and sip_get_header().

01646 {
01647    int x;
01648    int len = strlen(name);
01649    char *r;
01650    for (x = *start; x < req->headers; x++) {
01651       if (!strncasecmp(req->header[x], name, len) &&
01652           (req->header[x][len] == ':')) {
01653          r = req->header[x] + len + 1;
01654          while (*r && (*r < 33)) {
01655             r++;
01656          }
01657          *start = x + 1;
01658          return r;
01659       }
01660    }
01661    /* Don't return NULL, so get_header is always a valid pointer */
01662    return def;
01663 }

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

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

static void __reg_module ( void   )  [static]

Definition at line 5022 of file chan_mgcp.c.

static void __unreg_module ( void   )  [static]

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

04519 {
04520    struct mgcp_subchannel *sub = ast_channel_tech_pvt(chan);
04521    int res = 0;
04522 
04523    /* Sanity check */
04524    if (!chan || ast_channel_tech(chan) != &mgcp_tech) {
04525       ast_log(LOG_ERROR, "This function requires a valid MGCP channel\n");
04526       return -1;
04527    }
04528 
04529    if (!strcasecmp(args, "ncs")) {
04530       snprintf(buf, buflen, "%s", sub->parent->ncs ?  "yes":"no");
04531    } else {
04532       res = -1;
04533    }
04534    return res;
04535 }

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

Definition at line 2076 of file chan_mgcp.c.

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

Referenced by __transmit_response(), add_cc_call_info_to_response(), add_date(), add_digit(), add_diversion(), add_expires(), add_header_offhook(), add_max_forwards(), add_required_respheader(), add_route(), add_rpid(), add_sdp(), add_supported(), add_text(), add_vidupdate(), ast_sip_add_global_request_header(), ast_sip_add_global_response_header(), copy_all_header(), copy_header(), copy_via_headers(), finalize_content(), func_write_header(), initreqprep(), reqprep(), respprep(), sipinfo_send(), transmit_audit_endpoint(), transmit_cc_notify(), transmit_connect(), transmit_connect_with_sdp(), transmit_connection_del(), transmit_connection_del_w_params(), transmit_info_with_aoc(), transmit_invite(), transmit_modify_request(), transmit_modify_with_sdp(), transmit_notify_request(), transmit_notify_request_with_callerid(), transmit_notify_with_mwi(), transmit_notify_with_sipfrag(), transmit_register(), transmit_reinvite_with_sdp(), transmit_request(), transmit_request_with_auth(), transmit_response_with_allow(), transmit_response_with_auth(), transmit_response_with_minexpires(), transmit_response_with_minse(), transmit_response_with_retry_after(), transmit_response_with_sip_etag(), transmit_response_with_unsupported(), transmit_state_notify(), and update_connectedline().

02077 {
02078    if (req->len >= sizeof(req->data) - 4) {
02079       ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
02080       return -1;
02081    }
02082    if (req->lines) {
02083       ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n");
02084       return -1;
02085    }
02086    req->header[req->headers] = req->data + req->len;
02087    snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s: %s\r\n", var, value);
02088    req->len += strlen(req->header[req->headers]);
02089    if (req->headers < MGCP_MAX_HEADERS) {
02090       req->headers++;
02091    } else {
02092       ast_log(LOG_WARNING, "Out of header space\n");
02093       return -1;
02094    }
02095    return 0;
02096 }

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

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

02660 {
02661    struct mgcp_endpoint *p = sub->parent;
02662    char tone_indicate_end = 0;
02663 
02664    /* We also should check the tone to indicate, because it have no sense
02665       to request notify D/[0-9#*] (dtmf keys) if we are sending congestion
02666       tone for example G/cg */
02667    if (p && (!strcasecmp(tone, (p->ncs ? "L/ro" : "G/cg")))) {
02668       tone_indicate_end = 1;
02669    }
02670 
02671    if (p && p->sub && p->sub->owner &&
02672          ast_channel_state(p->sub->owner) >= AST_STATE_RINGING &&
02673          (p->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID))) {
02674        add_header(resp, "R", "L/hu(N),L/hf(N)");
02675 
02676    } else if (!tone_indicate_end){
02677        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)"));
02678    } else {
02679       ast_debug(1, "We don't want more digits if we will end the call\n");
02680       add_header(resp, "R", "L/hu(N),L/hf(N)");
02681    }
02682 }

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

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

02099 {
02100    if (req->len >= sizeof(req->data) - 4) {
02101       ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
02102       return -1;
02103    }
02104    if (!req->lines) {
02105       /* Add extra empty return */
02106       ast_copy_string(req->data + req->len, "\r\n", sizeof(req->data) - req->len);
02107       req->len += strlen(req->data + req->len);
02108    }
02109    req->line[req->lines] = req->data + req->len;
02110    snprintf(req->line[req->lines], sizeof(req->data) - req->len, "%s", line);
02111    req->len += strlen(req->line[req->lines]);
02112    if (req->lines < MGCP_MAX_LINES) {
02113       req->lines++;
02114    } else {
02115       ast_log(LOG_WARNING, "Out of line space\n");
02116       return -1;
02117    }
02118    return 0;
02119 }

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

Definition at line 2212 of file chan_mgcp.c.

References a, add_line(), ao2_ref, ast_copy_string(), ast_debug, ast_format_cap_count(), ast_format_cap_get_format(), ast_format_get_name(), ast_format_get_type(), ast_inet_ntoa(), ast_log, AST_MEDIA_TYPE_AUDIO, 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, c, mgcp_endpoint::cap, format, len(), LOG_WARNING, mgcp_endpoint::nonCodecCapability, NULL, mgcp_gateway::ourip, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_subchannel::rtp, and mgcp_subchannel::tmpdest.

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

02213 {
02214    int len;
02215    int codec;
02216    char costr[80];
02217    struct sockaddr_in sin;
02218    struct ast_sockaddr sin_tmp;
02219    char v[256];
02220    char s[256];
02221    char o[256];
02222    char c[256];
02223    char t[256];
02224    char m[256] = "";
02225    char a[1024] = "";
02226    int x;
02227    struct sockaddr_in dest = { 0, };
02228    struct ast_sockaddr dest_tmp;
02229    struct mgcp_endpoint *p = sub->parent;
02230    /* XXX We break with the "recommendation" and send our IP, in order that our
02231           peer doesn't have to ast_gethostbyname() us XXX */
02232    len = 0;
02233    if (!sub->rtp) {
02234       ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n");
02235       return -1;
02236    }
02237    ast_rtp_instance_get_local_address(sub->rtp, &sin_tmp);
02238    ast_sockaddr_to_sin(&sin_tmp, &sin);
02239    if (rtp) {
02240       ast_rtp_instance_get_remote_address(sub->rtp, &dest_tmp);
02241       ast_sockaddr_to_sin(&dest_tmp, &dest);
02242    } else {
02243       if (sub->tmpdest.sin_addr.s_addr) {
02244          dest.sin_addr = sub->tmpdest.sin_addr;
02245          dest.sin_port = sub->tmpdest.sin_port;
02246          /* Reset temporary destination */
02247          memset(&sub->tmpdest, 0, sizeof(sub->tmpdest));
02248       } else {
02249          dest.sin_addr = p->parent->ourip;
02250          dest.sin_port = sin.sin_port;
02251       }
02252    }
02253    ast_debug(1, "We're at %s port %d\n", ast_inet_ntoa(p->parent->ourip), ntohs(sin.sin_port));
02254    ast_copy_string(v, "v=0\r\n", sizeof(v));
02255    snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", (int)getpid(), (int)getpid(), ast_inet_ntoa(dest.sin_addr));
02256    ast_copy_string(s, "s=session\r\n", sizeof(s));
02257    snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr));
02258    ast_copy_string(t, "t=0 0\r\n", sizeof(t));
02259    snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port));
02260 
02261    for (x = 0; x < ast_format_cap_count(p->cap); x++) {
02262       struct ast_format *format = ast_format_cap_get_format(p->cap, x);
02263 
02264       if (ast_format_get_type(format) != AST_MEDIA_TYPE_AUDIO) {
02265          ao2_ref(format, -1);
02266          continue;
02267       }
02268 
02269       ast_debug(1, "Answering with capability %s\n", ast_format_get_name(format));
02270       codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 1, format, 0);
02271       if (codec > -1) {
02272          snprintf(costr, sizeof(costr), " %d", codec);
02273          strncat(m, costr, sizeof(m) - strlen(m) - 1);
02274          snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype2(1, format, 0, 0));
02275          strncat(a, costr, sizeof(a) - strlen(a) - 1);
02276       }
02277 
02278       ao2_ref(format, -1);
02279    }
02280 
02281    for (x = 1LL; x <= AST_RTP_MAX; x <<= 1) {
02282       if (p->nonCodecCapability & x) {
02283          ast_debug(1, "Answering with non-codec capability %d\n", (int) x);
02284          codec = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(sub->rtp), 0, NULL, x);
02285          if (codec > -1) {
02286             snprintf(costr, sizeof(costr), " %d", codec);
02287             strncat(m, costr, sizeof(m) - strlen(m) - 1);
02288             snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype2(0, NULL, x, 0));
02289             strncat(a, costr, sizeof(a) - strlen(a) - 1);
02290             if (x == AST_RTP_DTMF) {
02291                /* Indicate we support DTMF...  Not sure about 16,
02292                   but MSN supports it so dang it, we will too... */
02293                snprintf(costr, sizeof costr, "a=fmtp:%d 0-16\r\n", codec);
02294                strncat(a, costr, sizeof(a) - strlen(a) - 1);
02295             }
02296          }
02297       }
02298    }
02299    strncat(m, "\r\n", sizeof(m) - strlen(m) - 1);
02300    len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a);
02301    snprintf(costr, sizeof(costr), "%d", len);
02302    add_line(resp, v);
02303    add_line(resp, o);
02304    add_line(resp, s);
02305    add_line(resp, c);
02306    add_line(resp, t);
02307    add_line(resp, m);
02308    add_line(resp, a);
02309    return 0;
02310 }

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

Definition at line 4650 of file chan_mgcp.c.

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

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

04651 {
04652    struct ast_variable *tmpvar = NULL;
04653    char *varname = ast_strdupa(buf), *varval = NULL;
04654 
04655    if ((varval = strchr(varname, '='))) {
04656       *varval++ = '\0';
04657       if ((tmpvar = ast_variable_new(varname, varval, ""))) {
04658          tmpvar->next = list;
04659          list = tmpvar;
04660       }
04661    }
04662    return list;
04663 }

static int attempt_transfer ( struct mgcp_endpoint p,
struct mgcp_subchannel sub 
) [static]

Complete an attended transfer.

Parameters:
p The endpoint performing the attended transfer
sub The sub-channel completing the attended transfer
Note:
p->sub is the currently active sub-channel (the channel the phone is using)

p->sub->next is the sub-channel not in use, potentially on hold

Return values:
0 when channel should be hung up
1 when channel should not be hung up

Definition at line 3292 of file chan_mgcp.c.

References mgcp_subchannel::alreadygone, ast_bridge_transfer_attended(), AST_BRIDGE_TRANSFER_SUCCESS, ast_channel_softhangup_internal_flag_add(), AST_CONTROL_RINGING, ast_mutex_lock, ast_mutex_unlock, ast_queue_control(), ast_queue_unhold(), AST_SOFTHANGUP_DEV, AST_STATE_RINGING, mgcp_subchannel::lock, mgcp_queue_hangup(), mgcp_subchannel::next, mgcp_subchannel::owner, mgcp_endpoint::sub, and unalloc_sub().

03293 {
03294    enum ast_transfer_result res;
03295 
03296    /* Ensure that the other channel goes off hold and that it is indicating properly */
03297    ast_queue_unhold(sub->next->owner);
03298    if (ast_channel_state(sub->owner) == AST_STATE_RINGING) {
03299       ast_queue_control(sub->next->owner, AST_CONTROL_RINGING);
03300    }
03301 
03302    ast_mutex_unlock(&p->sub->next->lock);
03303    ast_mutex_unlock(&p->sub->lock);
03304    res = ast_bridge_transfer_attended(sub->owner, sub->next->owner);
03305 
03306    /* Subs are only freed when the endpoint itself is destroyed, so they will continue to exist
03307     * after ast_bridge_transfer_attended returns making this safe without reference counting
03308     */
03309    ast_mutex_lock(&p->sub->lock);
03310    ast_mutex_lock(&p->sub->next->lock);
03311 
03312    if (res != AST_BRIDGE_TRANSFER_SUCCESS) {
03313       /* If transferring fails hang up the other channel if present and us */
03314       if (sub->next->owner) {
03315          ast_channel_softhangup_internal_flag_add(sub->next->owner, AST_SOFTHANGUP_DEV);
03316          mgcp_queue_hangup(sub->next);
03317       }
03318       sub->next->alreadygone = 1;
03319       return 0;
03320    }
03321 
03322    unalloc_sub(sub->next);
03323 
03324    /* If the active sub is NOT the one completing the transfer change it to be, and hang up the other sub */
03325    if (p->sub != sub) {
03326       p->sub = sub;
03327       return 1;
03328    }
03329 
03330    return 0;
03331 }

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

References __ourip, mgcp_endpoint::accountcode, add_var(), mgcp_gateway::addr, mgcp_endpoint::adsi, mgcp_endpoint::amaflags, ast_append_ha(), ast_callerid_split(), ast_calloc, ast_channel_string2amaflag(), ast_copy_string(), ast_format_cap_alloc, ast_format_cap_append_from_cap(), AST_FORMAT_CAP_FLAG_DEFAULT, ast_free, ast_get_group(), ast_get_ip(), ast_log, AST_MEDIA_TYPE_UNKNOWN, ast_mutex_destroy, ast_mutex_init, ast_mwi_topic(), 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, mgcp_endpoint::callreturn, mgcp_endpoint::callwaiting, mgcp_endpoint::cancallforward, mgcp_endpoint::cap, mgcp_endpoint::chanvars, mgcp_endpoint::cid_name, mgcp_endpoint::cid_num, mgcp_endpoint::cmd_queue_lock, mgcp_endpoint::context, copy_vars(), mgcp_subchannel::cx_queue_lock, mgcp_subchannel::cxmode, mgcp_gateway::defaddr, DEFAULT_MGCP_GW_PORT, mgcp_endpoint::delme, mgcp_gateway::delme, mgcp_endpoint::directmedia, DIRECTMEDIA, mgcp_endpoint::dtmfmode, mgcp_gateway::dynamic, e, mgcp_gateway::endpoints, mgcp_gateway::expire, mgcp_subchannel::gate, gateways, mgcp_gateway::ha, mgcp_endpoint::hangupongateremove, mgcp_endpoint::hascallwaiting, mgcp_endpoint::hookstate, mgcp_subchannel::id, mgcp_endpoint::immediate, INADDR_NONE, mgcp_gateway::isnamedottedip, mgcp_endpoint::language, ast_variable::lineno, mgcp_subchannel::lock, mgcp_endpoint::lock, LOG_WARNING, mgcp_subchannel::magic, mgcp_endpoint::mailbox, MAX_SUBS, MGCP_CX_INACTIVE, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, MGCP_DTMF_RFC2833, MGCP_ONHOOK, MGCP_SUBCHANNEL_MAGIC, mgcp_gateway::msgs_lock, mgcp_endpoint::msgstate, mgcp_endpoint::musicclass, mwi_event_cb(), mgcp_endpoint::mwi_event_sub, mgcp_endpoint::name, ast_variable::name, mgcp_gateway::name, mgcp_subchannel::nat, mgcp_endpoint::ncs, mgcp_endpoint::needaudit, mgcp_subchannel::next, mgcp_endpoint::next, ast_variable::next, mgcp_gateway::next, NULL, mgcp_endpoint::onhooktime, mgcp_gateway::ourip, mgcp_subchannel::parent, mgcp_endpoint::parent, mgcp_endpoint::parkinglot, mgcp_endpoint::pickupgroup, mgcp_endpoint::pktcgatealloc, mgcp_gateway::realtime, mgcp_gateway::retransid, mgcp_endpoint::rqnt_ident, mgcp_endpoint::rqnt_queue_lock, mgcp_subchannel::rtp, mgcp_subchannel::sdpsent, mgcp_endpoint::singlepath, mgcp_endpoint::slowsequence, stasis_subscribe_pool(), mgcp_endpoint::sub, sub, mgcp_endpoint::threewaycalling, mgcp_endpoint::transfer, mgcp_subchannel::txident, mgcp_endpoint::type, TYPE_LINE, TYPE_TRUNK, ast_variable::value, and mgcp_gateway::wcardep.

Referenced by find_realtime_gw().

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

static char* control2str ( int  ind  )  [static]

Definition at line 1416 of file chan_mgcp.c.

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

Referenced by mgcp_indicate(), skinny_indicate(), and unistim_indicate().

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

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

duplicate a list of channel variables,

Returns:
the copy.

Definition at line 4668 of file chan_mgcp.c.

References ast_variable_new(), ast_variable::next, NULL, and tmp().

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

04669 {
04670    struct ast_variable *res = NULL, *tmp, *v = NULL;
04671 
04672    for (v = src ; v ; v = v->next) {
04673       if ((tmp = ast_variable_new(v->name, v->value, v->file))) {
04674          tmp->next = res;
04675          res = tmp;
04676       }
04677    }
04678    return res;
04679 }

static void destroy_endpoint ( struct mgcp_endpoint e  )  [static]

Definition at line 4538 of file chan_mgcp.c.

References ao2_ref, ast_dsp_free(), ast_free, ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, ast_rtp_instance_destroy(), ast_strlen_zero, ast_variables_destroy(), mgcp_endpoint::cap, mgcp_endpoint::chanvars, mgcp_endpoint::cmd_queue_lock, mgcp_subchannel::cxident, mgcp_endpoint::dsp, dump_cmd_queues(), dump_queue(), mgcp_subchannel::gate, cops_gate::gate_open, cops_gate::gate_remove, cops_gate::got_dq_gi, mgcp_endpoint::lock, mgcp_subchannel::lock, mgcp_subchannel::magic, MAX_SUBS, mgcp_queue_hangup(), mgcp_endpoint::mwi_event_sub, mgcp_subchannel::next, NULL, mgcp_endpoint::parent, mgcp_endpoint::rqnt_queue_lock, mgcp_subchannel::rtp, stasis_unsubscribe(), mgcp_endpoint::sub, sub, cops_gate::tech_pvt, and transmit_connection_del().

Referenced by prune_gateways().

04539 {
04540    struct mgcp_subchannel *sub = e->sub->next, *s;
04541    int i;
04542 
04543    for (i = 0; i < MAX_SUBS; i++) {
04544       ast_mutex_lock(&sub->lock);
04545       if (!ast_strlen_zero(sub->cxident)) {
04546          transmit_connection_del(sub);
04547       }
04548       if (sub->rtp) {
04549          ast_rtp_instance_destroy(sub->rtp);
04550          sub->rtp = NULL;
04551       }
04552       memset(sub->magic, 0, sizeof(sub->magic));
04553       mgcp_queue_hangup(sub);
04554       dump_cmd_queues(NULL, sub);
04555       if(sub->gate) {
04556          sub->gate->tech_pvt = NULL;
04557          sub->gate->got_dq_gi = NULL;
04558          sub->gate->gate_remove = NULL;
04559          sub->gate->gate_open = NULL;
04560       }
04561       ast_mutex_unlock(&sub->lock);
04562       sub = sub->next;
04563    }
04564 
04565    if (e->dsp) {
04566       ast_dsp_free(e->dsp);
04567    }
04568 
04569    dump_queue(e->parent, e);
04570    dump_cmd_queues(e, NULL);
04571 
04572    sub = e->sub;
04573    for (i = 0; (i < MAX_SUBS) && sub; i++) {
04574       s = sub;
04575       sub = sub->next;
04576       ast_mutex_destroy(&s->lock);
04577       ast_mutex_destroy(&s->cx_queue_lock);
04578       ast_free(s);
04579    }
04580 
04581    if (e->mwi_event_sub) {
04582       e->mwi_event_sub = stasis_unsubscribe(e->mwi_event_sub);
04583    }
04584 
04585    if (e->chanvars) {
04586       ast_variables_destroy(e->chanvars);
04587       e->chanvars = NULL;
04588    }
04589 
04590    ast_mutex_destroy(&e->lock);
04591    ast_mutex_destroy(&e->rqnt_queue_lock);
04592    ast_mutex_destroy(&e->cmd_queue_lock);
04593    ao2_ref(e->cap, -1);
04594    ast_free(e);
04595 }

static void destroy_gateway ( struct mgcp_gateway g  )  [static]

Definition at line 4597 of file chan_mgcp.c.

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

Referenced by fax_gateway_new(), and prune_gateways().

04598 {
04599    if (g->ha)
04600       ast_free_ha(g->ha);
04601 
04602    dump_queue(g, NULL);
04603 
04604    ast_free(g);
04605 }

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

Definition at line 3829 of file chan_mgcp.c.

References ast_free, 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, e, mgcp_gateway::endpoints, gatelock, gateways, has_voicemail(), MGCP_ONHOOK, mgcp_prune_realtime_gateway(), mgcp_reload_lock, mgcpsock_read(), monlock, mgcp_gateway::msgs_lock, netlock, mgcp_gateway::next, NULL, mgcp_gateway::realtime, reload_config(), transmit_notify_request(), and TYPE_LINE.

03830 {
03831    int res;
03832    int reloading;
03833    struct mgcp_gateway *g, *gprev;
03834    /*struct mgcp_gateway *g;*/
03835    /*struct mgcp_endpoint *e;*/
03836    /*time_t thispass = 0, lastpass = 0;*/
03837    time_t lastrun = 0;
03838 
03839    /* Add an I/O event to our UDP socket */
03840    if (mgcpsock > -1) {
03841       mgcpsock_read_id = ast_io_add(io, mgcpsock, mgcpsock_read, AST_IO_IN, NULL);
03842    }
03843    /* This thread monitors all the frame relay interfaces which are not yet in use
03844       (and thus do not have a separate thread) indefinitely */
03845    /* From here on out, we die whenever asked */
03846    for (;;) {
03847       /* Check for a reload request */
03848       ast_mutex_lock(&mgcp_reload_lock);
03849       reloading = mgcp_reloading;
03850       mgcp_reloading = 0;
03851       ast_mutex_unlock(&mgcp_reload_lock);
03852       if (reloading) {
03853          ast_verb(1, "Reloading MGCP\n");
03854          reload_config(1);
03855          /* Add an I/O event to our UDP socket */
03856          if (mgcpsock > -1 && !mgcpsock_read_id) {
03857             mgcpsock_read_id = ast_io_add(io, mgcpsock, mgcpsock_read, AST_IO_IN, NULL);
03858          }
03859       }
03860 
03861       /* Check for interfaces needing to be killed */
03862       /* Don't let anybody kill us right away.  Nobody should lock the interface list
03863          and wait for the monitor list, but the other way around is okay. */
03864       ast_mutex_lock(&monlock);
03865       /* Lock the network interface */
03866       ast_mutex_lock(&netlock);
03867 
03868 #if 0
03869       /* XXX THIS IS COMPLETELY HOSED */
03870       /* The gateway goes into a state of panic */
03871       /* If the vmwi indicator is sent while it is reseting interfaces */
03872       lastpass = thispass;
03873       thispass = time(NULL);
03874       g = gateways;
03875       while(g) {
03876          if (thispass != lastpass) {
03877             e = g->endpoints;
03878             while(e) {
03879                if (e->type == TYPE_LINE) {
03880                   res = has_voicemail(e);
03881                   if ((e->msgstate != res) && (e->hookstate == MGCP_ONHOOK) && (!e->rtp)){
03882                      if (res) {
03883                         transmit_notify_request(e, "L/vmwi(+)");
03884                      } else {
03885                         transmit_notify_request(e, "L/vmwi(-)");
03886                      }
03887                      e->msgstate = res;
03888                      e->onhooktime = thispass;
03889                   }
03890                }
03891                e = e->next;
03892             }
03893          }
03894          g = g->next;
03895       }
03896 #endif
03897       /* pruning unused realtime gateways, running in every 60 seconds*/
03898       if(time(NULL) > (lastrun + 60)) {
03899          ast_mutex_lock(&gatelock);
03900          g = gateways;
03901          gprev = NULL;
03902          while(g) {
03903             if(g->realtime) {
03904                if(mgcp_prune_realtime_gateway(g)) {
03905                   if(gprev) {
03906                      gprev->next = g->next;
03907                   } else {
03908                      gateways = g->next;
03909                   }
03910                   ast_mutex_unlock(&g->msgs_lock);
03911                   ast_mutex_destroy(&g->msgs_lock);
03912                   ast_free(g);
03913                } else {
03914                   ast_mutex_unlock(&g->msgs_lock);
03915                   gprev = g;
03916                }
03917             } else {
03918                gprev = g;
03919             }
03920             g = g->next;
03921          }
03922          ast_mutex_unlock(&gatelock);
03923          lastrun = time(NULL);
03924       }
03925       /* Okay, now that we know what to do, release the network lock */
03926       ast_mutex_unlock(&netlock);
03927       /* And from now on, we're okay to be killed, so release the monitor lock as well */
03928       ast_mutex_unlock(&monlock);
03929       pthread_testcancel();
03930       /* Wait for sched or io */
03931       res = ast_sched_wait(sched);
03932       /* copied from chan_sip.c */
03933       if ((res < 0) || (res > 1000)) {
03934          res = 1000;
03935       }
03936       res = ast_io_wait(io, res);
03937       ast_mutex_lock(&monlock);
03938       if (res >= 0) {
03939          ast_sched_runq(sched);
03940       }
03941       ast_mutex_unlock(&monlock);
03942    }
03943    /* Never reached */
03944    return NULL;
03945 }

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

dump_cmd_queues: (SC:) cleanup pending commands

Definition at line 2745 of file chan_mgcp.c.

References ast_free, ast_mutex_lock, ast_mutex_unlock, mgcp_endpoint::cmd_queue, mgcp_endpoint::cmd_queue_lock, mgcp_subchannel::cx_queue, mgcp_subchannel::cx_queue_lock, mgcp_subchannel::next, mgcp_request::next, NULL, mgcp_endpoint::rqnt_queue, mgcp_endpoint::rqnt_queue_lock, and mgcp_endpoint::sub.

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

02746 {
02747    struct mgcp_request *t, *q;
02748 
02749    if (p) {
02750       ast_mutex_lock(&p->rqnt_queue_lock);
02751       for (q = p->rqnt_queue; q; t = q->next, ast_free(q), q=t);
02752       p->rqnt_queue = NULL;
02753       ast_mutex_unlock(&p->rqnt_queue_lock);
02754 
02755       ast_mutex_lock(&p->cmd_queue_lock);
02756       for (q = p->cmd_queue; q; t = q->next, ast_free(q), q=t);
02757       p->cmd_queue = NULL;
02758       ast_mutex_unlock(&p->cmd_queue_lock);
02759 
02760       ast_mutex_lock(&p->sub->cx_queue_lock);
02761       for (q = p->sub->cx_queue; q; t = q->next, ast_free(q), q=t);
02762       p->sub->cx_queue = NULL;
02763       ast_mutex_unlock(&p->sub->cx_queue_lock);
02764 
02765       ast_mutex_lock(&p->sub->next->cx_queue_lock);
02766       for (q = p->sub->next->cx_queue; q; t = q->next, ast_free(q), q=t);
02767       p->sub->next->cx_queue = NULL;
02768       ast_mutex_unlock(&p->sub->next->cx_queue_lock);
02769    } else if (sub) {
02770       ast_mutex_lock(&sub->cx_queue_lock);
02771       for (q = sub->cx_queue; q; t = q->next, ast_free(q), q=t);
02772       sub->cx_queue = NULL;
02773       ast_mutex_unlock(&sub->cx_queue_lock);
02774    }
02775 }

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, NULL, mgcp_message::owner_ep, and mgcp_message::seqno.

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

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

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

Definition at line 3650 of file chan_mgcp.c.

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

Referenced by mgcpsock_read().

03651 {
03652    int seqno=0;
03653    time_t now;
03654    struct mgcp_response *prev = NULL, *cur, *next, *answer = NULL;
03655    time(&now);
03656    if (sscanf(req->identifier, "%30d", &seqno) != 1) {
03657       seqno = 0;
03658    }
03659    for (cur = sub->parent->parent->responses, next = cur ? cur->next : NULL; cur; cur = next, next = cur ? cur->next : NULL) {
03660       if (now - cur->whensent > RESPONSE_TIMEOUT) {
03661          /* Delete this entry */
03662          if (prev)
03663             prev->next = next;
03664          else
03665             sub->parent->parent->responses = next;
03666          ast_free(cur);
03667       } else {
03668          if (seqno == cur->seqno)
03669             answer = cur;
03670          prev = cur;
03671       }
03672    }
03673    if (answer) {
03674       resend_response(sub, answer);
03675       return 1;
03676    }
03677    return 0;
03678 }

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 2779 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, NULL, and mgcp_endpoint::parent.

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

02781 {
02782    struct mgcp_request *prev, *req;
02783 
02784    ast_mutex_lock(l);
02785    for (prev = NULL, req = *queue; req; prev = req, req = req->next) {
02786       if (req->trid == ident) {
02787          /* remove from queue */
02788          if (!prev)
02789             *queue = req->next;
02790          else
02791             prev->next = req->next;
02792 
02793          /* send next pending command */
02794          if (*queue) {
02795             ast_debug(1, "Posting Queued Request:\n%s to %s:%d\n", (*queue)->data,
02796                ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port));
02797 
02798             mgcp_postrequest(p, sub, (*queue)->data, (*queue)->len, (*queue)->trid);
02799          }
02800          break;
02801       }
02802    }
02803    ast_mutex_unlock(l);
02804    return req;
02805 }

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 1696 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(), e, mgcp_gateway::endpoints, gateways, ast_variable::name, mgcp_endpoint::needaudit, mgcp_endpoint::next, mgcp_gateway::next, ast_variable::next, NULL, mgcp_gateway::realtime, transmit_audit_endpoint(), and ast_variable::value.

Referenced by find_subchannel_and_lock().

01697 {
01698    struct mgcp_gateway *g = NULL;
01699    struct ast_variable *mgcpgwconfig = NULL;
01700    struct ast_variable *gwv, *epname = NULL;
01701    struct mgcp_endpoint *e;
01702    char lines[256];
01703    int i, j;
01704 
01705    ast_debug(1, "*** find Realtime MGCPGW\n");
01706 
01707    if (!(i = ast_check_realtime("mgcpgw")) || !(j = ast_check_realtime("mgcpep"))) {
01708       return NULL;
01709    }
01710 
01711    if (ast_strlen_zero(at)) {
01712       ast_debug(1, "null gw name\n");
01713       return NULL;
01714    }
01715 
01716    if (!(mgcpgwconfig = ast_load_realtime("mgcpgw", "name", at, NULL))) {
01717       return NULL;
01718    }
01719 
01720    /*!
01721     * \note This is a fairly odd way of instantiating lines.  Instead of each
01722     * line created by virtue of being in the database (and loaded via
01723     * ast_load_realtime_multientry), this code forces a specific order with a
01724     * "lines" entry in the "mgcpgw" record.  This has benefits, because as with
01725     * chan_dahdi, values are inherited across definitions.  The downside is
01726     * that it's not as clear what the values will be simply by looking at a
01727     * single row in the database, and it's probable that the sanest configuration
01728     * should have the first column in the "mgcpep" table be "clearvars", with a
01729     * static value of "all", if any variables are set at all.  It may be worth
01730     * making this assumption explicit in the code in the future, and then just
01731     * using ast_load_realtime_multientry for the "mgcpep" records.
01732     */
01733    lines[0] = '\0';
01734    for (gwv = mgcpgwconfig; gwv; gwv = gwv->next) {
01735       if (!strcasecmp(gwv->name, "lines")) {
01736          ast_copy_string(lines, gwv->value, sizeof(lines));
01737          break;
01738       }
01739    }
01740    /* Position gwv at the end of the list */
01741    for (gwv = gwv && gwv->next ? gwv : mgcpgwconfig; gwv->next; gwv = gwv->next);
01742 
01743    if (!ast_strlen_zero(lines)) {
01744       AST_DECLARE_APP_ARGS(args,
01745          AST_APP_ARG(line)[100];
01746       );
01747       AST_STANDARD_APP_ARGS(args, lines);
01748       for (i = 0; i < args.argc; i++) {
01749          gwv->next = ast_load_realtime("mgcpep", "name", at, "line", args.line[i], NULL);
01750 
01751          /* Remove "line" AND position gwv at the end of the list. */
01752          for (epname = NULL; gwv->next; gwv = gwv->next) {
01753             if (!strcasecmp(gwv->next->name, "line")) {
01754                /* Remove it from the list */
01755                epname = gwv->next;
01756                gwv->next = gwv->next->next;
01757             }
01758          }
01759          /* Since "line" instantiates the configuration, we have to move it to the end. */
01760          if (epname) {
01761             gwv->next = epname;
01762             epname->next = NULL;
01763             gwv = gwv->next;
01764          }
01765       }
01766    }
01767    for (gwv = mgcpgwconfig; gwv; gwv = gwv->next) {
01768       ast_debug(1, "MGCP Realtime var: %s => %s\n", gwv->name, gwv->value);
01769    }
01770 
01771    if (mgcpgwconfig) {
01772       g = build_gateway(at, mgcpgwconfig);
01773       ast_variables_destroy(mgcpgwconfig);
01774    }
01775    if (g) {
01776       g->next = gateways;
01777       g->realtime = 1;
01778       gateways = g;
01779       for (e = g->endpoints; e; e = e->next) {
01780          transmit_audit_endpoint(e);
01781          e->needaudit = 0;
01782       }
01783    }
01784    return g;
01785 }

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

Definition at line 1787 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, c, 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, NULL, mgcp_gateway::ourip, mgcp_endpoint::sub, sub, and tmp().

Referenced by mgcp_request(), and mgcpsock_read().

01788 {
01789    struct mgcp_endpoint *p = NULL;
01790    struct mgcp_subchannel *sub = NULL;
01791    struct mgcp_gateway *g;
01792    char tmp[256] = "";
01793    char *at = NULL, *c;
01794    int found = 0;
01795    if (name) {
01796       ast_copy_string(tmp, name, sizeof(tmp));
01797       at = strchr(tmp, '@');
01798       if (!at) {
01799          ast_log(LOG_NOTICE, "Endpoint '%s' has no at sign!\n", name);
01800          return NULL;
01801       }
01802       *at++ = '\0';
01803    }
01804    ast_mutex_lock(&gatelock);
01805    if (at && (at[0] == '[')) {
01806       at++;
01807       c = strrchr(at, ']');
01808       if (c) {
01809          *c = '\0';
01810       }
01811    }
01812    for (g = gateways ? gateways : find_realtime_gw(name, at, sin); g; g = g->next ? g->next : find_realtime_gw(name, at, sin)) {
01813       if ((!name || !strcasecmp(g->name, at)) &&
01814           (sin || g->addr.sin_addr.s_addr || g->defaddr.sin_addr.s_addr)) {
01815          /* Found the gateway.  If it's dynamic, save it's address -- now for the endpoint */
01816          if (sin && g->dynamic && name) {
01817             if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
01818                (g->addr.sin_port != sin->sin_port)) {
01819                memcpy(&g->addr, sin, sizeof(g->addr));
01820                {
01821                   struct ast_sockaddr tmp1, tmp2;
01822                   struct sockaddr_in tmp3 = {0,};
01823 
01824                   tmp3.sin_addr = g->ourip;
01825                   ast_sockaddr_from_sin(&tmp1, &g->addr);
01826                   ast_sockaddr_from_sin(&tmp2, &tmp3);
01827                   if (ast_ouraddrfor(&tmp1, &tmp2)) {
01828                      memcpy(&g->ourip, &__ourip, sizeof(g->ourip));
01829                   }
01830                   ast_sockaddr_to_sin(&tmp2, &tmp3);
01831                   g->ourip = tmp3.sin_addr;
01832                }
01833                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));
01834             }
01835          /* not dynamic, check if the name matches */
01836          } else if (name) {
01837             if (strcasecmp(g->name, at)) {
01838                continue;
01839             }
01840          /* not dynamic, no name, check if the addr matches */
01841          } else if (!name && sin) {
01842             if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) ||
01843                 (g->addr.sin_port != sin->sin_port)) {
01844                continue;
01845             }
01846          } else {
01847             continue;
01848          }
01849          for (p = g->endpoints; p; p = p->next) {
01850             ast_debug(1, "Searching on %s@%s for subchannel\n", p->name, g->name);
01851             if (msgid) {
01852                sub = p->sub;
01853                found = 1;
01854                break;
01855             } else if (name && !strcasecmp(p->name, tmp)) {
01856                ast_debug(1, "Coundn't determine subchannel, assuming current master %s@%s-%d\n",
01857                   p->name, g->name, p->sub->id);
01858                sub = p->sub;
01859                found = 1;
01860                break;
01861             }
01862          }
01863          if (sub && found) {
01864             ast_mutex_lock(&sub->lock);
01865             break;
01866          }
01867       }
01868    }
01869    ast_mutex_unlock(&gatelock);
01870    if (!sub) {
01871       if (name) {
01872          if (g) {
01873             ast_log(LOG_NOTICE, "Endpoint '%s' not found on gateway '%s'\n", tmp, at);
01874          } else {
01875             ast_log(LOG_NOTICE, "Gateway '%s' (and thus its endpoint '%s') does not exist\n", at, tmp);
01876          }
01877       }
01878    }
01879    return sub;
01880 }

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

get_csv: (SC:) get comma separated value

Definition at line 1672 of file chan_mgcp.c.

References NULL.

Referenced by handle_response().

01673 {
01674    char *s;
01675 
01676    *next = NULL, *len = 0;
01677    if (!c) return NULL;
01678 
01679    while (*c && (*c < 33 || *c == ',')) {
01680       c++;
01681    }
01682 
01683    s = c;
01684    while (*c && (*c >= 33 && *c != ',')) {
01685       c++, (*len)++;
01686    }
01687    *next = c;
01688 
01689    if (*len == 0) {
01690       s = NULL, *next = NULL;
01691    }
01692 
01693    return s;
01694 }

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

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

Definition at line 1616 of file chan_mgcp.c.

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

Referenced by process_sdp().

01617 {
01618    int x;
01619    int len = strlen(name);
01620    char *r;
01621 
01622    for (x = 0; x < req->lines; x++) {
01623       r = get_sdp_by_line(req->line[x], name, len);
01624       if (r[0] != '\0') return r;
01625    }
01626    return "";
01627 }

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

Definition at line 1606 of file chan_mgcp.c.

Referenced by get_sdp(), and get_sdp_iterate().

01607 {
01608    if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') {
01609       char *r = line + nameLen + 1;
01610       while (*r && (*r < 33)) ++r;
01611       return r;
01612    }
01613    return "";
01614 }

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

Definition at line 1634 of file chan_mgcp.c.

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

Referenced by process_sdp().

01635 {
01636    int len = strlen(name);
01637    char *r;
01638    while (*iterator < req->lines) {
01639       r = get_sdp_by_line(req->line[(*iterator)++], name, len);
01640       if (r[0] != '\0') return r;
01641    }
01642    return "";
01643 }

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

Definition at line 3333 of file chan_mgcp.c.

References AST_CONTROL_ANSWER, ast_hangup(), ast_log, ast_pthread_create_detached, ast_queue_unhold(), AST_STATE_DOWN, AST_STATE_RING, c, mgcp_subchannel::cxmode, errno, has_voicemail(), mgcp_endpoint::hookstate, mgcp_endpoint::immediate, LOG_WARNING, MGCP_CX_SENDRECV, mgcp_new(), MGCP_OFFHOOK, mgcp_queue_control(), mgcp_ss(), mgcp_gateway::name, mgcp_endpoint::name, mgcp_endpoint::ncs, NULL, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_subchannel::rtp, start_rtp(), transmit_modify_request(), and transmit_notify_request().

Referenced by handle_request().

03334 {
03335    struct mgcp_endpoint *p = sub->parent;
03336    struct ast_channel *c;
03337    pthread_t t;
03338 
03339    /* Off hook / answer */
03340    if (sub->outgoing) {
03341       /* Answered */
03342       if (sub->owner) {
03343          ast_queue_unhold(sub->owner);
03344          sub->cxmode = MGCP_CX_SENDRECV;
03345          if (!sub->rtp) {
03346             start_rtp(sub);
03347          } else {
03348             transmit_modify_request(sub);
03349          }
03350          /*transmit_notify_request(sub, "aw");*/
03351          transmit_notify_request(sub, "");
03352          mgcp_queue_control(sub, AST_CONTROL_ANSWER);
03353       }
03354    } else {
03355       /* Start switch */
03356       /*sub->cxmode = MGCP_CX_SENDRECV;*/
03357       if (!sub->owner) {
03358          if (!sub->rtp) {
03359             start_rtp(sub);
03360          } else {
03361             transmit_modify_request(sub);
03362          }
03363          if (p->immediate) {
03364             /* The channel is immediately up. Start right away */
03365 #ifdef DLINK_BUGGY_FIRMWARE
03366             transmit_notify_request(sub, "rt");
03367 #else
03368             transmit_notify_request(sub, p->ncs ? "L/rt" : "G/rt");
03369 #endif
03370             c = mgcp_new(sub, AST_STATE_RING, NULL, NULL);
03371             if (!c) {
03372                ast_log(LOG_WARNING, "Unable to start PBX on channel %s@%s\n", p->name, p->parent->name);
03373                transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
03374                ast_hangup(c);
03375             }
03376          } else {
03377             if (has_voicemail(p)) {
03378                transmit_notify_request(sub, "L/sl");
03379             } else {
03380                transmit_notify_request(sub, "L/dl");
03381             }
03382             c = mgcp_new(sub, AST_STATE_DOWN, NULL, NULL);
03383             if (c) {
03384                if (ast_pthread_create_detached(&t, NULL, mgcp_ss, c)) {
03385                   ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
03386                   ast_hangup(c);
03387                }
03388             } else {
03389                ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", p->name, p->parent->name);
03390             }
03391          }
03392       } else {
03393          if (p->hookstate == MGCP_OFFHOOK) {
03394             ast_log(LOG_WARNING, "Off hook, but already have owner on %s@%s\n", p->name, p->parent->name);
03395          } else {
03396             ast_log(LOG_WARNING, "On hook, but already have owner on %s@%s\n", p->name, p->parent->name);
03397             ast_log(LOG_WARNING, "If we're onhook why are we here trying to handle a hd or hf?\n");
03398          }
03399          ast_queue_unhold(sub->owner);
03400          sub->cxmode = MGCP_CX_SENDRECV;
03401          if (!sub->rtp) {
03402             start_rtp(sub);
03403          } else {
03404             transmit_modify_request(sub);
03405          }
03406          /*transmit_notify_request(sub, "aw");*/
03407          transmit_notify_request(sub, "");
03408          /*ast_queue_control(sub->owner, AST_CONTROL_ANSWER);*/
03409       }
03410    }
03411 }

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

Definition at line 1070 of file chan_mgcp.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_mutex_lock, ast_mutex_unlock, ast_strdupa, c, 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, NULL, transmit_audit_endpoint(), and ast_cli_entry::usage.

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

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

Definition at line 1131 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, NULL, and ast_cli_entry::usage.

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

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

Definition at line 1028 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, NULL, mgcp_subchannel::owner, mgcp_gateway::realtime, mgcp_endpoint::sub, ast_cli_entry::usage, and ast_variable::value.

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

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

Definition at line 3413 of file chan_mgcp.c.

References mgcp_subchannel::alreadygone, ast_debug, AST_FRAME_DTMF, ast_inet_ntoa(), ast_log, ast_mutex_lock, ast_mutex_unlock, ast_queue_hold(), ast_queue_unhold(), AST_STATE_DOWN, AST_STATE_UP, ast_verb, attempt_transfer(), mgcp_endpoint::callwaiting, mgcp_endpoint::curtone, mgcp_subchannel::cxmode, mgcp_endpoint::dtmf_buf, dump_cmd_queues(), dump_queue(), mgcp_gateway::endpoints, ast_frame::frametype, get_header(), handle_hd_hf(), has_voicemail(), mgcp_endpoint::hascallwaiting, mgcp_endpoint::hidecallerid, mgcp_endpoint::hookstate, mgcp_subchannel::id, ast_frame_subclass::integer, mgcp_subchannel::lock, LOG_NOTICE, LOG_WARNING, MGCP_CX_CONF, MGCP_CX_MUTE, MGCP_CX_RECVONLY, MGCP_CX_SENDRECV, MGCP_OFFHOOK, MGCP_ONHOOK, mgcp_queue_frame(), mgcp_queue_hangup(), mgcp_gateway::name, mgcp_endpoint::name, mgcp_endpoint::ncs, mgcp_subchannel::next, mgcp_endpoint::next, NULL, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_subchannel::rtp, ast_frame::src, mgcp_endpoint::sub, ast_frame::subclass, mgcp_endpoint::threewaycalling, mgcp_endpoint::transfer, transmit_audit_endpoint(), transmit_connection_del(), transmit_modify_request(), transmit_notify_request(), transmit_response(), mgcp_request::verb, and mgcp_gateway::wcardep.

Referenced by mgcpsock_read().

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

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 2808 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, c, 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, NULL, mgcp_subchannel::owner, mgcp_endpoint::parent, process_sdp(), mgcp_endpoint::rqnt_queue, mgcp_endpoint::rqnt_queue_lock, mgcp_subchannel::rtp, mgcp_endpoint::slowsequence, start_rtp(), mgcp_endpoint::sub, mgcp_subchannel::tmpdest, transmit_connection_del(), transmit_connection_del_w_params(), transmit_modify_with_sdp(), transmit_notify_request(), and transmit_response().

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

02810 {
02811    char *c;
02812    struct mgcp_request *req;
02813    struct mgcp_gateway *gw = p->parent;
02814 
02815    if (result < 200) {
02816       /* provisional response */
02817       return;
02818    }
02819 
02820    if (p->slowsequence)
02821       req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident);
02822    else if (sub)
02823       req = find_command(p, sub, &sub->cx_queue, &sub->cx_queue_lock, ident);
02824    else if (!(req = find_command(p, sub, &p->rqnt_queue, &p->rqnt_queue_lock, ident)))
02825       req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident);
02826 
02827    if (!req) {
02828       ast_verb(3, "No command found on [%s] for transaction %u. Ignoring...\n",
02829             gw->name, ident);
02830       return;
02831    }
02832 
02833    if (p && (result >= 400) && (result <= 599)) {
02834       switch (result) {
02835       case 401:
02836          p->hookstate = MGCP_OFFHOOK;
02837          break;
02838       case 402:
02839          p->hookstate = MGCP_ONHOOK;
02840          break;
02841       case 406:
02842          ast_log(LOG_NOTICE, "Transaction %u timed out\n", ident);
02843          break;
02844       case 407:
02845          ast_log(LOG_NOTICE, "Transaction %u aborted\n", ident);
02846          break;
02847       }
02848       if (sub) {
02849          if (!sub->cxident[0] && (req->cmd == MGCP_CMD_CRCX)) {
02850              ast_log(LOG_NOTICE, "DLCX for all connections on %s due to error %d\n", gw->name, result);
02851              transmit_connection_del(sub);
02852          }
02853          if (sub->owner) {
02854             ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
02855                result, p->name, p->parent->name, sub ? sub->id:-1);
02856             mgcp_queue_hangup(sub);
02857          }
02858       } else {
02859          if (p->sub->next->owner) {
02860             ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
02861                result, p->name, p->parent->name, sub ? sub->id:-1);
02862             mgcp_queue_hangup(p->sub);
02863          }
02864 
02865          if (p->sub->owner) {
02866             ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n",
02867                result, p->name, p->parent->name, sub ? sub->id:-1);
02868             mgcp_queue_hangup(p->sub);
02869          }
02870 
02871          dump_cmd_queues(p, NULL);
02872       }
02873    }
02874 
02875    if (resp) {
02876       /* responseAck: */
02877       if (result == 200 && (req->cmd == MGCP_CMD_CRCX || req->cmd == MGCP_CMD_MDCX)) {
02878             if (sub) {
02879                transmit_response(sub, "000", resp, "OK");
02880                if (sub->owner && ast_channel_state(sub->owner) == AST_STATE_RINGING) {
02881                   ast_queue_control(sub->owner, AST_CONTROL_RINGING);
02882                }
02883             }
02884       }
02885       if (req->cmd == MGCP_CMD_CRCX) {
02886          if ((c = get_header(resp, "I"))) {
02887             if (!ast_strlen_zero(c) && sub) {
02888                /* if we are hanging up do not process this conn. */
02889                if (sub->owner) {
02890                   if (!ast_strlen_zero(sub->cxident)) {
02891                      if (strcasecmp(c, sub->cxident)) {
02892                         ast_log(LOG_WARNING, "Subchannel already has a cxident. sub->cxident: %s requested %s\n", sub->cxident, c);
02893                      }
02894                   }
02895                   ast_copy_string(sub->cxident, c, sizeof(sub->cxident));
02896                   if (sub->tmpdest.sin_addr.s_addr) {
02897                      transmit_modify_with_sdp(sub, NULL, 0);
02898                   }
02899                } else {
02900                   /* XXX delete this one
02901                      callid and conn id may already be lost.
02902                      so the following del conn may have a side effect of
02903                      cleaning up the next subchannel */
02904                   transmit_connection_del(sub);
02905                }
02906             }
02907          }
02908       }
02909 
02910       if (req->cmd == MGCP_CMD_AUEP) {
02911          /* check stale connection ids */
02912          if ((c = get_header(resp, "I"))) {
02913             char *v, *n;
02914             int len;
02915             while ((v = get_csv(c, &len, &n))) {
02916                if (len) {
02917                   if (strncasecmp(v, p->sub->cxident, len) &&
02918                       strncasecmp(v, p->sub->next->cxident, len)) {
02919                      /* connection id not found. delete it */
02920                      char cxident[80] = "";
02921 
02922                      if (len > (sizeof(cxident) - 1))
02923                         len = sizeof(cxident) - 1;
02924                      ast_copy_string(cxident, v, len);
02925                      ast_verb(3, "Non existing connection id %s on %s@%s \n",
02926                                cxident, p->name, gw->name);
02927                      transmit_connection_del_w_params(p, NULL, cxident);
02928                   }
02929                }
02930                c = n;
02931             }
02932          }
02933 
02934          /* Try to determine the hookstate returned from an audit endpoint command */
02935          if ((c = get_header(resp, "ES"))) {
02936             if (!ast_strlen_zero(c)) {
02937                if (strstr(c, "hu")) {
02938                   if (p->hookstate != MGCP_ONHOOK) {
02939                      /* XXX cleanup if we think we are offhook XXX */
02940                      if ((p->sub->owner || p->sub->next->owner ) &&
02941                          p->hookstate == MGCP_OFFHOOK)
02942                         mgcp_queue_hangup(sub);
02943                      p->hookstate = MGCP_ONHOOK;
02944 
02945                      /* update the requested events according to the new hookstate */
02946                      transmit_notify_request(p->sub, "");
02947 
02948                      ast_verb(3, "Setting hookstate of %s@%s to ONHOOK\n", p->name, gw->name);
02949                      }
02950                } else if (strstr(c, "hd")) {
02951                   if (p->hookstate != MGCP_OFFHOOK) {
02952                      p->hookstate = MGCP_OFFHOOK;
02953 
02954                      /* update the requested events according to the new hookstate */
02955                      transmit_notify_request(p->sub, "");
02956 
02957                      ast_verb(3, "Setting hookstate of %s@%s to OFFHOOK\n", p->name, gw->name);
02958                      }
02959                   }
02960                }
02961             }
02962          }
02963 
02964       if (resp && resp->lines) {
02965          /* do not process sdp if we are hanging up. this may be a late response */
02966          if (sub && sub->owner) {
02967             if (!sub->rtp)
02968                start_rtp(sub);
02969             if (sub->rtp)
02970                process_sdp(sub, resp);
02971          }
02972       }
02973    }
02974 
02975    ast_free(req);
02976 }

static int has_voicemail ( struct mgcp_endpoint p  )  [static]

Definition at line 500 of file chan_mgcp.c.

References ao2_cleanup, ast_app_has_voicemail(), ast_mwi_state_cache(), ast_mwi_state_type(), mgcp_endpoint::mailbox, ast_mwi_state::new_msgs, NULL, RAII_VAR, stasis_cache_get(), and stasis_message_data().

00501 {
00502    int new_msgs;
00503    RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
00504 
00505    msg = stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(), p->mailbox);
00506    if (msg) {
00507       struct ast_mwi_state *mwi_state = stasis_message_data(msg);
00508       new_msgs = mwi_state->new_msgs;
00509    } else {
00510       new_msgs = ast_app_has_voicemail(p->mailbox, NULL);
00511    }
00512 
00513    return new_msgs;
00514 }

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

Definition at line 2139 of file chan_mgcp.c.

References ast_log, mgcp_request::data, mgcp_request::header, mgcp_request::headers, mgcp_gateway::isnamedottedip, mgcp_request::len, LOG_WARNING, MGCP_MAX_HEADERS, mgcp_gateway::name, mgcp_endpoint::name, mgcp_endpoint::ncs, and mgcp_endpoint::parent.

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

02140 {
02141    /* Initialize a response */
02142    if (req->headers || req->len) {
02143       ast_log(LOG_WARNING, "Request already initialized?!?\n");
02144       return -1;
02145    }
02146    req->header[req->headers] = req->data + req->len;
02147    /* check if we need brackets around the gw name */
02148    if (p->parent->isnamedottedip) {
02149       snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %u %s@[%s] MGCP 1.0%s\r\n", verb, oseq, p->name, p->parent->name, p->ncs ? " NCS 1.0" : "");
02150    } else {
02151 +     snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %u %s@%s MGCP 1.0%s\r\n", verb, oseq, p->name, p->parent->name, p->ncs ? " NCS 1.0" : "");
02152    }
02153    req->len += strlen(req->header[req->headers]);
02154    if (req->headers < MGCP_MAX_HEADERS) {
02155       req->headers++;
02156    } else {
02157       ast_log(LOG_WARNING, "Out of header space\n");
02158    }
02159    return 0;
02160 }

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

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

02122 {
02123    /* Initialize a response */
02124    if (req->headers || req->len) {
02125       ast_log(LOG_WARNING, "Request already initialized?!?\n");
02126       return -1;
02127    }
02128    req->header[req->headers] = req->data + req->len;
02129    snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %s %s\r\n", resp, orig->identifier, resprest);
02130    req->len += strlen(req->header[req->headers]);
02131    if (req->headers < MGCP_MAX_HEADERS) {
02132       req->headers++;
02133    } else {
02134       ast_log(LOG_WARNING, "Out of header space\n");
02135    }
02136    return 0;
02137 }

static int load_module ( void   )  [static]

Load the module.

Module loading including tests for configuration or dependencies. This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails tests return AST_MODULE_LOAD_FAILURE. If the module can not load the configuration file or other non-critical problem return AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.

Definition at line 4855 of file chan_mgcp.c.

References ao2_ref, ast_channel_register(), ast_cli_register_multiple(), ast_format_alaw, ast_format_cap_alloc, ast_format_cap_append, AST_FORMAT_CAP_FLAG_DEFAULT, 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().

04856 {
04857    if (!(global_capability = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
04858       return AST_MODULE_LOAD_FAILURE;
04859    }
04860    if (!(mgcp_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
04861       ao2_ref(global_capability, -1);
04862       return AST_MODULE_LOAD_FAILURE;
04863    }
04864    ast_format_cap_append(global_capability, ast_format_ulaw, 0);
04865    ast_format_cap_append(mgcp_tech.capabilities, ast_format_ulaw, 0);
04866    ast_format_cap_append(mgcp_tech.capabilities, ast_format_alaw, 0);
04867    if (!(sched = ast_sched_context_create())) {
04868       ast_log(LOG_WARNING, "Unable to create schedule context\n");
04869       ao2_ref(global_capability, -1);
04870       ao2_ref(mgcp_tech.capabilities, -1);
04871       return AST_MODULE_LOAD_FAILURE;
04872    }
04873 
04874    if (!(io = io_context_create())) {
04875       ast_log(LOG_WARNING, "Unable to create I/O context\n");
04876       ast_sched_context_destroy(sched);
04877       ao2_ref(global_capability, -1);
04878       ao2_ref(mgcp_tech.capabilities, -1);
04879       return AST_MODULE_LOAD_FAILURE;
04880    }
04881 
04882    if (reload_config(0)) {
04883       ao2_ref(global_capability, -1);
04884       ao2_ref(mgcp_tech.capabilities, -1);
04885       return AST_MODULE_LOAD_DECLINE;
04886    }
04887 
04888    /* Make sure we can register our mgcp channel type */
04889    if (ast_channel_register(&mgcp_tech)) {
04890       ast_log(LOG_ERROR, "Unable to register channel class 'MGCP'\n");
04891       io_context_destroy(io);
04892       ast_sched_context_destroy(sched);
04893       ao2_ref(global_capability, -1);
04894       ao2_ref(mgcp_tech.capabilities, -1);
04895       return AST_MODULE_LOAD_FAILURE;
04896    }
04897 
04898    ast_rtp_glue_register(&mgcp_rtp_glue);
04899    ast_cli_register_multiple(cli_mgcp, sizeof(cli_mgcp) / sizeof(struct ast_cli_entry));
04900 
04901    /* And start the monitor for the first time */
04902    restart_monitor();
04903 
04904    return AST_MODULE_LOAD_SUCCESS;
04905 }

static int mgcp_alloc_pktcgate ( struct mgcp_subchannel sub  )  [static]

Definition at line 2459 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(), NULL, mgcp_endpoint::parent, mgcp_subchannel::parent, and cops_gate::tech_pvt.

Referenced by start_rtp().

02460 {
02461    struct mgcp_endpoint *p = sub->parent;
02462    sub->gate = ast_pktccops_gate_alloc(GATE_SET, NULL, ntohl(p->parent->addr.sin_addr.s_addr),
02463                8, 128000, 232, 0, 0, NULL, &mgcp_pktcgate_remove);
02464 
02465    if (!sub->gate) {
02466       return 0;
02467    }
02468    sub->gate->tech_pvt = sub;
02469    sub->gate->gate_open = &mgcp_pktcgate_open;
02470    return 1;
02471 }

static int mgcp_answer ( struct ast_channel ast  )  [static]

Definition at line 1166 of file chan_mgcp.c.

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

01167 {
01168    int res = 0;
01169    struct mgcp_subchannel *sub = ast_channel_tech_pvt(ast);
01170    struct mgcp_endpoint *p = sub->parent;
01171 
01172    ast_mutex_lock(&sub->lock);
01173    sub->cxmode = MGCP_CX_SENDRECV;
01174    if (!sub->rtp) {
01175       start_rtp(sub);
01176    } else {
01177       transmit_modify_request(sub);
01178    }
01179    ast_verb(3, "MGCP mgcp_answer(%s) on %s@%s-%d\n",
01180          ast_channel_name(ast), p->name, p->parent->name, sub->id);
01181    if (ast_channel_state(ast) != AST_STATE_UP) {
01182       ast_setstate(ast, AST_STATE_UP);
01183       ast_debug(1, "mgcp_answer(%s)\n", ast_channel_name(ast));
01184       transmit_notify_request(sub, "");
01185       transmit_modify_request(sub);
01186    }
01187    ast_mutex_unlock(&sub->lock);
01188    return res;
01189 }

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_copy_string(), ast_debug, ast_log, ast_mutex_lock, ast_mutex_unlock, ast_setstate(), AST_STATE_DOWN, AST_STATE_RESERVED, AST_STATE_RINGING, ast_strlen_zero, mgcp_subchannel::callid, mgcp_subchannel::cxident, mgcp_subchannel::cxmode, mgcp_endpoint::hookstate, mgcp_subchannel::lock, LOG_NOTICE, LOG_WARNING, MGCP_CX_RECVONLY, MGCP_CX_SENDRECV, MGCP_OFFHOOK, MGCP_ONHOOK, name, mgcp_endpoint::ncs, mgcp_subchannel::next, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_subchannel::parent, pbx_builtin_getvar_helper(), mgcp_subchannel::rtp, S_COR, start_rtp(), sub, transmit_modify_request(), transmit_notify_request_with_callerid(), mgcp_endpoint::type, and TYPE_LINE.

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

static int mgcp_devicestate ( const char *  data  )  [static]

mgcp_devicestate: channel callback for device status monitoring

Parameters:
data tech/resource name of MGCP device to query
Callback for device state management in channel subsystem to obtain device status (up/down) of a specific MGCP endpoint

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

Definition at line 1370 of file chan_mgcp.c.

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

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

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

Definition at line 1292 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_set_owner(), mgcp_subchannel::owner, and sub.

01293 {
01294    struct mgcp_subchannel *sub = ast_channel_tech_pvt(newchan);
01295 
01296    ast_mutex_lock(&sub->lock);
01297    ast_log(LOG_NOTICE, "mgcp_fixup(%s, %s)\n", ast_channel_name(oldchan), ast_channel_name(newchan));
01298    if (sub->owner != oldchan) {
01299       ast_mutex_unlock(&sub->lock);
01300       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
01301       return -1;
01302    }
01303    mgcp_set_owner(sub, newchan);
01304    ast_mutex_unlock(&sub->lock);
01305    return 0;
01306 }

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]

Definition at line 4475 of file chan_mgcp.c.

References ao2_ref, ast_channel_tech_pvt(), AST_RTP_GLUE_RESULT_FORBID, AST_RTP_GLUE_RESULT_LOCAL, AST_RTP_GLUE_RESULT_REMOTE, mgcp_endpoint::directmedia, NULL, mgcp_subchannel::parent, mgcp_subchannel::rtp, and sub.

04476 {
04477    struct mgcp_subchannel *sub = NULL;
04478 
04479    if (!(sub = ast_channel_tech_pvt(chan)) || !(sub->rtp))
04480       return AST_RTP_GLUE_RESULT_FORBID;
04481 
04482    *instance = sub->rtp ? ao2_ref(sub->rtp, +1), sub->rtp : NULL;
04483 
04484    if (sub->parent->directmedia)
04485       return AST_RTP_GLUE_RESULT_REMOTE;
04486    else
04487       return AST_RTP_GLUE_RESULT_LOCAL;
04488 }

static int mgcp_hangup ( struct ast_channel ast  )  [static]

Definition at line 912 of file chan_mgcp.c.

References mgcp_subchannel::alreadygone, ast_channel_bridge_peer(), ast_channel_caller(), ast_channel_cleanup, 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_set_owner(), MGCP_SUBCHANNEL_MAGIC, name, mgcp_gateway::name, mgcp_endpoint::name, mgcp_endpoint::ncs, mgcp_subchannel::next, NULL, mgcp_subchannel::outgoing, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_subchannel::parent, mgcp_endpoint::pktcgatealloc, RAII_VAR, mgcp_subchannel::rtp, S_COR, cops_gate::state, mgcp_endpoint::sub, sub, cops_gate::tech_pvt, mgcp_subchannel::tmpdest, transmit_connection_del(), transmit_modify_request(), transmit_notify_request(), and transmit_notify_request_with_callerid().

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

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

Definition at line 1448 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, NULL, mgcp_subchannel::parent, mgcp_subchannel::rtp, mgcp_subchannel::sdpsent, sub, transmit_modify_request(), and transmit_notify_request().

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

static struct ast_channel* mgcp_new ( struct mgcp_subchannel sub,
int  state,
const struct ast_assigned_ids assignedids,
const struct ast_channel requestor 
) [static, read]

Definition at line 1504 of file chan_mgcp.c.

References mgcp_endpoint::accountcode, mgcp_endpoint::adsi, mgcp_endpoint::amaflags, ast_party_caller::ani, ao2_ref, AST_ADSI_UNAVAILABLE, 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_nativeformats_set(), ast_channel_pickupgroup_set(), ast_channel_priority_set(), ast_channel_rings_set(), ast_channel_set_fd(), ast_channel_set_rawreadformat(), ast_channel_set_rawwriteformat(), ast_channel_set_readformat(), ast_channel_set_writeformat(), ast_channel_stage_snapshot(), ast_channel_stage_snapshot_done(), ast_channel_tech_pvt_set(), ast_channel_tech_set(), ast_channel_unlock, ast_dsp_new(), ast_dsp_set_digitmode(), ast_dsp_set_features(), ast_format_cap_alloc, ast_format_cap_append_from_cap(), ast_format_cap_count(), AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_cap_get_format(), ast_get_encoded_str(), ast_hangup(), ast_jb_configure(), ast_log, AST_MEDIA_TYPE_UNKNOWN, 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_ERROR, LOG_WARNING, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, mgcp_set_owner(), ast_variable::name, mgcp_gateway::name, mgcp_endpoint::name, ast_variable::next, NULL, ast_party_id::number, mgcp_endpoint::parent, mgcp_subchannel::parent, pbx_builtin_setvar_helper(), mgcp_endpoint::pickupgroup, mgcp_subchannel::rtp, ast_party_number::str, tmp(), ast_party_number::valid, and ast_variable::value.

Referenced by handle_hd_hf(), and mgcp_request().

01505 {
01506    struct ast_format_cap *caps = NULL;
01507    struct ast_channel *tmp;
01508    struct ast_variable *v = NULL;
01509    struct mgcp_endpoint *i = sub->parent;
01510    struct ast_format *tmpfmt;
01511 
01512    caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
01513    if (!caps) {
01514       ast_log(LOG_ERROR, "Format capabilities could not be created\n");
01515       return NULL;
01516    }
01517    tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, assignedids, requestor, i->amaflags, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id);
01518    if (!tmp) {
01519       ast_log(LOG_WARNING, "Channel could not be created\n");
01520       ao2_ref(caps, -1);
01521       return NULL;
01522    }
01523 
01524    ast_channel_stage_snapshot(tmp);
01525    ast_channel_tech_set(tmp, &mgcp_tech);
01526    if (ast_format_cap_count(i->cap)) {
01527       ast_format_cap_append_from_cap(caps, i->cap, AST_MEDIA_TYPE_UNKNOWN);
01528    } else {
01529       ast_format_cap_append_from_cap(caps, global_capability, AST_MEDIA_TYPE_UNKNOWN);
01530    }
01531    ast_channel_nativeformats_set(tmp, caps);
01532    ao2_ref(caps, -1);
01533    if (sub->rtp) {
01534       ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0));
01535    }
01536    if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) {
01537       i->dsp = ast_dsp_new();
01538       ast_dsp_set_features(i->dsp, DSP_FEATURE_DIGIT_DETECT);
01539       /* this is to prevent clipping of dtmf tones during dsp processing */
01540       ast_dsp_set_digitmode(i->dsp, DSP_DIGITMODE_NOQUELCH);
01541    } else {
01542       i->dsp = NULL;
01543    }
01544    if (state == AST_STATE_RING) {
01545       ast_channel_rings_set(tmp, 1);
01546    }
01547 
01548    tmpfmt = ast_format_cap_get_format(ast_channel_nativeformats(tmp), 0);
01549    ast_channel_set_writeformat(tmp, tmpfmt);
01550    ast_channel_set_rawwriteformat(tmp, tmpfmt);
01551    ast_channel_set_readformat(tmp, tmpfmt);
01552    ast_channel_set_rawreadformat(tmp, tmpfmt);
01553    ao2_ref(tmpfmt, -1);
01554    ast_channel_tech_pvt_set(tmp, sub);
01555    if (!ast_strlen_zero(i->language))
01556       ast_channel_language_set(tmp, i->language);
01557    if (!ast_strlen_zero(i->accountcode))
01558       ast_channel_accountcode_set(tmp, i->accountcode);
01559    if (i->amaflags)
01560       ast_channel_amaflags_set(tmp, i->amaflags);
01561    mgcp_set_owner(sub, tmp);
01562    ast_module_ref(ast_module_info->self);
01563    ast_channel_callgroup_set(tmp, i->callgroup);
01564    ast_channel_pickupgroup_set(tmp, i->pickupgroup);
01565    ast_channel_call_forward_set(tmp, i->call_forward);
01566    ast_channel_context_set(tmp, i->context);
01567    ast_channel_exten_set(tmp, i->exten);
01568    /* Don't use ast_set_callerid() here because it will
01569     * generate a needless NewCallerID event */
01570    if (!ast_strlen_zero(i->cid_num)) {
01571       ast_channel_caller(tmp)->ani.number.valid = 1;
01572       ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_num);
01573    }
01574 
01575    if (!i->adsi) {
01576       ast_channel_adsicpe_set(tmp, AST_ADSI_UNAVAILABLE);
01577    }
01578    ast_channel_priority_set(tmp, 1);
01579 
01580    /* Set channel variables for this call from configuration */
01581    for (v = i->chanvars ; v ; v = v->next) {
01582       char valuebuf[1024];
01583       pbx_builtin_setvar_helper(tmp, v->name, ast_get_encoded_str(v->value, valuebuf, sizeof(valuebuf)));
01584    }
01585 
01586    if (sub->rtp) {
01587       ast_jb_configure(tmp, &global_jbconf);
01588    }
01589 
01590    ast_channel_stage_snapshot_done(tmp);
01591    ast_channel_unlock(tmp);
01592 
01593    if (state != AST_STATE_DOWN) {
01594       if (ast_pbx_start(tmp)) {
01595          ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
01596          ast_hangup(tmp);
01597          tmp = NULL;
01598       }
01599    }
01600    ast_verb(3, "MGCP mgcp_new(%s) created in state: %s\n",
01601          ast_channel_name(tmp), ast_state2str(state));
01602 
01603    return tmp;
01604 }

static int mgcp_pktcgate_open ( struct cops_gate gate  )  [static]

Definition at line 2446 of file chan_mgcp.c.

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

Referenced by mgcp_alloc_pktcgate().

02447 {
02448    struct mgcp_subchannel *sub = gate->tech_pvt;
02449    if (!sub) {
02450       return 1;
02451    }
02452    ast_mutex_lock(&sub->lock);
02453    ast_debug(1, "Pktc: gate 0x%x open\n", gate->gateid);
02454    if (!sub->sdpsent) transmit_modify_with_sdp(sub, NULL, 0);
02455    ast_mutex_unlock(&sub->lock);
02456    return 1;
02457 }

static int mgcp_pktcgate_remove ( struct cops_gate gate  )  [static]

Definition at line 2423 of file chan_mgcp.c.

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

Referenced by mgcp_alloc_pktcgate().

02424 {
02425    struct mgcp_subchannel *sub = gate->tech_pvt;
02426 
02427    if (!sub) {
02428       return 1;
02429    }
02430 
02431    ast_mutex_lock(&sub->lock);
02432    ast_debug(1, "Pktc: gate 0x%x deleted\n", gate->gateid);
02433    if (sub->gate->state != GATE_CLOSED && sub->parent->hangupongateremove) {
02434       sub->gate = NULL;
02435       if (sub->owner) {
02436          ast_softhangup(sub->owner, AST_CAUSE_REQUESTED_CHAN_UNAVAIL);
02437          ast_channel_unlock(sub->owner);
02438       }
02439    } else {
02440       sub->gate = NULL;
02441    }
02442    ast_mutex_unlock(&sub->lock);
02443    return 1;
02444 }

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, mgcp_gateway::msgs, mgcp_gateway::msgs_lock, mgcp_message::next, NULL, mgcp_message::owner_ep, mgcp_message::owner_sub, mgcp_endpoint::parent, mgcp_message::retrans, retrans_pkt(), mgcp_gateway::retransid, and mgcp_message::seqno.

Referenced by find_command(), and send_request().

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

static int mgcp_prune_realtime_gateway ( struct mgcp_gateway g  )  [static]

Definition at line 3771 of file chan_mgcp.c.

References ast_debug, ast_free, 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, e, mgcp_gateway::endpoints, mgcp_subchannel::gate, mgcp_gateway::ha, mgcp_subchannel::lock, mgcp_endpoint::lock, MAX_SUBS, mgcp_gateway::msgs, mgcp_gateway::msgs_lock, mgcp_gateway::name, mgcp_subchannel::next, mgcp_endpoint::next, mgcp_gateway::realtime, mgcp_endpoint::rqnt_queue, mgcp_endpoint::rqnt_queue_lock, mgcp_subchannel::rtp, mgcp_endpoint::sub, and sub.

Referenced by do_monitor().

03772 {
03773    struct mgcp_endpoint *enext, *e;
03774    struct mgcp_subchannel *s, *sub;
03775    int i, prune = 1;
03776 
03777    if (g->ha || !g->realtime || ast_mutex_trylock(&g->msgs_lock) || g->msgs) {
03778       ast_mutex_unlock(&g->msgs_lock);
03779       return 0;
03780    }
03781 
03782    for (e = g->endpoints; e; e = e->next) {
03783       ast_mutex_lock(&e->lock);
03784       if (e->dsp || ast_mutex_trylock(&e->rqnt_queue_lock) || ast_mutex_trylock(&e->cmd_queue_lock)) {
03785          prune = 0;
03786       } else if (e->rqnt_queue || e->cmd_queue) {
03787          prune = 0;
03788       }
03789       s = e->sub;
03790       for (i = 0; (i < MAX_SUBS) && s; i++) {
03791          ast_mutex_lock(&s->lock);
03792          if (!ast_strlen_zero(s->cxident) || s->rtp || ast_mutex_trylock(&s->cx_queue_lock) || s->gate) {
03793             prune = 0;
03794          } else if (s->cx_queue) {
03795             prune = 0;
03796          }
03797          s = s->next;
03798       }
03799    }
03800 
03801    for (e = g->endpoints, sub = e->sub, enext = e->next; e; e = enext, enext = e->next) {
03802       for (i = 0; (i < MAX_SUBS) && sub; i++) {
03803          s = sub;
03804          sub = sub->next;
03805          ast_mutex_unlock(&s->lock);
03806          ast_mutex_unlock(&s->cx_queue_lock);
03807          if (prune) {
03808             ast_mutex_destroy(&s->lock);
03809             ast_mutex_destroy(&s->cx_queue_lock);
03810             ast_free(s);
03811          }
03812       }
03813       ast_mutex_unlock(&e->lock);
03814       ast_mutex_unlock(&e->rqnt_queue_lock);
03815       ast_mutex_unlock(&e->cmd_queue_lock);
03816       if (prune) {
03817          ast_mutex_destroy(&e->lock);
03818          ast_mutex_destroy(&e->rqnt_queue_lock);
03819          ast_mutex_destroy(&e->cmd_queue_lock);
03820          ast_free(e);
03821       }
03822    }
03823    if (prune) {
03824       ast_debug(1, "***** MGCP REALTIME PRUNE GW: %s\n", g->name);
03825    }
03826    return prune;
03827 }

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

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

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

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

static void mgcp_queue_hangup ( struct mgcp_subchannel sub  )  [static]

Definition at line 631 of file chan_mgcp.c.

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

Referenced by attempt_transfer(), destroy_endpoint(), handle_request(), handle_response(), and start_rtp().

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

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

Definition at line 1240 of file chan_mgcp.c.

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

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

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

Definition at line 4907 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, NULL, restart_monitor(), and ast_cli_entry::usage.

Referenced by reload(), and unload_module().

04908 {
04909    static int deprecated = 0;
04910 
04911    if (e) {
04912       switch (cmd) {
04913       case CLI_INIT:
04914          e->command = "mgcp reload";
04915          e->usage =
04916             "Usage: mgcp reload\n"
04917             "       'mgcp reload' is deprecated.  Please use 'reload chan_mgcp.so' instead.\n";
04918          return NULL;
04919       case CLI_GENERATE:
04920          return NULL;
04921       }
04922    }
04923 
04924    if (!deprecated && a && a->argc > 0) {
04925       ast_log(LOG_WARNING, "'mgcp reload' is deprecated.  Please use 'reload chan_mgcp.so' instead.\n");
04926       deprecated = 1;
04927    }
04928 
04929    ast_mutex_lock(&mgcp_reload_lock);
04930    if (mgcp_reloading) {
04931       ast_verbose("Previous mgcp reload not yet done\n");
04932    } else {
04933       mgcp_reloading = 1;
04934    }
04935    ast_mutex_unlock(&mgcp_reload_lock);
04936    restart_monitor();
04937    return CLI_SUCCESS;
04938 }

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

Definition at line 3976 of file chan_mgcp.c.

References AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, ast_copy_string(), ast_format_cap_get_names(), ast_format_cap_iscompatible(), ast_log, ast_mutex_unlock, AST_STATE_DOWN, ast_str_alloca, 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, NULL, mgcp_subchannel::owner, mgcp_subchannel::parent, restart_monitor(), sub, tmp(), and transmit_notify_request().

03977 {
03978    struct mgcp_subchannel *sub;
03979    struct ast_channel *tmpc = NULL;
03980    char tmp[256];
03981 
03982    if (!(ast_format_cap_iscompatible(cap, global_capability))) {
03983       struct ast_str *cap_buf = ast_str_alloca(64);
03984       ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n",
03985          ast_format_cap_get_names(cap, &cap_buf));
03986       /*return NULL;*/
03987    }
03988    ast_copy_string(tmp, dest, sizeof(tmp));
03989    if (ast_strlen_zero(tmp)) {
03990       ast_log(LOG_NOTICE, "MGCP Channels require an endpoint\n");
03991       return NULL;
03992    }
03993    if (!(sub = find_subchannel_and_lock(tmp, 0, NULL))) {
03994       ast_log(LOG_WARNING, "Unable to find MGCP endpoint '%s'\n", tmp);
03995       *cause = AST_CAUSE_UNREGISTERED;
03996       return NULL;
03997    }
03998 
03999    ast_verb(3, "MGCP mgcp_request(%s)\n", tmp);
04000    ast_verb(3, "MGCP cw: %d, dnd: %d, so: %d, sno: %d\n",
04001          sub->parent->callwaiting, sub->parent->dnd, sub->owner ? 1 : 0, sub->next->owner ? 1: 0);
04002    /* Must be busy */
04003    if (((sub->parent->callwaiting) && ((sub->owner) && (sub->next->owner))) ||
04004       ((!sub->parent->callwaiting) && (sub->owner)) ||
04005        (sub->parent->dnd && (ast_strlen_zero(sub->parent->call_forward)))) {
04006       if (sub->parent->hookstate == MGCP_ONHOOK) {
04007          if (has_voicemail(sub->parent)) {
04008             transmit_notify_request(sub,"L/vmwi(+)");
04009          } else {
04010             transmit_notify_request(sub,"L/vmwi(-)");
04011          }
04012       }
04013       *cause = AST_CAUSE_BUSY;
04014       ast_mutex_unlock(&sub->lock);
04015       return NULL;
04016    }
04017    tmpc = mgcp_new(sub->owner ? sub->next : sub, AST_STATE_DOWN, assignedids, requestor);
04018    ast_mutex_unlock(&sub->lock);
04019    if (!tmpc)
04020       ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
04021    restart_monitor();
04022    return tmpc;
04023 }

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

Definition at line 1191 of file chan_mgcp.c.

References ao2_ref, ast_channel_nativeformats(), ast_channel_nativeformats_set(), ast_channel_readformat(), ast_channel_writeformat(), ast_debug, ast_dsp_process(), ast_format_cap_alloc, ast_format_cap_append, AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_cap_iscompatible_format(), AST_FORMAT_CMP_NOT_EQUAL, ast_format_get_name(), AST_FRAME_DTMF, AST_FRAME_VOICE, ast_log, ast_null_frame, ast_rtp_instance_read(), ast_set_read_format(), ast_set_write_format(), mgcp_endpoint::dsp, mgcp_endpoint::dtmfmode, f, ast_frame_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().

01192 {
01193    /* Retrieve audio/etc from channel.  Assumes sub->lock is already held. */
01194    struct ast_frame *f;
01195 
01196    f = ast_rtp_instance_read(sub->rtp, 0);
01197    /* Don't send RFC2833 if we're not supposed to */
01198    if (f && (f->frametype == AST_FRAME_DTMF) && !(sub->parent->dtmfmode & MGCP_DTMF_RFC2833))
01199       return &ast_null_frame;
01200    if (sub->owner) {
01201       /* We already hold the channel lock */
01202       if (f->frametype == AST_FRAME_VOICE) {
01203          if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(sub->owner), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
01204             struct ast_format_cap *caps;
01205 
01206             ast_debug(1, "Oooh, format changed to %s\n", ast_format_get_name(f->subclass.format));
01207 
01208             caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
01209             if (caps) {
01210                ast_format_cap_append(caps, f->subclass.format, 0);
01211                ast_channel_nativeformats_set(sub->owner, caps);
01212                ao2_ref(caps, -1);
01213             } else {
01214                return &ast_null_frame;
01215             }
01216 
01217             ast_set_read_format(sub->owner, ast_channel_readformat(sub->owner));
01218             ast_set_write_format(sub->owner, ast_channel_writeformat(sub->owner));
01219          }
01220          /* Courtesy fearnor aka alex@pilosoft.com */
01221          if ((sub->parent->dtmfmode & MGCP_DTMF_INBAND) && (sub->parent->dsp)) {
01222 #if 0
01223             ast_log(LOG_NOTICE, "MGCP ast_dsp_process\n");
01224 #endif
01225             f = ast_dsp_process(sub->owner, sub->parent->dsp, f);
01226          }
01227       }
01228    }
01229    return f;
01230 }

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

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

01309 {
01310    struct mgcp_subchannel *sub = ast_channel_tech_pvt(ast);
01311    struct mgcp_endpoint *p = sub->parent;
01312    int res = 0;
01313 
01314    ast_mutex_lock(&sub->lock);
01315    if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) {
01316       ast_debug(1, "Sending DTMF using inband/hybrid\n");
01317       res = -1; /* Let asterisk play inband indications */
01318    } else if (p->dtmfmode & MGCP_DTMF_RFC2833) {
01319       ast_debug(1, "Sending DTMF using RFC2833\n");
01320       ast_rtp_instance_dtmf_begin(sub->rtp, digit);
01321    } else {
01322       ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode);
01323    }
01324    ast_mutex_unlock(&sub->lock);
01325 
01326    return res;
01327 }

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

Definition at line 1329 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, tmp(), and transmit_notify_request().

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

static void mgcp_set_owner ( struct mgcp_subchannel sub,
struct ast_channel chan 
) [static]

Definition at line 1232 of file chan_mgcp.c.

References ast_channel_uniqueid(), ast_rtp_instance_set_channel_id(), mgcp_subchannel::owner, and mgcp_subchannel::rtp.

Referenced by mgcp_fixup(), mgcp_hangup(), mgcp_new(), and unalloc_sub().

01233 {
01234    sub->owner = chan;
01235    if (sub->rtp) {
01236       ast_rtp_instance_set_channel_id(sub->rtp, sub->owner ? ast_channel_uniqueid(chan) : "");
01237    }
01238 }

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

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

04491 {
04492    /* XXX Is there such thing as video support with MGCP? XXX */
04493    struct mgcp_subchannel *sub;
04494    sub = ast_channel_tech_pvt(chan);
04495    if (sub && !sub->alreadygone) {
04496       transmit_modify_with_sdp(sub, rtp, cap);
04497       return 0;
04498    }
04499    return -1;
04500 }

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

Definition at line 3011 of file chan_mgcp.c.

References ao2_cleanup, ast_canmatch_extension(), ast_channel_caller(), ast_channel_context(), ast_channel_dialed(), ast_channel_exten_set(), ast_channel_get_bridge_channel(), ast_channel_language(), ast_channel_lock, ast_channel_name(), ast_channel_tech_pvt(), ast_channel_unlock, ast_copy_string(), ast_db_put(), ast_debug, ast_exists_extension(), ast_get_chan_features_pickup_config(), ast_hangup(), ast_ignore_pattern(), ast_indicate(), ast_log, ast_matchmore_extension(), AST_MAX_EXTENSION, ast_parking_blind_transfer_park(), ast_parking_is_exten_park(), ast_parking_provider_registered(), ast_pbx_run(), ast_pickup_call(), ast_safe_sleep(), ast_say_digit_str(), ast_set_callerid(), ast_setstate(), AST_STATE_RING, ast_strdup, ast_strdupa, 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, mgcp_endpoint::dnd, mgcp_endpoint::dtmf_buf, mgcp_endpoint::dtmfmode, ast_channel::exten, exten, mgcp_endpoint::hascallwaiting, mgcp_endpoint::hidecallerid, mgcp_endpoint::lastcallerid, len(), LOG_ERROR, LOG_WARNING, MGCP_DTMF_HYBRID, MGCP_DTMF_INBAND, ast_channel::name, mgcp_gateway::name, mgcp_endpoint::name, mgcp_endpoint::ncs, mgcp_subchannel::next, NULL, ast_party_dialed::number, mgcp_subchannel::owner, mgcp_endpoint::parent, mgcp_subchannel::parent, RAII_VAR, ast_channel::rings, S_COR, start_rtp(), ast_party_dialed::str, sub, timeout, and transmit_notify_request().

Referenced by handle_hd_hf().

03012 {
03013    struct ast_channel *chan = data;
03014    struct mgcp_subchannel *sub = ast_channel_tech_pvt(chan);
03015    struct mgcp_endpoint *p = sub->parent;
03016    /* char exten[AST_MAX_EXTENSION] = ""; */
03017    int len = 0;
03018    int timeout = firstdigittimeout;
03019    int res= 0;
03020    int getforward = 0;
03021    int loop_pause = 100;
03022    RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
03023    const char *pickupexten;
03024 
03025    len = strlen(p->dtmf_buf);
03026 
03027    ast_channel_lock(chan);
03028    pickup_cfg = ast_get_chan_features_pickup_config(chan);
03029    if (!pickup_cfg) {
03030       ast_log(LOG_ERROR, "Unable to retrieve pickup configuration options. Unable to detect call pickup extension\n");
03031       pickupexten = "";
03032    } else {
03033       pickupexten = ast_strdupa(pickup_cfg->pickupexten);
03034    }
03035    ast_channel_unlock(chan);
03036 
03037    while (len < AST_MAX_EXTENSION - 1) {
03038       ast_debug(1, "Dtmf buffer '%s' for '%s@%s'\n", p->dtmf_buf, p->name, p->parent->name);
03039       res = 1;  /* Assume that we will get a digit */
03040       while (strlen(p->dtmf_buf) == len) {
03041          ast_safe_sleep(chan, loop_pause);
03042          timeout -= loop_pause;
03043          if (timeout <= 0){
03044             res = 0;
03045             break;
03046          }
03047          res = 1;
03048       }
03049 
03050       timeout = 0;
03051       len = strlen(p->dtmf_buf);
03052 
03053       if (!ast_ignore_pattern(ast_channel_context(chan), p->dtmf_buf)) {
03054          /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
03055          ast_indicate(chan, -1);
03056       } else {
03057          /* XXX Redundant?  We should already be playing dialtone */
03058          /*tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALTONE);*/
03059          transmit_notify_request(sub, "L/dl");
03060       }
03061       if (ast_exists_extension(chan, ast_channel_context(chan), p->dtmf_buf, 1, p->cid_num)) {
03062          if (!res || !ast_matchmore_extension(chan, ast_channel_context(chan), p->dtmf_buf, 1, p->cid_num)) {
03063             if (getforward) {
03064                /* Record this as the forwarding extension */
03065                ast_copy_string(p->call_forward, p->dtmf_buf, sizeof(p->call_forward));
03066                ast_verb(3, "Setting call forward to '%s' on channel %s\n",
03067                      p->call_forward, ast_channel_name(chan));
03068                /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03069                transmit_notify_request(sub, "L/sl");
03070                if (res)
03071                   break;
03072                usleep(500000);
03073                /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
03074                ast_indicate(chan, -1);
03075                sleep(1);
03076                memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03077                /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALTONE);*/
03078                transmit_notify_request(sub, "L/dl");
03079                len = 0;
03080                getforward = 0;
03081             } else {
03082                /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
03083                ast_indicate(chan, -1);
03084                ast_channel_lock(chan);
03085                ast_channel_exten_set(chan, p->dtmf_buf);
03086                ast_channel_dialed(chan)->number.str = ast_strdup(p->dtmf_buf);
03087                memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03088                ast_set_callerid(chan,
03089                   p->hidecallerid ? "" : p->cid_num,
03090                   p->hidecallerid ? "" : p->cid_name,
03091                   ast_channel_caller(chan)->ani.number.valid ? NULL : p->cid_num);
03092                ast_setstate(chan, AST_STATE_RING);
03093                ast_channel_unlock(chan);
03094                if (p->dtmfmode & MGCP_DTMF_HYBRID) {
03095                   p->dtmfmode |= MGCP_DTMF_INBAND;
03096                   ast_indicate(chan, -1);
03097                }
03098                res = ast_pbx_run(chan);
03099                if (res) {
03100                   ast_log(LOG_WARNING, "PBX exited non-zero\n");
03101                   /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
03102                   /*transmit_notify_request(p, "nbz", 1);*/
03103                   transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
03104                }
03105                return NULL;
03106             }
03107          } else {
03108             /* It's a match, but they just typed a digit, and there is an ambiguous match,
03109                so just set the timeout to matchdigittimeout and wait some more */
03110             timeout = matchdigittimeout;
03111          }
03112       } else if (res == 0) {
03113          ast_debug(1, "not enough digits (and no ambiguous match)...\n");
03114          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
03115          transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
03116          /*dahdi_wait_event(p->subs[index].zfd);*/
03117          ast_hangup(chan);
03118          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03119          return NULL;
03120       } else if (p->hascallwaiting && p->callwaiting && !strcmp(p->dtmf_buf, "*70")) {
03121          ast_verb(3, "Disabling call waiting on %s\n", ast_channel_name(chan));
03122          /* Disable call waiting if enabled */
03123          p->callwaiting = 0;
03124          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03125          transmit_notify_request(sub, "L/sl");
03126          len = 0;
03127          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03128          timeout = firstdigittimeout;
03129       } else if (!strcmp(p->dtmf_buf, pickupexten)) {
03130          /* Scan all channels and see if any there
03131           * ringing channqels with that have call groups
03132           * that equal this channels pickup group
03133           */
03134          if (ast_pickup_call(chan)) {
03135             ast_log(LOG_WARNING, "No call pickup possible...\n");
03136             /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_CONGESTION);*/
03137             transmit_notify_request(sub, p->ncs ? "L/cg" : "G/cg");
03138          }
03139          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03140          ast_hangup(chan);
03141          return NULL;
03142       } else if (!p->hidecallerid && !strcmp(p->dtmf_buf, "*67")) {
03143          ast_verb(3, "Disabling Caller*ID on %s\n", ast_channel_name(chan));
03144          /* Disable Caller*ID if enabled */
03145          p->hidecallerid = 1;
03146          ast_set_callerid(chan, "", "", NULL);
03147          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03148          transmit_notify_request(sub, "L/sl");
03149          len = 0;
03150          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03151          timeout = firstdigittimeout;
03152       } else if (p->callreturn && !strcmp(p->dtmf_buf, "*69")) {
03153          res = 0;
03154          if (!ast_strlen_zero(p->lastcallerid)) {
03155             res = ast_say_digit_str(chan, p->lastcallerid, "", ast_channel_language(chan));
03156          }
03157          if (!res)
03158             /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03159             transmit_notify_request(sub, "L/sl");
03160          break;
03161       } else if (!strcmp(p->dtmf_buf, "*78")) {
03162          /* Do not disturb */
03163          ast_verb(3, "Enabled DND on channel %s\n", ast_channel_name(chan));
03164          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03165          transmit_notify_request(sub, "L/sl");
03166          p->dnd = 1;
03167          getforward = 0;
03168          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03169          len = 0;
03170       } else if (!strcmp(p->dtmf_buf, "*79")) {
03171          /* Do not disturb */
03172          ast_verb(3, "Disabled DND on channel %s\n", ast_channel_name(chan));
03173          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03174          transmit_notify_request(sub, "L/sl");
03175          p->dnd = 0;
03176          getforward = 0;
03177          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03178          len = 0;
03179       } else if (p->cancallforward && !strcmp(p->dtmf_buf, "*72")) {
03180          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03181          transmit_notify_request(sub, "L/sl");
03182          getforward = 1;
03183          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03184          len = 0;
03185       } else if (p->cancallforward && !strcmp(p->dtmf_buf, "*73")) {
03186          ast_verb(3, "Cancelling call forwarding on channel %s\n", ast_channel_name(chan));
03187          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03188          transmit_notify_request(sub, "L/sl");
03189          memset(p->call_forward, 0, sizeof(p->call_forward));
03190          getforward = 0;
03191          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03192          len = 0;
03193       } else if (ast_parking_provider_registered() && ast_parking_is_exten_park(ast_channel_context(chan), p->dtmf_buf) &&
03194          sub->next->owner) {
03195          RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
03196          /* This is a three way call, the main call being a real channel,
03197             and we're parking the first call. */
03198          ast_channel_lock(chan);
03199          bridge_channel = ast_channel_get_bridge_channel(chan);
03200          ast_channel_unlock(chan);
03201          if (bridge_channel && !ast_parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), p->dtmf_buf, NULL, NULL)) {
03202             ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
03203          }
03204          break;
03205       } else if (!ast_strlen_zero(p->lastcallerid) && !strcmp(p->dtmf_buf, "*60")) {
03206          ast_verb(3, "Blacklisting number %s\n", p->lastcallerid);
03207          res = ast_db_put("blacklist", p->lastcallerid, "1");
03208          if (!res) {
03209             /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03210             transmit_notify_request(sub, "L/sl");
03211             memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03212             len = 0;
03213          }
03214       } else if (p->hidecallerid && !strcmp(p->dtmf_buf, "*82")) {
03215          ast_verb(3, "Enabling Caller*ID on %s\n", ast_channel_name(chan));
03216          /* Enable Caller*ID if enabled */
03217          p->hidecallerid = 0;
03218          ast_set_callerid(chan, p->cid_num, p->cid_name, NULL);
03219          /*res = tone_zone_play_tone(p->subs[index].zfd, DAHDI_TONE_DIALRECALL);*/
03220          transmit_notify_request(sub, "L/sl");
03221          len = 0;
03222          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03223          timeout = firstdigittimeout;
03224       } else if (!ast_canmatch_extension(chan, ast_channel_context(chan), p->dtmf_buf, 1,
03225          S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))
03226          && ((p->dtmf_buf[0] != '*') || (strlen(p->dtmf_buf) > 2))) {
03227          ast_debug(1, "Can't match %s from '%s' in context %s\n", p->dtmf_buf,
03228             S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<Unknown Caller>"),
03229             ast_channel_context(chan));
03230          break;
03231       }
03232       if (!timeout)
03233          timeout = gendigittimeout;
03234       if (len && !ast_ignore_pattern(ast_channel_context(chan), p->dtmf_buf))
03235          /*tone_zone_play_tone(p->subs[index].zfd, -1);*/
03236          ast_indicate(chan, -1);
03237    }
03238 #if 0
03239    for (;;) {
03240       res = ast_waitfordigit(chan, to);
03241       if (!res) {
03242          ast_debug(1, "Timeout...\n");
03243          break;
03244       }
03245       if (res < 0) {
03246          ast_debug(1, "Got hangup...\n");
03247          ast_hangup(chan);
03248          break;
03249       }
03250       exten[pos++] = res;
03251       if (!ast_ignore_pattern(chan->context, exten))
03252          ast_indicate(chan, -1);
03253       if (ast_matchmore_extension(chan, chan->context, exten, 1, chan->callerid)) {
03254          if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid))
03255             to = 3000;
03256          else
03257             to = 8000;
03258       } else
03259          break;
03260    }
03261    if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid)) {
03262       ast_copy_string(chan->exten, exten, sizeof(chan->exten)1);
03263       if (!p->rtp) {
03264          start_rtp(p);
03265       }
03266       ast_setstate(chan, AST_STATE_RING);
03267       chan->rings = 1;
03268       if (ast_pbx_run(chan)) {
03269          ast_log(LOG_WARNING, "Unable to launch PBX on %s\n", chan->name);
03270       } else {
03271          memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03272          return NULL;
03273       }
03274    }
03275 #endif
03276    ast_hangup(chan);
03277    memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
03278    return NULL;
03279 }

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

Definition at line 1250 of file chan_mgcp.c.

References ast_channel_nativeformats(), ast_channel_readformat(), ast_channel_tech_pvt(), ast_channel_writeformat(), ast_debug, ast_format_cap_get_names(), ast_format_cap_iscompatible_format(), AST_FORMAT_CMP_NOT_EQUAL, ast_format_get_name(), AST_FRAME_IMAGE, AST_FRAME_VOICE, ast_log, ast_mutex_lock, ast_mutex_unlock, ast_rtp_instance_write(), ast_str_alloca, ast_frame_subclass::format, ast_frame::frametype, mgcp_subchannel::gate, GATE_ALLOCATED, mgcp_subchannel::lock, LOG_WARNING, NULL, mgcp_subchannel::parent, mgcp_subchannel::rtp, mgcp_subchannel::sdpsent, mgcp_endpoint::singlepath, cops_gate::state, mgcp_endpoint::sub, sub, ast_frame::subclass, and transmit_modify_with_sdp().

01251 {
01252    struct mgcp_subchannel *sub = ast_channel_tech_pvt(ast);
01253    int res = 0;
01254 
01255    if (frame->frametype != AST_FRAME_VOICE) {
01256       if (frame->frametype == AST_FRAME_IMAGE)
01257          return 0;
01258       else {
01259          ast_log(LOG_WARNING, "Can't send %u type frames with MGCP write\n", frame->frametype);
01260          return 0;
01261       }
01262    } else {
01263       if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
01264          struct ast_str *cap_buf = ast_str_alloca(64);
01265 
01266          ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
01267             ast_format_get_name(frame->subclass.format),
01268             ast_format_cap_get_names(ast_channel_nativeformats(ast), &cap_buf),
01269             ast_format_get_name(ast_channel_readformat(ast)),
01270             ast_format_get_name(ast_channel_writeformat(ast)));
01271          /* return -1; */
01272       }
01273    }
01274    if (sub) {
01275       ast_mutex_lock(&sub->lock);
01276       if (!sub->sdpsent && sub->gate) {
01277          if (sub->gate->state == GATE_ALLOCATED) {
01278             ast_debug(1, "GATE ALLOCATED, sending sdp\n");
01279             transmit_modify_with_sdp(sub, NULL, 0);
01280          }
01281       }
01282       if ((sub->parent->sub == sub) || !sub->parent->singlepath) {
01283          if (sub->rtp) {
01284             res =  ast_rtp_instance_write(sub->rtp, frame);
01285          }
01286       }
01287       ast_mutex_unlock(&sub->lock);
01288    }
01289    return res;
01290 }

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

Definition at line 3680 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, NULL, mgcp_message::owner_ep, mgcp_message::owner_sub, mgcp_endpoint::parent, mgcp_subchannel::parent, parse(), result, mgcp_gateway::retransid, mgcp_message::seqno, sub, mgcp_request::verb, and mgcp_request::version.

Referenced by do_monitor().

03681 {
03682    struct mgcp_request req;
03683    struct sockaddr_in sin;
03684    struct mgcp_subchannel *sub;
03685    int res;
03686    socklen_t len;
03687    int result;
03688    int ident;
03689    len = sizeof(sin);
03690    memset(&req, 0, sizeof(req));
03691    res = recvfrom(mgcpsock, req.data, sizeof(req.data) - 1, 0, (struct sockaddr *)&sin, &len);
03692    if (res < 0) {
03693       if (errno != ECONNREFUSED)
03694          ast_log(LOG_WARNING, "Recv error: %s\n", strerror(errno));
03695       return 1;
03696    }
03697    req.data[res] = '\0';
03698    req.len = res;
03699    ast_debug(1, "MGCP read: \n%s\nfrom %s:%d\n", req.data, ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
03700    parse(&req);
03701    if (req.headers < 1) {
03702       /* Must have at least one header */
03703       return 1;
03704    }
03705    if (ast_strlen_zero(req.identifier)) {
03706       ast_log(LOG_NOTICE, "Message from %s missing identifier\n", ast_inet_ntoa(sin.sin_addr));
03707       return 1;
03708    }
03709 
03710    if (sscanf(req.verb, "%30d", &result) && sscanf(req.identifier, "%30d", &ident)) {
03711       if (result < 200) {
03712          ast_debug(1, "Ignoring provisional response on transaction %d\n", ident);
03713          return 1;
03714       }
03715       /* Try to find who this message is for, if it's important */
03716       sub = find_subchannel_and_lock(NULL, ident, &sin);
03717       if (sub) {
03718          struct mgcp_gateway *gw = sub->parent->parent;
03719          struct mgcp_message *cur, *prev;
03720 
03721          ast_mutex_unlock(&sub->lock);
03722          ast_mutex_lock(&gw->msgs_lock);
03723          for (prev = NULL, cur = gw->msgs; cur; prev = cur, cur = cur->next) {
03724             if (cur->seqno == ident) {
03725                ast_debug(1, "Got response back on transaction %d\n", ident);
03726                if (prev)
03727                   prev->next = cur->next;
03728                else
03729                   gw->msgs = cur->next;
03730                break;
03731             }
03732          }
03733 
03734          /* stop retrans timer if the queue is empty */
03735          if (!gw->msgs) {
03736             AST_SCHED_DEL(sched, gw->retransid);
03737          }
03738 
03739          ast_mutex_unlock(&gw->msgs_lock);
03740          if (cur) {
03741             handle_response(cur->owner_ep, cur->owner_sub, result, ident, &req);
03742             ast_free(cur);
03743             return 1;
03744          }
03745 
03746          ast_log(LOG_NOTICE, "Got response back on [%s] for transaction %d we aren't sending?\n",
03747             gw->name, ident);
03748       }
03749    } else {
03750       if (ast_strlen_zero(req.endpoint) ||
03751          ast_strlen_zero(req.version) ||
03752          ast_strlen_zero(req.verb)) {
03753          ast_log(LOG_NOTICE, "Message must have a verb, an idenitifier, version, and endpoint\n");
03754          return 1;
03755       }
03756       /* Process request, with iflock held */
03757       sub = find_subchannel_and_lock(req.endpoint, 0, &sin);
03758       if (sub) {
03759          /* look first to find a matching response in the queue */
03760          if (!find_and_retrans(sub, &req))
03761             /* pass the request off to the currently mastering subchannel */
03762             handle_request(sub, &req, &sin);
03763          ast_mutex_unlock(&sub->lock);
03764       }
03765    }
03766    return 1;
03767 }

static void mwi_event_cb ( void *  userdata,
struct stasis_subscription sub,
struct stasis_message msg 
) [static]

Definition at line 492 of file chan_mgcp.c.

00493 {
00494    /* This module does not handle MWI in an event-based manner.  However, it
00495     * subscribes to MWI for each mailbox that is configured so that the core
00496     * knows that we care about it.  Then, chan_mgcp will get the MWI from the
00497     * event cache instead of checking the mailbox directly. */
00498 }

static void parse ( struct mgcp_request req  )  [static]

Definition at line 1882 of file chan_mgcp.c.

References ast_debug, ast_log, ast_strlen_zero, c, 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(), add_hintdevice(), agent_function_read(), agent_login_exec(), agent_request_exec(), aMYSQL_clear(), aMYSQL_connect(), aMYSQL_disconnect(), aMYSQL_fetch(), aMYSQL_nextresult(), aMYSQL_query(), aMYSQL_set(), app_exec(), applicationmap_handler(), aqm_exec(), ast_format_cap_update_by_allow_disallow(), AST_TEST_DEFINE(), bridgewait_exec(), cdr_prop_write_callback(), cdr_write_callback(), celgenuserevent_exec(), chanspy_exec(), conf_exec(), conf_run(), confbridge_exec(), config_function_read(), cut_internal(), dial_exec_full(), dictate_exec(), directory_exec(), dundi_query_read(), dundi_result_read(), dundifunc_read(), enum_query_read(), enum_result_read(), execif_exec(), expand_gosub_args(), extenspy_exec(), find_conf(), forkcdr_exec(), func_confbridge_helper(), func_confbridge_info(), get_comma(), get_in_brackets_const(), get_in_brackets_full(), gosub_exec(), hook_on(), iconv_read(), isAnsweringMachine(), isexten_function_read(), jb_helper(), load_channelvars(), local_alloc(), log_exec(), man_do_variable_value(), mbl_sendsms_exec(), mbl_status_exec(), mgcpsock_read(), mixmonitor_exec(), msg_send_exec(), multicast_rtp_request(), mwi_has_voicemail(), mwi_inboxcount(), originate_exec(), oss_call(), oss_request(), page_exec(), park_and_announce_app_exec(), park_app_parse_data(), parked_call_app_exec(), parse_cookies(), pbx_builtin_answer(), pbx_builtin_background(), pbx_builtin_saycharacters_case(), pbx_builtin_waitexten(), pickup_exec(), pickupchan_exec(), pjsip_acf_channel_read(), play_moh_exec(), pqm_exec(), presence_read(), privacy_exec(), ql_exec(), queue_exec(), queue_function_queuegetchannel(), 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(), talk_detect_fn_write(), transfer_exec(), transport_tls_cipher_handler(), unicast_rtp_request(), upqm_exec(), user_event_hook_cb(), userevent_exec(), verbose_exec(), and zapateller_exec().

01883 {
01884    /* Divide fields by NULL's */
01885    char *c;
01886    int f = 0;
01887    c = req->data;
01888 
01889    /* First header starts immediately */
01890    req->header[f] = c;
01891    for (; *c; c++) {
01892       if (*c == '\n') {
01893          /* We've got a new header */
01894          *c = 0;
01895          ast_debug(3, "Header: %s (%d)\n", req->header[f], (int) strlen(req->header[f]));
01896          if (ast_strlen_zero(req->header[f])) {
01897             /* Line by itself means we're now in content */
01898             c++;
01899             break;
01900          }
01901          if (f >= MGCP_MAX_HEADERS - 1) {
01902             ast_log(LOG_WARNING, "Too many MGCP headers...\n");
01903          } else {
01904             f++;
01905          }
01906          req->header[f] = c + 1;
01907       } else if (*c == '\r') {
01908          /* Ignore but eliminate \r's */
01909          *c = 0;
01910       }
01911    }
01912    /* Check for last header */
01913    if (!ast_strlen_zero(req->header[f])) {
01914       f++;
01915    }
01916    req->headers = f;
01917    /* Now we process any mime content */
01918    f = 0;
01919    req->line[f] = c;
01920    for (; *c; c++) {
01921       if (*c == '\n') {
01922          /* We've got a new line */
01923          *c = 0;
01924          ast_debug(3, "Line: %s (%d)\n", req->line[f], (int) strlen(req->line[f]));
01925          if (f >= MGCP_MAX_LINES - 1) {
01926             ast_log(LOG_WARNING, "Too many SDP lines...\n");
01927          } else {
01928             f++;
01929          }
01930          req->line[f] = c + 1;
01931       } else if (*c == '\r') {
01932          /* Ignore and eliminate \r's */
01933          *c = 0;
01934       }
01935    }
01936    /* Check for last line */
01937    if (!ast_strlen_zero(req->line[f])) {
01938       f++;
01939    }
01940    req->lines = f;
01941    /* Parse up the initial header */
01942    c = req->header[0];
01943    while (*c && *c < 33) c++;
01944    /* First the verb */
01945    req->verb = c;
01946    while (*c && (*c > 32)) c++;
01947    if (*c) {
01948       *c = '\0';
01949       c++;
01950       while (*c && (*c < 33)) c++;
01951       req->identifier = c;
01952       while (*c && (*c > 32)) c++;
01953       if (*c) {
01954          *c = '\0';
01955          c++;
01956          while (*c && (*c < 33)) c++;
01957          req->endpoint = c;
01958          while (*c && (*c > 32)) c++;
01959          if (*c) {
01960             *c = '\0';
01961             c++;
01962             while (*c && (*c < 33)) c++;
01963             req->version = c;
01964             while (*c && (*c > 32)) c++;
01965             while (*c && (*c < 33)) c++;
01966             while (*c && (*c > 32)) c++;
01967             *c = '\0';
01968          }
01969       }
01970    }
01971 
01972    ast_debug(1, "Verb: '%s', Identifier: '%s', Endpoint: '%s', Version: '%s'\n",
01973          req->verb, req->identifier, req->endpoint, req->version);
01974    ast_debug(1, "%d headers, %d lines\n", req->headers, req->lines);
01975    if (*c) {
01976       ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c);
01977    }
01978 }

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

Definition at line 1980 of file chan_mgcp.c.

References a, ao2_ref, ast_debug, ast_format_cap_alloc, ast_format_cap_count(), AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_cap_get_compatible(), ast_format_cap_get_names(), 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_str_alloca, ast_strdupa, ast_strlen_zero, c, mgcp_endpoint::cap, codecs, get_sdp(), get_sdp_iterate(), host, hp, len(), LOG_WARNING, mgcp_endpoint::nonCodecCapability, mgcp_subchannel::parent, mgcp_subchannel::rtp, and sdpLineNum_iterator_init().

Referenced by handle_incoming(), handle_request_invite(), handle_response(), and handle_response_invite().

01981 {
01982    char *m;
01983    char *c;
01984    char *a;
01985    char host[258];
01986    int len = 0;
01987    int portno;
01988    struct ast_format_cap *peercap;
01989    int peerNonCodecCapability;
01990    struct sockaddr_in sin;
01991    struct ast_sockaddr sin_tmp;
01992    char *codecs;
01993    struct ast_hostent ahp; struct hostent *hp;
01994    int codec, codec_count=0;
01995    int iterator;
01996    struct mgcp_endpoint *p = sub->parent;
01997    struct ast_str *global_buf = ast_str_alloca(64);
01998    struct ast_str *peer_buf = ast_str_alloca(64);
01999    struct ast_str *pvt_buf = ast_str_alloca(64);
02000 
02001    /* Get codec and RTP info from SDP */
02002    m = get_sdp(req, "m");
02003    c = get_sdp(req, "c");
02004    if (ast_strlen_zero(m) || ast_strlen_zero(c)) {
02005       ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s', c = '%s')\n", m, c);
02006       return -1;
02007    }
02008    if (sscanf(c, "IN IP4 %256s", host) != 1) {
02009       ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
02010       return -1;
02011    }
02012    /* XXX This could block for a long time, and block the main thread! XXX */
02013    hp = ast_gethostbyname(host, &ahp);
02014    if (!hp) {
02015       ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c);
02016       return -1;
02017    }
02018    if (sscanf(m, "audio %30d RTP/AVP %n", &portno, &len) != 1 || !len) {
02019       ast_log(LOG_WARNING, "Malformed media stream descriptor: %s\n", m);
02020       return -1;
02021    }
02022    sin.sin_family = AF_INET;
02023    memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
02024    sin.sin_port = htons(portno);
02025    ast_sockaddr_from_sin(&sin_tmp, &sin);
02026    ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp);
02027    ast_debug(3, "Peer RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
02028    /* Scan through the RTP payload types specified in a "m=" line: */
02029    ast_rtp_codecs_payloads_clear(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp);
02030    codecs = ast_strdupa(m + len);
02031    while (!ast_strlen_zero(codecs)) {
02032       if (sscanf(codecs, "%30d%n", &codec, &len) != 1) {
02033          if (codec_count) {
02034             break;
02035          }
02036          ast_log(LOG_WARNING, "Error in codec string '%s' at '%s'\n", m, codecs);
02037          return -1;
02038       }
02039       ast_rtp_codecs_payloads_set_m_type(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp, codec);
02040       codec_count++;
02041       codecs += len;
02042    }
02043 
02044    /* Next, scan through each "a=rtpmap:" line, noting each */
02045    /* specified RTP payload type (with corresponding MIME subtype): */
02046    sdpLineNum_iterator_init(&iterator);
02047    while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
02048       char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
02049       if (sscanf(a, "rtpmap: %30d %127[^/]/", &codec, mimeSubtype) != 2)
02050          continue;
02051       /* Note: should really look at the 'freq' and '#chans' params too */
02052       ast_rtp_codecs_payloads_set_rtpmap_type(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp, codec, "audio", mimeSubtype, 0);
02053    }
02054 
02055    /* Now gather all of the codecs that were asked for: */
02056    if (!(peercap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
02057       return -1;
02058    }
02059    ast_rtp_codecs_payload_formats(ast_rtp_instance_get_codecs(sub->rtp), peercap, &peerNonCodecCapability);
02060    ast_format_cap_get_compatible(global_capability, peercap, p->cap);
02061    ast_debug(1, "Capabilities: us - %s, them - %s, combined - %s\n",
02062       ast_format_cap_get_names(global_capability, &global_buf),
02063       ast_format_cap_get_names(peercap, &peer_buf),
02064       ast_format_cap_get_names(p->cap, &pvt_buf));
02065    ao2_ref(peercap, -1);
02066 
02067    ast_debug(1, "Non-codec capabilities: us - %d, them - %d, combined - %d\n",
02068       nonCodecCapability, peerNonCodecCapability, p->nonCodecCapability);
02069    if (!ast_format_cap_count(p->cap)) {
02070       ast_log(LOG_WARNING, "No compatible codecs!\n");
02071       return -1;
02072    }
02073    return 0;
02074 }

static void prune_gateways ( void   )  [static]

Definition at line 4607 of file chan_mgcp.c.

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

Referenced by unload_module().

04608 {
04609    struct mgcp_gateway *g, *z, *r;
04610    struct mgcp_endpoint *e, *p, *t;
04611 
04612    ast_mutex_lock(&gatelock);
04613 
04614    /* prune gateways */
04615    for (z = NULL, g = gateways; g;) {
04616       /* prune endpoints */
04617       for (p = NULL, e = g->endpoints; e; ) {
04618          if (!g->realtime && (e->delme || g->delme)) {
04619             t = e;
04620             e = e->next;
04621             if (!p)
04622                g->endpoints = e;
04623             else
04624                p->next = e;
04625             destroy_endpoint(t);
04626          } else {
04627             p = e;
04628             e = e->next;
04629          }
04630       }
04631 
04632       if (g->delme) {
04633          r = g;
04634          g = g->next;
04635          if (!z)
04636             gateways = g;
04637          else
04638             z->next = g;
04639 
04640          destroy_gateway(r);
04641       } else {
04642          z = g;
04643          g = g->next;
04644       }
04645    }
04646 
04647    ast_mutex_unlock(&gatelock);
04648 }

static int reload ( void   )  [static]

Definition at line 4940 of file chan_mgcp.c.

References mgcp_reload(), and NULL.

04941 {
04942    mgcp_reload(NULL, 0, NULL);
04943    return 0;
04944 }

static int reload_config ( int  reload  )  [static]

Definition at line 2767 of file chan_ooh323.c.

References ast_calloc, ast_category_browse(), ast_channel_string2amaflag(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_false(), ast_format_cap_append, ast_format_cap_remove_by_type(), ast_format_cap_update_by_allow_disallow(), ast_format_ulaw, ast_free, ast_jb_read_conf(), ast_log, AST_MEDIA_TYPE_UNKNOWN, ast_mutex_lock, ast_mutex_unlock, ast_parse_arg(), ast_sockaddr_is_ipv6(), ast_strdup, ast_strdupa, ast_strlen_zero, ast_true(), ast_variable_browse(), ast_variable_retrieve(), ast_verb, bindaddr, buf, build_peer(), build_user(), config, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_CONTEXT, DEFAULT_H323ACCNT, DEFAULT_H323ID, DEFAULT_LOGFILE, delete_peers(), delete_users(), FALSE, FAXDETECT_CNG, FAXDETECT_T38, format, g729onlyA, gAccountcode, gAliasList, gAMAFLAGS, gANIasDNI, gBeMaster, gCallerID, gContext, gDirectRTP, gDTMFCodec, gDTMFMode, gEarlyDirect, gFastStart, gFAXdetect, gGatekeeper, gH323Debug, gIncomingLimit, gIP, gIsGateway, global_jbconf, gLogFile, gMediaWaitForConnect, gNat, gOutgoingLimit, gPort, gRasGkMode, gRTDRCount, gRTDRInterval, gRTPTimeout, gT38Support, gTOS, gTRCLVL, gTunneling, H323_DTMF_CISCO, H323_DTMF_H245ALPHANUMERIC, H323_DTMF_H245SIGNAL, H323_DTMF_INBAND, H323_DTMF_INBANDRELAX, H323_DTMF_Q931, H323_DTMF_RFC2833, ast_variable::lineno, ast_peer_list::lock, ast_user_list::lock, LOG_ERROR, LOG_NOTICE, LOG_WARNING, manufacturer, ooh323_config::mTCPPortEnd, ooh323_config::mTCPPortStart, ast_variable::name, ooh323_user::next, ooh323_peer::next, ast_variable::next, NULL, ooconfig, PARSE_ADDR, peerl, ast_peer_list::peers, RESULT_SUCCESS, strsep(), t35countrycode, t35extensions, T38_DISABLED, T38_ENABLED, T38_FAXGW, tmp(), userl, ast_user_list::users, v6mode, ast_variable::value, vendor, and version.

Referenced by acl_change_stasis_cb(), do_monitor(), handle_cli_iax2_reload(), handle_cli_misdn_reload(), load_module(), ooh323_do_reload(), reload(), and sip_do_reload().

02768 {
02769    int format;
02770    struct ooAliases  *pNewAlias = NULL, *cur, *prev;
02771    struct ast_config *cfg;
02772    struct ast_variable *v;
02773    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
02774    struct ooh323_user *user = NULL;
02775    struct ooh323_peer *peer = NULL;
02776    char *cat;
02777    const char *utype;
02778 
02779    if (gH323Debug)
02780       ast_verb(0, "---   reload_config\n");
02781 
02782    cfg = ast_config_load((char*)config, config_flags);
02783 
02784    /* We *must* have a config file otherwise stop immediately */
02785    if (!cfg) {
02786       ast_log(LOG_NOTICE, "Unable to load config %s, OOH323 disabled\n", config);
02787       return 1;
02788    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
02789       return RESULT_SUCCESS;
02790 
02791    if (reload) {
02792       delete_users();
02793       delete_peers();
02794       if (gH323Debug) {
02795          ast_verb(0, "  reload_config - Freeing up alias list\n");
02796       }
02797       cur = gAliasList;
02798       while (cur) {
02799          prev = cur;
02800          cur = cur->next;
02801          ast_free(prev->value);
02802          ast_free(prev);
02803       }
02804       gAliasList = NULL;
02805       ooH323EpClearAllAliases();
02806    }
02807 
02808    /* Inintialize everything to default */
02809    strcpy(gLogFile, DEFAULT_LOGFILE);
02810    gPort = 1720;
02811    gIP[0] = '\0';
02812    strcpy(gCallerID, DEFAULT_H323ID);
02813    ast_format_cap_remove_by_type(gCap, AST_MEDIA_TYPE_UNKNOWN);
02814    ast_format_cap_append(gCap, ast_format_ulaw, 0);
02815    gDTMFMode = H323_DTMF_RFC2833;
02816    gDTMFCodec = 101;
02817    gFAXdetect = FAXDETECT_CNG;
02818    gT38Support = T38_FAXGW;
02819    gTRCLVL = OOTRCLVLERR;
02820    gRasGkMode = RasNoGatekeeper;
02821    gGatekeeper[0] = '\0';
02822    gRTPTimeout = 60;
02823    gNat = FALSE;
02824    gRTDRInterval = 0;
02825    gRTDRCount = 0;
02826    strcpy(gAccountcode, DEFAULT_H323ACCNT);
02827    gFastStart = 1;
02828    gTunneling = 1;
02829    gTOS = 0;
02830    strcpy(gContext, DEFAULT_CONTEXT);
02831    gAliasList = NULL;
02832    gMediaWaitForConnect = 0;
02833    ooconfig.mTCPPortStart = 12030;
02834    ooconfig.mTCPPortEnd = 12230;
02835    memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
02836 
02837    v = ast_variable_browse(cfg, "general");
02838    while (v) {
02839 
02840       if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
02841          v = v->next;
02842          continue;
02843       }
02844    
02845       if (!strcasecmp(v->name, "port")) {
02846          gPort = (int)strtol(v->value, NULL, 10);
02847       } else if (!strcasecmp(v->name, "bindaddr")) {
02848          ast_copy_string(gIP, v->value, sizeof(gIP));
02849          if (ast_parse_arg(v->value, PARSE_ADDR, &bindaddr)) {
02850             ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
02851             ast_config_destroy(cfg);
02852             return 1;
02853          }
02854          if (ast_sockaddr_is_ipv6(&bindaddr)) {
02855             v6mode = 1;
02856          }
02857       } else if (!strcasecmp(v->name, "h225portrange")) {
02858          char* endlimit = 0;
02859                char temp[512];
02860          ast_copy_string(temp, v->value, sizeof(temp));
02861          endlimit = strchr(temp, ',');
02862          if (endlimit) {
02863             *endlimit = '\0';
02864             endlimit++;
02865             ooconfig.mTCPPortStart = atoi(temp);
02866             ooconfig.mTCPPortEnd = atoi(endlimit);
02867 
02868          } else {
02869             ast_log(LOG_ERROR, "h225portrange: Invalid format, separate port range with \",\"\n");
02870          }
02871       } else if (!strcasecmp(v->name, "gateway")) {
02872          gIsGateway = ast_true(v->value);
02873             } else if (!strcasecmp(v->name, "faststart")) {
02874          gFastStart = ast_true(v->value);
02875          if (gFastStart)
02876             ooH323EpEnableFastStart();
02877          else
02878             ooH323EpDisableFastStart();
02879       } else if (!strcasecmp(v->name, "mediawaitforconnect")) {
02880          gMediaWaitForConnect = ast_true(v->value);
02881          if (gMediaWaitForConnect)
02882             ooH323EpEnableMediaWaitForConnect();
02883          else 
02884             ooH323EpDisableMediaWaitForConnect();
02885       } else if (!strcasecmp(v->name, "h245tunneling")) {
02886          gTunneling = ast_true(v->value);
02887          if (gTunneling)
02888             ooH323EpEnableH245Tunneling();
02889          else
02890             ooH323EpDisableH245Tunneling();
02891       } else if (!strcasecmp(v->name, "directrtp") || !strcasecmp(v->name, "directmedia")) {
02892          gDirectRTP = ast_true(v->value);
02893          gEarlyDirect = ast_true(v->value);
02894       } else if (!strcasecmp(v->name, "earlydirect") || !strcasecmp(v->name, "directrtpsetup")) {
02895          gEarlyDirect = ast_true(v->value);
02896       } else if (!strcasecmp(v->name, "g729onlyA")) {
02897          g729onlyA = ast_true(v->value);
02898       } else if (!strcasecmp(v->name, "roundtrip")) {
02899          sscanf(v->value, "%d,%d", &gRTDRCount, &gRTDRInterval);
02900             } else if (!strcasecmp(v->name, "trybemaster")) {
02901          gBeMaster = ast_true(v->value);
02902          if (gBeMaster)
02903             ooH323EpTryBeMaster(1);
02904          else