Skip to content
Snippets Groups Projects
chan_sip.c 620 KiB
Newer Older
  • Learn to ignore specific revisions
  • /*! \brief Get a line from an SDP message body */
    
    static const char *get_sdp(struct sip_request *req, const char *name) 
    {
    	int dummy = 0;
    
    	return get_sdp_iterate(&dummy, req, name);
    }
    
    
    /*! \brief Get a specific line from the message body */
    static char *get_body(struct sip_request *req, char *name) 
    {
    	int x;
    	int len = strlen(name);
    	char *r;
    
    	for (x = 0; x < req->lines; x++) {
    		r = get_body_by_line(req->line[x], name, len);
    		if (r[0] != '\0')
    			return r;
    	}
    
    	return "";
    }
    
    
    static const char *find_alias(const char *name, const char *_default)
    {
    	/*! \brief Structure for conversion between compressed SIP and "normal" SIP */
    	static const struct cfalias {
    		char * const fullname;
    		char * const shortname;
    	} aliases[] = {
    
    		{ "Content-Type",	 "c" },
    		{ "Content-Encoding",	 "e" },
    		{ "From",		 "f" },
    		{ "Call-ID",		 "i" },
    		{ "Contact",		 "m" },
    		{ "Content-Length",	 "l" },
    		{ "Subject",		 "s" },
    		{ "To",			 "t" },
    		{ "Supported",		 "k" },
    		{ "Refer-To",		 "r" },
    		{ "Referred-By",	 "b" },
    		{ "Allow-Events",	 "u" },
    		{ "Event",		 "o" },
    		{ "Via",		 "v" },
    
    		{ "Accept-Contact",      "a" },
    		{ "Reject-Contact",      "j" },
    		{ "Request-Disposition", "d" },
    		{ "Session-Expires",     "x" },
    
    		{ "Identity",            "y" },
    		{ "Identity-Info",       "n" },
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int x;
    
    	for (x=0; x<sizeof(aliases) / sizeof(aliases[0]); x++) 
    
    		if (!strcasecmp(aliases[x].fullname, name))
    			return aliases[x].shortname;
    
    static const char *__get_header(const struct sip_request *req, const char *name, int *start)
    
    {
    	int pass;
    
    	/*
    	 * Technically you can place arbitrary whitespace both before and after the ':' in
    	 * a header, although RFC3261 clearly says you shouldn't before, and place just
    	 * one afterwards.  If you shouldn't do it, what absolute idiot decided it was 
    	 * a good idea to say you can do it, and if you can do it, why in the hell would.
    	 * you say you shouldn't.
    	 * Anyways, pedanticsipchecking controls whether we allow spaces before ':',
    	 * and we always allow spaces after that for compatibility.
    	 */
    	for (pass = 0; name && pass < 2;pass++) {
    		int x, len = strlen(name);
    
    		for (x=*start; x<req->headers; x++) {
    
    			if (!strncasecmp(req->header[x], name, len)) {
    
    				char *r = req->header[x] + len;	/* skip name */
    				if (pedanticsipchecking)
    					r = ast_skip_blanks(r);
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    					*start = x+1;
    
    					return ast_skip_blanks(r+1);
    
    		if (pass == 0) /* Try aliases */
    			name = find_alias(name, NULL);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	/* Don't return NULL, so get_header is always a valid pointer */
    	return "";
    }
    
    
    /*! \brief Get header from SIP request 
    	\return Always return something, so don't check for NULL because it won't happen :-)
    */
    
    static const char *get_header(const struct sip_request *req, const char *name)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	int start = 0;
    	return __get_header(req, name, &start);
    }
    
    
    /*! \brief Read RTP from network */
    
    static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p, int *faxdetect)
    
    	/* Retrieve audio/etc from channel.  Assumes p->lock is already held. */
    	struct ast_frame *f;
    
    	
    	if (!p->rtp) {
    		/* We have no RTP allocated for this channel */
    
    		f = ast_rtp_read(p->rtp);	/* RTP Audio */
    
    		f = ast_rtcp_read(p->rtp);	/* RTCP Control Channel */
    
    		f = ast_rtp_read(p->vrtp);	/* RTP Video */
    
    		f = ast_rtcp_read(p->vrtp);	/* RTCP Control Channel for video */
    
    	case 5:
    		f = ast_udptl_read(p->udptl);	/* UDPTL for T.38 */
    		break;
    
    	/* Don't forward RFC2833 if we're not supposed to */
    
    	if (f && (f->frametype == AST_FRAME_DTMF) &&
    	    (ast_test_flag(&p->flags[0], SIP_DTMF) != SIP_DTMF_RFC2833))
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (p->owner) {
    
    		/* We already hold the channel lock */
    		if (f->frametype == AST_FRAME_VOICE) {
    
    			if (f->subclass != (p->owner->nativeformats & AST_FORMAT_AUDIO_MASK)) {
    
    				if (option_debug)
    					ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass);
    
    				p->owner->nativeformats = (p->owner->nativeformats & AST_FORMAT_VIDEO_MASK) | f->subclass;
    
    				ast_set_read_format(p->owner, p->owner->readformat);
    				ast_set_write_format(p->owner, p->owner->writeformat);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			}
    
    			if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
    
    				f = ast_dsp_process(p->owner, p->vad, f);
    
    				if (f && f->frametype == AST_FRAME_DTMF) {
    					if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) && f->subclass == 'f') {
    						if (option_debug)
    							ast_log(LOG_DEBUG, "Fax CNG detected on %s\n", ast->name);
    						*faxdetect = 1;
    					} else if (option_debug) {
    						ast_log(LOG_DEBUG, "* Detected inband DTMF '%c'\n", f->subclass);
    					}
    				}
    
    /*! \brief Read SIP RTP from channel */
    
    static struct ast_frame *sip_read(struct ast_channel *ast)
    {
    	struct ast_frame *fr;
    
    Olle Johansson's avatar
    Olle Johansson committed
    	int faxdetected = FALSE;
    
    	fr = sip_rtp_read(ast, p, &faxdetected);
    
    
    	/* If we are NOT bridged to another channel, and we have detected fax tone we issue T38 re-invite to a peer */
    	/* If we are bridged then it is the responsibility of the SIP device to issue T38 re-invite if it detects CNG or fax preamble */
    	if (faxdetected && ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) && (p->t38.state == T38_DISABLED) && !(ast_bridged_channel(ast))) {
    		if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
    			if (!p->pendinginvite) {
    				if (option_debug > 2)
    					ast_log(LOG_DEBUG, "Sending reinvite on SIP (%s) for T.38 negotiation.\n",ast->name);
    				p->t38.state = T38_LOCAL_REINVITE;
    
    				transmit_reinvite_with_sdp(p, TRUE);
    
    					ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, ast->name);
    
    			}
    		} else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
    			if (option_debug > 2)
    				ast_log(LOG_DEBUG, "Deferring reinvite on SIP (%s) - it will be re-negotiated for T.38\n", ast->name);
    			ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
    		}
    	}
    
    
    	return fr;
    
    
    /*! \brief Generate 32 byte random string for callid's etc */
    static char *generate_random_string(char *buf, size_t size)
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int x;
    
    		val[x] = ast_random();
    	snprintf(buf, size, "%08lx%08lx%08lx%08lx", val[0], val[1], val[2], val[3]);
    
    
    	return buf;
    }
    
    /*! \brief Build SIP Call-ID value for a non-REGISTER transaction */
    static void build_callid_pvt(struct sip_pvt *pvt)
    {
    	char buf[33];
    
    
    	const char *host = S_OR(pvt->fromdomain, ast_inet_ntoa(pvt->ourip));
    
    	
    	ast_string_field_build(pvt, callid, "%s@%s", generate_random_string(buf, sizeof(buf)), host);
    
    /*! \brief Build SIP Call-ID value for a REGISTER transaction */
    
    static void build_callid_registry(struct sip_registry *reg, struct in_addr ourip, const char *fromdomain)
    {
    
    	const char *host = S_OR(fromdomain, ast_inet_ntoa(ourip));
    
    	ast_string_field_build(reg, callid, "%s@%s", generate_random_string(buf, sizeof(buf)), host);
    
    /*! \brief Make our SIP dialog tag */
    
    static void make_our_tag(char *tagbuf, size_t len)
    {
    
    	snprintf(tagbuf, len, "as%08lx", ast_random());
    
    /*! \brief Allocate SIP_PVT structure and set defaults */
    
    static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin,
    				 int useglobal_nat, const int intended_method)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct sip_pvt *p;
    
    	if (!(p = ast_calloc(1, sizeof(*p))))
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return NULL;
    
    	if (ast_string_field_init(p, 512)) {
    
    	ast_mutex_init(&p->pvt_lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	p->initid = -1;
    
    	p->autokillid = -1;
    
    	p->prefs = default_prefs;		/* Set default codecs for this call */
    
    
    	if (intended_method != SIP_OPTIONS)	/* Peerpoke has it's own system */
    
    		p->timer_t1 = SIP_TIMER_T1;	/* Default SIP retransmission timer T1 (RFC 3261) */
    
    		if (ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip))
    
    
    	/* Copy global flags to this PVT at setup. */
    
    	ast_copy_flags(&p->flags[0], &global_flags[0], SIP_FLAGS_TO_COPY);
    	ast_copy_flags(&p->flags[1], &global_flags[1], SIP_PAGE2_FLAGS_TO_COPY);
    
    	ast_set2_flag(&p->flags[0], !recordhistory, SIP_NO_HISTORY);
    
    
    
    	if (sip_methods[intended_method].need_rtp) {
    		p->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
    
    		/* If the global videosupport flag is on, we always create a RTP interface for video */
    
    		if (ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT))
    
    			p->vrtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
    
    		if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT))
    			p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr);
    
    		if (!p->rtp || (ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && !p->vrtp)) {
    			ast_log(LOG_WARNING, "Unable to create RTP audio %s session: %s\n",
    				ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) ? "and video" : "", strerror(errno));
    
    			ast_mutex_destroy(&p->pvt_lock);
    
    			if (p->chanvars) {
    
    				ast_variables_destroy(p->chanvars);
    				p->chanvars = NULL;
    			}
    			free(p);
    			return NULL;
    
    		ast_rtp_setdtmf(p->rtp, ast_test_flag(&p->flags[0], SIP_DTMF) != SIP_DTMF_INFO);
    
    		ast_rtp_setdtmfcompensate(p->rtp, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
    
    		ast_rtp_set_rtptimeout(p->rtp, global_rtptimeout);
    		ast_rtp_set_rtpholdtimeout(p->rtp, global_rtpholdtimeout);
    		ast_rtp_set_rtpkeepalive(p->rtp, global_rtpkeepalive);
    
    			ast_rtp_setdtmf(p->vrtp, 0);
    
    			ast_rtp_setdtmfcompensate(p->vrtp, 0);
    
    			ast_rtp_set_rtptimeout(p->vrtp, global_rtptimeout);
    			ast_rtp_set_rtpholdtimeout(p->vrtp, global_rtpholdtimeout);
    			ast_rtp_set_rtpkeepalive(p->vrtp, global_rtpkeepalive);
    
    Olle Johansson's avatar
    Olle Johansson committed
    		if (p->udptl)
    
    			ast_udptl_settos(p->udptl, global_tos_audio);
    
    Olle Johansson's avatar
    Olle Johansson committed
    		p->maxcallbitrate = default_maxcallbitrate;
    
    		/* Setup NAT structure according to global settings if we have an address */
    
    		ast_copy_flags(&p->flags[0], &global_flags[0], SIP_NAT);
    
    		do_setnat(p, ast_test_flag(&p->flags[0], SIP_NAT) & SIP_NAT_ROUTE);
    
    		ast_string_field_set(p, fromdomain, default_fromdomain);
    	build_via(p);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!callid)
    
    Mark Spencer's avatar
    Mark Spencer committed
    	else
    
    		ast_string_field_set(p, callid, callid);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Assign default music on hold class */
    
    	ast_string_field_set(p, mohinterpret, default_mohinterpret);
    	ast_string_field_set(p, mohsuggest, default_mohsuggest);
    
    	p->allowtransfer = global_allowtransfer;
    
    	if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
    	    (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
    
    Mark Spencer's avatar
    Mark Spencer committed
    		p->noncodeccapability |= AST_RTP_DTMF;
    
    	if (p->udptl) {
    		p->t38.capability = global_t38_capability;
    		if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_REDUNDANCY)
    			p->t38.capability |= T38FAX_UDP_EC_REDUNDANCY;
    		else if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_FEC)
    			p->t38.capability |= T38FAX_UDP_EC_FEC;
    		else if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_NONE)
    			p->t38.capability |= T38FAX_UDP_EC_NONE;
    		p->t38.capability |= T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF;
    		p->t38.jointcapability = p->t38.capability;
    	}
    
    	ast_string_field_set(p, context, default_context);
    
    	dialoglist_lock();
    
    	dialoglist_unlock();
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (option_debug)
    
    		ast_log(LOG_DEBUG, "Allocating new SIP dialog for %s - %s (%s)\n", callid ? callid : "(No Call-ID)", sip_methods[intended_method].text, p->rtp ? "With RTP" : "No RTP");
    
    /*! \brief Connect incoming SIP message to current dialog or create new dialog structure
    	Called by handle_request, sipsock_read */
    
    static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *sin, const int intended_method)
    
    	struct sip_pvt *p = NULL;
    
    	char *tag = "";	/* note, tag is never NULL */
    
    	char totag[128];
    	char fromtag[128];
    
    	const char *callid = get_header(req, "Call-ID");
    
    	const char *from = get_header(req, "From");
    	const char *to = get_header(req, "To");
    	const char *cseq = get_header(req, "Cseq");
    
    
    	/* Call-ID, to, from and Cseq are required by RFC 3261. (Max-forwards and via too - ignored now) */
    	/* get_header always returns non-NULL so we must use ast_strlen_zero() */
    	if (ast_strlen_zero(callid) || ast_strlen_zero(to) ||
    			ast_strlen_zero(from) || ast_strlen_zero(cseq))
    
    
    	if (pedanticsipchecking) {
    
    		/* In principle Call-ID's uniquely identify a call, but with a forking SIP proxy
    		   we need more to identify a branch - so we have to check branch, from
    		   and to tags to identify a call leg.
    
    		   For Asterisk to behave correctly, you need to turn on pedanticsipchecking
    
    		if (gettag(req, "To", totag, sizeof(totag)))
    			ast_set_flag(req, SIP_PKT_WITH_TOTAG);	/* Used in handle_request/response */
    		gettag(req, "From", fromtag, sizeof(fromtag));
    
    
    		tag = (req->method == SIP_RESPONSE) ? totag : fromtag;
    
    
    		if (option_debug > 4 )
    			ast_log(LOG_DEBUG, "= Looking for  Call ID: %s (Checking %s) --From tag %s --To-tag %s  \n", callid, req->method==SIP_RESPONSE ? "To" : "From", fromtag, totag);
    
    
    		/* All messages must always have From: tag */
    		if (ast_strlen_zero(fromtag)) {
    			if (option_debug > 4 ) 
    				ast_log(LOG_DEBUG, "%s request has no from tag, dropping callid: %s from: %s\n", sip_methods[req->method].text , callid, from );
    			return NULL;
    		}
    		/* reject requests that must always have a To: tag */
    		if (ast_strlen_zero(totag) && (req->method == SIP_ACK || req->method == SIP_BYE || req->method == SIP_INFO )) {
    			if (option_debug > 4) 
    				ast_log(LOG_DEBUG, "%s must have a to tag. dropping callid: %s from: %s\n", sip_methods[req->method].text , callid, from );
    			return NULL;
    		}
    
    	dialoglist_lock();
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    		/* In pedantic, we do not want packets with bad syntax to be connected to a PVT */
    
    		int found = FALSE;
    
    		if (req->method == SIP_REGISTER)
    			found = (!strcmp(p->callid, callid));
    		else 
    			found = (!strcmp(p->callid, callid) && 
    			(!pedanticsipchecking || !tag || ast_strlen_zero(p->theirtag) || !strcmp(p->theirtag, tag))) ;
    
    
    		if (option_debug > 4)
    			ast_log(LOG_DEBUG, "= %s Their Call ID: %s Their Tag %s Our tag: %s\n", found ? "Found" : "No match", p->callid, p->theirtag, p->tag);
    
    		/* If we get a new request within an existing to-tag - check the to tag as well */
    		if (pedanticsipchecking && found  && req->method != SIP_RESPONSE) {	/* SIP Request */
    			if (p->tag[0] == '\0' && totag[0]) {
    				/* We have no to tag, but they have. Wrong dialog */
    
    				found = FALSE;
    
    			} else if (totag[0]) {			/* Both have tags, compare them */
    				if (strcmp(totag, p->tag)) {
    
    					found = FALSE;		/* This is not our packet */
    
    				}
    			}
    			if (!found && option_debug > 4)
    				ast_log(LOG_DEBUG, "= Being pedantic: This is not our match on request: Call ID: %s Ourtag <null> Totag %s Method %s\n", p->callid, totag, sip_methods[req->method].text);
    		}
    
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    			/* Found the call */
    
    			dialoglist_unlock();
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return p;
    		}
    	}
    
    	dialoglist_unlock();
    
    	
    	/* See if the method is capable of creating a dialog */
    
    	if (sip_methods[intended_method].can_create == CAN_CREATE_DIALOG) {
    		if (intended_method == SIP_REFER) {
    			/* We do support REFER, but not outside of a dialog yet */
    			transmit_response_using_temp(callid, sin, 1, intended_method, req, "603 Declined (no dialog)");
    		} else if (intended_method == SIP_NOTIFY) {
    			/* We do not support out-of-dialog NOTIFY either,
    		   	like voicemail notification, so cancel that early */
    			transmit_response_using_temp(callid, sin, 1, intended_method, req, "489 Bad event");
    		} else {
    			/* Ok, time to create a new SIP dialog object, a pvt */
    
    			if ((p = sip_alloc(callid, sin, 1, intended_method)))  {
    
    				/* Ok, we've created a dialog, let's go and process it */
    
    			} else {
    				/* We have a memory or file/socket error (can't allocate RTP sockets or something) so we're not
    					getting a dialog from sip_alloc. 
    	
    					Without a dialog we can't retransmit and handle ACKs and all that, but at least
    					send an error message.
    	
    					Sorry, we apologize for the inconvienience
    				*/
    				transmit_response_using_temp(callid, sin, 1, intended_method, req, "500 Server internal error");
    				if (option_debug > 3)
    					ast_log(LOG_DEBUG, "Failed allocating SIP dialog, sending 500 Server internal error and giving up\n");
    			}
    
    		}
    		return p;
    	} else if( sip_methods[intended_method].can_create == CAN_CREATE_DIALOG_UNSUPPORTED_METHOD) {
    		/* A method we do not support, let's take it on the volley */
    		transmit_response_using_temp(callid, sin, 1, intended_method, req, "501 Method Not Implemented");
    		if (option_debug > 1 )
    			ast_log(LOG_DEBUG, "Got a request with unsupported SIP method.\n");
    
    	} else if (intended_method != SIP_RESPONSE && intended_method != SIP_ACK) {
    
    		/* This is a request outside of a dialog that we don't know about */
    		transmit_response_using_temp(callid, sin, 1, intended_method, req, "481 Call leg/transaction does not exist");
    
    			ast_log(LOG_DEBUG, "That's odd...  Got a request in unknown dialog. Callid %s\n", callid ? callid : "<unknown>");
    
    	/* We do not respond to responses for dialogs that we don't know about, we just drop
    	   the session quickly */
    	if (option_debug > 1 && intended_method == SIP_RESPONSE)
    		ast_log(LOG_DEBUG, "That's odd...  Got a response on a call we dont know about. Callid %s\n", callid ? callid : "<unknown>");
    
    	return p;
    
    /*! \brief Parse register=> line in sip.conf and add to registry */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sip_register(char *value, int lineno)
    {
    	struct sip_registry *reg;
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	int portnum = 0;
    	char username[256] = "";
    	char *hostname=NULL, *secret=NULL, *authuser=NULL;
    
    	char *porta=NULL;
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!value)
    		return -1;
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	ast_copy_string(username, value, sizeof(username));
    	/* First split around the last '@' then parse the two components. */
    	hostname = strrchr(username, '@'); /* allow @ in the first part */
    
    	if (hostname)
    		*hostname++ = '\0';
    
    	if (ast_strlen_zero(username) || ast_strlen_zero(hostname)) {
    
    		ast_log(LOG_WARNING, "Format for registration is user[:secret[:authuser]]@host[:port][/contact] at line %d\n", lineno);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    	}
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	/* split user[:secret[:authuser]] */
    	secret = strchr(username, ':');
    	if (secret) {
    		*secret++ = '\0';
    		authuser = strchr(secret, ':');
    		if (authuser)
    			*authuser++ = '\0';
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	/* split host[:port][/contact] */
    
    	callback = strchr(hostname, '/');
    	if (callback)
    		*callback++ = '\0';
    	if (ast_strlen_zero(callback))
    		callback = "s";
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	porta = strchr(hostname, ':');
    	if (porta) {
    		*porta++ = '\0';
    		portnum = atoi(porta);
    		if (portnum == 0) {
    			ast_log(LOG_WARNING, "%s is not a valid port number at line %d\n", porta, lineno);
    			return -1;
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	if (!(reg = ast_calloc(1, sizeof(*reg)))) {
    		ast_log(LOG_ERROR, "Out of memory. Can't allocate SIP registry entry\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    
    	if (ast_string_field_init(reg, 256)) {
    
    		ast_log(LOG_ERROR, "Out of memory. Can't allocate SIP registry strings\n");
    
    	regobjs++;
    	ASTOBJ_INIT(reg);
    
    	ast_string_field_set(reg, callback, callback);
    
    	if (username)
    
    		ast_string_field_set(reg, username, username);
    
    	if (hostname)
    
    		ast_string_field_set(reg, hostname, hostname);
    
    	if (authuser)
    
    		ast_string_field_set(reg, authuser, authuser);
    
    		ast_string_field_set(reg, secret, secret);
    
    	reg->expire = -1;
    
    	reg->timeout =  -1;
    	reg->refresh = default_expiry;
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	reg->portno = portnum;
    
    	reg->callid_valid = FALSE;
    
    	ASTOBJ_CONTAINER_LINK(&regl, reg);	/* Add the new registry entry to the list */
    
    	unref_registry(reg);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    
    /*! \brief  Parse multiline SIP headers into one header
    	This is enabled if pedanticsipchecking is enabled */
    
    static int lws2sws(char *msgbuf, int len) 
    
    	int h = 0, t = 0; 
    	int lws = 0; 
    
    	for (; h < len;) { 
    		/* Eliminate all CRs */ 
    		if (msgbuf[h] == '\r') { 
    			h++; 
    			continue; 
    		} 
    		/* Check for end-of-line */ 
    		if (msgbuf[h] == '\n') { 
    
    			/* Check for end-of-message */ 
    
    				break; 
    			/* Check for a continuation line */ 
    			if (msgbuf[h + 1] == ' ' || msgbuf[h + 1] == '\t') { 
    				/* Merge continuation line */ 
    				h++; 
    				continue; 
    			} 
    			/* Propagate LF and start new line */ 
    			msgbuf[t++] = msgbuf[h++]; 
    			lws = 0;
    
    		if (msgbuf[h] == ' ' || msgbuf[h] == '\t') { 
    			if (lws) { 
    				h++; 
    				continue; 
    			} 
    			msgbuf[t++] = msgbuf[h++]; 
    			lws = 1; 
    
    			continue; 
    		} 
    		msgbuf[t++] = msgbuf[h++]; 
    
    /*! \brief Parse a SIP message 
    	\note this function is used both on incoming and outgoing packets
    */
    
    static void parse_request(struct sip_request *req)
    
    	char *c = req->data, **dst = req->header;
    	int i = 0, lim = SIP_MAX_HEADERS - 1;
    
    	req->header[0] = c;
    	req->headers = -1;	/* mark that we are working on the header */
    	for (; *c; c++) {
    		if (*c == '\r')		/* remove \r */
    			*c = '\0';
    		else if (*c == '\n') { /* end of this line */
    			*c = '\0';
    
    				ast_log(LOG_DEBUG, "%7s %2d [%3d]: %s\n",
    
    					req->headers < 0 ? "Header" : "Body",
    
    					i, (int)strlen(dst[i]), dst[i]);
    
    			if (ast_strlen_zero(dst[i]) && req->headers < 0) {
    				req->headers = i;	/* record number of header lines */
    				dst = req->line;	/* start working on the body */
    				i = 0;
    				lim = SIP_MAX_LINES - 1;
    			} else {	/* move to next line, check for overflows */
    				if (i++ >= lim)
    					break;
    
    			dst[i] = c + 1; /* record start of next line */
    
            }
    	/* update count of header or body lines */
    	if (req->headers >= 0)	/* we are in the body */
    		req->lines = i;
    	else {			/* no body */
    		req->headers = i;
    		req->lines = 0;
    		req->line[0] = "";
    
    
    	if (*c)
    		ast_log(LOG_WARNING, "Too many lines, skipping <%s>\n", c);
    
    	/* Split up the first line parts */
    	determine_firstline_parts(req);
    
    /*!
      \brief Determine whether a SIP message contains an SDP in its body
      \param req the SIP request to process
      \return 1 if SDP found, 0 if not found
    
      Also updates req->sdp_start and req->sdp_end to indicate where the SDP
      lives in the message body.
    */
    static int find_sdp(struct sip_request *req)
    {
    	const char *content_type;
    	const char *search;
    	char *boundary;
    	unsigned int x;
    
    	content_type = get_header(req, "Content-Type");
    
    	/* if the body contains only SDP, this is easy */
    	if (!strcasecmp(content_type, "application/sdp")) {
    		req->sdp_start = 0;
    		req->sdp_end = req->lines;
    		return 1;
    	}
    
    	/* if it's not multipart/mixed, there cannot be an SDP */
    	if (strncasecmp(content_type, "multipart/mixed", 15))
    		return 0;
    
    	/* if there is no boundary marker, it's invalid */
    	if (!(search = strcasestr(content_type, ";boundary=")))
    		return 0;
    
    	search += 10;
    
    	if (ast_strlen_zero(search))
    		return 0;
    
    	/* make a duplicate of the string, with two extra characters
    	   at the beginning */
    	boundary = ast_strdupa(search - 2);
    	boundary[0] = boundary[1] = '-';
    
    	/* search for the boundary marker, but stop when there are not enough
    	   lines left for it, the Content-Type header and at least one line of
    	   body */
    	for (x = 0; x < (req->lines - 2); x++) {
    		if (!strncasecmp(req->line[x], boundary, strlen(boundary)) &&
    		    !strcasecmp(req->line[x + 1], "Content-Type: application/sdp")) {
    
    			/* search for the end of the body part */
    			for ( ; x < req->lines; x++) {
    				if (!strncasecmp(req->line[x], boundary, strlen(boundary)))
    					break;
    			}
    			req->sdp_end = x;
    			return 1;
    		}
    	}
    
    	return 0;
    }
    
    
    /*! \brief Process SIP SDP offer, select formats and activate RTP channels
    	If offer is rejected, we will not change any properties of the call
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
     	Return 0 on success, a negative value on errors.
    	Must be called after find_sdp().
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int process_sdp(struct sip_pvt *p, struct sip_request *req)
    {
    
    Olle Johansson's avatar
    Olle Johansson committed
    	const char *m;		/* SDP media offer */
    
    	const char *c;
    	const char *a;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char host[258];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int len = -1;
    
    	int portno = -1;		/*!< RTP Audio port number */
    	int vportno = -1;		/*!< RTP Video port number */
    
    	int udptlportno = -1;
    	int peert38capability = 0;
    	char s[256];
    	int old = 0;
    
    Olle Johansson's avatar
    Olle Johansson committed
    
    	/* Peer capability is the capability in the SDP, non codec is RFC2833 DTMF (101) */	
    
    	int peercapability = 0, peernoncodeccapability = 0;
    
    	int vpeercapability = 0, vpeernoncodeccapability = 0;
    	struct sockaddr_in sin;		/*!< media socket address */
    	struct sockaddr_in vsin;	/*!< Video socket address */
    
    Olle Johansson's avatar
    Olle Johansson committed
    
    
    	const char *codecs;
    
    	struct hostent *hp;		/*!< RTP Audio host IP */
    	struct hostent *vhp = NULL;	/*!< RTP video host IP */
    	struct ast_hostent audiohp;
    	struct ast_hostent videohp;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int codec;
    
    	int iterator;
    
    	struct ast_channel *bridgepeer = NULL;
    
    	struct ast_rtp *newaudiortp, *newvideortp;	/* Buffers for codec handling */
    
    	int newjointcapability;				/* Negotiated capability */
    	int newpeercapability;
    	int newnoncodeccapability;
    	int numberofmediastreams = 0;
    	int debug = sip_debug_test_pvt(p);
    		
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	int found_rtpmap_codecs[32];
    	int last_rtpmap_codec=0;
    
    
    	if (!p->rtp) {
    		ast_log(LOG_ERROR, "Got SDP but have no RTP session allocated.\n");
    		return -1;
    	}
    
    
    	/* Initialize the temporary RTP structures we use to evaluate the offer from the peer */
    
    	newaudiortp = alloca(ast_rtp_alloc_size());
    	memset(newaudiortp, 0, ast_rtp_alloc_size());
    
    	ast_rtp_new_init(newaudiortp);
    
    
    	newvideortp = alloca(ast_rtp_alloc_size());
    	memset(newvideortp, 0, ast_rtp_alloc_size());
    
    	ast_rtp_new_init(newvideortp);
    
    	/* Update our last rtprx when we receive an SDP, too */
    
    	p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	m = get_sdp(req, "m");
    
    	destiterator = req->sdp_start;
    
    	c = get_sdp_iterate(&destiterator, req, "c");
    
    	if (ast_strlen_zero(m) || ast_strlen_zero(c)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s', c = '%s')\n", m, c);
    		return -1;
    	}
    
    
    	/* Check for IPv4 address (not IPv6 yet) */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (sscanf(c, "IN IP4 %256s", host) != 1) {
    		ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
    		return -1;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* XXX This could block for a long time, and block the main thread! XXX */
    
    	hp = ast_gethostbyname(host, &audiohp);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!hp) {
    		ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c);
    		return -1;
    	}
    
    	vhp = hp;	/* Copy to video address as default too */
    	
    
    	iterator = req->sdp_start;
    
    	ast_set_flag(&p->flags[0], SIP_NOVIDEO);	
    
    	while ((m = get_sdp_iterate(&iterator, req, "m"))[0] != '\0') {
    
    		int x;
    		int audio = FALSE;
    
    		numberofports = 1;
    		if ((sscanf(m, "audio %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2) ||
    
    		    (sscanf(m, "audio %d RTP/AVP %n", &x, &len) == 1)) {
    
    			/* Found audio stream in this media definition */
    
    			/* Scan through the RTP payload types specified in a "m=" line: */
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    			for (codecs = m + len; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) {
    
    				if (sscanf(codecs, "%d%n", &codec, &len) != 1) {
    					ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs);
    					return -1;
    				}
    
    				if (debug)
    
    					ast_verbose("Found RTP audio format %d\n", codec);
    
    				ast_rtp_set_m_type(newaudiortp, codec);
    
    		} else if ((sscanf(m, "video %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2) ||
    		    (sscanf(m, "video %d RTP/AVP %n", &x, &len) == 1)) {
    			/* If it is not audio - is it video ? */
    
    			ast_clear_flag(&p->flags[0], SIP_NOVIDEO);	
    
    			/* Scan through the RTP payload types specified in a "m=" line: */
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    			for (codecs = m + len; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) {
    
    				if (sscanf(codecs, "%d%n", &codec, &len) != 1) {
    					ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs);
    					return -1;
    				}
    
    				if (debug)
    
    					ast_verbose("Found RTP video format %d\n", codec);
    
    				ast_rtp_set_m_type(newvideortp, codec);
    
    		} else if (p->udptl && ( (sscanf(m, "image %d udptl t38%n", &x, &len) == 1) || 
    		 (sscanf(m, "image %d UDPTL t38%n", &x, &len) == 1) )) {
    
    				ast_verbose("Got T.38 offer in SDP in dialog %s\n", p->callid);
    
    			
    			if (p->owner && p->lastinvite) {
    				p->t38.state = T38_PEER_REINVITE; /* T38 Offered in re-invite from remote party */
    				if (option_debug > 1)
    					ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>" );
    			} else {
    				p->t38.state = T38_PEER_DIRECT; /* T38 Offered directly from peer in first invite */
    				if (option_debug > 1)
    					ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
    			}
    
    		} else 
    			ast_log(LOG_WARNING, "Unsupported SDP media type in offer: %s\n", m);
    		if (numberofports > 1)
    			ast_log(LOG_WARNING, "SDP offered %d ports for media, not supported by Asterisk. Will try anyway...\n", numberofports);
    		
    
    		/* Check for Media-description-level-address for audio */
    
    		c = get_sdp_iterate(&destiterator, req, "c");
    		if (!ast_strlen_zero(c)) {
    			if (sscanf(c, "IN IP4 %256s", host) != 1) {
    				ast_log(LOG_WARNING, "Invalid secondary host in c= line, '%s'\n", c);
    			} else {
    				/* XXX This could block for a long time, and block the main thread! XXX */
    
    				if (audio) {
    					if ( !(hp = ast_gethostbyname(host, &audiohp)))
    						ast_log(LOG_WARNING, "Unable to lookup RTP Audio host in secondary c= line, '%s'\n", c);
    				} else if (!(vhp = ast_gethostbyname(host, &videohp)))
    					ast_log(LOG_WARNING, "Unable to lookup RTP video host in secondary c= line, '%s'\n", c);
    
    	if (portno == -1 && vportno == -1 && udptlportno == -1)
    
    		/* No acceptable offer found in SDP  - we have no ports */
    		/* Do not change RTP or VRTP if this is a re-invite */
    		return -2;
    
    	if (numberofmediastreams > 2)
    
    		/* We have too many fax, audio and/or video media streams, fail this offer */
    
    	/* RTP addresses and ports for audio and video */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	sin.sin_family = AF_INET;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
    
    	if (vhp)
    		memcpy(&vsin.sin_addr, vhp->h_addr, sizeof(vsin.sin_addr));
    
    	/* Setup UDPTL port number */
    	if (p->udptl) {
    		if (udptlportno > 0) {
    			sin.sin_port = htons(udptlportno);
    			ast_udptl_set_peer(p->udptl, &sin);
    			if (debug)
    
    				ast_log(LOG_DEBUG,"Peer T.38 UDPTL is at port %s:%d\n",ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
    
    		} else {
    			ast_udptl_stop(p->udptl);
    			if (debug)
    				ast_log(LOG_DEBUG, "Peer doesn't provide T.38 UDPTL\n");
    		}
    	}
    
    
    		
    	if (p->rtp) {
    		if (portno > 0) {
    			sin.sin_port = htons(portno);
    			ast_rtp_set_peer(p->rtp, &sin);
    			if (debug)
    				ast_verbose("Peer audio RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
    		} else {
    			if (udptlportno > 0) {
    				if (debug)
    					ast_verbose("Got T.38 Re-invite without audio. Keeping RTP active during T.38 session. Callid %s\n", p->callid);
    			} else {
    				ast_rtp_stop(p->rtp);
    				if (debug)
    					ast_verbose("Peer doesn't provide audio. Callid %s\n", p->callid);
    			}
    		}
    	}
    	/* Setup video port number */
    	if (vportno != -1)
    		vsin.sin_port = htons(vportno);
    
    
    	/* Next, scan through each "a=rtpmap:" line, noting each
    	 * specified RTP payload type (with corresponding MIME subtype):
    	 */
    
    	/* XXX This needs to be done per media stream, since it's media stream specific */
    
    	iterator = req->sdp_start;
    
    	while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
    
    		char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */
    
    		if (option_debug > 1) {
    			int breakout = FALSE;
    		
    
    			/* If we're debugging, check for unsupported sdp options */
    
    			if (!strncasecmp(a, "rtcp:", (size_t) 5)) {
    
    				if (debug)
    					ast_verbose("Got unsupported a:rtcp in SDP offer \n");
    
    			} else if (!strncasecmp(a, "fmtp:", (size_t) 5)) {
    				/* Format parameters:  Not supported */
    				/* Note: This is used for codec parameters, like bitrate for
    					G722 and video formats for H263 and H264 
    					See RFC2327 for an example */
    				if (debug)
    					ast_verbose("Got unsupported a:fmtp in SDP offer \n");
    
    			} else if (!strncasecmp(a, "framerate:", (size_t) 10)) {
    				/* Video stuff:  Not supported */
    				if (debug)
    					ast_verbose("Got unsupported a:framerate in SDP offer \n");
    
    			} else if (!strncasecmp(a, "maxprate:", (size_t) 9)) {
    				/* Video stuff:  Not supported */
    				if (debug)
    					ast_verbose("Got unsupported a:maxprate in SDP offer \n");
    
    			} else if (!strncasecmp(a, "crypto:", (size_t) 7)) {
    				/* SRTP stuff, not yet supported */
    				if (debug)
    					ast_verbose("Got unsupported a:crypto in SDP offer \n");