@ -66,7 +66,6 @@ AmSession::AmSession()
m_dtmfDetector ( this ) , m_dtmfEventQueue ( & m_dtmfDetector ) ,
m_dtmfDetectionEnabled ( true ) ,
accept_early_session ( false ) ,
reliable_1xx ( AmConfig : : rel100 ) ,
refresh_method ( REFRESH_UPDATE_FB_REINV ) ,
processing_status ( SESSION_PROCESSING_EVENTS )
# ifdef WITH_ZRTP
@ -79,8 +78,6 @@ AmSession::AmSession()
{
use_local_audio [ AM_AUDIO_IN ] = false ;
use_local_audio [ AM_AUDIO_OUT ] = false ;
if ( reliable_1xx )
dlg . rseq = 0 ; //???
}
AmSession : : ~ AmSession ( )
@ -687,40 +684,6 @@ void AmSession::onSipRequest(const AmSipRequest& req)
if ( req . method = = SIP_METH_INVITE ) {
switch ( reliable_1xx ) {
case REL100_SUPPORTED : /* if support is on, enforce if asked by UAC */
if ( key_in_list ( getHeader ( req . hdrs , SIP_HDR_SUPPORTED ) ,
SIP_EXT_100REL ) | |
key_in_list ( getHeader ( req . hdrs , SIP_HDR_REQUIRE ) ,
SIP_EXT_100REL ) ) {
reliable_1xx = REL100_REQUIRE ;
DBG ( SIP_EXT_100REL " now active. \n " ) ;
}
break ;
case REL100_REQUIRE : /* if support is required, reject if UAC doesn't */
if ( ! ( key_in_list ( getHeader ( req . hdrs , SIP_HDR_SUPPORTED ) ,
SIP_EXT_100REL ) | |
key_in_list ( getHeader ( req . hdrs , SIP_HDR_REQUIRE ) ,
SIP_EXT_100REL ) ) ) {
ERROR ( " ' " SIP_EXT_100REL " ' extension required, but not advertised "
" by peer. \n " ) ;
dlg . reply ( req , 421 , " Extension Required " , " " , " " ,
SIP_HDR_COLSP ( SIP_HDR_REQUIRE ) SIP_EXT_100REL CRLF ) ;
if ( dlg . getStatus ( ) < AmSipDialog : : Connected )
setStopped ( ) ;
return ;
}
break ; // 100rel required
default :
ERROR ( " BUG: unexpected value `%d' for ' " SIP_EXT_100REL " ' switch. " ,
reliable_1xx ) ;
# ifndef NDEBUG
abort ( ) ;
# endif
case 0 : /* support disabled */
break ;
}
try {
onInvite ( req ) ;
}
@ -765,23 +728,9 @@ void AmSession::onSipRequest(const AmSipRequest& req)
} else {
dlg . reply ( req , 415 , " Unsupported Media Type " ) ;
}
} else if ( req . method = = SIP_METH_PRACK ) {
if ( reliable_1xx ! = REL100_REQUIRE ) {
WARN ( " unexpected PRACK received while " SIP_EXT_100REL " not active. \n " ) ;
return ;
}
if ( ( 1 < < MAX_RSEQ_BITS ) < = req . rseq & & req . rseq < = ( unsigned ) abs ( dlg . rseq ) ) {
// call interface function
onPrack ( req , LOC_RSEQ_ORDER ( req . rseq ) ) ;
if ( req . rseq = = ( unsigned ) - dlg . rseq ) {
dlg . rseq = - dlg . rseq ; // confirmed
DBG ( " latest RSeq (%u) confirmed. \n " , dlg . rseq ) ;
}
} else {
WARN ( " no matching RAck value in PRACK (%s). \n " , req . hdrs . c_str ( ) ) ;
return ;
}
} else if ( req . method = = SIP_METH_PRACK ) {
// TODO: SDP
dlg . reply ( req , 200 , " OK " ) ;
}
}
@ -876,47 +825,6 @@ void AmSession::onSipReply(const AmSipReply& reply,
} break ;
default : break ; // continue waiting.
}
// FIXME: should this stay under negotiate_onreply???
if ( 100 < reply . code & & reply . code < 200 & &
reply . method = = SIP_METH_INVITE ) {
switch ( reliable_1xx ) {
case REL100_SUPPORTED :
if ( key_in_list ( getHeader ( reply . hdrs , SIP_HDR_REQUIRE ) ,
SIP_EXT_100REL ) )
reliable_1xx = REL100_REQUIRE ;
else
break ;
case REL100_REQUIRE : {
if ( ! reply . rseq ) {
ERROR ( " no RSeq value (or unsupported 0) in reliable 1xx. \n " ) ;
dlg . cancel ( ) ;
setStopped ( ) ;
break ;
}
string cseq_val = int2str ( reply . cseq ) + " " + reply . method ;
sendPrack ( /*rcvd sdp_offr [TODO]*/ " " , int2str ( reply . rseq ) , cseq_val ) ;
DBG ( SIP_EXT_100REL " now active. \n " ) ;
}
break ;
case 0 :
// 100rel support disabled
break ;
default :
ERROR ( " BUG: unexpected value `%d' for " SIP_EXT_100REL " switch. " ,
reliable_1xx ) ;
# ifndef NDEBUG
abort ( ) ;
# endif
} // switch reliable 1xx
} else if ( 300 < = reply . code & & reliable_1xx & &
reply . method = = SIP_METH_PRACK ) {
// if PRACK fails, tear down session
dlg . cancel ( ) ;
setStopped ( ) ;
} // if 1xx && INVITE || failed && PRACK
} // switch dlg status
} // status < Connected
} //if negotiate_onreply
@ -939,18 +847,11 @@ void AmSession::onNoAck(unsigned int cseq)
void AmSession : : onNoPrack ( const AmSipRequest & req , const AmSipReply & rpl )
{
INFO ( " reply <%s> timed out. \n " , rpl . print ( ) . c_str ( ) ) ;
if ( 100 < rpl . code & & rpl . code < 200 & & reliable_1xx = = REL100_REQUIRE & &
( unsigned ) dlg . rseq = = rpl . rseq & & rpl . method = = SIP_METH_INVITE ) {
INFO ( " reliable %d reply timed out; rejecting request. \n " , rpl . code ) ;
dlg . reply ( req , 504 , " Server Time-out " ) ;
// TODO: handle forking case (when more PRACKs are sent, out of which some
// might time-out/fail).
if ( dlg . getStatus ( ) < AmSipDialog : : Connected )
setStopped ( ) ;
} else {
WARN ( " reply timed-out, but not reliable. \n " ) ; // debugging
}
dlg . reply ( req , 504 , " Server Time-out " ) ;
// TODO: handle forking case (when more PRACKs are sent, out of which some
// might time-out/fail).
if ( dlg . getStatus ( ) < AmSipDialog : : Connected )
setStopped ( ) ;
}
void AmSession : : onAudioEvent ( AmAudioEvent * audio_ev )
@ -982,12 +883,6 @@ void AmSession::onBye(const AmSipRequest& req)
setStopped ( ) ;
}
void AmSession : : onPrack ( const AmSipRequest & req , unsigned cnt )
{
DBG ( " handling #%u PRACK. \n " , cnt ) ;
dlg . reply ( req , 200 , " OK " ) ;
}
int AmSession : : acceptAudio ( const string & body ,
const string & hdrs ,
string * sdp_reply )
@ -1050,46 +945,6 @@ void AmSession::onSendReply(const AmSipRequest& req, unsigned int code,
const string & reason , const string & content_type ,
const string & body , string & hdrs , int flags )
{
if ( req . method = = SIP_METH_INVITE ) {
if ( 100 < code & & code < 200 ) {
switch ( reliable_1xx ) {
case REL100_SUPPORTED :
hdrs + = SIP_HDR_COLSP ( SIP_HDR_SUPPORTED ) SIP_EXT_100REL CRLF ;
break ;
case REL100_REQUIRE :
// add Require HF
hdrs + = SIP_HDR_COLSP ( SIP_HDR_REQUIRE ) SIP_EXT_100REL CRLF ;
// add RSeq HF
# ifndef NDEBUG
if ( ( abs ( dlg . rseq ) & ( ( 1 < < MAX_RSEQ_BITS ) - 1 ) ) = =
( ( 1 < < MAX_RSEQ_BITS ) - 1 ) ) {
ERROR ( " CRITICAL: RSeq value too high: increase MAX_RSEQ_BITS "
" (now %d) and recompile. \n " , MAX_RSEQ_BITS ) ;
abort ( ) ;
}
# endif
if ( dlg . rseq < 0 ) { // RSeq not yet PRACKed
// refuse subsequent 1xx if first isn't yet PRACKed
if ( ( ( ( unsigned ) - dlg . rseq ) & ( ( 1 < < MAX_RSEQ_BITS ) - 1 ) ) = = 0 )
throw AmSession : : Exception ( 491 , " last reliable 1xx not yet "
" PRACKed " ) ;
dlg . rseq - - ;
} else if ( ! dlg . rseq ) { // only init rseq if 1xx is used
unsigned rseq_1st = ( get_random ( ) + 1 ) < < MAX_RSEQ_BITS ;
rseq_1st & = 0x7fffffff ;
dlg . rseq = - ( ( signed ) rseq_1st ) ;
} else {
dlg . rseq = - ( + + dlg . rseq ) ;
}
hdrs + = SIP_HDR_COLSP ( SIP_HDR_RSEQ ) + int2str ( - dlg . rseq ) + CRLF ;
break ;
}
} else if ( code < 300 & & reliable_1xx = = REL100_REQUIRE ) {
if ( dlg . rseq < 0 ) // reliable 1xx is pending
throw AmSession : : Exception ( 491 , " last reliable 1xx not yet PRACKed " ) ;
}
}
CALL_EVENT_H ( onSendReply , req , code , reason , content_type , body , hdrs , flags ) ;
}
@ -1137,19 +992,18 @@ int AmSession::sendUpdate(const string &cont_type, const string &body,
return dlg . update ( cont_type , body , hdrs ) ;
}
void AmSession : : sendPrack ( const string & sdp_offer ,
const string & rseq_val ,
const string & cseq_val )
void AmSession : : onInvite1xxRel ( const AmSipReply & reply )
{
string hdrs = " RAck: " + rseq_val + " " + cseq_val + " \r \n " ;
// TODO: digest an answer based on the sdp_offer
// TODO: should't cseq&rseq be handled in dialog, entirely?!?!
if ( dlg . prack ( /*cont. type*/ " " , /*body*/ " " , hdrs ) < 0 )
// TODO: SDP
if ( dlg . prack ( reply , /*cont. type*/ " " , /*body*/ " " , /*headers*/ " " ) < 0 )
ERROR ( " failed to send PRACK request in session '%s'. \n " , sid4dbg ( ) . c_str ( ) ) ;
}
void AmSession : : onPrack2xx ( const AmSipReply & reply )
{
/* TODO: SDP */
}
string AmSession : : sid4dbg ( )
{
string dbg ;
@ -1165,10 +1019,9 @@ int AmSession::sendReinvite(bool updateSDP, const string& headers, int flags)
RTPStream ( ) - > setLocalIP ( AmConfig : : LocalIP ) ;
string sdp_body ;
sdp . genResponse ( advertisedIP ( ) , RTPStream ( ) - > getLocalPort ( ) , sdp_body ) ;
return dlg . reinvite ( headers + get_100rel_hdr ( reliable_1xx ) , SIP_APPLICATION_SDP ,
sdp_body , flags ) ;
return dlg . reinvite ( headers , SIP_APPLICATION_SDP , sdp_body , flags ) ;
} else {
return dlg . reinvite ( headers + get_100rel_hdr ( reliable_1xx ) , " " , " " , flags ) ;
return dlg . reinvite ( headers , " " , " " , flags ) ;
}
}
@ -1183,8 +1036,7 @@ int AmSession::sendInvite(const string& headers)
// Generate SDP.
string sdp_body ;
sdp . genRequest ( advertisedIP ( ) , RTPStream ( ) - > getLocalPort ( ) , sdp_body ) ;
return dlg . invite ( headers + get_100rel_hdr ( reliable_1xx ) , SIP_APPLICATION_SDP ,
sdp_body ) ;
return dlg . invite ( headers , SIP_APPLICATION_SDP , sdp_body ) ;
}
void AmSession : : setOnHold ( bool hold )
@ -1197,6 +1049,27 @@ void AmSession::setOnHold(bool hold)
unlockAudio ( ) ;
}
void AmSession : : onFailure ( AmSipDialogEventHandler : : FailureCause cause ,
const AmSipRequest * req , const AmSipReply * rpl )
{
switch ( cause ) {
case FAIL_REL100 :
if ( rpl ) {
dlg . cancel ( ) ;
if ( dlg . getStatus ( ) < AmSipDialog : : Connected )
setStopped ( ) ;
} else if ( req ) {
dlg . reply ( * req , 421 , " Extension Required " , " " , " " ,
SIP_HDR_COLSP ( SIP_HDR_REQUIRE ) SIP_EXT_100REL CRLF ) ;
if ( dlg . getStatus ( ) < AmSipDialog : : Connected )
setStopped ( ) ;
}
break ;
default :
break ;
}
}
// Utility for basic NAT handling: allow the config file to specify the IP
// address to use in SDP bodies
string AmSession : : advertisedIP ( )