Skip to content
Snippets Groups Projects
chan_sip.c 699 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		case 480:	/* No answer */
    
    			return AST_CAUSE_NO_ANSWER;
    
    		case 481:	/* No answer */
    			return AST_CAUSE_INTERWORKING;
    		case 482:	/* Loop detected */
    			return AST_CAUSE_INTERWORKING;
    
    		case 483:	/* Too many hops */
    
    			return AST_CAUSE_NO_ANSWER;
    
    		case 484:	/* Address incomplete */
    			return AST_CAUSE_INVALID_NUMBER_FORMAT;
    
    		case 485:	/* Ambiguous */
    
    		case 486:	/* Busy everywhere */
    
    		case 487:	/* Request terminated */
    			return AST_CAUSE_INTERWORKING;
    
    		case 488:	/* No codecs approved */
    			return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
    
    		case 491:	/* Request pending */
    			return AST_CAUSE_INTERWORKING;
    		case 493:	/* Undecipherable */
    			return AST_CAUSE_INTERWORKING;
    
    		case 500:	/* Server internal failure */
    			return AST_CAUSE_FAILURE;
    		case 501:	/* Call rejected */
    			return AST_CAUSE_FACILITY_REJECTED;
    		case 502:	
    			return AST_CAUSE_DESTINATION_OUT_OF_ORDER;
    		case 503:	/* Service unavailable */
    			return AST_CAUSE_CONGESTION;
    
    		case 504:	/* Gateway timeout */
    			return AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
    		case 505:	/* SIP version not supported */
    			return AST_CAUSE_INTERWORKING;
    		case 600:	/* Busy everywhere */
    			return AST_CAUSE_USER_BUSY;
    		case 603:	/* Decline */
    			return AST_CAUSE_CALL_REJECTED;
    		case 604:	/* Does not exist anywhere */
    			return AST_CAUSE_UNALLOCATED;
    		case 606:	/* Not acceptable */
    			return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
    
    /*! \brief Convert Asterisk hangup causes to SIP codes 
    
    \verbatim
     Possible values from causes.h
    
            AST_CAUSE_NOTDEFINED    AST_CAUSE_NORMAL        AST_CAUSE_BUSY
            AST_CAUSE_FAILURE       AST_CAUSE_CONGESTION    AST_CAUSE_UNALLOCATED
    
    	In addition to these, a lot of PRI codes is defined in causes.h 
    	...should we take care of them too ?
    	
    	Quote RFC 3398
    
       ISUP Cause value                        SIP response
       ----------------                        ------------
       1  unallocated number                   404 Not Found
       2  no route to network                  404 Not found
       3  no route to destination              404 Not found
       16 normal call clearing                 --- (*)
       17 user busy                            486 Busy here
       18 no user responding                   408 Request Timeout
       19 no answer from the user              480 Temporarily unavailable
       20 subscriber absent                    480 Temporarily unavailable
       21 call rejected                        403 Forbidden (+)
       22 number changed (w/o diagnostic)      410 Gone
       22 number changed (w/ diagnostic)       301 Moved Permanently
       23 redirection to new destination       410 Gone
       26 non-selected user clearing           404 Not Found (=)
       27 destination out of order             502 Bad Gateway
       28 address incomplete                   484 Address incomplete
       29 facility rejected                    501 Not implemented
       31 normal unspecified                   480 Temporarily unavailable
    
    \endverbatim
    
    static const char *hangup_cause2sip(int cause)
    
    		case AST_CAUSE_UNALLOCATED:		/* 1 */
    		case AST_CAUSE_NO_ROUTE_DESTINATION:	/* 3 IAX2: Can't find extension in context */
    		case AST_CAUSE_NO_ROUTE_TRANSIT_NET:	/* 2 */
    			return "404 Not Found";
    
    Olle Johansson's avatar
    Olle Johansson committed
    		case AST_CAUSE_CONGESTION:		/* 34 */
    		case AST_CAUSE_SWITCH_CONGESTION:	/* 42 */
    			return "503 Service Unavailable";
    
    		case AST_CAUSE_NO_USER_RESPONSE:	/* 18 */
    			return "408 Request Timeout";
    		case AST_CAUSE_NO_ANSWER:		/* 19 */
    			return "480 Temporarily unavailable";
    		case AST_CAUSE_CALL_REJECTED:		/* 21 */
    			return "403 Forbidden";
    		case AST_CAUSE_NUMBER_CHANGED:		/* 22 */
    			return "410 Gone";
    		case AST_CAUSE_NORMAL_UNSPECIFIED:	/* 31 */
    			return "480 Temporarily unavailable";
    		case AST_CAUSE_INVALID_NUMBER_FORMAT:
    			return "484 Address incomplete";
    		case AST_CAUSE_USER_BUSY:
    			return "486 Busy here";
    
    		case AST_CAUSE_FAILURE:
    
    Olle Johansson's avatar
    Olle Johansson committed
    			return "500 Server internal failure";
    
    		case AST_CAUSE_FACILITY_REJECTED:	/* 29 */
    			return "501 Not Implemented";
    		case AST_CAUSE_CHAN_NOT_IMPLEMENTED:
    
    			return "503 Service Unavailable";
    
    		/* Used in chan_iax2 */
    		case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
    
    			return "502 Bad Gateway";
    
    		case AST_CAUSE_BEARERCAPABILITY_NOTAVAIL:	/* Can't find codec to connect to host */
    
    			return "488 Not Acceptable Here";
    
    			ast_debug(1, "AST hangup cause %d (no match found in SIP)\n", cause);
    
     * Part of PBX interface, called from ast_hangup */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sip_hangup(struct ast_channel *ast)
    {
    
    	int needcancel = FALSE;
    
    Russell Bryant's avatar
    Russell Bryant committed
    	struct ast_channel *oldowner = ast;
    
    		ast_debug(1, "Asked to hangup channel that was not connected\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return 0;
    	}
    
    	if (ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE)) {
    
    		ast_debug(1, "This call was answered elsewhere");
    
    		append_history(p, "Cancel", "Call answered elsewhere");
    
    		p->answered_elsewhere = TRUE;
    
    	if (ast_test_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER)) {
    
    		if (ast_test_flag(&p->flags[0], SIP_INC_COUNT) || ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) {
    
    			if (sipdebug)
    				ast_debug(1, "update_call_counter(%s) - decrement call limit counter on hangup\n", p->username);
    
    			update_call_counter(p, DEC_CALL_LIMIT);
    		}
    
    		ast_debug(4, "SIP Transfer: Not hanging up right now... Rescheduling hangup for %s.\n", p->callid);
    
    		if (p->autokillid > -1)
    			sip_cancel_destroy(p);
    
    		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
    
    		ast_clear_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER);	/* Really hang up next time */
    
    		p->owner->tech_pvt = dialog_unref(p->owner->tech_pvt);
    
    		p->owner = NULL;  /* Owner will be gone after we return, so take it away */
    		return 0;
    	}
    
    Joshua Colp's avatar
    Joshua Colp committed
    	if (ast_test_flag(ast, AST_FLAG_ZOMBIE)) {
    		if (p->refer)
    			ast_debug(1, "SIP Transfer: Hanging up Zombie channel %s after transfer ... Call-ID: %s\n", ast->name, p->callid);
    		else
    			ast_debug(1, "Hanging up zombie call. Be scared.\n");
    	} else
    		ast_debug(1, "Hangup call %s, SIP callid %s\n", ast->name, p->callid);
    
    	if (ast_test_flag(&p->flags[0], SIP_INC_COUNT) || ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) {
    
    		if (sipdebug)
    			ast_debug(1, "update_call_counter(%s) - decrement call limit counter on hangup\n", p->username);
    
    		update_call_counter(p, DEC_CALL_LIMIT);
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Determine how to disconnect */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (p->owner != ast) {
    
    		ast_log(LOG_WARNING, "Huh?  We aren't the owner? Can't hangup call.\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return 0;
    	}
    
    	/* If the call is not UP, we need to send CANCEL instead of BYE */
    
    	/* In case of re-invites, the call might be UP even though we have an incomplete invite transaction */
    	if (p->invitestate < INV_COMPLETED && p->owner->_state != AST_STATE_UP) {
    
    		needcancel = TRUE;
    
    		ast_debug(4, "Hanging up channel in state %s (not UP)\n", ast_state2str(ast->_state));
    
    	stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */
    
    
    	append_history(p, needcancel ? "Cancel" : "Hangup", "Cause %s", p->owner ? ast_cause2str(p->owner->hangupcause) : "Unknown");
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Disconnect */
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_dsp_free(p->vad);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	p->owner = NULL;
    
    	ast->tech_pvt = dialog_unref(ast->tech_pvt);
    
    	ast_module_unref(ast_module_info->self);
    
    	/* Do not destroy this pvt until we have timeout or
    	   get an answer to the BYE or INVITE/CANCEL 
    	   If we get no answer during retransmit period, drop the call anyway.
    	   (Sorry, mother-in-law, you can't deny a hangup by sending
    	   603 declined to BYE...)
    	*/
    
    		needdestroy = 1;	/* Set destroy flag at end of this function */
    
    	else if (p->invitestate != INV_CALLING)
    
    		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Start the process if it's not already started */
    
    	if (!p->alreadygone && !ast_strlen_zero(p->initreq.data)) {
    
    			if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
    
    				/* stop retransmitting an INVITE that has not received a response */
    				__sip_pretend_ack(p);
    
    
    				/* if we can't send right now, mark it pending */
    
    				if (p->invitestate == INV_CALLING) {
    					/* We can't send anything in CALLING state */
    
    					ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
    
    					/* Do we need a timer here if we don't hear from them at all? */
    
    					sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
    					append_history(p, "DELAY", "Not sending cancel, waiting for timeout");
    
    					transmit_request(p, SIP_CANCEL, p->ocseq, XMIT_RELIABLE, FALSE);
    
    					/* Actually don't destroy us yet, wait for the 487 on our original 
    					   INVITE, but do set an autodestruct just in case we never get it. */
    
    					sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
    
    					p->invitestate = INV_CANCELLED;
    
    Mark Spencer's avatar
    Mark Spencer committed
    				if ( p->initid != -1 ) {
    					/* channel still up - reverse dec of inUse counter
    					   only if the channel is not auto-congested */
    
    Mark Spencer's avatar
    Mark Spencer committed
    				}
    
    				const char *res;
    				if (ast->hangupcause && (res = hangup_cause2sip(ast->hangupcause)))
    
    					transmit_response_reliable(p, res, &p->initreq);
    
    					transmit_response_reliable(p, "603 Declined", &p->initreq);
    
    				p->invitestate = INV_TERMINATED;
    
    				char *audioqos = "";
    				char *videoqos = "";
    
    					audioqos = ast_rtp_get_quality(p->rtp, NULL);
    
    					videoqos = ast_rtp_get_quality(p->vrtp, NULL);
    
    					textqos = ast_rtp_get_quality(p->trtp, NULL);
    
    				transmit_request_with_auth(p, SIP_BYE, 0, XMIT_RELIABLE, 1);
    
    
    				/* Get RTCP quality before end of call */
    
    					if (p->rtp)
    
    						append_history(p, "RTCPaudio", "Quality:%s", audioqos);
    
    					if (p->vrtp)
    
    						append_history(p, "RTCPvideo", "Quality:%s", videoqos);
    
    					if (p->trtp)
    						append_history(p, "RTCPtext", "Quality:%s", textqos);
    
    				if (p->rtp && oldowner)
    					pbx_builtin_setvar_helper(oldowner, "RTPAUDIOQOS", audioqos);
    				if (p->vrtp && oldowner)
    					pbx_builtin_setvar_helper(oldowner, "RTPVIDEOQOS", videoqos);
    
    				if (p->trtp && oldowner)
    					pbx_builtin_setvar_helper(oldowner, "RTPTEXTQOS", textqos);
    
    				/* Note we will need a BYE when this all settles out
    				   but we can't send one while we have "INVITE" outstanding. */
    
    				ast_set_flag(&p->flags[0], SIP_PENDINGBYE);	
    				ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE);	
    
    				if (p->waitid)
    					ast_sched_del(sched, p->waitid);
    				p->waitid = -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    /*! \brief Try setting codec suggested by the SIP_CODEC channel variable */
    static void try_suggested_sip_codec(struct sip_pvt *p)
    {
    	int fmt;
    	const char *codec;
    
    	codec = pbx_builtin_getvar_helper(p->owner, "SIP_CODEC");
    	if (!codec) 
    		return;
    
    	fmt = ast_getformatbyname(codec);
    	if (fmt) {
    
    		ast_log(LOG_NOTICE, "Changing codec to '%s' for this call because of ${SIP_CODEC} variable\n", codec);
    
    		if (p->jointcapability & fmt) {
    			p->jointcapability &= fmt;
    			p->capability &= fmt;
    		} else
    			ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because it is not shared by both ends.\n");
    	} else
    		ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because of unrecognized/not configured codec (check allow/disallow in sip.conf): %s\n", codec);
    	return;	
    }
    
    
    /*! \brief  sip_answer: Answer SIP call , send 200 OK on Invite 
     * Part of PBX interface */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sip_answer(struct ast_channel *ast)
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (ast->_state != AST_STATE_UP) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_setstate(ast, AST_STATE_UP);
    
    		ast_debug(1, "SIP answering channel: %s\n", ast->name);
    
    		if (p->t38.state == T38_PEER_DIRECT) {
    			p->t38.state = T38_ENABLED;
    
    			ast_debug(2,"T38State change to %d on channel %s\n", p->t38.state, ast->name);
    
    			res = transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
    
    			res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    }
    
    
    /*! \brief Send frame to media channel (rtp) */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res = 0;
    
    	switch (frame->frametype) {
    	case AST_FRAME_VOICE:
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (!(frame->subclass & ast->nativeformats)) {
    
    			char s1[512], s2[512], s3[512];
    			ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %s(%d) read/write = %s(%d)/%s(%d)\n",
    				frame->subclass, 
    				ast_getformatname_multiple(s1, sizeof(s1) - 1, ast->nativeformats & AST_FORMAT_AUDIO_MASK),
    				ast->nativeformats & AST_FORMAT_AUDIO_MASK,
    				ast_getformatname_multiple(s2, sizeof(s2) - 1, ast->readformat),
    				ast->readformat,
    				ast_getformatname_multiple(s3, sizeof(s3) - 1, ast->writeformat),
    				ast->writeformat);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    				/* If channel is not up, activate early media session */
    
    				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);	
    
    				p->lastrtptx = time(NULL);
    				res = ast_rtp_write(p->rtp, frame);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			}
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    		break;
    	case AST_FRAME_VIDEO:
    
    				/* Activate video early media */
    
    				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);	
    
    				p->lastrtptx = time(NULL);
    				res = ast_rtp_write(p->vrtp, frame);
    
    	case AST_FRAME_TEXT:
    		if (p) {
    			sip_pvt_lock(p);
    			if (p->trtp) {
    				/* Activate text early media */
    				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);	
    				}
    				p->lastrtptx = time(NULL);
    				res = ast_rtp_write(p->trtp, frame);
    			}
    			sip_pvt_unlock(p);
    		}
    		break;
    
    	case AST_FRAME_IMAGE:
    
    			/* UDPTL requires two-way communication, so early media is not needed here.
    				we simply forget the frames if we get modem frames before the bridge is up.
    				Fax will re-transmit.
    			*/
    
    			if (p->udptl && ast->_state == AST_STATE_UP) 
    
    				res = ast_udptl_write(p->udptl, frame);
    
    		ast_log(LOG_WARNING, "Can't send %d type frames with SIP write\n", frame->frametype);
    		return 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    
    /*! \brief  sip_fixup: Fix up a channel:  If a channel is consumed, this is called.
    
            Basically update any ->owner links */
    
    static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
    
    	if (newchan && ast_test_flag(newchan, AST_FLAG_ZOMBIE))
    		ast_debug(1, "New channel is zombie\n");
    	if (oldchan && ast_test_flag(oldchan, AST_FLAG_ZOMBIE))
    		ast_debug(1, "Old channel is zombie\n");
    
    	if (!newchan || !newchan->tech_pvt) {
    
    Olle Johansson's avatar
    Olle Johansson committed
    		if (!newchan)
    			ast_log(LOG_WARNING, "No new channel! Fixup of %s failed.\n", oldchan->name);
    		else
    			ast_log(LOG_WARNING, "No SIP tech_pvt! Fixup of %s failed.\n", oldchan->name);
    
    		return -1;
    	}
    	p = newchan->tech_pvt;
    
    	append_history(p, "Masq", "Old channel: %s\n", oldchan->name);
    
    	append_history(p, "Masq (cont)", "...new owner: %s\n", newchan->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;
    
    	ast_debug(3, "SIP Fixup: New owner for dialogue %s: %s (Old parent: %s)\n", p->callid, p->owner->name, oldchan->name);
    
    static int sip_senddigit_begin(struct ast_channel *ast, char digit)
    {
    	struct sip_pvt *p = ast->tech_pvt;
    	int res = 0;
    
    
    	switch (ast_test_flag(&p->flags[0], SIP_DTMF)) {
    	case SIP_DTMF_INBAND:
    		res = -1; /* Tell Asterisk to generate inband indications */
    		break;
    	case SIP_DTMF_RFC2833:
    		if (p->rtp)
    			ast_rtp_senddigit_begin(p->rtp, digit);
    		break;
    	default:
    		break;
    	}
    
    /*! \brief Send DTMF character on SIP channel
    	within one call, we're able to transmit in many methods simultaneously */
    
    static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res = 0;
    
    	switch (ast_test_flag(&p->flags[0], SIP_DTMF)) {
    
    	case SIP_DTMF_INFO:
    
    		transmit_info_with_digit(p, digit, duration);
    
    		break;
    	case SIP_DTMF_RFC2833:
    		if (p->rtp)
    
    			ast_rtp_senddigit_end(p->rtp, digit);
    
    		break;
    	case SIP_DTMF_INBAND:
    
    		res = -1; /* Tell Asterisk to stop inband indications */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return res;
    
    /*! \brief Transfer SIP call */
    
    static int sip_transfer(struct ast_channel *ast, const char *dest)
    
    	if (dest == NULL)	/* functions below do not take a NULL */
    		dest = "";
    
    	if (ast->_state == AST_STATE_RING)
    		res = sip_sipredirect(p, dest);
    	else
    		res = transmit_refer(p, dest);
    
    /*! \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;
    
    
    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) {
    
    Olle Johansson's avatar
    Olle Johansson committed
    			p->invitestate = INV_EARLY_MEDIA;
    
    			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);
    
    			p->invitestate = INV_COMPLETED;
    
    Olle Johansson's avatar
    Olle Johansson committed
    			sip_alreadygone(p);
    
    			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);
    
    			p->invitestate = INV_COMPLETED;
    
    Olle Johansson's avatar
    Olle Johansson committed
    			sip_alreadygone(p);
    
    			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)) {
    
    Olle Johansson's avatar
    Olle Johansson committed
    			p->invitestate = INV_PROCEEDING;  
    
    		if ((ast->_state != AST_STATE_UP) &&
    		    !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
    		    !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
    
    Olle Johansson's avatar
    Olle Johansson committed
    			p->invitestate = INV_EARLY_MEDIA;
    
    			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:
    		ast_moh_start(ast, data, p->mohinterpret);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	case AST_CONTROL_VIDUPDATE:	/* Request a video frame update */
    
    		if (p->vrtp && !p->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
    		} 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
    	return res;
    
    /*! \brief Initiate a call in the SIP channel
    
    	called from sip_request_call (calls from the pbx ) for outbound channels
    	and from handle_request_invite for inbound channels
    	
    */
    
    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;
    
    	char *decoded_exten;
    
    	{
    		const char *my_name;	/* pick a good name */
    
    		if (title)
    			my_name = title;
    		else if ( (my_name = strchr(i->fromdomain,':')) )
    			my_name++;	/* skip ':' */
    		else
    			my_name = i->fromdomain;
    
    		sip_pvt_unlock(i);
    		/* Don't hold a sip pvt lock while we allocate a channel */
    
    		tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "SIP/%s-%08x", my_name, (int)(long) i);
    
    		ast_log(LOG_WARNING, "Unable to allocate AST channel structure for SIP channel\n");
    
    	sip_pvt_lock(i);
    
    	tmp->tech = ( ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_INFO || ast_test_flag(&i->flags[0], SIP_DTMF) == SIP_DTMF_SHORTINFO) ?  &sip_tech_info : &sip_tech;
    
    	/* Select our native format based on codec preference until we receive
    	   something from another device to the contrary. */
    
    	if (i->jointcapability) { 	/* The joint capabilities of us and peer */
    
    		video = i->jointcapability & AST_FORMAT_VIDEO_MASK;
    		text = i->jointcapability & AST_FORMAT_TEXT_MASK;
    	} else if (i->capability) {		/* Our configured capability for this peer */
    
    		video = i->capability & AST_FORMAT_VIDEO_MASK;
    		text = i->capability & AST_FORMAT_TEXT_MASK;
    	} else {
    
    		what = global_capability;	/* Global codec support */
    
    		video = global_capability & AST_FORMAT_VIDEO_MASK;
    		text = global_capability & AST_FORMAT_TEXT_MASK;
    	}
    
    
    	/* Set the native formats for audio  and merge in video */
    
    	tmp->nativeformats = ast_codec_choose(&i->prefs, what, 1) | video | text;
    
    	ast_debug(3, "*** Our native formats are %s \n", ast_getformatname_multiple(buf, BUFSIZ, tmp->nativeformats));
    	ast_debug(3, "*** Joint capabilities are %s \n", ast_getformatname_multiple(buf, BUFSIZ, i->jointcapability));
    	ast_debug(3, "*** Our capabilities are %s \n", ast_getformatname_multiple(buf, BUFSIZ, i->capability));
    	ast_debug(3, "*** AST_CODEC_CHOOSE formats are %s \n", ast_getformatname_multiple(buf, BUFSIZ, ast_codec_choose(&i->prefs, what, 1)));
    	if (i->prefcodec)
    		ast_debug(3, "*** Our preferred formats from the incoming channel are %s \n", ast_getformatname_multiple(buf, BUFSIZ, i->prefcodec));
    
    
    	/* XXX Why are we choosing a codec from the native formats?? */
    
    	fmt = ast_best_codec(tmp->nativeformats);
    
    
    	/* If we have a prefcodec setting, we have an inbound channel that set a 
    	   preferred format for this call. Otherwise, we check the jointcapability
    	   We also check for vrtp. If it's not there, we are not allowed do any video anyway.
    	 */
    	if (i->vrtp) {
    		if (i->prefcodec)
    			needvideo = i->prefcodec & AST_FORMAT_VIDEO_MASK;	/* Outbound call */
     		else
    			needvideo = i->jointcapability & AST_FORMAT_VIDEO_MASK;	/* Inbound call */
    	}
    
    
    	if (i->trtp) {
    		if (i->prefcodec)
    			needtext = i->prefcodec & AST_FORMAT_TEXT_MASK;	/* Outbound call */
     		else
    			needtext = i->jointcapability & AST_FORMAT_TEXT_MASK;	/* Inbound call */
    	}
    
    
    	if (needvideo) 
    		ast_debug(3, "This channel can handle video! HOLLYWOOD next!\n");
    	else
    		ast_debug(3, "This channel will not be able to handle video.\n");
    
    	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);
    	}
    
    
    	/* Set file descriptors for audio, video, realtime text and UDPTL as needed */
    
    		ast_channel_set_fd(tmp, 0, ast_rtp_fd(i->rtp));
    		ast_channel_set_fd(tmp, 1, ast_rtcp_fd(i->rtp));
    
    		ast_channel_set_fd(tmp, 2, ast_rtp_fd(i->vrtp));
    		ast_channel_set_fd(tmp, 3, ast_rtcp_fd(i->vrtp));
    
    	if (needtext && i->trtp) 
    
    		ast_channel_set_fd(tmp, 4, ast_rtp_fd(i->trtp));
    
    	if (i->udptl)
    
    		ast_channel_set_fd(tmp, 5, ast_udptl_fd(i->udptl));
    
    	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->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);
    
    	i->owner = tmp;
    
    	ast_module_ref(ast_module_info->self);
    
    	ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
    
    	/*Since it is valid to have extensions in the dialplan that have unescaped characters in them
    	 * we should decode the uri before storing it in the channel, but leave it encoded in the sip_pvt
    	 * structure so that there aren't issues when forming URI's
    	 */
    	decoded_exten = ast_strdupa(i->exten);
    	ast_uri_decode(decoded_exten);
    	ast_copy_string(tmp->exten, decoded_exten, sizeof(tmp->exten));
    
    	/* Don't use ast_set_callerid() here because it will
    
    	 * generate an unnecessary NewCallerID event  */
    
    	tmp->cid.cid_ani = ast_strdup(i->cid_num);
    
    	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->callid))
    
    		pbx_builtin_setvar_helper(tmp, "SIPCALLID", i->callid);
    
    	if (i->rtp)
    		ast_jb_configure(tmp, &global_jbconf);
    
    	/* If the INVITE contains T.38 SDP information set the proper channel variable so a created outgoing call will also have T.38 */
    	if (i->udptl && i->t38.state == T38_PEER_DIRECT)
    		pbx_builtin_setvar_helper(tmp, "_T38CALL", "1");
    
    
    	/* 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 (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);
    
    		append_history(i, "NewChan", "Channel %s - from %s", tmp->name, i->callid);
    
    	/* Inform manager user about new channel and their SIP call ID */
    	if (global_callevents)
    		manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
    			"Channel: %s\r\nUniqueid: %s\r\nChanneltype: %s\r\nSIPcallid: %s\r\nSIPfullcontact: %s\r\n",
    			tmp->name, tmp->uniqueid, "SIP", i->callid, i->fullcontact);
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return tmp;
    }
    
    
    /*! \brief Reads one line of SIP message body */
    
    static char *get_body_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 Lookup 'name' in the SDP 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->sdp_end) {
    		const char *r = get_body_by_line(req->line[(*start)++], name, len);
    
    		if (r[0] != '\0')
    			return r;
    	}
    
    /*! \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 4:
    		f = ast_rtp_read(p->trtp);	/* RTP Text */
    		if (sipdebug_text) {
    			int i;
    			unsigned char* arr = f->data;
    			for (i=0; i < f->datalen; i++)
    				ast_verbose("%c", (arr[i] > ' ' && arr[i] < '}') ? arr[i] : '.');
    			ast_verbose(" -> ");
    			for (i=0; i < f->datalen; i++)
    				ast_verbose("%02X ", arr[i]);
    			ast_verbose("\n");
    		}
    		break;
    
    	case 5:
    		f = ast_udptl_read(p->udptl);	/* UDPTL for T.38 */
    		break;