Skip to content
Snippets Groups Projects
chan_sip.c 1.01 MiB
Newer Older
  • Learn to ignore specific revisions
  •  * Asterisk -- An open source telephony toolkit.
    
    Mark Spencer's avatar
    Mark Spencer committed
     *
    
     * Copyright (C) 1999 - 2006, Digium, Inc.
    
    Mark Spencer's avatar
    Mark Spencer committed
     *
    
     * Mark Spencer <markster@digium.com>
    
    Mark Spencer's avatar
    Mark Spencer committed
     *
    
     * See http://www.asterisk.org for more information about
     * the Asterisk project. Please do not directly contact
     * any of the maintainers of this project for assistance;
     * the project provides a web site, mailing lists and IRC
     * channels for your use.
     *
    
    Mark Spencer's avatar
    Mark Spencer committed
     * This program is free software, distributed under the terms of
    
     * the GNU General Public License Version 2. See the LICENSE file
     * at the top of the source tree.
     */
    
    
    /*!
     * \file
     * \brief Implementation of Session Initiation Protocol
    
     *
     * \author Mark Spencer <markster@digium.com>
     *
     * See Also:
     * \arg \ref AstCREDITS
     *
    
    Olle Johansson's avatar
    Olle Johansson committed
     * Implementation of RFC 3261 - without S/MIME, and experimental TCP and TLS support
    
     * Configuration file \link Config_sip sip.conf \endlink
    
    Olle Johansson's avatar
    Olle Johansson committed
     * ********** IMPORTANT *
     * \note TCP/TLS support is EXPERIMENTAL and WILL CHANGE. This applies to configuration
     *	settings, dialplan commands and dialplans apps/functions
    
     * ******** General TODO:s
    
     * \todo Better support of forking
    
     * \todo VIA branch tag transaction checking
     * \todo Transaction support
    
     * ******** Wishlist: Improvements
     * - Support of SIP domains for devices, so that we match on username@domain in the From: header
     * - Connect registrations with a specific device on the incoming call. It's not done
    
    Russell Bryant's avatar
    Russell Bryant committed
     *   automatically in Asterisk
    
    Olle Johansson's avatar
    Olle Johansson committed
     * \par Overview of the handling of SIP sessions
     * The SIP channel handles several types of SIP sessions, or dialogs,
     * not all of them being "telephone calls".
     * - Incoming calls that will be sent to the PBX core
     * - Outgoing calls, generated by the PBX
     * - SIP subscriptions and notifications of states and voicemail messages
     * - SIP registrations, both inbound and outbound
     * - SIP peer management (peerpoke, OPTIONS)
     * - SIP text messages
     *
     * In the SIP channel, there's a list of active SIP dialogs, which includes
     * all of these when they are active. "sip show channels" in the CLI will
     * show most of these, excluding subscriptions which are shown by
     * "sip show subscriptions"
     *
     * \par incoming packets
     * Incoming packets are received in the monitoring thread, then handled by
    
     * sipsock_read() for udp only. In tcp, packets are read by the tcp_helper thread.
     * sipsock_read() function parses the packet and matches an existing
    
    Olle Johansson's avatar
    Olle Johansson committed
     * dialog or starts a new SIP dialog.
    
     * sipsock_read sends the packet to handle_incoming(), that parses a bit more.
     * If it is a response to an outbound request, the packet is sent to handle_response().
     * If it is a request, handle_incoming() sends it to one of a list of functions
    
    Olle Johansson's avatar
    Olle Johansson committed
     * depending on the request type - INVITE, OPTIONS, REFER, BYE, CANCEL etc
    
     * sipsock_read locks the ast_channel if it exists (an active call) and
     * unlocks it after we have processed the SIP message.
    
    Olle Johansson's avatar
    Olle Johansson committed
     *
     * A new INVITE is sent to handle_request_invite(), that will end up
     * starting a new channel in the PBX, the new channel after that executing
     * in a separate channel thread. This is an incoming "call".
     * When the call is answered, either by a bridged channel or the PBX itself
     * the sip_answer() function is called.
     *
     * The actual media - Video or Audio - is mostly handled by the RTP subsystem
    
    Olle Johansson's avatar
    Olle Johansson committed
     * \par Outbound calls
     * Outbound calls are set up by the PBX through the sip_request_call()
     * function. After that, they are activated by sip_call().
    
    Olle Johansson's avatar
    Olle Johansson committed
     * \par Hanging up
     * The PBX issues a hangup on both incoming and outgoing calls through
     * the sip_hangup() function
    
     * \page sip_tcp_tls SIP TCP and TLS support
    
     * \par tcpfixes TCP implementation changes needed
     * \todo Fix TCP/TLS handling in dialplan, SRV records, transfers and much more
     * \todo Save TCP/TLS sessions in registry
     *	If someone registers a SIPS uri, this forces us to set up a TLS connection back.
     * \todo Add TCP/TLS information to function SIPPEER and SIPCHANINFO
     * \todo If tcpenable=yes, we must open a TCP socket on the same address as the IP for UDP.
    
     * 	The tcpbindaddr config option should only be used to open ADDITIONAL ports
     * 	So we should propably go back to
    
     *		bindaddr= the default address to bind to. If tcpenable=yes, then bind this to both udp and TCP
     *				if tlsenable=yes, open TLS port (provided we also have cert)
     *		tcpbindaddr = extra address for additional TCP connections
     *		tlsbindaddr = extra address for additional TCP/TLS connections
     *		udpbindaddr = extra address for additional UDP connections
     *			These three options should take multiple IP/port pairs
     *	Note: Since opening additional listen sockets is a *new* feature we do not have today
     *		the XXXbindaddr options needs to be disabled until we have support for it
    
     * \todo re-evaluate the transport= setting in sip.conf. This is right now not well
     * 	thought of. If a device in sip.conf contacts us via TCP, we should not switch transport,
     *	even if udp is the configured first transport.
    
     * \todo Be prepared for one outbound and another incoming socket per pvt. This applies
     *       specially to communication with other peers (proxies).
     * \todo We need to test TCP sessions with SIP proxies and in regards
     *       to the SIP outbound specs.
    
     * \todo ;transport=tls was deprecated in RFC3261 and should not be used at all. See section 26.2.2.
    
     *
     * \todo If the message is smaller than the given Content-length, the request should get a 400 Bad request
     *       message. If it's a response, it should be dropped. (RFC 3261, Section 18.3)
     * \todo Since we have had multidomain support in Asterisk for quite a while, we need to support
     *       multiple domains in our TLS implementation, meaning one socket and one cert per domain
     * \todo Selection of transport for a request needs to be done after we've parsed all route headers,
     *	 also considering outbound proxy options.
     *		First request: Outboundproxy, routes, (reg contact or URI. If URI doesn't have port:  DNS naptr, srv, AAA)
     *		Intermediate requests: Outboundproxy(only when forced), routes, contact/uri
     *	DNS naptr support is crucial. A SIP uri might lead to a TLS connection.
     *	Also note that due to outbound proxy settings, a SIPS uri might have to be sent on UDP (not to recommend though)
     * \todo Default transports are set to UDP, which cause the wrong behaviour when contacting remote
     *	devices directly from the dialplan. UDP is only a fallback if no other method works,
     *	in order to be compatible with RFC2543 (SIP/1.0) devices. For transactions that exceed the
    
     *	MTU (like INIVTE with video, audio and RTT)  TCP should be preferred.
    
     *
     *	When dialling unconfigured peers (with no port number)  or devices in external domains
     *	NAPTR records MUST be consulted to find configured transport. If they are not found,
     *	SRV records for both TCP and UDP should be checked. If there's a record for TCP, use that.
     *	If there's no record for TCP, then use UDP as a last resort. If there's no SRV records,
     *	\note this only applies if there's no outbound proxy configured for the session. If an outbound
     *	proxy is configured, these procedures might apply for locating the proxy and determining
     *	the transport to use for communication with the proxy.
     * \par Other bugs to fix ----
     * __set_address_from_contact(const char *fullcontact, struct sockaddr_in *sin, int tcp)
     *	- sets TLS port as default for all TCP connections, unless other port is given in contact.
     * parse_register_contact(struct sip_pvt *pvt, struct sip_peer *peer, struct sip_request *req)
    
     *	- assumes that the contact the UA registers is using the same transport as the REGISTER request, which is
    
     *	  a bad guess.
     *      - Does not save any information about TCP/TLS connected devices, which is a severe BUG, as discussed on the mailing list.
     * get_destination(struct sip_pvt *p, struct sip_request *oreq)
     *	- Doesn't store the information that we got an incoming SIPS request in the channel, so that
     *	  we can require a secure signalling path OUT of Asterisk (on SIP or IAX2). Possibly, the call should
     *	  fail on in-secure signalling paths if there's no override in our configuration. At least, provide a
     *	  channel variable in the dialplan.
     * get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoing_req)
     *	- As above, if we have a SIPS: uri in the refer-to header
     * 	- Does not check transport in refer_to uri.
     */
    
    
    	<use>res_crypto</use>
    
    	<depend>chan_local</depend>
    
    /*!  \page sip_session_timers SIP Session Timers in Asterisk Chan_sip
    
    	The SIP Session-Timers is an extension of the SIP protocol that allows end-points and proxies to
    	refresh a session periodically. The sessions are kept alive by sending a RE-INVITE or UPDATE
    	request at a negotiated interval. If a session refresh fails then all the entities that support Session-
    	Timers clear their internal session state. In addition, UAs generate a BYE request in order to clear
    	the state in the proxies and the remote UA (this is done for the benefit of SIP entities in the path
    	that do not support Session-Timers).
    
    	The Session-Timers can be configured on a system-wide, per-user, or per-peer basis. The peruser/
    	per-peer settings override the global settings. The following new parameters have been
    	added to the sip.conf file.
    		session-timers=["accept", "originate", "refuse"]
    		session-expires=[integer]
    		session-minse=[integer]
    		session-refresher=["uas", "uac"]
    
    	The session-timers parameter in sip.conf defines the mode of operation of SIP session-timers feature in
    	Asterisk. The Asterisk can be configured in one of the following three modes:
    
    	1. Accept :: In the "accept" mode, the Asterisk server honors session-timers requests
    		made by remote end-points. A remote end-point can request Asterisk to engage
    		session-timers by either sending it an INVITE request with a "Supported: timer"
    		header in it or by responding to Asterisk's INVITE with a 200 OK that contains
    
    		Session-Expires: header in it. In this mode, the Asterisk server does not
    
    		request session-timers from remote end-points. This is the default mode.
    
    	2. Originate :: In the "originate" mode, the Asterisk server requests the remote
    
    		end-points to activate session-timers in addition to honoring such requests
    		made by the remote end-pints. In order to get as much protection as possible
    		against hanging SIP channels due to network or end-point failures, Asterisk
    		resends periodic re-INVITEs even if a remote end-point does not support
    		the session-timers feature.
    	3. Refuse :: In the "refuse" mode, Asterisk acts as if it does not support session-
    		timers for inbound or outbound requests. If a remote end-point requests
    		session-timers in a dialog, then Asterisk ignores that request unless it's
    
    		noted as a requirement (Require: header), in which case the INVITE is
    
    #include "asterisk.h"
    
    ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
    
    
    #include <signal.h>
    #include <sys/signal.h>
    #include <regex.h>
    
    #include <inttypes.h>
    
    #include "asterisk/network.h"
    
    #include "asterisk/paths.h"	/* need ast_config_AST_SYSTEM_NAME */
    
    /*
       Uncomment the define below,  if you are having refcount related memory leaks.
       With this uncommented, this module will generate a file, /tmp/refs, which contains
       a history of the ao2_ref() calls. To be useful, all calls to ao2_* functions should
       be modified to ao2_t_* calls, and include a tag describing what is happening with
       enough detail, to make pairing up a reference count increment with its corresponding decrement.
       The refcounter program in utils/ can be invaluable in highlighting objects that are not
       balanced, along with the complete history for that object.
       In normal operation, the macros defined will throw away the tags, so they do not
       affect the speed of the program at all. They can be considered to be documentation.
    */
    /* #define  REF_DEBUG 1 */
    
    #include "asterisk/lock.h"
    #include "asterisk/config.h"
    #include "asterisk/module.h"
    #include "asterisk/pbx.h"
    #include "asterisk/sched.h"
    #include "asterisk/io.h"
    
    #include "asterisk/rtp_engine.h"
    
    #include "asterisk/acl.h"
    #include "asterisk/manager.h"
    #include "asterisk/callerid.h"
    #include "asterisk/cli.h"
    #include "asterisk/musiconhold.h"
    #include "asterisk/dsp.h"
    #include "asterisk/features.h"
    #include "asterisk/srv.h"
    #include "asterisk/astdb.h"
    #include "asterisk/causes.h"
    #include "asterisk/utils.h"
    #include "asterisk/file.h"
    
    #include "asterisk/monitor.h"
    
    Mark Michelson's avatar
    Mark Michelson committed
    #include "asterisk/netsock2.h"
    
    #include "asterisk/threadstorage.h"
    
    #include "asterisk/translate.h"
    
    #include "asterisk/event.h"
    
    #include "asterisk/cel.h"
    
    #include "asterisk/aoc.h"
    
    David Vossel's avatar
    David Vossel committed
    #include "sip/include/sip.h"
    
    David Vossel's avatar
    David Vossel committed
    #include "sip/include/config_parser.h"
    #include "sip/include/reqresp_parser.h"
    #include "sip/include/sip_utils.h"
    
    #include "sip/include/srtp.h"
    #include "sip/include/sdp_crypto.h"
    
    #include "asterisk/ccss.h"
    #include "asterisk/xml.h"
    
    #include "sip/include/dialog.h"
    #include "sip/include/dialplan_functions.h"
    
    /*** DOCUMENTATION
    	<application name="SIPDtmfMode" language="en_US">
    		<synopsis>
    			Change the dtmfmode for a SIP call.
    		</synopsis>
    		<syntax>
    			<parameter name="mode" required="true">
    				<enumlist>
    					<enum name="inband" />
    					<enum name="info" />
    					<enum name="rfc2833" />
    				</enumlist>
    			</parameter>
    		</syntax>
    		<description>
    			<para>Changes the dtmfmode for a SIP call.</para>
    		</description>
    	</application>
    	<application name="SIPAddHeader" language="en_US">
    		<synopsis>
    			Add a SIP header to the outbound call.
    		</synopsis>
    		<syntax argsep=":">
    			<parameter name="Header" required="true" />
    			<parameter name="Content" required="true" />
    		</syntax>
    		<description>
    			<para>Adds a header to a SIP call placed with DIAL.</para>
    			<para>Remember to use the X-header if you are adding non-standard SIP
    			headers, like <literal>X-Asterisk-Accountcode:</literal>. Use this with care.
    			Adding the wrong headers may jeopardize the SIP dialog.</para>
    			<para>Always returns <literal>0</literal>.</para>
    		</description>
    	</application>
    
    	<application name="SIPRemoveHeader" language="en_US">
    		<synopsis>
    			Remove SIP headers previously added with SIPAddHeader
    		</synopsis>
    		<syntax>
    			<parameter name="Header" required="false" />
    		</syntax>
    		<description>
    
    			<para>SIPRemoveHeader() allows you to remove headers which were previously
    			added with SIPAddHeader(). If no parameter is supplied, all previously added
    			headers will be removed. If a parameter is supplied, only the matching headers
    
    			will be removed.</para>
    			<para>For example you have added these 2 headers:</para>
    			<para>SIPAddHeader(P-Asserted-Identity: sip:foo@bar);</para>
    			<para>SIPAddHeader(P-Preferred-Identity: sip:bar@foo);</para>
    			<para></para>
    			<para>// remove all headers</para>
    			<para>SIPRemoveHeader();</para>
    			<para>// remove all P- headers</para>
    			<para>SIPRemoveHeader(P-);</para>
    			<para>// remove only the PAI header (note the : at the end)</para>
    			<para>SIPRemoveHeader(P-Asserted-Identity:);</para>
    			<para></para>
    			<para>Always returns <literal>0</literal>.</para>
    		</description>
    	</application>
    
    	<function name="SIP_HEADER" language="en_US">
    		<synopsis>
    			Gets the specified SIP header.
    		</synopsis>
    		<syntax>
    			<parameter name="name" required="true" />
    			<parameter name="number">
    				<para>If not specified, defaults to <literal>1</literal>.</para>
    			</parameter>
    		</syntax>
    		<description>
    			<para>Since there are several headers (such as Via) which can occur multiple
    			times, SIP_HEADER takes an optional second argument to specify which header with
    			that name to retrieve. Headers start at offset <literal>1</literal>.</para>
    		</description>
    	</function>
    	<function name="SIPPEER" language="en_US">
    		<synopsis>
    			Gets SIP peer information.
    		</synopsis>
    		<syntax>
    			<parameter name="peername" required="true" />
    			<parameter name="item">
    				<enumlist>
    					<enum name="ip">
    						<para>(default) The ip address.</para>
    					</enum>
    					<enum name="port">
    						<para>The port number.</para>
    					</enum>
    					<enum name="mailbox">
    						<para>The configured mailbox.</para>
    					</enum>
    					<enum name="context">
    						<para>The configured context.</para>
    					</enum>
    					<enum name="expire">
    						<para>The epoch time of the next expire.</para>
    					</enum>
    					<enum name="dynamic">
    						<para>Is it dynamic? (yes/no).</para>
    					</enum>
    					<enum name="callerid_name">
    						<para>The configured Caller ID name.</para>
    					</enum>
    					<enum name="callerid_num">
    						<para>The configured Caller ID number.</para>
    					</enum>
    					<enum name="callgroup">
    						<para>The configured Callgroup.</para>
    					</enum>
    					<enum name="pickupgroup">
    						<para>The configured Pickupgroup.</para>
    					</enum>
    					<enum name="codecs">
    						<para>The configured codecs.</para>
    					</enum>
    					<enum name="status">
    						<para>Status (if qualify=yes).</para>
    					</enum>
    					<enum name="regexten">
    						<para>Registration extension.</para>
    					</enum>
    					<enum name="limit">
    						<para>Call limit (call-limit).</para>
    					</enum>
    					<enum name="busylevel">
    						<para>Configured call level for signalling busy.</para>
    					</enum>
    					<enum name="curcalls">
    						<para>Current amount of calls. Only available if call-limit is set.</para>
    					</enum>
    					<enum name="language">
    						<para>Default language for peer.</para>
    					</enum>
    					<enum name="accountcode">
    						<para>Account code for this peer.</para>
    					</enum>
    					<enum name="useragent">
    						<para>Current user agent id for peer.</para>
    					</enum>
    
    					<enum name="maxforwards">
    						<para>The value used for SIP loop prevention in outbound requests</para>
    					</enum>
    
    					<enum name="chanvar[name]">
    						<para>A channel variable configured with setvar for this peer.</para>
    					</enum>
    					<enum name="codec[x]">
    						<para>Preferred codec index number <replaceable>x</replaceable> (beginning with zero).</para>
    					</enum>
    				</enumlist>
    			</parameter>
    		</syntax>
    
    		<description></description>
    
    	</function>
    	<function name="SIPCHANINFO" language="en_US">
    		<synopsis>
    			Gets the specified SIP parameter from the current channel.
    		</synopsis>
    		<syntax>
    			<parameter name="item" required="true">
    				<enumlist>
    					<enum name="peerip">
    						<para>The IP address of the peer.</para>
    					</enum>
    					<enum name="recvip">
    						<para>The source IP address of the peer.</para>
    					</enum>
    					<enum name="from">
    						<para>The URI from the <literal>From:</literal> header.</para>
    					</enum>
    					<enum name="uri">
    						<para>The URI from the <literal>Contact:</literal> header.</para>
    					</enum>
    					<enum name="useragent">
    						<para>The useragent.</para>
    					</enum>
    					<enum name="peername">
    						<para>The name of the peer.</para>
    					</enum>
    					<enum name="t38passthrough">
    						<para><literal>1</literal> if T38 is offered or enabled in this channel,
    						otherwise <literal>0</literal>.</para>
    					</enum>
    				</enumlist>
    			</parameter>
    		</syntax>
    
    		<description></description>
    
    	</function>
    	<function name="CHECKSIPDOMAIN" language="en_US">
    		<synopsis>
    			Checks if domain is a local domain.
    		</synopsis>
    		<syntax>
    			<parameter name="domain" required="true" />
    		</syntax>
    		<description>
    			<para>This function checks if the <replaceable>domain</replaceable> in the argument is configured
    			as a local SIP domain that this Asterisk server is configured to handle.
    			Returns the domain name if it is locally handled, otherwise an empty string.
    			Check the <literal>domain=</literal> configuration in <filename>sip.conf</filename>.</para>
    		</description>
    	</function>
    
    	<manager name="SIPpeers" language="en_US">
    		<synopsis>
    			List SIP peers (text format).
    		</synopsis>
    		<syntax>
    			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
    		</syntax>
    		<description>
    			<para>Lists SIP peers in text format with details on current status.
    			Peerlist will follow as separate events, followed by a final event called
    			PeerlistComplete.</para>
    		</description>
    	</manager>
    	<manager name="SIPshowpeer" language="en_US">
    		<synopsis>
    			show SIP peer (text format).
    		</synopsis>
    		<syntax>
    			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
    			<parameter name="Peer" required="true">
    				<para>The peer name you want to check.</para>
    			</parameter>
    		</syntax>
    		<description>
    			<para>Show one SIP peer with details on current status.</para>
    		</description>
    	</manager>
    	<manager name="SIPqualifypeer" language="en_US">
    		<synopsis>
    			Qualify SIP peers.
    		</synopsis>
    		<syntax>
    			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
    			<parameter name="Peer" required="true">
    				<para>The peer name you want to qualify.</para>
    			</parameter>
    		</syntax>
    		<description>
    			<para>Qualify a SIP peer.</para>
    		</description>
    	</manager>
    	<manager name="SIPshowregistry" language="en_US">
    		<synopsis>
    			Show SIP registrations (text format).
    		</synopsis>
    		<syntax>
    			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
    		</syntax>
    		<description>
    			<para>Lists all registration requests and status. Registrations will follow as separate
    			events. followed by a final event called RegistrationsComplete.</para>
    		</description>
    	</manager>
    	<manager name="SIPnotify" language="en_US">
    		<synopsis>
    			Send a SIP notify.
    		</synopsis>
    		<syntax>
    			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
    			<parameter name="Channel" required="true">
    				<para>Peer to receive the notify.</para>
    			</parameter>
    			<parameter name="Variable" required="true">
    				<para>At least one variable pair must be specified.
    				<replaceable>name</replaceable>=<replaceable>value</replaceable></para>
    			</parameter>
    		</syntax>
    		<description>
    			<para>Sends a SIP Notify event.</para>
    			<para>All parameters for this event must be specified in the body of this request
    			via multiple Variable: name=value sequences.</para>
    		</description>
    	</manager>
    
    static int min_expiry = DEFAULT_MIN_EXPIRY;        /*!< Minimum accepted registration time */
    static int max_expiry = DEFAULT_MAX_EXPIRY;        /*!< Maximum accepted registration time */
    
    static int default_expiry = DEFAULT_DEFAULT_EXPIRY;
    
    static int mwi_expiry = DEFAULT_MWI_EXPIRY;
    
    static int unauth_sessions = 0;
    static int authlimit = DEFAULT_AUTHLIMIT;
    static int authtimeout = DEFAULT_AUTHTIMEOUT;
    
    
    /*! \brief Global jitterbuffer configuration - by default, jb is disabled */
    
    static struct ast_jb_conf default_jbconf =
    {
    
    	.flags = 0,
    
    	.impl = "",
    	.target_extra = -1,
    
    David Vossel's avatar
    David Vossel committed
    static struct ast_jb_conf global_jbconf;                /*!< Global jitterbuffer configuration */
    
    David Vossel's avatar
    David Vossel committed
    static const char config[] = "sip.conf";                /*!< Main configuration file */
    static const char notify_config[] = "sip_notify.conf";  /*!< Configuration file for sending Notify with CLI commands to reconfigure or reboot phones */
    
    /*! \brief Readable descriptions of device states.
    
    David Vossel's avatar
    David Vossel committed
     *  \note Should be aligned to above table as index */
    
    static const struct invstate2stringtable {
    	const enum invitestates state;
    
    	const char *desc;
    
    } invitestate2string[] = {
    	{INV_NONE,              "None"  },
    	{INV_CALLING,           "Calling (Trying)"},
    	{INV_PROCEEDING,        "Proceeding "},
    	{INV_EARLY_MEDIA,       "Early media"},
    	{INV_COMPLETED,         "Completed (done)"},
    	{INV_CONFIRMED,         "Confirmed (up)"},
    	{INV_TERMINATED,        "Done"},
    	{INV_CANCELLED,         "Cancelled"}
    };
    
    
    Olle Johansson's avatar
    Olle Johansson committed
    /*! \brief Subscription types that we support. We support
    
    David Vossel's avatar
    David Vossel committed
     * - dialoginfo updates (really device status, not dialog info as was the original intent of the standard)
     * - SIMPLE presence used for device status
     * - Voicemail notification subscriptions
     */
    
    static const struct cfsubscription_types {
    	enum subscriptiontype type;
    	const char * const event;
    	const char * const mediatype;
    	const char * const text;
    } subscription_types[] = {
    
    Olle Johansson's avatar
    Olle Johansson committed
    	{ NONE,		   "-",        "unknown",	             "unknown" },
    
    	/* RFC 4235: SIP Dialog event package */
    
    	{ DIALOG_INFO_XML, "dialog",   "application/dialog-info+xml", "dialog-info+xml" },
    	{ CPIM_PIDF_XML,   "presence", "application/cpim-pidf+xml",   "cpim-pidf+xml" },  /* RFC 3863 */
    	{ PIDF_XML,        "presence", "application/pidf+xml",        "pidf+xml" },       /* RFC 3863 */
    
    	{ XPIDF_XML,       "presence", "application/xpidf+xml",       "xpidf+xml" },       /* Pre-RFC 3863 with MS additions */
    
    	{ MWI_NOTIFICATION,	"message-summary", "application/simple-message-summary", "mwi" } /* RFC 3842: Mailbox notification */
    
    David Vossel's avatar
    David Vossel committed
    /*! \brief The core structure to setup dialogs. We parse incoming messages by using
     *  structure and then route the messages according to the type.
    
    David Vossel's avatar
    David Vossel committed
     *  \note Note that sip_methods[i].id == i must hold or the code breaks
    
    static const struct  cfsip_methods {
    
    	int need_rtp;		/*!< when this is the 'primary' use for a pvt structure, does it need RTP? */
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    	char * const text;
    
    David Vossel's avatar
    David Vossel committed
    	{ SIP_UNKNOWN,   RTP,    "-UNKNOWN-",CAN_CREATE_DIALOG },
    	{ SIP_RESPONSE,  NO_RTP, "SIP/2.0",  CAN_NOT_CREATE_DIALOG },
    	{ SIP_REGISTER,  NO_RTP, "REGISTER", CAN_CREATE_DIALOG },
    	{ SIP_OPTIONS,   NO_RTP, "OPTIONS",  CAN_CREATE_DIALOG },
    	{ SIP_NOTIFY,    NO_RTP, "NOTIFY",   CAN_CREATE_DIALOG },
    	{ SIP_INVITE,    RTP,    "INVITE",   CAN_CREATE_DIALOG },
    	{ SIP_ACK,       NO_RTP, "ACK",      CAN_NOT_CREATE_DIALOG },
    	{ SIP_PRACK,     NO_RTP, "PRACK",    CAN_NOT_CREATE_DIALOG },
    	{ SIP_BYE,       NO_RTP, "BYE",      CAN_NOT_CREATE_DIALOG },
    	{ SIP_REFER,     NO_RTP, "REFER",    CAN_CREATE_DIALOG },
    	{ SIP_SUBSCRIBE, NO_RTP, "SUBSCRIBE",CAN_CREATE_DIALOG },
    	{ SIP_MESSAGE,   NO_RTP, "MESSAGE",  CAN_CREATE_DIALOG },
    	{ SIP_UPDATE,    NO_RTP, "UPDATE",   CAN_NOT_CREATE_DIALOG },
    	{ SIP_INFO,      NO_RTP, "INFO",     CAN_NOT_CREATE_DIALOG },
    	{ SIP_CANCEL,    NO_RTP, "CANCEL",   CAN_NOT_CREATE_DIALOG },
    
    	{ SIP_PUBLISH,   NO_RTP, "PUBLISH",  CAN_CREATE_DIALOG },
    
    David Vossel's avatar
    David Vossel committed
    	{ SIP_PING,      NO_RTP, "PING",     CAN_CREATE_DIALOG_UNSUPPORTED_METHOD }
    
    /*! \brief Diversion header reasons
     *
     * The core defines a bunch of constants used to define
     * redirecting reasons. This provides a translation table
     * between those and the strings which may be present in
     * a SIP Diversion header
     */
    static const struct sip_reasons {
    	enum AST_REDIRECTING_REASON code;
    	char * const text;
    } sip_reason_table[] = {
    	{ AST_REDIRECTING_REASON_UNKNOWN, "unknown" },
    	{ AST_REDIRECTING_REASON_USER_BUSY, "user-busy" },
    	{ AST_REDIRECTING_REASON_NO_ANSWER, "no-answer" },
    	{ AST_REDIRECTING_REASON_UNAVAILABLE, "unavailable" },
    	{ AST_REDIRECTING_REASON_UNCONDITIONAL, "unconditional" },
    	{ AST_REDIRECTING_REASON_TIME_OF_DAY, "time-of-day" },
    	{ AST_REDIRECTING_REASON_DO_NOT_DISTURB, "do-not-disturb" },
    	{ AST_REDIRECTING_REASON_DEFLECTION, "deflection" },
    	{ AST_REDIRECTING_REASON_FOLLOW_ME, "follow-me" },
    	{ AST_REDIRECTING_REASON_OUT_OF_ORDER, "out-of-service" },
    	{ AST_REDIRECTING_REASON_AWAY, "away" },
    	{ AST_REDIRECTING_REASON_CALL_FWD_DTE, "unknown"}
    };
    
    
    /*! \name DefaultSettings
    	Default setttings are used as a channel setting and as a default when
    
    David Vossel's avatar
    David Vossel committed
    static char default_language[MAX_LANGUAGE];      /*!< Default language setting for new channels */
    static char default_callerid[AST_MAX_EXTENSION]; /*!< Default caller ID for sip messages */
    static char default_mwi_from[80];                /*!< Default caller ID for MWI updates */
    static char default_fromdomain[AST_MAX_EXTENSION]; /*!< Default domain on outound messages */
    
    static int default_fromdomainport;                 /*!< Default domain port on outbound messages */
    
    David Vossel's avatar
    David Vossel committed
    static char default_notifymime[AST_MAX_EXTENSION]; /*!< Default MIME media type for MWI notify messages */
    static char default_vmexten[AST_MAX_EXTENSION];    /*!< Default From Username on MWI updates */
    static int default_qualify;                        /*!< Default Qualify= setting */
    
    static char default_mohinterpret[MAX_MUSICCLASS];  /*!< Global setting for moh class to use when put on hold */
    
    David Vossel's avatar
    David Vossel committed
    static char default_mohsuggest[MAX_MUSICCLASS];    /*!< Global setting for moh class to suggest when putting
    
    David Vossel's avatar
    David Vossel committed
    static char default_parkinglot[AST_MAX_CONTEXT];   /*!< Parkinglot */
    static char default_engine[256];                   /*!< Default RTP engine */
    static int default_maxcallbitrate;                 /*!< Maximum bitrate for call */
    static struct ast_codec_pref default_prefs;        /*!< Default codec prefs */
    static unsigned int default_transports;            /*!< Default Transports (enum sip_transport) that are acceptable */
    static unsigned int default_primary_transport;     /*!< Default primary Transport (enum sip_transport) for outbound connections to devices */
    
    Olle Johansson's avatar
    Olle Johansson committed
    static struct sip_settings sip_cfg;		/*!< SIP configuration data.
    					\note in the future we could have multiple of these (per domain, per device group etc) */
    
    /*!< use this macro when ast_uri_decode is dependent on pedantic checking to be on. */
    #define SIP_PEDANTIC_DECODE(str)	\
    	if (sip_cfg.pedanticsipchecking && !ast_strlen_zero(str)) {	\
    
    		ast_uri_decode(str, ast_uri_sip_user);	\
    
    David Vossel's avatar
    David Vossel committed
    static unsigned int chan_idx;       /*!< used in naming sip channel */
    static int global_match_auth_username;    /*!< Match auth username if available instead of From: Default off. */
    
    static int global_relaxdtmf;        /*!< Relax DTMF */
    static int global_prematuremediafilter;   /*!< Enable/disable premature frames in a call (causing 183 early media) */
    static int global_rtptimeout;       /*!< Time out call if no RTP */
    static int global_rtpholdtimeout;   /*!< Time out call if no RTP during hold */
    static int global_rtpkeepalive;     /*!< Send RTP keepalives */
    static int global_reg_timeout;      /*!< Global time between attempts for outbound registrations */
    static int global_regattempts_max;  /*!< Registration attempts before giving up */
    static int global_shrinkcallerid;   /*!< enable or disable shrinking of caller id  */
    static int global_callcounter;      /*!< Enable call counters for all devices. This is currently enabled by setting the peer
                                         *   call-limit to INT_MAX. When we remove the call-limit from the code, we can make it
                                         *   with just a boolean flag in the device structure */
    static unsigned int global_tos_sip;      /*!< IP type of service for SIP packets */
    static unsigned int global_tos_audio;    /*!< IP type of service for audio RTP packets */
    static unsigned int global_tos_video;    /*!< IP type of service for video RTP packets */
    static unsigned int global_tos_text;     /*!< IP type of service for text RTP packets */
    static unsigned int global_cos_sip;      /*!< 802.1p class of service for SIP packets */
    static unsigned int global_cos_audio;    /*!< 802.1p class of service for audio RTP packets */
    static unsigned int global_cos_video;    /*!< 802.1p class of service for video RTP packets */
    static unsigned int global_cos_text;     /*!< 802.1p class of service for text RTP packets */
    static unsigned int recordhistory;       /*!< Record SIP history. Off by default */
    static unsigned int dumphistory;         /*!< Dump history to verbose before destroying SIP dialog */
    static char global_useragent[AST_MAX_EXTENSION];    /*!< Useragent for the SIP channel */
    static char global_sdpsession[AST_MAX_EXTENSION];   /*!< SDP session name for the SIP channel */
    static char global_sdpowner[AST_MAX_EXTENSION];     /*!< SDP owner name for the SIP channel */
    static int global_authfailureevents;     /*!< Whether we send authentication failure manager events or not. Default no. */
    static int global_t1;           /*!< T1 time */
    static int global_t1min;        /*!< T1 roundtrip time minimum */
    static int global_timer_b;      /*!< Timer B - RFC 3261 Section 17.1.1.2 */
    static unsigned int global_autoframing; /*!< Turn autoframing on or off. */
    static int global_qualifyfreq;          /*!< Qualify frequency */
    static int global_qualify_gap;          /*!< Time between our group of peer pokes */
    static int global_qualify_peers;        /*!< Number of peers to poke at a given time */
    
    Olle Johansson's avatar
    Olle Johansson committed
    static enum st_mode global_st_mode;           /*!< Mode of operation for Session-Timers           */
    static enum st_refresher global_st_refresher; /*!< Session-Timer refresher                        */
    static int global_min_se;                     /*!< Lowest threshold for session refresh interval  */
    static int global_max_se;                     /*!< Highest threshold for session refresh interval */
    
    
    David Vossel's avatar
    David Vossel committed
    static int global_dynamic_exclude_static = 0; /*!< Exclude static peers from contact registrations */
    
    /*!
     * We use libxml2 in order to parse XML that may appear in the body of a SIP message. Currently,
     * the only usage is for parsing PIDF bodies of incoming PUBLISH requests in the call-completion
     * event package. This variable is set at module load time and may be checked at runtime to determine
     * if XML parsing support was found.
     */
    static int can_parse_xml;
    
    
    /*! \name Object counters @{
    
    David Vossel's avatar
    David Vossel committed
     *  \bug These counters are not handled in a thread-safe way ast_atomic_fetchadd_int()
     *  should be used to modify these values. */
    static int speerobjs = 0;     /*!< Static peers */
    static int rpeerobjs = 0;     /*!< Realtime peers */
    static int apeerobjs = 0;     /*!< Autocreated peer objects */
    static int regobjs = 0;       /*!< Registry objects */
    
    static struct ast_flags global_flags[3] = {{0}};  /*!< global SIP_ flags */
    
    David Vossel's avatar
    David Vossel committed
    static int global_t38_maxdatagram;                /*!< global T.38 FaxMaxDatagram override */
    
    static struct ast_event_sub *network_change_event_subscription; /*!< subscription id for network change events */
    static int network_change_event_sched_id = -1;
    
    
    David Vossel's avatar
    David Vossel committed
    static char used_context[AST_MAX_CONTEXT];        /*!< name of automatically created context for unloading */
    
    AST_MUTEX_DEFINE_STATIC(netlock);
    
    
    /*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
    
    Mark Spencer's avatar
    Mark Spencer committed
       when it's doing something critical. */
    
    AST_MUTEX_DEFINE_STATIC(monlock);
    
    AST_MUTEX_DEFINE_STATIC(sip_reload_lock);
    
    
    /*! \brief This is the thread for the monitor which checks for input on the channels
    
    Mark Spencer's avatar
    Mark Spencer committed
       which are not currently in use.  */
    
    static pthread_t monitor_thread = AST_PTHREADT_NULL;
    
    static int sip_reloading = FALSE;                       /*!< Flag for avoiding multiple reloads at the same time */
    static enum channelreloadreason sip_reloadreason;       /*!< Reason for last reload/load of configuration */
    
    struct ast_sched_context *sched;     /*!< The scheduling context */
    
    static struct io_context *io;           /*!< The IO context */
    
    static int *sipsock_read_id;            /*!< ID of IO entry for sipsock FD */
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct sip_pkt;
    
    David Vossel's avatar
    David Vossel committed
    static AST_LIST_HEAD_STATIC(domain_list, domain);    /*!< The SIP domain list */
    
    AST_LIST_HEAD_NOLOCK(sip_history_head, sip_history); /*!< history list, entry in sip_pvt */
    
    
    static enum sip_debug_e sipdebug;
    
    /*! \brief extra debugging for 'text' related events.
    
    David Vossel's avatar
    David Vossel committed
     *  At the moment this is set together with sip_debug_console.
     *  \note It should either go away or be implemented properly.
    
     */
    static int sipdebug_text;
    
    static const struct _map_x_s referstatusstrings[] = {
    
    David Vossel's avatar
    David Vossel committed
    	{ REFER_IDLE,      "<none>" },
    	{ REFER_SENT,      "Request sent" },
    	{ REFER_RECEIVED,  "Request received" },
    	{ REFER_CONFIRMED, "Confirmed" },
    	{ REFER_ACCEPTED,  "Accepted" },
    	{ REFER_RINGING,   "Target ringing" },
    	{ REFER_200OK,     "Done" },
    	{ REFER_FAILED,    "Failed" },
    	{ REFER_NOAUTH,    "Failed - auth failure" },
    	{ -1,               NULL} /* terminator */
    
    /* --- Hash tables of various objects --------*/
    #ifdef LOW_MEMORY
    
    static const int HASH_PEER_SIZE = 17;
    static const int HASH_DIALOG_SIZE = 17;
    
    static const int HASH_PEER_SIZE = 563;	/*!< Size of peer hash table, prime number preferred! */
    static const int HASH_DIALOG_SIZE = 563;
    
    static const struct {
    	enum ast_cc_service_type service;
    	const char *service_string;
    } sip_cc_service_map [] = {
    	[AST_CC_NONE] = { AST_CC_NONE, "" },
    	[AST_CC_CCBS] = { AST_CC_CCBS, "BS" },
    	[AST_CC_CCNR] = { AST_CC_CCNR, "NR" },
    	[AST_CC_CCNL] = { AST_CC_CCNL, "NL" },
    };
    
    static enum ast_cc_service_type service_string_to_service_type(const char * const service_string)
    {
    	enum ast_cc_service_type service;
    	for (service = AST_CC_CCBS; service <= AST_CC_CCNL; ++service) {
    		if (!strcasecmp(service_string, sip_cc_service_map[service].service_string)) {
    			return service;
    		}
    	}
    	return AST_CC_NONE;
    }
    
    static const struct {
    	enum sip_cc_notify_state state;
    	const char *state_string;
    } sip_cc_notify_state_map [] = {
    	[CC_QUEUED] = {CC_QUEUED, "cc-state: queued"},
    	[CC_READY] = {CC_READY, "cc-state: ready"},
    };
    
    AST_LIST_HEAD_STATIC(epa_static_data_list, epa_backend);
    
    static int sip_epa_register(const struct epa_static_data *static_data)
    {
    	struct epa_backend *backend = ast_calloc(1, sizeof(*backend));
    
    	if (!backend) {
    		return -1;
    	}
    
    	backend->static_data = static_data;
    
    	AST_LIST_LOCK(&epa_static_data_list);
    	AST_LIST_INSERT_TAIL(&epa_static_data_list, backend, next);
    	AST_LIST_UNLOCK(&epa_static_data_list);
    	return 0;
    }
    
    static void cc_handle_publish_error(struct sip_pvt *pvt, const int resp, struct sip_request *req, struct sip_epa_entry *epa_entry);
    
    static void cc_epa_destructor(void *data)
    {
    	struct sip_epa_entry *epa_entry = data;
    	struct cc_epa_entry *cc_entry = epa_entry->instance_data;
    	ast_free(cc_entry);
    }
    
    static const struct epa_static_data cc_epa_static_data  = {
    	.event = CALL_COMPLETION,
    	.name = "call-completion",
    	.handle_error = cc_handle_publish_error,
    	.destructor = cc_epa_destructor,
    };
    
    static const struct epa_static_data *find_static_data(const char * const event_package)
    {
    	const struct epa_backend *backend = NULL;
    
    	AST_LIST_LOCK(&epa_static_data_list);
    	AST_LIST_TRAVERSE(&epa_static_data_list, backend, next) {
    		if (!strcmp(backend->static_data->name, event_package)) {
    			break;
    		}
    	}
    	AST_LIST_UNLOCK(&epa_static_data_list);
    	return backend ? backend->static_data : NULL;
    }
    
    static struct sip_epa_entry *create_epa_entry (const char * const event_package, const char * const destination)
    {
    	struct sip_epa_entry *epa_entry;
    	const struct epa_static_data *static_data;
    
    	if (!(static_data = find_static_data(event_package))) {
    		return NULL;
    	}
    
    	if (!(epa_entry = ao2_t_alloc(sizeof(*epa_entry), static_data->destructor, "Allocate new EPA entry"))) {
    		return NULL;
    	}
    
    	epa_entry->static_data = static_data;
    	ast_copy_string(epa_entry->destination, destination, sizeof(epa_entry->destination));
    	return epa_entry;
    }
    
    /*!
     * Used to create new entity IDs by ESCs.
     */
    static int esc_etag_counter;
    static const int DEFAULT_PUBLISH_EXPIRES = 3600;
    
    #ifdef HAVE_LIBXML2
    static int cc_esc_publish_handler(struct sip_pvt *pvt, struct sip_request *req, struct event_state_compositor *esc, struct sip_esc_entry *esc_entry);
    
    static const struct sip_esc_publish_callbacks cc_esc_publish_callbacks = {
    	.initial_handler = cc_esc_publish_handler,
    	.modify_handler = cc_esc_publish_handler,
    };
    #endif
    
    /*!
     * \brief The Event State Compositors
     *
     * An Event State Compositor is an entity which
     * accepts PUBLISH requests and acts appropriately
     * based on these requests.
     *
     * The actual event_state_compositor structure is simply
     * an ao2_container of sip_esc_entrys. When an incoming
     * PUBLISH is received, we can match the appropriate sip_esc_entry
     * using the entity ID of the incoming PUBLISH.
     */
    static struct event_state_compositor {
    	enum subscriptiontype event;
    	const char * name;
    	const struct sip_esc_publish_callbacks *callbacks;
    	struct ao2_container *compositor;
    } event_state_compositors [] = {
    #ifdef HAVE_LIBXML2
    	{CALL_COMPLETION, "call-completion", &cc_esc_publish_callbacks},
    #endif
    };
    
    static const int ESC_MAX_BUCKETS = 37;
    
    static void esc_entry_destructor(void *obj)
    {
    	struct sip_esc_entry *esc_entry = obj;
    	if (esc_entry->sched_id > -1) {
    		AST_SCHED_DEL(sched, esc_entry->sched_id);
    	}
    }
    
    static int esc_hash_fn(const void *obj, const int flags)
    {
    	const struct sip_esc_entry *entry = obj;
    	return ast_str_hash(entry->entity_tag);
    }
    
    static int esc_cmp_fn(void *obj, void *arg, int flags)
    {
    	struct sip_esc_entry *entry1 = obj;
    	struct sip_esc_entry *entry2 = arg;
    
    	return (!strcmp(entry1->entity_tag, entry2->entity_tag)) ? (CMP_MATCH | CMP_STOP) : 0;
    }
    
    static struct event_state_compositor *get_esc(const char * const event_package) {
    	int i;
    	for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) {
    		if (!strcasecmp(event_package, event_state_compositors[i].name)) {
    			return &event_state_compositors[i];
    		}
    	}
    	return NULL;
    }
    
    static struct sip_esc_entry *get_esc_entry(const char * entity_tag, struct event_state_compositor *esc) {
    	struct sip_esc_entry *entry;
    	struct sip_esc_entry finder;
    
    	ast_copy_string(finder.entity_tag, entity_tag, sizeof(finder.entity_tag));
    
    	entry = ao2_find(esc->compositor, &finder, OBJ_POINTER);