@ -118,75 +118,7 @@ int open_socket(net_utils::addr_family ip_type, net_utils::socket_type socket_ty
perror ( " Could not create socket \n " ) ;
return - 1 ;
}
if ( protocol = = protocol_type : : SCTP ) {
// Sets the data_io_event to be able to use sendrecv_info
// Subscribes to the SCTP_SHUTDOWN event, to handle graceful shutdown
// Also subscribes to SCTP_PEER_ADDR_CHANGE, to handle ungraceful shutdown of the link.
struct sctp_event_subscribe evnts = { } ;
evnts . sctp_data_io_event = 1 ;
evnts . sctp_shutdown_event = 1 ;
evnts . sctp_address_event = 1 ;
if ( setsockopt ( fd , IPPROTO_SCTP , SCTP_EVENTS , & evnts , sizeof ( evnts ) ) ! = 0 ) {
srslog : : fetch_basic_logger ( LOGSERVICE ) . error ( " Failed to subscribe to SCTP_SHUTDOWN event: %s " , strerror ( errno ) ) ;
perror ( " Could not register socket to SCTP events \n " ) ;
close ( fd ) ;
return - 1 ;
}
/*
* Modify SCTP default parameters for quicker detection of broken links .
* This includes changes to the SCTP_INITMSG parameters ( to control the timeout of the connect ( ) syscall )
* And changes to the maximum re - transmission timeout ( rto_max ) , for quicker detection of broken links .
*/
// Set RTO_MAX to quickly detect broken links.
sctp_rtoinfo rto_opts ;
socklen_t rto_sz = sizeof ( sctp_rtoinfo ) ;
rto_opts . srto_assoc_id = 0 ;
if ( getsockopt ( fd , SOL_SCTP , SCTP_RTOINFO , & rto_opts , & rto_sz ) < 0 ) {
printf ( " Error getting RTO_INFO sockopts \n " ) ;
close ( fd ) ;
return - 1 ;
}
rto_opts . srto_max = 6000 ; // 6 seconds
srslog : : fetch_basic_logger ( LOGSERVICE )
. debug (
" Setting RTO_INFO options on SCTP socket. Association %d, Initial RTO %d, Minimum RTO %d, Maximum RTO %d " ,
rto_opts . srto_assoc_id ,
rto_opts . srto_initial ,
rto_opts . srto_min ,
rto_opts . srto_max ) ;
if ( setsockopt ( fd , SOL_SCTP , SCTP_RTOINFO , & rto_opts , rto_sz ) < 0 ) {
perror ( " Error setting RTO_INFO sockopts \n " ) ;
close ( fd ) ;
return - 1 ;
}
// Set SCTP INITMSG options to reduce blocking timeout of connect()
sctp_initmsg init_opts ;
socklen_t init_sz = sizeof ( sctp_initmsg ) ;
if ( getsockopt ( fd , SOL_SCTP , SCTP_INITMSG , & init_opts , & init_sz ) < 0 ) {
printf ( " Error getting sockopts \n " ) ;
close ( fd ) ;
return - 1 ;
}
init_opts . sinit_max_attempts = 3 ;
init_opts . sinit_max_init_timeo = 5000 ; // 5 seconds
srslog : : fetch_basic_logger ( LOGSERVICE )
. debug ( " Setting SCTP_INITMSG options on SCTP socket. Max attempts %d, Max init attempts timeout %d " ,
init_opts . sinit_max_attempts ,
init_opts . sinit_max_init_timeo ) ;
if ( setsockopt ( fd , SOL_SCTP , SCTP_INITMSG , & init_opts , init_sz ) < 0 ) {
perror ( " Error setting SCTP_INITMSG sockopts \n " ) ;
close ( fd ) ;
return - 1 ;
}
}
srslog : : fetch_basic_logger ( LOGSERVICE ) . debug ( " Opened %s socket=%d " , net_utils : : protocol_to_string ( protocol ) , fd ) ;
return fd ;
}
@ -200,7 +132,12 @@ bool bind_addr(int fd, const sockaddr_in& addr_in)
if ( bind ( fd , ( struct sockaddr * ) & addr_in , sizeof ( addr_in ) ) ! = 0 ) {
srslog : : fetch_basic_logger ( LOGSERVICE )
. error ( " Failed to bind on address %s: %s errno %d " , get_ip ( addr_in ) . c_str ( ) , strerror ( errno ) , errno ) ;
. error ( " Failed to bind on address %s:%d. Socket=%d, strerror=%s, errno=%d " ,
get_ip ( addr_in ) . c_str ( ) ,
get_port ( addr_in ) ,
fd ,
strerror ( errno ) ,
errno ) ;
perror ( " bind() " ) ;
return false ;
}
@ -267,6 +204,107 @@ bool start_listen(int fd)
return true ;
}
bool reuse_addr ( int fd )
{
if ( fd < 0 ) {
srslog : : fetch_basic_logger ( LOGSERVICE ) . error ( " Trying reuse_addr a closed socket. Socket=%d " , fd ) ;
return false ;
}
int enable = 1 ;
if ( setsockopt ( fd , SOL_SOCKET , SO_REUSEADDR , & enable , sizeof ( int ) ) < 0 ) {
srslog : : fetch_basic_logger ( LOGSERVICE ) . error ( " Failed to set SO_REUSEADDR. Socket=%d " , fd ) ;
return false ;
}
srslog : : fetch_basic_logger ( LOGSERVICE ) . debug ( " Successfully set SO_REUSEADDR. Socket=%d " , fd ) ;
return true ;
}
bool sctp_subscribe_to_events ( int fd )
{
if ( fd < 0 ) {
srslog : : fetch_basic_logger ( LOGSERVICE ) . error ( " Trying subscribe to SCTP events on a closed socket. Socket=%d " , fd ) ;
return false ;
}
// Sets the data_io_event to be able to use sendrecv_info
// Subscribes to the SCTP_SHUTDOWN event, to handle graceful shutdown
// Also subscribes to SCTP_PEER_ADDR_CHANGE, to handle ungraceful shutdown of the link.
struct sctp_event_subscribe evnts = { } ;
evnts . sctp_data_io_event = 1 ;
evnts . sctp_shutdown_event = 1 ;
evnts . sctp_address_event = 1 ;
if ( setsockopt ( fd , IPPROTO_SCTP , SCTP_EVENTS , & evnts , sizeof ( evnts ) ) ! = 0 ) {
srslog : : fetch_basic_logger ( LOGSERVICE ) . error ( " Failed to subscribe to SCTP_SHUTDOWN event: %s " , strerror ( errno ) ) ;
perror ( " Could not register socket to SCTP events \n " ) ;
close ( fd ) ;
return false ;
}
return true ;
}
/*
* Modify SCTP default parameters for quicker detection of broken links .
* Changes to the maximum re - transmission timeout ( rto_max ) .
*/
bool sctp_set_rto_opts ( int fd , int rto_max )
{
// Set RTO_MAX to quickly detect broken links.
sctp_rtoinfo rto_opts ;
socklen_t rto_sz = sizeof ( sctp_rtoinfo ) ;
rto_opts . srto_assoc_id = 0 ;
if ( getsockopt ( fd , SOL_SCTP , SCTP_RTOINFO , & rto_opts , & rto_sz ) < 0 ) {
printf ( " Error getting RTO_INFO sockopts \n " ) ;
close ( fd ) ;
return false ;
}
rto_opts . srto_max = rto_max ;
srslog : : fetch_basic_logger ( LOGSERVICE )
. debug ( " Setting RTO_INFO options on SCTP socket. Association %d, Initial RTO %d, Minimum RTO %d, Maximum RTO %d " ,
rto_opts . srto_assoc_id ,
rto_opts . srto_initial ,
rto_opts . srto_min ,
rto_opts . srto_max ) ;
if ( setsockopt ( fd , SOL_SCTP , SCTP_RTOINFO , & rto_opts , rto_sz ) < 0 ) {
perror ( " Error setting RTO_INFO sockopts \n " ) ;
close ( fd ) ;
return false ;
}
return true ;
}
/*
* Modify SCTP default parameters for quicker detection of broken links .
* Changes to the SCTP_INITMSG parameters ( to control the timeout of the connect ( ) syscall )
*/
bool sctp_set_init_msg_opts ( int fd , int init_max_attempts , int max_init_timeo )
{
// Set SCTP INITMSG options to reduce blocking timeout of connect()
sctp_initmsg init_opts ;
socklen_t init_sz = sizeof ( sctp_initmsg ) ;
if ( getsockopt ( fd , SOL_SCTP , SCTP_INITMSG , & init_opts , & init_sz ) < 0 ) {
printf ( " Error getting sockopts \n " ) ;
close ( fd ) ;
return false ;
}
init_opts . sinit_max_attempts = init_max_attempts ;
init_opts . sinit_max_init_timeo = max_init_timeo ;
srslog : : fetch_basic_logger ( LOGSERVICE )
. debug ( " Setting SCTP_INITMSG options on SCTP socket. Max attempts %d, Max init attempts timeout %d " ,
init_opts . sinit_max_attempts ,
init_opts . sinit_max_init_timeo ) ;
if ( setsockopt ( fd , SOL_SCTP , SCTP_INITMSG , & init_opts , init_sz ) < 0 ) {
perror ( " Error setting SCTP_INITMSG sockopts \n " ) ;
close ( fd ) ;
return false ;
}
return true ;
}
} // namespace net_utils
/********************************************
@ -306,9 +344,15 @@ bool unique_socket::open_socket(net_utils::addr_family ip_type,
void unique_socket : : close ( )
{
if ( sockfd > = 0 ) {
: : close ( sockfd ) ;
if ( : : close ( sockfd ) = = - 1 ) {
srslog : : fetch_basic_logger ( LOGSERVICE ) . error ( " Socket=%d could not be closed. " , sockfd ) ;
} else {
srslog : : fetch_basic_logger ( LOGSERVICE ) . debug ( " Socket=%d was closed. " , sockfd ) ;
}
sockfd = - 1 ;
addr = { } ;
} else {
srslog : : fetch_basic_logger ( LOGSERVICE ) . debug ( " Socket=%d could not be closed. " , sockfd ) ;
}
}
@ -327,25 +371,25 @@ bool unique_socket::start_listen()
return net_utils : : start_listen ( sockfd ) ;
}
/***********************************************************************
* SCTP socket
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool unique_socket : : reuse_addr ( )
{
return net_utils : : reuse_addr ( sockfd ) ;
}
namespace net_utils {
bool unique_socket : : sctp_subscribe_to_events ( )
{
return net_utils : : sctp_subscribe_to_events ( sockfd ) ;
}
bool sctp_init_socket ( unique_socket * socket , net_utils : : socket_type socktype , const char * bind_addr_str , int bind_port )
bool unique_socket: : sctp_set_rto_opts ( int rto_max )
{
if ( not socket - > open_socket ( net_utils : : addr_family : : ipv4 , socktype , net_utils : : protocol_type : : SCTP ) ) {
return false ;
}
if ( not socket - > bind_addr ( bind_addr_str , bind_port ) ) {
socket - > close ( ) ;
return false ;
}
return true ;
return net_utils : : sctp_set_rto_opts ( sockfd , rto_max ) ;
}
} // namespace net_utils
bool unique_socket : : sctp_set_init_msg_opts ( int max_init_attempts , int max_init_timeo )
{
return net_utils : : sctp_set_init_msg_opts ( sockfd , max_init_attempts , max_init_timeo ) ;
}
/***************************************************************
* Rx Multisocket Handler