2018-02-27 19:20:58 +00:00
/*-
2015-02-24 18:19:20 +00:00
* SSLsplit - transparent SSL / TLS interception
2018-02-27 19:20:58 +00:00
* https : //www.roe.ch/SSLsplit
*
* Copyright ( c ) 2009 - 2018 , Daniel Roethlisberger < daniel @ roe . ch > .
2019-03-13 11:42:40 +00:00
* Copyright ( c ) 2017 - 2019 , Soner Tari < sonertari @ gmail . com > .
2012-04-13 12:47:30 +00:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
2018-02-27 19:20:58 +00:00
* modification , are permitted provided that the following conditions are met :
* 1. Redistributions of source code must retain the above copyright notice ,
* this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright notice ,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution .
2012-04-13 12:47:30 +00:00
*
2018-02-27 19:20:58 +00:00
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ` ` AS IS ' '
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR
* CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
* CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE )
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE .
2012-04-13 12:47:30 +00:00
*/
# include "pxythrmgr.h"
# include "sys.h"
# include "log.h"
2017-06-29 21:38:37 +00:00
# include "pxyconn.h"
2012-04-13 12:47:30 +00:00
2014-06-21 17:20:34 +00:00
# include <string.h>
2017-07-02 14:47:26 +00:00
# include <event2/bufferevent.h>
2012-04-13 12:47:30 +00:00
# include <pthread.h>
2017-06-30 21:29:39 +00:00
# include <assert.h>
2017-07-29 21:34:46 +00:00
# include <sys/param.h>
2012-04-13 12:47:30 +00:00
/*
* Proxy thread manager : manages the connection handling worker threads
* and the per - thread resources ( i . e . event bases ) . The load is shared
* across num_cpu * 2 connection handling threads , using the number of
* currently assigned connections as the sole metric .
*
* The attach and detach functions are thread - safe .
*/
2017-07-14 19:34:15 +00:00
static void
2017-07-15 01:07:42 +00:00
pxy_thrmgr_get_thr_expired_conns ( pxy_thr_ctx_t * tctx , pxy_conn_ctx_t * * expired_conns )
2017-07-14 19:34:15 +00:00
{
* expired_conns = NULL ;
2017-08-13 01:36:33 +00:00
if ( tctx - > conns ) {
time_t now = time ( NULL ) ;
2017-07-14 19:34:15 +00:00
2017-08-13 01:36:33 +00:00
pxy_conn_ctx_t * ctx = tctx - > conns ;
2017-07-15 01:07:42 +00:00
while ( ctx ) {
2018-03-10 18:29:21 +00:00
time_t elapsed_time = now - ctx - > atime ;
2018-03-11 11:57:58 +00:00
if ( elapsed_time > ( time_t ) tctx - > thrmgr - > opts - > conn_idle_timeout ) {
2017-08-13 01:36:33 +00:00
ctx - > next_expired = * expired_conns ;
* expired_conns = ctx ;
}
ctx = ctx - > next ;
}
2019-03-22 12:21:39 +00:00
ctx = tctx - > pending_ssl_conns ;
while ( ctx ) {
time_t elapsed_time = now - ctx - > atime ;
if ( elapsed_time > ( time_t ) tctx - > thrmgr - > opts - > conn_idle_timeout ) {
ctx - > next_expired = * expired_conns ;
* expired_conns = ctx ;
}
ctx = ctx - > sslctx - > next_pending ;
}
2017-08-13 01:36:33 +00:00
if ( tctx - > thrmgr - > opts - > statslog ) {
ctx = * expired_conns ;
while ( ctx ) {
# ifdef DEBUG_PROXY
2019-03-23 20:32:44 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_thrmgr_get_expired_conns: thr=%d, fd=%d, child_fd=%d, time=%lld, src_addr=%s:%s, dst_addr=%s:%s, user=%s, valid=%d, pc=%d \n " ,
ctx - > thr - > thridx , ctx - > fd , ctx - > child_fd , ( long long ) ( now - ctx - > atime ) ,
STRORDASH ( ctx - > srchost_str ) , STRORDASH ( ctx - > srcport_str ) , STRORDASH ( ctx - > dsthost_str ) , STRORDASH ( ctx - > dstport_str ) ,
STRORDASH ( ctx - > user ) , ctx - > protoctx - > is_valid , ctx - > sslctx ? ctx - > sslctx - > pending : 0 ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
char * msg ;
2019-03-08 22:09:08 +00:00
if ( asprintf ( & msg , " EXPIRED: thr=%d, time=%lld, src_addr=%s:%s, dst_addr=%s:%s, user=%s, valid=%d \n " ,
ctx - > thr - > thridx , ( long long ) ( now - ctx - > atime ) ,
STRORDASH ( ctx - > srchost_str ) , STRORDASH ( ctx - > srcport_str ) , STRORDASH ( ctx - > dsthost_str ) , STRORDASH ( ctx - > dstport_str ) ,
STRORDASH ( ctx - > user ) , ctx - > protoctx - > is_valid ) < 0 ) {
break ;
2017-10-26 15:57:46 +00:00
}
2017-08-13 01:36:33 +00:00
2017-10-29 22:22:34 +00:00
if ( log_conn ( msg ) = = - 1 ) {
log_err_level_printf ( LOG_WARNING , " Expired conn logging failed \n " ) ;
2017-08-13 01:36:33 +00:00
}
free ( msg ) ;
ctx = ctx - > next_expired ;
}
2017-07-14 19:34:15 +00:00
}
}
}
2017-07-29 21:34:46 +00:00
static evutil_socket_t
2019-03-31 14:19:16 +00:00
pxy_thrmgr_print_children ( pxy_conn_child_ctx_t * ctx ,
# ifdef DEBUG_PROXY
unsigned int parent_idx ,
# endif /* DEBUG_PROXY */
evutil_socket_t max_fd )
2017-07-14 19:34:15 +00:00
{
2019-03-31 14:19:16 +00:00
while ( ctx ) {
// @attention No need to log child stats
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2019-03-31 14:19:16 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_thrmgr_print_children: CHILD CONN: thr=%d, id=%d, pid=%u, src=%d, dst=%d, c=%d-%d \n " ,
ctx - > conn - > thr - > thridx , ctx - > conn - > child_count , parent_idx , ctx - > fd , ctx - > dst_fd , ctx - > src . closed , ctx - > dst . closed ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-25 13:07:39 +00:00
2019-03-31 14:19:16 +00:00
max_fd = MAX ( max_fd , MAX ( ctx - > fd , ctx - > dst_fd ) ) ;
ctx = ctx - > next ;
2017-07-14 19:34:15 +00:00
}
2019-03-31 14:19:16 +00:00
return max_fd ;
2017-07-14 19:34:15 +00:00
}
static void
2017-07-15 01:07:42 +00:00
pxy_thrmgr_print_thr_info ( pxy_thr_ctx_t * tctx )
2017-07-14 19:34:15 +00:00
{
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_thrmgr_print_thr_info: thr=%d, load=%lu \n " , tctx - > thridx , tctx - > load ) ;
# endif /* DEBUG_PROXY */
2017-07-14 19:34:15 +00:00
2017-08-13 01:36:33 +00:00
unsigned int idx = 1 ;
2017-07-29 21:34:46 +00:00
evutil_socket_t max_fd = 0 ;
time_t max_atime = 0 ;
time_t max_ctime = 0 ;
2017-08-13 01:36:33 +00:00
char * smsg = NULL ;
2019-03-23 20:32:44 +00:00
if ( tctx - > conns | | tctx - > pending_ssl_conns ) {
2017-07-14 19:34:15 +00:00
time_t now = time ( NULL ) ;
2019-03-23 20:32:44 +00:00
int conns_list = 1 ;
2017-07-15 01:07:42 +00:00
pxy_conn_ctx_t * ctx = tctx - > conns ;
2019-03-23 20:32:44 +00:00
if ( ! ctx ) {
ctx = tctx - > pending_ssl_conns ;
conns_list = 0 ;
}
2017-07-15 01:07:42 +00:00
while ( ctx ) {
2017-07-29 21:34:46 +00:00
time_t atime = now - ctx - > atime ;
time_t ctime = now - ctx - > ctime ;
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2019-03-23 20:32:44 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_thrmgr_print_thr_info: PARENT CONN: thr=%d, id=%u, fd=%d, child_fd=%d, dst=%d, srvdst=%d, child_src=%d, child_dst=%d, p=%d-%d-%d c=%d-%d, ce=%d cc=%d, at=%lld ct=%lld, src_addr=%s:%s, dst_addr=%s:%s, user=%s, valid=%d, pc=%d \n " ,
tctx - > thridx , idx , ctx - > fd , ctx - > child_fd , ctx - > dst_fd , ctx - > srvdst_fd , ctx - > child_src_fd , ctx - > child_dst_fd ,
ctx - > src . closed , ctx - > dst . closed , ctx - > srvdst . closed , ctx - > children ? ctx - > children - > src . closed : 0 , ctx - > children ? ctx - > children - > dst . closed : 0 ,
ctx - > children ? 1 : 0 , ctx - > child_count , ( long long ) atime , ( long long ) ctime ,
STRORDASH ( ctx - > srchost_str ) , STRORDASH ( ctx - > srcport_str ) , STRORDASH ( ctx - > dsthost_str ) , STRORDASH ( ctx - > dstport_str ) ,
STRORDASH ( ctx - > user ) , ctx - > protoctx - > is_valid , ctx - > sslctx ? ctx - > sslctx - > pending : 0 ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-08-19 22:46:57 +00:00
// @attention Report idle connections only, i.e. the conns which have been idle since the last time we checked for expired conns
2018-03-10 19:34:28 +00:00
if ( atime > = ( time_t ) tctx - > thrmgr - > opts - > expired_conn_check_period ) {
2019-03-23 20:32:44 +00:00
if ( asprintf ( & smsg , " IDLE: thr=%d, id=%u, ce=%d cc=%d, at=%lld ct=%lld, src_addr=%s:%s, dst_addr=%s:%s, user=%s, valid=%d, pc=%d \n " ,
2019-03-08 22:09:08 +00:00
tctx - > thridx , idx , ctx - > children ? 1 : 0 , ctx - > child_count , ( long long ) atime , ( long long ) ctime ,
2019-03-23 20:32:44 +00:00
STRORDASH ( ctx - > srchost_str ) , STRORDASH ( ctx - > srcport_str ) , STRORDASH ( ctx - > dsthost_str ) , STRORDASH ( ctx - > dstport_str ) ,
STRORDASH ( ctx - > user ) , ctx - > protoctx - > is_valid , ctx - > sslctx ? ctx - > sslctx - > pending : 0 ) < 0 ) {
return ;
2017-08-19 22:46:57 +00:00
}
2017-10-29 22:22:34 +00:00
if ( log_conn ( smsg ) = = - 1 ) {
log_err_level_printf ( LOG_WARNING , " Idle conn logging failed \n " ) ;
2017-08-19 22:46:57 +00:00
}
free ( smsg ) ;
smsg = NULL ;
2017-07-29 21:34:46 +00:00
}
2017-08-19 22:46:57 +00:00
2019-03-31 14:19:16 +00:00
// child_src_fd and child_dst_fd fields are mostly for debugging purposes, used in debug printing parent conns.
// However, while an ssl child is closing, the children list may be empty, but child's ssl fd may be still open,
// hence we include those fields in this max comparisons too
max_fd = MAX ( max_fd , MAX ( ctx - > fd , MAX ( ctx - > dst_fd , MAX ( ctx - > srvdst_fd , MAX ( ctx - > child_fd , MAX ( ctx - > child_src_fd , ctx - > child_dst_fd ) ) ) ) ) ) ;
2017-07-29 21:34:46 +00:00
max_atime = MAX ( max_atime , atime ) ;
max_ctime = MAX ( max_ctime , ctime ) ;
2017-07-15 01:07:42 +00:00
if ( ctx - > children ) {
2019-03-31 14:19:16 +00:00
max_fd = pxy_thrmgr_print_children ( ctx - > children ,
# ifdef DEBUG_PROXY
idx ,
# endif /* DEBUG_PROXY */
max_fd ) ;
2017-07-14 19:34:15 +00:00
}
2017-08-13 01:36:33 +00:00
idx + + ;
2019-03-23 20:32:44 +00:00
if ( conns_list ) {
ctx = ctx - > next ;
if ( ! ctx ) {
// Switch to pending ssl conns list
ctx = tctx - > pending_ssl_conns ;
conns_list = 0 ;
}
} else {
ctx = ctx - > sslctx - > next_pending ;
}
2017-07-14 19:34:15 +00:00
}
}
2017-07-29 21:34:46 +00:00
2019-03-22 12:21:39 +00:00
if ( asprintf ( & smsg , " STATS: thr=%d, mld=%zu, mfd=%d, mat=%lld, mct=%lld, iib=%llu, iob=%llu, eib=%llu, eob=%llu, swm=%zu, uwm=%zu, to=%zu, err=%zu, pc=%llu, si=%u \n " ,
2018-03-10 18:29:21 +00:00
tctx - > thridx , tctx - > max_load , tctx - > max_fd , ( long long ) max_atime , ( long long ) max_ctime , tctx - > intif_in_bytes , tctx - > intif_out_bytes , tctx - > extif_in_bytes , tctx - > extif_out_bytes ,
2019-03-23 20:32:44 +00:00
tctx - > set_watermarks , tctx - > unset_watermarks , tctx - > timedout_conns , tctx - > errors , tctx - > pending_ssl_conn_count , tctx - > stats_id ) < 0 ) {
return ;
2017-07-29 21:34:46 +00:00
}
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_thrmgr_print_thr_info: %s " , smsg ) ;
# endif /* DEBUG_PROXY */
if ( log_stats ( smsg ) = = - 1 ) {
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_WARNING , " Stats logging failed \n " ) ;
2017-08-13 01:36:33 +00:00
}
free ( smsg ) ;
smsg = NULL ;
2019-03-23 20:32:44 +00:00
tctx - > stats_id + + ;
2017-08-19 22:46:57 +00:00
2017-07-29 21:34:46 +00:00
tctx - > timedout_conns = 0 ;
tctx - > errors = 0 ;
tctx - > set_watermarks = 0 ;
tctx - > unset_watermarks = 0 ;
tctx - > intif_in_bytes = 0 ;
tctx - > intif_out_bytes = 0 ;
tctx - > extif_in_bytes = 0 ;
tctx - > extif_out_bytes = 0 ;
// Reset these stats with the current values (do not reset to 0 directly, there may be active conns)
tctx - > max_fd = max_fd ;
tctx - > max_load = tctx - > load ;
2017-07-14 19:34:15 +00:00
}
2017-07-03 23:12:17 +00:00
2012-04-13 12:47:30 +00:00
/*
2017-07-14 19:34:15 +00:00
* Recurring timer event to prevent the event loops from exiting when
2012-04-13 12:47:30 +00:00
* they run out of events .
*/
static void
2019-03-15 21:44:12 +00:00
pxy_thrmgr_timer_cb ( UNUSED evutil_socket_t fd , UNUSED short what , UNUSED void * arg )
2012-04-13 12:47:30 +00:00
{
2017-07-03 23:12:17 +00:00
pxy_thr_ctx_t * ctx = arg ;
2019-03-14 00:47:03 +00:00
pthread_mutex_lock ( & ctx - > mutex ) ;
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_thrmgr_timer_cb: thr=%d, load=%lu, to=%u \n " , ctx - > thridx , ctx - > load , ctx - > timeout_count ) ;
# endif /* DEBUG_PROXY */
2019-03-15 21:44:12 +00:00
2017-07-15 01:07:42 +00:00
pxy_conn_ctx_t * expired = NULL ;
2017-07-03 23:12:17 +00:00
pxy_thrmgr_get_thr_expired_conns ( ctx , & expired ) ;
if ( expired ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2017-07-03 23:12:17 +00:00
time_t now = time ( NULL ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-03 23:12:17 +00:00
while ( expired ) {
2017-07-15 01:07:42 +00:00
pxy_conn_ctx_t * next = expired - > next_expired ;
2017-07-03 23:12:17 +00:00
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_thrmgr_timer_cb: Delete timed out conn thr=%d, fd=%d, child_fd=%d, at=%lld ct=%lld \n " ,
2019-03-23 20:32:44 +00:00
expired - > thr - > thridx , expired - > fd , expired - > child_fd , ( long long ) ( now - expired - > atime ) , ( long long ) ( now - expired - > ctime ) ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2019-03-14 21:20:53 +00:00
2019-03-15 12:39:15 +00:00
// We have already locked the thr mutex above, do not lock again while detaching, otherwise we get signal 6 crash
2019-03-14 21:20:53 +00:00
// When detach_unlocked is set, *_ctx_free() functions call non-thread-safe detach functions
2019-03-15 12:39:15 +00:00
expired - > thr_locked = 1 ;
2019-03-14 21:20:53 +00:00
2018-10-28 22:59:26 +00:00
// @attention Do not call the term function here, free the conn directly
2017-07-25 13:07:39 +00:00
pxy_conn_free ( expired , 1 ) ;
2017-07-29 21:34:46 +00:00
ctx - > timedout_conns + + ;
2017-07-03 23:12:17 +00:00
expired = next ;
}
}
2017-08-16 13:01:52 +00:00
// @attention Print thread info only if stats logging is enabled, if disabled debug logs are not printed either
2017-08-13 01:36:33 +00:00
if ( ctx - > thrmgr - > opts - > statslog ) {
ctx - > timeout_count + + ;
2019-03-23 22:31:19 +00:00
if ( ctx - > timeout_count > = ctx - > thrmgr - > opts - > stats_period ) {
2017-08-13 01:36:33 +00:00
ctx - > timeout_count = 0 ;
pxy_thrmgr_print_thr_info ( ctx ) ;
}
2017-07-03 23:12:17 +00:00
}
2019-03-14 00:47:03 +00:00
pthread_mutex_unlock ( & ctx - > mutex ) ;
2012-04-13 12:47:30 +00:00
}
/*
* Thread entry point ; runs the event loop of the event base .
* Does not exit until the libevent loop is broken explicitly .
*/
static void *
pxy_thrmgr_thr ( void * arg )
{
pxy_thr_ctx_t * ctx = arg ;
2017-08-16 13:01:52 +00:00
struct timeval timer_delay = { ctx - > thrmgr - > opts - > expired_conn_check_period , 0 } ;
2012-04-13 12:47:30 +00:00
struct event * ev ;
2017-07-03 23:12:17 +00:00
ev = event_new ( ctx - > evbase , - 1 , EV_PERSIST , pxy_thrmgr_timer_cb , ctx ) ;
2012-04-13 12:47:30 +00:00
if ( ! ev )
return NULL ;
evtimer_add ( ev , & timer_delay ) ;
2012-10-23 20:52:54 +00:00
ctx - > running = 1 ;
2012-04-13 12:47:30 +00:00
event_base_dispatch ( ctx - > evbase ) ;
event_free ( ev ) ;
return NULL ;
}
2017-07-01 20:17:45 +00:00
/*
* Create new thread manager but do not start any threads yet .
* This gets called before forking to background .
*/
pxy_thrmgr_ctx_t *
pxy_thrmgr_new ( opts_t * opts )
{
pxy_thrmgr_ctx_t * ctx ;
if ( ! ( ctx = malloc ( sizeof ( pxy_thrmgr_ctx_t ) ) ) )
return NULL ;
memset ( ctx , 0 , sizeof ( pxy_thrmgr_ctx_t ) ) ;
ctx - > opts = opts ;
ctx - > num_thr = 2 * sys_get_cpu_cores ( ) ;
return ctx ;
}
/*
* Start the thread manager and associated threads .
* This must be called after forking .
*
* Returns - 1 on failure , 0 on success .
*/
2013-07-02 13:54:46 +00:00
int
2017-07-01 20:17:45 +00:00
pxy_thrmgr_run ( pxy_thrmgr_ctx_t * ctx )
2013-07-02 13:54:46 +00:00
{
2015-09-27 14:39:24 +00:00
int idx = - 1 , dns = 0 ;
2013-07-02 13:54:46 +00:00
2015-09-27 14:39:24 +00:00
dns = opts_has_dns_spec ( ctx - > opts ) ;
2014-11-04 17:35:00 +00:00
if ( ! ( ctx - > thr = malloc ( ctx - > num_thr * sizeof ( pxy_thr_ctx_t * ) ) ) ) {
2014-01-15 00:03:12 +00:00
log_dbg_printf ( " Failed to allocate memory \n " ) ;
2012-04-13 12:47:30 +00:00
goto leave ;
2014-01-15 00:03:12 +00:00
}
2014-11-04 17:36:08 +00:00
memset ( ctx - > thr , 0 , ctx - > num_thr * sizeof ( pxy_thr_ctx_t * ) ) ;
2012-04-13 12:47:30 +00:00
for ( idx = 0 ; idx < ctx - > num_thr ; idx + + ) {
2014-01-15 00:03:12 +00:00
if ( ! ( ctx - > thr [ idx ] = malloc ( sizeof ( pxy_thr_ctx_t ) ) ) ) {
log_dbg_printf ( " Failed to allocate memory \n " ) ;
2012-04-13 12:47:30 +00:00
goto leave ;
2014-01-15 00:03:12 +00:00
}
2014-11-04 17:36:08 +00:00
memset ( ctx - > thr [ idx ] , 0 , sizeof ( pxy_thr_ctx_t ) ) ;
2012-04-13 12:47:30 +00:00
ctx - > thr [ idx ] - > evbase = event_base_new ( ) ;
2014-01-15 00:03:12 +00:00
if ( ! ctx - > thr [ idx ] - > evbase ) {
log_dbg_printf ( " Failed to create evbase %d \n " , idx ) ;
2012-04-13 12:47:30 +00:00
goto leave ;
2014-01-15 00:03:12 +00:00
}
2015-09-27 14:39:24 +00:00
if ( dns ) {
/* only create dns base if we actually need it later */
ctx - > thr [ idx ] - > dnsbase = evdns_base_new (
ctx - > thr [ idx ] - > evbase , 1 ) ;
if ( ! ctx - > thr [ idx ] - > dnsbase ) {
log_dbg_printf ( " Failed to create dnsbase %d \n " ,
idx ) ;
goto leave ;
}
2014-01-15 00:03:12 +00:00
}
2012-04-13 12:47:30 +00:00
ctx - > thr [ idx ] - > load = 0 ;
2012-10-23 20:52:54 +00:00
ctx - > thr [ idx ] - > running = 0 ;
2017-07-15 01:07:42 +00:00
ctx - > thr [ idx ] - > conns = NULL ;
2017-07-03 23:12:17 +00:00
ctx - > thr [ idx ] - > thridx = idx ;
ctx - > thr [ idx ] - > timeout_count = 0 ;
2017-07-29 21:34:46 +00:00
ctx - > thr [ idx ] - > thrmgr = ctx ;
2019-02-16 14:29:14 +00:00
2019-04-20 22:00:46 +00:00
if ( ctx - > opts - > user_auth & & sqlite3_prepare_v2 ( ctx - > opts - > userdb , " SELECT user,ether,atime,desc FROM users WHERE ip = ?1 " , 100 , & ctx - > thr [ idx ] - > get_user , NULL ) ) {
2019-03-02 00:44:14 +00:00
log_err_level_printf ( LOG_CRIT , " Error preparing get_user sql stmt: %s \n " , sqlite3_errmsg ( ctx - > opts - > userdb ) ) ;
2019-02-16 14:29:14 +00:00
goto leave ;
}
2019-03-14 00:47:03 +00:00
if ( pthread_mutex_init ( & ctx - > thr [ idx ] - > mutex , NULL ) ) {
log_dbg_printf ( " Failed to initialize thr mutex \n " ) ;
goto leave ;
}
2012-04-13 12:47:30 +00:00
}
2013-08-23 15:28:08 +00:00
log_dbg_printf ( " Initialized %d connection handling threads \n " ,
ctx - > num_thr ) ;
2012-04-13 12:47:30 +00:00
for ( idx = 0 ; idx < ctx - > num_thr ; idx + + ) {
if ( pthread_create ( & ctx - > thr [ idx ] - > thr , NULL ,
pxy_thrmgr_thr , ctx - > thr [ idx ] ) )
goto leave_thr ;
2012-10-23 20:52:54 +00:00
while ( ! ctx - > thr [ idx ] - > running ) {
sched_yield ( ) ;
}
2012-04-13 12:47:30 +00:00
}
log_dbg_printf ( " Started %d connection handling threads \n " ,
ctx - > num_thr ) ;
2013-07-02 13:54:46 +00:00
return 0 ;
2012-04-13 12:47:30 +00:00
leave_thr :
idx - - ;
while ( idx > = 0 ) {
pthread_cancel ( ctx - > thr [ idx ] - > thr ) ;
pthread_join ( ctx - > thr [ idx ] - > thr , NULL ) ;
idx - - ;
}
2013-08-24 19:44:40 +00:00
idx = ctx - > num_thr - 1 ;
2012-04-13 12:47:30 +00:00
leave :
while ( idx > = 0 ) {
if ( ctx - > thr [ idx ] ) {
if ( ctx - > thr [ idx ] - > dnsbase ) {
evdns_base_free ( ctx - > thr [ idx ] - > dnsbase , 0 ) ;
}
if ( ctx - > thr [ idx ] - > evbase ) {
event_base_free ( ctx - > thr [ idx ] - > evbase ) ;
}
2019-03-14 00:47:03 +00:00
if ( ctx - > opts - > user_auth ) {
sqlite3_finalize ( ctx - > thr [ idx ] - > get_user ) ;
}
pthread_mutex_destroy ( & ctx - > thr [ idx ] - > mutex ) ;
2012-04-13 12:47:30 +00:00
free ( ctx - > thr [ idx ] ) ;
}
idx - - ;
}
2013-08-23 14:56:12 +00:00
if ( ctx - > thr ) {
2012-04-13 12:47:30 +00:00
free ( ctx - > thr ) ;
2013-08-23 14:56:12 +00:00
ctx - > thr = NULL ;
}
2013-07-02 13:54:46 +00:00
return - 1 ;
2012-04-13 12:47:30 +00:00
}
/*
* Destroy the event manager and stop all threads .
*/
void
pxy_thrmgr_free ( pxy_thrmgr_ctx_t * ctx )
{
2013-08-23 14:56:12 +00:00
if ( ctx - > thr ) {
for ( int idx = 0 ; idx < ctx - > num_thr ; idx + + ) {
event_base_loopbreak ( ctx - > thr [ idx ] - > evbase ) ;
sched_yield ( ) ;
}
for ( int idx = 0 ; idx < ctx - > num_thr ; idx + + ) {
pthread_join ( ctx - > thr [ idx ] - > thr , NULL ) ;
}
for ( int idx = 0 ; idx < ctx - > num_thr ; idx + + ) {
2016-03-25 22:40:45 +00:00
if ( ctx - > thr [ idx ] - > dnsbase ) {
evdns_base_free ( ctx - > thr [ idx ] - > dnsbase , 0 ) ;
}
if ( ctx - > thr [ idx ] - > evbase ) {
event_base_free ( ctx - > thr [ idx ] - > evbase ) ;
}
2019-02-28 23:08:24 +00:00
if ( ctx - > opts - > user_auth ) {
sqlite3_finalize ( ctx - > thr [ idx ] - > get_user ) ;
}
2019-03-14 00:47:03 +00:00
pthread_mutex_destroy ( & ctx - > thr [ idx ] - > mutex ) ;
2013-08-23 14:56:12 +00:00
free ( ctx - > thr [ idx ] ) ;
}
free ( ctx - > thr ) ;
2012-04-13 12:47:30 +00:00
}
free ( ctx ) ;
}
2019-03-22 12:21:39 +00:00
void
pxy_thrmgr_add_pending_ssl_conn ( pxy_conn_ctx_t * ctx )
{
pthread_mutex_lock ( & ctx - > thr - > mutex ) ;
if ( ! ctx - > sslctx - > pending ) {
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_thrmgr_add_pending_ssl_conn: Adding conn, id=%llu, fd=%d \n " , ctx - > id , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
ctx - > sslctx - > pending = 1 ;
ctx - > thr - > pending_ssl_conn_count + + ;
ctx - > sslctx - > next_pending = ctx - > thr - > pending_ssl_conns ;
ctx - > thr - > pending_ssl_conns = ctx ;
}
pthread_mutex_unlock ( & ctx - > thr - > mutex ) ;
}
static void NONNULL ( 1 )
pxy_thrmgr_remove_pending_ssl_conn_unlocked ( pxy_conn_ctx_t * ctx )
{
if ( ctx - > sslctx & & ctx - > sslctx - > pending ) {
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_thrmgr_remove_pending_ssl_conn_unlocked: Removing conn, id=%llu, fd=%d \n " , ctx - > id , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
2019-03-29 12:38:03 +00:00
// Thr pending_ssl_conns list cannot be empty, if the sslctx->pending flag of a conn is set
assert ( ctx - > thr - > pending_ssl_conns ! = NULL ) ;
2019-03-22 12:21:39 +00:00
ctx - > sslctx - > pending = 0 ;
ctx - > thr - > pending_ssl_conn_count - - ;
// @attention We may get multiple conns with the same fd combinations, so fds cannot uniquely define a conn; hence the need for unique ids.
if ( ctx - > id = = ctx - > thr - > pending_ssl_conns - > id ) {
ctx - > thr - > pending_ssl_conns = ctx - > thr - > pending_ssl_conns - > sslctx - > next_pending ;
return ;
} else {
pxy_conn_ctx_t * current = ctx - > thr - > pending_ssl_conns - > sslctx - > next_pending ;
pxy_conn_ctx_t * previous = ctx - > thr - > pending_ssl_conns ;
while ( current ! = NULL & & previous ! = NULL ) {
if ( ctx - > id = = current - > id ) {
previous - > sslctx - > next_pending = current - > sslctx - > next_pending ;
return ;
}
previous = current ;
current = current - > sslctx - > next_pending ;
}
// This should never happen
log_err_level_printf ( LOG_CRIT , " Cannot find conn in thrmgr pending_conns \n " ) ;
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_thrmgr_remove_pending_ssl_conn_unlocked: Cannot find conn in thrmgr pending_conns, id=%llu, fd=%d \n " , ctx - > id , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
assert ( 0 ) ;
}
}
}
void
pxy_thrmgr_remove_pending_ssl_conn ( pxy_conn_ctx_t * ctx )
{
pthread_mutex_lock ( & ctx - > thr - > mutex ) ;
pxy_thrmgr_remove_pending_ssl_conn_unlocked ( ctx ) ;
pthread_mutex_unlock ( & ctx - > thr - > mutex ) ;
}
2019-03-14 00:47:03 +00:00
void
pxy_thrmgr_add_conn ( pxy_conn_ctx_t * ctx )
{
2019-03-18 00:59:40 +00:00
pthread_mutex_lock ( & ctx - > thr - > mutex ) ;
if ( ! ctx - > in_thr_conns ) {
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_thrmgr_add_conn: Adding conn, id=%llu, fd=%d \n " , ctx - > id , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
2019-03-23 17:41:59 +00:00
ctx - > in_thr_conns = 1 ;
2019-03-18 00:59:40 +00:00
// Always keep thr load and conns list in sync
ctx - > thr - > load + + ;
ctx - > next = ctx - > thr - > conns ;
ctx - > thr - > conns = ctx ;
} else {
2019-03-14 21:20:53 +00:00
// Do not add conns twice
2019-03-15 12:39:15 +00:00
// While switching to passthrough mode, the conn must have already been added to its thread's conn list by the previous proto
2019-03-14 21:20:53 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_thrmgr_add_conn: Will not add conn twice, id=%llu, fd=%d \n " , ctx - > id , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
}
2019-03-14 00:47:03 +00:00
pthread_mutex_unlock ( & ctx - > thr - > mutex ) ;
}
2019-03-18 23:08:53 +00:00
static void NONNULL ( 1 )
2019-03-22 12:21:39 +00:00
pxy_thrmgr_remove_conn_unlocked ( pxy_conn_ctx_t * ctx )
2017-06-30 21:29:39 +00:00
{
2019-03-18 23:08:53 +00:00
assert ( ctx ! = NULL ) ;
assert ( ctx - > children = = NULL ) ;
2017-08-13 01:36:33 +00:00
2019-03-18 23:08:53 +00:00
if ( ctx - > in_thr_conns ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2019-03-22 12:21:39 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_thrmgr_remove_conn_unlocked: Removing conn, id=%llu, fd=%d \n " , ctx - > id , ctx - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2019-03-18 23:08:53 +00:00
2019-03-29 12:38:03 +00:00
// Thr conns list cannot be empty, if the in_thr_conns flag of a conn is set
assert ( ctx - > thr - > conns ! = NULL ) ;
2019-03-18 23:08:53 +00:00
// Shouldn't need to reset the in_thr_conns flag, because the conn ctx will be freed next, but just in case
ctx - > in_thr_conns = 0 ;
2019-03-23 17:41:59 +00:00
// We increment thr load in pxy_thrmgr_add_conn() only (for parent conns)
ctx - > thr - > load - - ;
2019-03-18 23:08:53 +00:00
// @attention We may get multiple conns with the same fd combinations, so fds cannot uniquely define a conn; hence the need for unique ids.
if ( ctx - > id = = ctx - > thr - > conns - > id ) {
ctx - > thr - > conns = ctx - > thr - > conns - > next ;
return ;
} else {
pxy_conn_ctx_t * current = ctx - > thr - > conns - > next ;
pxy_conn_ctx_t * previous = ctx - > thr - > conns ;
while ( current ! = NULL & & previous ! = NULL ) {
if ( ctx - > id = = current - > id ) {
previous - > next = current - > next ;
return ;
}
previous = current ;
current = current - > next ;
}
// This should never happen
log_err_level_printf ( LOG_CRIT , " Cannot find conn in thr conns \n " ) ;
# ifdef DEBUG_PROXY
2019-03-22 12:21:39 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_thrmgr_remove_conn_unlocked: Cannot find conn in thr conns, id=%llu, fd=%d \n " , ctx - > id , ctx - > fd ) ;
2019-03-18 23:08:53 +00:00
# endif /* DEBUG_PROXY */
assert ( 0 ) ;
}
} else {
// This can happen if we are closing the conn after a fatal error before setting its event callback
# ifdef DEBUG_PROXY
2019-03-22 12:21:39 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_thrmgr_remove_conn_unlocked: Conn not in thr conns, id=%llu, fd=%d \n " , ctx - > id , ctx - > fd ) ;
2019-03-18 23:08:53 +00:00
# endif /* DEBUG_PROXY */
}
2017-06-29 21:38:37 +00:00
}
2012-04-13 12:47:30 +00:00
/*
* Attach a new connection to a thread . Chooses the thread with the fewest
* currently active connections , returns the appropriate event bases .
2019-03-14 00:47:03 +00:00
* No need to be so accurate about balancing thread loads , so uses
* thread - level mutexes , instead of a thrmgr level mutex .
2012-04-13 12:47:30 +00:00
* Returns the index of the chosen thread ( for passing to _detach later ) .
* This function cannot fail .
*/
2017-07-12 13:46:51 +00:00
void
2017-07-15 01:07:42 +00:00
pxy_thrmgr_attach ( pxy_conn_ctx_t * ctx )
2012-04-13 12:47:30 +00:00
{
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2019-04-03 17:23:30 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_thrmgr_attach: ENTER, fd=%d \n " , ctx - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2012-04-13 12:47:30 +00:00
2017-08-13 01:36:33 +00:00
int thridx = 0 ;
size_t minload ;
2017-07-15 01:07:42 +00:00
pxy_thrmgr_ctx_t * tmctx = ctx - > thrmgr ;
2019-03-14 00:47:03 +00:00
pthread_mutex_lock ( & tmctx - > thr [ 0 ] - > mutex ) ;
minload = tmctx - > thr [ 0 ] - > load ;
pthread_mutex_unlock ( & tmctx - > thr [ 0 ] - > mutex ) ;
2017-07-15 01:07:42 +00:00
2012-04-13 12:47:30 +00:00
# ifdef DEBUG_THREAD
log_dbg_printf ( " ===> Proxy connection handler thread status: \n "
2019-03-14 00:47:03 +00:00
" thr[0]: %zu \n " , minload ) ;
2012-04-13 12:47:30 +00:00
# endif /* DEBUG_THREAD */
2017-07-15 01:07:42 +00:00
for ( int idx = 1 ; idx < tmctx - > num_thr ; idx + + ) {
2019-03-14 00:47:03 +00:00
pthread_mutex_lock ( & tmctx - > thr [ idx ] - > mutex ) ;
2012-04-13 12:47:30 +00:00
# ifdef DEBUG_THREAD
2017-07-15 01:07:42 +00:00
log_dbg_printf ( " thr[%d]: %zu \n " , idx , tmctx - > thr [ idx ] - > load ) ;
2012-04-13 12:47:30 +00:00
# endif /* DEBUG_THREAD */
2017-07-15 01:07:42 +00:00
if ( minload > tmctx - > thr [ idx ] - > load ) {
minload = tmctx - > thr [ idx ] - > load ;
2012-04-13 12:47:30 +00:00
thridx = idx ;
}
2019-03-14 00:47:03 +00:00
pthread_mutex_unlock ( & tmctx - > thr [ idx ] - > mutex ) ;
2012-04-13 12:47:30 +00:00
}
2017-07-15 01:07:42 +00:00
2019-03-15 12:39:15 +00:00
// Defer adding the conn to the conn list of its thread until after a successful conn setup while returning from pxy_conn_connect()
2019-03-14 00:47:03 +00:00
// otherwise pxy_thrmgr_timer_cb() may try to access the conn ctx while it is being freed on failure (signal 6 crash)
2019-03-22 21:09:18 +00:00
ctx - > thr = tmctx - > thr [ thridx ] ;
2017-07-15 01:07:42 +00:00
ctx - > evbase = ctx - > thr - > evbase ;
ctx - > dnsbase = ctx - > thr - > dnsbase ;
2017-07-12 13:46:51 +00:00
2017-07-01 20:17:45 +00:00
# ifdef DEBUG_THREAD
log_dbg_printf ( " thridx: %d \n " , thridx ) ;
# endif /* DEBUG_THREAD */
2012-04-13 12:47:30 +00:00
}
2017-07-03 23:12:17 +00:00
void
2017-07-15 01:07:42 +00:00
pxy_thrmgr_attach_child ( pxy_conn_ctx_t * ctx )
2017-07-03 23:12:17 +00:00
{
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2019-04-03 17:23:30 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_thrmgr_attach_child: ENTER, fd=%d \n " , ctx - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2019-03-14 00:47:03 +00:00
pthread_mutex_lock ( & ctx - > thr - > mutex ) ;
2017-07-15 01:07:42 +00:00
ctx - > thr - > load + + ;
2019-03-14 00:47:03 +00:00
pthread_mutex_unlock ( & ctx - > thr - > mutex ) ;
2017-07-03 23:12:17 +00:00
}
2012-04-13 12:47:30 +00:00
/*
* Detach a connection from a thread by index .
* This function cannot fail .
*/
void
2019-03-22 12:21:39 +00:00
pxy_thrmgr_detach_unlocked ( pxy_conn_ctx_t * ctx )
2012-04-13 12:47:30 +00:00
{
2019-03-14 21:20:53 +00:00
# ifdef DEBUG_PROXY
2019-04-03 17:23:30 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_thrmgr_detach_unlocked: ENTER, fd=%d \n " , ctx - > fd ) ;
2019-03-14 21:20:53 +00:00
# endif /* DEBUG_PROXY */
2019-03-22 12:21:39 +00:00
pxy_thrmgr_remove_pending_ssl_conn_unlocked ( ctx ) ;
pxy_thrmgr_remove_conn_unlocked ( ctx ) ;
2019-03-14 21:20:53 +00:00
}
void
2019-03-22 12:21:39 +00:00
pxy_thrmgr_detach ( pxy_conn_ctx_t * ctx )
2019-03-14 21:20:53 +00:00
{
pthread_mutex_lock ( & ctx - > thr - > mutex ) ;
2019-03-22 12:21:39 +00:00
pxy_thrmgr_detach_unlocked ( ctx ) ;
2019-03-14 00:47:03 +00:00
pthread_mutex_unlock ( & ctx - > thr - > mutex ) ;
2017-06-29 21:38:37 +00:00
}
2017-07-02 14:47:26 +00:00
void
2019-03-22 12:21:39 +00:00
pxy_thrmgr_detach_child_unlocked ( pxy_conn_ctx_t * ctx )
2017-07-02 14:47:26 +00:00
{
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2019-04-03 17:23:30 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_thrmgr_detach_child_unlocked: ENTER, fd=%d \n " , ctx - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-15 01:07:42 +00:00
ctx - > thr - > load - - ;
2019-03-14 21:20:53 +00:00
}
void
2019-03-22 12:21:39 +00:00
pxy_thrmgr_detach_child ( pxy_conn_ctx_t * ctx )
2019-03-14 21:20:53 +00:00
{
pthread_mutex_lock ( & ctx - > thr - > mutex ) ;
2019-03-22 12:21:39 +00:00
pxy_thrmgr_detach_child_unlocked ( ctx ) ;
2019-03-14 00:47:03 +00:00
pthread_mutex_unlock ( & ctx - > thr - > mutex ) ;
2017-07-02 14:47:26 +00:00
}
2012-04-13 12:47:30 +00:00
/* vim: set noet ft=c: */