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-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>
# if defined(HCL_HAVE_CFG_H) && defined(HCL_ENABLE_LIBLTDL)
# include <ltdl.h>
# define USE_LTDL
# endif
# 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(HCL_ENABLE_LIBLTDL)
# include <ltdl.h>
# define USE_LTDL
# define sys_dl_error() lt_dlerror()
# define sys_dl_open(x) lt_dlopen(x)
# define sys_dl_openext(x) lt_dlopenext(x)
# define sys_dl_close(x) lt_dlclose(x)
# define sys_dl_getsym(x,n) lt_dlsym(x,n)
# elif defined(HAVE_DLFCN_H)
# include <dlfcn.h>
# define USE_DLFCN
# define sys_dl_error() dlerror()
# define sys_dl_open(x) dlopen(x,RTLD_NOW)
# define sys_dl_openext(x) dlopen(x,RTLD_NOW)
# define sys_dl_close(x) dlclose(x)
# define sys_dl_getsym(x,n) dlsym(x,n)
# else
# error UNSUPPORTED DYNAMIC LINKER
# endif
# 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
# if !defined(HCL_DEFAULT_PFMODPREFIX)
# if defined(_WIN32)
# define HCL_DEFAULT_PFMODPREFIX "hcl-"
# elif defined(__OS2__)
# define HCL_DEFAULT_PFMODPREFIX "hcl"
# elif defined(__DOS__)
# define HCL_DEFAULT_PFMODPREFIX "hcl"
# else
# define HCL_DEFAULT_PFMODPREFIX "libhcl-"
# endif
# endif
# if !defined(HCL_DEFAULT_PFMODPOSTFIX)
# if defined(_WIN32)
# define HCL_DEFAULT_PFMODPOSTFIX ""
# elif defined(__OS2__)
# define HCL_DEFAULT_PFMODPOSTFIX ""
# elif defined(__DOS__)
# define HCL_DEFAULT_PFMODPOSTFIX ""
# else
# if defined(USE_DLFCN)
# define HCL_DEFAULT_PFMODPOSTFIX ".so"
# else
# define HCL_DEFAULT_PFMODPOSTFIX ""
# endif
# endif
# 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
2018-03-14 10:14:38 +00:00
struct dummy_hcl_xtn_t
{
hcl_server_t * server ;
2018-03-13 10:20:50 +00:00
} ;
2018-03-17 11:57:02 +00:00
typedef struct dummy_hcl_xtn_t dummy_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 ;
hcl_ioloc_t loc ;
} ;
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 ;
hcl_iolxc_t * lxc ;
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 ;
2018-03-17 05:44:40 +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
{
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 .
*
* 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
{
unsigned int trait ;
unsigned int logmask ;
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 ;
} ;
/* ========================================================================= */
# if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
# define IS_PATH_SEP(c) ((c) == ' / ' || (c) == '\\')
2018-03-17 05:44:40 +00:00
# define PATH_SEP_CHAR ('\\')
2018-03-13 10:20:50 +00:00
# else
# define IS_PATH_SEP(c) ((c) == ' / ')
2018-03-17 05:44:40 +00:00
# define PATH_SEP_CHAR (' / ')
2018-03-13 10:20:50 +00:00
# endif
2018-03-17 05:44:40 +00:00
2018-03-13 10:20:50 +00:00
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 + + )
{
if ( IS_PATH_SEP ( * p ) ) last = p ;
}
return ( last = = HCL_NULL ) ? path : ( last + 1 ) ;
}
static HCL_INLINE int open_input ( hcl_t * hcl , hcl_ioinarg_t * arg )
{
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 */
2018-03-17 05:44:40 +00:00
/* TOOD: Do i need to skip prepending the include path if the included path is an absolute path?
* 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
if ( ! IS_PATH_SEP ( bb - > fn [ parlen ] ) ) bb - > fn [ parlen + + ] = PATH_SEP_CHAR ; /* +2 was used in hcl_callocmem() for this (+1 for this, +1 for '\0' */
}
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 ) ;
}
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 ;
}
if ( bb - > fd < = - 1 )
{
hcl_seterrnum ( hcl , HCL_EIOERR ) ;
goto oops ;
}
arg - > handle = bb ;
return 0 ;
oops :
if ( bb )
{
if ( bb - > fd > = 0 & & bb - > fd ! = xtn - > proto - > worker - > sck ) close ( bb - > fd ) ;
hcl_freemem ( hcl , bb ) ;
}
return - 1 ;
}
static HCL_INLINE int close_input ( hcl_t * hcl , hcl_ioinarg_t * arg )
{
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 ;
}
static HCL_INLINE int read_input ( hcl_t * hcl , hcl_ioinarg_t * arg )
{
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 ;
2018-03-13 10:20:50 +00:00
int x ;
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 ;
if ( bb - > fd = = worker - > sck )
2018-03-13 10:20:50 +00:00
{
ssize_t x ;
2018-03-22 07:15:19 +00:00
hcl_server_t * server ;
server = worker - > server ;
2018-03-13 10:20:50 +00:00
start_over :
while ( 1 )
{
int n ;
struct pollfd pfd ;
2018-03-22 07:15:19 +00:00
int tmout , actual_tmout ;
if ( 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 ;
hcl_seterrwithsyserr ( hcl , errno ) ;
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 )
{
hcl_seterrbfmt ( hcl , HCL_EGENERIC , " no activity on the worker socket %d " , worker - > sck ) ;
return - 1 ;
}
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 ;
hcl_seterrwithsyserr ( hcl , errno ) ;
return - 1 ;
}
bb - > len + = x ;
}
else
{
ssize_t x ;
x = read ( bb - > fd , & bb - > buf [ bb - > len ] , HCL_COUNTOF ( bb - > buf ) - bb - > len ) ;
if ( x < = - 1 )
{
hcl_seterrnum ( hcl , HCL_EIOERR ) ;
return - 1 ;
}
bb - > len + = x ;
}
# if defined(HCL_OOCH_IS_UCH)
bcslen = bb - > len ;
ucslen = HCL_COUNTOF ( arg - > buf ) ;
x = hcl_convbtooochars ( hcl , bb - > buf , & bcslen , arg - > buf , & ucslen ) ;
if ( x < = - 1 & & ucslen < = 0 ) return - 1 ;
/* 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 ;
if ( remlen > 0 ) memmove ( bb - > buf , & bb - > buf [ bcslen ] , remlen ) ;
bb - > len = remlen ;
arg - > xlen = ucslen ;
return 0 ;
}
static int read_handler ( hcl_t * hcl , hcl_iocmd_t cmd , void * arg )
{
switch ( cmd )
{
case HCL_IO_OPEN :
return open_input ( hcl , ( hcl_ioinarg_t * ) arg ) ;
case HCL_IO_CLOSE :
return close_input ( hcl , ( hcl_ioinarg_t * ) arg ) ;
case HCL_IO_READ :
return read_input ( hcl , ( hcl_ioinarg_t * ) arg ) ;
default :
hcl_seterrnum ( hcl , HCL_EINTERN ) ;
return - 1 ;
}
}
static int print_handler ( hcl_t * hcl , hcl_iocmd_t cmd , void * arg )
{
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 ) ;
2018-03-13 10:20:50 +00:00
hcl_iooutarg_t * outarg = ( hcl_iooutarg_t * ) arg ;
if ( hcl_server_proto_feed_reply ( 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 ;
}
default :
hcl_seterrnum ( hcl , HCL_EINTERN ) ;
return - 1 ;
}
}
/* ========================================================================= */
static void * alloc_heap ( hcl_t * hcl , hcl_oow_t size )
{
# if defined(HAVE_MMAP) && defined(HAVE_MUNMAP) && defined(MAP_ANONYMOUS)
/* It's called via hcl_makeheap() when HCL creates a GC heap.
* The heap is large in size . I can use a different memory allocation
* function instead of an ordinary malloc .
* upon failure , it doesn ' t require to set error information as hcl_makeheap ( )
* set the error number to HCL_EOOMEM . */
# if !defined(MAP_HUGETLB) && (defined(__amd64__) || defined(__x86_64__))
# define MAP_HUGETLB 0x40000
# endif
hcl_oow_t * ptr ;
int flags ;
hcl_oow_t actual_size ;
flags = MAP_PRIVATE | MAP_ANONYMOUS ;
# if defined(MAP_HUGETLB)
flags | = MAP_HUGETLB ;
# endif
# if defined(MAP_UNINITIALIZED)
flags | = MAP_UNINITIALIZED ;
# endif
actual_size = HCL_SIZEOF ( hcl_oow_t ) + size ;
actual_size = HCL_ALIGN_POW2 ( actual_size , 2 * 1024 * 1024 ) ;
ptr = ( hcl_oow_t * ) mmap ( NULL , actual_size , PROT_READ | PROT_WRITE , flags , - 1 , 0 ) ;
if ( ptr = = MAP_FAILED )
{
# if defined(MAP_HUGETLB)
flags & = ~ MAP_HUGETLB ;
ptr = ( hcl_oow_t * ) mmap ( NULL , actual_size , PROT_READ | PROT_WRITE , flags , - 1 , 0 ) ;
if ( ptr = = MAP_FAILED ) return HCL_NULL ;
# else
return HCL_NULL ;
# endif
}
* ptr = actual_size ;
return ( void * ) ( ptr + 1 ) ;
# else
return HCL_MMGR_ALLOC ( hcl - > mmgr , size ) ;
# endif
}
static void free_heap ( hcl_t * hcl , void * ptr )
{
# if defined(HAVE_MMAP) && defined(HAVE_MUNMAP)
hcl_oow_t * actual_ptr ;
actual_ptr = ( hcl_oow_t * ) ptr - 1 ;
munmap ( actual_ptr , * actual_ptr ) ;
# else
return HCL_MMGR_FREE ( hcl - > mmgr , ptr ) ;
# endif
}
2018-03-14 10:14:38 +00:00
static void log_write ( hcl_t * hcl , unsigned int 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-03-14 10:14:38 +00:00
static void log_write_for_dummy ( hcl_t * hcl , unsigned int 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
dummy_hcl_xtn_t * xtn = ( dummy_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 - > 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 void syserrstrb ( hcl_t * hcl , int syserr , hcl_bch_t * buf , hcl_oow_t len )
{
# if defined(HAVE_STRERROR_R)
strerror_r ( syserr , buf , len ) ;
# else
2018-03-15 10:30:06 +00:00
/* this may not be thread safe */
2018-04-07 15:54:16 +00:00
hcl_copy_bcstr ( buf , len , strerror ( syserr ) ) ;
2018-03-13 10:20:50 +00:00
# endif
}
/* ========================================================================= */
static void * dl_open ( hcl_t * hcl , const hcl_ooch_t * name , int flags )
{
# if defined(USE_LTDL) || defined(USE_DLFCN)
hcl_bch_t stabuf [ 128 ] , * bufptr ;
hcl_oow_t ucslen , bcslen , bufcapa ;
void * handle ;
# if defined(HCL_OOCH_IS_UCH)
if ( hcl_convootobcstr ( hcl , name , & ucslen , HCL_NULL , & bufcapa ) < = - 1 ) return HCL_NULL ;
/* +1 for terminating null. but it's not needed because HCL_COUNTOF(HCL_DEFAULT_PFMODPREFIX)
* and HCL_COUNTOF ( HCL_DEFAULT_PFMODPOSTIFX ) include the terminating nulls . Never mind about
* the extra 2 characters . */
# else
2018-04-07 15:54:16 +00:00
bufcapa = hcl_count_bcstr ( name ) ;
2018-03-13 10:20:50 +00:00
# endif
bufcapa + = HCL_COUNTOF ( HCL_DEFAULT_PFMODPREFIX ) + HCL_COUNTOF ( HCL_DEFAULT_PFMODPOSTFIX ) + 1 ;
if ( bufcapa < = HCL_COUNTOF ( stabuf ) ) bufptr = stabuf ;
else
{
bufptr = ( hcl_bch_t * ) hcl_allocmem ( hcl , bufcapa * HCL_SIZEOF ( * bufptr ) ) ;
if ( ! bufptr ) return HCL_NULL ;
}
if ( flags & HCL_VMPRIM_OPENDL_PFMOD )
{
hcl_oow_t len , i , xlen ;
/* opening a primitive function module - mostly libhcl-xxxx */
2018-04-07 15:54:16 +00:00
len = hcl_copy_bcstr ( bufptr , bufcapa , HCL_DEFAULT_PFMODPREFIX ) ;
2018-03-13 10:20:50 +00:00
bcslen = bufcapa - len ;
# if defined(HCL_OOCH_IS_UCH)
hcl_convootobcstr ( hcl , name , & ucslen , & bufptr [ len ] , & bcslen ) ;
# else
2018-04-07 15:54:16 +00:00
bcslen = hcl_copy_bcstr ( & bufptr [ len ] , bcslen , name ) ;
2018-03-13 10:20:50 +00:00
# endif
/* length including the prefix and the name. but excluding the postfix */
xlen = len + bcslen ;
for ( i = len ; i < xlen ; i + + )
{
/* convert a period(.) to a dash(-) */
if ( bufptr [ i ] = = ' . ' ) bufptr [ i ] = ' - ' ;
}
retry :
2018-04-07 15:54:16 +00:00
hcl_copy_bcstr ( & bufptr [ xlen ] , bufcapa - xlen , HCL_DEFAULT_PFMODPOSTFIX ) ;
2018-03-13 10:20:50 +00:00
/* both prefix and postfix attached. for instance, libhcl-xxx */
handle = sys_dl_openext ( bufptr ) ;
if ( ! handle )
{
HCL_DEBUG3 ( hcl , " Failed to open(ext) DL %hs[%js] - %hs \n " , bufptr , name , sys_dl_error ( ) ) ;
/* try without prefix and postfix */
bufptr [ xlen ] = ' \0 ' ;
handle = sys_dl_openext ( & bufptr [ len ] ) ;
if ( ! handle )
{
hcl_bch_t * dash ;
const hcl_bch_t * dl_errstr ;
dl_errstr = sys_dl_error ( ) ;
HCL_DEBUG3 ( hcl , " Failed to open(ext) DL %hs[%js] - %hs \n " , & bufptr [ len ] , name , dl_errstr ) ;
hcl_seterrbfmt ( hcl , HCL_ESYSERR , " unable to open(ext) DL %js - %hs " , name , dl_errstr ) ;
2018-04-07 15:54:16 +00:00
dash = hcl_rfind_bchar ( bufptr , hcl_count_bcstr ( bufptr ) , ' - ' ) ;
2018-03-13 10:20:50 +00:00
if ( dash )
{
/* remove a segment at the back.
* [ NOTE ] a dash contained in the original name before
* period - to - dash transformation may cause extraneous / wrong
* loading reattempts . */
xlen = dash - bufptr ;
goto retry ;
}
}
else
{
HCL_DEBUG3 ( hcl , " Opened(ext) DL %hs[%js] handle %p \n " , & bufptr [ len ] , name , handle ) ;
}
}
else
{
HCL_DEBUG3 ( hcl , " Opened(ext) DL %hs[%js] handle %p \n " , bufptr , name , handle ) ;
}
}
else
{
/* opening a raw shared object without a prefix and/or a postfix */
# if defined(HCL_OOCH_IS_UCH)
bcslen = bufcapa ;
hcl_convootobcstr ( hcl , name , & ucslen , bufptr , & bcslen ) ;
# else
2018-04-07 15:54:16 +00:00
bcslen = hcl_copy_bcstr ( bufptr , bufcapa , name ) ;
2018-03-13 10:20:50 +00:00
# endif
2018-04-07 15:54:16 +00:00
if ( hcl_find_bchar ( bufptr , bcslen , ' . ' ) )
2018-03-13 10:20:50 +00:00
{
handle = sys_dl_open ( bufptr ) ;
if ( ! handle )
{
const hcl_bch_t * dl_errstr ;
dl_errstr = sys_dl_error ( ) ;
HCL_DEBUG2 ( hcl , " Failed to open DL %hs - %hs \n " , bufptr , dl_errstr ) ;
hcl_seterrbfmt ( hcl , HCL_ESYSERR , " unable to open DL %js - %hs " , name , dl_errstr ) ;
}
else HCL_DEBUG2 ( hcl , " Opened DL %hs handle %p \n " , bufptr , handle ) ;
}
else
{
handle = sys_dl_openext ( bufptr ) ;
if ( ! handle )
{
const hcl_bch_t * dl_errstr ;
dl_errstr = sys_dl_error ( ) ;
HCL_DEBUG2 ( hcl , " Failed to open(ext) DL %hs - %s \n " , bufptr , dl_errstr ) ;
hcl_seterrbfmt ( hcl , HCL_ESYSERR , " unable to open(ext) DL %js - %hs " , name , dl_errstr ) ;
}
else HCL_DEBUG2 ( hcl , " Opened(ext) DL % hs handle % p \ n " , bufptr, handle) ;
}
}
if ( bufptr ! = stabuf ) hcl_freemem ( hcl , bufptr ) ;
return handle ;
# else
/* TODO: support various platforms */
/* TODO: implemenent this */
HCL_DEBUG1 ( hcl , " Dynamic loading not implemented - cannot open %js \n " , name ) ;
hcl_seterrnum ( hcl , HCL_ENOIMPL , " dynamic loading not implemented - cannot open %js " , name ) ;
return HCL_NULL ;
# endif
}
static void dl_close ( hcl_t * hcl , void * handle )
{
# if defined(USE_LTDL) || defined(USE_DLFCN)
HCL_DEBUG1 ( hcl , " Closed DL handle %p \n " , handle ) ;
sys_dl_close ( handle ) ;
# else
/* TODO: implemenent this */
HCL_DEBUG1 ( hcl , " Dynamic loading not implemented - cannot close handle %p \n " , handle ) ;
# endif
}
static void * dl_getsym ( hcl_t * hcl , void * handle , const hcl_ooch_t * name )
{
# if defined(USE_LTDL) || defined(USE_DLFCN)
hcl_bch_t stabuf [ 64 ] , * bufptr ;
hcl_oow_t bufcapa , ucslen , bcslen , i ;
const hcl_bch_t * symname ;
void * sym ;
# if defined(HCL_OOCH_IS_UCH)
if ( hcl_convootobcstr ( hcl , name , & ucslen , HCL_NULL , & bcslen ) < = - 1 ) return HCL_NULL ;
# else
2018-04-07 15:54:16 +00:00
bcslen = hcl_count_bcstr ( name ) ;
2018-03-13 10:20:50 +00:00
# endif
if ( bcslen > = HCL_COUNTOF ( stabuf ) - 2 )
{
bufcapa = bcslen + 3 ;
bufptr = ( hcl_bch_t * ) hcl_allocmem ( hcl , bufcapa * HCL_SIZEOF ( * bufptr ) ) ;
if ( ! bufptr ) return HCL_NULL ;
}
else
{
bufcapa = HCL_COUNTOF ( stabuf ) ;
bufptr = stabuf ;
}
bcslen = bufcapa - 1 ;
# if defined(HCL_OOCH_IS_UCH)
hcl_convootobcstr ( hcl , name , & ucslen , & bufptr [ 1 ] , & bcslen ) ;
# else
2018-04-07 15:54:16 +00:00
bcslen = hcl_copy_bcstr ( & bufptr [ 1 ] , bcslen , name ) ;
2018-03-13 10:20:50 +00:00
# endif
/* convert a period(.) to an underscore(_) */
for ( i = 1 ; i < = bcslen ; i + + ) if ( bufptr [ i ] = = ' . ' ) bufptr [ i ] = ' _ ' ;
symname = & bufptr [ 1 ] ; /* try the name as it is */
sym = sys_dl_getsym ( handle , symname ) ;
if ( ! sym )
{
bufptr [ 0 ] = ' _ ' ;
symname = & bufptr [ 0 ] ; /* try _name */
sym = sys_dl_getsym ( handle , symname ) ;
if ( ! sym )
{
bufptr [ bcslen + 1 ] = ' _ ' ;
bufptr [ bcslen + 2 ] = ' \0 ' ;
symname = & bufptr [ 1 ] ; /* try name_ */
sym = sys_dl_getsym ( handle , symname ) ;
if ( ! sym )
{
symname = & bufptr [ 0 ] ; /* try _name_ */
sym = sys_dl_getsym ( handle , symname ) ;
if ( ! sym )
{
const hcl_bch_t * dl_errstr ;
dl_errstr = sys_dl_error ( ) ;
HCL_DEBUG3 ( hcl , " Failed to get module symbol %js from handle %p - %hs \n " , name , handle , dl_errstr ) ;
hcl_seterrbfmt ( hcl , HCL_ENOENT , " unable to get module symbol %hs - %hs " , symname , dl_errstr ) ;
}
}
}
}
if ( sym ) HCL_DEBUG3 ( hcl , " Loaded module symbol %js from handle %p - %hs \n " , name , handle , symname ) ;
if ( bufptr ! = stabuf ) hcl_freemem ( hcl , bufptr ) ;
return sym ;
# else
/* TODO: IMPLEMENT THIS */
HCL_DEBUG2 ( hcl , " Dynamic loading not implemented - Cannot load module symbol %js from handle %p \n " , name , handle ) ;
hcl_seterrbfmt ( hcl , HCL_ENOIMPL , " dynamic loading not implemented - Cannot load module symbol %js from handle %p " , name , handle ) ;
return HCL_NULL ;
# endif
}
/* ========================================================================= */
static void vm_gettime ( hcl_t * hcl , hcl_ntime_t * now )
{
# if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
struct timespec ts ;
clock_gettime ( CLOCK_MONOTONIC , & ts ) ;
HCL_INITNTIME ( now , ts . tv_sec , ts . tv_nsec ) ;
# elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
struct timespec ts ;
clock_gettime ( CLOCK_REALTIME , & ts ) ;
HCL_INITNTIME ( now , ts . tv_sec , ts . tv_nsec ) ;
# else
struct timeval tv ;
gettimeofday ( & tv , HCL_NULL ) ;
HCL_INITNTIME ( now , tv . tv_sec , HCL_USEC_TO_NSEC ( tv . tv_usec ) ) ;
# endif
}
static void vm_sleep ( hcl_t * hcl , const hcl_ntime_t * dur )
{
# if defined(HAVE_NANOSLEEP)
struct timespec ts ;
ts . tv_sec = dur - > sec ;
ts . tv_nsec = dur - > nsec ;
nanosleep ( & ts , HCL_NULL ) ;
# elif defined(HAVE_USLEEP)
usleep ( HCL_SECNSEC_TO_USEC ( dur - > sec , dur - > nsec ) ) ;
# else
# error UNSUPPORT SLEEP
# endif
}
/* ========================================================================= */
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_vmprim_t vmprim ;
hcl_cb_t hclcb ;
2018-03-14 10:14:38 +00:00
worker_hcl_xtn_t * xtn ;
2018-03-13 10:20:50 +00:00
unsigned int trait ;
HCL_MEMSET ( & vmprim , 0 , HCL_SIZEOF ( vmprim ) ) ;
if ( worker - > server - > cfg . trait & HCL_SERVER_TRAIT_USE_LARGE_PAGES )
{
vmprim . alloc_heap = alloc_heap ;
vmprim . free_heap = free_heap ;
}
vmprim . log_write = log_write ;
vmprim . syserrstrb = syserrstrb ;
vmprim . dl_open = dl_open ;
vmprim . dl_close = dl_close ;
vmprim . dl_getsym = dl_getsym ;
vmprim . vm_gettime = vm_gettime ;
vmprim . vm_sleep = vm_sleep ;
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
2018-03-14 10:14:38 +00:00
proto - > hcl = hcl_open ( proto - > worker - > server - > mmgr , HCL_SIZEOF ( * xtn ) , worker - > server - > cfg . actor_heap_size , & vmprim , HCL_NULL ) ;
if ( ! proto - > hcl ) goto oops ;
2018-03-13 10:20:50 +00:00
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 ) ;
hcl_setcmgr ( proto - > hcl , proto - > worker - > server - > cmgr ) ;
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)
if ( proto - > worker - > server - > cfg . trait & HCL_SERVER_TRAIT_DEBUG_GC ) trait | = HCL_DEBUG_GC ;
if ( proto - > worker - > server - > cfg . trait & HCL_SERVER_TRAIT_DEBUG_BIGINT ) trait | = HCL_DEBUG_BIGINT ;
# 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 ) ;
if ( hcl_ignite ( proto - > hcl ) < = - 1 ) goto oops ;
if ( hcl_addbuiltinprims ( proto - > hcl ) < = - 1 ) goto oops ;
if ( hcl_attachio ( proto - > hcl , read_handler , print_handler ) < = - 1 ) goto oops ;
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 */
2018-03-21 10:38:10 +00:00
iov [ count ] . iov_base = " .OK \n .DATA chunked \n " ;
iov [ count + + ] . iov_len = 18 ;
2018-03-13 10:20:50 +00:00
}
iov [ count ] . iov_base = cl ,
2018-03-21 10:38:10 +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);*/
if ( nwritten < = - 1 )
{
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 ) ) ;
2018-03-14 14:40:05 +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
}
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 ;
}
else
{
/* 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 )
{
proto - > lxc = hcl_readchar ( proto - > hcl ) ;
if ( ! proto - > lxc ) return - 1 ;
return 0 ;
}
static HCL_INLINE int unread_last_char ( hcl_server_proto_t * proto )
{
return hcl_unreadchar ( proto - > hcl , proto - > lxc ) ;
}
# define GET_CHAR_TO(proto,c) \
do { \
if ( read_char ( proto ) < = - 1 ) return - 1 ; \
c = ( proto ) - > lxc - > c ; \
} while ( 0 )
# 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))
# define ADD_TOKEN_CHAR(proto,c) \
do { if ( add_token_char ( proto , c ) < = - 1 ) return - 1 ; } while ( 0 )
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 ) ) ;
2018-03-13 10:20:50 +00:00
if ( ! tmp )
{
2018-03-16 17:27:24 +00:00
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " Out of memory in allocating a token buffer \n " ) ;
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 ] ;
} tab [ ] =
{
{ 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 ' } } ,
{ 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 + + )
{
2018-04-07 15:54:16 +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 ;
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-03-16 17:27:24 +00:00
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " Alphabetic character expected after a period \n " ) ;
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 ) ) ;
UNGET_LAST_CHAR ( proto ) ;
break ;
}
HCL_LOG1 ( proto - > hcl , SERVER_LOGMASK_ERROR , " Unrecognized character - [%jc] \n " , 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 )
{
2018-03-15 15:23:51 +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 )
{
2018-03-15 15:23:51 +00:00
/* [NOTE] this handler is executed in the main server thread
* 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 ) ;
2018-03-15 15:23:51 +00:00
/* the event is being removed by hcl_tmr_fire() or by hcl_tmr_delete()
* 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 */
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 ;
proto - > hcl - > vmprim . vm_gettime ( proto - > hcl , & event . when ) ;
HCL_ADDNTIME ( & event . when , & event . when , tmout ) ;
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
* in the server thread , proto - > exec_runtime_event_index should be
* 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 )
{
2018-03-15 15:23:51 +00:00
/* the event has not been fired yet. let's delete it
* 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 ) ;
}
}
if ( hcl_server_proto_end_reply ( proto , failmsg ) < = - 1 )
{
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
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... */
hcl_proutbfmt ( proto - > hcl , 0 , " %zu %d %d \n " , w - > wid , w - > sck , 1000 ) ;
}
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 ;
if ( ! worker )
{
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 )
{
if ( get_token ( proto ) < = - 1 ) return - 1 ;
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-03-15 15:23:51 +00:00
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " Unexpected EOF without .END \n " ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
/* drop connection silently */
return 0 ;
case HCL_SERVER_PROTO_TOKEN_EXIT :
if ( proto - > req . state ! = HCL_SERVER_PROTO_REQ_IN_TOP_LEVEL )
{
2018-03-15 15:23:51 +00:00
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " .EXIT allowed in the top level only \n " ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
if ( get_token ( proto ) < = - 1 ) return - 1 ;
if ( proto - > tok . type ! = HCL_SERVER_PROTO_TOKEN_NL )
{
2018-03-15 15:23:51 +00:00
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " No new line after .EXIT \n " ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
hcl_server_proto_start_reply ( 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 .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-03-15 15:23:51 +00:00
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " .BEGIN not allowed to be nested \n " ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
if ( get_token ( proto ) < = - 1 ) return - 1 ;
if ( proto - > tok . type ! = HCL_SERVER_PROTO_TOKEN_NL )
{
2018-03-15 15:23:51 +00:00
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " No new line after .BEGIN \n " ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
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-03-15 15:23:51 +00:00
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " .END without opening .BEGIN \n " ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
if ( get_token ( proto ) < = - 1 ) return - 1 ;
if ( proto - > tok . type ! = HCL_SERVER_PROTO_TOKEN_NL )
{
2018-03-15 15:23:51 +00:00
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " No new line after .BEGIN \n " ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
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 , " .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 :
{
hcl_oop_t obj ;
2018-03-16 16:20:40 +00:00
hcl_ooci_t c ;
/* do a special check bypassing get_token(). it checks if the script contents
* come on the same line as . SCRIPT */
GET_CHAR_TO ( proto , c ) ;
while ( is_spacechar ( c ) ) GET_CHAR_TO ( proto , c ) ;
if ( c = = HCL_OOCI_EOF | | c = = ' \n ' )
{
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " No contents on the .SCRIPT line \n " ) ;
return - 1 ;
}
UNGET_LAST_CHAR ( proto ) ;
2018-03-13 10:20:50 +00:00
if ( proto - > req . state = = HCL_SERVER_PROTO_REQ_IN_TOP_LEVEL ) hcl_reset ( proto - > hcl ) ;
2018-03-17 05:44:40 +00:00
proto - > worker - > opstate = HCL_SERVER_WORKER_OPSTATE_READ ;
2018-03-13 10:20:50 +00:00
obj = hcl_read ( proto - > hcl ) ;
if ( ! obj )
{
2018-03-15 15:23:51 +00:00
HCL_LOG1 ( proto - > hcl , SERVER_LOGMASK_ERROR , " Unable to read .SCRIPT contents - %js \n " , hcl_geterrmsg ( proto - > hcl ) ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
if ( get_token ( proto ) < = - 1 ) return - 1 ;
if ( proto - > tok . type ! = HCL_SERVER_PROTO_TOKEN_NL )
{
2018-03-16 17:27:24 +00:00
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " No new line after .SCRIPT contents \n " ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
2018-03-17 05:44:40 +00:00
proto - > worker - > opstate = HCL_SERVER_WORKER_OPSTATE_COMPILE ;
2018-03-13 10:20:50 +00:00
if ( hcl_compile ( proto - > hcl , obj ) < = - 1 )
{
2018-03-15 15:23:51 +00:00
HCL_LOG1 ( proto - > hcl , SERVER_LOGMASK_ERROR , " Unable to compile .SCRIPT contents - %js \n " , hcl_geterrmsg ( proto - > hcl ) ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
if ( proto - > req . state = = HCL_SERVER_PROTO_REQ_IN_TOP_LEVEL )
{
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 )
{
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " .SHOW-WORKERS not allowed to be nested \n " ) ;
return - 1 ;
}
if ( get_token ( proto ) < = - 1 ) return - 1 ;
if ( proto - > tok . type ! = HCL_SERVER_PROTO_TOKEN_NL )
{
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " No new line after .SHOW-WORKERS \n " ) ;
return - 1 ;
}
2018-03-13 10:20:50 +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 ;
}
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 )
{
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " .KILL-WORKER not allowed to be nested \n " ) ;
return - 1 ;
}
if ( get_token ( proto ) < = - 1 ) return - 1 ;
if ( proto - > tok . type ! = HCL_SERVER_PROTO_TOKEN_NUMBER )
{
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " No worker ID after .KILL-WORKER \n " ) ;
return - 1 ;
}
for ( wid = 0 , wp = 0 ; wp < proto - > tok . len ; wp + + ) wid = wid * 10 + ( proto - > tok . ptr [ wp ] - ' 0 ' ) ;
if ( get_token ( proto ) < = - 1 ) return - 1 ;
if ( proto - > tok . type ! = HCL_SERVER_PROTO_TOKEN_NL )
{
HCL_LOG0 ( proto - > hcl , SERVER_LOGMASK_ERROR , " No new line after worker ID of .KILL-WORKER \n " ) ;
return - 1 ;
}
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 :
2018-03-15 15:23:51 +00:00
HCL_LOG3 ( proto - > hcl , SERVER_LOGMASK_ERROR , " Unknown token - %d - %.*js \n " , ( int ) proto - > tok . type , proto - > tok . len , proto - > tok . ptr ) ;
2018-03-13 10:20:50 +00:00
return - 1 ;
}
return 1 ;
}
/* ========================================================================= */
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 ;
2018-03-14 10:14:38 +00:00
hcl_vmprim_t vmprim ;
2018-03-18 15:29:16 +00:00
hcl_tmr_t * tmr = HCL_NULL ;
2018-03-14 10:14:38 +00:00
dummy_hcl_xtn_t * xtn ;
2018-03-15 15:23:51 +00:00
int pfd [ 2 ] , fcv ;
2018-03-16 01:46:59 +00:00
unsigned int trait ;
2018-03-14 10:14:38 +00:00
server = ( hcl_server_t * ) HCL_MMGR_ALLOC ( mmgr , HCL_SIZEOF ( * server ) + xtnsize ) ;
if ( ! server )
{
if ( errnum ) * errnum = HCL_ESYSMEM ;
return HCL_NULL ;
}
2018-03-13 10:20:50 +00:00
2018-03-14 10:14:38 +00:00
HCL_MEMSET ( & vmprim , 0 , HCL_SIZEOF ( vmprim ) ) ;
vmprim . log_write = log_write_for_dummy ;
vmprim . syserrstrb = syserrstrb ;
vmprim . dl_open = dl_open ;
vmprim . dl_close = dl_close ;
vmprim . dl_getsym = dl_getsym ;
vmprim . vm_gettime = vm_gettime ;
vmprim . vm_sleep = vm_sleep ;
2018-03-13 10:20:50 +00:00
2018-03-15 10:30:06 +00:00
hcl = hcl_open ( mmgr , HCL_SIZEOF ( * xtn ) , 2048 , & vmprim , errnum ) ;
2018-03-18 15:29:16 +00:00
if ( ! hcl ) goto oops ;
2018-03-13 10:20:50 +00:00
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 )
{
2018-03-18 15:29:16 +00:00
if ( errnum ) * errnum = hcl_syserr_to_errnum ( errno ) ;
goto oops ;
2018-03-15 15:23:51 +00:00
}
# if defined(O_CLOEXEC)
fcv = fcntl ( pfd [ 0 ] , F_GETFD , 0 ) ;
if ( fcv > = 0 ) fcntl ( pfd [ 0 ] , F_SETFD , fcv | O_CLOEXEC ) ;
fcv = fcntl ( pfd [ 1 ] , F_GETFD , 0 ) ;
if ( fcv > = 0 ) fcntl ( pfd [ 1 ] , F_SETFD , fcv | O_CLOEXEC ) ;
# endif
# if defined(O_NONBLOCK)
fcv = fcntl ( pfd [ 0 ] , F_GETFL , 0 ) ;
if ( fcv > = 0 ) fcntl ( pfd [ 0 ] , F_SETFL , fcv | O_NONBLOCK ) ;
fcv = fcntl ( pfd [ 1 ] , F_GETFL , 0 ) ;
if ( fcv > = 0 ) fcntl ( pfd [ 1 ] , F_SETFL , fcv | O_NONBLOCK ) ;
# endif
2018-03-14 10:14:38 +00:00
xtn = ( dummy_hcl_xtn_t * ) hcl_getxtn ( hcl ) ;
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 ) ;
server - > mmgr = mmgr ;
server - > cmgr = hcl_get_utf8_cmgr ( ) ;
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-03-14 10:14:38 +00:00
server - > cfg . logmask = ~ 0u ;
2018-03-13 10:20:50 +00:00
server - > cfg . worker_stack_size = 512000UL ;
server - > cfg . actor_heap_size = 512000UL ;
2018-03-15 10:30:06 +00:00
HCL_INITNTIME ( & server - > cfg . worker_idle_timeout , 0 , 0 ) ;
HCL_INITNTIME ( & server - > cfg . actor_max_runtime , 0 , 0 ) ;
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
* such as getting system time or logging . so the heap size doesn ' t
* need to be changed from the tiny value set above . */
hcl_setoption ( server - > dummy_hcl , HCL_LOG_MASK , & server - > cfg . logmask ) ;
hcl_setcmgr ( server - > dummy_hcl , server - > cmgr ) ;
hcl_getoption ( server - > dummy_hcl , HCL_TRAIT , & trait ) ;
# if defined(HCL_BUILD_DEBUG)
if ( server - > cfg . trait & HCL_SERVER_TRAIT_DEBUG_GC ) trait | = HCL_DEBUG_GC ;
if ( server - > cfg . trait & HCL_SERVER_TRAIT_DEBUG_BIGINT ) trait | = HCL_DEBUG_BIGINT ;
# endif
hcl_setoption ( server - > dummy_hcl , HCL_TRAIT , & trait ) ;
2018-03-13 10:20:50 +00:00
return server ;
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 ) ;
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 ;
}
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 ) ;
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 ;
hcl_ooi_t i , j ;
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 ;
2018-03-17 11:57:02 +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
if ( server - > wid_map . free_first = = HCL_SERVER_WID_INVALID & & prepare_to_acquire_wid ( server ) < = - 1 )
{
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 )
{
if ( worker - > sck > = 0 )
{
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 ) ;
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 ;
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 ;
if ( hcl_server_proto_handle_request ( worker - > proto ) < = 0 )
{
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 ) ;
2018-03-15 08:35:38 +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 ;
if ( worker )
{
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-03-14 10:14:38 +00:00
void hcl_server_logbfmt ( hcl_server_t * server , unsigned int 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 ) ;
}
void hcl_server_logufmt ( hcl_server_t * server , unsigned int mask , const hcl_uch_t * fmt , . . . )
{
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-03-14 14:40:05 +00:00
static void set_err_with_syserr ( hcl_server_t * server , int syserr , const char * bfmt , . . . )
{
hcl_t * hcl = server - > dummy_hcl ;
hcl_errnum_t errnum ;
hcl_oow_t tmplen , tmplen2 ;
va_list ap ;
static hcl_bch_t b_dash [ ] = { ' ' , ' - ' , ' ' , ' \0 ' } ;
static hcl_uch_t u_dash [ ] = { ' ' , ' - ' , ' ' , ' \0 ' } ;
if ( hcl - > shuterr ) return ;
errnum = hcl_syserr_to_errnum ( syserr ) ;
if ( hcl - > vmprim . syserrstrb )
{
hcl - > vmprim . syserrstrb ( hcl , syserr , hcl - > errmsg . tmpbuf . bch , HCL_COUNTOF ( hcl - > errmsg . tmpbuf . bch ) ) ;
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 ) ;
hcl - > vmprim . syserrstru ( hcl , syserr , hcl - > errmsg . tmpbuf . uch , HCL_COUNTOF ( hcl - > errmsg . tmpbuf . uch ) ) ;
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-03-22 09:46:44 +00:00
set_err_with_syserr ( server , errno , " unable to create multiplexer " ) ;
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-03-22 09:46:44 +00:00
set_err_with_syserr ( server , errno , " unable to register pipe %d to multiplexer " , server - > mux_pipe [ 0 ] ) ;
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 ) ;
if ( sck_fam < = - 1 )
{
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 )
{
set_err_with_syserr ( server , errno , " unable to open server socket for %.*hs " , addr_len , addr_ptr ) ;
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-03-22 09:53:16 +00:00
# if defined(O_CLOEXEC)
2018-03-22 09:46:44 +00:00
fcv = fcntl ( srv_fd , F_GETFD , 0 ) ;
if ( fcv > = 0 ) fcntl ( srv_fd , F_SETFD , fcv | O_CLOEXEC ) ;
2018-03-22 09:53:16 +00:00
# endif
2018-03-23 10:02:08 +00:00
# if defined(O_NONBLOCK)
fcv = fcntl ( srv_fd , F_GETFL , 0 ) ;
if ( fcv > = 0 ) fcntl ( srv_fd , F_SETFL , fcv | O_NONBLOCK ) ;
# endif
2018-03-22 09:46:44 +00:00
if ( bind ( srv_fd , ( struct sockaddr * ) & srv_addr , srv_len ) = = - 1 )
{
set_err_with_syserr ( server , errno , " unable to bind server socket %d for %.*hs " , srv_fd , addr_len , addr_ptr ) ;
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 )
{
set_err_with_syserr ( server , errno , " unable to listen on server socket %d for %.*hs " , srv_fd , addr_len , addr_ptr ) ;
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 )
{
set_err_with_syserr ( server , errno , " unable to register server socket %d to multiplexer for %.*hs " , srv_fd , addr_len , addr_ptr ) ;
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-03-15 15:23:51 +00:00
if ( n < = - 1 ) HCL_INITNTIME ( & 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-03-15 10:30:06 +00:00
set_err_with_syserr ( server , 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-03-22 09:46:44 +00:00
set_err_with_syserr ( server , errno , " unable to accept worker on server socket %d " , evp - > data . fd ) ;
2018-03-15 10:30:06 +00:00
xret = - 1 ;
break ;
}
2018-03-22 09:53:16 +00:00
# if defined(O_CLOEXEC)
2018-03-22 09:46:44 +00:00
fcv = fcntl ( cli_fd , F_GETFD , 0 ) ;
if ( fcv > = 0 ) fcntl ( cli_fd , F_SETFD , fcv | O_CLOEXEC ) ;
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 ) ;
2018-03-24 06:06:01 +00:00
if ( flood )
{
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-24 06:06:01 +00:00
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 :
server - > cfg . trait = * ( const unsigned int * ) value ;
2018-03-16 01:46:59 +00:00
if ( server - > dummy_hcl )
{
/* setting this affects the dummy hcl immediately.
* existing hcl instances inside worker threads won ' t get
* affected . new hcl instances to be created later
* is supposed to use the new value */
unsigned int trait ;
hcl_getoption ( server - > dummy_hcl , HCL_TRAIT , & trait ) ;
# if defined(HCL_BUILD_DEBUG)
if ( server - > cfg . trait & HCL_SERVER_TRAIT_DEBUG_GC ) trait | = HCL_DEBUG_GC ;
if ( server - > cfg . trait & HCL_SERVER_TRAIT_DEBUG_BIGINT ) trait | = HCL_DEBUG_BIGINT ;
# endif
hcl_setoption ( server - > dummy_hcl , HCL_TRAIT , & trait ) ;
}
2018-03-13 10:20:50 +00:00
return 0 ;
case HCL_SERVER_LOG_MASK :
server - > cfg . logmask = * ( const unsigned int * ) value ;
2018-03-16 01:46:59 +00:00
if ( server - > dummy_hcl )
{
/* setting this affects the dummy hcl immediately.
* existing hcl instances inside worker threads won ' t get
* affected . new hcl instances to be created later
* 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 ;
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 ;
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 ;
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 :
* ( unsigned int * ) value = server - > cfg . trait ;
return 0 ;
case HCL_SERVER_LOG_MASK :
* ( unsigned int * ) value = server - > cfg . logmask ;
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 ;
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 )
{
return ( void * ) ( server + 1 ) ;
}
hcl_mmgr_t * hcl_server_getmmgr ( hcl_server_t * server )
{
return server - > mmgr ;
}
hcl_cmgr_t * hcl_server_getcmgr ( hcl_server_t * server )
{
return server - > cmgr ;
}
void hcl_server_setcmgr ( hcl_server_t * server , hcl_cmgr_t * cmgr )
{
server - > cmgr = cmgr ;
}
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 ;
ptr = HCL_MMGR_ALLOC ( server - > mmgr , size ) ;
if ( ! ptr ) hcl_server_seterrnum ( server , HCL_ESYSMEM ) ;
return ptr ;
}
void * hcl_server_callocmem ( hcl_server_t * server , hcl_oow_t size )
{
void * ptr ;
ptr = HCL_MMGR_ALLOC ( server - > mmgr , size ) ;
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 )
{
ptr = HCL_MMGR_REALLOC ( server - > mmgr , ptr , size ) ;
if ( ! ptr ) hcl_server_seterrnum ( server , HCL_ESYSMEM ) ;
return ptr ;
}
void hcl_server_freemem ( hcl_server_t * server , void * ptr )
{
HCL_MMGR_FREE ( server - > mmgr , ptr ) ;
}