Skip to content
Snippets Groups Projects
chan_sip.c 175 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) 1999, Mark Spencer
     *
     * Mark Spencer <markster@linux-support.net>
     *
     * This program is free software, distributed under the terms of
     * the GNU General Public License
     */
    
    #include <stdio.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <ctype.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <pthread.h>
    #include <string.h>
    #include <asterisk/lock.h>
    #include <asterisk/channel.h>
    #include <asterisk/channel_pvt.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/callerid.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <asterisk/cli.h>
    #include <asterisk/md5.h>
    #include <asterisk/app.h>
    
    #include <asterisk/musiconhold.h>
    
    #include <asterisk/dsp.h>
    
    #include <asterisk/parking.h>
    
    #include <asterisk/acl.h>
    
    #include <asterisk/astdb.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <sys/socket.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <sys/ioctl.h>
    #include <net/if.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <errno.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <sys/signal.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <netinet/in_systm.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <netinet/ip.h>
    
    
    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 EXPIRY_GUARD_SECS	15
    
    #define SIP_DTMF_RFC2833	(1 << 0)
    #define SIP_DTMF_INBAND		(1 << 1)
    #define SIP_DTMF_INFO		(1 << 2)
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int max_expiry = DEFAULT_MAX_EXPIRY;
    static int default_expiry = DEFAULT_DEFAULT_EXPIRY;
    
    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		1000			/* How frequently to retransmit */
    #define MAX_RETRANS			5				/* Try only 5 times for retransmissions */
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static char *desc = "Session Initiation Protocol (SIP)";
    static char *type = "sip";
    static char *tdesc = "Session Initiation Protocol (SIP)";
    static char *config = "sip.conf";
    
    #define DEFAULT_SIP_PORT	5060	/* From RFC 2543 */
    #define SIP_MAX_PACKET	1500		/* Also from RFC 2543, should sub headers tho */
    
    
    #define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER"
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static char context[AST_MAX_EXTENSION] = "default";
    
    static char language[MAX_LANGUAGE] = "";
    
    
    static char callerid[AST_MAX_EXTENSION] = "asterisk";
    
    
    static char fromdomain[AST_MAX_EXTENSION] = "";
    
    
    static char notifymime[AST_MAX_EXTENSION] = "application/simple-message-summary";
    
    
    static int pedanticsipchecking = 0;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int usecnt =0;
    
    static ast_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    /* Protect the interface list (of sip_pvt's) */
    
    static ast_mutex_t iflock = AST_MUTEX_INITIALIZER;
    
    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. */
    
    static ast_mutex_t netlock = AST_MUTEX_INITIALIZER;
    
    static ast_mutex_t monlock = AST_MUTEX_INITIALIZER;
    
    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 = 0;
    
    static int restart_monitor(void);
    
    
    /* Codecs that we support by default: */
    
    static int 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 char ourhost[256];
    
    Mark Spencer's avatar
    Mark Spencer committed
    static struct in_addr __ourip;
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int ourport;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sipdebug = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    static int tos = 0;
    
    
    static int globaldtmfmode = SIP_DTMF_RFC2833;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    /* Expire slowly */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int expiry = 900;
    
    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
    
    
    static struct sip_codec_pref {
    	int codec;
    	struct sip_codec_pref *next;
    } *prefs;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct sip_request {
    
    Mark Spencer's avatar
    Mark Spencer committed
      char *rlPart1; /* SIP Method Name or "SIP/2.0" protocol version */
      char *rlPart2; /* The Request URI or Response Status */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int len;
    	int headers;					/* SIP Headers */
    	char *header[SIP_MAX_HEADERS];
    	int lines;						/* SDP Content */
    	char *line[SIP_MAX_LINES];
    	char data[SIP_MAX_PACKET];
    };
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct sip_pkt;
    
    
    struct sip_route {
    	struct sip_route *next;
    	char hop[0];
    };
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static struct sip_pvt {
    
    	ast_mutex_t lock;				/* Channel private lock */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char callid[80];					/* Global CallID */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char randdata[80];	/* Random data */
    	unsigned int ocseq;					/* Current outgoing seqno */
    	unsigned int icseq;					/* Current incoming seqno */
    
    	unsigned int callgroup;
    	unsigned int pickupgroup;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int lastinvite;						/* Last Cseq of invite */
    	int alreadygone;					/* Whether or not we've already been destroyed by or peer */
    	int needdestroy;					/* if we need to be destroyed */
    	int capability;						/* Special capability */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int noncodeccapability;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int outgoing;						/* Outgoing or incoming call? */
    
    	int authtries;						/* Times we've tried to authenticate */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int insecure;						/* Don't check source port/ip */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int expiry;						/* How long we take to expire */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int branch;							/* One random number */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int canreinvite;					/* Do we support reinvite */
    
    	int ringing;						/* Have sent 180 ringing */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int progress;						/* Have sent 183 message progress */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int tag;							/* Another random number */
    
    	int nat;							/* Whether to try to support NAT */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sockaddr_in sa;				/* Our peer */
    
    	struct sockaddr_in redirip;			/* Where our RTP should be going if not to us */
    
    	struct sockaddr_in vredirip;		/* Where our Video RTP should be going if not to us */
    
    	struct sockaddr_in recv;			/* Received as */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct in_addr ourip;				/* Our IP */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_channel *owner;			/* Who owns us */
    	char exten[AST_MAX_EXTENSION];		/* Extention 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) */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char remote_party_id[256];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char from[256];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char context[AST_MAX_EXTENSION];
    
    	char fromdomain[AST_MAX_EXTENSION];	/* Domain to show in the from field */
    
    	char fromuser[AST_MAX_EXTENSION];	/* Domain to show in the user field */
    
    	char tohost[AST_MAX_EXTENSION];		/* Host we should put in the "to" field */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char language[MAX_LANGUAGE];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char rdnis[256];				/* Referring DNIS */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char theirtag[256];				/* Their tag */
    	char username[81];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char peername[81];
    
    	char uri[81];					/* Original requested URI */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char peersecret[81];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char callerid[256];					/* Caller*ID */
    
    	int restrictcid;			/* hide presentation from remote user */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char via[256];
    
    	char accountcode[20];				/* Account code */
    
    	char our_contact[256];				/* Our contact header */
    
    	char realm[256];				/* Authorization realm */
    	char nonce[256];				/* Authorization nonce */
    
    	char domain[256];				/* Authorization nonce */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int amaflags;						/* AMA Flags */
    
    	int pendinginvite;					/* Any pending invite */
    	int pendingbye;						/* Need to send bye after we ack? */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sip_request initreq;			/* Initial request */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	
    	int maxtime;						/* Max time for first response */
    	int initid;							/* Auto-congest ID if appropriate */
    
    	int autokillid;						/* Auto-kill ID */
    
    	int subscribed;
        	int stateid;
    	int dialogver;
    	
    
            int dtmfmode;
            struct ast_dsp *vad;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	
    	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 */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_rtp *rtp;				/* RTP Session */
    
    	struct ast_rtp *vrtp;				/* Video RTP session */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sip_pkt *packets;			/* Packets scheduled for re-transmission */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sip_pvt *next;
    } *iflist = NULL;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct sip_pkt {
    	struct sip_pkt *next;				/* Next packet */
    	int retrans;						/* Retransmission number */
    	int seqno;							/* Sequence number */
    
    	int resp;							/* non-zero if this is a response packet (e.g. 200 OK) */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sip_pvt *owner;				/* Owner call */
    	int retransid;						/* Retransmission ID */
    	int packetlen;						/* Length of packet */
    	char data[0];
    };	
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    struct sip_user {
    	/* Users who can access various contexts */
    	char name[80];
    	char secret[80];
    	char context[80];
    	char callerid[80];
    	char methods[80];
    
    	char accountcode[20];
    
    	unsigned int callgroup;
    	unsigned int pickupgroup;
    
    	int nat;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int hascallerid;
    	int amaflags;
    	int insecure;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int canreinvite;
    
    	int dtmfmode;
    	int inUse;
    	int incominglimit;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_ha *ha;
    	struct sip_user *next;
    };
    
    struct sip_peer {
    	char name[80];
    	char secret[80];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char context[80];		/* JK02: peers need context too to allow parking etc */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char methods[80];
    	char username[80];
    
    	char tohost[80];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char mailbox[AST_MAX_EXTENSION];
    
    	int lastmsgssent;
    	time_t	lastmsgcheck;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int dynamic;
    	int expire;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int expiry;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int capability;
    	int insecure;
    
    	int nat;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int canreinvite;
    
    	unsigned int callgroup;
    	unsigned int pickupgroup;
    
            int dtmfmode;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sockaddr_in addr;
    	struct in_addr mask;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	/* Qualification */
    	struct sip_pvt *call;		/* Call pointer */
    	int pokeexpire;				/* When to expire poke */
    	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 */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	
    	struct sockaddr_in defaddr;
    	struct ast_ha *ha;
    	int delme;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int lastmsg;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sip_peer *next;
    };
    
    static struct ast_user_list {
    	struct sip_user *users;
    
    Mark Spencer's avatar
    Mark Spencer committed
    } userl = { NULL, AST_MUTEX_INITIALIZER };
    
    static struct ast_peer_list {
    	struct sip_peer *peers;
    
    Mark Spencer's avatar
    Mark Spencer committed
    } peerl = { NULL, AST_MUTEX_INITIALIZER };
    
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    #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
    
    struct sip_registry {
    
    	ast_mutex_t lock;				/* Channel private lock */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sockaddr_in addr;		/* Who we connect to for registration purposes */
    
    	char username[80];				/* Who we are registering as */
    	char authuser[80];				/* Who we *authenticate* as */
    
    	char hostname[80];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char secret[80];			/* Password or key name in []'s */
    
    	char contact[80];			/* Contact extension */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char random[80];
    	int expire;					/* Sched ID of expiration */
    	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;
    	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 */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sockaddr_in us;			/* Who the server thinks we are */
    	struct sip_registry *next;
    };
    
    
    #define REINVITE_INVITE		1
    #define REINVITE_UPDATE		2
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sip_do_register(struct sip_registry *r);
    
    static struct sip_registry *registrations;
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sipsock  = -1;
    
    static int globalnat = 0;
    
    static int globalcanreinvite = REINVITE_INVITE;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    static struct sockaddr_in bindaddr;
    
    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_auth(struct sip_pvt *p, char *msg, struct sip_request *req, char *rand, int reliable);
    static int transmit_request(struct sip_pvt *p, char *msg, int inc, int reliable);
    
    static int transmit_request_with_auth(struct sip_pvt *p, char *msg, int inc, int reliable);
    
    static int transmit_invite(struct sip_pvt *p, char *msg, int sendsdp, char *auth, char *vxml_url,char *distinctive_ring, int init);
    
    static int transmit_reinvite_with_sdp(struct sip_pvt *p, struct ast_rtp *rtp, struct ast_rtp *vrtp);
    
    static int transmit_info_with_digit(struct sip_pvt *p, char digit);
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int transmit_message_with_text(struct sip_pvt *p, char *text);
    
    static int transmit_refer(struct sip_pvt *p, char *dest);
    
    static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req, char *msg, int init);
    
    static char *getsipuri(char *header);
    
    static void free_old_route(struct sip_route *route);
    
    static int build_reply_digest(struct sip_pvt *p, char *orig_header, char *digest, int digest_len);
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    static int __sip_xmit(struct sip_pvt *p, char *data, int len)
    {
    	int res;
    
    	if (p->nat)
    	    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) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s returned %d: %s\n", data, len, inet_ntoa(p->sa.sin_addr), res, strerror(errno));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    	return res;
    }
    
    
    static void sip_destroy(struct sip_pvt *p);
    
    
    static int ast_sip_ouraddrfor(struct in_addr *them, struct in_addr *us)
    {
    	if (bindaddr.sin_addr.s_addr)
    		memcpy(us, &bindaddr.sin_addr, sizeof(struct in_addr));
    	else
    		return ast_ouraddrfor(them, us);
    	return 0;
    }
    
    
    static int retrans_pkt(void *data)
    {
    	struct sip_pkt *pkt=data;
    	int res = 0;
    
    	if (pkt->retrans < MAX_RETRANS) {
    		pkt->retrans++;
    		if (sipdebug) {
    			if (pkt->owner->nat)
    				ast_verbose("Retransmitting #%d (NAT):\n%s\n to %s:%d\n", pkt->retrans, pkt->data, inet_ntoa(pkt->owner->recv.sin_addr), ntohs(pkt->owner->recv.sin_port));
    			else
    				ast_verbose("Retransmitting #%d (no NAT):\n%s\n to %s:%d\n", pkt->retrans, pkt->data, inet_ntoa(pkt->owner->sa.sin_addr), ntohs(pkt->owner->sa.sin_port));
    
    		__sip_xmit(pkt->owner, pkt->data, pkt->packetlen);
    		res = 1;
    
    	} else {
    
    		ast_log(LOG_WARNING, "Maximum retries exceeded on call %s for seqno %d (%s)\n", pkt->owner->callid, pkt->seqno, pkt->resp ? "Response" : "Request");
    
    		pkt->retransid = -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		while(pkt->owner->owner && ast_mutex_lock(&pkt->owner->owner->lock)) {
    
    			ast_mutex_unlock(&pkt->owner->lock);
    			usleep(1);
    			ast_mutex_lock(&pkt->owner->lock);
    		}
    
    		if (pkt->owner->owner) {
    			/* XXX Potential deadlocK?? XXX */
    
    			ast_queue_hangup(pkt->owner->owner, 0);
    			ast_mutex_unlock(&pkt->owner->owner->lock);
    
    		} else {
    			/* If no owner, destroy now */
    
    Mark Spencer's avatar
    Mark Spencer committed
    			pkt->owner->needdestroy = 1;
    
    		ast_mutex_unlock(&pkt->owner->lock);
    
    	return res;
    }
    
    static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, char *data, int len)
    {
    	struct sip_pkt *pkt;
    	pkt = malloc(sizeof(struct sip_pkt) + len);
    	if (!pkt)
    		return -1;
    	memset(pkt, 0, sizeof(struct sip_pkt));
    	memcpy(pkt->data, data, len);
    	pkt->packetlen = len;
    	pkt->next = p->packets;
    	pkt->owner = p;
    	pkt->seqno = seqno;
    	pkt->resp = resp;
    	/* Schedule retransmission */
    
    Martin Pycko's avatar
    Martin Pycko committed
    	pkt->retransid = ast_sched_add(sched, DEFAULT_RETRANS, retrans_pkt, pkt);
    
    	pkt->next = p->packets;
    	p->packets = pkt;
    	__sip_xmit(pkt->owner, pkt->data, pkt->packetlen);
    
    	if (!strncasecmp(pkt->data, "INVITE", 6)) {
    		/* Note this is a pending invite */
    		p->pendinginvite = seqno;
    	}
    
    	return 0;
    }
    
    static int __sip_autodestruct(void *data)
    {
    	struct sip_pvt *p = data;
    	p->autokillid = -1;
    	ast_log(LOG_DEBUG, "Auto destroying call '%s'\n", p->callid);
    	if (p->owner) {
    		ast_log(LOG_WARNING, "Autodestruct on call '%s' with owner in place\n", p->callid);
    		ast_queue_hangup(p->owner, 0);
    	} else {
    		sip_destroy(p);
    	}
    	return 0;
    }
    
    static int sip_scheddestroy(struct sip_pvt *p, int ms)
    {
    	if (p->autokillid > -1)
    		ast_sched_del(sched, p->autokillid);
    	p->autokillid = ast_sched_add(sched, ms, __sip_autodestruct, p);
    	return 0;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sip_cancel_destroy(struct sip_pvt *p)
    {
    	if (p->autokillid > -1)
    		ast_sched_del(sched, p->autokillid);
    	p->autokillid = -1;
    	return 0;
    }
    
    
    static int __sip_ack(struct sip_pvt *p, int seqno, int resp)
    {
    	struct sip_pkt *cur, *prev = NULL;
    	int res = -1;
    
    	cur = p->packets;
    	while(cur) {
    		if ((cur->seqno == seqno) && (cur->resp == resp)) {
    
    			if (!resp && (seqno == p->pendinginvite)) {
    				ast_log(LOG_DEBUG, "Acked pending invite %d\n", p->pendinginvite);
    				p->pendinginvite = 0;
    				resetinvite = 1;
    			}
    
    			/* this is our baby */
    			if (prev)
    				prev->next = cur->next;
    			else
    				p->packets = cur->next;
    			if (cur->retransid > -1)
    				ast_sched_del(sched, cur->retransid);
    			free(cur);
    			res = 0;
    			break;
    		}
    		prev = cur;
    		cur = cur->next;
    	}
    
    	ast_log(LOG_DEBUG, "Stopping retransmission on '%s' of %s %d: %s\n", p->callid, resp ? "Response" : "Request", seqno, res ? "Not Found" : "Found");
    
    static int __sip_semi_ack(struct sip_pvt *p, int seqno, int resp)
    {
    
    	int res = -1;
    	cur = p->packets;
    	while(cur) {
    		if ((cur->seqno == seqno) && (cur->resp == resp)) {
    			/* this is our baby */
    			if (cur->retransid > -1)
    				ast_sched_del(sched, cur->retransid);
    			cur->retransid = -1;
    			res = 0;
    			break;
    		}
    		cur = cur->next;
    	}
    
    	ast_log(LOG_DEBUG, "(Provisional) Stopping retransmission (but retaining packet) on '%s' %s %d: %s\n", p->callid, resp ? "Response" : "Request", seqno, res ? "Not Found" : "Found");
    
    static int send_response(struct sip_pvt *p, struct sip_request *req, int reliable, int seqno)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	int res;
    
    	if (sipdebug) {
    		if (p->nat)
    
    			ast_verbose("%sTransmitting (NAT):\n%s\n to %s:%d\n", reliable ? "Reliably " : "", req->data, inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port));
    
    			ast_verbose("%sTransmitting (no NAT):\n%s\n to %s:%d\n", reliable ? "Reliably " : "", req->data, inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port));
    
    	if (reliable)
    		res = __sip_reliable_xmit(p, seqno, 1, req->data, req->len);
    	else
    		res = __sip_xmit(p, req->data, req->len);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (res > 0)
    		res = 0;
    	return res;
    }
    
    
    static int send_request(struct sip_pvt *p, struct sip_request *req, int reliable, int seqno)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	int res;
    
    	if (sipdebug) {
    		if (p->nat)
    
    			ast_verbose("%sTransmitting:\n%s (NAT) to %s:%d\n", reliable ? "Reliably " : "", req->data, inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port));
    
    			ast_verbose("%sTransmitting:\n%s (no NAT) to %s:%d\n", reliable ? "Reliably " : "", req->data, inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port));
    
    	if (reliable)
    		res = __sip_reliable_xmit(p, seqno, 0, req->data, req->len);
    	else
    		res = __sip_xmit(p, req->data, req->len);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    static char *ditch_braces(char *tmp)
    {
    	char *c = tmp;
    	char *n;
    	c = tmp;
    	if ((n = strchr(tmp, '<')) ) {
    		c = n + 1;
    		while(*c && *c != '>') c++;
    		if (*c != '>') {
    			ast_log(LOG_WARNING, "No closing brace in '%s'\n", tmp);
    		} else {
    			*c = '\0';
    		}
    		return n+1;
    	}
    	return c;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sip_sendtext(struct ast_channel *ast, char *text)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sip_pvt *p = ast->pvt->pvt;
    	if (sipdebug) 
    		ast_verbose("Sending text %s on %s\n", text, ast->name);
    	if (!p)
    		return -1;
    	if (!text || !strlen(text))
    		return 0;
    	if (sipdebug)
    		ast_verbose("Really sending text %s on %s\n", text, ast->name);
    	transmit_message_with_text(p, text);
    	return 0;	
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int create_addr(struct sip_pvt *r, char *peer)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct hostent *hp;
    	struct sip_peer *p;
    	int found=0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char *port;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	r->sa.sin_family = AF_INET;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	p = peerl.peers;
    	while(p) {
    		if (!strcasecmp(p->name, peer)) {
    			found++;
    
    Mark Spencer's avatar
    Mark Spencer committed
    			r->capability = p->capability;
    
    			r->nat = p->nat;
    			if (r->rtp) {
    				ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", r->nat);
    				ast_rtp_setnat(r->rtp, r->nat);
    			}
    
    			if (r->vrtp) {
    				ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", r->nat);
    				ast_rtp_setnat(r->vrtp, r->nat);
    			}
    
    Mark Spencer's avatar
    Mark Spencer committed
    			strncpy(r->peername, p->username, sizeof(r->peername)-1);
    			strncpy(r->peersecret, p->secret, sizeof(r->peersecret)-1);
    			strncpy(r->username, p->username, sizeof(r->username)-1);
    
    			strncpy(r->tohost, p->tohost, sizeof(r->tohost)-1);
    
    			if (!strlen(r->tohost)) {
    				if (p->addr.sin_addr.s_addr)
    					snprintf(r->tohost, sizeof(r->tohost), inet_ntoa(p->addr.sin_addr));
    				else
    					snprintf(r->tohost, sizeof(r->tohost), inet_ntoa(p->defaddr.sin_addr));
    			}
    
    			if (strlen(p->fromdomain))
    				strncpy(r->fromdomain, p->fromdomain, sizeof(r->fromdomain)-1);
    
    			if (strlen(p->fromuser))
    				strncpy(r->fromuser, p->fromuser, sizeof(r->fromuser)-1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			r->insecure = p->insecure;
    			r->canreinvite = p->canreinvite;
    			r->maxtime = p->maxms;
    
    			r->callgroup = p->callgroup;
    			r->pickupgroup = p->pickupgroup;
    
    			if (p->dtmfmode) {
    
    				r->dtmfmode = p->dtmfmode;
    
    				if (r->dtmfmode & SIP_DTMF_RFC2833)
    
    Mark Spencer's avatar
    Mark Spencer committed
    					r->noncodeccapability |= AST_RTP_DTMF;
    
    Mark Spencer's avatar
    Mark Spencer committed
    					r->noncodeccapability &= ~AST_RTP_DTMF;
    
    Mark Spencer's avatar
    Mark Spencer committed
    			strncpy(r->context, p->context,sizeof(r->context)-1);
    			if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) &&
    				(!p->maxms || ((p->lastms > 0)  && (p->lastms <= p->maxms)))) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    				if (p->addr.sin_addr.s_addr) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    					r->sa.sin_addr = p->addr.sin_addr;
    					r->sa.sin_port = p->addr.sin_port;
    
    Mark Spencer's avatar
    Mark Spencer committed
    				} else {
    
    Mark Spencer's avatar
    Mark Spencer committed
    					r->sa.sin_addr = p->defaddr.sin_addr;
    					r->sa.sin_port = p->defaddr.sin_port;
    
    Mark Spencer's avatar
    Mark Spencer committed
    				}
    
    				memcpy(&r->recv, &r->sa, sizeof(r->recv));
    
    Mark Spencer's avatar
    Mark Spencer committed
    				break;
    			}
    		}
    		p = p->next;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!p && !found) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if ((port=strchr(peer, ':'))) {
    			*port='\0';
    			port++;
    		}
    
    		hostn = peer;
    		if (port)
    			portno = atoi(port);
    		else
    			portno = DEFAULT_SIP_PORT;
    		if (srvlookup) {
    			char service[256];
    			int tportno;
    			int ret;
    			snprintf(service, sizeof(service), "_sip._udp.%s", peer);
    			ret = ast_get_srv(NULL, host, sizeof(host), &tportno, service);
    			if (ret > 0) {
    				hostn = host;
    				portno = tportno;
    			}
    		}
    		hp = gethostbyname(hostn);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (hp) {
    
    			strncpy(r->tohost, peer, sizeof(r->tohost) - 1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			memcpy(&r->sa.sin_addr, hp->h_addr, sizeof(r->sa.sin_addr));
    
    			memcpy(&r->recv, &r->sa, sizeof(r->recv));
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return 0;
    		} else {
    			ast_log(LOG_WARNING, "No such host: %s\n", peer);
    			return -1;
    		}
    	} else if (!p)
    		return -1;
    	else
    		return 0;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int auto_congest(void *nothing)
    {
    	struct sip_pvt *p = nothing;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	p->initid = -1;
    	if (p->owner) {
    
    		if (!ast_mutex_trylock(&p->owner->lock)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ast_log(LOG_NOTICE, "Auto-congesting %s\n", p->owner->name);
    			ast_queue_control(p->owner, AST_CONTROL_CONGESTION, 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    
    static void sip_prefs_free(void)
    {
    	struct sip_codec_pref *cur, *next;
    	cur = prefs;
    	while(cur) {
    		next = cur->next;
    		free(cur);
    		cur = next;
    	}
    	prefs = NULL;
    }
    
    static void sip_pref_remove(int format)
    {
    
    	struct sip_codec_pref *cur, *prev=NULL;
    
    	cur = prefs;
    	while(cur) {
    		if (cur->codec == format) {
    			if (prev)
    				prev->next = cur->next;
    			else
    				prefs = cur->next;
    			free(cur);
    			return;
    		}
    		prev = cur;
    		cur = cur->next;
    	}
    }
    
    static int sip_pref_append(int format)
    {
    	struct sip_codec_pref *cur, *tmp;
    	sip_pref_remove(format);
    	tmp = (struct sip_codec_pref *)malloc(sizeof(struct sip_codec_pref));
    	if (!tmp)
    		return -1;
    	memset(tmp, 0, sizeof(struct sip_codec_pref));
    	tmp->codec = format;
    	if (prefs) {
    		cur = prefs;
    		while(cur->next)
    			cur = cur->next;
    		cur->next = tmp;
    	} else
    		prefs = tmp;
    	return 0;
    }
    
    static int sip_codec_choose(int formats)
    {
    	struct sip_codec_pref *cur;
    
    	formats &= (AST_FORMAT_MAX_AUDIO - 1);
    
    	cur = prefs;
    	while(cur) {
    		if (formats & cur->codec)
    			return cur->codec;
    		cur = cur->next;
    	}
    	return ast_best_codec(formats);
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sip_call(struct ast_channel *ast, char *dest, int timeout)
    {
    	int res;
    	struct sip_pvt *p;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char *vxml_url = NULL;
    
    	char *distinctive_ring = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct varshead *headp;
    	struct ast_var_t *current;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	
    	p = ast->pvt->pvt;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "sip_call called on %s, neither down nor reserved\n", ast->name);
    		return -1;
    	}
    
    	/* Check whether there is vxml_url, distinctive ring variables */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	headp=&ast->varshead;
    	AST_LIST_TRAVERSE(headp,current,entries) {
    
    		/* Check whether there is a VXML_URL variable */
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (strcasecmp(ast_var_name(current),"VXML_URL")==0)
    	        {
    			vxml_url = ast_var_value(current);
    			break;
    		}
    
    		/* Check whether there is a ALERT_INFO variable */
    		if (strcasecmp(ast_var_name(current),"ALERT_INFO")==0)
    	        {
    			distinctive_ring = ast_var_value(current);
    			break;
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	res = 0;
    	p->outgoing = 1;
    
    	transmit_invite(p, "INVITE", 1, NULL, vxml_url,distinctive_ring, 1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (p->maxtime) {
    		/* Initialize auto-congest time */
    		p->initid = ast_sched_add(sched, p->maxtime * 2, auto_congest, p);
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static void __sip_destroy(struct sip_pvt *p, int lockowner)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct sip_pvt *cur, *prev = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sip_pkt *cp;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (sipdebug)
    		ast_log(LOG_DEBUG, "Destorying call '%s'\n", p->callid);
    
    	if (p->stateid > -1)
    		ast_extension_state_del(p->stateid, NULL);
    
    	if (p->initid > -1)
    		ast_sched_del(sched, p->initid);
    	if (p->autokillid > -1)
    		ast_sched_del(sched, p->autokillid);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (p->rtp) {
    		ast_rtp_destroy(p->rtp);
    	}
    
    	if (p->vrtp) {
    		ast_rtp_destroy(p->vrtp);
    	}
    
    	if (p->route) {
    		free_old_route(p->route);
    		p->route = NULL;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Unlink us from the owner if we have one */
    	if (p->owner) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (lockowner)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_DEBUG, "Detaching from %s\n", p->owner->name);
    		p->owner->pvt->pvt = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (lockowner)
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	cur = iflist;
    	while(cur) {
    		if (cur == p) {
    			if (prev)
    				prev->next = cur->next;
    			else
    				iflist = cur->next;
    			break;
    		}
    		prev = cur;
    		cur = cur->next;
    	}
    	if (!cur) {
    		ast_log(LOG_WARNING, "%p is not in list?!?! \n", cur);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	} else {
    		if (p->initid > -1)
    			ast_sched_del(sched, p->initid);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		while((cp = p->packets)) {
    			p->packets = p->packets->next;
    			if (cp->retransid > -1)
    				ast_sched_del(sched, cp->retransid);
    			free(cp);
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		free(p);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int find_user(struct sip_pvt *fup, int event)
    
    {
    	char name[256] = "";
    	struct sip_user *u;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	strncpy(name, fup->username, sizeof(name) - 1);
    
    	u = userl.users;
    	while(u) {
    		if (!strcasecmp(u->name, name)) {
    			break;
    		}
    		u = u->next;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!u) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_DEBUG, "%s is not a local user\n", name);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	if(event == 0) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if ( u->inUse > 0 ) {
    			u->inUse = u->inUse - 1;
    		} else {
    			u->inUse = 0;
    		}
    
    	} else {
    		if (u->incominglimit > 0 ) {
    			if (u->inUse >= u->incominglimit) {
    				ast_log(LOG_ERROR, "Call from user '%s' rejected due to usage limit of %d\n", u->name, u->incominglimit);
    
    				return -1; 
    			}
    		}
    		u->inUse++;
    		ast_log(LOG_DEBUG, "Call from user '%s' is %d out of %d\n", u->name, u->inUse, u->incominglimit);
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    static void sip_destroy(struct sip_pvt *p)
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	__sip_destroy(p, 1);
    
    static int transmit_response_reliable(struct sip_pvt *p, char *msg, struct sip_request *req);
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    static int sip_hangup(struct ast_channel *ast)
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sip_pvt *p = ast->pvt->pvt;
    	int needcancel = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (option_debug)
    		ast_log(LOG_DEBUG, "sip_hangup(%s)\n", ast->name);
    	if (!ast->pvt->pvt) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_DEBUG, "Asked to hangup channel not connected\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return 0;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_log(LOG_DEBUG, "find_user(%s)\n", p->username);
    	find_user(p, 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Determine how to disconnect */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (p->owner != ast) {
    		ast_log(LOG_WARNING, "Huh?  We aren't the owner?\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return 0;
    	}
    	if (!ast || (ast->_state != AST_STATE_UP))
    
    Mark Spencer's avatar
    Mark Spencer committed
    		needcancel = 1;
    	/* Disconnect */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	p = ast->pvt->pvt;
    
            if (p->vad) {
                ast_dsp_free(p->vad);
            }
    
    Mark Spencer's avatar
    Mark Spencer committed
    	p->owner = NULL;
    	ast->pvt->pvt = NULL;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Start the process if it's not already started */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!p->alreadygone && strlen(p->initreq.data)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (needcancel) {