2018-03-13 10:20:50 +00:00
/*
* $ Id $
*
Copyright ( c ) 2016 - 2018 Chung , Hyung - Hwan . All rights reserved .
Redistribution and use in source and binary forms , with or without
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 .
THIS SOFTWARE IS PROVIDED BY THE AUTHOR " 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 AUTHOR 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 .
*/
# include "hcl-s.h"
# include "hcl-prv.h"
2018-03-15 10:30:06 +00:00
# include "hcl-tmr.h"
2018-04-10 13:57:17 +00:00
# include "hcl-xutl.h"
2018-03-13 10:20:50 +00:00
# include <stdio.h>
# include <string.h>
# include <errno.h>
2018-03-16 16:20:40 +00:00
# define HCL_SERVER_TOKEN_NAME_ALIGN 64
# define HCL_SERVER_WID_MAP_ALIGN 512
# define HCL_SERVER_PROTO_REPLY_BUF_SIZE 1300
2018-03-16 14:57:34 +00:00
2018-03-13 10:20:50 +00:00
# if defined(_WIN32)
# include <windows.h>
# include <tchar.h>
# elif defined(__OS2__)
# define INCL_DOSMODULEMGR
# define INCL_DOSPROCESS
# define INCL_DOSERRORS
# include <os2.h>
# elif defined(__MSDOS__)
# include <dos.h>
# include <time.h>
# elif defined(macintosh)
# include <Timer.h>
# else
# if defined(HAVE_TIME_H)
# include <time.h>
# endif
# if defined(HAVE_SYS_TIME_H)
# include <sys / time.h>
# endif
# if defined(HAVE_SIGNAL_H)
# include <signal.h>
# endif
# if defined(HAVE_SYS_MMAN_H)
# include <sys / mman.h>
# endif
2018-03-16 16:20:40 +00:00
# if defined(HAVE_SYS_UIO_H)
# include <sys / uio.h>
# endif
2018-03-22 09:46:44 +00:00
# if defined(HAVE_SYS_EPOLL_H)
# include <sys / epoll.h>
# endif
2018-03-14 14:46:23 +00:00
2018-03-13 10:20:50 +00:00
# include <unistd.h>
# include <fcntl.h>
# include <sys / types.h>
# include <sys / socket.h>
# include <netinet / in.h>
# include <pthread.h>
# include <poll.h>
# endif
struct bb_t
{
char buf [ 1024 ] ;
hcl_oow_t pos ;
hcl_oow_t len ;
int fd ;
hcl_bch_t * fn ;
} ;
2018-03-17 11:57:02 +00:00
typedef struct bb_t bb_t ;
2018-03-13 10:20:50 +00:00
2018-03-14 10:14:38 +00:00
struct worker_hcl_xtn_t
2018-03-13 10:20:50 +00:00
{
hcl_server_proto_t * proto ;
int vm_running ;
2018-03-14 10:14:38 +00:00
} ;
2018-03-17 11:57:02 +00:00
typedef struct worker_hcl_xtn_t worker_hcl_xtn_t ;
2018-03-13 10:20:50 +00:00
2019-05-04 17:56:45 +00:00
struct server_hcl_xtn_t
2018-03-14 10:14:38 +00:00
{
hcl_server_t * server ;
2018-03-13 10:20:50 +00:00
} ;
2019-05-04 17:56:45 +00:00
typedef struct server_hcl_xtn_t server_hcl_xtn_t ;
2018-03-13 10:20:50 +00:00
enum hcl_server_proto_token_type_t
{
HCL_SERVER_PROTO_TOKEN_EOF ,
HCL_SERVER_PROTO_TOKEN_NL ,
HCL_SERVER_PROTO_TOKEN_BEGIN ,
HCL_SERVER_PROTO_TOKEN_END ,
HCL_SERVER_PROTO_TOKEN_SCRIPT ,
HCL_SERVER_PROTO_TOKEN_EXIT ,
/*HCL_SERVER_PROTO_TOKEN_AUTH,*/
HCL_SERVER_PROTO_TOKEN_KILL_WORKER ,
HCL_SERVER_PROTO_TOKEN_SHOW_WORKERS ,
2018-03-16 17:27:24 +00:00
HCL_SERVER_PROTO_TOKEN_IDENT ,
HCL_SERVER_PROTO_TOKEN_NUMBER
2018-03-13 10:20:50 +00:00
} ;
typedef enum hcl_server_proto_token_type_t hcl_server_proto_token_type_t ;
typedef struct hcl_server_proto_token_t hcl_server_proto_token_t ;
struct hcl_server_proto_token_t
{
hcl_server_proto_token_type_t type ;
hcl_ooch_t * ptr ;
hcl_oow_t len ;
hcl_oow_t capa ;
2023-11-04 13:58:31 +00:00
hcl_loc_t loc ;
2018-03-13 10:20:50 +00:00
} ;
enum hcl_server_proto_req_state_t
{
HCL_SERVER_PROTO_REQ_IN_TOP_LEVEL ,
HCL_SERVER_PROTO_REQ_IN_BLOCK_LEVEL
} ;
enum hcl_server_proto_reply_type_t
{
HCL_SERVER_PROTO_REPLY_SIMPLE = 0 ,
HCL_SERVER_PROTO_REPLY_CHUNKED
} ;
typedef enum hcl_server_proto_reply_type_t hcl_server_proto_reply_type_t ;
struct hcl_server_proto_t
{
hcl_server_worker_t * worker ;
hcl_t * hcl ;
2023-11-04 13:58:31 +00:00
hcl_lxc_t * lxc ;
2022-08-02 13:41:13 +00:00
hcl_oow_t unread_count ;
2023-11-04 13:58:31 +00:00
hcl_lxc_t unread_lxc ;
2018-03-13 10:20:50 +00:00
hcl_server_proto_token_t tok ;
2018-03-15 10:30:06 +00:00
hcl_tmr_index_t exec_runtime_event_index ;
2018-03-13 10:20:50 +00:00
struct
{
int state ;
} req ;
struct
{
hcl_server_proto_reply_type_t type ;
hcl_oow_t nchunks ;
hcl_bch_t buf [ HCL_SERVER_PROTO_REPLY_BUF_SIZE ] ;
hcl_oow_t len ;
} reply ;
} ;
enum hcl_server_worker_state_t
{
HCL_SERVER_WORKER_STATE_DEAD = 0 ,
2018-03-17 05:44:40 +00:00
HCL_SERVER_WORKER_STATE_ALIVE = 1 ,
HCL_SERVER_WORKER_STATE_ZOMBIE = 2 /* the worker is not chained in the server's client list */
2018-03-13 10:20:50 +00:00
} ;
typedef enum hcl_server_worker_state_t hcl_server_worker_state_t ;
2018-03-17 05:44:40 +00:00
enum hcl_server_worker_opstate_t
{
HCL_SERVER_WORKER_OPSTATE_IDLE = 0 ,
HCL_SERVER_WORKER_OPSTATE_ERROR = 1 ,
HCL_SERVER_WORKER_OPSTATE_WAIT = 2 ,
HCL_SERVER_WORKER_OPSTATE_READ = 3 ,
HCL_SERVER_WORKER_OPSTATE_COMPILE = 4 ,
HCL_SERVER_WORKER_OPSTATE_EXECUTE = 5
} ;
typedef enum hcl_server_worker_opstate_t hcl_server_worker_opstate_t ;
2018-03-13 10:20:50 +00:00
struct hcl_server_worker_t
{
pthread_t thr ;
2018-03-16 05:56:05 +00:00
hcl_oow_t wid ;
2018-03-13 10:20:50 +00:00
int sck ;
2018-03-22 04:31:18 +00:00
hcl_sckaddr_t peeraddr ;
2018-03-13 10:20:50 +00:00
int claimed ;
2023-05-31 15:30:41 +00:00
2018-03-17 11:57:02 +00:00
hcl_ntime_t alloc_time ;
2018-03-13 10:20:50 +00:00
hcl_server_worker_state_t state ;
2018-03-17 05:44:40 +00:00
hcl_server_worker_opstate_t opstate ;
2018-03-13 10:20:50 +00:00
hcl_server_proto_t * proto ;
hcl_server_t * server ;
hcl_server_worker_t * prev_worker ;
hcl_server_worker_t * next_worker ;
} ;
2018-03-16 17:27:24 +00:00
struct hcl_server_wid_map_data_t
2018-03-16 05:56:05 +00:00
{
2018-03-16 17:27:24 +00:00
int used ;
union
{
hcl_server_worker_t * worker ;
hcl_oow_t next ;
} u ;
2018-03-16 05:56:05 +00:00
} ;
2018-03-16 17:27:24 +00:00
typedef struct hcl_server_wid_map_data_t hcl_server_wid_map_data_t ;
2018-03-21 10:38:10 +00:00
2018-03-22 09:46:44 +00:00
typedef struct hcl_server_listener_t hcl_server_listener_t ;
struct hcl_server_listener_t
{
int sck ;
hcl_sckaddr_t sckaddr ;
hcl_server_listener_t * next_listener ;
} ;
2018-03-13 10:20:50 +00:00
struct hcl_server_t
{
2019-06-21 12:36:25 +00:00
hcl_oow_t _instsize ;
hcl_mmgr_t * _mmgr ;
hcl_cmgr_t * _cmgr ;
2018-03-14 10:14:38 +00:00
hcl_server_prim_t prim ;
2018-03-24 06:06:01 +00:00
/* [NOTE]
* this dummy_hcl is used when the main thread requires logging mostly .
* as there is no explicit locking when calling HCL_LOG ( ) functions ,
* the code must ensure that the logging functions are called in the
* context of the main server thraed only . error message setting is
* also performed in the main thread context for the same reason .
2023-05-31 15:30:41 +00:00
*
2018-03-24 06:06:01 +00:00
* however , you may have noticed mixed use of HCL_ASSERT with dummy_hcl
* in both the server thread context and the client thread contexts .
* it should be ok as assertion is only for debugging and it ' s operation
* is thread safe . */
2018-03-14 10:14:38 +00:00
hcl_t * dummy_hcl ;
2018-03-24 06:06:01 +00:00
2018-03-15 10:30:06 +00:00
hcl_tmr_t * tmr ;
2018-03-13 10:20:50 +00:00
hcl_errnum_t errnum ;
2018-03-14 10:14:38 +00:00
struct
{
2018-03-14 14:54:10 +00:00
hcl_ooch_t buf [ HCL_ERRMSG_CAPA ] ;
2018-03-14 10:14:38 +00:00
hcl_oow_t len ;
} errmsg ;
2018-03-13 10:20:50 +00:00
int stopreq ;
struct
{
2018-04-26 04:39:20 +00:00
hcl_bitmask_t trait ;
hcl_bitmask_t logmask ;
2018-03-13 10:20:50 +00:00
hcl_oow_t worker_stack_size ;
2018-03-16 14:57:34 +00:00
hcl_oow_t worker_max_count ;
2018-03-14 14:40:05 +00:00
hcl_ntime_t worker_idle_timeout ;
2018-03-13 10:20:50 +00:00
hcl_oow_t actor_heap_size ;
2018-03-14 14:40:05 +00:00
hcl_ntime_t actor_max_runtime ;
2018-03-17 05:44:40 +00:00
hcl_ooch_t script_include_path [ HCL_PATH_MAX + 1 ] ;
2018-04-09 15:54:54 +00:00
void * module_inctx ;
2018-03-13 10:20:50 +00:00
} cfg ;
2018-03-22 09:46:44 +00:00
struct
{
int ep_fd ;
struct epoll_event ev_buf [ 128 ] ;
hcl_server_listener_t * head ;
hcl_oow_t count ;
} listener ;
2018-03-13 10:20:50 +00:00
struct
{
hcl_server_worker_t * head ;
hcl_server_worker_t * tail ;
2018-03-16 14:57:34 +00:00
hcl_oow_t count ;
2018-03-13 10:20:50 +00:00
} worker_list [ 2 ] ;
2018-03-16 05:56:05 +00:00
struct
{
hcl_server_wid_map_data_t * ptr ;
hcl_oow_t capa ;
hcl_oow_t free_first ;
hcl_oow_t free_last ;
2018-03-16 14:57:34 +00:00
} wid_map ; /* worker's id map */
2018-03-16 05:56:05 +00:00
2018-03-15 15:23:51 +00:00
int mux_pipe [ 2 ] ; /* pipe to break the blocking multiplexer in the main server loop */
2018-03-13 10:20:50 +00:00
pthread_mutex_t worker_mutex ;
2018-03-15 10:30:06 +00:00
pthread_mutex_t tmr_mutex ;
2018-03-13 10:20:50 +00:00
pthread_mutex_t log_mutex ;
} ;
/* ========================================================================= */
static const hcl_bch_t * get_base_name ( const hcl_bch_t * path )
{
const hcl_bch_t * p , * last = HCL_NULL ;
for ( p = path ; * p ! = ' \0 ' ; p + + )
{
2018-11-03 15:57:14 +00:00
if ( HCL_IS_PATH_SEP ( * p ) ) last = p ;
2018-03-13 10:20:50 +00:00
}
return ( last = = HCL_NULL ) ? path : ( last + 1 ) ;
}
2022-08-03 05:17:01 +00:00
2023-11-05 13:31:33 +00:00
static HCL_INLINE int open_read_stream ( hcl_t * hcl , hcl_io_cciarg_t * arg )
2018-03-13 10:20:50 +00:00
{
2018-03-14 10:14:38 +00:00
worker_hcl_xtn_t * xtn = ( worker_hcl_xtn_t * ) hcl_getxtn ( hcl ) ;
2018-03-13 10:20:50 +00:00
bb_t * bb = HCL_NULL ;
2018-03-17 05:44:40 +00:00
hcl_server_t * server ;
server = xtn - > proto - > worker - > server ;
2018-03-13 10:20:50 +00:00
if ( arg - > includer )
{
/* includee */
2023-05-31 15:30:41 +00:00
/* TOOD: Do i need to skip prepending the include path if the included path is an absolute path?
2018-03-17 05:44:40 +00:00
* it may be good for security if i don ' t skip it . we can lock the included files in a given directory */
2018-03-13 10:20:50 +00:00
hcl_oow_t ucslen , bcslen , parlen ;
const hcl_bch_t * fn , * fb ;
# if defined(HCL_OOCH_IS_UCH)
2018-03-17 05:44:40 +00:00
if ( hcl_convootobcstr ( hcl , arg - > name , & ucslen , HCL_NULL , & bcslen ) < = - 1 ) goto oops ;
2018-03-13 10:20:50 +00:00
# else
2018-04-07 15:54:16 +00:00
bcslen = hcl_count_bcstr ( arg - > name ) ;
2018-03-13 10:20:50 +00:00
# endif
fn = ( ( bb_t * ) arg - > includer - > handle ) - > fn ;
2018-03-17 05:44:40 +00:00
if ( fn [ 0 ] = = ' \0 ' & & server - > cfg . script_include_path [ 0 ] ! = ' \0 ' )
{
# if defined(HCL_OOCH_IS_UCH)
if ( hcl_convootobcstr ( hcl , server - > cfg . script_include_path , & ucslen , HCL_NULL , & parlen ) < = - 1 ) goto oops ;
# else
2018-04-07 15:54:16 +00:00
parlen = hcl_count_bcstr ( server - > cfg . script_include_path ) ;
2018-03-17 05:44:40 +00:00
# endif
}
else
{
fb = get_base_name ( fn ) ;
parlen = fb - fn ;
}
2018-03-13 10:20:50 +00:00
2018-03-17 05:44:40 +00:00
bb = ( bb_t * ) hcl_callocmem ( hcl , HCL_SIZEOF ( * bb ) + ( HCL_SIZEOF ( hcl_bch_t ) * ( parlen + bcslen + 2 ) ) ) ;
2018-03-13 10:20:50 +00:00
if ( ! bb ) goto oops ;
bb - > fn = ( hcl_bch_t * ) ( bb + 1 ) ;
2018-03-17 05:44:40 +00:00
if ( fn [ 0 ] = = ' \0 ' & & server - > cfg . script_include_path [ 0 ] ! = ' \0 ' )
{
# if defined(HCL_OOCH_IS_UCH)
hcl_convootobcstr ( hcl , server - > cfg . script_include_path , & ucslen , bb - > fn , & parlen ) ;
# else
2018-04-07 15:54:16 +00:00
hcl_copy_bchars ( bb - > fn , server - > cfg . script_include_path , parlen ) ;
2018-03-17 05:44:40 +00:00
# endif
2021-02-09 15:06:41 +00:00
if ( ! HCL_IS_PATH_SEP ( bb - > fn [ parlen ] ) ) bb - > fn [ parlen + + ] = HCL_DFL_PATH_SEP ; /* +2 was used in hcl_callocmem() for this (+1 for this, +1 for '\0' */
2018-03-17 05:44:40 +00:00
}
else
{
2018-04-07 15:54:16 +00:00
hcl_copy_bchars ( bb - > fn , fn , parlen ) ;
2018-03-17 05:44:40 +00:00
}
2018-03-13 10:20:50 +00:00
# if defined(HCL_OOCH_IS_UCH)
hcl_convootobcstr ( hcl , arg - > name , & ucslen , & bb - > fn [ parlen ] , & bcslen ) ;
# else
2018-04-07 15:54:16 +00:00
hcl_copy_bcstr ( & bb - > fn [ parlen ] , bcslen + 1 , arg - > name ) ;
2018-03-13 10:20:50 +00:00
# endif
bb - > fd = open ( bb - > fn , O_RDONLY , 0 ) ;
2022-08-03 05:17:01 +00:00
if ( bb - > fd < = - 1 )
{
hcl_seterrnum ( hcl , HCL_EIOERR ) ;
goto oops ;
}
2018-03-13 10:20:50 +00:00
}
else
{
/* main stream */
hcl_oow_t pathlen = 0 ;
2018-03-17 05:44:40 +00:00
bb = ( bb_t * ) hcl_callocmem ( hcl , HCL_SIZEOF ( * bb ) + ( HCL_SIZEOF ( hcl_bch_t ) * ( pathlen + 1 ) ) ) ;
2018-03-13 10:20:50 +00:00
if ( ! bb ) goto oops ;
2018-03-17 05:44:40 +00:00
/* copy ane empty string as a main stream's name */
bb - > fn = ( hcl_bch_t * ) ( bb + 1 ) ;
2018-04-07 15:54:16 +00:00
hcl_copy_bcstr ( bb - > fn , pathlen + 1 , " " ) ;
2018-03-13 10:20:50 +00:00
bb - > fd = xtn - > proto - > worker - > sck ;
}
2022-08-03 05:17:01 +00:00
HCL_ASSERT ( hcl , bb - > fd > = 0 ) ;
2018-03-13 10:20:50 +00:00
arg - > handle = bb ;
return 0 ;
oops :
2023-05-31 15:30:41 +00:00
if ( bb )
2018-03-13 10:20:50 +00:00
{
if ( bb - > fd > = 0 & & bb - > fd ! = xtn - > proto - > worker - > sck ) close ( bb - > fd ) ;
hcl_freemem ( hcl , bb ) ;
}
return - 1 ;
}
2023-11-05 13:31:33 +00:00
static HCL_INLINE int close_read_stream ( hcl_t * hcl , hcl_io_cciarg_t * arg )
2018-03-13 10:20:50 +00:00
{
2018-03-14 10:14:38 +00:00
worker_hcl_xtn_t * xtn = ( worker_hcl_xtn_t * ) hcl_getxtn ( hcl ) ;
2018-03-13 10:20:50 +00:00
bb_t * bb ;
bb = ( bb_t * ) arg - > handle ;
HCL_ASSERT ( hcl , bb ! = HCL_NULL & & bb - > fd > = 0 ) ;
if ( bb - > fd ! = xtn - > proto - > worker - > sck ) close ( bb - > fd ) ;
hcl_freemem ( hcl , bb ) ;
arg - > handle = HCL_NULL ;
return 0 ;
}
2023-11-05 13:31:33 +00:00
static HCL_INLINE int read_input ( hcl_t * hcl , hcl_io_cciarg_t * arg )
2018-03-13 10:20:50 +00:00
{
2018-03-14 10:14:38 +00:00
worker_hcl_xtn_t * xtn = ( worker_hcl_xtn_t * ) hcl_getxtn ( hcl ) ;
2018-03-13 10:20:50 +00:00
bb_t * bb ;
hcl_oow_t bcslen , ucslen , remlen ;
2018-03-22 07:15:19 +00:00
hcl_server_worker_t * worker ;
2022-08-02 13:41:13 +00:00
ssize_t x ;
int y ;
2018-03-13 10:20:50 +00:00
bb = ( bb_t * ) arg - > handle ;
HCL_ASSERT ( hcl , bb ! = HCL_NULL & & bb - > fd > = 0 ) ;
2018-03-22 07:15:19 +00:00
worker = xtn - > proto - > worker ;
2022-08-02 13:41:13 +00:00
start_over :
2022-08-03 13:56:20 +00:00
if ( arg - > includer )
{
/* includee */
if ( HCL_UNLIKELY ( worker - > server - > stopreq ) )
{
hcl_seterrbfmt ( hcl , HCL_EGENERIC , " stop requested " ) ;
return - 1 ;
}
x = read ( bb - > fd , & bb - > buf [ bb - > len ] , HCL_COUNTOF ( bb - > buf ) - bb - > len ) ;
if ( x < = - 1 )
{
if ( errno = = EINTR ) goto start_over ;
hcl_seterrwithsyserr ( hcl , 0 , errno ) ;
return - 1 ;
}
bb - > len + = x ;
}
2023-05-31 15:30:41 +00:00
else
2018-03-13 10:20:50 +00:00
{
2022-08-03 13:56:20 +00:00
/* main stream */
2018-03-22 07:15:19 +00:00
hcl_server_t * server ;
2022-08-03 13:56:20 +00:00
HCL_ASSERT ( hcl , bb - > fd = = worker - > sck ) ;
2018-03-22 07:15:19 +00:00
server = worker - > server ;
2018-03-13 10:20:50 +00:00
while ( 1 )
{
int n ;
struct pollfd pfd ;
2018-03-22 07:15:19 +00:00
int tmout , actual_tmout ;
2022-08-02 13:41:13 +00:00
if ( HCL_UNLIKELY ( server - > stopreq ) )
2018-03-13 10:20:50 +00:00
{
hcl_seterrbfmt ( hcl , HCL_EGENERIC , " stop requested " ) ;
return - 1 ;
}
2018-03-22 07:15:19 +00:00
tmout = HCL_SECNSEC_TO_MSEC ( server - > cfg . worker_idle_timeout . sec , server - > cfg . worker_idle_timeout . nsec ) ;
actual_tmout = ( tmout < = 0 ) ? 10000 : tmout ;
2018-03-13 10:20:50 +00:00
pfd . fd = bb - > fd ;
pfd . events = POLLIN | POLLERR ;
2018-03-22 07:15:19 +00:00
n = poll ( & pfd , 1 , actual_tmout ) ;
2018-03-13 10:20:50 +00:00
if ( n < = - 1 )
{
if ( errno = = EINTR ) goto start_over ;
2018-11-02 14:15:28 +00:00
hcl_seterrwithsyserr ( hcl , 0 , errno ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
else if ( n > = 1 ) break ;
2018-03-22 07:15:19 +00:00
/* timed out - no activity on the pfd */
if ( tmout > 0 )
{
2022-08-03 13:56:20 +00:00
hcl_seterrbfmt ( hcl , HCL_EGENERIC , " no activity on the worker socket %d " , bb - > fd ) ;
2018-03-22 07:15:19 +00:00
return - 1 ;
}
2018-03-13 10:20:50 +00:00
}
2022-08-01 06:31:33 +00:00
2018-03-13 10:20:50 +00:00
x = recv ( bb - > fd , & bb - > buf [ bb - > len ] , HCL_COUNTOF ( bb - > buf ) - bb - > len , 0 ) ;
if ( x < = - 1 )
{
if ( errno = = EINTR ) goto start_over ;
2018-11-02 14:15:28 +00:00
hcl_seterrwithsyserr ( hcl , 0 , errno ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
bb - > len + = x ;
}
# if defined(HCL_OOCH_IS_UCH)
bcslen = bb - > len ;
ucslen = HCL_COUNTOF ( arg - > buf ) ;
2022-08-02 13:41:13 +00:00
y = hcl_convbtooochars ( hcl , bb - > buf , & bcslen , arg - > buf , & ucslen ) ;
2023-05-31 15:30:41 +00:00
if ( y < = - 1 & & ucslen < = 0 )
2022-08-02 13:41:13 +00:00
{
if ( y = = - 3 & & x ! = 0 ) goto start_over ; /* incomplete sequence and not EOF yet */
return - 1 ;
}
2018-03-13 10:20:50 +00:00
/* if ucslen is greater than 0, i see that some characters have been
* converted properly */
# else
bcslen = ( bb - > len < HCL_COUNTOF ( arg - > buf ) ) ? bb - > len : HCL_COUNTOF ( arg - > buf ) ;
ucslen = bcslen ;
2018-04-07 15:54:16 +00:00
hcl_copy_bchars ( arg - > buf , bb - > buf , bcslen ) ;
2018-03-13 10:20:50 +00:00
# endif
remlen = bb - > len - bcslen ;
2022-08-01 06:31:33 +00:00
if ( remlen > 0 ) HCL_MEMMOVE ( bb - > buf , & bb - > buf [ bcslen ] , remlen ) ;
2018-03-13 10:20:50 +00:00
bb - > len = remlen ;
arg - > xlen = ucslen ;
return 0 ;
}
2023-11-04 13:58:31 +00:00
static int read_handler ( hcl_t * hcl , hcl_io_cmd_t cmd , void * arg )
2018-03-13 10:20:50 +00:00
{
switch ( cmd )
{
case HCL_IO_OPEN :
2023-11-05 13:31:33 +00:00
return open_read_stream ( hcl , ( hcl_io_cciarg_t * ) arg ) ;
2022-08-01 06:31:33 +00:00
2018-03-13 10:20:50 +00:00
case HCL_IO_CLOSE :
2023-11-05 13:31:33 +00:00
return close_read_stream ( hcl , ( hcl_io_cciarg_t * ) arg ) ;
2018-03-13 10:20:50 +00:00
case HCL_IO_READ :
2023-11-05 13:31:33 +00:00
return read_input ( hcl , ( hcl_io_cciarg_t * ) arg ) ;
2018-03-13 10:20:50 +00:00
default :
hcl_seterrnum ( hcl , HCL_EINTERN ) ;
return - 1 ;
}
}
2023-11-04 13:58:31 +00:00
static int print_handler ( hcl_t * hcl , hcl_io_cmd_t cmd , void * arg )
2018-03-13 10:20:50 +00:00
{
switch ( cmd )
{
case HCL_IO_OPEN :
return 0 ;
case HCL_IO_CLOSE :
return 0 ;
case HCL_IO_WRITE :
{
2018-03-14 10:14:38 +00:00
worker_hcl_xtn_t * xtn = ( worker_hcl_xtn_t * ) hcl_getxtn ( hcl ) ;
2023-11-04 14:23:20 +00:00
hcl_io_udoarg_t * outarg = ( hcl_io_udoarg_t * ) arg ;
2018-03-13 10:20:50 +00:00
2023-05-31 15:30:41 +00:00
if ( hcl_server_proto_feed_reply ( xtn - > proto , outarg - > ptr , outarg - > len , 0 ) < = - 1 )
2018-03-13 10:20:50 +00:00
{
/* TODO: change error code and message. propagage the errormessage from proto */
hcl_seterrbfmt ( hcl , HCL_EIOERR , " failed to write message via proto " ) ;
2023-05-31 15:30:41 +00:00
/* writing failure on the socket is a critical failure.
2018-03-13 10:20:50 +00:00
* execution must get aborted */
hcl_abort ( hcl ) ;
return - 1 ;
}
outarg - > xlen = outarg - > len ;
return 0 ;
}
2023-05-31 15:30:41 +00:00
case HCL_IO_WRITE_BYTES :
{
worker_hcl_xtn_t * xtn = ( worker_hcl_xtn_t * ) hcl_getxtn ( hcl ) ;
2023-11-04 14:23:20 +00:00
hcl_io_udoarg_t * outarg = ( hcl_io_udoarg_t * ) arg ;
2023-05-31 15:30:41 +00:00
if ( hcl_server_proto_feed_reply_bytes ( xtn - > proto , outarg - > ptr , outarg - > len , 0 ) < = - 1 )
{
/* TODO: change error code and message. propagage the errormessage from proto */
hcl_seterrbfmt ( hcl , HCL_EIOERR , " failed to write message via proto " ) ;
/* writing failure on the socket is a critical failure.
* execution must get aborted */
hcl_abort ( hcl ) ;
return - 1 ;
}
outarg - > xlen = outarg - > len ;
return 0 ;
}
2018-03-13 10:20:50 +00:00
default :
hcl_seterrnum ( hcl , HCL_EINTERN ) ;
return - 1 ;
}
}
/* ========================================================================= */
2018-04-26 04:39:20 +00:00
static void log_write ( hcl_t * hcl , hcl_bitmask_t mask , const hcl_ooch_t * msg , hcl_oow_t len )
2018-03-13 10:20:50 +00:00
{
2018-03-14 10:14:38 +00:00
worker_hcl_xtn_t * xtn = ( worker_hcl_xtn_t * ) hcl_getxtn ( hcl ) ;
hcl_server_t * server ;
2018-03-13 10:20:50 +00:00
2018-03-14 10:14:38 +00:00
server = xtn - > proto - > worker - > server ;
pthread_mutex_lock ( & server - > log_mutex ) ;
2018-03-16 05:56:05 +00:00
server - > prim . log_write ( server , xtn - > proto - > worker - > wid , mask , msg , len ) ;
2018-03-14 10:14:38 +00:00
pthread_mutex_unlock ( & server - > log_mutex ) ;
2018-03-13 10:20:50 +00:00
}
2018-04-26 04:39:20 +00:00
static void log_write_for_dummy ( hcl_t * hcl , hcl_bitmask_t mask , const hcl_ooch_t * msg , hcl_oow_t len )
2018-03-13 10:20:50 +00:00
{
2019-05-04 17:56:45 +00:00
server_hcl_xtn_t * xtn = ( server_hcl_xtn_t * ) hcl_getxtn ( hcl ) ;
2018-03-14 10:14:38 +00:00
hcl_server_t * server ;
2018-03-13 10:20:50 +00:00
2018-03-14 10:14:38 +00:00
server = xtn - > server ;
pthread_mutex_lock ( & server - > log_mutex ) ;
2018-03-16 05:56:05 +00:00
server - > prim . log_write ( server , HCL_SERVER_WID_INVALID , mask , msg , len ) ;
2018-03-14 10:14:38 +00:00
pthread_mutex_unlock ( & server - > log_mutex ) ;
2018-03-13 10:20:50 +00:00
}
/* ========================================================================= */
static int vm_startup ( hcl_t * hcl )
{
2018-03-14 10:14:38 +00:00
worker_hcl_xtn_t * xtn = ( worker_hcl_xtn_t * ) hcl_getxtn ( hcl ) ;
2018-03-13 10:20:50 +00:00
xtn - > vm_running = 1 ;
return 0 ;
}
static void vm_cleanup ( hcl_t * hcl )
{
2018-03-14 10:14:38 +00:00
worker_hcl_xtn_t * xtn = ( worker_hcl_xtn_t * ) hcl_getxtn ( hcl ) ;
2018-03-13 10:20:50 +00:00
xtn - > vm_running = 0 ;
}
static void vm_checkbc ( hcl_t * hcl , hcl_oob_t bcode )
{
2018-03-14 10:14:38 +00:00
worker_hcl_xtn_t * xtn = ( worker_hcl_xtn_t * ) hcl_getxtn ( hcl ) ;
2018-03-13 10:20:50 +00:00
if ( xtn - > proto - > worker - > server - > stopreq ) hcl_abort ( hcl ) ;
}
/*
static void gc_hcl ( hcl_t * hcl )
{
2018-03-14 14:40:05 +00:00
worker_hcl_xtn_t * xtn = ( worker_hcl_xtn_t * ) hcl_getxtn ( hcl ) ;
2018-03-13 10:20:50 +00:00
}
2018-03-14 10:14:38 +00:00
2018-03-13 10:20:50 +00:00
static void fini_hcl ( hcl_t * hcl )
{
2018-03-14 10:14:38 +00:00
worker_hcl_xtn_t * xtn = ( worker_hcl_xtn_t * ) hcl_getxtn ( hcl ) ;
2018-03-13 10:20:50 +00:00
}
2018-03-14 10:14:38 +00:00
*/
2018-03-13 10:20:50 +00:00
/* ========================================================================= */
2018-03-15 08:35:38 +00:00
# define SERVER_LOGMASK_INFO (HCL_LOG_INFO | HCL_LOG_APP)
# define SERVER_LOGMASK_ERROR (HCL_LOG_ERROR | HCL_LOG_APP)
2018-03-13 10:20:50 +00:00
hcl_server_proto_t * hcl_server_proto_open ( hcl_oow_t xtnsize , hcl_server_worker_t * worker )
{
hcl_server_proto_t * proto ;
hcl_cb_t hclcb ;
2018-03-14 10:14:38 +00:00
worker_hcl_xtn_t * xtn ;
2018-04-26 04:39:20 +00:00
hcl_bitmask_t trait ;
2018-03-13 10:20:50 +00:00
2018-03-18 15:29:16 +00:00
proto = ( hcl_server_proto_t * ) hcl_server_allocmem ( worker - > server , HCL_SIZEOF ( * proto ) ) ;
2018-03-14 10:14:38 +00:00
if ( ! proto ) return HCL_NULL ;
2018-03-13 10:20:50 +00:00
2018-03-14 10:14:38 +00:00
HCL_MEMSET ( proto , 0 , HCL_SIZEOF ( * proto ) ) ;
2018-03-13 10:20:50 +00:00
proto - > worker = worker ;
2018-03-15 10:30:06 +00:00
proto - > exec_runtime_event_index = HCL_TMR_INVALID_INDEX ;
2018-03-13 10:20:50 +00:00
2021-02-09 17:47:22 +00:00
proto - > hcl = hcl_openstdwithmmgr ( hcl_server_getmmgr ( proto - > worker - > server ) , HCL_SIZEOF ( * xtn ) , HCL_NULL ) ;
2018-03-14 10:14:38 +00:00
if ( ! proto - > hcl ) goto oops ;
2018-03-13 10:20:50 +00:00
2021-02-09 14:54:54 +00:00
/* replace the vmprim.log_write function */
2021-02-08 15:42:24 +00:00
proto - > hcl - > vmprim . log_write = log_write ;
2018-03-14 10:14:38 +00:00
xtn = ( worker_hcl_xtn_t * ) hcl_getxtn ( proto - > hcl ) ;
2018-03-13 10:20:50 +00:00
xtn - > proto = proto ;
2018-04-09 15:54:54 +00:00
hcl_setoption ( proto - > hcl , HCL_MOD_INCTX , & proto - > worker - > server - > cfg . module_inctx ) ;
2018-03-14 10:14:38 +00:00
hcl_setoption ( proto - > hcl , HCL_LOG_MASK , & proto - > worker - > server - > cfg . logmask ) ;
2019-06-21 12:36:25 +00:00
hcl_setcmgr ( proto - > hcl , hcl_server_getcmgr ( proto - > worker - > server ) ) ;
2018-03-13 10:20:50 +00:00
hcl_getoption ( proto - > hcl , HCL_TRAIT , & trait ) ;
2018-03-14 10:14:38 +00:00
# if defined(HCL_BUILD_DEBUG)
2020-09-28 15:44:04 +00:00
if ( proto - > worker - > server - > cfg . trait & HCL_SERVER_TRAIT_DEBUG_GC ) trait | = HCL_TRAIT_DEBUG_GC ;
2021-02-01 03:32:09 +00:00
if ( proto - > worker - > server - > cfg . trait & HCL_SERVER_TRAIT_DEBUG_BIGINT ) trait | = HCL_TRAIT_DEBUG_BIGINT ;
2018-03-14 10:14:38 +00:00
# endif
2018-03-13 10:20:50 +00:00
hcl_setoption ( proto - > hcl , HCL_TRAIT , & trait ) ;
HCL_MEMSET ( & hclcb , 0 , HCL_SIZEOF ( hclcb ) ) ;
2018-03-14 10:14:38 +00:00
/*hclcb.fini = fini_hcl;
hclcb . gc = gc_hcl ; */
2018-03-13 10:20:50 +00:00
hclcb . vm_startup = vm_startup ;
hclcb . vm_cleanup = vm_cleanup ;
hclcb . vm_checkbc = vm_checkbc ;
hcl_regcb ( proto - > hcl , & hclcb ) ;
2021-02-09 17:47:22 +00:00
if ( hcl_ignite ( proto - > hcl , worker - > server - > cfg . actor_heap_size ) < = - 1 ) goto oops ;
2018-03-13 10:20:50 +00:00
if ( hcl_addbuiltinprims ( proto - > hcl ) < = - 1 ) goto oops ;
2023-11-05 13:31:33 +00:00
if ( hcl_attachccio ( proto - > hcl , read_handler ) < = - 1 ) goto oops ;
2023-11-05 07:58:45 +00:00
if ( hcl_attachudio ( proto - > hcl , HCL_NULL , print_handler ) < = - 1 ) goto oops ;
2018-03-13 10:20:50 +00:00
return proto ;
oops :
if ( proto )
{
if ( proto - > hcl ) hcl_close ( proto - > hcl ) ;
2018-03-18 15:29:16 +00:00
hcl_server_freemem ( proto - > worker - > server , proto ) ;
2018-03-13 10:20:50 +00:00
}
2018-03-14 10:14:38 +00:00
return HCL_NULL ;
2018-03-13 10:20:50 +00:00
}
void hcl_server_proto_close ( hcl_server_proto_t * proto )
{
2018-03-18 15:29:16 +00:00
if ( proto - > tok . ptr ) hcl_server_freemem ( proto - > worker - > server , proto - > tok . ptr ) ;
2018-03-13 10:20:50 +00:00
hcl_close ( proto - > hcl ) ;
2018-03-18 15:29:16 +00:00
hcl_server_freemem ( proto - > worker - > server , proto ) ;
2018-03-13 10:20:50 +00:00
}
static int write_reply_chunk ( hcl_server_proto_t * proto )
{
struct msghdr msg ;
struct iovec iov [ 3 ] ;
hcl_bch_t cl [ 16 ] ; /* ensure that this is large enough for the chunk length string */
int index = 0 , count = 0 ;
if ( proto - > reply . type = = HCL_SERVER_PROTO_REPLY_CHUNKED )
{
if ( proto - > reply . nchunks < = 0 )
{
/* this is the first chunk */
2019-05-04 17:56:45 +00:00
iov [ count ] . iov_base = ( void * ) " .OK \n .DATA chunked \n " ;
2018-03-21 10:38:10 +00:00
iov [ count + + ] . iov_len = 18 ;
2018-03-13 10:20:50 +00:00
}
iov [ count ] . iov_base = cl ,
2023-05-31 15:30:41 +00:00
iov [ count + + ] . iov_len = snprintf ( cl , HCL_SIZEOF ( cl ) , " %zu: " , proto - > reply . len ) ;
2018-03-13 10:20:50 +00:00
}
iov [ count ] . iov_base = proto - > reply . buf ;
iov [ count + + ] . iov_len = proto - > reply . len ;
while ( 1 )
{
ssize_t nwritten ;
2018-03-14 10:14:38 +00:00
HCL_MEMSET ( & msg , 0 , HCL_SIZEOF ( msg ) ) ;
2018-03-13 10:20:50 +00:00
msg . msg_iov = ( struct iovec * ) & iov [ index ] ;
msg . msg_iovlen = count - index ;
nwritten = sendmsg ( proto - > worker - > sck , & msg , 0 ) ;
/*nwritten = writev(proto->worker->sck, (const struct iovec*)&iov[index], count - index);*/
2023-05-31 15:30:41 +00:00
if ( nwritten < = - 1 )
2018-03-13 10:20:50 +00:00
{
2018-03-14 14:40:05 +00:00
/* error occurred inside the worker thread shouldn't affect the error information
* in the server object . so here , i just log a message */
2018-03-16 17:27:24 +00:00
HCL_LOG2 ( proto - > hcl , SERVER_LOGMASK_ERROR , " Unable to sendmsg on %d - %hs \n " , proto - > worker - > sck , strerror ( errno ) ) ;
2023-05-31 15:30:41 +00:00
return - 1 ;
2018-03-13 10:20:50 +00:00
}
while ( index < count & & ( size_t ) nwritten > = iov [ index ] . iov_len )
nwritten - = iov [ index + + ] . iov_len ;
if ( index = = count ) break ;
iov [ index ] . iov_base = ( void * ) ( ( hcl_uint8_t * ) iov [ index ] . iov_base + nwritten ) ;
iov [ index ] . iov_len - = nwritten ;
}
if ( proto - > reply . len < = 0 )
{
/* this should be the last chunk */
proto - > reply . nchunks = 0 ;
}
else
{
proto - > reply . nchunks + + ;
proto - > reply . len = 0 ;
}
return 0 ;
}
void hcl_server_proto_start_reply ( hcl_server_proto_t * proto )
{
proto - > reply . type = HCL_SERVER_PROTO_REPLY_CHUNKED ;
proto - > reply . nchunks = 0 ;
proto - > reply . len = 0 ;
}
int hcl_server_proto_feed_reply ( hcl_server_proto_t * proto , const hcl_ooch_t * ptr , hcl_oow_t len , int escape )
{
2018-03-29 03:08:43 +00:00
# if defined(HCL_OOCH_IS_UCH)
2018-03-13 10:20:50 +00:00
hcl_oow_t bcslen , ucslen , donelen ;
int x ;
2018-03-29 03:08:43 +00:00
donelen = 0 ;
while ( donelen < len )
2018-03-13 10:20:50 +00:00
{
2018-03-29 03:08:43 +00:00
if ( escape )
2018-03-13 10:20:50 +00:00
{
2018-03-29 03:08:43 +00:00
if ( ptr [ donelen ] = = ' \\ ' | | ptr [ donelen ] = = ' \" ' )
{
/* i know that these characters don't need encoding conversion */
if ( proto - > reply . len > = HCL_COUNTOF ( proto - > reply . buf ) & & write_reply_chunk ( proto ) < = - 1 ) return - 1 ;
proto - > reply . buf [ proto - > reply . len + + ] = ' \\ ' ;
}
bcslen = HCL_COUNTOF ( proto - > reply . buf ) - proto - > reply . len ;
if ( bcslen < HCL_BCSIZE_MAX )
{
if ( write_reply_chunk ( proto ) < = - 1 ) return - 1 ;
bcslen = HCL_COUNTOF ( proto - > reply . buf ) - proto - > reply . len ;
}
ucslen = 1 ; /* i must go one by one for escaping */
}
else
{
bcslen = HCL_COUNTOF ( proto - > reply . buf ) - proto - > reply . len ;
if ( bcslen < HCL_BCSIZE_MAX )
{
if ( write_reply_chunk ( proto ) < = - 1 ) return - 1 ;
bcslen = HCL_COUNTOF ( proto - > reply . buf ) - proto - > reply . len ;
}
ucslen = len - donelen ;
2018-03-13 10:20:50 +00:00
}
2018-03-29 03:08:43 +00:00
x = hcl_convootobchars ( proto - > hcl , & ptr [ donelen ] , & ucslen , & proto - > reply . buf [ proto - > reply . len ] , & bcslen ) ;
if ( x < = - 1 & & ucslen < = 0 ) return - 1 ;
donelen + = ucslen ;
proto - > reply . len + = bcslen ;
2018-03-13 10:20:50 +00:00
}
return 0 ;
# else
2018-03-29 03:08:43 +00:00
while ( len > 0 )
2018-03-13 10:20:50 +00:00
{
if ( escape & & ( * ptr = = ' \\ ' | | * ptr = = ' \" ' ) )
{
if ( proto - > reply . len > = HCL_COUNTOF ( proto - > reply . buf ) & & write_reply_chunk ( proto ) < = - 1 ) return - 1 ;
proto - > reply . buf [ proto - > reply . len + + ] = ' \\ ' ;
}
2018-03-29 03:08:43 +00:00
if ( proto - > reply . len > = HCL_COUNTOF ( proto - > reply . buf ) & & write_reply_chunk ( proto ) < = - 1 ) return - 1 ;
proto - > reply . buf [ proto - > reply . len + + ] = * ptr + + ;
len - - ;
2018-03-13 10:20:50 +00:00
}
2018-03-29 03:08:43 +00:00
2018-03-13 10:20:50 +00:00
return 0 ;
2018-03-29 03:08:43 +00:00
# endif
2018-03-13 10:20:50 +00:00
}
2023-05-31 15:30:41 +00:00
int hcl_server_proto_feed_reply_bytes ( hcl_server_proto_t * proto , const hcl_bch_t * ptr , hcl_oow_t len , int escape )
{
while ( len > 0 )
{
if ( escape & & ( * ptr = = ' \\ ' | | * ptr = = ' \" ' ) )
{
if ( proto - > reply . len > = HCL_COUNTOF ( proto - > reply . buf ) & & write_reply_chunk ( proto ) < = - 1 ) return - 1 ;
proto - > reply . buf [ proto - > reply . len + + ] = ' \\ ' ;
}
if ( proto - > reply . len > = HCL_COUNTOF ( proto - > reply . buf ) & & write_reply_chunk ( proto ) < = - 1 ) return - 1 ;
proto - > reply . buf [ proto - > reply . len + + ] = * ptr + + ;
len - - ;
}
return 0 ;
}
2018-03-13 10:20:50 +00:00
int hcl_server_proto_end_reply ( hcl_server_proto_t * proto , const hcl_ooch_t * failmsg )
{
HCL_ASSERT ( proto - > hcl , proto - > reply . type = = HCL_SERVER_PROTO_REPLY_CHUNKED ) ;
if ( failmsg )
{
if ( proto - > reply . nchunks < = 0 & & proto - > reply . len < = 0 )
{
static hcl_ooch_t err1 [ ] = { ' . ' , ' E ' , ' R ' , ' R ' , ' O ' , ' R ' , ' ' , ' \" ' } ;
static hcl_ooch_t err2 [ ] = { ' \" ' , ' \n ' } ;
proto - > reply . type = HCL_SERVER_PROTO_REPLY_SIMPLE ; /* switch to the simple mode forcibly */
simple_error :
if ( hcl_server_proto_feed_reply ( proto , err1 , 8 , 0 ) < = - 1 | |
2018-04-07 15:54:16 +00:00
hcl_server_proto_feed_reply ( proto , failmsg , hcl_count_oocstr ( failmsg ) , 1 ) < = - 1 | |
2018-03-13 10:20:50 +00:00
hcl_server_proto_feed_reply ( proto , err2 , 2 , 0 ) < = - 1 ) return - 1 ;
if ( write_reply_chunk ( proto ) < = - 1 ) return - 1 ;
}
2023-05-31 15:30:41 +00:00
else
2018-03-13 10:20:50 +00:00
{
/* some chunks have beed emitted. but at the end, an error has occurred.
* send - 1 : as the last chunk . the receiver must rub out the reply
* buffer received so far and expect the following . ERROR response */
2018-03-21 10:38:10 +00:00
static hcl_ooch_t err0 [ ] = { ' - ' , ' 1 ' , ' : ' } ;
2018-03-13 10:20:50 +00:00
if ( proto - > reply . len > 0 & & write_reply_chunk ( proto ) < = - 1 ) return - 1 ;
proto - > reply . type = HCL_SERVER_PROTO_REPLY_SIMPLE ; /* switch to the simple mode forcibly */
proto - > reply . nchunks = 0 ;
proto - > reply . len = 0 ;
2018-03-21 10:38:10 +00:00
if ( hcl_server_proto_feed_reply ( proto , err0 , 3 , 0 ) < = - 1 ) return - 1 ;
2018-03-13 10:20:50 +00:00
goto simple_error ;
}
}
else
{
if ( proto - > reply . nchunks < = 0 & & proto - > reply . len < = 0 )
{
/* in the chunked mode. but no output has been made so far */
static hcl_ooch_t ok [ ] = { ' . ' , ' O ' , ' K ' , ' ' , ' \" ' , ' \" ' , ' \n ' } ;
proto - > reply . type = HCL_SERVER_PROTO_REPLY_SIMPLE ; /* switch to the simple mode forcibly */
if ( hcl_server_proto_feed_reply ( proto , ok , 7 , 0 ) < = - 1 ) return - 1 ;
if ( write_reply_chunk ( proto ) < = - 1 ) return - 1 ;
}
else
{
if ( proto - > reply . len > 0 & & write_reply_chunk ( proto ) < = - 1 ) return - 1 ;
if ( write_reply_chunk ( proto ) < = - 1 ) return - 1 ; /* write 0: */
}
}
return 0 ;
}
static HCL_INLINE int is_spacechar ( hcl_ooci_t c )
{
/* TODO: handle other space unicode characters */
switch ( c )
{
case ' ' :
case ' \f ' : /* formfeed */
case ' \r ' : /* carriage return */
case ' \t ' : /* horizon tab */
case ' \v ' : /* vertical tab */
return 1 ;
default :
return 0 ;
}
}
2018-03-18 15:29:16 +00:00
static HCL_INLINE int is_alphachar ( hcl_ooci_t c )
{
/* TODO: support full unicode */
return ( c > = ' a ' & & c < = ' z ' ) | | ( c > = ' A ' & & c < = ' Z ' ) ;
}
static HCL_INLINE int is_digitchar ( hcl_ooci_t c )
{
/* TODO: support full unicode */
return ( c > = ' 0 ' & & c < = ' 9 ' ) ;
}
2018-03-13 10:20:50 +00:00
static HCL_INLINE int read_char ( hcl_server_proto_t * proto )
{
2023-05-31 15:30:41 +00:00
if ( proto - > unread_count > 0 )
2022-08-02 13:41:13 +00:00
{
proto - > lxc = & proto - > unread_lxc ;
proto - > unread_count - - ;
return 0 ;
}
2023-05-19 03:55:08 +00:00
proto - > lxc = hcl_readbasesrchar ( proto - > hcl ) ;
2018-03-13 10:20:50 +00:00
if ( ! proto - > lxc ) return - 1 ;
return 0 ;
}
static HCL_INLINE int unread_last_char ( hcl_server_proto_t * proto )
{
2022-08-02 13:41:13 +00:00
if ( proto - > unread_count > = 1 )
{
/* only 1 character can be unread */
hcl_seterrbfmt ( proto - > hcl , HCL_EFLOOD , " too many unread characters " ) ;
return - 1 ;
}
if ( proto - > lxc ! = & proto - > unread_lxc ) proto - > unread_lxc = * proto - > lxc ;
proto - > unread_count + + ;
return 0 ;
2018-03-13 10:20:50 +00:00
}
2022-08-02 13:41:13 +00:00
# define GET_CHAR_TO(proto,ch) \
2018-03-13 10:20:50 +00:00
do { \
if ( read_char ( proto ) < = - 1 ) return - 1 ; \
2022-08-02 13:41:13 +00:00
ch = ( proto ) - > lxc - > c ; \
2018-03-13 10:20:50 +00:00
} while ( 0 )
2022-08-02 13:41:13 +00:00
# define GET_CHAR_TO_WITH_GOTO(proto,ch,oops) \
2018-04-12 02:22:17 +00:00
do { \
if ( read_char ( proto ) < = - 1 ) goto oops ; \
2022-08-02 13:41:13 +00:00
ch = ( proto ) - > lxc - > c ; \
2018-04-12 02:22:17 +00:00
} while ( 0 )
2018-03-13 10:20:50 +00:00
# define UNGET_LAST_CHAR(proto) \
do { \
if ( unread_last_char ( proto ) < = - 1 ) return - 1 ; \
} while ( 0 )
# define SET_TOKEN_TYPE(proto,tv) ((proto)->tok.type = (tv))
2022-08-02 13:41:13 +00:00
# define ADD_TOKEN_CHAR(proto,ch) \
do { if ( add_token_char ( proto , ch ) < = - 1 ) return - 1 ; } while ( 0 )
2018-03-13 10:20:50 +00:00
static HCL_INLINE int add_token_char ( hcl_server_proto_t * proto , hcl_ooch_t c )
{
if ( proto - > tok . len > = proto - > tok . capa )
{
hcl_ooch_t * tmp ;
hcl_oow_t capa ;
2018-03-16 16:20:40 +00:00
capa = HCL_ALIGN_POW2 ( proto - > tok . len + 1 , HCL_SERVER_TOKEN_NAME_ALIGN ) ;
2018-03-18 15:29:16 +00:00
tmp = ( hcl_ooch_t * ) hcl_server_reallocmem ( proto - > worker - > server , proto - > tok . ptr , capa * HCL_SIZEOF ( * tmp ) ) ;
2023-05-31 15:30:41 +00:00
if ( ! tmp )
2018-03-13 10:20:50 +00:00
{
2018-04-12 02:22:17 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_ESYSMEM , " Out of memory in allocating token buffer " ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
proto - > tok . ptr = tmp ;
proto - > tok . capa = capa ;
}
proto - > tok . ptr [ proto - > tok . len + + ] = c ;
return 0 ;
}
static void classify_current_ident_token ( hcl_server_proto_t * proto )
{
static struct cmd_t
{
hcl_server_proto_token_type_t type ;
hcl_ooch_t name [ 32 ] ;
2023-05-31 15:30:41 +00:00
} tab [ ] =
2018-03-13 10:20:50 +00:00
{
{ HCL_SERVER_PROTO_TOKEN_BEGIN , { ' . ' , ' B ' , ' E ' , ' G ' , ' I ' , ' N ' , ' \0 ' } } ,
{ HCL_SERVER_PROTO_TOKEN_END , { ' . ' , ' E ' , ' N ' , ' D ' , ' \0 ' } } ,
{ HCL_SERVER_PROTO_TOKEN_SCRIPT , { ' . ' , ' S ' , ' C ' , ' R ' , ' I ' , ' P ' , ' T ' , ' \0 ' } } ,
{ HCL_SERVER_PROTO_TOKEN_EXIT , { ' . ' , ' E ' , ' X ' , ' I ' , ' T ' , ' \0 ' } } ,
2023-05-31 15:30:41 +00:00
2018-03-13 10:20:50 +00:00
{ HCL_SERVER_PROTO_TOKEN_KILL_WORKER , { ' . ' , ' K ' , ' I ' , ' L ' , ' L ' , ' - ' , ' W ' , ' O ' , ' R ' , ' K ' , ' E ' , ' R ' , ' \0 ' } } ,
{ HCL_SERVER_PROTO_TOKEN_SHOW_WORKERS , { ' . ' , ' S ' , ' H ' , ' O ' , ' W ' , ' - ' , ' W ' , ' O ' , ' R ' , ' K ' , ' E ' , ' R ' , ' S ' , ' \0 ' } } ,
/* TODO: add more */
} ;
hcl_oow_t i ;
for ( i = 0 ; i < HCL_COUNTOF ( tab ) ; i + + )
{
2023-05-31 15:30:41 +00:00
if ( hcl_comp_oochars_oocstr ( proto - > tok . ptr , proto - > tok . len , tab [ i ] . name ) = = 0 )
2018-03-13 10:20:50 +00:00
{
SET_TOKEN_TYPE ( proto , tab [ i ] . type ) ;
break ;
}
}
}
static int get_token ( hcl_server_proto_t * proto )
{
hcl_ooci_t c ;
GET_CHAR_TO ( proto , c ) ;
/* skip spaces */
while ( is_spacechar ( c ) ) GET_CHAR_TO ( proto , c ) ;
SET_TOKEN_TYPE ( proto , HCL_SERVER_PROTO_TOKEN_EOF ) ; /* is it correct? */
proto - > tok . len = 0 ;
2018-03-19 09:22:12 +00:00
proto - > tok . loc = proto - > lxc - > l ; /* set token location */
2018-03-13 10:20:50 +00:00
switch ( c )
{
case HCL_OOCI_EOF :
SET_TOKEN_TYPE ( proto , HCL_SERVER_PROTO_TOKEN_EOF ) ;
break ;
2022-08-01 06:31:33 +00:00
2018-03-13 10:20:50 +00:00
case ' \n ' :
SET_TOKEN_TYPE ( proto , HCL_SERVER_PROTO_TOKEN_NL ) ;
break ;
case ' . ' :
SET_TOKEN_TYPE ( proto , HCL_SERVER_PROTO_TOKEN_IDENT ) ;
ADD_TOKEN_CHAR ( proto , c ) ;
GET_CHAR_TO ( proto , c ) ;
if ( ! is_alphachar ( c ) )
{
2018-04-12 02:22:17 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " Alphabetic character expected after a period " ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
do
{
ADD_TOKEN_CHAR ( proto , c ) ;
GET_CHAR_TO ( proto , c ) ;
}
while ( is_alphachar ( c ) | | c = = ' - ' ) ;
UNGET_LAST_CHAR ( proto ) ;
classify_current_ident_token ( proto ) ;
break ;
default :
2018-03-16 17:27:24 +00:00
if ( is_digitchar ( c ) )
{
SET_TOKEN_TYPE ( proto , HCL_SERVER_PROTO_TOKEN_NUMBER ) ;
do
{
ADD_TOKEN_CHAR ( proto , c ) ;
GET_CHAR_TO ( proto , c ) ;
}
while ( is_digitchar ( c ) ) ;
2022-08-02 13:41:13 +00:00
2018-03-16 17:27:24 +00:00
UNGET_LAST_CHAR ( proto ) ;
break ;
}
2018-04-12 02:22:17 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " Unrecognized character - [%jc] " , c ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
return 0 ;
}
2018-03-15 10:30:06 +00:00
static void exec_runtime_handler ( hcl_tmr_t * tmr , const hcl_ntime_t * now , hcl_tmr_event_t * evt )
{
2023-05-31 15:30:41 +00:00
/* [NOTE] this handler is executed in the main server thread
2018-03-24 06:06:01 +00:00
* when it calls hcl_tmr_fire ( ) . */
2018-03-15 15:23:51 +00:00
2018-03-15 10:30:06 +00:00
hcl_server_proto_t * proto ;
proto = ( hcl_server_proto_t * ) evt - > ctx ;
2018-03-15 15:23:51 +00:00
2018-03-16 14:57:34 +00:00
HCL_LOG1 ( proto - > worker - > server - > dummy_hcl , SERVER_LOGMASK_INFO , " Aborting script execution for max_actor_runtime exceeded [%zu] \n " , proto - > worker - > wid ) ;
2018-03-15 10:30:06 +00:00
hcl_abort ( proto - > hcl ) ;
}
static void exec_runtime_updater ( hcl_tmr_t * tmr , hcl_tmr_index_t old_index , hcl_tmr_index_t new_index , hcl_tmr_event_t * evt )
{
2023-05-31 15:30:41 +00:00
/* [NOTE] this handler is executed in the main server thread
2018-03-15 15:23:51 +00:00
* when it calls hcl_tmr_fire ( ) */
2018-03-15 10:30:06 +00:00
hcl_server_proto_t * proto ;
proto = ( hcl_server_proto_t * ) evt - > ctx ;
HCL_ASSERT ( proto - > hcl , proto - > exec_runtime_event_index = = old_index ) ;
2023-05-31 15:30:41 +00:00
/* the event is being removed by hcl_tmr_fire() or by hcl_tmr_delete()
2018-03-15 15:23:51 +00:00
* if new_index is HCL_TMR_INVALID_INDEX . it ' s being updated if not . */
2018-03-15 10:30:06 +00:00
proto - > exec_runtime_event_index = new_index ;
}
static int insert_exec_timer ( hcl_server_proto_t * proto , const hcl_ntime_t * tmout )
{
2018-03-15 15:23:51 +00:00
/* [NOTE] this is executed in the worker thread */
2023-05-31 15:30:41 +00:00
2018-03-15 10:30:06 +00:00
hcl_tmr_event_t event ;
hcl_tmr_index_t index ;
2018-03-15 15:23:51 +00:00
hcl_server_t * server ;
2018-03-15 10:30:06 +00:00
HCL_ASSERT ( proto - > hcl , proto - > exec_runtime_event_index = = HCL_TMR_INVALID_INDEX ) ;
2018-03-15 15:23:51 +00:00
server = proto - > worker - > server ;
2018-03-15 10:30:06 +00:00
HCL_MEMSET ( & event , 0 , HCL_SIZEOF ( event ) ) ;
event . ctx = proto ;
2020-12-31 18:02:58 +00:00
proto - > hcl - > vmprim . vm_gettime ( proto - > hcl , & event . when ) ;
2018-11-02 14:15:28 +00:00
HCL_ADD_NTIME ( & event . when , & event . when , tmout ) ;
2018-03-15 10:30:06 +00:00
event . handler = exec_runtime_handler ;
event . updater = exec_runtime_updater ;
2018-03-15 15:23:51 +00:00
pthread_mutex_lock ( & server - > tmr_mutex ) ;
index = hcl_tmr_insert ( server - > tmr , & event ) ;
2018-03-15 10:30:06 +00:00
proto - > exec_runtime_event_index = index ;
2018-03-15 15:23:51 +00:00
if ( index ! = HCL_TMR_INVALID_INDEX )
{
/* inform the server of timer event change */
write ( server - > mux_pipe [ 1 ] , " X " , 1 ) ; /* don't care even if it fails */
}
pthread_mutex_unlock ( & server - > tmr_mutex ) ;
return ( index = = HCL_TMR_INVALID_INDEX ) ? - 1 : 0 ;
2018-03-15 10:30:06 +00:00
}
static void delete_exec_timer ( hcl_server_proto_t * proto )
{
2018-03-15 15:23:51 +00:00
/* [NOTE] this is executed in the worker thread. if the event has been fired
2023-05-31 15:30:41 +00:00
* in the server thread , proto - > exec_runtime_event_index should be
2018-03-15 15:23:51 +00:00
* HCL_TMR_INVALID_INDEX as set by exec_runtime_handler */
hcl_server_t * server ;
server = proto - > worker - > server ;
pthread_mutex_lock ( & server - > tmr_mutex ) ;
2018-03-15 10:30:06 +00:00
if ( proto - > exec_runtime_event_index ! = HCL_TMR_INVALID_INDEX )
{
2023-05-31 15:30:41 +00:00
/* the event has not been fired yet. let's delete it
2018-03-15 15:23:51 +00:00
* if it has been fired , the index it shall be HCL_TMR_INVALID_INDEX already */
hcl_tmr_delete ( server - > tmr , proto - > exec_runtime_event_index ) ;
HCL_ASSERT ( proto - > hcl , proto - > exec_runtime_event_index = = HCL_TMR_INVALID_INDEX ) ;
/*proto->exec_runtime_event_index = HCL_TMR_INVALID_INDEX; */
}
pthread_mutex_unlock ( & server - > tmr_mutex ) ;
}
static int execute_script ( hcl_server_proto_t * proto , const hcl_bch_t * trigger )
{
hcl_oop_t obj ;
const hcl_ooch_t * failmsg = HCL_NULL ;
hcl_server_t * server ;
server = proto - > worker - > server ;
hcl_server_proto_start_reply ( proto ) ;
if ( server - > cfg . actor_max_runtime . sec < = 0 & & server - > cfg . actor_max_runtime . sec < = 0 )
{
obj = hcl_execute ( proto - > hcl ) ;
if ( ! obj ) failmsg = hcl_geterrmsg ( proto - > hcl ) ;
}
else
{
if ( insert_exec_timer ( proto , & server - > cfg . actor_max_runtime ) < = - 1 )
{
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " Cannot start execution timer \n " ) ;
hcl_seterrbfmt ( proto - > hcl , HCL_ESYSMEM , " cannot start execution timer " ) ; /* i do this just to compose the error message */
failmsg = hcl_geterrmsg ( proto - > hcl ) ;
}
else
{
obj = hcl_execute ( proto - > hcl ) ;
if ( ! obj ) failmsg = hcl_geterrmsg ( proto - > hcl ) ;
delete_exec_timer ( proto ) ;
}
}
2023-05-31 15:30:41 +00:00
if ( hcl_server_proto_end_reply ( proto , failmsg ) < = - 1 )
2018-03-15 15:23:51 +00:00
{
HCL_LOG1 ( proto - > hcl , SERVER_LOGMASK_ERROR , " Cannot finalize reply for %hs \n " , trigger ) ;
return - 1 ;
2018-03-15 10:30:06 +00:00
}
2018-03-15 15:23:51 +00:00
return 0 ;
2018-03-15 10:30:06 +00:00
}
2018-03-16 17:27:24 +00:00
2018-04-12 02:22:17 +00:00
static void send_error_message ( hcl_server_proto_t * proto , const hcl_ooch_t * errmsg )
2018-04-11 09:44:29 +00:00
{
hcl_server_proto_start_reply ( proto ) ;
if ( hcl_server_proto_end_reply ( proto , errmsg ) < = - 1 )
{
HCL_LOG1 ( proto - > hcl , SERVER_LOGMASK_ERROR , " Unable to send error message - %s \n " , errmsg ) ;
}
}
2022-08-03 13:56:20 +00:00
static void reformat_synerr ( hcl_t * hcl )
2022-08-02 13:41:13 +00:00
{
2022-08-03 13:56:20 +00:00
hcl_synerr_t synerr ;
const hcl_ooch_t * orgmsg ;
static hcl_ooch_t nullstr [ ] = { ' \0 ' } ;
2022-08-02 13:41:13 +00:00
2022-08-03 13:56:20 +00:00
hcl_getsynerr ( hcl , & synerr ) ;
orgmsg = hcl_backuperrmsg ( hcl ) ;
hcl_seterrbfmt (
hcl , HCL_ESYNERR ,
2023-05-31 15:30:41 +00:00
" %js%hs%.*js at %js%hsline %zu column %zu " ,
2022-08-03 13:56:20 +00:00
orgmsg ,
( synerr . tgt . len > 0 ? " near " : " " ) ,
synerr . tgt . len , synerr . tgt . val ,
( synerr . loc . file ? synerr . loc . file : nullstr ) ,
( synerr . loc . file ? " " : " " ) ,
synerr . loc . line , synerr . loc . colm
) ;
}
static void send_proto_hcl_error ( hcl_server_proto_t * proto )
{
if ( hcl_geterrnum ( proto - > hcl ) = = HCL_ESYNERR ) reformat_synerr ( proto - > hcl ) ;
2022-08-02 13:41:13 +00:00
send_error_message ( proto , hcl_geterrmsg ( proto - > hcl ) ) ;
}
2018-03-16 17:27:24 +00:00
static void show_server_workers ( hcl_server_proto_t * proto )
{
hcl_server_t * server ;
hcl_server_worker_t * w ;
server = proto - > worker - > server ;
pthread_mutex_lock ( & server - > worker_mutex ) ;
for ( w = server - > worker_list [ HCL_SERVER_WORKER_STATE_ALIVE ] . head ; w ; w = w - > next_worker )
{
/* TODO: implement this better... */
2019-05-31 10:54:13 +00:00
hcl_prbfmt ( proto - > hcl , " %zu %d %d \n " , w - > wid , w - > sck , 1000 ) ;
2018-03-16 17:27:24 +00:00
}
pthread_mutex_unlock ( & server - > worker_mutex ) ;
}
static int kill_server_worker ( hcl_server_proto_t * proto , hcl_oow_t wid )
{
hcl_server_t * server ;
int xret = 0 ;
server = proto - > worker - > server ;
pthread_mutex_lock ( & server - > worker_mutex ) ;
if ( wid > = server - > wid_map . capa )
{
hcl_server_seterrnum ( server , HCL_ENOENT ) ;
xret = - 1 ;
}
else
{
hcl_server_worker_t * worker ;
if ( ! server - > wid_map . ptr [ wid ] . used )
{
hcl_server_seterrnum ( server , HCL_ENOENT ) ;
xret = - 1 ;
}
else
{
worker = server - > wid_map . ptr [ wid ] . u . worker ;
2023-05-31 15:30:41 +00:00
if ( ! worker )
2018-03-16 17:27:24 +00:00
{
hcl_server_seterrnum ( server , HCL_ENOENT ) ;
xret = - 1 ;
}
else
{
if ( worker - > sck ) shutdown ( worker - > sck , SHUT_RDWR ) ;
if ( worker - > proto ) hcl_abort ( worker - > proto - > hcl ) ;
}
}
}
pthread_mutex_unlock ( & server - > worker_mutex ) ;
return xret ;
}
2018-03-13 10:20:50 +00:00
int hcl_server_proto_handle_request ( hcl_server_proto_t * proto )
{
2018-04-12 02:22:17 +00:00
if ( get_token ( proto ) < = - 1 ) goto fail_with_errmsg ;
2018-03-13 10:20:50 +00:00
switch ( proto - > tok . type )
{
case HCL_SERVER_PROTO_TOKEN_NL :
/* ignore new lines */
break ;
case HCL_SERVER_PROTO_TOKEN_EOF :
if ( proto - > req . state ! = HCL_SERVER_PROTO_REQ_IN_TOP_LEVEL )
{
2018-04-12 02:22:17 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " Unexpected EOF without .END " ) ;
goto fail_with_errmsg ;
2018-03-13 10:20:50 +00:00
}
/* drop connection silently */
return 0 ;
case HCL_SERVER_PROTO_TOKEN_EXIT :
if ( proto - > req . state ! = HCL_SERVER_PROTO_REQ_IN_TOP_LEVEL )
{
2018-04-12 02:22:17 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " .EXIT allowed in the top level only " ) ;
goto fail_with_errmsg ;
2018-03-13 10:20:50 +00:00
}
2018-04-12 02:22:17 +00:00
if ( get_token ( proto ) < = - 1 ) goto fail_with_errmsg ;
2018-03-13 10:20:50 +00:00
if ( proto - > tok . type ! = HCL_SERVER_PROTO_TOKEN_NL )
{
2018-04-12 02:22:17 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " No new line after .EXIT " ) ;
goto fail_with_errmsg ;
2018-03-13 10:20:50 +00:00
}
2023-05-31 15:30:41 +00:00
2018-03-13 10:20:50 +00:00
hcl_server_proto_start_reply ( proto ) ;
2023-05-31 15:30:41 +00:00
if ( hcl_server_proto_end_reply ( proto , HCL_NULL ) < = - 1 )
2018-03-13 10:20:50 +00:00
{
2018-03-15 15:23:51 +00:00
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " Unable to finalize reply for .EXIT \n " ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
return 0 ;
case HCL_SERVER_PROTO_TOKEN_BEGIN :
if ( proto - > req . state ! = HCL_SERVER_PROTO_REQ_IN_TOP_LEVEL )
{
2018-04-12 02:22:17 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " .BEGIN not allowed to be nested " ) ;
goto fail_with_errmsg ;
2018-03-13 10:20:50 +00:00
}
2018-04-12 02:22:17 +00:00
if ( get_token ( proto ) < = - 1 ) goto fail_with_errmsg ;
2018-03-13 10:20:50 +00:00
if ( proto - > tok . type ! = HCL_SERVER_PROTO_TOKEN_NL )
{
2018-04-12 02:22:17 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " No new line after .BEGIN " ) ;
goto fail_with_errmsg ;
2018-03-13 10:20:50 +00:00
}
proto - > req . state = HCL_SERVER_PROTO_REQ_IN_BLOCK_LEVEL ;
hcl_reset ( proto - > hcl ) ;
break ;
case HCL_SERVER_PROTO_TOKEN_END :
if ( proto - > req . state ! = HCL_SERVER_PROTO_REQ_IN_BLOCK_LEVEL )
{
2018-04-12 02:22:17 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " .END without opening .BEGIN " ) ;
goto fail_with_errmsg ;
2018-03-13 10:20:50 +00:00
}
2018-04-12 02:22:17 +00:00
if ( get_token ( proto ) < = - 1 ) goto fail_with_errmsg ;
2018-03-13 10:20:50 +00:00
if ( proto - > tok . type ! = HCL_SERVER_PROTO_TOKEN_NL )
{
2018-04-12 02:22:17 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " No new line after .END " ) ;
goto fail_with_errmsg ;
2018-03-13 10:20:50 +00:00
}
2022-08-02 13:41:13 +00:00
if ( hcl_endfeed ( proto - > hcl ) < = - 1 ) goto fail_with_errmsg ;
2018-03-17 05:44:40 +00:00
proto - > worker - > opstate = HCL_SERVER_WORKER_OPSTATE_EXECUTE ;
2018-04-12 02:22:17 +00:00
/* i must not jump to fail_with_errmsg when execute_script() fails.
* it may have produced some normal output already . so the function
* is supposed to handle an error in itself */
2023-05-31 15:30:41 +00:00
if ( execute_script ( proto , " .END " ) < = - 1 ) return - 1 ;
2018-03-13 10:20:50 +00:00
proto - > req . state = HCL_SERVER_PROTO_REQ_IN_TOP_LEVEL ;
break ;
case HCL_SERVER_PROTO_TOKEN_SCRIPT :
{
2018-03-16 16:20:40 +00:00
hcl_ooci_t c ;
2022-08-02 13:41:13 +00:00
hcl_ooch_t ch ;
hcl_oow_t feed_count = 0 ;
2018-03-16 16:20:40 +00:00
2023-05-31 15:30:41 +00:00
if ( proto - > req . state = = HCL_SERVER_PROTO_REQ_IN_TOP_LEVEL )
2022-08-02 13:41:13 +00:00
{
2023-05-19 03:55:08 +00:00
hcl_setbasesrloc ( proto - > hcl , 1 , 1 ) ;
2022-08-02 13:41:13 +00:00
hcl_reset ( proto - > hcl ) ;
}
2018-04-12 02:50:37 +00:00
2022-08-02 13:41:13 +00:00
/* check the first character after .SCRIPT */
2018-04-12 02:22:17 +00:00
GET_CHAR_TO_WITH_GOTO ( proto , c , fail_with_errmsg ) ;
2022-08-02 13:41:13 +00:00
if ( c = = HCL_OOCI_EOF )
2018-03-16 16:20:40 +00:00
{
2018-04-12 02:22:17 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " No contents on the .SCRIPT line " ) ;
goto fail_with_errmsg ;
2018-03-16 16:20:40 +00:00
}
2018-03-13 10:20:50 +00:00
2022-08-02 13:41:13 +00:00
if ( c = = ' \n ' ) goto script_eol ;
2018-03-13 10:20:50 +00:00
2022-08-02 13:41:13 +00:00
if ( ! is_spacechar ( c ) )
2018-03-13 10:20:50 +00:00
{
2022-08-02 13:41:13 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " No space after .SCRIPT " ) ;
2018-04-12 02:22:17 +00:00
goto fail_with_errmsg ;
2018-03-13 10:20:50 +00:00
}
2022-08-02 13:41:13 +00:00
while ( 1 )
2021-01-29 08:35:31 +00:00
{
2022-08-02 13:41:13 +00:00
GET_CHAR_TO_WITH_GOTO ( proto , c , fail_with_errmsg ) ;
if ( c = = ' \n ' | | c = = HCL_OOCI_EOF )
{
if ( c = = ' \n ' )
{
script_eol :
ch = c ;
if ( hcl_feed ( proto - > hcl , & ch , 1 ) < = - 1 ) goto fail_with_errmsg ;
feed_count + + ;
}
break ;
}
2022-07-31 13:17:44 +00:00
2022-08-02 13:41:13 +00:00
ch = c ;
if ( hcl_feed ( proto - > hcl , & ch , 1 ) < = - 1 ) goto fail_with_errmsg ;
feed_count + + ;
}
2022-07-31 13:17:44 +00:00
2022-08-02 13:41:13 +00:00
/*
if ( feed_count = = 0 )
2018-03-13 10:20:50 +00:00
{
2022-08-02 13:41:13 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " No contents on the .SCRIPT line " ) ;
2018-04-12 02:22:17 +00:00
goto fail_with_errmsg ;
2022-08-02 13:41:13 +00:00
} */
2018-03-13 10:20:50 +00:00
if ( proto - > req . state = = HCL_SERVER_PROTO_REQ_IN_TOP_LEVEL )
{
2022-08-02 13:41:13 +00:00
if ( hcl_endfeed ( proto - > hcl ) < = - 1 ) goto fail_with_errmsg ;
2018-03-17 05:44:40 +00:00
proto - > worker - > opstate = HCL_SERVER_WORKER_OPSTATE_EXECUTE ;
2018-03-15 15:23:51 +00:00
if ( execute_script ( proto , " .SCRIPT " ) < = - 1 ) return - 1 ;
2018-03-13 10:20:50 +00:00
}
break ;
}
case HCL_SERVER_PROTO_TOKEN_SHOW_WORKERS :
2018-03-16 17:27:24 +00:00
if ( proto - > req . state ! = HCL_SERVER_PROTO_REQ_IN_TOP_LEVEL )
{
2018-04-12 02:22:17 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " .SHOW-WORKERS not allowed to be nested " ) ;
goto fail_with_errmsg ;
2018-03-16 17:27:24 +00:00
}
2018-04-12 02:22:17 +00:00
if ( get_token ( proto ) < = - 1 ) goto fail_with_errmsg ;
2018-03-16 17:27:24 +00:00
if ( proto - > tok . type ! = HCL_SERVER_PROTO_TOKEN_NL )
{
2018-04-12 02:22:17 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " No new line after .SHOW-WORKERS " ) ;
goto fail_with_errmsg ;
2018-03-16 17:27:24 +00:00
}
2023-05-31 15:30:41 +00:00
2018-03-16 17:27:24 +00:00
hcl_server_proto_start_reply ( proto ) ;
2018-03-17 05:44:40 +00:00
proto - > worker - > opstate = HCL_SERVER_WORKER_OPSTATE_EXECUTE ;
2018-03-16 17:27:24 +00:00
show_server_workers ( proto ) ;
2018-03-14 10:14:38 +00:00
if ( hcl_server_proto_end_reply ( proto , HCL_NULL ) < = - 1 )
2018-03-13 10:20:50 +00:00
{
2018-03-15 15:23:51 +00:00
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " Unable to finalize reply for .SHOW-WORKERS \n " ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
2023-05-31 15:30:41 +00:00
2018-03-13 10:20:50 +00:00
break ;
case HCL_SERVER_PROTO_TOKEN_KILL_WORKER :
2018-03-16 17:27:24 +00:00
{
int n ;
hcl_oow_t wid , wp ;
static hcl_ooch_t failmsg [ ] = { ' U ' , ' n ' , ' a ' , ' b ' , ' l ' , ' e ' , ' ' , ' t ' , ' o ' , ' ' , ' k ' , ' i ' , ' l ' , ' l ' , ' \0 ' } ;
if ( proto - > req . state ! = HCL_SERVER_PROTO_REQ_IN_TOP_LEVEL )
{
2018-04-12 02:22:17 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " .KILL-WORKER not allowed to be nested " ) ;
goto fail_with_errmsg ;
2018-03-16 17:27:24 +00:00
}
2018-04-12 02:22:17 +00:00
if ( get_token ( proto ) < = - 1 ) goto fail_with_errmsg ;
2018-03-16 17:27:24 +00:00
if ( proto - > tok . type ! = HCL_SERVER_PROTO_TOKEN_NUMBER )
{
2018-04-12 02:22:17 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " No worker ID after .KILL-WORKER " ) ;
goto fail_with_errmsg ;
2018-03-16 17:27:24 +00:00
}
for ( wid = 0 , wp = 0 ; wp < proto - > tok . len ; wp + + ) wid = wid * 10 + ( proto - > tok . ptr [ wp ] - ' 0 ' ) ;
2018-04-12 02:22:17 +00:00
if ( get_token ( proto ) < = - 1 ) goto fail_with_errmsg ;
2018-03-16 17:27:24 +00:00
if ( proto - > tok . type ! = HCL_SERVER_PROTO_TOKEN_NL )
{
2018-04-12 02:22:17 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " No new line after worker ID of .KILL-WORKER " ) ;
goto fail_with_errmsg ;
2018-03-16 17:27:24 +00:00
}
2018-03-13 10:20:50 +00:00
hcl_server_proto_start_reply ( proto ) ;
2018-03-17 05:44:40 +00:00
proto - > worker - > opstate = HCL_SERVER_WORKER_OPSTATE_EXECUTE ;
2018-03-16 17:27:24 +00:00
n = kill_server_worker ( proto , wid ) ;
if ( hcl_server_proto_end_reply ( proto , ( n < = - 1 ? failmsg : HCL_NULL ) ) < = - 1 )
2018-03-13 10:20:50 +00:00
{
2018-03-15 15:23:51 +00:00
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " Unable to finalize reply for .KILL-WORKER \n " ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
break ;
2018-03-16 17:27:24 +00:00
}
2018-03-13 10:20:50 +00:00
default :
2022-08-03 13:56:20 +00:00
hcl_seterrbfmt ( proto - > hcl , HCL_EINVAL , " Unknown token %.*js " , proto - > tok . len , proto - > tok . ptr ) ;
2018-04-12 02:22:17 +00:00
goto fail_with_errmsg ;
2018-03-13 10:20:50 +00:00
}
return 1 ;
2018-04-12 02:22:17 +00:00
fail_with_errmsg :
2022-08-02 13:41:13 +00:00
send_proto_hcl_error ( proto ) ;
2018-04-12 02:22:17 +00:00
HCL_LOG1 ( proto - > hcl , SERVER_LOGMASK_ERROR , " Unable to compile .SCRIPT contents - %js \n " , hcl_geterrmsg ( proto - > hcl ) ) ;
return - 1 ;
2018-03-13 10:20:50 +00:00
}
/* ========================================================================= */
2018-03-14 10:14:38 +00:00
hcl_server_t * hcl_server_open ( hcl_mmgr_t * mmgr , hcl_oow_t xtnsize , hcl_server_prim_t * prim , hcl_errnum_t * errnum )
2018-03-13 10:20:50 +00:00
{
2018-03-18 15:29:16 +00:00
hcl_server_t * server = HCL_NULL ;
hcl_t * hcl = HCL_NULL ;
hcl_tmr_t * tmr = HCL_NULL ;
2019-05-04 17:56:45 +00:00
server_hcl_xtn_t * xtn ;
2018-03-15 15:23:51 +00:00
int pfd [ 2 ] , fcv ;
2018-04-26 04:39:20 +00:00
hcl_bitmask_t trait ;
2018-03-14 10:14:38 +00:00
server = ( hcl_server_t * ) HCL_MMGR_ALLOC ( mmgr , HCL_SIZEOF ( * server ) + xtnsize ) ;
2023-05-31 15:30:41 +00:00
if ( ! server )
2018-03-14 10:14:38 +00:00
{
if ( errnum ) * errnum = HCL_ESYSMEM ;
return HCL_NULL ;
}
2018-03-13 10:20:50 +00:00
2021-02-09 17:47:22 +00:00
hcl = hcl_openstdwithmmgr ( mmgr , HCL_SIZEOF ( * xtn ) , errnum ) ;
2018-03-18 15:29:16 +00:00
if ( ! hcl ) goto oops ;
2018-03-13 10:20:50 +00:00
2021-02-09 14:54:54 +00:00
/* replace the vmprim.log_write function */
2021-02-08 15:42:24 +00:00
hcl - > vmprim . log_write = log_write_for_dummy ;
2018-03-15 10:30:06 +00:00
tmr = hcl_tmr_open ( hcl , 0 , 1024 ) ; /* TOOD: make the timer's default size configurable */
if ( ! tmr )
{
2018-03-18 15:29:16 +00:00
if ( errnum ) * errnum = HCL_ESYSMEM ;
goto oops ;
2018-03-15 10:30:06 +00:00
}
2018-03-15 15:23:51 +00:00
if ( pipe ( pfd ) < = - 1 )
{
2021-02-08 15:42:24 +00:00
if ( errnum ) * errnum = hcl - > vmprim . syserrstrb ( hcl , 0 , errno , HCL_NULL , 0 ) ;
2018-03-18 15:29:16 +00:00
goto oops ;
2018-03-15 15:23:51 +00:00
}
2018-06-29 06:27:38 +00:00
# if defined(O_NONBLOCK) || defined(O_CLOEXEC)
2018-03-15 15:23:51 +00:00
fcv = fcntl ( pfd [ 0 ] , F_GETFD , 0 ) ;
2023-05-31 15:30:41 +00:00
if ( fcv > = 0 )
2018-06-29 06:27:38 +00:00
{
# if defined(O_NONBLOCK)
fcv | = O_NONBLOCK ;
# endif
# if defined(O_CLOEXEC)
fcv | = O_CLOEXEC ;
# endif
fcntl ( pfd [ 0 ] , F_SETFD , fcv ) ;
}
2018-03-15 15:23:51 +00:00
fcv = fcntl ( pfd [ 1 ] , F_GETFD , 0 ) ;
2023-05-31 15:30:41 +00:00
if ( fcv > = 0 )
2018-06-29 06:27:38 +00:00
{
# if defined(O_NONBLOCK)
fcv | = O_NONBLOCK ;
# endif
# if defined(O_CLOEXEC)
fcv | = O_CLOEXEC ;
# endif
fcntl ( pfd [ 1 ] , F_SETFD , fcv ) ;
}
2018-03-15 15:23:51 +00:00
# endif
2023-05-31 15:30:41 +00:00
2019-05-04 17:56:45 +00:00
xtn = ( server_hcl_xtn_t * ) hcl_getxtn ( hcl ) ;
2018-03-14 10:14:38 +00:00
xtn - > server = server ;
2018-03-13 10:20:50 +00:00
2018-03-14 10:14:38 +00:00
HCL_MEMSET ( server , 0 , HCL_SIZEOF ( * server ) + xtnsize ) ;
2019-06-21 12:36:25 +00:00
server - > _instsize = HCL_SIZEOF ( * server ) ;
server - > _mmgr = mmgr ;
server - > _cmgr = hcl_get_utf8_cmgr ( ) ;
2018-03-14 10:14:38 +00:00
server - > prim = * prim ;
server - > dummy_hcl = hcl ;
2018-03-15 10:30:06 +00:00
server - > tmr = tmr ;
2018-03-13 10:20:50 +00:00
2018-04-26 04:39:20 +00:00
server - > cfg . logmask = ~ ( hcl_bitmask_t ) 0 ;
2023-05-31 15:30:41 +00:00
server - > cfg . worker_stack_size = 512000UL ;
2018-03-13 10:20:50 +00:00
server - > cfg . actor_heap_size = 512000UL ;
2018-11-02 14:15:28 +00:00
HCL_INIT_NTIME ( & server - > cfg . worker_idle_timeout , 0 , 0 ) ;
HCL_INIT_NTIME ( & server - > cfg . actor_max_runtime , 0 , 0 ) ;
2018-03-15 10:30:06 +00:00
2018-03-15 15:23:51 +00:00
server - > mux_pipe [ 0 ] = pfd [ 0 ] ;
server - > mux_pipe [ 1 ] = pfd [ 1 ] ;
2018-03-16 05:56:05 +00:00
server - > wid_map . free_first = HCL_SERVER_WID_INVALID ;
server - > wid_map . free_last = HCL_SERVER_WID_INVALID ;
2018-03-22 09:46:44 +00:00
server - > listener . ep_fd = - 1 ;
2018-03-14 10:14:38 +00:00
pthread_mutex_init ( & server - > worker_mutex , HCL_NULL ) ;
2018-03-15 10:30:06 +00:00
pthread_mutex_init ( & server - > tmr_mutex , HCL_NULL ) ;
2018-03-14 10:14:38 +00:00
pthread_mutex_init ( & server - > log_mutex , HCL_NULL ) ;
2018-03-16 01:46:59 +00:00
/* the dummy hcl is used for this server to perform primitive operations
2023-05-31 15:30:41 +00:00
* such as getting system time or logging . so the heap size doesn ' t
2018-03-16 01:46:59 +00:00
* need to be changed from the tiny value set above . */
hcl_setoption ( server - > dummy_hcl , HCL_LOG_MASK , & server - > cfg . logmask ) ;
2019-06-21 12:36:25 +00:00
hcl_setcmgr ( server - > dummy_hcl , hcl_server_getcmgr ( server ) ) ;
2018-03-16 01:46:59 +00:00
hcl_getoption ( server - > dummy_hcl , HCL_TRAIT , & trait ) ;
# if defined(HCL_BUILD_DEBUG)
2020-09-28 15:44:04 +00:00
if ( server - > cfg . trait & HCL_SERVER_TRAIT_DEBUG_GC ) trait | = HCL_TRAIT_DEBUG_GC ;
2021-02-01 03:32:09 +00:00
if ( server - > cfg . trait & HCL_SERVER_TRAIT_DEBUG_BIGINT ) trait | = HCL_TRAIT_DEBUG_BIGINT ;
2018-03-16 01:46:59 +00:00
# endif
hcl_setoption ( server - > dummy_hcl , HCL_TRAIT , & trait ) ;
2018-03-13 10:20:50 +00:00
return server ;
2023-05-31 15:30:41 +00:00
2018-03-18 15:29:16 +00:00
oops :
/* NOTE: pipe should be closed if jump to here is made after pipe() above */
if ( tmr ) hcl_tmr_close ( tmr ) ;
if ( hcl ) hcl_close ( hcl ) ;
if ( server ) HCL_MMGR_FREE ( mmgr , server ) ;
2018-04-25 04:12:13 +00:00
2018-03-18 15:29:16 +00:00
return HCL_NULL ;
2018-03-13 10:20:50 +00:00
}
void hcl_server_close ( hcl_server_t * server )
{
2018-03-22 09:46:44 +00:00
HCL_ASSERT ( server - > dummy_hcl , server - > listener . head = = HCL_NULL ) ;
HCL_ASSERT ( server - > dummy_hcl , server - > listener . count = = 0 ) ;
HCL_ASSERT ( server - > dummy_hcl , server - > listener . ep_fd = = - 1 ) ;
2018-03-16 05:56:05 +00:00
if ( server - > wid_map . ptr )
{
2018-03-18 15:29:16 +00:00
hcl_server_freemem ( server , server - > wid_map . ptr ) ;
2018-03-16 05:56:05 +00:00
server - > wid_map . capa = 0 ;
server - > wid_map . free_first = HCL_SERVER_WID_INVALID ;
server - > wid_map . free_last = HCL_SERVER_WID_INVALID ;
}
2023-05-31 15:30:41 +00:00
2018-03-13 10:20:50 +00:00
pthread_mutex_destroy ( & server - > log_mutex ) ;
2018-03-15 10:30:06 +00:00
pthread_mutex_destroy ( & server - > tmr_mutex ) ;
2018-03-13 10:20:50 +00:00
pthread_mutex_destroy ( & server - > worker_mutex ) ;
2018-03-14 10:14:38 +00:00
2018-03-15 15:23:51 +00:00
close ( server - > mux_pipe [ 0 ] ) ;
close ( server - > mux_pipe [ 1 ] ) ;
2018-03-22 09:46:44 +00:00
2018-03-15 10:30:06 +00:00
hcl_tmr_close ( server - > tmr ) ;
2018-03-14 10:14:38 +00:00
hcl_close ( server - > dummy_hcl ) ;
2018-04-25 04:12:13 +00:00
2019-06-21 12:36:25 +00:00
HCL_MMGR_FREE ( server - > _mmgr , server ) ;
2018-03-13 10:20:50 +00:00
}
2018-03-16 05:56:05 +00:00
static HCL_INLINE int prepare_to_acquire_wid ( hcl_server_t * server )
{
hcl_oow_t new_capa ;
2018-07-01 13:17:42 +00:00
hcl_oow_t i , j ;
2018-03-16 05:56:05 +00:00
hcl_server_wid_map_data_t * tmp ;
HCL_ASSERT ( server - > dummy_hcl , server - > wid_map . free_first = = HCL_SERVER_WID_INVALID ) ;
HCL_ASSERT ( server - > dummy_hcl , server - > wid_map . free_last = = HCL_SERVER_WID_INVALID ) ;
2018-03-16 16:20:40 +00:00
new_capa = HCL_ALIGN_POW2 ( server - > wid_map . capa + 1 , HCL_SERVER_WID_MAP_ALIGN ) ;
2018-03-16 05:56:05 +00:00
if ( new_capa > HCL_SERVER_WID_MAX )
{
if ( server - > wid_map . capa > = HCL_SERVER_WID_MAX )
{
2018-03-16 14:57:34 +00:00
hcl_server_seterrnum ( server , HCL_EFLOOD ) ;
2018-03-16 05:56:05 +00:00
return - 1 ;
}
new_capa = HCL_SERVER_WID_MAX ;
}
2018-03-18 15:29:16 +00:00
tmp = ( hcl_server_wid_map_data_t * ) hcl_server_reallocmem ( server , server - > wid_map . ptr , HCL_SIZEOF ( * tmp ) * new_capa ) ;
if ( ! tmp ) return - 1 ;
2018-03-16 05:56:05 +00:00
server - > wid_map . free_first = server - > wid_map . capa ;
for ( i = server - > wid_map . capa , j = server - > wid_map . capa + 1 ; j < new_capa ; i + + , j + + )
{
2018-03-16 17:27:24 +00:00
tmp [ i ] . used = 0 ;
tmp [ i ] . u . next = j ;
2018-03-16 05:56:05 +00:00
}
2018-03-16 17:27:24 +00:00
tmp [ i ] . used = 0 ;
tmp [ i ] . u . next = HCL_SERVER_WID_INVALID ;
2018-03-16 05:56:05 +00:00
server - > wid_map . free_last = i ;
server - > wid_map . ptr = tmp ;
server - > wid_map . capa = new_capa ;
return 0 ;
}
static HCL_INLINE void acquire_wid ( hcl_server_t * server , hcl_server_worker_t * worker )
{
hcl_oow_t wid ;
wid = server - > wid_map . free_first ;
worker - > wid = wid ;
2018-03-16 17:27:24 +00:00
server - > wid_map . free_first = server - > wid_map . ptr [ wid ] . u . next ;
2018-03-16 05:56:05 +00:00
if ( server - > wid_map . free_first = = HCL_SERVER_WID_INVALID ) server - > wid_map . free_last = HCL_SERVER_WID_INVALID ;
2018-03-16 17:27:24 +00:00
server - > wid_map . ptr [ wid ] . used = 1 ;
server - > wid_map . ptr [ wid ] . u . worker = worker ;
2018-03-16 05:56:05 +00:00
}
static HCL_INLINE void release_wid ( hcl_server_t * server , hcl_server_worker_t * worker )
{
hcl_oow_t wid ;
wid = worker - > wid ;
HCL_ASSERT ( server - > dummy_hcl , wid < server - > wid_map . capa & & wid ! = HCL_SERVER_WID_INVALID ) ;
2018-03-16 17:27:24 +00:00
server - > wid_map . ptr [ wid ] . used = 0 ;
server - > wid_map . ptr [ wid ] . u . next = HCL_SERVER_WID_INVALID ;
2018-03-16 05:56:05 +00:00
if ( server - > wid_map . free_last = = HCL_SERVER_WID_INVALID )
{
HCL_ASSERT ( server - > dummy_hcl , server - > wid_map . free_first < = HCL_SERVER_WID_INVALID ) ;
server - > wid_map . free_first = wid ;
}
else
{
2018-03-16 17:27:24 +00:00
server - > wid_map . ptr [ server - > wid_map . free_last ] . u . next = wid ;
2018-03-16 05:56:05 +00:00
}
server - > wid_map . free_last = wid ;
worker - > wid = HCL_SERVER_WID_INVALID ;
}
2018-03-22 04:31:18 +00:00
static hcl_server_worker_t * alloc_worker ( hcl_server_t * server , int cli_sck , const hcl_sckaddr_t * peeraddr )
2018-03-13 10:20:50 +00:00
{
hcl_server_worker_t * worker ;
2018-03-15 10:30:06 +00:00
2018-03-18 15:29:16 +00:00
worker = ( hcl_server_worker_t * ) hcl_server_allocmem ( server , HCL_SIZEOF ( * worker ) ) ;
2018-03-14 10:14:38 +00:00
if ( ! worker ) return HCL_NULL ;
2018-03-13 10:20:50 +00:00
2018-03-14 10:14:38 +00:00
HCL_MEMSET ( worker , 0 , HCL_SIZEOF ( * worker ) ) ;
2018-03-17 05:44:40 +00:00
worker - > state = HCL_SERVER_WORKER_STATE_ZOMBIE ;
worker - > opstate = HCL_SERVER_WORKER_OPSTATE_IDLE ;
2018-03-13 10:20:50 +00:00
worker - > sck = cli_sck ;
2018-03-17 11:57:02 +00:00
worker - > peeraddr = * peeraddr ;
2018-03-13 10:20:50 +00:00
worker - > server = server ;
2023-05-31 15:30:41 +00:00
2020-12-31 18:02:58 +00:00
server - > dummy_hcl - > vmprim . vm_gettime ( server - > dummy_hcl , & worker - > alloc_time ) ; /* TODO: the callback may return monotonic time. find a way to guarantee it is realtime??? */
2018-03-16 05:56:05 +00:00
2023-05-31 15:30:41 +00:00
if ( server - > wid_map . free_first = = HCL_SERVER_WID_INVALID & & prepare_to_acquire_wid ( server ) < = - 1 )
2018-03-16 05:56:05 +00:00
{
2018-03-18 15:29:16 +00:00
hcl_server_freemem ( server , worker ) ;
2018-03-16 05:56:05 +00:00
return HCL_NULL ;
}
acquire_wid ( server , worker ) ;
2018-03-13 10:20:50 +00:00
return worker ;
}
2018-03-15 08:35:38 +00:00
static void close_worker_socket ( hcl_server_worker_t * worker )
{
2023-05-31 15:30:41 +00:00
if ( worker - > sck > = 0 )
2018-03-15 08:35:38 +00:00
{
if ( worker - > proto )
{
2018-03-16 14:57:34 +00:00
HCL_LOG2 ( worker - > proto - > hcl , SERVER_LOGMASK_INFO , " Closing worker socket %d [%zu] \n " , worker - > sck , worker - > wid ) ;
2018-03-15 08:35:38 +00:00
}
else
{
2018-03-24 06:06:01 +00:00
/* this should be in the main server thread. i use dummy_hcl for logging */
2018-03-16 14:57:34 +00:00
HCL_LOG2 ( worker - > server - > dummy_hcl , SERVER_LOGMASK_INFO , " Closing worker socket %d [%zu] \n " , worker - > sck , worker - > wid ) ;
2018-03-15 08:35:38 +00:00
}
close ( worker - > sck ) ;
worker - > sck = - 1 ;
}
}
2018-03-13 10:20:50 +00:00
static void free_worker ( hcl_server_worker_t * worker )
{
2018-03-15 08:35:38 +00:00
close_worker_socket ( worker ) ;
2023-05-31 15:30:41 +00:00
2018-03-16 14:57:34 +00:00
if ( worker - > proto )
{
HCL_LOG1 ( worker - > proto - > hcl , SERVER_LOGMASK_INFO , " Killing worker [%zu] \n " , worker - > wid ) ;
}
else
{
2018-03-24 06:06:01 +00:00
/* this should be in the main server thread. i use dummy_hcl for logging */
2018-03-16 14:57:34 +00:00
HCL_LOG1 ( worker - > server - > dummy_hcl , SERVER_LOGMASK_INFO , " Killing worker [%zu] \n " , worker - > wid ) ;
}
2018-03-16 05:56:05 +00:00
release_wid ( worker - > server , worker ) ;
2018-03-18 15:29:16 +00:00
hcl_server_freemem ( worker - > server , worker ) ;
2018-03-13 10:20:50 +00:00
}
2018-03-16 14:57:34 +00:00
static void add_worker_to_server ( hcl_server_t * server , hcl_server_worker_state_t wstate , hcl_server_worker_t * worker )
2018-03-13 10:20:50 +00:00
{
2018-03-14 14:40:05 +00:00
HCL_ASSERT ( server - > dummy_hcl , worker - > server = = server ) ;
2018-03-13 10:20:50 +00:00
if ( server - > worker_list [ wstate ] . tail )
{
server - > worker_list [ wstate ] . tail - > next_worker = worker ;
worker - > prev_worker = server - > worker_list [ wstate ] . tail ;
server - > worker_list [ wstate ] . tail = worker ;
2018-03-14 10:14:38 +00:00
worker - > next_worker = HCL_NULL ;
2018-03-13 10:20:50 +00:00
}
else
{
server - > worker_list [ wstate ] . tail = worker ;
server - > worker_list [ wstate ] . head = worker ;
2018-03-14 10:14:38 +00:00
worker - > prev_worker = HCL_NULL ;
worker - > next_worker = HCL_NULL ;
2018-03-13 10:20:50 +00:00
}
2018-03-16 14:57:34 +00:00
server - > worker_list [ wstate ] . count + + ;
2018-03-13 10:20:50 +00:00
worker - > state = wstate ;
}
static void zap_worker_in_server ( hcl_server_t * server , hcl_server_worker_t * worker )
{
hcl_server_worker_state_t wstate ;
2023-05-31 15:30:41 +00:00
2018-03-14 14:40:05 +00:00
HCL_ASSERT ( server - > dummy_hcl , worker - > server = = server ) ;
2018-03-13 10:20:50 +00:00
wstate = worker - > state ;
if ( worker - > prev_worker ) worker - > prev_worker - > next_worker = worker - > next_worker ;
else server - > worker_list [ wstate ] . head = worker - > next_worker ;
if ( worker - > next_worker ) worker - > next_worker - > prev_worker = worker - > prev_worker ;
else server - > worker_list [ wstate ] . tail = worker - > prev_worker ;
2018-03-16 14:57:34 +00:00
HCL_ASSERT ( server - > dummy_hcl , server - > worker_list [ wstate ] . count > 0 ) ;
server - > worker_list [ wstate ] . count - - ;
2018-03-17 05:44:40 +00:00
worker - > state = HCL_SERVER_WORKER_STATE_ZOMBIE ;
2018-03-14 10:14:38 +00:00
worker - > prev_worker = HCL_NULL ;
worker - > next_worker = HCL_NULL ;
2018-03-13 10:20:50 +00:00
}
static void * worker_main ( void * ctx )
{
hcl_server_worker_t * worker = ( hcl_server_worker_t * ) ctx ;
hcl_server_t * server = worker - > server ;
sigset_t set ;
sigfillset ( & set ) ;
2018-03-14 10:14:38 +00:00
pthread_sigmask ( SIG_BLOCK , & set , HCL_NULL ) ;
2018-03-13 10:20:50 +00:00
worker - > thr = pthread_self ( ) ;
2018-03-14 14:40:05 +00:00
worker - > proto = hcl_server_proto_open ( 0 , worker ) ;
2018-03-13 10:20:50 +00:00
if ( ! worker - > proto )
{
free_worker ( worker ) ;
2018-03-14 10:14:38 +00:00
return HCL_NULL ;
2018-03-13 10:20:50 +00:00
}
pthread_mutex_lock ( & server - > worker_mutex ) ;
2018-03-16 14:57:34 +00:00
add_worker_to_server ( server , HCL_SERVER_WORKER_STATE_ALIVE , worker ) ;
2018-03-13 10:20:50 +00:00
pthread_mutex_unlock ( & server - > worker_mutex ) ;
while ( ! server - > stopreq )
{
2018-03-17 05:44:40 +00:00
worker - > opstate = HCL_SERVER_WORKER_OPSTATE_WAIT ;
2023-05-31 15:30:41 +00:00
if ( hcl_server_proto_handle_request ( worker - > proto ) < = 0 )
2018-03-17 05:44:40 +00:00
{
worker - > opstate = HCL_SERVER_WORKER_OPSTATE_ERROR ;
break ;
}
2018-03-13 10:20:50 +00:00
}
hcl_server_proto_close ( worker - > proto ) ;
2018-03-14 10:14:38 +00:00
worker - > proto = HCL_NULL ;
2018-03-13 10:20:50 +00:00
pthread_mutex_lock ( & server - > worker_mutex ) ;
2023-05-31 15:30:41 +00:00
close_worker_socket ( worker ) ;
2018-03-13 10:20:50 +00:00
if ( ! worker - > claimed )
{
zap_worker_in_server ( server , worker ) ;
2018-03-16 14:57:34 +00:00
add_worker_to_server ( server , HCL_SERVER_WORKER_STATE_DEAD , worker ) ;
2018-03-13 10:20:50 +00:00
}
pthread_mutex_unlock ( & server - > worker_mutex ) ;
2018-03-14 10:14:38 +00:00
return HCL_NULL ;
2018-03-13 10:20:50 +00:00
}
static void purge_all_workers ( hcl_server_t * server , hcl_server_worker_state_t wstate )
{
hcl_server_worker_t * worker ;
while ( 1 )
{
pthread_mutex_lock ( & server - > worker_mutex ) ;
worker = server - > worker_list [ wstate ] . head ;
2023-05-31 15:30:41 +00:00
if ( worker )
2018-03-13 10:20:50 +00:00
{
zap_worker_in_server ( server , worker ) ;
worker - > claimed = 1 ;
if ( worker - > sck > = 0 ) shutdown ( worker - > sck , SHUT_RDWR ) ;
}
pthread_mutex_unlock ( & server - > worker_mutex ) ;
if ( ! worker ) break ;
2018-03-14 10:14:38 +00:00
pthread_join ( worker - > thr , HCL_NULL ) ;
2018-03-13 10:20:50 +00:00
free_worker ( worker ) ;
}
}
2018-04-26 04:39:20 +00:00
void hcl_server_logbfmt ( hcl_server_t * server , hcl_bitmask_t mask , const hcl_bch_t * fmt , . . . )
2018-03-13 10:20:50 +00:00
{
va_list ap ;
va_start ( ap , fmt ) ;
2018-03-14 10:14:38 +00:00
hcl_logbfmtv ( server - > dummy_hcl , mask , fmt , ap ) ;
va_end ( ap ) ;
}
2018-04-26 04:39:20 +00:00
void hcl_server_logufmt ( hcl_server_t * server , hcl_bitmask_t mask , const hcl_uch_t * fmt , . . . )
2018-03-14 10:14:38 +00:00
{
va_list ap ;
va_start ( ap , fmt ) ;
hcl_logufmtv ( server - > dummy_hcl , mask , fmt , ap ) ;
2018-03-13 10:20:50 +00:00
va_end ( ap ) ;
}
2018-11-02 14:15:28 +00:00
static void set_err_with_syserr ( hcl_server_t * server , int syserr_type , int syserr_code , const char * bfmt , . . . )
2018-03-14 14:40:05 +00:00
{
hcl_t * hcl = server - > dummy_hcl ;
hcl_errnum_t errnum ;
hcl_oow_t tmplen , tmplen2 ;
va_list ap ;
2023-05-31 15:30:41 +00:00
2018-03-14 14:40:05 +00:00
static hcl_bch_t b_dash [ ] = { ' ' , ' - ' , ' ' , ' \0 ' } ;
static hcl_uch_t u_dash [ ] = { ' ' , ' - ' , ' ' , ' \0 ' } ;
if ( hcl - > shuterr ) return ;
if ( hcl - > vmprim . syserrstrb )
{
2018-11-02 14:15:28 +00:00
errnum = hcl - > vmprim . syserrstrb ( hcl , syserr_type , syserr_code , hcl - > errmsg . tmpbuf . bch , HCL_COUNTOF ( hcl - > errmsg . tmpbuf . bch ) ) ;
2018-03-14 14:40:05 +00:00
va_start ( ap , bfmt ) ;
hcl_seterrbfmtv ( hcl , errnum , bfmt , ap ) ;
va_end ( ap ) ;
2018-03-29 03:08:43 +00:00
# if defined(HCL_OOCH_IS_UCH)
2018-04-07 15:54:16 +00:00
hcl - > errmsg . len + = hcl_copy_ucstr ( & hcl - > errmsg . buf [ hcl - > errmsg . len ] , HCL_COUNTOF ( hcl - > errmsg . buf ) - hcl - > errmsg . len , u_dash ) ;
2018-03-14 14:40:05 +00:00
tmplen2 = HCL_COUNTOF ( hcl - > errmsg . buf ) - hcl - > errmsg . len ;
2018-03-14 14:54:10 +00:00
hcl_convbtoucstr ( hcl , hcl - > errmsg . tmpbuf . bch , & tmplen , & hcl - > errmsg . buf [ hcl - > errmsg . len ] , & tmplen2 ) ;
2018-03-14 14:40:05 +00:00
hcl - > errmsg . len + = tmplen2 ; /* ignore conversion errors */
2018-03-29 03:08:43 +00:00
# else
2018-04-07 15:54:16 +00:00
hcl - > errmsg . len + = hcl_copy_bcstr ( & hcl - > errmsg . buf [ hcl - > errmsg . len ] , HCL_COUNTOF ( hcl - > errmsg . buf ) - hcl - > errmsg . len , b_dash ) ;
hcl - > errmsg . len + = hcl_copy_bcstr ( & hcl - > errmsg . buf [ hcl - > errmsg . len ] , HCL_COUNTOF ( hcl - > errmsg . buf ) - hcl - > errmsg . len , hcl - > errmsg . tmpbuf . bch ) ;
2018-03-29 03:08:43 +00:00
2018-03-14 14:40:05 +00:00
# endif
}
else
{
HCL_ASSERT ( hcl , hcl - > vmprim . syserrstru ! = HCL_NULL ) ;
2018-11-02 14:15:28 +00:00
errnum = hcl - > vmprim . syserrstru ( hcl , syserr_type , syserr_code , hcl - > errmsg . tmpbuf . uch , HCL_COUNTOF ( hcl - > errmsg . tmpbuf . uch ) ) ;
2018-03-14 14:40:05 +00:00
va_start ( ap , bfmt ) ;
hcl_seterrbfmtv ( hcl , errnum , bfmt , ap ) ;
va_end ( ap ) ;
2018-03-29 03:08:43 +00:00
# if defined(HCL_OOCH_IS_UCH)
2018-04-07 15:54:16 +00:00
hcl - > errmsg . len + = hcl_copy_ucstr ( & hcl - > errmsg . buf [ hcl - > errmsg . len ] , HCL_COUNTOF ( hcl - > errmsg . buf ) - hcl - > errmsg . len , u_dash ) ;
hcl - > errmsg . len + = hcl_copy_ucstr ( & hcl - > errmsg . buf [ hcl - > errmsg . len ] , HCL_COUNTOF ( hcl - > errmsg . buf ) - hcl - > errmsg . len , hcl - > errmsg . tmpbuf . uch ) ;
2018-03-29 03:08:43 +00:00
# else
2018-04-07 15:54:16 +00:00
hcl - > errmsg . len + = hcl_copy_bcstr ( & hcl - > errmsg . buf [ hcl - > errmsg . len ] , HCL_COUNTOF ( hcl - > errmsg . buf ) - hcl - > errmsg . len , b_dash ) ;
2018-03-14 14:40:05 +00:00
tmplen2 = HCL_COUNTOF ( hcl - > errmsg . buf ) - hcl - > errmsg . len ;
2018-03-14 14:54:10 +00:00
hcl_convutobcstr ( hcl , hcl - > errmsg . tmpbuf . uch , & tmplen , & hcl - > errmsg . buf [ hcl - > errmsg . len ] , & tmplen2 ) ;
2018-03-14 14:40:05 +00:00
hcl - > errmsg . len + = tmplen2 ; /* ignore conversion errors */
# endif
}
server - > errnum = errnum ;
2018-04-07 15:54:16 +00:00
hcl_copy_oochars ( server - > errmsg . buf , server - > dummy_hcl - > errmsg . buf , HCL_COUNTOF ( server - > errmsg . buf ) ) ;
2018-03-14 14:40:05 +00:00
server - > errmsg . len = server - > dummy_hcl - > errmsg . len ;
}
2018-03-22 09:46:44 +00:00
static void free_all_listeners ( hcl_server_t * server )
2018-03-13 10:20:50 +00:00
{
2018-03-22 09:46:44 +00:00
hcl_server_listener_t * lp ;
struct epoll_event dummy_ev ;
2018-03-13 10:20:50 +00:00
2018-03-22 09:46:44 +00:00
epoll_ctl ( server - > listener . ep_fd , EPOLL_CTL_DEL , server - > mux_pipe [ 0 ] , & dummy_ev ) ;
while ( server - > listener . head )
2018-03-14 15:01:07 +00:00
{
2018-03-22 09:46:44 +00:00
lp = server - > listener . head ;
server - > listener . head = lp - > next_listener ;
server - > listener . count - - ;
epoll_ctl ( server - > listener . ep_fd , EPOLL_CTL_DEL , lp - > sck , & dummy_ev ) ;
close ( lp - > sck ) ;
hcl_server_freemem ( server , lp ) ;
2018-03-14 15:01:07 +00:00
}
2018-03-13 10:20:50 +00:00
2018-03-22 09:46:44 +00:00
HCL_ASSERT ( server - > dummy_hcl , server - > listener . ep_fd > = 0 ) ;
close ( server - > listener . ep_fd ) ;
server - > listener . ep_fd = - 1 ;
}
static int setup_listeners ( hcl_server_t * server , const hcl_bch_t * addrs )
{
const hcl_bch_t * addr_ptr , * comma ;
int ep_fd , fcv ;
struct epoll_event ev ;
ep_fd = epoll_create ( 1024 ) ;
if ( ep_fd < = - 1 )
2018-03-13 10:20:50 +00:00
{
2018-11-02 14:15:28 +00:00
set_err_with_syserr ( server , 0 , errno , " unable to create multiplexer " ) ;
2018-03-22 09:46:44 +00:00
HCL_LOG1 ( server - > dummy_hcl , SERVER_LOGMASK_ERROR , " %js \n " , hcl_server_geterrmsg ( server ) ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
2018-03-22 09:53:16 +00:00
# if defined(O_CLOEXEC)
2018-03-22 09:46:44 +00:00
fcv = fcntl ( ep_fd , F_GETFD , 0 ) ;
if ( fcv > = 0 ) fcntl ( ep_fd , F_SETFD , fcv | O_CLOEXEC ) ;
2018-03-22 09:53:16 +00:00
# endif
2018-03-13 10:20:50 +00:00
2018-03-22 09:46:44 +00:00
HCL_MEMSET ( & ev , 0 , HCL_SIZEOF ( ev ) ) ;
ev . events = EPOLLIN | EPOLLHUP | EPOLLERR ;
ev . data . fd = server - > mux_pipe [ 0 ] ;
if ( epoll_ctl ( ep_fd , EPOLL_CTL_ADD , server - > mux_pipe [ 0 ] , & ev ) < = - 1 )
2018-03-13 10:20:50 +00:00
{
2018-11-02 14:15:28 +00:00
set_err_with_syserr ( server , 0 , errno , " unable to register pipe %d to multiplexer " , server - > mux_pipe [ 0 ] ) ;
2018-03-22 09:46:44 +00:00
HCL_LOG1 ( server - > dummy_hcl , SERVER_LOGMASK_ERROR , " %js \n " , hcl_server_geterrmsg ( server ) ) ;
close ( ep_fd ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
2018-03-22 09:46:44 +00:00
server - > listener . ep_fd = ep_fd ;
addr_ptr = addrs ;
while ( 1 )
{
hcl_sckaddr_t srv_addr ;
int srv_fd , sck_fam , optval ;
hcl_scklen_t srv_len ;
hcl_oow_t addr_len ;
hcl_server_listener_t * listener ;
2018-04-07 15:54:16 +00:00
comma = hcl_find_bchar_in_bcstr ( addr_ptr , ' , ' ) ;
addr_len = comma ? comma - addr_ptr : hcl_count_bcstr ( addr_ptr ) ;
2018-03-22 09:46:44 +00:00
/* [NOTE] no whitespaces are allowed before and after a comma */
sck_fam = hcl_bchars_to_sckaddr ( addr_ptr , addr_len , & srv_addr , & srv_len ) ;
2023-05-31 15:30:41 +00:00
if ( sck_fam < = - 1 )
2018-03-22 09:46:44 +00:00
{
hcl_server_seterrbfmt ( server , HCL_EINVAL , " unable to convert address - %.*hs " , addr_len , addr_ptr ) ;
HCL_LOG1 ( server - > dummy_hcl , SERVER_LOGMASK_ERROR , " %js \n " , hcl_server_geterrmsg ( server ) ) ;
goto next_segment ;
}
srv_fd = socket ( sck_fam , SOCK_STREAM , 0 ) ;
if ( srv_fd < = - 1 )
{
2018-11-02 14:15:28 +00:00
set_err_with_syserr ( server , 0 , errno , " unable to open server socket for %.*hs " , addr_len , addr_ptr ) ;
2018-03-22 09:46:44 +00:00
HCL_LOG1 ( server - > dummy_hcl , SERVER_LOGMASK_ERROR , " %js \n " , hcl_server_geterrmsg ( server ) ) ;
goto next_segment ;
}
optval = 1 ;
setsockopt ( srv_fd , SOL_SOCKET , SO_REUSEADDR , & optval , HCL_SIZEOF ( int ) ) ;
2018-06-29 06:27:38 +00:00
# if defined(O_NONBLOCK) || defined(O_CLOEXEC)
2018-03-22 09:46:44 +00:00
fcv = fcntl ( srv_fd , F_GETFD , 0 ) ;
2023-05-31 15:30:41 +00:00
if ( fcv > = 0 )
2018-06-29 06:27:38 +00:00
{
# if defined(O_NONBLOCK)
fcv | = O_NONBLOCK ;
# endif
# if defined(O_CLOEXEC)
fcv | = O_CLOEXEC ;
# endif
fcntl ( srv_fd , F_SETFL , fcv ) ;
}
2018-03-23 10:02:08 +00:00
# endif
2018-03-22 09:46:44 +00:00
if ( bind ( srv_fd , ( struct sockaddr * ) & srv_addr , srv_len ) = = - 1 )
{
2018-11-02 14:15:28 +00:00
set_err_with_syserr ( server , 0 , errno , " unable to bind server socket %d for %.*hs " , srv_fd , addr_len , addr_ptr ) ;
2018-03-22 09:46:44 +00:00
HCL_LOG1 ( server - > dummy_hcl , SERVER_LOGMASK_ERROR , " %js \n " , hcl_server_geterrmsg ( server ) ) ;
close ( srv_fd ) ;
goto next_segment ;
}
if ( listen ( srv_fd , 128 ) < = - 1 )
{
2018-11-02 14:15:28 +00:00
set_err_with_syserr ( server , 0 , errno , " unable to listen on server socket %d for %.*hs " , srv_fd , addr_len , addr_ptr ) ;
2018-03-22 09:46:44 +00:00
HCL_LOG1 ( server - > dummy_hcl , SERVER_LOGMASK_ERROR , " %js \n " , hcl_server_geterrmsg ( server ) ) ;
close ( srv_fd ) ;
goto next_segment ;
}
HCL_MEMSET ( & ev , 0 , HCL_SIZEOF ( ev ) ) ;
ev . events = EPOLLIN | EPOLLHUP | EPOLLERR ;
ev . data . fd = srv_fd ;
if ( epoll_ctl ( ep_fd , EPOLL_CTL_ADD , srv_fd , & ev ) < = - 1 )
{
2018-11-02 14:15:28 +00:00
set_err_with_syserr ( server , 0 , errno , " unable to register server socket %d to multiplexer for %.*hs " , srv_fd , addr_len , addr_ptr ) ;
2018-03-22 09:46:44 +00:00
HCL_LOG1 ( server - > dummy_hcl , SERVER_LOGMASK_ERROR , " %js \n " , hcl_server_geterrmsg ( server ) ) ;
close ( srv_fd ) ;
goto next_segment ;
}
listener = ( hcl_server_listener_t * ) hcl_server_allocmem ( server , HCL_SIZEOF ( * listener ) ) ;
if ( ! listener )
{
close ( srv_fd ) ;
goto next_segment ;
}
HCL_MEMSET ( listener , 0 , HCL_SIZEOF ( * listener ) ) ;
listener - > sck = srv_fd ;
listener - > sckaddr = srv_addr ;
listener - > next_listener = server - > listener . head ;
server - > listener . head = listener ;
server - > listener . count + + ;
next_segment :
if ( ! comma ) break ;
addr_ptr = comma + 1 ;
}
if ( ! server - > listener . head )
2018-03-13 10:20:50 +00:00
{
2018-03-22 09:46:44 +00:00
/* no valid server has been configured */
hcl_server_seterrbfmt ( server , HCL_EINVAL , " unable to set up listeners with %hs " , addrs ) ;
free_all_listeners ( server ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
2018-03-22 09:46:44 +00:00
return 0 ;
}
int hcl_server_start ( hcl_server_t * server , const hcl_bch_t * addrs )
{
int xret = 0 , fcv ;
pthread_attr_t thr_attr ;
if ( setup_listeners ( server , addrs ) < = - 1 ) return - 1 ;
2018-03-13 10:20:50 +00:00
pthread_attr_init ( & thr_attr ) ;
pthread_attr_setstacksize ( & thr_attr , server - > cfg . worker_stack_size ) ;
server - > stopreq = 0 ;
while ( ! server - > stopreq )
{
2018-03-22 04:31:18 +00:00
hcl_sckaddr_t cli_addr ;
hcl_scklen_t cli_len ;
2018-03-24 06:06:01 +00:00
int cli_fd ;
2018-03-13 10:20:50 +00:00
pthread_t thr ;
2018-03-15 10:30:06 +00:00
hcl_ntime_t tmout ;
2018-03-13 10:20:50 +00:00
hcl_server_worker_t * worker ;
2018-03-22 09:46:44 +00:00
int n ;
2018-03-13 10:20:50 +00:00
2018-03-15 10:30:06 +00:00
pthread_mutex_lock ( & server - > tmr_mutex ) ;
n = hcl_tmr_gettmout ( server - > tmr , HCL_NULL , & tmout ) ;
pthread_mutex_unlock ( & server - > tmr_mutex ) ;
2018-11-02 14:15:28 +00:00
if ( n < = - 1 ) HCL_INIT_NTIME ( & tmout , 10 , 0 ) ;
2018-03-15 10:30:06 +00:00
2018-03-22 09:46:44 +00:00
n = epoll_wait ( server - > listener . ep_fd , server - > listener . ev_buf , HCL_COUNTOF ( server - > listener . ev_buf ) , HCL_SECNSEC_TO_MSEC ( tmout . sec , tmout . nsec ) ) ;
2018-03-15 15:23:51 +00:00
2018-03-16 14:57:34 +00:00
purge_all_workers ( server , HCL_SERVER_WORKER_STATE_DEAD ) ;
2018-03-15 10:30:06 +00:00
if ( n < = - 1 )
2018-03-13 10:20:50 +00:00
{
2018-03-15 08:35:38 +00:00
if ( server - > stopreq ) break ; /* normal termination requested */
if ( errno = = EINTR ) continue ; /* interrupted but not termination requested */
2018-11-02 14:15:28 +00:00
set_err_with_syserr ( server , 0 , errno , " unable to poll for events in server " ) ;
2018-03-15 08:35:38 +00:00
xret = - 1 ;
2018-03-13 10:20:50 +00:00
break ;
}
2018-03-15 10:30:06 +00:00
pthread_mutex_lock ( & server - > tmr_mutex ) ;
hcl_tmr_fire ( server - > tmr , HCL_NULL , HCL_NULL ) ;
pthread_mutex_unlock ( & server - > tmr_mutex ) ;
2018-03-15 08:35:38 +00:00
2018-03-22 09:46:44 +00:00
while ( n > 0 )
2018-03-13 10:20:50 +00:00
{
2018-03-22 09:46:44 +00:00
struct epoll_event * evp ;
2018-03-24 06:06:01 +00:00
2018-03-22 09:46:44 +00:00
- - n ;
2018-03-15 10:30:06 +00:00
2018-03-22 09:46:44 +00:00
evp = & server - > listener . ev_buf [ n ] ;
if ( ! evp - > events /*& (POLLIN | POLLHUP | POLLERR) */ ) continue ;
if ( evp - > data . fd = = server - > mux_pipe [ 0 ] )
2018-03-15 15:23:51 +00:00
{
char tmp [ 128 ] ;
while ( read ( server - > mux_pipe [ 0 ] , tmp , HCL_SIZEOF ( tmp ) ) > 0 ) /* nothing */ ;
}
2018-03-22 09:46:44 +00:00
else
2018-03-15 10:30:06 +00:00
{
2018-03-22 09:46:44 +00:00
/* the reset should be the listener's socket */
2018-03-15 10:30:06 +00:00
cli_len = HCL_SIZEOF ( cli_addr ) ;
2018-03-22 09:46:44 +00:00
cli_fd = accept ( evp - > data . fd , ( struct sockaddr * ) & cli_addr , & cli_len ) ;
2018-03-15 10:30:06 +00:00
if ( cli_fd = = - 1 )
{
if ( server - > stopreq ) break ; /* normal termination requested */
2018-03-22 09:46:44 +00:00
if ( errno = = EINTR ) continue ; /* interrupted but no termination requested */
2018-03-23 10:02:08 +00:00
# if defined(EWOULDBLOCK) && defined(EAGAIN) && (EWOULDBLOCK != EAGAIN)
if ( errno = = EWOULDBLOCK | | errno = = EAGAIN ) continue ;
# elif defined(EWOULDBLOCK)
if ( errno = = EWOULDBLOCK ) continue ;
# elif defined(EAGAIN)
if ( errno = = EAGAIN ) continue ;
# endif
2018-03-15 10:30:06 +00:00
2018-11-02 14:15:28 +00:00
set_err_with_syserr ( server , 0 , errno , " unable to accept worker on server socket %d " , evp - > data . fd ) ;
2018-03-15 10:30:06 +00:00
xret = - 1 ;
break ;
}
2018-06-29 06:27:38 +00:00
# if defined(O_NONBLOCK) || defined(O_CLOEXEC)
2018-03-22 09:46:44 +00:00
fcv = fcntl ( cli_fd , F_GETFD , 0 ) ;
2023-05-31 15:30:41 +00:00
if ( fcv > = 0 )
2018-06-29 06:27:38 +00:00
{
# if defined(O_NONBLOCK)
fcv & = ~ O_NONBLOCK ; // force the accepted socket to be blocking
# endif
# if defined(O_CLOEXEC)
fcv | = O_CLOEXEC ;
# endif
fcntl ( cli_fd , F_SETFD , fcv ) ;
}
2018-03-22 09:53:16 +00:00
# endif
2018-03-22 09:46:44 +00:00
2018-03-16 14:57:34 +00:00
if ( server - > cfg . worker_max_count > 0 )
{
int flood ;
pthread_mutex_lock ( & server - > worker_mutex ) ;
flood = ( server - > worker_list [ HCL_SERVER_WORKER_STATE_ALIVE ] . count > = server - > cfg . worker_max_count ) ;
pthread_mutex_unlock ( & server - > worker_mutex ) ;
2023-05-31 15:30:41 +00:00
if ( flood )
2018-03-24 06:06:01 +00:00
{
HCL_LOG1 ( server - > dummy_hcl , SERVER_LOGMASK_ERROR , " Not accepting connection for too many workers - socket %d \n " , cli_fd ) ;
goto drop_connection ;
}
2018-03-16 14:57:34 +00:00
}
2018-03-15 10:30:06 +00:00
2018-03-17 11:57:02 +00:00
worker = alloc_worker ( server , cli_fd , & cli_addr ) ;
2018-03-16 05:56:05 +00:00
if ( ! worker )
{
2018-03-16 14:57:34 +00:00
HCL_LOG1 ( server - > dummy_hcl , SERVER_LOGMASK_ERROR , " Unable to accomodate worker - socket %d \n " , cli_fd ) ;
2018-03-24 06:06:01 +00:00
drop_connection :
2018-03-16 05:56:05 +00:00
close ( cli_fd ) ;
}
else
2018-03-15 10:30:06 +00:00
{
2018-03-16 14:57:34 +00:00
HCL_LOG2 ( server - > dummy_hcl , SERVER_LOGMASK_INFO , " Accomodated worker [%zu] - socket %d \n " , worker - > wid , cli_fd ) ;
2018-03-16 05:56:05 +00:00
if ( pthread_create ( & thr , & thr_attr , worker_main , worker ) ! = 0 )
{
free_worker ( worker ) ;
}
2018-03-15 10:30:06 +00:00
}
}
2018-03-13 10:20:50 +00:00
}
}
purge_all_workers ( server , HCL_SERVER_WORKER_STATE_ALIVE ) ;
purge_all_workers ( server , HCL_SERVER_WORKER_STATE_DEAD ) ;
pthread_attr_destroy ( & thr_attr ) ;
2018-03-22 09:46:44 +00:00
free_all_listeners ( server ) ;
2018-03-15 08:35:38 +00:00
return xret ;
2018-03-13 10:20:50 +00:00
}
void hcl_server_stop ( hcl_server_t * server )
{
server - > stopreq = 1 ;
2018-03-15 15:23:51 +00:00
write ( server - > mux_pipe [ 1 ] , " Q " , 1 ) ; /* don't care about failure */
2018-03-13 10:20:50 +00:00
}
int hcl_server_setoption ( hcl_server_t * server , hcl_server_option_t id , const void * value )
{
switch ( id )
{
case HCL_SERVER_TRAIT :
2018-04-26 04:39:20 +00:00
server - > cfg . trait = * ( const hcl_bitmask_t * ) value ;
2018-03-16 01:46:59 +00:00
if ( server - > dummy_hcl )
{
/* setting this affects the dummy hcl immediately.
2023-05-31 15:30:41 +00:00
* existing hcl instances inside worker threads won ' t get
* affected . new hcl instances to be created later
2018-03-16 01:46:59 +00:00
* is supposed to use the new value */
2018-04-26 04:39:20 +00:00
hcl_bitmask_t trait ;
2018-03-16 01:46:59 +00:00
hcl_getoption ( server - > dummy_hcl , HCL_TRAIT , & trait ) ;
# if defined(HCL_BUILD_DEBUG)
2020-09-28 15:44:04 +00:00
if ( server - > cfg . trait & HCL_SERVER_TRAIT_DEBUG_GC ) trait | = HCL_TRAIT_DEBUG_GC ;
2021-02-01 03:32:09 +00:00
if ( server - > cfg . trait & HCL_SERVER_TRAIT_DEBUG_BIGINT ) trait | = HCL_TRAIT_DEBUG_BIGINT ;
2018-03-16 01:46:59 +00:00
# endif
hcl_setoption ( server - > dummy_hcl , HCL_TRAIT , & trait ) ;
}
2018-03-13 10:20:50 +00:00
return 0 ;
case HCL_SERVER_LOG_MASK :
2018-04-26 04:39:20 +00:00
server - > cfg . logmask = * ( const hcl_bitmask_t * ) value ;
2023-05-31 15:30:41 +00:00
if ( server - > dummy_hcl )
2018-03-16 01:46:59 +00:00
{
/* setting this affects the dummy hcl immediately.
2023-05-31 15:30:41 +00:00
* existing hcl instances inside worker threads won ' t get
* affected . new hcl instances to be created later
2018-03-16 01:46:59 +00:00
* is supposed to use the new value */
hcl_setoption ( server - > dummy_hcl , HCL_LOG_MASK , value ) ;
}
2018-03-13 10:20:50 +00:00
return 0 ;
2018-03-16 14:57:34 +00:00
case HCL_SERVER_WORKER_MAX_COUNT :
server - > cfg . worker_max_count = * ( hcl_oow_t * ) value ;
return 0 ;
2023-05-31 15:30:41 +00:00
2018-03-13 10:20:50 +00:00
case HCL_SERVER_WORKER_STACK_SIZE :
server - > cfg . worker_stack_size = * ( hcl_oow_t * ) value ;
return 0 ;
2023-05-31 15:30:41 +00:00
2018-03-14 14:40:05 +00:00
case HCL_SERVER_WORKER_IDLE_TIMEOUT :
server - > cfg . worker_idle_timeout = * ( hcl_ntime_t * ) value ;
return 0 ;
2018-03-13 10:20:50 +00:00
case HCL_SERVER_ACTOR_HEAP_SIZE :
server - > cfg . actor_heap_size = * ( hcl_oow_t * ) value ;
return 0 ;
2023-05-31 15:30:41 +00:00
2018-03-14 14:40:05 +00:00
case HCL_SERVER_ACTOR_MAX_RUNTIME :
server - > cfg . actor_max_runtime = * ( hcl_ntime_t * ) value ;
return 0 ;
2018-03-17 05:44:40 +00:00
case HCL_SERVER_SCRIPT_INCLUDE_PATH :
2018-04-07 15:54:16 +00:00
hcl_copy_oocstr ( server - > cfg . script_include_path , HCL_COUNTOF ( server - > cfg . script_include_path ) , ( const hcl_ooch_t * ) value ) ;
2018-03-17 05:44:40 +00:00
return 0 ;
2018-04-09 15:54:54 +00:00
case HCL_SERVER_MODULE_INCTX :
server - > cfg . module_inctx = * ( void * * ) value ;
return 0 ;
2018-03-13 10:20:50 +00:00
}
2018-03-14 10:14:38 +00:00
hcl_server_seterrnum ( server , HCL_EINVAL ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
int hcl_server_getoption ( hcl_server_t * server , hcl_server_option_t id , void * value )
{
switch ( id )
{
case HCL_SERVER_TRAIT :
2018-04-26 04:39:20 +00:00
* ( hcl_bitmask_t * ) value = server - > cfg . trait ;
2018-03-13 10:20:50 +00:00
return 0 ;
case HCL_SERVER_LOG_MASK :
2018-04-26 04:39:20 +00:00
* ( hcl_bitmask_t * ) value = server - > cfg . logmask ;
2018-03-13 10:20:50 +00:00
return 0 ;
2018-03-16 14:57:34 +00:00
case HCL_SERVER_WORKER_MAX_COUNT :
* ( hcl_oow_t * ) value = server - > cfg . worker_max_count ;
return 0 ;
2018-03-13 10:20:50 +00:00
case HCL_SERVER_WORKER_STACK_SIZE :
* ( hcl_oow_t * ) value = server - > cfg . worker_stack_size ;
return 0 ;
2023-05-31 15:30:41 +00:00
2018-03-14 14:40:05 +00:00
case HCL_SERVER_WORKER_IDLE_TIMEOUT :
* ( hcl_ntime_t * ) value = server - > cfg . worker_idle_timeout ;
return 0 ;
2018-03-13 10:20:50 +00:00
case HCL_SERVER_ACTOR_HEAP_SIZE :
* ( hcl_oow_t * ) value = server - > cfg . actor_heap_size ;
return 0 ;
2018-03-14 14:40:05 +00:00
case HCL_SERVER_ACTOR_MAX_RUNTIME :
* ( hcl_ntime_t * ) value = server - > cfg . actor_max_runtime ;
return 0 ;
2018-03-22 03:42:17 +00:00
2018-03-17 05:44:40 +00:00
case HCL_SERVER_SCRIPT_INCLUDE_PATH :
* ( hcl_ooch_t * * ) value = server - > cfg . script_include_path ;
return 0 ;
2018-04-09 15:54:54 +00:00
case HCL_SERVER_MODULE_INCTX :
* ( void * * ) value = server - > cfg . module_inctx ;
return 0 ;
2018-03-13 10:20:50 +00:00
} ;
2018-03-14 10:14:38 +00:00
hcl_server_seterrnum ( server , HCL_EINVAL ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
2018-03-14 10:14:38 +00:00
void * hcl_server_getxtn ( hcl_server_t * server )
{
2019-06-21 12:36:25 +00:00
return ( void * ) ( ( hcl_uint8_t * ) server + server - > _instsize ) ;
2018-03-14 10:14:38 +00:00
}
hcl_mmgr_t * hcl_server_getmmgr ( hcl_server_t * server )
{
2019-06-21 12:36:25 +00:00
return server - > _mmgr ;
2018-03-14 10:14:38 +00:00
}
hcl_cmgr_t * hcl_server_getcmgr ( hcl_server_t * server )
{
2019-06-21 12:36:25 +00:00
return server - > _cmgr ;
2018-03-14 10:14:38 +00:00
}
void hcl_server_setcmgr ( hcl_server_t * server , hcl_cmgr_t * cmgr )
{
2019-06-21 12:36:25 +00:00
server - > _cmgr = cmgr ;
2018-03-14 10:14:38 +00:00
}
hcl_errnum_t hcl_server_geterrnum ( hcl_server_t * server )
{
return server - > errnum ;
}
const hcl_ooch_t * hcl_server_geterrstr ( hcl_server_t * server )
{
return hcl_errnum_to_errstr ( server - > errnum ) ;
}
const hcl_ooch_t * hcl_server_geterrmsg ( hcl_server_t * server )
{
if ( server - > errmsg . len < = 0 ) return hcl_errnum_to_errstr ( server - > errnum ) ;
return server - > errmsg . buf ;
}
void hcl_server_seterrnum ( hcl_server_t * server , hcl_errnum_t errnum )
{
/*if (server->shuterr) return; */
server - > errnum = errnum ;
server - > errmsg . len = 0 ;
}
2018-03-14 14:40:05 +00:00
void hcl_server_seterrbfmt ( hcl_server_t * server , hcl_errnum_t errnum , const hcl_bch_t * fmt , . . . )
{
va_list ap ;
va_start ( ap , fmt ) ;
hcl_seterrbfmtv ( server - > dummy_hcl , errnum , fmt , ap ) ;
va_end ( ap ) ;
HCL_ASSERT ( server - > dummy_hcl , HCL_COUNTOF ( server - > errmsg . buf ) = = HCL_COUNTOF ( server - > dummy_hcl - > errmsg . buf ) ) ;
server - > errnum = errnum ;
2018-04-07 15:54:16 +00:00
hcl_copy_oochars ( server - > errmsg . buf , server - > dummy_hcl - > errmsg . buf , HCL_COUNTOF ( server - > errmsg . buf ) ) ;
2018-03-14 14:40:05 +00:00
server - > errmsg . len = server - > dummy_hcl - > errmsg . len ;
}
void hcl_server_seterrufmt ( hcl_server_t * server , hcl_errnum_t errnum , const hcl_uch_t * fmt , . . . )
{
va_list ap ;
va_start ( ap , fmt ) ;
hcl_seterrufmtv ( server - > dummy_hcl , errnum , fmt , ap ) ;
va_end ( ap ) ;
HCL_ASSERT ( server - > dummy_hcl , HCL_COUNTOF ( server - > errmsg . buf ) = = HCL_COUNTOF ( server - > dummy_hcl - > errmsg . buf ) ) ;
server - > errnum = errnum ;
2018-03-29 03:08:43 +00:00
server - > errnum = errnum ;
2018-04-07 15:54:16 +00:00
hcl_copy_oochars ( server - > errmsg . buf , server - > dummy_hcl - > errmsg . buf , HCL_COUNTOF ( server - > errmsg . buf ) ) ;
2018-03-14 14:40:05 +00:00
server - > errmsg . len = server - > dummy_hcl - > errmsg . len ;
}
2018-03-18 15:29:16 +00:00
void * hcl_server_allocmem ( hcl_server_t * server , hcl_oow_t size )
{
void * ptr ;
2019-06-21 12:36:25 +00:00
ptr = HCL_MMGR_ALLOC ( server - > _mmgr , size ) ;
2018-03-18 15:29:16 +00:00
if ( ! ptr ) hcl_server_seterrnum ( server , HCL_ESYSMEM ) ;
return ptr ;
}
void * hcl_server_callocmem ( hcl_server_t * server , hcl_oow_t size )
{
void * ptr ;
2019-06-21 12:36:25 +00:00
ptr = HCL_MMGR_ALLOC ( server - > _mmgr , size ) ;
2018-03-18 15:29:16 +00:00
if ( ! ptr ) hcl_server_seterrnum ( server , HCL_ESYSMEM ) ;
else HCL_MEMSET ( ptr , 0 , size ) ;
return ptr ;
}
void * hcl_server_reallocmem ( hcl_server_t * server , void * ptr , hcl_oow_t size )
{
2019-06-21 12:36:25 +00:00
ptr = HCL_MMGR_REALLOC ( server - > _mmgr , ptr , size ) ;
2018-03-18 15:29:16 +00:00
if ( ! ptr ) hcl_server_seterrnum ( server , HCL_ESYSMEM ) ;
return ptr ;
}
void hcl_server_freemem ( hcl_server_t * server , void * ptr )
{
2019-06-21 12:36:25 +00:00
HCL_MMGR_FREE ( server - > _mmgr , ptr ) ;
2018-03-18 15:29:16 +00:00
}