Skip to content
Snippets Groups Projects
chan_sip.c 586 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	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 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 */
    
    	enum transfermodes allowtransfer;	/*! SIP Refer restriction scheme */
    
    	char vmexten[AST_MAX_EXTENSION]; /*!< Dialplan extension for MWI notify message*/
    	char mailbox[AST_MAX_EXTENSION]; /*!< Mailbox setting for MWI checks */
    	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;
    
    	time_t	lastmsgcheck;		/*!<  Last time we checked for MWI */
    	unsigned int sipoptions;	/*!<  Supported SIP options */
    
    	struct ast_flags flags[2];	/*!<  SIP_ flags */
    
    	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 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 */
    	struct timeval ps;		/*!<  Ping send time */
    
    	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 */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int lastmsg;
    
    /*! \brief Registrations with other SIP proxies */
    
    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(contact);	/*!< Contact extension */
    		AST_STRING_FIELD(random);
    	);
    
    	int portno;			/*!<  Optional port override */
    	int expire;			/*!< Sched ID of expiration */
    	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) */
    
    	time_t regtime;		/*!< Last succesful 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 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 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);
    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 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(void *data);
    static int transmit_sip_request(struct sip_pvt *p, struct sip_request *req);
    
    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);
    
    static int transmit_info_with_digit(struct sip_pvt *p, const 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_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);
    
    static int transmit_state_notify(struct sip_pvt *p, int state, int full);
    
    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);
    static int does_peer_need_mwi(struct sip_peer *peer);
    
    
    /*--- 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 void sip_scheddestroy(struct sip_pvt *p, int ms);
    static void 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 void __sip_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod, int reset);
    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(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 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,
    			     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 */
    
    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 do_proxy_auth(struct sip_pvt *p, struct sip_request *req, char *header, char *respheader, int sipmethod, int init);
    static int build_reply_digest(struct sip_pvt *p, int method, char* digest, int digest_len);
    
    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);
    
    /*--- SIP realm authentication */
    static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, char *configuration, int lineno);
    static int clear_realm_authentication(struct sip_auth *authlist);
    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(void *data);
    static int sip_sipredirect(struct sip_pvt *p, const char *dest);
    
    static void *do_monitor(void *data);
    
    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_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 handling */
    static int cb_extensionstate(char *context, char* exten, int state, void *data);
    static int sip_devicestate(void *data);
    static int sip_poke_noanswer(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);
    
    
    /*--- Applications, functions, CLI and manager command helpers */
    
    static const char *sip_nat_mode(const struct sip_pvt *p);
    
    static int sip_show_inuse(int fd, int argc, char *argv[]);
    
    static char *transfermode2str(enum transfermodes mode) attribute_const;
    static char *nat2str(int nat) attribute_const;
    
    static int peer_status(struct sip_peer *peer, char *status, int statuslen);
    static int sip_show_users(int fd, int argc, char *argv[]);
    static int _sip_show_peers(int fd, int *total, struct mansession *s, struct message *m, int argc, char *argv[]);
    static int manager_sip_show_peers( struct mansession *s, struct message *m );
    static int sip_show_peers(int fd, int argc, char *argv[]);
    static int sip_show_objects(int fd, int argc, char *argv[]);
    static void  print_group(int fd, unsigned int group, int crlf);
    
    static const char *dtmfmode2str(int mode) attribute_const;
    static const char *insecure2str(int port, int invite) 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);
    static int sip_show_domains(int fd, int argc, char *argv[]);
    static int _sip_show_peer(int type, int fd, struct mansession *s, struct message *m, int argc, char *argv[]);
    static int manager_sip_show_peer( struct mansession *s, struct message *m);
    static int sip_show_peer(int fd, int argc, char *argv[]);
    static int _sip_show_peer(int type, int fd, struct mansession *s, struct message *m, int argc, char *argv[]);
    static int sip_show_user(int fd, int argc, char *argv[]);
    static int sip_show_registry(int fd, int argc, char *argv[]);
    static int sip_show_settings(int fd, int argc, char *argv[]);
    
    static const char *subscription_type2str(enum subscriptiontype subtype) attribute_pure;
    
    static const struct cfsubscription_types *find_subscription_type(enum subscriptiontype subtype);
    static int __sip_show_channels(int fd, int argc, char *argv[], int subscriptions);
    static int sip_show_channels(int fd, int argc, char *argv[]);
    static int sip_show_subscriptions(int fd, int argc, char *argv[]);
    static int __sip_show_channels(int fd, int argc, char *argv[], int subscriptions);
    static char *complete_sipch(const char *line, const char *word, int pos, int state);
    static char *complete_sip_peer(const char *word, int state, int flags2);
    static char *complete_sip_show_peer(const char *line, const char *word, int pos, int state);
    static char *complete_sip_debug_peer(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);
    static char *complete_sip_prune_realtime_peer(const char *line, const char *word, int pos, int state);
    static char *complete_sip_prune_realtime_user(const char *line, const char *word, int pos, int state);
    static int sip_show_channel(int fd, int argc, char *argv[]);
    static int sip_show_history(int fd, int argc, char *argv[]);
    static int sip_do_debug_ip(int fd, int argc, char *argv[]);
    static int sip_do_debug_peer(int fd, int argc, char *argv[]);
    static int sip_do_debug(int fd, int argc, char *argv[]);
    static int sip_no_debug(int fd, int argc, char *argv[]);
    static int sip_notify(int fd, int argc, char *argv[]);
    static int sip_do_history(int fd, int argc, char *argv[]);
    static int sip_no_history(int fd, int argc, char *argv[]);
    static int func_header_read(struct ast_channel *chan, char *function, char *data, char *buf, size_t len);
    static int func_check_sipdomain(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len);
    static int function_sippeer(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len);
    static int function_sipchaninfo_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len);
    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);
    static int sip_reload(int fd, int argc, char *argv[]);
    
    /*--- 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 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 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, 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);
    
    static int sip_poke_peer_s(void *data);
    static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_request *req);
    static int expire_register(void *data);
    static void reg_source_db(struct sip_peer *peer);
    static void destroy_association(struct sip_peer *peer);
    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 sip_peer *realtime_peer(const char *peername, struct sockaddr_in *sin);
    
    static int sip_prune_realtime(int fd, int argc, char *argv[]);
    
    
    /*--- Internal UA client handling (outbound registrations) */
    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);
    
    static char *regstate2str(enum sipregistrystate regstate) attribute_const;
    
    static int sip_reregister(void *data);
    static int __sip_do_register(struct sip_registry *r);
    static int sip_reg_timeout(void *data);
    static int do_register_auth(struct sip_pvt *p, struct sip_request *req, char *header, char *respheader);
    static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header, int sipmethod,  char *digest, int digest_len);
    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 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 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);
    
    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 const char *gettag(const struct sip_request *req, const char *header, char *tagbuf, int tagbufsize);
    static void free_old_route(struct sip_route *route);
    
    
    /*--- 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);
    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_request(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);
    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);
    
    static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int ignore, 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 handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int ignore, int seqno, struct sockaddr_in *sin);
    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_peerpoke(struct sip_pvt *p, int resp, struct sip_request *req);
    
    static int handle_response_register(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int ignore, int seqno);
    static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int ignore, int seqno);
    
    /*----- 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 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 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); /*!< T38 negotiation helper function */
    static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
    static int transmit_reinvite_with_t38_sdp(struct sip_pvt *p);
    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_MAX_AUDIO << 1) - 1),
    
    	.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
    
    	.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 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 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 (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;
    
    		if (!found && option_debug > 2 && sipdebug) {
    			if (!strncasecmp(next, "x-", 2))
    				ast_log(LOG_DEBUG, "Found private SIP option, not supported: %s\n", next);
    			else
    				ast_log(LOG_DEBUG, "Found no match for SIP option: %s (Please file bug report!)\n", next);
    		}
    
    	if (pvt)
    		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;
    
    	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(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)
    
    	/* 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",
    
    			 ast_inet_ntoa(p->ourip), ourport, p->branch, rport);
    
    /*! \brief NAT fix - decide which IP address to use for ASterisk server?
    
     *
     * Using the localaddr structure built up with localnet statements in sip.conf
     * apply it to their address to see if we need to substitute our
     * externip or can get away with our internal bindaddr
     */
    
    static enum sip_result ast_sip_ouraddrfor(struct in_addr *them, struct in_addr *us)
    
    	struct sockaddr_in theirs, ours;
    
    	/* Get our local information */
    	ast_ouraddrfor(them, us);
    
    	if (localaddr && externip.sin_addr.s_addr &&
    
    	    ast_apply_ha(localaddr, &theirs) &&
    	    !ast_apply_ha(localaddr, &ours)) {
    
    		if (externexpire && time(NULL) >= externexpire) {
    
    			struct ast_hostent ahp;
    			struct hostent *hp;
    
    			externexpire = time(NULL) + 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);
    		}
    
    			ast_log(LOG_DEBUG, "Target address %s is not local, substituting externip\n", 
    				ast_inet_ntoa(*(struct in_addr *)&them->s_addr));
    
    		}
    	} else if (bindaddr.sin_addr.s_addr)
    
    	return AST_SUCCESS;
    
    /*! \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, ...)
    
    /*! \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 void 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);
    
    /*! \brief Retransmit SIP message if no answer (Called from scheduler) */
    
    static int retrans_pkt(void *data)
    {
    
    	struct sip_pkt *pkt = data, *prev, *cur = NULL;
    
    	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 (sip_debug_test_pvt(pkt->owner)) {
    			const struct sockaddr_in *dst = sip_real_dst(pkt->owner);
    			ast_verbose("Retransmitting #%d (%s) to %s:%d:\n%s\n---\n",
    				pkt->retrans, sip_nat_mode(pkt->owner),
    
    				ntohs(dst->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_channel_trylock(pkt->owner->owner)) {
    			ast_mutex_unlock(&pkt->owner->lock);	/* SIP_PVT, not channel */
    
    			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 enum sip_result __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)))
    
    	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);
    
    Olle Johansson's avatar
    Olle Johansson committed
    	append_history(p, "AutoDestroy", "%s", 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 if (p->refer) {
    		transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);
    
    	} else {
    		sip_destroy(p);
    	}
    	return 0;
    }
    
    
    /*! \brief Schedule destruction of SIP call */
    
    static void 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);
    }
    
    
    /*! \brief Cancel destruction of SIP dialog */
    
    static void sip_cancel_destroy(struct sip_pvt *p)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	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
    }
    
    
    /*! \brief Acknowledges receipt of a packet and stops retransmission */
    
    static void __sip_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod, int reset)
    
    {
    	struct sip_pkt *cur, *prev = NULL;
    
    	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);
    
    			break;