Skip to content
Snippets Groups Projects
chan_sip.c 482 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	 * specified RTP payload type (with corresponding MIME subtype):
    	 */
    
    	while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
    
    		char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
    		if (!strcasecmp(a, "sendonly")) {
    			sendonly=1;
    			continue;
    		}
    		if (!strcasecmp(a, "sendrecv")) {
    		  	sendonly=0;
    		}
    		if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2) continue;
    		if (debug)
    			ast_verbose("Found description format %s\n", mimeSubtype);
    		/* Note: should really look at the 'freq' and '#chans' params too */
    		ast_rtp_set_rtpmap_type(p->rtp, codec, "audio", mimeSubtype);
    		if (p->vrtp)
    			ast_rtp_set_rtpmap_type(p->vrtp, codec, "video", mimeSubtype);
    
    	/* Now gather all of the codecs that were asked for: */
    
    	ast_rtp_get_current_formats(p->rtp,
    
    Mark Spencer's avatar
    Mark Spencer committed
    				&peercapability, &peernoncodeccapability);
    
    	if (p->vrtp)
    		ast_rtp_get_current_formats(p->vrtp,
    
    				&vpeercapability, &vpeernoncodeccapability);
    
    	p->jointcapability = p->capability & (peercapability | vpeercapability);
    
    	p->peercapability = (peercapability | vpeercapability);
    
    	p->noncodeccapability = noncodeccapability & peernoncodeccapability;
    
    	if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO) {
    		ast_clear_flag(&p->flags[0], SIP_DTMF);
    
    		if (p->noncodeccapability & AST_RTP_DTMF) {
    			/* XXX Would it be reasonable to drop the DSP at this point? XXX */
    
    			ast_set_flag(&p->flags[0], SIP_DTMF_RFC2833);
    
    			ast_set_flag(&p->flags[0], SIP_DTMF_INBAND);
    
    	if (debug) {
    
    		/* shame on whoever coded this.... */
    		const unsigned slen=512;
    
    		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_rtp_lookup_mime_multiple(s1, slen, noncodeccapability, 0),
    			ast_rtp_lookup_mime_multiple(s2, slen, peernoncodeccapability, 0),
    			ast_rtp_lookup_mime_multiple(s3, slen, p->noncodeccapability, 0));
    
    		ast_log(LOG_NOTICE, "No compatible codecs!\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    
    
    	if (!p->owner) 	/* There's no open channel owning us */
    		return 0;
    
    
    	if (!(p->owner->nativeformats & p->jointcapability & AST_FORMAT_AUDIO_MASK)) {
    
    		const unsigned slen=512;
    		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));
    
    		p->owner->nativeformats = ast_codec_choose(&p->prefs, p->jointcapability, 1) | (p->capability & vpeercapability);
    
    		ast_set_read_format(p->owner, p->owner->readformat);
    		ast_set_write_format(p->owner, p->owner->writeformat);
    	}
    	if ((bridgepeer=ast_bridged_channel(p->owner))) {
    		/* We have a bridge */
    		/* Turn on/off music on hold if we are holding/unholding */
    		if (sin.sin_addr.s_addr && !sendonly) {
    			ast_moh_stop(bridgepeer);
    
    			ast_queue_frame(p->owner, &ast_null_frame);
    
    		} else {
    			/* No address for RTP, we're on hold */
    
    			ast_moh_start(bridgepeer, NULL);
    			if (sendonly)
    				ast_rtp_stop(p->rtp);
    
    			ast_queue_frame(p->owner, &ast_null_frame);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    
    	/* Manager Hold and Unhold events must be generated, if necessary */
    
    Olle Johansson's avatar
    Olle Johansson committed
    	if (sin.sin_addr.s_addr && !sendonly) {
    		append_history(p, "Unhold", "%s", req->data);
    
    		if (global_callevents && ast_test_flag(&p->flags[0], SIP_CALL_ONHOLD)) {
    
    			manager_event(EVENT_FLAG_CALL, "Unhold",
    				"Channel: %s\r\n"
    				"Uniqueid: %s\r\n",
    				p->owner->name, 
    				p->owner->uniqueid);
    
    
    Olle Johansson's avatar
    Olle Johansson committed
    		}
    
    		ast_clear_flag(&p->flags[0], SIP_CALL_ONHOLD);
    
    Olle Johansson's avatar
    Olle Johansson committed
    	} else {
    
    Olle Johansson's avatar
    Olle Johansson committed
    		append_history(p, "Hold", "%s", req->data);
    
    		if (global_callevents && !ast_test_flag(&p->flags[0], SIP_CALL_ONHOLD)) {
    
    Olle Johansson's avatar
    Olle Johansson committed
    				"Uniqueid: %s\r\n",
    
    		ast_set_flag(&p->flags[0], SIP_CALL_ONHOLD);
    
    /*! \brief Add header to SIP message */
    
    static int add_header(struct sip_request *req, const char *var, const char *value)
    
    	int maxlen = sizeof(req->data) - 4 - req->len; /* 4 bytes are for two \r\n ? */
    
    
    	if (req->headers == SIP_MAX_HEADERS) {
    		ast_log(LOG_WARNING, "Out of SIP header space\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (req->lines) {
    		ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n");
    		return -1;
    	}
    
    	if (maxlen <= 0) {
    
    		ast_log(LOG_WARNING, "Out of space, can't add anymore (%s:%s)\n", var, value);
    		return -1;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	req->header[req->headers] = req->data + req->len;
    
    	if (compactheaders)
    		var = find_alias(var, var);
    
    	snprintf(req->header[req->headers], maxlen, "%s: %s\r\n", var, value);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	req->len += strlen(req->header[req->headers]);
    
    	req->headers++;
    
    /*! \brief Add 'Content-Length' header to SIP message */
    
    static int add_header_contentLength(struct sip_request *req, int len)
    {
    	char clen[10];
    
    	snprintf(clen, sizeof(clen), "%d", len);
    	return add_header(req, "Content-Length", clen);
    }
    
    
    /*! \brief Add content (not header) to SIP message */
    
    static int add_line(struct sip_request *req, const char *line)
    
    	if (req->lines == SIP_MAX_LINES)  {
    		ast_log(LOG_WARNING, "Out of SIP line space\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!req->lines) {
    		/* Add extra empty return */
    
    Mark Spencer's avatar
    Mark Spencer committed
    		snprintf(req->data + req->len, sizeof(req->data) - req->len, "\r\n");
    		req->len += strlen(req->data + req->len);
    
    	if (req->len >= sizeof(req->data) - 4) {
    		ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
    		return -1;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	req->line[req->lines] = req->data + req->len;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	snprintf(req->line[req->lines], sizeof(req->data) - req->len, "%s", line);
    	req->len += strlen(req->line[req->lines]);
    
    	req->lines++;
    
    /*! \brief Copy one header field from one request to another */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int copy_header(struct sip_request *req, struct sip_request *orig, char *field)
    {
    
    	const char *tmp = get_header(orig, field);
    
    	if (!ast_strlen_zero(tmp)) /* Add what we're responding to */
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return add_header(req, field, tmp);
    	ast_log(LOG_NOTICE, "No field '%s' present to copy\n", field);
    	return -1;
    }
    
    
    /*! \brief Copy all headers from one request to another */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int copy_all_header(struct sip_request *req, struct sip_request *orig, char *field)
    {
    	int start = 0;
    	int copied = 0;
    	for (;;) {
    
    		const char *tmp = __get_header(orig, field, &start);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			break;
    
    		/* Add what we're responding to */
    		add_header(req, field, tmp);
    		copied++;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	return copied ? 0 : -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    /*! \brief Copy SIP VIA Headers from the request to the response
    \note	If the client indicates that it wishes to know the port we received from,
    
    	it adds ;rport without an argument to the topmost via header. We need to
    	add the port number (from our point of view) to that parameter.
    	We always add ;received=<ip address> to the topmost via header.
    	Received: RFC 3261, rport RFC 3581 */
    
    static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, struct sip_request *orig, char *field)
    {
    	int copied = 0;
    
    	for (;;) {
    
    		const char *oh = __get_header(orig, field, &start);
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    		if (!copied) {	/* Only check for empty rport in topmost via header */
    			char iabuf[INET_ADDRSTRLEN];
    			char *rport;
    
    			/* Find ;rport;  (empty request) */
    			rport = strstr(oh, ";rport");
    			if (rport && *(rport+6) == '=') 
    				rport = NULL;		/* We already have a parameter to rport */
    
    			if (rport && ast_test_flag(&p->flags[0], SIP_NAT) == SIP_NAT_ALWAYS) {
    				/* We need to add received port - rport */
    				char tmp[256], *end;
    
    				ast_copy_string(tmp, oh, sizeof(tmp));
    
    				rport = strstr(tmp, ";rport");
    
    				if (rport) {
    					end = strchr(rport + 1, ';');
    					if (end)
    						memmove(rport, end, strlen(end) + 1);
    					else
    						*rport = '\0';
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    
    				/* Add rport to first VIA header if requested */
    				/* Whoo hoo!  Now we can indicate port address translation too!  Just
    				   another RFC (RFC3581). I'll leave the original comments in for
    				   posterity.  */
    				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));
    			} else {
    				/* We should *always* add a received to the topmost via */
    				snprintf(new, sizeof(new), "%s;received=%s",
    					oh, ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr));
    			}
    			oh = new;	/* the header to copy */
    		}  /* else add the following via headers untouched */
    		add_header(req, field, oh);
    		copied++;
    
    	}
    	if (!copied) {
    
    		ast_log(LOG_NOTICE, "No header field '%s' present to copy\n", field);
    
    		return -1;
    	}
    	return 0;
    }
    
    /*! \brief Add route header into request per learned route */
    
    static void add_route(struct sip_request *req, struct sip_route *route)
    {
    	char r[256], *p;
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	if (!route)
    		return;
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	for (;route ; route = route->next) {
    
    		n = strlen(route->hop);
    
    		if (rem < n+3) /* we need room for ",<route>" */
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    			break;
    
    		if (p != r) {	/* add a separator after fist route */
    
    			*p++ = ',';
    			--rem;
    		}
    		*p++ = '<';
    
    		ast_copy_string(p, route->hop, rem); /* cannot fail */
    		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);
    
    	/* XXX bug here if string has been trimmed to 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 */
    
    static int init_resp(struct sip_request *resp, const char *msg)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	/* Initialize a response */
    
    	memset(resp, 0, sizeof(*resp));
    	resp->method = SIP_RESPONSE;
    	resp->header[0] = resp->data;
    	snprintf(resp->header[0], sizeof(resp->data), "SIP/2.0 %s\r\n", msg);
    	resp->len = strlen(resp->header[0]);
    	resp->headers++;
    
    /*! \brief Initialize SIP request */
    
    static int init_req(struct sip_request *req, int sipmethod, const char *recip)
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	/* Initialize a request */
    	memset(req, 0, sizeof(*req));
            req->method = sipmethod;
    	req->header[0] = req->data;
    	snprintf(req->header[0], sizeof(req->data), "%s %s SIP/2.0\r\n", sip_methods[sipmethod].text, recip);
    	req->len = strlen(req->header[0]);
    
    	req->headers++;
    
    /*! \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)
    
    	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);
    
    Olle Johansson's avatar
    Olle Johansson committed
    	add_header(resp, "Supported", SUPPORTED_EXTENSIONS);
    
    	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, const 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 */
    
    Olle Johansson's avatar
    Olle Johansson committed
    	if (p->method == SIP_INVITE && msg[0] != '1' && p->owner && p->owner->hangupcause) {
    		char buf[10];
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    		add_header(&resp, "X-Asterisk-HangupCause", ast_cause2str(p->owner->hangupcause));
    
    Olle Johansson's avatar
    Olle Johansson committed
    		snprintf(buf, sizeof(buf), "%d", p->owner->hangupcause);
    		add_header(&resp, "X-Asterisk-HangupCauseCode", buf);
    
    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, const 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);
    
    	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);
    
    	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);
    
    	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));
    
    
    	if (ast_test_flag(&p->flags[0], SIP_CALL_ONHOLD))
    
    	/* 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) + strlen(hold);
    
    	if ((p->vrtp) &&
    	    (!ast_test_flag(&p->flags[0], SIP_NOVIDEO)) &&
    	    (capability & VIDEO_CODEC_MASK)) /* only if video response is appropriate */
    
    		len += strlen(m_video) + strlen(a_video) + strlen(b) + strlen(hold);
    
    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 */
    
    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);