21int max_http_request_size = 16384;
29 " -p 'port' : set the https server port\n"
30 " -k 'key file' : SSL key file path\n"
31 " -c 'cert file' : SSL certificate file path\n"
32 " -a 'address name/ip' : optional, specify where to bind interface\n"
33 " -i 'ipmode' : optional, force 'ipv4' or 'ipv6', default supports both\n"
34 " -s 'size' : optional, maximum http request size (default: %d)\n"
35 " -d 'html root' : optional, specify a different http root dir (default: ./DATAS/)\n"
38 " -V 'log level' : optional, set the log level (default: LOG_ERR)\n",
39 max_http_request_size);
42void process_args(
int argc_nb,
char** argv_ptr,
char** addr_ptr,
char** port_ptr,
char** key_ptr,
char** cert_ptr,
LIST* routes_ptr,
int* ip_version_ptr,
int* max_http_request_size_ptr,
char** root_dir_ptr) {
47 fprintf(stderr,
"No arguments given, help:\n");
51 while ((getoptret = getopt(argc_nb, argv_ptr,
"hvs:V:p:i:a:r:k:c:s:d:")) != EOF) {
54 if (!strcmp(
"v4", optarg)) {
57 }
else if (!strcmp(
"v6", optarg)) {
65 fprintf(stderr,
"Date de compilation : %s a %s.\n", __DATE__, __TIME__);
68 if (!strncmp(
"LOG_NULL", optarg, 8)) {
71 if (!strncmp(
"LOG_NOTICE", optarg, 10)) {
74 if (!strncmp(
"LOG_INFO", optarg, 8)) {
77 if (!strncmp(
"LOG_ERR", optarg, 7)) {
80 if (!strncmp(
"LOG_DEBUG", optarg, 9)) {
83 fprintf(stderr,
"%s n'est pas un niveau de log valide.\n", optarg);
92 (*port_ptr) = strdup(optarg);
95 list_push(routes_ptr, strdup(optarg), &free);
98 (*addr_ptr) = strdup(optarg);
101 (*key_ptr) = strdup(optarg);
104 (*cert_ptr) = strdup(optarg);
107 (*max_http_request_size_ptr) = atoi(optarg);
110 (*root_dir_ptr) = strdup(optarg);
115 fprintf(stderr,
"\n Missing html root directory\n");
118 fprintf(stderr,
"\n Missing max http size string\n");
121 fprintf(stderr,
"\n Missing key file string\n");
124 fprintf(stderr,
"\n Missing certificate file string\n");
128 fprintf(stderr,
"\n Missing route string\n");
131 fprintf(stderr,
"\n Missing binding host/addr string\n");
134 fprintf(stderr,
"\n Missing ip version (v4 or v6) string \n");
135 }
else if (optopt ==
'V') {
136 fprintf(stderr,
"\n Missing log level string\n");
137 }
else if (optopt ==
'p') {
138 fprintf(stderr,
"\n Missing port\n");
139 }
else if (optopt !=
's') {
140 fprintf(stderr,
"\n Unknow missing option %c\n", optopt);
155void action_on_sig(
int recvd_signal) {
158 static int nb_sigterm = 0;
159 switch (recvd_signal) {
181 if (nb_sigterm >= 2) {
182 n_log(
LOG_ERR,
"Caught too much SIGTERM, trying _exit() !!");
185 n_log(
LOG_ERR,
"Caught %d SIGTERM, exiting now !!", nb_sigterm);
199 n_log(
LOG_ERR,
"Caught unknow signal %d", recvd_signal);
206void handle_request(
NETWORK* netw_ptr,
LIST* routes_ptr) {
211 char** split_results = NULL;
212 char* http_url = NULL;
213 N_STR* dynamic_request_answer = NULL;
216 char* http_buffer = NULL;
217 Alloca(http_buffer, max_http_request_size + 1);
220 SSL_read(netw_ptr->
ssl, http_buffer, max_http_request_size);
233 N_STR* http_body = NULL;
235 split_results =
split(url,
"?", 0);
236 if (!split_results || !split_results[0]) {
237 http_body =
char_to_nstr(
"<html><body><h1>Bad Request</h1></body></html>");
239 n_log(
LOG_ERR,
"couldn't build a Bad Request answer for %s", url);
243 http_url = split_results[0];
245 if (strcmp(
"OPTIONS", http_request.type) == 0) {
247 n_log(
LOG_ERR,
"couldn't build an OPTION answer for %s", url);
250 }
else if (strcmp(
"GET", http_request.type) == 0) {
251 char system_url[4096] =
"";
254 snprintf(system_url,
sizeof(system_url),
"./DATAS%s", http_url);
256 snprintf(system_url,
sizeof(system_url),
"%s%s", root_dir, http_url);
265 http_body =
char_to_nstr(
"<html><body><h1>Internal Server Error</h1></body></html>");
267 n_log(
LOG_ERR,
"couldn't build an Internal Server Error answer for %s", url);
272 n_log(
LOG_ERR,
"couldn't build an http answer for %s", url);
277 http_body =
char_to_nstr(
"<html><body><h1>404 Not Found</h1></body></html>");
279 n_log(
LOG_ERR,
"couldn't build a NOT FOUND answer for %s", url);
283 }
else if (strcmp(
"POST", http_request.type) == 0) {
287 if (strcmp(node->ptr, http_url) == 0) {
293 n_log(
LOG_DEBUG,
"%s: POST DATA: %s=%s",
_nstr(origin), hnode->key, (
char*)hnode->data.ptr);
298 if (
netw_build_http_response(&dynamic_request_answer, 200,
"ex_network_ssl server",
"application/json",
"", http_body) == FALSE) {
299 n_log(
LOG_ERR,
"couldn't build a route 200 answer for %s", url);
307 http_body =
char_to_nstr(
"<html><body><h1>404 Not Found</h1></body></html>");
309 n_log(
LOG_ERR,
"couldn't build a NOT FOUND answer for %s", url);
314 http_body =
char_to_nstr(
"<html><body><h1>Bad Request</h1></body></html>");
316 n_log(
LOG_ERR,
"couldn't build a Bad Request answer for %s", url);
322 if (dynamic_request_answer) {
323 SSL_write(netw_ptr->
ssl,
_nstr(dynamic_request_answer), dynamic_request_answer->
written);
326 n_log(
LOG_ERR,
"couldn't build an answer for %s: %s %s",
_nstr(origin), http_request.type, url);
341void* ssl_network_thread(
void* params) {
344 handle_request(ssl_params->
netw, ssl_params->
routes);
350int main(
int argc,
char* argv[]) {
357 process_args(argc, argv, &addr, &port, &key, &cert, routes, &ip_version, &max_http_request_size, &root_dir);
384 signal(SIGPIPE, SIG_IGN);
386 struct sigaction signal_catcher;
389 signal_catcher.sa_handler = action_on_sig;
390 sigemptyset(&signal_catcher.sa_mask);
391 signal_catcher.sa_flags = SA_SIGINFO;
393 sigaction(SIGTERM, &signal_catcher, NULL);
394 sigaction(SIGUSR1, &signal_catcher, NULL);
398 int nb_waiting_threads = 10 * nb_active_threads;
399 n_log(
LOG_INFO,
"Creating a new thread pool of %d active and %d waiting threads", nb_active_threads, nb_waiting_threads);
405 n_log(
LOG_ERR,
"Fatal error with network initialization");
416 if (return_code == EINTR) {
420 n_log(
LOG_ERR,
"error on accept, NULL netw returned !");
426 netw_ssl_params->
netw = netw;
427 netw_ssl_params->
routes = routes;
429 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.
#define MAX_LIST_ITEMS
flag to pass to new_generic_list for the maximum possible number of item in a list
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
size_t written
size of the written data inside the string
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
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
#define nstrprintf(__nstr_var, __format,...)
Macro to quickly allocate and sprintf to N_STR.
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.
char * ip
ip of the connected socket
N_SOCKET link
networking socket
SOCKET sock
a normal socket
int 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_set_crypto(NETWORK *netw, char *key, char *certificate)
activate SSL encryption on selected network, using key and certificate
#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
NETWORK * netw_accept_from_ex(NETWORK *from, size_t send_list_limit, size_t recv_list_limit, int blocking, int *retval)
make a normal 'accept' .
#define NETWORK_IPALL
Flag for auto detection by OS of ip version to use.
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
THREAD_POOL * new_thread_pool(size_t nbmaxthr, size_t nb_max_waiting)
Create a new pool of nbmaxthr threads.
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
int destroy_threaded_pool(THREAD_POOL **pool, unsigned int delay)
delete a thread_pool, exit the threads and free the structs
long int get_nb_cpu_cores()
get number of core of current system
#define DIRECT_PROC
processing mode for added func, direct start
int wait_for_threaded_pool(THREAD_POOL *thread_pool, unsigned int delay)
Wait for all the launched process in the thread pool to terminate.
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