2002-06-28 20:34:46 +00:00
/*
* Asterisk - - A telephony toolkit for Linux .
*
* Implementation of Session Initiation Protocol
*
2004-08-27 02:45:35 +00:00
* Copyright ( C ) 2004 , Digium , Inc .
2002-06-28 20:34:46 +00:00
*
2004-08-27 02:45:35 +00:00
* Mark Spencer < markster @ digium . com >
2002-06-28 20:34:46 +00:00
*
* This program is free software , distributed under the terms of
* the GNU General Public License
*/
2004-06-24 04:07:44 +00:00
2002-06-28 20:34:46 +00:00
# include <stdio.h>
2003-02-07 04:07:10 +00:00
# include <ctype.h>
2002-06-28 20:34:46 +00:00
# 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>
2004-09-16 16:18:53 +00:00
# include <asterisk/manager.h>
2002-06-28 20:34:46 +00:00
# include <asterisk/callerid.h>
2003-02-07 04:07:10 +00:00
# include <asterisk/cli.h>
# include <asterisk/md5.h>
# include <asterisk/app.h>
2003-02-16 06:00:12 +00:00
# include <asterisk/musiconhold.h>
2003-03-08 06:00:17 +00:00
# include <asterisk/dsp.h>
2004-07-17 20:58:01 +00:00
# include <asterisk/features.h>
2003-05-04 05:52:52 +00:00
# include <asterisk/acl.h>
2003-06-12 12:48:57 +00:00
# include <asterisk/srv.h>
2003-08-24 22:35:06 +00:00
# include <asterisk/astdb.h>
2003-10-01 16:05:40 +00:00
# include <asterisk/causes.h>
2004-05-03 21:01:14 +00:00
# include <asterisk/utils.h>
2004-06-25 03:59:07 +00:00
# ifdef OSP_SUPPORT
# include <asterisk/astosp.h>
# endif
2002-06-28 20:34:46 +00:00
# include <sys/socket.h>
2002-09-12 17:13:17 +00:00
# include <sys/ioctl.h>
# include <net/if.h>
2002-06-28 20:34:46 +00:00
# include <errno.h>
# include <unistd.h>
# include <stdlib.h>
# include <fcntl.h>
# include <netdb.h>
# include <arpa/inet.h>
2004-02-02 06:38:08 +00:00
# include <signal.h>
2002-06-28 20:34:46 +00:00
# include <sys/signal.h>
2003-04-24 23:35:17 +00:00
# include <netinet/in_systm.h>
2003-02-07 04:07:10 +00:00
# include <netinet/ip.h>
2004-05-25 05:36:49 +00:00
# ifndef DEFAULT_USERAGENT
# define DEFAULT_USERAGENT "Asterisk PBX"
# endif
2004-04-26 14:54:33 +00:00
# define VIDEO_CODEC_MASK 0x1fc0000 /* Video codecs from H.261 thru AST_FORMAT_MAX_VIDEO */
2003-04-24 23:35:17 +00:00
# ifndef IPTOS_MINCOST
# define IPTOS_MINCOST 0x02
# endif
2003-02-07 04:07:10 +00:00
/* #define VOCAL_DATA_HACK */
2002-06-28 20:34:46 +00:00
# define SIPDUMPER
2003-04-08 03:24:12 +00:00
# define DEFAULT_DEFAULT_EXPIRY 120
# define DEFAULT_MAX_EXPIRY 3600
2004-05-03 02:22:19 +00:00
/* guard limit must be larger than guard secs */
2004-05-03 05:03:19 +00:00
/* guard min must be < 1000, and should be >= 250 */
2004-05-03 02:22:19 +00:00
# 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 */
2004-05-03 05:03:19 +00:00
# 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 . */
2004-05-03 02:22:19 +00:00
# define EXPIRY_GUARD_PCT 0.20 /* Percentage of expires timeout to use when below EXPIRY_GUARD_LIMIT */
# ifndef MAX
# define MAX(a,b) ((a) > (b) ? (a) : (b))
# endif
2003-02-16 06:00:12 +00:00
2003-09-05 04:00:57 +00:00
# define CALLERID_UNKNOWN "Unknown"
2004-05-13 19:54:42 +00:00
/* --- Choices for DTMF support in SIP channel */
2003-03-08 06:00:17 +00:00
# define SIP_DTMF_RFC2833 (1 << 0)
# define SIP_DTMF_INBAND (1 << 1)
# define SIP_DTMF_INFO (1 << 2)
2003-04-08 03:24:12 +00:00
static int max_expiry = DEFAULT_MAX_EXPIRY ;
static int default_expiry = DEFAULT_DEFAULT_EXPIRY ;
2003-02-16 06:00:12 +00:00
2003-02-07 04:07:10 +00:00
# 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... */
2002-06-28 20:34:46 +00:00
2003-03-28 06:13:04 +00:00
# define DEFAULT_RETRANS 1000 /* How frequently to retransmit */
2004-05-13 19:54:42 +00:00
# define MAX_RETRANS 5 /* Try only 5 times for retransmissions */
2003-03-28 06:13:04 +00:00
2004-05-01 21:25:31 +00:00
/* SIP Debug */
# define DEBUG_READ 0 /* Recieved data */
# define DEBUG_SEND 1 /* Transmit data */
2002-06-28 20:34:46 +00:00
static char * desc = " Session Initiation Protocol (SIP) " ;
2004-01-12 19:34:40 +00:00
static char * type = " SIP " ;
2002-06-28 20:34:46 +00:00
static char * tdesc = " Session Initiation Protocol (SIP) " ;
static char * config = " sip.conf " ;
# define DEFAULT_SIP_PORT 5060 /* From RFC 2543 */
2004-10-10 17:32:55 +00:00
# define SIP_MAX_PACKET 4096 /* Also from RFC 2543, should sub headers tho */
2002-06-28 20:34:46 +00:00
2003-08-12 16:48:16 +00:00
# define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER"
2004-07-08 11:05:03 +00:00
static char default_useragent [ AST_MAX_EXTENSION ] = DEFAULT_USERAGENT ;
2004-05-25 05:36:49 +00:00
2004-07-08 11:05:03 +00:00
static char default_context [ AST_MAX_EXTENSION ] = " default " ;
2002-06-28 20:34:46 +00:00
2004-07-08 11:05:03 +00:00
static char default_language [ MAX_LANGUAGE ] = " " ;
2002-06-28 20:34:46 +00:00
2004-07-08 11:05:03 +00:00
static char default_callerid [ AST_MAX_EXTENSION ] = " asterisk " ;
2003-03-20 17:21:54 +00:00
2004-07-08 11:05:03 +00:00
static char default_fromdomain [ AST_MAX_EXTENSION ] = " " ;
2003-04-06 02:51:10 +00:00
2003-04-30 18:48:30 +00:00
static char notifymime [ AST_MAX_EXTENSION ] = " application/simple-message-summary " ;
2003-06-12 12:48:57 +00:00
static int srvlookup = 0 ;
2003-08-12 16:48:16 +00:00
static int pedanticsipchecking = 0 ;
2004-05-13 19:54:42 +00:00
static int autocreatepeer = 0 ;
2003-11-11 20:46:41 +00:00
2004-04-29 22:27:40 +00:00
static int relaxdtmf = 0 ;
2004-07-08 11:05:03 +00:00
static int global_rtptimeout = 0 ;
2004-05-27 22:12:55 +00:00
2004-07-08 11:05:03 +00:00
static int global_rtpholdtimeout = 0 ;
2004-05-27 22:12:55 +00:00
2004-07-08 11:05:03 +00:00
static int global_trustrpid = 0 ;
2004-06-21 04:29:50 +00:00
2004-07-08 11:05:03 +00:00
static int global_progressinband = 0 ;
2004-06-26 21:17:12 +00:00
2004-06-25 05:52:55 +00:00
# ifdef OSP_SUPPORT
2004-07-08 11:05:03 +00:00
static int global_ospauth = 0 ;
2004-06-25 05:52:55 +00:00
# endif
2002-06-28 20:34:46 +00:00
static int usecnt = 0 ;
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( usecnt_lock ) ;
2002-06-28 20:34:46 +00:00
/* Protect the interface list (of sip_pvt's) */
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( iflock ) ;
2002-06-28 20:34:46 +00:00
/* Protect the monitoring thread, so only one process can kill or start it, and not
when it ' s doing something critical . */
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( netlock ) ;
2002-06-28 20:34:46 +00:00
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( monlock ) ;
2002-06-28 20:34:46 +00:00
/* This is the thread for the monitor which checks for input on the channels
which are not currently in use . */
2004-03-15 07:51:22 +00:00
static pthread_t monitor_thread = AST_PTHREADT_NULL ;
2002-06-28 20:34:46 +00:00
static int restart_monitor ( void ) ;
2003-03-12 06:00:18 +00:00
/* Codecs that we support by default: */
2004-07-08 11:05:03 +00:00
static int global_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_GSM | AST_FORMAT_H263 ;
2003-03-27 20:13:47 +00:00
static int noncodeccapability = AST_RTP_DTMF ;
2002-06-28 20:34:46 +00:00
static char ourhost [ 256 ] ;
2002-09-12 17:13:17 +00:00
static struct in_addr __ourip ;
2002-06-28 20:34:46 +00:00
static int ourport ;
2003-08-24 22:56:54 +00:00
static int sipdebug = 0 ;
2004-05-01 21:25:31 +00:00
static struct sockaddr_in debugaddr ;
2003-02-07 04:07:10 +00:00
static int tos = 0 ;
2003-06-28 16:40:02 +00:00
static int videosupport = 0 ;
2004-07-08 11:05:03 +00:00
static int global_dtmfmode = SIP_DTMF_RFC2833 ; /* DTMF mode default */
2004-05-12 00:17:31 +00:00
static int recordhistory = 0 ;
2004-07-08 11:05:03 +00:00
static int global_promiscredir ;
2004-05-12 00:17:31 +00:00
2004-07-08 11:05:03 +00:00
static char global_musicclass [ MAX_LANGUAGE ] = " " ; /* Global music on hold class */
2004-05-06 20:00:19 +00:00
static char global_realm [ AST_MAX_EXTENSION ] = " asterisk " ; /* Default realm */
2004-09-07 23:45:34 +00:00
static char regcontext [ AST_MAX_EXTENSION ] = " " ;
2003-03-12 06:00:18 +00:00
2002-06-28 20:34:46 +00:00
/* Expire slowly */
2003-04-08 03:24:12 +00:00
static int expiry = 900 ;
2002-06-28 20:34:46 +00:00
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
2003-09-13 20:26:20 +00:00
# define DEC_IN_USE 0
# define INC_IN_USE 1
# define DEC_OUT_USE 2
# define INC_OUT_USE 3
2003-02-18 18:15:30 +00:00
static struct sip_codec_pref {
int codec ;
struct sip_codec_pref * next ;
} * prefs ;
2004-05-13 19:54:42 +00:00
/* sip_request: The data grabbed from the UDP socket */
2002-06-28 20:34:46 +00:00
struct sip_request {
2003-02-07 04:07:10 +00:00
char * rlPart1 ; /* SIP Method Name or "SIP/2.0" protocol version */
char * rlPart2 ; /* The Request URI or Response Status */
2002-06-28 20:34:46 +00:00
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 ] ;
} ;
2003-03-27 20:13:47 +00:00
struct sip_pkt ;
2003-04-05 22:29:46 +00:00
struct sip_route {
struct sip_route * next ;
char hop [ 0 ] ;
} ;
2004-05-12 00:17:31 +00:00
struct sip_history {
char event [ 80 ] ;
struct sip_history * next ;
} ;
2004-05-13 19:54:42 +00:00
/* sip_pvt: PVT structures are used for each SIP conversation, ie. a call */
2002-06-28 20:34:46 +00:00
static struct sip_pvt {
2004-05-09 21:05:43 +00:00
ast_mutex_t lock ; /* Channel private lock */
char callid [ 80 ] ; /* Global CallID */
char randdata [ 80 ] ; /* Random data */
unsigned int ocseq ; /* Current outgoing seqno */
unsigned int icseq ; /* Current incoming seqno */
unsigned int callgroup ; /* Call group */
unsigned int pickupgroup ; /* Pickup group */
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 (codec) */
2004-08-18 02:16:04 +00:00
int novideo ; /* Didn't get video in invite, don't offer */
2004-05-09 21:05:43 +00:00
int jointcapability ; /* Supported capability at both ends (codecs ) */
2004-08-18 13:55:03 +00:00
int peercapability ; /* Supported peer capability */
2004-05-09 21:05:43 +00:00
int prefcodec ; /* Preferred codec (outbound only) */
2003-03-27 20:13:47 +00:00
int noncodeccapability ;
2004-10-02 00:58:31 +00:00
int callingpres ; /* Calling presentation */
2004-05-09 21:05:43 +00:00
int outgoing ; /* Outgoing or incoming call? */
int authtries ; /* Times we've tried to authenticate */
int insecure ; /* Don't check source port/ip */
int expiry ; /* How long we take to expire */
int branch ; /* One random number */
int canreinvite ; /* Do we support reinvite */
int ringing ; /* Have sent 180 ringing */
int progress ; /* Have sent 183 message progress */
int tag ; /* Another random number */
int nat ; /* Whether to try to support NAT */
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 */
2003-06-28 16:40:02 +00:00
struct sockaddr_in vredirip ; /* Where our Video RTP should be going if not to us */
2004-05-27 05:06:32 +00:00
int redircodecs ; /* Redirect codecs */
2004-05-09 21:05:43 +00:00
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 */
2003-02-07 04:07:10 +00:00
char refer_to [ AST_MAX_EXTENSION ] ; /* Place to store REFER-TO extension */
2004-05-09 21:05:43 +00:00
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_EXTENSION ] ; /* Context for this call */
2003-04-06 03:01:03 +00:00
char fromdomain [ AST_MAX_EXTENSION ] ; /* Domain to show in the from field */
2003-04-09 21:30:27 +00:00
char fromuser [ AST_MAX_EXTENSION ] ; /* Domain to show in the user field */
2003-04-18 15:47:33 +00:00
char tohost [ AST_MAX_EXTENSION ] ; /* Host we should put in the "to" field */
2004-05-09 21:05:43 +00:00
char language [ MAX_LANGUAGE ] ; /* Default language for this call */
2004-05-04 20:10:37 +00:00
char musicclass [ MAX_LANGUAGE ] ; /* Music on Hold class */
2004-05-09 21:05:43 +00:00
char rdnis [ 256 ] ; /* Referring DNIS */
char theirtag [ 256 ] ; /* Their tag */
2003-10-06 00:39:34 +00:00
char username [ 256 ] ;
char peername [ 256 ] ;
2004-05-09 21:05:43 +00:00
char authname [ 256 ] ; /* Who we use for authentication */
char uri [ 256 ] ; /* Original requested URI */
2003-10-06 00:39:34 +00:00
char peersecret [ 256 ] ;
2003-10-15 17:32:19 +00:00
char peermd5secret [ 256 ] ;
2004-10-02 00:58:31 +00:00
char cid_num [ 256 ] ; /* Caller*ID */
char cid_name [ 256 ] ; /* Caller*ID */
2003-02-07 04:07:10 +00:00
char via [ 256 ] ;
2004-08-31 17:12:09 +00:00
char fullcontact [ 128 ] ; /* Extra parameters to go in the "To" header */
2004-05-09 21:05:43 +00:00
char accountcode [ 20 ] ; /* Account code */
char our_contact [ 256 ] ; /* Our contact header */
char realm [ 256 ] ; /* Authorization realm */
char nonce [ 256 ] ; /* Authorization nonce */
char opaque [ 256 ] ; /* Opaque nonsense */
2004-04-05 05:12:00 +00:00
char qop [ 80 ] ; /* Quality of Protection, since SIP wasn't complicated enough yet. */
2004-05-09 21:05:43 +00:00
char domain [ 256 ] ; /* Authorization nonce */
char lastmsg [ 256 ] ; /* Last Message sent/received */
int amaflags ; /* AMA Flags */
int pendinginvite ; /* Any pending invite */
2004-05-27 05:06:32 +00:00
int needreinvite ; /* Do we need to send another reinvite? */
2004-05-09 21:05:43 +00:00
int pendingbye ; /* Need to send bye after we ack? */
int gotrefer ; /* Got a refer? */
2004-06-25 03:59:07 +00:00
# ifdef OSP_SUPPORT
2004-06-25 05:52:55 +00:00
int ospauth ; /* Allow OSP Authentication */
2004-06-25 03:59:07 +00:00
int osphandle ; /* OSP Handle for call */
time_t ospstart ; /* OSP Start time */
# endif
2004-05-09 21:05:43 +00:00
struct sip_request initreq ; /* Initial request */
2003-02-07 04:07:10 +00:00
2004-05-09 21:05:43 +00:00
int maxtime ; /* Max time for first response */
int initid ; /* Auto-congest ID if appropriate */
int autokillid ; /* Auto-kill ID */
2004-05-27 22:12:55 +00:00
time_t lastrtprx ; /* Last RTP received */
int rtptimeout ; /* RTP timeout time */
int rtpholdtimeout ; /* RTP timeout when on hold */
2003-03-08 06:00:17 +00:00
2003-04-06 18:19:51 +00:00
int subscribed ;
int stateid ;
int dialogver ;
2004-06-21 06:11:56 +00:00
int promiscredir ; /* Promiscuous redirection */
2003-04-06 18:19:51 +00:00
2004-06-26 21:17:12 +00:00
int trustrpid ;
int progressinband ;
2004-06-21 04:29:50 +00:00
2004-06-26 21:17:12 +00:00
int dtmfmode ;
struct ast_dsp * vad ;
2003-02-07 04:07:10 +00:00
2004-05-09 21:05:43 +00:00
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 */
2004-05-12 00:17:31 +00:00
struct sip_history * history ; /* History of this SIP dialog */
2004-05-09 21:05:43 +00:00
struct sip_pvt * next ; /* Next call in chain */
2002-06-28 20:34:46 +00:00
} * iflist = NULL ;
2004-03-24 21:21:59 +00:00
# define FLAG_RESPONSE (1 << 0)
# define FLAG_FATAL (1 << 1)
2004-05-13 19:54:42 +00:00
/* sip packet - read in sipsock_read, transmitted in send_request */
2003-03-27 20:13:47 +00:00
struct sip_pkt {
struct sip_pkt * next ; /* Next packet */
int retrans ; /* Retransmission number */
int seqno ; /* Sequence number */
2004-03-24 21:21:59 +00:00
int flags ; /* non-zero if this is a response packet (e.g. 200 OK) */
2003-03-27 20:13:47 +00:00
struct sip_pvt * owner ; /* Owner call */
int retransid ; /* Retransmission ID */
int packetlen ; /* Length of packet */
char data [ 0 ] ;
} ;
2002-06-28 20:34:46 +00:00
2004-05-13 19:54:42 +00:00
/* Structure for SIP user data. User's place calls to us */
2002-06-28 20:34:46 +00:00
struct sip_user {
/* Users who can access various contexts */
char name [ 80 ] ;
char secret [ 80 ] ;
2003-10-15 17:32:19 +00:00
char md5secret [ 80 ] ;
2002-06-28 20:34:46 +00:00
char context [ 80 ] ;
2004-10-02 00:58:31 +00:00
char cid_num [ 80 ] ;
char cid_name [ 80 ] ;
2003-04-25 03:56:46 +00:00
char accountcode [ 20 ] ;
2003-10-22 04:19:22 +00:00
char language [ MAX_LANGUAGE ] ;
2004-05-04 20:10:37 +00:00
char musicclass [ MAX_LANGUAGE ] ; /* Music on Hold class */
2004-05-09 21:05:43 +00:00
char useragent [ 256 ] ; /* User agent in SIP request */
2003-04-09 04:00:43 +00:00
unsigned int callgroup ;
unsigned int pickupgroup ;
2003-03-05 06:00:17 +00:00
int nat ;
2002-06-28 20:34:46 +00:00
int hascallerid ;
int amaflags ;
2004-10-02 00:58:31 +00:00
int callingpres ;
2002-06-28 20:34:46 +00:00
int insecure ;
2003-02-07 04:07:10 +00:00
int canreinvite ;
2003-10-23 03:50:34 +00:00
int capability ;
2004-06-25 05:52:55 +00:00
# ifdef OSP_SUPPORT
int ospauth ; /* Allow OSP Authentication */
# endif
2003-07-26 15:12:37 +00:00
int dtmfmode ;
int inUse ;
int incominglimit ;
2003-09-13 20:26:20 +00:00
int outUse ;
int outgoinglimit ;
2004-06-21 06:11:56 +00:00
int promiscredir ;
2004-06-24 04:07:44 +00:00
int trustrpid ;
2004-06-26 21:17:12 +00:00
int progressinband ;
2002-06-28 20:34:46 +00:00
struct ast_ha * ha ;
2004-06-24 04:07:44 +00:00
int temponly ;
2002-06-28 20:34:46 +00:00
struct sip_user * next ;
} ;
2004-05-13 19:54:42 +00:00
/* Structure for SIP peer data, we place calls to peers if registred or fixed IP address (host) */
2002-06-28 20:34:46 +00:00
struct sip_peer {
char name [ 80 ] ;
char secret [ 80 ] ;
2003-10-15 17:32:19 +00:00
char md5secret [ 80 ] ;
2003-02-07 04:07:10 +00:00
char context [ 80 ] ; /* JK02: peers need context too to allow parking etc */
2002-06-28 20:34:46 +00:00
char username [ 80 ] ;
2003-04-18 15:47:33 +00:00
char tohost [ 80 ] ;
2004-09-07 23:45:34 +00:00
char regexten [ AST_MAX_EXTENSION ] ; /* Extension to register (if regcontext is used) */
2003-04-09 21:30:27 +00:00
char fromuser [ 80 ] ;
2003-04-06 03:01:03 +00:00
char fromdomain [ 80 ] ;
2004-08-31 17:12:09 +00:00
char fullcontact [ 128 ] ;
2003-02-07 04:07:10 +00:00
char mailbox [ AST_MAX_EXTENSION ] ;
2004-05-04 20:10:37 +00:00
char language [ MAX_LANGUAGE ] ;
char musicclass [ MAX_LANGUAGE ] ; /* Music on Hold class */
2004-05-09 21:05:43 +00:00
char useragent [ 256 ] ; /* User agent in SIP request */
2003-02-12 13:59:15 +00:00
int lastmsgssent ;
time_t lastmsgcheck ;
2002-06-28 20:34:46 +00:00
int dynamic ;
int expire ;
2003-04-08 03:24:12 +00:00
int expiry ;
2002-06-28 20:34:46 +00:00
int capability ;
2004-05-27 22:12:55 +00:00
int rtptimeout ;
int rtpholdtimeout ;
2002-06-28 20:34:46 +00:00
int insecure ;
2004-06-25 05:52:55 +00:00
# ifdef OSP_SUPPORT
int ospauth ; /* Allow OSP Authentication */
# endif
2003-03-05 06:00:17 +00:00
int nat ;
2003-02-07 04:07:10 +00:00
int canreinvite ;
2003-04-09 04:00:43 +00:00
unsigned int callgroup ;
unsigned int pickupgroup ;
2004-06-21 06:11:56 +00:00
int promiscredir ;
2004-06-26 21:17:12 +00:00
int dtmfmode ;
int trustrpid ;
int progressinband ;
2002-06-28 20:34:46 +00:00
struct sockaddr_in addr ;
struct in_addr mask ;
2003-02-07 04:07:10 +00:00
/* 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 */
2002-06-28 20:34:46 +00:00
struct sockaddr_in defaddr ;
struct ast_ha * ha ;
int delme ;
2003-11-11 20:46:41 +00:00
int selfdestruct ;
2003-02-07 04:07:10 +00:00
int lastmsg ;
2004-01-22 16:29:02 +00:00
int temponly ;
2002-06-28 20:34:46 +00:00
struct sip_peer * next ;
} ;
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( sip_reload_lock ) ;
2004-02-02 23:48:31 +00:00
static int sip_reloading = 0 ;
2002-06-28 20:34:46 +00:00
2003-02-07 04:07:10 +00:00
# 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
2004-06-28 23:24:36 +00:00
# define SIP_NAT_NEVER 0
2004-08-27 02:45:35 +00:00
# define SIP_NAT_RFC3581 (1 << 0)
# define SIP_NAT_ROUTE (1 << 2)
# define SIP_NAT_ALWAYS (SIP_NAT_ROUTE | SIP_NAT_RFC3581)
2004-06-28 23:24:36 +00:00
2004-05-13 19:54:42 +00:00
/* sip_registry: Registrations with other SIP proxies */
2003-02-07 04:07:10 +00:00
struct sip_registry {
2004-07-13 02:20:44 +00:00
int portno ; /* Optional port override */
2004-05-13 19:54:42 +00:00
char username [ 80 ] ; /* Who we are registering as */
char authuser [ 80 ] ; /* Who we *authenticate* as */
2003-04-09 21:13:11 +00:00
char hostname [ 80 ] ;
2004-05-13 19:54:42 +00:00
char secret [ 80 ] ; /* Password or key name in []'s */
2003-10-15 17:32:19 +00:00
char md5secret [ 80 ] ;
2004-05-13 19:54:42 +00:00
char contact [ 80 ] ; /* Contact extension */
2003-02-07 04:07:10 +00:00
char random [ 80 ] ;
2004-05-13 19:54:42 +00:00
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 */
2003-02-07 04:07:10 +00:00
int regstate ;
int callid_valid ; /* 0 means we haven't chosen callid for this registry yet. */
char callid [ 80 ] ; /* Global CallID for this registry */
2003-04-21 16:49:41 +00:00
unsigned int ocseq ; /* Sequence number we got to for REGISTERs for this registry */
2004-05-13 19:54:42 +00:00
struct sockaddr_in us ; /* Who the server thinks we are */
2003-02-07 04:07:10 +00:00
struct sip_registry * next ;
} ;
2004-05-13 19:54:42 +00:00
/*--- The user list: Users and friends ---*/
2004-02-02 22:35:33 +00:00
static struct ast_user_list {
struct sip_user * users ;
ast_mutex_t lock ;
2004-06-09 01:45:08 +00:00
} userl ;
2004-02-02 22:35:33 +00:00
2004-05-13 19:54:42 +00:00
/*--- The peer list: Peers and Friends ---*/
2004-02-02 22:35:33 +00:00
static struct ast_peer_list {
struct sip_peer * peers ;
ast_mutex_t lock ;
2004-06-09 01:45:08 +00:00
} peerl ;
2004-02-02 22:35:33 +00:00
2004-05-13 19:54:42 +00:00
/*--- The register list: Other SIP proxys we register with and call ---*/
2004-02-02 22:35:33 +00:00
static struct ast_register_list {
struct sip_registry * registrations ;
ast_mutex_t lock ;
2004-02-02 23:21:36 +00:00
int recheck ;
2004-06-09 01:45:08 +00:00
} regl ;
2004-02-02 22:35:33 +00:00
2003-03-28 06:59:34 +00:00
# define REINVITE_INVITE 1
# define REINVITE_UPDATE 2
2004-02-02 23:21:36 +00:00
static int __sip_do_register ( struct sip_registry * r ) ;
2003-02-07 04:07:10 +00:00
2002-06-28 20:34:46 +00:00
static int sipsock = - 1 ;
2004-07-08 11:05:03 +00:00
static int global_nat = SIP_NAT_RFC3581 ;
static int global_canreinvite = REINVITE_INVITE ;
2004-01-13 01:31:42 +00:00
2002-06-28 20:34:46 +00:00
static struct sockaddr_in bindaddr ;
2004-01-13 01:31:42 +00:00
static struct sockaddr_in externip ;
2004-05-08 20:58:24 +00:00
static struct ast_ha * localaddr ;
2002-06-28 20:34:46 +00:00
static struct ast_frame * sip_read ( struct ast_channel * ast ) ;
2002-09-12 17:13:17 +00:00
static int transmit_response ( struct sip_pvt * p , char * msg , struct sip_request * req ) ;
2003-03-29 16:53:55 +00:00
static int transmit_response_with_sdp ( struct sip_pvt * p , char * msg , struct sip_request * req , int retrans ) ;
2004-06-12 16:38:36 +00:00
static int transmit_response_with_auth ( struct sip_pvt * p , char * msg , struct sip_request * req , char * rand , int reliable , char * header ) ;
2004-03-28 04:05:58 +00:00
static int transmit_request ( struct sip_pvt * p , char * msg , int inc , int reliable , int newbranch ) ;
static int transmit_request_with_auth ( struct sip_pvt * p , char * msg , int inc , int reliable , int newbranch ) ;
2004-06-25 03:59:07 +00:00
static int transmit_invite ( struct sip_pvt * p , char * msg , int sendsdp , char * auth , char * authheader , char * vxml_url , char * distinctive_ring , char * osptoken , int init ) ;
2004-05-27 05:06:32 +00:00
static int transmit_reinvite_with_sdp ( struct sip_pvt * p ) ;
2003-03-12 06:00:18 +00:00
static int transmit_info_with_digit ( struct sip_pvt * p , char digit ) ;
2003-02-07 04:07:10 +00:00
static int transmit_message_with_text ( struct sip_pvt * p , char * text ) ;
2003-05-14 05:52:59 +00:00
static int transmit_refer ( struct sip_pvt * p , char * dest ) ;
2003-11-11 20:46:41 +00:00
static struct sip_peer * temp_peer ( char * name ) ;
2003-11-10 04:22:33 +00:00
static int do_proxy_auth ( struct sip_pvt * p , struct sip_request * req , char * header , char * respheader , char * msg , int init ) ;
2003-04-05 22:29:46 +00:00
static void free_old_route ( struct sip_route * route ) ;
2003-04-07 03:46:20 +00:00
static int build_reply_digest ( struct sip_pvt * p , char * orig_header , char * digest , int digest_len ) ;
2004-04-26 14:54:33 +00:00
static int update_user_counter ( struct sip_pvt * fup , int event ) ;
2003-11-11 20:46:41 +00:00
static void prune_peers ( void ) ;
2004-02-02 23:48:31 +00:00
static int sip_do_reload ( void ) ;
2004-06-18 13:53:48 +00:00
/*--- sip_debug_test_addr: See if we pass debug IP filter */
2004-06-18 16:23:56 +00:00
static inline int sip_debug_test_addr ( struct sockaddr_in * addr )
{
2004-06-18 13:53:48 +00:00
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 ;
}
2004-06-18 16:23:56 +00:00
static inline int sip_debug_test_pvt ( struct sip_pvt * p )
{
2004-06-18 13:53:48 +00:00
if ( sipdebug = = 0 )
return 0 ;
2004-08-27 02:45:35 +00:00
return sip_debug_test_addr ( ( ( p - > nat & SIP_NAT_ROUTE ) ? & p - > recv : & p - > sa ) ) ;
2004-06-18 13:53:48 +00:00
}
2002-06-28 20:34:46 +00:00
2004-05-13 19:54:42 +00:00
/*--- __sip_xmit: Transmit SIP message ---*/
2002-06-28 20:34:46 +00:00
static int __sip_xmit ( struct sip_pvt * p , char * data , int len )
{
int res ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2004-08-27 02:45:35 +00:00
if ( p - > nat & SIP_NAT_ROUTE )
2003-03-05 06:00:17 +00:00
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 ) ) ;
2002-06-28 20:34:46 +00:00
if ( res ! = len ) {
2004-06-29 12:56:46 +00:00
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 ) ) ;
2002-06-28 20:34:46 +00:00
}
return res ;
}
2003-03-28 06:13:04 +00:00
static void sip_destroy ( struct sip_pvt * p ) ;
2004-05-13 19:54:42 +00:00
/*--- ast_sip_ouraddrfor: NAT fix - decide which IP address to use for ASterisk server? ---*/
/* Only used for outbound registrations */
2003-08-21 02:27:25 +00:00
static int ast_sip_ouraddrfor ( struct in_addr * them , struct in_addr * us )
{
2004-01-13 01:31:42 +00:00
/*
2004-05-08 20:58:24 +00:00
* 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 ) ) {
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2004-01-13 01:31:42 +00:00
memcpy ( us , & externip . sin_addr , sizeof ( struct in_addr ) ) ;
2004-07-08 11:05:03 +00:00
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 ) ;
2004-05-08 20:58:24 +00:00
}
2004-01-13 01:31:42 +00:00
else if ( bindaddr . sin_addr . s_addr )
memcpy ( us , & bindaddr . sin_addr , sizeof ( struct in_addr ) ) ;
else
return ast_ouraddrfor ( them , us ) ;
2003-08-21 02:27:25 +00:00
return 0 ;
}
2004-05-12 00:17:31 +00:00
static int append_history ( struct sip_pvt * p , char * event , char * data )
{
struct sip_history * hist , * prev ;
char * c ;
if ( ! recordhistory )
return 0 ;
hist = malloc ( sizeof ( struct sip_history ) ) ;
if ( hist ) {
memset ( hist , 0 , sizeof ( struct sip_history ) ) ;
snprintf ( hist - > event , sizeof ( hist - > event ) , " %-15s %s " , event , data ) ;
/* Trim up nicely */
c = hist - > event ;
while ( * c ) {
if ( ( * c = = ' \r ' ) | | ( * c = = ' \n ' ) ) {
* c = ' \0 ' ;
break ;
}
c + + ;
}
/* Enqueue into history */
prev = p - > history ;
if ( prev ) {
while ( prev - > next )
prev = prev - > next ;
prev - > next = hist ;
} else {
p - > history = hist ;
}
}
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- retrans_pkt: Retransmit SIP message if no answer ---*/
2003-03-28 06:13:04 +00:00
static int retrans_pkt ( void * data )
{
2004-05-16 16:31:42 +00:00
struct sip_pkt * pkt = data , * prev , * cur ;
2003-03-28 06:13:04 +00:00
int res = 0 ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & pkt - > owner - > lock ) ;
2003-09-08 19:38:24 +00:00
if ( pkt - > retrans < MAX_RETRANS ) {
pkt - > retrans + + ;
2004-05-01 21:25:31 +00:00
if ( sip_debug_test_pvt ( pkt - > owner ) ) {
2004-08-27 02:45:35 +00:00
if ( pkt - > owner - > nat & SIP_NAT_ROUTE )
2004-06-29 12:56:46 +00:00
ast_verbose ( " Retransmitting #%d (NAT): \n %s \n to %s:%d \n " , pkt - > retrans , pkt - > data , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , pkt - > owner - > recv . sin_addr ) , ntohs ( pkt - > owner - > recv . sin_port ) ) ;
2003-09-08 19:38:24 +00:00
else
2004-06-29 12:56:46 +00:00
ast_verbose ( " Retransmitting #%d (no NAT): \n %s \n to %s:%d \n " , pkt - > retrans , pkt - > data , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , pkt - > owner - > sa . sin_addr ) , ntohs ( pkt - > owner - > sa . sin_port ) ) ;
2003-03-28 06:13:04 +00:00
}
2004-05-12 00:17:31 +00:00
append_history ( pkt - > owner , " ReTx " , pkt - > data ) ;
2003-09-08 19:38:24 +00:00
__sip_xmit ( pkt - > owner , pkt - > data , pkt - > packetlen ) ;
res = 1 ;
2003-03-28 06:13:04 +00:00
} else {
2004-03-24 21:21:59 +00:00
ast_log ( LOG_WARNING , " Maximum retries exceeded on call %s for seqno %d (%s %s) \n " , pkt - > owner - > callid , pkt - > seqno , ( pkt - > flags & FLAG_FATAL ) ? " Critical " : " Non-critical " , ( pkt - > flags & FLAG_RESPONSE ) ? " Response " : " Request " ) ;
2004-05-12 00:17:31 +00:00
append_history ( pkt - > owner , " MaxRetries " , pkt - > flags & FLAG_FATAL ? " (Critical) " : " (Non-critical) " ) ;
2003-03-28 06:13:04 +00:00
pkt - > retransid = - 1 ;
2004-03-24 21:21:59 +00:00
if ( pkt - > flags & FLAG_FATAL ) {
while ( pkt - > owner - > owner & & ast_mutex_trylock ( & pkt - > owner - > owner - > lock ) ) {
ast_mutex_unlock ( & pkt - > owner - > lock ) ;
usleep ( 1 ) ;
ast_mutex_lock ( & pkt - > owner - > lock ) ;
}
if ( pkt - > owner - > owner ) {
2004-04-06 22:17:32 +00:00
ast_queue_hangup ( pkt - > owner - > owner ) ;
2004-03-24 21:21:59 +00:00
ast_mutex_unlock ( & pkt - > owner - > owner - > lock ) ;
} else {
/* If no owner, destroy now */
pkt - > owner - > needdestroy = 1 ;
}
2003-03-31 15:56:00 +00:00
}
2004-05-16 16:31:42 +00:00
/* In any case, go ahead and remove the packet */
prev = NULL ;
cur = pkt - > owner - > packets ;
while ( cur ) {
if ( cur = = pkt )
break ;
prev = cur ;
cur = cur - > next ;
}
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 " ) ;
2003-03-28 06:13:04 +00:00
}
2003-03-31 15:56:00 +00:00
if ( pkt )
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & pkt - > owner - > lock ) ;
2003-03-28 06:13:04 +00:00
return res ;
}
2004-05-13 19:54:42 +00:00
/*--- __sip_reliable_xmit: transmit packet with retransmits ---*/
2004-03-24 21:21:59 +00:00
static int __sip_reliable_xmit ( struct sip_pvt * p , int seqno , int resp , char * data , int len , int fatal )
2003-03-28 06:13:04 +00:00
{
struct sip_pkt * pkt ;
2004-08-17 23:53:15 +00:00
pkt = malloc ( sizeof ( struct sip_pkt ) + len + 1 ) ;
2003-03-28 06:13:04 +00:00
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 ;
2004-03-24 21:21:59 +00:00
pkt - > flags = resp ;
2004-08-17 23:53:15 +00:00
pkt - > data [ len ] = ' \0 ' ;
2004-03-24 21:21:59 +00:00
if ( fatal )
pkt - > flags | = FLAG_FATAL ;
2003-03-28 06:13:04 +00:00
/* Schedule retransmission */
2003-07-22 22:07:16 +00:00
pkt - > retransid = ast_sched_add ( sched , DEFAULT_RETRANS , retrans_pkt , pkt ) ;
2003-03-28 06:13:04 +00:00
pkt - > next = p - > packets ;
p - > packets = pkt ;
__sip_xmit ( pkt - > owner , pkt - > data , pkt - > packetlen ) ;
2003-04-07 06:12:19 +00:00
if ( ! strncasecmp ( pkt - > data , " INVITE " , 6 ) ) {
/* Note this is a pending invite */
p - > pendinginvite = seqno ;
}
2003-03-28 06:13:04 +00:00
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- __sip_autodestruct: Kill a call (called by scheduler) ---*/
2003-03-28 06:13:04 +00:00
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 ) ;
2004-05-12 00:17:31 +00:00
append_history ( p , " AutoDestroy " , " " ) ;
2003-03-28 06:13:04 +00:00
if ( p - > owner ) {
ast_log ( LOG_WARNING , " Autodestruct on call '%s' with owner in place \n " , p - > callid ) ;
2004-04-06 22:17:32 +00:00
ast_queue_hangup ( p - > owner ) ;
2003-03-28 06:13:04 +00:00
} else {
sip_destroy ( p ) ;
}
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_scheddestroy: Schedule destruction of SIP call ---*/
2003-03-28 06:13:04 +00:00
static int sip_scheddestroy ( struct sip_pvt * p , int ms )
{
2004-05-12 00:17:31 +00:00
char tmp [ 80 ] ;
2004-05-01 21:25:31 +00:00
if ( sip_debug_test_pvt ( p ) )
2004-04-04 01:55:16 +00:00
ast_verbose ( " Scheduling destruction of call '%s' in %d ms \n " , p - > callid , ms ) ;
2004-05-12 00:17:31 +00:00
if ( recordhistory ) {
snprintf ( tmp , sizeof ( tmp ) , " %d ms " , ms ) ;
append_history ( p , " SchedDestroy " , tmp ) ;
}
2003-03-28 06:13:04 +00:00
if ( p - > autokillid > - 1 )
ast_sched_del ( sched , p - > autokillid ) ;
p - > autokillid = ast_sched_add ( sched , ms , __sip_autodestruct , p ) ;
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_cancel_destroy: Cancel destruction of SIP call ---*/
2003-03-29 16:09:58 +00:00
static int sip_cancel_destroy ( struct sip_pvt * p )
{
if ( p - > autokillid > - 1 )
ast_sched_del ( sched , p - > autokillid ) ;
2004-05-12 00:17:31 +00:00
append_history ( p , " CancelDestroy " , " " ) ;
2003-03-29 16:09:58 +00:00
p - > autokillid = - 1 ;
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- __sip_ack: Acknowledges receipt of a packet and stops retransmission ---*/
2004-07-16 15:45:37 +00:00
static int __sip_ack ( struct sip_pvt * p , int seqno , int resp , const char * msg )
2003-03-28 06:13:04 +00:00
{
struct sip_pkt * cur , * prev = NULL ;
int res = - 1 ;
2003-04-07 06:12:19 +00:00
int resetinvite = 0 ;
2004-07-16 15:45:37 +00:00
/* Just in case... */
if ( ! msg ) msg = " ___NEVER___ " ;
2003-03-28 06:13:04 +00:00
cur = p - > packets ;
while ( cur ) {
2004-07-16 15:45:37 +00:00
if ( ( cur - > seqno = = seqno ) & & ( ( cur - > flags & FLAG_RESPONSE ) = = resp ) & &
( ( cur - > flags & FLAG_RESPONSE ) | |
( ! strncasecmp ( msg , cur - > data , strlen ( msg ) ) & & ( cur - > data [ strlen ( msg ) ] < 33 ) ) ) ) {
2003-04-07 06:12:19 +00:00
if ( ! resp & & ( seqno = = p - > pendinginvite ) ) {
ast_log ( LOG_DEBUG , " Acked pending invite %d \n " , p - > pendinginvite ) ;
p - > pendinginvite = 0 ;
resetinvite = 1 ;
}
2003-03-28 06:13:04 +00:00
/* 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 ;
}
2003-03-28 06:36:10 +00:00
ast_log ( LOG_DEBUG , " Stopping retransmission on '%s' of %s %d: %s \n " , p - > callid , resp ? " Response " : " Request " , seqno , res ? " Not Found " : " Found " ) ;
2003-03-28 06:13:04 +00:00
return res ;
}
2004-09-28 12:55:08 +00:00
/* Pretend to ack all packets */
static int __sip_pretend_ack ( struct sip_pvt * p )
{
while ( p - > packets ) {
__sip_ack ( p , p - > packets - > seqno , ( p - > packets - > flags & FLAG_RESPONSE ) , p - > packets - > data ) ;
}
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- __sip_semi_ack: Acks receipt of packet, keep it around (used for provisional responses) ---*/
2004-07-16 15:45:37 +00:00
static int __sip_semi_ack ( struct sip_pvt * p , int seqno , int resp , const char * msg )
2003-08-20 23:03:44 +00:00
{
2003-08-21 02:27:25 +00:00
struct sip_pkt * cur ;
2003-08-20 23:03:44 +00:00
int res = - 1 ;
cur = p - > packets ;
while ( cur ) {
2004-07-16 15:45:37 +00:00
if ( ( cur - > seqno = = seqno ) & & ( ( cur - > flags & FLAG_RESPONSE ) = = resp ) & &
( ( cur - > flags & FLAG_RESPONSE ) | |
( ! strncasecmp ( msg , cur - > data , strlen ( msg ) ) & & ( cur - > data [ strlen ( msg ) ] < 33 ) ) ) ) {
2003-08-20 23:03:44 +00:00
/* this is our baby */
if ( cur - > retransid > - 1 )
ast_sched_del ( sched , cur - > retransid ) ;
cur - > retransid = - 1 ;
res = 0 ;
break ;
}
cur = cur - > next ;
}
2003-08-21 02:27:25 +00:00
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 " ) ;
2003-08-20 23:03:44 +00:00
return res ;
}
2004-07-14 11:51:44 +00:00
static void parse ( struct sip_request * req ) ;
static char * get_header ( struct sip_request * req , char * name ) ;
static void copy_request ( struct sip_request * dst , struct sip_request * src ) ;
static void parse_copy ( struct sip_request * dst , struct sip_request * src )
{
memset ( dst , 0 , sizeof ( * dst ) ) ;
memcpy ( dst - > data , src - > data , sizeof ( dst - > data ) ) ;
dst - > len = src - > len ;
parse ( dst ) ;
}
2004-05-13 19:54:42 +00:00
/*--- send_response: Transmit response on SIP request---*/
2003-03-28 06:13:04 +00:00
static int send_response ( struct sip_pvt * p , struct sip_request * req , int reliable , int seqno )
2002-06-28 20:34:46 +00:00
{
int res ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2004-07-14 11:51:44 +00:00
struct sip_request tmp ;
char tmpmsg [ 80 ] ;
2004-05-01 21:25:31 +00:00
if ( sip_debug_test_pvt ( p ) ) {
2004-08-27 02:45:35 +00:00
if ( p - > nat & SIP_NAT_ROUTE )
2004-06-29 12:56:46 +00:00
ast_verbose ( " %sTransmitting (NAT): \n %s \n to %s:%d \n " , reliable ? " Reliably " : " " , req - > data , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > recv . sin_addr ) , ntohs ( p - > recv . sin_port ) ) ;
2003-03-05 06:00:17 +00:00
else
2004-06-29 12:56:46 +00:00
ast_verbose ( " %sTransmitting (no NAT): \n %s \n to %s:%d \n " , reliable ? " Reliably " : " " , req - > data , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > sa . sin_addr ) , ntohs ( p - > sa . sin_port ) ) ;
2003-03-05 06:00:17 +00:00
}
2004-05-12 00:17:31 +00:00
if ( reliable ) {
2004-07-14 11:51:44 +00:00
if ( recordhistory ) {
parse_copy ( & tmp , req ) ;
snprintf ( tmpmsg , sizeof ( tmpmsg ) , " %s / %s " , tmp . data , get_header ( & tmp , " CSeq " ) ) ;
append_history ( p , " TxRespRel " , tmpmsg ) ;
}
2004-03-24 21:21:59 +00:00
res = __sip_reliable_xmit ( p , seqno , 1 , req - > data , req - > len , ( reliable > 1 ) ) ;
2004-05-12 00:17:31 +00:00
} else {
2004-07-14 11:51:44 +00:00
if ( recordhistory ) {
parse_copy ( & tmp , req ) ;
snprintf ( tmpmsg , sizeof ( tmpmsg ) , " %s / %s " , tmp . data , get_header ( & tmp , " CSeq " ) ) ;
append_history ( p , " TxResp " , tmpmsg ) ;
}
2003-03-28 06:13:04 +00:00
res = __sip_xmit ( p , req - > data , req - > len ) ;
2004-05-12 00:17:31 +00:00
}
2002-06-28 20:34:46 +00:00
if ( res > 0 )
res = 0 ;
return res ;
}
2004-05-13 19:54:42 +00:00
/*--- send_request: Send SIP Request to the other part of the dialogue ---*/
2003-03-28 06:13:04 +00:00
static int send_request ( struct sip_pvt * p , struct sip_request * req , int reliable , int seqno )
2002-06-28 20:34:46 +00:00
{
int res ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2004-07-14 11:51:44 +00:00
struct sip_request tmp ;
char tmpmsg [ 80 ] ;
2004-05-01 21:25:31 +00:00
if ( sip_debug_test_pvt ( p ) ) {
2004-08-27 02:45:35 +00:00
if ( p - > nat & SIP_NAT_ROUTE )
2004-06-29 12:56:46 +00:00
ast_verbose ( " %sTransmitting: \n %s (NAT) to %s:%d \n " , reliable ? " Reliably " : " " , req - > data , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > recv . sin_addr ) , ntohs ( p - > recv . sin_port ) ) ;
2003-03-05 06:00:17 +00:00
else
2004-06-29 12:56:46 +00:00
ast_verbose ( " %sTransmitting: \n %s (no NAT) to %s:%d \n " , reliable ? " Reliably " : " " , req - > data , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > sa . sin_addr ) , ntohs ( p - > sa . sin_port ) ) ;
2003-03-05 06:00:17 +00:00
}
2004-05-12 00:17:31 +00:00
if ( reliable ) {
2004-07-14 11:51:44 +00:00
if ( recordhistory ) {
parse_copy ( & tmp , req ) ;
snprintf ( tmpmsg , sizeof ( tmpmsg ) , " %s / %s " , tmp . data , get_header ( & tmp , " CSeq " ) ) ;
append_history ( p , " TxReqRel " , tmpmsg ) ;
}
2004-03-24 21:21:59 +00:00
res = __sip_reliable_xmit ( p , seqno , 0 , req - > data , req - > len , ( reliable > 1 ) ) ;
2004-05-12 00:17:31 +00:00
} else {
2004-07-14 11:51:44 +00:00
if ( recordhistory ) {
parse_copy ( & tmp , req ) ;
snprintf ( tmpmsg , sizeof ( tmpmsg ) , " %s / %s " , tmp . data , get_header ( & tmp , " CSeq " ) ) ;
append_history ( p , " TxReq " , tmpmsg ) ;
}
2003-03-28 06:13:04 +00:00
res = __sip_xmit ( p , req - > data , req - > len ) ;
2004-05-12 00:17:31 +00:00
}
2002-06-28 20:34:46 +00:00
return res ;
}
2004-07-15 22:14:27 +00:00
/*--- url_decode: Decode SIP URL ---*/
2004-06-25 18:23:06 +00:00
static void url_decode ( char * s )
{
char * o = s ;
unsigned int tmp ;
while ( * s ) {
switch ( * s ) {
case ' % ' :
if ( strlen ( s ) > 2 ) {
if ( sscanf ( s + 1 , " %2x " , & tmp ) = = 1 ) {
* o = tmp ;
s + = 2 ; /* Will be incremented once more when we break out */
break ;
}
}
/* Fall through if something wasn't right with the formatting */
default :
* o = * s ;
}
s + + ;
o + + ;
}
* o = ' \0 ' ;
}
2004-05-13 19:54:42 +00:00
/*--- ditch_braces: Pick out text in braces from character string ---*/
2002-06-28 20:34:46 +00:00
static char * ditch_braces ( char * tmp )
{
char * c = tmp ;
char * n ;
2004-08-23 14:16:25 +00:00
char * q ;
if ( ( q = strchr ( tmp , ' " ' ) ) ) {
c = q + 1 ;
if ( ( q = strchr ( c , ' " ' ) ) )
c = q + 1 ;
else {
ast_log ( LOG_WARNING , " No closing quote in '%s' \n " , tmp ) ;
c = tmp ;
}
}
if ( ( n = strchr ( c , ' < ' ) ) ) {
2002-06-28 20:34:46 +00:00
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 ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_sendtext: Send SIP MESSAGE text within a call ---*/
/* Called from PBX core text message functions */
2003-02-07 04:07:10 +00:00
static int sip_sendtext ( struct ast_channel * ast , char * text )
2002-06-28 20:34:46 +00:00
{
2003-02-07 04:07:10 +00:00
struct sip_pvt * p = ast - > pvt - > pvt ;
2004-06-18 13:53:48 +00:00
int debug = sip_debug_test_pvt ( p ) ;
if ( debug )
2003-02-07 04:07:10 +00:00
ast_verbose ( " Sending text %s on %s \n " , text , ast - > name ) ;
if ( ! p )
return - 1 ;
2004-05-03 21:01:14 +00:00
if ( ! text | | ast_strlen_zero ( text ) )
2003-02-07 04:07:10 +00:00
return 0 ;
2004-06-18 13:53:48 +00:00
if ( debug )
2003-02-07 04:07:10 +00:00
ast_verbose ( " Really sending text %s on %s \n " , text , ast - > name ) ;
transmit_message_with_text ( p , text ) ;
return 0 ;
2002-06-28 20:34:46 +00:00
}
2004-10-07 15:46:08 +00:00
static void realtime_update_peer ( const char * peername , struct sockaddr_in * sin , const char * username , int expirey )
{
char port [ 10 ] ;
char ipaddr [ 20 ] ;
char regseconds [ 20 ] ;
time_t nowtime ;
time ( & nowtime ) ;
nowtime + = expirey ;
snprintf ( regseconds , sizeof ( regseconds ) , " %ld " , nowtime ) ;
ast_inet_ntoa ( ipaddr , sizeof ( ipaddr ) , sin - > sin_addr ) ;
snprintf ( port , sizeof ( port ) , " %d " , ntohs ( sin - > sin_port ) ) ;
ast_update_realtime ( " sipfriends " , " name " , peername , " ipaddr " , ipaddr , " port " , port , " regseconds " , regseconds , " username " , username , NULL ) ;
}
2004-01-22 16:29:02 +00:00
2004-10-07 15:46:08 +00:00
static void register_peer_exten ( struct sip_peer * peer , int onoff )
2004-06-24 04:07:44 +00:00
{
2004-10-07 15:46:08 +00:00
unsigned char multi [ 256 ] = " " ;
char * stringp , * ext ;
if ( ! ast_strlen_zero ( regcontext ) ) {
strncpy ( multi , ast_strlen_zero ( peer - > regexten ) ? peer - > name : peer - > regexten , sizeof ( multi ) - 1 ) ;
stringp = multi ;
while ( ( ext = strsep ( & stringp , " & " ) ) ) {
if ( onoff )
ast_add_extension ( regcontext , 1 , ext , 1 , NULL , NULL , " Noop " , strdup ( peer - > name ) , free , type ) ;
else
ast_context_remove_extension ( regcontext , ext , 1 , NULL ) ;
2004-07-08 11:05:03 +00:00
}
}
2004-06-24 04:07:44 +00:00
}
2004-10-07 15:46:08 +00:00
static void destroy_peer ( struct sip_peer * peer )
2004-01-22 16:29:02 +00:00
{
2004-10-07 15:46:08 +00:00
/* Delete it, it needs to disappear */
if ( peer - > call )
sip_destroy ( peer - > call ) ;
if ( peer - > expire > - 1 )
ast_sched_del ( sched , peer - > expire ) ;
if ( peer - > pokeexpire > - 1 )
ast_sched_del ( sched , peer - > pokeexpire ) ;
register_peer_exten ( peer , 0 ) ;
2004-10-07 18:27:12 +00:00
ast_free_ha ( peer - > ha ) ;
2004-10-07 15:46:08 +00:00
free ( peer ) ;
2004-01-22 16:29:02 +00:00
}
2004-10-07 15:46:08 +00:00
/*--- update_peer: Update peer data in database (if used) ---*/
static void update_peer ( struct sip_peer * p , int expiry )
2004-01-22 16:29:02 +00:00
{
2004-10-07 15:46:08 +00:00
if ( p - > temponly )
realtime_update_peer ( p - > name , & p - > addr , p - > username , expiry ) ;
}
2004-10-12 19:54:54 +00:00
static struct sip_peer * build_peer ( const char * name , struct ast_variable * v , int temponly ) ;
2004-10-07 15:46:08 +00:00
static struct sip_peer * realtime_peer ( const char * peername , struct sockaddr_in * sin )
{
struct ast_variable * var , * tmp = NULL ;
char iabuf [ 80 ] ;
struct sip_peer * peer = NULL ;
time_t nowtime , regseconds ;
int dynamic = 0 ;
2004-01-22 16:29:02 +00:00
2004-10-07 15:46:08 +00:00
if ( sin )
ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , sin - > sin_addr ) ;
if ( peername )
2004-10-07 19:57:50 +00:00
var = ast_load_realtime ( " sipfriends " , " name " , peername , NULL ) ;
2004-10-07 15:46:08 +00:00
else
2004-10-07 19:57:50 +00:00
var = ast_load_realtime ( " sipfriends " , " ipaddr " , iabuf , NULL ) ;
2004-10-07 15:46:08 +00:00
if ( var ) {
/* Make sure it's not a user only... */
2004-10-12 19:54:54 +00:00
peer = build_peer ( peername , var , 1 ) ;
2004-01-22 16:29:02 +00:00
if ( peer ) {
2004-10-07 15:46:08 +00:00
/* Add some finishing touches, addresses, etc */
peer - > temponly = 1 ;
tmp = var ;
while ( tmp ) {
if ( ! strcasecmp ( tmp - > name , " type " ) ) {
if ( strcasecmp ( tmp - > value , " friend " ) & &
strcasecmp ( tmp - > value , " peer " ) ) {
/* Whoops, we weren't supposed to exist! */
destroy_peer ( peer ) ;
peer = NULL ;
break ;
}
} else if ( ! strcasecmp ( tmp - > name , " regseconds " ) ) {
if ( sscanf ( tmp - > value , " %li " , & regseconds ) ! = 1 )
regseconds = 0 ;
} else if ( ! strcasecmp ( tmp - > name , " ipaddr " ) ) {
inet_aton ( tmp - > value , & ( peer - > addr . sin_addr ) ) ;
} else if ( ! strcasecmp ( tmp - > name , " port " ) ) {
peer - > addr . sin_port = htons ( atoi ( tmp - > value ) ) ;
} else if ( ! strcasecmp ( tmp - > name , " host " ) ) {
if ( ! strcasecmp ( tmp - > value , " dynamic " ) )
dynamic = 1 ;
2004-01-22 16:29:02 +00:00
}
2004-10-07 15:46:08 +00:00
tmp = tmp - > next ;
}
if ( peer & & dynamic ) {
2004-01-22 16:29:02 +00:00
time ( & nowtime ) ;
2004-10-07 15:46:08 +00:00
if ( ( nowtime - regseconds ) > 0 ) {
memset ( & peer - > addr , 0 , sizeof ( peer - > addr ) ) ;
if ( option_debug )
ast_log ( LOG_DEBUG , " Bah, we're expired (%ld/%ld/%ld)! \n " , nowtime - regseconds , regseconds , nowtime ) ;
}
2004-01-22 16:29:02 +00:00
}
}
2004-10-07 15:46:08 +00:00
ast_destroy_realtime ( var ) ;
2004-01-22 16:29:02 +00:00
}
2004-10-09 20:08:41 +00:00
return peer ;
2004-04-26 14:54:33 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- find_peer: Locate peer by name or ip address */
2004-10-07 15:46:08 +00:00
static struct sip_peer * find_peer ( const char * peer , struct sockaddr_in * sin )
2004-04-26 14:54:33 +00:00
{
struct sip_peer * p = NULL ;
p = peerl . peers ;
if ( peer ) {
/* Find by peer name */
while ( p ) {
if ( ! strcasecmp ( p - > name , peer ) ) {
break ;
}
p = p - > next ;
}
}
else {
/* Find by sin */
while ( p ) {
if ( ! inaddrcmp ( & p - > addr , sin ) | |
( p - > insecure & &
( p - > addr . sin_addr . s_addr = = sin - > sin_addr . s_addr ) ) ) {
break ;
}
p = p - > next ;
}
}
if ( ! p ) {
2004-10-07 15:46:08 +00:00
p = realtime_peer ( peer , sin ) ;
2004-04-26 14:54:33 +00:00
}
return ( p ) ;
}
2004-10-07 15:46:08 +00:00
static void destroy_user ( struct sip_user * user )
{
ast_free_ha ( user - > ha ) ;
free ( user ) ;
}
static struct sip_user * build_user ( const char * name , struct ast_variable * v ) ;
static struct sip_user * realtime_user ( const char * username )
{
struct ast_variable * var ;
struct ast_variable * tmp ;
struct sip_user * user = NULL ;
2004-10-07 19:57:50 +00:00
var = ast_load_realtime ( " sipfriends " , " name " , username , NULL ) ;
2004-10-07 15:46:08 +00:00
if ( var ) {
/* Make sure it's not a user only... */
user = build_user ( username , var ) ;
if ( user ) {
/* Add some finishing touches, addresses, etc */
user - > temponly = 1 ;
tmp = var ;
while ( tmp ) {
if ( ! strcasecmp ( tmp - > name , " type " ) ) {
if ( strcasecmp ( tmp - > value , " friend " ) & &
strcasecmp ( tmp - > value , " user " ) ) {
/* Whoops, we weren't supposed to exist! */
destroy_user ( user ) ;
user = NULL ;
break ;
}
}
tmp = tmp - > next ;
}
}
ast_destroy_realtime ( var ) ;
}
return user ;
}
2004-05-13 19:54:42 +00:00
/*--- find_user: Locate user by name */
2004-04-26 14:54:33 +00:00
static struct sip_user * find_user ( char * name )
{
struct sip_user * u = NULL ;
u = userl . users ;
while ( u ) {
if ( ! strcasecmp ( u - > name , name ) ) {
break ;
}
u = u - > next ;
}
2004-06-24 04:07:44 +00:00
if ( ! u ) {
2004-10-07 15:46:08 +00:00
u = realtime_user ( name ) ;
2004-06-24 04:07:44 +00:00
}
2004-04-26 14:54:33 +00:00
return ( u ) ;
}
2004-05-13 19:54:42 +00:00
/*--- create_addr: create address structure from peer definition ---*/
/* Or, if peer not found, find it in the global DNS */
/* returns TRUE on failure, FALSE on success */
2004-07-17 23:27:11 +00:00
static int create_addr ( struct sip_pvt * r , char * opeer )
2002-06-28 20:34:46 +00:00
{
struct hostent * hp ;
2004-04-22 00:20:34 +00:00
struct ast_hostent ahp ;
2002-06-28 20:34:46 +00:00
struct sip_peer * p ;
int found = 0 ;
2003-04-16 21:42:08 +00:00
char * port ;
2004-09-13 12:24:38 +00:00
char * callhost ;
2003-06-12 12:48:57 +00:00
int portno ;
char host [ 256 ] , * hostn ;
2004-07-17 23:27:11 +00:00
char peer [ 256 ] = " " ;
2003-04-16 21:42:08 +00:00
2004-07-17 23:27:11 +00:00
strncpy ( peer , opeer , sizeof ( peer ) - 1 ) ;
port = strchr ( peer , ' : ' ) ;
if ( port ) {
* port = ' \0 ' ;
port + + ;
}
2003-02-07 04:07:10 +00:00
r - > sa . sin_family = AF_INET ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & peerl . lock ) ;
2004-04-26 14:54:33 +00:00
p = find_peer ( peer , NULL ) ;
2004-01-22 16:29:02 +00:00
if ( p ) {
2002-06-28 20:34:46 +00:00
found + + ;
2003-02-07 04:07:10 +00:00
r - > capability = p - > capability ;
2003-03-09 06:00:18 +00:00
r - > nat = p - > nat ;
if ( r - > rtp ) {
2004-08-27 02:45:35 +00:00
ast_log ( LOG_DEBUG , " Setting NAT on RTP to %d \n " , ( r - > nat & SIP_NAT_ROUTE ) ) ;
ast_rtp_setnat ( r - > rtp , ( r - > nat & SIP_NAT_ROUTE ) ) ;
2003-03-09 06:00:18 +00:00
}
2003-06-28 16:40:02 +00:00
if ( r - > vrtp ) {
2004-08-27 02:45:35 +00:00
ast_log ( LOG_DEBUG , " Setting NAT on VRTP to %d \n " , ( r - > nat & SIP_NAT_ROUTE ) ) ;
ast_rtp_setnat ( r - > vrtp , ( r - > nat & SIP_NAT_ROUTE ) ) ;
2003-06-28 16:40:02 +00:00
}
2003-02-07 04:07:10 +00:00
strncpy ( r - > peername , p - > username , sizeof ( r - > peername ) - 1 ) ;
2004-05-02 16:30:05 +00:00
strncpy ( r - > authname , p - > username , sizeof ( r - > authname ) - 1 ) ;
2003-02-07 04:07:10 +00:00
strncpy ( r - > peersecret , p - > secret , sizeof ( r - > peersecret ) - 1 ) ;
2003-10-15 17:32:19 +00:00
strncpy ( r - > peermd5secret , p - > md5secret , sizeof ( r - > peermd5secret ) - 1 ) ;
2003-02-07 04:07:10 +00:00
strncpy ( r - > username , p - > username , sizeof ( r - > username ) - 1 ) ;
2003-04-18 15:47:33 +00:00
strncpy ( r - > tohost , p - > tohost , sizeof ( r - > tohost ) - 1 ) ;
2004-08-31 17:12:09 +00:00
strncpy ( r - > fullcontact , p - > fullcontact , sizeof ( r - > fullcontact ) - 1 ) ;
2004-09-13 12:24:38 +00:00
if ( ! r - > initreq . headers & & ! ast_strlen_zero ( p - > fromdomain ) ) {
if ( ( callhost = strchr ( r - > callid , ' @ ' ) ) ) {
strncpy ( callhost + 1 , p - > fromdomain , sizeof ( r - > callid ) - ( callhost - r - > callid ) - 2 ) ;
}
}
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( r - > tohost ) ) {
2003-04-23 18:50:53 +00:00
if ( p - > addr . sin_addr . s_addr )
2004-07-08 11:05:03 +00:00
ast_inet_ntoa ( r - > tohost , sizeof ( r - > tohost ) , p - > addr . sin_addr ) ;
2003-04-23 18:50:53 +00:00
else
2004-07-08 11:05:03 +00:00
ast_inet_ntoa ( r - > tohost , sizeof ( r - > tohost ) , p - > defaddr . sin_addr ) ;
2003-04-23 18:50:53 +00:00
}
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( p - > fromdomain ) )
2003-04-06 03:01:03 +00:00
strncpy ( r - > fromdomain , p - > fromdomain , sizeof ( r - > fromdomain ) - 1 ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( p - > fromuser ) )
2003-04-09 21:30:27 +00:00
strncpy ( r - > fromuser , p - > fromuser , sizeof ( r - > fromuser ) - 1 ) ;
2003-02-07 04:07:10 +00:00
r - > insecure = p - > insecure ;
r - > canreinvite = p - > canreinvite ;
r - > maxtime = p - > maxms ;
2003-04-09 04:00:43 +00:00
r - > callgroup = p - > callgroup ;
r - > pickupgroup = p - > pickupgroup ;
2003-03-18 18:11:43 +00:00
if ( p - > dtmfmode ) {
2003-03-12 06:00:18 +00:00
r - > dtmfmode = p - > dtmfmode ;
2003-03-18 18:11:43 +00:00
if ( r - > dtmfmode & SIP_DTMF_RFC2833 )
2003-03-27 20:13:47 +00:00
r - > noncodeccapability | = AST_RTP_DTMF ;
2003-03-18 18:11:43 +00:00
else
2003-03-27 20:13:47 +00:00
r - > noncodeccapability & = ~ AST_RTP_DTMF ;
2003-03-18 18:11:43 +00:00
}
2004-06-21 06:11:56 +00:00
r - > promiscredir = p - > promiscredir ;
2003-02-07 04:07:10 +00:00
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 ) ) ) ) {
2002-06-28 20:34:46 +00:00
if ( p - > addr . sin_addr . s_addr ) {
2003-02-07 04:07:10 +00:00
r - > sa . sin_addr = p - > addr . sin_addr ;
r - > sa . sin_port = p - > addr . sin_port ;
2002-06-28 20:34:46 +00:00
} else {
2003-02-07 04:07:10 +00:00
r - > sa . sin_addr = p - > defaddr . sin_addr ;
r - > sa . sin_port = p - > defaddr . sin_port ;
2002-06-28 20:34:46 +00:00
}
2003-03-05 06:00:17 +00:00
memcpy ( & r - > recv , & r - > sa , sizeof ( r - > recv ) ) ;
2004-02-20 15:39:43 +00:00
} else {
2004-04-26 14:54:33 +00:00
if ( p - > temponly ) {
2004-10-07 18:27:12 +00:00
destroy_peer ( p ) ;
2004-04-26 14:54:33 +00:00
}
2004-02-01 23:55:17 +00:00
p = NULL ;
2004-02-20 15:39:43 +00:00
}
2002-06-28 20:34:46 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2002-06-28 20:34:46 +00:00
if ( ! p & & ! found ) {
2003-06-12 12:48:57 +00:00
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 ;
}
}
2004-04-22 00:20:34 +00:00
hp = ast_gethostbyname ( hostn , & ahp ) ;
2002-06-28 20:34:46 +00:00
if ( hp ) {
2003-04-18 15:47:33 +00:00
strncpy ( r - > tohost , peer , sizeof ( r - > tohost ) - 1 ) ;
2003-02-07 04:07:10 +00:00
memcpy ( & r - > sa . sin_addr , hp - > h_addr , sizeof ( r - > sa . sin_addr ) ) ;
2003-06-12 12:48:57 +00:00
r - > sa . sin_port = htons ( portno ) ;
2003-03-05 06:00:17 +00:00
memcpy ( & r - > recv , & r - > sa , sizeof ( r - > recv ) ) ;
2002-06-28 20:34:46 +00:00
return 0 ;
} else {
ast_log ( LOG_WARNING , " No such host: %s \n " , peer ) ;
return - 1 ;
}
} else if ( ! p )
return - 1 ;
2004-01-22 16:29:02 +00:00
else {
2004-04-26 14:54:33 +00:00
if ( p - > temponly ) {
2004-10-07 18:27:12 +00:00
destroy_peer ( p ) ;
2004-04-26 14:54:33 +00:00
}
2002-06-28 20:34:46 +00:00
return 0 ;
2004-01-22 16:29:02 +00:00
}
2002-06-28 20:34:46 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- auto_congest: Scheduled congestion on a call ---*/
2003-02-07 04:07:10 +00:00
static int auto_congest ( void * nothing )
{
struct sip_pvt * p = nothing ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-02-07 04:07:10 +00:00
p - > initid = - 1 ;
if ( p - > owner ) {
2003-08-13 15:25:16 +00:00
if ( ! ast_mutex_trylock ( & p - > owner - > lock ) ) {
2003-02-07 04:07:10 +00:00
ast_log ( LOG_NOTICE , " Auto-congesting %s \n " , p - > owner - > name ) ;
2004-04-06 22:17:32 +00:00
ast_queue_control ( p - > owner , AST_CONTROL_CONGESTION ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > owner - > lock ) ;
2003-02-07 04:07:10 +00:00
}
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2003-02-07 04:07:10 +00:00
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_prefs_free: Free codec list in preference structure ---*/
2003-02-18 18:15:30 +00:00
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 ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_pref_remove: Remove codec from pref list ---*/
2003-02-18 18:15:30 +00:00
static void sip_pref_remove ( int format )
{
2003-03-18 06:00:18 +00:00
struct sip_codec_pref * cur , * prev = NULL ;
2003-02-18 18:15:30 +00:00
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 ;
}
}
2004-05-13 19:54:42 +00:00
/*--- sip_pref_append: Append codec to list ---*/
2003-02-18 18:15:30 +00:00
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 ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_codec_choose: Pick a codec ---*/
2003-02-18 18:15:30 +00:00
static int sip_codec_choose ( int formats )
{
struct sip_codec_pref * cur ;
2004-03-19 08:00:13 +00:00
formats & = ( ( AST_FORMAT_MAX_AUDIO < < 1 ) - 1 ) ;
2003-02-18 18:15:30 +00:00
cur = prefs ;
while ( cur ) {
if ( formats & cur - > codec )
return cur - > codec ;
cur = cur - > next ;
}
return ast_best_codec ( formats ) ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_call: Initiate SIP call from PBX ---*/
/* used from the dial() application */
2002-06-28 20:34:46 +00:00
static int sip_call ( struct ast_channel * ast , char * dest , int timeout )
{
int res ;
struct sip_pvt * p ;
2003-02-07 04:07:10 +00:00
char * vxml_url = NULL ;
2003-06-18 22:34:55 +00:00
char * distinctive_ring = NULL ;
2004-06-25 03:59:07 +00:00
char * osptoken = NULL ;
# ifdef OSP_SUPPORT
char * osphandle = NULL ;
# endif
2003-02-07 04:07:10 +00:00
struct varshead * headp ;
struct ast_var_t * current ;
2002-06-28 20:34:46 +00:00
p = ast - > pvt - > pvt ;
2002-09-12 17:13:17 +00:00
if ( ( ast - > _state ! = AST_STATE_DOWN ) & & ( ast - > _state ! = AST_STATE_RESERVED ) ) {
2002-06-28 20:34:46 +00:00
ast_log ( LOG_WARNING , " sip_call called on %s, neither down nor reserved \n " , ast - > name ) ;
return - 1 ;
}
2003-06-18 22:34:55 +00:00
/* Check whether there is vxml_url, distinctive ring variables */
2002-09-12 17:13:17 +00:00
2003-02-07 04:07:10 +00:00
headp = & ast - > varshead ;
AST_LIST_TRAVERSE ( headp , current , entries ) {
2003-06-18 22:34:55 +00:00
/* Check whether there is a VXML_URL variable */
2003-02-07 04:07:10 +00:00
if ( strcasecmp ( ast_var_name ( current ) , " VXML_URL " ) = = 0 )
{
vxml_url = ast_var_value ( current ) ;
2004-06-25 03:59:07 +00:00
} else
2003-06-18 22:34:55 +00:00
/* Check whether there is a ALERT_INFO variable */
if ( strcasecmp ( ast_var_name ( current ) , " ALERT_INFO " ) = = 0 )
{
distinctive_ring = ast_var_value ( current ) ;
}
2004-06-25 03:59:07 +00:00
# ifdef OSP_SUPPORT
else if ( ! strcasecmp ( ast_var_name ( current ) , " OSPTOKEN " ) ) {
osptoken = ast_var_value ( current ) ;
} else if ( ! strcasecmp ( ast_var_name ( current ) , " OSPHANDLE " ) ) {
osphandle = ast_var_value ( current ) ;
}
# endif
2003-02-07 04:07:10 +00:00
}
2002-06-28 20:34:46 +00:00
res = 0 ;
p - > outgoing = 1 ;
2004-06-25 03:59:07 +00:00
# ifdef OSP_SUPPORT
if ( ! osptoken | | ! osphandle | | ( sscanf ( osphandle , " %i " , & p - > osphandle ) ! = 1 ) ) {
/* Force Disable OSP support */
osptoken = NULL ;
osphandle = NULL ;
p - > osphandle = - 1 ;
}
# endif
2003-09-13 20:26:20 +00:00
ast_log ( LOG_DEBUG , " Outgoing Call for %s \n " , p - > username ) ;
2004-04-26 14:54:33 +00:00
res = update_user_counter ( p , INC_OUT_USE ) ;
2003-11-26 19:24:57 +00:00
if ( res ! = - 1 ) {
2004-10-02 00:58:31 +00:00
p - > callingpres = ast - > cid . cid_pres ;
2003-11-26 19:24:57 +00:00
p - > jointcapability = p - > capability ;
2004-06-25 03:59:07 +00:00
transmit_invite ( p , " INVITE " , 1 , NULL , NULL , vxml_url , distinctive_ring , osptoken , 1 ) ;
2003-11-26 19:24:57 +00:00
if ( p - > maxtime ) {
/* Initialize auto-congest time */
2004-01-09 06:51:25 +00:00
p - > initid = ast_sched_add ( sched , p - > maxtime * 4 , auto_congest , p ) ;
2003-11-26 19:24:57 +00:00
}
2003-02-07 04:07:10 +00:00
}
2002-06-28 20:34:46 +00:00
return res ;
}
2004-05-13 19:54:42 +00:00
/*--- __sip_destroy: Execute destrucion of call structure, release memory---*/
2003-02-07 04:07:10 +00:00
static void __sip_destroy ( struct sip_pvt * p , int lockowner )
2002-06-28 20:34:46 +00:00
{
struct sip_pvt * cur , * prev = NULL ;
2003-03-27 20:13:47 +00:00
struct sip_pkt * cp ;
2004-05-12 00:17:31 +00:00
struct sip_history * hist ;
2004-06-18 13:53:48 +00:00
2004-05-01 21:25:31 +00:00
if ( sip_debug_test_pvt ( p ) )
2004-04-04 01:55:16 +00:00
ast_verbose ( " Destroying call '%s' \n " , p - > callid ) ;
2003-04-06 18:19:51 +00:00
if ( p - > stateid > - 1 )
ast_extension_state_del ( p - > stateid , NULL ) ;
2003-03-28 06:13:04 +00:00
if ( p - > initid > - 1 )
ast_sched_del ( sched , p - > initid ) ;
if ( p - > autokillid > - 1 )
ast_sched_del ( sched , p - > autokillid ) ;
2003-04-06 18:19:51 +00:00
2002-06-28 20:34:46 +00:00
if ( p - > rtp ) {
ast_rtp_destroy ( p - > rtp ) ;
}
2003-06-28 16:40:02 +00:00
if ( p - > vrtp ) {
ast_rtp_destroy ( p - > vrtp ) ;
}
2003-04-05 22:29:46 +00:00
if ( p - > route ) {
free_old_route ( p - > route ) ;
p - > route = NULL ;
}
2003-07-15 05:05:19 +00:00
if ( p - > registry ) {
2003-10-01 04:53:53 +00:00
/* Carefully unlink from registry */
struct sip_registry * reg ;
2004-02-02 22:35:33 +00:00
ast_mutex_lock ( & regl . lock ) ;
reg = regl . registrations ;
2003-10-01 04:53:53 +00:00
while ( reg ) {
if ( ( reg = = p - > registry ) & & ( p - > registry - > call = = p ) )
p - > registry - > call = NULL ;
reg = reg - > next ;
}
2004-02-02 22:35:33 +00:00
ast_mutex_unlock ( & regl . lock ) ;
2003-07-15 05:05:19 +00:00
}
2002-09-12 17:13:17 +00:00
/* Unlink us from the owner if we have one */
if ( p - > owner ) {
2003-02-07 04:07:10 +00:00
if ( lockowner )
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > owner - > lock ) ;
2002-09-12 17:13:17 +00:00
ast_log ( LOG_DEBUG , " Detaching from %s \n " , p - > owner - > name ) ;
p - > owner - > pvt - > pvt = NULL ;
2003-02-07 04:07:10 +00:00
if ( lockowner )
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > owner - > lock ) ;
2002-09-12 17:13:17 +00:00
}
2004-05-12 00:17:31 +00:00
/* Clear history */
while ( p - > history ) {
hist = p - > history ;
p - > history = p - > history - > next ;
free ( hist ) ;
}
2002-06-28 20:34:46 +00:00
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 ) ;
2003-02-07 04:07:10 +00:00
} else {
if ( p - > initid > - 1 )
ast_sched_del ( sched , p - > initid ) ;
2003-03-27 20:13:47 +00:00
while ( ( cp = p - > packets ) ) {
p - > packets = p - > packets - > next ;
if ( cp - > retransid > - 1 )
ast_sched_del ( sched , cp - > retransid ) ;
free ( cp ) ;
}
2004-10-07 19:00:00 +00:00
ast_mutex_destroy ( & p - > lock ) ;
2002-06-28 20:34:46 +00:00
free ( p ) ;
2003-02-07 04:07:10 +00:00
}
2002-06-28 20:34:46 +00:00
}
2003-07-26 15:12:37 +00:00
2004-05-13 19:54:42 +00:00
/*--- update_user_counter: Handle incominglimit and outgoinglimit for SIP users ---*/
/* Note: This is going to be replaced by app_groupcount */
2004-04-26 14:54:33 +00:00
static int update_user_counter ( struct sip_pvt * fup , int event )
2003-07-26 15:12:37 +00:00
{
char name [ 256 ] = " " ;
struct sip_user * u ;
2003-07-26 23:14:27 +00:00
strncpy ( name , fup - > username , sizeof ( name ) - 1 ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & userl . lock ) ;
2004-04-26 14:54:33 +00:00
u = find_user ( name ) ;
2003-07-30 20:45:17 +00:00
if ( ! u ) {
2003-07-26 23:14:27 +00:00
ast_log ( LOG_DEBUG , " %s is not a local user \n " , name ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & userl . lock ) ;
2003-07-30 18:39:41 +00:00
return 0 ;
2003-07-26 23:14:27 +00:00
}
2003-09-13 20:26:20 +00:00
switch ( event ) {
2003-11-26 19:24:57 +00:00
/* incoming and outgoing affects the inUse counter */
case DEC_OUT_USE :
2003-09-13 20:26:20 +00:00
case DEC_IN_USE :
if ( u - > inUse > 0 ) {
u - > inUse - - ;
} else {
u - > inUse = 0 ;
2003-07-26 15:12:37 +00:00
}
2003-09-13 20:26:20 +00:00
break ;
case INC_IN_USE :
2003-11-26 19:24:57 +00:00
case INC_OUT_USE :
2003-09-13 20:26:20 +00:00
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 ) ;
2003-11-26 19:24:57 +00:00
/* inc inUse as well */
if ( event = = INC_OUT_USE ) {
u - > inUse + + ;
}
2004-04-26 14:54:33 +00:00
ast_mutex_unlock ( & userl . lock ) ;
2004-10-07 18:27:12 +00:00
if ( u - > temponly ) {
destroy_user ( u ) ;
}
2003-09-13 20:26:20 +00:00
return - 1 ;
}
}
u - > inUse + + ;
ast_log ( LOG_DEBUG , " Call from user '%s' is %d out of %d \n " , u - > name , u - > inUse , u - > incominglimit ) ;
break ;
2003-11-26 19:24:57 +00:00
/* we don't use these anymore
2003-09-13 20:26:20 +00:00
case DEC_OUT_USE :
if ( u - > outUse > 0 ) {
u - > outUse - - ;
} else {
u - > outUse = 0 ;
}
break ;
case INC_OUT_USE :
if ( u - > outgoinglimit > 0 ) {
if ( u - > outUse > = u - > outgoinglimit ) {
ast_log ( LOG_ERROR , " Outgoing call from user '%s' rejected due to usage limit of %d \n " , u - > name , u - > outgoinglimit ) ;
ast_mutex_unlock ( & userl . lock ) ;
2004-10-07 18:27:12 +00:00
if ( u - > temponly ) {
destroy_user ( u ) ;
}
2003-09-13 20:26:20 +00:00
return - 1 ;
}
}
u - > outUse + + ;
break ;
2003-11-26 19:24:57 +00:00
*/
2003-09-13 20:26:20 +00:00
default :
2004-04-26 14:54:33 +00:00
ast_log ( LOG_ERROR , " update_user_counter(%s,%d) called with no event! \n " , u - > name , event ) ;
2003-07-26 15:12:37 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & userl . lock ) ;
2004-10-07 18:27:12 +00:00
if ( u - > temponly ) {
destroy_user ( u ) ;
}
2003-07-26 15:12:37 +00:00
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_destroy: Destroy SIP call structure ---*/
2002-06-28 20:34:46 +00:00
static void sip_destroy ( struct sip_pvt * p )
{
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & iflock ) ;
2003-02-07 04:07:10 +00:00
__sip_destroy ( p , 1 ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
2002-06-28 20:34:46 +00:00
}
2004-05-13 19:54:42 +00:00
2004-03-24 21:21:59 +00:00
static int transmit_response_reliable ( struct sip_pvt * p , char * msg , struct sip_request * req , int fatal ) ;
2003-04-06 03:58:02 +00:00
2003-10-15 22:12:05 +00:00
static int hangup_sip2cause ( int cause )
{
2004-05-13 19:54:42 +00:00
/* Possible values from causes.h
AST_CAUSE_NOTDEFINED AST_CAUSE_NORMAL AST_CAUSE_BUSY
AST_CAUSE_FAILURE AST_CAUSE_CONGESTION AST_CAUSE_UNALLOCATED
*/
switch ( cause ) {
case 404 : /* Not found */
return AST_CAUSE_UNALLOCATED ;
2004-06-25 18:23:06 +00:00
case 483 : /* Too many hops */
return AST_CAUSE_FAILURE ;
2003-10-15 22:12:05 +00:00
case 486 :
return AST_CAUSE_BUSY ;
default :
return AST_CAUSE_NORMAL ;
}
/* Never reached */
return 0 ;
}
static char * hangup_cause2sip ( int cause )
{
switch ( cause )
{
2004-05-13 19:54:42 +00:00
case AST_CAUSE_FAILURE :
return " 500 Server internal failure " ;
case AST_CAUSE_CONGESTION :
return " 503 Service Unavailable " ;
2003-10-15 22:12:05 +00:00
case AST_CAUSE_BUSY :
return " 486 Busy " ;
default :
return NULL ;
}
/* Never reached */
return 0 ;
}
2002-06-28 20:34:46 +00:00
2004-05-13 19:54:42 +00:00
/*--- sip_hangup: Hangup SIP call */
2002-06-28 20:34:46 +00:00
static int sip_hangup ( struct ast_channel * ast )
{
2002-09-12 17:13:17 +00:00
struct sip_pvt * p = ast - > pvt - > pvt ;
int needcancel = 0 ;
2003-04-09 19:35:24 +00:00
int needdestroy = 0 ;
2002-06-28 20:34:46 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " sip_hangup(%s) \n " , ast - > name ) ;
if ( ! ast - > pvt - > pvt ) {
2002-09-12 17:13:17 +00:00
ast_log ( LOG_DEBUG , " Asked to hangup channel not connected \n " ) ;
2002-06-28 20:34:46 +00:00
return 0 ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2004-06-25 03:59:07 +00:00
# ifdef OSP_SUPPORT
if ( ( p - > osphandle > - 1 ) & & ( ast - > _state = = AST_STATE_UP ) ) {
ast_osp_terminate ( p - > osphandle , AST_CAUSE_NORMAL , p - > ospstart , time ( NULL ) - p - > ospstart ) ;
}
# endif
2003-09-13 20:26:20 +00:00
if ( p - > outgoing ) {
2004-04-26 14:54:33 +00:00
ast_log ( LOG_DEBUG , " update_user_counter(%s) - decrement outUse counter \n " , p - > username ) ;
update_user_counter ( p , DEC_OUT_USE ) ;
2003-09-13 20:26:20 +00:00
} else {
2004-04-26 14:54:33 +00:00
ast_log ( LOG_DEBUG , " update_user_counter(%s) - decrement inUse counter \n " , p - > username ) ;
update_user_counter ( p , DEC_IN_USE ) ;
2003-09-13 20:26:20 +00:00
}
2002-09-12 17:13:17 +00:00
/* Determine how to disconnect */
2003-02-07 04:07:10 +00:00
if ( p - > owner ! = ast ) {
ast_log ( LOG_WARNING , " Huh? We aren't the owner? \n " ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2003-02-07 04:07:10 +00:00
return 0 ;
}
if ( ! ast | | ( ast - > _state ! = AST_STATE_UP ) )
2002-09-12 17:13:17 +00:00
needcancel = 1 ;
/* Disconnect */
2002-06-28 20:34:46 +00:00
p = ast - > pvt - > pvt ;
2003-03-08 06:00:17 +00:00
if ( p - > vad ) {
ast_dsp_free ( p - > vad ) ;
}
2002-09-12 17:13:17 +00:00
p - > owner = NULL ;
ast - > pvt - > pvt = NULL ;
2003-09-27 02:30:03 +00:00
ast_mutex_lock ( & usecnt_lock ) ;
usecnt - - ;
ast_mutex_unlock ( & usecnt_lock ) ;
ast_update_use_count ( ) ;
2004-05-27 22:12:55 +00:00
needdestroy = 1 ;
2002-09-12 17:13:17 +00:00
/* Start the process if it's not already started */
2004-05-03 21:01:14 +00:00
if ( ! p - > alreadygone & & ! ast_strlen_zero ( p - > initreq . data ) ) {
2002-09-12 17:13:17 +00:00
if ( needcancel ) {
2003-04-06 03:58:02 +00:00
if ( p - > outgoing ) {
2004-03-28 04:05:58 +00:00
transmit_request_with_auth ( p , " CANCEL " , p - > ocseq , 1 , 0 ) ;
2003-04-06 03:58:02 +00:00
/* Actually don't destroy us yet, wait for the 487 on our original
2004-05-16 16:31:42 +00:00
INVITE , but do set an autodestruct just in case we never get it . */
2003-04-09 19:35:24 +00:00
needdestroy = 0 ;
2003-04-06 03:58:02 +00:00
sip_scheddestroy ( p , 15000 ) ;
2003-12-09 22:04:23 +00:00
if ( p - > initid ! = - 1 ) {
/* channel still up - reverse dec of inUse counter
only if the channel is not auto - congested */
if ( p - > outgoing ) {
2004-04-26 14:54:33 +00:00
update_user_counter ( p , INC_OUT_USE ) ;
2003-12-09 22:04:23 +00:00
}
else {
2004-04-26 14:54:33 +00:00
update_user_counter ( p , INC_IN_USE ) ;
2003-12-09 22:04:23 +00:00
}
2003-11-26 19:24:57 +00:00
}
2003-10-15 22:12:05 +00:00
} else {
char * res ;
if ( ast - > hangupcause & & ( ( res = hangup_cause2sip ( ast - > hangupcause ) ) ) ) {
2004-03-24 21:21:59 +00:00
transmit_response_reliable ( p , res , & p - > initreq , 1 ) ;
2003-10-15 22:12:05 +00:00
} else
2004-03-24 21:21:59 +00:00
transmit_response_reliable ( p , " 403 Forbidden " , & p - > initreq , 1 ) ;
2003-10-15 22:12:05 +00:00
}
2002-09-12 17:13:17 +00:00
} else {
2003-04-07 06:12:19 +00:00
if ( ! p - > pendinginvite ) {
/* Send a hangup */
2004-03-28 04:05:58 +00:00
transmit_request_with_auth ( p , " BYE " , 0 , 1 , 1 ) ;
2003-04-07 06:12:19 +00:00
} else {
2003-04-09 19:35:24 +00:00
/* Note we will need a BYE when this all settles out
but we can ' t send one while we have " INVITE " outstanding . */
2003-04-07 06:12:19 +00:00
p - > pendingbye = 1 ;
2004-05-27 05:06:32 +00:00
p - > needreinvite = 0 ;
2003-04-07 06:12:19 +00:00
}
2002-09-12 17:13:17 +00:00
}
2002-06-28 20:34:46 +00:00
}
2003-04-09 19:35:24 +00:00
p - > needdestroy = needdestroy ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2002-06-28 20:34:46 +00:00
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_answer: Answer SIP call , send 200 OK on Invite */
2002-06-28 20:34:46 +00:00
static int sip_answer ( struct ast_channel * ast )
{
2003-03-18 06:00:18 +00:00
int res = 0 , fmt ;
2003-02-23 06:00:11 +00:00
char * codec ;
2002-06-28 20:34:46 +00:00
struct sip_pvt * p = ast - > pvt - > pvt ;
2003-02-23 06:00:11 +00:00
2004-06-23 17:41:51 +00:00
ast_mutex_lock ( & p - > lock ) ;
2002-09-12 17:13:17 +00:00
if ( ast - > _state ! = AST_STATE_UP ) {
2004-06-25 03:59:07 +00:00
# ifdef OSP_SUPPORT
time ( & p - > ospstart ) ;
# endif
2003-02-23 06:00:11 +00:00
codec = pbx_builtin_getvar_helper ( p - > owner , " SIP_CODEC " ) ;
if ( codec ) {
fmt = ast_getformatbyname ( codec ) ;
if ( fmt ) {
2003-11-04 00:34:17 +00:00
ast_log ( LOG_NOTICE , " Changing codec to '%s' for this call because of ${SIP_CODEC) variable \n " , codec ) ;
2004-10-04 13:03:53 +00:00
if ( p - > jointcapability & fmt ) {
p - > jointcapability & = fmt ;
p - > capability & = fmt ;
} else
ast_log ( LOG_NOTICE , " Ignoring ${SIP_CODEC} variable because it is not shared by both ends. \n " ) ;
2003-11-04 00:34:17 +00:00
} else ast_log ( LOG_NOTICE , " Ignoring ${SIP_CODEC} variable because of unrecognized/not configured codec (check allow/disallow in sip.conf): %s \n " , codec ) ;
2003-02-23 06:00:11 +00:00
}
2002-09-12 17:13:17 +00:00
ast_setstate ( ast , AST_STATE_UP ) ;
2002-06-28 20:34:46 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " sip_answer(%s) \n " , ast - > name ) ;
2003-03-29 16:53:55 +00:00
res = transmit_response_with_sdp ( p , " 200 OK " , & p - > initreq , 1 ) ;
2002-06-28 20:34:46 +00:00
}
2004-06-23 17:41:51 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2002-06-28 20:34:46 +00:00
return res ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_write: Send response, support audio media ---*/
2002-06-28 20:34:46 +00:00
static int sip_write ( struct ast_channel * ast , struct ast_frame * frame )
{
struct sip_pvt * p = ast - > pvt - > pvt ;
2002-09-12 17:13:17 +00:00
int res = 0 ;
2003-06-28 16:40:02 +00:00
if ( frame - > frametype = = AST_FRAME_VOICE ) {
2002-09-12 17:13:17 +00:00
if ( ! ( frame - > subclass & ast - > nativeformats ) ) {
ast_log ( LOG_WARNING , " Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d) \n " ,
frame - > subclass , ast - > nativeformats , ast - > readformat , ast - > writeformat ) ;
2004-07-07 16:02:13 +00:00
return 0 ;
2002-09-12 17:13:17 +00:00
}
2003-06-28 16:40:02 +00:00
if ( p ) {
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-06-28 16:40:02 +00:00
if ( p - > rtp ) {
if ( ( ast - > _state ! = AST_STATE_UP ) & & ! p - > progress & & ! p - > outgoing ) {
transmit_response_with_sdp ( p , " 183 Session Progress " , & p - > initreq , 0 ) ;
p - > progress = 1 ;
}
res = ast_rtp_write ( p - > rtp , frame ) ;
2003-02-07 04:07:10 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2002-09-12 17:13:17 +00:00
}
2003-06-28 16:40:02 +00:00
} else if ( frame - > frametype = = AST_FRAME_VIDEO ) {
if ( p ) {
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-06-28 16:40:02 +00:00
if ( p - > vrtp ) {
if ( ( ast - > _state ! = AST_STATE_UP ) & & ! p - > progress & & ! p - > outgoing ) {
transmit_response_with_sdp ( p , " 183 Session Progress " , & p - > initreq , 0 ) ;
p - > progress = 1 ;
}
res = ast_rtp_write ( p - > vrtp , frame ) ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2003-06-28 16:40:02 +00:00
}
} else if ( frame - > frametype = = AST_FRAME_IMAGE ) {
return 0 ;
} else {
ast_log ( LOG_WARNING , " Can't send %d type frames with SIP write \n " , frame - > frametype ) ;
return 0 ;
2002-09-12 17:13:17 +00:00
}
2003-06-28 16:40:02 +00:00
2002-09-12 17:13:17 +00:00
return res ;
2002-06-28 20:34:46 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- sip_fixup: Fix up a channel: If a channel is consumed, this is called.
Basically update any - > owner links - - - - */
2004-04-06 22:17:32 +00:00
static int sip_fixup ( struct ast_channel * oldchan , struct ast_channel * newchan )
2002-06-28 20:34:46 +00:00
{
struct sip_pvt * p = newchan - > pvt - > pvt ;
2004-04-06 22:17:32 +00:00
ast_mutex_lock ( & p - > lock ) ;
2002-06-28 20:34:46 +00:00
if ( p - > owner ! = oldchan ) {
ast_log ( LOG_WARNING , " old channel wasn't %p but was %p \n " , oldchan , p - > owner ) ;
2004-04-06 22:17:32 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2002-06-28 20:34:46 +00:00
return - 1 ;
}
p - > owner = newchan ;
2004-04-06 22:17:32 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2002-06-28 20:34:46 +00:00
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_senddigit: Send DTMF character on SIP channel */
/* within one call, we're able to transmit in many methods simultaneously */
2003-02-07 04:07:10 +00:00
static int sip_senddigit ( struct ast_channel * ast , char digit )
{
struct sip_pvt * p = ast - > pvt - > pvt ;
2003-03-12 06:00:18 +00:00
if ( p & & ( p - > dtmfmode & SIP_DTMF_INFO ) ) {
transmit_info_with_digit ( p , digit ) ;
}
2003-03-08 06:00:17 +00:00
if ( p & & p - > rtp & & ( p - > dtmfmode & SIP_DTMF_RFC2833 ) ) {
2003-02-07 04:07:10 +00:00
ast_rtp_senddigit ( p - > rtp , digit ) ;
}
2003-03-08 06:00:17 +00:00
/* If in-band DTMF is desired, send that */
if ( p - > dtmfmode & SIP_DTMF_INBAND )
return - 1 ;
return 0 ;
2003-02-07 04:07:10 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- sip_transfer: Transfer SIP call */
2003-05-14 05:52:59 +00:00
static int sip_transfer ( struct ast_channel * ast , char * dest )
{
struct sip_pvt * p = ast - > pvt - > pvt ;
int res ;
res = transmit_refer ( p , dest ) ;
return res ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_indicate: Play indication to user */
/* With SIP a lot of indications is sent as messages, letting the device play
the indication - busy signal , congestion etc */
2002-06-28 20:34:46 +00:00
static int sip_indicate ( struct ast_channel * ast , int condition )
{
struct sip_pvt * p = ast - > pvt - > pvt ;
switch ( condition ) {
case AST_CONTROL_RINGING :
2002-09-12 17:13:17 +00:00
if ( ast - > _state = = AST_STATE_RING ) {
2004-03-23 18:09:25 +00:00
if ( ! p - > progress ) {
2003-04-09 05:38:39 +00:00
transmit_response ( p , " 180 Ringing " , & p - > initreq ) ;
2003-05-22 14:24:06 +00:00
p - > ringing = 1 ;
2004-06-26 21:17:12 +00:00
if ( ! p - > progressinband )
break ;
2003-04-09 05:38:39 +00:00
} else {
/* Oops, we've sent progress tones. Let Asterisk do it instead */
}
2002-06-28 20:34:46 +00:00
}
2003-02-07 04:07:10 +00:00
return - 1 ;
2002-06-28 20:34:46 +00:00
case AST_CONTROL_BUSY :
2002-09-12 17:13:17 +00:00
if ( ast - > _state ! = AST_STATE_UP ) {
2003-04-24 18:21:46 +00:00
transmit_response ( p , " 486 Busy Here " , & p - > initreq ) ;
2003-02-07 04:07:10 +00:00
p - > alreadygone = 1 ;
2003-08-15 23:57:13 +00:00
ast_softhangup_nolock ( ast , AST_SOFTHANGUP_DEV ) ;
2003-02-07 04:07:10 +00:00
break ;
2002-06-28 20:34:46 +00:00
}
2003-02-07 04:07:10 +00:00
return - 1 ;
2002-06-28 20:34:46 +00:00
case AST_CONTROL_CONGESTION :
2002-09-12 17:13:17 +00:00
if ( ast - > _state ! = AST_STATE_UP ) {
2003-04-24 18:21:46 +00:00
transmit_response ( p , " 503 Service Unavailable " , & p - > initreq ) ;
2003-02-07 04:07:10 +00:00
p - > alreadygone = 1 ;
2003-08-15 23:57:13 +00:00
ast_softhangup_nolock ( ast , AST_SOFTHANGUP_DEV ) ;
2003-02-07 04:07:10 +00:00
break ;
2002-06-28 20:34:46 +00:00
}
2003-02-07 04:07:10 +00:00
return - 1 ;
2003-05-15 22:39:01 +00:00
case AST_CONTROL_PROGRESS :
2004-06-14 21:18:52 +00:00
case AST_CONTROL_PROCEEDING :
2003-05-15 22:39:01 +00:00
if ( ( ast - > _state ! = AST_STATE_UP ) & & ! p - > progress & & ! p - > outgoing ) {
transmit_response_with_sdp ( p , " 183 Session Progress " , & p - > initreq , 0 ) ;
p - > progress = 1 ;
break ;
}
return - 1 ;
2003-02-07 04:07:10 +00:00
case - 1 :
return - 1 ;
2002-06-28 20:34:46 +00:00
default :
2003-02-07 04:07:10 +00:00
ast_log ( LOG_WARNING , " Don't know how to indicate condition %d \n " , condition ) ;
return - 1 ;
2002-06-28 20:34:46 +00:00
}
return 0 ;
}
2003-02-07 04:07:10 +00:00
2004-05-13 19:54:42 +00:00
/*--- sip_new: Initiate a call in the SIP channel */
/* called from sip_request_call (calls from the pbx ) */
2003-02-13 06:00:14 +00:00
static struct ast_channel * sip_new ( struct sip_pvt * i , int state , char * title )
2002-06-28 20:34:46 +00:00
{
struct ast_channel * tmp ;
int fmt ;
2004-10-14 18:29:47 +00:00
2004-06-09 23:07:55 +00:00
ast_mutex_unlock ( & i - > lock ) ;
/* Don't hold a sip pvt lock while we allocate a channel */
2002-06-28 20:34:46 +00:00
tmp = ast_channel_alloc ( 1 ) ;
2004-06-09 23:07:55 +00:00
ast_mutex_lock ( & i - > lock ) ;
2002-06-28 20:34:46 +00:00
if ( tmp ) {
2003-02-18 18:15:30 +00:00
/* Select our native format based on codec preference until we receive
something from another device to the contrary . */
2003-09-25 13:18:03 +00:00
if ( i - > jointcapability )
tmp - > nativeformats = sip_codec_choose ( i - > jointcapability ) ;
else if ( i - > capability )
2003-02-18 18:15:30 +00:00
tmp - > nativeformats = sip_codec_choose ( i - > capability ) ;
2003-09-25 13:18:03 +00:00
else
2004-07-08 11:05:03 +00:00
tmp - > nativeformats = sip_codec_choose ( global_capability ) ;
2002-06-28 20:34:46 +00:00
fmt = ast_best_codec ( tmp - > nativeformats ) ;
2003-02-13 06:00:14 +00:00
if ( title )
2003-02-16 06:00:12 +00:00
snprintf ( tmp - > name , sizeof ( tmp - > name ) , " SIP/%s-%04x " , title , rand ( ) & 0xffff ) ;
2003-02-13 06:00:14 +00:00
else
2003-08-22 16:12:06 +00:00
if ( strchr ( i - > fromdomain , ' : ' ) )
2003-06-24 12:51:28 +00:00
{
2004-06-13 21:25:10 +00:00
snprintf ( tmp - > name , sizeof ( tmp - > name ) , " SIP/%s-%08x " , strchr ( i - > fromdomain , ' : ' ) + 1 , ( int ) ( long ) ( i ) ) ;
2003-06-24 12:51:28 +00:00
}
else
{
2004-06-13 21:25:10 +00:00
snprintf ( tmp - > name , sizeof ( tmp - > name ) , " SIP/%s-%08x " , i - > fromdomain , ( int ) ( long ) ( i ) ) ;
2003-06-24 12:51:28 +00:00
}
2002-06-28 20:34:46 +00:00
tmp - > type = type ;
2003-03-08 06:00:17 +00:00
if ( i - > dtmfmode & SIP_DTMF_INBAND ) {
i - > vad = ast_dsp_new ( ) ;
ast_dsp_set_features ( i - > vad , DSP_FEATURE_DTMF_DETECT ) ;
2004-04-29 22:27:40 +00:00
if ( relaxdtmf )
ast_dsp_digitmode ( i - > vad , DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF ) ;
2003-03-08 06:00:17 +00:00
}
2003-02-12 13:59:15 +00:00
tmp - > fds [ 0 ] = ast_rtp_fd ( i - > rtp ) ;
2003-06-28 16:40:02 +00:00
tmp - > fds [ 1 ] = ast_rtcp_fd ( i - > rtp ) ;
if ( i - > vrtp ) {
tmp - > fds [ 2 ] = ast_rtp_fd ( i - > vrtp ) ;
tmp - > fds [ 3 ] = ast_rtcp_fd ( i - > vrtp ) ;
}
2002-06-28 20:34:46 +00:00
if ( state = = AST_STATE_RING )
tmp - > rings = 1 ;
2003-03-06 06:00:17 +00:00
tmp - > adsicpe = AST_ADSI_UNAVAILABLE ;
2002-06-28 20:34:46 +00:00
tmp - > writeformat = fmt ;
tmp - > pvt - > rawwriteformat = fmt ;
tmp - > readformat = fmt ;
tmp - > pvt - > rawreadformat = fmt ;
tmp - > pvt - > pvt = i ;
2003-02-07 04:07:10 +00:00
tmp - > pvt - > send_text = sip_sendtext ;
2002-06-28 20:34:46 +00:00
tmp - > pvt - > call = sip_call ;
tmp - > pvt - > hangup = sip_hangup ;
tmp - > pvt - > answer = sip_answer ;
tmp - > pvt - > read = sip_read ;
tmp - > pvt - > write = sip_write ;
2003-06-28 16:40:02 +00:00
tmp - > pvt - > write_video = sip_write ;
2002-06-28 20:34:46 +00:00
tmp - > pvt - > indicate = sip_indicate ;
2003-05-14 05:52:59 +00:00
tmp - > pvt - > transfer = sip_transfer ;
2002-06-28 20:34:46 +00:00
tmp - > pvt - > fixup = sip_fixup ;
2003-02-07 04:07:10 +00:00
tmp - > pvt - > send_digit = sip_senddigit ;
2003-06-24 12:51:28 +00:00
2003-02-16 06:00:12 +00:00
tmp - > pvt - > bridge = ast_rtp_bridge ;
2003-06-24 12:51:28 +00:00
2003-04-09 04:00:43 +00:00
tmp - > callgroup = i - > callgroup ;
tmp - > pickupgroup = i - > pickupgroup ;
2004-10-02 00:58:31 +00:00
tmp - > cid . cid_pres = i - > callingpres ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( i - > accountcode ) )
2003-04-25 03:56:46 +00:00
strncpy ( tmp - > accountcode , i - > accountcode , sizeof ( tmp - > accountcode ) - 1 ) ;
if ( i - > amaflags )
tmp - > amaflags = i - > amaflags ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( i - > language ) )
2002-06-28 20:34:46 +00:00
strncpy ( tmp - > language , i - > language , sizeof ( tmp - > language ) - 1 ) ;
2004-05-04 20:10:37 +00:00
if ( ! ast_strlen_zero ( i - > musicclass ) )
strncpy ( tmp - > musicclass , i - > musicclass , sizeof ( tmp - > musicclass ) - 1 ) ;
2002-06-28 20:34:46 +00:00
i - > owner = tmp ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & usecnt_lock ) ;
2002-06-28 20:34:46 +00:00
usecnt + + ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & usecnt_lock ) ;
2002-06-28 20:34:46 +00:00
strncpy ( tmp - > context , i - > context , sizeof ( tmp - > context ) - 1 ) ;
strncpy ( tmp - > exten , i - > exten , sizeof ( tmp - > exten ) - 1 ) ;
2004-10-03 14:57:01 +00:00
if ( ! ast_strlen_zero ( i - > cid_num ) )
2004-10-02 00:58:31 +00:00
tmp - > cid . cid_num = strdup ( i - > cid_num ) ;
if ( ! ast_strlen_zero ( i - > cid_name ) )
tmp - > cid . cid_name = strdup ( i - > cid_name ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( i - > rdnis ) )
2004-10-02 00:58:31 +00:00
tmp - > cid . cid_rdnis = strdup ( i - > rdnis ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( i - > exten ) & & strcmp ( i - > exten , " s " ) )
2004-10-02 00:58:31 +00:00
tmp - > cid . cid_dnid = strdup ( i - > exten ) ;
2002-06-28 20:34:46 +00:00
tmp - > priority = 1 ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( i - > domain ) ) {
2003-11-11 20:46:41 +00:00
pbx_builtin_setvar_helper ( tmp , " SIPDOMAIN " , i - > domain ) ;
}
2004-05-09 21:05:43 +00:00
if ( ! ast_strlen_zero ( i - > useragent ) ) {
pbx_builtin_setvar_helper ( tmp , " SIPUSERAGENT " , i - > useragent ) ;
}
if ( ! ast_strlen_zero ( i - > callid ) ) {
pbx_builtin_setvar_helper ( tmp , " SIPCALLID " , i - > callid ) ;
}
2004-04-28 14:35:20 +00:00
ast_setstate ( tmp , state ) ;
2002-06-28 20:34:46 +00:00
if ( state ! = AST_STATE_DOWN ) {
if ( ast_pbx_start ( tmp ) ) {
ast_log ( LOG_WARNING , " Unable to start PBX on %s \n " , tmp - > name ) ;
ast_hangup ( tmp ) ;
tmp = NULL ;
}
}
} else
ast_log ( LOG_WARNING , " Unable to allocate channel structure \n " ) ;
return tmp ;
}
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 " } ,
2004-05-13 19:54:42 +00:00
{ " Supported " , " k " } ,
2004-06-14 21:47:08 +00:00
{ " Refer-To " , " r " } ,
{ " Allow-Events " , " u " } ,
{ " Event " , " o " } ,
2002-06-28 20:34:46 +00:00
{ " Via " , " v " } ,
} ;
2004-05-13 19:54:42 +00:00
/*--- get_sdp_by_line: Reads one line of SIP message body */
2003-03-12 06:00:18 +00:00
static char * get_sdp_by_line ( char * line , char * name , int nameLen ) {
if ( strncasecmp ( line , name , nameLen ) = = 0 & & line [ nameLen ] = = ' = ' ) {
char * r = line + nameLen + 1 ;
while ( * r & & ( * r < 33 ) ) + + r ;
return r ;
}
return " " ;
}
2004-05-13 19:54:42 +00:00
/*--- get_sdp: Gets all kind of SIP message bodies, including SDP,
but the name wrongly applies _only_ sdp */
2003-03-12 06:00:18 +00:00
static char * get_sdp ( struct sip_request * req , char * name ) {
int x ;
int len = strlen ( name ) ;
char * r ;
for ( x = 0 ; x < req - > lines ; x + + ) {
r = get_sdp_by_line ( req - > line [ x ] , name , len ) ;
if ( r [ 0 ] ! = ' \0 ' ) return r ;
}
return " " ;
}
2004-05-13 19:54:42 +00:00
2003-03-12 06:00:18 +00:00
static void sdpLineNum_iterator_init ( int * iterator ) {
* iterator = 0 ;
}
static char * get_sdp_iterate ( int * iterator ,
struct sip_request * req , char * name ) {
int len = strlen ( name ) ;
char * r ;
while ( * iterator < req - > lines ) {
r = get_sdp_by_line ( req - > line [ ( * iterator ) + + ] , name , len ) ;
if ( r [ 0 ] ! = ' \0 ' ) return r ;
}
return " " ;
2002-06-28 20:34:46 +00:00
}
2002-09-12 17:13:17 +00:00
static char * __get_header ( struct sip_request * req , char * name , int * start )
2002-06-28 20:34:46 +00:00
{
int x ;
int len = strlen ( name ) ;
char * r ;
2004-09-10 02:03:05 +00:00
if ( pedanticsipchecking ) {
/* Technically you can place arbitrary whitespace both before and after the ':' in
a header , although RFC3261 clearly says you shouldn ' t before , and place just
one afterwards . If you shouldn ' t do it , what absolute idiot decided it was
a good idea to say you can do it , and if you can do it , why in the hell would
you say you shouldn ' t . */
for ( x = * start ; x < req - > headers ; x + + ) {
if ( ! strncasecmp ( req - > header [ x ] , name , len ) ) {
r = req - > header [ x ] + len ;
while ( * r & & ( * r < 33 ) )
r + + ;
if ( * r = = ' : ' ) {
r + + ;
2002-06-28 20:34:46 +00:00
while ( * r & & ( * r < 33 ) )
2004-09-10 02:03:05 +00:00
r + + ;
2002-09-12 17:13:17 +00:00
* start = x + 1 ;
2002-06-28 20:34:46 +00:00
return r ;
2004-09-10 02:03:05 +00:00
}
}
}
} else {
/* We probably shouldn't even bother counting whitespace afterwards but
I guess for backwards compatibility we will */
for ( x = * start ; x < req - > headers ; x + + ) {
if ( ! strncasecmp ( req - > header [ x ] , name , len ) & &
( req - > header [ x ] [ len ] = = ' : ' ) ) {
r = req - > header [ x ] + len + 1 ;
while ( * r & & ( * r < 33 ) )
r + + ;
* start = x + 1 ;
return r ;
}
2002-06-28 20:34:46 +00:00
}
}
/* Try aliases */
for ( x = 0 ; x < sizeof ( aliases ) / sizeof ( aliases [ 0 ] ) ; x + + )
2002-09-12 17:13:17 +00:00
if ( ! strcasecmp ( aliases [ x ] . fullname , name ) )
return __get_header ( req , aliases [ x ] . shortname , start ) ;
2002-06-28 20:34:46 +00:00
/* Don't return NULL, so get_header is always a valid pointer */
return " " ;
}
2004-05-13 19:54:42 +00:00
/*--- get_header: Get header from SIP request ---*/
2002-09-12 17:13:17 +00:00
static char * get_header ( struct sip_request * req , char * name )
{
int start = 0 ;
return __get_header ( req , name , & start ) ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_rtp_read: Read RTP from network ---*/
2003-06-28 16:40:02 +00:00
static struct ast_frame * sip_rtp_read ( struct ast_channel * ast , struct sip_pvt * p )
2002-06-28 20:34:46 +00:00
{
2003-02-12 13:59:15 +00:00
/* Retrieve audio/etc from channel. Assumes p->lock is already held. */
struct ast_frame * f ;
2003-03-08 06:00:17 +00:00
static struct ast_frame null_frame = { AST_FRAME_NULL , } ;
2003-06-28 16:40:02 +00:00
switch ( ast - > fdno ) {
case 0 :
2004-05-13 19:54:42 +00:00
f = ast_rtp_read ( p - > rtp ) ; /* RTP Audio */
2003-06-28 16:40:02 +00:00
break ;
case 1 :
2004-05-13 19:54:42 +00:00
f = ast_rtcp_read ( p - > rtp ) ; /* RTCP Control Channel */
2003-06-28 16:40:02 +00:00
break ;
case 2 :
2004-05-13 19:54:42 +00:00
f = ast_rtp_read ( p - > vrtp ) ; /* RTP Video */
2003-06-28 16:40:02 +00:00
break ;
case 3 :
2004-05-13 19:54:42 +00:00
f = ast_rtcp_read ( p - > vrtp ) ; /* RTCP Control Channel for video */
2003-06-28 16:40:02 +00:00
break ;
default :
f = & null_frame ;
}
2003-03-08 06:00:17 +00:00
/* Don't send RFC2833 if we're not supposed to */
if ( f & & ( f - > frametype = = AST_FRAME_DTMF ) & & ! ( p - > dtmfmode & SIP_DTMF_RFC2833 ) )
return & null_frame ;
2002-09-12 17:13:17 +00:00
if ( p - > owner ) {
2003-02-12 13:59:15 +00:00
/* We already hold the channel lock */
if ( f - > frametype = = AST_FRAME_VOICE ) {
if ( f - > subclass ! = p - > owner - > nativeformats ) {
ast_log ( LOG_DEBUG , " Oooh, format changed to %d \n " , f - > subclass ) ;
p - > owner - > nativeformats = f - > subclass ;
2004-04-06 22:17:32 +00:00
ast_set_read_format ( p - > owner , p - > owner - > readformat ) ;
ast_set_write_format ( p - > owner , p - > owner - > writeformat ) ;
2002-09-12 17:13:17 +00:00
}
2004-04-02 14:40:21 +00:00
if ( ( p - > dtmfmode & SIP_DTMF_INBAND ) & & p - > vad ) {
2004-04-06 22:17:32 +00:00
f = ast_dsp_process ( p - > owner , p - > vad , f ) ;
2004-04-29 22:27:40 +00:00
if ( f & & ( f - > frametype = = AST_FRAME_DTMF ) )
ast_log ( LOG_DEBUG , " Detected DTMF '%c' \n " , f - > subclass ) ;
2003-03-08 06:00:17 +00:00
}
2002-09-12 17:13:17 +00:00
}
}
2003-02-12 13:59:15 +00:00
return f ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_read: Read SIP RTP from channel */
2003-02-12 13:59:15 +00:00
static struct ast_frame * sip_read ( struct ast_channel * ast )
{
struct ast_frame * fr ;
struct sip_pvt * p = ast - > pvt - > pvt ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-06-28 16:40:02 +00:00
fr = sip_rtp_read ( ast , p ) ;
2004-05-27 22:12:55 +00:00
time ( & p - > lastrtprx ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2003-02-12 13:59:15 +00:00
return fr ;
2002-06-28 20:34:46 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- build_callid: Build SIP CALLID header ---*/
2004-09-13 12:32:04 +00:00
static void build_callid ( char * callid , int len , struct in_addr ourip , char * fromdomain )
2002-06-28 20:34:46 +00:00
{
int res ;
int val ;
int x ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2002-06-28 20:34:46 +00:00
for ( x = 0 ; x < 4 ; x + + ) {
val = rand ( ) ;
res = snprintf ( callid , len , " %08x " , val ) ;
len - = res ;
callid + = res ;
}
2004-09-13 12:32:04 +00:00
if ( ! ast_strlen_zero ( fromdomain ) )
snprintf ( callid , len , " @%s " , fromdomain ) ;
else
2002-09-12 17:13:17 +00:00
/* It's not important that we really use our right IP here... */
2004-09-13 12:32:04 +00:00
snprintf ( callid , len , " @%s " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , ourip ) ) ;
2002-06-28 20:34:46 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- sip_alloc: Allocate SIP_PVT structure and set defaults ---*/
2004-07-08 11:05:03 +00:00
static struct sip_pvt * sip_alloc ( char * callid , struct sockaddr_in * sin , int useglobal_nat )
2002-06-28 20:34:46 +00:00
{
struct sip_pvt * p ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2002-09-12 17:13:17 +00:00
2002-06-28 20:34:46 +00:00
p = malloc ( sizeof ( struct sip_pvt ) ) ;
if ( ! p )
return NULL ;
/* Keep track of stuff */
memset ( p , 0 , sizeof ( struct sip_pvt ) ) ;
2004-06-22 17:42:14 +00:00
ast_mutex_init ( & p - > lock ) ;
2003-02-07 04:07:10 +00:00
p - > initid = - 1 ;
2003-03-28 06:13:04 +00:00
p - > autokillid = - 1 ;
2003-04-06 18:19:51 +00:00
p - > stateid = - 1 ;
2004-06-25 03:59:07 +00:00
# ifdef OSP_SUPPORT
p - > osphandle = - 1 ;
# endif
2004-07-08 11:46:15 +00:00
if ( sin ) {
memcpy ( & p - > sa , sin , sizeof ( p - > sa ) ) ;
if ( ast_sip_ouraddrfor ( & p - > sa . sin_addr , & p - > ourip ) )
memcpy ( & p - > ourip , & __ourip , sizeof ( p - > ourip ) ) ;
} else {
memcpy ( & p - > ourip , & __ourip , sizeof ( p - > ourip ) ) ;
}
2004-07-08 14:06:22 +00:00
p - > rtp = ast_rtp_new_with_bindaddr ( sched , io , 1 , 0 , bindaddr . sin_addr ) ;
2003-06-28 16:40:02 +00:00
if ( videosupport )
2004-07-08 14:06:22 +00:00
p - > vrtp = ast_rtp_new_with_bindaddr ( sched , io , 1 , 0 , bindaddr . sin_addr ) ;
2003-02-07 04:07:10 +00:00
p - > branch = rand ( ) ;
p - > tag = rand ( ) ;
2003-04-06 18:19:51 +00:00
2003-02-07 04:07:10 +00:00
/* Start with 101 instead of 1 */
p - > ocseq = 101 ;
2002-06-28 20:34:46 +00:00
if ( ! p - > rtp ) {
ast_log ( LOG_WARNING , " Unable to create RTP session: %s \n " , strerror ( errno ) ) ;
2004-06-09 01:45:08 +00:00
ast_mutex_destroy ( & p - > lock ) ;
2002-06-28 20:34:46 +00:00
free ( p ) ;
return NULL ;
}
2003-02-07 04:07:10 +00:00
ast_rtp_settos ( p - > rtp , tos ) ;
2003-06-28 16:40:02 +00:00
if ( p - > vrtp )
ast_rtp_settos ( p - > vrtp , tos ) ;
2004-07-08 11:05:03 +00:00
if ( useglobal_nat & & sin ) {
2003-03-10 22:05:28 +00:00
/* Setup NAT structure according to global settings if we have an address */
2004-07-08 11:05:03 +00:00
p - > nat = global_nat ;
2003-03-10 22:05:28 +00:00
memcpy ( & p - > recv , sin , sizeof ( p - > recv ) ) ;
2004-08-27 02:45:35 +00:00
ast_rtp_setnat ( p - > rtp , ( p - > nat & SIP_NAT_ROUTE ) ) ;
2003-06-28 16:40:02 +00:00
if ( p - > vrtp )
2004-08-27 02:45:35 +00:00
ast_rtp_setnat ( p - > vrtp , ( p - > nat & SIP_NAT_ROUTE ) ) ;
2003-03-10 22:05:28 +00:00
}
2003-06-28 16:40:02 +00:00
2004-09-13 12:32:04 +00:00
strncpy ( p - > fromdomain , default_fromdomain , sizeof ( p - > fromdomain ) - 1 ) ;
2003-05-04 05:52:52 +00:00
/* z9hG4bK is a magic cookie. See RFC 3261 section 8.1.1.7 */
2004-06-28 23:24:36 +00:00
if ( p - > nat ! = SIP_NAT_NEVER )
2004-06-29 12:56:46 +00:00
snprintf ( p - > via , sizeof ( p - > via ) , " SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) , ourport , p - > branch ) ;
2004-06-28 23:24:36 +00:00
else
2004-06-29 12:56:46 +00:00
snprintf ( p - > via , sizeof ( p - > via ) , " SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) , ourport , p - > branch ) ;
2002-09-12 17:13:17 +00:00
if ( ! callid )
2004-09-13 12:32:04 +00:00
build_callid ( p - > callid , sizeof ( p - > callid ) , p - > ourip , p - > fromdomain ) ;
2002-09-12 17:13:17 +00:00
else
strncpy ( p - > callid , callid , sizeof ( p - > callid ) - 1 ) ;
2003-03-28 06:59:34 +00:00
/* Assume reinvite OK and via INVITE */
2004-07-08 11:05:03 +00:00
p - > canreinvite = global_canreinvite ;
2004-05-04 20:10:37 +00:00
/* Assign default music on hold class */
2004-07-16 04:40:54 +00:00
strncpy ( p - > musicclass , global_musicclass , sizeof ( p - > musicclass ) - 1 ) ;
2004-07-08 11:05:03 +00:00
p - > dtmfmode = global_dtmfmode ;
p - > promiscredir = global_promiscredir ;
p - > trustrpid = global_trustrpid ;
p - > progressinband = global_progressinband ;
2004-06-25 05:52:55 +00:00
# ifdef OSP_SUPPORT
2004-07-08 11:05:03 +00:00
p - > ospauth = global_ospauth ;
2004-06-25 05:52:55 +00:00
# endif
2004-07-08 11:05:03 +00:00
p - > rtptimeout = global_rtptimeout ;
p - > rtpholdtimeout = global_rtpholdtimeout ;
p - > capability = global_capability ;
2003-03-18 18:11:43 +00:00
if ( p - > dtmfmode & SIP_DTMF_RFC2833 )
2003-03-27 20:13:47 +00:00
p - > noncodeccapability | = AST_RTP_DTMF ;
2004-07-08 11:05:03 +00:00
strncpy ( p - > context , default_context , sizeof ( p - > context ) - 1 ) ;
2002-06-28 20:34:46 +00:00
/* Add to list */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & iflock ) ;
2002-06-28 20:34:46 +00:00
p - > next = iflist ;
iflist = p ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
2003-02-07 04:07:10 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Allocating new SIP call for %s \n " , callid ) ;
2002-06-28 20:34:46 +00:00
return p ;
}
2004-05-13 19:54:42 +00:00
/*--- find_call: Connect incoming SIP message to current call or create new call structure */
/* Called by handle_request ,sipsock_read */
2002-06-28 20:34:46 +00:00
static struct sip_pvt * find_call ( struct sip_request * req , struct sockaddr_in * sin )
{
struct sip_pvt * p ;
char * callid ;
2003-08-12 16:48:16 +00:00
char tmp [ 256 ] = " " ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-08-12 16:48:16 +00:00
char * cmd ;
char * tag = " " , * c ;
2004-09-15 00:43:13 +00:00
2002-06-28 20:34:46 +00:00
callid = get_header ( req , " Call-ID " ) ;
2003-08-12 16:48:16 +00:00
if ( pedanticsipchecking ) {
/* In principle Call-ID's uniquely identify a call, however some vendors
( i . e . Pingtel ) send multiple calls with the same Call - ID and different
tags in order to simplify billing . The RFC does state that we have to
compare tags in addition to the call - id , but this generate substantially
more overhead which is totally unnecessary for the vast majority of sane
SIP implementations , and thus Asterisk does not enable this behavior
by default . Short version : You ' ll need this option to support conferencing
on the pingtel */
strncpy ( tmp , req - > header [ 0 ] , sizeof ( tmp ) - 1 ) ;
cmd = tmp ;
c = strchr ( tmp , ' ' ) ;
if ( c )
* c = ' \0 ' ;
2004-09-15 19:27:23 +00:00
if ( ! strcasecmp ( cmd , " SIP/2.0 " ) )
strncpy ( tmp , get_header ( req , " To " ) , sizeof ( tmp ) - 1 ) ;
else
strncpy ( tmp , get_header ( req , " From " ) , sizeof ( tmp ) - 1 ) ;
2003-08-12 16:48:16 +00:00
tag = strstr ( tmp , " tag= " ) ;
if ( tag ) {
tag + = 4 ;
c = strchr ( tag , ' ; ' ) ;
if ( c )
* c = ' \0 ' ;
}
}
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( callid ) ) {
2004-06-29 12:56:46 +00:00
ast_log ( LOG_WARNING , " Call missing call ID from '%s' \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , sin - > sin_addr ) ) ;
2002-06-28 20:34:46 +00:00
return NULL ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & iflock ) ;
2002-06-28 20:34:46 +00:00
p = iflist ;
while ( p ) {
2003-08-12 16:48:16 +00:00
if ( ! strcmp ( p - > callid , callid ) & &
2004-09-15 19:27:23 +00:00
( ! pedanticsipchecking | | ! tag | | ast_strlen_zero ( p - > theirtag ) | | ! strcmp ( p - > theirtag , tag ) ) ) {
2002-06-28 20:34:46 +00:00
/* Found the call */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
ast_mutex_unlock ( & iflock ) ;
2002-06-28 20:34:46 +00:00
return p ;
}
p = p - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
2003-05-17 14:47:17 +00:00
p = sip_alloc ( callid , sin , 1 ) ;
if ( p )
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-05-17 14:47:17 +00:00
return p ;
2002-06-28 20:34:46 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- sip_register: Parse register=> line in sip.conf and add to registry */
2003-02-07 04:07:10 +00:00
static int sip_register ( char * value , int lineno )
{
struct sip_registry * reg ;
char copy [ 256 ] = " " ;
2003-04-12 17:06:14 +00:00
char * username = NULL , * hostname = NULL , * secret = NULL , * authuser = NULL ;
char * porta = NULL ;
char * contact = NULL ;
2003-02-07 04:07:10 +00:00
char * stringp = NULL ;
if ( ! value )
return - 1 ;
strncpy ( copy , value , sizeof ( copy ) - 1 ) ;
stringp = copy ;
2003-02-24 06:00:18 +00:00
username = stringp ;
hostname = strrchr ( stringp , ' @ ' ) ;
if ( hostname ) {
* hostname = ' \0 ' ;
hostname + + ;
}
2004-05-08 20:58:24 +00:00
if ( ! username | | ast_strlen_zero ( username ) | | ! hostname | | ast_strlen_zero ( hostname ) ) {
2003-09-13 20:20:14 +00:00
ast_log ( LOG_WARNING , " Format for registration is user[:secret[:authuser]]@host[:port][/contact] at line %d " , lineno ) ;
2003-02-07 04:07:10 +00:00
return - 1 ;
}
stringp = username ;
username = strsep ( & stringp , " : " ) ;
2003-04-12 17:06:14 +00:00
if ( username ) {
secret = strsep ( & stringp , " : " ) ;
if ( secret )
authuser = strsep ( & stringp , " : " ) ;
}
2003-02-17 06:00:19 +00:00
stringp = hostname ;
hostname = strsep ( & stringp , " / " ) ;
2003-04-12 17:06:14 +00:00
if ( hostname )
contact = strsep ( & stringp , " / " ) ;
2004-05-03 21:01:14 +00:00
if ( ! contact | | ast_strlen_zero ( contact ) )
2003-02-17 06:00:19 +00:00
contact = " s " ;
2003-02-07 04:07:10 +00:00
stringp = hostname ;
hostname = strsep ( & stringp , " : " ) ;
2003-02-17 06:00:19 +00:00
porta = strsep ( & stringp , " : " ) ;
2003-02-07 04:07:10 +00:00
if ( porta & & ! atoi ( porta ) ) {
ast_log ( LOG_WARNING , " %s is not a valid port number at line %d \n " , porta , lineno ) ;
return - 1 ;
}
reg = malloc ( sizeof ( struct sip_registry ) ) ;
if ( reg ) {
memset ( reg , 0 , sizeof ( struct sip_registry ) ) ;
2003-02-17 06:00:19 +00:00
strncpy ( reg - > contact , contact , sizeof ( reg - > contact ) - 1 ) ;
2003-04-12 17:06:14 +00:00
if ( username )
strncpy ( reg - > username , username , sizeof ( reg - > username ) - 1 ) ;
if ( hostname )
strncpy ( reg - > hostname , hostname , sizeof ( reg - > hostname ) - 1 ) ;
if ( authuser )
strncpy ( reg - > authuser , authuser , sizeof ( reg - > authuser ) - 1 ) ;
2003-02-07 04:07:10 +00:00
if ( secret )
strncpy ( reg - > secret , secret , sizeof ( reg - > secret ) - 1 ) ;
reg - > expire = - 1 ;
2003-04-09 19:35:24 +00:00
reg - > timeout = - 1 ;
2003-04-08 03:24:12 +00:00
reg - > refresh = default_expiry ;
2004-07-15 22:14:27 +00:00
reg - > portno = porta ? atoi ( porta ) : 0 ;
2003-02-07 04:07:10 +00:00
reg - > callid_valid = 0 ;
2003-04-21 16:49:41 +00:00
reg - > ocseq = 101 ;
2004-02-02 22:35:33 +00:00
ast_mutex_lock ( & regl . lock ) ;
reg - > next = regl . registrations ;
regl . registrations = reg ;
ast_mutex_unlock ( & regl . lock ) ;
2003-02-07 04:07:10 +00:00
} else {
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
return - 1 ;
}
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- lws2sws: Parse multiline SIP headers into one header */
/* This is enabled if pedanticsipchecking is enabled */
2004-04-27 22:32:57 +00:00
static int lws2sws ( char * msgbuf , int len )
{
int h = 0 , t = 0 ;
int lws = 0 ;
for ( ; h < len ; ) {
/* Eliminate all CRs */
if ( msgbuf [ h ] = = ' \r ' ) {
h + + ;
continue ;
}
/* Check for end-of-line */
if ( msgbuf [ h ] = = ' \n ' ) {
/* Check for end-of-message */
if ( h + 1 = = len )
break ;
/* Check for a continuation line */
if ( msgbuf [ h + 1 ] = = ' ' ) {
/* Merge continuation line */
h + + ;
continue ;
}
/* Propagate LF and start new line */
msgbuf [ t + + ] = msgbuf [ h + + ] ;
lws = 0 ;
continue ;
}
if ( msgbuf [ h ] = = ' ' | | msgbuf [ h ] = = ' \t ' ) {
if ( lws ) {
h + + ;
continue ;
}
msgbuf [ t + + ] = msgbuf [ h + + ] ;
lws = 1 ;
continue ;
}
msgbuf [ t + + ] = msgbuf [ h + + ] ;
if ( lws )
lws = 0 ;
}
msgbuf [ t ] = ' \0 ' ;
return t ;
}
2004-05-13 19:54:42 +00:00
/*--- parse: Parse a SIP message ----*/
2002-06-28 20:34:46 +00:00
static void parse ( struct sip_request * req )
{
/* Divide fields by NULL's */
2004-04-26 03:41:07 +00:00
char * c ;
2002-06-28 20:34:46 +00:00
int f = 0 ;
c = req - > data ;
/* First header starts immediately */
req - > header [ f ] = c ;
while ( * c ) {
if ( * c = = ' \n ' ) {
/* We've got a new header */
* c = 0 ;
#if 0
printf ( " Header: %s (%d) \n " , req - > header [ f ] , strlen ( req - > header [ f ] ) ) ;
# endif
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( req - > header [ f ] ) ) {
2002-06-28 20:34:46 +00:00
/* Line by itself means we're now in content */
c + + ;
break ;
}
if ( f > = SIP_MAX_HEADERS - 1 ) {
ast_log ( LOG_WARNING , " Too many SIP headers... \n " ) ;
2004-04-27 22:32:57 +00:00
} else
f + + ;
req - > header [ f ] = c + 1 ;
2002-06-28 20:34:46 +00:00
} else if ( * c = = ' \r ' ) {
/* Ignore but eliminate \r's */
* c = 0 ;
2004-04-27 22:32:57 +00:00
}
2002-06-28 20:34:46 +00:00
c + + ;
}
/* Check for last header */
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( req - > header [ f ] ) )
2002-06-28 20:34:46 +00:00
f + + ;
req - > headers = f ;
/* Now we process any mime content */
f = 0 ;
req - > line [ f ] = c ;
while ( * c ) {
if ( * c = = ' \n ' ) {
/* We've got a new line */
* c = 0 ;
#if 0
printf ( " Line: %s (%d) \n " , req - > line [ f ] , strlen ( req - > line [ f ] ) ) ;
# endif
if ( f > = SIP_MAX_LINES - 1 ) {
ast_log ( LOG_WARNING , " Too many SDP lines... \n " ) ;
} else
f + + ;
req - > line [ f ] = c + 1 ;
} else if ( * c = = ' \r ' ) {
/* Ignore and eliminate \r's */
* c = 0 ;
}
c + + ;
}
/* Check for last line */
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( req - > line [ f ] ) )
2002-06-28 20:34:46 +00:00
f + + ;
req - > lines = f ;
if ( * c )
ast_log ( LOG_WARNING , " Odd content, extra stuff left over ('%s') \n " , c ) ;
}
2004-05-13 19:54:42 +00:00
/*--- process_sdp: Process SIP SDP ---*/
2002-06-28 20:34:46 +00:00
static int process_sdp ( struct sip_pvt * p , struct sip_request * req )
{
char * m ;
char * c ;
2003-03-12 06:00:18 +00:00
char * a ;
2002-06-28 20:34:46 +00:00
char host [ 258 ] ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-02-07 04:07:10 +00:00
int len = - 1 ;
2003-06-28 16:40:02 +00:00
int portno = 0 ;
int vportno = 0 ;
2003-03-27 20:13:47 +00:00
int peercapability , peernoncodeccapability ;
2003-06-28 18:35:58 +00:00
int vpeercapability = 0 , vpeernoncodeccapability = 0 ;
2002-06-28 20:34:46 +00:00
struct sockaddr_in sin ;
char * codecs ;
struct hostent * hp ;
2004-04-22 00:20:34 +00:00
struct ast_hostent ahp ;
2002-06-28 20:34:46 +00:00
int codec ;
2003-03-12 06:00:18 +00:00
int iterator ;
2003-12-13 22:54:37 +00:00
int sendonly = 0 ;
2003-06-28 16:40:02 +00:00
int x ;
2004-06-18 13:53:48 +00:00
int debug = sip_debug_test_pvt ( p ) ;
2003-03-12 06:00:18 +00:00
2004-05-27 22:12:55 +00:00
/* Update our last rtprx when we receive an SDP, too */
time ( & p - > lastrtprx ) ;
2002-06-28 20:34:46 +00:00
/* Get codec and RTP info from SDP */
if ( strcasecmp ( get_header ( req , " Content-Type " ) , " application/sdp " ) ) {
ast_log ( LOG_NOTICE , " Content is '%s', not 'application/sdp' \n " , get_header ( req , " Content-Type " ) ) ;
return - 1 ;
}
m = get_sdp ( req , " m " ) ;
c = get_sdp ( req , " c " ) ;
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( m ) | | ast_strlen_zero ( c ) ) {
2002-06-28 20:34:46 +00:00
ast_log ( LOG_WARNING , " Insufficient information for SDP (m = '%s', c = '%s') \n " , m , c ) ;
return - 1 ;
}
if ( sscanf ( c , " IN IP4 %256s " , host ) ! = 1 ) {
ast_log ( LOG_WARNING , " Invalid host in c= line, '%s' \n " , c ) ;
return - 1 ;
}
/* XXX This could block for a long time, and block the main thread! XXX */
2004-04-22 00:20:34 +00:00
hp = ast_gethostbyname ( host , & ahp ) ;
2002-06-28 20:34:46 +00:00
if ( ! hp ) {
ast_log ( LOG_WARNING , " Unable to lookup host in c= line, '%s' \n " , c ) ;
return - 1 ;
}
2003-06-28 16:40:02 +00:00
sdpLineNum_iterator_init ( & iterator ) ;
2004-08-18 02:16:04 +00:00
p - > novideo = 1 ;
2003-06-28 16:40:02 +00:00
while ( ( m = get_sdp_iterate ( & iterator , req , " m " ) ) [ 0 ] ! = ' \0 ' ) {
if ( ( sscanf ( m , " audio %d RTP/AVP %n " , & x , & len ) = = 1 ) ) {
portno = x ;
2004-04-26 14:54:33 +00:00
/* Scan through the RTP payload types specified in a "m=" line: */
2003-06-28 16:40:02 +00:00
ast_rtp_pt_clear ( p - > rtp ) ;
codecs = m + len ;
2004-05-03 21:01:14 +00:00
while ( ! ast_strlen_zero ( codecs ) ) {
2003-06-28 16:40:02 +00:00
if ( sscanf ( codecs , " %d%n " , & codec , & len ) ! = 1 ) {
ast_log ( LOG_WARNING , " Error in codec string '%s' \n " , codecs ) ;
return - 1 ;
}
2004-06-18 13:53:48 +00:00
if ( debug )
2004-05-01 20:59:37 +00:00
ast_verbose ( " Found RTP audio format %d \n " , codec ) ;
2003-06-28 16:40:02 +00:00
ast_rtp_set_m_type ( p - > rtp , codec ) ;
codecs + = len ;
/* Skip over any whitespace */
while ( * codecs & & ( * codecs < 33 ) ) codecs + + ;
}
}
2004-04-04 21:54:38 +00:00
if ( p - > vrtp )
2004-04-26 14:54:33 +00:00
ast_rtp_pt_clear ( p - > vrtp ) ; /* Must be cleared in case no m=video line exists */
2004-04-04 21:54:38 +00:00
2003-06-28 16:40:02 +00:00
if ( p - > vrtp & & ( sscanf ( m , " video %d RTP/AVP %n " , & x , & len ) = = 1 ) ) {
2004-08-18 02:16:04 +00:00
p - > novideo = 0 ;
2003-06-28 16:40:02 +00:00
vportno = x ;
2004-04-26 14:54:33 +00:00
/* Scan through the RTP payload types specified in a "m=" line: */
2003-06-28 16:40:02 +00:00
codecs = m + len ;
2004-05-03 21:01:14 +00:00
while ( ! ast_strlen_zero ( codecs ) ) {
2003-06-28 16:40:02 +00:00
if ( sscanf ( codecs , " %d%n " , & codec , & len ) ! = 1 ) {
ast_log ( LOG_WARNING , " Error in codec string '%s' \n " , codecs ) ;
return - 1 ;
}
2004-06-18 13:53:48 +00:00
if ( debug )
2003-08-16 05:10:35 +00:00
ast_verbose ( " Found video format %s \n " , ast_getformatname ( codec ) ) ;
2003-06-28 16:40:02 +00:00
ast_rtp_set_m_type ( p - > vrtp , codec ) ;
codecs + = len ;
/* Skip over any whitespace */
while ( * codecs & & ( * codecs < 33 ) ) codecs + + ;
}
}
2002-06-28 20:34:46 +00:00
}
2004-05-19 03:39:44 +00:00
/* RTP addresses and ports for audio and video */
2002-06-28 20:34:46 +00:00
sin . sin_family = AF_INET ;
memcpy ( & sin . sin_addr , hp - > h_addr , sizeof ( sin . sin_addr ) ) ;
2004-07-31 02:31:24 +00:00
2003-06-28 16:40:02 +00:00
/* Setup audio port number */
2002-06-28 20:34:46 +00:00
sin . sin_port = htons ( portno ) ;
2004-07-31 02:31:24 +00:00
if ( p - > rtp & & sin . sin_port ) {
2003-02-07 04:07:10 +00:00
ast_rtp_set_peer ( p - > rtp , & sin ) ;
2004-07-31 02:31:24 +00:00
if ( debug ) {
ast_verbose ( " Peer audio RTP is at port %s:%d \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , sin . sin_addr ) , ntohs ( sin . sin_port ) ) ;
ast_log ( LOG_DEBUG , " Peer audio RTP is at port %s:%d \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , sin . sin_addr ) , ntohs ( sin . sin_port ) ) ;
}
}
2003-06-28 16:40:02 +00:00
/* Setup video port number */
sin . sin_port = htons ( vportno ) ;
2004-07-31 02:31:24 +00:00
if ( p - > vrtp & & sin . sin_port ) {
2003-06-28 16:40:02 +00:00
ast_rtp_set_peer ( p - > vrtp , & sin ) ;
2004-07-31 02:31:24 +00:00
if ( debug ) {
ast_verbose ( " Peer video RTP is at port %s:%d \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , sin . sin_addr ) , ntohs ( sin . sin_port ) ) ;
ast_log ( LOG_DEBUG , " Peer video RTP is at port %s:%d \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , sin . sin_addr ) , ntohs ( sin . sin_port ) ) ;
}
}
2004-05-19 03:39:44 +00:00
2004-04-26 14:54:33 +00:00
/* Next, scan through each "a=rtpmap:" line, noting each
* specified RTP payload type ( with corresponding MIME subtype ) :
*/
2003-03-12 06:00:18 +00:00
sdpLineNum_iterator_init ( & iterator ) ;
while ( ( a = get_sdp_iterate ( & iterator , req , " a " ) ) [ 0 ] ! = ' \0 ' ) {
2004-04-26 14:54:33 +00:00
char * mimeSubtype = ast_strdupa ( a ) ; /* ensures we have enough space */
2003-12-13 22:54:37 +00:00
if ( ! strcasecmp ( a , " sendonly " ) ) {
sendonly = 1 ;
continue ;
}
if ( ! strcasecmp ( a , " sendrecv " ) ) {
sendonly = 0 ;
}
2003-03-12 06:00:18 +00:00
if ( sscanf ( a , " rtpmap: %u %[^/]/ " , & codec , mimeSubtype ) ! = 2 ) continue ;
2004-06-18 13:53:48 +00:00
if ( debug )
2003-06-28 16:40:02 +00:00
ast_verbose ( " Found description format %s \n " , mimeSubtype ) ;
2004-04-26 14:54:33 +00:00
/* Note: should really look at the 'freq' and '#chans' params too */
2003-03-13 06:00:20 +00:00
ast_rtp_set_rtpmap_type ( p - > rtp , codec , " audio " , mimeSubtype ) ;
2003-06-28 16:40:02 +00:00
if ( p - > vrtp )
ast_rtp_set_rtpmap_type ( p - > vrtp , codec , " video " , mimeSubtype ) ;
2003-03-12 06:00:18 +00:00
}
2004-04-26 14:54:33 +00:00
/* Now gather all of the codecs that were asked for: */
2003-03-13 06:00:20 +00:00
ast_rtp_get_current_formats ( p - > rtp ,
2003-03-27 20:13:47 +00:00
& peercapability , & peernoncodeccapability ) ;
2003-06-28 18:35:58 +00:00
if ( p - > vrtp )
ast_rtp_get_current_formats ( p - > vrtp ,
2003-06-28 16:40:02 +00:00
& vpeercapability , & vpeernoncodeccapability ) ;
2003-09-25 13:18:03 +00:00
p - > jointcapability = p - > capability & ( peercapability | vpeercapability ) ;
2004-08-18 13:55:03 +00:00
p - > peercapability = ( peercapability | vpeercapability ) ;
2004-09-09 02:07:26 +00:00
p - > noncodeccapability = noncodeccapability & peernoncodeccapability ;
2003-06-28 16:40:02 +00:00
2004-06-18 13:53:48 +00:00
if ( debug ) {
2004-05-19 03:39:44 +00:00
const unsigned slen = 80 ;
char s1 [ slen ] , s2 [ slen ] , s3 [ slen ] , s4 [ slen ] ;
ast_verbose ( " Capabilities: us - %s, peer - audio=%s/video=%s, combined - %s \n " ,
ast_getformatname_multiple ( s1 , slen , p - > capability ) ,
ast_getformatname_multiple ( s2 , slen , peercapability ) ,
ast_getformatname_multiple ( s3 , slen , vpeercapability ) ,
ast_getformatname_multiple ( s4 , slen , p - > jointcapability ) ) ;
ast_verbose ( " Non-codec capabilities: us - %s, peer - %s, combined - %s \n " ,
ast_getformatname_multiple ( s1 , slen , noncodeccapability ) ,
ast_getformatname_multiple ( s2 , slen , peernoncodeccapability ) ,
ast_getformatname_multiple ( s3 , slen , p - > noncodeccapability ) ) ;
2003-03-12 06:00:18 +00:00
}
2003-09-25 13:18:03 +00:00
if ( ! p - > jointcapability ) {
2002-06-28 20:34:46 +00:00
ast_log ( LOG_WARNING , " No compatible codecs! \n " ) ;
return - 1 ;
}
2003-02-16 06:00:12 +00:00
if ( p - > owner ) {
2003-09-25 13:18:03 +00:00
if ( ! ( p - > owner - > nativeformats & p - > jointcapability ) ) {
2004-05-19 03:39:44 +00:00
const unsigned slen = 80 ;
char s1 [ slen ] , s2 [ slen ] ;
ast_log ( LOG_DEBUG , " Oooh, we need to change our formats since our peer supports only %s and not %s \n " ,
ast_getformatname_multiple ( s1 , slen , p - > jointcapability ) ,
ast_getformatname_multiple ( s2 , slen , p - > owner - > nativeformats ) ) ;
2003-09-25 13:18:03 +00:00
p - > owner - > nativeformats = sip_codec_choose ( p - > jointcapability ) ;
2004-04-06 22:17:32 +00:00
ast_set_read_format ( p - > owner , p - > owner - > readformat ) ;
ast_set_write_format ( p - > owner , p - > owner - > writeformat ) ;
2003-02-16 06:00:12 +00:00
}
2004-10-23 12:19:47 +00:00
if ( ast_bridged_channel ( p - > owner ) ) {
2003-02-16 06:00:12 +00:00
/* Turn on/off music on hold if we are holding/unholding */
2003-12-13 22:54:37 +00:00
if ( sin . sin_addr . s_addr & & ! sendonly ) {
2004-10-23 12:19:47 +00:00
ast_moh_stop ( ast_bridged_channel ( p - > owner ) ) ;
2003-02-16 06:00:12 +00:00
} else {
2004-10-23 12:19:47 +00:00
ast_moh_start ( ast_bridged_channel ( p - > owner ) , NULL ) ;
2003-02-16 06:00:12 +00:00
}
}
2003-02-07 04:07:10 +00:00
}
2002-06-28 20:34:46 +00:00
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- add_header: Add header to SIP message */
2002-06-28 20:34:46 +00:00
static int add_header ( struct sip_request * req , char * var , char * value )
{
2003-02-07 04:07:10 +00:00
if ( req - > len > = sizeof ( req - > data ) - 4 ) {
2003-08-12 21:18:24 +00:00
ast_log ( LOG_WARNING , " Out of space, can't add anymore (%s:%s) \n " , var , value ) ;
2003-02-07 04:07:10 +00:00
return - 1 ;
}
2002-06-28 20:34:46 +00:00
if ( req - > lines ) {
ast_log ( LOG_WARNING , " Can't add more headers when lines have been added \n " ) ;
return - 1 ;
}
req - > header [ req - > headers ] = req - > data + req - > len ;
2003-02-07 04:07:10 +00:00
snprintf ( req - > header [ req - > headers ] , sizeof ( req - > data ) - req - > len - 4 , " %s: %s \r \n " , var , value ) ;
req - > len + = strlen ( req - > header [ req - > headers ] ) ;
2002-06-28 20:34:46 +00:00
if ( req - > headers < SIP_MAX_HEADERS )
req - > headers + + ;
else {
ast_log ( LOG_WARNING , " Out of header space \n " ) ;
return - 1 ;
}
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- add_blank_header: Add blank header to SIP message */
2002-06-28 20:34:46 +00:00
static int add_blank_header ( struct sip_request * req )
{
2003-02-07 04:07:10 +00:00
if ( req - > len > = sizeof ( req - > data ) - 4 ) {
ast_log ( LOG_WARNING , " Out of space, can't add anymore \n " ) ;
return - 1 ;
}
2002-06-28 20:34:46 +00:00
if ( req - > lines ) {
ast_log ( LOG_WARNING , " Can't add more headers when lines have been added \n " ) ;
return - 1 ;
}
req - > header [ req - > headers ] = req - > data + req - > len ;
2003-02-07 04:07:10 +00:00
snprintf ( req - > header [ req - > headers ] , sizeof ( req - > data ) - req - > len , " \r \n " ) ;
req - > len + = strlen ( req - > header [ req - > headers ] ) ;
2002-06-28 20:34:46 +00:00
if ( req - > headers < SIP_MAX_HEADERS )
req - > headers + + ;
else {
ast_log ( LOG_WARNING , " Out of header space \n " ) ;
return - 1 ;
}
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- add_line: Add content (not header) to SIP message */
2002-06-28 20:34:46 +00:00
static int add_line ( struct sip_request * req , char * line )
{
2003-02-07 04:07:10 +00:00
if ( req - > len > = sizeof ( req - > data ) - 4 ) {
ast_log ( LOG_WARNING , " Out of space, can't add anymore \n " ) ;
return - 1 ;
}
2002-06-28 20:34:46 +00:00
if ( ! req - > lines ) {
/* Add extra empty return */
2003-02-07 04:07:10 +00:00
snprintf ( req - > data + req - > len , sizeof ( req - > data ) - req - > len , " \r \n " ) ;
req - > len + = strlen ( req - > data + req - > len ) ;
2002-06-28 20:34:46 +00:00
}
req - > line [ req - > lines ] = req - > data + req - > len ;
2003-02-07 04:07:10 +00:00
snprintf ( req - > line [ req - > lines ] , sizeof ( req - > data ) - req - > len , " %s " , line ) ;
req - > len + = strlen ( req - > line [ req - > lines ] ) ;
2002-06-28 20:34:46 +00:00
if ( req - > lines < SIP_MAX_LINES )
req - > lines + + ;
else {
ast_log ( LOG_WARNING , " Out of line space \n " ) ;
return - 1 ;
}
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- copy_header: Copy one header field from one request to another */
2002-06-28 20:34:46 +00:00
static int copy_header ( struct sip_request * req , struct sip_request * orig , char * field )
{
char * tmp ;
tmp = get_header ( orig , field ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( tmp ) ) {
2002-06-28 20:34:46 +00:00
/* Add what we're responding to */
return add_header ( req , field , tmp ) ;
}
ast_log ( LOG_NOTICE , " No field '%s' present to copy \n " , field ) ;
return - 1 ;
}
2004-05-13 19:54:42 +00:00
/*--- copy_all_header: Copy all headers from one request to another ---*/
2002-09-12 17:13:17 +00:00
static int copy_all_header ( struct sip_request * req , struct sip_request * orig , char * field )
{
char * tmp ;
int start = 0 ;
int copied = 0 ;
for ( ; ; ) {
tmp = __get_header ( orig , field , & start ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( tmp ) ) {
2002-09-12 17:13:17 +00:00
/* Add what we're responding to */
add_header ( req , field , tmp ) ;
copied + + ;
} else
break ;
}
2003-04-05 22:29:46 +00:00
return copied ? 0 : - 1 ;
2002-09-12 17:13:17 +00:00
}
2003-04-05 22:29:46 +00:00
2004-05-13 19:54:42 +00:00
/*--- copy_via_headers: Copy SIP VIA Headers from one request to another ---*/
2003-03-05 06:00:17 +00:00
static int copy_via_headers ( struct sip_pvt * p , struct sip_request * req , struct sip_request * orig , char * field )
{
2004-07-08 07:21:52 +00:00
char tmp [ 256 ] = " " , * oh , * end ;
2003-03-05 06:00:17 +00:00
int start = 0 ;
int copied = 0 ;
char new [ 256 ] ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-03-05 06:00:17 +00:00
for ( ; ; ) {
2004-07-08 07:21:52 +00:00
oh = __get_header ( orig , field , & start ) ;
if ( ! ast_strlen_zero ( oh ) ) {
/* Strip ;rport */
strncpy ( tmp , oh , sizeof ( tmp ) - 1 ) ;
oh = strstr ( tmp , " ;rport " ) ;
if ( oh ) {
end = strchr ( oh + 1 , ' ; ' ) ;
if ( end )
memmove ( oh , end , strlen ( end ) + 1 ) ;
else
* oh = ' \0 ' ;
}
2004-06-28 23:24:36 +00:00
if ( ! copied & & ( p - > nat = = SIP_NAT_ALWAYS ) ) {
2004-06-16 14:14:57 +00:00
/* Whoo hoo! Now we can indicate port address translation too! Just
another RFC ( RFC3581 ) . I ' ll leave the original comments in for
posterity . */
2004-06-29 12:56:46 +00:00
snprintf ( new , sizeof ( new ) , " %s;received=%s;rport=%d " , tmp , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > recv . sin_addr ) , ntohs ( p - > recv . sin_port ) ) ;
2003-03-05 06:00:17 +00:00
add_header ( req , field , new ) ;
} else {
/* Add what we're responding to */
add_header ( req , field , tmp ) ;
}
copied + + ;
} else
break ;
}
if ( ! copied ) {
ast_log ( LOG_NOTICE , " No field '%s' present to copy \n " , field ) ;
return - 1 ;
}
return 0 ;
}
2002-09-12 17:13:17 +00:00
2004-05-13 19:54:42 +00:00
/*--- add_route: Add route header into request per learned route ---*/
2003-04-05 22:29:46 +00:00
static void add_route ( struct sip_request * req , struct sip_route * route )
{
char r [ 256 ] , * p ;
int n , rem = 255 ; /* sizeof(r)-1: Room for terminating 0 */
if ( ! route ) return ;
p = r ;
while ( route ) {
n = strlen ( route - > hop ) ;
if ( ( n + 3 ) > rem ) break ;
if ( p ! = r ) {
* p + + = ' , ' ;
- - rem ;
}
* p + + = ' < ' ;
2004-07-08 11:05:03 +00:00
strncpy ( p , route - > hop , rem ) ; p + = n ;
2003-04-05 22:29:46 +00:00
* p + + = ' > ' ;
rem - = ( n + 2 ) ;
route = route - > next ;
}
* p = ' \0 ' ;
add_header ( req , " Route " , r ) ;
}
2004-05-13 19:54:42 +00:00
/*--- set_destination: Set destination from SIP URI ---*/
2003-04-05 22:29:46 +00:00
static void set_destination ( struct sip_pvt * p , char * uri )
{
2004-07-16 04:40:54 +00:00
char * h , * maddr , hostname [ 256 ] = " " ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-04-05 22:29:46 +00:00
int port , hn ;
struct hostent * hp ;
2004-04-22 00:20:34 +00:00
struct ast_hostent ahp ;
2004-06-18 13:53:48 +00:00
int debug = sip_debug_test_pvt ( p ) ;
2003-04-05 22:29:46 +00:00
/* Parse uri to h (host) and port - uri is already just the part inside the <> */
/* general form we are expecting is sip[s]:username[:password]@host[:port][;...] */
2004-06-18 13:53:48 +00:00
if ( debug )
2003-04-05 22:29:46 +00:00
ast_verbose ( " set_destination: Parsing <%s> for address/port to send to \n " , uri ) ;
2003-04-06 23:32:31 +00:00
/* Find and parse hostname */
2003-04-05 22:29:46 +00:00
h = strchr ( uri , ' @ ' ) ;
2003-04-06 23:32:31 +00:00
if ( h )
+ + h ;
else {
h = uri ;
if ( strncmp ( h , " sip: " , 4 ) = = 0 )
h + = 4 ;
else if ( strncmp ( h , " sips: " , 5 ) = = 0 )
h + = 5 ;
2003-04-05 22:29:46 +00:00
}
hn = strcspn ( h , " :;> " ) ;
2004-07-16 04:40:54 +00:00
if ( hn > ( sizeof ( hostname ) - 1 ) ) hn = sizeof ( hostname ) - 1 ;
strncpy ( hostname , h , hn ) ; hostname [ hn ] = ' \0 ' ; /* safe */
2003-04-05 22:29:46 +00:00
h + = hn ;
2003-04-06 23:32:31 +00:00
2003-04-05 22:29:46 +00:00
/* Is "port" present? if not default to 5060 */
if ( * h = = ' : ' ) {
/* Parse port */
+ + h ;
port = strtol ( h , & h , 10 ) ;
}
else
port = 5060 ;
2003-04-06 23:32:31 +00:00
/* Got the hostname:port - but maybe there's a "maddr=" to override address? */
maddr = strstr ( h , " maddr= " ) ;
2003-04-05 22:29:46 +00:00
if ( maddr ) {
2003-04-06 23:32:31 +00:00
maddr + = 6 ;
2003-04-05 22:29:46 +00:00
hn = strspn ( maddr , " 0123456789. " ) ;
2004-07-16 04:40:54 +00:00
if ( hn > ( sizeof ( hostname ) - 1 ) ) hn = sizeof ( hostname ) - 1 ;
strncpy ( hostname , maddr , hn ) ; hostname [ hn ] = ' \0 ' ; /* safe */
2003-04-05 22:29:46 +00:00
}
2004-04-22 00:20:34 +00:00
hp = ast_gethostbyname ( hostname , & ahp ) ;
2003-04-05 22:29:46 +00:00
if ( hp = = NULL ) {
2003-04-05 23:05:45 +00:00
ast_log ( LOG_WARNING , " Can't find address for host '%s' \n " , hostname ) ;
2003-04-05 22:29:46 +00:00
return ;
}
p - > sa . sin_family = AF_INET ;
memcpy ( & p - > sa . sin_addr , hp - > h_addr , sizeof ( p - > sa . sin_addr ) ) ;
p - > sa . sin_port = htons ( port ) ;
2004-06-18 13:53:48 +00:00
if ( debug )
2004-06-29 12:56:46 +00:00
ast_verbose ( " set_destination: set destination to %s, port %d \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > sa . sin_addr ) , port ) ;
2003-04-05 22:29:46 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- init_resp: Initialize SIP response, based on SIP request ---*/
2002-06-28 20:34:46 +00:00
static int init_resp ( struct sip_request * req , char * resp , struct sip_request * orig )
{
/* Initialize a response */
if ( req - > headers | | req - > len ) {
ast_log ( LOG_WARNING , " Request already initialized?!? \n " ) ;
return - 1 ;
}
req - > header [ req - > headers ] = req - > data + req - > len ;
2003-02-07 04:07:10 +00:00
snprintf ( req - > header [ req - > headers ] , sizeof ( req - > data ) - req - > len , " SIP/2.0 %s \r \n " , resp ) ;
req - > len + = strlen ( req - > header [ req - > headers ] ) ;
2002-06-28 20:34:46 +00:00
if ( req - > headers < SIP_MAX_HEADERS )
req - > headers + + ;
else
ast_log ( LOG_WARNING , " Out of header space \n " ) ;
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- init_req: Initialize SIP request ---*/
2002-06-28 20:34:46 +00:00
static int init_req ( struct sip_request * req , char * resp , char * recip )
{
/* Initialize a response */
if ( req - > headers | | req - > len ) {
ast_log ( LOG_WARNING , " Request already initialized?!? \n " ) ;
return - 1 ;
}
req - > header [ req - > headers ] = req - > data + req - > len ;
2003-02-07 04:07:10 +00:00
snprintf ( req - > header [ req - > headers ] , sizeof ( req - > data ) - req - > len , " %s %s SIP/2.0 \r \n " , resp , recip ) ;
req - > len + = strlen ( req - > header [ req - > headers ] ) ;
2002-06-28 20:34:46 +00:00
if ( req - > headers < SIP_MAX_HEADERS )
req - > headers + + ;
else
ast_log ( LOG_WARNING , " Out of header space \n " ) ;
return 0 ;
}
2004-05-13 19:54:42 +00:00
2002-09-12 17:13:17 +00:00
static int respprep ( struct sip_request * resp , struct sip_pvt * p , char * msg , struct sip_request * req )
2002-06-28 20:34:46 +00:00
{
2003-02-07 04:07:10 +00:00
char newto [ 256 ] = " " , * ot ;
2004-07-08 11:05:03 +00:00
2002-06-28 20:34:46 +00:00
memset ( resp , 0 , sizeof ( * resp ) ) ;
init_resp ( resp , msg , req ) ;
2003-03-05 06:00:17 +00:00
copy_via_headers ( p , resp , req , " Via " ) ;
2003-04-05 22:29:46 +00:00
if ( msg [ 0 ] = = ' 2 ' ) copy_all_header ( resp , req , " Record-Route " ) ;
2002-06-28 20:34:46 +00:00
copy_header ( resp , req , " From " ) ;
2002-09-12 17:13:17 +00:00
ot = get_header ( req , " To " ) ;
if ( ! strstr ( ot , " tag= " ) ) {
/* Add the proper tag if we don't have it already. If they have specified
their tag , use it . Otherwise , use our own tag */
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( p - > theirtag ) & & p - > outgoing )
2002-09-12 17:13:17 +00:00
snprintf ( newto , sizeof ( newto ) , " %s;tag=%s " , ot , p - > theirtag ) ;
2003-04-07 06:12:19 +00:00
else if ( p - > tag & & ! p - > outgoing )
snprintf ( newto , sizeof ( newto ) , " %s;tag=as%08x " , ot , p - > tag ) ;
2004-07-08 11:05:03 +00:00
else {
2002-09-12 17:13:17 +00:00
strncpy ( newto , ot , sizeof ( newto ) - 1 ) ;
2004-07-08 11:05:03 +00:00
newto [ sizeof ( newto ) - 1 ] = ' \0 ' ;
}
2002-09-12 17:13:17 +00:00
ot = newto ;
}
add_header ( resp , " To " , ot ) ;
2002-06-28 20:34:46 +00:00
copy_header ( resp , req , " Call-ID " ) ;
copy_header ( resp , req , " CSeq " ) ;
2004-07-08 11:05:03 +00:00
add_header ( resp , " User-Agent " , default_useragent ) ;
2003-08-12 21:18:24 +00:00
add_header ( resp , " Allow " , ALLOWED_METHODS ) ;
2003-04-08 03:24:12 +00:00
if ( p - > expiry ) {
/* For registration responses, we also need expiry and
2002-06-28 20:34:46 +00:00
contact info */
2003-03-16 06:00:11 +00:00
char contact [ 256 ] ;
2003-04-08 03:24:12 +00:00
char tmp [ 256 ] ;
2003-04-08 14:49:12 +00:00
snprintf ( contact , sizeof ( contact ) , " %s;expires=%d " , p - > our_contact , p - > expiry ) ;
2003-04-08 03:24:12 +00:00
snprintf ( tmp , sizeof ( tmp ) , " %d " , p - > expiry ) ;
2002-06-28 20:34:46 +00:00
add_header ( resp , " Expires " , tmp ) ;
add_header ( resp , " Contact " , contact ) ;
2002-09-12 17:13:17 +00:00
} else {
2003-04-08 14:49:12 +00:00
add_header ( resp , " Contact " , p - > our_contact ) ;
2002-06-28 20:34:46 +00:00
}
return 0 ;
}
2004-03-28 04:05:58 +00:00
static int reqprep ( struct sip_request * req , struct sip_pvt * p , char * msg , int seqno , int newbranch )
2002-06-28 20:34:46 +00:00
{
struct sip_request * orig = & p - > initreq ;
2003-02-07 04:07:10 +00:00
char stripped [ 80 ] = " " ;
2002-06-28 20:34:46 +00:00
char tmp [ 80 ] ;
2002-09-12 17:13:17 +00:00
char newto [ 256 ] ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2002-06-28 20:34:46 +00:00
char * c , * n ;
char * ot , * of ;
memset ( req , 0 , sizeof ( struct sip_request ) ) ;
2003-02-07 04:07:10 +00:00
2003-11-04 02:40:09 +00:00
snprintf ( p - > lastmsg , sizeof ( p - > lastmsg ) , " Tx: %s " , msg ) ;
2003-04-07 06:12:19 +00:00
if ( ! seqno ) {
2003-02-07 04:07:10 +00:00
p - > ocseq + + ;
2003-04-07 06:12:19 +00:00
seqno = p - > ocseq ;
}
2004-03-28 04:05:58 +00:00
if ( newbranch ) {
p - > branch ^ = rand ( ) ;
2004-08-27 02:45:35 +00:00
if ( p - > nat & SIP_NAT_RFC3581 )
2004-06-29 12:56:46 +00:00
snprintf ( p - > via , sizeof ( p - > via ) , " SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) , ourport , p - > branch ) ;
2004-06-28 23:24:36 +00:00
else /* Some implementations (e.g. Uniden UIP200) can't handle rport being in the message!! */
2004-06-29 12:56:46 +00:00
snprintf ( p - > via , sizeof ( p - > via ) , " SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) , ourport , p - > branch ) ;
2004-03-28 04:05:58 +00:00
}
2004-07-27 19:00:06 +00:00
if ( ! strcasecmp ( msg , " CANCEL " ) | | ! strcasecmp ( msg , " ACK " ) ) {
2004-07-27 04:04:45 +00:00
/* MUST use original URI */
c = p - > initreq . rlPart2 ;
} else if ( ! ast_strlen_zero ( p - > uri ) ) {
2003-08-24 06:24:38 +00:00
c = p - > uri ;
} else {
if ( p - > outgoing )
strncpy ( stripped , get_header ( orig , " To " ) , sizeof ( stripped ) - 1 ) ;
else
strncpy ( stripped , get_header ( orig , " From " ) , sizeof ( stripped ) - 1 ) ;
c = strchr ( stripped , ' < ' ) ;
if ( c )
c + + ;
else
c = stripped ;
n = strchr ( c , ' > ' ) ;
if ( n )
* n = ' \0 ' ;
n = strchr ( c , ' ; ' ) ;
if ( n )
* n = ' \0 ' ;
}
2002-06-28 20:34:46 +00:00
init_req ( req , msg , c ) ;
2003-04-07 06:12:19 +00:00
snprintf ( tmp , sizeof ( tmp ) , " %d %s " , seqno , msg ) ;
2002-06-28 20:34:46 +00:00
2003-02-07 04:07:10 +00:00
add_header ( req , " Via " , p - > via ) ;
2003-04-05 22:29:46 +00:00
if ( p - > route ) {
set_destination ( p , p - > route - > hop ) ;
add_route ( req , p - > route - > next ) ;
}
2002-06-28 20:34:46 +00:00
ot = get_header ( orig , " To " ) ;
of = get_header ( orig , " From " ) ;
2002-09-12 17:13:17 +00:00
2003-04-06 04:41:16 +00:00
/* Add tag *unless* this is a CANCEL, in which case we need to send it exactly
as our original request , including tag ( or presumably lack thereof ) */
if ( ! strstr ( ot , " tag= " ) & & strcasecmp ( msg , " CANCEL " ) ) {
2002-09-12 17:13:17 +00:00
/* Add the proper tag if we don't have it already. If they have specified
their tag , use it . Otherwise , use our own tag */
2004-05-03 21:01:14 +00:00
if ( p - > outgoing & & ! ast_strlen_zero ( p - > theirtag ) )
2002-09-12 17:13:17 +00:00
snprintf ( newto , sizeof ( newto ) , " %s;tag=%s " , ot , p - > theirtag ) ;
2003-04-06 23:39:57 +00:00
else if ( ! p - > outgoing )
2003-04-07 06:12:19 +00:00
snprintf ( newto , sizeof ( newto ) , " %s;tag=as%08x " , ot , p - > tag ) ;
2003-04-06 04:41:16 +00:00
else
snprintf ( newto , sizeof ( newto ) , " %s " , ot ) ;
2002-09-12 17:13:17 +00:00
ot = newto ;
}
2002-06-28 20:34:46 +00:00
if ( p - > outgoing ) {
add_header ( req , " From " , of ) ;
add_header ( req , " To " , ot ) ;
} else {
add_header ( req , " From " , ot ) ;
add_header ( req , " To " , of ) ;
}
2003-04-08 14:49:12 +00:00
add_header ( req , " Contact " , p - > our_contact ) ;
2002-06-28 20:34:46 +00:00
copy_header ( req , orig , " Call-ID " ) ;
2002-09-12 17:13:17 +00:00
add_header ( req , " CSeq " , tmp ) ;
2004-07-08 11:05:03 +00:00
add_header ( req , " User-Agent " , default_useragent ) ;
2002-06-28 20:34:46 +00:00
return 0 ;
}
2003-04-05 21:36:30 +00:00
static int __transmit_response ( struct sip_pvt * p , char * msg , struct sip_request * req , int reliable )
2002-06-28 20:34:46 +00:00
{
struct sip_request resp ;
2003-04-05 21:36:30 +00:00
int seqno = 0 ;
if ( reliable & & ( sscanf ( get_header ( req , " CSeq " ) , " %i " , & seqno ) ! = 1 ) ) {
ast_log ( LOG_WARNING , " Unable to determine sequence number from '%s' \n " , get_header ( req , " CSeq " ) ) ;
return - 1 ;
}
2002-09-12 17:13:17 +00:00
respprep ( & resp , p , msg , req ) ;
2002-06-28 20:34:46 +00:00
add_header ( & resp , " Content-Length " , " 0 " ) ;
add_blank_header ( & resp ) ;
2003-04-05 21:36:30 +00:00
return send_response ( p , & resp , reliable , seqno ) ;
}
2004-05-13 19:54:42 +00:00
/*--- transmit_response: Transmit response, no retransmits */
2003-04-05 21:36:30 +00:00
static int transmit_response ( struct sip_pvt * p , char * msg , struct sip_request * req )
{
return __transmit_response ( p , msg , req , 0 ) ;
}
2004-05-13 19:54:42 +00:00
/*--- transmit_response: Transmit response, Make sure you get a reply */
2004-03-24 21:21:59 +00:00
static int transmit_response_reliable ( struct sip_pvt * p , char * msg , struct sip_request * req , int fatal )
2003-04-05 21:36:30 +00:00
{
2004-03-24 21:21:59 +00:00
return __transmit_response ( p , msg , req , fatal ? 2 : 1 ) ;
2002-06-28 20:34:46 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- append_date: Append date to SIP message ---*/
2003-04-06 04:54:04 +00:00
static void append_date ( struct sip_request * req )
{
char tmpdat [ 256 ] ;
struct tm tm ;
time_t t ;
time ( & t ) ;
gmtime_r ( & t , & tm ) ;
strftime ( tmpdat , sizeof ( tmpdat ) , " %a, %d %b %Y %T GMT " , & tm ) ;
add_header ( req , " Date " , tmpdat ) ;
}
2004-05-13 19:54:42 +00:00
/*--- transmit_response_with_date: Append date and content length before transmitting response ---*/
2003-04-06 04:54:04 +00:00
static int transmit_response_with_date ( struct sip_pvt * p , char * msg , struct sip_request * req )
{
struct sip_request resp ;
respprep ( & resp , p , msg , req ) ;
append_date ( & resp ) ;
add_header ( & resp , " Content-Length " , " 0 " ) ;
add_blank_header ( & resp ) ;
return send_response ( p , & resp , 0 , 0 ) ;
}
2004-05-13 19:54:42 +00:00
/*--- transmit_response_with_allow: Append Accept header, content length before transmitting response ---*/
2004-05-12 23:35:50 +00:00
static int transmit_response_with_allow ( struct sip_pvt * p , char * msg , struct sip_request * req , int reliable )
2003-02-07 04:07:10 +00:00
{
struct sip_request resp ;
respprep ( & resp , p , msg , req ) ;
add_header ( & resp , " Accept " , " application/sdp " ) ;
add_header ( & resp , " Content-Length " , " 0 " ) ;
add_blank_header ( & resp ) ;
2004-05-12 23:35:50 +00:00
return send_response ( p , & resp , reliable , 0 ) ;
2003-02-07 04:07:10 +00:00
}
2004-05-13 19:54:42 +00:00
/* transmit_response_with_auth: Respond with authorization request */
2004-06-12 16:38:36 +00:00
static int transmit_response_with_auth ( struct sip_pvt * p , char * msg , struct sip_request * req , char * randdata , int reliable , char * header )
2003-02-07 04:07:10 +00:00
{
struct sip_request resp ;
char tmp [ 256 ] ;
2003-03-28 06:13:04 +00:00
int seqno = 0 ;
if ( reliable & & ( sscanf ( get_header ( req , " CSeq " ) , " %i " , & seqno ) ! = 1 ) ) {
ast_log ( LOG_WARNING , " Unable to determine sequence number from '%s' \n " , get_header ( req , " CSeq " ) ) ;
return - 1 ;
}
2004-05-06 20:00:19 +00:00
snprintf ( tmp , sizeof ( tmp ) , " Digest realm= \" %s \" , nonce= \" %s \" " , global_realm , randdata ) ;
2003-02-07 04:07:10 +00:00
respprep ( & resp , p , msg , req ) ;
2004-06-12 16:38:36 +00:00
add_header ( & resp , header , tmp ) ;
2003-02-07 04:07:10 +00:00
add_header ( & resp , " Content-Length " , " 0 " ) ;
add_blank_header ( & resp ) ;
2003-03-28 06:13:04 +00:00
return send_response ( p , & resp , reliable , seqno ) ;
2003-02-07 04:07:10 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- add_text: Add text body to SIP message ---*/
2003-02-07 04:07:10 +00:00
static int add_text ( struct sip_request * req , char * text )
{
/* XXX Convert \n's to \r\n's XXX */
int len = strlen ( text ) ;
char clen [ 256 ] ;
snprintf ( clen , sizeof ( clen ) , " %d " , len ) ;
add_header ( req , " Content-Type " , " text/plain " ) ;
add_header ( req , " Content-Length " , clen ) ;
add_line ( req , text ) ;
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- add_digit: add DTMF INFO tone to sip message ---*/
/* Always adds default duration 250 ms, regardless of what came in over the line */
2003-03-12 06:00:18 +00:00
static int add_digit ( struct sip_request * req , char digit )
{
char tmp [ 256 ] ;
int len ;
char clen [ 256 ] ;
snprintf ( tmp , sizeof ( tmp ) , " Signal=%c \r \n Duration=250 \r \n " , digit ) ;
len = strlen ( tmp ) ;
snprintf ( clen , sizeof ( clen ) , " %d " , len ) ;
add_header ( req , " Content-Type " , " application/dtmf-relay " ) ;
add_header ( req , " Content-Length " , clen ) ;
add_line ( req , tmp ) ;
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- add_sdp: Add Session Description Protocol message ---*/
2004-05-27 05:06:32 +00:00
static int add_sdp ( struct sip_request * resp , struct sip_pvt * p )
2002-06-28 20:34:46 +00:00
{
int len ;
int codec ;
2003-02-20 06:00:14 +00:00
int alreadysent = 0 ;
2002-06-28 20:34:46 +00:00
char costr [ 80 ] ;
struct sockaddr_in sin ;
2003-06-28 16:40:02 +00:00
struct sockaddr_in vsin ;
2003-02-20 06:00:14 +00:00
struct sip_codec_pref * cur ;
2004-05-16 16:31:42 +00:00
char v [ 256 ] = " " ;
char s [ 256 ] = " " ;
char o [ 256 ] = " " ;
char c [ 256 ] = " " ;
char t [ 256 ] = " " ;
char m [ 256 ] = " " ;
char m2 [ 256 ] = " " ;
2002-09-12 17:13:17 +00:00
char a [ 1024 ] = " " ;
2003-06-28 16:40:02 +00:00
char a2 [ 1024 ] = " " ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2002-06-28 20:34:46 +00:00
int x ;
2004-05-27 04:18:46 +00:00
int capability ;
2003-02-07 04:07:10 +00:00
struct sockaddr_in dest ;
2004-03-23 05:06:50 +00:00
struct sockaddr_in vdest = { 0 , } ;
2004-06-18 13:53:48 +00:00
int debug = sip_debug_test_pvt ( p ) ;
2002-06-28 20:34:46 +00:00
/* XXX We break with the "recommendation" and send our IP, in order that our
2004-04-22 00:20:34 +00:00
peer doesn ' t have to ast_gethostbyname ( ) us XXX */
2002-06-28 20:34:46 +00:00
len = 0 ;
2003-02-07 04:07:10 +00:00
if ( ! p - > rtp ) {
ast_log ( LOG_WARNING , " No way to add SDP without an RTP structure \n " ) ;
return - 1 ;
}
2004-08-18 13:55:03 +00:00
capability = p - > capability ;
2004-05-27 04:18:46 +00:00
2003-11-24 19:13:32 +00:00
if ( ! p - > sessionid ) {
p - > sessionid = getpid ( ) ;
p - > sessionversion = p - > sessionid ;
} else
p - > sessionversion + + ;
2002-06-28 20:34:46 +00:00
ast_rtp_get_us ( p - > rtp , & sin ) ;
2003-06-28 16:40:02 +00:00
if ( p - > vrtp )
ast_rtp_get_us ( p - > vrtp , & vsin ) ;
2003-04-30 21:53:55 +00:00
if ( p - > redirip . sin_addr . s_addr ) {
dest . sin_port = p - > redirip . sin_port ;
dest . sin_addr = p - > redirip . sin_addr ;
2004-05-27 05:06:32 +00:00
if ( p - > redircodecs )
capability = p - > redircodecs ;
2003-02-07 04:07:10 +00:00
} else {
dest . sin_addr = p - > ourip ;
dest . sin_port = sin . sin_port ;
}
2003-06-28 16:40:02 +00:00
/* Determine video destination */
if ( p - > vrtp ) {
if ( p - > vredirip . sin_addr . s_addr ) {
vdest . sin_port = p - > vredirip . sin_port ;
vdest . sin_addr = p - > vredirip . sin_addr ;
} else {
vdest . sin_addr = p - > ourip ;
vdest . sin_port = vsin . sin_port ;
}
}
2004-06-18 13:53:48 +00:00
if ( debug ) {
2004-06-29 12:56:46 +00:00
ast_verbose ( " We're at %s port %d \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) , ntohs ( sin . sin_port ) ) ;
2004-06-18 13:53:48 +00:00
if ( p - > vrtp )
2004-06-29 12:56:46 +00:00
ast_verbose ( " Video is at %s port %d \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) , ntohs ( vsin . sin_port ) ) ;
2004-06-18 13:53:48 +00:00
}
2002-06-28 20:34:46 +00:00
snprintf ( v , sizeof ( v ) , " v=0 \r \n " ) ;
2004-06-29 12:56:46 +00:00
snprintf ( o , sizeof ( o ) , " o=root %d %d IN IP4 %s \r \n " , p - > sessionid , p - > sessionversion , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , dest . sin_addr ) ) ;
2002-09-12 17:13:17 +00:00
snprintf ( s , sizeof ( s ) , " s=session \r \n " ) ;
2004-06-29 12:56:46 +00:00
snprintf ( c , sizeof ( c ) , " c=IN IP4 %s \r \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , dest . sin_addr ) ) ;
2002-06-28 20:34:46 +00:00
snprintf ( t , sizeof ( t ) , " t=0 0 \r \n " ) ;
2003-02-07 04:07:10 +00:00
snprintf ( m , sizeof ( m ) , " m=audio %d RTP/AVP " , ntohs ( dest . sin_port ) ) ;
2003-06-28 16:40:02 +00:00
snprintf ( m2 , sizeof ( m2 ) , " m=video %d RTP/AVP " , ntohs ( vdest . sin_port ) ) ;
2004-05-27 04:18:46 +00:00
if ( capability & p - > prefcodec ) {
2004-06-18 13:53:48 +00:00
if ( debug )
2004-03-19 08:00:13 +00:00
ast_verbose ( " Answering/Requesting with root capability %d \n " , p - > prefcodec ) ;
codec = ast_rtp_lookup_code ( p - > rtp , 1 , p - > prefcodec ) ;
if ( codec > - 1 ) {
snprintf ( costr , sizeof ( costr ) , " %d " , codec ) ;
if ( p - > prefcodec < = AST_FORMAT_MAX_AUDIO ) {
2004-07-08 11:05:03 +00:00
strncat ( m , costr , sizeof ( m ) - strlen ( m ) - 1 ) ;
2004-03-19 08:00:13 +00:00
snprintf ( costr , sizeof ( costr ) , " a=rtpmap:%d %s/8000 \r \n " , codec , ast_rtp_lookup_mime_subtype ( 1 , p - > prefcodec ) ) ;
2004-07-08 11:05:03 +00:00
strncpy ( a , costr , sizeof ( a ) - 1 ) ;
2004-03-19 08:00:13 +00:00
} else {
2004-07-08 11:05:03 +00:00
strncat ( m2 , costr , sizeof ( m2 ) - strlen ( m2 ) - 1 ) ;
2004-03-19 08:00:13 +00:00
snprintf ( costr , sizeof ( costr ) , " a=rtpmap:%d %s/90000 \r \n " , codec , ast_rtp_lookup_mime_subtype ( 1 , p - > prefcodec ) ) ;
2004-07-08 11:05:03 +00:00
strncpy ( a2 , costr , sizeof ( a2 ) - 1 ) ;
2004-03-19 08:00:13 +00:00
}
}
alreadysent | = p - > prefcodec ;
}
2003-02-20 06:00:14 +00:00
/* Start by sending our preferred codecs */
cur = prefs ;
while ( cur ) {
2004-05-27 04:18:46 +00:00
if ( ( capability & cur - > codec ) & & ! ( alreadysent & cur - > codec ) ) {
2004-06-18 13:53:48 +00:00
if ( debug )
2004-05-19 03:39:44 +00:00
ast_verbose ( " Answering with preferred capability 0x%x(%s) \n " , cur - > codec , ast_getformatname ( cur - > codec ) ) ;
2003-03-13 06:00:20 +00:00
codec = ast_rtp_lookup_code ( p - > rtp , 1 , cur - > codec ) ;
2003-03-12 06:00:18 +00:00
if ( codec > - 1 ) {
2003-02-20 06:00:14 +00:00
snprintf ( costr , sizeof ( costr ) , " %d " , codec ) ;
2004-03-19 08:00:13 +00:00
if ( cur - > codec < = AST_FORMAT_MAX_AUDIO ) {
2004-07-08 11:05:03 +00:00
strncat ( m , costr , sizeof ( m ) - strlen ( m ) - 1 ) ;
2003-06-28 16:40:02 +00:00
snprintf ( costr , sizeof ( costr ) , " a=rtpmap:%d %s/8000 \r \n " , codec , ast_rtp_lookup_mime_subtype ( 1 , cur - > codec ) ) ;
2004-07-08 11:05:03 +00:00
strncat ( a , costr , sizeof ( a ) - strlen ( a ) - 1 ) ;
2003-06-28 16:40:02 +00:00
} else {
2004-07-08 11:05:03 +00:00
strncat ( m2 , costr , sizeof ( m2 ) - strlen ( m2 ) - 1 ) ;
2003-06-28 16:40:02 +00:00
snprintf ( costr , sizeof ( costr ) , " a=rtpmap:%d %s/90000 \r \n " , codec , ast_rtp_lookup_mime_subtype ( 1 , cur - > codec ) ) ;
2004-07-08 11:05:03 +00:00
strncat ( a2 , costr , sizeof ( a2 ) - strlen ( a ) - 1 ) ;
2003-06-28 16:40:02 +00:00
}
2003-02-20 06:00:14 +00:00
}
}
alreadysent | = cur - > codec ;
cur = cur - > next ;
}
2003-03-12 06:00:18 +00:00
/* Now send any other common codecs, and non-codec formats: */
2004-08-17 01:57:16 +00:00
for ( x = 1 ; x < = ( ( videosupport & & p - > vrtp ) ? AST_FORMAT_MAX_VIDEO : AST_FORMAT_MAX_AUDIO ) ; x < < = 1 ) {
2004-05-27 04:18:46 +00:00
if ( ( capability & x ) & & ! ( alreadysent & x ) ) {
2004-06-18 13:53:48 +00:00
if ( debug )
2004-05-19 03:39:44 +00:00
ast_verbose ( " Answering with capability 0x%x(%s) \n " , x , ast_getformatname ( x ) ) ;
2003-03-13 06:00:20 +00:00
codec = ast_rtp_lookup_code ( p - > rtp , 1 , x ) ;
2003-03-12 06:00:18 +00:00
if ( codec > - 1 ) {
2003-06-28 16:40:02 +00:00
snprintf ( costr , sizeof ( costr ) , " %d " , codec ) ;
2004-03-19 08:00:13 +00:00
if ( x < = AST_FORMAT_MAX_AUDIO ) {
2004-07-08 11:05:03 +00:00
strncat ( m , costr , sizeof ( m ) - strlen ( m ) - 1 ) ;
2003-06-28 16:40:02 +00:00
snprintf ( costr , sizeof ( costr ) , " a=rtpmap:%d %s/8000 \r \n " , codec , ast_rtp_lookup_mime_subtype ( 1 , x ) ) ;
2004-07-08 11:05:03 +00:00
strncat ( a , costr , sizeof ( a ) - strlen ( a ) - 1 ) ;
2003-06-28 16:40:02 +00:00
} else {
2004-07-16 04:40:54 +00:00
strncat ( m2 , costr , sizeof ( m2 ) - strlen ( m2 ) - 1 ) ;
2003-06-28 16:40:02 +00:00
snprintf ( costr , sizeof ( costr ) , " a=rtpmap:%d %s/90000 \r \n " , codec , ast_rtp_lookup_mime_subtype ( 1 , x ) ) ;
2004-07-08 11:05:03 +00:00
strncat ( a2 , costr , sizeof ( a2 ) - strlen ( a2 ) - 1 ) ;
2003-06-28 16:40:02 +00:00
}
2003-03-12 06:00:18 +00:00
}
}
}
for ( x = 1 ; x < = AST_RTP_MAX ; x < < = 1 ) {
2003-03-27 20:13:47 +00:00
if ( p - > noncodeccapability & x ) {
2004-06-18 13:53:48 +00:00
if ( debug )
2004-05-19 03:39:44 +00:00
ast_verbose ( " Answering with non-codec capability 0x%x(%s) \n " , x , ast_getformatname ( x ) ) ;
2003-03-13 06:00:20 +00:00
codec = ast_rtp_lookup_code ( p - > rtp , 0 , x ) ;
2003-03-12 06:00:18 +00:00
if ( codec > - 1 ) {
2002-06-28 20:34:46 +00:00
snprintf ( costr , sizeof ( costr ) , " %d " , codec ) ;
2004-07-08 11:05:03 +00:00
strncat ( m , costr , sizeof ( m ) - strlen ( m ) - 1 ) ;
2003-03-13 06:00:20 +00:00
snprintf ( costr , sizeof ( costr ) , " a=rtpmap:%d %s/8000 \r \n " , codec , ast_rtp_lookup_mime_subtype ( 0 , x ) ) ;
2004-07-08 11:05:03 +00:00
strncat ( a , costr , sizeof ( a ) - strlen ( a ) - 1 ) ;
2003-03-12 06:00:18 +00:00
if ( x = = AST_RTP_DTMF ) {
/* Indicate we support DTMF... Not sure about 16, but MSN supports it so dang it, we will too... */
snprintf ( costr , sizeof costr , " a=fmtp:%d 0-16 \r \n " ,
codec ) ;
2004-07-08 11:05:03 +00:00
strncat ( a , costr , sizeof ( a ) - strlen ( a ) - 1 ) ;
2003-03-12 06:00:18 +00:00
}
2002-06-28 20:34:46 +00:00
}
}
}
2004-07-08 11:05:03 +00:00
strncat ( a , " a=silenceSupp:off - - - - \r \n " , sizeof ( a ) - strlen ( a ) - 1 ) ;
2004-01-11 19:24:15 +00:00
if ( strlen ( m ) < sizeof ( m ) - 2 )
2004-07-16 04:40:54 +00:00
strncat ( m , " \r \n " , sizeof ( m ) - strlen ( m ) - 1 ) ;
2004-01-11 19:24:15 +00:00
if ( strlen ( m2 ) < sizeof ( m2 ) - 2 )
2004-07-16 04:40:54 +00:00
strncat ( m2 , " \r \n " , sizeof ( m2 ) - strlen ( m2 ) - 1 ) ;
2004-01-11 19:24:15 +00:00
if ( ( sizeof ( m ) < = strlen ( m ) - 2 ) | | ( sizeof ( m2 ) < = strlen ( m2 ) - 2 ) | | ( sizeof ( a ) = = strlen ( a ) ) | | ( sizeof ( a2 ) = = strlen ( a2 ) ) )
ast_log ( LOG_WARNING , " SIP SDP may be truncated due to undersized buffer!! \n " ) ;
2002-09-12 17:13:17 +00:00
len = strlen ( v ) + strlen ( s ) + strlen ( o ) + strlen ( c ) + strlen ( t ) + strlen ( m ) + strlen ( a ) ;
2004-08-18 02:16:04 +00:00
if ( ( p - > vrtp ) & & ( ! p - > novideo ) & & ( capability & VIDEO_CODEC_MASK ) ) /* only if video response is appropriate */
2003-06-28 16:40:02 +00:00
len + = strlen ( m2 ) + strlen ( a2 ) ;
2002-06-28 20:34:46 +00:00
snprintf ( costr , sizeof ( costr ) , " %d " , len ) ;
add_header ( resp , " Content-Type " , " application/sdp " ) ;
add_header ( resp , " Content-Length " , costr ) ;
add_line ( resp , v ) ;
add_line ( resp , o ) ;
2002-09-12 17:13:17 +00:00
add_line ( resp , s ) ;
2002-06-28 20:34:46 +00:00
add_line ( resp , c ) ;
add_line ( resp , t ) ;
add_line ( resp , m ) ;
2002-09-12 17:13:17 +00:00
add_line ( resp , a ) ;
2004-08-18 02:16:04 +00:00
if ( ( p - > vrtp ) & & ( ! p - > novideo ) & & ( capability & VIDEO_CODEC_MASK ) ) { /* only if video response is appropriate */
2003-06-28 16:40:02 +00:00
add_line ( resp , m2 ) ;
add_line ( resp , a2 ) ;
}
2004-05-27 22:12:55 +00:00
/* Update lastrtprx when we send our SDP */
time ( & p - > lastrtprx ) ;
2002-06-28 20:34:46 +00:00
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- copy_request: copy SIP request (mostly used to save request for responses) ---*/
2002-06-28 20:34:46 +00:00
static void copy_request ( struct sip_request * dst , struct sip_request * src )
{
long offset ;
int x ;
offset = ( ( void * ) dst ) - ( ( void * ) src ) ;
/* First copy stuff */
memcpy ( dst , src , sizeof ( * dst ) ) ;
/* Now fix pointer arithmetic */
for ( x = 0 ; x < src - > headers ; x + + )
dst - > header [ x ] + = offset ;
for ( x = 0 ; x < src - > lines ; x + + )
dst - > line [ x ] + = offset ;
}
2004-05-13 19:54:42 +00:00
/*--- transmit_response_with_sdp: Used for 200 OK ---*/
2003-03-29 16:53:55 +00:00
static int transmit_response_with_sdp ( struct sip_pvt * p , char * msg , struct sip_request * req , int retrans )
2002-06-28 20:34:46 +00:00
{
struct sip_request resp ;
2003-03-28 06:13:04 +00:00
int seqno ;
if ( sscanf ( get_header ( req , " CSeq " ) , " %i " , & seqno ) ! = 1 ) {
ast_log ( LOG_WARNING , " Unable to get seqno from '%s' \n " , get_header ( req , " CSeq " ) ) ;
return - 1 ;
}
2002-09-12 17:13:17 +00:00
respprep ( & resp , p , msg , req ) ;
2004-08-26 04:56:26 +00:00
ast_rtp_offered_from_local ( p - > rtp , 0 ) ;
2004-05-27 05:06:32 +00:00
add_sdp ( & resp , p ) ;
2003-03-29 16:53:55 +00:00
return send_response ( p , & resp , retrans , seqno ) ;
2003-02-07 04:07:10 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- determine_firstline_parts: parse first line of incoming SIP request */
2003-05-02 02:18:41 +00:00
static int determine_firstline_parts ( struct sip_request * req ) {
char * e , * cmd ;
int len ;
cmd = req - > header [ 0 ] ;
while ( * cmd & & ( * cmd < 33 ) ) {
cmd + + ;
}
if ( ! * cmd ) {
return - 1 ;
}
e = cmd ;
while ( * e & & ( * e > 32 ) ) {
e + + ;
}
/* Get the command */
if ( * e ) {
* e = ' \0 ' ;
e + + ;
}
req - > rlPart1 = cmd ;
while ( * e & & ( * e < 33 ) ) {
e + + ;
}
if ( ! * e ) {
return - 1 ;
}
if ( ! strcasecmp ( cmd , " SIP/2.0 " ) ) {
/* We have a response */
req - > rlPart2 = e ;
len = strlen ( req - > rlPart2 ) ;
if ( len < 2 ) { return - 1 ; }
e + = len - 1 ;
while ( * e & & * e < 33 ) {
e - - ;
}
* ( + + e ) = ' \0 ' ;
} else {
/* We have a request */
if ( * e = = ' < ' ) {
e + + ;
if ( ! * e ) { return - 1 ; }
}
req - > rlPart2 = e ;
if ( ( e = strrchr ( req - > rlPart2 , ' S ' ) ) = = NULL ) {
return - 1 ;
}
while ( isspace ( * ( - - e ) ) ) { }
if ( * e = = ' > ' ) {
* e = ' \0 ' ;
} else {
* ( + + e ) = ' \0 ' ;
}
}
return 1 ;
}
2004-05-13 19:54:42 +00:00
/* transmit_reinvite_with_sdp: Transmit reinvite with SDP :-) ---*/
/* A re-invite is basically a new INVITE with the same CALL-ID and TAG as the
INVITE that opened the SIP dialogue */
2004-05-27 05:06:32 +00:00
static int transmit_reinvite_with_sdp ( struct sip_pvt * p )
2003-02-07 04:07:10 +00:00
{
2003-04-07 06:12:19 +00:00
struct sip_request req ;
2003-03-28 06:59:34 +00:00
if ( p - > canreinvite = = REINVITE_UPDATE )
2004-03-28 04:05:58 +00:00
reqprep ( & req , p , " UPDATE " , 0 , 1 ) ;
else
reqprep ( & req , p , " INVITE " , 0 , 1 ) ;
2003-08-12 21:18:24 +00:00
add_header ( & req , " Allow " , ALLOWED_METHODS ) ;
2004-08-26 04:56:26 +00:00
ast_rtp_offered_from_local ( p - > rtp , 1 ) ;
2004-05-27 05:06:32 +00:00
add_sdp ( & req , p ) ;
2003-04-07 06:12:19 +00:00
/* Use this as the basis */
copy_request ( & p - > initreq , & req ) ;
parse ( & p - > initreq ) ;
2004-05-01 21:25:31 +00:00
if ( sip_debug_test_pvt ( p ) )
ast_verbose ( " %d headers, %d lines \n " , p - > initreq . headers , p - > initreq . lines ) ;
2003-05-02 02:18:41 +00:00
determine_firstline_parts ( & p - > initreq ) ;
2003-04-07 06:12:19 +00:00
p - > lastinvite = p - > ocseq ;
p - > outgoing = 1 ;
return send_request ( p , & req , 1 , p - > ocseq ) ;
2002-06-28 20:34:46 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- extract_uri: Check Contact: URI of SIP message ---*/
2003-08-24 06:24:38 +00:00
static void extract_uri ( struct sip_pvt * p , struct sip_request * req )
{
char stripped [ 256 ] = " " ;
char * c , * n ;
strncpy ( stripped , get_header ( req , " Contact " ) , sizeof ( stripped ) - 1 ) ;
c = strchr ( stripped , ' < ' ) ;
if ( c )
c + + ;
else
c = stripped ;
n = strchr ( c , ' > ' ) ;
if ( n )
* n = ' \0 ' ;
n = strchr ( c , ' ; ' ) ;
if ( n )
* n = ' \0 ' ;
2004-05-03 21:01:14 +00:00
if ( c & & ! ast_strlen_zero ( c ) )
2003-08-24 06:24:38 +00:00
strncpy ( p - > uri , c , sizeof ( p - > uri ) - 1 ) ;
}
2004-05-13 19:54:42 +00:00
/*--- build_contact: Build contact header - the contact header we send out ---*/
2003-04-08 14:49:12 +00:00
static void build_contact ( struct sip_pvt * p )
{
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-04-08 14:49:12 +00:00
/* Construct Contact: header */
if ( ourport ! = 5060 )
2004-07-15 14:31:20 +00:00
snprintf ( p - > our_contact , sizeof ( p - > our_contact ) , " <sip:%s%s%s:%d> " , p - > exten , ast_strlen_zero ( p - > exten ) ? " " : " @ " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) , ourport ) ;
2003-04-08 14:49:12 +00:00
else
2004-07-15 14:31:20 +00:00
snprintf ( p - > our_contact , sizeof ( p - > our_contact ) , " <sip:%s%s%s> " , p - > exten , ast_strlen_zero ( p - > exten ) ? " " : " @ " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) ) ;
2003-04-08 14:49:12 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- initreqprep: Initiate SIP request to peer/user ---*/
2003-02-12 13:59:15 +00:00
static void initreqprep ( struct sip_request * req , struct sip_pvt * p , char * cmd , char * vxml_url )
2002-06-28 20:34:46 +00:00
{
2004-08-31 17:12:09 +00:00
char invite [ 256 ] = " " ;
2002-06-28 20:34:46 +00:00
char from [ 256 ] ;
char to [ 256 ] ;
char tmp [ 80 ] ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2004-07-08 11:05:03 +00:00
char * l = default_callerid , * n = NULL ;
2003-11-04 02:40:09 +00:00
snprintf ( p - > lastmsg , sizeof ( p - > lastmsg ) , " Init: %s " , cmd ) ;
2004-10-02 01:56:08 +00:00
if ( p - > owner ) {
l = p - > owner - > cid . cid_num ;
n = p - > owner - > cid . cid_name ;
}
2004-10-02 00:58:31 +00:00
if ( ! l | | ! ast_isphonenumber ( l ) )
l = default_callerid ;
2003-09-05 04:00:57 +00:00
/* if user want's his callerid restricted */
2004-10-02 00:58:31 +00:00
if ( p - > callingpres & AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED ) {
2003-09-05 04:00:57 +00:00
l = CALLERID_UNKNOWN ;
2004-03-16 17:07:51 +00:00
n = l ;
}
2004-05-03 21:01:14 +00:00
if ( ! n | | ast_strlen_zero ( n ) )
2003-03-30 18:20:23 +00:00
n = l ;
2003-04-09 21:30:27 +00:00
/* Allow user to be overridden */
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( p - > fromuser ) )
2003-04-09 21:30:27 +00:00
l = p - > fromuser ;
2003-04-11 04:33:53 +00:00
2004-05-03 21:01:14 +00:00
if ( ( ourport ! = 5060 ) & & ast_strlen_zero ( p - > fromdomain ) )
2004-06-29 12:56:46 +00:00
snprintf ( from , sizeof ( from ) , " \" %s \" <sip:%s@%s:%d>;tag=as%08x " , n , l , ast_strlen_zero ( p - > fromdomain ) ? ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) : p - > fromdomain , ourport , p - > tag ) ;
2003-04-06 02:51:10 +00:00
else
2004-06-29 12:56:46 +00:00
snprintf ( from , sizeof ( from ) , " \" %s \" <sip:%s@%s>;tag=as%08x " , n , l , ast_strlen_zero ( p - > fromdomain ) ? ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) : p - > fromdomain , p - > tag ) ;
2003-03-30 22:55:42 +00:00
2004-10-14 18:29:47 +00:00
/* If we're calling a registred SIP peer, use the fullcontact to dial to the peer */
2004-08-31 16:49:20 +00:00
if ( ! ast_strlen_zero ( p - > fullcontact ) ) {
/* If we have full contact, trust it */
strncpy ( invite , p - > fullcontact , sizeof ( invite ) - 1 ) ;
2004-10-14 18:29:47 +00:00
/* Otherwise, use the username while waiting for registration */
2004-08-31 16:49:20 +00:00
} else if ( ! ast_strlen_zero ( p - > username ) ) {
2002-09-12 17:13:17 +00:00
if ( ntohs ( p - > sa . sin_port ) ! = DEFAULT_SIP_PORT ) {
2003-04-18 15:47:33 +00:00
snprintf ( invite , sizeof ( invite ) , " sip:%s@%s:%d " , p - > username , p - > tohost , ntohs ( p - > sa . sin_port ) ) ;
2002-09-12 17:13:17 +00:00
} else {
2003-04-18 15:47:33 +00:00
snprintf ( invite , sizeof ( invite ) , " sip:%s@%s " , p - > username , p - > tohost ) ;
2002-09-12 17:13:17 +00:00
}
} else if ( ntohs ( p - > sa . sin_port ) ! = DEFAULT_SIP_PORT ) {
2003-04-18 15:47:33 +00:00
snprintf ( invite , sizeof ( invite ) , " sip:%s:%d " , p - > tohost , ntohs ( p - > sa . sin_port ) ) ;
2002-09-12 17:13:17 +00:00
} else {
2003-04-18 15:47:33 +00:00
snprintf ( invite , sizeof ( invite ) , " sip:%s " , p - > tohost ) ;
2002-09-12 17:13:17 +00:00
}
2003-04-12 15:46:22 +00:00
strncpy ( p - > uri , invite , sizeof ( p - > uri ) - 1 ) ;
2003-02-07 04:07:10 +00:00
/* If there is a VXML URL append it to the SIP URL */
if ( vxml_url )
{
2004-08-31 16:33:00 +00:00
snprintf ( to , sizeof ( to ) , " <%s>;%s " , invite , vxml_url ) ;
2003-02-07 04:07:10 +00:00
}
else
{
2004-08-31 16:33:00 +00:00
snprintf ( to , sizeof ( to ) , " <%s> " , invite ) ;
2003-02-07 04:07:10 +00:00
}
2003-02-12 13:59:15 +00:00
memset ( req , 0 , sizeof ( struct sip_request ) ) ;
init_req ( req , cmd , invite ) ;
2003-02-07 04:07:10 +00:00
snprintf ( tmp , sizeof ( tmp ) , " %d %s " , + + p - > ocseq , cmd ) ;
2003-02-12 13:59:15 +00:00
add_header ( req , " Via " , p - > via ) ;
2003-04-05 22:29:46 +00:00
/* SLD: FIXME?: do Route: here too? I think not cos this is the first request.
* OTOH , then we won ' t have anything in p - > route anyway */
2003-02-12 13:59:15 +00:00
add_header ( req , " From " , from ) ;
2003-04-08 14:49:12 +00:00
strncpy ( p - > exten , l , sizeof ( p - > exten ) - 1 ) ;
build_contact ( p ) ;
2003-02-12 13:59:15 +00:00
add_header ( req , " To " , to ) ;
2003-04-11 04:31:33 +00:00
add_header ( req , " Contact " , p - > our_contact ) ;
2003-02-12 13:59:15 +00:00
add_header ( req , " Call-ID " , p - > callid ) ;
add_header ( req , " CSeq " , tmp ) ;
2004-07-08 11:05:03 +00:00
add_header ( req , " User-Agent " , default_useragent ) ;
2003-02-12 13:59:15 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- transmit_invite: Build REFER/INVITE/OPTIONS message and trasmit it ---*/
2004-06-25 03:59:07 +00:00
static int transmit_invite ( struct sip_pvt * p , char * cmd , int sdp , char * auth , char * authheader , char * vxml_url , char * distinctive_ring , char * osptoken , int init )
2003-02-12 13:59:15 +00:00
{
struct sip_request req ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-08-21 22:20:27 +00:00
2004-04-06 14:02:47 +00:00
if ( init ) {
/* Bump branch even on initial requests */
p - > branch ^ = rand ( ) ;
2004-08-27 02:45:35 +00:00
if ( p - > nat & SIP_NAT_RFC3581 )
2004-06-29 12:56:46 +00:00
snprintf ( p - > via , sizeof ( p - > via ) , " SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) , ourport , p - > branch ) ;
2004-06-28 23:24:36 +00:00
else /* Work around buggy UNIDEN UIP200 firmware */
2004-06-29 12:56:46 +00:00
snprintf ( p - > via , sizeof ( p - > via ) , " SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) , ourport , p - > branch ) ;
2003-08-21 22:20:27 +00:00
initreqprep ( & req , p , cmd , vxml_url ) ;
2004-04-06 14:02:47 +00:00
} else
2004-03-28 04:05:58 +00:00
reqprep ( & req , p , cmd , 0 , 1 ) ;
2003-08-21 22:20:27 +00:00
2003-02-07 04:07:10 +00:00
if ( auth )
2003-11-10 04:22:33 +00:00
add_header ( & req , authheader , auth ) ;
2003-12-19 17:42:50 +00:00
append_date ( & req ) ;
2003-11-25 21:19:25 +00:00
if ( ! strcasecmp ( cmd , " REFER " ) ) {
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( p - > refer_to ) )
2003-11-25 21:19:25 +00:00
add_header ( & req , " Refer-To " , p - > refer_to ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( p - > referred_by ) )
2003-11-25 21:19:25 +00:00
add_header ( & req , " Referred-By " , p - > referred_by ) ;
}
2004-06-25 03:59:07 +00:00
# ifdef OSP_SUPPORT
if ( osptoken & & ! ast_strlen_zero ( osptoken ) ) {
add_header ( & req , " P-OSP-Auth-Token " , osptoken ) ;
}
# endif
2004-05-13 19:54:42 +00:00
if ( distinctive_ring & & ! ast_strlen_zero ( distinctive_ring ) )
2003-06-18 22:34:55 +00:00
{
add_header ( & req , " Alert-info " , distinctive_ring ) ;
}
2003-08-12 16:48:16 +00:00
add_header ( & req , " Allow " , ALLOWED_METHODS ) ;
2003-02-07 04:07:10 +00:00
if ( sdp ) {
2004-08-26 04:56:26 +00:00
ast_rtp_offered_from_local ( p - > rtp , 1 ) ;
2004-05-27 05:06:32 +00:00
add_sdp ( & req , p ) ;
2003-02-07 04:07:10 +00:00
} else {
add_header ( & req , " Content-Length " , " 0 " ) ;
add_blank_header ( & req ) ;
}
2003-06-18 22:34:55 +00:00
2003-02-07 04:07:10 +00:00
if ( ! p - > initreq . headers ) {
/* Use this as the basis */
copy_request ( & p - > initreq , & req ) ;
parse ( & p - > initreq ) ;
2004-05-01 21:25:31 +00:00
if ( sip_debug_test_pvt ( p ) )
ast_verbose ( " %d headers, %d lines \n " , p - > initreq . headers , p - > initreq . lines ) ;
2003-05-02 02:18:41 +00:00
determine_firstline_parts ( & p - > initreq ) ;
2003-02-07 04:07:10 +00:00
}
p - > lastinvite = p - > ocseq ;
2004-03-24 21:21:59 +00:00
return send_request ( p , & req , init ? 2 : 1 , p - > ocseq ) ;
2003-02-07 04:07:10 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- transmit_state_notify: Used in the SUBSCRIBE notification subsystem ----*/
2003-04-06 18:19:51 +00:00
static int transmit_state_notify ( struct sip_pvt * p , int state , int full )
{
2004-05-07 18:57:17 +00:00
char tmp [ 4000 ] ;
2004-07-08 11:05:03 +00:00
int maxbytes = 0 ;
int bytes = 0 ;
2003-04-06 18:19:51 +00:00
char from [ 256 ] , to [ 256 ] ;
char * t , * c , * a ;
char * mfrom , * mto ;
struct sip_request req ;
char clen [ 20 ] ;
2004-07-08 11:05:03 +00:00
memset ( from , 0 , sizeof ( from ) ) ;
memset ( to , 0 , sizeof ( to ) ) ;
2003-04-06 18:19:51 +00:00
strncpy ( from , get_header ( & p - > initreq , " From " ) , sizeof ( from ) - 1 ) ;
c = ditch_braces ( from ) ;
if ( strncmp ( c , " sip: " , 4 ) ) {
ast_log ( LOG_WARNING , " Huh? Not a SIP header (%s)? \n " , c ) ;
return - 1 ;
}
if ( ( a = strchr ( c , ' ; ' ) ) ) {
* a = ' \0 ' ;
}
mfrom = c ;
2004-07-08 11:05:03 +00:00
2004-03-28 04:05:58 +00:00
reqprep ( & req , p , " NOTIFY " , 0 , 1 ) ;
2003-04-06 18:19:51 +00:00
if ( p - > subscribed = = 1 ) {
2004-07-08 11:05:03 +00:00
strncpy ( to , get_header ( & p - > initreq , " To " ) , sizeof ( to ) - 1 ) ;
2003-04-06 18:19:51 +00:00
2004-07-08 11:05:03 +00:00
c = ditch_braces ( to ) ;
if ( strncmp ( c , " sip: " , 4 ) ) {
ast_log ( LOG_WARNING , " Huh? Not a SIP header (%s)? \n " , c ) ;
return - 1 ;
}
if ( ( a = strchr ( c , ' ; ' ) ) ) {
* a = ' \0 ' ;
}
mto = c ;
add_header ( & req , " Content-Type " , " application/xpidf+xml " ) ;
if ( ( state = = AST_EXTENSION_UNAVAILABLE ) | | ( state = = AST_EXTENSION_BUSY ) )
state = 2 ;
else if ( state = = AST_EXTENSION_INUSE )
state = 1 ;
else
state = 0 ;
t = tmp ;
maxbytes = sizeof ( tmp ) ;
bytes = snprintf ( t , maxbytes , " <?xml version= \" 1.0 \" ?> \n " ) ;
t + = bytes ;
maxbytes - = bytes ;
bytes = snprintf ( t , maxbytes , " <!DOCTYPE presence PUBLIC \" -//IETF//DTD RFCxxxx XPIDF 1.0//EN \" \" xpidf.dtd \" > \n " ) ;
t + = bytes ;
maxbytes - = bytes ;
bytes = snprintf ( t , maxbytes , " <presence> \n " ) ;
t + = bytes ;
maxbytes - = bytes ;
bytes = snprintf ( t , maxbytes , " <presentity uri= \" %s;method=SUBSCRIBE \" /> \n " , mfrom ) ;
t + = bytes ;
maxbytes - = bytes ;
bytes = snprintf ( t , maxbytes , " <atom id= \" %s \" > \n " , p - > exten ) ;
t + = bytes ;
maxbytes - = bytes ;
bytes = snprintf ( t , maxbytes , " <address uri= \" %s;user=ip \" priority= \" 0,800000 \" > \n " , mto ) ;
t + = bytes ;
maxbytes - = bytes ;
bytes = snprintf ( t , maxbytes , " <status status= \" %s \" /> \n " , ! state ? " open " : ( state = = 1 ) ? " inuse " : " closed " ) ;
t + = bytes ;
maxbytes - = bytes ;
bytes = snprintf ( t , maxbytes , " <msnsubstatus substatus= \" %s \" /> \n " , ! state ? " online " : ( state = = 1 ) ? " onthephone " : " offline " ) ;
t + = bytes ;
maxbytes - = bytes ;
bytes = snprintf ( t , maxbytes , " </address> \n </atom> \n </presence> \n " ) ;
2003-04-06 18:19:51 +00:00
} else {
2004-07-08 11:05:03 +00:00
add_header ( & req , " Event " , " dialog " ) ;
add_header ( & req , " Content-Type " , " application/dialog-info+xml " ) ;
t = tmp ;
maxbytes = sizeof ( tmp ) ;
bytes = snprintf ( t , maxbytes , " <?xml version= \" 1.0 \" ?> \n " ) ;
t + = bytes ;
maxbytes - = bytes ;
bytes = snprintf ( t , maxbytes , " <dialog-info xmlns= \" urn:ietf:params:xml:ns:dialog-info \" version= \" %d \" state= \" %s \" entity= \" %s \" > \n " , p - > dialogver + + , full ? " full " : " partial " , mfrom ) ;
t + = bytes ;
maxbytes - = bytes ;
bytes = snprintf ( t , maxbytes , " <dialog id= \" %s \" > \n " , p - > exten ) ;
t + = bytes ;
maxbytes - = bytes ;
bytes = snprintf ( t , maxbytes , " <state>%s</state> \n " , state ? " confirmed " : " terminated " ) ;
t + = bytes ;
maxbytes - = bytes ;
bytes = snprintf ( t , maxbytes , " </dialog> \n </dialog-info> \n " ) ;
2003-04-06 18:19:51 +00:00
}
2004-01-11 19:24:15 +00:00
if ( t > tmp + sizeof ( tmp ) )
ast_log ( LOG_WARNING , " Buffer overflow detected!! (Please file a bug report) \n " ) ;
2003-04-06 18:19:51 +00:00
2004-06-13 21:25:10 +00:00
snprintf ( clen , sizeof ( clen ) , " %d " , ( int ) strlen ( tmp ) ) ;
2003-04-06 18:19:51 +00:00
add_header ( & req , " Content-Length " , clen ) ;
add_line ( & req , tmp ) ;
return send_request ( p , & req , 1 , p - > ocseq ) ;
}
2004-08-17 14:20:43 +00:00
/*--- transmit_notify_with_mwi: Notify user of messages waiting in voicemail ---*/
2004-05-13 19:54:42 +00:00
/* Notification only works for registred peers with mailbox= definitions
* in sip . conf
* We use the SIP Event package message - summary
* MIME type defaults to " application/simple-message-summary " ;
*/
2004-08-17 14:20:43 +00:00
static int transmit_notify_with_mwi ( struct sip_pvt * p , int newmsgs , int oldmsgs )
2003-02-12 13:59:15 +00:00
{
struct sip_request req ;
char tmp [ 256 ] ;
2003-03-26 00:15:11 +00:00
char tmp2 [ 256 ] ;
2003-02-12 13:59:15 +00:00
char clen [ 20 ] ;
2004-10-07 15:47:39 +00:00
initreqprep ( & req , p , " NOTIFY " , NULL ) ;
2003-02-12 13:59:15 +00:00
add_header ( & req , " Event " , " message-summary " ) ;
2003-04-30 18:48:30 +00:00
add_header ( & req , " Content-Type " , notifymime ) ;
2003-02-12 13:59:15 +00:00
2004-10-06 04:30:16 +00:00
snprintf ( tmp , sizeof ( tmp ) , " Messages-Waiting: %s \r \n " , newmsgs ? " yes " : " no " ) ;
snprintf ( tmp2 , sizeof ( tmp2 ) , " Voicemail: %d/%d \r \n " , newmsgs , oldmsgs ) ;
2004-06-13 21:25:10 +00:00
snprintf ( clen , sizeof ( clen ) , " %d " , ( int ) ( strlen ( tmp ) + strlen ( tmp2 ) ) ) ;
2003-02-12 13:59:15 +00:00
add_header ( & req , " Content-Length " , clen ) ;
add_line ( & req , tmp ) ;
2003-03-26 00:15:11 +00:00
add_line ( & req , tmp2 ) ;
2003-02-12 13:59:15 +00:00
if ( ! p - > initreq . headers ) {
/* Use this as the basis */
copy_request ( & p - > initreq , & req ) ;
parse ( & p - > initreq ) ;
2004-05-01 21:25:31 +00:00
if ( sip_debug_test_pvt ( p ) )
ast_verbose ( " %d headers, %d lines \n " , p - > initreq . headers , p - > initreq . lines ) ;
2003-05-02 02:18:41 +00:00
determine_firstline_parts ( & p - > initreq ) ;
2003-02-12 13:59:15 +00:00
}
2003-04-07 02:04:56 +00:00
return send_request ( p , & req , 1 , p - > ocseq ) ;
2003-02-12 13:59:15 +00:00
}
2004-08-17 14:20:43 +00:00
/*--- transmit_notify_with_sipfrag: Notify a transferring party of the status of trasnfer ---*/
/* Apparently the draft SIP REFER structure was too simple, so it was decided that the
* status of transfers also needed to be sent via NOTIFY instead of just the 202 Accepted
* that had worked heretofore .
*/
static int transmit_notify_with_sipfrag ( struct sip_pvt * p , int cseq )
{
struct sip_request req ;
char tmp [ 256 ] ;
char clen [ 20 ] ;
2004-10-07 15:47:39 +00:00
reqprep ( & req , p , " NOTIFY " , 0 , 1 ) ;
2004-08-17 14:20:43 +00:00
snprintf ( tmp , sizeof ( tmp ) , " refer;id=%d " , cseq ) ;
add_header ( & req , " Event " , tmp ) ;
add_header ( & req , " Subscription-state " , " terminated;reason=noresource " ) ;
add_header ( & req , " Content-Type " , " message/sipfrag;version=2.0 " ) ;
strncpy ( tmp , " SIP/2.0 200 OK " , sizeof ( tmp ) - 1 ) ;
snprintf ( clen , sizeof ( clen ) , " %d " , ( int ) ( strlen ( tmp ) ) ) ;
add_header ( & req , " Content-Length " , clen ) ;
add_line ( & req , tmp ) ;
if ( ! p - > initreq . headers ) {
/* Use this as the basis */
copy_request ( & p - > initreq , & req ) ;
parse ( & p - > initreq ) ;
if ( sip_debug_test_pvt ( p ) )
ast_verbose ( " %d headers, %d lines \n " , p - > initreq . headers , p - > initreq . lines ) ;
determine_firstline_parts ( & p - > initreq ) ;
}
return send_request ( p , & req , 1 , p - > ocseq ) ;
}
2004-09-16 18:45:34 +00:00
static char * regstate2str ( int regstate )
{
switch ( regstate ) {
case REG_STATE_UNREGISTERED :
return " Unregistered " ;
case REG_STATE_REGSENT :
return " Request Sent " ;
case REG_STATE_AUTHSENT :
return " Auth. Sent " ;
case REG_STATE_REGISTERED :
return " Registered " ;
case REG_STATE_REJECTED :
return " Rejected " ;
case REG_STATE_TIMEOUT :
return " Timeout " ;
case REG_STATE_NOAUTH :
return " No Authentication " ;
default :
return " Unknown " ;
}
}
2003-08-24 22:33:43 +00:00
static int transmit_register ( struct sip_registry * r , char * cmd , char * auth , char * authheader ) ;
2003-02-07 04:07:10 +00:00
2004-05-13 19:54:42 +00:00
/*--- sip_reregister: Update registration with SIP Proxy---*/
2003-02-07 04:07:10 +00:00
static int sip_reregister ( void * data )
{
/* if we are here, we know that we need to reregister. */
struct sip_registry * r = ( struct sip_registry * ) data ;
2004-02-02 23:21:36 +00:00
ast_mutex_lock ( & regl . lock ) ;
2003-04-09 19:35:24 +00:00
r - > expire = - 1 ;
2004-02-02 23:21:36 +00:00
__sip_do_register ( r ) ;
ast_mutex_unlock ( & regl . lock ) ;
2003-04-09 19:35:24 +00:00
return 0 ;
2003-02-07 04:07:10 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- __sip_do_register: Register with SIP proxy ---*/
2004-02-02 23:21:36 +00:00
static int __sip_do_register ( struct sip_registry * r )
2003-02-07 04:07:10 +00:00
{
int res ;
2003-08-24 22:33:43 +00:00
res = transmit_register ( r , " REGISTER " , NULL , NULL ) ;
2003-02-07 04:07:10 +00:00
return res ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_reg_timeout: Registration timeout, register again */
2003-02-07 04:07:10 +00:00
static int sip_reg_timeout ( void * data )
{
/* if we are here, our registration timed out, so we'll just do it over */
struct sip_registry * r = data ;
2003-04-09 19:35:24 +00:00
struct sip_pvt * p ;
2003-02-07 04:07:10 +00:00
int res ;
2004-02-02 23:21:36 +00:00
ast_mutex_lock ( & regl . lock ) ;
2004-07-13 02:20:44 +00:00
ast_log ( LOG_NOTICE , " Registration for '%s@%s' timed out, trying again \n " , r - > username , r - > hostname ) ;
2003-04-09 19:35:24 +00:00
if ( r - > call ) {
/* Unlink us, destroy old call. Locking is not relevent here because all this happens
in the single SIP manager thread . */
p = r - > call ;
p - > registry = NULL ;
r - > call = NULL ;
p - > needdestroy = 1 ;
2004-09-28 12:55:08 +00:00
/* Pretend to ACK anything just in case */
__sip_pretend_ack ( p ) ;
2003-04-09 19:35:24 +00:00
}
2003-02-07 04:07:10 +00:00
r - > regstate = REG_STATE_UNREGISTERED ;
2004-09-16 16:18:53 +00:00
manager_event ( EVENT_FLAG_SYSTEM , " Registry " , " Channel: SIP \r \n Domain: %s \r \n Status: %s \r \n " , r - > hostname , regstate2str ( r - > regstate ) ) ;
2003-04-09 19:35:24 +00:00
r - > timeout = - 1 ;
2003-08-24 22:33:43 +00:00
res = transmit_register ( r , " REGISTER " , NULL , NULL ) ;
2004-02-02 23:21:36 +00:00
ast_mutex_unlock ( & regl . lock ) ;
2003-04-09 19:35:24 +00:00
return 0 ;
2003-02-07 04:07:10 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- transmit_register: Transmit register to SIP proxy ---*/
2003-08-24 22:33:43 +00:00
static int transmit_register ( struct sip_registry * r , char * cmd , char * auth , char * authheader )
2003-02-07 04:07:10 +00:00
{
struct sip_request req ;
char from [ 256 ] ;
char to [ 256 ] ;
char tmp [ 80 ] ;
char via [ 80 ] ;
char addr [ 80 ] ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-02-07 04:07:10 +00:00
struct sip_pvt * p ;
2004-01-13 01:31:42 +00:00
2003-02-07 04:07:10 +00:00
/* exit if we are already in process with this registrar ?*/
2003-04-09 21:13:11 +00:00
if ( r = = NULL | | ( ( auth = = NULL ) & & ( r - > regstate = = REG_STATE_REGSENT | | r - > regstate = = REG_STATE_AUTHSENT ) ) ) {
2003-02-07 04:07:10 +00:00
ast_log ( LOG_NOTICE , " Strange, trying to register when registration already pending \n " ) ;
return 0 ;
}
2003-04-09 19:35:24 +00:00
if ( r - > call ) {
2003-04-09 21:13:11 +00:00
if ( ! auth ) {
ast_log ( LOG_WARNING , " Already have a call?? \n " ) ;
return 0 ;
} else
p = r - > call ;
} else {
2003-04-20 22:19:22 +00:00
if ( ! r - > callid_valid ) {
2004-09-13 12:32:04 +00:00
build_callid ( r - > callid , sizeof ( r - > callid ) , __ourip , default_fromdomain ) ;
2003-04-20 22:19:22 +00:00
r - > callid_valid = 1 ;
}
2004-07-13 02:20:44 +00:00
p = sip_alloc ( r - > callid , NULL , 0 ) ;
2003-04-09 21:13:11 +00:00
if ( ! p ) {
ast_log ( LOG_WARNING , " Unable to allocate registration call \n " ) ;
return 0 ;
}
2004-07-13 02:20:44 +00:00
if ( create_addr ( p , r - > hostname ) ) {
sip_destroy ( p ) ;
return 0 ;
}
2004-09-13 12:32:04 +00:00
/* Copy back Call-ID in case create_addr changed it */
strncpy ( r - > callid , p - > callid , sizeof ( r - > callid ) - 1 ) ;
2004-07-13 02:20:44 +00:00
if ( r - > portno )
2004-07-15 22:14:27 +00:00
p - > sa . sin_port = htons ( r - > portno ) ;
2003-04-09 21:13:11 +00:00
p - > outgoing = 1 ;
r - > call = p ;
p - > registry = r ;
2004-07-13 02:20:44 +00:00
if ( ! ast_strlen_zero ( r - > secret ) )
strncpy ( p - > peersecret , r - > secret , sizeof ( p - > peersecret ) - 1 ) ;
if ( ! ast_strlen_zero ( r - > md5secret ) )
strncpy ( p - > peermd5secret , r - > md5secret , sizeof ( p - > peermd5secret ) - 1 ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( r - > authuser ) ) {
2003-04-12 17:06:14 +00:00
strncpy ( p - > peername , r - > authuser , sizeof ( p - > peername ) - 1 ) ;
2004-05-02 16:30:05 +00:00
strncpy ( p - > authname , r - > authuser , sizeof ( p - > authname ) - 1 ) ;
} else {
2004-07-13 02:20:44 +00:00
if ( ! ast_strlen_zero ( r - > username ) ) {
strncpy ( p - > peername , r - > username , sizeof ( p - > peername ) - 1 ) ;
strncpy ( p - > authname , r - > username , sizeof ( p - > authname ) - 1 ) ;
}
2004-05-02 16:30:05 +00:00
}
2004-07-13 02:20:44 +00:00
if ( ! ast_strlen_zero ( r - > username ) )
strncpy ( p - > username , r - > username , sizeof ( p - > username ) - 1 ) ;
2003-04-09 21:13:11 +00:00
strncpy ( p - > exten , r - > contact , sizeof ( p - > exten ) - 1 ) ;
2004-01-13 01:31:42 +00:00
/*
check which address we should use in our contact header
based on whether the remote host is on the external or
internal network so we can register through nat
*/
2004-07-13 02:20:44 +00:00
if ( ast_sip_ouraddrfor ( & p - > sa . sin_addr , & p - > ourip ) )
memcpy ( & p - > ourip , & bindaddr . sin_addr , sizeof ( p - > ourip ) ) ;
2003-04-09 21:13:11 +00:00
build_contact ( p ) ;
2003-02-07 04:07:10 +00:00
}
/* set up a timeout */
2003-04-09 19:35:24 +00:00
if ( auth = = NULL ) {
if ( r - > timeout > - 1 ) {
ast_log ( LOG_WARNING , " Still have a timeout, %d \n " , r - > timeout ) ;
ast_sched_del ( sched , r - > timeout ) ;
}
2003-04-12 17:06:14 +00:00
r - > timeout = ast_sched_add ( sched , 20 * 1000 , sip_reg_timeout , r ) ;
2003-04-09 19:35:24 +00:00
ast_log ( LOG_DEBUG , " Scheduled a timeout # %d \n " , r - > timeout ) ;
2003-02-07 04:07:10 +00:00
}
2003-06-15 22:53:05 +00:00
if ( strchr ( r - > username , ' @ ' ) ) {
snprintf ( from , sizeof ( from ) , " <sip:%s>;tag=as%08x " , r - > username , p - > tag ) ;
2004-09-15 19:27:23 +00:00
if ( ! ast_strlen_zero ( p - > theirtag ) )
snprintf ( to , sizeof ( to ) , " <sip:%s>;tag=%s " , r - > username , p - > theirtag ) ;
else
snprintf ( to , sizeof ( to ) , " <sip:%s> " , r - > username ) ;
2003-06-15 22:53:05 +00:00
} else {
2004-07-13 02:44:11 +00:00
snprintf ( from , sizeof ( from ) , " <sip:%s@%s>;tag=as%08x " , r - > username , p - > tohost , p - > tag ) ;
2004-09-15 19:27:23 +00:00
if ( ! ast_strlen_zero ( p - > theirtag ) )
snprintf ( to , sizeof ( to ) , " <sip:%s@%s>;tag=%s " , r - > username , p - > tohost , p - > theirtag ) ;
else
snprintf ( to , sizeof ( to ) , " <sip:%s@%s> " , r - > username , p - > tohost ) ;
2003-06-15 22:53:05 +00:00
}
2003-02-07 04:07:10 +00:00
2003-04-12 15:46:22 +00:00
snprintf ( addr , sizeof ( addr ) , " sip:%s " , r - > hostname ) ;
strncpy ( p - > uri , addr , sizeof ( p - > uri ) - 1 ) ;
2002-06-28 20:34:46 +00:00
2004-03-29 08:20:35 +00:00
p - > branch ^ = rand ( ) ;
2002-09-12 17:13:17 +00:00
memset ( & req , 0 , sizeof ( req ) ) ;
2003-02-07 04:07:10 +00:00
init_req ( & req , cmd , addr ) ;
2002-06-28 20:34:46 +00:00
2003-04-21 16:49:41 +00:00
snprintf ( tmp , sizeof ( tmp ) , " %u %s " , + + r - > ocseq , cmd ) ;
p - > ocseq = r - > ocseq ;
2003-02-07 04:07:10 +00:00
2003-05-04 05:52:52 +00:00
/* z9hG4bK is a magic cookie. See RFC 3261 section 8.1.1.7 */
2004-08-27 02:45:35 +00:00
if ( p - > nat & SIP_NAT_RFC3581 )
2004-06-29 12:56:46 +00:00
snprintf ( via , sizeof ( via ) , " SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) , ourport , p - > branch ) ;
2004-06-28 23:24:36 +00:00
else /* Work around buggy UNIDEN UIP200 firmware */
2004-06-29 12:56:46 +00:00
snprintf ( via , sizeof ( via ) , " SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) , ourport , p - > branch ) ;
2002-09-12 17:13:17 +00:00
add_header ( & req , " Via " , via ) ;
2002-06-28 20:34:46 +00:00
add_header ( & req , " From " , from ) ;
2002-09-12 17:13:17 +00:00
add_header ( & req , " To " , to ) ;
2002-06-28 20:34:46 +00:00
add_header ( & req , " Call-ID " , p - > callid ) ;
2002-09-12 17:13:17 +00:00
add_header ( & req , " CSeq " , tmp ) ;
2004-07-08 11:05:03 +00:00
add_header ( & req , " User-Agent " , default_useragent ) ;
2003-02-07 04:07:10 +00:00
if ( auth )
2003-08-24 22:33:43 +00:00
add_header ( & req , authheader , auth ) ;
2003-02-07 04:07:10 +00:00
2003-04-08 03:24:12 +00:00
snprintf ( tmp , sizeof ( tmp ) , " %d " , default_expiry ) ;
2003-02-12 13:59:15 +00:00
add_header ( & req , " Expires " , tmp ) ;
2003-04-09 21:45:32 +00:00
add_header ( & req , " Contact " , p - > our_contact ) ;
2003-02-07 04:07:10 +00:00
add_header ( & req , " Event " , " registration " ) ;
2004-03-15 02:06:47 +00:00
add_header ( & req , " Content-Length " , " 0 " ) ;
2003-04-06 02:51:10 +00:00
add_blank_header ( & req ) ;
2002-06-28 20:34:46 +00:00
copy_request ( & p - > initreq , & req ) ;
2003-04-09 21:52:56 +00:00
parse ( & p - > initreq ) ;
2004-05-01 21:25:31 +00:00
if ( sip_debug_test_pvt ( p ) )
ast_verbose ( " %d headers, %d lines \n " , p - > initreq . headers , p - > initreq . lines ) ;
2003-05-02 02:18:41 +00:00
determine_firstline_parts ( & p - > initreq ) ;
2003-02-07 04:07:10 +00:00
r - > regstate = auth ? REG_STATE_AUTHSENT : REG_STATE_REGSENT ;
2004-03-24 21:21:59 +00:00
return send_request ( p , & req , 2 , p - > ocseq ) ;
2003-02-07 04:07:10 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- transmit_message_with_text: Transmit text with SIP MESSAGE method ---*/
2003-02-07 04:07:10 +00:00
static int transmit_message_with_text ( struct sip_pvt * p , char * text )
{
struct sip_request req ;
2004-03-28 04:05:58 +00:00
reqprep ( & req , p , " MESSAGE " , 0 , 1 ) ;
2003-02-07 04:07:10 +00:00
add_text ( & req , text ) ;
2003-03-28 06:13:04 +00:00
return send_request ( p , & req , 1 , p - > ocseq ) ;
2002-06-28 20:34:46 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- transmit_refer: Transmit SIP REFER message ---*/
2003-05-14 05:52:59 +00:00
static int transmit_refer ( struct sip_pvt * p , char * dest )
{
struct sip_request req ;
2003-05-15 22:39:01 +00:00
char from [ 256 ] ;
char * of , * c ;
char referto [ 256 ] ;
if ( p - > outgoing )
of = get_header ( & p - > initreq , " To " ) ;
else
of = get_header ( & p - > initreq , " From " ) ;
strncpy ( from , of , sizeof ( from ) - 1 ) ;
of = ditch_braces ( from ) ;
2003-06-24 12:51:28 +00:00
strncpy ( p - > from , of , sizeof ( p - > from ) - 1 ) ;
2003-05-15 22:39:01 +00:00
if ( strncmp ( of , " sip: " , 4 ) ) {
ast_log ( LOG_NOTICE , " From address missing 'sip:', using it anyway \n " ) ;
} else
of + = 4 ;
/* Get just the username part */
if ( ( c = strchr ( of , ' @ ' ) ) ) {
* c = ' \0 ' ;
c + + ;
}
if ( c ) {
snprintf ( referto , sizeof ( referto ) , " <sip:%s@%s> " , dest , c ) ;
} else {
snprintf ( referto , sizeof ( referto ) , " <sip:%s> " , dest ) ;
}
2003-11-25 21:19:25 +00:00
/* save in case we get 407 challenge */
strncpy ( p - > refer_to , referto , sizeof ( p - > refer_to ) - 1 ) ;
strncpy ( p - > referred_by , p - > our_contact , sizeof ( p - > referred_by ) - 1 ) ;
2004-03-28 04:05:58 +00:00
reqprep ( & req , p , " REFER " , 0 , 1 ) ;
2003-05-15 22:39:01 +00:00
add_header ( & req , " Refer-To " , referto ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( p - > our_contact ) )
2003-11-25 21:19:25 +00:00
add_header ( & req , " Referred-By " , p - > our_contact ) ;
2004-02-07 07:13:33 +00:00
add_blank_header ( & req ) ;
2003-05-14 05:52:59 +00:00
return send_request ( p , & req , 1 , p - > ocseq ) ;
}
2004-05-13 19:54:42 +00:00
/*--- transmit_info_with_digit: Send SIP INFO dtmf message, see Cisco documentation on cisco.co
m - - - */
2003-03-12 06:00:18 +00:00
static int transmit_info_with_digit ( struct sip_pvt * p , char digit )
{
struct sip_request req ;
2004-03-28 04:05:58 +00:00
reqprep ( & req , p , " INFO " , 0 , 1 ) ;
2003-03-12 06:00:18 +00:00
add_digit ( & req , digit ) ;
2003-03-28 06:13:04 +00:00
return send_request ( p , & req , 1 , p - > ocseq ) ;
2003-03-12 06:00:18 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- transmit_request: transmit generic SIP request ---*/
2004-03-28 04:05:58 +00:00
static int transmit_request ( struct sip_pvt * p , char * msg , int seqno , int reliable , int newbranch )
2002-06-28 20:34:46 +00:00
{
struct sip_request resp ;
2004-03-28 04:05:58 +00:00
reqprep ( & resp , p , msg , seqno , newbranch ) ;
2002-06-28 20:34:46 +00:00
add_header ( & resp , " Content-Length " , " 0 " ) ;
add_blank_header ( & resp ) ;
2003-04-07 06:12:19 +00:00
return send_request ( p , & resp , reliable , seqno ? seqno : p - > ocseq ) ;
2002-06-28 20:34:46 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- transmit_request_with_auth: Transmit SIP request, auth added ---*/
2004-03-28 04:05:58 +00:00
static int transmit_request_with_auth ( struct sip_pvt * p , char * msg , int seqno , int reliable , int newbranch )
2003-04-07 03:46:20 +00:00
{
struct sip_request resp ;
2004-03-28 04:05:58 +00:00
reqprep ( & resp , p , msg , seqno , newbranch ) ;
2003-04-07 03:46:20 +00:00
if ( * p - > realm )
{
2004-04-21 21:55:40 +00:00
char digest [ 1024 ] ;
2003-04-07 03:46:20 +00:00
memset ( digest , 0 , sizeof ( digest ) ) ;
build_reply_digest ( p , msg , digest , sizeof ( digest ) ) ;
add_header ( & resp , " Proxy-Authorization " , digest ) ;
}
add_header ( & resp , " Content-Length " , " 0 " ) ;
add_blank_header ( & resp ) ;
2003-04-07 06:12:19 +00:00
return send_request ( p , & resp , reliable , seqno ? seqno : p - > ocseq ) ;
2003-04-07 03:46:20 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- expire_register: Expire registration of SIP peer ---*/
2002-06-28 20:34:46 +00:00
static int expire_register ( void * data )
{
struct sip_peer * p = data ;
memset ( & p - > addr , 0 , sizeof ( p - > addr ) ) ;
2003-08-24 22:35:06 +00:00
ast_db_del ( " SIP/Registry " , p - > name ) ;
2004-09-16 16:18:53 +00:00
manager_event ( EVENT_FLAG_SYSTEM , " PeerStatus " , " Peer: SIP/%s \r \n PeerStatus: Unregistered \r \n Cause: Expired \r \n " , p - > name ) ;
2004-09-07 23:45:34 +00:00
register_peer_exten ( p , 0 ) ;
2002-06-28 20:34:46 +00:00
p - > expire = - 1 ;
2003-04-06 18:19:51 +00:00
ast_device_state_changed ( " SIP/%s " , p - > name ) ;
2003-11-11 20:46:41 +00:00
if ( p - > selfdestruct ) {
p - > delme = 1 ;
prune_peers ( ) ;
}
2002-06-28 20:34:46 +00:00
return 0 ;
}
2003-02-07 04:07:10 +00:00
static int sip_poke_peer ( struct sip_peer * peer ) ;
2004-09-11 13:50:26 +00:00
static int sip_poke_peer_s ( void * data )
{
struct sip_peer * peer = data ;
peer - > pokeexpire = - 1 ;
sip_poke_peer ( peer ) ;
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- reg_source_db: Save registration in Asterisk DB ---*/
2003-08-24 22:35:06 +00:00
static void reg_source_db ( struct sip_peer * p )
{
2004-08-31 17:17:00 +00:00
char data [ 256 ] ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-08-24 22:35:06 +00:00
struct in_addr in ;
2004-08-30 05:21:34 +00:00
char * c , * d , * u , * e ;
2003-08-24 22:35:06 +00:00
int expiry ;
if ( ! ast_db_get ( " SIP/Registry " , p - > name , data , sizeof ( data ) ) ) {
c = strchr ( data , ' : ' ) ;
if ( c ) {
* c = ' \0 ' ;
c + + ;
if ( inet_aton ( data , & in ) ) {
d = strchr ( c , ' : ' ) ;
if ( d ) {
* d = ' \0 ' ;
d + + ;
2004-01-11 21:37:50 +00:00
u = strchr ( d , ' : ' ) ;
if ( u ) {
* u = ' \0 ' ;
u + + ;
2004-08-30 05:21:34 +00:00
e = strchr ( u , ' : ' ) ;
if ( e ) {
* e = ' \0 ' ;
e + + ;
2004-08-31 16:49:20 +00:00
strncpy ( p - > fullcontact , e , sizeof ( p - > fullcontact ) - 1 ) ;
2004-08-30 05:21:34 +00:00
}
2004-07-16 04:40:54 +00:00
strncpy ( p - > username , u , sizeof ( p - > username ) - 1 ) ;
2004-08-30 05:21:34 +00:00
2004-01-11 21:37:50 +00:00
}
ast_verbose ( VERBOSE_PREFIX_3 " SIP Seeding '%s' at %s@%s:%d for %d \n " , p - > name ,
2004-06-29 12:56:46 +00:00
p - > username , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , in ) , atoi ( c ) , atoi ( d ) ) ;
2003-08-24 22:35:06 +00:00
expiry = atoi ( d ) ;
memset ( & p - > addr , 0 , sizeof ( p - > addr ) ) ;
p - > addr . sin_family = AF_INET ;
p - > addr . sin_addr = in ;
p - > addr . sin_port = htons ( atoi ( c ) ) ;
2004-09-11 13:50:26 +00:00
if ( sipsock < 0 ) {
/* SIP isn't up yet, so schedule a poke only, pretty soon */
if ( p - > pokeexpire > - 1 )
ast_sched_del ( sched , p - > pokeexpire ) ;
p - > pokeexpire = ast_sched_add ( sched , rand ( ) % 5000 + 1 , sip_poke_peer_s , p ) ;
} else
sip_poke_peer ( p ) ;
2003-08-24 22:35:06 +00:00
if ( p - > expire > - 1 )
ast_sched_del ( sched , p - > expire ) ;
p - > expire = ast_sched_add ( sched , ( expiry + 10 ) * 1000 , expire_register , ( void * ) p ) ;
2004-09-07 23:45:34 +00:00
register_peer_exten ( p , 1 ) ;
2003-08-24 22:35:06 +00:00
}
}
}
}
}
2004-05-13 19:54:42 +00:00
/*--- parse_contact: Parse contact header and save registration ---*/
2002-06-28 20:34:46 +00:00
static int parse_contact ( struct sip_pvt * pvt , struct sip_peer * p , struct sip_request * req )
{
2003-02-07 04:07:10 +00:00
char contact [ 80 ] = " " ;
2003-08-24 22:35:06 +00:00
char data [ 256 ] ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2002-06-28 20:34:46 +00:00
char * expires = get_header ( req , " Expires " ) ;
2003-04-08 03:24:12 +00:00
int expiry = atoi ( expires ) ;
2002-06-28 20:34:46 +00:00
char * c , * n , * pt ;
int port ;
2004-05-09 22:03:38 +00:00
char * useragent ;
2002-06-28 20:34:46 +00:00
struct hostent * hp ;
2004-04-22 00:20:34 +00:00
struct ast_hostent ahp ;
2002-06-28 20:34:46 +00:00
struct sockaddr_in oldsin ;
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( expires ) ) {
2002-06-28 20:34:46 +00:00
expires = strstr ( get_header ( req , " Contact " ) , " expires= " ) ;
2003-04-09 21:13:11 +00:00
if ( expires ) {
2003-04-08 03:24:12 +00:00
if ( sscanf ( expires + 8 , " %d; " , & expiry ) ! = 1 )
2003-04-09 21:13:11 +00:00
expiry = default_expiry ;
} else {
/* Nothing has been specified */
expiry = default_expiry ;
}
2002-06-28 20:34:46 +00:00
}
/* Look for brackets */
strncpy ( contact , get_header ( req , " Contact " ) , sizeof ( contact ) - 1 ) ;
c = contact ;
if ( ( n = strchr ( c , ' < ' ) ) ) {
c = n + 1 ;
n = strchr ( c , ' > ' ) ;
/* Lose the part after the > */
if ( n )
* n = ' \0 ' ;
}
2003-04-08 03:24:12 +00:00
if ( ! strcasecmp ( c , " * " ) | | ! expiry ) {
2003-03-05 06:00:17 +00:00
/* This means remove all registrations and return OK */
memset ( & p - > addr , 0 , sizeof ( p - > addr ) ) ;
if ( p - > expire > - 1 )
ast_sched_del ( sched , p - > expire ) ;
p - > expire = - 1 ;
2003-11-21 05:20:43 +00:00
ast_db_del ( " SIP/Registry " , p - > name ) ;
2004-09-07 23:45:34 +00:00
register_peer_exten ( p , 0 ) ;
2004-08-31 16:49:20 +00:00
p - > fullcontact [ 0 ] = ' \0 ' ;
2004-07-08 11:05:03 +00:00
p - > useragent [ 0 ] = ' \0 ' ;
2004-05-09 23:40:49 +00:00
p - > lastms = 0 ;
2003-03-05 06:00:17 +00:00
if ( option_verbose > 2 )
2003-08-24 22:35:06 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Unregistered SIP '%s' \n " , p - > name ) ;
2004-09-16 16:18:53 +00:00
manager_event ( EVENT_FLAG_SYSTEM , " PeerStatus " , " Peer: SIP/%s \r \n PeerStatus: Unregistered \r \n " , p - > name ) ;
2003-03-05 06:00:17 +00:00
return 0 ;
}
2004-08-31 16:49:20 +00:00
strncpy ( p - > fullcontact , c , sizeof ( p - > fullcontact ) - 1 ) ;
2004-07-31 04:04:05 +00:00
/* For the 200 OK, we should use the received contact */
snprintf ( pvt - > our_contact , sizeof ( pvt - > our_contact ) - 1 , " <%s> " , c ) ;
2002-06-28 20:34:46 +00:00
/* Make sure it's a SIP URL */
if ( strncasecmp ( c , " sip: " , 4 ) ) {
2003-02-24 21:10:24 +00:00
ast_log ( LOG_NOTICE , " '%s' is not a valid SIP contact (missing sip:) trying to use anyway \n " , c ) ;
} else
c + = 4 ;
2002-06-28 20:34:46 +00:00
/* Ditch q */
n = strchr ( c , ' ; ' ) ;
2004-08-30 05:21:34 +00:00
if ( n ) {
2002-06-28 20:34:46 +00:00
* n = ' \0 ' ;
2004-08-31 16:49:20 +00:00
}
2002-06-28 20:34:46 +00:00
/* Grab host */
n = strchr ( c , ' @ ' ) ;
if ( ! n ) {
n = c ;
c = NULL ;
} else {
* n = ' \0 ' ;
n + + ;
}
pt = strchr ( n , ' : ' ) ;
if ( pt ) {
* pt = ' \0 ' ;
pt + + ;
port = atoi ( pt ) ;
} else
port = DEFAULT_SIP_PORT ;
2003-03-13 15:44:31 +00:00
memcpy ( & oldsin , & p - > addr , sizeof ( oldsin ) ) ;
2004-08-27 20:19:14 +00:00
if ( ! ( p - > nat & SIP_NAT_ROUTE ) ) {
2003-03-08 06:00:17 +00:00
/* XXX This could block for a long time XXX */
2004-04-22 00:20:34 +00:00
hp = ast_gethostbyname ( n , & ahp ) ;
2003-03-08 06:00:17 +00:00
if ( ! hp ) {
ast_log ( LOG_WARNING , " Invalid host '%s' \n " , n ) ;
return - 1 ;
}
p - > addr . sin_family = AF_INET ;
memcpy ( & p - > addr . sin_addr , hp - > h_addr , sizeof ( p - > addr . sin_addr ) ) ;
p - > addr . sin_port = htons ( port ) ;
} else {
/* Don't trust the contact field. Just use what they came to us
with */
memcpy ( & p - > addr , & pvt - > recv , sizeof ( p - > addr ) ) ;
2002-06-28 20:34:46 +00:00
}
if ( c )
strncpy ( p - > username , c , sizeof ( p - > username ) - 1 ) ;
else
2004-07-08 11:05:03 +00:00
p - > username [ 0 ] = ' \0 ' ;
2002-06-28 20:34:46 +00:00
if ( p - > expire > - 1 )
ast_sched_del ( sched , p - > expire ) ;
2003-04-08 03:24:12 +00:00
if ( ( expiry < 1 ) | | ( expiry > max_expiry ) )
expiry = max_expiry ;
2004-01-22 16:29:02 +00:00
if ( ! p - > temponly )
p - > expire = ast_sched_add ( sched , ( expiry + 10 ) * 1000 , expire_register , p ) ;
2004-10-12 22:29:58 +00:00
else
p - > expire = - 1 ;
2003-04-08 03:24:12 +00:00
pvt - > expiry = expiry ;
2004-08-31 16:49:20 +00:00
snprintf ( data , sizeof ( data ) , " %s:%d:%d:%s:%s " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > addr . sin_addr ) , ntohs ( p - > addr . sin_port ) , expiry , p - > username , p - > fullcontact ) ;
2004-02-20 15:39:43 +00:00
ast_db_put ( " SIP/Registry " , p - > name , data ) ;
2004-09-16 16:18:53 +00:00
manager_event ( EVENT_FLAG_SYSTEM , " PeerStatus " , " Peer: SIP/%s \r \n PeerStatus: Registered \r \n " , p - > name ) ;
2004-02-20 15:39:43 +00:00
if ( inaddrcmp ( & p - > addr , & oldsin ) ) {
2003-02-07 04:07:10 +00:00
sip_poke_peer ( p ) ;
2002-06-28 20:34:46 +00:00
if ( option_verbose > 2 )
2004-06-29 12:56:46 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Registered SIP '%s' at %s port %d expires %d \n " , p - > name , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > addr . sin_addr ) , ntohs ( p - > addr . sin_port ) , expiry ) ;
2004-09-07 23:45:34 +00:00
register_peer_exten ( p , 1 ) ;
2002-06-28 20:34:46 +00:00
}
2004-05-09 21:05:43 +00:00
/* Save User agent */
2004-05-09 22:03:38 +00:00
useragent = get_header ( req , " User-Agent " ) ;
if ( useragent & & strcasecmp ( useragent , p - > useragent ) ) {
2004-07-16 04:40:54 +00:00
strncpy ( p - > useragent , useragent , sizeof ( p - > useragent ) - 1 ) ;
2004-07-17 22:06:26 +00:00
if ( option_verbose > 3 ) {
2004-05-09 22:03:38 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Saved useragent \" %s \" for peer %s \n " , p - > useragent , p - > name ) ;
}
}
2002-06-28 20:34:46 +00:00
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- free_old_route: Remove route from route list ---*/
2003-04-05 22:29:46 +00:00
static void free_old_route ( struct sip_route * route )
{
struct sip_route * next ;
while ( route ) {
next = route - > next ;
free ( route ) ;
route = next ;
}
}
2004-05-13 19:54:42 +00:00
/*--- list_route: List all routes - mostly for debugging ---*/
2003-04-05 22:29:46 +00:00
static void list_route ( struct sip_route * route )
{
if ( ! route ) {
ast_verbose ( " list_route: no route \n " ) ;
return ;
}
while ( route ) {
ast_verbose ( " list_route: hop: <%s> \n " , route - > hop ) ;
route = route - > next ;
}
}
2004-05-13 19:54:42 +00:00
/*--- build_route: Build route headers ---*/
2003-04-05 22:29:46 +00:00
static void build_route ( struct sip_pvt * p , struct sip_request * req , int backwards )
{
struct sip_route * thishop , * head , * tail ;
int start = 0 ;
int len ;
char * rr , * contact , * c ;
2004-05-03 20:06:38 +00:00
/* Once a persistant route is set, don't fool with it */
if ( p - > route & & p - > route_persistant ) {
ast_log ( LOG_DEBUG , " build_route: Retaining previous route: <%s> \n " , p - > route - > hop ) ;
return ;
}
2004-05-01 03:04:04 +00:00
if ( p - > route ) {
free_old_route ( p - > route ) ;
p - > route = NULL ;
}
2004-05-03 20:06:38 +00:00
p - > route_persistant = backwards ;
2003-04-05 22:29:46 +00:00
/* We build up head, then assign it to p->route when we're done */
head = NULL ; tail = head ;
2003-04-06 23:32:31 +00:00
/* 1st we pass through all the hops in any Record-Route headers */
2003-04-05 22:29:46 +00:00
for ( ; ; ) {
/* Each Record-Route header */
rr = __get_header ( req , " Record-Route " , & start ) ;
if ( * rr = = ' \0 ' ) break ;
for ( ; ; ) {
/* Each route entry */
/* Find < */
rr = strchr ( rr , ' < ' ) ;
if ( ! rr ) break ; /* No more hops */
+ + rr ;
len = strcspn ( rr , " > " ) ;
/* Make a struct route */
thishop = ( struct sip_route * ) malloc ( sizeof ( struct sip_route ) + len + 1 ) ;
if ( thishop ) {
2004-07-16 04:40:54 +00:00
strncpy ( thishop - > hop , rr , len ) ; /* safe */
2003-04-05 22:29:46 +00:00
thishop - > hop [ len ] = ' \0 ' ;
2003-04-06 23:32:31 +00:00
ast_log ( LOG_DEBUG , " build_route: Record-Route hop: <%s> \n " , thishop - > hop ) ;
2003-04-05 22:29:46 +00:00
/* Link in */
if ( backwards ) {
/* Link in at head so they end up in reverse order */
thishop - > next = head ;
head = thishop ;
/* If this was the first then it'll be the tail */
if ( ! tail ) tail = thishop ;
} else {
2003-04-05 22:33:42 +00:00
thishop - > next = NULL ;
2003-04-05 22:29:46 +00:00
/* Link in at the end */
if ( tail )
tail - > next = thishop ;
else
head = thishop ;
tail = thishop ;
}
}
rr + = len + 1 ;
}
}
/* 2nd append the Contact: if there is one */
/* Can be multiple Contact headers, comma separated values - we just take the first */
contact = get_header ( req , " Contact " ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( contact ) ) {
2003-04-05 22:29:46 +00:00
ast_log ( LOG_DEBUG , " build_route: Contact hop: %s \n " , contact ) ;
/* Look for <: delimited address */
c = strchr ( contact , ' < ' ) ;
if ( c ) {
/* Take to > */
+ + c ;
len = strcspn ( c , " > " ) ;
} else {
/* No <> - just take the lot */
c = contact ; len = strlen ( contact ) ;
}
thishop = ( struct sip_route * ) malloc ( sizeof ( struct sip_route ) + len + 1 ) ;
2003-04-06 23:32:31 +00:00
if ( thishop ) {
2004-07-16 04:40:54 +00:00
strncpy ( thishop - > hop , c , len ) ; /* safe */
2003-04-06 23:32:31 +00:00
thishop - > hop [ len ] = ' \0 ' ;
thishop - > next = NULL ;
/* Goes at the end */
if ( tail )
tail - > next = thishop ;
else
head = thishop ;
}
2003-04-05 22:29:46 +00:00
}
/* Store as new route */
p - > route = head ;
/* For debugging dump what we ended up with */
2004-05-01 21:25:31 +00:00
if ( sip_debug_test_pvt ( p ) )
2003-04-05 22:29:46 +00:00
list_route ( p - > route ) ;
}
2004-05-13 19:54:42 +00:00
/*--- md5_hash: Produce MD5 hash of value. Used for authentication ---*/
2003-02-07 04:07:10 +00:00
static void md5_hash ( char * output , char * input )
{
struct MD5Context md5 ;
unsigned char digest [ 16 ] ;
char * ptr ;
int x ;
MD5Init ( & md5 ) ;
MD5Update ( & md5 , input , strlen ( input ) ) ;
MD5Final ( digest , & md5 ) ;
ptr = output ;
for ( x = 0 ; x < 16 ; x + + )
ptr + = sprintf ( ptr , " %2.2x " , digest [ x ] ) ;
}
2004-05-13 19:54:42 +00:00
/*--- check_auth: Check user authorization from peer definition ---*/
/* Some actions, like REGISTER and INVITEs from peers require
authentication ( if peer have secret set ) */
2004-03-21 19:25:13 +00:00
static int check_auth ( struct sip_pvt * p , struct sip_request * req , char * randdata , int randlen , char * username , char * secret , char * md5secret , char * method , char * uri , int reliable , int ignore )
2003-02-07 04:07:10 +00:00
{
int res = - 1 ;
2004-06-12 16:38:36 +00:00
char * response = " 407 Proxy Authentication Required " ;
char * reqheader = " Proxy-Authorization " ;
char * respheader = " Proxy-Authenticate " ;
char * authtoken ;
2004-06-25 05:52:55 +00:00
# ifdef OSP_SUPPORT
2004-09-07 15:18:14 +00:00
char tmp [ 80 ] ;
2004-06-25 05:52:55 +00:00
char * osptoken ;
unsigned int osptimelimit ;
# endif
2003-02-07 04:07:10 +00:00
/* Always OK if no secret */
2004-06-25 05:52:55 +00:00
if ( ast_strlen_zero ( secret ) & & ast_strlen_zero ( md5secret )
# ifdef OSP_SUPPORT
& & ! p - > ospauth
# endif
)
2003-02-07 04:07:10 +00:00
return 0 ;
2004-06-12 16:38:36 +00:00
if ( ! strcasecmp ( method , " REGISTER " ) ) {
/* On a REGISTER, we have to use 401 and its family of headers instead of 407 and its family
of headers - - GO SIP ! Whoo hoo ! Two things that do the same thing but are used in
different circumstances ! What a surprise . */
response = " 401 Unauthorized " ;
reqheader = " Authorization " ;
respheader = " WWW-Authenticate " ;
}
2004-06-25 05:52:55 +00:00
# ifdef OSP_SUPPORT
else if ( p - > ospauth ) {
ast_log ( LOG_DEBUG , " Checking OSP Authentication! \n " ) ;
osptoken = get_header ( req , " P-OSP-Auth-Token " ) ;
/* Check for token existence */
if ( ! strlen ( osptoken ) )
return - 1 ;
/* Validate token */
2004-10-02 00:58:31 +00:00
if ( ast_osp_validate ( NULL , osptoken , & p - > osphandle , & osptimelimit , p - > cid_num , p - > sa . sin_addr , p - > exten ) < 1 )
2004-06-25 05:52:55 +00:00
return - 1 ;
2004-09-07 15:18:14 +00:00
snprintf ( tmp , sizeof ( tmp ) , " %d " , p - > osphandle ) ;
pbx_builtin_setvar_helper ( p - > owner , " OSPHANDLE " , tmp ) ;
2004-06-25 05:52:55 +00:00
/* If ospauth is 'exclusive' don't require further authentication */
if ( ( p - > ospauth > 1 ) | | ( ast_strlen_zero ( secret ) & & ast_strlen_zero ( md5secret ) ) )
return 0 ;
}
# endif
2004-06-12 16:38:36 +00:00
authtoken = get_header ( req , reqheader ) ;
if ( ignore & & ! ast_strlen_zero ( randdata ) & & ast_strlen_zero ( authtoken ) ) {
2004-03-21 19:25:13 +00:00
/* This is a retransmitted invite/register/etc, don't reconstruct authentication
information */
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( randdata ) ) {
2004-03-21 19:25:13 +00:00
if ( ! reliable ) {
/* Resend message if this was NOT a reliable delivery. Otherwise the
retransmission should get it */
2004-06-12 16:38:36 +00:00
transmit_response_with_auth ( p , response , req , randdata , reliable , respheader ) ;
2004-03-21 19:25:13 +00:00
/* Schedule auto destroy in 15 seconds */
sip_scheddestroy ( p , 15000 ) ;
}
res = 1 ;
}
2004-06-12 16:38:36 +00:00
} else if ( ast_strlen_zero ( randdata ) | | ast_strlen_zero ( authtoken ) ) {
2003-02-07 04:07:10 +00:00
snprintf ( randdata , randlen , " %08x " , rand ( ) ) ;
2004-06-12 16:38:36 +00:00
transmit_response_with_auth ( p , response , req , randdata , reliable , respheader ) ;
2003-03-28 06:13:04 +00:00
/* Schedule auto destroy in 15 seconds */
sip_scheddestroy ( p , 15000 ) ;
2003-02-07 04:07:10 +00:00
res = 1 ;
} else {
/* Whoever came up with the authentication section of SIP can suck my %&#$&* for not putting
an example in the spec of just what it is you ' re doing a hash on . */
char a1 [ 256 ] ;
char a2 [ 256 ] ;
char a1_hash [ 256 ] ;
char a2_hash [ 256 ] ;
char resp [ 256 ] ;
2004-03-23 05:06:50 +00:00
char resp_hash [ 256 ] = " " ;
2003-02-07 04:07:10 +00:00
char tmp [ 256 ] = " " ;
char * c ;
2003-06-17 16:36:24 +00:00
char * z ;
2003-02-07 04:07:10 +00:00
char * response = " " ;
char * resp_uri = " " ;
/* Find their response among the mess that we'r sent for comparison */
2004-06-12 16:38:36 +00:00
strncpy ( tmp , authtoken , sizeof ( tmp ) - 1 ) ;
2003-02-07 04:07:10 +00:00
c = tmp ;
while ( c ) {
while ( * c & & ( * c < 33 ) ) c + + ;
if ( ! * c )
break ;
if ( ! strncasecmp ( c , " response= " , strlen ( " response= " ) ) ) {
c + = strlen ( " response= " ) ;
if ( ( * c = = ' \" ' ) ) {
response = + + c ;
if ( ( c = strchr ( c , ' \" ' ) ) )
* c = ' \0 ' ;
} else {
response = c ;
if ( ( c = strchr ( c , ' , ' ) ) )
* c = ' \0 ' ;
}
} else if ( ! strncasecmp ( c , " uri= " , strlen ( " uri= " ) ) ) {
c + = strlen ( " uri= " ) ;
if ( ( * c = = ' \" ' ) ) {
resp_uri = + + c ;
if ( ( c = strchr ( c , ' \" ' ) ) )
* c = ' \0 ' ;
} else {
resp_uri = c ;
if ( ( c = strchr ( c , ' , ' ) ) )
* c = ' \0 ' ;
}
} else
2003-06-17 16:36:24 +00:00
if ( ( z = strchr ( c , ' ' ) ) | | ( z = strchr ( c , ' , ' ) ) ) c = z ;
2003-02-07 04:07:10 +00:00
if ( c )
c + + ;
}
2004-05-06 20:00:19 +00:00
snprintf ( a1 , sizeof ( a1 ) , " %s:%s:%s " , username , global_realm , secret ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( resp_uri ) )
2003-02-07 04:07:10 +00:00
snprintf ( a2 , sizeof ( a2 ) , " %s:%s " , method , resp_uri ) ;
else
snprintf ( a2 , sizeof ( a2 ) , " %s:%s " , method , uri ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( md5secret ) )
2003-10-15 17:32:19 +00:00
snprintf ( a1_hash , sizeof ( a1_hash ) , " %s " , md5secret ) ;
else
md5_hash ( a1_hash , a1 ) ;
2003-02-07 04:07:10 +00:00
md5_hash ( a2_hash , a2 ) ;
snprintf ( resp , sizeof ( resp ) , " %s:%s:%s " , a1_hash , randdata , a2_hash ) ;
md5_hash ( resp_hash , resp ) ;
/* resp_hash now has the expected response, compare the two */
if ( response & & ! strncasecmp ( response , resp_hash , strlen ( resp_hash ) ) ) {
/* Auth is OK */
res = 0 ;
}
/* Assume success ;-) */
}
return res ;
}
2004-05-13 19:54:42 +00:00
/*--- cb_extensionstate: Part of thte SUBSCRIBE support subsystem ---*/
2003-04-06 18:19:51 +00:00
static int cb_extensionstate ( char * context , char * exten , int state , void * data )
{
struct sip_pvt * p = data ;
if ( state = = - 1 ) {
sip_scheddestroy ( p , 15000 ) ;
p - > stateid = - 1 ;
return 0 ;
}
transmit_state_notify ( p , state , 1 ) ;
if ( option_debug )
ast_verbose ( VERBOSE_PREFIX_1 " Extension Changed %s new state %d for Notify User %s \n " , exten , state , p - > username ) ;
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- register_verify: Verify registration of user */
2004-03-21 19:25:13 +00:00
static int register_verify ( struct sip_pvt * p , struct sockaddr_in * sin , struct sip_request * req , char * uri , int ignore )
2002-06-28 20:34:46 +00:00
{
int res = - 1 ;
struct sip_peer * peer ;
2003-02-07 04:07:10 +00:00
char tmp [ 256 ] = " " ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2002-06-28 20:34:46 +00:00
char * name , * c ;
2003-02-07 04:07:10 +00:00
char * t ;
/* Terminate URI */
t = uri ;
while ( * t & & ( * t > 32 ) & & ( * t ! = ' ; ' ) )
t + + ;
* t = ' \0 ' ;
2002-06-28 20:34:46 +00:00
strncpy ( tmp , get_header ( req , " To " ) , sizeof ( tmp ) - 1 ) ;
c = ditch_braces ( tmp ) ;
2003-04-10 00:06:16 +00:00
/* Ditch ;user=phone */
name = strchr ( c , ' ; ' ) ;
if ( name )
* name = ' \0 ' ;
2003-02-24 21:10:24 +00:00
if ( ! strncmp ( c , " sip: " , 4 ) ) {
name = c + 4 ;
} else {
name = c ;
2004-06-29 12:56:46 +00:00
ast_log ( LOG_NOTICE , " Invalid to address: '%s' from %s (missing sip:) trying to use anyway... \n " , c , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , sin - > sin_addr ) ) ;
2002-06-28 20:34:46 +00:00
}
c = strchr ( name , ' @ ' ) ;
if ( c )
* c = ' \0 ' ;
2003-04-08 14:49:12 +00:00
strncpy ( p - > exten , name , sizeof ( p - > exten ) - 1 ) ;
build_contact ( p ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & peerl . lock ) ;
2004-04-26 14:54:33 +00:00
peer = find_peer ( name , NULL ) ;
if ( ! ( peer & & ast_apply_ha ( peer - > ha , sin ) ) ) {
if ( peer & & peer - > temponly ) {
2004-10-07 15:46:08 +00:00
destroy_peer ( peer ) ;
2004-04-26 14:54:33 +00:00
}
peer = NULL ;
2004-01-22 16:29:02 +00:00
}
ast_mutex_unlock ( & peerl . lock ) ;
2004-04-26 14:54:33 +00:00
2004-01-22 16:29:02 +00:00
if ( peer ) {
2003-11-11 20:46:41 +00:00
if ( ! peer - > dynamic ) {
2004-03-09 17:42:29 +00:00
ast_log ( LOG_NOTICE , " Peer '%s' is trying to register, but not configured as host=dynamic \n " , peer - > name ) ;
2004-01-22 16:29:02 +00:00
} else {
p - > nat = peer - > nat ;
transmit_response ( p , " 100 Trying " , req ) ;
2004-03-21 19:25:13 +00:00
if ( ! ( res = check_auth ( p , req , p - > randdata , sizeof ( p - > randdata ) , peer - > name , peer - > secret , peer - > md5secret , " REGISTER " , uri , 0 , ignore ) ) ) {
2004-01-22 16:29:02 +00:00
sip_cancel_destroy ( p ) ;
if ( parse_contact ( p , peer , req ) ) {
ast_log ( LOG_WARNING , " Failed to parse contact info \n " ) ;
} else {
2004-04-26 14:54:33 +00:00
update_peer ( peer , p - > expiry ) ;
2004-02-25 01:16:45 +00:00
/* Say OK and ask subsystem to retransmit msg counter */
2004-01-22 16:29:02 +00:00
transmit_response_with_date ( p , " 200 OK " , req ) ;
peer - > lastmsgssent = - 1 ;
res = 0 ;
}
}
2003-11-11 20:46:41 +00:00
}
2002-06-28 20:34:46 +00:00
}
2003-11-11 20:46:41 +00:00
if ( ! peer & & autocreatepeer ) {
/* Create peer if we have autocreate mode enabled */
peer = temp_peer ( name ) ;
if ( peer ) {
2004-09-26 20:42:03 +00:00
ast_mutex_lock ( & peerl . lock ) ;
2003-11-11 20:46:41 +00:00
peer - > next = peerl . peers ;
peerl . peers = peer ;
2004-09-26 20:42:03 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2003-11-11 20:46:41 +00:00
peer - > lastmsgssent = - 1 ;
sip_cancel_destroy ( p ) ;
if ( parse_contact ( p , peer , req ) ) {
ast_log ( LOG_WARNING , " Failed to parse contact info \n " ) ;
} else {
/* Say OK and ask subsystem to retransmit msg counter */
2004-09-16 16:18:53 +00:00
manager_event ( EVENT_FLAG_SYSTEM , " PeerStatus " , " Peer: SIP/%s \r \n PeerStatus: Registered \r \n " , peer - > name ) ;
2003-11-11 20:46:41 +00:00
transmit_response_with_date ( p , " 200 OK " , req ) ;
peer - > lastmsgssent = - 1 ;
res = 0 ;
}
}
}
2003-04-06 18:19:51 +00:00
if ( ! res ) {
ast_device_state_changed ( " SIP/%s " , peer - > name ) ;
}
2003-02-07 04:07:10 +00:00
if ( res < 0 )
2004-06-12 16:38:36 +00:00
transmit_response ( p , " 403 Forbidden " , & p - > initreq ) ;
2004-04-26 14:54:33 +00:00
if ( peer & & peer - > temponly ) {
2004-10-07 15:46:08 +00:00
destroy_peer ( peer ) ;
2004-04-26 14:54:33 +00:00
}
2002-06-28 20:34:46 +00:00
return res ;
}
2004-05-13 19:54:42 +00:00
/*--- get_rdnis: get referring dnis ---*/
2003-05-12 21:12:48 +00:00
static int get_rdnis ( struct sip_pvt * p , struct sip_request * oreq )
{
char tmp [ 256 ] = " " , * c , * a ;
struct sip_request * req ;
req = oreq ;
if ( ! req )
req = & p - > initreq ;
2003-05-13 00:17:14 +00:00
strncpy ( tmp , get_header ( req , " Diversion " ) , sizeof ( tmp ) - 1 ) ;
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( tmp ) )
2003-05-12 21:12:48 +00:00
return 0 ;
c = ditch_braces ( tmp ) ;
if ( strncmp ( c , " sip: " , 4 ) ) {
ast_log ( LOG_WARNING , " Huh? Not an RDNIS SIP header (%s)? \n " , c ) ;
return - 1 ;
}
c + = 4 ;
if ( ( a = strchr ( c , ' @ ' ) ) | | ( a = strchr ( c , ' ; ' ) ) ) {
* a = ' \0 ' ;
}
2004-05-01 21:25:31 +00:00
if ( sip_debug_test_pvt ( p ) )
2003-05-12 21:12:48 +00:00
ast_verbose ( " RDNIS is %s \n " , c ) ;
strncpy ( p - > rdnis , c , sizeof ( p - > rdnis ) - 1 ) ;
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- get_destination: Find out who the call is for --*/
2003-02-07 04:07:10 +00:00
static int get_destination ( struct sip_pvt * p , struct sip_request * oreq )
2002-06-28 20:34:46 +00:00
{
2003-02-07 04:07:10 +00:00
char tmp [ 256 ] = " " , * c , * a ;
2003-10-09 22:50:42 +00:00
char tmpf [ 256 ] = " " , * fr ;
2003-02-07 04:07:10 +00:00
struct sip_request * req ;
req = oreq ;
if ( ! req )
req = & p - > initreq ;
2003-05-09 19:02:10 +00:00
if ( req - > rlPart2 )
strncpy ( tmp , req - > rlPart2 , sizeof ( tmp ) - 1 ) ;
2002-06-28 20:34:46 +00:00
c = ditch_braces ( tmp ) ;
2003-10-09 22:50:42 +00:00
2003-10-10 02:05:17 +00:00
strncpy ( tmpf , get_header ( req , " From " ) , sizeof ( tmpf ) - 1 ) ;
2003-10-09 22:50:42 +00:00
fr = ditch_braces ( tmpf ) ;
2002-06-28 20:34:46 +00:00
if ( strncmp ( c , " sip: " , 4 ) ) {
ast_log ( LOG_WARNING , " Huh? Not a SIP header (%s)? \n " , c ) ;
return - 1 ;
}
c + = 4 ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( fr ) ) {
2003-10-10 18:58:52 +00:00
if ( strncmp ( fr , " sip: " , 4 ) ) {
ast_log ( LOG_WARNING , " Huh? Not a SIP header (%s)? \n " , fr ) ;
return - 1 ;
}
fr + = 4 ;
} else
fr = NULL ;
2003-11-11 20:46:41 +00:00
if ( ( a = strchr ( c , ' @ ' ) ) ) {
* a = ' \0 ' ;
a + + ;
strncpy ( p - > domain , a , sizeof ( p - > domain ) - 1 ) ;
}
if ( ( a = strchr ( c , ' ; ' ) ) ) {
2002-06-28 20:34:46 +00:00
* a = ' \0 ' ;
}
2004-02-07 07:13:33 +00:00
if ( fr ) {
2004-04-15 00:02:07 +00:00
if ( ( a = strchr ( fr , ' ; ' ) ) )
2004-02-07 07:13:33 +00:00
* a = ' \0 ' ;
2004-04-15 00:02:07 +00:00
if ( ( a = strchr ( fr , ' @ ' ) ) ) {
* a = ' \0 ' ;
strncpy ( p - > fromdomain , a + 1 , sizeof ( p - > fromdomain ) - 1 ) ;
2004-04-29 05:01:32 +00:00
} else
strncpy ( p - > fromdomain , fr , sizeof ( p - > fromdomain ) - 1 ) ;
2003-10-12 11:43:18 +00:00
}
2004-06-25 18:23:06 +00:00
if ( pedanticsipchecking )
url_decode ( c ) ;
2004-05-01 21:25:31 +00:00
if ( sip_debug_test_pvt ( p ) )
2003-02-07 04:07:10 +00:00
ast_verbose ( " Looking for %s in %s \n " , c , p - > context ) ;
2003-10-09 22:50:42 +00:00
if ( ast_exists_extension ( NULL , p - > context , c , 1 , fr ) | |
2003-04-09 04:00:43 +00:00
! strcmp ( c , ast_pickup_ext ( ) ) ) {
2003-11-27 22:09:42 +00:00
if ( ! oreq )
strncpy ( p - > exten , c , sizeof ( p - > exten ) - 1 ) ;
2002-06-28 20:34:46 +00:00
return 0 ;
}
2002-09-12 17:13:17 +00:00
2003-10-09 22:50:42 +00:00
if ( ast_canmatch_extension ( NULL , p - > context , c , 1 , fr ) | |
2003-04-09 04:00:43 +00:00
! strncmp ( c , ast_pickup_ext ( ) , strlen ( c ) ) ) {
2002-09-12 17:13:17 +00:00
return 1 ;
}
2002-06-28 20:34:46 +00:00
return - 1 ;
}
2004-05-13 19:54:42 +00:00
/*--- hex2int: Convert hex code to integer ---*/
2003-11-13 00:43:02 +00:00
static int hex2int ( char a )
{
if ( ( a > = ' 0 ' ) & & ( a < = ' 9 ' ) ) {
return a - ' 0 ' ;
} else if ( ( a > = ' a ' ) & & ( a < = ' f ' ) ) {
return a - ' a ' + 10 ;
} else if ( ( a > = ' A ' ) & & ( a < = ' F ' ) ) {
return a - ' A ' + 10 ;
}
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- get_refer_info: Call transfer support (new standard) ---*/
2003-02-07 04:07:10 +00:00
static int get_refer_info ( struct sip_pvt * p , struct sip_request * oreq )
2002-06-28 20:34:46 +00:00
{
2003-02-07 04:07:10 +00:00
char tmp [ 256 ] = " " , * c , * a ;
char tmp2 [ 256 ] = " " , * c2 , * a2 ;
char tmp3 [ 256 ] ;
char tmp4 [ 256 ] ;
2003-02-16 06:00:12 +00:00
char tmp5 [ 256 ] = " " ; /* CallID to replace */
2003-02-07 04:07:10 +00:00
struct sip_request * req ;
2003-02-16 06:00:12 +00:00
struct sip_pvt * p2 ;
2003-02-07 04:07:10 +00:00
req = oreq ;
if ( ! req )
req = & p - > initreq ;
strncpy ( tmp , get_header ( req , " Refer-To " ) , sizeof ( tmp ) - 1 ) ;
strncpy ( tmp2 , get_header ( req , " Referred-By " ) , sizeof ( tmp2 ) - 1 ) ;
strncpy ( tmp3 , get_header ( req , " Contact " ) , sizeof ( tmp3 ) - 1 ) ;
strncpy ( tmp4 , get_header ( req , " Remote-Party-ID " ) , sizeof ( tmp4 ) - 1 ) ;
c = ditch_braces ( tmp ) ;
c2 = ditch_braces ( tmp2 ) ;
if ( strncmp ( c , " sip: " , 4 ) & & strncmp ( c2 , " sip: " , 4 ) ) {
ast_log ( LOG_WARNING , " Huh? Not a SIP header (%s)? \n " , c ) ;
ast_log ( LOG_WARNING , " Huh? Not a SIP header (%s)? \n " , c2 ) ;
return - 1 ;
}
c + = 4 ;
c2 + = 4 ;
2003-02-16 06:00:12 +00:00
if ( ( a = strchr ( c , ' ? ' ) ) ) {
/* Search for arguemnts */
2003-02-07 04:07:10 +00:00
* a = ' \0 ' ;
2003-02-16 06:00:12 +00:00
a + + ;
if ( ! strncasecmp ( a , " REPLACES= " , strlen ( " REPLACES= " ) ) ) {
strncpy ( tmp5 , a + strlen ( " REPLACES= " ) , sizeof ( tmp5 ) - 1 ) ;
2004-02-09 05:38:17 +00:00
a = tmp5 ;
while ( ( a = strchr ( a , ' % ' ) ) ) {
2003-02-16 06:00:12 +00:00
/* Yuck! Pingtel converts the '@' to a %40, icky icky! Convert
back to an ' @ ' */
2004-02-09 05:38:17 +00:00
if ( strlen ( a ) < 3 )
break ;
2003-11-13 00:43:02 +00:00
* a = hex2int ( a [ 1 ] ) * 16 + hex2int ( a [ 2 ] ) ;
memmove ( a + 1 , a + 3 , strlen ( a + 3 ) + 1 ) ;
2004-02-09 05:38:17 +00:00
a + + ;
2003-02-16 06:00:12 +00:00
}
if ( ( a = strchr ( tmp5 , ' % ' ) ) )
* a = ' \0 ' ;
2003-11-13 00:43:02 +00:00
if ( ( a = strchr ( tmp5 , ' ; ' ) ) )
* a = ' \0 ' ;
/* Skip leading whitespace */
2003-11-13 00:44:31 +00:00
while ( tmp5 [ 0 ] & & ( tmp5 [ 0 ] < 33 ) )
memmove ( tmp5 , tmp5 + 1 , strlen ( tmp5 ) ) ;
2003-11-13 00:43:02 +00:00
2003-02-16 06:00:12 +00:00
}
2003-02-07 04:07:10 +00:00
}
2003-02-16 06:00:12 +00:00
if ( ( a = strchr ( c , ' @ ' ) ) )
* a = ' \0 ' ;
if ( ( a = strchr ( c , ' ; ' ) ) )
* a = ' \0 ' ;
if ( ( a2 = strchr ( c2 , ' @ ' ) ) )
* a2 = ' \0 ' ;
if ( ( a2 = strchr ( c2 , ' ; ' ) ) )
2003-02-07 04:07:10 +00:00
* a2 = ' \0 ' ;
2003-02-16 06:00:12 +00:00
2003-02-07 04:07:10 +00:00
2004-05-01 21:25:31 +00:00
if ( sip_debug_test_pvt ( p ) ) {
2003-02-07 04:07:10 +00:00
ast_verbose ( " Looking for %s in %s \n " , c , p - > context ) ;
ast_verbose ( " Looking for %s in %s \n " , c2 , p - > context ) ;
2003-02-24 06:00:18 +00:00
}
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( tmp5 ) ) {
2003-02-16 06:00:12 +00:00
/* This is a supervised transfer */
ast_log ( LOG_DEBUG , " Assigning Replace-Call-ID Info %s to REPLACE_CALL_ID \n " , tmp5 ) ;
strncpy ( p - > refer_to , " " , sizeof ( p - > refer_to ) - 1 ) ;
strncpy ( p - > referred_by , " " , sizeof ( p - > referred_by ) - 1 ) ;
strncpy ( p - > refer_contact , " " , sizeof ( p - > refer_contact ) - 1 ) ;
p - > refer_call = NULL ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & iflock ) ;
2003-02-16 06:00:12 +00:00
/* Search interfaces and find the match */
p2 = iflist ;
while ( p2 ) {
if ( ! strcmp ( p2 - > callid , tmp5 ) ) {
2004-05-20 07:52:07 +00:00
/* Go ahead and lock it (and its owner) before returning */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p2 - > lock ) ;
2004-05-20 07:52:07 +00:00
if ( p2 - > owner ) {
while ( ast_mutex_trylock ( & p2 - > owner - > lock ) ) {
ast_mutex_unlock ( & p2 - > lock ) ;
usleep ( 1 ) ;
ast_mutex_lock ( & p2 - > lock ) ;
if ( ! p2 - > owner )
break ;
}
}
2003-02-16 06:00:12 +00:00
p - > refer_call = p2 ;
break ;
}
p2 = p2 - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
2003-02-16 06:00:12 +00:00
if ( p - > refer_call )
2003-02-07 04:07:10 +00:00
return 0 ;
2003-02-16 06:00:12 +00:00
else
ast_log ( LOG_NOTICE , " Supervised transfer requested, but unable to find callid '%s' \n " , tmp5 ) ;
2004-07-09 10:46:50 +00:00
} else if ( ast_exists_extension ( NULL , p - > context , c , 1 , NULL ) | | ! strcmp ( c , ast_parking_ext ( ) ) ) {
2003-02-16 06:00:12 +00:00
/* This is an unsupervised transfer */
ast_log ( LOG_DEBUG , " Assigning Extension %s to REFER-TO \n " , c ) ;
ast_log ( LOG_DEBUG , " Assigning Extension %s to REFERRED-BY \n " , c2 ) ;
ast_log ( LOG_DEBUG , " Assigning Contact Info %s to REFER_CONTACT \n " , tmp3 ) ;
strncpy ( p - > refer_to , c , sizeof ( p - > refer_to ) - 1 ) ;
strncpy ( p - > referred_by , c2 , sizeof ( p - > referred_by ) - 1 ) ;
strncpy ( p - > refer_contact , tmp3 , sizeof ( p - > refer_contact ) - 1 ) ;
p - > refer_call = NULL ;
return 0 ;
} else if ( ast_canmatch_extension ( NULL , p - > context , c , 1 , NULL ) ) {
2003-02-07 04:07:10 +00:00
return 1 ;
}
return - 1 ;
}
2004-05-13 19:54:42 +00:00
/*--- get_also_info: Call transfer support (old way, depreciated)--*/
2003-08-25 00:05:48 +00:00
static int get_also_info ( struct sip_pvt * p , struct sip_request * oreq )
{
char tmp [ 256 ] = " " , * c , * a ;
struct sip_request * req ;
req = oreq ;
if ( ! req )
req = & p - > initreq ;
strncpy ( tmp , get_header ( req , " Also " ) , sizeof ( tmp ) - 1 ) ;
c = ditch_braces ( tmp ) ;
if ( strncmp ( c , " sip: " , 4 ) ) {
ast_log ( LOG_WARNING , " Huh? Not a SIP header (%s)? \n " , c ) ;
return - 1 ;
}
c + = 4 ;
if ( ( a = strchr ( c , ' @ ' ) ) )
* a = ' \0 ' ;
if ( ( a = strchr ( c , ' ; ' ) ) )
* a = ' \0 ' ;
2004-05-01 21:25:31 +00:00
if ( sip_debug_test_pvt ( p ) ) {
2003-08-25 00:05:48 +00:00
ast_verbose ( " Looking for %s in %s \n " , c , p - > context ) ;
}
if ( ast_exists_extension ( NULL , p - > context , c , 1 , NULL ) ) {
/* This is an unsupervised transfer */
ast_log ( LOG_DEBUG , " Assigning Extension %s to REFER-TO \n " , c ) ;
strncpy ( p - > refer_to , c , sizeof ( p - > refer_to ) - 1 ) ;
strncpy ( p - > referred_by , " " , sizeof ( p - > referred_by ) - 1 ) ;
strncpy ( p - > refer_contact , " " , sizeof ( p - > refer_contact ) - 1 ) ;
p - > refer_call = NULL ;
return 0 ;
} else if ( ast_canmatch_extension ( NULL , p - > context , c , 1 , NULL ) ) {
return 1 ;
}
return - 1 ;
}
2003-02-07 04:07:10 +00:00
2004-05-13 19:54:42 +00:00
/*--- check_via: check Via: headers ---*/
2003-02-07 04:07:10 +00:00
static int check_via ( struct sip_pvt * p , struct sip_request * req )
{
char via [ 256 ] = " " ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-02-07 04:07:10 +00:00
char * c , * pt ;
struct hostent * hp ;
2004-04-22 00:20:34 +00:00
struct ast_hostent ahp ;
2003-02-07 04:07:10 +00:00
memset ( via , 0 , sizeof ( via ) ) ;
strncpy ( via , get_header ( req , " Via " ) , sizeof ( via ) - 1 ) ;
c = strchr ( via , ' ; ' ) ;
if ( c )
2002-09-12 17:13:17 +00:00
* c = ' \0 ' ;
2002-06-28 20:34:46 +00:00
c = strchr ( via , ' ' ) ;
if ( c ) {
* c = ' \0 ' ;
c + + ;
2002-09-12 17:13:17 +00:00
while ( * c & & ( * c < 33 ) )
c + + ;
2002-06-28 20:34:46 +00:00
if ( strcmp ( via , " SIP/2.0/UDP " ) ) {
ast_log ( LOG_WARNING , " Don't know how to respond via '%s' \n " , via ) ;
return - 1 ;
}
pt = strchr ( c , ' : ' ) ;
if ( pt ) {
* pt = ' \0 ' ;
pt + + ;
}
2004-04-22 00:20:34 +00:00
hp = ast_gethostbyname ( c , & ahp ) ;
2002-06-28 20:34:46 +00:00
if ( ! hp ) {
ast_log ( LOG_WARNING , " '%s' is not a valid host \n " , c ) ;
return - 1 ;
}
memset ( & p - > sa , 0 , sizeof ( p - > sa ) ) ;
p - > sa . sin_family = AF_INET ;
memcpy ( & p - > sa . sin_addr , hp - > h_addr , sizeof ( p - > sa . sin_addr ) ) ;
2003-03-05 06:00:17 +00:00
p - > sa . sin_port = htons ( pt ? atoi ( pt ) : DEFAULT_SIP_PORT ) ;
2004-06-16 14:14:57 +00:00
c = strstr ( via , " ;rport " ) ;
if ( c & & ( c [ 6 ] ! = ' = ' ) )
2004-08-27 02:45:35 +00:00
p - > nat | = SIP_NAT_ROUTE ;
2004-05-01 21:25:31 +00:00
if ( sip_debug_test_pvt ( p ) ) {
2004-08-27 02:45:35 +00:00
if ( p - > nat & SIP_NAT_ROUTE )
2004-06-29 12:56:46 +00:00
ast_verbose ( " Sending to %s : %d (NAT) \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > sa . sin_addr ) , ntohs ( p - > sa . sin_port ) ) ;
2003-03-05 06:00:17 +00:00
else
2004-06-29 12:56:46 +00:00
ast_verbose ( " Sending to %s : %d (non-NAT) \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > sa . sin_addr ) , ntohs ( p - > sa . sin_port ) ) ;
2003-03-05 06:00:17 +00:00
}
2002-06-28 20:34:46 +00:00
}
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- get_calleridname: Get caller id name from SIP headers ---*/
2004-07-16 04:40:54 +00:00
static char * get_calleridname ( char * input , char * output , size_t outputsize )
2003-06-06 00:06:52 +00:00
{
char * end = strchr ( input , ' < ' ) ;
char * tmp = strchr ( input , ' \" ' ) ;
2004-07-16 04:40:54 +00:00
int bytes = 0 ;
int maxbytes = outputsize - 1 ;
2003-06-08 16:26:08 +00:00
if ( ! end | | ( end = = input ) ) return NULL ;
2003-06-06 00:06:52 +00:00
/* move away from "<" */
end - - ;
/* we found "name" */
if ( tmp & & tmp < end ) {
end = strchr ( tmp + 1 , ' \" ' ) ;
if ( ! end ) return NULL ;
2004-07-16 04:40:54 +00:00
bytes = ( int ) ( end - tmp - 1 ) ;
/* protect the output buffer */
if ( bytes > maxbytes ) {
bytes = maxbytes ;
}
strncpy ( output , tmp + 1 , bytes ) ; /* safe */
output [ maxbytes ] = ' \0 ' ;
2003-06-06 00:06:52 +00:00
} else {
/* we didn't find "name" */
/* clear the empty characters in the begining*/
while ( * input & & ( * input < 33 ) )
input + + ;
/* clear the empty characters in the end */
while ( * end & & ( * end < 33 ) & & end > input )
end - - ;
2004-07-16 04:40:54 +00:00
if ( end > = input ) {
bytes = ( int ) ( end - input ) + 1 ;
/* protect the output buffer */
if ( bytes > maxbytes ) {
bytes = maxbytes ;
}
strncpy ( output , input , bytes ) ; /* safe */
output [ maxbytes ] = ' \0 ' ;
}
2003-06-08 16:26:08 +00:00
else
2004-07-16 04:40:54 +00:00
return ( NULL ) ;
2003-06-06 00:06:52 +00:00
}
return output ;
}
2004-05-13 19:54:42 +00:00
2004-06-21 04:29:50 +00:00
/*--- get_rpid_num: Get caller id number from Remote-Party-ID header field
2004-07-15 22:14:27 +00:00
* Returns true if number should be restricted ( privacy setting found )
* output is set to NULL if no number found
2004-06-21 04:29:50 +00:00
*/
static int get_rpid_num ( char * input , char * output , int maxlen )
{
char * start ;
char * end ;
start = strchr ( input , ' : ' ) ;
if ( ! start ) {
2004-07-08 11:05:03 +00:00
output [ 0 ] = ' \0 ' ;
2004-06-21 04:29:50 +00:00
return 0 ;
}
start + + ;
/* we found "number" */
strncpy ( output , start , maxlen - 1 ) ;
output [ maxlen - 1 ] = ' \0 ' ;
end = strchr ( output , ' @ ' ) ;
if ( end )
* end = ' \0 ' ;
if ( strstr ( input , " privacy=full " ) | | strstr ( input , " privacy=uri " ) )
2004-10-02 00:58:31 +00:00
return AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED ;
2004-06-21 04:29:50 +00:00
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- check_user: Check if matching user or peer is defined ---*/
2004-06-21 14:39:19 +00:00
static int check_user_full ( struct sip_pvt * p , struct sip_request * req , char * cmd , char * uri , int reliable , struct sockaddr_in * sin , int ignore , char * mailbox , int mailboxlen )
2002-09-12 17:13:17 +00:00
{
struct sip_user * user ;
2003-03-18 18:11:43 +00:00
struct sip_peer * peer ;
2003-02-07 04:07:10 +00:00
char * of , from [ 256 ] = " " , * c ;
2004-06-21 04:29:50 +00:00
char * rpid , rpid_num [ 50 ] ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-02-07 04:07:10 +00:00
int res = 0 ;
char * t ;
2003-06-06 00:06:52 +00:00
char calleridname [ 50 ] ;
2004-06-18 13:53:48 +00:00
int debug = sip_debug_test_addr ( sin ) ;
2003-02-07 04:07:10 +00:00
/* Terminate URI */
t = uri ;
while ( * t & & ( * t > 32 ) & & ( * t ! = ' ; ' ) )
t + + ;
* t = ' \0 ' ;
2002-09-12 17:13:17 +00:00
of = get_header ( req , " From " ) ;
strncpy ( from , of , sizeof ( from ) - 1 ) ;
2003-06-06 00:06:52 +00:00
memset ( calleridname , 0 , sizeof ( calleridname ) ) ;
2004-07-16 04:40:54 +00:00
get_calleridname ( from , calleridname , sizeof ( calleridname ) ) ;
2004-06-21 04:29:50 +00:00
rpid = get_header ( req , " Remote-Party-ID " ) ;
memset ( rpid_num , 0 , sizeof ( rpid_num ) ) ;
if ( ! ast_strlen_zero ( rpid ) )
2004-10-02 00:58:31 +00:00
p - > callingpres = get_rpid_num ( rpid , rpid_num , sizeof ( rpid_num ) ) ;
2004-06-21 04:29:50 +00:00
2002-09-12 17:13:17 +00:00
of = ditch_braces ( from ) ;
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( p - > exten ) ) {
2003-11-28 04:01:25 +00:00
t = uri ;
if ( ! strncmp ( t , " sip: " , 4 ) )
t + = 4 ;
strncpy ( p - > exten , t , sizeof ( p - > exten ) - 1 ) ;
t = strchr ( p - > exten , ' @ ' ) ;
if ( t )
* t = ' \0 ' ;
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( p - > our_contact ) )
2003-11-28 04:01:25 +00:00
build_contact ( p ) ;
}
2003-02-24 21:10:24 +00:00
if ( strncmp ( of , " sip: " , 4 ) ) {
ast_log ( LOG_NOTICE , " From address missing 'sip:', using it anyway \n " ) ;
} else
2002-09-12 17:13:17 +00:00
of + = 4 ;
/* Get just the username part */
if ( ( c = strchr ( of , ' @ ' ) ) )
* c = ' \0 ' ;
if ( ( c = strchr ( of , ' : ' ) ) )
* c = ' \0 ' ;
2004-10-02 00:58:31 +00:00
strncpy ( p - > cid_num , of , sizeof ( p - > cid_num ) - 1 ) ;
2004-10-03 14:57:01 +00:00
ast_shrink_phone_number ( p - > cid_num ) ;
2003-06-06 00:06:52 +00:00
if ( * calleridname )
2004-10-02 00:58:31 +00:00
strncpy ( p - > cid_name , calleridname , sizeof ( p - > cid_name ) - 1 ) ;
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( of ) )
2002-09-12 17:13:17 +00:00
return 0 ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & userl . lock ) ;
2004-04-26 14:54:33 +00:00
user = find_user ( of ) ;
2004-07-15 22:14:27 +00:00
/* Find user based on user name in the from header */
2004-04-26 14:54:33 +00:00
if ( user & & ast_apply_ha ( user - > ha , sin ) ) {
p - > nat = user - > nat ;
2004-06-25 05:52:55 +00:00
# ifdef OSP_SUPPORT
p - > ospauth = user - > ospauth ;
# endif
p - > trustrpid = user - > trustrpid ;
2004-06-26 21:17:12 +00:00
p - > progressinband = user - > progressinband ;
2004-06-25 05:52:55 +00:00
/* replace callerid if rpid found, and not restricted */
if ( ! ast_strlen_zero ( rpid_num ) & & p - > trustrpid ) {
if ( * calleridname )
2004-10-02 00:58:31 +00:00
strncpy ( p - > cid_name , calleridname , sizeof ( p - > cid_name ) - 1 ) ;
strncpy ( p - > cid_num , rpid_num , sizeof ( p - > cid_num ) - 1 ) ;
2004-10-03 14:57:01 +00:00
ast_shrink_phone_number ( p - > cid_num ) ;
2004-06-25 05:52:55 +00:00
}
2004-04-26 14:54:33 +00:00
if ( p - > rtp ) {
2004-08-27 02:45:35 +00:00
ast_log ( LOG_DEBUG , " Setting NAT on RTP to %d \n " , ( p - > nat & SIP_NAT_ROUTE ) ) ;
ast_rtp_setnat ( p - > rtp , ( p - > nat & SIP_NAT_ROUTE ) ) ;
2004-04-26 14:54:33 +00:00
}
if ( p - > vrtp ) {
2004-08-27 02:45:35 +00:00
ast_log ( LOG_DEBUG , " Setting NAT on VRTP to %d \n " , ( p - > nat & SIP_NAT_ROUTE ) ) ;
ast_rtp_setnat ( p - > vrtp , ( p - > nat & SIP_NAT_ROUTE ) ) ;
2004-04-26 14:54:33 +00:00
}
if ( ! ( res = check_auth ( p , req , p - > randdata , sizeof ( p - > randdata ) , user - > name , user - > secret , user - > md5secret , cmd , uri , reliable , ignore ) ) ) {
sip_cancel_destroy ( p ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( user - > context ) )
2004-04-26 14:54:33 +00:00
strncpy ( p - > context , user - > context , sizeof ( p - > context ) - 1 ) ;
2004-10-03 14:57:01 +00:00
if ( ! ast_strlen_zero ( user - > cid_num ) & & ! ast_strlen_zero ( p - > cid_num ) ) {
2004-10-02 00:58:31 +00:00
strncpy ( p - > cid_num , user - > cid_num , sizeof ( p - > cid_num ) - 1 ) ;
2004-10-03 14:57:01 +00:00
ast_shrink_phone_number ( p - > cid_num ) ;
}
2004-10-02 00:58:31 +00:00
if ( ! ast_strlen_zero ( user - > cid_name ) & & ! ast_strlen_zero ( p - > cid_name ) )
2004-10-02 02:31:36 +00:00
strncpy ( p - > cid_name , user - > cid_name , sizeof ( p - > cid_name ) - 1 ) ;
2004-04-26 14:54:33 +00:00
strncpy ( p - > username , user - > name , sizeof ( p - > username ) - 1 ) ;
strncpy ( p - > peersecret , user - > secret , sizeof ( p - > peersecret ) - 1 ) ;
strncpy ( p - > peermd5secret , user - > md5secret , sizeof ( p - > peermd5secret ) - 1 ) ;
strncpy ( p - > accountcode , user - > accountcode , sizeof ( p - > accountcode ) - 1 ) ;
strncpy ( p - > language , user - > language , sizeof ( p - > language ) - 1 ) ;
2004-05-04 20:10:37 +00:00
strncpy ( p - > musicclass , user - > musicclass , sizeof ( p - > musicclass ) - 1 ) ;
2004-04-26 14:54:33 +00:00
p - > canreinvite = user - > canreinvite ;
p - > amaflags = user - > amaflags ;
p - > callgroup = user - > callgroup ;
p - > pickupgroup = user - > pickupgroup ;
2004-10-02 00:58:31 +00:00
p - > callingpres = user - > callingpres ;
2004-04-26 14:54:33 +00:00
p - > capability = user - > capability ;
p - > jointcapability = user - > capability ;
2004-08-18 13:55:03 +00:00
if ( p - > peercapability )
p - > jointcapability & = p - > peercapability ;
2004-06-21 06:11:56 +00:00
p - > promiscredir = user - > promiscredir ;
2004-04-26 14:54:33 +00:00
if ( user - > dtmfmode ) {
p - > dtmfmode = user - > dtmfmode ;
if ( p - > dtmfmode & SIP_DTMF_RFC2833 )
p - > noncodeccapability | = AST_RTP_DTMF ;
else
p - > noncodeccapability & = ~ AST_RTP_DTMF ;
2003-02-07 04:07:10 +00:00
}
2002-09-12 17:13:17 +00:00
}
2004-06-18 13:53:48 +00:00
if ( user & & debug )
2004-05-06 01:33:24 +00:00
ast_verbose ( " Found user '%s' \n " , user - > name ) ;
} else {
2004-10-09 20:08:41 +00:00
if ( user ) {
if ( debug )
ast_verbose ( " Found user '%s', but fails host access \n " , user - > name ) ;
if ( user - > temponly )
destroy_user ( user ) ;
}
2004-05-06 01:33:24 +00:00
user = NULL ;
2002-09-12 17:13:17 +00:00
}
2004-10-09 20:08:41 +00:00
/* Temp user gets cleaned up at the end */
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & userl . lock ) ;
2003-03-18 18:11:43 +00:00
if ( ! user ) {
2004-07-15 22:14:27 +00:00
/* If we didn't find a user match, check for peers */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & peerl . lock ) ;
2004-05-24 14:44:47 +00:00
/* Look for peer based on the IP address we received data from */
/* If peer is registred from this IP address or have this as a default
IP address , this call is from the peer
*/
2004-04-26 14:54:33 +00:00
peer = find_peer ( NULL , & p - > recv ) ;
2004-01-22 16:29:02 +00:00
if ( peer ) {
2004-06-18 13:53:48 +00:00
if ( debug )
2004-05-24 14:44:47 +00:00
ast_verbose ( " Found peer '%s' \n " , peer - > name ) ;
/* Take the peer */
p - > nat = peer - > nat ;
2004-06-25 05:52:55 +00:00
p - > trustrpid = peer - > trustrpid ;
2004-06-26 21:17:12 +00:00
p - > progressinband = peer - > progressinband ;
2004-06-25 05:52:55 +00:00
/* replace callerid if rpid found, and not restricted */
if ( ! ast_strlen_zero ( rpid_num ) & & p - > trustrpid ) {
if ( * calleridname )
2004-10-02 00:58:31 +00:00
strncpy ( p - > cid_name , calleridname , sizeof ( p - > cid_name ) - 1 ) ;
strncpy ( p - > cid_num , rpid_num , sizeof ( p - > cid_num ) - 1 ) ;
2004-10-03 14:57:01 +00:00
ast_shrink_phone_number ( p - > cid_num ) ;
2004-06-25 05:52:55 +00:00
}
# ifdef OSP_SUPPORT
p - > ospauth = peer - > ospauth ;
# endif
2004-05-24 14:44:47 +00:00
if ( p - > rtp ) {
2004-08-27 02:45:35 +00:00
ast_log ( LOG_DEBUG , " Setting NAT on RTP to %d \n " , ( p - > nat & SIP_NAT_ROUTE ) ) ;
ast_rtp_setnat ( p - > rtp , ( p - > nat & SIP_NAT_ROUTE ) ) ;
2004-05-24 14:44:47 +00:00
}
if ( p - > vrtp ) {
2004-08-27 02:45:35 +00:00
ast_log ( LOG_DEBUG , " Setting NAT on VRTP to %d \n " , ( p - > nat & SIP_NAT_ROUTE ) ) ;
ast_rtp_setnat ( p - > vrtp , ( p - > nat & SIP_NAT_ROUTE ) ) ;
2004-05-24 14:44:47 +00:00
}
2004-07-08 11:05:03 +00:00
strncpy ( p - > peersecret , peer - > secret , sizeof ( p - > peersecret ) - 1 ) ;
p - > peersecret [ sizeof ( p - > peersecret ) - 1 ] = ' \0 ' ;
strncpy ( p - > peermd5secret , peer - > md5secret , sizeof ( p - > peermd5secret ) - 1 ) ;
p - > peermd5secret [ sizeof ( p - > peermd5secret ) - 1 ] = ' \0 ' ;
2004-05-24 14:44:47 +00:00
if ( peer - > insecure > 1 ) {
/* Pretend there is no required authentication if insecure is "very" */
2004-07-08 11:05:03 +00:00
p - > peersecret [ 0 ] = ' \0 ' ;
p - > peermd5secret [ 0 ] = ' \0 ' ;
2004-05-24 14:44:47 +00:00
}
2004-05-28 15:47:57 +00:00
if ( ! ( res = check_auth ( p , req , p - > randdata , sizeof ( p - > randdata ) , peer - > name , p - > peersecret , p - > peermd5secret , cmd , uri , reliable , ignore ) ) ) {
2003-03-18 18:11:43 +00:00
p - > canreinvite = peer - > canreinvite ;
2003-08-22 16:36:33 +00:00
strncpy ( p - > peername , peer - > name , sizeof ( p - > peername ) - 1 ) ;
2004-05-02 16:30:05 +00:00
strncpy ( p - > authname , peer - > name , sizeof ( p - > authname ) - 1 ) ;
2004-06-21 14:39:19 +00:00
if ( mailbox )
snprintf ( mailbox , mailboxlen , " ,%s, " , peer - > mailbox ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( peer - > username ) ) {
2004-05-02 16:17:40 +00:00
strncpy ( p - > username , peer - > username , sizeof ( p - > username ) - 1 ) ;
2004-05-02 16:30:05 +00:00
strncpy ( p - > authname , peer - > username , sizeof ( p - > authname ) - 1 ) ;
2004-05-02 16:17:40 +00:00
}
2004-08-31 16:49:20 +00:00
strncpy ( p - > fullcontact , peer - > fullcontact , sizeof ( p - > fullcontact ) - 1 ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( peer - > context ) )
2003-04-09 04:00:43 +00:00
strncpy ( p - > context , peer - > context , sizeof ( p - > context ) - 1 ) ;
2003-08-22 18:51:58 +00:00
strncpy ( p - > peersecret , peer - > secret , sizeof ( p - > peersecret ) - 1 ) ;
2003-10-15 17:32:19 +00:00
strncpy ( p - > peermd5secret , peer - > md5secret , sizeof ( p - > peermd5secret ) - 1 ) ;
2003-04-09 04:00:43 +00:00
p - > callgroup = peer - > callgroup ;
p - > pickupgroup = peer - > pickupgroup ;
2003-10-23 03:50:34 +00:00
p - > capability = peer - > capability ;
2003-10-23 03:58:40 +00:00
p - > jointcapability = peer - > capability ;
2004-08-18 13:55:03 +00:00
if ( p - > peercapability )
p - > jointcapability & = p - > peercapability ;
2004-06-21 06:11:56 +00:00
p - > promiscredir = peer - > promiscredir ;
2003-03-18 18:11:43 +00:00
if ( peer - > dtmfmode ) {
p - > dtmfmode = peer - > dtmfmode ;
if ( p - > dtmfmode & SIP_DTMF_RFC2833 )
2003-03-27 20:13:47 +00:00
p - > noncodeccapability | = AST_RTP_DTMF ;
2003-03-18 18:11:43 +00:00
else
2003-03-27 20:13:47 +00:00
p - > noncodeccapability & = ~ AST_RTP_DTMF ;
2003-03-18 18:11:43 +00:00
}
2004-05-24 14:44:47 +00:00
}
2004-10-07 15:46:08 +00:00
if ( peer - > temponly )
destroy_peer ( peer ) ;
2004-05-06 01:33:24 +00:00
} else
2004-06-18 13:53:48 +00:00
if ( debug )
2004-06-29 12:56:46 +00:00
ast_verbose ( " Found no matching peer or user for '%s:%d' \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > recv . sin_addr ) , ntohs ( p - > recv . sin_port ) ) ;
2004-05-24 14:44:47 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2004-05-06 01:33:24 +00:00
2003-03-18 18:11:43 +00:00
}
2004-06-21 04:29:50 +00:00
2004-10-09 20:08:41 +00:00
if ( user & & user - > temponly )
2004-10-07 18:27:12 +00:00
destroy_user ( user ) ;
2003-02-07 04:07:10 +00:00
return res ;
}
2004-06-21 14:39:19 +00:00
static int check_user ( struct sip_pvt * p , struct sip_request * req , char * cmd , char * uri , int reliable , struct sockaddr_in * sin , int ignore )
{
return check_user_full ( p , req , cmd , uri , reliable , sin , ignore , NULL , 0 ) ;
}
2004-05-13 19:54:42 +00:00
/*--- get_msg_text: Get text out of a SIP MESSAGE ---*/
2003-02-07 04:07:10 +00:00
static int get_msg_text ( char * buf , int len , struct sip_request * req )
{
int x ;
2003-08-15 18:50:49 +00:00
int y ;
2004-07-08 11:05:03 +00:00
buf [ 0 ] = ' \0 ' ;
2003-08-15 18:50:49 +00:00
y = len - strlen ( buf ) - 5 ;
if ( y < 0 )
y = 0 ;
2003-02-07 04:07:10 +00:00
for ( x = 0 ; x < req - > lines ; x + + ) {
2004-07-16 04:40:54 +00:00
strncat ( buf , req - > line [ x ] , y ) ; /* safe */
2004-01-11 18:50:46 +00:00
y - = strlen ( req - > line [ x ] ) + 1 ;
if ( y < 0 )
y = 0 ;
if ( y ! = 0 )
2004-07-16 04:40:54 +00:00
strcat ( buf , " \n " ) ; /* safe */
2003-02-07 04:07:10 +00:00
}
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- receive_message: Receive SIP MESSAGE method messages ---*/
/* we handle messages within current calls currently */
2003-02-07 04:07:10 +00:00
static void receive_message ( struct sip_pvt * p , struct sip_request * req )
{
char buf [ 1024 ] ;
struct ast_frame f ;
if ( get_msg_text ( buf , sizeof ( buf ) , req ) ) {
ast_log ( LOG_WARNING , " Unable to retrieve text from %s \n " , p - > callid ) ;
return ;
}
if ( p - > owner ) {
2004-05-01 21:25:31 +00:00
if ( sip_debug_test_pvt ( p ) )
2003-02-07 04:07:10 +00:00
ast_verbose ( " Message received: '%s' \n " , buf ) ;
2003-03-08 06:00:17 +00:00
memset ( & f , 0 , sizeof ( f ) ) ;
f . frametype = AST_FRAME_TEXT ;
f . subclass = 0 ;
f . offset = 0 ;
f . data = buf ;
f . datalen = strlen ( buf ) ;
2004-04-06 22:17:32 +00:00
ast_queue_frame ( p - > owner , & f ) ;
2003-02-07 04:07:10 +00:00
}
}
2004-05-13 19:54:42 +00:00
/*--- sip_show_inuse: CLI Command to show calls within limits set by
outgoinglimit and incominglimit - - - */
2003-07-26 23:14:27 +00:00
static int sip_show_inuse ( int fd , int argc , char * argv [ ] ) {
2003-09-13 20:26:20 +00:00
# define FORMAT "%-15.15s %-15.15s %-15.15s %-15.15s %-15.15s\n"
# define FORMAT2 "%-15.15s %-15.15s %-15.15s %-15.15s %-15.15s\n"
2003-07-26 23:14:27 +00:00
struct sip_user * user ;
2004-07-16 04:40:54 +00:00
char ilimits [ 40 ] = " " ;
char olimits [ 40 ] = " " ;
2003-09-13 20:26:20 +00:00
char iused [ 40 ] ;
char oused [ 40 ] ;
2003-07-26 23:14:27 +00:00
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & userl . lock ) ;
2003-07-26 23:14:27 +00:00
user = userl . users ;
2003-09-13 20:26:20 +00:00
ast_cli ( fd , FORMAT , " Username " , " incoming " , " Limit " , " outgoing " , " Limit " ) ;
2003-07-26 23:14:27 +00:00
for ( user = userl . users ; user ; user = user - > next ) {
if ( user - > incominglimit )
2003-09-13 20:26:20 +00:00
snprintf ( ilimits , sizeof ( ilimits ) , " %d " , user - > incominglimit ) ;
else
2004-07-16 04:40:54 +00:00
strncpy ( ilimits , " N/A " , sizeof ( ilimits ) - 1 ) ;
2003-09-13 20:26:20 +00:00
if ( user - > outgoinglimit )
snprintf ( olimits , sizeof ( olimits ) , " %d " , user - > outgoinglimit ) ;
2003-07-26 23:14:27 +00:00
else
2004-07-16 04:40:54 +00:00
strncpy ( olimits , " N/A " , sizeof ( olimits ) - 1 ) ;
2003-09-13 20:26:20 +00:00
snprintf ( iused , sizeof ( iused ) , " %d " , user - > inUse ) ;
snprintf ( oused , sizeof ( oused ) , " %d " , user - > outUse ) ;
ast_cli ( fd , FORMAT2 , user - > name , iused , ilimits , oused , olimits ) ;
2003-07-26 23:14:27 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & userl . lock ) ;
2003-07-26 23:14:27 +00:00
return RESULT_SUCCESS ;
# undef FORMAT
# undef FORMAT2
}
2004-08-27 02:45:35 +00:00
static char * nat2str ( int nat )
{
switch ( nat ) {
case SIP_NAT_NEVER :
return " No " ;
case SIP_NAT_ROUTE :
return " Route " ;
case SIP_NAT_ALWAYS :
return " Always " ;
case SIP_NAT_RFC3581 :
return " RFC3581 " ;
default :
return " Unknown " ;
}
}
2004-05-13 19:54:42 +00:00
/*--- sip_show_users: CLI Command 'SIP Show Users' ---*/
2003-02-07 04:07:10 +00:00
static int sip_show_users ( int fd , int argc , char * argv [ ] )
{
2004-05-13 19:51:54 +00:00
# define FORMAT "%-15.15s %-15.15s %-15.15s %-15.15s %-5.5s%-5.5s\n"
2003-02-07 04:07:10 +00:00
struct sip_user * user ;
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & userl . lock ) ;
2004-05-13 19:51:54 +00:00
ast_cli ( fd , FORMAT , " Username " , " Secret " , " Accountcode " , " Def.Context " , " ACL " , " NAT " ) ;
2003-02-07 04:07:10 +00:00
for ( user = userl . users ; user ; user = user - > next ) {
2004-05-13 19:51:54 +00:00
ast_cli ( fd , FORMAT , user - > name ,
user - > secret ,
user - > accountcode ,
user - > context ,
user - > ha ? " Yes " : " No " ,
2004-08-27 02:45:35 +00:00
nat2str ( user - > nat ) ) ;
2003-02-07 04:07:10 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & userl . lock ) ;
2003-02-07 04:07:10 +00:00
return RESULT_SUCCESS ;
# undef FORMAT
}
2004-05-13 19:54:42 +00:00
/*--- sip_show_peers: CLI Show Peers command */
2003-02-07 04:07:10 +00:00
static int sip_show_peers ( int fd , int argc , char * argv [ ] )
{
2004-05-08 20:58:24 +00:00
# define FORMAT2 "%-15.15s %-15.15s %s %s %s %-15.15s %-8s %-10s\n"
# define FORMAT "%-15.15s %-15.15s %s %s %s %-15.15s %-8d %-10s\n"
2003-02-07 04:07:10 +00:00
struct sip_peer * peer ;
char name [ 256 ] = " " ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2004-10-13 01:05:31 +00:00
int total_peers = 0 ;
int peers_online = 0 ;
int peers_offline = 0 ;
2004-05-02 05:38:20 +00:00
if ( argc ! = 3 & & argc ! = 5 )
2003-02-07 04:07:10 +00:00
return RESULT_SHOWUSAGE ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & peerl . lock ) ;
2004-05-07 18:57:17 +00:00
ast_cli ( fd , FORMAT2 , " Name/username " , " Host " , " Dyn " , " Nat " , " ACL " , " Mask " , " Port " , " Status " ) ;
2004-10-13 01:05:31 +00:00
2003-02-07 04:07:10 +00:00
for ( peer = peerl . peers ; peer ; peer = peer - > next ) {
char nm [ 20 ] = " " ;
2004-07-16 04:40:54 +00:00
char status [ 20 ] = " " ;
2004-05-02 05:38:20 +00:00
int print_line = - 1 ;
char srch [ 2000 ] ;
2004-10-13 01:05:31 +00:00
2004-07-08 11:05:03 +00:00
ast_inet_ntoa ( nm , sizeof ( nm ) , peer - > mask ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( peer - > username ) )
2003-02-07 04:07:10 +00:00
snprintf ( name , sizeof ( name ) , " %s/%s " , peer - > name , peer - > username ) ;
else
strncpy ( name , peer - > name , sizeof ( name ) - 1 ) ;
if ( peer - > maxms ) {
2004-10-13 01:05:31 +00:00
if ( peer - > lastms < 0 ) {
2004-07-16 04:40:54 +00:00
strncpy ( status , " UNREACHABLE " , sizeof ( status ) - 1 ) ;
2004-10-13 01:05:31 +00:00
peers_offline + + ;
} else if ( peer - > lastms > peer - > maxms ) {
2003-02-07 04:07:10 +00:00
snprintf ( status , sizeof ( status ) , " LAGGED (%d ms) " , peer - > lastms ) ;
2004-10-13 01:05:31 +00:00
peers_online + + ;
} else if ( peer - > lastms ) {
2003-02-07 04:07:10 +00:00
snprintf ( status , sizeof ( status ) , " OK (%d ms) " , peer - > lastms ) ;
2004-10-13 01:05:31 +00:00
peers_online + + ;
} else {
/* Checking if port is 0 */
if ( ntohs ( peer - > addr . sin_port ) = = 0 ) {
peers_offline + + ;
} else {
peers_online + + ;
}
2004-07-16 04:40:54 +00:00
strncpy ( status , " UNKNOWN " , sizeof ( status ) - 1 ) ;
2004-10-13 01:05:31 +00:00
}
2004-10-16 22:40:48 +00:00
} else {
2004-07-16 04:40:54 +00:00
strncpy ( status , " Unmonitored " , sizeof ( status ) - 1 ) ;
2004-10-16 22:40:48 +00:00
/* Checking if port is 0 */
if ( ntohs ( peer - > addr . sin_port ) = = 0 ) {
peers_offline + + ;
} else {
peers_online + + ;
2004-07-08 11:05:03 +00:00
}
2004-10-16 22:40:48 +00:00
}
snprintf ( srch , sizeof ( srch ) , FORMAT , name ,
peer - > addr . sin_addr . s_addr ? ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , peer - > addr . sin_addr ) : " (Unspecified) " ,
peer - > dynamic ? " D " : " " , /* Dynamic or not? */
( peer - > nat & SIP_NAT_ROUTE ) ? " N " : " " , /* NAT=yes? */
peer - > ha ? " A " : " " , /* permit/deny */
nm , ntohs ( peer - > addr . sin_port ) , status ) ;
if ( argc = = 5 ) {
if ( ! strcasecmp ( argv [ 3 ] , " include " ) & & strstr ( srch , argv [ 4 ] ) ) {
print_line = - 1 ;
} else if ( ! strcasecmp ( argv [ 3 ] , " exclude " ) & & ! strstr ( srch , argv [ 4 ] ) ) {
print_line = 1 ;
} else if ( ! strcasecmp ( argv [ 3 ] , " begin " ) & & ! strncasecmp ( srch , argv [ 4 ] , strlen ( argv [ 4 ] ) ) ) {
print_line = - 1 ;
} else {
print_line = 0 ;
}
}
2004-05-02 05:38:20 +00:00
if ( print_line ) {
2004-05-07 18:57:17 +00:00
ast_cli ( fd , FORMAT , name ,
2004-06-29 12:56:46 +00:00
peer - > addr . sin_addr . s_addr ? ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , peer - > addr . sin_addr ) : " (Unspecified) " ,
2004-05-07 18:57:17 +00:00
peer - > dynamic ? " D " : " " , /* Dynamic or not? */
2004-08-27 02:45:35 +00:00
( peer - > nat & SIP_NAT_ROUTE ) ? " N " : " " , /* NAT=yes? */
2004-05-07 18:57:17 +00:00
peer - > ha ? " A " : " " , /* permit/deny */
nm ,
ntohs ( peer - > addr . sin_port ) , status ) ;
2004-05-02 05:38:20 +00:00
}
2004-10-13 01:05:31 +00:00
total_peers + + ;
2003-02-07 04:07:10 +00:00
}
2004-10-16 22:40:48 +00:00
ast_cli ( fd , " %d sip peers loaded [%d online , %d offline] \n " , total_peers , peers_online , peers_offline ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2003-02-07 04:07:10 +00:00
return RESULT_SUCCESS ;
# undef FORMAT
# undef FORMAT2
}
2004-05-08 20:58:24 +00:00
/*--- print_group: Print call group and pickup group ---*/
static void print_group ( int fd , unsigned int group )
{
unsigned int i ;
int first = 1 ;
for ( i = 0 ; i < = 31 ; i + + ) { /* Max group is 31 */
if ( group & ( 1 < < i ) ) {
if ( ! first ) {
ast_cli ( fd , " , " ) ;
} else {
first = 0 ;
}
ast_cli ( fd , " %u " , i ) ;
}
}
ast_cli ( fd , " (%u) \n " , group ) ;
}
2004-05-07 18:57:17 +00:00
/*--- sip_show_peer: Show one peer in detail ---*/
static int sip_show_peer ( int fd , int argc , char * argv [ ] )
{
2004-07-16 04:40:54 +00:00
char status [ 30 ] = " " ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2004-05-07 18:57:17 +00:00
struct sip_peer * peer ;
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
ast_mutex_lock ( & peerl . lock ) ;
peer = find_peer ( argv [ 3 ] , NULL ) ;
if ( peer ) {
ast_cli ( fd , " \n \n " ) ;
ast_cli ( fd , " * Name : %s \n " , peer - > name ) ;
2004-05-08 20:58:24 +00:00
ast_cli ( fd , " Secret : %s \n " , ast_strlen_zero ( peer - > secret ) ? " <Not set> " : " <Set> " ) ;
ast_cli ( fd , " MD5Secret : %s \n " , ast_strlen_zero ( peer - > md5secret ) ? " <Not set> " : " <Set> " ) ;
2004-05-07 18:57:17 +00:00
ast_cli ( fd , " Context : %s \n " , peer - > context ) ;
ast_cli ( fd , " Language : %s \n " , peer - > language ) ;
ast_cli ( fd , " FromUser : %s \n " , peer - > fromuser ) ;
ast_cli ( fd , " FromDomain : %s \n " , peer - > fromdomain ) ;
2004-05-08 20:58:24 +00:00
ast_cli ( fd , " Callgroup : " ) ;
print_group ( fd , peer - > callgroup ) ;
ast_cli ( fd , " Pickupgroup : " ) ;
print_group ( fd , peer - > pickupgroup ) ;
2004-05-07 18:57:17 +00:00
ast_cli ( fd , " Mailbox : %s \n " , peer - > mailbox ) ;
ast_cli ( fd , " LastMsgsSent : %d \n " , peer - > lastmsgssent ) ;
ast_cli ( fd , " Dynamic : %s \n " , ( peer - > dynamic ? " Yes " : " No " ) ) ;
ast_cli ( fd , " Expire : %d \n " , peer - > expire ) ;
ast_cli ( fd , " Expiry : %d \n " , peer - > expiry ) ;
ast_cli ( fd , " Insecure : %s \n " , ( peer - > insecure ? ( ( peer - > insecure = = 2 ) ? " Very " : " Yes " ) : " No " ) ) ;
2004-08-27 02:45:35 +00:00
ast_cli ( fd , " Nat : %s \n " , nat2str ( peer - > nat ) ) ;
2004-05-07 18:57:17 +00:00
ast_cli ( fd , " ACL : %s \n " , ( peer - > ha ? " Yes " : " No " ) ) ;
ast_cli ( fd , " CanReinvite : %s \n " , ( peer - > canreinvite ? " Yes " : " No " ) ) ;
2004-06-21 06:11:56 +00:00
ast_cli ( fd , " PromiscRedir : %s \n " , ( peer - > promiscredir ? " Yes " : " No " ) ) ;
2004-05-07 18:57:17 +00:00
2004-06-21 06:11:56 +00:00
/* - is enumerated */
2004-05-07 18:57:17 +00:00
ast_cli ( fd , " DTMFmode : " ) ;
if ( peer - > dtmfmode = = SIP_DTMF_RFC2833 )
ast_cli ( fd , " rfc2833 " ) ;
if ( peer - > dtmfmode = = SIP_DTMF_INFO )
ast_cli ( fd , " info " ) ;
if ( peer - > dtmfmode = = SIP_DTMF_INBAND )
ast_cli ( fd , " inband " ) ;
ast_cli ( fd , " \n " ) ;
ast_cli ( fd , " LastMsg : %d \n " , peer - > lastmsg ) ;
ast_cli ( fd , " ToHost : %s \n " , peer - > tohost ) ;
2004-06-29 12:56:46 +00:00
ast_cli ( fd , " Addr->IP : %s Port %d \n " , peer - > addr . sin_addr . s_addr ? ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , peer - > addr . sin_addr ) : " (Unspecified) " , ntohs ( peer - > addr . sin_port ) ) ;
ast_cli ( fd , " Defaddr->IP : %s Port %d \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , peer - > defaddr . sin_addr ) , ntohs ( peer - > defaddr . sin_port ) ) ;
2004-07-28 21:07:38 +00:00
ast_cli ( fd , " Username : %s \n " , peer - > username ) ;
2004-05-07 18:57:17 +00:00
ast_cli ( fd , " Codecs : " ) ;
/* This should really be a function in frame.c */
if ( peer - > capability & AST_FORMAT_G723_1 )
ast_cli ( fd , " G723 " ) ;
if ( peer - > capability & AST_FORMAT_GSM )
ast_cli ( fd , " GSM " ) ;
if ( peer - > capability & AST_FORMAT_ULAW )
ast_cli ( fd , " ULAW " ) ;
if ( peer - > capability & AST_FORMAT_ALAW )
ast_cli ( fd , " ALAW " ) ;
if ( peer - > capability & AST_FORMAT_G726 )
ast_cli ( fd , " G.726 " ) ;
if ( peer - > capability & AST_FORMAT_SLINEAR )
ast_cli ( fd , " SLINR " ) ;
if ( peer - > capability & AST_FORMAT_LPC10 )
ast_cli ( fd , " LPC10 " ) ;
if ( peer - > capability & AST_FORMAT_ADPCM )
ast_cli ( fd , " ADPCM " ) ;
if ( peer - > capability & AST_FORMAT_G729A )
ast_cli ( fd , " G.729A " ) ;
if ( peer - > capability & AST_FORMAT_SPEEX )
ast_cli ( fd , " SPEEX " ) ;
if ( peer - > capability & AST_FORMAT_ILBC )
ast_cli ( fd , " ILBC " ) ;
if ( peer - > capability & AST_FORMAT_JPEG )
ast_cli ( fd , " JPEG " ) ;
if ( peer - > capability & AST_FORMAT_PNG )
ast_cli ( fd , " PNG " ) ;
if ( peer - > capability & AST_FORMAT_H261 )
ast_cli ( fd , " H.261 " ) ;
if ( peer - > capability & AST_FORMAT_H263 )
ast_cli ( fd , " H.263 " ) ;
ast_cli ( fd , " \n " ) ;
ast_cli ( fd , " Status : " ) ;
if ( peer - > lastms < 0 )
2004-07-16 04:40:54 +00:00
strncpy ( status , " UNREACHABLE " , sizeof ( status ) - 1 ) ;
2004-05-07 18:57:17 +00:00
else if ( peer - > lastms > peer - > maxms )
snprintf ( status , sizeof ( status ) , " LAGGED (%d ms) " , peer - > lastms ) ;
else if ( peer - > lastms )
snprintf ( status , sizeof ( status ) , " OK (%d ms) " , peer - > lastms ) ;
else
2004-07-16 04:40:54 +00:00
strncpy ( status , " UNKNOWN " , sizeof ( status ) - 1 ) ;
2004-05-07 18:57:17 +00:00
ast_cli ( fd , " %s \n " , status ) ;
2004-05-09 21:05:43 +00:00
ast_cli ( fd , " Useragent : %s \n " , peer - > useragent ) ;
2004-08-31 16:49:20 +00:00
ast_cli ( fd , " Full Contact : %s \n " , peer - > fullcontact ) ;
2004-05-07 18:57:17 +00:00
ast_cli ( fd , " \n " ) ;
} else {
ast_cli ( fd , " Peer %s not found. \n " , argv [ 3 ] ) ;
ast_cli ( fd , " \n " ) ;
}
ast_mutex_unlock ( & peerl . lock ) ;
2004-10-07 18:27:12 +00:00
2004-10-12 21:51:08 +00:00
if ( peer & & peer - > temponly ) {
2004-10-07 18:27:12 +00:00
destroy_peer ( peer ) ;
}
2004-05-07 18:57:17 +00:00
return RESULT_SUCCESS ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_show_registry: Show SIP Registry (registrations with other SIP proxies ---*/
2003-02-07 04:07:10 +00:00
static int sip_show_registry ( int fd , int argc , char * argv [ ] )
{
2004-07-15 22:14:27 +00:00
# define FORMAT2 "%-30.30s %-12.12s %8.8s %-20.20s\n"
# define FORMAT "%-30.30s %-12.12s %8d %-20.20s\n"
2003-02-07 04:07:10 +00:00
struct sip_registry * reg ;
char host [ 80 ] ;
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
2004-02-02 22:35:33 +00:00
ast_mutex_lock ( & regl . lock ) ;
2003-02-07 04:07:10 +00:00
ast_cli ( fd , FORMAT2 , " Host " , " Username " , " Refresh " , " State " ) ;
2004-02-02 22:35:33 +00:00
for ( reg = regl . registrations ; reg ; reg = reg - > next ) {
2004-07-15 22:14:27 +00:00
snprintf ( host , sizeof ( host ) , " %s:%d " , reg - > hostname , reg - > portno ? reg - > portno : DEFAULT_SIP_PORT ) ;
2003-03-21 07:21:28 +00:00
ast_cli ( fd , FORMAT , host ,
reg - > username , reg - > refresh , regstate2str ( reg - > regstate ) ) ;
2003-02-07 04:07:10 +00:00
}
2004-02-02 22:35:33 +00:00
ast_mutex_unlock ( & regl . lock ) ;
2003-02-07 04:07:10 +00:00
return RESULT_SUCCESS ;
# undef FORMAT
# undef FORMAT2
}
2004-05-06 21:30:45 +00:00
/* Forward declaration */
static int __sip_show_channels ( int fd , int argc , char * argv [ ] , int subscriptions ) ;
/*--- sip_show_channels: Show active SIP channels ---*/
static int sip_show_channels ( int fd , int argc , char * argv [ ] )
{
return __sip_show_channels ( fd , argc , argv , 0 ) ;
}
/*--- sip_show_subscriptions: Show active SIP subscriptions ---*/
static int sip_show_subscriptions ( int fd , int argc , char * argv [ ] )
{
return __sip_show_channels ( fd , argc , argv , 1 ) ;
}
static int __sip_show_channels ( int fd , int argc , char * argv [ ] , int subscriptions )
2003-02-07 04:07:10 +00:00
{
2004-05-06 21:30:45 +00:00
# define FORMAT3 "%-15.15s %-10.10s %-21.21s %-15.15s\n"
2004-05-09 19:18:15 +00:00
# define FORMAT2 "%-15.15s %-10.10s %-11.11s %-11.11s %s\n"
2004-05-09 23:40:49 +00:00
# define FORMAT "%-15.15s %-10.10s %-11.11s %5.5d / %5.5d %-6.6s%s\n"
2003-02-07 04:07:10 +00:00
struct sip_pvt * cur ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-02-14 06:00:11 +00:00
int numchans = 0 ;
2003-02-07 04:07:10 +00:00
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & iflock ) ;
2003-02-07 04:07:10 +00:00
cur = iflist ;
2004-05-06 21:30:45 +00:00
if ( ! subscriptions )
2004-05-09 19:18:15 +00:00
ast_cli ( fd , FORMAT2 , " Peer " , " User/ANR " , " Call ID " , " Seq (Tx/Rx) " , " Format " ) ;
2004-05-06 21:30:45 +00:00
else
ast_cli ( fd , FORMAT3 , " Peer " , " User " , " Call ID " , " URI " ) ;
2003-02-07 04:07:10 +00:00
while ( cur ) {
2004-05-06 21:30:45 +00:00
if ( ! cur - > subscribed & & ! subscriptions ) {
2004-06-29 12:56:46 +00:00
ast_cli ( fd , FORMAT , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , cur - > sa . sin_addr ) ,
2004-10-02 00:58:31 +00:00
ast_strlen_zero ( cur - > username ) ? ( ast_strlen_zero ( cur - > cid_num ) ? " (None) " : cur - > cid_num ) : cur - > username ,
2004-05-06 21:30:45 +00:00
cur - > callid ,
cur - > ocseq , cur - > icseq ,
ast_getformatname ( cur - > owner ? cur - > owner - > nativeformats : 0 ) , cur - > needdestroy ? " (d) " : " " ) ;
2003-02-14 06:00:11 +00:00
numchans + + ;
2003-04-06 18:19:51 +00:00
}
2004-05-06 21:30:45 +00:00
if ( cur - > subscribed & & subscriptions ) {
2004-06-29 12:56:46 +00:00
ast_cli ( fd , FORMAT3 , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , cur - > sa . sin_addr ) ,
2004-10-02 00:58:31 +00:00
ast_strlen_zero ( cur - > username ) ? ( ast_strlen_zero ( cur - > cid_num ) ? " (None) " : cur - > cid_num ) : cur - > username ,
2004-05-06 21:30:45 +00:00
cur - > callid , cur - > uri ) ;
}
2003-04-06 18:19:51 +00:00
cur = cur - > next ;
2003-02-07 04:07:10 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
2004-05-06 21:30:45 +00:00
if ( ! subscriptions )
ast_cli ( fd , " %d active SIP channel(s) \n " , numchans ) ;
else
ast_cli ( fd , " %d active SIP subscriptions(s) \n " , numchans ) ;
2003-02-07 04:07:10 +00:00
return RESULT_SUCCESS ;
# undef FORMAT
# undef FORMAT2
2004-05-06 21:30:45 +00:00
# undef FORMAT3
2003-02-07 04:07:10 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- complete_sipch: Support routine for 'sip show channel' CLI ---*/
2003-03-10 22:05:28 +00:00
static char * complete_sipch ( char * line , char * word , int pos , int state )
{
int which = 0 ;
struct sip_pvt * cur ;
char * c = NULL ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & iflock ) ;
2003-03-10 22:05:28 +00:00
cur = iflist ;
while ( cur ) {
if ( ! strncasecmp ( word , cur - > callid , strlen ( word ) ) ) {
if ( + + which > state ) {
c = strdup ( cur - > callid ) ;
break ;
}
}
cur = cur - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
2003-03-10 22:05:28 +00:00
return c ;
}
2004-05-09 21:05:43 +00:00
/*--- sip_show_channel: Show details of one call ---*/
2003-03-10 22:05:28 +00:00
static int sip_show_channel ( int fd , int argc , char * argv [ ] )
{
struct sip_pvt * cur ;
2003-03-12 06:00:18 +00:00
char tmp [ 256 ] ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-10-02 06:46:19 +00:00
size_t len ;
2004-05-12 00:17:31 +00:00
int found = 0 ;
2003-03-10 22:05:28 +00:00
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
2003-10-02 06:46:19 +00:00
len = strlen ( argv [ 3 ] ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & iflock ) ;
2003-03-10 22:05:28 +00:00
cur = iflist ;
while ( cur ) {
2003-10-02 06:46:19 +00:00
if ( ! strncasecmp ( cur - > callid , argv [ 3 ] , len ) ) {
2004-05-09 21:05:43 +00:00
ast_cli ( fd , " \n " ) ;
if ( cur - > subscribed )
ast_cli ( fd , " * Subscription \n " ) ;
else
ast_cli ( fd , " * SIP Call \n " ) ;
ast_cli ( fd , " Direction: %s \n " , cur - > outgoing ? " Outgoing " : " Incoming " ) ;
ast_cli ( fd , " Call-ID: %s \n " , cur - > callid ) ;
ast_cli ( fd , " Our Codec Capability: %d \n " , cur - > capability ) ;
ast_cli ( fd , " Non-Codec Capability: %d \n " , cur - > noncodeccapability ) ;
2004-08-18 13:55:03 +00:00
ast_cli ( fd , " Their Codec Capability: %d \n " , cur - > peercapability ) ;
2004-05-09 21:05:43 +00:00
ast_cli ( fd , " Joint Codec Capability: %d \n " , cur - > jointcapability ) ;
ast_cli ( fd , " Format %s \n " , ast_getformatname ( cur - > owner ? cur - > owner - > nativeformats : 0 ) ) ;
2004-06-29 12:56:46 +00:00
ast_cli ( fd , " Theoretical Address: %s:%d \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , cur - > sa . sin_addr ) , ntohs ( cur - > sa . sin_port ) ) ;
ast_cli ( fd , " Received Address: %s:%d \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , cur - > recv . sin_addr ) , ntohs ( cur - > recv . sin_port ) ) ;
2004-08-27 02:45:35 +00:00
ast_cli ( fd , " NAT Support: %s \n " , nat2str ( cur - > nat ) ) ;
2004-05-09 21:05:43 +00:00
ast_cli ( fd , " Our Tag: %08d \n " , cur - > tag ) ;
ast_cli ( fd , " Their Tag: %s \n " , cur - > theirtag ) ;
ast_cli ( fd , " SIP User agent: %s \n " , cur - > useragent ) ;
if ( ! ast_strlen_zero ( cur - > username ) )
ast_cli ( fd , " Username: %s \n " , cur - > username ) ;
if ( ! ast_strlen_zero ( cur - > peername ) )
ast_cli ( fd , " Peername: %s \n " , cur - > peername ) ;
if ( ! ast_strlen_zero ( cur - > uri ) )
ast_cli ( fd , " Original uri: %s \n " , cur - > uri ) ;
2004-10-02 00:58:31 +00:00
if ( ! ast_strlen_zero ( cur - > cid_num ) )
ast_cli ( fd , " Caller-ID: %s \n " , cur - > cid_num ) ;
2004-05-09 21:05:43 +00:00
ast_cli ( fd , " Need Destroy: %d \n " , cur - > needdestroy ) ;
ast_cli ( fd , " Last Message: %s \n " , cur - > lastmsg ) ;
2004-06-21 06:11:56 +00:00
ast_cli ( fd , " Promiscuous Redir: %s \n " , cur - > promiscredir ? " Yes " : " No " ) ;
2004-05-09 21:05:43 +00:00
ast_cli ( fd , " Route: %s \n " , cur - > route ? cur - > route - > hop : " N/A " ) ;
2004-07-08 11:05:03 +00:00
tmp [ 0 ] = ' \0 ' ;
2003-03-12 06:00:18 +00:00
if ( cur - > dtmfmode & SIP_DTMF_RFC2833 )
2004-07-08 11:05:03 +00:00
strncat ( tmp , " rfc2833 " , sizeof ( tmp ) - strlen ( tmp ) - 1 ) ;
2003-03-12 06:00:18 +00:00
if ( cur - > dtmfmode & SIP_DTMF_INFO )
2004-07-08 11:05:03 +00:00
strncat ( tmp , " info " , sizeof ( tmp ) - strlen ( tmp ) - 1 ) ;
2003-03-12 06:00:18 +00:00
if ( cur - > dtmfmode & SIP_DTMF_INBAND )
2004-07-08 11:05:03 +00:00
strncat ( tmp , " inband " , sizeof ( tmp ) - strlen ( tmp ) - 1 ) ;
2004-05-09 21:05:43 +00:00
ast_cli ( fd , " DTMF Mode: %s \n \n " , tmp ) ;
2004-05-12 00:17:31 +00:00
found + + ;
2003-03-10 22:05:28 +00:00
}
cur = cur - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
2004-05-12 00:17:31 +00:00
if ( ! found )
ast_cli ( fd , " No such SIP Call ID starting with '%s' \n " , argv [ 3 ] ) ;
return RESULT_SUCCESS ;
}
/*--- sip_show_channel: Show details of one call ---*/
static int sip_show_history ( int fd , int argc , char * argv [ ] )
{
struct sip_pvt * cur ;
struct sip_history * hist ;
size_t len ;
int x ;
int found = 0 ;
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
if ( ! recordhistory )
ast_cli ( fd , " \n ***Note: History recording is currently DISABLED. Use 'sip history' to ENABLE. \n " ) ;
len = strlen ( argv [ 3 ] ) ;
ast_mutex_lock ( & iflock ) ;
cur = iflist ;
while ( cur ) {
if ( ! strncasecmp ( cur - > callid , argv [ 3 ] , len ) ) {
ast_cli ( fd , " \n " ) ;
if ( cur - > subscribed )
ast_cli ( fd , " * Subscription \n " ) ;
else
ast_cli ( fd , " * SIP Call \n " ) ;
x = 0 ;
hist = cur - > history ;
while ( hist ) {
x + + ;
ast_cli ( fd , " %d. %s \n " , x , hist - > event ) ;
hist = hist - > next ;
}
if ( ! x )
ast_cli ( fd , " Call '%s' has no history \n " , cur - > callid ) ;
found + + ;
}
cur = cur - > next ;
}
ast_mutex_unlock ( & iflock ) ;
if ( ! found )
2003-10-02 06:46:19 +00:00
ast_cli ( fd , " No such SIP Call ID starting with '%s' \n " , argv [ 3 ] ) ;
2003-03-10 22:05:28 +00:00
return RESULT_SUCCESS ;
}
2004-05-05 01:56:03 +00:00
2004-05-13 19:54:42 +00:00
/*--- receive_info: Receive SIP INFO Message ---*/
/* Doesn't read the duration of the DTMF signal */
2003-02-07 04:07:10 +00:00
static void receive_info ( struct sip_pvt * p , struct sip_request * req )
{
char buf [ 1024 ] = " " ;
2003-07-24 00:36:03 +00:00
unsigned int event ;
char resp = 0 ;
2003-02-07 04:07:10 +00:00
struct ast_frame f ;
char * c ;
2004-05-05 01:56:03 +00:00
/* Need to check the media/type */
2004-10-08 15:52:44 +00:00
if ( ! strcasecmp ( get_header ( req , " Content-Type " ) , " application/dtmf-relay " ) | |
! strcasecmp ( get_header ( req , " Content-Type " ) , " application/vnd.nortelnetworks.digits " ) ) {
2004-05-05 01:56:03 +00:00
/* Try getting the "signal=" part */
2004-05-08 20:58:24 +00:00
if ( ast_strlen_zero ( c = get_sdp ( req , " Signal " ) ) & & ast_strlen_zero ( c = get_sdp ( req , " d " ) ) ) {
2004-05-05 01:56:03 +00:00
ast_log ( LOG_WARNING , " Unable to retrieve DTMF signal from INFO message from %s \n " , p - > callid ) ;
transmit_response ( p , " 200 OK " , req ) ; /* Should return error */
return ;
2004-05-09 20:46:18 +00:00
} else {
strncpy ( buf , c , sizeof ( buf ) - 1 ) ;
2004-05-05 01:56:03 +00:00
}
if ( p - > owner ) { /* PBX call */
if ( ! ast_strlen_zero ( buf ) ) {
if ( sipdebug )
ast_verbose ( " * DTMF received: '%c' \n " , buf [ 0 ] ) ;
2003-10-21 17:07:18 +00:00
if ( buf [ 0 ] = = ' * ' )
event = 10 ;
else if ( buf [ 0 ] = = ' # ' )
event = 11 ;
else
event = atoi ( buf ) ;
2003-07-24 00:36:03 +00:00
if ( event < 10 ) {
resp = ' 0 ' + event ;
} else if ( event < 11 ) {
resp = ' * ' ;
} else if ( event < 12 ) {
resp = ' # ' ;
} else if ( event < 16 ) {
resp = ' A ' + ( event - 12 ) ;
}
2004-05-05 01:56:03 +00:00
/* Build DTMF frame and deliver to PBX for transmission to other call leg*/
2003-07-24 00:36:03 +00:00
memset ( & f , 0 , sizeof ( f ) ) ;
f . frametype = AST_FRAME_DTMF ;
f . subclass = resp ;
f . offset = 0 ;
f . data = NULL ;
f . datalen = 0 ;
2004-04-06 22:17:32 +00:00
ast_queue_frame ( p - > owner , & f ) ;
2004-05-05 01:56:03 +00:00
}
transmit_response ( p , " 200 OK " , req ) ;
return ;
2004-05-27 22:12:55 +00:00
} else {
transmit_response ( p , " 481 Call leg/transaction does not exist " , req ) ;
p - > needdestroy = 1 ;
2003-02-07 04:07:10 +00:00
}
2004-05-05 01:56:03 +00:00
return ;
2003-02-07 04:07:10 +00:00
}
2004-05-05 01:56:03 +00:00
/* Other type of INFO message, not really understood by Asterisk */
/* if (get_msg_text(buf, sizeof(buf), req)) { */
ast_log ( LOG_WARNING , " Unable to parse INFO message from %s. Content %s \n " , p - > callid , buf ) ;
transmit_response ( p , " 415 Unsupported media type " , req ) ;
return ;
2003-02-07 04:07:10 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- sip_do_debug: Enable SIP Debugging in CLI ---*/
2004-05-01 21:25:31 +00:00
static int sip_do_debug_ip ( int fd , int argc , char * argv [ ] )
2003-02-07 04:07:10 +00:00
{
2004-05-01 21:25:31 +00:00
struct hostent * hp ;
struct ast_hostent ahp ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2004-05-01 21:25:31 +00:00
int port = 0 ;
char * p , * arg ;
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
arg = argv [ 3 ] ;
p = strstr ( arg , " : " ) ;
if ( p ) {
* p = ' \0 ' ;
p + + ;
port = atoi ( p ) ;
}
hp = ast_gethostbyname ( arg , & ahp ) ;
if ( hp = = NULL ) {
2003-02-07 04:07:10 +00:00
return RESULT_SHOWUSAGE ;
2004-05-01 21:25:31 +00:00
}
debugaddr . sin_family = AF_INET ;
memcpy ( & debugaddr . sin_addr , hp - > h_addr , sizeof ( debugaddr . sin_addr ) ) ;
debugaddr . sin_port = htons ( port ) ;
if ( port = = 0 )
2004-06-29 12:56:46 +00:00
ast_cli ( fd , " SIP Debugging Enabled for IP: %s \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , debugaddr . sin_addr ) ) ;
2004-05-01 21:25:31 +00:00
else
2004-06-29 12:56:46 +00:00
ast_cli ( fd , " SIP Debugging Enabled for IP: %s:%d \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , debugaddr . sin_addr ) , port ) ;
2004-05-01 21:25:31 +00:00
sipdebug = 1 ;
return RESULT_SUCCESS ;
}
static int sip_do_debug_peer ( int fd , int argc , char * argv [ ] )
{
struct sip_peer * peer ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2004-05-01 21:25:31 +00:00
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
ast_mutex_lock ( & peerl . lock ) ;
for ( peer = peerl . peers ; peer ; peer = peer - > next )
if ( ! strcmp ( peer - > name , argv [ 3 ] ) )
break ;
ast_mutex_unlock ( & peerl . lock ) ;
if ( ! peer )
2004-10-07 15:46:08 +00:00
peer = realtime_peer ( argv [ 3 ] , NULL ) ;
2004-05-01 21:25:31 +00:00
if ( peer ) {
if ( peer - > addr . sin_addr . s_addr ) {
debugaddr . sin_family = AF_INET ;
memcpy ( & debugaddr . sin_addr , & peer - > addr . sin_addr , sizeof ( debugaddr . sin_addr ) ) ;
debugaddr . sin_port = peer - > addr . sin_port ;
2004-06-29 12:56:46 +00:00
ast_cli ( fd , " SIP Debugging Enabled for IP: %s:%d \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , debugaddr . sin_addr ) , ntohs ( debugaddr . sin_port ) ) ;
2004-05-01 21:25:31 +00:00
sipdebug = 1 ;
} else
ast_cli ( fd , " Unable to get IP address of peer '%s' \n " , argv [ 3 ] ) ;
if ( peer - > temponly )
2004-10-07 15:46:08 +00:00
destroy_peer ( peer ) ;
2004-05-01 21:25:31 +00:00
peer = NULL ;
} else
ast_cli ( fd , " No such peer '%s' \n " , argv [ 3 ] ) ;
return RESULT_SUCCESS ;
}
static int sip_do_debug ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 2 ) {
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
else if ( strncmp ( argv [ 2 ] , " ip \0 " , 3 ) = = 0 )
return sip_do_debug_ip ( fd , argc , argv ) ;
else if ( strncmp ( argv [ 2 ] , " peer \0 " , 5 ) = = 0 )
return sip_do_debug_peer ( fd , argc , argv ) ;
else return RESULT_SHOWUSAGE ;
}
2003-02-07 04:07:10 +00:00
sipdebug = 1 ;
2004-05-01 21:25:31 +00:00
memset ( & debugaddr , 0 , sizeof ( debugaddr ) ) ;
2003-02-07 04:07:10 +00:00
ast_cli ( fd , " SIP Debugging Enabled \n " ) ;
return RESULT_SUCCESS ;
}
2004-05-12 00:17:31 +00:00
static int sip_do_history ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 2 ) {
return RESULT_SHOWUSAGE ;
}
recordhistory = 1 ;
ast_cli ( fd , " SIP History Recording Enabled (use 'sip show history') \n " ) ;
return RESULT_SUCCESS ;
}
static int sip_no_history ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 3 ) {
return RESULT_SHOWUSAGE ;
}
recordhistory = 0 ;
ast_cli ( fd , " SIP History Recording Disabled \n " ) ;
return RESULT_SUCCESS ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_no_debug: Disable SIP Debugging in CLI ---*/
2003-02-07 04:07:10 +00:00
static int sip_no_debug ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
sipdebug = 0 ;
ast_cli ( fd , " SIP Debugging Disabled \n " ) ;
return RESULT_SUCCESS ;
}
2003-11-10 04:22:33 +00:00
static int reply_digest ( struct sip_pvt * p , struct sip_request * req , char * header , char * respheader , char * digest , int digest_len ) ;
2003-02-07 04:07:10 +00:00
2004-05-13 19:54:42 +00:00
/*--- do_register_auth: Challenge for registration ---*/
2003-08-24 22:33:43 +00:00
static int do_register_auth ( struct sip_pvt * p , struct sip_request * req , char * header , char * respheader ) {
2004-04-01 06:27:10 +00:00
char digest [ 1024 ] ;
2003-04-12 15:46:22 +00:00
p - > authtries + + ;
2003-02-07 04:07:10 +00:00
memset ( digest , 0 , sizeof ( digest ) ) ;
2003-08-24 22:33:43 +00:00
if ( reply_digest ( p , req , header , " REGISTER " , digest , sizeof ( digest ) ) ) {
2003-04-09 21:13:11 +00:00
/* There's nothing to use for authentication */
return - 1 ;
}
2003-08-24 22:33:43 +00:00
return transmit_register ( p - > registry , " REGISTER " , digest , respheader ) ;
2003-02-07 04:07:10 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- do_proxy_auth: Challenge user ---*/
2003-11-10 04:22:33 +00:00
static int do_proxy_auth ( struct sip_pvt * p , struct sip_request * req , char * header , char * respheader , char * msg , int init ) {
2004-04-01 06:27:10 +00:00
char digest [ 1024 ] ;
2003-04-12 15:46:22 +00:00
p - > authtries + + ;
2003-02-07 04:07:10 +00:00
memset ( digest , 0 , sizeof ( digest ) ) ;
2004-04-04 21:09:22 +00:00
if ( reply_digest ( p , req , header , msg , digest , sizeof ( digest ) ) ) {
2003-04-09 21:13:11 +00:00
/* No way to authenticate */
return - 1 ;
}
2004-06-25 03:59:07 +00:00
return transmit_invite ( p , msg , ! strcasecmp ( msg , " INVITE " ) , digest , respheader , NULL , NULL , NULL , init ) ;
2003-02-07 04:07:10 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- reply_digest: reply to authentication for outbound registrations ---*/
/* This is used for register= servers in sip.conf, SIP proxies we register
with for receiving calls from . */
2003-02-07 04:07:10 +00:00
static int reply_digest ( struct sip_pvt * p , struct sip_request * req , char * header , char * orig_header , char * digest , int digest_len ) {
2004-04-01 06:27:10 +00:00
char tmp [ 512 ] = " " ;
2003-02-07 04:07:10 +00:00
char * realm = " " ;
char * nonce = " " ;
2003-08-22 16:53:36 +00:00
char * domain = " " ;
2004-03-31 08:00:26 +00:00
char * opaque = " " ;
2004-04-05 05:12:00 +00:00
char * qop = " " ;
2003-02-07 04:07:10 +00:00
char * c ;
strncpy ( tmp , get_header ( req , header ) , sizeof ( tmp ) - 1 ) ;
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( tmp ) )
2003-04-09 21:13:11 +00:00
return - 1 ;
2003-02-07 04:07:10 +00:00
c = tmp ;
2003-02-15 06:00:16 +00:00
c + = strlen ( " Digest " ) ;
2003-02-07 04:07:10 +00:00
while ( c ) {
while ( * c & & ( * c < 33 ) ) c + + ;
if ( ! * c )
break ;
2003-04-07 03:46:20 +00:00
if ( ! strncasecmp ( c , " realm= " , strlen ( " realm= " ) ) ) {
c + = strlen ( " realm= " ) ;
if ( ( * c = = ' \" ' ) ) {
realm = + + c ;
if ( ( c = strchr ( c , ' \" ' ) ) )
* c = ' \0 ' ;
} else {
realm = c ;
if ( ( c = strchr ( c , ' , ' ) ) )
* c = ' \0 ' ;
2003-02-07 04:07:10 +00:00
}
2003-04-07 03:46:20 +00:00
} else if ( ! strncasecmp ( c , " nonce= " , strlen ( " nonce= " ) ) ) {
c + = strlen ( " nonce= " ) ;
if ( ( * c = = ' \" ' ) ) {
nonce = + + c ;
if ( ( c = strchr ( c , ' \" ' ) ) )
* c = ' \0 ' ;
} else {
nonce = c ;
if ( ( c = strchr ( c , ' , ' ) ) )
* c = ' \0 ' ;
}
2004-03-31 08:00:26 +00:00
} else if ( ! strncasecmp ( c , " opaque= " , strlen ( " opaque= " ) ) ) {
c + = strlen ( " opaque= " ) ;
if ( ( * c = = ' \" ' ) ) {
opaque = + + c ;
if ( ( c = strchr ( c , ' \" ' ) ) )
* c = ' \0 ' ;
} else {
opaque = c ;
if ( ( c = strchr ( c , ' , ' ) ) )
* c = ' \0 ' ;
}
2004-04-05 05:12:00 +00:00
} else if ( ! strncasecmp ( c , " qop= " , strlen ( " qop= " ) ) ) {
c + = strlen ( " qop= " ) ;
if ( ( * c = = ' \" ' ) ) {
qop = + + c ;
if ( ( c = strchr ( c , ' \" ' ) ) )
* c = ' \0 ' ;
} else {
qop = c ;
if ( ( c = strchr ( c , ' , ' ) ) )
* c = ' \0 ' ;
}
2003-08-22 16:53:36 +00:00
} else if ( ! strncasecmp ( c , " domain= " , strlen ( " domain= " ) ) ) {
c + = strlen ( " domain= " ) ;
if ( ( * c = = ' \" ' ) ) {
domain = + + c ;
if ( ( c = strchr ( c , ' \" ' ) ) )
* c = ' \0 ' ;
} else {
domain = c ;
if ( ( c = strchr ( c , ' , ' ) ) )
* c = ' \0 ' ;
}
2003-04-07 03:46:20 +00:00
} else
c = strchr ( c , ' , ' ) ;
if ( c )
c + + ;
}
2004-01-11 19:24:15 +00:00
if ( strlen ( tmp ) > = sizeof ( tmp ) )
ast_log ( LOG_WARNING , " Buffer overflow detected! Please file a bug. \n " ) ;
2003-04-07 03:46:20 +00:00
/* copy realm and nonce for later authorization of CANCELs and BYEs */
strncpy ( p - > realm , realm , sizeof ( p - > realm ) - 1 ) ;
strncpy ( p - > nonce , nonce , sizeof ( p - > nonce ) - 1 ) ;
2003-08-22 16:53:36 +00:00
strncpy ( p - > domain , domain , sizeof ( p - > domain ) - 1 ) ;
2004-03-31 08:00:26 +00:00
strncpy ( p - > opaque , opaque , sizeof ( p - > opaque ) - 1 ) ;
2004-04-05 05:12:00 +00:00
strncpy ( p - > qop , qop , sizeof ( p - > qop ) - 1 ) ;
2003-04-07 03:46:20 +00:00
build_reply_digest ( p , orig_header , digest , digest_len ) ;
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- build_reply_digest: Build reply digest ---*/
/* Build digest challenge for authentication of peers (for registration)
and users ( for calls ) . Also used for authentication of CANCEL and BYE */
2003-04-07 03:46:20 +00:00
static int build_reply_digest ( struct sip_pvt * p , char * orig_header , char * digest , int digest_len )
{
char a1 [ 256 ] ;
char a2 [ 256 ] ;
char a1_hash [ 256 ] ;
char a2_hash [ 256 ] ;
char resp [ 256 ] ;
char resp_hash [ 256 ] ;
char uri [ 256 ] = " " ;
2004-04-05 05:12:00 +00:00
char cnonce [ 80 ] ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-02-07 04:07:10 +00:00
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( p - > domain ) )
2003-08-22 16:53:36 +00:00
strncpy ( uri , p - > domain , sizeof ( uri ) - 1 ) ;
2004-05-03 21:01:14 +00:00
else if ( ! ast_strlen_zero ( p - > uri ) )
2003-04-12 15:46:22 +00:00
strncpy ( uri , p - > uri , sizeof ( uri ) - 1 ) ;
else
2004-06-29 12:56:46 +00:00
snprintf ( uri , sizeof ( uri ) , " sip:%s@%s " , p - > username , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > sa . sin_addr ) ) ;
2003-02-07 04:07:10 +00:00
2004-04-05 05:12:00 +00:00
snprintf ( cnonce , sizeof ( cnonce ) , " %08x " , rand ( ) ) ;
2004-05-02 16:30:05 +00:00
snprintf ( a1 , sizeof ( a1 ) , " %s:%s:%s " , p - > authname , p - > realm , p - > peersecret ) ;
2003-02-07 04:07:10 +00:00
snprintf ( a2 , sizeof ( a2 ) , " %s:%s " , orig_header , uri ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( p - > peermd5secret ) )
2003-10-15 17:32:19 +00:00
strncpy ( a1_hash , p - > peermd5secret , sizeof ( a1_hash ) - 1 ) ;
else
md5_hash ( a1_hash , a1 ) ;
2003-02-07 04:07:10 +00:00
md5_hash ( a2_hash , a2 ) ;
2004-04-05 05:12:00 +00:00
/* XXX We hard code the nonce-number to 1... What are the odds? Are we seriously going to keep
track of every nonce we ' ve seen ? Also we hard code to " auth " . . . XXX */
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( p - > qop ) )
2004-04-05 05:12:00 +00:00
snprintf ( resp , sizeof ( resp ) , " %s:%s:%s:%s:%s:%s " , a1_hash , p - > nonce , " 00000001 " , cnonce , " auth " , a2_hash ) ;
else
snprintf ( resp , sizeof ( resp ) , " %s:%s:%s " , a1_hash , p - > nonce , a2_hash ) ;
2003-02-07 04:07:10 +00:00
md5_hash ( resp_hash , resp ) ;
2004-04-05 05:12:00 +00:00
/* XXX We hard code our qop to "auth" for now. XXX */
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( p - > qop ) )
2004-07-22 23:16:40 +00:00
snprintf ( digest , digest_len , " Digest username= \" %s \" , realm= \" %s \" , algorithm=MD5, uri= \" %s \" , nonce= \" %s \" , response= \" %s \" , opaque= \" %s \" , qop= \" %s \" , cnonce= \" %s \" , nc=%s " , p - > authname , p - > realm , uri , p - > nonce , resp_hash , p - > opaque , " auth " , cnonce , " 00000001 " ) ;
2004-04-05 05:12:00 +00:00
else
2004-07-22 23:16:40 +00:00
snprintf ( digest , digest_len , " Digest username= \" %s \" , realm= \" %s \" , algorithm=MD5, uri= \" %s \" , nonce= \" %s \" , response= \" %s \" , opaque= \" %s \" " , p - > authname , p - > realm , uri , p - > nonce , resp_hash , p - > opaque ) ;
2003-02-07 04:07:10 +00:00
return 0 ;
}
static char show_users_usage [ ] =
" Usage: sip show users \n "
" Lists all users known to the SIP (Session Initiation Protocol) subsystem. \n " ;
2003-07-26 23:14:27 +00:00
static char show_inuse_usage [ ] =
" Usage: sip show inuse \n "
2003-09-13 20:26:20 +00:00
" List all users known to the SIP (Session Initiation Protocol) subsystem usage counters and limits. \n " ;
2003-07-26 23:14:27 +00:00
2003-02-07 04:07:10 +00:00
static char show_channels_usage [ ] =
" Usage: sip show channels \n "
" Lists all currently active SIP channels. \n " ;
2003-03-10 22:05:28 +00:00
static char show_channel_usage [ ] =
" Usage: sip show channel <channel> \n "
" Provides detailed status on a given SIP channel. \n " ;
2004-05-12 00:17:31 +00:00
static char show_history_usage [ ] =
" Usage: sip show history <channel> \n "
" Provides detailed dialog history on a given SIP channel. \n " ;
2003-02-07 04:07:10 +00:00
static char show_peers_usage [ ] =
" Usage: sip show peers \n "
" Lists all known SIP peers. \n " ;
2004-05-07 18:57:17 +00:00
static char show_peer_usage [ ] =
" Usage: sip show peer <peername> \n "
" Lists all details on one SIP peer and the current status. \n " ;
2003-02-07 04:07:10 +00:00
static char show_reg_usage [ ] =
" Usage: sip show registry \n "
" Lists all registration requests and status. \n " ;
static char debug_usage [ ] =
" Usage: sip debug \n "
2004-05-01 21:25:31 +00:00
" Enables dumping of SIP packets for debugging purposes \n \n "
" sip debug ip <host[:PORT]> \n "
" Enables dumping of SIP packets to and from host. \n \n "
" sip debug peer <peername> \n "
" Enables dumping of SIP packets to and from host. \n "
" Require peer to be registered. \n " ;
2003-02-07 04:07:10 +00:00
static char no_debug_usage [ ] =
" Usage: sip no debug \n "
" Disables dumping of SIP packets for debugging purposes \n " ;
2004-05-12 00:17:31 +00:00
static char no_history_usage [ ] =
" Usage: sip no history \n "
" Disables recording of SIP dialog history for debugging purposes \n " ;
static char history_usage [ ] =
" Usage: sip history \n "
" Enables recording of SIP dialog history for debugging purposes. \n "
" Use 'sip show hitory' to view the history of a call number. \n " ;
2004-01-23 15:43:31 +00:00
static char sip_reload_usage [ ] =
" Usage: sip reload \n "
" Reloads SIP configuration from sip.conf \n " ;
2004-05-06 21:30:45 +00:00
static char show_subscriptions_usage [ ] =
" Usage: sip show subscriptions \n "
" Shows active SIP subscriptions for extension states \n " ;
2003-02-07 04:07:10 +00:00
static struct ast_cli_entry cli_show_users =
{ { " sip " , " show " , " users " , NULL } , sip_show_users , " Show defined SIP users " , show_users_usage } ;
2004-05-06 21:30:45 +00:00
static struct ast_cli_entry cli_show_subscriptions =
{ { " sip " , " show " , " subscriptions " , NULL } , sip_show_subscriptions , " Show active SIP subscriptions " , show_subscriptions_usage } ;
2003-02-07 04:07:10 +00:00
static struct ast_cli_entry cli_show_channels =
2003-03-10 22:05:28 +00:00
{ { " sip " , " show " , " channels " , NULL } , sip_show_channels , " Show active SIP channels " , show_channels_usage } ;
static struct ast_cli_entry cli_show_channel =
{ { " sip " , " show " , " channel " , NULL } , sip_show_channel , " Show detailed SIP channel info " , show_channel_usage , complete_sipch } ;
2004-05-12 00:17:31 +00:00
static struct ast_cli_entry cli_show_history =
{ { " sip " , " show " , " history " , NULL } , sip_show_history , " Show SIP dialog history " , show_history_usage , complete_sipch } ;
2004-05-01 21:25:31 +00:00
static struct ast_cli_entry cli_debug_ip =
{ { " sip " , " debug " , " ip " , NULL } , sip_do_debug , " Enable SIP debugging on IP " , debug_usage } ;
static struct ast_cli_entry cli_debug_peer =
{ { " sip " , " debug " , " peer " , NULL } , sip_do_debug , " Enable SIP debugging on Peername " , debug_usage } ;
2004-05-07 18:57:17 +00:00
static struct ast_cli_entry cli_show_peer =
{ { " sip " , " show " , " peer " , NULL } , sip_show_peer , " Show details on specific SIP peer " , show_peer_usage } ;
2003-02-07 04:07:10 +00:00
static struct ast_cli_entry cli_show_peers =
{ { " sip " , " show " , " peers " , NULL } , sip_show_peers , " Show defined SIP peers " , show_peers_usage } ;
2004-05-02 05:38:20 +00:00
static struct ast_cli_entry cli_show_peers_include =
{ { " sip " , " show " , " peers " , " include " , NULL } , sip_show_peers , " Show defined SIP peers " , show_peers_usage } ;
static struct ast_cli_entry cli_show_peers_exclude =
{ { " sip " , " show " , " peers " , " exclude " , NULL } , sip_show_peers , " Show defined SIP peers " , show_peers_usage } ;
static struct ast_cli_entry cli_show_peers_begin =
{ { " sip " , " show " , " peers " , " begin " , NULL } , sip_show_peers , " Show defined SIP peers " , show_peers_usage } ;
2003-07-26 23:14:27 +00:00
static struct ast_cli_entry cli_inuse_show =
{ { " sip " , " show " , " inuse " , NULL } , sip_show_inuse , " List all inuse/limit " , show_inuse_usage } ;
2003-02-07 04:07:10 +00:00
static struct ast_cli_entry cli_show_registry =
{ { " sip " , " show " , " registry " , NULL } , sip_show_registry , " Show SIP registration status " , show_reg_usage } ;
static struct ast_cli_entry cli_debug =
{ { " sip " , " debug " , NULL } , sip_do_debug , " Enable SIP debugging " , debug_usage } ;
2004-05-12 00:17:31 +00:00
static struct ast_cli_entry cli_history =
{ { " sip " , " history " , NULL } , sip_do_history , " Enable SIP history " , history_usage } ;
static struct ast_cli_entry cli_no_history =
{ { " sip " , " no " , " history " , NULL } , sip_no_history , " Disable SIP history " , no_history_usage } ;
2003-02-07 04:07:10 +00:00
static struct ast_cli_entry cli_no_debug =
{ { " sip " , " no " , " debug " , NULL } , sip_no_debug , " Disable SIP debugging " , no_debug_usage } ;
2004-05-13 19:54:42 +00:00
/*--- parse_moved_contact: Parse 302 Moved temporalily response */
2003-03-29 00:42:16 +00:00
static void parse_moved_contact ( struct sip_pvt * p , struct sip_request * req )
{
char tmp [ 256 ] = " " ;
char * s , * e ;
strncpy ( tmp , get_header ( req , " Contact " ) , sizeof ( tmp ) - 1 ) ;
2003-03-30 20:46:30 +00:00
s = ditch_braces ( tmp ) ;
2004-09-30 19:59:00 +00:00
e = strchr ( s , ' ; ' ) ;
if ( e )
* e = ' \0 ' ;
2004-06-21 06:11:56 +00:00
if ( p - > promiscredir ) {
if ( ! strncasecmp ( s , " sip: " , 4 ) )
s + = 4 ;
e = strchr ( s , ' / ' ) ;
if ( e )
* e = ' \0 ' ;
ast_log ( LOG_DEBUG , " Found promiscuous redirection to 'SIP/%s' \n " , s ) ;
if ( p - > owner )
snprintf ( p - > owner - > call_forward , sizeof ( p - > owner - > call_forward ) , " SIP/%s " , s ) ;
} else {
e = strchr ( tmp , ' @ ' ) ;
if ( e )
* e = ' \0 ' ;
e = strchr ( tmp , ' / ' ) ;
if ( e )
* e = ' \0 ' ;
if ( ! strncasecmp ( s , " sip: " , 4 ) )
s + = 4 ;
ast_log ( LOG_DEBUG , " Found 302 Redirect to extension '%s' \n " , s ) ;
if ( p - > owner )
strncpy ( p - > owner - > call_forward , s , sizeof ( p - > owner - > call_forward ) - 1 ) ;
}
2003-03-29 00:42:16 +00:00
}
2004-05-27 05:06:32 +00:00
static void check_pendings ( struct sip_pvt * p )
{
/* Go ahead and send bye at this point */
if ( p - > pendingbye ) {
transmit_request_with_auth ( p , " BYE " , 0 , 1 , 1 ) ;
p - > needdestroy = 1 ;
p - > needreinvite = 0 ;
} else if ( p - > needreinvite ) {
ast_log ( LOG_DEBUG , " Sending pending reinvite on '%s' \n " , p - > callid ) ;
/* Didn't get to reinvite yet, so do it now */
transmit_reinvite_with_sdp ( p ) ;
p - > needreinvite = 0 ;
}
}
2004-05-13 19:54:42 +00:00
/*--- handle_response: Handle SIP response in dialogue ---*/
2003-12-09 22:09:05 +00:00
static void handle_response ( struct sip_pvt * p , int resp , char * rest , struct sip_request * req , int ignore )
2002-06-28 20:34:46 +00:00
{
2002-09-12 17:13:17 +00:00
char * to ;
2003-02-07 04:07:10 +00:00
char * msg , * c ;
struct ast_channel * owner ;
struct sip_peer * peer ;
int pingtime ;
struct timeval tv ;
2003-03-28 06:13:04 +00:00
int seqno = 0 ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-02-07 04:07:10 +00:00
c = get_header ( req , " Cseq " ) ;
2003-03-28 06:13:04 +00:00
if ( sscanf ( c , " %d " , & seqno ) ! = 1 ) {
ast_log ( LOG_WARNING , " Unable to determine sequence number \n " ) ;
}
2003-02-07 04:07:10 +00:00
msg = strchr ( c , ' ' ) ;
if ( ! msg ) msg = " " ; else msg + + ;
owner = p - > owner ;
2003-10-01 16:05:40 +00:00
if ( owner )
owner - > hangupcause = hangup_sip2cause ( resp ) ;
2003-04-08 21:19:51 +00:00
/* Acknowledge whatever it is destined for */
2003-08-20 23:03:44 +00:00
if ( ( resp > = 100 ) & & ( resp < = 199 ) )
2004-07-16 15:45:37 +00:00
__sip_semi_ack ( p , seqno , 0 , msg ) ;
2003-08-20 23:03:44 +00:00
else
2004-07-16 15:45:37 +00:00
__sip_ack ( p , seqno , 0 , msg ) ;
2003-08-20 14:28:51 +00:00
/* Get their tag if we haven't already */
to = get_header ( req , " To " ) ;
to = strstr ( to , " tag= " ) ;
if ( to ) {
to + = 4 ;
strncpy ( p - > theirtag , to , sizeof ( p - > theirtag ) - 1 ) ;
to = strchr ( p - > theirtag , ' ; ' ) ;
if ( to )
* to = ' \0 ' ;
}
2003-02-07 04:07:10 +00:00
if ( p - > peerpoke ) {
/* We don't really care what the response is, just that it replied back.
Well , as long as it ' s not a 100 response . . . since we might
need to hang around for something more " difinitive " */
if ( resp ! = 100 ) {
2003-04-06 18:19:51 +00:00
int statechanged = 0 ;
2004-09-16 16:18:53 +00:00
int newstate = 0 ;
2003-02-07 04:07:10 +00:00
peer = p - > peerpoke ;
gettimeofday ( & tv , NULL ) ;
pingtime = ( tv . tv_sec - peer - > ps . tv_sec ) * 1000 +
( tv . tv_usec - peer - > ps . tv_usec ) / 1000 ;
if ( pingtime < 1 )
pingtime = 1 ;
if ( ( peer - > lastms < 0 ) | | ( peer - > lastms > peer - > maxms ) ) {
2003-04-06 18:19:51 +00:00
if ( pingtime < = peer - > maxms ) {
2004-10-16 15:36:16 +00:00
ast_log ( LOG_NOTICE , " Peer '%s' is now REACHABLE! (%dms / %dms) \n " , peer - > name , pingtime , peer - > maxms ) ;
2003-04-06 18:19:51 +00:00
statechanged = 1 ;
2004-09-16 16:18:53 +00:00
newstate = 1 ;
2003-04-06 18:19:51 +00:00
}
2003-02-07 04:07:10 +00:00
} else if ( ( peer - > lastms > 0 ) & & ( peer - > lastms < = peer - > maxms ) ) {
2003-04-06 18:19:51 +00:00
if ( pingtime > peer - > maxms ) {
2004-10-16 15:36:16 +00:00
ast_log ( LOG_NOTICE , " Peer '%s' is now TOO LAGGED! (%dms / %dms) \n " , peer - > name , pingtime , peer - > maxms ) ;
2003-04-06 18:19:51 +00:00
statechanged = 1 ;
2004-09-16 16:18:53 +00:00
newstate = 2 ;
2003-04-06 18:19:51 +00:00
}
2003-02-07 04:07:10 +00:00
}
2003-04-06 18:19:51 +00:00
if ( ! peer - > lastms )
statechanged = 1 ;
2003-02-07 04:07:10 +00:00
peer - > lastms = pingtime ;
peer - > call = NULL ;
2004-09-16 16:18:53 +00:00
if ( statechanged ) {
ast_device_state_changed ( " SIP/%s " , peer - > name ) ;
if ( newstate = = 2 ) {
manager_event ( EVENT_FLAG_SYSTEM , " PeerStatus " , " Peer: SIP/%s \r \n PeerStatus: Lagged \r \n Time: %d \r \n " , peer - > name , pingtime ) ;
} else {
manager_event ( EVENT_FLAG_SYSTEM , " PeerStatus " , " Peer: SIP/%s \r \n PeerStatus: Reachable \r \n Time: %d \r \n " , peer - > name , pingtime ) ;
}
}
2003-04-06 18:19:51 +00:00
2003-02-07 04:07:10 +00:00
if ( peer - > pokeexpire > - 1 )
ast_sched_del ( sched , peer - > pokeexpire ) ;
if ( ! strcasecmp ( msg , " INVITE " ) )
2004-03-28 04:05:58 +00:00
transmit_request ( p , " ACK " , seqno , 0 , 0 ) ;
2003-04-05 21:36:30 +00:00
p - > needdestroy = 1 ;
2003-02-07 04:07:10 +00:00
/* Try again eventually */
if ( ( peer - > lastms < 0 ) | | ( peer - > lastms > peer - > maxms ) )
2003-04-06 18:19:51 +00:00
peer - > pokeexpire = ast_sched_add ( sched , DEFAULT_FREQ_NOTOK , sip_poke_peer_s , peer ) ;
2003-02-07 04:07:10 +00:00
else
peer - > pokeexpire = ast_sched_add ( sched , DEFAULT_FREQ_OK , sip_poke_peer_s , peer ) ;
}
} else if ( p - > outgoing ) {
2003-03-28 06:13:04 +00:00
/* Acknowledge sequence number */
2003-02-07 04:07:10 +00:00
if ( p - > initid > - 1 ) {
/* Don't auto congest anymore since we've gotten something useful back */
ast_sched_del ( sched , p - > initid ) ;
p - > initid = - 1 ;
}
2002-06-28 20:34:46 +00:00
switch ( resp ) {
case 100 :
2004-05-26 18:46:36 +00:00
if ( ! strcasecmp ( msg , " INVITE " ) ) {
sip_cancel_destroy ( p ) ;
}
2003-02-07 04:07:10 +00:00
break ;
2003-05-15 22:39:01 +00:00
case 183 :
2004-03-02 23:29:00 +00:00
if ( ! strcasecmp ( msg , " INVITE " ) ) {
2004-05-26 18:46:36 +00:00
sip_cancel_destroy ( p ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( get_header ( req , " Content-Type " ) ) )
2004-03-02 23:29:00 +00:00
process_sdp ( p , req ) ;
if ( p - > owner ) {
/* Queue a progress frame */
2004-04-06 22:17:32 +00:00
ast_queue_control ( p - > owner , AST_CONTROL_PROGRESS ) ;
2004-03-02 23:29:00 +00:00
}
2003-04-08 21:50:32 +00:00
}
2002-06-28 20:34:46 +00:00
break ;
case 180 :
2004-05-26 18:46:36 +00:00
if ( ! strcasecmp ( msg , " INVITE " ) ) {
sip_cancel_destroy ( p ) ;
if ( p - > owner ) {
ast_queue_control ( p - > owner , AST_CONTROL_RINGING ) ;
if ( p - > owner - > _state ! = AST_STATE_UP )
ast_setstate ( p - > owner , AST_STATE_RINGING ) ;
}
2002-06-28 20:34:46 +00:00
}
break ;
case 200 :
2003-03-28 06:13:04 +00:00
if ( ! strcasecmp ( msg , " NOTIFY " ) ) {
/* They got the notify, this is the end */
if ( p - > owner ) {
ast_log ( LOG_WARNING , " Notify answer on an owned channel? \n " ) ;
2004-04-06 22:17:32 +00:00
ast_queue_hangup ( p - > owner ) ;
2003-03-28 06:13:04 +00:00
} else {
2003-04-06 18:19:51 +00:00
if ( ! p - > subscribed ) {
2003-04-14 15:56:14 +00:00
p - > needdestroy = 1 ;
2003-04-06 18:19:51 +00:00
}
2002-06-28 20:34:46 +00:00
}
2003-03-28 06:13:04 +00:00
} else if ( ! strcasecmp ( msg , " INVITE " ) ) {
2004-05-04 20:10:37 +00:00
sip_cancel_destroy ( p ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( get_header ( req , " Content-Type " ) ) )
2003-03-28 06:13:04 +00:00
process_sdp ( p , req ) ;
2003-04-05 22:29:46 +00:00
/* Save Record-Route for any later requests we make on this dialogue */
build_route ( p , req , 1 ) ;
2003-03-28 06:13:04 +00:00
if ( p - > owner ) {
if ( p - > owner - > _state ! = AST_STATE_UP ) {
2004-06-25 03:59:07 +00:00
# ifdef OSP_SUPPORT
time ( & p - > ospstart ) ;
# endif
2004-04-06 22:17:32 +00:00
ast_queue_control ( p - > owner , AST_CONTROL_ANSWER ) ;
2003-04-30 22:14:36 +00:00
} else {
struct ast_frame af = { AST_FRAME_NULL , } ;
2004-04-06 22:17:32 +00:00
ast_queue_frame ( p - > owner , & af ) ;
2003-03-28 06:13:04 +00:00
}
2004-07-14 11:10:05 +00:00
} else /* It's possible we're getting an ACK after we've tried to disconnect
by sending CANCEL */
p - > pendingbye = 1 ;
2003-08-20 05:56:13 +00:00
p - > authtries = 0 ;
2004-03-28 04:05:58 +00:00
/* If I understand this right, the branch is different for a non-200 ACK only */
transmit_request ( p , " ACK " , seqno , 0 , 1 ) ;
2004-05-27 05:06:32 +00:00
check_pendings ( p ) ;
2003-03-28 06:13:04 +00:00
} else if ( ! strcasecmp ( msg , " REGISTER " ) ) {
2003-02-07 04:07:10 +00:00
/* char *exp; */
2004-05-03 05:03:19 +00:00
int expires , expires_ms ;
2003-02-07 04:07:10 +00:00
struct sip_registry * r ;
r = p - > registry ;
2003-04-09 19:35:24 +00:00
if ( r ) {
r - > regstate = REG_STATE_REGISTERED ;
2004-09-16 16:18:53 +00:00
manager_event ( EVENT_FLAG_SYSTEM , " Registry " , " Channel: SIP \r \n Domain: %s \r \n Status: %s \r \n " , r - > hostname , regstate2str ( r - > regstate ) ) ;
2003-04-09 19:55:59 +00:00
ast_log ( LOG_DEBUG , " Registration successful \n " ) ;
2003-04-09 19:35:24 +00:00
if ( r - > timeout > - 1 ) {
ast_log ( LOG_DEBUG , " Cancelling timeout %d \n " , r - > timeout ) ;
ast_sched_del ( sched , r - > timeout ) ;
}
r - > timeout = - 1 ;
2003-04-09 19:55:59 +00:00
r - > call = NULL ;
2003-04-09 21:13:11 +00:00
p - > registry = NULL ;
2003-04-09 19:55:59 +00:00
p - > needdestroy = 1 ;
2003-04-09 19:35:24 +00:00
/* set us up for re-registering */
/* figure out how long we got registered for */
if ( r - > expire > - 1 )
ast_sched_del ( sched , r - > expire ) ;
2004-05-03 02:22:19 +00:00
/* according to section 6.13 of RFC, contact headers override
expires headers , so check those first */
expires = 0 ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( get_header ( req , " Contact " ) ) ) {
2004-05-03 02:22:19 +00:00
char * contact = NULL ;
char * tmptmp = NULL ;
int start = 0 ;
for ( ; ; ) {
contact = __get_header ( req , " Contact " , & start ) ;
/* this loop ensures we get a contact header about our register request */
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( contact ) ) {
2004-07-09 11:03:33 +00:00
if ( ( tmptmp = strstr ( contact , p - > our_contact ) ) ) {
contact = tmptmp ;
2004-05-03 02:22:19 +00:00
break ;
2004-07-09 11:03:33 +00:00
}
2004-05-03 02:22:19 +00:00
} else
break ;
}
tmptmp = strstr ( contact , " expires= " ) ;
if ( tmptmp ) {
if ( sscanf ( tmptmp + 8 , " %d; " , & expires ) ! = 1 )
expires = 0 ;
}
}
if ( ! expires ) expires = atoi ( get_header ( req , " expires " ) ) ;
2003-04-09 19:35:24 +00:00
if ( ! expires ) expires = default_expiry ;
2004-05-03 05:03:19 +00:00
expires_ms = expires * 1000 ;
if ( expires < = EXPIRY_GUARD_LIMIT )
expires_ms - = MAX ( ( expires_ms * EXPIRY_GUARD_PCT ) , EXPIRY_GUARD_MIN ) ;
2004-05-03 02:22:19 +00:00
else
2004-05-03 05:03:19 +00:00
expires_ms - = EXPIRY_GUARD_SECS * 1000 ;
2004-07-09 11:03:33 +00:00
r - > refresh = ( int ) expires_ms / 1000 ;
2004-05-03 05:03:19 +00:00
r - > expire = ast_sched_add ( sched , expires_ms , sip_reregister , r ) ;
2003-04-09 19:35:24 +00:00
} else
ast_log ( LOG_WARNING , " Got 200 OK on REGISTER that isn't a register \n " ) ;
2003-02-07 04:07:10 +00:00
2002-06-28 20:34:46 +00:00
}
break ;
2003-02-07 04:07:10 +00:00
case 401 : /* Not authorized on REGISTER */
2003-11-10 04:22:33 +00:00
if ( ! strcasecmp ( msg , " INVITE " ) ) {
/* First we ACK */
2004-03-28 04:05:58 +00:00
transmit_request ( p , " ACK " , seqno , 0 , 0 ) ;
2003-11-10 04:22:33 +00:00
/* Then we AUTH */
if ( ( p - > authtries > 1 ) | | do_proxy_auth ( p , req , " WWW-Authenticate " , " Authorization " , " INVITE " , 1 ) ) {
ast_log ( LOG_NOTICE , " Failed to authenticate on INVITE to '%s' \n " , get_header ( & p - > initreq , " From " ) ) ;
p - > needdestroy = 1 ;
}
} else if ( p - > registry & & ! strcasecmp ( msg , " REGISTER " ) ) {
2003-08-24 22:33:43 +00:00
if ( ( p - > authtries > 1 ) | | do_register_auth ( p , req , " WWW-Authenticate " , " Authorization " ) ) {
2003-04-09 21:13:11 +00:00
ast_log ( LOG_NOTICE , " Failed to authenticate on REGISTER to '%s' \n " , get_header ( & p - > initreq , " From " ) ) ;
p - > needdestroy = 1 ;
}
} else
p - > needdestroy = 1 ;
2003-02-07 04:07:10 +00:00
break ;
case 407 :
2003-04-09 21:13:11 +00:00
if ( ! strcasecmp ( msg , " INVITE " ) ) {
/* First we ACK */
2004-03-28 04:05:58 +00:00
transmit_request ( p , " ACK " , seqno , 0 , 0 ) ;
2003-04-09 21:13:11 +00:00
/* Then we AUTH */
2003-12-09 22:09:05 +00:00
/* But only if the packet wasn't marked as ignore in handle_request */
if ( ! ignore ) {
if ( ( p - > authtries > 1 ) | | do_proxy_auth ( p , req , " Proxy-Authenticate " , " Proxy-Authorization " , " INVITE " , 1 ) ) {
ast_log ( LOG_NOTICE , " Failed to authenticate on INVITE to '%s' \n " , get_header ( & p - > initreq , " From " ) ) ;
p - > needdestroy = 1 ;
}
2003-04-09 21:13:11 +00:00
}
2003-11-25 21:19:25 +00:00
} else if ( ! strcasecmp ( msg , " BYE " ) | | ! strcasecmp ( msg , " REFER " ) ) {
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( p - > authname ) )
2003-11-25 21:19:25 +00:00
ast_log ( LOG_WARNING , " Asked to authenticate %s, to %s:%d but we have no matching peer! \n " ,
2004-06-29 12:56:46 +00:00
msg , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > recv . sin_addr ) , ntohs ( p - > recv . sin_port ) ) ;
2003-11-25 21:19:25 +00:00
if ( ( p - > authtries > 1 ) | | do_proxy_auth ( p , req , " Proxy-Authenticate " , " Proxy-Authorization " , msg , 0 ) ) {
ast_log ( LOG_NOTICE , " Failed to authenticate on %s to '%s' \n " , msg , get_header ( & p - > initreq , " From " ) ) ;
2003-08-20 05:56:13 +00:00
p - > needdestroy = 1 ;
}
2003-08-24 21:47:25 +00:00
} else if ( p - > registry & & ! strcasecmp ( msg , " REGISTER " ) ) {
2003-08-24 22:33:43 +00:00
if ( ( p - > authtries > 1 ) | | do_register_auth ( p , req , " Proxy-Authenticate " , " Proxy-Authorization " ) ) {
ast_log ( LOG_NOTICE , " Failed to authenticate on REGISTER to '%s' (tries '%d') \n " , get_header ( & p - > initreq , " From " ) , p - > authtries ) ;
2003-08-24 21:47:25 +00:00
p - > needdestroy = 1 ;
}
} else
p - > needdestroy = 1 ;
2003-02-07 04:07:10 +00:00
break ;
2003-08-10 19:36:46 +00:00
case 501 : /* Not Implemented */
2004-09-09 15:40:07 +00:00
if ( ! strcasecmp ( msg , " INVITE " ) ) {
if ( p - > owner )
ast_queue_control ( p - > owner , AST_CONTROL_CONGESTION ) ;
} else
2004-06-29 12:56:46 +00:00
ast_log ( LOG_WARNING , " Host '%s' does not implement '%s' \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > sa . sin_addr ) , msg ) ;
2003-08-10 19:36:46 +00:00
break ;
2002-06-28 20:34:46 +00:00
default :
2003-03-30 20:46:30 +00:00
if ( ( resp > = 300 ) & & ( resp < 700 ) ) {
2003-04-11 16:02:23 +00:00
if ( ( option_verbose > 2 ) & & ( resp ! = 487 ) )
2004-06-29 12:56:46 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Got SIP response %d \" %s \" back from %s \n " , resp , rest , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > sa . sin_addr ) ) ;
2002-06-28 20:34:46 +00:00
p - > alreadygone = 1 ;
if ( p - > rtp ) {
2003-03-20 22:01:53 +00:00
/* Immediately stop RTP */
ast_rtp_stop ( p - > rtp ) ;
2002-06-28 20:34:46 +00:00
}
2003-06-28 16:40:02 +00:00
if ( p - > vrtp ) {
/* Immediately stop VRTP */
ast_rtp_stop ( p - > vrtp ) ;
}
2003-02-07 04:07:10 +00:00
/* XXX Locking issues?? XXX */
switch ( resp ) {
2004-03-05 18:09:35 +00:00
case 300 : /* Multiple Choices */
case 301 : /* Moved permenantly */
2003-03-29 00:42:16 +00:00
case 302 : /* Moved temporarily */
2004-03-05 18:09:35 +00:00
case 305 : /* Use Proxy */
2003-03-29 00:42:16 +00:00
parse_moved_contact ( p , req ) ;
if ( p - > owner )
2004-04-06 22:17:32 +00:00
ast_queue_control ( p - > owner , AST_CONTROL_BUSY ) ;
2003-03-29 00:42:16 +00:00
break ;
2003-11-26 19:24:57 +00:00
case 487 :
/* channel now destroyed - dec the inUse counter */
if ( p - > outgoing ) {
2004-04-26 14:54:33 +00:00
update_user_counter ( p , DEC_OUT_USE ) ;
2003-11-26 19:24:57 +00:00
}
else {
2004-04-26 14:54:33 +00:00
update_user_counter ( p , DEC_IN_USE ) ;
2003-11-26 19:24:57 +00:00
}
break ;
2004-08-27 03:16:16 +00:00
case 482 : /* SIP is incapable of performing a hairpin call, which
is yet another failure of not having a layer 2 ( again , YAY
IETF for thinking ahead ) . So we treat this as a call
forward and hope we end up at the right place . . . */
ast_log ( LOG_DEBUG , " Hairpin detected, setting up call forward for what it's worth \n " ) ;
if ( p - > owner )
snprintf ( p - > owner - > call_forward , sizeof ( p - > owner - > call_forward ) , " Local/%s@%s " , p - > username , p - > context ) ;
/* Fall through */
2003-02-07 04:07:10 +00:00
case 486 : /* Busy here */
case 600 : /* Busy everywhere */
2004-04-04 22:54:35 +00:00
case 603 : /* Decline */
2003-02-07 04:07:10 +00:00
if ( p - > owner )
2004-04-06 22:17:32 +00:00
ast_queue_control ( p - > owner , AST_CONTROL_BUSY ) ;
2003-02-07 04:07:10 +00:00
break ;
case 480 : /* Temporarily Unavailable */
case 404 : /* Not Found */
case 410 : /* Gone */
2004-09-04 00:29:00 +00:00
case 400 : /* Bad Request */
2003-02-07 04:07:10 +00:00
case 500 : /* Server error */
2004-09-07 01:25:18 +00:00
case 503 : /* Service Unavailable */
2003-02-07 04:07:10 +00:00
if ( owner )
2004-04-06 22:17:32 +00:00
ast_queue_control ( p - > owner , AST_CONTROL_CONGESTION ) ;
2003-02-07 04:07:10 +00:00
break ;
default :
/* Send hangup */
if ( owner )
2004-04-06 22:17:32 +00:00
ast_queue_hangup ( p - > owner ) ;
2003-02-07 04:07:10 +00:00
break ;
}
2003-04-09 21:46:58 +00:00
/* ACK on invite */
if ( ! strcasecmp ( msg , " INVITE " ) )
2004-03-28 04:05:58 +00:00
transmit_request ( p , " ACK " , seqno , 0 , 0 ) ;
2003-03-26 02:39:14 +00:00
p - > alreadygone = 1 ;
2003-04-06 03:58:02 +00:00
if ( ! p - > owner )
p - > needdestroy = 1 ;
2004-10-22 13:18:20 +00:00
} else if ( ( resp > = 100 ) & & ( resp < 200 ) ) {
if ( ! strcasecmp ( msg , " INVITE " ) ) {
sip_cancel_destroy ( p ) ;
2004-10-22 13:24:00 +00:00
if ( ! ast_strlen_zero ( get_header ( req , " Content-Type " ) ) )
process_sdp ( p , req ) ;
if ( p - > owner ) {
/* Queue a progress frame */
ast_queue_control ( p - > owner , AST_CONTROL_PROGRESS ) ;
}
2004-10-22 13:18:20 +00:00
}
2002-06-28 20:34:46 +00:00
} else
2004-06-29 12:56:46 +00:00
ast_log ( LOG_NOTICE , " Dunno anything about a %d %s response from %s \n " , resp , rest , p - > owner ? p - > owner - > name : ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > sa . sin_addr ) ) ;
2002-06-28 20:34:46 +00:00
}
2003-02-07 04:07:10 +00:00
} else {
2004-05-01 21:25:31 +00:00
if ( sip_debug_test_pvt ( p ) )
2003-04-11 04:49:00 +00:00
ast_verbose ( " Message is %s \n " , msg ) ;
switch ( resp ) {
case 200 :
2004-03-28 04:05:58 +00:00
/* Change branch since this is a 200 response */
2003-04-11 04:49:00 +00:00
if ( ! strcasecmp ( msg , " INVITE " ) | | ! strcasecmp ( msg , " REGISTER " ) )
2004-03-28 04:05:58 +00:00
transmit_request ( p , " ACK " , seqno , 0 , 1 ) ;
2003-04-11 04:49:00 +00:00
break ;
2003-08-20 14:28:51 +00:00
case 407 :
2003-11-25 21:19:25 +00:00
if ( ! strcasecmp ( msg , " BYE " ) | | ! strcasecmp ( msg , " REFER " ) ) {
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( p - > authname ) )
2003-11-25 21:19:25 +00:00
ast_log ( LOG_WARNING , " Asked to authenticate %s, to %s:%d but we have no matching peer! \n " ,
2004-06-29 12:56:46 +00:00
msg , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > recv . sin_addr ) , ntohs ( p - > recv . sin_port ) ) ;
2003-11-25 21:19:25 +00:00
if ( ( p - > authtries > 1 ) | | do_proxy_auth ( p , req , " Proxy-Authenticate " , " Proxy-Authorization " , msg , 0 ) ) {
ast_log ( LOG_NOTICE , " Failed to authenticate on %s to '%s' \n " , msg , get_header ( & p - > initreq , " From " ) ) ;
2003-08-20 14:28:51 +00:00
p - > needdestroy = 1 ;
}
}
break ;
2003-02-07 04:07:10 +00:00
}
2002-06-28 20:34:46 +00:00
}
}
2004-07-09 10:46:50 +00:00
struct sip_dual {
struct ast_channel * chan1 ;
struct ast_channel * chan2 ;
2004-07-09 22:43:15 +00:00
struct sip_request req ;
2004-07-09 10:46:50 +00:00
} ;
static void * sip_park_thread ( void * stuff )
{
struct ast_channel * chan1 , * chan2 ;
struct sip_dual * d ;
2004-07-09 22:43:15 +00:00
struct sip_request req ;
2004-07-09 10:46:50 +00:00
int ext ;
int res ;
d = stuff ;
chan1 = d - > chan1 ;
chan2 = d - > chan2 ;
2004-07-09 22:43:15 +00:00
copy_request ( & req , & d - > req ) ;
2004-07-09 10:46:50 +00:00
free ( d ) ;
ast_mutex_lock ( & chan1 - > lock ) ;
ast_do_masquerade ( chan1 ) ;
ast_mutex_unlock ( & chan1 - > lock ) ;
res = ast_park_call ( chan1 , chan2 , 0 , & ext ) ;
2004-07-09 22:43:15 +00:00
/* Then hangup */
2004-07-09 10:46:50 +00:00
ast_hangup ( chan2 ) ;
ast_log ( LOG_DEBUG , " Parked on extension '%d' \n " , ext ) ;
return NULL ;
}
2004-07-09 22:43:15 +00:00
static int sip_park ( struct ast_channel * chan1 , struct ast_channel * chan2 , struct sip_request * req )
2004-07-09 10:46:50 +00:00
{
struct sip_dual * d ;
struct ast_channel * chan1m , * chan2m ;
pthread_t th ;
chan1m = ast_channel_alloc ( 0 ) ;
chan2m = ast_channel_alloc ( 0 ) ;
if ( chan2m & & chan1m ) {
snprintf ( chan1m - > name , sizeof ( chan1m - > name ) , " Parking/%s " , chan1 - > name ) ;
/* Make formats okay */
chan1m - > readformat = chan1 - > readformat ;
chan1m - > writeformat = chan1 - > writeformat ;
ast_channel_masquerade ( chan1m , chan1 ) ;
/* Setup the extensions and such */
strncpy ( chan1m - > context , chan1 - > context , sizeof ( chan1m - > context ) - 1 ) ;
strncpy ( chan1m - > exten , chan1 - > exten , sizeof ( chan1m - > exten ) - 1 ) ;
chan1m - > priority = chan1 - > priority ;
/* We make a clone of the peer channel too, so we can play
back the announcement */
snprintf ( chan2m - > name , sizeof ( chan2m - > name ) , " SIPPeer/%s " , chan2 - > name ) ;
/* Make formats okay */
chan2m - > readformat = chan2 - > readformat ;
chan2m - > writeformat = chan2 - > writeformat ;
ast_channel_masquerade ( chan2m , chan2 ) ;
/* Setup the extensions and such */
strncpy ( chan2m - > context , chan2 - > context , sizeof ( chan2m - > context ) - 1 ) ;
strncpy ( chan2m - > exten , chan2 - > exten , sizeof ( chan2m - > exten ) - 1 ) ;
chan2m - > priority = chan2 - > priority ;
ast_mutex_lock ( & chan2m - > lock ) ;
if ( ast_do_masquerade ( chan2m ) ) {
ast_log ( LOG_WARNING , " Masquerade failed :( \n " ) ;
ast_mutex_unlock ( & chan2m - > lock ) ;
ast_hangup ( chan2m ) ;
return - 1 ;
}
ast_mutex_unlock ( & chan2m - > lock ) ;
} else {
if ( chan1m )
ast_hangup ( chan1m ) ;
if ( chan2m )
ast_hangup ( chan2m ) ;
return - 1 ;
}
d = malloc ( sizeof ( struct sip_dual ) ) ;
if ( d ) {
memset ( d , 0 , sizeof ( * d ) ) ;
2004-07-09 22:43:15 +00:00
/* Save original request for followup */
copy_request ( & d - > req , req ) ;
2004-07-09 10:46:50 +00:00
d - > chan1 = chan1m ;
d - > chan2 = chan2m ;
2004-08-08 17:15:02 +00:00
if ( ! ast_pthread_create ( & th , NULL , sip_park_thread , d ) )
2004-07-09 10:46:50 +00:00
return 0 ;
free ( d ) ;
}
return - 1 ;
}
2004-05-13 19:54:42 +00:00
/*--- attempt_transfer: Attempt transfer of SIP call ---*/
2003-02-16 06:00:12 +00:00
static int attempt_transfer ( struct sip_pvt * p1 , struct sip_pvt * p2 )
{
if ( ! p1 - > owner | | ! p2 - > owner ) {
ast_log ( LOG_WARNING , " Transfer attempted without dual ownership? \n " ) ;
return - 1 ;
}
2004-10-23 12:19:47 +00:00
if ( ast_bridged_channel ( p1 - > owner ) ) {
if ( ast_bridged_channel ( p2 - > owner ) )
ast_moh_stop ( ast_bridged_channel ( p2 - > owner ) ) ;
ast_moh_stop ( ast_bridged_channel ( p1 - > owner ) ) ;
ast_moh_stop ( ast_bridged_channel ( p1 - > owner ) ) ;
ast_moh_stop ( ast_bridged_channel ( p2 - > owner ) ) ;
2004-10-03 19:59:46 +00:00
if ( p1 - > owner - > cdr ) {
p2 - > owner - > cdr = ast_cdr_append ( p2 - > owner - > cdr , p1 - > owner - > cdr ) ;
p1 - > owner - > cdr = NULL ;
}
2004-10-23 12:19:47 +00:00
if ( ast_bridged_channel ( p1 - > owner ) - > cdr ) {
p2 - > owner - > cdr = ast_cdr_append ( p2 - > owner - > cdr , ast_bridged_channel ( p1 - > owner ) - > cdr ) ;
ast_bridged_channel ( p1 - > owner ) - > cdr = NULL ;
2004-10-03 19:59:46 +00:00
}
2004-10-23 12:19:47 +00:00
if ( ast_channel_masquerade ( p2 - > owner , ast_bridged_channel ( p1 - > owner ) ) ) {
ast_log ( LOG_WARNING , " Failed to masquerade %s into %s \n " , p2 - > owner - > name , ast_bridged_channel ( p1 - > owner ) - > name ) ;
2003-02-16 06:00:12 +00:00
return - 1 ;
}
2004-10-23 12:19:47 +00:00
} else if ( ast_bridged_channel ( p2 - > owner ) ) {
ast_moh_stop ( ast_bridged_channel ( p2 - > owner ) ) ;
2003-02-16 06:00:12 +00:00
ast_moh_stop ( p2 - > owner ) ;
ast_moh_stop ( p1 - > owner ) ;
2004-10-03 19:59:46 +00:00
if ( p2 - > owner - > cdr ) {
p1 - > owner - > cdr = ast_cdr_append ( p1 - > owner - > cdr , p2 - > owner - > cdr ) ;
p2 - > owner - > cdr = NULL ;
}
2004-10-23 12:19:47 +00:00
if ( ast_bridged_channel ( p2 - > owner ) - > cdr ) {
p1 - > owner - > cdr = ast_cdr_append ( p1 - > owner - > cdr , ast_bridged_channel ( p2 - > owner ) - > cdr ) ;
ast_bridged_channel ( p2 - > owner ) - > cdr = NULL ;
2004-10-03 19:59:46 +00:00
}
2004-10-23 12:19:47 +00:00
if ( ast_channel_masquerade ( p1 - > owner , ast_bridged_channel ( p2 - > owner ) ) ) {
ast_log ( LOG_WARNING , " Failed to masquerade %s into %s \n " , p1 - > owner - > name , ast_bridged_channel ( p2 - > owner ) - > name ) ;
2003-02-16 06:00:12 +00:00
return - 1 ;
}
} else {
ast_log ( LOG_NOTICE , " Transfer attempted with no bridged calls to transfer \n " ) ;
2003-08-18 05:23:10 +00:00
if ( p1 - > owner )
2003-08-18 14:05:40 +00:00
ast_softhangup_nolock ( p1 - > owner , AST_SOFTHANGUP_DEV ) ;
2003-08-18 05:23:10 +00:00
if ( p2 - > owner )
2003-08-18 14:05:40 +00:00
ast_softhangup_nolock ( p2 - > owner , AST_SOFTHANGUP_DEV ) ;
2003-02-16 06:00:12 +00:00
return - 1 ;
}
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- handle_request: Handle SIP requests (methods) ---*/
/* this is where all incoming requests go first */
2004-07-09 10:46:50 +00:00
static int handle_request ( struct sip_pvt * p , struct sip_request * req , struct sockaddr_in * sin , int * recount , int * nounlock )
2002-06-28 20:34:46 +00:00
{
2003-04-05 21:36:30 +00:00
/* Called with p->lock held, as well as p->owner->lock if appropriate, keeping things
relatively static */
2002-06-28 20:34:46 +00:00
struct sip_request resp ;
char * cmd ;
char * cseq ;
2003-04-03 16:20:47 +00:00
char * from ;
2002-06-28 20:34:46 +00:00
char * e ;
2004-05-09 21:05:43 +00:00
char * useragent ;
2003-02-12 13:59:15 +00:00
struct ast_channel * c = NULL ;
2003-08-25 00:05:48 +00:00
struct ast_channel * transfer_to ;
2002-06-28 20:34:46 +00:00
int seqno ;
int len ;
int ignore = 0 ;
int respid ;
2002-09-12 17:13:17 +00:00
int res ;
2003-04-08 14:49:12 +00:00
int gotdest ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-04-30 22:14:36 +00:00
struct ast_frame af = { AST_FRAME_NULL , } ;
2004-06-18 13:53:48 +00:00
int debug = sip_debug_test_pvt ( p ) ;
2002-06-28 20:34:46 +00:00
/* Clear out potential response */
memset ( & resp , 0 , sizeof ( resp ) ) ;
/* Get Method and Cseq */
cseq = get_header ( req , " Cseq " ) ;
cmd = req - > header [ 0 ] ;
/* Must have Cseq */
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( cmd ) | | ast_strlen_zero ( cseq ) )
2002-06-28 20:34:46 +00:00
return - 1 ;
if ( sscanf ( cseq , " %i%n " , & seqno , & len ) ! = 1 ) {
ast_log ( LOG_DEBUG , " No seqno in '%s' \n " , cmd ) ;
return - 1 ;
}
/* Get the command */
cseq + = len ;
2003-02-07 04:07:10 +00:00
2004-05-09 21:05:43 +00:00
/* Determine the request URI for sip, sips or tel URIs */
2003-02-07 04:07:10 +00:00
if ( determine_firstline_parts ( req ) < 0 ) {
return - 1 ;
2002-06-28 20:34:46 +00:00
}
2003-02-07 04:07:10 +00:00
cmd = req - > rlPart1 ;
e = req - > rlPart2 ;
2004-05-09 21:05:43 +00:00
/* Save useragent of the client */
useragent = get_header ( req , " User-Agent " ) ;
strncpy ( p - > useragent , useragent , sizeof ( p - > useragent ) - 1 ) ;
2003-02-07 04:07:10 +00:00
if ( strcasecmp ( cmd , " SIP/2.0 " ) ) {
/* Request coming in */
2004-07-22 23:16:40 +00:00
if ( p - > icseq & & ( p - > icseq > seqno ) ) {
ast_log ( LOG_DEBUG , " Ignoring too old packet packet %d (expecting >= %d) \n " , seqno , p - > icseq ) ;
2003-02-07 04:07:10 +00:00
return - 1 ;
2004-10-19 03:17:26 +00:00
} else if ( p - > icseq & & ( p - > icseq = = seqno ) & & ( strcasecmp ( cmd , " CANCEL " ) | | p - > alreadygone ) ) {
2003-02-07 04:07:10 +00:00
/* ignore means "don't do anything with it" but still have to
2004-07-22 23:16:40 +00:00
respond appropriately . We do this if we receive a repeat of
the last sequence number */
2003-02-07 04:07:10 +00:00
ignore = 1 ;
}
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( p - > theirtag ) ) {
2003-04-03 16:20:47 +00:00
from = get_header ( req , " From " ) ;
from = strstr ( from , " tag= " ) ;
if ( from ) {
from + = 4 ;
strncpy ( p - > theirtag , from , sizeof ( p - > theirtag ) - 1 ) ;
from = strchr ( p - > theirtag , ' ; ' ) ;
if ( from )
* from = ' \0 ' ;
}
}
2003-11-04 02:40:09 +00:00
snprintf ( p - > lastmsg , sizeof ( p - > lastmsg ) , " Rx: %s " , cmd ) ;
2003-02-07 04:07:10 +00:00
} else {
/* Response to our request -- Do some sanity checks */
if ( ! p - > initreq . headers ) {
ast_log ( LOG_DEBUG , " That's odd... Got a response on a call we dont know about. \n " ) ;
2003-04-05 21:36:30 +00:00
p - > needdestroy = 1 ;
2003-02-07 04:07:10 +00:00
return 0 ;
} else if ( p - > ocseq & & ( p - > ocseq < seqno ) ) {
ast_log ( LOG_DEBUG , " Ignoring out of order response %d (expecting %d) \n " , seqno , p - > ocseq ) ;
return - 1 ;
} else if ( p - > ocseq & & ( p - > ocseq ! = seqno ) ) {
/* ignore means "don't do anything with it" but still have to
respond appropriately */
ignore = 1 ;
}
}
2003-03-18 18:11:43 +00:00
if ( strcmp ( cmd , " SIP/2.0 " ) & & ( seqno > = p - > icseq ) )
2004-07-22 23:16:40 +00:00
/* Next should follow monotonically (but not necessarily
incrementally - - thanks again to the genius authors of SIP - -
increasing */
p - > icseq = seqno ;
2003-02-07 04:07:10 +00:00
/* Initialize the context if it hasn't been already */
if ( ! strcasecmp ( cmd , " OPTIONS " ) ) {
2003-04-08 14:49:12 +00:00
res = get_destination ( p , req ) ;
build_contact ( p ) ;
/* XXX Should we authenticate OPTIONS? XXX */
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( p - > context ) )
2004-07-08 11:05:03 +00:00
strncpy ( p - > context , default_context , sizeof ( p - > context ) - 1 ) ;
2003-02-07 04:07:10 +00:00
if ( res < 0 )
2004-05-12 23:35:50 +00:00
transmit_response_with_allow ( p , " 404 Not Found " , req , 0 ) ;
2003-02-07 04:07:10 +00:00
else if ( res > 0 )
2004-05-12 23:35:50 +00:00
transmit_response_with_allow ( p , " 484 Address Incomplete " , req , 0 ) ;
2003-02-07 04:07:10 +00:00
else
2004-05-12 23:35:50 +00:00
transmit_response_with_allow ( p , " 200 OK " , req , 0 ) ;
2003-05-14 19:17:20 +00:00
/* Destroy if this OPTIONS was the opening request, but not if
it ' s in the middle of a normal call flow . */
if ( ! p - > lastinvite )
p - > needdestroy = 1 ;
2003-02-07 04:07:10 +00:00
} else if ( ! strcasecmp ( cmd , " INVITE " ) ) {
2003-02-18 18:15:30 +00:00
if ( p - > outgoing & & p - > owner & & ( p - > owner - > _state ! = AST_STATE_UP ) ) {
/* This is a call to ourself. Send ourselves an error code and stop
processing immediately , as SIP really has no good mechanism for
being able to call yourself */
transmit_response ( p , " 482 Loop Detected " , req ) ;
/* We do NOT destroy p here, so that our response will be accepted */
return 0 ;
}
2002-06-28 20:34:46 +00:00
/* Process the SDP portion */
if ( ! ignore ) {
/* Use this as the basis */
2004-06-18 13:53:48 +00:00
if ( debug )
2003-02-07 04:07:10 +00:00
ast_verbose ( " Using latest request as basis request \n " ) ;
2004-05-26 22:18:59 +00:00
sip_cancel_destroy ( p ) ;
2003-02-28 06:00:18 +00:00
/* This call is no longer outgoing if it ever was */
p - > outgoing = 0 ;
2004-05-27 05:06:32 +00:00
/* This also counts as a pending invite */
2004-05-27 22:12:55 +00:00
p - > pendinginvite = seqno ;
2002-06-28 20:34:46 +00:00
copy_request ( & p - > initreq , req ) ;
check_via ( p , req ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( get_header ( req , " Content-Type " ) ) ) {
2003-02-07 04:07:10 +00:00
if ( process_sdp ( p , req ) )
return - 1 ;
} else {
2003-09-25 13:18:03 +00:00
p - > jointcapability = p - > capability ;
2004-02-19 00:14:58 +00:00
ast_log ( LOG_DEBUG , " Hm.... No sdp for the moment \n " ) ;
2003-02-07 04:07:10 +00:00
}
2003-04-30 22:14:36 +00:00
/* Queue NULL frame to prod ast_rtp_bridge if appropriate */
2003-04-30 22:17:21 +00:00
if ( p - > owner )
2004-04-06 22:17:32 +00:00
ast_queue_frame ( p - > owner , & af ) ;
2004-06-18 13:53:48 +00:00
} else if ( debug )
2003-02-07 04:07:10 +00:00
ast_verbose ( " Ignoring this request \n " ) ;
2002-06-28 20:34:46 +00:00
if ( ! p - > lastinvite ) {
2003-02-07 04:07:10 +00:00
/* Handle authentication if this is our first invite */
2004-03-21 19:25:13 +00:00
res = check_user ( p , req , cmd , e , 1 , sin , ignore ) ;
2003-02-07 04:07:10 +00:00
if ( res ) {
if ( res < 0 ) {
ast_log ( LOG_NOTICE , " Failed to authenticate user %s \n " , get_header ( req , " From " ) ) ;
2004-06-18 03:59:19 +00:00
if ( ignore )
transmit_response ( p , " 403 Forbidden " , req ) ;
else
transmit_response_reliable ( p , " 403 Forbidden " , req , 1 ) ;
2003-04-05 21:36:30 +00:00
p - > needdestroy = 1 ;
2003-02-07 04:07:10 +00:00
}
return 0 ;
}
2002-06-28 20:34:46 +00:00
/* Initialize the context if it hasn't been already */
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( p - > context ) )
2004-07-08 11:05:03 +00:00
strncpy ( p - > context , default_context , sizeof ( p - > context ) - 1 ) ;
2003-07-26 15:12:37 +00:00
/* Check number of concurrent calls -vs- incoming limit HERE */
2003-09-13 20:26:20 +00:00
ast_log ( LOG_DEBUG , " Check for res for %s \n " , p - > username ) ;
2004-04-26 14:54:33 +00:00
res = update_user_counter ( p , INC_IN_USE ) ;
2003-07-26 15:12:37 +00:00
if ( res ) {
if ( res < 0 ) {
ast_log ( LOG_DEBUG , " Failed to place call for user %s, too many calls \n " , p - > username ) ;
p - > needdestroy = 1 ;
}
return 0 ;
}
2003-04-09 04:19:59 +00:00
/* Get destination right away */
gotdest = get_destination ( p , NULL ) ;
2003-05-12 21:12:48 +00:00
get_rdnis ( p , NULL ) ;
2003-08-24 06:24:38 +00:00
extract_uri ( p , req ) ;
2003-04-09 04:19:59 +00:00
build_contact ( p ) ;
2003-04-08 14:49:12 +00:00
if ( gotdest ) {
2003-07-26 15:12:37 +00:00
if ( gotdest < 0 ) {
2004-05-16 16:01:09 +00:00
if ( ignore )
transmit_response ( p , " 404 Not Found " , req ) ;
else
transmit_response_reliable ( p , " 404 Not Found " , req , 1 ) ;
2004-04-26 14:54:33 +00:00
update_user_counter ( p , DEC_IN_USE ) ;
2003-07-26 15:12:37 +00:00
} else {
2004-05-16 16:01:09 +00:00
if ( ignore )
transmit_response ( p , " 484 Address Incomplete " , req ) ;
else
transmit_response_reliable ( p , " 484 Address Incomplete " , req , 1 ) ;
2004-04-26 14:54:33 +00:00
update_user_counter ( p , DEC_IN_USE ) ;
2003-07-26 15:12:37 +00:00
}
2003-04-05 21:36:30 +00:00
p - > needdestroy = 1 ;
2002-06-28 20:34:46 +00:00
} else {
/* If no extension was specified, use the s one */
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( p - > exten ) )
2003-02-07 04:07:10 +00:00
strncpy ( p - > exten , " s " , sizeof ( p - > exten ) - 1 ) ;
2002-09-12 17:13:17 +00:00
/* Initialize tag */
p - > tag = rand ( ) ;
2002-06-28 20:34:46 +00:00
/* First invitation */
2004-05-03 21:01:14 +00:00
c = sip_new ( p , AST_STATE_DOWN , ast_strlen_zero ( p - > username ) ? NULL : p - > username ) ;
2003-12-19 16:14:51 +00:00
* recount = 1 ;
2003-04-05 22:29:46 +00:00
/* Save Record-Route for any later requests we make on this dialogue */
build_route ( p , req , 0 ) ;
2003-04-05 21:36:30 +00:00
if ( c ) {
/* Pre-lock the call */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & c - > lock ) ;
2003-04-05 21:36:30 +00:00
}
2002-06-28 20:34:46 +00:00
}
} else
c = p - > owner ;
if ( ! ignore & & p )
p - > lastinvite = seqno ;
if ( c ) {
2002-09-12 17:13:17 +00:00
switch ( c - > _state ) {
2003-02-07 04:07:10 +00:00
case AST_STATE_DOWN :
transmit_response ( p , " 100 Trying " , req ) ;
ast_setstate ( c , AST_STATE_RING ) ;
2003-04-09 04:00:43 +00:00
if ( strcmp ( p - > exten , ast_pickup_ext ( ) ) ) {
if ( ast_pbx_start ( c ) ) {
ast_log ( LOG_WARNING , " Failed to start PBX :( \n " ) ;
2003-04-11 18:22:21 +00:00
/* Unlock locks so ast_hangup can do its magic */
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & c - > lock ) ;
ast_mutex_unlock ( & p - > lock ) ;
2003-04-09 16:47:40 +00:00
ast_hangup ( c ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & p - > lock ) ;
2004-05-16 16:01:09 +00:00
if ( ignore )
transmit_response ( p , " 503 Unavailable " , req ) ;
else
transmit_response_reliable ( p , " 503 Unavailable " , req , 1 ) ;
2003-04-09 04:00:43 +00:00
c = NULL ;
}
} else {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & c - > lock ) ;
2003-08-23 22:27:10 +00:00
if ( ast_pickup_call ( c ) ) {
ast_log ( LOG_NOTICE , " Nothing to pick up \n " ) ;
2004-05-16 16:01:09 +00:00
if ( ignore )
transmit_response ( p , " 503 Unavailable " , req ) ;
else
transmit_response_reliable ( p , " 503 Unavailable " , req , 1 ) ;
2003-08-23 22:27:10 +00:00
p - > alreadygone = 1 ;
/* Unlock locks so ast_hangup can do its magic */
ast_mutex_unlock ( & p - > lock ) ;
ast_hangup ( c ) ;
ast_mutex_lock ( & p - > lock ) ;
c = NULL ;
} else {
ast_mutex_unlock ( & p - > lock ) ;
2003-10-25 17:41:02 +00:00
ast_setstate ( c , AST_STATE_DOWN ) ;
2003-08-23 22:27:10 +00:00
ast_hangup ( c ) ;
ast_mutex_lock ( & p - > lock ) ;
c = NULL ;
}
2003-02-07 04:07:10 +00:00
}
break ;
2002-06-28 20:34:46 +00:00
case AST_STATE_RING :
2002-09-12 17:13:17 +00:00
transmit_response ( p , " 100 Trying " , req ) ;
2002-06-28 20:34:46 +00:00
break ;
case AST_STATE_RINGING :
2002-09-12 17:13:17 +00:00
transmit_response ( p , " 180 Ringing " , req ) ;
2002-06-28 20:34:46 +00:00
break ;
case AST_STATE_UP :
2003-03-29 16:53:55 +00:00
transmit_response_with_sdp ( p , " 200 OK " , req , 1 ) ;
2002-06-28 20:34:46 +00:00
break ;
default :
2002-09-12 17:13:17 +00:00
ast_log ( LOG_WARNING , " Don't know how to handle INVITE in state %d \n " , c - > _state ) ;
transmit_response ( p , " 100 Trying " , req ) ;
2002-06-28 20:34:46 +00:00
}
} else {
2003-04-08 04:26:24 +00:00
if ( p & & ! p - > needdestroy ) {
2002-06-28 20:34:46 +00:00
ast_log ( LOG_NOTICE , " Unable to create/find channel \n " ) ;
2004-05-16 16:01:09 +00:00
if ( ignore )
transmit_response ( p , " 503 Unavailable " , req ) ;
else
transmit_response_reliable ( p , " 503 Unavailable " , req , 1 ) ;
2003-04-05 21:36:30 +00:00
p - > needdestroy = 1 ;
2003-02-12 13:59:15 +00:00
}
2002-06-28 20:34:46 +00:00
}
2003-02-12 13:59:15 +00:00
} else if ( ! strcasecmp ( cmd , " REFER " ) ) {
ast_log ( LOG_DEBUG , " We found a REFER! \n " ) ;
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( p - > context ) )
2004-07-08 11:05:03 +00:00
strncpy ( p - > context , default_context , sizeof ( p - > context ) - 1 ) ;
2003-02-12 13:59:15 +00:00
res = get_refer_info ( p , req ) ;
if ( res < 0 )
2004-05-12 23:35:50 +00:00
transmit_response_with_allow ( p , " 404 Not Found " , req , 1 ) ;
2003-02-12 13:59:15 +00:00
else if ( res > 0 )
2004-05-12 23:35:50 +00:00
transmit_response_with_allow ( p , " 484 Address Incomplete " , req , 1 ) ;
2003-02-16 06:00:12 +00:00
else {
2004-07-09 10:46:50 +00:00
int nobye = 0 ;
2004-04-19 22:55:35 +00:00
if ( ! ignore ) {
if ( p - > refer_call ) {
ast_log ( LOG_DEBUG , " 202 Accepted (supervised) \n " ) ;
attempt_transfer ( p , p - > refer_call ) ;
2004-05-20 07:52:07 +00:00
if ( p - > refer_call - > owner )
ast_mutex_unlock ( & p - > refer_call - > owner - > lock ) ;
2004-04-19 22:55:35 +00:00
ast_mutex_unlock ( & p - > refer_call - > lock ) ;
p - > refer_call = NULL ;
p - > gotrefer = 1 ;
} else {
ast_log ( LOG_DEBUG , " 202 Accepted (blind) \n " ) ;
c = p - > owner ;
if ( c ) {
2004-10-23 12:19:47 +00:00
transfer_to = ast_bridged_channel ( c ) ;
2004-04-19 22:55:35 +00:00
if ( transfer_to ) {
ast_moh_stop ( transfer_to ) ;
2004-07-09 10:46:50 +00:00
if ( ! strcmp ( p - > refer_to , ast_parking_ext ( ) ) ) {
/* Must release c's lock now, because it will not longer
be accessible after the transfer ! */
* nounlock = 1 ;
ast_mutex_unlock ( & c - > lock ) ;
2004-07-09 22:43:15 +00:00
sip_park ( transfer_to , c , req ) ;
2004-07-09 10:46:50 +00:00
nobye = 1 ;
} else {
/* Must release c's lock now, because it will not longer
be accessible after the transfer ! */
* nounlock = 1 ;
ast_mutex_unlock ( & c - > lock ) ;
ast_async_goto ( transfer_to , p - > context , p - > refer_to , 1 ) ;
}
2004-04-19 22:55:35 +00:00
} else {
ast_queue_hangup ( p - > owner ) ;
}
2003-06-25 16:12:23 +00:00
}
2004-04-19 22:55:35 +00:00
p - > gotrefer = 1 ;
2003-02-16 06:00:12 +00:00
}
2004-08-17 14:20:43 +00:00
transmit_response ( p , " 202 Accepted " , req ) ;
transmit_notify_with_sipfrag ( p , seqno ) ;
2004-04-19 22:55:35 +00:00
/* Always increment on a BYE */
2004-07-09 10:46:50 +00:00
if ( ! nobye ) {
transmit_request_with_auth ( p , " BYE " , 0 , 1 , 1 ) ;
p - > alreadygone = 1 ;
}
2003-02-16 06:00:12 +00:00
}
2003-02-14 06:00:11 +00:00
}
2003-04-06 04:23:18 +00:00
} else if ( ! strcasecmp ( cmd , " CANCEL " ) ) {
2003-05-11 21:07:53 +00:00
check_via ( p , req ) ;
2003-04-06 04:23:18 +00:00
p - > alreadygone = 1 ;
if ( p - > rtp ) {
/* Immediately stop RTP */
ast_rtp_stop ( p - > rtp ) ;
}
2003-06-28 16:40:02 +00:00
if ( p - > vrtp ) {
/* Immediately stop VRTP */
ast_rtp_stop ( p - > vrtp ) ;
}
2003-04-06 04:23:18 +00:00
if ( p - > owner )
2004-04-06 22:17:32 +00:00
ast_queue_hangup ( p - > owner ) ;
2003-11-10 17:18:09 +00:00
else
p - > needdestroy = 1 ;
2004-01-26 05:28:14 +00:00
if ( p - > initreq . len > 0 ) {
2004-05-16 16:01:09 +00:00
if ( ! ignore )
transmit_response_reliable ( p , " 487 Request Terminated " , & p - > initreq , 1 ) ;
2004-01-26 05:28:14 +00:00
transmit_response ( p , " 200 OK " , req ) ;
} else {
2004-05-16 16:01:09 +00:00
transmit_response ( p , " 481 Call Leg Does Not Exist " , req ) ;
2004-01-26 05:28:14 +00:00
}
2003-04-06 04:23:18 +00:00
} else if ( ! strcasecmp ( cmd , " BYE " ) ) {
2002-06-28 20:34:46 +00:00
copy_request ( & p - > initreq , req ) ;
2003-05-11 21:07:53 +00:00
check_via ( p , req ) ;
2002-06-28 20:34:46 +00:00
p - > alreadygone = 1 ;
if ( p - > rtp ) {
/* Immediately stop RTP */
2003-03-20 22:01:53 +00:00
ast_rtp_stop ( p - > rtp ) ;
2002-06-28 20:34:46 +00:00
}
2003-06-28 16:40:02 +00:00
if ( p - > vrtp ) {
/* Immediately stop VRTP */
ast_rtp_stop ( p - > vrtp ) ;
}
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( get_header ( req , " Also " ) ) ) {
2004-02-19 00:42:10 +00:00
ast_log ( LOG_NOTICE , " Client '%s' using deprecated BYE/Also transfer method. Ask vendor to support REFER instead \n " ,
2004-06-29 12:56:46 +00:00
ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > recv . sin_addr ) ) ;
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( p - > context ) )
2004-07-08 11:05:03 +00:00
strncpy ( p - > context , default_context , sizeof ( p - > context ) - 1 ) ;
2003-08-25 14:17:14 +00:00
res = get_also_info ( p , req ) ;
2003-08-25 00:05:48 +00:00
if ( ! res ) {
c = p - > owner ;
if ( c ) {
2004-10-23 12:19:47 +00:00
transfer_to = ast_bridged_channel ( c ) ;
2003-08-25 00:05:48 +00:00
if ( transfer_to ) {
/* Don't actually hangup here... */
ast_moh_stop ( transfer_to ) ;
2004-04-06 22:17:32 +00:00
ast_async_goto ( transfer_to , p - > context , p - > refer_to , 1 ) ;
2003-08-25 00:05:48 +00:00
} else
2004-04-06 22:17:32 +00:00
ast_queue_hangup ( p - > owner ) ;
2003-08-25 00:05:48 +00:00
}
} else {
2004-06-29 12:56:46 +00:00
ast_log ( LOG_WARNING , " Invalid transfer information from '%s' \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > recv . sin_addr ) ) ;
2004-04-06 22:17:32 +00:00
ast_queue_hangup ( p - > owner ) ;
2003-08-25 00:05:48 +00:00
}
} else if ( p - > owner )
2004-04-06 22:17:32 +00:00
ast_queue_hangup ( p - > owner ) ;
2003-09-30 04:57:20 +00:00
else
p - > needdestroy = 1 ;
2002-09-12 17:13:17 +00:00
transmit_response ( p , " 200 OK " , req ) ;
2003-02-07 04:07:10 +00:00
} else if ( ! strcasecmp ( cmd , " MESSAGE " ) ) {
2004-04-28 22:12:08 +00:00
if ( ! ignore ) {
2004-06-18 13:53:48 +00:00
if ( debug )
2004-04-28 22:12:08 +00:00
ast_verbose ( " Receiving message! \n " ) ;
receive_message ( p , req ) ;
}
2003-02-07 04:07:10 +00:00
transmit_response ( p , " 200 OK " , req ) ;
2003-04-06 18:19:51 +00:00
} else if ( ! strcasecmp ( cmd , " SUBSCRIBE " ) ) {
if ( ! ignore ) {
/* Use this as the basis */
2004-06-18 13:53:48 +00:00
if ( debug )
2003-04-06 18:19:51 +00:00
ast_verbose ( " Using latest SUBSCRIBE request as basis request \n " ) ;
/* This call is no longer outgoing if it ever was */
p - > outgoing = 0 ;
copy_request ( & p - > initreq , req ) ;
check_via ( p , req ) ;
2004-06-18 13:53:48 +00:00
} else if ( debug )
2003-04-06 18:19:51 +00:00
ast_verbose ( " Ignoring this request \n " ) ;
2003-11-27 22:09:42 +00:00
2003-04-06 18:19:51 +00:00
if ( ! p - > lastinvite ) {
2004-06-21 14:39:19 +00:00
char mailbox [ 256 ] = " " ;
char rbox [ 256 ] ;
int found = 0 ;
2003-04-06 18:19:51 +00:00
/* Handle authentication if this is our first subscribe */
2004-06-21 14:39:19 +00:00
res = check_user_full ( p , req , cmd , e , 0 , sin , ignore , mailbox , sizeof ( mailbox ) ) ;
2003-04-06 18:19:51 +00:00
if ( res ) {
if ( res < 0 ) {
ast_log ( LOG_NOTICE , " Failed to authenticate user %s for SUBSCRIBE \n " , get_header ( req , " From " ) ) ;
2003-08-21 23:00:22 +00:00
p - > needdestroy = 1 ;
2003-04-06 18:19:51 +00:00
}
return 0 ;
}
/* Initialize the context if it hasn't been already */
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( p - > context ) )
2004-07-08 11:05:03 +00:00
strncpy ( p - > context , default_context , sizeof ( p - > context ) - 1 ) ;
2003-04-09 04:19:59 +00:00
/* Get destination right away */
gotdest = get_destination ( p , NULL ) ;
build_contact ( p ) ;
2003-04-08 14:49:12 +00:00
if ( gotdest ) {
if ( gotdest < 0 )
2003-04-06 18:19:51 +00:00
transmit_response ( p , " 404 Not Found " , req ) ;
else
transmit_response ( p , " 484 Address Incomplete " , req ) ;
2003-08-21 23:00:22 +00:00
p - > needdestroy = 1 ;
2003-04-06 18:19:51 +00:00
} else {
/* Initialize tag */
p - > tag = rand ( ) ;
if ( ! strcmp ( get_header ( req , " Accept " ) , " application/dialog-info+xml " ) )
p - > subscribed = 2 ;
2004-06-21 14:39:19 +00:00
else if ( ! strcmp ( get_header ( req , " Accept " ) , " application/simple-message-summary " ) ) {
/* Looks like they actually want a mailbox */
snprintf ( rbox , sizeof ( rbox ) , " ,%s@%s, " , p - > exten , p - > context ) ;
if ( strstr ( mailbox , rbox ) )
found + + ;
if ( ! found ) {
snprintf ( rbox , sizeof ( rbox ) , " ,%s, " , p - > exten ) ;
if ( strstr ( mailbox , rbox ) )
found + + ;
}
if ( found )
transmit_response ( p , " 200 OK " , req ) ;
2004-06-28 21:37:25 +00:00
else {
2004-06-21 14:51:38 +00:00
transmit_response ( p , " 403 Forbidden " , req ) ;
2004-06-28 21:37:25 +00:00
p - > needdestroy = 1 ;
}
2004-06-21 14:39:19 +00:00
} else
2003-04-06 18:19:51 +00:00
p - > subscribed = 1 ;
2004-06-21 14:39:19 +00:00
if ( p - > subscribed )
p - > stateid = ast_extension_state_add ( p - > context , p - > exten , cb_extensionstate , p ) ;
2003-04-06 18:19:51 +00:00
}
} else
c = p - > owner ;
if ( ! ignore & & p )
p - > lastinvite = seqno ;
2004-06-29 13:52:03 +00:00
if ( p & & ! p - > needdestroy ) {
2003-04-08 03:24:12 +00:00
if ( ! ( p - > expiry = atoi ( get_header ( req , " Expires " ) ) ) ) {
2003-04-06 18:19:51 +00:00
transmit_response ( p , " 200 OK " , req ) ;
2003-08-21 23:00:22 +00:00
p - > needdestroy = 1 ;
2003-04-06 18:19:51 +00:00
return 0 ;
}
2004-04-26 14:54:33 +00:00
/* The next line can be removed if the SNOM200 Expires bug is fixed */
2003-04-06 18:19:51 +00:00
if ( p - > subscribed = = 1 ) {
2003-04-08 03:24:12 +00:00
if ( p - > expiry > max_expiry )
p - > expiry = max_expiry ;
2003-04-06 18:19:51 +00:00
}
transmit_response ( p , " 200 OK " , req ) ;
2003-04-08 03:24:12 +00:00
sip_scheddestroy ( p , ( p - > expiry + 10 ) * 1000 ) ;
2003-04-06 18:19:51 +00:00
transmit_state_notify ( p , ast_extension_state ( NULL , p - > context , p - > exten ) , 1 ) ;
}
2003-02-07 04:07:10 +00:00
} else if ( ! strcasecmp ( cmd , " INFO " ) ) {
2004-04-28 22:12:08 +00:00
if ( ! ignore ) {
2004-06-18 13:53:48 +00:00
if ( debug )
2004-04-28 22:12:08 +00:00
ast_verbose ( " Receiving DTMF! \n " ) ;
receive_info ( p , req ) ;
2004-05-30 20:03:39 +00:00
} else { /* if ignoring, transmit response */
transmit_response ( p , " 200 OK " , req ) ;
2004-04-28 22:12:08 +00:00
}
2004-05-30 20:03:39 +00:00
} else if ( ! strcasecmp ( cmd , " NOTIFY " ) ) {
/* XXX we get NOTIFY's from some servers. WHY?? Maybe we should
look into this someday XXX */
transmit_response ( p , " 200 OK " , req ) ;
if ( ! p - > lastinvite ) p - > needdestroy = 1 ;
2002-06-28 20:34:46 +00:00
} else if ( ! strcasecmp ( cmd , " REGISTER " ) ) {
/* Use this as the basis */
2004-06-18 13:53:48 +00:00
if ( debug )
2003-02-07 04:07:10 +00:00
ast_verbose ( " Using latest request as basis request \n " ) ;
2002-06-28 20:34:46 +00:00
copy_request ( & p - > initreq , req ) ;
check_via ( p , req ) ;
2004-03-21 19:25:13 +00:00
if ( ( res = register_verify ( p , sin , req , e , ignore ) ) < 0 )
2004-06-29 12:56:46 +00:00
ast_log ( LOG_NOTICE , " Registration from '%s' failed for '%s' \n " , get_header ( req , " To " ) , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , sin - > sin_addr ) ) ;
2003-02-12 13:59:15 +00:00
if ( res < 1 ) {
2004-04-02 21:43:07 +00:00
/* Destroy the session, but keep us around for just a bit in case they don't
get our 200 OK */
sip_scheddestroy ( p , 15 * 1000 ) ;
2003-02-12 13:59:15 +00:00
}
2002-06-28 20:34:46 +00:00
} else if ( ! strcasecmp ( cmd , " ACK " ) ) {
2004-05-27 22:12:55 +00:00
/* Make sure we don't ignore this */
if ( seqno = = p - > pendinginvite ) {
p - > pendinginvite = 0 ;
2004-07-16 15:45:37 +00:00
__sip_ack ( p , seqno , FLAG_RESPONSE , NULL ) ;
2004-05-27 22:12:55 +00:00
if ( ! ast_strlen_zero ( get_header ( req , " Content-Type " ) ) ) {
if ( process_sdp ( p , req ) )
return - 1 ;
}
check_pendings ( p ) ;
}
2004-05-03 21:01:14 +00:00
if ( ! p - > lastinvite & & ast_strlen_zero ( p - > randdata ) )
2003-04-11 18:22:21 +00:00
p - > needdestroy = 1 ;
2002-06-28 20:34:46 +00:00
} else if ( ! strcasecmp ( cmd , " SIP/2.0 " ) ) {
2003-09-04 04:40:37 +00:00
extract_uri ( p , req ) ;
2002-06-28 20:34:46 +00:00
while ( * e & & ( * e < 33 ) ) e + + ;
if ( sscanf ( e , " %i %n " , & respid , & len ) ! = 1 ) {
ast_log ( LOG_WARNING , " Invalid response: '%s' \n " , e ) ;
} else {
2003-12-09 22:09:05 +00:00
handle_response ( p , respid , e + len , req , ignore ) ;
2002-06-28 20:34:46 +00:00
}
} else {
2004-05-12 23:35:50 +00:00
transmit_response_with_allow ( p , " 405 Method Not Allowed " , req , 0 ) ;
2002-06-28 20:34:46 +00:00
ast_log ( LOG_NOTICE , " Unknown SIP command '%s' from '%s' \n " ,
2004-06-29 12:56:46 +00:00
cmd , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > sa . sin_addr ) ) ;
2004-02-15 06:35:22 +00:00
/* If this is some new method, and we don't have a call, destroy it now */
2003-04-06 02:41:42 +00:00
if ( ! p - > initreq . headers )
p - > needdestroy = 1 ;
2002-06-28 20:34:46 +00:00
}
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- sipsock_read: Read data from SIP socket ---*/
/* Successful messages is connected to SIP call and forwarded to handle_request() */
2002-06-28 20:34:46 +00:00
static int sipsock_read ( int * id , int fd , short events , void * ignore )
{
struct sip_request req ;
2003-03-13 15:44:31 +00:00
struct sockaddr_in sin = { 0 , } ;
2002-06-28 20:34:46 +00:00
struct sip_pvt * p ;
int res ;
int len ;
2004-07-09 10:46:50 +00:00
int nounlock ;
2003-12-19 16:14:51 +00:00
int recount = 0 ;
2004-08-17 14:26:25 +00:00
int debug ;
2004-06-18 13:53:48 +00:00
2002-06-28 20:34:46 +00:00
len = sizeof ( sin ) ;
2002-09-12 17:13:17 +00:00
memset ( & req , 0 , sizeof ( req ) ) ;
2002-06-28 20:34:46 +00:00
res = recvfrom ( sipsock , req . data , sizeof ( req . data ) - 1 , 0 , ( struct sockaddr * ) & sin , & len ) ;
if ( res < 0 ) {
2004-06-29 14:22:27 +00:00
if ( errno = = EAGAIN )
ast_log ( LOG_NOTICE , " SIP: Received packet with bad UDP checksum \n " ) ;
else if ( errno ! = ECONNREFUSED )
2002-06-28 20:34:46 +00:00
ast_log ( LOG_WARNING , " Recv error: %s \n " , strerror ( errno ) ) ;
return 1 ;
}
req . data [ res ] = ' \0 ' ;
req . len = res ;
2004-08-17 14:26:25 +00:00
debug = sip_debug_test_addr ( & sin ) ;
2004-06-18 13:53:48 +00:00
if ( debug )
2004-01-12 21:37:50 +00:00
ast_verbose ( " \n \n Sip read: \n %s \n " , req . data ) ;
2004-04-27 22:32:57 +00:00
if ( pedanticsipchecking )
req . len = lws2sws ( req . data , req . len ) ;
2002-06-28 20:34:46 +00:00
parse ( & req ) ;
2004-06-18 13:53:48 +00:00
if ( debug )
2004-05-01 21:25:31 +00:00
ast_verbose ( " %d headers, %d lines \n " , req . headers , req . lines ) ;
2002-06-28 20:34:46 +00:00
if ( req . headers < 2 ) {
/* Must have at least two headers */
return 1 ;
}
2003-02-16 06:00:12 +00:00
/* Process request, with netlock held */
2003-09-17 20:51:53 +00:00
retrylock :
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & netlock ) ;
2002-06-28 20:34:46 +00:00
p = find_call ( & req , & sin ) ;
if ( p ) {
2003-04-05 21:36:30 +00:00
/* Go ahead and lock the owner if it has one -- we may need it */
2003-08-13 15:25:16 +00:00
if ( p - > owner & & ast_mutex_trylock ( & p - > owner - > lock ) ) {
2003-04-05 21:36:30 +00:00
ast_log ( LOG_DEBUG , " Failed to grab lock, trying again... \n " ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2003-09-17 20:51:53 +00:00
ast_mutex_unlock ( & netlock ) ;
2003-04-05 21:36:30 +00:00
/* Sleep infintismly short amount of time */
usleep ( 1 ) ;
goto retrylock ;
}
2003-03-05 06:00:17 +00:00
memcpy ( & p - > recv , & sin , sizeof ( p - > recv ) ) ;
2004-07-14 11:51:44 +00:00
if ( recordhistory ) {
char tmp [ 80 ] = " " ;
/* This is a response, note what it was for */
snprintf ( tmp , sizeof ( tmp ) , " %s / %s " , req . data , get_header ( & req , " CSeq " ) ) ;
append_history ( p , " Rx " , tmp ) ;
}
2004-07-09 10:46:50 +00:00
nounlock = 0 ;
handle_request ( p , & req , & sin , & recount , & nounlock ) ;
if ( p - > owner & & ! nounlock )
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & p - > owner - > lock ) ;
ast_mutex_unlock ( & p - > lock ) ;
2002-06-28 20:34:46 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & netlock ) ;
2003-12-19 16:14:51 +00:00
if ( recount )
ast_update_use_count ( ) ;
2002-06-28 20:34:46 +00:00
return 1 ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_send_mwi_to_peer: Send message waiting indication ---*/
2003-02-12 13:59:15 +00:00
static int sip_send_mwi_to_peer ( struct sip_peer * peer )
{
/* Called with peerl lock, but releases it */
struct sip_pvt * p ;
char name [ 256 ] = " " ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-03-26 00:15:11 +00:00
int newmsgs , oldmsgs ;
2003-02-12 13:59:15 +00:00
/* Check for messages */
2003-03-26 00:15:11 +00:00
ast_app_messagecount ( peer - > mailbox , & newmsgs , & oldmsgs ) ;
2003-02-12 13:59:15 +00:00
time ( & peer - > lastmsgcheck ) ;
/* Return now if it's the same thing we told them last time */
2003-03-26 00:15:11 +00:00
if ( ( ( newmsgs < < 8 ) | ( oldmsgs ) ) = = peer - > lastmsgssent ) {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2003-02-12 13:59:15 +00:00
return 0 ;
}
2003-03-10 22:05:28 +00:00
p = sip_alloc ( NULL , NULL , 0 ) ;
2003-02-12 13:59:15 +00:00
if ( ! p ) {
ast_log ( LOG_WARNING , " Unable to build sip pvt data for MWI \n " ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2003-02-12 13:59:15 +00:00
return - 1 ;
}
strncpy ( name , peer - > name , sizeof ( name ) - 1 ) ;
2003-03-26 00:15:11 +00:00
peer - > lastmsgssent = ( ( newmsgs < < 8 ) | ( oldmsgs ) ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2004-02-01 23:55:17 +00:00
if ( create_addr ( p , name ) ) {
2003-02-12 13:59:15 +00:00
/* Maybe they're not registered, etc. */
sip_destroy ( p ) ;
return 0 ;
}
/* Recalculate our side, and recalculate Call ID */
2003-08-21 02:27:25 +00:00
if ( ast_sip_ouraddrfor ( & p - > sa . sin_addr , & p - > ourip ) )
2003-05-04 05:52:52 +00:00
memcpy ( & p - > ourip , & __ourip , sizeof ( p - > ourip ) ) ;
/* z9hG4bK is a magic cookie. See RFC 3261 section 8.1.1.7 */
2004-08-27 02:45:35 +00:00
if ( p - > nat & SIP_NAT_RFC3581 )
2004-06-29 12:56:46 +00:00
snprintf ( p - > via , sizeof ( p - > via ) , " SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) , ourport , p - > branch ) ;
2004-06-28 23:24:36 +00:00
else /* UNIDEN UIP200 bug */
2004-06-29 12:56:46 +00:00
snprintf ( p - > via , sizeof ( p - > via ) , " SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) , ourport , p - > branch ) ;
2004-09-13 12:32:04 +00:00
build_callid ( p - > callid , sizeof ( p - > callid ) , p - > ourip , p - > fromdomain ) ;
2003-02-12 13:59:15 +00:00
/* Send MWI */
2003-03-28 06:13:04 +00:00
p - > outgoing = 1 ;
2004-08-17 14:20:43 +00:00
transmit_notify_with_mwi ( p , newmsgs , oldmsgs ) ;
2003-03-28 06:13:04 +00:00
sip_scheddestroy ( p , 15000 ) ;
2003-02-12 13:59:15 +00:00
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- do_monitor: The SIP monitoring thread ---*/
2002-06-28 20:34:46 +00:00
static void * do_monitor ( void * data )
{
int res ;
struct sip_pvt * sip ;
2003-02-12 13:59:15 +00:00
struct sip_peer * peer ;
time_t t ;
2003-05-24 20:42:44 +00:00
int fastrestart = 0 ;
2003-05-24 20:47:25 +00:00
int lastpeernum = - 1 ;
int curpeernum ;
2004-02-02 23:48:31 +00:00
int reloading ;
2002-06-28 20:34:46 +00:00
/* Add an I/O event to our UDP socket */
if ( sipsock > - 1 )
ast_io_add ( io , sipsock , sipsock_read , AST_IO_IN , NULL ) ;
/* This thread monitors all the frame relay interfaces which are not yet in use
( and thus do not have a separate thread ) indefinitely */
/* From here on out, we die whenever asked */
for ( ; ; ) {
2004-02-02 23:48:31 +00:00
/* Check for a reload request */
ast_mutex_lock ( & sip_reload_lock ) ;
reloading = sip_reloading ;
2004-02-02 23:51:25 +00:00
sip_reloading = 0 ;
2004-02-02 23:48:31 +00:00
ast_mutex_unlock ( & sip_reload_lock ) ;
if ( reloading ) {
if ( option_verbose > 0 )
ast_verbose ( VERBOSE_PREFIX_1 " Reloading SIP \n " ) ;
sip_do_reload ( ) ;
}
2002-06-28 20:34:46 +00:00
/* Check for interfaces needing to be killed */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & iflock ) ;
2002-06-28 20:34:46 +00:00
restartsearch :
2004-05-27 22:12:55 +00:00
time ( & t ) ;
2002-06-28 20:34:46 +00:00
sip = iflist ;
while ( sip ) {
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & sip - > lock ) ;
2004-09-09 01:33:17 +00:00
if ( sip - > rtp & & sip - > owner & & ( sip - > owner - > _state = = AST_STATE_UP ) & & sip - > lastrtprx & & ( sip - > rtptimeout | | sip - > rtpholdtimeout ) & & ! sip - > redirip . sin_addr . s_addr ) {
2004-05-27 22:12:55 +00:00
if ( t > sip - > lastrtprx + sip - > rtptimeout ) {
/* Might be a timeout now -- see if we're on hold */
struct sockaddr_in sin ;
ast_rtp_get_peer ( sip - > rtp , & sin ) ;
if ( sin . sin_addr . s_addr | |
( sip - > rtpholdtimeout & &
( t > sip - > lastrtprx + sip - > rtpholdtimeout ) ) ) {
/* Needs a hangup */
if ( sip - > rtptimeout ) {
while ( sip - > owner & & ast_mutex_trylock ( & sip - > owner - > lock ) ) {
ast_mutex_unlock ( & sip - > lock ) ;
usleep ( 1 ) ;
ast_mutex_lock ( & sip - > lock ) ;
}
if ( sip - > owner ) {
ast_log ( LOG_NOTICE , " Disconnecting call '%s' for lack of RTP activity in %ld seconds \n " , sip - > owner - > name , ( long ) ( t - sip - > lastrtprx ) ) ;
/* Issue a softhangup */
ast_softhangup ( sip - > owner , AST_SOFTHANGUP_DEV ) ;
ast_mutex_unlock ( & sip - > owner - > lock ) ;
}
}
}
}
}
2004-07-20 15:29:09 +00:00
if ( sip - > needdestroy & & ! sip - > packets & & ! sip - > owner ) {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & sip - > lock ) ;
2003-02-07 04:07:10 +00:00
__sip_destroy ( sip , 1 ) ;
2002-06-28 20:34:46 +00:00
goto restartsearch ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & sip - > lock ) ;
2002-06-28 20:34:46 +00:00
sip = sip - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
2002-06-28 20:34:46 +00:00
/* Don't let anybody kill us right away. Nobody should lock the interface list
and wait for the monitor list , but the other way around is okay . */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & monlock ) ;
2002-06-28 20:34:46 +00:00
/* Lock the network interface */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & netlock ) ;
2002-06-28 20:34:46 +00:00
/* Okay, now that we know what to do, release the network lock */
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & netlock ) ;
2002-06-28 20:34:46 +00:00
/* And from now on, we're okay to be killed, so release the monitor lock as well */
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & monlock ) ;
2002-06-28 20:34:46 +00:00
pthread_testcancel ( ) ;
/* Wait for sched or io */
res = ast_sched_wait ( sched ) ;
2003-02-07 04:07:10 +00:00
if ( ( res < 0 ) | | ( res > 1000 ) )
res = 1000 ;
2003-05-24 20:42:44 +00:00
/* If we might need to send more mailboxes, don't wait long at all.*/
if ( fastrestart )
res = 1 ;
2002-06-28 20:34:46 +00:00
res = ast_io_wait ( io , res ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & monlock ) ;
2002-06-28 20:34:46 +00:00
if ( res > = 0 )
ast_sched_runq ( sched ) ;
2004-10-07 15:46:08 +00:00
/* needs work to send mwi to realtime peers */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & peerl . lock ) ;
2003-02-12 13:59:15 +00:00
peer = peerl . peers ;
time ( & t ) ;
2003-05-24 20:42:44 +00:00
fastrestart = 0 ;
2003-05-24 20:47:25 +00:00
curpeernum = 0 ;
2003-02-12 13:59:15 +00:00
while ( peer ) {
2004-05-03 21:01:14 +00:00
if ( ( curpeernum > lastpeernum ) & & ! ast_strlen_zero ( peer - > mailbox ) & & ( ( t - peer - > lastmsgcheck ) > 10 ) ) {
2003-02-12 13:59:15 +00:00
sip_send_mwi_to_peer ( peer ) ;
2003-05-24 20:42:44 +00:00
fastrestart = 1 ;
2003-05-24 20:47:25 +00:00
lastpeernum = curpeernum ;
2003-02-12 13:59:15 +00:00
break ;
}
2003-05-24 20:47:25 +00:00
curpeernum + + ;
2003-02-12 13:59:15 +00:00
peer = peer - > next ;
}
/* Remember, sip_send_mwi_to_peer releases the lock if we've called it */
2003-05-24 20:47:25 +00:00
if ( ! peer ) {
/* Reset where we come from */
lastpeernum = - 1 ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2003-05-24 20:47:25 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & monlock ) ;
2002-06-28 20:34:46 +00:00
}
/* Never reached */
return NULL ;
}
2004-05-13 19:54:42 +00:00
/*--- restart_monitor: Start the channel monitor thread ---*/
2002-06-28 20:34:46 +00:00
static int restart_monitor ( void )
{
2004-04-02 07:24:33 +00:00
pthread_attr_t attr ;
2002-06-28 20:34:46 +00:00
/* If we're supposed to be stopped -- stay stopped */
2004-03-15 07:51:22 +00:00
if ( monitor_thread = = AST_PTHREADT_STOP )
2002-06-28 20:34:46 +00:00
return 0 ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & monlock ) ) {
2002-06-28 20:34:46 +00:00
ast_log ( LOG_WARNING , " Unable to lock monitor \n " ) ;
return - 1 ;
}
if ( monitor_thread = = pthread_self ( ) ) {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & monlock ) ;
2002-06-28 20:34:46 +00:00
ast_log ( LOG_WARNING , " Cannot kill myself \n " ) ;
return - 1 ;
}
2004-03-15 09:14:16 +00:00
if ( monitor_thread ! = AST_PTHREADT_NULL ) {
2002-06-28 20:34:46 +00:00
/* Wake up the thread */
pthread_kill ( monitor_thread , SIGURG ) ;
} else {
2004-04-02 07:24:33 +00:00
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
2002-06-28 20:34:46 +00:00
/* Start a new monitor */
2004-08-08 17:15:02 +00:00
if ( ast_pthread_create ( & monitor_thread , & attr , do_monitor , NULL ) < 0 ) {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & monlock ) ;
2002-06-28 20:34:46 +00:00
ast_log ( LOG_ERROR , " Unable to start monitor thread. \n " ) ;
return - 1 ;
}
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & monlock ) ;
2002-06-28 20:34:46 +00:00
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_poke_noanswer: No answer to Qualify poke ---*/
2003-02-07 04:07:10 +00:00
static int sip_poke_noanswer ( void * data )
{
struct sip_peer * peer = data ;
2003-04-06 18:19:51 +00:00
2003-02-07 04:07:10 +00:00
peer - > pokeexpire = - 1 ;
2004-09-16 16:18:53 +00:00
if ( peer - > lastms > - 1 ) {
2004-10-16 15:36:16 +00:00
ast_log ( LOG_NOTICE , " Peer '%s' is now UNREACHABLE! Last qualify: %d \n " , peer - > name , peer - > lastms ) ;
2004-09-16 16:18:53 +00:00
manager_event ( EVENT_FLAG_SYSTEM , " PeerStatus " , " Peer: SIP/%s \r \n PeerStatus: Unreachable \r \n Time: %d \r \n " , peer - > name , - 1 ) ;
}
2003-02-07 04:07:10 +00:00
if ( peer - > call )
sip_destroy ( peer - > call ) ;
peer - > call = NULL ;
peer - > lastms = - 1 ;
2003-04-06 18:19:51 +00:00
ast_device_state_changed ( " SIP/%s " , peer - > name ) ;
2003-02-07 04:07:10 +00:00
/* Try again quickly */
peer - > pokeexpire = ast_sched_add ( sched , DEFAULT_FREQ_NOTOK , sip_poke_peer_s , peer ) ;
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_poke_peer: Check availability of peer, also keep NAT open ---*/
2003-02-07 04:07:10 +00:00
static int sip_poke_peer ( struct sip_peer * peer )
{
struct sip_pvt * p ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-02-07 04:07:10 +00:00
if ( ! peer - > maxms | | ! peer - > addr . sin_addr . s_addr ) {
/* IF we have no IP, or this isn't to be monitored, return
imeediately after clearing things out */
2004-09-11 13:50:26 +00:00
if ( peer - > pokeexpire > - 1 )
ast_sched_del ( sched , peer - > pokeexpire ) ;
2003-02-07 04:07:10 +00:00
peer - > lastms = 0 ;
peer - > pokeexpire = - 1 ;
peer - > call = NULL ;
return 0 ;
}
if ( peer - > call > 0 ) {
ast_log ( LOG_NOTICE , " Still have a call... \n " ) ;
sip_destroy ( peer - > call ) ;
}
2003-03-10 22:05:28 +00:00
p = peer - > call = sip_alloc ( NULL , NULL , 0 ) ;
2003-02-07 04:07:10 +00:00
if ( ! peer - > call ) {
ast_log ( LOG_WARNING , " Unable to allocate call for poking peer '%s' \n " , peer - > name ) ;
return - 1 ;
}
memcpy ( & p - > sa , & peer - > addr , sizeof ( p - > sa ) ) ;
2003-03-05 06:00:17 +00:00
memcpy ( & p - > recv , & peer - > addr , sizeof ( p - > sa ) ) ;
2004-05-03 21:01:14 +00:00
if ( ! ast_strlen_zero ( p - > tohost ) )
2003-05-03 03:29:58 +00:00
strncpy ( p - > tohost , peer - > tohost , sizeof ( p - > tohost ) - 1 ) ;
else
2004-07-08 11:05:03 +00:00
ast_inet_ntoa ( p - > tohost , sizeof ( p - > tohost ) , peer - > addr . sin_addr ) ;
2003-02-07 04:07:10 +00:00
/* Recalculate our side, and recalculate Call ID */
2003-08-21 02:27:25 +00:00
if ( ast_sip_ouraddrfor ( & p - > sa . sin_addr , & p - > ourip ) )
2003-05-04 05:52:52 +00:00
memcpy ( & p - > ourip , & __ourip , sizeof ( p - > ourip ) ) ;
/* z9hG4bK is a magic cookie. See RFC 3261 section 8.1.1.7 */
2004-08-27 02:45:35 +00:00
if ( p - > nat & SIP_NAT_RFC3581 )
2004-06-29 12:56:46 +00:00
snprintf ( p - > via , sizeof ( p - > via ) , " SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) , ourport , p - > branch ) ;
2004-06-28 23:24:36 +00:00
else
2004-06-29 12:56:46 +00:00
snprintf ( p - > via , sizeof ( p - > via ) , " SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) , ourport , p - > branch ) ;
2004-09-13 12:32:04 +00:00
build_callid ( p - > callid , sizeof ( p - > callid ) , p - > ourip , p - > fromdomain ) ;
2003-02-07 04:07:10 +00:00
if ( peer - > pokeexpire > - 1 )
ast_sched_del ( sched , peer - > pokeexpire ) ;
p - > peerpoke = peer ;
p - > outgoing = 1 ;
# ifdef VOCAL_DATA_HACK
2004-07-16 04:40:54 +00:00
strncpy ( p - > username , " __VOCAL_DATA_SHOULD_READ_THE_SIP_SPEC__ " , sizeof ( p - > username ) - 1 ) ;
2004-06-25 03:59:07 +00:00
transmit_invite ( p , " INVITE " , 0 , NULL , NULL , NULL , NULL , NULL , 1 ) ;
2003-02-07 04:07:10 +00:00
# else
2004-06-25 03:59:07 +00:00
transmit_invite ( p , " OPTIONS " , 0 , NULL , NULL , NULL , NULL , NULL , 1 ) ;
2003-02-07 04:07:10 +00:00
# endif
gettimeofday ( & peer - > ps , NULL ) ;
peer - > pokeexpire = ast_sched_add ( sched , DEFAULT_MAXMS * 2 , sip_poke_noanswer , peer ) ;
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_devicestate: Part of PBX channel interface ---*/
2003-04-06 18:19:51 +00:00
static int sip_devicestate ( void * data )
{
char * ext , * host ;
char tmp [ 256 ] = " " ;
char * dest = data ;
struct hostent * hp ;
2004-04-22 00:20:34 +00:00
struct ast_hostent ahp ;
2003-04-06 18:19:51 +00:00
struct sip_peer * p ;
int found = 0 ;
int res = AST_DEVICE_INVALID ;
strncpy ( tmp , dest , sizeof ( tmp ) - 1 ) ;
host = strchr ( tmp , ' @ ' ) ;
if ( host ) {
* host = ' \0 ' ;
host + + ;
ext = tmp ;
} else {
host = tmp ;
ext = NULL ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & peerl . lock ) ;
2004-04-26 14:54:33 +00:00
p = find_peer ( host , NULL ) ;
if ( p ) {
found + + ;
res = AST_DEVICE_UNAVAILABLE ;
if ( ( p - > addr . sin_addr . s_addr | | p - > defaddr . sin_addr . s_addr ) & &
( ! p - > maxms | | ( ( p - > lastms > - 1 ) & & ( p - > lastms < = p - > maxms ) ) ) ) {
/* peer found and valid */
res = AST_DEVICE_UNKNOWN ;
2003-04-06 18:19:51 +00:00
}
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2003-04-06 18:19:51 +00:00
if ( ! p & & ! found ) {
2004-04-22 00:20:34 +00:00
hp = ast_gethostbyname ( host , & ahp ) ;
2003-04-06 18:19:51 +00:00
if ( hp )
res = AST_DEVICE_UNKNOWN ;
}
2004-10-07 18:27:12 +00:00
2004-10-12 22:02:19 +00:00
if ( p & & p - > temponly ) {
2004-10-07 18:27:12 +00:00
destroy_peer ( p ) ;
}
2003-04-06 18:19:51 +00:00
return res ;
}
2003-02-07 04:07:10 +00:00
2004-05-13 19:54:42 +00:00
/*--- sip_request: PBX interface function -build SIP pvt structure ---*/
/* SIP calls initiated by the PBX arrive here */
2004-10-03 04:19:59 +00:00
static struct ast_channel * sip_request ( const char * type , int format , void * data )
2002-06-28 20:34:46 +00:00
{
int oldformat ;
struct sip_pvt * p ;
2002-09-12 17:13:17 +00:00
struct ast_channel * tmpc = NULL ;
char * ext , * host ;
2003-02-07 04:07:10 +00:00
char tmp [ 256 ] = " " ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2002-09-12 17:13:17 +00:00
char * dest = data ;
2002-06-28 20:34:46 +00:00
oldformat = format ;
2004-03-19 08:00:13 +00:00
format & = ( ( AST_FORMAT_MAX_AUDIO < < 1 ) - 1 ) ;
2002-06-28 20:34:46 +00:00
if ( ! format ) {
2004-07-08 11:05:03 +00:00
ast_log ( LOG_NOTICE , " Asked to get a channel of unsupported format %s while capability is %s \n " , ast_getformatname ( oldformat ) , ast_getformatname ( global_capability ) ) ;
2002-06-28 20:34:46 +00:00
return NULL ;
}
2003-03-10 22:05:28 +00:00
p = sip_alloc ( NULL , NULL , 0 ) ;
2002-06-28 20:34:46 +00:00
if ( ! p ) {
ast_log ( LOG_WARNING , " Unable to build sip pvt data for '%s' \n " , ( char * ) data ) ;
return NULL ;
}
2002-09-12 17:13:17 +00:00
strncpy ( tmp , dest , sizeof ( tmp ) - 1 ) ;
host = strchr ( tmp , ' @ ' ) ;
if ( host ) {
* host = ' \0 ' ;
host + + ;
ext = tmp ;
} else {
2003-11-24 01:49:43 +00:00
ext = strchr ( tmp , ' / ' ) ;
if ( ext ) {
* ext + + = ' \0 ' ;
host = tmp ;
}
else {
host = tmp ;
ext = NULL ;
}
2002-09-12 17:13:17 +00:00
}
2003-02-07 04:07:10 +00:00
/* Assign a default capability */
2004-07-08 11:05:03 +00:00
p - > capability = global_capability ;
2003-02-07 04:07:10 +00:00
if ( create_addr ( p , host ) ) {
2002-09-12 17:13:17 +00:00
sip_destroy ( p ) ;
return NULL ;
}
2004-05-03 21:01:14 +00:00
if ( ast_strlen_zero ( p - > peername ) & & ext )
2003-04-12 17:06:14 +00:00
strncpy ( p - > peername , ext , sizeof ( p - > peername ) - 1 ) ;
2002-09-12 17:13:17 +00:00
/* Recalculate our side, and recalculate Call ID */
2003-08-21 02:27:25 +00:00
if ( ast_sip_ouraddrfor ( & p - > sa . sin_addr , & p - > ourip ) )
2003-05-04 05:52:52 +00:00
memcpy ( & p - > ourip , & __ourip , sizeof ( p - > ourip ) ) ;
/* z9hG4bK is a magic cookie. See RFC 3261 section 8.1.1.7 */
2004-08-27 02:45:35 +00:00
if ( p - > nat & SIP_NAT_RFC3581 )
2004-06-29 12:56:46 +00:00
snprintf ( p - > via , sizeof ( p - > via ) , " SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) , ourport , p - > branch ) ;
2004-06-28 23:24:36 +00:00
else /* UNIDEN bug */
2004-06-29 12:56:46 +00:00
snprintf ( p - > via , sizeof ( p - > via ) , " SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , p - > ourip ) , ourport , p - > branch ) ;
2004-09-13 12:32:04 +00:00
build_callid ( p - > callid , sizeof ( p - > callid ) , p - > ourip , p - > fromdomain ) ;
2004-10-14 18:29:47 +00:00
/* We have an extension to call, don't use the full contact here */
/* This to enable dialling registred peers with extension dialling,
like SIP / peername / extension
SIP / peername will still use the full contact */
if ( ext ) {
2002-09-12 17:13:17 +00:00
strncpy ( p - > username , ext , sizeof ( p - > username ) - 1 ) ;
2004-10-14 18:29:47 +00:00
p - > fullcontact [ 0 ] = 0 ;
}
2003-02-07 04:07:10 +00:00
#if 0
2002-09-12 17:13:17 +00:00
printf ( " Setting up to call extension '%s' at '%s' \n " , ext ? ext : " <none> " , host ) ;
2003-02-07 04:07:10 +00:00
# endif
2004-03-19 08:00:13 +00:00
p - > prefcodec = format ;
2004-06-09 23:07:55 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-02-13 06:00:14 +00:00
tmpc = sip_new ( p , AST_STATE_DOWN , host ) ;
2004-06-09 23:07:55 +00:00
ast_mutex_unlock ( & p - > lock ) ;
2002-09-12 17:13:17 +00:00
if ( ! tmpc )
sip_destroy ( p ) ;
2003-12-19 16:14:51 +00:00
ast_update_use_count ( ) ;
2002-06-28 20:34:46 +00:00
restart_monitor ( ) ;
2002-09-12 17:13:17 +00:00
return tmpc ;
2002-06-28 20:34:46 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- build_user: Initiate a SIP user structure from sip.conf ---*/
2004-10-07 15:46:08 +00:00
static struct sip_user * build_user ( const char * name , struct ast_variable * v )
2002-06-28 20:34:46 +00:00
{
struct sip_user * user ;
int format ;
2004-01-10 21:19:56 +00:00
struct ast_ha * oldha = NULL ;
2002-06-28 20:34:46 +00:00
user = ( struct sip_user * ) malloc ( sizeof ( struct sip_user ) ) ;
if ( user ) {
memset ( user , 0 , sizeof ( struct sip_user ) ) ;
strncpy ( user - > name , name , sizeof ( user - > name ) - 1 ) ;
2004-01-10 21:19:56 +00:00
oldha = user - > ha ;
user - > ha = NULL ;
2003-07-26 15:12:37 +00:00
/* set the usage flag to a sane staring value*/
user - > inUse = 0 ;
2003-09-13 20:26:20 +00:00
user - > outUse = 0 ;
2004-07-08 11:05:03 +00:00
user - > capability = global_capability ;
user - > canreinvite = global_canreinvite ;
user - > trustrpid = global_trustrpid ;
2004-08-29 18:58:30 +00:00
user - > dtmfmode = global_dtmfmode ;
2004-07-08 11:05:03 +00:00
user - > progressinband = global_progressinband ;
2004-06-25 05:52:55 +00:00
# ifdef OSP_SUPPORT
2004-07-08 11:05:03 +00:00
user - > ospauth = global_ospauth ;
2004-06-25 05:52:55 +00:00
# endif
2004-05-04 20:10:37 +00:00
/* set default context */
2004-07-08 11:05:03 +00:00
strncpy ( user - > context , default_context , sizeof ( user - > context ) - 1 ) ;
strncpy ( user - > language , default_language , sizeof ( user - > language ) - 1 ) ;
strncpy ( user - > musicclass , global_musicclass , sizeof ( user - > musicclass ) - 1 ) ;
2002-06-28 20:34:46 +00:00
while ( v ) {
if ( ! strcasecmp ( v - > name , " context " ) ) {
2004-07-16 04:40:54 +00:00
strncpy ( user - > context , v - > value , sizeof ( user - > context ) - 1 ) ;
2002-06-28 20:34:46 +00:00
} else if ( ! strcasecmp ( v - > name , " permit " ) | |
! strcasecmp ( v - > name , " deny " ) ) {
user - > ha = ast_append_ha ( v - > name , v - > value , user - > ha ) ;
} else if ( ! strcasecmp ( v - > name , " secret " ) ) {
2003-03-08 06:00:17 +00:00
strncpy ( user - > secret , v - > value , sizeof ( user - > secret ) - 1 ) ;
2003-10-15 17:32:19 +00:00
} else if ( ! strcasecmp ( v - > name , " md5secret " ) ) {
2004-09-16 12:53:10 +00:00
strncpy ( user - > md5secret , v - > value , sizeof ( user - > md5secret ) - 1 ) ;
2004-06-21 06:11:56 +00:00
} else if ( ! strcasecmp ( v - > name , " promiscredir " ) ) {
user - > promiscredir = ast_true ( v - > value ) ;
2003-03-08 06:00:17 +00:00
} else if ( ! strcasecmp ( v - > name , " dtmfmode " ) ) {
if ( ! strcasecmp ( v - > value , " inband " ) )
user - > dtmfmode = SIP_DTMF_INBAND ;
else if ( ! strcasecmp ( v - > value , " rfc2833 " ) )
user - > dtmfmode = SIP_DTMF_RFC2833 ;
else if ( ! strcasecmp ( v - > value , " info " ) )
user - > dtmfmode = SIP_DTMF_INFO ;
else {
ast_log ( LOG_WARNING , " Unknown dtmf mode '%s', using rfc2833 \n " , v - > value ) ;
user - > dtmfmode = SIP_DTMF_RFC2833 ;
}
2003-02-07 04:07:10 +00:00
} else if ( ! strcasecmp ( v - > name , " canreinvite " ) ) {
2003-03-28 06:59:34 +00:00
if ( ! strcasecmp ( v - > value , " update " ) )
user - > canreinvite = REINVITE_UPDATE ;
else
user - > canreinvite = ast_true ( v - > value ) ;
2003-03-05 06:00:17 +00:00
} else if ( ! strcasecmp ( v - > name , " nat " ) ) {
2004-06-28 23:24:36 +00:00
if ( ! strcasecmp ( v - > value , " never " ) )
user - > nat = SIP_NAT_NEVER ;
2004-08-27 02:45:35 +00:00
else if ( ! strcasecmp ( v - > value , " route " ) )
user - > nat = SIP_NAT_ROUTE ;
2004-06-28 23:24:36 +00:00
else if ( ast_true ( v - > value ) )
user - > nat = SIP_NAT_ALWAYS ;
else
user - > nat = SIP_NAT_RFC3581 ;
2002-06-28 20:34:46 +00:00
} else if ( ! strcasecmp ( v - > name , " callerid " ) ) {
2004-10-02 00:58:31 +00:00
ast_callerid_split ( v - > value , user - > cid_name , sizeof ( user - > cid_name ) , user - > cid_num , sizeof ( user - > cid_num ) ) ;
2002-06-28 20:34:46 +00:00
user - > hascallerid = 1 ;
2003-04-09 04:00:43 +00:00
} else if ( ! strcasecmp ( v - > name , " callgroup " ) ) {
user - > callgroup = ast_get_group ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " pickupgroup " ) ) {
user - > pickupgroup = ast_get_group ( v - > value ) ;
2003-10-22 04:19:22 +00:00
} else if ( ! strcasecmp ( v - > name , " language " ) ) {
strncpy ( user - > language , v - > value , sizeof ( user - > language ) - 1 ) ;
2004-05-04 20:10:37 +00:00
} else if ( ! strcasecmp ( v - > name , " musiconhold " ) ) {
strncpy ( user - > musicclass , v - > value , sizeof ( user - > musicclass ) - 1 ) ;
2002-06-28 20:34:46 +00:00
} else if ( ! strcasecmp ( v - > name , " accountcode " ) ) {
strncpy ( user - > accountcode , v - > value , sizeof ( user - > accountcode ) - 1 ) ;
2003-07-26 15:12:37 +00:00
} else if ( ! strcasecmp ( v - > name , " incominglimit " ) ) {
user - > incominglimit = atoi ( v - > value ) ;
if ( user - > incominglimit < 0 )
user - > incominglimit = 0 ;
2003-09-13 20:26:20 +00:00
} else if ( ! strcasecmp ( v - > name , " outgoinglimit " ) ) {
user - > outgoinglimit = atoi ( v - > value ) ;
if ( user - > outgoinglimit < 0 )
user - > outgoinglimit = 0 ;
2002-06-28 20:34:46 +00:00
} else if ( ! strcasecmp ( v - > name , " amaflags " ) ) {
format = ast_cdr_amaflags2int ( v - > value ) ;
if ( format < 0 ) {
ast_log ( LOG_WARNING , " Invalid AMA Flags: %s at line %d \n " , v - > value , v - > lineno ) ;
} else {
user - > amaflags = format ;
}
2003-10-23 03:50:34 +00:00
} else if ( ! strcasecmp ( v - > name , " allow " ) ) {
format = ast_getformatbyname ( v - > value ) ;
if ( format < 1 )
ast_log ( LOG_WARNING , " Cannot allow unknown format '%s' \n " , v - > value ) ;
else
user - > capability | = format ;
} else if ( ! strcasecmp ( v - > name , " disallow " ) ) {
format = ast_getformatbyname ( v - > value ) ;
if ( format < 1 )
ast_log ( LOG_WARNING , " Cannot disallow unknown format '%s' \n " , v - > value ) ;
else
user - > capability & = ~ format ;
2002-06-28 20:34:46 +00:00
} else if ( ! strcasecmp ( v - > name , " insecure " ) ) {
user - > insecure = ast_true ( v - > value ) ;
2004-10-02 00:58:31 +00:00
} else if ( ! strcasecmp ( v - > name , " callingpres " ) ) {
user - > callingpres = atoi ( v - > value ) ;
2004-06-21 04:29:50 +00:00
} else if ( ! strcasecmp ( v - > name , " trustrpid " ) ) {
2004-06-25 05:52:55 +00:00
user - > trustrpid = ast_true ( v - > value ) ;
2004-06-26 21:17:12 +00:00
} else if ( ! strcasecmp ( v - > name , " progressinband " ) ) {
user - > progressinband = ast_true ( v - > value ) ;
2004-06-25 05:52:55 +00:00
# ifdef OSP_SUPPORT
} else if ( ! strcasecmp ( v - > name , " ospauth " ) ) {
if ( ! strcasecmp ( v - > value , " exclusive " ) ) {
user - > ospauth = 2 ;
} else if ( ast_true ( v - > value ) ) {
user - > ospauth = 1 ;
} else
user - > ospauth = 0 ;
# endif
2004-04-26 14:54:33 +00:00
}
/*else if (strcasecmp(v->name,"type"))
* ast_log ( LOG_WARNING , " Ignoring %s \n " , v - > name ) ;
*/
2002-06-28 20:34:46 +00:00
v = v - > next ;
}
}
2004-10-07 18:27:12 +00:00
ast_free_ha ( oldha ) ;
2002-06-28 20:34:46 +00:00
return user ;
}
2004-05-13 19:54:42 +00:00
/*--- temp_peer: Create temporary peer (used in autocreatepeer mode) ---*/
2003-11-11 20:46:41 +00:00
static struct sip_peer * temp_peer ( char * name )
{
struct sip_peer * peer ;
peer = malloc ( sizeof ( struct sip_peer ) ) ;
2004-10-23 07:03:01 +00:00
if ( ! peer )
return NULL ;
2003-11-11 20:46:41 +00:00
memset ( peer , 0 , sizeof ( struct sip_peer ) ) ;
peer - > expire = - 1 ;
peer - > pokeexpire = - 1 ;
strncpy ( peer - > name , name , sizeof ( peer - > name ) - 1 ) ;
2004-07-08 11:05:03 +00:00
strncpy ( peer - > context , default_context , sizeof ( peer - > context ) - 1 ) ;
strncpy ( peer - > language , default_language , sizeof ( peer - > language ) - 1 ) ;
strncpy ( peer - > musicclass , global_musicclass , sizeof ( peer - > musicclass ) - 1 ) ;
2003-11-11 20:46:41 +00:00
peer - > addr . sin_port = htons ( DEFAULT_SIP_PORT ) ;
2004-05-16 05:53:33 +00:00
peer - > addr . sin_family = AF_INET ;
2003-11-11 20:46:41 +00:00
peer - > expiry = expiry ;
2004-07-08 11:05:03 +00:00
peer - > capability = global_capability ;
2003-11-11 20:46:41 +00:00
/* Assume can reinvite */
2004-07-08 11:05:03 +00:00
peer - > canreinvite = global_canreinvite ;
peer - > dtmfmode = global_dtmfmode ;
peer - > promiscredir = global_promiscredir ;
peer - > nat = global_nat ;
peer - > rtptimeout = global_rtptimeout ;
peer - > rtpholdtimeout = global_rtpholdtimeout ;
2003-11-11 20:46:41 +00:00
peer - > selfdestruct = 1 ;
peer - > dynamic = 1 ;
2004-07-08 11:05:03 +00:00
peer - > trustrpid = global_trustrpid ;
peer - > progressinband = global_progressinband ;
2004-06-25 05:52:55 +00:00
# ifdef OSP_SUPPORT
2004-07-08 11:05:03 +00:00
peer - > ospauth = global_ospauth ;
2004-06-25 05:52:55 +00:00
# endif
2003-11-11 20:46:41 +00:00
reg_source_db ( peer ) ;
return peer ;
}
2004-05-13 19:54:42 +00:00
/*--- build_peer: Build peer from config file ---*/
2004-10-12 19:54:54 +00:00
static struct sip_peer * build_peer ( const char * name , struct ast_variable * v , int temponly )
2002-06-28 20:34:46 +00:00
{
struct sip_peer * peer ;
struct sip_peer * prev ;
2004-01-10 21:19:56 +00:00
struct ast_ha * oldha = NULL ;
2002-06-28 20:34:46 +00:00
int maskfound = 0 ;
int format ;
int found = 0 ;
prev = NULL ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & peerl . lock ) ;
2004-10-12 19:54:54 +00:00
if ( temponly ) {
peer = NULL ;
} else {
peer = peerl . peers ;
while ( peer ) {
if ( ! strcasecmp ( peer - > name , name ) ) {
break ;
}
prev = peer ;
peer = peer - > next ;
2002-06-28 20:34:46 +00:00
}
}
if ( peer ) {
found + + ;
/* Already in the list, remove it and it will be added back (or FREE'd) */
if ( prev ) {
prev - > next = peer - > next ;
} else {
peerl . peers = peer - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2002-06-28 20:34:46 +00:00
} else {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2002-06-28 20:34:46 +00:00
peer = malloc ( sizeof ( struct sip_peer ) ) ;
2004-10-23 07:03:01 +00:00
if ( peer ) {
memset ( peer , 0 , sizeof ( struct sip_peer ) ) ;
peer - > expire = - 1 ;
peer - > pokeexpire = - 1 ;
}
2002-06-28 20:34:46 +00:00
}
if ( peer ) {
2004-10-23 07:03:01 +00:00
peer - > lastmsgssent = - 1 ;
2002-06-28 20:34:46 +00:00
if ( ! found ) {
strncpy ( peer - > name , name , sizeof ( peer - > name ) - 1 ) ;
2004-07-08 11:05:03 +00:00
strncpy ( peer - > context , default_context , sizeof ( peer - > context ) - 1 ) ;
strncpy ( peer - > language , default_language , sizeof ( peer - > language ) - 1 ) ;
strncpy ( peer - > musicclass , global_musicclass , sizeof ( peer - > musicclass ) - 1 ) ;
2002-06-28 20:34:46 +00:00
peer - > addr . sin_port = htons ( DEFAULT_SIP_PORT ) ;
2004-05-16 05:53:33 +00:00
peer - > addr . sin_family = AF_INET ;
peer - > defaddr . sin_family = AF_INET ;
2003-04-08 03:24:12 +00:00
peer - > expiry = expiry ;
2002-06-28 20:34:46 +00:00
}
2004-01-10 21:19:56 +00:00
oldha = peer - > ha ;
peer - > ha = NULL ;
2004-08-08 04:49:43 +00:00
peer - > addr . sin_family = AF_INET ;
2004-07-08 11:05:03 +00:00
peer - > capability = global_capability ;
2003-02-16 06:00:12 +00:00
/* Assume can reinvite */
2004-07-08 11:05:03 +00:00
peer - > canreinvite = global_canreinvite ;
peer - > rtptimeout = global_rtptimeout ;
peer - > rtpholdtimeout = global_rtpholdtimeout ;
2004-08-29 18:58:30 +00:00
peer - > dtmfmode = global_dtmfmode ;
2004-07-08 11:05:03 +00:00
peer - > promiscredir = global_promiscredir ;
peer - > trustrpid = global_trustrpid ;
peer - > progressinband = global_progressinband ;
2004-06-25 05:52:55 +00:00
# ifdef OSP_SUPPORT
2004-07-08 11:05:03 +00:00
peer - > ospauth = global_ospauth ;
2004-06-25 05:52:55 +00:00
# endif
2002-06-28 20:34:46 +00:00
while ( v ) {
if ( ! strcasecmp ( v - > name , " secret " ) )
strncpy ( peer - > secret , v - > value , sizeof ( peer - > secret ) - 1 ) ;
2003-10-15 17:32:19 +00:00
else if ( ! strcasecmp ( v - > name , " md5secret " ) )
strncpy ( peer - > md5secret , v - > value , sizeof ( peer - > md5secret ) - 1 ) ;
2003-03-28 06:59:34 +00:00
else if ( ! strcasecmp ( v - > name , " canreinvite " ) ) {
if ( ! strcasecmp ( v - > value , " update " ) )
peer - > canreinvite = REINVITE_UPDATE ;
else
peer - > canreinvite = ast_true ( v - > value ) ;
2004-06-28 23:24:36 +00:00
} else if ( ! strcasecmp ( v - > name , " nat " ) ) {
if ( ! strcasecmp ( v - > value , " rfc3581 " ) )
peer - > nat = SIP_NAT_RFC3581 ;
2004-08-27 02:45:35 +00:00
else if ( ! strcasecmp ( v - > value , " route " ) )
peer - > nat = SIP_NAT_ROUTE ;
2004-06-28 23:24:36 +00:00
else if ( ast_true ( v - > value ) )
peer - > nat = SIP_NAT_ALWAYS ;
else
peer - > nat = SIP_NAT_NEVER ;
} else if ( ! strcasecmp ( v - > name , " context " ) )
2003-02-07 04:07:10 +00:00
strncpy ( peer - > context , v - > value , sizeof ( peer - > context ) - 1 ) ;
2003-04-06 03:01:03 +00:00
else if ( ! strcasecmp ( v - > name , " fromdomain " ) )
strncpy ( peer - > fromdomain , v - > value , sizeof ( peer - > fromdomain ) - 1 ) ;
2004-06-21 06:11:56 +00:00
else if ( ! strcasecmp ( v - > name , " promiscredir " ) )
peer - > promiscredir = ast_true ( v - > value ) ;
2003-04-09 21:30:27 +00:00
else if ( ! strcasecmp ( v - > name , " fromuser " ) )
strncpy ( peer - > fromuser , v - > value , sizeof ( peer - > fromuser ) - 1 ) ;
2004-07-07 16:02:13 +00:00
else if ( ! strcasecmp ( v - > name , " dtmfmode " ) ) {
2003-03-08 06:00:17 +00:00
if ( ! strcasecmp ( v - > value , " inband " ) )
peer - > dtmfmode = SIP_DTMF_INBAND ;
else if ( ! strcasecmp ( v - > value , " rfc2833 " ) )
peer - > dtmfmode = SIP_DTMF_RFC2833 ;
else if ( ! strcasecmp ( v - > value , " info " ) )
peer - > dtmfmode = SIP_DTMF_INFO ;
else {
ast_log ( LOG_WARNING , " Unknown dtmf mode '%s', using rfc2833 \n " , v - > value ) ;
peer - > dtmfmode = SIP_DTMF_RFC2833 ;
}
} else if ( ! strcasecmp ( v - > name , " host " ) ) {
2002-06-28 20:34:46 +00:00
if ( ! strcasecmp ( v - > value , " dynamic " ) ) {
/* They'll register with us */
peer - > dynamic = 1 ;
if ( ! found ) {
/* Initialize stuff iff we're not found, otherwise
we keep going with what we had */
memset ( & peer - > addr . sin_addr , 0 , 4 ) ;
if ( peer - > addr . sin_port ) {
/* If we've already got a port, make it the default rather than absolute */
peer - > defaddr . sin_port = peer - > addr . sin_port ;
peer - > addr . sin_port = 0 ;
}
}
} else {
/* Non-dynamic. Make sure we become that way if we're not */
if ( peer - > expire > - 1 )
ast_sched_del ( sched , peer - > expire ) ;
peer - > expire = - 1 ;
peer - > dynamic = 0 ;
if ( ast_get_ip ( & peer - > addr , v - > value ) ) {
2004-10-07 15:46:08 +00:00
destroy_peer ( peer ) ;
2002-06-28 20:34:46 +00:00
return NULL ;
}
2003-04-18 15:47:33 +00:00
strncpy ( peer - > tohost , v - > value , sizeof ( peer - > tohost ) - 1 ) ;
2002-06-28 20:34:46 +00:00
}
if ( ! maskfound )
inet_aton ( " 255.255.255.255 " , & peer - > mask ) ;
} else if ( ! strcasecmp ( v - > name , " defaultip " ) ) {
if ( ast_get_ip ( & peer - > defaddr , v - > value ) ) {
2004-10-07 15:46:08 +00:00
destroy_peer ( peer ) ;
2002-06-28 20:34:46 +00:00
return NULL ;
}
} else if ( ! strcasecmp ( v - > name , " permit " ) | |
! strcasecmp ( v - > name , " deny " ) ) {
peer - > ha = ast_append_ha ( v - > name , v - > value , peer - > ha ) ;
} else if ( ! strcasecmp ( v - > name , " mask " ) ) {
maskfound + + ;
inet_aton ( v - > value , & peer - > mask ) ;
} else if ( ! strcasecmp ( v - > name , " port " ) ) {
if ( peer - > dynamic )
peer - > defaddr . sin_port = htons ( atoi ( v - > value ) ) ;
else
peer - > addr . sin_port = htons ( atoi ( v - > value ) ) ;
} else if ( ! strcasecmp ( v - > name , " username " ) ) {
strncpy ( peer - > username , v - > value , sizeof ( peer - > username ) - 1 ) ;
2004-05-04 20:10:37 +00:00
} else if ( ! strcasecmp ( v - > name , " language " ) ) {
strncpy ( peer - > language , v - > value , sizeof ( peer - > language ) - 1 ) ;
2004-09-07 23:45:34 +00:00
} else if ( ! strcasecmp ( v - > name , " regexten " ) ) {
strncpy ( peer - > regexten , v - > value , sizeof ( peer - > regexten ) - 1 ) ;
2004-05-04 20:10:37 +00:00
} else if ( ! strcasecmp ( v - > name , " musiconhold " ) ) {
strncpy ( peer - > musicclass , v - > value , sizeof ( peer - > musicclass ) - 1 ) ;
2003-02-07 04:07:10 +00:00
} else if ( ! strcasecmp ( v - > name , " mailbox " ) ) {
2003-02-12 13:59:15 +00:00
strncpy ( peer - > mailbox , v - > value , sizeof ( peer - > mailbox ) - 1 ) ;
2003-10-23 03:50:34 +00:00
} else if ( ! strcasecmp ( v - > name , " callgroup " ) ) {
peer - > callgroup = ast_get_group ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " pickupgroup " ) ) {
peer - > pickupgroup = ast_get_group ( v - > value ) ;
2002-06-28 20:34:46 +00:00
} else if ( ! strcasecmp ( v - > name , " allow " ) ) {
format = ast_getformatbyname ( v - > value ) ;
if ( format < 1 )
ast_log ( LOG_WARNING , " Cannot allow unknown format '%s' \n " , v - > value ) ;
else
peer - > capability | = format ;
} else if ( ! strcasecmp ( v - > name , " disallow " ) ) {
format = ast_getformatbyname ( v - > value ) ;
if ( format < 1 )
ast_log ( LOG_WARNING , " Cannot disallow unknown format '%s' \n " , v - > value ) ;
else
peer - > capability & = ~ format ;
} else if ( ! strcasecmp ( v - > name , " insecure " ) ) {
2004-05-03 05:14:52 +00:00
if ( ! strcasecmp ( v - > value , " very " ) ) {
peer - > insecure = 2 ;
} else if ( ast_true ( v - > value ) )
peer - > insecure = 1 ;
else
peer - > insecure = 0 ;
2004-05-27 22:12:55 +00:00
} else if ( ! strcasecmp ( v - > name , " rtptimeout " ) ) {
if ( ( sscanf ( v - > value , " %d " , & peer - > rtptimeout ) ! = 1 ) | | ( peer - > rtptimeout < 0 ) ) {
ast_log ( LOG_WARNING , " '%s' is not a valid RTP hold time at line %d. Using default. \n " , v - > value , v - > lineno ) ;
2004-07-08 11:05:03 +00:00
peer - > rtptimeout = global_rtptimeout ;
2004-05-27 22:12:55 +00:00
}
} else if ( ! strcasecmp ( v - > name , " rtpholdtimeout " ) ) {
if ( ( sscanf ( v - > value , " %d " , & peer - > rtpholdtimeout ) ! = 1 ) | | ( peer - > rtpholdtimeout < 0 ) ) {
ast_log ( LOG_WARNING , " '%s' is not a valid RTP hold time at line %d. Using default. \n " , v - > value , v - > lineno ) ;
2004-07-08 11:05:03 +00:00
peer - > rtpholdtimeout = global_rtpholdtimeout ;
2004-05-27 22:12:55 +00:00
}
2003-02-07 04:07:10 +00:00
} else if ( ! strcasecmp ( v - > name , " qualify " ) ) {
if ( ! strcasecmp ( v - > value , " no " ) ) {
peer - > maxms = 0 ;
} else if ( ! strcasecmp ( v - > value , " yes " ) ) {
peer - > maxms = DEFAULT_MAXMS ;
} else if ( sscanf ( v - > value , " %d " , & peer - > maxms ) ! = 1 ) {
2003-10-21 03:10:43 +00:00
ast_log ( LOG_WARNING , " Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of sip.conf \n " , peer - > name , v - > lineno ) ;
2003-02-07 04:07:10 +00:00
peer - > maxms = 0 ;
}
2004-06-21 04:29:50 +00:00
} else if ( ! strcasecmp ( v - > name , " trustrpid " ) ) {
2004-06-26 21:17:12 +00:00
peer - > trustrpid = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " progressinband " ) ) {
peer - > progressinband = ast_true ( v - > value ) ;
2004-06-25 05:52:55 +00:00
# ifdef OSP_SUPPORT
} else if ( ! strcasecmp ( v - > name , " ospauth " ) ) {
if ( ! strcasecmp ( v - > value , " exclusive " ) ) {
peer - > ospauth = 2 ;
} else if ( ast_true ( v - > value ) ) {
peer - > ospauth = 1 ;
} else
peer - > ospauth = 0 ;
# endif
2004-04-26 14:54:33 +00:00
}
/* else if (strcasecmp(v->name,"type"))
* ast_log ( LOG_WARNING , " Ignoring %s \n " , v - > name ) ;
*/
2002-06-28 20:34:46 +00:00
v = v - > next ;
}
2004-09-11 13:50:26 +00:00
if ( ! found & & peer - > dynamic )
2003-08-24 22:35:06 +00:00
reg_source_db ( peer ) ;
2002-06-28 20:34:46 +00:00
peer - > delme = 0 ;
}
2004-10-07 18:27:12 +00:00
ast_free_ha ( oldha ) ;
2002-06-28 20:34:46 +00:00
return peer ;
}
2004-05-13 19:54:42 +00:00
/*--- reload_config: Re-read SIP.conf config file ---*/
2003-03-05 06:00:17 +00:00
static int reload_config ( void )
2002-06-28 20:34:46 +00:00
{
struct ast_config * cfg ;
struct ast_variable * v ;
struct sip_peer * peer ;
struct sip_user * user ;
2004-04-22 00:20:34 +00:00
struct ast_hostent ahp ;
2002-06-28 20:34:46 +00:00
char * cat ;
char * utype ;
struct hostent * hp ;
2003-02-07 04:07:10 +00:00
int format ;
int oldport = ntohs ( bindaddr . sin_port ) ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-03-12 06:00:18 +00:00
2004-07-08 11:05:03 +00:00
global_dtmfmode = SIP_DTMF_RFC2833 ;
global_promiscredir = 0 ;
2002-06-28 20:34:46 +00:00
if ( gethostname ( ourhost , sizeof ( ourhost ) ) ) {
ast_log ( LOG_WARNING , " Unable to get hostname, SIP disabled \n " ) ;
return 0 ;
}
cfg = ast_load ( config ) ;
/* We *must* have a config file otherwise stop immediately */
if ( ! cfg ) {
ast_log ( LOG_NOTICE , " Unable to load config %s, SIP disabled \n " , config ) ;
return 0 ;
}
2003-02-18 18:15:30 +00:00
2004-07-08 11:05:03 +00:00
global_nat = SIP_NAT_RFC3581 ;
2003-03-10 20:39:12 +00:00
2003-02-18 18:15:30 +00:00
sip_prefs_free ( ) ;
2002-06-28 20:34:46 +00:00
memset ( & bindaddr , 0 , sizeof ( bindaddr ) ) ;
2004-05-08 20:58:24 +00:00
memset ( & localaddr , 0 , sizeof ( localaddr ) ) ;
2004-01-13 01:31:42 +00:00
memset ( & externip , 0 , sizeof ( externip ) ) ;
2003-02-07 04:07:10 +00:00
/* Initialize some reasonable defaults */
2004-07-08 11:05:03 +00:00
strncpy ( default_context , " default " , sizeof ( default_context ) - 1 ) ;
default_language [ 0 ] = ' \0 ' ;
default_fromdomain [ 0 ] = ' \0 ' ;
2004-07-20 22:22:36 +00:00
strncpy ( default_useragent , DEFAULT_USERAGENT , sizeof ( default_useragent ) - 1 ) ;
2004-05-06 20:00:19 +00:00
strncpy ( global_realm , " asterisk " , sizeof ( global_realm ) - 1 ) ;
2004-07-08 11:05:03 +00:00
global_realm [ sizeof ( global_realm ) - 1 ] = ' \0 ' ;
global_canreinvite = REINVITE_INVITE ;
2003-06-28 16:40:02 +00:00
videosupport = 0 ;
2004-04-29 22:27:40 +00:00
relaxdtmf = 0 ;
2004-07-29 18:58:57 +00:00
ourport = DEFAULT_SIP_PORT ;
2004-07-08 11:05:03 +00:00
global_rtptimeout = 0 ;
global_rtpholdtimeout = 0 ;
2003-08-12 16:48:16 +00:00
pedanticsipchecking = 0 ;
2002-06-28 20:34:46 +00:00
v = ast_variable_browse ( cfg , " general " ) ;
while ( v ) {
/* Create the interface list */
if ( ! strcasecmp ( v - > name , " context " ) ) {
2004-07-08 11:05:03 +00:00
strncpy ( default_context , v - > value , sizeof ( default_context ) - 1 ) ;
2004-05-06 20:00:19 +00:00
} else if ( ! strcasecmp ( v - > name , " realm " ) ) {
strncpy ( global_realm , v - > value , sizeof ( global_realm ) - 1 ) ;
2004-07-08 11:05:03 +00:00
global_realm [ sizeof ( global_realm ) - 1 ] = ' \0 ' ;
2004-05-25 05:36:49 +00:00
} else if ( ! strcasecmp ( v - > name , " useragent " ) ) {
2004-07-08 11:05:03 +00:00
strncpy ( default_useragent , v - > value , sizeof ( default_useragent ) - 1 ) ;
ast_log ( LOG_DEBUG , " Setting User Agent Name to %s \n " ,
default_useragent ) ;
2004-04-29 22:27:40 +00:00
} else if ( ! strcasecmp ( v - > name , " relaxdtmf " ) ) {
relaxdtmf = ast_true ( v - > value ) ;
2004-06-21 06:11:56 +00:00
} else if ( ! strcasecmp ( v - > name , " promiscredir " ) ) {
2004-07-08 11:05:03 +00:00
global_promiscredir = ast_true ( v - > value ) ;
2003-03-12 06:00:18 +00:00
} else if ( ! strcasecmp ( v - > name , " dtmfmode " ) ) {
if ( ! strcasecmp ( v - > value , " inband " ) )
2004-07-08 11:05:03 +00:00
global_dtmfmode = SIP_DTMF_INBAND ;
2003-03-12 06:00:18 +00:00
else if ( ! strcasecmp ( v - > value , " rfc2833 " ) )
2004-07-08 11:05:03 +00:00
global_dtmfmode = SIP_DTMF_RFC2833 ;
2003-03-12 06:00:18 +00:00
else if ( ! strcasecmp ( v - > value , " info " ) )
2004-07-08 11:05:03 +00:00
global_dtmfmode = SIP_DTMF_INFO ;
2003-03-12 06:00:18 +00:00
else {
ast_log ( LOG_WARNING , " Unknown dtmf mode '%s', using rfc2833 \n " , v - > value ) ;
2004-07-08 11:05:03 +00:00
global_dtmfmode = SIP_DTMF_RFC2833 ;
2003-03-12 06:00:18 +00:00
}
2004-05-27 22:12:55 +00:00
} else if ( ! strcasecmp ( v - > name , " rtptimeout " ) ) {
2004-07-08 11:05:03 +00:00
if ( ( sscanf ( v - > value , " %d " , & global_rtptimeout ) ! = 1 ) | | ( global_rtptimeout < 0 ) ) {
2004-05-27 22:12:55 +00:00
ast_log ( LOG_WARNING , " '%s' is not a valid RTP hold time at line %d. Using default. \n " , v - > value , v - > lineno ) ;
2004-07-08 11:05:03 +00:00
global_rtptimeout = 0 ;
2004-05-27 22:12:55 +00:00
}
} else if ( ! strcasecmp ( v - > name , " rtpholdtimeout " ) ) {
2004-07-08 11:05:03 +00:00
if ( ( sscanf ( v - > value , " %d " , & global_rtpholdtimeout ) ! = 1 ) | | ( global_rtpholdtimeout < 0 ) ) {
2004-05-27 22:12:55 +00:00
ast_log ( LOG_WARNING , " '%s' is not a valid RTP hold time at line %d. Using default. \n " , v - > value , v - > lineno ) ;
2004-07-08 11:05:03 +00:00
global_rtpholdtimeout = 0 ;
2004-05-27 22:12:55 +00:00
}
2003-06-28 16:40:02 +00:00
} else if ( ! strcasecmp ( v - > name , " videosupport " ) ) {
videosupport = ast_true ( v - > value ) ;
2003-04-30 18:48:30 +00:00
} else if ( ! strcasecmp ( v - > name , " notifymimetype " ) ) {
strncpy ( notifymime , v - > value , sizeof ( notifymime ) - 1 ) ;
2004-05-04 20:10:37 +00:00
} else if ( ! strcasecmp ( v - > name , " musicclass " ) ) {
2004-07-08 11:05:03 +00:00
strncpy ( global_musicclass , v - > value , sizeof ( global_musicclass ) - 1 ) ;
2002-06-28 20:34:46 +00:00
} else if ( ! strcasecmp ( v - > name , " language " ) ) {
2004-07-08 11:05:03 +00:00
strncpy ( default_language , v - > value , sizeof ( default_language ) - 1 ) ;
2004-09-07 23:45:34 +00:00
} else if ( ! strcasecmp ( v - > name , " regcontext " ) ) {
strncpy ( regcontext , v - > value , sizeof ( regcontext ) - 1 ) ;
/* Create context if it doesn't exist already */
if ( ! ast_context_find ( regcontext ) )
ast_context_create ( NULL , regcontext , type ) ;
2003-03-20 17:21:54 +00:00
} else if ( ! strcasecmp ( v - > name , " callerid " ) ) {
2004-07-08 11:05:03 +00:00
strncpy ( default_callerid , v - > value , sizeof ( default_callerid ) - 1 ) ;
2003-04-06 02:51:10 +00:00
} else if ( ! strcasecmp ( v - > name , " fromdomain " ) ) {
2004-07-08 11:05:03 +00:00
strncpy ( default_fromdomain , v - > value , sizeof ( default_fromdomain ) - 1 ) ;
2003-03-10 20:39:12 +00:00
} else if ( ! strcasecmp ( v - > name , " nat " ) ) {
2004-06-28 23:24:36 +00:00
if ( ! strcasecmp ( v - > value , " rfc3581 " ) )
2004-07-08 11:05:03 +00:00
global_nat = SIP_NAT_RFC3581 ;
2004-08-27 02:45:35 +00:00
else if ( ! strcasecmp ( v - > value , " route " ) )
global_nat = SIP_NAT_ROUTE ;
2004-06-28 23:24:36 +00:00
else if ( ast_true ( v - > value ) )
2004-07-08 11:05:03 +00:00
global_nat = SIP_NAT_ALWAYS ;
2004-06-28 23:24:36 +00:00
else
2004-07-08 11:05:03 +00:00
global_nat = SIP_NAT_NEVER ;
2003-11-11 20:46:41 +00:00
} else if ( ! strcasecmp ( v - > name , " autocreatepeer " ) ) {
autocreatepeer = ast_true ( v - > value ) ;
2003-06-12 12:48:57 +00:00
} else if ( ! strcasecmp ( v - > name , " srvlookup " ) ) {
srvlookup = ast_true ( v - > value ) ;
2004-06-21 04:29:50 +00:00
} else if ( ! strcasecmp ( v - > name , " trustrpid " ) ) {
2004-07-08 11:05:03 +00:00
global_trustrpid = ast_true ( v - > value ) ;
2004-06-26 21:17:12 +00:00
} else if ( ! strcasecmp ( v - > name , " progressinband " ) ) {
2004-07-08 11:05:03 +00:00
global_progressinband = ast_true ( v - > value ) ;
2004-06-25 05:52:55 +00:00
# ifdef OSP_SUPPORT
} else if ( ! strcasecmp ( v - > name , " ospauth " ) ) {
if ( ! strcasecmp ( v - > value , " exclusive " ) ) {
2004-07-08 11:05:03 +00:00
global_ospauth = 2 ;
2004-06-25 05:52:55 +00:00
} else if ( ast_true ( v - > value ) ) {
2004-07-08 11:05:03 +00:00
global_ospauth = 1 ;
2004-06-25 05:52:55 +00:00
} else
2004-07-08 11:05:03 +00:00
global_ospauth = 0 ;
2004-06-25 05:52:55 +00:00
# endif
2003-08-12 16:48:16 +00:00
} else if ( ! strcasecmp ( v - > name , " pedantic " ) ) {
pedanticsipchecking = ast_true ( v - > value ) ;
2003-05-12 16:16:33 +00:00
} else if ( ! strcasecmp ( v - > name , " canreinvite " ) ) {
if ( ! strcasecmp ( v - > value , " update " ) )
2004-07-08 11:05:03 +00:00
global_canreinvite = REINVITE_UPDATE ;
2003-05-12 16:16:33 +00:00
else
2004-07-08 11:05:03 +00:00
global_canreinvite = ast_true ( v - > value ) ;
2003-04-08 03:24:12 +00:00
} else if ( ! strcasecmp ( v - > name , " maxexpirey " ) | | ! strcasecmp ( v - > name , " maxexpiry " ) ) {
max_expiry = atoi ( v - > value ) ;
if ( max_expiry < 1 )
max_expiry = DEFAULT_MAX_EXPIRY ;
2003-04-14 19:18:49 +00:00
} else if ( ! strcasecmp ( v - > name , " defaultexpiry " ) | | ! strcasecmp ( v - > name , " defaultexpirey " ) ) {
2003-04-08 03:24:12 +00:00
default_expiry = atoi ( v - > value ) ;
if ( default_expiry < 1 )
default_expiry = DEFAULT_DEFAULT_EXPIRY ;
2002-06-28 20:34:46 +00:00
} else if ( ! strcasecmp ( v - > name , " bindaddr " ) ) {
2004-04-22 00:20:34 +00:00
if ( ! ( hp = ast_gethostbyname ( v - > value , & ahp ) ) ) {
2002-06-28 20:34:46 +00:00
ast_log ( LOG_WARNING , " Invalid address: %s \n " , v - > value ) ;
} else {
memcpy ( & bindaddr . sin_addr , hp - > h_addr , sizeof ( bindaddr . sin_addr ) ) ;
}
2004-01-13 01:31:42 +00:00
} else if ( ! strcasecmp ( v - > name , " localnet " ) ) {
2004-05-08 20:58:24 +00:00
struct ast_ha * na ;
if ( ! ( na = ast_append_ha ( " d " , v - > value , localaddr ) ) )
ast_log ( LOG_WARNING , " Invalid localnet value: %s \n " , v - > value ) ;
2004-01-13 01:31:42 +00:00
else
2004-05-08 20:58:24 +00:00
localaddr = na ;
} else if ( ! strcasecmp ( v - > name , " localmask " ) ) {
2004-05-12 17:30:55 +00:00
ast_log ( LOG_WARNING , " Use of localmask is no long supported -- use localnet with mask syntax \n " ) ;
2003-10-31 16:13:49 +00:00
} else if ( ! strcasecmp ( v - > name , " externip " ) ) {
2004-04-22 00:20:34 +00:00
if ( ! ( hp = ast_gethostbyname ( v - > value , & ahp ) ) )
2003-10-31 16:13:49 +00:00
ast_log ( LOG_WARNING , " Invalid address for externip keyword: %s \n " , v - > value ) ;
2004-01-13 01:31:42 +00:00
else
memcpy ( & externip . sin_addr , hp - > h_addr , sizeof ( externip . sin_addr ) ) ;
2003-02-07 04:07:10 +00:00
} else if ( ! strcasecmp ( v - > name , " allow " ) ) {
format = ast_getformatbyname ( v - > value ) ;
if ( format < 1 )
ast_log ( LOG_WARNING , " Cannot allow unknown format '%s' \n " , v - > value ) ;
2003-02-18 18:15:30 +00:00
else {
2004-07-08 11:05:03 +00:00
global_capability | = format ;
2003-02-18 18:15:30 +00:00
sip_pref_append ( format ) ;
}
2003-02-07 04:07:10 +00:00
} else if ( ! strcasecmp ( v - > name , " disallow " ) ) {
format = ast_getformatbyname ( v - > value ) ;
if ( format < 1 )
ast_log ( LOG_WARNING , " Cannot disallow unknown format '%s' \n " , v - > value ) ;
2003-02-18 18:15:30 +00:00
else {
2004-07-08 11:05:03 +00:00
global_capability & = ~ format ;
2003-02-18 18:15:30 +00:00
sip_pref_remove ( format ) ;
}
2003-02-07 04:07:10 +00:00
} else if ( ! strcasecmp ( v - > name , " register " ) ) {
sip_register ( v - > value , v - > lineno ) ;
2004-06-29 14:44:29 +00:00
} else if ( ! strcasecmp ( v - > name , " recordhistory " ) ) {
recordhistory = ast_true ( v - > value ) ;
2003-02-07 04:07:10 +00:00
} else if ( ! strcasecmp ( v - > name , " tos " ) ) {
if ( sscanf ( v - > value , " %i " , & format ) = = 1 )
tos = format & 0xff ;
else if ( ! strcasecmp ( v - > value , " lowdelay " ) )
tos = IPTOS_LOWDELAY ;
else if ( ! strcasecmp ( v - > value , " throughput " ) )
tos = IPTOS_THROUGHPUT ;
else if ( ! strcasecmp ( v - > value , " reliability " ) )
tos = IPTOS_RELIABILITY ;
else if ( ! strcasecmp ( v - > value , " mincost " ) )
tos = IPTOS_MINCOST ;
else if ( ! strcasecmp ( v - > value , " none " ) )
tos = 0 ;
else
ast_log ( LOG_WARNING , " Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none' \n " , v - > lineno ) ;
2002-06-28 20:34:46 +00:00
} else if ( ! strcasecmp ( v - > name , " port " ) ) {
if ( sscanf ( v - > value , " %i " , & ourport ) = = 1 ) {
bindaddr . sin_port = htons ( ourport ) ;
} else {
ast_log ( LOG_WARNING , " Invalid port number '%s' at line %d of %s \n " , v - > value , v - > lineno , config ) ;
}
2004-04-26 14:54:33 +00:00
}
/* else if (strcasecmp(v->name,"type"))
* ast_log ( LOG_WARNING , " Ignoring %s \n " , v - > name ) ;
*/
2003-03-12 06:00:18 +00:00
v = v - > next ;
2002-06-28 20:34:46 +00:00
}
cat = ast_category_browse ( cfg , NULL ) ;
while ( cat ) {
if ( strcasecmp ( cat , " general " ) ) {
utype = ast_variable_retrieve ( cfg , cat , " type " ) ;
if ( utype ) {
if ( ! strcasecmp ( utype , " user " ) | | ! strcasecmp ( utype , " friend " ) ) {
user = build_user ( cat , ast_variable_browse ( cfg , cat ) ) ;
if ( user ) {
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & userl . lock ) ;
2002-06-28 20:34:46 +00:00
user - > next = userl . users ;
userl . users = user ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & userl . lock ) ;
2002-06-28 20:34:46 +00:00
}
}
if ( ! strcasecmp ( utype , " peer " ) | | ! strcasecmp ( utype , " friend " ) ) {
2004-10-12 19:54:54 +00:00
peer = build_peer ( cat , ast_variable_browse ( cfg , cat ) , 0 ) ;
2002-06-28 20:34:46 +00:00
if ( peer ) {
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & peerl . lock ) ;
2002-06-28 20:34:46 +00:00
peer - > next = peerl . peers ;
peerl . peers = peer ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2002-06-28 20:34:46 +00:00
}
} else if ( strcasecmp ( utype , " user " ) ) {
ast_log ( LOG_WARNING , " Unknown type '%s' for '%s' in %s \n " , utype , cat , " sip.conf " ) ;
}
} else
ast_log ( LOG_WARNING , " Section '%s' lacks type \n " , cat ) ;
}
cat = ast_category_browse ( cfg , cat ) ;
}
2004-01-13 01:31:42 +00:00
if ( ntohl ( bindaddr . sin_addr . s_addr ) ) {
memcpy ( & __ourip , & bindaddr . sin_addr , sizeof ( __ourip ) ) ;
} else {
2004-04-22 00:20:34 +00:00
hp = ast_gethostbyname ( ourhost , & ahp ) ;
2004-01-13 01:31:42 +00:00
if ( ! hp ) {
ast_log ( LOG_WARNING , " Unable to get IP address for %s, SIP disabled \n " , ourhost ) ;
2004-05-12 23:35:50 +00:00
if ( ! __ourip . s_addr ) {
ast_destroy ( cfg ) ;
2004-05-02 17:43:15 +00:00
return 0 ;
2004-05-12 23:35:50 +00:00
}
2004-05-02 17:43:15 +00:00
} else
memcpy ( & __ourip , hp - > h_addr , sizeof ( __ourip ) ) ;
2002-09-12 17:13:17 +00:00
}
2002-06-28 20:34:46 +00:00
if ( ! ntohs ( bindaddr . sin_port ) )
bindaddr . sin_port = ntohs ( DEFAULT_SIP_PORT ) ;
bindaddr . sin_family = AF_INET ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & netlock ) ;
2003-02-07 04:07:10 +00:00
if ( ( sipsock > - 1 ) & & ( ntohs ( bindaddr . sin_port ) ! = oldport ) ) {
2002-06-28 20:34:46 +00:00
close ( sipsock ) ;
2003-02-07 04:07:10 +00:00
sipsock = - 1 ;
}
2002-06-28 20:34:46 +00:00
if ( sipsock < 0 ) {
2003-02-07 04:07:10 +00:00
sipsock = socket ( AF_INET , SOCK_DGRAM , 0 ) ;
if ( sipsock < 0 ) {
ast_log ( LOG_WARNING , " Unable to create SIP socket: %s \n " , strerror ( errno ) ) ;
} else {
2004-04-26 14:54:33 +00:00
/* Allow SIP clients on the same host to access us: */
2003-03-12 06:00:18 +00:00
const int reuseFlag = 1 ;
setsockopt ( sipsock , SOL_SOCKET , SO_REUSEADDR ,
( const char * ) & reuseFlag ,
sizeof reuseFlag ) ;
2003-02-07 04:07:10 +00:00
if ( bind ( sipsock , ( struct sockaddr * ) & bindaddr , sizeof ( bindaddr ) ) < 0 ) {
ast_log ( LOG_WARNING , " Failed to bind to %s:%d: %s \n " ,
2004-06-29 12:56:46 +00:00
ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , bindaddr . sin_addr ) , ntohs ( bindaddr . sin_port ) ,
2003-02-07 04:07:10 +00:00
strerror ( errno ) ) ;
close ( sipsock ) ;
sipsock = - 1 ;
2003-07-30 20:49:23 +00:00
} else {
if ( option_verbose > 1 ) {
ast_verbose ( VERBOSE_PREFIX_2 " SIP Listening on %s:%d \n " ,
2004-06-29 12:56:46 +00:00
ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , bindaddr . sin_addr ) , ntohs ( bindaddr . sin_port ) ) ;
2003-02-07 04:07:10 +00:00
ast_verbose ( VERBOSE_PREFIX_2 " Using TOS bits %d \n " , tos ) ;
2003-07-30 20:49:23 +00:00
}
2003-04-23 20:22:14 +00:00
if ( setsockopt ( sipsock , IPPROTO_IP , IP_TOS , & tos , sizeof ( tos ) ) )
2003-02-07 04:07:10 +00:00
ast_log ( LOG_WARNING , " Unable to set TOS to %d \n " , tos ) ;
}
}
2002-06-28 20:34:46 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & netlock ) ;
2002-06-28 20:34:46 +00:00
ast_destroy ( cfg ) ;
2003-02-07 04:07:10 +00:00
return 0 ;
}
2003-02-16 06:00:12 +00:00
static struct ast_rtp * sip_get_rtp_peer ( struct ast_channel * chan )
{
struct sip_pvt * p ;
2004-08-23 14:31:20 +00:00
struct ast_rtp * rtp = NULL ;
2003-02-16 06:00:12 +00:00
p = chan - > pvt - > pvt ;
2004-08-23 14:31:20 +00:00
if ( p ) {
ast_mutex_lock ( & p - > lock ) ;
if ( p - > rtp & & p - > canreinvite )
rtp = p - > rtp ;
ast_mutex_unlock ( & p - > lock ) ;
}
return rtp ;
2003-02-16 06:00:12 +00:00
}
2003-06-28 16:40:02 +00:00
static struct ast_rtp * sip_get_vrtp_peer ( struct ast_channel * chan )
{
struct sip_pvt * p ;
2004-08-23 14:31:20 +00:00
struct ast_rtp * rtp = NULL ;
2003-06-28 16:40:02 +00:00
p = chan - > pvt - > pvt ;
2004-08-23 14:31:20 +00:00
if ( p ) {
ast_mutex_lock ( & p - > lock ) ;
if ( p - > vrtp & & p - > canreinvite )
rtp = p - > vrtp ;
ast_mutex_unlock ( & p - > lock ) ;
}
return rtp ;
2003-06-28 16:40:02 +00:00
}
2004-05-27 05:06:32 +00:00
static int sip_set_rtp_peer ( struct ast_channel * chan , struct ast_rtp * rtp , struct ast_rtp * vrtp , int codecs )
2003-02-16 06:00:12 +00:00
{
struct sip_pvt * p ;
p = chan - > pvt - > pvt ;
if ( p ) {
2004-08-23 14:31:20 +00:00
ast_mutex_lock ( & p - > lock ) ;
2003-04-30 21:53:55 +00:00
if ( rtp )
ast_rtp_get_peer ( rtp , & p - > redirip ) ;
else
memset ( & p - > redirip , 0 , sizeof ( p - > redirip ) ) ;
2003-06-28 16:40:02 +00:00
if ( vrtp )
ast_rtp_get_peer ( vrtp , & p - > vredirip ) ;
else
memset ( & p - > vredirip , 0 , sizeof ( p - > vredirip ) ) ;
2004-05-27 05:06:32 +00:00
p - > redircodecs = codecs ;
2003-11-12 00:13:55 +00:00
if ( ! p - > gotrefer ) {
2004-05-27 05:06:32 +00:00
if ( ! p - > pendinginvite )
transmit_reinvite_with_sdp ( p ) ;
else if ( ! p - > pendingbye ) {
ast_log ( LOG_DEBUG , " Deferring reinvite on '%s' \n " , p - > callid ) ;
p - > needreinvite = 1 ;
}
2003-11-12 00:13:55 +00:00
}
2004-08-23 14:31:20 +00:00
/* Reset lastrtprx timer */
time ( & p - > lastrtprx ) ;
ast_mutex_unlock ( & p - > lock ) ;
2003-02-16 06:00:12 +00:00
return 0 ;
}
return - 1 ;
}
2003-09-11 22:41:30 +00:00
static char * synopsis_dtmfmode = " Change the dtmfmode for a SIP call " ;
static char * descrip_dtmfmode = " SIPDtmfMode(inband|info|rfc2833): Changes the dtmfmode for a SIP call \n " ;
static char * app_dtmfmode = " SIPDtmfMode " ;
2004-05-13 19:54:42 +00:00
/*--- sip_dtmfmode: change the DTMFmode for a SIP call (application) ---*/
2003-09-11 22:41:30 +00:00
static int sip_dtmfmode ( struct ast_channel * chan , void * data )
{
2004-04-02 07:24:33 +00:00
struct sip_pvt * p ;
2003-09-11 22:41:30 +00:00
char * mode ;
if ( data )
mode = ( char * ) data ;
else {
ast_log ( LOG_WARNING , " This application requires the argument: info, inband, rfc2833 \n " ) ;
return 0 ;
}
2004-04-02 07:24:33 +00:00
ast_mutex_lock ( & chan - > lock ) ;
if ( chan - > type ! = type ) {
ast_log ( LOG_WARNING , " Call this application only on SIP incoming calls \n " ) ;
ast_mutex_unlock ( & chan - > lock ) ;
return 0 ;
}
p = chan - > pvt - > pvt ;
if ( p ) {
ast_mutex_lock ( & p - > lock ) ;
if ( ! strcasecmp ( mode , " info " ) )
p - > dtmfmode = SIP_DTMF_INFO ;
else if ( ! strcasecmp ( mode , " rfc2833 " ) )
p - > dtmfmode = SIP_DTMF_RFC2833 ;
else if ( ! strcasecmp ( mode , " inband " ) )
p - > dtmfmode = SIP_DTMF_INBAND ;
else
ast_log ( LOG_WARNING , " I don't know about this dtmf mode: %s \n " , mode ) ;
2004-04-02 14:40:21 +00:00
if ( p - > dtmfmode & SIP_DTMF_INBAND ) {
if ( ! p - > vad ) {
p - > vad = ast_dsp_new ( ) ;
ast_dsp_set_features ( p - > vad , DSP_FEATURE_DTMF_DETECT ) ;
}
} else {
if ( p - > vad ) {
ast_dsp_free ( p - > vad ) ;
p - > vad = NULL ;
}
}
2004-04-02 07:24:33 +00:00
ast_mutex_unlock ( & p - > lock ) ;
}
ast_mutex_unlock ( & chan - > lock ) ;
2003-09-11 22:41:30 +00:00
return 0 ;
}
2003-11-15 00:52:49 +00:00
static int sip_get_codec ( struct ast_channel * chan )
{
struct sip_pvt * p = chan - > pvt - > pvt ;
2004-08-18 13:55:03 +00:00
return p - > peercapability ;
2003-11-15 00:52:49 +00:00
}
2003-02-16 06:00:12 +00:00
static struct ast_rtp_protocol sip_rtp = {
get_rtp_info : sip_get_rtp_peer ,
2003-06-28 16:40:02 +00:00
get_vrtp_info : sip_get_vrtp_peer ,
2003-02-16 06:00:12 +00:00
set_rtp_peer : sip_set_rtp_peer ,
2003-11-15 00:52:49 +00:00
get_codec : sip_get_codec ,
2003-02-16 06:00:12 +00:00
} ;
2004-05-13 19:54:42 +00:00
/*--- delete_users: Delete all registred users ---*/
/* Also, check registations with other SIP proxies */
2003-04-27 21:34:27 +00:00
static void delete_users ( void )
2003-02-07 04:07:10 +00:00
{
struct sip_user * user , * userlast ;
struct sip_peer * peer ;
2004-02-02 23:48:31 +00:00
struct sip_registry * reg , * regn ;
2003-02-07 04:07:10 +00:00
/* Delete all users */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & userl . lock ) ;
2003-02-07 04:07:10 +00:00
for ( user = userl . users ; user ; ) {
userlast = user ;
user = user - > next ;
2004-10-07 16:42:37 +00:00
destroy_user ( userlast ) ;
2003-02-07 04:07:10 +00:00
}
userl . users = NULL ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & userl . lock ) ;
2003-02-07 04:07:10 +00:00
2004-02-02 22:35:33 +00:00
ast_mutex_lock ( & regl . lock ) ;
for ( reg = regl . registrations ; reg ; ) {
2004-02-02 23:48:31 +00:00
regn = reg - > next ;
/* Really delete */
if ( reg - > call ) {
/* Clear registry before destroying to ensure
we don ' t get reentered trying to grab the registry lock */
reg - > call - > registry = NULL ;
sip_destroy ( reg - > call ) ;
}
if ( reg - > expire > - 1 )
ast_sched_del ( sched , reg - > expire ) ;
if ( reg - > timeout > - 1 )
ast_sched_del ( sched , reg - > timeout ) ;
free ( reg ) ;
reg = regn ;
2003-02-07 04:07:10 +00:00
}
2004-02-02 22:35:33 +00:00
regl . registrations = NULL ;
ast_mutex_unlock ( & regl . lock ) ;
2004-02-02 23:48:31 +00:00
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & peerl . lock ) ;
2003-02-07 04:07:10 +00:00
for ( peer = peerl . peers ; peer ; ) {
/* Assume all will be deleted, and we'll find out for sure later */
peer - > delme = 1 ;
peer = peer - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2003-02-07 04:07:10 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- prune_peers: Delete all peers marked for deletion ---*/
2003-04-27 21:34:27 +00:00
static void prune_peers ( void )
2003-02-07 04:07:10 +00:00
{
/* Prune peers who still are supposed to be deleted */
struct sip_peer * peer , * peerlast , * peernext ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & peerl . lock ) ;
2003-02-07 04:07:10 +00:00
peerlast = NULL ;
for ( peer = peerl . peers ; peer ; ) {
peernext = peer - > next ;
if ( peer - > delme ) {
2004-10-07 15:46:08 +00:00
destroy_peer ( peer ) ;
2003-02-07 04:07:10 +00:00
if ( peerlast )
peerlast - > next = peernext ;
else
peerl . peers = peernext ;
} else
peerlast = peer ;
peer = peernext ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2003-02-07 04:07:10 +00:00
}
2004-05-13 19:54:42 +00:00
/*--- sip_do_reload: Reload module */
2004-02-02 23:48:31 +00:00
static int sip_do_reload ( void )
2003-02-07 04:07:10 +00:00
{
struct sip_registry * reg ;
struct sip_peer * peer ;
delete_users ( ) ;
reload_config ( ) ;
prune_peers ( ) ;
2002-06-28 20:34:46 +00:00
/* And start the monitor for the first time */
2004-02-02 22:35:33 +00:00
ast_mutex_lock ( & regl . lock ) ;
for ( reg = regl . registrations ; reg ; reg = reg - > next )
2004-02-02 23:21:36 +00:00
__sip_do_register ( reg ) ;
2004-02-02 22:35:33 +00:00
ast_mutex_unlock ( & regl . lock ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & peerl . lock ) ;
2003-02-07 04:07:10 +00:00
for ( peer = peerl . peers ; peer ; peer = peer - > next )
sip_poke_peer ( peer ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2004-01-23 15:43:31 +00:00
2002-06-28 20:34:46 +00:00
return 0 ;
}
2004-05-13 19:54:42 +00:00
/*--- sip_reload: Force reload of module from cli ---*/
2004-02-02 23:48:31 +00:00
static int sip_reload ( int fd , int argc , char * argv [ ] )
{
ast_mutex_lock ( & sip_reload_lock ) ;
if ( sip_reloading ) {
ast_verbose ( " Previous SIP reload not yet done \n " ) ;
} else
sip_reloading = 1 ;
ast_mutex_unlock ( & sip_reload_lock ) ;
restart_monitor ( ) ;
return 0 ;
}
2004-01-23 15:43:31 +00:00
int reload ( void )
{
return sip_reload ( 0 , 0 , NULL ) ;
}
static struct ast_cli_entry cli_sip_reload =
{ { " sip " , " reload " , NULL } , sip_reload , " Reload SIP configuration " , sip_reload_usage } ;
2004-05-13 19:54:42 +00:00
/*--- load_module: PBX load module - initialization ---*/
2004-01-23 15:43:31 +00:00
int load_module ( )
{
int res ;
struct sip_peer * peer ;
struct sip_registry * reg ;
2004-06-09 01:45:08 +00:00
ast_mutex_init ( & userl . lock ) ;
ast_mutex_init ( & peerl . lock ) ;
ast_mutex_init ( & regl . lock ) ;
2004-01-23 15:43:31 +00:00
sched = sched_context_create ( ) ;
if ( ! sched ) {
ast_log ( LOG_WARNING , " Unable to create schedule context \n " ) ;
}
io = io_context_create ( ) ;
if ( ! io ) {
ast_log ( LOG_WARNING , " Unable to create I/O context \n " ) ;
}
res = reload_config ( ) ;
if ( ! res ) {
/* Make sure we can register our sip channel type */
2004-03-19 08:00:13 +00:00
if ( ast_channel_register_ex ( type , tdesc , ( ( AST_FORMAT_MAX_AUDIO < < 1 ) - 1 ) , sip_request , sip_devicestate ) ) {
2004-01-23 15:43:31 +00:00
ast_log ( LOG_ERROR , " Unable to register channel class %s \n " , type ) ;
return - 1 ;
}
ast_cli_register ( & cli_show_users ) ;
2004-05-06 21:30:45 +00:00
ast_cli_register ( & cli_show_subscriptions ) ;
2004-01-23 15:43:31 +00:00
ast_cli_register ( & cli_show_channels ) ;
ast_cli_register ( & cli_show_channel ) ;
2004-05-12 00:17:31 +00:00
ast_cli_register ( & cli_show_history ) ;
2004-05-07 18:57:17 +00:00
ast_cli_register ( & cli_show_peer ) ;
2004-01-23 15:43:31 +00:00
ast_cli_register ( & cli_show_peers ) ;
2004-05-02 05:38:20 +00:00
ast_cli_register ( & cli_show_peers_begin ) ;
ast_cli_register ( & cli_show_peers_include ) ;
ast_cli_register ( & cli_show_peers_exclude ) ;
2004-01-23 15:43:31 +00:00
ast_cli_register ( & cli_show_registry ) ;
ast_cli_register ( & cli_debug ) ;
2004-05-01 21:25:31 +00:00
ast_cli_register ( & cli_debug_ip ) ;
ast_cli_register ( & cli_debug_peer ) ;
2004-01-23 15:43:31 +00:00
ast_cli_register ( & cli_no_debug ) ;
2004-05-12 00:17:31 +00:00
ast_cli_register ( & cli_history ) ;
ast_cli_register ( & cli_no_history ) ;
2004-01-23 15:43:31 +00:00
ast_cli_register ( & cli_sip_reload ) ;
ast_cli_register ( & cli_inuse_show ) ;
sip_rtp . type = type ;
ast_rtp_proto_register ( & sip_rtp ) ;
ast_register_application ( app_dtmfmode , sip_dtmfmode , synopsis_dtmfmode , descrip_dtmfmode ) ;
ast_mutex_lock ( & peerl . lock ) ;
for ( peer = peerl . peers ; peer ; peer = peer - > next )
sip_poke_peer ( peer ) ;
2004-02-02 22:35:33 +00:00
ast_mutex_unlock ( & peerl . lock ) ;
2004-01-23 15:43:31 +00:00
2004-02-02 22:35:33 +00:00
ast_mutex_lock ( & regl . lock ) ;
for ( reg = regl . registrations ; reg ; reg = reg - > next )
2004-02-02 23:22:57 +00:00
__sip_do_register ( reg ) ;
2004-02-02 22:35:33 +00:00
ast_mutex_unlock ( & regl . lock ) ;
2004-01-23 15:43:31 +00:00
/* And start the monitor for the first time */
restart_monitor ( ) ;
}
return res ;
}
2002-06-28 20:34:46 +00:00
int unload_module ( )
{
struct sip_pvt * p , * pl ;
2003-04-06 18:19:51 +00:00
2002-06-28 20:34:46 +00:00
/* First, take us out of the channel loop */
2003-09-11 22:41:30 +00:00
ast_unregister_application ( app_dtmfmode ) ;
2004-01-12 06:01:46 +00:00
ast_cli_unregister ( & cli_show_users ) ;
ast_cli_unregister ( & cli_show_channels ) ;
ast_cli_unregister ( & cli_show_channel ) ;
2004-05-12 00:17:31 +00:00
ast_cli_unregister ( & cli_show_history ) ;
2004-05-07 18:57:17 +00:00
ast_cli_unregister ( & cli_show_peer ) ;
2004-01-12 06:01:46 +00:00
ast_cli_unregister ( & cli_show_peers ) ;
2004-05-02 05:38:20 +00:00
ast_cli_unregister ( & cli_show_peers_include ) ;
ast_cli_unregister ( & cli_show_peers_exclude ) ;
ast_cli_unregister ( & cli_show_peers_begin ) ;
2004-01-12 06:01:46 +00:00
ast_cli_unregister ( & cli_show_registry ) ;
2004-05-06 21:30:45 +00:00
ast_cli_unregister ( & cli_show_subscriptions ) ;
2004-01-12 06:01:46 +00:00
ast_cli_unregister ( & cli_debug ) ;
2004-05-01 21:25:31 +00:00
ast_cli_unregister ( & cli_debug_ip ) ;
ast_cli_unregister ( & cli_debug_peer ) ;
2004-01-12 06:01:46 +00:00
ast_cli_unregister ( & cli_no_debug ) ;
2004-05-12 00:17:31 +00:00
ast_cli_unregister ( & cli_history ) ;
ast_cli_unregister ( & cli_no_history ) ;
2004-01-23 15:43:31 +00:00
ast_cli_unregister ( & cli_sip_reload ) ;
2004-01-12 06:01:46 +00:00
ast_cli_unregister ( & cli_inuse_show ) ;
ast_rtp_proto_unregister ( & sip_rtp ) ;
2004-01-14 06:10:53 +00:00
ast_channel_unregister ( type ) ;
2003-08-13 15:25:16 +00:00
if ( ! ast_mutex_lock ( & iflock ) ) {
2002-06-28 20:34:46 +00:00
/* Hangup all interfaces if they have an owner */
p = iflist ;
while ( p ) {
if ( p - > owner )
2002-09-12 17:13:17 +00:00
ast_softhangup ( p - > owner , AST_SOFTHANGUP_APPUNLOAD ) ;
2002-06-28 20:34:46 +00:00
p = p - > next ;
}
iflist = NULL ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
2002-06-28 20:34:46 +00:00
} else {
2004-01-13 01:59:36 +00:00
ast_log ( LOG_WARNING , " Unable to lock the interface list \n " ) ;
2002-06-28 20:34:46 +00:00
return - 1 ;
}
2003-08-13 15:25:16 +00:00
if ( ! ast_mutex_lock ( & monlock ) ) {
2004-03-15 07:51:22 +00:00
if ( monitor_thread & & ( monitor_thread ! = AST_PTHREADT_STOP ) ) {
2002-06-28 20:34:46 +00:00
pthread_cancel ( monitor_thread ) ;
pthread_kill ( monitor_thread , SIGURG ) ;
pthread_join ( monitor_thread , NULL ) ;
}
2004-03-15 07:51:22 +00:00
monitor_thread = AST_PTHREADT_STOP ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & monlock ) ;
2002-06-28 20:34:46 +00:00
} else {
ast_log ( LOG_WARNING , " Unable to lock the monitor \n " ) ;
return - 1 ;
}
2003-08-13 15:25:16 +00:00
if ( ! ast_mutex_lock ( & iflock ) ) {
2002-06-28 20:34:46 +00:00
/* Destroy all the interfaces and free their memory */
p = iflist ;
while ( p ) {
pl = p ;
p = p - > next ;
/* Free associated memory */
2004-06-22 17:42:14 +00:00
ast_mutex_destroy ( & pl - > lock ) ;
2002-06-28 20:34:46 +00:00
free ( pl ) ;
}
iflist = NULL ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & iflock ) ;
2002-06-28 20:34:46 +00:00
} else {
2004-01-13 01:59:36 +00:00
ast_log ( LOG_WARNING , " Unable to lock the interface list \n " ) ;
2002-06-28 20:34:46 +00:00
return - 1 ;
}
2004-05-08 20:58:24 +00:00
/* Free memory for local network address mask */
2004-10-07 18:27:12 +00:00
ast_free_ha ( localaddr ) ;
ast_mutex_destroy ( & userl . lock ) ;
ast_mutex_destroy ( & peerl . lock ) ;
ast_mutex_destroy ( & regl . lock ) ;
2002-06-28 20:34:46 +00:00
return 0 ;
}
int usecount ( )
{
int res ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & usecnt_lock ) ;
2002-06-28 20:34:46 +00:00
res = usecnt ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & usecnt_lock ) ;
2002-06-28 20:34:46 +00:00
return res ;
}
char * key ( )
{
return ASTERISK_GPL_KEY ;
}
char * description ( )
{
return desc ;
}
2003-09-11 22:41:30 +00:00