19char *root_dir = NULL ;
22int max_http_request_size = 16384 ;
31 " -p 'port' : set the https server port\n"
32 " -k 'key file' : SSL key file path\n"
33 " -c 'cert file' : SSL certificate file path\n"
34 " -a 'address name/ip' : optional, specify where to bind interface\n"
35 " -i 'ipmode' : optional, force 'ipv4' or 'ipv6', default supports both\n"
36 " -s 'size' : optional, maximum http request size (default: %d)\n"
37 " -d 'html root' : optional, specify a different http root dir (default: ./DATAS/)\n"
40 " -V 'log level' : optional, set the log level (default: LOG_ERR)\n" , max_http_request_size );
43void process_args(
int argc,
char **argv,
char **addr,
char **port,
char **key,
char **cert,
LIST *routes ,
int *ip_version ,
int *max_http_request_size ,
char **root_dir )
50 fprintf( stderr,
"No arguments given, help:\n" );
54 while( ( getoptret = getopt( argc, argv,
"hvs:V:p:i:a:r:k:c:s:d:" ) ) != EOF)
59 if( !strcmp(
"v4", optarg ) )
64 else if( !strcmp(
"v6", optarg ) )
75 fprintf( stderr,
"Date de compilation : %s a %s.\n", __DATE__, __TIME__ );
78 if( !strncmp(
"LOG_NULL", optarg, 8 ) )
84 if( !strncmp(
"LOG_NOTICE", optarg, 10 ) )
90 if( !strncmp(
"LOG_INFO", optarg, 8 ) )
96 if( !strncmp(
"LOG_ERR", optarg, 7 ) )
102 if( !strncmp(
"LOG_DEBUG", optarg, 9 ) )
108 fprintf( stderr,
"%s n'est pas un niveau de log valide.\n", optarg );
117 (*port) = strdup( optarg );
120 list_push( routes , strdup( optarg ) , &free );
123 (*addr) = strdup( optarg );
126 (*key) = strdup( optarg );
129 (*cert) = strdup( optarg );
132 (*max_http_request_size) = atoi( optarg );
135 (*root_dir) = strdup( optarg );
142 fprintf( stderr,
"\n Missing html root directory\n" );
146 fprintf( stderr,
"\n Missing max http size string\n" );
150 fprintf( stderr,
"\n Missing key file string\n" );
154 fprintf( stderr,
"\n Missing certificate file string\n" );
159 fprintf( stderr,
"\n Missing route string\n" );
163 fprintf( stderr,
"\n Missing binding host/addr string\n" );
167 fprintf( stderr,
"\n Missing ip version (v4 or v6) string \n" );
169 else if( optopt ==
'V' )
171 fprintf( stderr,
"\n Missing log level string\n" );
173 else if( optopt ==
'p' )
175 fprintf( stderr,
"\n Missing port\n" );
177 else if( optopt !=
's' )
179 fprintf( stderr,
"\n Unknow missing option %c\n", optopt );
197void action_on_sig(
int recvd_signal )
199 static int nb_sigterm = 0 ;
201 switch( recvd_signal )
225 if( nb_sigterm >= 2 )
227 n_log(
LOG_ERR,
"Caught too much SIGTERM, trying _exit() !!" );
230 n_log(
LOG_ERR,
"Caught %d SIGTERM, exiting now !!" , nb_sigterm );
245 n_log(
LOG_ERR,
"Caught unknow signal %d", recvd_signal );
257 char **split_results = NULL ;
258 char *http_url = NULL ;
259 N_STR *dynamic_request_answer = NULL ;
262 char *http_buffer = NULL ;
263 Alloca( http_buffer , max_http_request_size + 1 );
266 SSL_read(netw -> ssl, http_buffer, max_http_request_size );
279 N_STR *http_body = NULL ;
281 split_results =
split( url ,
"?" , 0 );
282 if( !split_results || !split_results[ 0 ] )
284 http_body =
char_to_nstr(
"<html><body><h1>Bad Request</h1></body></html>");
287 n_log(
LOG_ERR ,
"couldn't build a Bad Request answer for %s" , url );
289 n_log(
LOG_ERR ,
"%s: %s %s 400" ,
_nstr( origin ) , http_request . type , url );
293 http_url = split_results[ 0 ];
294 n_log(
LOG_INFO ,
"%s: %s %s request..." ,
_nstr( origin ) , http_request . type , url );
295 if( strcmp(
"OPTIONS" , http_request . type ) == 0 )
299 n_log(
LOG_ERR ,
"couldn't build an OPTION answer for %s" , url );
303 else if( strcmp(
"GET" , http_request . type ) == 0 )
305 char system_url[ 4096 ] =
"" ;
309 snprintf(system_url,
sizeof(system_url),
"./DATAS%s" , http_url );
313 snprintf(system_url,
sizeof(system_url),
"%s%s" , root_dir ,http_url );
324 http_body =
char_to_nstr(
"<html><body><h1>Internal Server Error</h1></body></html>");
327 n_log(
LOG_ERR ,
"couldn't build an Internal Server Error answer for %s" , url );
329 n_log(
LOG_ERR ,
"%s: %s %s 500" ,
_nstr( origin ) , http_request . type , url );
335 n_log(
LOG_ERR ,
"couldn't build an http answer for %s" , url );
342 http_body =
char_to_nstr(
"<html><body><h1>404 Not Found</h1></body></html>");
345 n_log(
LOG_ERR ,
"couldn't build a NOT FOUND answer for %s" , url );
347 n_log(
LOG_ERR ,
"%s: %s %s 404" ,
_nstr( origin ) , http_request . type , url );
350 else if( strcmp(
"POST" , http_request . type ) == 0 )
356 if( strcmp( node -> ptr , http_url ) == 0 )
364 n_log(
LOG_DEBUG ,
"%s: POST DATA: %s=%s" ,
_nstr( origin ) , node -> key , (
char *)node -> data . ptr );
369 if(
netw_build_http_response( &dynamic_request_answer, 200,
"ex_network_ssl server",
"application/json" ,
"", http_body ) == FALSE )
371 n_log(
LOG_ERR ,
"couldn't build a route 200 answer for %s" , url );
374 n_log(
LOG_INFO ,
"%s: %s virtual:%s 200" ,
_nstr( origin ) , http_request . type , url );
380 http_body =
char_to_nstr(
"<html><body><h1>404 Not Found</h1></body></html>");
383 n_log(
LOG_ERR ,
"couldn't build a NOT FOUND answer for %s" , url );
385 n_log(
LOG_ERR ,
"%s: %s %s 404" ,
_nstr( origin ) , http_request . type , url );
390 http_body =
char_to_nstr(
"<html><body><h1>Bad Request</h1></body></html>");
393 n_log(
LOG_ERR ,
"couldn't build a Bad Request answer for %s" , url );
395 n_log(
LOG_ERR ,
"%s: %s %s 400" ,
_nstr( origin ) , http_request . type , url );
399 if( dynamic_request_answer )
401 SSL_write( netw -> ssl,
_nstr( dynamic_request_answer ), dynamic_request_answer -> written );
406 n_log(
LOG_ERR ,
"couldn't build an answer for %s: %s %s" ,
_nstr( origin ) , http_request . type , url );
423void *ssl_network_thread(
void *params )
427 handle_request(ssl_params -> netw , ssl_params -> routes);
433int main(
int argc ,
char *argv[] ) {
441 process_args( argc, argv, &addr, &port, &key, &cert, routes, &ip_version , &max_http_request_size , &root_dir );
446 exit_code = 1;
goto clean_and_exit ;
451 exit_code = 1;
goto clean_and_exit ;
456 exit_code = 1;
goto clean_and_exit ;
458 if( routes -> nb_items == 0 )
461 exit_code = 1;
goto clean_and_exit ;
466 sigignore( SIGPIPE );
468 struct sigaction signal_catcher ;
471 signal_catcher . sa_handler = action_on_sig ;
472 sigemptyset( &signal_catcher . sa_mask );
473 signal_catcher . sa_flags = SA_SIGINFO;
475 sigaction( SIGTERM, &signal_catcher, NULL );
476 sigaction( SIGUSR1, &signal_catcher, NULL );
481 int nb_waiting_threads = 10 * nb_active_threads ;
482 n_log(
LOG_INFO,
"Creating a new thread pool of %d active and %d waiting threads" , nb_active_threads , nb_waiting_threads );
485 n_log(
LOG_INFO,
"Creating listening network for %s:%s %d",
_str( addr ),
_str( port ), ip_version );
489 n_log(
LOG_ERR,
"Fatal error with network initialization" );
493 netw_set_crypto( server , key , cert );
498 int return_code = 0 ;
501 if( return_code == EINTR )
504 goto clean_and_exit ;
508 n_log(
LOG_ERR,
"error on accept, %s !" , strerror( return_code ) );
515 netw_ssl_params -> netw = netw ;
516 netw_ssl_params -> routes = routes ;
519 n_log(
LOG_ERR,
"Error adding client management to thread pool" );
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
#define __n_assert(__ptr, __ret)
macro to assert things
#define _str(__PTR)
define true
#define Alloca(__ptr, __size)
Malloca Handler to get errors and set to 0.
int file_exist(const char *filename)
test if file exist and if it's readable
#define Free(__ptr)
Free Handler to get errors.
#define _nstr(__PTR)
N_STR or "NULL" string for logging purposes.
int destroy_ht(HASH_TABLE **table)
empty a table and destroy it
#define HT_FOREACH(__ITEM_, __HASH_,...)
ForEach macro helper.
structure of a hash table
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
#define list_foreach(__ITEM_, __LIST_)
ForEach macro helper.
int list_destroy(LIST **list)
Empty and Free a list container.
LIST * new_generic_list(int max_items)
Initialiaze a generic list container to max_items pointers.
Structure of a generic LIST container.
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_DEBUG
debug-level messages
#define LOG_ERR
error conditions
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
#define LOG_NOTICE
normal but significant condition
#define LOG_NULL
no log output
#define LOG_INFO
informational
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
#define nstrprintf(__nstr_var,...)
Macro to quickly allocate and sprintf to N_STR
N_STR * char_to_nstr(const char *src)
Convert a char into a N_STR, short version.
N_STR * new_nstr(NSTRBYTE size)
create a new N_STR string
char ** split(const char *str, const char *delim, int empty)
split the strings into a an array of char *pointer , ended by a NULL one.
N_STR * file_to_nstr(char *filename)
Load a whole file into a N_STR.
int free_split_result(char ***tab)
Free a split result allocated array.
A box including a string and his lenght.
NETWORK * netw_accept_from_ex(NETWORK *from, int send_list_limit, int recv_list_limit, int blocking, int *retval)
make a normal 'accept' .
#define NETWORK_IPV6
Flag to force IPV6
int netw_make_listening(NETWORK **netw, char *addr, char *port, int nbpending, int ip_version)
Make a NETWORK be a Listening network.
#define NETWORK_IPV4
Flag to force IPV4
int netw_build_http_response(N_STR **http_response, int status_code, const char *server_name, const char *content_type, char *additional_headers, N_STR *body)
function to dynamically generate an HTTP response
#define SOCKET_SIZE_FORMAT
socket associated printf style
#define NETWORK_IPALL
Flag for auto detection by OS of ip version to use.
void netw_get_url_from_http_request(const char *request, char *url, size_t size)
Helper function to extract the URL from the HTTP request line.
int netw_close(NETWORK **netw)
Closing a specified Network, destroy queues, free the structure.
NETWORK_HTTP_INFO netw_extract_http_info(char *request)
extract a lot of informations, mostly as pointers, and populate a NETWORK_HTTP_INFO structure
int netw_info_destroy(NETWORK_HTTP_INFO http_request)
destroy a NETWORK_HTTP_INFO loaded informations
HASH_TABLE * netw_parse_post_data(const char *post_data)
Function to parse POST data.
const char * netw_guess_http_content_type(const char *url)
function to guess the content type based on URL extension
structure for splitting HTTP requests
int get_nb_cpu_cores()
get number of core of current system
int destroy_threaded_pool(THREAD_POOL **pool, int delay)
delete a thread_pool, exit the threads and free the structs
int add_threaded_process(THREAD_POOL *thread_pool, void *(*func_ptr)(void *param), void *param, int mode)
add a function and params to a thread pool
#define DIRECT_PROC
processing mode for added func, direct start
int wait_for_threaded_pool(THREAD_POOL *thread_pool, int delay)
Wait for all the launched process in the thread pool to terminate.
THREAD_POOL * new_thread_pool(int nbmaxthr, int nb_max_waiting)
Create a new pool of nbmaxthr threads.
Structure of a trhead pool.
List structures and definitions.
Signals general handling with stack printing, from https://gist.github.com/jvranish/4441299.
N_STR and string function declaration.
structure of a NETWORK_SSL_THREAD_PARAMS
LIST * routes
virtual routes for the server
NETWORK * netw
network to use for the receiving thread