Skip to content
Snippets Groups Projects
chan_sip.c 699 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	{ REFER_200OK,		"Done" },
    	{ REFER_FAILED,		"Failed" },
    
    	{ REFER_NOAUTH,		"Failed - auth failure" },
    	{ -1,			NULL} /* terminator */
    };
    
    Olle Johansson's avatar
    Olle Johansson committed
    /*! \brief Structure to handle SIP transfers. Dynamically allocated when needed
    	\note OEJ: Should be moved to string fields */
    
    struct sip_refer {
    	char refer_to[AST_MAX_EXTENSION];		/*!< Place to store REFER-TO extension */
    	char refer_to_domain[AST_MAX_EXTENSION];	/*!< Place to store REFER-TO domain */
    	char refer_to_urioption[AST_MAX_EXTENSION];	/*!< Place to store REFER-TO uri options */
    	char refer_to_context[AST_MAX_EXTENSION];	/*!< Place to store REFER-TO context */
    	char referred_by[AST_MAX_EXTENSION];		/*!< Place to store REFERRED-BY extension */
    	char referred_by_name[AST_MAX_EXTENSION];	/*!< Place to store REFERRED-BY extension */
    	char refer_contact[AST_MAX_EXTENSION];		/*!< Place to store Contact info from a REFER extension */
    
    	char replaces_callid[BUFSIZ];			/*!< Replace info: callid */
    	char replaces_callid_totag[BUFSIZ/2];		/*!< Replace info: to-tag */
    	char replaces_callid_fromtag[BUFSIZ/2];		/*!< Replace info: from-tag */
    
    	struct sip_pvt *refer_call;			/*!< Call we are referring. This is just a reference to a
    							 * dialog owned by someone else, so we should not destroy
    							 * it when the sip_refer object goes.
    							 */
    
    	int attendedtransfer;				/*!< Attended or blind transfer? */
    	int localtransfer;				/*!< Transfer to local domain? */
    	enum referstatus status;			/*!< REFER status */
    };
    
    /*! \brief sip_pvt: structures used for each SIP dialog, ie. a call, a registration, a subscribe.
     * Created and initialized by sip_alloc(), the descriptor goes into the list of
     * descriptors (dialoglist).
     */
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	struct sip_pvt *next;			/*!< Next dialog in chain */
    
    	ast_mutex_t pvt_lock;			/*!< Dialog private lock */
    
    	enum invitestates invitestate;		/*!< Track state of SIP_INVITEs */
    
    	int method;				/*!< SIP method that opened this dialog */
    
    	AST_DECLARE_STRING_FIELDS(
    		AST_STRING_FIELD(callid);	/*!< Global CallID */
    		AST_STRING_FIELD(randdata);	/*!< Random data */
    		AST_STRING_FIELD(accountcode);	/*!< Account code */
    		AST_STRING_FIELD(realm);	/*!< Authorization realm */
    		AST_STRING_FIELD(nonce);	/*!< Authorization nonce */
    		AST_STRING_FIELD(opaque);	/*!< Opaque nonsense */
    		AST_STRING_FIELD(qop);		/*!< Quality of Protection, since SIP wasn't complicated enough yet. */
    		AST_STRING_FIELD(domain);	/*!< Authorization domain */
    		AST_STRING_FIELD(from);		/*!< The From: header */
    		AST_STRING_FIELD(useragent);	/*!< User agent in SIP request */
    		AST_STRING_FIELD(exten);	/*!< Extension where to start */
    		AST_STRING_FIELD(context);	/*!< Context for this call */
    		AST_STRING_FIELD(subscribecontext); /*!< Subscribecontext */
    
    		AST_STRING_FIELD(subscribeuri); /*!< Subscribecontext */
    
    		AST_STRING_FIELD(fromdomain);	/*!< Domain to show in the from field */
    		AST_STRING_FIELD(fromuser);	/*!< User to show in the user field */
    		AST_STRING_FIELD(fromname);	/*!< Name to show in the user field */
    		AST_STRING_FIELD(tohost);	/*!< Host we should put in the "to" field */
    
    		AST_STRING_FIELD(todnid);	/*!< DNID of this call (overrides host) */
    
    		AST_STRING_FIELD(language);	/*!< Default language for this call */
    
    		AST_STRING_FIELD(mohinterpret);	/*!< MOH class to use when put on hold */
    		AST_STRING_FIELD(mohsuggest);	/*!< MOH class to suggest when putting a peer on hold */
    
    		AST_STRING_FIELD(rdnis);	/*!< Referring DNIS */
    
    		AST_STRING_FIELD(redircause);	/*!< Referring cause */
    
    		AST_STRING_FIELD(theirtag);	/*!< Their tag */
    		AST_STRING_FIELD(username);	/*!< [user] name */
    		AST_STRING_FIELD(peername);	/*!< [peer] name, not set if [user] */
    		AST_STRING_FIELD(authname);	/*!< Who we use for authentication */
    		AST_STRING_FIELD(uri);		/*!< Original requested URI */
    		AST_STRING_FIELD(okcontacturi);	/*!< URI from the 200 OK on INVITE */
    		AST_STRING_FIELD(peersecret);	/*!< Password */
    		AST_STRING_FIELD(peermd5secret);
    
    		AST_STRING_FIELD(cid_num);	/*!< Caller*ID number */
    		AST_STRING_FIELD(cid_name);	/*!< Caller*ID name */
    
    		AST_STRING_FIELD(via);		/*!< Via: header */
    		AST_STRING_FIELD(fullcontact);	/*!< The Contact: that the UA registers with us */
    
    			/* we only store the part in <brackets> in this field. */
    
    		AST_STRING_FIELD(our_contact);	/*!< Our contact header */
    		AST_STRING_FIELD(rpid);		/*!< Our RPID header */
    		AST_STRING_FIELD(rpid_from);	/*!< Our RPID From header */
    
    		AST_STRING_FIELD(url);		/*!< URL to be sent with next message to peer */
    
    	unsigned int ocseq;			/*!< Current outgoing seqno */
    	unsigned int icseq;			/*!< Current incoming seqno */
    	ast_group_t callgroup;			/*!< Call group */
    	ast_group_t pickupgroup;		/*!< Pickup group */
    	int lastinvite;				/*!< Last Cseq of invite */
    
    	int lastnoninvite;                      /*!< Last Cseq of non-invite */
    
    	struct ast_flags flags[2];		/*!< SIP_ flags */
    
    
    	/* boolean or small integers that don't belong in flags */
    	char do_history;			/*!< Set if we want to record history */
    
    	char alreadygone;			/*!< already destroyed by our peer */
    	char needdestroy;			/*!< need to be destroyed by the monitor thread */
    
    	char outgoing_call;			/*!< this is an outgoing call */
    	char answered_elsewhere;		/*!< This call is cancelled due to answer on another channel */
    	char novideo;				/*!< Didn't get video in invite, don't offer */
    	char notext;				/*!< Text not supported  (?) */
    
    	int timer_t1;				/*!< SIP timer T1, ms rtt */
    
    	unsigned int sipoptions;		/*!< Supported SIP options on the other end */
    	struct ast_codec_pref prefs;		/*!< codec prefs */
    
    	int capability;				/*!< Special capability (codec) */
    
    	int jointcapability;			/*!< Supported capability at both ends (codecs) */
    
    	int peercapability;			/*!< Supported peer capability */
    	int prefcodec;				/*!< Preferred codec (outbound only) */
    
    Olle Johansson's avatar
    Olle Johansson committed
    	int noncodeccapability;			/*!< DTMF RFC2833 telephony-event */
    
    	int jointnoncodeccapability;            /*!< Joint Non codec capability */
    
    Olle Johansson's avatar
    Olle Johansson committed
    	int redircodecs;			/*!< Redirect codecs */
    
    Olle Johansson's avatar
    Olle Johansson committed
    	int maxcallbitrate;			/*!< Maximum Call Bitrate for Video Calls */	
    
    	struct sip_proxy *outboundproxy;	/*!< Outbound proxy for this dialog */
    
    	struct t38properties t38;		/*!< T38 settings */
    	struct sockaddr_in udptlredirip;	/*!< Where our T.38 UDPTL should be going if not to us */
    	struct ast_udptl *udptl;		/*!< T.38 UDPTL session */
    
    	int callingpres;			/*!< Calling presentation */
    	int authtries;				/*!< Times we've tried to authenticate */
    	int expiry;				/*!< How long we take to expire */
    
    	long branch;				/*!< The branch identifier of this session */
    	char tag[11];				/*!< Our tag for this session */
    
    	int sessionid;				/*!< SDP Session ID */
    	int sessionversion;			/*!< SDP Session Version */
    	struct sockaddr_in sa;			/*!< Our peer */
    	struct sockaddr_in redirip;		/*!< Where our RTP should be going if not to us */
    	struct sockaddr_in vredirip;		/*!< Where our Video RTP should be going if not to us */
    
    	struct sockaddr_in tredirip;		/*!< Where our Text RTP should be going if not to us */
    
    	time_t lastrtprx;			/*!< Last RTP received */
    	time_t lastrtptx;			/*!< Last RTP sent */
    	int rtptimeout;				/*!< RTP timeout time */
    
    	struct sockaddr_in recv;		/*!< Received as */
    
    	struct sockaddr_in ourip;		/*!< Our IP (as seen from the outside) */
    
    	struct ast_channel *owner;		/*!< Who owns us (if we have an owner) */
    
    	struct sip_route *route;		/*!< Head of linked list of routing steps (fm Record-Route) */
    	int route_persistant;			/*!< Is this the "real" route? */
    	struct sip_auth *peerauth;		/*!< Realm authentication */
    	int noncecount;				/*!< Nonce-count */
    	char lastmsg[256];			/*!< Last Message sent/received */
    	int amaflags;				/*!< AMA Flags */
    
    	int pendinginvite;			/*!< Any pending invite ? (seqno of this) */
    
    	struct sip_request initreq;		/*!< Latest request that opened a new transaction
    							within this dialog.
    							NOT the request that opened the dialog
    
    	int initid;				/*!< Auto-congest ID if appropriate (scheduler) */
    
    	int waitid;				/*!< Wait ID for scheduler after 491 or other delays */
    
    	int autokillid;				/*!< Auto-kill ID (scheduler) */
    	enum transfermodes allowtransfer;	/*!< REFER: restriction scheme */
    	struct sip_refer *refer;		/*!< REFER: SIP transfer data structure */
    
    Olle Johansson's avatar
    Olle Johansson committed
    	enum subscriptiontype subscribed;	/*!< SUBSCRIBE: Is this dialog a subscription?  */
    	int stateid;				/*!< SUBSCRIBE: ID for devicestate subscriptions */
    	int laststate;				/*!< SUBSCRIBE: Last known extension state */
    	int dialogver;				/*!< SUBSCRIBE: Version for subscription dialog-info */
    
    Olle Johansson's avatar
    Olle Johansson committed
    	struct ast_dsp *vad;			/*!< Inband DTMF Detection dsp */
    
    	struct sip_peer *relatedpeer;		/*!< If this dialog is related to a peer, which one 
    							Used in peerpoke, mwi subscriptions */
    
    	struct sip_registry *registry;		/*!< If this is a REGISTER dialog, to which registry */
    
    	struct ast_rtp *rtp;			/*!< RTP Session */
    	struct ast_rtp *vrtp;			/*!< Video RTP session */
    
    	struct ast_rtp *trtp;			/*!< Text RTP session */
    
    	struct sip_pkt *packets;		/*!< Packets scheduled for re-transmission */
    
    	struct sip_history_head *history;	/*!< History of this SIP dialog */
    
    	size_t history_entries;			/*!< Number of entires in the history */
    
    Olle Johansson's avatar
    Olle Johansson committed
    	struct ast_variable *chanvars;		/*!< Channel variables to set for inbound call */
    
    	struct sip_invite_param *options;	/*!< Options for INVITE */
    
    	int autoframing;			/*!< The number of Asters we group in a Pyroflax
    							before strolling to the Grokyzpå
    							(A bit unsure of this, please correct if
    							you know more) */
    
    /*! Max entires in the history list for a sip_pvt */
    #define MAX_HISTORY_ENTRIES 50
    
    /*!
    
     * Here we implement the container for dialogs (sip_pvt), defining
     * generic wrapper functions to ease the transition from the current
     * implementation (a single linked list) to a different container.
     * In addition to a reference to the container, we need functions to lock/unlock
     * the container and individual items, and functions to add/remove
     * references to the individual items.
     */
    
    /*! \brief Protect the SIP dialog list (of sip_pvt's) */
    AST_MUTEX_DEFINE_STATIC(dialoglock);
    
    
    /*! \brief hide the way the list is locked/unlocked */
    static void dialoglist_lock(void)
    {
    	ast_mutex_lock(&dialoglock);
    }
    
    static void dialoglist_unlock(void)
    {
    	ast_mutex_unlock(&dialoglock);
    }
    
    #else
    /* we don't want to HIDE the information about where the lock was requested if trying to debug 
     * deadlocks!  So, just make these macros! */
    #define dialoglist_lock(x) ast_mutex_lock(&dialoglock)
    #define dialoglist_unlock(x) ast_mutex_unlock(&dialoglock)
    #endif
    
    /*!
     * when we create or delete references, make sure to use these
     * functions so we keep track of the refcounts.
     * To simplify the code, we allow a NULL to be passed to dialog_unref().
     */
    static struct sip_pvt *dialog_ref(struct sip_pvt *p)
    {
    	return p;
    }
    
    static struct sip_pvt *dialog_unref(struct sip_pvt *p)
    {
    	return NULL;
    }
    
    
    /*! \brief sip packet - raw format for outbound packets that are sent or scheduled for transmission
     * Packets are linked in a list, whose head is in the struct sip_pvt they belong to.
     * Each packet holds a reference to the parent struct sip_pvt.
     * This structure is allocated in __sip_reliable_xmit() and only for packets that
     * require retransmissions.
     */
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct sip_pkt {
    
    	struct sip_pkt *next;			/*!< Next packet in linked list */
    
    	int retrans;				/*!< Retransmission number */
    	int method;				/*!< SIP method for this packet */
    	int seqno;				/*!< Sequence number */
    
    	char is_resp;				/*!< 1 if this is a response packet (e.g. 200 OK), 0 if it is a request */
    	char is_fatal;				/*!< non-zero if there is a fatal error */
    
    	struct sip_pvt *owner;			/*!< Owner AST call */
    
    	int retransid;				/*!< Retransmission ID */
    	int timer_a;				/*!< SIP timer A, retransmission timer */
    	int timer_t1;				/*!< SIP Timer T1, estimated RTT or 500 ms */
    	int packetlen;				/*!< Length of packet */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char data[0];
    };	
    
    /*! \brief Structure for SIP user data. User's place calls to us */
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct sip_user {
    	/* Users who can access various contexts */
    
    	char secret[80];		/*!< Password */
    	char md5secret[80];		/*!< Password in md5 */
    	char context[AST_MAX_CONTEXT];	/*!< Default context for incoming calls */
    
    	char subscribecontext[AST_MAX_CONTEXT];	/* Default context for subscriptions */
    
    	char cid_num[80];		/*!< Caller ID num */
    	char cid_name[80];		/*!< Caller ID name */
    
    	char accountcode[AST_MAX_ACCOUNT_CODE];	/* Account code */
    
    	char language[MAX_LANGUAGE];	/*!< Default language for this user */
    
    	char mohinterpret[MAX_MUSICCLASS];/*!< Music on Hold class */
    	char mohsuggest[MAX_MUSICCLASS];/*!< Music on Hold class */
    
    	char useragent[256];		/*!< User agent in SIP request */
    	struct ast_codec_pref prefs;	/*!< codec prefs */
    	ast_group_t callgroup;		/*!< Call group */
    	ast_group_t pickupgroup;	/*!< Pickup Group */
    	unsigned int sipoptions;	/*!< Supported SIP options */
    
    	struct ast_flags flags[2];	/*!< SIP_ flags */
    
    
    	/* things that don't belong in flags */
    	char is_realtime;		/*!< this is a 'realtime' user */
    
    
    	int amaflags;			/*!< AMA flags for billing */
    	int callingpres;		/*!< Calling id presentation */
    	int capability;			/*!< Codec capability */
    	int inUse;			/*!< Number of calls in use */
    	int call_limit;			/*!< Limit of concurrent calls */
    
    	enum transfermodes allowtransfer;	/*! SIP Refer restriction scheme */
    
    	struct ast_ha *ha;		/*!< ACL setting */
    	struct ast_variable *chanvars;	/*!< Variables to set for channel created by user */
    
    Olle Johansson's avatar
    Olle Johansson committed
    	int maxcallbitrate;		/*!< Maximum Bitrate for a video call */
    
    /*!
     * \brief A peer's mailbox
     *
     * We could use STRINGFIELDS here, but for only two strings, it seems like
     * too much effort ...
     */
    struct sip_mailbox {
    	char *mailbox;
    	char *context;
    	/*! Associated MWI subscription */
    	struct ast_event_sub *event_sub;
    	AST_LIST_ENTRY(sip_mailbox) entry;
    };
    
    
    /*! \brief Structure for SIP peer data, we place calls to peers if registered  or fixed IP address (host) */
    
    /* XXX field 'name' must be first otherwise sip_addrcmp() will fail */
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct sip_peer {
    
    	ASTOBJ_COMPONENTS(struct sip_peer);	/*!< name, refcount, objflags,  object pointers */
    					/*!< peer->name is the unique name of this object */
    	char secret[80];		/*!< Password */
    	char md5secret[80];		/*!< Password in MD5 */
    	struct sip_auth *auth;		/*!< Realm authentication list */
    	char context[AST_MAX_CONTEXT];	/*!< Default context for incoming calls */
    	char subscribecontext[AST_MAX_CONTEXT];	/*!< Default context for subscriptions */
    	char username[80];		/*!< Temporary username until registration */ 
    	char accountcode[AST_MAX_ACCOUNT_CODE];	/*!< Account code */
    	int amaflags;			/*!< AMA Flags (for billing) */
    	char tohost[MAXHOSTNAMELEN];	/*!< If not dynamic, IP address */
    	char regexten[AST_MAX_EXTENSION]; /*!< Extension to register (if regcontext is used) */
    	char fromuser[80];		/*!< From: user when calling this peer */
    	char fromdomain[MAXHOSTNAMELEN];	/*!< From: domain when calling this peer */
    	char fullcontact[256];		/*!< Contact registered with us (not in sip.conf) */
    	char cid_num[80];		/*!< Caller ID num */
    	char cid_name[80];		/*!< Caller ID name */
    	int callingpres;		/*!< Calling id presentation */
    	int inUse;			/*!< Number of calls in use */
    
    	int inRinging;			/*!< Number of calls ringing */
    
    	int onHold;                     /*!< Peer has someone on hold */
    
    	int call_limit;			/*!< Limit of concurrent calls */
    
    	int busy_level;			/*!< Level of active channels where we signal busy */
    
    	enum transfermodes allowtransfer;	/*! SIP Refer restriction scheme */
    
    	char vmexten[AST_MAX_EXTENSION]; /*!< Dialplan extension for MWI notify message*/
    	char language[MAX_LANGUAGE];	/*!<  Default language for prompts */
    
    	char mohinterpret[MAX_MUSICCLASS];/*!<  Music on Hold class */
    	char mohsuggest[MAX_MUSICCLASS];/*!<  Music on Hold class */
    
    	char useragent[256];		/*!<  User agent in SIP request (saved from registration) */
    	struct ast_codec_pref prefs;	/*!<  codec prefs */
    
    	int lastmsgssent;
    
    	unsigned int sipoptions;	/*!<  Supported SIP options */
    
    	struct ast_flags flags[2];	/*!<  SIP_ flags */
    
    	
    	/*! Mailboxes that this peer cares about */
    	AST_LIST_HEAD_NOLOCK(, sip_mailbox) mailboxes;
    
    
    	/* things that don't belong in flags */
    	char is_realtime;		/*!< this is a 'realtime' peer */
    
    	char rt_fromcontact;		/*!< P: copy fromcontact from realtime */
    
    	char host_dynamic;		/*!< P: Dynamic Peers register with Asterisk */
    	char selfdestruct;		/*!< P: Automatic peers need to destruct themselves */
    
    	int expire;			/*!<  When to expire this peer registration */
    	int capability;			/*!<  Codec capability */
    	int rtptimeout;			/*!<  RTP timeout */
    	int rtpholdtimeout;		/*!<  RTP Hold Timeout */
    	int rtpkeepalive;		/*!<  Send RTP packets for keepalive */
    	ast_group_t callgroup;		/*!<  Call group */
    	ast_group_t pickupgroup;	/*!<  Pickup group */
    
    	struct sip_proxy *outboundproxy;	/*!< Outbound proxy for this peer */
    
    	struct ast_dnsmgr_entry *dnsmgr;/*!<  DNS refresh manager for peer */
    	struct sockaddr_in addr;	/*!<  IP address of peer */
    
    Olle Johansson's avatar
    Olle Johansson committed
    	int maxcallbitrate;		/*!< Maximum Bitrate for a video call */
    	
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Qualification */
    
    	struct sip_pvt *call;		/*!<  Call pointer */
    	int pokeexpire;			/*!<  When to expire poke (qualify= checking) */
    	int lastms;			/*!<  How long last response took (in ms), or -1 for no response */
    	int maxms;			/*!<  Max ms we will accept for the host to be up, 0 to not monitor */
    
    	int qualifyfreq;		/*!<  Qualification: How often to check for the host to be up */
    
    	struct timeval ps;		/*!<  Time for sending SIP OPTION in sip_pke_peer() */
    
    	struct sockaddr_in defaddr;	/*!<  Default IP address, used until registration */
    	struct ast_ha *ha;		/*!<  Access control list */
    	struct ast_variable *chanvars;	/*!<  Variables to set for channel created by user */
    
    	struct sip_pvt *mwipvt;		/*!<  Subscription for MWI */
    
    	int timer_t1;		/*!<  The maximum T1 value for the peer */
    	int timer_b;      /*!<  The maximum timer B (transaction timeouts) */
    
    /*! \brief Registrations with other SIP proxies
     * Created by sip_register(), the entry is linked in the 'regl' list,
     * and never deleted (other than at 'sip reload' or module unload times).
     * The entry always has a pending timeout, either waiting for an ACK to
     * the REGISTER message (in which case we have to retransmit the request),
     * or waiting for the next REGISTER message to be sent (either the initial one,
     * or once the previously completed registration one expires).
     * The registration can be in one of many states, though at the moment
     * the handling is a bit mixed.
     * Note that the entire evolution of sip_registry (transmissions,
     * incoming packets and timeouts) is driven by one single thread,
     * do_monitor(), so there is almost no synchronization issue.
     * The only exception  is the sip_pvt creation/lookup,
     * as the dialoglist is also manipulated by other threads.
     */
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct sip_registry {
    
    	ASTOBJ_COMPONENTS_FULL(struct sip_registry,1,1);
    
    	AST_DECLARE_STRING_FIELDS(
    		AST_STRING_FIELD(callid);	/*!< Global Call-ID */
    		AST_STRING_FIELD(realm);	/*!< Authorization realm */
    		AST_STRING_FIELD(nonce);	/*!< Authorization nonce */
    		AST_STRING_FIELD(opaque);	/*!< Opaque nonsense */
    		AST_STRING_FIELD(qop);		/*!< Quality of Protection, since SIP wasn't complicated enough yet. */
    		AST_STRING_FIELD(domain);	/*!< Authorization domain */
    		AST_STRING_FIELD(username);	/*!< Who we are registering as */
    		AST_STRING_FIELD(authuser);	/*!< Who we *authenticate* as */
    		AST_STRING_FIELD(hostname);	/*!< Domain or host we register to */
    		AST_STRING_FIELD(secret);	/*!< Password in clear text */	
    		AST_STRING_FIELD(md5secret);	/*!< Password in md5 */
    
    		AST_STRING_FIELD(callback);	/*!< Contact extension */
    
    	int portno;			/*!<  Optional port override */
    	int expire;			/*!< Sched ID of expiration */
    
    	int expiry;			/*!< Value to use for the Expires header */
    
    	int regattempts;		/*!< Number of attempts (since the last success) */
    	int timeout; 			/*!< sched id of sip_reg_timeout */
    	int refresh;			/*!< How often to refresh */
    
    	struct sip_pvt *call;		/*!< create a sip_pvt structure for each outbound "registration dialog" in progress */
    
    Olle Johansson's avatar
    Olle Johansson committed
    	enum sipregistrystate regstate;	/*!< Registration state (see above) */
    
    	struct timeval regtime;		/*!< Last successful registration time */
    
    	int callid_valid;		/*!< 0 means we haven't chosen callid for this registry yet. */
    	unsigned int ocseq;		/*!< Sequence number we got to for REGISTERs for this registry */
    	struct sockaddr_in us;		/*!< Who the server thinks we are */
    	int noncecount;			/*!< Nonce-count */
    
    	char lastmsg[256];		/*!< Last Message sent/received */
    
    /* --- Linked lists of various objects --------*/
    
    
    /*! \brief  The user list: Users and friends */
    
    static struct ast_user_list {
    
    	ASTOBJ_CONTAINER_COMPONENTS(struct sip_user);
    
    /*! \brief  The peer list: Peers and Friends */
    
    static struct ast_peer_list {
    
    	ASTOBJ_CONTAINER_COMPONENTS(struct sip_peer);
    
    /*! \brief  The register list: Other SIP proxies we register with and place calls to */
    
    static struct ast_register_list {
    
    	ASTOBJ_CONTAINER_COMPONENTS(struct sip_registry);
    
    /*! \brief A per-thread temporary pvt structure */
    
    AST_THREADSTORAGE_CUSTOM(ts_temp_pvt, temp_pvt_init, temp_pvt_cleanup);
    
    /*! \brief Authentication list for realm authentication 
    
     * \todo Move the sip_auth list to AST_LIST */
    static struct sip_auth *authl = NULL;
    
    /* --- Sockets and networking --------------*/
    
    
    /*! \brief Main socket for SIP communication.
     * sipsock is shared between the manager thread (which handles reload
     * requests), the io handler (sipsock_read()) and the user routines that
     * issue writes (using __sip_xmit()).
     * The socket is -1 only when opening fails (this is a permanent condition),
     * or when we are handling a reload() that changes its address (this is
     * a transient situation during which we might have a harmless race, see
     * below). Because the conditions for the race to be possible are extremely
     * rare, we don't want to pay the cost of locking on every I/O.
     * Rather, we remember that when the race may occur, communication is
     * bound to fail anyways, so we just live with this event and let
     * the protocol handle this above us.
     */
    static int sipsock  = -1;
    
    
    static struct sockaddr_in bindaddr;	/*!< The address we bind to */
    
    /*! \brief our (internal) default address/port to put in SIP/SDP messages
     *  internip is initialized picking a suitable address from one of the
     * interfaces, and the same port number we bind to. It is used as the
     * default address/port in SIP messages, and as the default address
     * (but not port) in SDP messages.
     */
    static struct sockaddr_in internip;
    
    
    /*! \brief our external IP address/port for SIP sessions.
     * externip.sin_addr is only set when we know we might be behind
     * a NAT, and this is done using a variety of (mutually exclusive)
     * ways from the config file:
     *
     * + with "externip = host[:port]" we specify the address/port explicitly.
     *   The address is looked up only once when (re)loading the config file;
     * 
     * + with "externhost = host[:port]" we do a similar thing, but the
     *   hostname is stored in externhost, and the hostname->IP mapping
     *   is refreshed every 'externrefresh' seconds;
     * 
     * + with "stunaddr = host[:port]" we run queries every externrefresh seconds
     *   to the specified server, and store the result in externip.
     *
     * Other variables (externhost, externexpire, externrefresh) are used
     * to support the above functions.
     */
    
    static struct sockaddr_in externip;		/*!< External IP address if we are behind NAT */
    
    static char externhost[MAXHOSTNAMELEN];		/*!< External host name */
    static time_t externexpire;			/*!< Expiration counter for re-resolving external host name in dynamic DNS */
    
    static struct sockaddr_in stunaddr;		/*!< stun server address */
    
    
    /*! \brief  List of local networks
     * We store "localnet" addresses from the config file into an access list,
     * marked as 'DENY', so the call to ast_apply_ha() will return
     * AST_SENSE_DENY for 'local' addresses, and AST_SENSE_ALLOW for 'non local'
     * (i.e. presumably public) addresses.
     */
    
    static struct ast_ha *localaddr;		/*!< List of local networks, on the same side of NAT as this Asterisk */
    
    static struct sockaddr_in debugaddr;
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    static struct ast_config *notify_types;		/*!< The list of manual NOTIFY types we know how to send */
    
    /*! some list management macros. */
     
    #define UNLINK(element, head, prev) do {	\
    	if (prev)				\
    		(prev)->next = (element)->next;	\
    	else					\
    		(head) = (element)->next;	\
    	} while (0)
    
    
    /*---------------------------- Forward declarations of functions in chan_sip.c */
    
    /*! \note This is added to help splitting up chan_sip.c into several files
    	in coming releases */
    
    /*--- PBX interface functions */
    static struct ast_channel *sip_request_call(const char *type, int format, void *data, int *cause);
    static int sip_devicestate(void *data);
    static int sip_sendtext(struct ast_channel *ast, const char *text);
    static int sip_call(struct ast_channel *ast, char *dest, int timeout);
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sip_sendhtml(struct ast_channel *chan, int subclass, const char *data, int datalen);
    
    static int sip_hangup(struct ast_channel *ast);
    static int sip_answer(struct ast_channel *ast);
    static struct ast_frame *sip_read(struct ast_channel *ast);
    static int sip_write(struct ast_channel *ast, struct ast_frame *frame);
    static int sip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
    static int sip_transfer(struct ast_channel *ast, const char *dest);
    static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
    
    static int sip_senddigit_begin(struct ast_channel *ast, char digit);
    
    static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
    
    /*--- Transmitting responses and requests */
    
    static int sipsock_read(int *id, int fd, short events, void *ignore);
    
    static int __sip_xmit(struct sip_pvt *p, char *data, int len);
    static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, char *data, int len, int fatal, int sipmethod);
    
    static int __transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
    
    static int retrans_pkt(const void *data);
    
    static int transmit_sip_request(struct sip_pvt *p, struct sip_request *req);
    
    static int transmit_response_using_temp(ast_string_field callid, struct sockaddr_in *sin, int useglobal_nat, const int intended_method, const struct sip_request *req, const char *msg);
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    static int transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req);
    static int transmit_response_reliable(struct sip_pvt *p, const char *msg, const struct sip_request *req);
    static int transmit_response_with_date(struct sip_pvt *p, const char *msg, const struct sip_request *req);
    static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
    static int transmit_response_with_unsupported(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *unsupported);
    static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *rand, enum xmittype reliable, const char *header, int stale);
    static int transmit_response_with_allow(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
    
    static void transmit_fake_auth_response(struct sip_pvt *p, struct sip_request *req, int reliable);
    
    static int transmit_request(struct sip_pvt *p, int sipmethod, int inc, enum xmittype reliable, int newbranch);
    
    static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, int seqno, enum xmittype reliable, int newbranch);
    static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init);
    
    static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version);
    
    static int transmit_info_with_digit(struct sip_pvt *p, const char digit, unsigned int duration);
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int transmit_info_with_vidupdate(struct sip_pvt *p);
    
    static int transmit_message_with_text(struct sip_pvt *p, const char *text);
    static int transmit_refer(struct sip_pvt *p, const char *dest);
    
    static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, char *vmexten);
    static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message, int terminate);
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    static int transmit_register(struct sip_registry *r, int sipmethod, const char *auth, const char *authheader);
    
    static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno);
    static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno);
    
    static void copy_request(struct sip_request *dst, const struct sip_request *src);
    
    static void receive_message(struct sip_pvt *p, struct sip_request *req);
    static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req);
    
    static int sip_send_mwi_to_peer(struct sip_peer *peer, const struct ast_event *event, int cache_only);
    
    
    /*--- Dialog management */
    static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin,
    				 int useglobal_nat, const int intended_method);
    
    static int __sip_autodestruct(const void *data);
    
    static void sip_scheddestroy(struct sip_pvt *p, int ms);
    static void sip_cancel_destroy(struct sip_pvt *p);
    
    static struct sip_pvt *sip_destroy(struct sip_pvt *p);
    
    static void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist);
    
    static void __sip_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod);
    
    static void __sip_pretend_ack(struct sip_pvt *p);
    
    static int __sip_semi_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod);
    
    static int auto_congest(const void *arg);
    
    static int update_call_counter(struct sip_pvt *fup, int event);
    static int hangup_sip2cause(int cause);
    static const char *hangup_cause2sip(int cause);
    static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *sin, const int intended_method);
    
    static void free_old_route(struct sip_route *route);
    static void list_route(struct sip_route *route);
    static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards);
    static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr_in *sin,
    					      struct sip_request *req, char *uri);
    static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag);
    static void check_pendings(struct sip_pvt *p);
    static void *sip_park_thread(void *stuff);
    static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno);
    static int sip_sipredirect(struct sip_pvt *p, const char *dest);
    
    
    /*--- Codec handling / SDP */
    static void try_suggested_sip_codec(struct sip_pvt *p);
    static const char* get_sdp_iterate(int* start, struct sip_request *req, const char *name);
    static const char *get_sdp(struct sip_request *req, const char *name);
    
    static int find_sdp(struct sip_request *req);
    
    static int process_sdp(struct sip_pvt *p, struct sip_request *req);
    static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
    
    			     struct ast_str **m_buf, struct ast_str **a_buf,
    
    			     int debug, int *min_packet_size);
    
    static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_rate,
    
    				struct ast_str **m_buf, struct ast_str **a_buf,
    
    static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p);
    
    static void do_setnat(struct sip_pvt *p, int natflags);
    
    static void stop_media_flows(struct sip_pvt *p);
    
    Olle Johansson's avatar
    Olle Johansson committed
    static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header, int sipmethod, char *digest, int digest_len);
    
    static int build_reply_digest(struct sip_pvt *p, int method, char *digest, int digest_len);
    
    static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *req, const char *username,
    					 const char *secret, const char *md5secret, int sipmethod,
    					 char *uri, enum xmittype reliable, int ignore);
    
    static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_request *req,
    					      int sipmethod, char *uri, enum xmittype reliable,
    					      struct sockaddr_in *sin, struct sip_peer **authpeer);
    static int check_user(struct sip_pvt *p, struct sip_request *req, int sipmethod, char *uri, enum xmittype reliable, struct sockaddr_in *sin);
    
    static int check_sip_domain(const char *domain, char *context, size_t len); /* Check if domain is one of our local domains */
    
    static int add_sip_domain(const char *domain, const enum domain_mode mode, const char *context);
    static void clear_sip_domains(void);
    
    static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, const char *configuration, int lineno);
    
    static int clear_realm_authentication(struct sip_auth *authlist);	/* Clear realm authentication list (at reload) */
    
    static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, const char *realm);
    
    
    /*--- Misc functions */
    static int sip_do_reload(enum channelreloadreason reason);
    
    static int reload_config(enum channelreloadreason reason);
    
    static int expire_register(const void *data);
    
    static void *do_monitor(void *data);
    
    static int restart_monitor(void);
    static int sip_addrcmp(char *name, struct sockaddr_in *sin);	/* Support for peer matching */
    
    static int sip_refer_allocate(struct sip_pvt *p);
    static void ast_quiet_chan(struct ast_channel *chan);
    static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target);
    
    
    /*--- Device monitoring and Device/extension state/event handling */
    
    static int cb_extensionstate(char *context, char* exten, int state, void *data);
    static int sip_devicestate(void *data);
    
    static int sip_poke_noanswer(const void *data);
    
    static int sip_poke_peer(struct sip_peer *peer);
    static void sip_poke_all_peers(void);
    
    static void sip_peer_hold(struct sip_pvt *p, int hold);
    
    static void mwi_event_cb(const struct ast_event *, void *);
    
    
    /*--- Applications, functions, CLI and manager command helpers */
    
    static const char *sip_nat_mode(const struct sip_pvt *p);
    
    Jason Parker's avatar
    Jason Parker committed
    static char *sip_show_inuse(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    
    static char *transfermode2str(enum transfermodes mode) attribute_const;
    
    static const char *nat2str(int nat) attribute_const;
    
    static int peer_status(struct sip_peer *peer, char *status, int statuslen);
    
    Jason Parker's avatar
    Jason Parker committed
    static char *sip_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    static char * _sip_show_peers(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *argv[]);
    static char *sip_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    static char *sip_show_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    
    static void  print_group(int fd, ast_group_t group, int crlf);
    
    static const char *dtmfmode2str(int mode) attribute_const;
    
    static int str2dtmfmode(const char *str) attribute_unused;
    
    static const char *insecure2str(int mode) attribute_const;
    
    static void cleanup_stale_contexts(char *new, char *old);
    static void print_codec_to_cli(int fd, struct ast_codec_pref *pref);
    static const char *domain_mode_to_text(const enum domain_mode mode);
    
    Jason Parker's avatar
    Jason Parker committed
    static char *sip_show_domains(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[]);
    static char *sip_show_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    static char *sip_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    static char *sip_show_registry(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    static char *sip_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    
    static const char *subscription_type2str(enum subscriptiontype subtype) attribute_pure;
    
    static const struct cfsubscription_types *find_subscription_type(enum subscriptiontype subtype);
    static char *complete_sip_peer(const char *word, int state, int flags2);
    
    static char *complete_sip_registered_peer(const char *word, int state, int flags2);
    
    static char *complete_sip_show_history(const char *line, const char *word, int pos, int state);
    
    static char *complete_sip_show_peer(const char *line, const char *word, int pos, int state);
    
    static char *complete_sip_unregister(const char *line, const char *word, int pos, int state);
    
    static char *complete_sip_user(const char *word, int state, int flags2);
    static char *complete_sip_show_user(const char *line, const char *word, int pos, int state);
    static char *complete_sipnotify(const char *line, const char *word, int pos, int state);
    
    Jason Parker's avatar
    Jason Parker committed
    static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    static char *sip_show_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    
    static char *sip_do_debug_ip(int fd, char *arg);
    static char *sip_do_debug_peer(int fd, char *arg);
    static char *sip_do_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    
    Jason Parker's avatar
    Jason Parker committed
    static char *sip_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    static char *sip_do_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    static char *sip_no_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    
    static int sip_dtmfmode(struct ast_channel *chan, void *data);
    static int sip_addheader(struct ast_channel *chan, void *data);
    static int sip_do_reload(enum channelreloadreason reason);
    
    Jason Parker's avatar
    Jason Parker committed
    static char *sip_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    
    static int acf_channel_read(struct ast_channel *chan, const char *funcname, char *preparse, char *buf, size_t buflen);
    
    /*--- Debugging 
    	Functions for enabling debug per IP or fully, or enabling history logging for
    	a SIP dialog
    */
    
    static void sip_dump_history(struct sip_pvt *dialog);	/* Dump history to debuglog at end of dialog, before destroying data */
    
    static inline int sip_debug_test_addr(const struct sockaddr_in *addr);
    static inline int sip_debug_test_pvt(struct sip_pvt *p);
    
    static void append_history_full(struct sip_pvt *p, const char *fmt, ...);
    
    static void sip_dump_history(struct sip_pvt *dialog);
    
    
    /*--- Device object handling */
    static struct sip_peer *temp_peer(const char *name);
    
    static struct sip_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime);
    
    static struct sip_user *build_user(const char *name, struct ast_variable *v, int realtime);
    static int update_call_counter(struct sip_pvt *fup, int event);
    static void sip_destroy_peer(struct sip_peer *peer);
    static void sip_destroy_user(struct sip_user *user);
    static int sip_poke_peer(struct sip_peer *peer);
    static void set_peer_defaults(struct sip_peer *peer);
    static struct sip_peer *temp_peer(const char *name);
    static void register_peer_exten(struct sip_peer *peer, int onoff);
    static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime);
    static struct sip_user *find_user(const char *name, int realtime);
    
    static int sip_poke_peer_s(const void *data);
    
    static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_request *req);
    static void reg_source_db(struct sip_peer *peer);
    static void destroy_association(struct sip_peer *peer);
    
    static void set_insecure_flags(struct ast_flags *flags, const char *value, int lineno);
    
    static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask, struct ast_variable *v);
    
    
    /* Realtime device support */
    static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, const char *fullcontact, int expirey);
    static struct sip_user *realtime_user(const char *username);
    static void update_peer(struct sip_peer *p, int expiry);
    
    static struct ast_variable *get_insecure_variable_from_config(struct ast_config *config);
    static const char *get_name_from_variable(struct ast_variable *var, const char *newpeername);
    
    static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *sin);
    
    static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
    
    
    /*--- Internal UA client handling (outbound registrations) */
    
    static void ast_sip_ouraddrfor(struct in_addr *them, struct sockaddr_in *us);
    
    static void sip_registry_destroy(struct sip_registry *reg);
    
    static int sip_register(const char *value, int lineno);
    
    static const char *regstate2str(enum sipregistrystate regstate) attribute_const;
    
    static int sip_reregister(const void *data);
    
    static int __sip_do_register(struct sip_registry *r);
    
    static int sip_reg_timeout(const void *data);
    
    static void sip_send_all_registers(void);
    
    static void append_date(struct sip_request *req);	/* Append date to SIP packet */
    
    static int determine_firstline_parts(struct sip_request *req);
    
    static const struct cfsubscription_types *find_subscription_type(enum subscriptiontype subtype);
    
    static const char *gettag(const struct sip_request *req, const char *header, char *tagbuf, int tagbufsize);
    
    static int find_sip_method(const char *msg);
    static unsigned int parse_sip_options(struct sip_pvt *pvt, const char *supported);
    
    static void parse_request(struct sip_request *req);
    
    static const char *get_header(const struct sip_request *req, const char *name);
    
    static const char *referstatus2str(enum referstatus rstatus) attribute_pure;
    
    static int method_match(enum sipmethod id, const char *name);
    
    static void parse_copy(struct sip_request *dst, const struct sip_request *src);
    
    static char *get_in_brackets(char *tmp);
    static const char *find_alias(const char *name, const char *_default);
    static const char *__get_header(const struct sip_request *req, const char *name, int *start);
    static int lws2sws(char *msgbuf, int len);
    static void extract_uri(struct sip_pvt *p, struct sip_request *req);
    
    static char *remove_uri_parameters(char *uri);
    
    static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoing_req);
    static int get_also_info(struct sip_pvt *p, struct sip_request *oreq);
    static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req);
    static int set_address_from_contact(struct sip_pvt *pvt);
    static void check_via(struct sip_pvt *p, struct sip_request *req);
    static char *get_calleridname(const char *input, char *output, size_t outputsize);
    static int get_rpid_num(const char *input, char *output, int maxlen);
    static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq);
    static int get_destination(struct sip_pvt *p, struct sip_request *oreq);
    static int get_msg_text(char *buf, int len, struct sip_request *req);
    
    static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout);
    
    
    /*--- Constructing requests and responses */
    static void initialize_initreq(struct sip_pvt *p, struct sip_request *req);
    static int init_req(struct sip_request *req, int sipmethod, const char *recip);
    static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, int seqno, int newbranch);
    
    static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod);
    
    static int init_resp(struct sip_request *resp, const char *msg);
    
    static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg, const struct sip_request *req);
    
    static const struct sockaddr_in *sip_real_dst(const struct sip_pvt *p);
    static void build_via(struct sip_pvt *p);
    static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer);
    static int create_addr(struct sip_pvt *dialog, const char *opeer);
    static char *generate_random_string(char *buf, size_t size);
    static void build_callid_pvt(struct sip_pvt *pvt);
    static void build_callid_registry(struct sip_registry *reg, struct in_addr ourip, const char *fromdomain);
    static void make_our_tag(char *tagbuf, size_t len);
    static int add_header(struct sip_request *req, const char *var, const char *value);
    static int add_header_contentLength(struct sip_request *req, int len);
    static int add_line(struct sip_request *req, const char *line);
    static int add_text(struct sip_request *req, const char *text);
    
    static int add_digit(struct sip_request *req, char digit, unsigned int duration, int mode);
    
    static int add_vidupdate(struct sip_request *req);
    static void add_route(struct sip_request *req, struct sip_route *route);
    
    static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field);
    
    static int copy_all_header(struct sip_request *req, const struct sip_request *orig, const char *field);
    static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const struct sip_request *orig, const char *field);
    
    static void set_destination(struct sip_pvt *p, char *uri);
    static void append_date(struct sip_request *req);
    static void build_contact(struct sip_pvt *p);
    static void build_rpid(struct sip_pvt *p);
    
    /*------Request handling functions */
    
    static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int *recount, int *nounlock);
    
    static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *recount, char *e, int *nounlock);
    
    static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, int *nounlock);
    
    static int handle_request_bye(struct sip_pvt *p, struct sip_request *req);
    static int handle_request_register(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, char *e);
    static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req);
    static int handle_request_message(struct sip_pvt *p, struct sip_request *req);
    static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e);
    static void handle_request_info(struct sip_pvt *p, struct sip_request *req);
    static int handle_request_options(struct sip_pvt *p, struct sip_request *req);
    
    static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin);
    
    static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, char *e);
    static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *current, struct sip_request *req, int seqno);
    
    
    /*------Response handling functions */
    
    static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
    
    static void handle_response_refer(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
    
    static int handle_response_register(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
    static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno);
    
    /*----- RTP interface functions */
    
    static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp,  struct ast_rtp *trtp, int codecs, int nat_active);
    
    static enum ast_rtp_get_result sip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
    static enum ast_rtp_get_result sip_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
    
    static enum ast_rtp_get_result sip_get_trtp_peer(struct ast_channel *chan, struct ast_rtp **rtp);
    
    static int sip_get_codec(struct ast_channel *chan);
    
    static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p, int *faxdetect);
    
    /*------ T38 Support --------- */
    
    static int sip_handle_t38_reinvite(struct ast_channel *chan, struct sip_pvt *pvt, int reinvite); 
    
    static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
    static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan);
    static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl);
    
    /*! \brief Definition of this channel for PBX channel registration */
    
    static const struct ast_channel_tech sip_tech = {
    
    	.description = "Session Initiation Protocol (SIP)",
    
    	.capabilities = AST_FORMAT_AUDIO_MASK,	/* all audio formats */
    
    	.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
    
    	.requester = sip_request_call,			/* called with chan unlocked */
    	.devicestate = sip_devicestate,			/* called with chan unlocked (not chan-specific) */
    	.call = sip_call,			/* called with chan locked */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	.send_html = sip_sendhtml,
    
    	.hangup = sip_hangup,			/* called with chan locked */
    	.answer = sip_answer,			/* called with chan locked */
    	.read = sip_read,			/* called with chan locked */
    	.write = sip_write,			/* called with chan locked */
    	.write_video = sip_write,		/* called with chan locked */
    
    	.write_text = sip_write,
    
    	.indicate = sip_indicate,		/* called with chan locked */
    	.transfer = sip_transfer,		/* called with chan locked */
    	.fixup = sip_fixup,			/* called with chan locked */
    	.send_digit_begin = sip_senddigit_begin,	/* called with chan unlocked */
    
    	.bridge = ast_rtp_bridge,			/* XXX chan unlocked ? */
    
    	.send_text = sip_sendtext,		/* called with chan locked */
    
    	.func_channel_read = acf_channel_read,
    
    /*! \brief This version of the sip channel tech has no send_digit_begin
    
     * callback so that the core knows that the channel does not want
     * DTMF BEGIN frames.
     * The struct is initialized just before registering the channel driver,
     * and is for use with channels using SIP INFO DTMF.
     */
    static struct ast_channel_tech sip_tech_info;
    
    /* wrapper macro to tell whether t points to one of the sip_tech descriptors */
    #define IS_SIP_TECH(t)  ((t) == &sip_tech || (t) == &sip_tech_info)
    
    
    Jason Parker's avatar
    Jason Parker committed
    /*! \brief map from an integer value to a string.
    
     * If no match is found, return errorstring
     */
    static const char *map_x_s(const struct _map_x_s *table, int x, const char *errorstring)
    {
    	const struct _map_x_s *cur;
    
    	for (cur = table; cur->s; cur++)
    		if (cur->x == x)
    			return cur->s;
    	return errorstring;
    }
    
    
    Jason Parker's avatar
    Jason Parker committed
    /*! \brief map from a string to an integer value, case insensitive.
    
     * If no match is found, return errorvalue.
     */
    static int map_s_x(const struct _map_x_s *table, const char *s, int errorvalue)
    {
    	const struct _map_x_s *cur;
    
    	for (cur = table; cur->s; cur++)
    		if (!strcasecmp(cur->s, s))
    			return cur->x;
    	return errorvalue;
    }
    
    
    /*! \brief Interface structure with callbacks used to connect to RTP module */
    static struct ast_rtp_protocol sip_rtp = {
    
    	.type = "SIP",
    	.get_rtp_info = sip_get_rtp_peer,
    	.get_vrtp_info = sip_get_vrtp_peer,
    	.get_trtp_info = sip_get_trtp_peer,
    	.set_rtp_peer = sip_set_rtp_peer,
    	.get_codec = sip_get_codec,
    
    #define sip_pvt_lock(x) ast_mutex_lock(&x->pvt_lock)
    #define sip_pvt_unlock(x) ast_mutex_unlock(&x->pvt_lock)
    
    /*!
     * helper functions to unreference various types of objects.
     * By handling them this way, we don't have to declare the
     * destructor on each call, which removes the chance of errors.
     */
    static void unref_peer(struct sip_peer *peer)
    {
    	ASTOBJ_UNREF(peer, sip_destroy_peer);
    }
    
    static void unref_user(struct sip_user *user)
    {
    	ASTOBJ_UNREF(user, sip_destroy_user);
    }
    
    
    static void *registry_unref(struct sip_registry *reg)
    
    	ast_debug(3, "SIP Registry %s: refcount now %d\n", reg->hostname, reg->refcount - 1);
    
    	ASTOBJ_UNREF(reg, sip_registry_destroy);
    
    /*! \brief Add object reference to SIP registry */
    static struct sip_registry *registry_addref(struct sip_registry *reg)
    {
    
    	ast_debug(3, "SIP Registry %s: refcount now %d\n", reg->hostname, reg->refcount + 1);
    
    	return ASTOBJ_REF(reg);	/* Add pointer to registry in packet */
    }
    
    
    /*! \brief Interface structure with callbacks used to connect to UDPTL module*/
    static struct ast_udptl_protocol sip_udptl = {
    	type: "SIP",
    	get_udptl_info: sip_get_udptl_peer,
    	set_udptl_peer: sip_set_udptl_peer,
    };
    
    
    /*! \brief Append to SIP dialog history 
    	\return Always returns 0 */
    #define append_history(p, event, fmt , args... )	append_history_full(p, "%-15s " fmt, event, ## args)
    
    static void append_history_full(struct sip_pvt *p, const char *fmt, ...)
    	__attribute__ ((format (printf, 2, 3)));
    
    
    
    /*! \brief Convert transfer status to string */
    
    static const char *referstatus2str(enum referstatus rstatus)
    
    	return map_x_s(referstatusstrings, rstatus, "");
    
    /*! \brief Initialize the initital request packet in the pvt structure.
     	This packet is used for creating replies and future requests in
    	a dialog */
    
    static void initialize_initreq(struct sip_pvt *p, struct sip_request *req)
    
    	if (p->initreq.headers)
    		ast_debug(1, "Initializing already initialized SIP dialog %s (presumably reinvite)\n", p->callid);
    	else
    		ast_debug(1, "Initializing initreq for method %s - callid %s\n", sip_methods[req->method].text, p->callid);
    
    	/* Use this as the basis */
    	copy_request(&p->initreq, req);
    	parse_request(&p->initreq);
    
    		ast_verbose("Initreq: %d headers, %d lines\n", p->initreq.headers, p->initreq.lines);
    
    Olle Johansson's avatar
    Olle Johansson committed
    /*! \brief Encapsulate setting of SIP_ALREADYGONE to be able to trace it with debugging */
    static void sip_alreadygone(struct sip_pvt *dialog)
    {
    
    	ast_debug(3, "Setting SIP_ALREADYGONE on dialog %s\n", dialog->callid);
    
    /*! Resolve DNS srv name or host name in a sip_proxy structure */
    static int proxy_update(struct sip_proxy *proxy)
    {