@ -559,6 +559,10 @@ static int max_expiry = DEFAULT_MAX_EXPIRY; /*!< Maximum accepted registr
static int default_expiry = DEFAULT_DEFAULT_EXPIRY ;
static int default_expiry = DEFAULT_DEFAULT_EXPIRY ;
static int mwi_expiry = DEFAULT_MWI_EXPIRY ;
static int mwi_expiry = DEFAULT_MWI_EXPIRY ;
static int unauth_sessions = 0 ;
static int authlimit = DEFAULT_AUTHLIMIT ;
static int authtimeout = DEFAULT_AUTHTIMEOUT ;
/*! \brief Global jitterbuffer configuration - by default, jb is disabled */
/*! \brief Global jitterbuffer configuration - by default, jb is disabled */
static struct ast_jb_conf default_jbconf =
static struct ast_jb_conf default_jbconf =
{
{
@ -2456,20 +2460,47 @@ static void *sip_tcp_worker_fn(void *data)
return _sip_tcp_helper_thread ( NULL , tcptls_session ) ;
return _sip_tcp_helper_thread ( NULL , tcptls_session ) ;
}
}
/*! \brief Check if the authtimeout has expired.
* \ param start the time when the session started
*
* \ retval 0 the timeout has expired
* \ retval - 1 error
* \ return the number of milliseconds until the timeout will expire
*/
static int sip_check_authtimeout ( time_t start )
{
int timeout ;
time_t now ;
if ( time ( & now ) = = - 1 ) {
ast_log ( LOG_ERROR , " error executing time(): %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
timeout = ( authtimeout - ( now - start ) ) * 1000 ;
if ( timeout < 0 ) {
/* we have timed out */
return 0 ;
}
return timeout ;
}
/*! \brief SIP TCP thread management function
/*! \brief SIP TCP thread management function
This function reads from the socket , parses the packet into a request
This function reads from the socket , parses the packet into a request
*/
*/
static void * _sip_tcp_helper_thread ( struct sip_pvt * pvt , struct ast_tcptls_session_instance * tcptls_session )
static void * _sip_tcp_helper_thread ( struct sip_pvt * pvt , struct ast_tcptls_session_instance * tcptls_session )
{
{
int res , cl ;
int res , cl , timeout = - 1 , authenticated = 0 , flags ;
time_t start ;
struct sip_request req = { 0 , } , reqcpy = { 0 , } ;
struct sip_request req = { 0 , } , reqcpy = { 0 , } ;
struct sip_threadinfo * me = NULL ;
struct sip_threadinfo * me = NULL ;
char buf [ 1024 ] = " " ;
char buf [ 1024 ] = " " ;
struct pollfd fds [ 2 ] = { { 0 } , { 0 } , } ;
struct pollfd fds [ 2 ] = { { 0 } , { 0 } , } ;
struct ast_tcptls_session_args * ca = NULL ;
struct ast_tcptls_session_args * ca = NULL ;
/* If this is a server session, then the connection has already been setup,
/* If this is a server session, then the connection has already been
* simply create the threadinfo object so we can access this thread for writing .
* setup . Check if the authlimit has been reached and if not create the
* threadinfo object so we can access this thread for writing .
*
*
* if this is a client connection more work must be done .
* if this is a client connection more work must be done .
* 1. We own the parent session args for a client connection . This pointer needs
* 1. We own the parent session args for a client connection . This pointer needs
@ -2479,6 +2510,22 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
* 3. Last , the tcptls_session must be started .
* 3. Last , the tcptls_session must be started .
*/
*/
if ( ! tcptls_session - > client ) {
if ( ! tcptls_session - > client ) {
if ( ast_atomic_fetchadd_int ( & unauth_sessions , + 1 ) > = authlimit ) {
/* unauth_sessions is decremented in the cleanup code */
goto cleanup ;
}
if ( ( flags = fcntl ( tcptls_session - > fd , F_GETFL ) ) = = - 1 ) {
ast_log ( LOG_ERROR , " error setting socket to non blocking mode, fcntl() failed: %s \n " , strerror ( errno ) ) ;
goto cleanup ;
}
flags | = O_NONBLOCK ;
if ( fcntl ( tcptls_session - > fd , F_SETFL , flags ) = = - 1 ) {
ast_log ( LOG_ERROR , " error setting socket to non blocking mode, fcntl() failed: %s \n " , strerror ( errno ) ) ;
goto cleanup ;
}
if ( ! ( me = sip_threadinfo_create ( tcptls_session , tcptls_session - > ssl ? SIP_TRANSPORT_TLS : SIP_TRANSPORT_TCP ) ) ) {
if ( ! ( me = sip_threadinfo_create ( tcptls_session , tcptls_session - > ssl ? SIP_TRANSPORT_TLS : SIP_TRANSPORT_TCP ) ) ) {
goto cleanup ;
goto cleanup ;
}
}
@ -2510,13 +2557,41 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
goto cleanup ;
goto cleanup ;
}
}
if ( time ( & start ) = = - 1 ) {
ast_log ( LOG_ERROR , " error executing time(): %s \n " , strerror ( errno ) ) ;
goto cleanup ;
}
for ( ; ; ) {
for ( ; ; ) {
struct ast_str * str_save ;
struct ast_str * str_save ;
res = ast_poll ( fds , 2 , - 1 ) ; /* polls for both socket and alert_pipe */
if ( ! tcptls_session - > client & & req . authenticated & & ! authenticated ) {
authenticated = 1 ;
ast_atomic_fetchadd_int ( & unauth_sessions , - 1 ) ;
}
/* calculate the timeout for unauthenticated server sessions */
if ( ! tcptls_session - > client & & ! authenticated ) {
if ( ( timeout = sip_check_authtimeout ( start ) ) < 0 ) {
goto cleanup ;
}
if ( timeout = = 0 ) {
ast_debug ( 2 , " SIP %s server timed out \n " , tcptls_session - > ssl ? " SSL " : " TCP " ) ;
goto cleanup ;
}
} else {
timeout = - 1 ;
}
res = ast_poll ( fds , 2 , timeout ) ; /* polls for both socket and alert_pipe */
if ( res < 0 ) {
if ( res < 0 ) {
ast_debug ( 2 , " SIP %s server :: ast_wait_for_input returned %d \n " , tcptls_session - > ssl ? " SSL " : " TCP " , res ) ;
ast_debug ( 2 , " SIP %s server :: ast_wait_for_input returned %d \n " , tcptls_session - > ssl ? " SSL " : " TCP " , res ) ;
goto cleanup ;
goto cleanup ;
} else if ( res = = 0 ) {
/* timeout */
ast_debug ( 2 , " SIP %s server timed out \n " , tcptls_session - > ssl ? " SSL " : " TCP " ) ;
goto cleanup ;
}
}
/* handle the socket event, check for both reads from the socket fd,
/* handle the socket event, check for both reads from the socket fd,
@ -2549,6 +2624,29 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
/* Read in headers one line at a time */
/* Read in headers one line at a time */
while ( req . len < 4 | | strncmp ( REQ_OFFSET_TO_STR ( & req , len - 4 ) , " \r \n \r \n " , 4 ) ) {
while ( req . len < 4 | | strncmp ( REQ_OFFSET_TO_STR ( & req , len - 4 ) , " \r \n \r \n " , 4 ) ) {
if ( ! tcptls_session - > client & & ! authenticated ) {
if ( ( timeout = sip_check_authtimeout ( start ) ) < 0 ) {
goto cleanup ;
}
if ( timeout = = 0 ) {
ast_debug ( 2 , " SIP %s server timed out \n " , tcptls_session - > ssl ? " SSL " : " TCP " ) ;
goto cleanup ;
}
} else {
timeout = - 1 ;
}
res = ast_wait_for_input ( tcptls_session - > fd , timeout ) ;
if ( res < 0 ) {
ast_debug ( 2 , " SIP %s server :: ast_wait_for_input returned %d \n " , tcptls_session - > ssl ? " SSL " : " TCP " , res ) ;
goto cleanup ;
} else if ( res = = 0 ) {
/* timeout */
ast_debug ( 2 , " SIP %s server timed out \n " , tcptls_session - > ssl ? " SSL " : " TCP " ) ;
goto cleanup ;
}
ast_mutex_lock ( & tcptls_session - > lock ) ;
ast_mutex_lock ( & tcptls_session - > lock ) ;
if ( ! fgets ( buf , sizeof ( buf ) , tcptls_session - > f ) ) {
if ( ! fgets ( buf , sizeof ( buf ) , tcptls_session - > f ) ) {
ast_mutex_unlock ( & tcptls_session - > lock ) ;
ast_mutex_unlock ( & tcptls_session - > lock ) ;
@ -2567,6 +2665,29 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
if ( sscanf ( get_header ( & reqcpy , " Content-Length " ) , " %30d " , & cl ) ) {
if ( sscanf ( get_header ( & reqcpy , " Content-Length " ) , " %30d " , & cl ) ) {
while ( cl > 0 ) {
while ( cl > 0 ) {
size_t bytes_read ;
size_t bytes_read ;
if ( ! tcptls_session - > client & & ! authenticated ) {
if ( ( timeout = sip_check_authtimeout ( start ) ) < 0 ) {
goto cleanup ;
}
if ( timeout = = 0 ) {
ast_debug ( 2 , " SIP %s server timed out " , tcptls_session - > ssl ? " SSL " : " TCP " ) ;
goto cleanup ;
}
} else {
timeout = - 1 ;
}
res = ast_wait_for_input ( tcptls_session - > fd , timeout ) ;
if ( res < 0 ) {
ast_debug ( 2 , " SIP %s server :: ast_wait_for_input returned %d \n " , tcptls_session - > ssl ? " SSL " : " TCP " , res ) ;
goto cleanup ;
} else if ( res = = 0 ) {
/* timeout */
ast_debug ( 2 , " SIP %s server timed out " , tcptls_session - > ssl ? " SSL " : " TCP " ) ;
goto cleanup ;
}
ast_mutex_lock ( & tcptls_session - > lock ) ;
ast_mutex_lock ( & tcptls_session - > lock ) ;
if ( ! ( bytes_read = fread ( buf , 1 , MIN ( sizeof ( buf ) - 1 , cl ) , tcptls_session - > f ) ) ) {
if ( ! ( bytes_read = fread ( buf , 1 , MIN ( sizeof ( buf ) - 1 , cl ) , tcptls_session - > f ) ) ) {
ast_mutex_unlock ( & tcptls_session - > lock ) ;
ast_mutex_unlock ( & tcptls_session - > lock ) ;
@ -2626,6 +2747,10 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
ast_debug ( 2 , " Shutting down thread for %s server \n " , tcptls_session - > ssl ? " SSL " : " TCP " ) ;
ast_debug ( 2 , " Shutting down thread for %s server \n " , tcptls_session - > ssl ? " SSL " : " TCP " ) ;
cleanup :
cleanup :
if ( ! tcptls_session - > client & & ! authenticated ) {
ast_atomic_fetchadd_int ( & unauth_sessions , - 1 ) ;
}
if ( me ) {
if ( me ) {
ao2_t_unlink ( threadt , me , " Removing tcptls helper thread, thread is closing " ) ;
ao2_t_unlink ( threadt , me , " Removing tcptls helper thread, thread is closing " ) ;
ao2_t_ref ( me , - 1 , " Removing tcp_helper_threads threadinfo ref " ) ;
ao2_t_ref ( me , - 1 , " Removing tcp_helper_threads threadinfo ref " ) ;
@ -21789,6 +21914,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
}
}
}
}
req - > authenticated = 1 ;
/* We have a successful authentication, process the SDP portion if there is one */
/* We have a successful authentication, process the SDP portion if there is one */
if ( find_sdp ( req ) ) {
if ( find_sdp ( req ) ) {
if ( process_sdp ( p , req , SDP_T38_INITIATE ) ) {
if ( process_sdp ( p , req , SDP_T38_INITIATE ) ) {
@ -24020,8 +24147,10 @@ static int handle_request_register(struct sip_pvt *p, struct sip_request *req, s
get_header ( req , " To " ) , ast_sockaddr_stringify ( addr ) ,
get_header ( req , " To " ) , ast_sockaddr_stringify ( addr ) ,
reason ) ;
reason ) ;
append_history ( p , " RegRequest " , " Failed : Account %s : %s " , get_header ( req , " To " ) , reason ) ;
append_history ( p , " RegRequest " , " Failed : Account %s : %s " , get_header ( req , " To " ) , reason ) ;
} else
} else {
req - > authenticated = 1 ;
append_history ( p , " RegRequest " , " Succeeded : Account %s " , get_header ( req , " To " ) ) ;
append_history ( p , " RegRequest " , " Succeeded : Account %s " , get_header ( req , " To " ) ) ;
}
if ( res < 1 ) {
if ( res < 1 ) {
/* Destroy the session, but keep us around for just a bit in case they don't
/* Destroy the session, but keep us around for just a bit in case they don't
@ -24407,6 +24536,11 @@ static int handle_request_do(struct sip_request *req, struct ast_sockaddr *addr)
copy_socket_data ( & p - > socket , & req - > socket ) ;
copy_socket_data ( & p - > socket , & req - > socket ) ;
ast_sockaddr_copy ( & p - > recv , addr ) ;
ast_sockaddr_copy ( & p - > recv , addr ) ;
/* if we have an owner, then this request has been authenticated */
if ( p - > owner ) {
req - > authenticated = 1 ;
}
if ( p - > do_history ) /* This is a request or response, note what it was for */
if ( p - > do_history ) /* This is a request or response, note what it was for */
append_history ( p , " Rx " , " %s / %s / %s " , req - > data - > str , get_header ( req , " CSeq " ) , REQ_OFFSET_TO_STR ( req , rlPart2 ) ) ;
append_history ( p , " Rx " , " %s / %s / %s " , req - > data - > str , get_header ( req , " CSeq " ) , REQ_OFFSET_TO_STR ( req , rlPart2 ) ) ;
@ -27073,6 +27207,8 @@ static int reload_config(enum channelreloadreason reason)
global_qualifyfreq = DEFAULT_QUALIFYFREQ ;
global_qualifyfreq = DEFAULT_QUALIFYFREQ ;
global_t38_maxdatagram = - 1 ;
global_t38_maxdatagram = - 1 ;
global_shrinkcallerid = 1 ;
global_shrinkcallerid = 1 ;
authlimit = DEFAULT_AUTHLIMIT ;
authtimeout = DEFAULT_AUTHTIMEOUT ;
sip_cfg . matchexternaddrlocally = DEFAULT_MATCHEXTERNADDRLOCALLY ;
sip_cfg . matchexternaddrlocally = DEFAULT_MATCHEXTERNADDRLOCALLY ;
@ -27336,6 +27472,18 @@ static int reload_config(enum channelreloadreason reason)
if ( mwi_expiry < 1 ) {
if ( mwi_expiry < 1 ) {
mwi_expiry = DEFAULT_MWI_EXPIRY ;
mwi_expiry = DEFAULT_MWI_EXPIRY ;
}
}
} else if ( ! strcasecmp ( v - > name , " tcpauthtimeout " ) ) {
if ( ast_parse_arg ( v - > value , PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE ,
& authtimeout , DEFAULT_AUTHTIMEOUT , 1 , INT_MAX ) ) {
ast_log ( LOG_WARNING , " Invalid %s '%s' at line %d of %s \n " ,
v - > name , v - > value , v - > lineno , config ) ;
}
} else if ( ! strcasecmp ( v - > name , " tcpauthlimit " ) ) {
if ( ast_parse_arg ( v - > value , PARSE_INT32 | PARSE_DEFAULT | PARSE_IN_RANGE ,
& authlimit , DEFAULT_AUTHLIMIT , 1 , INT_MAX ) ) {
ast_log ( LOG_WARNING , " Invalid %s '%s' at line %d of %s \n " ,
v - > name , v - > value , v - > lineno , config ) ;
}
} else if ( ! strcasecmp ( v - > name , " sipdebug " ) ) {
} else if ( ! strcasecmp ( v - > name , " sipdebug " ) ) {
if ( ast_true ( v - > value ) )
if ( ast_true ( v - > value ) )
sipdebug | = sip_debug_config ;
sipdebug | = sip_debug_config ;