Skip to content
Snippets Groups Projects
chan_sip.c 699 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	if (fmt.cur_ms && (fmt.cur_ms < *min_packet_size))
    		*min_packet_size = fmt.cur_ms;
    
    
    	/* Our first codec packetization processed cannot be zero */
    	if ((*min_packet_size)==0 && fmt.cur_ms)
    		*min_packet_size = fmt.cur_ms;
    
    /*! \brief Add video codec offer to SDP offer/answer body in INVITE or 200 OK */
    /* This is different to the audio one now so we can add more caps later */
    static void add_vcodec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
    
    			     struct ast_str **m_buf, struct ast_str **a_buf,
    
    			     int debug, int *min_packet_size)
    {
    	int rtp_code;
    
    	if (!p->vrtp)
    		return;
    
    	if (debug)
    		ast_verbose("Adding video codec 0x%x (%s) to SDP\n", codec, ast_getformatname(codec));
    
    	if ((rtp_code = ast_rtp_lookup_code(p->vrtp, 1, codec)) == -1)
    		return;
    
    
    	ast_str_append(m_buf, 0, " %d", rtp_code);
    	ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code,
    
    			 ast_rtp_lookup_mime_subtype(1, codec, 0), sample_rate);
    	/* Add fmtp code here */
    }
    
    /*! \brief Add text codec offer to SDP offer/answer body in INVITE or 200 OK */
    static void add_tcodec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
    
    			     struct ast_str **m_buf, struct ast_str **a_buf,
    
    			     int debug, int *min_packet_size)
    {
    	int rtp_code;
    
    	if (!p->trtp)
    		return;
    
    	if (debug)
    		ast_verbose("Adding text codec 0x%x (%s) to SDP\n", codec, ast_getformatname(codec));
    
    	if ((rtp_code = ast_rtp_lookup_code(p->trtp, 1, codec)) == -1)
    		return;
    
    
    	ast_str_append(m_buf, 0, " %d", rtp_code);
    	ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code,
    
    			 ast_rtp_lookup_mime_subtype(1, codec, 0), sample_rate);
    	/* Add fmtp code here */
    }
    
    
    
    /*! \brief Get Max T.38 Transmission rate from T38 capabilities */
    
    static int t38_get_rate(int t38cap)
    {
    	int maxrate = (t38cap & (T38FAX_RATE_14400 | T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400));
    	
    	if (maxrate & T38FAX_RATE_14400) {
    
    		ast_debug(2, "T38MaxFaxRate 14400 found\n");
    
    		return 14400;
    	} else if (maxrate & T38FAX_RATE_12000) {
    
    		ast_debug(2, "T38MaxFaxRate 12000 found\n");
    
    		return 12000;
    	} else if (maxrate & T38FAX_RATE_9600) {
    
    		ast_debug(2, "T38MaxFaxRate 9600 found\n");
    
    		return 9600;
    	} else if (maxrate & T38FAX_RATE_7200) {
    
    		ast_debug(2, "T38MaxFaxRate 7200 found\n");
    
    		return 7200;
    	} else if (maxrate & T38FAX_RATE_4800) {
    
    		ast_debug(2, "T38MaxFaxRate 4800 found\n");
    
    		return 4800;
    	} else if (maxrate & T38FAX_RATE_2400) {
    
    		ast_debug(2, "T38MaxFaxRate 2400 found\n");
    
    		ast_debug(2, "Strange, T38MaxFaxRate NOT found in peers T38 SDP.\n");
    
    		return 0;
    	}
    }
    
    /*! \brief Add T.38 Session Description Protocol message */
    static int add_t38_sdp(struct sip_request *resp, struct sip_pvt *p)
    {
    	int len = 0;
    	int x = 0;
    	struct sockaddr_in udptlsin;
    
    	struct ast_str *m_modem = ast_str_alloca(1024);
    	struct ast_str *a_modem = ast_str_alloca(1024);
    
    	struct sockaddr_in udptldest = { 0, };
    	int debug;
    	
    	debug = sip_debug_test_pvt(p);
    	len = 0;
    	if (!p->udptl) {
    		ast_log(LOG_WARNING, "No way to add SDP without an UDPTL structure\n");
    		return -1;
    	}
    	
    	if (!p->sessionid) {
    
    		p->sessionid = (int)ast_random();
    
    		p->sessionversion = p->sessionid;
    	} else
    		p->sessionversion++;
    	
    	/* Our T.38 end is */
    	ast_udptl_get_us(p->udptl, &udptlsin);
    	
    	/* Determine T.38 UDPTL destination */
    	if (p->udptlredirip.sin_addr.s_addr) {
    		udptldest.sin_port = p->udptlredirip.sin_port;
    		udptldest.sin_addr = p->udptlredirip.sin_addr;
    	} else {
    
    		udptldest.sin_addr = p->ourip.sin_addr;
    
    		udptldest.sin_port = udptlsin.sin_port;
    	}
    	
    
    		ast_debug(1, "T.38 UDPTL is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(udptlsin.sin_port));
    
    	
    	/* We break with the "recommendation" and send our IP, in order that our
    	   peer doesn't have to ast_gethostbyname() us */
    	
    	if (debug) {
    
    		ast_debug(1, "Our T38 capability (%d), peer T38 capability (%d), joint capability (%d)\n",
    
    			p->t38.capability,
    			p->t38.peercapability,
    			p->t38.jointcapability);
    	}
    
    	ast_str_append(&m_modem, 0, "v=0\r\n");
    
    	ast_str_append(&m_modem, 0, "o=%s %d %d IN IP4 %s\r\n", ast_strlen_zero(global_sdpowner) ? "-" : global_sdpowner , p->sessionid, p->sessionversion, ast_inet_ntoa(udptldest.sin_addr));
    	ast_str_append(&m_modem, 0, "s=%s\r\n", ast_strlen_zero(global_sdpsession) ? "-" : global_sdpsession);
    
    	ast_str_append(&m_modem, 0, "c=IN IP4 %s\r\n", ast_inet_ntoa(udptldest.sin_addr));
    	ast_str_append(&m_modem, 0, "t=0 0\r\n");
    	ast_str_append(&m_modem, 0, "m=image %d udptl t38\r\n", ntohs(udptldest.sin_port));
    
    	
    	if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_0)
    
    		ast_str_append(&a_modem, 0, "a=T38FaxVersion:0\r\n");
    
    	if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_1)
    
    		ast_str_append(&a_modem, 0, "a=T38FaxVersion:1\r\n");
    
    	if ((x = t38_get_rate(p->t38.jointcapability)))
    
    		ast_str_append(&a_modem, 0, "a=T38MaxBitRate:%d\r\n",x);
    	ast_str_append(&a_modem, 0, "a=T38FaxFillBitRemoval:%d\r\n", (p->t38.jointcapability & T38FAX_FILL_BIT_REMOVAL) ? 1 : 0);
    	ast_str_append(&a_modem, 0, "a=T38FaxTranscodingMMR:%d\r\n", (p->t38.jointcapability & T38FAX_TRANSCODING_MMR) ? 1 : 0);
    	ast_str_append(&a_modem, 0, "a=T38FaxTranscodingJBIG:%d\r\n", (p->t38.jointcapability & T38FAX_TRANSCODING_JBIG) ? 1 : 0);
    	ast_str_append(&a_modem, 0, "a=T38FaxRateManagement:%s\r\n", (p->t38.jointcapability & T38FAX_RATE_MANAGEMENT_LOCAL_TCF) ? "localTCF" : "transferredTCF");
    
    	x = ast_udptl_get_local_max_datagram(p->udptl);
    
    	ast_str_append(&a_modem, 0, "a=T38FaxMaxBuffer:%d\r\n",x);
    	ast_str_append(&a_modem, 0, "a=T38FaxMaxDatagram:%d\r\n",x);
    
    	if (p->t38.jointcapability != T38FAX_UDP_EC_NONE)
    
    		ast_str_append(&a_modem, 0, "a=T38FaxUdpEC:%s\r\n", (p->t38.jointcapability & T38FAX_UDP_EC_REDUNDANCY) ? "t38UDPRedundancy" : "t38UDPFEC");
    	len = m_modem->used + a_modem->used;
    
    	add_header(resp, "Content-Type", "application/sdp");
    	add_header_contentLength(resp, len);
    
    	add_line(resp, m_modem->str);
    	add_line(resp, a_modem->str);
    
    
    	/* Update lastrtprx when we send our SDP */
    	p->lastrtprx = p->lastrtptx = time(NULL);
    	
    	return 0;
    }
    
    
    
    /*! \brief Add RFC 2833 DTMF offer to SDP */
    
    static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_rate,
    
    				struct ast_str **m_buf, struct ast_str **a_buf,
    
    		ast_verbose("Adding non-codec 0x%x (%s) to SDP\n", format, ast_rtp_lookup_mime_subtype(0, format, 0));
    
    	if ((rtp_code = ast_rtp_lookup_code(p->rtp, 0, format)) == -1)
    		return;
    
    
    	ast_str_append(m_buf, 0, " %d", rtp_code);
    	ast_str_append(a_buf, 0, "a=rtpmap:%d %s/%d\r\n", rtp_code,
    
    			 ast_rtp_lookup_mime_subtype(0, format, 0),
    
    	if (format == AST_RTP_DTMF)	/* Indicate we support DTMF and FLASH... */
    		ast_str_append(a_buf, 0, "a=fmtp:%d 0-16\r\n", rtp_code);
    
    /*! \brief Set all IP media addresses for this call 
    	\note called from add_sdp()
    */
    
    static void get_our_media_address(struct sip_pvt *p, int needvideo,
    	struct sockaddr_in *sin, struct sockaddr_in *vsin, struct sockaddr_in *tsin,
    	struct sockaddr_in *dest, struct sockaddr_in *vdest)
    
    {
    	/* First, get our address */
    	ast_rtp_get_us(p->rtp, sin);
    	if (p->vrtp)
    		ast_rtp_get_us(p->vrtp, vsin);
    
    	if (p->trtp)
    		ast_rtp_get_us(p->trtp, tsin);
    
    
    	/* Now, try to figure out where we want them to send data */
    	/* Is this a re-invite to move the media out, then use the original offer from caller  */
    	if (p->redirip.sin_addr.s_addr) {	/* If we have a redirection IP, use it */
    		dest->sin_port = p->redirip.sin_port;
    		dest->sin_addr = p->redirip.sin_addr;
    	} else {
    
    		dest->sin_addr = p->ourip.sin_addr;
    
    		dest->sin_port = sin->sin_port;
    	}
    	if (needvideo) {
    		/* Determine video destination */
    		if (p->vredirip.sin_addr.s_addr) {
    			vdest->sin_addr = p->vredirip.sin_addr;
    			vdest->sin_port = p->vredirip.sin_port;
    		} else {
    
    			vdest->sin_addr = p->ourip.sin_addr;
    
    #define SDP_SAMPLE_RATE(x) (x == AST_FORMAT_G722) ? 16000 : 8000
    
    
    /*! \brief Add Session Description Protocol message */
    
    static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
    
    	int alreadysent = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sockaddr_in sin;
    
    	struct sockaddr_in tsin;
    
    	struct sockaddr_in dest;
    	struct sockaddr_in vdest = { 0, };
    
    	struct sockaddr_in tdest = { 0, };
    
    
    	/* SDP fields */
    	char *version = 	"v=0\r\n";		/* Protocol version */
    
    	char subject[256];				/* Subject of the session */
    
    	char owner[256];				/* Session owner/creator */
    	char connection[256];				/* Connection data */
    	char *stime = "t=0 0\r\n"; 			/* Time the session is active */
    	char bandwidth[256] = "";			/* Max bitrate */
    
    	struct ast_str *m_audio = ast_str_alloca(256);  /* Media declaration line for audio */
    	struct ast_str *m_video = ast_str_alloca(256);  /* Media declaration line for video */
    	struct ast_str *m_text = ast_str_alloca(256);   /* Media declaration line for text */
    	struct ast_str *a_audio = ast_str_alloca(1024); /* Attributes for audio */
    	struct ast_str *a_video = ast_str_alloca(1024); /* Attributes for video */
    	struct ast_str *a_text = ast_str_alloca(1024);  /* Attributes for text */
    
    	int needtext = FALSE;
    
    	int min_audio_packet_size = 0;
    	int min_video_packet_size = 0;
    
    	int min_text_packet_size = 0;
    
    	char codecbuf[BUFSIZ];
    	char buf[BUFSIZ];
    
    
    	/* Set the SDP session name */
    	snprintf(subject, sizeof(subject), "s=%s\r\n", ast_strlen_zero(global_sdpsession) ? "-" : global_sdpsession);
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!p->rtp) {
    		ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	/* XXX We should not change properties in the SIP dialog until 
    		we have acceptance of the offer if this is a re-invite */
    
    		p->sessionid = (int)ast_random();
    
    		p->sessionversion = p->sessionid;
    	} else
    		p->sessionversion++;
    
    	/* XXX note, Video and Text are negated - 'true' means 'no' */
    
     	ast_debug(1, "** Our capability: %s Video flag: %s Text flag: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), capability), 
    
     		p->novideo ? "True" : "False", p->notext ? "True" : "False");
    
    	ast_debug(1, "** Our prefcodec: %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), p->prefcodec));
    
    #ifdef WHEN_WE_HAVE_T38_FOR_OTHER_TRANSPORTS
    
    	if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_RTP)) {
    
    		ast_str_append(&m_audio, 0, " %d", 191);
    		ast_str_append(&a_audio, 0, "a=rtpmap:%d %s/%d\r\n", 191, "t38", 8000);
    
    	if ((capability & AST_FORMAT_VIDEO_MASK) && !p->novideo) {
    
    			ast_debug(2, "This call needs video offers!\n");
    		} else
    			ast_debug(2, "This call needs video offers, but there's no video support enabled!\n");
    
    	/* Get our media addresses */
    
    	get_our_media_address(p, needvideo, &sin, &vsin, &tsin, &dest, &vdest);
    
    		ast_verbose("Audio is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(sin.sin_port));	
    
    	/* Ok, we need video. Let's add what we need for video and set codecs.
    	   Video is handled differently than audio since we can not transcode. */
    	if (needvideo) {
    
    		ast_str_append(&m_video, 0, "m=video %d RTP/AVP", ntohs(vdest.sin_port));
    
    
    		/* Build max bitrate string */
    		if (p->maxcallbitrate)
    			snprintf(bandwidth, sizeof(bandwidth), "b=CT:%d\r\n", p->maxcallbitrate);
    		if (debug) 
    
    			ast_verbose("Video is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(vsin.sin_port));	
    
    	/* Check if we need text in this call */
    
    	if((capability & AST_FORMAT_TEXT_MASK) && !p->notext) {
    
    		if (sipdebug_text)
    			ast_verbose("We think we can do text\n");
    
    			if (sipdebug_text)
    				ast_verbose("And we have a text rtp object\n");
    
    			ast_debug(2, "This call needs text offers! \n");
    		} else
    			ast_debug(2, "This call needs text offers, but there's no text support enabled ! \n");
    
    	}
    		
    	/* Ok, we need text. Let's add what we need for text and set codecs.
    	   Text is handled differently than audio since we can not transcode. */
    	if (needtext) {
    
    		if (sipdebug_text)
    			ast_verbose("Lets set up the text sdp\n");
    
    		/* Determine text destination */
    		if (p->tredirip.sin_addr.s_addr) {
    			tdest.sin_addr = p->tredirip.sin_addr;
    			tdest.sin_port = p->tredirip.sin_port;
    		} else {
    
    			tdest.sin_addr = p->ourip.sin_addr;
    
    			tdest.sin_port = tsin.sin_port;
    		}
    
    		ast_str_append(&m_text, 0, "m=text %d RTP/AVP", ntohs(tdest.sin_port));
    
    		if (debug) /* XXX should I use tdest below ? */
    			ast_verbose("Text is at %s port %d\n", ast_inet_ntoa(p->ourip.sin_addr), ntohs(tsin.sin_port));	
    
    
    	/* We break with the "recommendation" and send our IP, in order that our
    	   peer doesn't have to ast_gethostbyname() us */
    
    
    	snprintf(owner, sizeof(owner), "o=%s %d %d IN IP4 %s\r\n", ast_strlen_zero(global_sdpowner) ? "-" : global_sdpowner, p->sessionid, p->sessionversion, ast_inet_ntoa(dest.sin_addr));
    
    	snprintf(connection, sizeof(connection), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr));
    
    	ast_str_append(&m_audio, 0, "m=audio %d RTP/AVP", ntohs(dest.sin_port));
    
    	if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_ONEDIR)
    
    		hold = "a=recvonly\r\n";
    
    	else if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_INACTIVE)
    
    		hold = "a=sendrecv\r\n";
    
    	/* Now, start adding audio codecs. These are added in this order:
    		- First what was requested by the calling channel
    		- Then preferences in order from sip.conf device config for this peer/user
    		- Then other codecs in capabilities, including video
    	*/
    
    	/* Prefer the audio codec we were requested to use, first, no matter what 
    		Note that p->prefcodec can include video codecs, so mask them out
    	 */
    
    	if (capability & p->prefcodec) {
    
    		int codec = p->prefcodec & AST_FORMAT_AUDIO_MASK;
    
    		add_codec_to_sdp(p, codec, SDP_SAMPLE_RATE(codec),
    
    				 debug, &min_audio_packet_size);
    
    		alreadysent |= codec;
    
    	/* Start by sending our preferred audio codecs */
    
    		if (!(codec = ast_codec_pref_index(&p->prefs, x)))
    
    		if (!(capability & codec))
    
    		if (alreadysent & codec)
    
    		add_codec_to_sdp(p, codec, SDP_SAMPLE_RATE(codec),
    
    				 debug, &min_audio_packet_size);
    
    		alreadysent |= codec;
    
    	/* Now send any other common audio and video codecs, and non-codec formats: */
    
    	for (x = 1; x <= (needtext ? AST_FORMAT_TEXT_MASK : (needvideo ? AST_FORMAT_VIDEO_MASK : AST_FORMAT_AUDIO_MASK)); x <<= 1) {
    
    		if (!(capability & x))	/* Codec not requested */
    
    		if (alreadysent & x)	/* Already added to SDP */
    
    		if (x & AST_FORMAT_AUDIO_MASK)
    
    			add_codec_to_sdp(p, x, SDP_SAMPLE_RATE(x),
    
    				 &m_audio, &a_audio, debug, &min_audio_packet_size);
    
    		else if (x & AST_FORMAT_VIDEO_MASK) 
    
    			add_vcodec_to_sdp(p, x, 90000,
    
    				 &m_video, &a_video, debug, &min_video_packet_size);
    
    		else if (x & AST_FORMAT_TEXT_MASK)
    
    			add_tcodec_to_sdp(p, x, 1000,
    
    				 &m_text, &a_text, debug, &min_text_packet_size);
    
    	/* Now add DTMF RFC2833 telephony-event as a codec */
    
    	for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
    
    		if (!(p->jointnoncodeccapability & x))
    
    		add_noncodec_to_sdp(p, x, 8000, &m_audio, &a_audio, debug);
    
    	ast_debug(3, "-- Done with adding codecs to SDP\n");
    
    	if (!p->owner || !ast_internal_timing_enabled(p->owner))
    
    		ast_str_append(&a_audio, 0, "a=silenceSupp:off - - - -\r\n");
    
    	if (min_audio_packet_size)
    
    		ast_str_append(&a_audio, 0, "a=ptime:%d\r\n", min_audio_packet_size);
    
     	/* XXX don't think you can have ptime for video */
    
    	if (min_video_packet_size)
    
    		ast_str_append(&a_video, 0, "a=ptime:%d\r\n", min_video_packet_size);
    
     	/* XXX don't think you can have ptime for text */
     	if (min_text_packet_size)
    
     		ast_str_append(&a_text, 0, "a=ptime:%d\r\n", min_text_packet_size);
    
    	if (m_audio->len - m_audio->used < 2 || m_video->len - m_video->used < 2 ||
    			m_text->len - m_text->used < 2 || a_text->len - a_text->used < 2 ||
    			a_audio->len - a_audio->used < 2 || a_video->len - a_video->used < 2)
    
    		ast_log(LOG_WARNING, "SIP SDP may be truncated due to undersized buffer!!\n");
    
    
     	ast_str_append(&m_audio, 0, "\r\n");
    
     		ast_str_append(&m_video, 0, "\r\n");
    
     		ast_str_append(&m_text, 0, "\r\n");
    
     	len = strlen(version) + strlen(subject) + strlen(owner) +
    		strlen(connection) + strlen(stime) + m_audio->used + a_audio->used + strlen(hold);
    
     	if (needvideo) /* only if video response is appropriate */
    
     		len += m_video->used + a_video->used + strlen(bandwidth) + strlen(hold);
    
     	if (needtext) /* only if text response is appropriate */
    
     		len += m_text->used + a_text->used + strlen(hold);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	add_header(resp, "Content-Type", "application/sdp");
    
    	add_header_contentLength(resp, len);
    
    	add_line(resp, version);
    	add_line(resp, owner);
    	add_line(resp, subject);
    	add_line(resp, connection);
    	if (needvideo)	 	/* only if video response is appropriate */
    		add_line(resp, bandwidth);
    	add_line(resp, stime);
    
    	add_line(resp, m_audio->str);
    	add_line(resp, a_audio->str);
    
    	if (needvideo) { /* only if video response is appropriate */
    
    		add_line(resp, m_video->str);
    		add_line(resp, a_video->str);
    
    		add_line(resp, hold);	/* Repeat hold for the video stream */
    
    	if (needtext) { /* only if text response is appropriate */
    
    		add_line(resp, m_text->str);
    		add_line(resp, a_text->str);
    
    		add_line(resp, hold);	/* Repeat hold for the text stream */
    	}
    
    	/* Update lastrtprx when we send our SDP */
    
    	p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */
    
    	ast_debug(3, "Done building SDP. Settling with this capability: %s\n", ast_getformatname_multiple(buf, BUFSIZ, capability));
    
    /*! \brief Used for 200 OK and 183 early media */
    
    static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans)
    {
    	struct sip_request resp;
    	int seqno;
    	
    	if (sscanf(get_header(req, "CSeq"), "%d ", &seqno) != 1) {
    		ast_log(LOG_WARNING, "Unable to get seqno from '%s'\n", get_header(req, "CSeq"));
    		return -1;
    	}
    	respprep(&resp, p, msg, req);
    	if (p->udptl) {
    		ast_udptl_offered_from_local(p->udptl, 0);
    		add_t38_sdp(&resp, p);
    
    		ast_log(LOG_ERROR, "Can't add SDP to response, since we have no UDPTL session allocated. Call-ID %s\n", p->callid);
    
    	if (retrans && !p->pendinginvite)
    		p->pendinginvite = seqno;		/* Buggy clients sends ACK on RINGING too */
    
    	return send_response(p, &resp, retrans, seqno);
    }
    
    
    /*! \brief copy SIP request (mostly used to save request for responses) */
    
    static void copy_request(struct sip_request *dst, const struct sip_request *src)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	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++)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		dst->header[x] += offset;
    
    	for (x=0; x < src->lines; x++)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		dst->line[x] += offset;
    
    	dst->rlPart1 += offset;
    	dst->rlPart2 += offset;
    
    	\return Will return XMIT_ERROR for network errors.
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct sip_request resp;
    
    	int seqno;
    
    	if (sscanf(get_header(req, "CSeq"), "%d ", &seqno) != 1) {
    
    		ast_log(LOG_WARNING, "Unable to get seqno from '%s'\n", get_header(req, "CSeq"));
    		return -1;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	respprep(&resp, p, msg, req);
    
    		if (!p->autoframing && !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
    
    			ast_debug(1, "Setting framing from config on incoming call\n");
    
    			ast_rtp_codec_setpref(p->rtp, &p->prefs);
    		}
    
    		ast_log(LOG_ERROR, "Can't add SDP to response, since we have no RTP session allocated. Call-ID %s\n", p->callid);
    
    	if (reliable && !p->pendinginvite)
    		p->pendinginvite = seqno;		/* Buggy clients sends ACK on RINGING too */
    
    	return send_response(p, &resp, reliable, seqno);
    
    /*! \brief Parse first line of incoming SIP request */
    
    static int determine_firstline_parts(struct sip_request *req) 
    
    	char *e = ast_skip_blanks(req->header[0]);	/* there shouldn't be any */
    
    	if (!*e)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    
    	req->rlPart1 = e;	/* method or protocol */
    	e = ast_skip_nonblanks(e);
    
    	/* Get URI or status code */
    
    	e = ast_skip_blanks(e);
    	if ( !*e )
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    
    	ast_trim_blanks(e);
    
    	if (!strcasecmp(req->rlPart1, "SIP/2.0") ) { /* We have a response */
    		if (strlen(e) < 3)	/* status code is 3 digits */
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return -1;
    
    		req->rlPart2 = e;
    	} else { /* We have a request */
    		if ( *e == '<' ) { /* XXX the spec says it must not be in <> ! */
    
    			ast_debug(3, "Oops. Bogus uri in <> %s\n", e);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			e++;
    
    Mark Spencer's avatar
    Mark Spencer committed
    				return -1; 
    		}
    
    		req->rlPart2 = e;	/* URI */
    
    		e = ast_skip_nonblanks(e);
    		if (*e)
    			*e++ = '\0';
    		e = ast_skip_blanks(e);
    		if (strcasecmp(e, "SIP/2.0") ) {
    
    			ast_debug(3, "Skipping packet - Bad request protocol %s\n", e);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return -1;
    		}
    	}
    	return 1;
    
    /*! \brief Transmit reinvite with SDP
    \note 	A re-invite is basically a new INVITE with the same CALL-ID and TAG as the
    
    	INVITE that opened the SIP dialogue 
    	We reinvite so that the audio stream (RTP) go directly between
    	the SIP UAs. SIP Signalling stays with * in the path.
    
    	
    	If t38version is TRUE, we send T38 SDP for re-invite from audio/video to
    	T38 UDPTL transmission on the channel
    
    static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Olle Johansson's avatar
    Olle Johansson committed
    
    	reqprep(&req, p, ast_test_flag(&p->flags[0], SIP_REINVITE_UPDATE) ?  SIP_UPDATE : SIP_INVITE, 0, 1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	add_header(&req, "Allow", ALLOWED_METHODS);
    
    	add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
    
    		add_header(&req, "X-asterisk-Info", "SIP re-invite (External RTP bridge)");
    
    Olle Johansson's avatar
    Olle Johansson committed
    		append_history(p, "ReInv", "Re-invite sent");
    
    	if (t38version)
    		add_t38_sdp(&req, p);
    	else
    		add_sdp(&req, p);
    
    	/* Use this as the basis */
    	initialize_initreq(p, &req);
    	p->lastinvite = p->ocseq;
    
    	ast_set_flag(&p->flags[0], SIP_OUTGOING);		/* Change direction of this dialog */
    
    	return send_request(p, &req, XMIT_CRITICAL, p->ocseq);
    
    /* \brief Remove URI parameters at end of URI, not in username part though */
    static char *remove_uri_parameters(char *uri)
    {
    	char *atsign;
    	atsign = strchr(uri, '@');	/* First, locate the at sign */
    	if (!atsign)
    		atsign = uri;	/* Ok hostname only, let's stick with the rest */
    	atsign = strchr(atsign, ';');	/* Locate semi colon */
    	if (atsign)
    		*atsign = '\0';	/* Kill at the semi colon */
    	return uri;
    }
    
    
    /*! \brief Check Contact: URI of SIP message */
    
    static void extract_uri(struct sip_pvt *p, struct sip_request *req)
    {
    
    	char stripped[BUFSIZ];
    
    	ast_copy_string(stripped, get_header(req, "Contact"), sizeof(stripped));
    
    	c = get_in_brackets(stripped);
    
    	/* Cut the URI at the at sign after the @, not in the username part */
    
    		ast_string_field_set(p, uri, c);
    
    /*! \brief Build contact header - the contact header we send out */
    
    static void build_contact(struct sip_pvt *p)
    {
    	/* Construct Contact: header */
    
    	if (ntohs(p->ourip.sin_port) != STANDARD_SIP_PORT)
    		ast_string_field_build(p, our_contact, "<sip:%s%s%s:%d>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr), ntohs(p->ourip.sin_port));
    
    		ast_string_field_build(p, our_contact, "<sip:%s%s%s>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(p->ourip.sin_addr));
    
    /*! \brief Build the Remote Party-ID & From using callingpres options */
    
    	int send_pres_tags = TRUE;
    
    	const char *privacy=NULL;
    	const char *screen=NULL;
    
    	char buf[256];
    	const char *clid = default_callerid;
    	const char *clin = NULL;
    	const char *fromdomain;
    
    
    	if (!ast_strlen_zero(p->rpid) || !ast_strlen_zero(p->rpid_from))  
    
    	if (p->owner && p->owner->cid.cid_num)
    		clid = p->owner->cid.cid_num;
    	if (p->owner && p->owner->cid.cid_name)
    		clin = p->owner->cid.cid_name;
    
    		clin = clid;
    
    	switch (p->callingpres) {
    	case AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
    		privacy = "off";
    		screen = "no";
    		break;
    	case AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
    		privacy = "off";
    
    		screen = "yes";
    
    		break;
    	case AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
    		privacy = "off";
    
    		screen = "no";
    
    		break;
    	case AST_PRES_ALLOWED_NETWORK_NUMBER:
    		privacy = "off";
    		screen = "yes";
    		break;
    	case AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
    		privacy = "full";
    		screen = "no";
    		break;
    	case AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
    		privacy = "full";
    
    		screen = "yes";
    
    		break;
    	case AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
    		privacy = "full";
    
    		screen = "no";
    
    		break;
    	case AST_PRES_PROHIB_NETWORK_NUMBER:
    		privacy = "full";
    
    		screen = "yes";
    
    		send_pres_tags = FALSE;
    
    		break;
    	default:
    		ast_log(LOG_WARNING, "Unsupported callingpres (%d)\n", p->callingpres);
    		if ((p->callingpres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED)
    			privacy = "full";
    		else
    			privacy = "off";
    		screen = "no";
    		break;
    	}
    	
    
    	fromdomain = S_OR(p->fromdomain, ast_inet_ntoa(p->ourip.sin_addr));
    
    
    	snprintf(buf, sizeof(buf), "\"%s\" <sip:%s@%s>", clin, clid, fromdomain);
    	if (send_pres_tags)
    		snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ";privacy=%s;screen=%s", privacy, screen);
    
    	ast_string_field_set(p, rpid, buf);
    
    	ast_string_field_build(p, rpid_from, "\"%s\" <sip:%s@%s>;tag=%s", clin,
    
    			       S_OR(p->fromuser, clid),
    
    /*! \brief Initiate new SIP request to peer/user */
    
    static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod)
    
    	struct ast_str *invite = ast_str_alloca(256);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char from[256];
    	char to[256];
    
    	char tmp_n[BUFSIZ/2];	/* build a local copy of 'n' if needed */
    	char tmp_l[BUFSIZ/2];	/* build a local copy of 'l' if needed */
    	const char *l = NULL;	/* XXX what is this, exactly ? */
    	const char *n = NULL;	/* XXX what is this, exactly ? */
    
    	const char *urioptions = "";
    
    	if (ast_test_flag(&p->flags[0], SIP_USEREQPHONE)) {
    
    	 	const char *s = p->username;	/* being a string field, cannot be NULL */
    
    		/* Test p->username against allowed characters in AST_DIGIT_ANY
    
    Olle Johansson's avatar
    Olle Johansson committed
    			If it matches the allowed characters list, then sipuser = ";user=phone"
    			If not, then sipuser = ""
    		*/
    		/* + is allowed in first position in a tel: uri */
    
    		if (*s == '+')
    			s++;
    		for (; *s; s++) {
    			if (!strchr(AST_DIGIT_ANYNUM, *s) )
    
    		/* If we have only digits, add ;user=phone to the uri */
    
    		if (*s)
    			urioptions = ";user=phone";
    
    	snprintf(p->lastmsg, sizeof(p->lastmsg), "Init: %s", sip_methods[sipmethod].text);
    
    	if (p->owner) {
    		l = p->owner->cid.cid_num;
    		n = p->owner->cid.cid_name;
    	}
    
    	/* if we are not sending RPID and user wants his callerid restricted */
    
    	if (!ast_test_flag(&p->flags[0], SIP_SENDRPID) &&
    	    ((p->callingpres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED)) {
    
    	if (ast_strlen_zero(l))
    
    Mark Spencer's avatar
    Mark Spencer committed
    		n = l;
    
    	if (!ast_strlen_zero(p->fromuser))
    
    	else /* Save for any further attempts */
    
    		ast_string_field_set(p, fromuser, l);
    
    
    	/* Allow user to be overridden */
    	if (!ast_strlen_zero(p->fromname))
    		n = p->fromname;
    	else /* Save for any further attempts */
    
    		ast_string_field_set(p, fromname, n);
    
    	if (pedanticsipchecking) {
    
    		ast_uri_encode(n, tmp_n, sizeof(tmp_n), 0);
    		n = tmp_n;
    		ast_uri_encode(l, tmp_l, sizeof(tmp_l), 0);
    		l = tmp_l;
    
    	if (ntohs(p->ourip.sin_port) != STANDARD_SIP_PORT && ast_strlen_zero(p->fromdomain))
    		snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s:%d>;tag=%s", n, l, S_OR(p->fromdomain, ast_inet_ntoa(p->ourip.sin_addr)), ntohs(p->ourip.sin_port), p->tag);
    
    		snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s>;tag=%s", n, l, S_OR(p->fromdomain, ast_inet_ntoa(p->ourip.sin_addr)), p->tag);
    
    	/* If we're calling a registered SIP peer, use the fullcontact to dial to the peer */
    
    	if (!ast_strlen_zero(p->fullcontact)) {
    		/* If we have full contact, trust it */
    
    		ast_str_append(&invite, 0, "%s", p->fullcontact);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	} else {
    
    		/* Otherwise, use the username while waiting for registration */
    
    		ast_str_append(&invite, 0, "sip:");
    
    		if (!ast_strlen_zero(p->username)) {
    			n = p->username;
    			if (pedanticsipchecking) {
    
    				ast_uri_encode(n, tmp_n, sizeof(tmp_n), 0);
    				n = tmp_n;
    
    			ast_str_append(&invite, 0, "%s@", n);
    
    		ast_str_append(&invite, 0, "%s", p->tohost);
    
    		if (ntohs(p->sa.sin_port) != STANDARD_SIP_PORT)
    
    			ast_str_append(&invite, 0, ":%d", ntohs(p->sa.sin_port));
    		ast_str_append(&invite, 0, "%s", urioptions);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	/* If custom URI options have been provided, append them */
    
    	if (p->options && p->options->uri_options)
    
    		ast_str_append(&invite, 0, ";%s", p->options->uri_options);
    
     	/* This is the request URI, which is the next hop of the call
     		which may or may not be the destination of the call
     	*/
    
    	ast_string_field_set(p, uri, invite->str);
    
      
     	if (!ast_strlen_zero(p->todnid)) {
     		/*! \todo Need to add back the VXML URL here at some point, possibly use build_string for all this junk */
     		if (!strchr(p->todnid, '@')) {
     			/* We have no domain in the dnid */
     			snprintf(to, sizeof(to), "<sip:%s@%s>%s%s", p->todnid, p->tohost, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag);
     		} else {
     			snprintf(to, sizeof(to), "<sip:%s>%s%s", p->todnid, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag);
     		}
     	} else {
     		if (sipmethod == SIP_NOTIFY && !ast_strlen_zero(p->theirtag)) { 
     			/* If this is a NOTIFY, use the From: tag in the subscribe (RFC 3265) */
    			snprintf(to, sizeof(to), "<%s%s>;tag=%s", (strncasecmp(p->uri, "sip:", 4) ? "" : "sip:"), p->uri, p->theirtag);
     		} else if (p->options && p->options->vxml_url) {
     			/* If there is a VXML URL append it to the SIP URL */
     			snprintf(to, sizeof(to), "<%s>;%s", p->uri, p->options->vxml_url);
     		} else 
     			snprintf(to, sizeof(to), "<%s>", p->uri);
     	}
    
    	/* now tmp_n is available so reuse it to build the CSeq */
    	snprintf(tmp_n, sizeof(tmp_n), "%d %s", ++p->ocseq, sip_methods[sipmethod].text);
    
    	add_header(req, "Via", p->via);
    
    	add_header(req, "Max-Forwards", DEFAULT_MAX_FORWARDS);
    
    	/* 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 */
    
    	if (ast_test_flag(&p->flags[0], SIP_SENDRPID) && (sipmethod == SIP_INVITE)) {
    
    	ast_string_field_set(p, exten, l);
    
    	build_contact(p);
    
    	add_header(req, "Contact", p->our_contact);
    
    	add_header(req, "Call-ID", p->callid);
    
    	add_header(req, "CSeq", tmp_n);
    
    	if (!ast_strlen_zero(global_useragent))
    		add_header(req, "User-Agent", global_useragent);
    
    	if (!ast_strlen_zero(p->rpid))
    
    		add_header(req, "Remote-Party-ID", p->rpid);
    
    /*! \brief Build REFER/INVITE/OPTIONS message and transmit it 
    	\param init 0 = Prepare request within dialog, 1= prepare request, new branch, 2= prepare new request and new dialog. do_proxy_auth calls this with init!=2
    
     \param p sip_pvt structure
     \param sdp unknown 
     \param sipmethod unknown 
     
    */
    
    static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init)
    
    {
    	struct sip_request req;
    
    	if (init) {/* Bump branch even on initial requests */
    
    	}
    	if (init > 1)
    		initreqprep(&req, p, sipmethod);
    	else
    
    		reqprep(&req, p, sipmethod, 0, 1);
    
    	if (p->options && p->options->auth)
    		add_header(&req, p->options->authheader, p->options->auth);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	append_date(&req);
    
    	if (sipmethod == SIP_REFER) {	/* Call transfer */
    
    		if (p->refer) {
    			char buf[BUFSIZ];
    			if (!ast_strlen_zero(p->refer->refer_to))
    				add_header(&req, "Refer-To", p->refer->refer_to);
    			if (!ast_strlen_zero(p->refer->referred_by)) {
    
    				snprintf(buf, sizeof(buf), "%s <%s>", p->refer->referred_by_name, p->refer->referred_by);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	/* This new INVITE is part of an attended transfer. Make sure that the
    	other end knows and replace the current call with this new call */
    
    	if (p->options && !ast_strlen_zero(p->options->replaces)) {
    
    		add_header(&req, "Replaces", p->options->replaces);
    
    Olle Johansson's avatar
    Olle Johansson committed
    		add_header(&req, "Require", "replaces");
    
    	add_header(&req, "Allow", ALLOWED_METHODS);
    
    	add_header(&req, "Supported", SUPPORTED_EXTENSIONS);
    
    	if (p->options && p->options->addsipheaders && p->owner) {
    
    		struct ast_channel *chan = p->owner; /* The owner channel */
    		struct varshead *headp;
    	
    		ast_channel_lock(chan);
    
    		headp = &chan->varshead;
    
    		if (!headp)
    			ast_log(LOG_WARNING,"No Headp for the channel...ooops!\n");
    		else {
    			const struct ast_var_t *current;
    			AST_LIST_TRAVERSE(headp, current, entries) {  
    				/* SIPADDHEADER: Add SIP header to outgoing call */
    				if (!strncasecmp(ast_var_name(current), "SIPADDHEADER", strlen("SIPADDHEADER"))) {
    					char *content, *end;
    					const char *header = ast_var_value(current);
    					char *headdup = ast_strdupa(header);
    
    					/* Strip of the starting " (if it's there) */
    					if (*headdup == '"')
    				 		headdup++;
    					if ((content = strchr(headdup, ':'))) {
    						*content++ = '\0';
    						content = ast_skip_blanks(content); /* Skip white space */
    						/* Strip the ending " (if it's there) */
    				 		end = content + strlen(content) -1;	
    						if (*end == '"')
    							*end = '\0';
    					
    						add_header(&req, headdup, content);
    						if (sipdebug)
    							ast_debug(1, "Adding SIP Header \"%s\" with content :%s: \n", headdup, content);
    
    
    		ast_channel_unlock(chan);
    
    	if (sdp) {
    		if (p->udptl && p->t38.state == T38_LOCAL_DIRECT) {
    			ast_udptl_offered_from_local(p->udptl, 1);
    
    			ast_debug(1, "T38 is in state %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
    
    		} else if (p->rtp) 
    
    Mark Spencer's avatar
    Mark Spencer committed
    	} else {
    
    		add_header_contentLength(&req, 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	if (!p->initreq.headers)
    		initialize_initreq(p, &req);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	p->lastinvite = p->ocseq;