Skip to content
Snippets Groups Projects
chan_sip.c 455 KiB
Newer Older
  • Learn to ignore specific revisions
  • Luigi Rizzo's avatar
    Luigi Rizzo committed
    			break;
    
    		if (p != r) {
    			*p++ = ',';
    			--rem;
    		}
    		*p++ = '<';
    
    		ast_copy_string(p, route->hop, rem);  p += n;
    
    		*p++ = '>';
    		rem -= (n+2);
    	}
    	*p = '\0';
    	add_header(req, "Route", r);
    }
    
    
    /*! \brief Set destination from SIP URI */
    
    static void set_destination(struct sip_pvt *p, char *uri)
    {
    
    	char *h, *maddr, hostname[256];
    
    	char iabuf[INET_ADDRSTRLEN];
    
    	int port, hn;
    	struct hostent *hp;
    
    	struct ast_hostent ahp;
    
    	int debug=sip_debug_test_pvt(p);
    
    
    	/* 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][;...] */
    
    
    	if (debug)
    
    		ast_verbose("set_destination: Parsing <%s> for address/port to send to\n", uri);
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Find and parse hostname */
    
    	h = strchr(uri, '@');
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (h)
    		++h;
    	else {
    		h = uri;
    		if (strncmp(h, "sip:", 4) == 0)
    			h += 4;
    		else if (strncmp(h, "sips:", 5) == 0)
    			h += 5;
    
    	if (hn > sizeof(hostname)) 
    		hn = sizeof(hostname);
    
    	/* Is "port" present? if not default to DEFAULT_SIP_PORT */
    
    	if (*h == ':') {
    		/* Parse port */
    		++h;
    		port = strtol(h, &h, 10);
    	}
    	else
    
    		port = DEFAULT_SIP_PORT;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Got the hostname:port - but maybe there's a "maddr=" to override address? */
    	maddr = strstr(h, "maddr=");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		maddr += 6;
    
    		if (hn > sizeof(hostname))
    			hn = sizeof(hostname);
    
    		ast_copy_string(hostname, maddr, hn);
    
    	hp = ast_gethostbyname(hostname, &ahp);
    
    	if (hp == NULL)  {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "Can't find address for host '%s'\n", hostname);
    
    		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);
    
    	if (debug)
    
    		ast_verbose("set_destination: set destination to %s, port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), port);
    
    /*! \brief Initialize SIP response, based on SIP request */
    
    Olle Johansson's avatar
    Olle Johansson committed
    static int init_resp(struct sip_request *req, const char *resp, struct sip_request *orig)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	/* Initialize a response */
    	if (req->headers || req->len) {
    		ast_log(LOG_WARNING, "Request already initialized?!?\n");
    		return -1;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	req->header[req->headers] = req->data + req->len;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	snprintf(req->header[req->headers], sizeof(req->data) - req->len, "SIP/2.0 %s\r\n", resp);
    	req->len += strlen(req->header[req->headers]);
    
    	req->headers++;
    
    /*! \brief Initialize SIP request */
    
    static int init_req(struct sip_request *req, int sipmethod, const char *recip)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	/* 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;
    
    	snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %s SIP/2.0\r\n", sip_methods[sipmethod].text, recip);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	req->len += strlen(req->header[req->headers]);
    
    	req->headers++;
    
    	req->method = sipmethod;
    
    /*! \brief Prepare SIP response packet */
    
    Olle Johansson's avatar
    Olle Johansson committed
    static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg, struct sip_request *req)
    
    Mark Spencer's avatar
    Mark Spencer committed
    	memset(resp, 0, sizeof(*resp));
    	init_resp(resp, msg, req);
    
    	copy_via_headers(p, resp, req, "Via");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (msg[0] == '2')
    		copy_all_header(resp, req, "Record-Route");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	copy_header(resp, req, "From");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ot = get_header(req, "To");
    
    	if (!strcasestr(ot, "tag=") && strncmp(msg, "100", 3)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		/* Add the proper tag if we don't have it already.  If they have specified
    		   their tag, use it.  Otherwise, use our own tag */
    
    		if (!ast_strlen_zero(p->theirtag) && ast_test_flag(&p->flags[0], SIP_OUTGOING))
    
    Mark Spencer's avatar
    Mark Spencer committed
    			snprintf(newto, sizeof(newto), "%s;tag=%s", ot, p->theirtag);
    
    		else if (p->tag && !ast_test_flag(&p->flags[0], SIP_OUTGOING))
    
    			snprintf(newto, sizeof(newto), "%s;tag=%s", ot, p->tag);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ot = newto;
    	}
    	add_header(resp, "To", ot);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	copy_header(resp, req, "Call-ID");
    	copy_header(resp, req, "CSeq");
    
    	add_header(resp, "User-Agent", global_useragent);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	add_header(resp, "Allow", ALLOWED_METHODS);
    
    	if (msg[0] == '2' && (p->method == SIP_SUBSCRIBE || p->method == SIP_REGISTER)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		/* For registration responses, we also need expiry and
    
    Mark Spencer's avatar
    Mark Spencer committed
    		   contact info */
    
    Mark Spencer's avatar
    Mark Spencer committed
    		char tmp[256];
    
    Mark Spencer's avatar
    Mark Spencer committed
    		snprintf(tmp, sizeof(tmp), "%d", p->expiry);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		add_header(resp, "Expires", tmp);
    
    		if (p->expiry) {	/* Only add contact if we have an expiry time */
    			char contact[256];
    			snprintf(contact, sizeof(contact), "%s;expires=%d", p->our_contact, p->expiry);
    			add_header(resp, "Contact", contact);	/* Not when we unregister */
    		}
    
    		add_header(resp, "Contact", p->our_contact);
    
    /*! \brief Initialize a SIP request response packet */
    
    static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, int seqno, int newbranch)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct sip_request *orig = &p->initreq;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char tmp[80];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char newto[256];
    
    	int is_strict = FALSE;		/*!< Strict routing flag */
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	memset(req, 0, sizeof(struct sip_request));
    
    	snprintf(p->lastmsg, sizeof(p->lastmsg), "Tx: %s", sip_methods[sipmethod].text);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		p->ocseq++;
    
    
    	/* Check for strict or loose router */
    
    Olle Johansson's avatar
    Olle Johansson committed
    	if (p->route && !ast_strlen_zero(p->route->hop) && strstr(p->route->hop,";lr") == NULL) {
    
    		is_strict = TRUE;
    
    Olle Johansson's avatar
    Olle Johansson committed
    		if (sipdebug)
    			ast_log(LOG_DEBUG, "Strict routing enforced for session %s\n", p->callid);
    	}
    
    	if (sipmethod == SIP_CANCEL) {
    
    		c = p->initreq.rlPart2;	/* Use original URI */
    
    	} else if (sipmethod == SIP_ACK) {
    
    		/* Use URI from Contact: in 200 OK (if INVITE) 
    		(we only have the contacturi on INVITEs) */
    		if (!ast_strlen_zero(p->okcontacturi))
    
    			c = is_strict ? p->route->hop : p->okcontacturi;
     		else
     			c = p->initreq.rlPart2;
    
    	} else if (!ast_strlen_zero(p->okcontacturi)) {
    
    Olle Johansson's avatar
    Olle Johansson committed
    		c = is_strict ? p->route->hop : p->okcontacturi; /* Use for BYE or REINVITE */
    
    		c = p->uri;
    	} else {
    
    		/* We have no URI, use To: or From:  header as URI (depending on direction) */
    
    		ast_copy_string(stripped, get_header(orig, (ast_test_flag(&p->flags[0], SIP_OUTGOING)) ? "To" : "From"),
    
    		c = get_in_brackets(stripped);
    
    		n = strchr(c, ';');
    		if (n)
    			*n = '\0';
    	}	
    
    	init_req(req, sipmethod, c);
    
    	snprintf(tmp, sizeof(tmp), "%d %s", seqno, sip_methods[sipmethod].text);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	add_header(req, "Via", p->via);
    
    	if (p->route) {
    		set_destination(p, p->route->hop);
    
    		add_route(req, is_strict ? p->route->next : p->route);
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	ot = get_header(orig, "To");
    	of = get_header(orig, "From");
    
    	/* 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 (!strcasestr(ot, "tag=") && sipmethod != SIP_CANCEL) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		/* Add the proper tag if we don't have it already.  If they have specified
    		   their tag, use it.  Otherwise, use our own tag */
    
    		if (ast_test_flag(&p->flags[0], SIP_OUTGOING) && !ast_strlen_zero(p->theirtag))
    
    Mark Spencer's avatar
    Mark Spencer committed
    			snprintf(newto, sizeof(newto), "%s;tag=%s", ot, p->theirtag);
    
    		else if (!ast_test_flag(&p->flags[0], SIP_OUTGOING))
    
    			snprintf(newto, sizeof(newto), "%s;tag=%s", ot, p->tag);
    
    		else
    			snprintf(newto, sizeof(newto), "%s", ot);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ot = newto;
    	}
    
    
    	if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		add_header(req, "From", of);
    		add_header(req, "To", ot);
    	} else {
    		add_header(req, "From", ot);
    		add_header(req, "To", of);
    	}
    
    	add_header(req, "Contact", p->our_contact);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	copy_header(req, orig, "Call-ID");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	add_header(req, "CSeq", tmp);
    
    
    	add_header(req, "User-Agent", global_useragent);
    
    	add_header(req, "Max-Forwards", DEFAULT_MAX_FORWARDS);
    
    	if (!ast_strlen_zero(p->rpid))
    
    /*! \brief Base transmit response function */
    
    static int __transmit_response(struct sip_pvt *p, char *msg, struct sip_request *req, enum xmittype reliable)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct sip_request resp;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int seqno = 0;
    
    	if (reliable && (sscanf(get_header(req, "CSeq"), "%d ", &seqno) != 1)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "Unable to determine sequence number from '%s'\n", get_header(req, "CSeq"));
    		return -1;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	respprep(&resp, p, msg, req);
    
    	add_header_contentLength(&resp, 0);
    
    	/* If we are cancelling an incoming invite for some reason, add information
    		about the reason why we are doing this in clear text */
    
    	if (msg[0] != '1' && p->owner && p->owner->hangupcause) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		add_header(&resp, "X-Asterisk-HangupCause", ast_cause2str(p->owner->hangupcause));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	add_blank_header(&resp);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return send_response(p, &resp, reliable, seqno);
    }
    
    
    /*! \brief Transmit response, no retransmits */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int transmit_response(struct sip_pvt *p, char *msg, struct sip_request *req) 
    {
    
    	return __transmit_response(p, msg, req, XMIT_UNRELIABLE);
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    /*! \brief Transmit response, no retransmits */
    
    static int transmit_response_with_unsupported(struct sip_pvt *p, const char *msg, struct sip_request *req, const char *unsupported) 
    
    {
    	struct sip_request resp;
    	respprep(&resp, p, msg, req);
    	append_date(&resp);
    	add_header(&resp, "Unsupported", unsupported);
    
    	return send_response(p, &resp, XMIT_UNRELIABLE, 0);
    
    /*! \brief Transmit response, Make sure you get an ACK
    	This is only used for responses to INVITEs, where we need to make sure we get an ACK
    */
    static int transmit_response_reliable(struct sip_pvt *p, char *msg, struct sip_request *req)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	return __transmit_response(p, msg, req, XMIT_CRITICAL);
    
    /*! \brief Append date to SIP message */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static void append_date(struct sip_request *req)
    {
    	char tmpdat[256];
    	struct tm tm;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	gmtime_r(&t, &tm);
    	strftime(tmpdat, sizeof(tmpdat), "%a, %d %b %Y %T GMT", &tm);
    	add_header(req, "Date", tmpdat);
    }
    
    
    /*! \brief Append date and content length before transmitting response */
    
    Mark Spencer's avatar
    Mark Spencer committed
    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_contentLength(&resp, 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	add_blank_header(&resp);
    
    	return send_response(p, &resp, XMIT_UNRELIABLE, 0);
    
    /*! \brief Append Accept header, content length before transmitting response */
    
    static int transmit_response_with_allow(struct sip_pvt *p, char *msg, struct sip_request *req, enum xmittype reliable)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct sip_request resp;
    	respprep(&resp, p, msg, req);
    	add_header(&resp, "Accept", "application/sdp");
    
    	add_header_contentLength(&resp, 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	add_blank_header(&resp);
    
    	return send_response(p, &resp, reliable, 0);
    
    /*! \brief Respond with authorization request */
    
    static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, struct sip_request *req, const char *randdata, enum xmittype reliable, const char *header, int stale)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct sip_request resp;
    	char tmp[256];
    
    	int seqno = 0;
    
    	if (reliable && (sscanf(get_header(req, "CSeq"), "%d ", &seqno) != 1)) {
    
    		ast_log(LOG_WARNING, "Unable to determine sequence number from '%s'\n", get_header(req, "CSeq"));
    		return -1;
    	}
    
    	/* Stale means that they sent us correct authentication, but 
    	   based it on an old challenge (nonce) */
    
    	snprintf(tmp, sizeof(tmp), "Digest realm=\"%s\", nonce=\"%s\"%s", global_realm, randdata, stale ? ", stale=true" : "");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	respprep(&resp, p, msg, req);
    
    	add_header_contentLength(&resp, 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	add_blank_header(&resp);
    
    	return send_response(p, &resp, reliable, seqno);
    
    /*! \brief Add text body to SIP message */
    
    static int add_text(struct sip_request *req, const char *text)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	/* XXX Convert \n's to \r\n's XXX */
    	add_header(req, "Content-Type", "text/plain");
    
    	add_header_contentLength(req, strlen(text));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	add_line(req, text);
    	return 0;
    }
    
    
    /*! \brief Add DTMF INFO tone to sip message */
    
    /* Always adds default duration 250 ms, regardless of what came in over the line */
    
    static int add_digit(struct sip_request *req, char digit)
    {
    	char tmp[256];
    
    	snprintf(tmp, sizeof(tmp), "Signal=%c\r\nDuration=250\r\n", digit);
    	add_header(req, "Content-Type", "application/dtmf-relay");
    
    	add_header_contentLength(req, strlen(tmp));
    
    	add_line(req, tmp);
    	return 0;
    }
    
    
    /*! \brief add XML encoded media control with update */
    /*! \note XML: The only way to turn 0 bits of information into a few hundred. */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int add_vidupdate(struct sip_request *req)
    {
    	const char *xml_is_a_huge_waste_of_space =
    		"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n"
    		" <media_control>\r\n"
    		"  <vc_primitive>\r\n"
    		"   <to_encoder>\r\n"
    
    Mark Spencer's avatar
    Mark Spencer committed
    		"    </picture_fast_update>\r\n"
    		"   </to_encoder>\r\n"
    		"  </vc_primitive>\r\n"
    		" </media_control>\r\n";
    	add_header(req, "Content-Type", "application/media_control+xml");
    	add_header_contentLength(req, strlen(xml_is_a_huge_waste_of_space));
    	add_line(req, xml_is_a_huge_waste_of_space);
    	return 0;
    }
    
    
    static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate,
    			     char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
    			     int debug)
    {
    	int rtp_code;
    
    	if (debug)
    		ast_verbose("Adding codec 0x%x (%s) to SDP\n", codec, ast_getformatname(codec));
    	if ((rtp_code = ast_rtp_lookup_code(p->rtp, 1, codec)) == -1)
    		return;
    
    	ast_build_string(m_buf, m_size, " %d", rtp_code);
    	ast_build_string(a_buf, a_size, "a=rtpmap:%d %s/%d\r\n", rtp_code,
    			 ast_rtp_lookup_mime_subtype(1, codec),
    			 sample_rate);
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    	if (codec == AST_FORMAT_G729A)
    		/* Indicate that we don't support VAD (G.729 annex B) */
    
    		ast_build_string(a_buf, a_size, "a=fmtp:%d annexb=no\r\n", rtp_code);
    
    }
    
    static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_rate,
    				char **m_buf, size_t *m_size, char **a_buf, size_t *a_size,
    				int debug)
    {
    	int rtp_code;
    
    	if (debug)
    		ast_verbose("Adding non-codec 0x%x (%s) to SDP\n", format, ast_rtp_lookup_mime_subtype(0, format));
    	if ((rtp_code = ast_rtp_lookup_code(p->rtp, 0, format)) == -1)
    		return;
    
    	ast_build_string(m_buf, m_size, " %d", rtp_code);
    	ast_build_string(a_buf, a_size, "a=rtpmap:%d %s/%d\r\n", rtp_code,
    			 ast_rtp_lookup_mime_subtype(0, format),
    			 sample_rate);
    	if (format == AST_RTP_DTMF)
    		/* Indicate we support DTMF and FLASH... */
    		ast_build_string(a_buf, a_size, "a=fmtp:%d 0-16\r\n", rtp_code);
    }
    
    
    /*! \brief Add Session Description Protocol message */
    
    static int add_sdp(struct sip_request *resp, struct sip_pvt *p)
    
    	int alreadysent = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sockaddr_in sin;
    
    	char v[256];
    	char s[256];
    	char o[256];
    	char c[256];
    	char t[256];
    
    Olle Johansson's avatar
    Olle Johansson committed
    	char b[256];
    
    	char m_audio[256];
    	char m_video[256];
    	char a_audio[1024];
    	char a_video[1024];
    	char *m_audio_next = m_audio;
    	char *m_video_next = m_video;
    	size_t m_audio_left = sizeof(m_audio);
    	size_t m_video_left = sizeof(m_video);
    	char *a_audio_next = a_audio;
    	char *a_video_next = a_video;
    	size_t a_audio_left = sizeof(a_audio);
    	size_t a_video_left = sizeof(a_video);
    
    	char iabuf[INET_ADDRSTRLEN];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sockaddr_in dest;
    
    	
    	debug = sip_debug_test_pvt(p);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	len = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!p->rtp) {
    		ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n");
    		return -1;
    	}
    
    	capability = p->jointcapability;
    
    	if (!p->sessionid) {
    		p->sessionid = getpid();
    		p->sessionversion = p->sessionid;
    	} else
    		p->sessionversion++;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_rtp_get_us(p->rtp, &sin);
    
    	if (p->vrtp)
    		ast_rtp_get_us(p->vrtp, &vsin);
    
    
    	if (p->redirip.sin_addr.s_addr) {
    		dest.sin_port = p->redirip.sin_port;
    		dest.sin_addr = p->redirip.sin_addr;
    
    		if (p->redircodecs)
    			capability = p->redircodecs;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	} else {
    		dest.sin_addr = p->ourip;
    		dest.sin_port = sin.sin_port;
    	}
    
    
    	/* 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;
    		}
    	}
    
    		ast_verbose("We're at %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ntohs(sin.sin_port));	
    
    		if (p->vrtp)
    
    			ast_verbose("Video is at %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ntohs(vsin.sin_port));	
    
    
    	/* We break with the "recommendation" and send our IP, in order that our
    	   peer doesn't have to ast_gethostbyname() us */
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    	snprintf(v, sizeof(v), "v=0\r\n");
    
    	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));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	snprintf(s, sizeof(s), "s=session\r\n");
    
    	snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", ast_inet_ntoa(iabuf, sizeof(iabuf), dest.sin_addr));
    
    	if ((p->vrtp) &&
    	    (!ast_test_flag(&p->flags[0], SIP_NOVIDEO)) &&
    	    (capability & VIDEO_CODEC_MASK)) /* only if video response is appropriate */
    
    Olle Johansson's avatar
    Olle Johansson committed
    		snprintf(b, sizeof(b), "b=CT:%d\r\n", p->maxcallbitrate);	
    
    Mark Spencer's avatar
    Mark Spencer committed
    	snprintf(t, sizeof(t), "t=0 0\r\n");
    
    
    	ast_build_string(&m_audio_next, &m_audio_left, "m=audio %d RTP/AVP", ntohs(dest.sin_port));
    	ast_build_string(&m_video_next, &m_video_left, "m=video %d RTP/AVP", ntohs(vdest.sin_port));
    
    
    	/* Prefer the codec we were requested to use, first, no matter what */
    
    	if (capability & p->prefcodec) {
    
    		if (p->prefcodec <= AST_FORMAT_MAX_AUDIO)
    			add_codec_to_sdp(p, p->prefcodec, 8000,
    					 &m_audio_next, &m_audio_left,
    					 &a_audio_next, &a_audio_left,
    					 debug);
    		else
    			add_codec_to_sdp(p, p->prefcodec, 90000,
    					 &m_video_next, &m_video_left,
    					 &a_video_next, &a_video_left,
    					 debug);
    
    		alreadysent |= p->prefcodec;
    	}
    
    	/* Start by sending our preferred codecs */
    
    	for (x = 0; x < 32; x++) {
    		if (!(pref_codec = ast_codec_pref_index(&p->prefs, x)))
    
    
    		if (!(capability & pref_codec))
    			continue;
    
    		if (alreadysent & pref_codec)
    			continue;
    
    		if (pref_codec <= AST_FORMAT_MAX_AUDIO)
    			add_codec_to_sdp(p, pref_codec, 8000,
    					 &m_audio_next, &m_audio_left,
    					 &a_audio_next, &a_audio_left,
    					 debug);
    		else
    			add_codec_to_sdp(p, pref_codec, 90000,
    					 &m_video_next, &m_video_left,
    					 &a_video_next, &a_video_left,
    					 debug);
    
    		alreadysent |= pref_codec;
    
    	/* Now send any other common codecs, and non-codec formats: */
    
    	for (x = 1;
    	     x <= ((ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && p->vrtp) ? AST_FORMAT_MAX_VIDEO : AST_FORMAT_MAX_AUDIO);
    	     x <<= 1) {
    
    		if (!(capability & x))
    			continue;
    
    		if (alreadysent & x)
    			continue;
    
    		if (x <= AST_FORMAT_MAX_AUDIO)
    			add_codec_to_sdp(p, x, 8000,
    					 &m_audio_next, &m_audio_left,
    					 &a_audio_next, &a_audio_left,
    					 debug);
    		else
    			add_codec_to_sdp(p, x, 90000,
    					 &m_video_next, &m_video_left,
    					 &a_video_next, &a_video_left,
    					 debug);
    
    	for (x = 1; x <= AST_RTP_MAX; x <<= 1) {
    
    		if (!(p->noncodeccapability & x))
    			continue;
    
    		add_noncodec_to_sdp(p, x, 8000,
    				    &m_audio_next, &m_audio_left,
    				    &a_audio_next, &a_audio_left,
    				    debug);
    
    	if(!ast_internal_timing_enabled(p->owner))
    		ast_build_string(&a_audio_next, &a_audio_left, "a=silenceSupp:off - - - -\r\n");
    
    
    	if ((m_audio_left < 2) || (m_video_left < 2) || (a_audio_left == 0) || (a_video_left == 0))
    
    		ast_log(LOG_WARNING, "SIP SDP may be truncated due to undersized buffer!!\n");
    
    
    	ast_build_string(&m_audio_next, &m_audio_left, "\r\n");
    	ast_build_string(&m_video_next, &m_video_left, "\r\n");
    
    	len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m_audio) + strlen(a_audio);
    
    	if ((p->vrtp) &&
    	    (!ast_test_flag(&p->flags[0], SIP_NOVIDEO)) &&
    	    (capability & VIDEO_CODEC_MASK)) /* only if video response is appropriate */
    
    Olle Johansson's avatar
    Olle Johansson committed
    		len += strlen(m_video) + strlen(a_video) + strlen(b);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	add_header(resp, "Content-Type", "application/sdp");
    
    	add_header_contentLength(resp, len);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	add_line(resp, v);
    	add_line(resp, o);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	add_line(resp, s);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	add_line(resp, c);
    
    	if ((p->vrtp) &&
    	    (!ast_test_flag(&p->flags[0], SIP_NOVIDEO)) &&
    	    (capability & VIDEO_CODEC_MASK)) /* only if video response is appropriate */
    
    Olle Johansson's avatar
    Olle Johansson committed
    		add_line(resp, b);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	add_line(resp, t);
    
    	add_line(resp, m_audio);
    	add_line(resp, a_audio);
    
    	if ((p->vrtp) &&
    	    (!ast_test_flag(&p->flags[0], SIP_NOVIDEO)) &&
    	    (capability & VIDEO_CODEC_MASK)) { /* only if video response is appropriate */
    
    		add_line(resp, m_video);
    		add_line(resp, a_video);
    
    	/* Update lastrtprx when we send our SDP */
    	time(&p->lastrtprx);
    
    	time(&p->lastrtptx);
    
    /*! \brief copy SIP request (mostly used to save request for responses) */
    
    static void copy_request(struct sip_request *dst, 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;
    }
    
    
    /*! \brief Used for 200 OK and 183 early media */
    
    static int transmit_response_with_sdp(struct sip_pvt *p, char *msg, 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);
    
    		ast_log(LOG_ERROR, "Can't add SDP to response, since we have no RTP session allocated. Call-ID %s\n", p->callid);
    	}
    
    	return send_response(p, &resp, reliable, seqno);
    
    /*! \brief Parse first line of incoming SIP request */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int determine_firstline_parts( struct sip_request *req ) 
    {
    	char *e, *cmd;
    	int len;
    
    	cmd = ast_skip_blanks(req->header[0]);
    	if (!*cmd)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	req->rlPart1 = cmd;
    
    	e = ast_skip_nonblanks(cmd);
    	/* Get the command */
    	if (*e)
    		*e++ = '\0';
    	e = ast_skip_blanks(e);
    	if ( !*e )
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if ( !strcasecmp(cmd, "SIP/2.0") ) {
    		/* We have a response */
    
    		req->rlPart2 = e;
    		len = strlen( req->rlPart2 );
    
    		if ( len < 2 ) { 
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return -1;
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	} else {
    		/* We have a request */
    
    		if ( *e == '<' ) { 
    
    Mark Spencer's avatar
    Mark Spencer committed
    			e++;
    
    			if ( !*e ) { 
    
    Mark Spencer's avatar
    Mark Spencer committed
    				return -1; 
    			}  
    		}
    
    		req->rlPart2 = e;	/* URI */
    
    		if ( ( e= strrchr( req->rlPart2, 'S' ) ) == NULL ) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return -1;
    		}
    
    		/* XXX maybe trim_blanks() ? */
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    		while( isspace( *(--e) ) )
    			;
    
    		if ( *e == '>' ) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		} else {
    			*(++e)= '\0';
    		}
    	}
    	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.
    */
    
    static int transmit_reinvite_with_sdp(struct sip_pvt *p)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	if (ast_test_flag(&p->flags[0], SIP_REINVITE_UPDATE))
    
    		reqprep(&req, p, SIP_UPDATE, 0, 1);
    
    		reqprep(&req, p, SIP_INVITE, 0, 1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	add_header(&req, "Allow", ALLOWED_METHODS);
    
    		add_header(&req, "X-asterisk-info", "SIP re-invite (RTP bridge)");
    
    	if (recordhistory)
    		append_history(p, "%s", "Re-invite sent");
    
    	/* Use this as the basis */
    	copy_request(&p->initreq, &req);
    
    	if (sip_debug_test_pvt(p))
    		ast_verbose("%d headers, %d lines\n", p->initreq.headers, p->initreq.lines);
    
    	ast_set_flag(&p->flags[0], SIP_OUTGOING);
    
    	return send_request(p, &req, 1, p->ocseq);
    
    /*! \brief Check Contact: URI of SIP message */
    
    static void extract_uri(struct sip_pvt *p, struct sip_request *req)
    {
    
    	char *c, *n;
    
    	ast_copy_string(stripped, get_header(req, "Contact"), sizeof(stripped));
    
    	c = get_in_brackets(stripped);
    
    	n = strchr(c, ';');
    	if (n)
    		*n = '\0';
    
    		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)
    {
    
    	char iabuf[INET_ADDRSTRLEN];
    
    	/* Construct Contact: header */
    
    	if (ourport != 5060)	/* Needs to be 5060, according to the RFC */
    
    		ast_string_field_build(p, our_contact, "<sip:%s%s%s:%d>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport);
    
    		ast_string_field_build(p, our_contact, "<sip:%s%s%s>", p->exten, ast_strlen_zero(p->exten) ? "" : "@", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip));
    
    /*! \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;
    	char iabuf[INET_ADDRSTRLEN];
    	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 = "pass";
    		break;
    	case AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
    		privacy = "off";
    		screen = "fail";
    		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 = "pass";
    		break;
    	case AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
    		privacy = "full";
    		screen = "fail";
    		break;
    	case AST_PRES_PROHIB_NETWORK_NUMBER:
    		privacy = "full";
    
    		screen = "pass";
    
    		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(iabuf, sizeof(iabuf), p->ourip));
    
    
    	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)
    
    	char invite_buf[256] = "";
    	char *invite = invite_buf;
    	size_t invite_max = sizeof(invite_buf);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char from[256];
    	char to[256];
    
    	char tmp[BUFSIZ/2];
    	char tmp2[BUFSIZ/2];
    
    	char iabuf[INET_ADDRSTRLEN];
    
    	const char *l = NULL, *n = NULL;
    
    	int x;
    	char urioptions[256]="";
    
    
    	if (ast_test_flag(&p->flags[0], SIP_USEREQPHONE)) {
    
    	 	char onlydigits = TRUE;
    
    		/* 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 (p->username && p->username[0] == '+')
    
    		for (; x < strlen(p->username); x++) {
    
    			if (!strchr(AST_DIGIT_ANYNUM, p->username[x])) {
    
                    		onlydigits = FALSE;
    
    		/* If we have only digits, add ;user=phone to the uri */
    		if (onlydigits)
    			strcpy(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)) {
    
    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, sizeof(tmp), 0);
    		n = tmp;
    		ast_uri_encode(l, tmp2, sizeof(tmp2), 0);
    		l = tmp2;
    	}
    
    
    	if ((ourport != 5060) && ast_strlen_zero(p->fromdomain))	/* Needs to be 5060 */
    
    		snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s:%d>;tag=%s", n, l, S_OR(p->fromdomain, ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip)), ourport, p->tag);
    
    		snprintf(from, sizeof(from), "\"%s\" <sip:%s@%s>;tag=%s", n, l, S_OR(p->fromdomain, ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip)), 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_build_string(&invite, &invite_max, "%s", p->fullcontact);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	} else {
    
    		/* Otherwise, use the username while waiting for registration */
    		ast_build_string(&invite, &invite_max, "sip:");
    		if (!ast_strlen_zero(p->username)) {
    			n = p->username;
    			if (pedanticsipchecking) {
    				ast_uri_encode(n, tmp, sizeof(tmp), 0);
    				n = tmp;
    			}
    			ast_build_string(&invite, &invite_max, "%s@", n);
    		}
    		ast_build_string(&invite, &invite_max, "%s", p->tohost);
    		if (ntohs(p->sa.sin_port) != 5060)		/* Needs to be 5060 */
    			ast_build_string(&invite, &invite_max, ":%d", ntohs(p->sa.sin_port));
    		ast_build_string(&invite, &invite_max, "%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_build_string(&invite, &invite_max, ";%s", p->options->uri_options);
    
    	
    	ast_string_field_set(p, uri, invite_buf);
    
    	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), "<sip:%s>;tag=%s", 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);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	memset(req, 0, sizeof(struct sip_request));
    
    	init_req(req, sipmethod, p->uri);
    
    	snprintf(tmp, sizeof(tmp), "%d %s", ++p->ocseq, sip_methods[sipmethod].text);
    
    	add_header(req, "Via", p->via);
    
    	/* 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)) {