@ -1282,6 +1282,7 @@ struct sip_pvt {
int initid ; /*!< Auto-congest ID if appropriate (scheduler) */
int waitid ; /*!< Wait ID for scheduler after 491 or other delays */
int autokillid ; /*!< Auto-kill ID (scheduler) */
int t38id ; /*!< T.38 Response ID */
enum transfermodes allowtransfer ; /*!< REFER: restriction scheme */
struct sip_refer * refer ; /*!< REFER: SIP transfer data structure */
enum subscriptiontype subscribed ; /*!< SUBSCRIBE: Is this dialog a subscription? */
@ -2070,7 +2071,6 @@ static int sip_get_codec(struct ast_channel *chan);
static struct ast_frame * sip_rtp_read ( struct ast_channel * ast , struct sip_pvt * p , int * faxdetect ) ;
/*------ T38 Support --------- */
static int sip_handle_t38_reinvite ( struct ast_channel * chan , struct sip_pvt * pvt , int reinvite ) ;
static int transmit_response_with_t38_sdp ( struct sip_pvt * p , char * msg , struct sip_request * req , int retrans ) ;
static struct ast_udptl * sip_get_udptl_peer ( struct ast_channel * chan ) ;
static int sip_set_udptl_peer ( struct ast_channel * chan , struct ast_udptl * udptl ) ;
@ -3968,7 +3968,9 @@ static void change_t38_state(struct sip_pvt *p, int state)
return ;
/* Given the state requested and old state determine what control frame we want to queue up */
if ( state = = T38_ENABLED )
if ( state = = T38_PEER_REINVITE )
message = AST_T38_REQUEST_NEGOTIATE ;
else if ( state = = T38_ENABLED )
message = AST_T38_NEGOTIATED ;
else if ( state = = T38_DISABLED & & old = = T38_ENABLED )
message = AST_T38_TERMINATED ;
@ -4434,6 +4436,7 @@ static int __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
AST_SCHED_DEL ( sched , p - > waitid ) ;
AST_SCHED_DEL ( sched , p - > autokillid ) ;
AST_SCHED_DEL ( sched , p - > request_queue_sched_id ) ;
AST_SCHED_DEL ( sched , p - > t38id ) ;
if ( p - > rtp ) {
ast_rtp_destroy ( p - > rtp ) ;
@ -5381,8 +5384,13 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
ast_log ( LOG_ERROR , " Invalid datalen for AST_CONTROL_T38. Expected %d, got %d \n " , ( int ) sizeof ( enum ast_control_t38 ) , ( int ) datalen ) ;
} else {
switch ( * ( ( enum ast_control_t38 * ) data ) ) {
case AST_T38_NEGOTIATED :
case AST_T38_REQUEST_NEGOTIATE : /* Request T38 */
if ( p - > t38 . state ! = T38_ENABLED ) {
if ( p - > t38 . state = = T38_PEER_REINVITE ) {
AST_SCHED_DEL ( sched , p - > t38id ) ;
change_t38_state ( p , T38_ENABLED ) ;
transmit_response_with_t38_sdp ( p , " 200 OK " , & p - > initreq , XMIT_CRITICAL ) ;
} else if ( p - > t38 . state ! = T38_ENABLED ) {
change_t38_state ( p , T38_LOCAL_REINVITE ) ;
if ( ! p - > pendinginvite ) {
transmit_reinvite_with_sdp ( p , TRUE , FALSE ) ;
@ -5394,7 +5402,11 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
case AST_T38_TERMINATED :
case AST_T38_REFUSED :
case AST_T38_REQUEST_TERMINATE : /* Shutdown T38 */
if ( p - > t38 . state = = T38_ENABLED )
if ( p - > t38 . state = = T38_PEER_REINVITE ) {
AST_SCHED_DEL ( sched , p - > t38id ) ;
change_t38_state ( p , T38_DISABLED ) ;
transmit_response_reliable ( p , " 488 Not acceptable here " , & p - > initreq ) ;
} else if ( p - > t38 . state = = T38_ENABLED )
transmit_reinvite_with_sdp ( p , FALSE , FALSE ) ;
break ;
default :
@ -5943,6 +5955,7 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
p - > waitid = - 1 ;
p - > autokillid = - 1 ;
p - > request_queue_sched_id = - 1 ;
p - > t38id = - 1 ;
p - > subscribed = NONE ;
p - > stateid = - 1 ;
p - > sessionversion_remote = - 1 ;
@ -14966,7 +14979,6 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
int res = 0 ;
int xmitres = 0 ;
int reinvite = ( p - > owner & & p - > owner - > _state = = AST_STATE_UP ) ;
struct ast_channel * bridgepeer = NULL ;
char * p_hdrval ;
int rtn ;
@ -15078,41 +15090,6 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
}
}
if ( p - > owner & & ( p - > owner - > _state = = AST_STATE_UP ) & & ( bridgepeer = ast_bridged_channel ( p - > owner ) ) ) { /* if this is a re-invite */
struct sip_pvt * bridgepvt = NULL ;
if ( ! bridgepeer - > tech ) {
ast_log ( LOG_WARNING , " Ooooh.. no tech! That's REALLY bad \n " ) ;
break ;
}
if ( IS_SIP_TECH ( bridgepeer - > tech ) ) {
bridgepvt = ( struct sip_pvt * ) ( bridgepeer - > tech_pvt ) ;
if ( bridgepvt - > udptl ) {
if ( p - > t38 . state = = T38_ENABLED & & bridgepvt - > t38 . state = = T38_PEER_REINVITE ) {
sip_handle_t38_reinvite ( bridgepeer , p , 0 ) ;
ast_rtp_set_rtptimers_onhold ( p - > rtp ) ;
if ( p - > vrtp )
ast_rtp_set_rtptimers_onhold ( p - > vrtp ) ; /* Turn off RTP timers while we send fax */
} else if ( p - > t38 . state = = T38_DISABLED & & bridgepvt - > t38 . state = = T38_ENABLED ) {
ast_log ( LOG_WARNING , " RTP re-invite after T38 session not handled yet ! \n " ) ;
/* Insted of this we should somehow re-invite the other side of the bridge to RTP */
/* XXXX Should we really destroy this session here, without any response at all??? */
sip_scheddestroy ( p , DEFAULT_TRANS_TIMEOUT ) ;
}
} else {
ast_debug ( 2 , " Strange... The other side of the bridge does not have a udptl struct \n " ) ;
sip_pvt_lock ( bridgepvt ) ;
change_t38_state ( bridgepvt , T38_DISABLED ) ;
sip_pvt_unlock ( bridgepvt ) ;
change_t38_state ( p , T38_DISABLED ) ;
}
} else {
/* Other side is not a SIP channel */
ast_debug ( 2 , " Strange... The other side of the bridge is not a SIP channel \n " ) ;
change_t38_state ( p , T38_DISABLED ) ;
}
}
if ( ! req - > ignore & & p - > owner ) {
if ( ! reinvite ) {
@ -16875,6 +16852,16 @@ static int sip_uri_cmp(const char *input1, const char *input2)
return sip_uri_params_cmp ( params1 , params2 ) ;
}
/*! \brief Called to deny a T38 reinvite if the core does not respond to our request */
static int sip_t38_abort ( const void * data )
{
struct sip_pvt * p = ( struct sip_pvt * ) data ;
change_t38_state ( p , T38_DISABLED ) ;
transmit_response_reliable ( p , " 488 Not acceptable here " , & p - > initreq ) ;
p - > t38id = - 1 ;
return 0 ;
}
/*! \brief Handle incoming INVITE request
\ note If the INVITE has a Replaces header , it is part of an
@ -17466,70 +17453,14 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
transmit_response ( p , " 100 Trying " , req ) ;
if ( p - > t38 . state = = T38_PEER_REINVITE ) {
struct ast_channel * bridgepeer = NULL ;
struct sip_pvt * bridgepvt = NULL ;
if ( ( bridgepeer = ast_bridged_channel ( p - > owner ) ) ) {
/* We have a bridge, and this is re-invite to switchover to T38 so we send re-invite with T38 SDP, to other side of bridge*/
/*! XXX: we should also check here does the other side supports t38 at all !!! XXX */
if ( IS_SIP_TECH ( bridgepeer - > tech ) ) {
bridgepvt = ( struct sip_pvt * ) bridgepeer - > tech_pvt ;
if ( bridgepvt - > t38 . state = = T38_DISABLED ) {
if ( bridgepvt - > udptl ) { /* If everything is OK with other side's udptl struct */
/* Send re-invite to the bridged channel */
sip_handle_t38_reinvite ( bridgepeer , p , 1 ) ;
} else { /* Something is wrong with peers udptl struct */
ast_log ( LOG_WARNING , " Strange... The other side of the bridge don't have udptl struct \n " ) ;
sip_pvt_lock ( bridgepvt ) ;
change_t38_state ( bridgepvt , T38_DISABLED ) ;
sip_pvt_unlock ( bridgepvt ) ;
transmit_response_reliable ( p , " 488 Not acceptable here " , req ) ;
}
} else {
/* The other side is already setup for T.38 most likely so we need to acknowledge this too */
transmit_response_with_t38_sdp ( p , " 200 OK " , req , XMIT_CRITICAL ) ;
change_t38_state ( p , T38_ENABLED ) ;
}
} else {
/* Other side is not a SIP channel */
transmit_response_reliable ( p , " 488 Not acceptable here " , req ) ;
change_t38_state ( p , T38_DISABLED ) ;
if ( ! p - > lastinvite ) /* Only destroy if this is *not* a re-invite */
sip_scheddestroy ( p , DEFAULT_TRANS_TIMEOUT ) ;
}
} else {
/* we are not bridged in a call */
transmit_response_with_t38_sdp ( p , " 200 OK " , req , XMIT_CRITICAL ) ;
change_t38_state ( p , T38_ENABLED ) ;
}
} else if ( p - > t38 . state = = T38_DISABLED ) { /* Channel doesn't have T38 offered or enabled */
int sendok = TRUE ;
/* If we are bridged to a channel that has T38 enabled than this is a case of RTP re-invite after T38 session */
/* so handle it here (re-invite other party to RTP) */
struct ast_channel * bridgepeer = NULL ;
struct sip_pvt * bridgepvt = NULL ;
if ( ( bridgepeer = ast_bridged_channel ( p - > owner ) ) ) {
if ( IS_SIP_TECH ( bridgepeer - > tech ) & & ! ast_check_hangup ( bridgepeer ) ) {
bridgepvt = ( struct sip_pvt * ) bridgepeer - > tech_pvt ;
/* Does the bridged peer have T38 ? */
if ( bridgepvt - > t38 . state = = T38_ENABLED ) {
ast_log ( LOG_WARNING , " RTP re-invite after T38 session not handled yet ! \n " ) ;
/* Insted of this we should somehow re-invite the other side of the bridge to RTP */
transmit_response_reliable ( p , " 488 Not Acceptable Here (unsupported) " , req ) ;
sendok = FALSE ;
}
/* No bridged peer with T38 enabled*/
}
}
/* Respond to normal re-invite */
if ( sendok ) {
/* If this is not a re-invite or something to ignore - it's critical */
transmit_response_with_sdp ( p , " 200 OK " , req , ( reinvite ? XMIT_RELIABLE : ( req - > ignore ? XMIT_UNRELIABLE : XMIT_CRITICAL ) ) , p - > session_modify = = TRUE ? FALSE : TRUE ) ;
}
p - > t38id = ast_sched_add ( sched , 5000 , sip_t38_abort , p ) ;
} else if ( p - > t38 . state = = T38_ENABLED ) {
transmit_response_with_t38_sdp ( p , " 200 OK " , req , ( reinvite ? XMIT_RELIABLE : ( req - > ignore ? XMIT_UNRELIABLE : XMIT_CRITICAL ) ) ) ;
} else if ( p - > t38 . state = = T38_DISABLED ) {
/* If this is not a re-invite or something to ignore - it's critical */
transmit_response_with_sdp ( p , " 200 OK " , req , ( reinvite ? XMIT_RELIABLE : ( req - > ignore ? XMIT_UNRELIABLE : XMIT_CRITICAL ) ) , p - > session_modify = = TRUE ? FALSE : TRUE ) ;
}
p - > invitestate = INV_TERMINATED ;
break ;
default :
@ -22003,84 +21934,6 @@ static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl)
return 0 ;
}
/*! \brief Handle T38 reinvite
\ todo Make sure we don ' t destroy the call if we can ' t handle the re - invite .
Nothing should be changed until we have processed the SDP and know that we
can handle it .
*/
static int sip_handle_t38_reinvite ( struct ast_channel * chan , struct sip_pvt * pvt , int reinvite )
{
struct sip_pvt * p ;
int flag = 0 ;
p = chan - > tech_pvt ;
if ( ! p | | ! pvt - > udptl )
return - 1 ;
/* Setup everything on the other side like offered/responded from first side */
sip_pvt_lock ( p ) ;
/*! \todo check if this is not set earlier when setting up the PVT. If not
maybe it should move there . */
p - > t38 . jointcapability = p - > t38 . peercapability = pvt - > t38 . jointcapability ;
ast_udptl_set_far_max_datagram ( p - > udptl , ast_udptl_get_local_max_datagram ( pvt - > udptl ) ) ;
ast_udptl_set_local_max_datagram ( p - > udptl , ast_udptl_get_local_max_datagram ( pvt - > udptl ) ) ;
ast_udptl_set_error_correction_scheme ( p - > udptl , ast_udptl_get_error_correction_scheme ( pvt - > udptl ) ) ;
if ( reinvite ) { /* If we are handling sending re-invite to the other side of the bridge */
/*! \note The SIP_CAN_REINVITE flag is for RTP media redirects,
not really T38 re - invites which are different . In this
case it ' s used properly , to see if we can reinvite over
NAT
*/
if ( ast_test_flag ( & p - > flags [ 0 ] , SIP_CAN_REINVITE ) & & ast_test_flag ( & pvt - > flags [ 0 ] , SIP_CAN_REINVITE ) ) {
ast_udptl_get_peer ( pvt - > udptl , & p - > udptlredirip ) ;
flag = 1 ;
} else {
memset ( & p - > udptlredirip , 0 , sizeof ( p - > udptlredirip ) ) ;
}
if ( ! ast_test_flag ( & p - > flags [ 0 ] , SIP_GOTREFER ) ) {
if ( ! p - > pendinginvite ) {
if ( flag )
ast_debug ( 3 , " Sending reinvite on SIP '%s' - It's UDPTL soon redirected to IP %s:%d \n " , p - > callid , ast_inet_ntoa ( p - > udptlredirip . sin_addr ) , ntohs ( p - > udptlredirip . sin_port ) ) ;
else
ast_debug ( 3 , " Sending reinvite on SIP '%s' - It's UDPTL soon redirected to us (IP %s) \n " , p - > callid , ast_inet_ntoa ( p - > ourip . sin_addr ) ) ;
change_t38_state ( p , T38_LOCAL_REINVITE ) ;
transmit_reinvite_with_sdp ( p , TRUE , FALSE ) ;
} else if ( ! ast_test_flag ( & p - > flags [ 0 ] , SIP_PENDINGBYE ) ) {
if ( flag )
ast_debug ( 3 , " Deferring reinvite on SIP '%s' - It's UDPTL will be redirected to IP %s:%d \n " , p - > callid , ast_inet_ntoa ( p - > udptlredirip . sin_addr ) , ntohs ( p - > udptlredirip . sin_port ) ) ;
else
ast_debug ( 3 , " Deferring reinvite on SIP '%s' - It's UDPTL will be redirected to us (IP %s) \n " , p - > callid , ast_inet_ntoa ( p - > ourip . sin_addr ) ) ;
ast_set_flag ( & p - > flags [ 0 ] , SIP_NEEDREINVITE ) ;
}
}
/* Reset lastrtprx timer */
p - > lastrtprx = p - > lastrtptx = time ( NULL ) ;
sip_pvt_unlock ( p ) ;
return 0 ;
} else { /* If we are handling sending 200 OK to the other side of the bridge */
if ( ast_test_flag ( & p - > flags [ 0 ] , SIP_CAN_REINVITE ) & & ast_test_flag ( & pvt - > flags [ 0 ] , SIP_CAN_REINVITE ) ) {
ast_udptl_get_peer ( pvt - > udptl , & p - > udptlredirip ) ;
flag = 1 ;
} else {
memset ( & p - > udptlredirip , 0 , sizeof ( p - > udptlredirip ) ) ;
}
if ( flag )
ast_debug ( 3 , " Responding 200 OK on SIP '%s' - It's UDPTL soon redirected to IP %s:%d \n " , p - > callid , ast_inet_ntoa ( p - > udptlredirip . sin_addr ) , ntohs ( p - > udptlredirip . sin_port ) ) ;
else
ast_debug ( 3 , " Responding 200 OK on SIP '%s' - It's UDPTL soon redirected to us (IP %s) \n " , p - > callid , ast_inet_ntoa ( p - > ourip . sin_addr ) ) ;
change_t38_state ( pvt , T38_ENABLED ) ;
change_t38_state ( p , T38_ENABLED ) ;
transmit_response_with_t38_sdp ( p , " 200 OK " , & p - > initreq , XMIT_CRITICAL ) ;
p - > lastrtprx = p - > lastrtptx = time ( NULL ) ;
sip_pvt_unlock ( p ) ;
return 0 ;
}
}
/*! \brief Returns null if we can't reinvite audio (part of RTP interface) */
static enum ast_rtp_get_result sip_get_rtp_peer ( struct ast_channel * chan , struct ast_rtp * * rtp )
{