Skip to content
Snippets Groups Projects
chan_sip.c 482 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	ASTOBJ_CONTAINER_COMPONENTS(struct sip_peer);
    
    /*! \brief  The register list: Other SIP proxys we register with and place calls to */
    
    static struct ast_register_list {
    
    	ASTOBJ_CONTAINER_COMPONENTS(struct sip_registry);
    
    /*! \todo Move the sip_auth list to AST_LIST */
    
    Olle Johansson's avatar
    Olle Johansson committed
    static struct sip_auth *authl = NULL;		/*!< Authentication list for realm authentication */
    
    /* --- Sockets and networking --------------*/
    static int sipsock  = -1;			/*!< Main socket for SIP network communication */
    
    static struct sockaddr_in bindaddr = { 0, };	/*!< The address we bind to */
    static struct sockaddr_in externip;		/*!< External IP address if we are behind NAT */
    static char externhost[MAXHOSTNAMELEN];		/*!< External host name (possibly with dynamic DNS and DHCP */
    static time_t externexpire = 0;			/*!< Expiration counter for re-resolving external host name in dynamic DNS */
    
    static struct ast_ha *localaddr;		/*!< List of local networks, on the same side of NAT as this Asterisk */
    
    static struct in_addr __ourip;
    static struct sockaddr_in outboundproxyip;
    static int ourport;
    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 */
    
    /*---------------------------- Forward declarations of functions in chan_sip.c */
    /*! \note Sorted up from start to build_rpid.... Will continue categorization in order to
    	split up chan_sip.c into several files  */
    
    /*--- 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);
    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(struct ast_channel *ast, char digit);
    
    /*--- Transmitting responses and requests */
    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, struct sip_request *req, enum xmittype reliable);
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int transmit_response(struct sip_pvt *p, char *msg, struct sip_request *req);
    
    static int transmit_response_reliable(struct sip_pvt *p, const char *msg, struct sip_request *req);
    static int transmit_response_with_date(struct sip_pvt *p, char *msg, struct sip_request *req);
    
    static int transmit_response_with_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, enum xmittype reliable);
    
    static int transmit_response_with_unsupported(struct sip_pvt *p, const char *msg, struct sip_request *req, const char *unsupported);
    
    static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, 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, char *msg, struct sip_request *req, enum xmittype 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 inc, enum xmittype reliable, int newbranch);
    
    static int transmit_invite(struct sip_pvt *p, int sipmethod, int sendsdp, int init);
    
    static int transmit_reinvite_with_sdp(struct sip_pvt *p);
    
    static int transmit_info_with_digit(struct sip_pvt *p, char digit);
    
    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_state_notify(struct sip_pvt *p, int state, int full);
    static int transmit_register(struct sip_registry *r, int sipmethod, char *auth, char *authheader);
    static int retrans_pkt(void *data);
    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, struct sip_request *src);
    
    /*--- 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(void *data);
    static int sip_scheddestroy(struct sip_pvt *p, int ms);
    static int sip_cancel_destroy(struct sip_pvt *p);
    static void sip_destroy(struct sip_pvt *p);
    static void __sip_destroy(struct sip_pvt *p, int lockowner);
    static int __sip_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod, int reset);
    static int __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(void *nothing);
    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 int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
    static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *sin, const int intended_method);
    
    /*--- Codec handling / SDP */
    static void try_suggested_sip_codec(struct sip_pvt *p);
    static const char *get_sdp_by_line(const char* line, const char *name, int nameLen);
    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 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,
    			     char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
    			     int debug);
    static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_rate,
    				char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
    				int debug);
    static int add_sdp(struct sip_request *resp, struct sip_pvt *p);
    
    /*--- Authentication stuff */
    
    static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req, char *header, char *respheader, int sipmethod, int init);
    
    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);
    
    Olle Johansson's avatar
    Olle Johansson committed
    static int clear_realm_authentication(struct sip_auth *authlist);	/* Clear realm authentication list (at reload) */
    static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, char *configuration, int lineno);	/* Add realm authentication in list */
    static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, const char *realm);	/* Find authentication for a specific realm */
    
    Olle Johansson's avatar
    Olle Johansson committed
    static int check_auth(struct sip_pvt *p, struct sip_request *req, const char *username,
    
    Olle Johansson's avatar
    Olle Johansson committed
    		const char *secret, const char *md5secret, int sipmethod,
    
    		char *uri, enum xmittype reliable, int ignore);
    
    static int check_sip_domain(const char *domain, char *context, size_t len); /* Check if domain is one of our local domains */
    
    
    static void free_old_route(struct sip_route *route);
    
    /*--- Misc functions */
    static int sip_do_reload(enum channelreloadreason reason);
    static int expire_register(void *data);
    static int sip_sipredirect(struct sip_pvt *p, const char *dest);
    static int restart_monitor(void);
    static int sip_send_mwi_to_peer(struct sip_peer *peer);
    static void sip_destroy(struct sip_pvt *p);
    static int sip_scheddestroy(struct sip_pvt *p, int ms);
    static int sip_addrcmp(char *name, struct sockaddr_in *sin);	/* Support for peer matching */
    
    /*--- CLI and manager command helpers */
    static const char *sip_nat_mode(const struct sip_pvt *p);
    
    /*--- Debugging */
    static void sip_dump_history(struct sip_pvt *dialog);	/* Dump history to LOG_DEBUG 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 int append_history_full(struct sip_pvt *p, const char *fmt, ...);
    
    /*--- 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, 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 void sip_destroy_peer(struct sip_peer *peer);
    static void sip_destroy_user(struct sip_user *user);
    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);
    /* 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 sip_peer *realtime_peer(const char *peername, struct sockaddr_in *sin);
    
    /*--- Internal UA client handling (outbound registrations) */
    static int __sip_do_register(struct sip_registry *r);
    static int ast_sip_ouraddrfor(struct in_addr *them, struct in_addr *us);
    static void sip_registry_destroy(struct sip_registry *reg);
    static int sip_register(char *value, int lineno);
    
    /*--- Parsing SIP requests and responses */
    
    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, 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 char *referstatus2str(enum referstatus rstatus);
    static int method_match(enum sipmethod id, const char *name);
    static void parse_copy(struct sip_request *dst, 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 const char *get_header(const struct sip_request *req, const char *name);
    static int lws2sws(char *msgbuf, int len);
    static void extract_uri(struct sip_pvt *p, struct sip_request *req);
    
    /*--- 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 int init_resp(struct sip_request *resp, const char *msg);
    
    static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg, 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);
    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, struct sip_request *orig, char *field);
    static int copy_all_header(struct sip_request *req, struct sip_request *orig, char *field);
    static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, struct sip_request *orig, 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_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *recount, char *e);
    static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int debug, int ignore, 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);
    
    
    /*------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_peerpoke(struct sip_pvt *p, int resp, struct sip_request *req);
    
    /*----- RTP interface functions */
    static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active);
    static struct ast_rtp *sip_get_rtp_peer(struct ast_channel *chan);
    static struct ast_rtp *sip_get_vrtp_peer(struct ast_channel *chan);
    static int sip_get_codec(struct ast_channel *chan);
    
    static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p);
    
    /*! \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_MAX_AUDIO << 1) - 1),
    
    	.devicestate = sip_devicestate,
    	.call = sip_call,
    	.hangup = sip_hangup,
    	.answer = sip_answer,
    	.read = sip_read,
    	.write = sip_write,
    	.write_video = sip_write,
    	.indicate = sip_indicate,
    	.transfer = sip_transfer,
    	.fixup = sip_fixup,
    	.send_digit = sip_senddigit,
    	.bridge = ast_rtp_bridge,
    	.send_text = sip_sendtext,
    };
    
    
    /**--- some list management macros. **/
     
    #define UNLINK(element, head, prev) do {	\
    	if (prev)				\
    		(prev)->next = (element)->next;	\
    	else					\
    		(head) = (element)->next;	\
    	} while (0)
    
    
    /*! \brief Interface structure with callbacks used to connect to RTP module */
    static struct ast_rtp_protocol sip_rtp = {
    
    	get_rtp_info: sip_get_rtp_peer,
    	get_vrtp_info: sip_get_vrtp_peer,
    	set_rtp_peer: sip_set_rtp_peer,
    	get_codec: sip_get_codec,
    };
    
    
    /*! \brief Convert transfer status to string */
    static char *referstatus2str(enum referstatus rstatus)
    {
    	int i = (sizeof(referstatusstrings) / sizeof(referstatusstrings[0]));
    	int x;
    
    	for (x = 0; x < i; x++) {
    		if (referstatusstrings[x].status ==  rstatus)
    			return (char *) referstatusstrings[x].text;
    	}
    	return "";
    }
    
    
    /*! \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)
    
    		ast_log(LOG_DEBUG, "Initializing already initialized SIP dialog %s (presumably reinvite)\n", p->callid);
    
    	}
    	/* Use this as the basis */
    	copy_request(&p->initreq, req);
    	parse_request(&p->initreq);
    	if (ast_test_flag(req, SIP_PKT_DEBUG))
    		ast_verbose("%d headers, %d lines\n", p->initreq.headers, p->initreq.lines);
    }
    
    
    /*! \brief returns true if 'name' (with optional trailing whitespace)
     * matches the sip method 'id'.
     * Strictly speaking, SIP methods are case SENSITIVE, but we do
     * a case-insensitive comparison to be more tolerant.
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
     * following Jon Postel's rule: Be gentle in what you accept, strict with what you send
    
     */
    static int method_match(enum sipmethod id, const char *name)
    {
    	int len = strlen(sip_methods[id].text);
    	int l_name = name ? strlen(name) : 0;
    	/* true if the string is long enough, and ends with whitespace, and matches */
    	return (l_name >= len && name[len] < 33 &&
    		!strncasecmp(sip_methods[id].text, name, len));
    }
    
    /*! \brief  find_sip_method: Find SIP method from header */
    static int find_sip_method(const char *msg)
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	for (i = 1; i < (sizeof(sip_methods) / sizeof(sip_methods[0])) && !res; i++) {
    
    		if (method_match(i, msg))
    
    /*! \brief Parse supported header in incoming packet */
    
    static unsigned int parse_sip_options(struct sip_pvt *pvt, const char *supported)
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	char *next, *sep;
    
    	char *temp = ast_strdupa(supported);
    	unsigned int profile = 0;
    
    	int i, found;
    
    	if (!pvt || ast_strlen_zero(supported) )
    
    		ast_log(LOG_DEBUG, "Begin: parsing SIP \"Supported: %s\"\n", supported);
    
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	for (next = temp; next; next = sep) {
    
    		found = FALSE;
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    		if ( (sep = strchr(next, ',')) != NULL)
    			*sep++ = '\0';
    		next = ast_skip_blanks(next);
    
    			ast_log(LOG_DEBUG, "Found SIP option: -%s-\n", next);
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    		for (i=0; i < (sizeof(sip_options) / sizeof(sip_options[0])); i++) {
    
    			if (!strcasecmp(next, sip_options[i].text)) {
    				profile |= sip_options[i].id;
    
    				found = TRUE;
    
    					ast_log(LOG_DEBUG, "Matched SIP option: %s\n", next);
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    				break;
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    		if (!found && option_debug > 2 && sipdebug)
    			ast_log(LOG_DEBUG, "Found no match for SIP option: %s (Please file bug report!)\n", next);
    
    
    	pvt->sipoptions = profile;
    
    /*! \brief See if we pass debug IP filter */
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    static inline int sip_debug_test_addr(const struct sockaddr_in *addr) 
    
    James Golovich's avatar
    James Golovich committed
    {
    
    		return 0;
    	if (debugaddr.sin_addr.s_addr) {
    		if (((ntohs(debugaddr.sin_port) != 0)
    			&& (debugaddr.sin_port != addr->sin_port))
    			|| (debugaddr.sin_addr.s_addr != addr->sin_addr.s_addr))
    			return 0;
    	}
    	return 1;
    }
    
    
    /*! \brief The real destination address for a write */
    
    static const struct sockaddr_in *sip_real_dst(const struct sip_pvt *p)
    {
    	return ast_test_flag(&p->flags[0], SIP_NAT) & SIP_NAT_ROUTE ? &p->recv : &p->sa;
    }
    
    
    static const char *sip_nat_mode(const struct sip_pvt *p)
    {
    	return ast_test_flag(&p->flags[0], SIP_NAT) & SIP_NAT_ROUTE ? "NAT" : "no NAT";
    }
    
    
    /*! \brief Test PVT for debugging output */
    
    James Golovich's avatar
    James Golovich committed
    static inline int sip_debug_test_pvt(struct sip_pvt *p) 
    {
    
    		return 0;
    
    	return sip_debug_test_addr(sip_real_dst(p));
    
    /*! \brief Transmit SIP message */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int __sip_xmit(struct sip_pvt *p, char *data, int len)
    {
    	int res;
    
    	char iabuf[INET_ADDRSTRLEN];
    
    	const struct sockaddr_in *dst = sip_real_dst(p);
    	res=sendto(sipsock, data, len, 0, (const struct sockaddr *)dst, sizeof(struct sockaddr_in));
    
    	if (res != len)
    		ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s:%d returned %d: %s\n", data, len, ast_inet_ntoa(iabuf, sizeof(iabuf), dst->sin_addr), ntohs(dst->sin_port), res, strerror(errno));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    
    /*! \brief Build a Via header for a request */
    
    static void build_via(struct sip_pvt *p)
    
    {
    	char iabuf[INET_ADDRSTRLEN];
    
    	/* Work around buggy UNIDEN UIP200 firmware */
    
    	const char *rport = ast_test_flag(&p->flags[0], SIP_NAT) & SIP_NAT_RFC3581 ? ";rport" : "";
    
    
    	/* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
    
    	ast_string_field_build(p, via, "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x%s",
    
    Olle Johansson's avatar
    Olle Johansson committed
    			 ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch, rport);
    
    /*! \brief NAT fix - decide which IP address to use for ASterisk server?
     * Only used for outbound registrations */
    
    static int ast_sip_ouraddrfor(struct in_addr *them, struct in_addr *us)
    {
    
    	 * Using the localaddr structure built up with localnet statements
    	 * apply it to their address to see if we need to substitute our
    	 * externip or can get away with our internal bindaddr
    	 */
    	struct sockaddr_in theirs;
    	theirs.sin_addr = *them;
    
    	if (localaddr && externip.sin_addr.s_addr &&
    	   ast_apply_ha(localaddr, &theirs)) {
    
    		if (externexpire && time(NULL) >= externexpire) {
    
    			struct ast_hostent ahp;
    			struct hostent *hp;
    
    			time(&externexpire);
    			externexpire += externrefresh;
    			if ((hp = ast_gethostbyname(externhost, &ahp))) {
    				memcpy(&externip.sin_addr, hp->h_addr, sizeof(externip.sin_addr));
    			} else
    				ast_log(LOG_NOTICE, "Warning: Re-lookup of '%s' failed!\n", externhost);
    		}
    
    		if (option_debug) {
    			char iabuf[INET_ADDRSTRLEN];
    			ast_inet_ntoa(iabuf, sizeof(iabuf), *(struct in_addr *)&them->s_addr);
    		
    			ast_log(LOG_DEBUG, "Target address %s is not local, substituting externip\n", iabuf);
    		}
    	} else if (bindaddr.sin_addr.s_addr)
    
    	else
    		return ast_ouraddrfor(them, us);
    
    /*! \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 int append_history_full(struct sip_pvt *p, const char *fmt, ...)
    	__attribute__ ((format (printf, 2, 3)));
    
    
    /*! \brief Append to SIP dialog history with arg list  */
    
    static void append_history_va(struct sip_pvt *p, const char *fmt, va_list ap)
    
    	char buf[80], *c = buf; /* max history length */
    	struct sip_history *hist;
    	int l;
    
    	vsnprintf(buf, sizeof(buf), fmt, ap);
    	strsep(&c, "\r\n"); /* Trim up everything after \r or \n */
    	l = strlen(buf) + 1;
    
    	if (!(hist = ast_calloc(1, sizeof(*hist) + l)))
    
    	if (!p->history && !(p->history = ast_calloc(1, sizeof(*p->history)))) {
    
    	memcpy(hist->event, buf, l);
    	AST_LIST_INSERT_TAIL(p->history, hist, list);
    }
    
    
    /*! \brief Append to SIP dialog history with arg list  */
    
    static int append_history_full(struct sip_pvt *p, const char *fmt, ...)
    {
    
    Olle Johansson's avatar
    Olle Johansson committed
    	va_list ap;
    
    Olle Johansson's avatar
    Olle Johansson committed
    	va_start(ap, fmt);
    	append_history_va(p, fmt, ap);
    	va_end(ap);
    
    Olle Johansson's avatar
    Olle Johansson committed
    	return 0;
    
    /*! \brief Retransmit SIP message if no answer (Called from scheduler) */
    
    static int retrans_pkt(void *data)
    {
    
    	struct sip_pkt *pkt = data, *prev, *cur = NULL;
    
    	char iabuf[INET_ADDRSTRLEN];
    
    	int reschedule = DEFAULT_RETRANS;
    
    
    	/* Lock channel PVT */
    	ast_mutex_lock(&pkt->owner->lock);
    
    	if (pkt->retrans < MAX_RETRANS) {
    		pkt->retrans++;
    
     		if (!pkt->timer_t1) {	/* Re-schedule using timer_a and timer_t1 */
    
     				ast_log(LOG_DEBUG, "SIP TIMER: Not rescheduling id #%d:%s (Method %d) (No timer T1)\n", pkt->retransid, sip_methods[pkt->method].text, pkt->method);
    		} else {
     			int siptimer_a;
    
    
     				ast_log(LOG_DEBUG, "SIP TIMER: Rescheduling retransmission #%d (%d) %s - %d\n", pkt->retransid, pkt->retrans, sip_methods[pkt->method].text, pkt->method);
     			if (!pkt->timer_a)
     				pkt->timer_a = 2 ;
     			else
     				pkt->timer_a = 2 * pkt->timer_a;
     
     			/* For non-invites, a maximum of 4 secs */
     			siptimer_a = pkt->timer_t1 * pkt->timer_a;	/* Double each time */
    
     			if (pkt->method != SIP_INVITE && siptimer_a > 4000)
     				siptimer_a = 4000;
    
     		
     			/* Reschedule re-transmit */
    			reschedule = siptimer_a;
     			if (option_debug > 3)
     				ast_log(LOG_DEBUG, "** SIP timers: Rescheduling retransmission %d to %d ms (t1 %d ms (Retrans id #%d)) \n", pkt->retrans +1, siptimer_a, pkt->timer_t1, pkt->retransid);
     		} 
    
    		if (pkt->owner && sip_debug_test_pvt(pkt->owner)) {
    
    			if (ast_test_flag(&pkt->owner->flags[0], SIP_NAT_ROUTE))
    
    				ast_verbose("Retransmitting #%d (NAT) to %s:%d:\n%s\n---\n", pkt->retrans, ast_inet_ntoa(iabuf, sizeof(iabuf), pkt->owner->recv.sin_addr), ntohs(pkt->owner->recv.sin_port), pkt->data);
    
    				ast_verbose("Retransmitting #%d (no NAT) to %s:%d:\n%s\n---\n", pkt->retrans, ast_inet_ntoa(iabuf, sizeof(iabuf), pkt->owner->sa.sin_addr), ntohs(pkt->owner->sa.sin_port), pkt->data);
    
    		append_history(pkt->owner, "ReTx", "%d %s", reschedule, pkt->data);
    
    		__sip_xmit(pkt->owner, pkt->data, pkt->packetlen);
    
    		ast_mutex_unlock(&pkt->owner->lock);
    
    		return  reschedule;
    	} 
    	/* Too many retries */
    	if (pkt->owner && pkt->method != SIP_OPTIONS) {
    
    Olle Johansson's avatar
    Olle Johansson committed
    		if (ast_test_flag(pkt, FLAG_FATAL) || sipdebug)	/* Tell us if it's critical or if we're debugging */
    			ast_log(LOG_WARNING, "Maximum retries exceeded on transmission %s for seqno %d (%s %s)\n", pkt->owner->callid, pkt->seqno, (ast_test_flag(pkt, FLAG_FATAL)) ? "Critical" : "Non-critical", (ast_test_flag(pkt, FLAG_RESPONSE)) ? "Response" : "Request");
    	} else {
    
    		if ((pkt->method == SIP_OPTIONS) && sipdebug)
    
    			ast_log(LOG_WARNING, "Cancelling retransmit of OPTIONs (call id %s) \n", pkt->owner->callid);
    	}
    
    	append_history(pkt->owner, "MaxRetries", "%s", (ast_test_flag(pkt, FLAG_FATAL)) ? "(Critical)" : "(Non-critical)");
    
     		
    	pkt->retransid = -1;
    
    	if (ast_test_flag(pkt, FLAG_FATAL)) {
    		while(pkt->owner->owner && ast_mutex_trylock(&pkt->owner->owner->lock)) {
    			ast_mutex_unlock(&pkt->owner->lock);
    			usleep(1);
    			ast_mutex_lock(&pkt->owner->lock);
    
    		if (pkt->owner->owner) {
    
    			ast_set_flag(&pkt->owner->flags[0], SIP_ALREADYGONE);
    
    			ast_log(LOG_WARNING, "Hanging up call %s - no reply to our critical packet.\n", pkt->owner->callid);
    			ast_queue_hangup(pkt->owner->owner);
    
    			ast_channel_unlock(pkt->owner->owner);
    
    		} else {
    			/* If no channel owner, destroy now */
    
    			ast_set_flag(&pkt->owner->flags[0], SIP_NEEDDESTROY);	
    
    	/* In any case, go ahead and remove the packet */
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	for (prev = NULL, cur = pkt->owner->packets; cur; prev = cur, cur = cur->next) {
    
    		if (cur == pkt)
    			break;
    	}
    	if (cur) {
    		if (prev)
    			prev->next = cur->next;
    		else
    			pkt->owner->packets = cur->next;
    		ast_mutex_unlock(&pkt->owner->lock);
    		free(cur);
    		pkt = NULL;
    	} else
    		ast_log(LOG_WARNING, "Weird, couldn't find packet owner!\n");
    
    		ast_mutex_unlock(&pkt->owner->lock);
    
    /*! \brief Transmit packet with retransmits 
    	\return 0 on success, -1 on failure to allocate packet 
    */
    
    static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, char *data, int len, int fatal, int sipmethod)
    
    {
    	struct sip_pkt *pkt;
    
    	int siptimer_a = DEFAULT_RETRANS;
    
    
    	if (!(pkt = ast_calloc(1, sizeof(*pkt) + len + 1)))
    
    		return -1;
    	memcpy(pkt->data, data, len);
    
    	pkt->packetlen = len;
    	pkt->next = p->packets;
    	pkt->owner = p;
    	pkt->seqno = seqno;
    
    	pkt->data[len] = '\0';
    
    	pkt->timer_t1 = p->timer_t1;	/* Set SIP timer T1 */
    
    		ast_set_flag(pkt, FLAG_FATAL);
    
    	if (pkt->timer_t1)
    		siptimer_a = pkt->timer_t1 * 2;
    
    
    	/* Schedule retransmission */
    
    	pkt->retransid = ast_sched_add_variable(sched, siptimer_a, retrans_pkt, pkt, 1);
    
    		ast_log(LOG_DEBUG, "*** SIP TIMER: Initalizing retransmit timer on packet: Id  #%d\n", pkt->retransid);
    
    	pkt->next = p->packets;
    	p->packets = pkt;
    
    
    	__sip_xmit(pkt->owner, pkt->data, pkt->packetlen);	/* Send packet */
    	if (sipmethod == SIP_INVITE) {
    
    		/* Note this is a pending invite */
    		p->pendinginvite = seqno;
    	}
    
    /*! \brief Kill a SIP dialog (called by scheduler) */
    
    static int __sip_autodestruct(void *data)
    {
    	struct sip_pvt *p = data;
    
    	/* If this is a subscription, tell the phone that we got a timeout */
    	if (p->subscribed) {
    		p->subscribed = TIMEOUT;
    
    		transmit_state_notify(p, AST_EXTENSION_DEACTIVATED, 1);	/* Send last notification */
    
    		p->subscribed = NONE;
    		append_history(p, "Subscribestatus", "timeout");
    
    		if (option_debug > 2)
    			ast_log(LOG_DEBUG, "Re-scheduled destruction of SIP subsription %s\n", p->callid ? p->callid : "<unknown>");
    
    		return 10000;	/* Reschedule this destruction so that we know that it's gone */
    	}
    
    
    	/* Reset schedule ID */
    	p->autokillid = -1;
    
    	if (option_debug)
    		ast_log(LOG_DEBUG, "Auto destroying call '%s'\n", p->callid);
    
    	if (p->owner) {
    
    		ast_log(LOG_WARNING, "Autodestruct on dialog '%s' with owner in place (Method: %s)\n", p->callid, sip_methods[p->method].text);
    
    	} else {
    		sip_destroy(p);
    	}
    	return 0;
    }
    
    
    /*! \brief Schedule destruction of SIP call */
    
    static int sip_scheddestroy(struct sip_pvt *p, int ms)
    {
    
    		ast_verbose("Scheduling destruction of SIP dialog '%s' in %d ms (Method: %s)\n", p->callid, ms, sip_methods[p->method].text);
    
    	if (recordhistory)
    		append_history(p, "SchedDestroy", "%d ms", ms);
    
    	if (p->autokillid > -1)
    		ast_sched_del(sched, p->autokillid);
    	p->autokillid = ast_sched_add(sched, ms, __sip_autodestruct, p);
    	return 0;
    }
    
    
    /*! \brief Cancel destruction of SIP dialog */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sip_cancel_destroy(struct sip_pvt *p)
    {
    
    	if (p->autokillid > -1) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_sched_del(sched, p->autokillid);
    
    		append_history(p, "CancelDestroy", "");
    		p->autokillid = -1;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    
    /*! \brief Acknowledges receipt of a packet and stops retransmission */
    
    static int __sip_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod, int reset)
    
    {
    	struct sip_pkt *cur, *prev = NULL;
    	int res = -1;
    
    	ast_mutex_lock(&p->lock);
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	for (cur = p->packets; cur; prev = cur, cur = cur->next) {
    
    		if ((cur->seqno == seqno) && ((ast_test_flag(cur, FLAG_RESPONSE)) == resp) &&
    			((ast_test_flag(cur, FLAG_RESPONSE)) || 
    
    			 (!strncasecmp(msg, cur->data, strlen(msg)) && (cur->data[strlen(msg)] < 33)))) {
    
    			if (!resp && (seqno == p->pendinginvite)) {
    				ast_log(LOG_DEBUG, "Acked pending invite %d\n", p->pendinginvite);
    				p->pendinginvite = 0;
    			}
    
    			/* this is our baby */
    
    			UNLINK(cur, p->packets, prev);
    
    			if (cur->retransid > -1) {
    
    					ast_log(LOG_DEBUG, "** SIP TIMER: Cancelling retransmit of packet (reply received) Retransid #%d\n", cur->retransid);
    
    				ast_sched_del(sched, cur->retransid);
    
    			if (!reset)
    				free(cur);
    
    	ast_mutex_unlock(&p->lock);
    
    	if (option_debug)
    		ast_log(LOG_DEBUG, "Stopping retransmission on '%s' of %s %d: Match %s\n", p->callid, resp ? "Response" : "Request", seqno, res ? "Not Found" : "Found");
    
    /*! \brief Pretend to ack all packets */
    
    /* maybe the lock on p is not strictly necessary but there might be a race */
    
    static int __sip_pretend_ack(struct sip_pvt *p)
    {
    
    	struct sip_pkt *cur = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (cur == p->packets) {
    
    			ast_log(LOG_WARNING, "Have a packet that doesn't want to give up! %s\n", sip_methods[cur->method].text);
    
    			return -1;
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		cur = p->packets;
    
    		method = (cur->method) ? cur->method : find_sip_method(cur->data);
    		__sip_ack(p, cur->seqno, ast_test_flag(cur, FLAG_RESPONSE), method, FALSE);
    
    /*! \brief Acks receipt of packet, keep it around (used for provisional responses) */
    
    static int __sip_semi_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod)
    
    	int res = -1;
    
    	for (cur = p->packets; cur; cur = cur->next) {
    		if (cur->seqno == seqno && ast_test_flag(cur, FLAG_RESPONSE) == resp &&
    			(ast_test_flag(cur, FLAG_RESPONSE) || method_match(sipmethod, cur->data))) {
    
    			/* this is our baby */
    
    			if (cur->retransid > -1) {
    
    					ast_log(LOG_DEBUG, "*** SIP TIMER: Cancelling retransmission #%d - %s (got response)\n", cur->retransid, sip_methods[sipmethod].text);
    
    				ast_sched_del(sched, cur->retransid);
    
    			cur->retransid = -1;
    			res = 0;
    			break;
    		}
    	}
    
    	if (option_debug)
    		ast_log(LOG_DEBUG, "(Provisional) Stopping retransmission (but retaining packet) on '%s' %s %d: %s\n", p->callid, resp ? "Response" : "Request", seqno, res ? "Not Found" : "Found");
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    
    /*! \brief Copy SIP request, parse it */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static void parse_copy(struct sip_request *dst, struct sip_request *src)
    {
    	memset(dst, 0, sizeof(*dst));
    	memcpy(dst->data, src->data, sizeof(dst->data));
    	dst->len = src->len;
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    /* add a blank line if no body */
    static void add_blank(struct sip_request *req)
    {
    	if (!req->lines) {
    		/* Add extra empty return. add_header() reserves 4 bytes so cannot be truncated */
    		snprintf(req->data + req->len, sizeof(req->data) - req->len, "\r\n");
    		req->len += strlen(req->data + req->len);
    	}
    }
    
    
    /*! \brief Transmit response on SIP request*/
    
    static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	int res;
    
    		if (ast_test_flag(&p->flags[0], SIP_NAT_ROUTE))
    
    			ast_verbose("%sTransmitting (NAT) to %s:%d:\n%s\n---\n", reliable ? "Reliably " : "", ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr), ntohs(p->recv.sin_port), req->data);
    
    			ast_verbose("%sTransmitting (no NAT) to %s:%d:\n%s\n---\n", reliable ? "Reliably " : "", ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), ntohs(p->sa.sin_port), req->data);
    
    	if (recordhistory) {
    		struct sip_request tmp;
    		parse_copy(&tmp, req);
    
    		append_history(p, reliable ? "TxRespRel" : "TxResp", "%s / %s - %s", tmp.data, get_header(&tmp, "CSeq"), 
    			tmp.method == SIP_RESPONSE ? tmp.rlPart2 : sip_methods[tmp.method].text);
    
    		__sip_reliable_xmit(p, seqno, 1, req->data, req->len, (reliable == XMIT_CRITICAL), req->method) :
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (res > 0)
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    
    /*! \brief Send SIP Request to the other part of the dialogue */
    
    static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	int res;
    
    		if (ast_test_flag(&p->flags[0], SIP_NAT_ROUTE))
    
    			ast_verbose("%sTransmitting (NAT) to %s:%d:\n%s\n---\n", reliable ? "Reliably " : "", ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr), ntohs(p->recv.sin_port), req->data);
    
    			ast_verbose("%sTransmitting (no NAT) to %s:%d:\n%s\n---\n", reliable ? "Reliably " : "", ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), ntohs(p->sa.sin_port), req->data);
    
    	if (recordhistory) {
    		struct sip_request tmp;
    		parse_copy(&tmp, req);
    
    		append_history(p, reliable ? "TxReqRel" : "TxReq", "%s / %s - %s", tmp.data, get_header(&tmp, "CSeq"), sip_methods[tmp.method].text);
    
    	res = (reliable) ?
    		__sip_reliable_xmit(p, seqno, 0, req->data, req->len, (reliable > 1), req->method) :
    		__sip_xmit(p, req->data, req->len);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    
    /*! \brief Pick out text in brackets from character string
    	\return pointer to terminated stripped string
    	\param tmp input string that will be modified */
    
    static char *get_in_brackets(char *tmp)
    
    	char *parse;
    	char *first_quote;
    	char *first_bracket;
    	char *second_bracket;
    	char last_char;
    
    	parse = tmp;
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	for (;;) {
    
    		first_quote = strchr(parse, '"');
    		first_bracket = strchr(parse, '<');
    		if (first_quote && first_bracket && (first_quote < first_bracket)) {
    			last_char = '\0';
    			for (parse = first_quote + 1; *parse; parse++) {
    				if ((*parse == '"') && (last_char != '\\'))
    					break;
    				last_char = *parse;
    			}
    			if (!*parse) {
    				ast_log(LOG_WARNING, "No closing quote found in '%s'\n", tmp);
    				return tmp;
    			}
    			parse++;
    			continue;
    
    		if (first_bracket) {
    			second_bracket = strchr(first_bracket + 1, '>');
    			if (second_bracket) {
    				*second_bracket = '\0';
    				return first_bracket + 1;
    			} else {
    				ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp);
    				return tmp;
    			}
    		}
    		return tmp;
    
    /*! \brief Send SIP MESSAGE text within a call
    	Called from PBX core sendtext() application */
    
    static int sip_sendtext(struct ast_channel *ast, const char *text)
    
    	int debug = sip_debug_test_pvt(p);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_verbose("Sending text %s on %s\n", text, ast->name);
    	if (!p)
    		return -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return 0;
    
    	if (debug)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_verbose("Really sending text %s on %s\n", text, ast->name);
    	transmit_message_with_text(p, text);
    	return 0;	
    
    /*! \brief Update peer object in realtime storage */
    
    static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, const char *fullcontact, int expirey)
    
    	char port[10];
    	char ipaddr[20];
    
    	char regseconds[20];
    	time_t nowtime;
    
    	const char *fc = fullcontact ? "fullcontact" : NULL;
    
    	
    	time(&nowtime);
    	nowtime += expirey;
    	snprintf(regseconds, sizeof(regseconds), "%d", (int)nowtime);	/* Expiration time */
    	ast_inet_ntoa(ipaddr, sizeof(ipaddr), sin->sin_addr);
    	snprintf(port, sizeof(port), "%d", ntohs(sin->sin_port));
    
    	ast_update_realtime("sippeers", "name", peername, "ipaddr", ipaddr,
    		"port", port, "regseconds", regseconds,
    		"username", username, fc, fullcontact, NULL); /* note fc _can_ be NULL */
    
    /*! \brief Automatically add peer extension to dial plan */
    
    static void register_peer_exten(struct sip_peer *peer, int onoff)
    
    	char *stringp, *ext;
    
    	if (!ast_strlen_zero(global_regcontext)) {
    
    
    		ast_copy_string(multi, S_OR(peer->regexten, peer->name), sizeof(multi));
    
    		stringp = multi;
    		while((ext = strsep(&stringp, "&"))) {
    			if (onoff)
    
    				ast_add_extension(global_regcontext, 1, ext, 1, NULL, NULL, "Noop",
    
    						  ast_strdup(peer->name), free, "SIP");
    
    				ast_context_remove_extension(global_regcontext, ext, 1, NULL);
    
    /*! \brief Destroy peer object from memory */
    
    static void sip_destroy_peer(struct sip_peer *peer)
    
    	if (option_debug > 2)
    		ast_log(LOG_DEBUG, "Destroying SIP peer %s\n", peer->name);
    
    
    	/* Delete it, it needs to disappear */
    	if (peer->call)
    		sip_destroy(peer->call);
    
    
    	if (peer->mwipvt) {	/* We have an active subscription, delete it */
    		sip_destroy(peer->mwipvt);
    	}
    
    
    	if (peer->chanvars) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_variables_destroy(peer->chanvars);
    		peer->chanvars = NULL;
    	}
    
    	if (peer->expire > -1)
    		ast_sched_del(sched, peer->expire);
    	if (peer->pokeexpire > -1)
    		ast_sched_del(sched, peer->pokeexpire);
    
    	ast_free_ha(peer->ha);
    
    	if (ast_test_flag(&peer->flags[1], SIP_PAGE2_SELFDESTRUCT))
    
    	else if (ast_test_flag(&peer->flags[0], SIP_REALTIME))
    
    	clear_realm_authentication(peer->auth);
    
    	if (peer->dnsmgr)
    		ast_dnsmgr_release(peer->dnsmgr);
    
    	free(peer);
    
    /*! \brief Update peer data in database (if used) */
    
    static void update_peer(struct sip_peer *p, int expiry)
    
    	int rtcachefriends = ast_test_flag(&p->flags[1], SIP_PAGE2_RTCACHEFRIENDS);