Skip to content
Snippets Groups Projects
chan_sip.c 372 KiB
Newer Older
  • Learn to ignore specific revisions
  • Mark Spencer's avatar
    Mark Spencer committed
    /*
     * Asterisk -- A telephony toolkit for Linux.
     *
     * Implementation of Session Initiation Protocol
     * 
    
     * Copyright (C) 2004 - 2005, Digium, Inc.
    
    Mark Spencer's avatar
    Mark Spencer committed
     *
    
     * Mark Spencer <markster@digium.com>
    
    Mark Spencer's avatar
    Mark Spencer committed
     *
     * This program is free software, distributed under the terms of
     * the GNU General Public License
     */
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <stdio.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <ctype.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <string.h>
    
    #include <sys/socket.h>
    #include <sys/ioctl.h>
    #include <net/if.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <netdb.h>
    #include <signal.h>
    #include <sys/signal.h>
    
    #include <netinet/ip.h>
    #include <regex.h>
    
    #include "asterisk.h"
    
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
    
    #include "asterisk/lock.h"
    #include "asterisk/channel.h"
    #include "asterisk/config.h"
    #include "asterisk/logger.h"
    #include "asterisk/module.h"
    #include "asterisk/pbx.h"
    #include "asterisk/options.h"
    #include "asterisk/lock.h"
    #include "asterisk/sched.h"
    #include "asterisk/io.h"
    #include "asterisk/rtp.h"
    #include "asterisk/acl.h"
    #include "asterisk/manager.h"
    #include "asterisk/callerid.h"
    #include "asterisk/cli.h"
    #include "asterisk/app.h"
    #include "asterisk/musiconhold.h"
    #include "asterisk/dsp.h"
    #include "asterisk/features.h"
    #include "asterisk/acl.h"
    #include "asterisk/srv.h"
    #include "asterisk/astdb.h"
    #include "asterisk/causes.h"
    #include "asterisk/utils.h"
    #include "asterisk/file.h"
    #include "asterisk/astobj.h"
    #include "asterisk/dnsmgr.h"
    
    #ifdef OSP_SUPPORT
    
    #ifndef DEFAULT_USERAGENT
    #define DEFAULT_USERAGENT "Asterisk PBX"
    #endif
     
    
    #define VIDEO_CODEC_MASK        0x1fc0000 /* Video codecs from H.261 thru AST_FORMAT_MAX_VIDEO */
    
    Mark Spencer's avatar
    Mark Spencer committed
    #ifndef IPTOS_MINCOST
    #define IPTOS_MINCOST 0x02
    #endif
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    /* #define VOCAL_DATA_HACK */
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    #define SIPDUMPER
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define DEFAULT_DEFAULT_EXPIRY  120
    #define DEFAULT_MAX_EXPIRY      3600
    
    #define DEFAULT_REGISTRATION_TIMEOUT	20
    
    
    /* guard limit must be larger than guard secs */
    
    /* guard min must be < 1000, and should be >= 250 */
    
    #define EXPIRY_GUARD_SECS	15	/* How long before expiry do we reregister */
    
    #define EXPIRY_GUARD_LIMIT      30	/* Below here, we use EXPIRY_GUARD_PCT instead of 
    					   EXPIRY_GUARD_SECS */
    #define EXPIRY_GUARD_MIN	500	/* This is the minimum guard time applied. If 
    					   GUARD_PCT turns out to be lower than this, it 
    					   will use this time instead.
    					   This is in milliseconds. */
    #define EXPIRY_GUARD_PCT        0.20	/* Percentage of expires timeout to use when 
    					   below EXPIRY_GUARD_LIMIT */
    
    static int max_expiry = DEFAULT_MAX_EXPIRY;
    static int default_expiry = DEFAULT_DEFAULT_EXPIRY;
    
    
    #ifndef MAX
    #define MAX(a,b) ((a) > (b) ? (a) : (b))
    #endif
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define DEFAULT_MAXMS		2000		/* Must be faster than 2 seconds by default */
    
    #define DEFAULT_FREQ_OK		60 * 1000	/* How often to check for the host to be up */
    #define DEFAULT_FREQ_NOTOK	10 * 1000	/* How often to check, if the host is down... */
    
    #define DEFAULT_RETRANS		2000		/* How frequently to retransmit */
    
    #define MAX_RETRANS		5		/* Try only 5 times for retransmissions */
    
    #define DEBUG_READ	0			/* Recieved data	*/
    #define DEBUG_SEND	1			/* Transmit data	*/
    
    static const char desc[] = "Session Initiation Protocol (SIP)";
    static const char channeltype[] = "SIP";
    static const char config[] = "sip.conf";
    static const char notify_config[] = "sip_notify.conf";
    
    #define SIP_REGISTER	1
    #define SIP_OPTIONS	2
    #define SIP_NOTIFY	3
    #define SIP_INVITE	4
    #define SIP_ACK		5
    #define SIP_PRACK	6
    #define SIP_BYE		7
    #define SIP_REFER	8
    #define SIP_SUBSCRIBE	9
    #define SIP_MESSAGE	10
    #define SIP_UPDATE	11
    #define SIP_INFO	12
    #define SIP_CANCEL	13
    #define SIP_PUBLISH	14
    #define SIP_RESPONSE	100
    
    
    const struct  cfsip_methods { 
    	int id;
    
    	int need_rtp;		/* when this is the 'primary' use for a pvt structure, does it need RTP? */
    
    	char *text;
    } sip_methods[] = {
    
    	{ 0,		 RTP, "-UNKNOWN-" },
    	{ SIP_REGISTER,	 NO_RTP, "REGISTER" },
     	{ SIP_OPTIONS,	 NO_RTP, "OPTIONS" },
    	{ SIP_NOTIFY,	 NO_RTP, "NOTIFY" },
    	{ SIP_INVITE,	 RTP, "INVITE" },
    	{ SIP_ACK,	 NO_RTP, "ACK" },
    	{ SIP_PRACK,	 NO_RTP, "PRACK" },
    	{ SIP_BYE,	 NO_RTP, "BYE" },
    	{ SIP_REFER,	 NO_RTP, "REFER" },
    	{ SIP_SUBSCRIBE, NO_RTP, "SUBSCRIBE" },
    	{ SIP_MESSAGE,	 NO_RTP, "MESSAGE" },
    	{ SIP_UPDATE,	 NO_RTP, "UPDATE" },
    	{ SIP_INFO,	 NO_RTP, "INFO" },
    	{ SIP_CANCEL,	 NO_RTP, "CANCEL" },
    	{ SIP_PUBLISH,	 NO_RTP, "PUBLISH" }
    
    /* Structure for conversion between compressed SIP and "normal" SIP */
    static struct cfalias {
    	char *fullname;
    	char *shortname;
    } aliases[] = {
    	{ "Content-Type", "c" },
    	{ "Content-Encoding", "e" },
    	{ "From", "f" },
    	{ "Call-ID", "i" },
    	{ "Contact", "m" },
    	{ "Content-Length", "l" },
    	{ "Subject", "s" },
    	{ "To", "t" },
    	{ "Supported", "k" },
    	{ "Refer-To", "r" },
    
    	{ "Referred-By", "b" },
    
    	{ "Allow-Events", "u" },
    	{ "Event", "o" },
    	{ "Via", "v" },
    };
    
    
    /* Define SIP option tags, used in Require: and Supported: headers */
    /* 	We need to be aware of these properties in the phones to use 
    	the replace: header. We should not do that without knowing
    	that the other end supports it... 
    	This is nothing we can configure, we learn by the dialog
    	Supported: header on the REGISTER (peer) or the INVITE
    	(other devices)
    	We are not using many of these today, but will in the future.
    	This is documented in RFC 3261
    */
    #define SUPPORTED		1
    #define NOT_SUPPORTED		0
    
    #define SIP_OPT_REPLACES	(1 << 0)
    #define SIP_OPT_100REL		(1 << 1)
    #define SIP_OPT_TIMER		(1 << 2)
    #define SIP_OPT_EARLY_SESSION	(1 << 3)
    #define SIP_OPT_JOIN		(1 << 4)
    #define SIP_OPT_PATH		(1 << 5)
    #define SIP_OPT_PREF		(1 << 6)
    #define SIP_OPT_PRECONDITION	(1 << 7)
    #define SIP_OPT_PRIVACY		(1 << 8)
    #define SIP_OPT_SDP_ANAT	(1 << 9)
    #define SIP_OPT_SEC_AGREE	(1 << 10)
    #define SIP_OPT_EVENTLIST	(1 << 11)
    #define SIP_OPT_GRUU		(1 << 12)
    #define SIP_OPT_TARGET_DIALOG	(1 << 13)
    
    /* List of well-known SIP options. If we get this in a require,
       we should check the list and answer accordingly. */
    const struct cfsip_options {
    	int id;			/* Bitmap ID */
    	int supported;		/* Supported by Asterisk ? */
    	char *text;		/* Text id, as in standard */
    } sip_options[] = {
    	/* Replaces: header for transfer */
    	{ SIP_OPT_REPLACES,	SUPPORTED,	"replaces" },	
    	/* RFC3262: PRACK 100% reliability */
    	{ SIP_OPT_100REL,	NOT_SUPPORTED,	"100rel" },	
    	/* SIP Session Timers */
    	{ SIP_OPT_TIMER,	NOT_SUPPORTED,	"timer" },
    	/* RFC3959: SIP Early session support */
    	{ SIP_OPT_EARLY_SESSION, NOT_SUPPORTED,	"early-session" },
    	/* SIP Join header support */
    	{ SIP_OPT_JOIN,		NOT_SUPPORTED,	"join" },
    	/* RFC3327: Path support */
    	{ SIP_OPT_PATH,		NOT_SUPPORTED,	"path" },
    	/* RFC3840: Callee preferences */
    	{ SIP_OPT_PREF,		NOT_SUPPORTED,	"pref" },
    	/* RFC3312: Precondition support */
    	{ SIP_OPT_PRECONDITION,	NOT_SUPPORTED,	"precondition" },
    	/* RFC3323: Privacy with proxies*/
    	{ SIP_OPT_PRIVACY,	NOT_SUPPORTED,	"privacy" },
    	/* Not yet RFC, but registred with IANA */
    	{ SIP_OPT_SDP_ANAT,	NOT_SUPPORTED,	"sdp_anat" },
    	/* RFC3329: Security agreement mechanism */
    	{ SIP_OPT_SEC_AGREE,	NOT_SUPPORTED,	"sec_agree" },
    	/* SIMPLE events:  draft-ietf-simple-event-list-07.txt */
    	{ SIP_OPT_EVENTLIST,	NOT_SUPPORTED,	"eventlist" },
    	/* GRUU: Globally Routable User Agent URI's */
    	{ SIP_OPT_GRUU,		NOT_SUPPORTED,	"gruu" },
    	/* Target-dialog: draft-ietf-sip-target-dialog-00.txt */
    	{ SIP_OPT_TARGET_DIALOG,NOT_SUPPORTED,	"target-dialog" },
    };
    
    #define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY"
    
    /* SIP Extensions we support */
    #define SUPPORTED_EXTENSIONS "replaces" 
    
    #define DEFAULT_SIP_PORT	5060	/* From RFC 3261 (former 2543) */
    #define SIP_MAX_PACKET		4096	/* Also from RFC 3261 (2543), should sub headers tho */
    
    
    static char default_useragent[AST_MAX_EXTENSION] = DEFAULT_USERAGENT;
    
    #define DEFAULT_CONTEXT "default"
    
    static char default_context[AST_MAX_CONTEXT] = DEFAULT_CONTEXT;
    
    static char default_language[MAX_LANGUAGE] = "";
    
    #define DEFAULT_CALLERID "asterisk"
    static char default_callerid[AST_MAX_EXTENSION] = DEFAULT_CALLERID;
    
    static char default_fromdomain[AST_MAX_EXTENSION] = "";
    
    #define DEFAULT_NOTIFYMIME "application/simple-message-summary"
    static char default_notifymime[AST_MAX_EXTENSION] = DEFAULT_NOTIFYMIME;
    
    
    static int default_qualify = 0;		/* Default Qualify= setting */
    
    
    static struct ast_flags global_flags = {0};		/* global SIP_ flags */
    
    static struct ast_flags global_flags_page2 = {0};	/* more global SIP_ flags */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int srvlookup = 0;		/* SRV Lookup on or off. Default is off, RFC behavior is on */
    
    static int pedanticsipchecking = 0;	/* Extra checking ?  Default off */
    
    static int autocreatepeer = 0;		/* Auto creation of peers at registration? Default off. */
    
    static int relaxdtmf = 0;
    
    
    static int global_rtpkeepalive = 0;
    
    
    static int global_reg_timeout = DEFAULT_REGISTRATION_TIMEOUT;	
    static int global_regattempts_max = DEFAULT_REGATTEMPTS_MAX;
    
    /* Object counters */
    static int suserobjs = 0;
    static int ruserobjs = 0;
    static int speerobjs = 0;
    static int rpeerobjs = 0;
    static int apeerobjs = 0;
    static int regobjs = 0;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int global_allowguest = 1;    /* allow unauthenticated users/peers to connect? */
    
    #define DEFAULT_MWITIME 10
    static int global_mwitime = DEFAULT_MWITIME;	/* Time between MWI checks for peers */
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int usecnt =0;
    
    AST_MUTEX_DEFINE_STATIC(usecnt_lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    /* Protect the interface list (of sip_pvt's) */
    
    AST_MUTEX_DEFINE_STATIC(iflock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    /* Protect the monitoring thread, so only one process can kill or start it, and not
       when it's doing something critical. */
    
    AST_MUTEX_DEFINE_STATIC(netlock);
    
    AST_MUTEX_DEFINE_STATIC(monlock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    /* This is the thread for the monitor which checks for input on the channels
       which are not currently in use.  */
    
    static pthread_t monitor_thread = AST_PTHREADT_NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    static int restart_monitor(void);
    
    
    /* Codecs that we support by default: */
    
    static int global_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263;
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int noncodeccapability = AST_RTP_DTMF;
    
    Mark Spencer's avatar
    Mark Spencer committed
    static struct in_addr __ourip;
    
    static struct sockaddr_in outboundproxyip;
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int ourport;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sipdebug = 0;
    
    static struct sockaddr_in debugaddr;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    static int tos = 0;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int compactheaders = 0;				/* send compact sip headers */
    
    static int recordhistory = 0;				/* Record SIP history. Off by default */
    
    static char global_musicclass[MAX_MUSICCLASS] = "";	/* Global music on hold class */
    
    #define DEFAULT_REALM	"asterisk"
    
    static char global_realm[MAXHOSTNAMELEN] = DEFAULT_REALM; 	/* Default realm */
    
    static char regcontext[AST_MAX_CONTEXT] = "";		/* Context for auto-extensions */
    
    Mark Spencer's avatar
    Mark Spencer committed
    /* Expire slowly */
    
    #define DEFAULT_EXPIRY 900
    static int expiry = DEFAULT_EXPIRY;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    static struct sched_context *sched;
    static struct io_context *io;
    /* The private structures of the  sip channels are linked for
       selecting outgoing channels */
       
    #define SIP_MAX_HEADERS		64
    #define SIP_MAX_LINES 		64
    
    
    #define DEC_IN_USE	0
    #define INC_IN_USE	1
    #define DEC_OUT_USE	2
    #define INC_OUT_USE	3
    
    
    static struct ast_codec_pref prefs;
    
    
    /* sip_request: The data grabbed from the UDP socket */
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct sip_request {
    
    	char *rlPart1; 		/* SIP Method Name or "SIP/2.0" protocol version */
    	char *rlPart2; 		/* The Request URI or Response Status */
    	int len;		/* Length */
    	int headers;		/* # of SIP Headers */
    
    	int method;		/* Method of this request */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char *header[SIP_MAX_HEADERS];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char *line[SIP_MAX_LINES];
    	char data[SIP_MAX_PACKET];
    };
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct sip_pkt;
    
    
    /* Parameters to the transmit_invite function */
    struct sip_invite_param {
    	char *distinctive_ring;
    	char *osptoken;
    	int addsipheaders;
    	char *vxml_url;
    	char *auth;
    	char *authheader;
    };
    
    
    struct sip_route {
    	struct sip_route *next;
    	char hop[0];
    };
    
    
    /* sip_history: Structure for saving transactions within a SIP dialog */
    
    struct sip_history {
    	char event[80];
    	struct sip_history *next;
    };
    
    
    /* sip_auth: Creadentials for authentication to other SIP services */
    struct sip_auth {
    	char realm[AST_MAX_EXTENSION];  /* Realm in which these credentials are valid */
    	char username[256];             /* Username */
    	char secret[256];               /* Secret */
    	char md5secret[256];            /* MD5Secret */
    	struct sip_auth *next;          /* Next auth structure in list */
    };
    
    
    #define SIP_ALREADYGONE		(1 << 0)	/* Whether or not we've already been destroyed by our peer */
    #define SIP_NEEDDESTROY		(1 << 1)	/* if we need to be destroyed */
    #define SIP_NOVIDEO		(1 << 2)	/* Didn't get video in invite, don't offer */
    #define SIP_RINGING		(1 << 3)	/* Have sent 180 ringing */
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define SIP_PROGRESS_SENT	(1 << 4)	/* Have sent 183 message progress */
    
    #define SIP_NEEDREINVITE	(1 << 5)	/* Do we need to send another reinvite? */
    #define SIP_PENDINGBYE		(1 << 6)	/* Need to send bye after we ack? */
    #define SIP_GOTREFER		(1 << 7)	/* Got a refer? */
    #define SIP_PROMISCREDIR	(1 << 8)	/* Promiscuous redirection */
    #define SIP_TRUSTRPID		(1 << 9)	/* Trust RPID headers? */
    #define SIP_USEREQPHONE		(1 << 10)	/* Add user=phone to numeric URI. Default off */
    
    #define SIP_REALTIME		(1 << 11)	/* Flag for realtime users */
    
    #define SIP_USECLIENTCODE	(1 << 12)	/* Trust X-ClientCode info message */
    #define SIP_OUTGOING		(1 << 13)	/* Is this an outgoing call? */
    
    #define SIP_SELFDESTRUCT	(1 << 14)	
    #define SIP_DYNAMIC		(1 << 15)	/* Is this a dynamic peer? */
    
    /* --- Choices for DTMF support in SIP channel */
    #define SIP_DTMF		(3 << 16)	/* three settings, uses two bits */
    #define SIP_DTMF_RFC2833	(0 << 16)	/* RTP DTMF */
    #define SIP_DTMF_INBAND		(1 << 16)	/* Inband audio, only for ULAW/ALAW */
    #define SIP_DTMF_INFO		(2 << 16)	/* SIP Info messages */
    /* NAT settings */
    #define SIP_NAT			(3 << 18)	/* four settings, uses two bits */
    #define SIP_NAT_NEVER		(0 << 18)	/* No nat support */
    #define SIP_NAT_RFC3581		(1 << 18)
    #define SIP_NAT_ROUTE		(2 << 18)
    #define SIP_NAT_ALWAYS		(3 << 18)
    /* re-INVITE related settings */
    #define SIP_REINVITE		(3 << 20)	/* two bits used */
    
    #define SIP_CAN_REINVITE	(1 << 20)	/* allow peers to be reinvited to send media directly p2p */
    
    #define SIP_REINVITE_UPDATE	(2 << 20)	/* use UPDATE (RFC3311) when reinviting this peer */
    /* "insecure" settings */
    
    #define SIP_INSECURE_PORT	(1 << 22)	/* don't require matching port for incoming requests */
    #define SIP_INSECURE_INVITE	(1 << 23)	/* don't require authentication for incoming INVITEs */
    
    /* Sending PROGRESS in-band settings */
    #define SIP_PROG_INBAND		(3 << 24)	/* three settings, uses two bits */
    #define SIP_PROG_INBAND_NEVER	(0 << 24)
    #define SIP_PROG_INBAND_NO	(1 << 24)
    #define SIP_PROG_INBAND_YES	(2 << 24)
    /* Open Settlement Protocol authentication */
    #define SIP_OSPAUTH		(3 << 26)	/* three settings, uses two bits */
    #define SIP_OSPAUTH_NO		(0 << 26)
    #define SIP_OSPAUTH_YES		(1 << 26)
    #define SIP_OSPAUTH_EXCLUSIVE	(2 << 26)
    
    Mark Spencer's avatar
    Mark Spencer committed
    /* Call states */
    
    #define SIP_CALL_ONHOLD		(1 << 28)	 
    #define SIP_CALL_LIMIT		(1 << 29)
    
    /* a new page of flags for peer */
    
    #define SIP_PAGE2_RTCACHEFRIENDS 	(1 << 0)
    #define SIP_PAGE2_RTNOUPDATE 		(1 << 1)
    #define SIP_PAGE2_RTAUTOCLEAR 		(1 << 2)
    
    #define SIP_PAGE2_RTIGNOREREGEXPIRE       (1 << 3)
    
    
    static int global_rtautoclear = 120;
    
    
    /* sip_pvt: PVT structures are used for each SIP conversation, ie. a call  */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static struct sip_pvt {
    
    	ast_mutex_t lock;			/* Channel private lock */
    
    	int method;				/* SIP method of this packet */
    
    	char callid[80];			/* Global CallID */
    	char randdata[80];			/* Random data */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_codec_pref prefs;		/* codec prefs */
    
    	unsigned int ocseq;			/* Current outgoing seqno */
    	unsigned int icseq;			/* Current incoming seqno */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_group_t callgroup;			/* Call group */
    
    	ast_group_t pickupgroup;		/* Pickup group */
    
    	int lastinvite;				/* Last Cseq of invite */
    
    	unsigned int flags;			/* SIP_ flags */	
    
    	unsigned int sipoptions;		/* Supported SIP sipoptions on the other end */
    
    	int capability;				/* Special capability (codec) */
    	int jointcapability;			/* Supported capability at both ends (codecs ) */
    
    	int peercapability;			/* Supported peer capability */
    
    	int prefcodec;				/* Preferred codec (outbound only) */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int noncodeccapability;
    
    	int callingpres;			/* Calling presentation */
    
    	int authtries;				/* Times we've tried to authenticate */
    	int expiry;				/* How long we take to expire */
    	int branch;				/* One random number */
    	int tag;				/* Another random number */
    	int sessionid;				/* SDP Session ID */
    	int sessionversion;			/* SDP Session Version */
    	struct sockaddr_in sa;			/* Our peer */
    	struct sockaddr_in redirip;		/* Where our RTP should be going if not to us */
    
    	struct sockaddr_in vredirip;		/* Where our Video RTP should be going if not to us */
    
    	int redircodecs;			/* Redirect codecs */
    
    	struct sockaddr_in recv;		/* Received as */
    	struct in_addr ourip;			/* Our IP */
    	struct ast_channel *owner;		/* Who owns us */
    	char exten[AST_MAX_EXTENSION];		/* Extension where to start */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char refer_to[AST_MAX_EXTENSION];	/* Place to store REFER-TO extension */
    
    	char referred_by[AST_MAX_EXTENSION];	/* Place to store REFERRED-BY extension */
    	char refer_contact[AST_MAX_EXTENSION];	/* Place to store Contact info from a REFER extension */
    	struct sip_pvt *refer_call;		/* Call we are referring */
    	struct sip_route *route;		/* Head of linked list of routing steps (fm Record-Route) */
    	int route_persistant;			/* Is this the "real" route? */
    	char from[256];				/* The From: header */
    	char useragent[256];			/* User agent in SIP request */
    
    	char context[AST_MAX_CONTEXT];		/* Context for this call */
    
    	char fromdomain[MAXHOSTNAMELEN];	/* Domain to show in the from field */
    
    	char fromuser[AST_MAX_EXTENSION];	/* User to show in the user field */
    	char fromname[AST_MAX_EXTENSION];	/* Name to show in the user field */
    
    	char tohost[MAXHOSTNAMELEN];		/* Host we should put in the "to" field */
    
    	char language[MAX_LANGUAGE];		/* Default language for this call */
    
    	char musicclass[MAX_MUSICCLASS];          /* Music on Hold class */
    
    	char rdnis[256];			/* Referring DNIS */
    	char theirtag[256];			/* Their tag */
    
    	char username[256];			/* [user] name */
    	char peername[256];			/* [peer] name, not set if [user] */
    
    	char authname[256];			/* Who we use for authentication */
    	char uri[256];				/* Original requested URI */
    
    	char okcontacturi[256];			/* URI from the 200 OK on INVITE */
    
    	char peersecret[256];			/* Password */
    
    	char peermd5secret[256];
    
    	struct sip_auth *peerauth;		/* Realm authentication */
    
    	char cid_num[256];			/* Caller*ID */
    	char cid_name[256];			/* Caller*ID */
    
    	char via[256];				/* Via: header */
    	char fullcontact[128];			/* The Contact: that the UA registers with us */
    
    	char accountcode[AST_MAX_ACCOUNT_CODE];	/* Account code */
    
    	char our_contact[256];			/* Our contact header */
    
    	char realm[MAXHOSTNAMELEN];		/* Authorization realm */
    
    	char nonce[256];			/* Authorization nonce */
    	char opaque[256];			/* Opaque nonsense */
    
    	char qop[80];				/* Quality of Protection, since SIP wasn't complicated enough yet. */
    
    	char domain[MAXHOSTNAMELEN];		/* Authorization domain */
    
    	char lastmsg[256];			/* Last Message sent/received */
    	int amaflags;				/* AMA Flags */
    	int pendinginvite;			/* Any pending invite */
    
    #ifdef OSP_SUPPORT
    	int osphandle;				/* OSP Handle for call */
    	time_t ospstart;			/* OSP Start time */
    #endif
    
    	struct sip_request initreq;		/* Initial request */
    
    	int maxtime;				/* Max time for first response */
    
    	int maxforwards;			/* keep the max-forwards info */
    
    	int initid;				/* Auto-congest ID if appropriate */
    	int autokillid;				/* Auto-kill ID */
    
    	time_t lastrtprx;			/* Last RTP received */
    
    	time_t lastrtptx;			/* Last RTP sent */
    
    	int rtptimeout;				/* RTP timeout time */
    	int rtpholdtimeout;			/* RTP timeout when on hold */
    
    	int rtpkeepalive;			/* Send RTP packets for keepalive */
    
    	int subscribed;				/* Is this call a subscription?  */
    
    	int stateid;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_dsp *vad;			/* Voice Activation Detection dsp */
    
    	struct sip_peer *peerpoke;		/* If this calls is to poke a peer, which one */
    	struct sip_registry *registry;		/* If this is a REGISTER call, to which registry */
    	struct ast_rtp *rtp;			/* RTP Session */
    	struct ast_rtp *vrtp;			/* Video RTP session */
    	struct sip_pkt *packets;		/* Packets scheduled for re-transmission */
    
    	struct sip_history *history;		/* History of this SIP dialog */
    
    	struct ast_variable *chanvars;		/* Channel variables to set for call */
    
    	struct sip_pvt *next;			/* Next call in chain */
    
    Mark Spencer's avatar
    Mark Spencer committed
    } *iflist = NULL;
    
    
    #define FLAG_RESPONSE (1 << 0)
    #define FLAG_FATAL (1 << 1)
    
    
    /* sip packet - read in sipsock_read, transmitted in send_request */
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct sip_pkt {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sip_pkt *next;			/* Next packet */
    	int retrans;				/* Retransmission number */
    	int seqno;				/* Sequence number */
    	unsigned int flags;			/* non-zero if this is a response packet (e.g. 200 OK) */
    	struct sip_pvt *owner;			/* Owner call */
    	int retransid;				/* Retransmission ID */
    	int packetlen;				/* Length of packet */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char data[0];
    };	
    
    /* Structure for SIP user data. User's place calls to us */
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct sip_user {
    	/* Users who can access various contexts */
    
    	char secret[80];		/* Password */
    	char md5secret[80];		/* Password in md5 */
    
    	char context[AST_MAX_CONTEXT];	/* Default context for incoming calls */
    
    	char cid_num[80];		/* Caller ID num */
    	char cid_name[80];		/* Caller ID name */
    
    	char accountcode[AST_MAX_ACCOUNT_CODE];	/* Account code */
    
    	char language[MAX_LANGUAGE];	/* Default language for this user */
    
    	char musicclass[MAX_MUSICCLASS];/* Music on Hold class */
    
    	char useragent[256];		/* User agent in SIP request */
    
    	struct ast_codec_pref prefs;	/* codec prefs */
    	ast_group_t callgroup;		/* Call group */
    
    	ast_group_t pickupgroup;	/* Pickup Group */
    
    	unsigned int flags;		/* SIP flags */	
    	unsigned int sipoptions;	/* Supported SIP options */
    
    	struct ast_flags flags_page2;	/* SIP_PAGE2 flags */
    
    	int amaflags;			/* AMA flags for billing */
    	int callingpres;		/* Calling id presentation */
    	int capability;			/* Codec capability */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int inUse;			/* Number of calls in use */
    	int incominglimit;		/* Limit of incoming calls */
    	int outUse;			/* disabled */
    	int outgoinglimit;		/* disabled */
    
    	struct ast_ha *ha;		/* ACL setting */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_variable *chanvars;	/* Variables to set for channel created by user */
    
    /* Structure for SIP peer data, we place calls to peers if registred  or fixed IP address (host) */
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct sip_peer {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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 */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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 registred 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 incominglimit;		/* Limit of incoming calls */
    	int outUse;			/* disabled */
    	int outgoinglimit;		/* disabled */
    
    	char mailbox[AST_MAX_EXTENSION]; /* Mailbox setting for MWI checks */
    	char language[MAX_LANGUAGE];	/* Default language for prompts */
    
    	char musicclass[MAX_MUSICCLASS];/* Music on Hold class */
    
    	char useragent[256];		/* User agent in SIP request (saved from registration) */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_codec_pref prefs;	/* codec prefs */
    
    	int lastmsgssent;
    
    	time_t	lastmsgcheck;		/* Last time we checked for MWI */
    
    	unsigned int flags;		/* SIP flags */	
    	unsigned int sipoptions;	/* Supported SIP options */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_flags flags_page2;	/* SIP_PAGE2 flags */
    
    	int expire;			/* When to expire this peer registration */
    	int expiry;			/* Duration of registration */
    
    	int capability;			/* Codec capability */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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 */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct in_addr mask;
    
    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 */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_variable *chanvars;	/* Variables to set for channel created by user */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int lastmsg;
    
    AST_MUTEX_DEFINE_STATIC(sip_reload_lock);
    
    static int sip_reloading = 0;
    
    /* States for outbound registrations (with register= lines in sip.conf */
    #define REG_STATE_UNREGISTERED		0
    #define REG_STATE_REGSENT		1
    #define REG_STATE_AUTHSENT		2
    #define REG_STATE_REGISTERED   		3
    #define REG_STATE_REJECTED	   	4
    #define REG_STATE_TIMEOUT	   	5
    #define REG_STATE_NOAUTH	   	6
    
    #define REG_STATE_FAILED		7
    
    /* sip_registry: Registrations with other SIP proxies */
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct sip_registry {
    
    	ASTOBJ_COMPONENTS_FULL(struct sip_registry,1,1);
    
    	int portno;			/* Optional port override */
    
    	char username[80];		/* Who we are registering as */
    	char authuser[80];		/* Who we *authenticate* as */
    
    	char hostname[MAXHOSTNAMELEN];	/* Domain or host we register to */
    
    	char secret[80];		/* Password or key name in []'s */	
    
    	char md5secret[80];
    
    	char contact[256];		/* Contact extension */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char random[80];
    
    	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 call" in progress */
    
    	int regstate;			/* Registration state (see above) */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int callid_valid;		/* 0 means we haven't chosen callid for this registry yet. */
    	char callid[80];		/* Global CallID for this registry */
    
    	unsigned int ocseq;		/* Sequence number we got to for REGISTERs for this registry */
    
    	struct sockaddr_in us;		/* Who the server thinks we are */
    
     	char realm[MAXHOSTNAMELEN];	/* Authorization realm */
    
     	char domain[MAXHOSTNAMELEN];	/* Authorization domain */
    
     	char opaque[256];		/* Opaque nonsense */
     	char qop[80];			/* Quality of Protection. */
     
     	char lastmsg[256];		/* Last Message sent/received */
    
    /*--- The user list: Users and friends ---*/
    
    static struct ast_user_list {
    
    	ASTOBJ_CONTAINER_COMPONENTS(struct sip_user);
    
    /*--- The peer list: Peers and Friends ---*/
    
    static struct ast_peer_list {
    
    	ASTOBJ_CONTAINER_COMPONENTS(struct sip_peer);
    
    /*--- The register list: Other SIP proxys we register with and call ---*/
    
    static struct ast_register_list {
    
    	ASTOBJ_CONTAINER_COMPONENTS(struct sip_registry);
    
    static int __sip_do_register(struct sip_registry *r);
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sipsock  = -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    static struct sockaddr_in bindaddr;
    
    static struct sockaddr_in externip;
    
    static char externhost[MAXHOSTNAMELEN] = "";
    
    static time_t externexpire = 0;
    static int externrefresh = 10;
    
    /* The list of manual NOTIFY types we know how to send */
    struct ast_config *notify_types;
    
    
    static struct sip_auth *authl;          /* Authentication list */
    
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static struct ast_frame  *sip_read(struct ast_channel *ast);
    
    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_with_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
    
    static int transmit_response_with_unsupported(struct sip_pvt *p, char *msg, struct sip_request *req, char *unsupported);
    
    static int transmit_response_with_auth(struct sip_pvt *p, char *msg, struct sip_request *req, char *rand, int reliable, char *header, int stale);
    
    static int transmit_request(struct sip_pvt *p, int sipmethod, int inc, int reliable, int newbranch);
    static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, int inc, int reliable, int newbranch);
    
    static int transmit_invite(struct sip_pvt *p, int sipmethod, int sendsdp, struct sip_invite_param *options, int init);
    
    static int transmit_reinvite_with_sdp(struct sip_pvt *p);
    
    static int transmit_info_with_digit(struct sip_pvt *p, char digit);
    
    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 sip_sipredirect(struct sip_pvt *p, const char *dest);
    
    static struct sip_peer *temp_peer(const char *name);
    
    static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req, char *header, char *respheader, int sipmethod, int init);
    
    static void free_old_route(struct sip_route *route);
    
    static int build_reply_digest(struct sip_pvt *p, int method, char *digest, int digest_len);
    
    static int update_user_counter(struct sip_pvt *fup, int event);
    
    Mark Spencer's avatar
    Mark Spencer committed
    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 sip_do_reload(void);
    
    static int expire_register(void *data);
    
    static int callevents = 0;
    
    static struct ast_channel *sip_request(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);
    
    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);
    
    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, char *realm);         /* Find authentication for a specific realm */
    
    static void append_date(struct sip_request *req);	/* Append date to SIP packet */
    
    /* Definition of this channel for channel registration */
    
    static const struct ast_channel_tech sip_tech = {
    	.type = channeltype,
    	.description = "Session Initiation Protocol (SIP)",
    	.capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
    
    	.requester = sip_request,
    	.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,
    };
    
    
    /*--- find_sip_method: Find SIP method from header */
    int find_sip_method(char *msg)
    {
    	int i, res = 0;
    
    	/* Strictly speaking, SIP methods are case SENSITIVE, but we don't check */
    
    	for (i=1;(i < (sizeof(sip_methods) / sizeof(sip_methods[0]))) && !res; i++) {
    
    		if (!strcasecmp(sip_methods[i].text, msg)) 
    			res = sip_methods[i].id;
    	}
    	return res;
    }
    
    
    /*
     * If there is a string in <brackets>, strip everything around and return
     * the content. Otherwise return the original argument.
     */
    static char *get_in_brackets(char *c)
    {
    	char *n = strchr(c, '<');
    
    	if (n) {
    		c = n + 1;
    		n = strchr(c, '>');
    		/* Lose the part after the > */
    		if (n) 
    			*n = '\0';
    	}
    	return c;
    }
    
    
    /*--- parse_sip_options: Parse supported header in incoming packet */
    unsigned int parse_sip_options(struct sip_pvt *pvt, char *supported)
    {
    	char *next = NULL;
    	char *sep = NULL;
    	char *temp = ast_strdupa(supported);
    	int i;
    	unsigned int profile = 0;
    
    	if (!supported || ast_strlen_zero(supported) )
    		return 0;
    
    	if (option_debug > 2 && sipdebug)
    		ast_log(LOG_DEBUG, "Begin: parsing SIP \"Supported: %s\"\n", supported);
    
    	next = temp;
    	while (next) {
    		char res=0;
    		if ( (sep = strchr(next, ',')) != NULL) {
    			*sep = '\0';
    			sep++;
    		}
    		while (*next == ' ')	/* Skip spaces */
    			next++;
    		if (option_debug > 2 && sipdebug)
    			ast_log(LOG_DEBUG, "Found SIP option: -%s-\n", next);
    		for (i=0; (i < (sizeof(sip_options) / sizeof(sip_options[0]))) && !res; i++) {
    			if (!strcasecmp(next, sip_options[i].text)) {
    				profile |= sip_options[i].id;
    				res = 1;
    				if (option_debug > 2 && sipdebug)
    					ast_log(LOG_DEBUG, "Matched SIP option: %s\n", next);
    			}
    		}
    		if (!res) 
    			if (option_debug > 2 && sipdebug)
    				ast_log(LOG_DEBUG, "Found no match for SIP option: %s (Please file bug report!)\n", next);
    		next = sep;
    	}
    	if (pvt)
    		pvt->sipoptions = profile;
    	
    	ast_log(LOG_DEBUG, "* SIP extension value: %d for call %s\n", profile, pvt->callid);
    	return(profile);
    }
    
    
    /*--- sip_debug_test_addr: See if we pass debug IP filter */
    
    James Golovich's avatar
    James Golovich committed
    static inline int sip_debug_test_addr(struct sockaddr_in *addr) 
    {
    
    	if (sipdebug == 0)
    		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;
    }
    
    
    /*--- sip_debug_test_pvt: Test PVT for debugging output */
    
    James Golovich's avatar
    James Golovich committed
    static inline int sip_debug_test_pvt(struct sip_pvt *p) 
    {
    
    	if (sipdebug == 0)
    		return 0;
    
    	return sip_debug_test_addr(((ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE) ? &p->recv : &p->sa));
    
    /*--- __sip_xmit: 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];
    
    	if (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE)
    
    	    res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->recv, sizeof(struct sockaddr_in));
    	else
    	    res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->sa, sizeof(struct sockaddr_in));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (res != len) {
    
    		ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s returned %d: %s\n", data, len, ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), res, strerror(errno));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    	return res;
    }
    
    
    static void sip_destroy(struct sip_pvt *p);
    
    
    /*--- build_via: Build a Via header for a request ---*/
    static void build_via(struct sip_pvt *p, char *buf, int len)
    {
    	char iabuf[INET_ADDRSTRLEN];
    
    	/* z9hG4bK is a magic cookie.  See RFC 3261 section 8.1.1.7 */
    
    	if (ast_test_flag(p, SIP_NAT) & SIP_NAT_RFC3581)
    
    		snprintf(buf, len, "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
    	else /* Work around buggy UNIDEN UIP200 firmware */
    		snprintf(buf, len, "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch);
    }
    
    
    /*--- ast_sip_ouraddrfor: 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)) {
    
    		char iabuf[INET_ADDRSTRLEN];
    
    		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);
    		}
    
    		memcpy(us, &externip.sin_addr, sizeof(struct in_addr));
    
    		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)
    		memcpy(us, &bindaddr.sin_addr, sizeof(struct in_addr));
    	else
    		return ast_ouraddrfor(them, us);
    
    /*--- append_history: Append to SIP dialog history */
    
    /*	Always returns 0 */
    
    static int append_history(struct sip_pvt *p, char *event, char *data)
    {
    	struct sip_history *hist, *prev;
    	char *c;
    	if (!recordhistory)
    		return 0;