Skip to content
Snippets Groups Projects
chan_sip.c 482 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	append_history(p, "Masq (cont)", "...new owner: %s\n", p->owner->name);
    
    	if (p->owner != oldchan)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
    
    	else {
    		p->owner = newchan;
    		ret = 0;
    
    /*! \brief Send DTMF character on SIP channel
    	within one call, we're able to transmit in many methods simultaneously */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sip_senddigit(struct ast_channel *ast, char digit)
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_mutex_lock(&p->lock);
    
    	switch (ast_test_flag(&p->flags[0], SIP_DTMF)) {
    
    	case SIP_DTMF_INFO:
    
    		transmit_info_with_digit(p, digit);
    
    		break;
    	case SIP_DTMF_RFC2833:
    		if (p->rtp)
    			ast_rtp_senddigit(p->rtp, digit);
    		break;
    	case SIP_DTMF_INBAND:
    
    Mark Spencer's avatar
    Mark Spencer committed
    		res = -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_mutex_unlock(&p->lock);
    	return res;
    
    /*! \brief Transfer SIP call */
    
    static int sip_transfer(struct ast_channel *ast, const char *dest)
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_mutex_lock(&p->lock);
    
    	if (ast->_state == AST_STATE_RING)
    		res = sip_sipredirect(p, dest);
    	else
    		res = transmit_refer(p, dest);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_mutex_unlock(&p->lock);
    
    /*! \brief Play indication to user 
    
     * With SIP a lot of indications is sent as messages, letting the device play
    
       the indication - busy signal, congestion etc 
       \return -1 to force ast_indicate to send indication in audio, 0 if SIP can handle the indication by sending a message
    */
    
    static int sip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res = 0;
    
    	ast_mutex_lock(&p->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	switch(condition) {
    	case AST_CONTROL_RINGING:
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (ast->_state == AST_STATE_RING) {
    
    			if (!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) ||
    			    (ast_test_flag(&p->flags[0], SIP_PROG_INBAND) == SIP_PROG_INBAND_NEVER)) {				
    
    				/* Send 180 ringing if out-of-band seems reasonable */
    				transmit_response(p, "180 Ringing", &p->initreq);
    
    				ast_set_flag(&p->flags[0], SIP_RINGING);
    				if (ast_test_flag(&p->flags[0], SIP_PROG_INBAND) != SIP_PROG_INBAND_YES)
    
    				/* Well, if it's not reasonable, just send in-band */
    
    Mark Spencer's avatar
    Mark Spencer committed
    		res = -1;
    		break;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	case AST_CONTROL_BUSY:
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (ast->_state != AST_STATE_UP) {
    
    			transmit_response(p, "486 Busy Here", &p->initreq);
    
    			ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
    
    			ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			break;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		res = -1;
    		break;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	case AST_CONTROL_CONGESTION:
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (ast->_state != AST_STATE_UP) {
    
    			transmit_response(p, "503 Service Unavailable", &p->initreq);
    
    			ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
    
    			ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			break;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		res = -1;
    		break;
    
    	case AST_CONTROL_PROCEEDING:
    
    		if ((ast->_state != AST_STATE_UP) &&
    		    !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
    		    !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
    
    			transmit_response(p, "100 Trying", &p->initreq);
    			break;
    		}
    		res = -1;
    		break;
    	case AST_CONTROL_PROGRESS:
    
    		if ((ast->_state != AST_STATE_UP) &&
    		    !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
    		    !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
    
    			transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE);
    
    			ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);	
    
    Mark Spencer's avatar
    Mark Spencer committed
    		res = -1;
    		break;
    
    	case AST_CONTROL_HOLD:	/* The other part of the bridge are put on hold */
    
    			ast_log(LOG_DEBUG, "Bridged channel now on hold - %s\n", p->callid);
    
    	case AST_CONTROL_UNHOLD:	/* The other part of the bridge are back from hold */
    
    			ast_log(LOG_DEBUG, "Bridged channel is back from hold, let's talk! : %s\n", p->callid);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	case AST_CONTROL_VIDUPDATE:	/* Request a video frame update */
    
    		if (p->vrtp && !ast_test_flag(&p->flags[0], SIP_NOVIDEO)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			transmit_info_with_vidupdate(p);
    
    Olle Johansson's avatar
    Olle Johansson committed
    			/* ast_rtcp_send_h261fur(p->vrtp); */
    
    Mark Spencer's avatar
    Mark Spencer committed
    			res = 0;
    		} else
    			res = -1;
    		break;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	case -1:
    
    Mark Spencer's avatar
    Mark Spencer committed
    		res = -1;
    		break;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	default:
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", condition);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		res = -1;
    		break;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_mutex_unlock(&p->lock);
    	return res;
    
    /*! \brief Initiate a call in the SIP channel
    	called from sip_request_call (calls from the pbx ) */
    
    static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *title)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct ast_channel *tmp;
    
    	struct ast_variable *v = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int fmt;
    
    	ast_mutex_unlock(&i->lock);
    	/* Don't hold a sip pvt lock while we allocate a channel */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	tmp = ast_channel_alloc(1);
    
    	if (!tmp) {
    		ast_log(LOG_WARNING, "Unable to allocate SIP channel structure\n");
    		return NULL;
    	}
    	tmp->tech = &sip_tech;
    	/* Select our native format based on codec preference until we receive
    	   something from another device to the contrary. */
    	if (i->jointcapability)
    
    	else if (i->capability)
    
    	tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | (i->jointcapability & AST_FORMAT_VIDEO_MASK);
    
    	fmt = ast_best_codec(tmp->nativeformats);
    
    	if (title)
    
    		ast_string_field_build(tmp, name, "SIP/%s-%04lx", title, ast_random() & 0xffff);
    
    	else if (strchr(i->fromdomain,':'))
    
    		ast_string_field_build(tmp, name, "SIP/%s-%08x", strchr(i->fromdomain,':')+1, (int)(long)(i));
    
    		ast_string_field_build(tmp, name, "SIP/%s-%08x", i->fromdomain, (int)(long)(i));
    
    	if (ast_test_flag(&i->flags[0], SIP_DTMF) ==  SIP_DTMF_INBAND) {
    
    		i->vad = ast_dsp_new();
    		ast_dsp_set_features(i->vad, DSP_FEATURE_DTMF_DETECT);
    
    		if (global_relaxdtmf)
    
    			ast_dsp_digitmode(i->vad, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
    	}
    
    	if (i->rtp) {
    		tmp->fds[0] = ast_rtp_fd(i->rtp);
    		tmp->fds[1] = ast_rtcp_fd(i->rtp);
    	}
    
    	if (i->vrtp) {
    		tmp->fds[2] = ast_rtp_fd(i->vrtp);
    		tmp->fds[3] = ast_rtcp_fd(i->vrtp);
    	}
    	if (state == AST_STATE_RING)
    		tmp->rings = 1;
    	tmp->adsicpe = AST_ADSI_UNAVAILABLE;
    	tmp->writeformat = fmt;
    	tmp->rawwriteformat = fmt;
    	tmp->readformat = fmt;
    	tmp->rawreadformat = fmt;
    	tmp->tech_pvt = i;
    
    	tmp->callgroup = i->callgroup;
    	tmp->pickupgroup = i->pickupgroup;
    	tmp->cid.cid_pres = i->callingpres;
    	if (!ast_strlen_zero(i->accountcode))
    
    		ast_string_field_set(tmp, accountcode, i->accountcode);
    
    	if (i->amaflags)
    		tmp->amaflags = i->amaflags;
    	if (!ast_strlen_zero(i->language))
    
    		ast_string_field_set(tmp, language, i->language);
    
    	if (!ast_strlen_zero(i->musicclass))
    
    		ast_string_field_set(tmp, musicclass, i->musicclass);
    
    	i->owner = tmp;
    	ast_mutex_lock(&usecnt_lock);
    	usecnt++;
    	ast_mutex_unlock(&usecnt_lock);
    	ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
    	ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
    	if (!ast_strlen_zero(i->cid_num)) 
    
    		tmp->cid.cid_num = ast_strdup(i->cid_num);
    
    	if (!ast_strlen_zero(i->cid_name))
    
    		tmp->cid.cid_name = ast_strdup(i->cid_name);
    
    	if (!ast_strlen_zero(i->rdnis))
    
    		tmp->cid.cid_rdnis = ast_strdup(i->rdnis);
    
    	if (!ast_strlen_zero(i->exten) && strcmp(i->exten, "s"))
    
    		tmp->cid.cid_dnid = ast_strdup(i->exten);
    
    	tmp->priority = 1;
    
    	if (!ast_strlen_zero(i->uri))
    
    		pbx_builtin_setvar_helper(tmp, "SIPURI", i->uri);
    
    	if (!ast_strlen_zero(i->domain))
    
    		pbx_builtin_setvar_helper(tmp, "SIPDOMAIN", i->domain);
    
    	if (!ast_strlen_zero(i->useragent))
    
    		pbx_builtin_setvar_helper(tmp, "SIPUSERAGENT", i->useragent);
    
    	if (!ast_strlen_zero(i->callid))
    
    		pbx_builtin_setvar_helper(tmp, "SIPCALLID", i->callid);
    	ast_setstate(tmp, state);
    
    	if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
    		ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
    		tmp->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
    		ast_hangup(tmp);
    		tmp = NULL;
    
    	}
    	/* Set channel variables for this call from configuration */
    	for (v = i->chanvars ; v ; v = v->next)
    		pbx_builtin_setvar_helper(tmp,v->name,v->value);
    
    	if (recordhistory)
    		append_history(i, "NewChan", "Channel %s - from %s", tmp->name, i->callid);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return tmp;
    }
    
    
    /*! \brief Reads one line of SIP message body */
    
    static const char *get_sdp_by_line(const char* line, const char *name, int nameLen)
    
    	if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=')
    
    		return ast_skip_blanks(line + nameLen + 1);
    
    /*! \brief get_sdp_iterate: lookup 'name' in the request starting
     * at the 'start' line. Returns the matching line, and 'start'
     * is updated with the next line number.
     */
    
    static const char* get_sdp_iterate(int* start, struct sip_request *req, const char *name)
    
    {
    	int len = strlen(name);
    
    
    	while (*start < req->lines) {
    		const char *r = get_sdp_by_line(req->line[(*start)++], name, len);
    
    		if (r[0] != '\0')
    			return r;
    	}
    	return "";
    
    /*! \brief  get_sdp: Gets all kind of SIP message bodies, including SDP,
       but the name wrongly applies _only_ sdp */
    static const char *get_sdp(struct sip_request *req, const char *name) 
    {
    	int dummy = 0;
    	return get_sdp_iterate(&dummy, req, name);
    }
    
    
    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" },
    	};
    
    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;
    	return _default;
    }
    
    
    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 */
    
    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)
    
    	/* 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 */
    
    	/* 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 (option_debug && f && (f->frametype == AST_FRAME_DTMF)) 
    
    					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;
    
    	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 iabuf[INET_ADDRSTRLEN];
    	char buf[33];
    
    
    	const char *host = S_OR(pvt->fromdomain, ast_inet_ntoa(iabuf, sizeof(iabuf), 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)
    {
    	char iabuf[INET_ADDRSTRLEN];
    
    	const char *host = S_OR(fromdomain, ast_inet_ntoa(iabuf, sizeof(iabuf), 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->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 = 500;	/* Default SIP retransmission timer T1 (RFC 3261) */
    
    		if (ast_sip_ouraddrfor(&p->sa.sin_addr,&p->ourip))
    
    Olle Johansson's avatar
    Olle Johansson committed
    	
    
    	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);
    
    
    	if (sip_methods[intended_method].need_rtp) {
    		p->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
    
    		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 (!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));
    
    			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_setdtmf(p->vrtp, 0);
    		}
    
    		p->rtptimeout = global_rtptimeout;
    		p->rtpholdtimeout = global_rtpholdtimeout;
    		p->rtpkeepalive = global_rtpkeepalive;
    
    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);
    
    		natflags = ast_test_flag(&p->flags[0], SIP_NAT) & SIP_NAT_ROUTE;
    
    			ast_rtp_setnat(p->rtp, natflags);
    
    			ast_rtp_setnat(p->vrtp, natflags);
    
    		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, musicclass, default_musicclass);
    
    	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;
    
    	ast_string_field_set(p, context, default_context);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	p->next = iflist;
    	iflist = p;
    
    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)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct sip_pvt *p;
    
    	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");
    
    	if (!callid || !to || !from || !cseq)		/* Call-ID, to, from and Cseq are required by RFC 3261. (Max-forwards and via too - ignored now) */
    		return NULL;	/* Invalid packet */
    
    
    	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);
    
    Luigi Rizzo's avatar
    Luigi Rizzo committed
    	for (p = iflist; p; p = p->next) {
    		/* 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 */
    
    			ast_mutex_lock(&p->lock);
    			ast_mutex_unlock(&iflock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return p;
    		}
    	}
    
    	/* Allocate new call */
    	if ((p = sip_alloc(callid, sin, 1, intended_method)))
    
    	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;
    
    	char *username=NULL, *hostname=NULL, *secret=NULL, *authuser=NULL;
    	char *porta=NULL;
    	char *contact=NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char *stringp=NULL;
    	
    	if (!value)
    		return -1;
    
    	ast_copy_string(copy, value, sizeof(copy));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	stringp=copy;
    
    	username = stringp;
    	hostname = strrchr(stringp, '@');
    
    	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;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	username = strsep(&stringp, ":");
    
    	if (username) {
    		secret = strsep(&stringp, ":");
    		if (secret) 
    			authuser = strsep(&stringp, ":");
    	}
    
    	stringp = hostname;
    	hostname = strsep(&stringp, "/");
    
    	if (hostname) 
    		contact = strsep(&stringp, "/");
    
    		contact = "s";
    
    Mark Spencer's avatar
    Mark Spencer committed
    	stringp=hostname;
    	hostname = strsep(&stringp, ":");
    
    	porta = strsep(&stringp, ":");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	
    	if (porta && !atoi(porta)) {
    		ast_log(LOG_WARNING, "%s is not a valid port number at line %d\n", porta, lineno);
    		return -1;
    	}
    
    	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, contact, contact);
    
    	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;
    	reg->portno = porta ? atoi(porta) : 0;
    
    	reg->callid_valid = FALSE;
    
    	ASTOBJ_CONTAINER_LINK(&regl, reg);	/* Add the new registry entry to the list */
    
    	ASTOBJ_UNREF(reg,sip_registry_destroy);
    
    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)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	/* Divide fields by NULL's */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int f = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	c = req->data;
    
    	/* First header starts immediately */
    	req->header[f] = c;
    	while(*c) {
    		if (*c == '\n') {
    			/* We've got a new header */
    			*c = 0;
    
    
    				ast_log(LOG_DEBUG, "Header %d: %s (%d)\n", f, req->header[f], (int) strlen(req->header[f]));
    
    			if (ast_strlen_zero(req->header[f])) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    				/* Line by itself means we're now in content */
    				c++;
    				break;
    			}
    			if (f >= SIP_MAX_HEADERS - 1) {
    
    				ast_log(LOG_WARNING, "Too many SIP headers. Ignoring.\n");
    
    			} else
    				f++;
    			req->header[f] = c + 1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		} else if (*c == '\r') {
    			/* Ignore but eliminate \r's */
    			*c = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		c++;
    	}
    	/* Check for last header */
    
    	if (!ast_strlen_zero(req->header[f])) {
    
    			ast_log(LOG_DEBUG, "Header %d: %s (%d)\n", f, req->header[f], (int) strlen(req->header[f]));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		f++;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	req->headers = f;
    	/* Now we process any mime content */
    	f = 0;
    	req->line[f] = c;
    	while(*c) {
    		if (*c == '\n') {
    			/* We've got a new line */
    			*c = 0;
    
    				ast_log(LOG_DEBUG, "Line: %s (%d)\n", req->line[f], (int) strlen(req->line[f]));
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (f >= SIP_MAX_LINES - 1) {
    
    				ast_log(LOG_WARNING, "Too many SDP lines. Ignoring.\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    			} else
    				f++;
    			req->line[f] = c + 1;
    		} else if (*c == '\r') {
    			/* Ignore and eliminate \r's */
    			*c = 0;
    		}
    		c++;
    	}
    	/* Check for last line */
    
    	if (!ast_strlen_zero(req->line[f])) 
    
    Mark Spencer's avatar
    Mark Spencer committed
    		f++;
    	req->lines = f;
    	if (*c) 
    		ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c);
    
    	/* Split up the first line parts */
    	determine_firstline_parts(req);
    
    /*! \brief Process SIP SDP and activate RTP channels*/
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int process_sdp(struct sip_pvt *p, struct sip_request *req)
    {
    
    	const char *m;
    	const char *c;
    	const char *a;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char host[258];
    
    	char iabuf[INET_ADDRSTRLEN];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int len = -1;
    
    	int portno = -1;
    	int vportno = -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int peercapability, peernoncodeccapability;
    
    	int vpeercapability=0, vpeernoncodeccapability=0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct sockaddr_in sin;
    
    	const char *codecs;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct hostent *hp;
    
    	struct ast_hostent ahp;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int codec;
    
    	int iterator;
    
    	int debug=sip_debug_test_pvt(p);
    
    	struct ast_channel *bridgepeer = NULL;
    
    	if (!p->rtp) {
    		ast_log(LOG_ERROR, "Got SDP but have no RTP session allocated.\n");
    		return -1;
    	}
    
    
    	/* Update our last rtprx when we receive an SDP, too */
    	time(&p->lastrtprx);
    
    	time(&p->lastrtptx);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Get codec and RTP info from SDP */
    	if (strcasecmp(get_header(req, "Content-Type"), "application/sdp")) {
    		ast_log(LOG_NOTICE, "Content is '%s', not 'application/sdp'\n", get_header(req, "Content-Type"));
    		return -1;
    	}
    	m = get_sdp(req, "m");
    
    	c = get_sdp_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;
    	}
    	if (sscanf(c, "IN IP4 %256s", host) != 1) {
    		ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
    		return -1;
    	}
    	/* XXX This could block for a long time, and block the main thread! XXX */
    
    	hp = ast_gethostbyname(host, &ahp);
    
    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;
    	}
    
    	ast_set_flag(&p->flags[0], SIP_NOVIDEO);	
    
    	while ((m = get_sdp_iterate(&iterator, req, "m"))[0] != '\0') {
    
    		if ((sscanf(m, "audio %d/%d RTP/AVP %n", &x, &y, &len) == 2) ||
    		    (sscanf(m, "audio %d RTP/AVP %n", &x, &len) == 1)) {
    
    			/* 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);
    
    		if (p->vrtp)
    
    			ast_rtp_pt_clear(p->vrtp);  /* Must be cleared in case no m=video line exists */
    
    		if (p->vrtp && (sscanf(m, "video %d RTP/AVP %n", &x, &len) == 1)) {
    
    			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(p->vrtp, codec);
    			}
    		}
    
    		if (!found )
    			ast_log(LOG_WARNING, "Unknown SDP media type in offer: %s\n", m);
    	}
    	if (portno == -1 && vportno == -1) {
    		/* No acceptable offer found in SDP */
    		return -2;
    
    	/* Check for Media-description-level-address for audio */
    	if (pedanticsipchecking) {
    		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 */
    				hp = ast_gethostbyname(host, &ahp);
    				if (!hp) {
    					ast_log(LOG_WARNING, "Unable to lookup host in secondary c= line, '%s'\n", c);
    				}
    			}
    		}
    	}
    
    	/* RTP addresses and ports for audio and video */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	sin.sin_family = AF_INET;
    	memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
    
    	/* Setup audio port number */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	sin.sin_port = htons(portno);
    
    	if (p->rtp && sin.sin_port) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_rtp_set_peer(p->rtp, &sin);
    
    		if (debug) {
    			ast_verbose("Peer audio RTP is at port %s:%d\n", ast_inet_ntoa(iabuf,sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
    		}
    	}
    
    	/* Check for Media-description-level-address for video */
    	if (pedanticsipchecking) {
    		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 */
    				hp = ast_gethostbyname(host, &ahp);
    				if (!hp) {
    					ast_log(LOG_WARNING, "Unable to lookup host in secondary c= line, '%s'\n", c);
    				}
    			}
    		}
    	}
    
    	/* Setup video port number */
    	sin.sin_port = htons(vportno);
    
    	if (p->vrtp && sin.sin_port) {
    
    		ast_rtp_set_peer(p->vrtp, &sin);
    
    		if (debug) {
    			ast_verbose("Peer video RTP is at port %s:%d\n", ast_inet_ntoa(iabuf,sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
    		}
    	}
    
    	/* Next, scan through each "a=rtpmap:" line, noting each