2023-08-07 11:56:36 -04:00
# include <stdio.h>
# include <string.h>
2023-08-01 11:27:06 -04:00
# include <haproxy/api.h>
2023-08-23 11:16:07 -04:00
# include <haproxy/connection.h>
2023-08-01 11:27:06 -04:00
# include <haproxy/errors.h>
2023-11-22 12:02:37 -05:00
# include <haproxy/intops.h>
2023-08-01 11:27:06 -04:00
# include <haproxy/list.h>
# include <haproxy/listener.h>
2023-09-22 09:55:24 -04:00
# include <haproxy/log.h>
2023-08-23 11:16:07 -04:00
# include <haproxy/proto_tcp.h>
2023-08-01 11:27:06 -04:00
# include <haproxy/protocol.h>
2023-08-07 11:56:36 -04:00
# include <haproxy/proxy.h>
2023-11-03 06:03:49 -04:00
# include <haproxy/sample.h>
2023-08-07 11:56:36 -04:00
# include <haproxy/server.h>
2023-11-03 11:21:12 -04:00
# include <haproxy/session.h>
2023-08-23 11:16:07 -04:00
# include <haproxy/sock.h>
2023-11-03 06:03:49 -04:00
# include <haproxy/ssl_sock.h>
2023-08-23 11:16:07 -04:00
# include <haproxy/task.h>
2023-08-01 11:27:06 -04:00
2023-11-21 04:41:06 -05:00
# include <haproxy/proto_rhttp.h>
2023-08-01 11:27:06 -04:00
2023-11-21 05:10:34 -05:00
struct proto_fam proto_fam_rhttp = {
. name = " rhttp " ,
2024-08-09 12:59:46 -04:00
. sock_domain = AF_INET ,
. sock_family = AF_CUST_RHTTP_SRV ,
2024-08-09 14:13:10 -04:00
. real_family = AF_CUST_RHTTP_SRV ,
2023-11-21 05:10:34 -05:00
. bind = rhttp_bind_receiver ,
2023-08-01 11:27:06 -04:00
} ;
2023-11-21 05:10:34 -05:00
struct protocol proto_rhttp = {
2023-08-01 11:27:06 -04:00
. name = " rev " ,
2023-11-17 04:52:13 -05:00
/* connection layer (no outgoing connection) */
2023-11-21 05:10:34 -05:00
. listen = rhttp_bind_listener ,
. enable = rhttp_enable_listener ,
. disable = rhttp_disable_listener ,
2024-05-16 11:35:31 -04:00
. suspend = rhttp_suspend_listener ,
2023-08-07 11:56:36 -04:00
. add = default_add_listener ,
2023-11-21 05:10:34 -05:00
. unbind = rhttp_unbind_receiver ,
2023-08-07 11:56:36 -04:00
. resume = default_resume_listener ,
2023-11-21 05:10:34 -05:00
. accept_conn = rhttp_accept_conn ,
2024-07-11 05:32:29 -04:00
. bind_tid_prep = rhttp_bind_tid_prep ,
2023-08-01 11:27:06 -04:00
/* address family */
2023-11-21 05:10:34 -05:00
. fam = & proto_fam_rhttp ,
2023-08-01 11:27:06 -04:00
/* socket layer */
. proto_type = PROTO_TYPE_STREAM ,
. sock_type = SOCK_STREAM ,
. sock_prot = IPPROTO_TCP ,
2023-11-21 05:10:34 -05:00
. rx_listening = rhttp_accepting_conn ,
. receivers = LIST_HEAD_INIT ( proto_rhttp . receivers ) ,
2023-08-01 11:27:06 -04:00
} ;
2023-08-23 11:16:07 -04:00
static struct connection * new_reverse_conn ( struct listener * l , struct server * srv )
{
struct connection * conn = conn_new ( srv ) ;
2023-10-02 11:17:46 -04:00
struct sockaddr_storage * bind_addr = NULL ;
2023-11-03 11:21:12 -04:00
struct session * sess = NULL ;
2023-08-23 11:16:07 -04:00
if ( ! conn )
goto err ;
2023-11-22 11:55:58 -05:00
HA_ATOMIC_INC ( & th_ctx - > nb_rhttp_conns ) ;
2024-05-23 09:06:52 -04:00
/* session origin is only set after reversal. This ensures fetches
* will be functional only after reversal , in particular src / dst .
*/
2023-11-03 11:21:12 -04:00
sess = session_new ( l - > bind_conf - > frontend , l , NULL ) ;
if ( ! sess )
goto err ;
conn_set_owner ( conn , sess , conn_session_free ) ;
2023-08-23 11:16:07 -04:00
conn_set_reverse ( conn , & l - > obj_type ) ;
2023-10-02 11:17:46 -04:00
if ( alloc_bind_address ( & bind_addr , srv , srv - > proxy , NULL ) ! = SRV_STATUS_OK )
goto err ;
conn - > src = bind_addr ;
2023-08-23 11:16:07 -04:00
sockaddr_alloc ( & conn - > dst , 0 , 0 ) ;
if ( ! conn - > dst )
goto err ;
* conn - > dst = srv - > addr ;
2023-09-21 09:44:17 -04:00
set_host_port ( conn - > dst , srv - > svc_port ) ;
2023-08-23 11:16:07 -04:00
2024-05-14 10:34:49 -04:00
conn - > send_proxy_ofs = 0 ;
2025-03-02 21:58:46 -05:00
if ( srv - > pp_opts & SRV_PP_ENABLED ) {
2024-05-14 10:34:49 -04:00
conn - > flags | = CO_FL_SEND_PROXY ;
conn - > send_proxy_ofs = 1 ; /* must compute size */
}
/* TODO support SOCKS4 */
2023-08-23 11:16:07 -04:00
if ( conn_prepare ( conn , protocol_lookup ( conn - > dst - > ss_family , PROTO_TYPE_STREAM , 0 ) , srv - > xprt ) )
goto err ;
if ( conn - > ctrl - > connect ( conn , 0 ) ! = SF_ERR_NONE )
goto err ;
2023-11-03 06:03:49 -04:00
# ifdef USE_OPENSSL
2025-09-03 10:47:00 -04:00
if ( conn_is_ssl ( conn ) & & srv - > ssl_ctx . sni ) {
2023-11-03 06:03:49 -04:00
struct sample * sni_smp = NULL ;
/* TODO remove NULL session which can cause crash depending on the SNI sample expr used. */
2023-11-03 11:21:12 -04:00
sni_smp = sample_fetch_as_type ( srv - > proxy , sess , NULL ,
2023-11-03 06:03:49 -04:00
SMP_OPT_DIR_REQ | SMP_OPT_FINAL ,
srv - > ssl_ctx . sni , SMP_T_STR ) ;
if ( smp_make_safe ( sni_smp ) )
ssl_sock_set_servername ( conn , sni_smp - > data . u . str . area ) ;
}
# endif /* USE_OPENSSL */
2024-05-14 10:34:49 -04:00
/* The CO_FL_SEND_PROXY flag may have been set by the connect method,
* if so , add our handshake pseudo - XPRT now .
*/
if ( conn - > flags & CO_FL_HANDSHAKE ) {
if ( xprt_add_hs ( conn ) < 0 )
goto err ;
}
2023-08-23 11:16:07 -04:00
if ( conn_xprt_start ( conn ) < 0 )
goto err ;
if ( ! srv - > use_ssl | |
( ! srv - > ssl_ctx . alpn_str & & ! srv - > ssl_ctx . npn_str ) | |
srv - > mux_proto ) {
2023-11-03 11:21:12 -04:00
if ( conn_install_mux_be ( conn , NULL , sess , NULL ) < 0 )
2023-08-23 11:16:07 -04:00
goto err ;
}
return conn ;
err :
2024-05-21 10:35:11 -04:00
if ( l - > rx . rhttp . state ! = LI_PRECONN_ST_ERR ) {
send_log ( l - > bind_conf - > frontend , LOG_ERR ,
" preconnect %s::%s: Error on conn allocation. \n " ,
l - > bind_conf - > frontend - > id , l - > bind_conf - > rhttp_srvname ) ;
l - > rx . rhttp . state = LI_PRECONN_ST_ERR ;
}
2023-11-03 11:21:12 -04:00
/* No need to free session as conn.destroy_cb will take care of it. */
2023-08-23 11:16:07 -04:00
if ( conn ) {
2023-09-29 10:04:21 -04:00
conn_stop_tracking ( conn ) ;
conn_xprt_shutw ( conn ) ;
conn_xprt_close ( conn ) ;
conn_sock_shutw ( conn , 0 ) ;
conn_ctrl_close ( conn ) ;
if ( conn - > destroy_cb )
conn - > destroy_cb ( conn ) ;
2023-08-23 11:16:07 -04:00
/* Mark connection as non-reversable. This prevents conn_free()
2023-11-21 05:10:34 -05:00
* to reschedule rhttp task on freeing a preconnect connection .
2023-08-23 11:16:07 -04:00
*/
conn - > reverse . target = NULL ;
conn_free ( conn ) ;
}
return NULL ;
}
2023-09-22 10:28:35 -04:00
/* Report that a connection used for preconnect on listener <l> is freed before
* reversal is completed . This is used to cleanup any reference to the
* connection and rearm a new preconnect attempt .
*/
2023-11-21 05:10:34 -05:00
void rhttp_notify_preconn_err ( struct listener * l )
2023-09-22 10:28:35 -04:00
{
/* Receiver must reference a reverse connection as pending. */
2023-11-21 05:10:34 -05:00
BUG_ON ( ! l - > rx . rhttp . pend_conn ) ;
2023-09-22 10:28:35 -04:00
/* Remove reference to the freed connection. */
2023-11-21 05:10:34 -05:00
l - > rx . rhttp . pend_conn = NULL ;
2023-09-22 10:28:35 -04:00
2023-11-21 05:10:34 -05:00
if ( l - > rx . rhttp . state ! = LI_PRECONN_ST_ERR ) {
2023-09-22 09:55:24 -04:00
send_log ( l - > bind_conf - > frontend , LOG_ERR ,
" preconnect %s::%s: Error encountered. \n " ,
2023-11-21 05:10:34 -05:00
l - > bind_conf - > frontend - > id , l - > bind_conf - > rhttp_srvname ) ;
l - > rx . rhttp . state = LI_PRECONN_ST_ERR ;
2023-09-22 09:55:24 -04:00
}
2023-09-22 10:28:35 -04:00
/* Rearm a new preconnect attempt. */
2023-11-21 05:10:34 -05:00
l - > rx . rhttp . task - > expire = MS_TO_TICKS ( now_ms + 1000 ) ;
task_queue ( l - > rx . rhttp . task ) ;
2023-09-22 10:28:35 -04:00
}
2023-11-22 12:02:37 -05:00
/* Lookup over listener <l> threads for their current count of active reverse
* HTTP connections . Returns the less loaded thread ID .
*/
static unsigned int select_thread ( struct listener * l )
{
unsigned long mask = l - > rx . bind_thread & _HA_ATOMIC_LOAD ( & tg - > threads_enabled ) ;
unsigned int load_min = HA_ATOMIC_LOAD ( & th_ctx - > nb_rhttp_conns ) ;
unsigned int load_thr ;
unsigned int ret = tid ;
int i ;
/* Returns current tid if listener runs on one thread only. */
if ( ! atleast2 ( mask ) )
goto end ;
/* Loop over all threads and return the less loaded one. This needs to
* be just an approximation so it ' s not important if the selected
* thread load has varied since its selection .
*/
for ( i = tg - > base ; mask ; mask > > = 1 , i + + ) {
if ( ! ( mask & 0x1 ) )
continue ;
load_thr = HA_ATOMIC_LOAD ( & ha_thread_ctx [ i ] . nb_rhttp_conns ) ;
if ( load_min > load_thr ) {
ret = i ;
load_min = load_thr ;
}
}
end :
return ret ;
}
/* Detach <task> from its thread and assign it to <new_tid> thread. The task is
* queued to be woken up on the new thread .
*/
static void task_migrate ( struct task * task , uint new_tid )
{
task_unlink_wq ( task ) ;
task - > expire = TICK_ETERNITY ;
task_set_thread ( task , new_tid ) ;
task_wakeup ( task , TASK_WOKEN_MSG ) ;
}
2023-11-21 05:10:34 -05:00
struct task * rhttp_process ( struct task * task , void * ctx , unsigned int state )
2023-08-23 11:16:07 -04:00
{
struct listener * l = ctx ;
2023-11-21 05:10:34 -05:00
struct connection * conn = l - > rx . rhttp . pend_conn ;
2023-08-23 11:16:07 -04:00
if ( conn ) {
2023-11-07 11:10:38 -05:00
/* Either connection is on error ot the connect timeout fired. */
if ( conn - > flags & CO_FL_ERROR | | tick_is_expired ( task - > expire , now_ms ) ) {
/* If mux already instantiated, let it release the
* connection along with its context . Else do cleanup
* directly .
*/
if ( conn - > mux & & conn - > mux - > destroy ) {
conn - > mux - > destroy ( conn - > ctx ) ;
}
else {
conn_stop_tracking ( conn ) ;
conn_xprt_shutw ( conn ) ;
conn_xprt_close ( conn ) ;
conn_sock_shutw ( conn , 0 ) ;
conn_ctrl_close ( conn ) ;
if ( conn - > destroy_cb )
conn - > destroy_cb ( conn ) ;
conn_free ( conn ) ;
}
2023-08-14 04:52:50 -04:00
2023-11-21 05:10:34 -05:00
/* conn_free() must report preconnect failure using rhttp_notify_preconn_err(). */
BUG_ON ( l - > rx . rhttp . pend_conn ) ;
2023-11-22 12:02:37 -05:00
l - > rx . rhttp . task - > expire = TICKS_TO_MS ( now_ms ) ;
2023-08-14 04:52:50 -04:00
}
else {
2023-11-21 13:54:16 -05:00
/* Spurious receiver task woken up despite pend_conn not ready/on error. */
2023-11-16 11:13:28 -05:00
BUG_ON ( ! ( conn - > flags & CO_FL_ACT_REVERSING ) ) ;
2023-08-14 04:52:50 -04:00
/* A connection is ready to be accepted. */
listener_accept ( l ) ;
2023-11-21 05:10:34 -05:00
l - > rx . rhttp . task - > expire = TICK_ETERNITY ;
2023-08-14 04:52:50 -04:00
}
2023-08-23 11:16:07 -04:00
}
else {
2023-11-21 05:10:34 -05:00
struct server * srv = l - > rx . rhttp . srv ;
2023-11-07 11:10:38 -05:00
2023-11-22 12:02:37 -05:00
if ( ( state & TASK_WOKEN_ANY ) ! = TASK_WOKEN_MSG ) {
unsigned int new_tid = select_thread ( l ) ;
if ( new_tid ! = tid ) {
task_migrate ( l - > rx . rhttp . task , new_tid ) ;
return task ;
}
}
2023-08-23 11:16:07 -04:00
/* No pending reverse connection, prepare a new one. Store it in the
* listener and return NULL . Connection will be returned later after
* reversal is completed .
*/
2023-11-07 11:10:38 -05:00
conn = new_reverse_conn ( l , srv ) ;
2023-11-21 05:10:34 -05:00
l - > rx . rhttp . pend_conn = conn ;
2023-08-23 11:16:07 -04:00
/* On success task will be woken up by H2 mux after reversal. */
2025-04-10 12:05:55 -04:00
l - > rx . rhttp . task - > expire = conn & & tick_isset ( srv - > proxy - > timeout . connect ) ?
2023-11-07 11:10:38 -05:00
tick_add_ifset ( now_ms , srv - > proxy - > timeout . connect ) :
MS_TO_TICKS ( now_ms + 1000 ) ;
2023-08-23 11:16:07 -04:00
}
return task ;
}
2023-11-21 05:10:34 -05:00
int rhttp_bind_receiver ( struct receiver * rx , char * * errmsg )
2023-08-01 11:27:06 -04:00
{
2023-08-07 11:56:36 -04:00
rx - > flags | = RX_F_BOUND ;
2023-08-01 11:27:06 -04:00
return ERR_NONE ;
}
2023-11-21 05:10:34 -05:00
int rhttp_bind_listener ( struct listener * listener , char * errmsg , int errlen )
2023-08-01 11:27:06 -04:00
{
2023-08-23 11:16:07 -04:00
struct task * task ;
2023-08-07 11:56:36 -04:00
struct proxy * be ;
struct server * srv ;
struct ist be_name , sv_name ;
char * name = NULL ;
2023-11-22 12:02:37 -05:00
unsigned long mask ;
uint task_tid ;
if ( listener - > state ! = LI_ASSIGNED )
return ERR_NONE ; /* already bound */
/* Retrieve the first thread usable for this listener. */
mask = listener - > rx . bind_thread & _HA_ATOMIC_LOAD ( & tg - > threads_enabled ) ;
2024-05-21 10:35:28 -04:00
task_tid = my_ffsl ( mask ) - 1 + ha_tgroup_info [ listener - > rx . bind_tgroup ] . base ;
2023-11-22 12:02:37 -05:00
if ( ! ( task = task_new_on ( task_tid ) ) ) {
2023-08-23 11:16:07 -04:00
snprintf ( errmsg , errlen , " Out of memory. " ) ;
goto err ;
}
2023-11-03 11:21:12 -04:00
2023-11-21 05:10:34 -05:00
task - > process = rhttp_process ;
2023-08-23 11:16:07 -04:00
task - > context = listener ;
2023-11-21 05:10:34 -05:00
listener - > rx . rhttp . task = task ;
listener - > rx . rhttp . state = LI_PRECONN_ST_STOP ;
2023-08-23 11:16:07 -04:00
2023-10-19 03:25:20 -04:00
/* Set maxconn which is defined via the special kw nbconn for reverse
* connect . Use a default value of 1 if not set . This guarantees that
2023-11-21 13:54:16 -05:00
* listener will be automatically re - enable each time it fell back below
2023-10-19 03:25:20 -04:00
* it due to a connection error .
2023-09-22 09:51:23 -04:00
*/
2023-11-21 05:10:34 -05:00
listener - > bind_conf - > maxconn = listener - > bind_conf - > rhttp_nbconn ;
2023-09-22 09:51:23 -04:00
if ( ! listener - > bind_conf - > maxconn )
listener - > bind_conf - > maxconn = 1 ;
2023-11-21 05:10:34 -05:00
name = strdup ( listener - > bind_conf - > rhttp_srvname ) ;
2023-08-07 11:56:36 -04:00
if ( ! name ) {
snprintf ( errmsg , errlen , " Out of memory. " ) ;
goto err ;
}
sv_name = ist ( name ) ;
be_name = istsplit ( & sv_name , ' / ' ) ;
if ( ! istlen ( sv_name ) ) {
snprintf ( errmsg , errlen , " Invalid server name: '%s'. " , name ) ;
goto err ;
}
if ( ! ( be = proxy_be_by_name ( ist0 ( be_name ) ) ) ) {
snprintf ( errmsg , errlen , " No such backend: '%s'. " , name ) ;
goto err ;
}
2025-07-10 04:59:06 -04:00
if ( ! ( srv = server_find ( be , ist0 ( sv_name ) ) ) ) {
2023-08-07 11:56:36 -04:00
snprintf ( errmsg , errlen , " No such server: '%s/%s'. " , ist0 ( be_name ) , ist0 ( sv_name ) ) ;
goto err ;
}
2023-11-21 05:10:34 -05:00
if ( srv - > flags & SRV_F_RHTTP ) {
snprintf ( errmsg , errlen , " Cannot use reverse HTTP server '%s/%s' as target to a reverse bind. " , ist0 ( be_name ) , ist0 ( sv_name ) ) ;
2023-09-21 10:54:41 -04:00
goto err ;
}
if ( srv_is_transparent ( srv ) ) {
snprintf ( errmsg , errlen , " Cannot use transparent server '%s/%s' as target to a reverse bind. " , ist0 ( be_name ) , ist0 ( sv_name ) ) ;
2023-08-07 11:56:36 -04:00
goto err ;
}
/* Check that server uses HTTP/2 either with proto or ALPN. */
if ( ( ! srv - > mux_proto | | ! isteqi ( srv - > mux_proto - > token , ist ( " h2 " ) ) ) & &
( ! srv - > use_ssl | | ! isteqi ( ist ( srv - > ssl_ctx . alpn_str ) , ist ( " \x02 h2 " ) ) ) ) {
snprintf ( errmsg , errlen , " Cannot reverse connect with server '%s/%s' unless HTTP/2 is activated on it with either proto or alpn keyword. " , name , ist0 ( sv_name ) ) ;
goto err ;
}
2023-10-02 11:17:46 -04:00
/* Prevent dynamic source address settings. */
if ( ( ( srv - > conn_src . opts & CO_SRC_TPROXY_MASK ) & &
( srv - > conn_src . opts & CO_SRC_TPROXY_MASK ) ! = CO_SRC_TPROXY_ADDR ) | |
( ( srv - > proxy - > conn_src . opts & CO_SRC_TPROXY_MASK ) & &
( srv - > proxy - > conn_src . opts & CO_SRC_TPROXY_MASK ) ! = CO_SRC_TPROXY_ADDR ) ) {
snprintf ( errmsg , errlen , " Cannot reverse connect with server '%s/%s' which uses dynamic source address setting. " , name , ist0 ( sv_name ) ) ;
goto err ;
}
2023-08-07 11:56:36 -04:00
ha_free ( & name ) ;
2023-11-21 05:10:34 -05:00
listener - > rx . rhttp . srv = srv ;
2023-08-23 11:16:07 -04:00
listener_set_state ( listener , LI_LISTEN ) ;
2023-08-07 11:56:36 -04:00
2023-08-01 11:27:06 -04:00
return ERR_NONE ;
2023-08-07 11:56:36 -04:00
err :
ha_free ( & name ) ;
return ERR_ALERT | ERR_FATAL ;
}
2024-05-16 11:35:31 -04:00
/* Do not support "disable frontend" for rhttp protocol. */
int rhttp_suspend_listener ( struct listener * l )
{
send_log ( l - > bind_conf - > frontend , LOG_ERR , " cannot disable a reverse-HTTP listener. \n " ) ;
return - 1 ;
}
2023-11-21 05:10:34 -05:00
void rhttp_enable_listener ( struct listener * l )
2023-08-23 11:16:07 -04:00
{
2023-11-21 05:10:34 -05:00
if ( l - > rx . rhttp . state < LI_PRECONN_ST_INIT ) {
2023-09-22 09:55:24 -04:00
send_log ( l - > bind_conf - > frontend , LOG_INFO ,
" preconnect %s::%s: Initiating. \n " ,
2023-11-21 05:10:34 -05:00
l - > bind_conf - > frontend - > id , l - > bind_conf - > rhttp_srvname ) ;
l - > rx . rhttp . state = LI_PRECONN_ST_INIT ;
2023-09-22 09:55:24 -04:00
}
2024-05-16 11:37:46 -04:00
task_wakeup ( l - > rx . rhttp . task , TASK_WOKEN_INIT ) ;
2023-08-23 11:16:07 -04:00
}
2023-11-21 05:10:34 -05:00
void rhttp_disable_listener ( struct listener * l )
2023-08-23 11:16:07 -04:00
{
2023-11-21 05:10:34 -05:00
if ( l - > rx . rhttp . state < LI_PRECONN_ST_FULL ) {
2023-09-22 09:55:24 -04:00
send_log ( l - > bind_conf - > frontend , LOG_INFO ,
2023-10-19 03:25:20 -04:00
" preconnect %s::%s: Running with nbconn %d reached. \n " ,
2023-11-21 05:10:34 -05:00
l - > bind_conf - > frontend - > id , l - > bind_conf - > rhttp_srvname ,
2023-09-22 09:55:24 -04:00
l - > bind_conf - > maxconn ) ;
2023-11-21 05:10:34 -05:00
l - > rx . rhttp . state = LI_PRECONN_ST_FULL ;
2023-09-22 09:55:24 -04:00
}
2023-08-23 11:16:07 -04:00
}
2023-11-21 05:10:34 -05:00
struct connection * rhttp_accept_conn ( struct listener * l , int * status )
2023-08-23 11:16:07 -04:00
{
2023-11-21 05:10:34 -05:00
struct connection * conn = l - > rx . rhttp . pend_conn ;
2023-08-23 11:16:07 -04:00
if ( ! conn ) {
2023-09-22 09:51:23 -04:00
/* Reverse connect listener must have an explicit maxconn set
2023-11-21 13:54:16 -05:00
* to ensure it is re - enabled on connection error .
2023-09-22 09:51:23 -04:00
*/
BUG_ON ( ! l - > bind_conf - > maxconn ) ;
2023-08-23 11:16:07 -04:00
/* Instantiate a new conn if maxconn not yet exceeded. */
2023-09-22 09:51:23 -04:00
if ( l - > nbconn < = l - > bind_conf - > maxconn ) {
2023-11-22 12:02:37 -05:00
/* Try first if a new thread should be used for the new connection. */
unsigned int new_tid = select_thread ( l ) ;
if ( new_tid ! = tid ) {
task_migrate ( l - > rx . rhttp . task , new_tid ) ;
* status = CO_AC_DONE ;
return NULL ;
}
/* No need to use a new thread, use the opportunity to alloc the connection right now. */
2023-11-21 05:10:34 -05:00
l - > rx . rhttp . pend_conn = new_reverse_conn ( l , l - > rx . rhttp . srv ) ;
if ( ! l - > rx . rhttp . pend_conn ) {
2023-08-23 11:16:07 -04:00
* status = CO_AC_PAUSE ;
return NULL ;
}
}
* status = CO_AC_DONE ;
return NULL ;
}
/* listener_accept() must not be called if no pending connection is not yet reversed. */
2023-11-16 11:13:28 -05:00
BUG_ON ( ! ( conn - > flags & CO_FL_ACT_REVERSING ) ) ;
conn - > flags & = ~ CO_FL_ACT_REVERSING ;
conn - > flags | = CO_FL_REVERSED ;
2023-11-28 08:27:51 -05:00
conn - > mux - > ctl ( conn , MUX_CTL_REVERSE_CONN , NULL ) ;
2023-08-14 10:38:23 -04:00
2023-11-21 05:10:34 -05:00
l - > rx . rhttp . pend_conn = NULL ;
2023-08-23 11:16:07 -04:00
* status = CO_AC_NONE ;
return conn ;
}
2023-11-21 05:10:34 -05:00
void rhttp_unbind_receiver ( struct listener * l )
2023-08-07 11:56:36 -04:00
{
l - > rx . flags & = ~ RX_F_BOUND ;
2023-08-01 11:27:06 -04:00
}
2024-07-11 05:32:29 -04:00
int rhttp_bind_tid_prep ( struct connection * conn , int new_tid )
2023-08-23 11:16:07 -04:00
{
2023-12-29 14:05:20 -05:00
/* Explicitly disable connection thread migration on accept. Indeed,
2023-11-22 12:02:37 -05:00
* it ' s unsafe to move a connection with its FD to another thread . Note
* that active reverse task thread migration should be sufficient to
2023-12-29 14:05:20 -05:00
* ensure repartition of reversed connections across listener threads .
2023-08-23 11:16:07 -04:00
*/
return - 1 ;
}
2023-11-21 05:10:34 -05:00
int rhttp_accepting_conn ( const struct receiver * rx )
2023-08-01 11:27:06 -04:00
{
return 1 ;
}
2023-11-21 05:10:34 -05:00
INITCALL1 ( STG_REGISTER , protocol_register , & proto_rhttp ) ;
2023-11-22 11:55:58 -05:00
2023-12-29 14:05:20 -05:00
/* perform minimal initializations */
2023-11-22 11:55:58 -05:00
static void init_rhttp ( )
{
int i ;
for ( i = 0 ; i < MAX_THREADS ; i + + )
ha_thread_ctx [ i ] . nb_rhttp_conns = 0 ;
}
INITCALL0 ( STG_PREPARE , init_rhttp ) ;