From 89e3d7a3f043dad10e4273418b28c6cf6aa7624e Mon Sep 17 00:00:00 2001 From: lxsang Date: Fri, 5 Oct 2018 19:01:39 +0200 Subject: [PATCH] fix memory leak on the new non blocking system --- http_server.c | 578 +++++++++++++++++++++++++++++----------------- http_server.h | 14 +- httpd.c | 157 +++---------- libs/dictionary.c | 9 +- libs/dictionary.h | 1 - libs/handle.c | 8 +- libs/handle.h | 26 ++- libs/plugin.c | 10 +- libs/plugin.h | 19 +- libs/scheduler.c | 1 + libs/utils.c | 7 +- plugin_manager.c | 26 +-- plugin_manager.h | 3 +- 13 files changed, 461 insertions(+), 398 deletions(-) diff --git a/http_server.c b/http_server.c index 2da4dce..70cb3d7 100644 --- a/http_server.c +++ b/http_server.c @@ -1,52 +1,202 @@ #include "http_server.h" static pthread_mutex_t server_mux = PTHREAD_MUTEX_INITIALIZER; +config_t server_config; +config_t* config() +{ + return &server_config; +} -void* accept_request(void* client) +void destroy_config() +{ + list_free(&(server_config.rules)); + freedict(server_config.handlers); + if(server_config.plugins_dir) free(server_config.plugins_dir); + if(server_config.plugins_ext) free(server_config.plugins_ext); + if(server_config.db_path) free(server_config.db_path); + if(server_config.htdocs) free(server_config.htdocs); + if(server_config.tmpdir) free(server_config.tmpdir); + + LOG("Unclosed connection: %d\n", server_config.connection); +} + +static int config_handler(void* conf, const char* section, const char* name, + const char* value) +{ + config_t* pconfig = (config_t*)conf; + //char * ppath = NULL; + if (MATCH("SERVER", "port")) { + pconfig->port = atoi(value); + } else if (MATCH("SERVER", "plugins")) { + pconfig->plugins_dir = strdup(value); + } else if (MATCH("SERVER", "plugins_ext")) { + pconfig->plugins_ext = strdup(value); + } else if(MATCH("SERVER", "database")) { + pconfig->db_path = strdup(value); + } else if(MATCH("SERVER", "htdocs")) { + pconfig->htdocs = strdup(value); + } else if(MATCH("SERVER", "tmpdir")) { + pconfig->tmpdir = strdup(value); + } + else if(MATCH("SERVER", "maxcon")) { + pconfig->maxcon = atoi(value); + } + else if(MATCH("SERVER", "backlog")) { + pconfig->backlog = atoi(value); + } + else if(MATCH("SERVER", "workers")) { + pconfig->n_workers = atoi(value); + } +#ifdef USE_OPENSSL + else if(MATCH("SERVER", "ssl.enable")) { + pconfig->usessl = atoi(value); + } + else if(MATCH("SERVER", "ssl.cert")) { + pconfig->sslcert = strdup(value); + } + else if(MATCH("SERVER", "ssl.key")) { + pconfig->sslkey = strdup(value); + } +#endif + else if (strcmp(section, "RULES") == 0) + { + list_put_s(&pconfig->rules, name); + list_put_s(&pconfig->rules, value); + } + else if (strcmp(section, "FILEHANDLER") == 0) + { + dput( pconfig->handlers, name ,strdup(value)); + } + else if(strcmp(section,"AUTOSTART")==0){ + // The server section must be added before the autostart section + // auto start plugin + plugin_load(value); + } else { + return 0; /* unknown section/name, error */ + } + return 1; +} +void init_file_system() +{ + struct stat st; + if (stat(server_config.plugins_dir, &st) == -1) + mkdir(server_config.plugins_dir, 0755); + if (stat(server_config.db_path, &st) == -1) + mkdir(server_config.db_path, 0755); + if (stat(server_config.htdocs, &st) == -1) + mkdir(server_config.htdocs, 0755); + if (stat(server_config.tmpdir, &st) == -1) + mkdir(server_config.tmpdir, 0755); + else + { + removeAll(server_config.tmpdir,0); + } + +} +void load_config(const char* file) +{ + server_config.port = 8888; + server_config.plugins_dir = "plugins/"; + server_config.plugins_ext = ".dylib"; + server_config.db_path = "databases/"; + server_config.htdocs = "htdocs/"; + server_config.tmpdir = "tmp/"; + server_config.n_workers = 4; + server_config.backlog = 100; + server_config.rules = list_init(); + server_config.handlers = dict(); + server_config.maxcon = 1000; + server_config.connection = 0; +#ifdef USE_OPENSSL + server_config.usessl = 0; + server_config.sslcert = "cert.pem"; + server_config.sslkey = "key.pem"; +#endif + if (ini_parse(file, config_handler, &server_config) < 0) { + LOG("Can't load '%s'\n. Used defaut configuration", file); + } + else + { + LOG("Using configuration : %s\n", file); +#ifdef USE_OPENSSL + LOG("SSL enable %d\n", server_config.usessl); + LOG("SSL cert %s\n", server_config.sslcert); + LOG("SSL key %s\n", server_config.sslkey); +#endif + } + init_file_system(); +} +void set_nonblock(int socket) { + int flags; + flags = fcntl(socket,F_GETFL,0); + //assert(flags != -1); + fcntl(socket, F_SETFL, flags | O_NONBLOCK); +} + +void* accept_request(void* data) { int count; char buf[BUFFLEN]; - antd_request_t* request; - antd_task_t* task; char* token = NULL; char* line = NULL; - request = (antd_request_t*)malloc(sizeof(*request)); - request->client = client; - request->request = dict(); - count = read_buf(client, buf, sizeof(buf)); - task = antd_create_task(NULL,(void*)request,NULL); + antd_task_t* task; + antd_request_t* rq = (antd_request_t*) data; + + task = antd_create_task(NULL,(void*)rq,NULL); task->priority++; - if(count <= 0) + server_config.connection++; + fd_set read_flags; + // first verify if the socket is ready + antd_client_t* client = (antd_client_t*) rq->client; + FD_ZERO(&read_flags); + FD_SET(rq->client->sock, &read_flags); + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 500; + // select + int sel = select(client->sock+1, &read_flags, NULL, (fd_set*)0, &timeout); + if(sel == -1) { - unknow(client); + unknow(rq->client); return task; } + if(sel == 0 || !FD_ISSET(client->sock, &read_flags) ) + { + // retry it later + server_config.connection--; + task->handle = accept_request; + return task; + } + count = read_buf(rq->client, buf, sizeof(buf)); + //LOG("count is %d\n", count); line = buf; // get the method string token = strsep(&line," "); if(!line) { - unknow(client); + LOG("No method found\n"); + unknow(rq->client); return task; } trim(token,' '); trim(line,' '); - dput(request->request, "METHOD", strdup(token)); + dput(rq->request, "METHOD", strdup(token)); // get the request token = strsep(&line, " "); if(!line) { - unknow(client); + LOG("No request found\n"); + unknow(rq->client); return task; } trim(token,' '); trim(line,' '); trim(line, '\n'); trim(line, '\r'); - dput(request->request, "PROTOCOL", strdup(line)); - dput(request->request, "REQUEST_QUERY", strdup(token)); + dput(rq->request, "PROTOCOL", strdup(line)); + dput(rq->request, "REQUEST_QUERY", strdup(token)); line = token; token = strsep(&line, "?"); - dput(request->request, "REQUEST_PATH", strdup(token)); + dput(rq->request, "REQUEST_PATH", strdup(token)); // decode request // now return the task task->handle = decode_request_header; @@ -69,9 +219,6 @@ void* resolve_request(void* data) //if (path[strlen(path) - 1] == '/') // strcat(path, "index.html"); if (stat(path, &st) == -1) { - //if(execute_plugin(rq->client,rqp,method,rq) < 0) - // not_found(client); - LOG("execute plugin \n"); free(task); return execute_plugin(rq, rqp); } @@ -149,9 +296,23 @@ void* finish_request(void* data) LOG("Close request\n"); antd_request_t* rq = (antd_request_t*)data; // free all other thing - if(rq->request) freedict(rq->request); + if(rq->request) + { + dictionary tmp = dvalue(rq->request, "COOKIE"); + if(tmp) freedict(tmp); + tmp = dvalue(rq->request, "REQUEST_HEADER"); + if(tmp) freedict(tmp); + tmp = dvalue(rq->request, "REQUEST_DATA"); + if(tmp) freedict(tmp); + dput(rq->request, "REQUEST_HEADER", NULL); + dput(rq->request, "REQUEST_DATA", NULL); + dput(rq->request, "COOKIE", NULL); + freedict(rq->request); + } antd_close(rq->client); free(rq); + server_config.connection--; + LOG("Remaining connection %d\n", server_config.connection); return NULL; } @@ -225,12 +386,8 @@ int rule_check(const char*k, const char* v, const char* host, const char* _url, free(query); return 1; } -/**********************************************************************/ -/* Print out an error message with perror() (for system errors; based -* on value of errno, which indicates system call errors) and exit the -* program indicating an error. */ -/**********************************************************************/ -void error_die(const char *sc) + +static void error_die(const char *sc) { perror(sc); exit(1); @@ -251,14 +408,6 @@ void* serve_file(void* data) return task; } -/**********************************************************************/ -/* This function starts the process of listening for web connections -* on a specified port. If the port is 0, then dynamically allocate a -* port and modify the original port variable to reflect the actual -* port. -* Parameters: pointer to variable containing the port to connect on -* Returns: the socket */ -/**********************************************************************/ int startup(unsigned *port) { int httpd = 0; @@ -322,15 +471,7 @@ char* apply_rules(const char* host, char*url) return strdup(query_string); } /** - * Decode the HTTP request - * Get the cookie values - * if it is the GET request, decode the query string into a dictionary - * if it is a POST, check the content type of the request - * - if it is a POST request with URL encoded : decode the url encode - * - if it is a POST request with multipart form data: de code the multipart - * - if other - UNIMPLEMENTED - * @param an antd_request_t structure - * @return a task + * Decode the HTTP request header */ void* decode_request_header(void* data) @@ -375,7 +516,6 @@ void* decode_request_header(void* data) memset(buf, 0, sizeof(buf)); strcat(buf,url); query = apply_rules(host, buf); - LOG("BUGFGGGG is %s\n", buf); dput(rq->request,"RESOURCE_PATH",strdup(buf)); if(query) { @@ -384,7 +524,7 @@ void* decode_request_header(void* data) free(query); } if(cookie) - dput(request,"cookie",cookie); + dput(rq->request,"COOKIE",cookie); if(host) free(host); // header ok, now checkmethod antd_task_t* task = antd_create_task(decode_request,(void*)rq, NULL); @@ -451,6 +591,7 @@ void* decode_post_request(void* data) if(tmp) clen = atoi(tmp); task = antd_create_task(NULL,(void*)rq, NULL); + task->priority++; if(ctype == NULL || clen == -1) { LOG("Bad request\n"); @@ -468,7 +609,8 @@ void* decode_post_request(void* data) { //printf("Multi part form : %s\n", ctype); // TODO: split this to multiple task - decode_multi_part_request(rq->client,ctype,request); + free(task); + return decode_multi_part_request(rq,ctype,request); } else { @@ -545,193 +687,207 @@ dictionary decode_cookie(const char* line) token1 = strsep(&token,"="); if(token1 && token && strlen(token) > 0) { - if(dic == NULL) - dic = dict(); + if(dic == NULL) dic = dict(); + LOG("%s: %s\n", token1, token); dput(dic,token1,strdup(token)); } } - //} free(orgcpy); return dic; } /** * Decode the multi-part form data from the POST request * If it is a file upload, copy the file to tmp dir - * and generate the metadata for the server-side - * @param client the socket client - * @param ctype Content-Type of the request - * @param clen Content length, but not used here - * @return a dictionary of key - value */ -void decode_multi_part_request(void* client,const char* ctype, dictionary dic) +void* decode_multi_part_request(void* data,const char* ctype, dictionary dic) { char * boundary; - char * boundend; char * line; - char * orgline; char * str_copy = strdup(ctype); char* orgcpy = str_copy; - char* token; - char* keytoken ; - char* valtoken ; - char* part_name; - char* part_file; + antd_request_t* rq = (antd_request_t*) data; + antd_task_t* task = antd_create_task(NULL, (void*)rq, NULL); + task->priority++; + //dictionary dic = NULL; + FILE *fp = NULL; + boundary = strsep(&str_copy,"="); //discard first part + boundary = str_copy; + if(boundary && strlen(boundary)>0) + { + //dic = dict(); + trim(boundary,' '); + dput(rq->request, "MULTI_PART_BOUNDARY", strdup(boundary)); + //find first boundary + while((line = read_line(rq->client))&&strstr(line,boundary) <= 0) + { + if(line) free(line); + } + if(line) + { + task->handle = decode_multi_part_request_data; + task->type = HEAVY; + free(line); + } + } + free(orgcpy); + return task; +} +void* decode_multi_part_request_data(void* data) +{ + // loop through each part separated by the boundary + char* line; + char* orgline; + char* part_name = NULL; + char* part_file = NULL; char* file_path; char buf[BUFFLEN]; char* field; //dictionary dic = NULL; FILE *fp = NULL; - boundary = strsep(&str_copy,"="); //discard first part - boundary = strsep(&str_copy,"="); - if(boundary && strlen(boundary)>0) + char* token, *keytoken, *valtoken; + antd_request_t* rq = (antd_request_t*) data; + antd_task_t* task = antd_create_task(NULL, (void*)rq, NULL); + task->priority++; + char* boundary = (char*)dvalue(rq->request, "MULTI_PART_BOUNDARY"); + dictionary dic = (dictionary)dvalue(rq->request, "REQUEST_DATA"); + char* boundend = __s("%s--",boundary); + // search for content disposition: + while((line = read_line(rq->client)) && + strstr(line,"Content-Disposition:") <= 0) { - //dic = dict(); - trim(boundary,' '); - boundend = __s("%s--",boundary); - //find first boundary - while((line = read_line(client))&&strstr(line,boundary) <= 0) - { - if(line) free(line); - } - // loop through each part separated by the boundary - while(line && strstr(line,boundary) > 0){ - if(line) - { - free(line); - line = NULL; - } - // search for content disposition: - while((line = read_line(client)) && - strstr(line,"Content-Disposition:") <= 0) - { - free(line); - line = NULL; - } - if(!line || strstr(line,"Content-Disposition:") <= 0) - { - if(line) - free(line); - free(orgcpy); - free(boundend); - return; - } - orgline = line; - // extract parameters from header - part_name = NULL; - part_file = NULL; - while((token = strsep(&line,";"))) - { - keytoken = strsep(&token,"="); - if(keytoken && strlen(keytoken)>0) - { - trim(keytoken,' '); - valtoken = strsep(&token,"="); - if(valtoken) - { - trim(valtoken,' '); - trim(valtoken,'\n'); - trim(valtoken,'\r'); - trim(valtoken,'\"'); - if(strcmp(keytoken,"name") == 0) - { - part_name = strdup(valtoken); - } else if(strcmp(keytoken,"filename") == 0) - { - part_file = strdup(valtoken); - } - } - } - } - free(orgline); - line = NULL; - // get the binary data - if(part_name != NULL) - { - // go to the beginer of data bock - while((line = read_line(client)) && strcmp(line,"\r\n") != 0) - { - free(line); - line = NULL; - } - if(line) - { - free(line); - line = NULL; - } - if(part_file == NULL) - { - /** - * This allow only 1024 bytes of data (max), - * out of this range, the data is cut out. - * Need an efficient way to handle this - */ - line = read_line(client); - trim(line,'\n'); - trim(line,'\r'); - trim(line,' '); - dput(dic,part_name,line); - // find the next boundary - while((line = read_line(client)) && strstr(line,boundary) <= 0) - { - free(line); - line = NULL; - } - } - else - { - file_path = __s("%s%s.%u",server_config.tmpdir,part_file,(unsigned)time(NULL)); - fp=fopen(file_path, "wb"); - if(fp) - { - int totalsize=0,len=0; - //read until the next boundary - while((len = read_buf(client,buf,sizeof(buf))) > 0 && strstr(buf,boundary) <= 0) - { - fwrite(buf, len, 1, fp); - totalsize += len; - } - //remove \r\n at the end - fseek(fp,-2, SEEK_CUR); - totalsize -= 2; - fclose(fp); - line = strdup(buf); - - field = __s("%s.file",part_name); - dput(dic,field, strdup(part_file)); - free(field); - field = __s("%s.tmp",part_name); - dput(dic,field,strdup(file_path)); - free(field); - field = __s("%s.size",part_name); - dput(dic,field,__s("%d",totalsize)); - free(field); - field = __s("%s.ext",part_name); - dput(dic,field,ext(part_file)); - free(field); - - } - else - { - LOG("Cannot wirte file to :%s\n", file_path ); - } - free(file_path); - free(part_file); - } - free(part_name); - } - //printf("[Lines]:%s\n",line); - // check if end of request - if(line&&strstr(line,boundend)>0) - { - LOG("End request %s\n", boundend); - free(line); - break; - } - } - free(boundend); + free(line); + line = NULL; } - free(orgcpy); - //return dic; + if(!line || strstr(line,"Content-Disposition:") <= 0) + { + if(line) + free(line); + free(boundend); + return task; + } + orgline = line; + // extract parameters from header + while((token = strsep(&line,";"))) + { + keytoken = strsep(&token,"="); + if(keytoken && strlen(keytoken)>0) + { + trim(keytoken,' '); + valtoken = strsep(&token,"="); + if(valtoken) + { + trim(valtoken,' '); + trim(valtoken,'\n'); + trim(valtoken,'\r'); + trim(valtoken,'\"'); + if(strcmp(keytoken,"name") == 0) + { + part_name = strdup(valtoken); + } else if(strcmp(keytoken,"filename") == 0) + { + part_file = strdup(valtoken); + } + } + } + } + free(orgline); + line = NULL; + // get the binary data + if(part_name != NULL) + { + // go to the beginer of data bock + while((line = read_line(rq->client)) && strcmp(line,"\r\n") != 0) + { + free(line); + line = NULL; + } + if(line) + { + free(line); + line = NULL; + } + if(part_file == NULL) + { + /** + * This allow only 1024 bytes of data (max), + * out of this range, the data is cut out. + * Need an efficient way to handle this + */ + line = read_line(rq->client); + trim(line,'\n'); + trim(line,'\r'); + trim(line,' '); + dput(dic,part_name,line); + // find the next boundary + while((line = read_line(rq->client)) && strstr(line,boundary) <= 0) + { + free(line); + line = NULL; + } + } + else + { + file_path = __s("%s%s.%u",server_config.tmpdir,part_file,(unsigned)time(NULL)); + fp=fopen(file_path, "wb"); + if(fp) + { + int totalsize=0,len=0; + //read until the next boundary + while((len = read_buf(rq->client,buf,sizeof(buf))) > 0 && strstr(buf,boundary) <= 0) + { + fwrite(buf, len, 1, fp); + totalsize += len; + } + //remove \r\n at the end + fseek(fp, 0, SEEK_SET); + //fseek(fp,-2, SEEK_CUR); + totalsize -= 2; + ftruncate(fileno(fp),totalsize); + fclose(fp); + line = strdup(buf); + + field = __s("%s.file",part_name); + dput(dic,field, strdup(part_file)); + free(field); + field = __s("%s.tmp",part_name); + dput(dic,field,strdup(file_path)); + free(field); + field = __s("%s.size",part_name); + dput(dic,field,__s("%d",totalsize)); + free(field); + field = __s("%s.ext",part_name); + dput(dic,field,ext(part_file)); + free(field); + + } + else + { + LOG("Cannot wirte file to :%s\n", file_path ); + } + free(file_path); + free(part_file); + } + free(part_name); + } + //printf("[Lines]:%s\n",line); + // check if end of request + if(line&&strstr(line,boundend)>0) + { + LOG("End request %s\n", boundend); + task->handle = resolve_request; + free(line); + free(boundend); + return task; + } + if(line && strstr(line,boundary) > 0) + { + // continue upload + task->type = HEAVY; + task->handle = decode_multi_part_request_data; + } + free(line); + free(boundend); + return task; } /** * Decode a query string (GET request or POST URL encoded) to diff --git a/http_server.h b/http_server.h index 60a0031..6a965c7 100644 --- a/http_server.h +++ b/http_server.h @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include "libs/handle.h" #include "libs/scheduler.h" #include "plugin_manager.h" @@ -15,17 +17,16 @@ #define FORM_MULTI_PART "multipart/form-data" #define PLUGIN_HANDLER "handle" #define WS_MAGIC_STRING "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - -#define SERVER_STRING "Server: ant-httpd" +#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 #define CONFIG "config.ini" -extern config_t server_config; +config_t* config(); +void destroy_config(); void* accept_request(void*); void* finish_request(void*); void cat(void*, FILE *); void cannot_execute(void*); -void error_die(const char *); //int get_line(int, char *, int); void not_found(void*); void* serve_file(void*); @@ -40,10 +41,11 @@ void* decode_request_header(void* data); void* decode_request(void* data); void* decode_post_request(void* data); void* resolve_request(void* data); -void decode_multi_part_request(void*,const char*, dictionary); +void* decode_multi_part_request(void*,const char*, dictionary); +void* decode_multi_part_request_data(void* data); dictionary decode_cookie(const char*); char* post_data_decode(void*,int); - +void set_nonblock(int); void* execute_plugin(void* data, const char *path); #endif \ No newline at end of file diff --git a/httpd.c b/httpd.c index a5c2f4e..89ba04f 100644 --- a/httpd.c +++ b/httpd.c @@ -2,11 +2,9 @@ #include #include "http_server.h" #include "libs/ini.h" -#include static antd_scheduler_t scheduler; +static int server_sock = -1; -#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 -int server_sock = -1; #ifdef USE_OPENSSL static int ssl_session_ctx_id = 1; SSL_CTX *ctx; @@ -55,13 +53,13 @@ void configure_context(SSL_CTX *ctx) SSL_CTX_set_session_id_context(ctx, (void *)&ssl_session_ctx_id, sizeof(ssl_session_ctx_id)); /* Set the key and cert */ /* use the full chain bundle of certificate */ - //if (SSL_CTX_use_certificate_file(ctx, server_config.sslcert, SSL_FILETYPE_PEM) <= 0) { - if (SSL_CTX_use_certificate_chain_file(ctx, server_config.sslcert) <= 0) { + //if (SSL_CTX_use_certificate_file(ctx, server_config->sslcert, SSL_FILETYPE_PEM) <= 0) { + if (SSL_CTX_use_certificate_chain_file(ctx, config()->sslcert) <= 0) { ERR_print_errors_fp(stderr); exit(EXIT_FAILURE); } - if (SSL_CTX_use_PrivateKey_file(ctx, server_config.sslkey, SSL_FILETYPE_PEM) <= 0 ) { + if (SSL_CTX_use_PrivateKey_file(ctx, config()->sslkey, SSL_FILETYPE_PEM) <= 0 ) { ERR_print_errors_fp(stderr); exit(EXIT_FAILURE); } @@ -74,120 +72,23 @@ void configure_context(SSL_CTX *ctx) #endif -static int config_handler(void* conf, const char* section, const char* name, - const char* value) -{ - config_t* pconfig = (config_t*)conf; - //char * ppath = NULL; - if (MATCH("SERVER", "port")) { - pconfig->port = atoi(value); - } else if (MATCH("SERVER", "plugins")) { - pconfig->plugins_dir = strdup(value); - } else if (MATCH("SERVER", "plugins_ext")) { - pconfig->plugins_ext = strdup(value); - } else if(MATCH("SERVER", "database")) { - pconfig->db_path = strdup(value); - } else if(MATCH("SERVER", "htdocs")) { - pconfig->htdocs = strdup(value); - } else if(MATCH("SERVER", "tmpdir")) { - pconfig->tmpdir = strdup(value); - } - else if(MATCH("SERVER", "maxcon")) { - pconfig->maxcon = atoi(value); - } - else if(MATCH("SERVER", "backlog")) { - pconfig->backlog = atoi(value); - } -#ifdef USE_OPENSSL - else if(MATCH("SERVER", "ssl.enable")) { - pconfig->usessl = atoi(value); - } - else if(MATCH("SERVER", "ssl.cert")) { - pconfig->sslcert = strdup(value); - } - else if(MATCH("SERVER", "ssl.key")) { - pconfig->sslkey = strdup(value); - } -#endif - else if (strcmp(section, "RULES") == 0) - { - list_put_s(&pconfig->rules, name); - list_put_s(&pconfig->rules, value); - } - else if (strcmp(section, "FILEHANDLER") == 0) - { - dput( pconfig->handlers, name ,strdup(value)); - } - else if(strcmp(section,"AUTOSTART")==0){ - // The server section must be added before the autostart section - // auto start plugin - plugin_load(value); - } else { - return 0; /* unknown section/name, error */ - } - return 1; -} -void init_file_system() -{ - struct stat st; - if (stat(server_config.plugins_dir, &st) == -1) - mkdir(server_config.plugins_dir, 0755); - if (stat(server_config.db_path, &st) == -1) - mkdir(server_config.db_path, 0755); - if (stat(server_config.htdocs, &st) == -1) - mkdir(server_config.htdocs, 0755); - if (stat(server_config.tmpdir, &st) == -1) - mkdir(server_config.tmpdir, 0755); - else - { - removeAll(server_config.tmpdir,0); - } - -} -void load_config(const char* file) -{ - server_config.port = 8888; - server_config.plugins_dir = "plugins/"; - server_config.plugins_ext = ".dylib"; - server_config.db_path = "databases/"; - server_config.htdocs = "htdocs"; - server_config.tmpdir = "tmp"; - server_config.backlog = 100; - server_config.rules = list_init(); - server_config.handlers = dict(); - server_config.maxcon = 1000; - server_config.connection = 0; -#ifdef USE_OPENSSL - server_config.usessl = 0; - server_config.sslcert = "cert.pem"; - server_config.sslkey = "key.pem"; -#endif - if (ini_parse(file, config_handler, &server_config) < 0) { - LOG("Can't load '%s'\n. Used defaut configuration", file); - } - else - { - LOG("Using configuration : %s\n", file); -#ifdef USE_OPENSSL - LOG("SSL enable %d\n", server_config.usessl); - LOG("SSL cert %s\n", server_config.sslcert); - LOG("SSL key %s\n", server_config.sslkey); -#endif - } - init_file_system(); -} void stop_serve(int dummy) { UNUSED(dummy); - LOG("Shuting down server \n"); + sigset_t mask; + sigemptyset(&mask); + //Blocks the SIG_IGN signal (by adding SIG_IGN to newMask) + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGPIPE); + sigaddset(&mask, SIGABRT); + sigprocmask(SIG_BLOCK, &mask, NULL); antd_scheduler_destroy(&scheduler); - list_free(&(server_config.rules)); - freedict(server_config.handlers); - LOG("Unclosed connection: %d\n", server_config.connection); - unload_all_plugin(); + unload_all_plugin(); + destroy_config(); #ifdef USE_OPENSSL SSL_CTX_free(ctx); #endif close(server_sock); + sigprocmask(SIG_UNBLOCK, &mask, NULL); } int main(int argc, char* argv[]) { @@ -196,7 +97,7 @@ int main(int argc, char* argv[]) load_config(CONFIG); else load_config(argv[1]); - unsigned port = server_config.port; + unsigned port = config()->port; int client_sock = -1; struct sockaddr_in client_name; socklen_t client_name_len = sizeof(client_name); @@ -208,7 +109,7 @@ int main(int argc, char* argv[]) signal(SIGINT, stop_serve); #ifdef USE_OPENSSL - if( server_config.usessl == 1 ) + if( config()->usessl == 1 ) { init_openssl(); ctx = create_context(); @@ -217,12 +118,11 @@ int main(int argc, char* argv[]) } #endif - server_sock = startup(&port); LOG("httpd running on port %d\n", port); // default to 4 workers - antd_scheduler_init(&scheduler, 4); - fcntl(server_sock, F_SETFL, O_NONBLOCK); + antd_scheduler_init(&scheduler, config()->n_workers); + set_nonblock(server_sock); while (scheduler.status) { antd_task_schedule(&scheduler); @@ -233,6 +133,9 @@ int main(int argc, char* argv[]) continue; } antd_client_t* client = (antd_client_t*)malloc(sizeof(antd_client_t)); + antd_request_t* request = (antd_request_t*)malloc(sizeof(*request)); + request->client = client; + request->request = dict(); /* get the remote IP */ @@ -242,27 +145,29 @@ int main(int argc, char* argv[]) client_ip = inet_ntoa(client_name.sin_addr); client->ip = strdup(client_ip); LOG("Client IP: %s\n", client_ip); + LOG("socket: %d\n", client_sock); } //return &(((struct sockaddr_in6*)sa)->sin6_addr); /* accept_request(client_sock); */ // set timeout to socket - struct timeval timeout; - timeout.tv_sec = 20; - timeout.tv_usec = 0; + set_nonblock(client_sock); + /*struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 5000; if (setsockopt (client_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout)) < 0) perror("setsockopt failed\n"); if (setsockopt (client_sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,sizeof(timeout)) < 0) perror("setsockopt failed\n"); - + */ client->sock = client_sock; - server_config.connection++; - //LOG("Unclosed connection: %d\n", server_config.connection); + // 100 times retry connection before abort + //LOG("Unclosed connection: %d\n", server_config->connection); #ifdef USE_OPENSSL client->ssl = NULL; - if(server_config.usessl == 1) + if(config()->usessl == 1) { client->ssl = (void*)SSL_new(ctx); if(!client->ssl) continue; @@ -276,7 +181,7 @@ int main(int argc, char* argv[]) } #endif // create callback for the server - antd_add_task(&scheduler, antd_create_task(accept_request,(void*)client, finish_request )); + antd_add_task(&scheduler, antd_create_task(accept_request,(void*)request, finish_request )); /*if (pthread_create(&newthread , NULL,(void *(*)(void *))accept_request, (void *)client) != 0) { perror("pthread_create"); diff --git a/libs/dictionary.c b/libs/dictionary.c index a77dcb1..89e54c0 100644 --- a/libs/dictionary.c +++ b/libs/dictionary.c @@ -52,18 +52,25 @@ association __put_el_with_key(dictionary dic, const char* key) if(dic == NULL) return NULL; if ((np = dlookup(dic,key)) == NULL) { /* not found */ np = (association) malloc(sizeof(*np)); + np->value = NULL; if (np == NULL || (np->key = strdup(key)) == NULL) return NULL; hashval = hash(key, DHASHSIZE); np->next = dic[hashval]; dic[hashval] = np; } + // found return np; } association dput(dictionary dic,const char* key, void* value) { association np = __put_el_with_key(dic,key); - if(np == NULL) return NULL; + if(np == NULL) + { + if(value) free(value); + return NULL; + } + if(np->value && value) free(np->value); np->value = value; return np; } diff --git a/libs/dictionary.h b/libs/dictionary.h index 1675df4..752001a 100644 --- a/libs/dictionary.h +++ b/libs/dictionary.h @@ -46,6 +46,5 @@ void* dvalue(dictionary, const char*); association dput(dictionary,const char*, void*); int dremove(dictionary, const char*); void freedict(dictionary); -void stest(const char* ); #endif \ No newline at end of file diff --git a/libs/handle.c b/libs/handle.c index ac61708..eea6f16 100644 --- a/libs/handle.c +++ b/libs/handle.c @@ -1,5 +1,4 @@ -#include "handle.h" -config_t server_config; +#include "handle.h" #ifdef USE_OPENSSL int usessl() { @@ -133,10 +132,7 @@ int antd_close(void* src) #endif //printf("Close sock %d\n", source->sock); int ret = close(source->sock); - if(source->ip) free(source->ip); - // TODO remove this when using nonblocking - server_config.connection--; - LOG("Remaining connection %d\n", server_config.connection); + if(source->ip) free(source->ip); free(src); src = NULL; return ret; diff --git a/libs/handle.h b/libs/handle.h index 5aaf303..61da196 100644 --- a/libs/handle.h +++ b/libs/handle.h @@ -15,7 +15,7 @@ #include "list.h" #include "ini.h" -#define SERVER_NAME "antd" +#define SERVER_NAME "Antd" #define IS_POST(method) (strcmp(method,"POST")== 0) #define IS_GET(method) (strcmp(method,"GET")== 0) #define R_STR(d,k) ((char*)dvalue(d,k)) @@ -28,6 +28,18 @@ #ifdef USE_OPENSSL int __attribute__((weak)) usessl(); #endif +//extern config_t server_config; +typedef struct{ + int sock; + void* ssl; + char* ip; +} antd_client_t; + +typedef struct { + antd_client_t* client; + dictionary request; +} antd_request_t; + typedef struct { int port; @@ -41,23 +53,13 @@ typedef struct { int backlog; int maxcon; int connection; + int n_workers; #ifdef USE_OPENSSL int usessl; char* sslcert; char* sslkey; #endif }config_t; -//extern config_t server_config; -typedef struct{ - int sock; - void* ssl; - char* ip; -} antd_client_t; - -typedef struct { - antd_client_t* client; - dictionary request; -} antd_request_t; int response(void*, const char*); void ctype(void*,const char*); diff --git a/libs/plugin.c b/libs/plugin.c index b804861..31799c0 100644 --- a/libs/plugin.c +++ b/libs/plugin.c @@ -1,6 +1,6 @@ #include "plugin.h" -plugin_header __plugin__; +plugin_header_t __plugin__; // private function void __init_plugin__(const char* pl,config_t* conf){ __plugin__.name = strdup(pl); @@ -40,7 +40,10 @@ int usessl() return __plugin__.usessl; } #endif*/ - +plugin_header_t* meta() +{ + return &__plugin__; +} char* route(const char* repath) { int len = strlen(__plugin__.name) + 2; @@ -74,8 +77,9 @@ char* config_dir() return path; } -void __release() +void __release__() { + destroy(); printf("Releasing plugin\n"); if(__plugin__.name) free(__plugin__.name); if(__plugin__.dbpath) free(__plugin__.dbpath); diff --git a/libs/plugin.h b/libs/plugin.h index 8f5ac48..468dad0 100644 --- a/libs/plugin.h +++ b/libs/plugin.h @@ -5,6 +5,7 @@ #include "dbhelper.h" #endif #include "ws.h" +#include "scheduler.h" typedef struct { char *name; @@ -15,7 +16,7 @@ typedef struct { #ifdef USE_OPENSSL int usessl; #endif -} plugin_header; +} plugin_header_t; @@ -23,17 +24,6 @@ typedef struct { #ifdef USE_DB typedef sqlite3* sqldb; #endif -/* -Two server, -Two configuration different -Does it work -Replace this by a accessing function -that execute the set value to -the header, instead of -exporting global variables -*/ -extern plugin_header __plugin__; -//extern call __init__; #ifdef USE_DB @@ -47,6 +37,7 @@ char* config_dir(); /*Default function for plugin*/ // init the plugin void init(); -void handle(void*, const char*,const char*,dictionary); -void __release(); +void destroy(); +void* handle(void*); +plugin_header_t* meta(); #endif diff --git a/libs/scheduler.c b/libs/scheduler.c index 343fed7..0800231 100644 --- a/libs/scheduler.c +++ b/libs/scheduler.c @@ -165,6 +165,7 @@ void antd_scheduler_destroy(antd_scheduler_t* scheduler) { // free all the chains stop(scheduler); + LOG("Destroy remaining queue\n"); for(int i=0; i < N_PRIORITY; i++) { destroy_queue(scheduler->task_queue[i]); diff --git a/libs/utils.c b/libs/utils.c index 7ecef2b..aa34951 100644 --- a/libs/utils.c +++ b/libs/utils.c @@ -145,7 +145,11 @@ char* ext(const char* file) if(file == NULL) return NULL; char* str_cpy = strdup(file); char* str_org = str_cpy; - if(strstr(str_cpy,".")<= 0) return strdup(""); + if(strstr(str_cpy,".")<= 0) + { + free(str_org); + return NULL; + } if(*file == '.') trim(str_cpy,'.'); @@ -184,6 +188,7 @@ mime_t mime_from_type(const char* type) char* mime(const char* file) { char * ex = ext(file); + if(!ex) return "application/octet-stream"; mime_t m = mime_from_ext(ex); if(ex) free(ex); diff --git a/plugin_manager.c b/plugin_manager.c index 1c959b9..a6e2b57 100644 --- a/plugin_manager.c +++ b/plugin_manager.c @@ -31,10 +31,16 @@ struct plugin_entry *plugin_load(char *name) if ((np = plugin_lookup(name)) == NULL) { /* not found */ np = (struct plugin_entry *) malloc(sizeof(*np)); if (np == NULL || (np->pname = strdup(name)) == NULL) - return NULL; + { + if(np) free(np); + return NULL; + } if ((np->handle = plugin_from_file(name)) == NULL) + { + if(np) free(np); return NULL; - hashval = hash(name,HASHSIZE); + } + hashval = hash(name,HASHSIZE); np->next = plugin_table[hashval]; plugin_table[hashval] = np; } else /* already there */ @@ -53,7 +59,7 @@ void * plugin_from_file(char* name) { void *lib_handle; char* error; - char* path = __s("%s%s%s",server_config.plugins_dir,name,server_config.plugins_ext); + char* path = __s("%s%s%s",config()->plugins_dir,name,config()->plugins_ext); void (*fn)(const char*, config_t*); lib_handle = dlopen(path, RTLD_LAZY); if (!lib_handle) @@ -68,7 +74,7 @@ void * plugin_from_file(char* name) if ((error = dlerror()) != NULL) LOG("Problem when setting data path for %s : %s \n", name,error); else - (*fn)(name,&server_config); + (*fn)(name,config()); if(path) free(path); return lib_handle; @@ -79,17 +85,7 @@ void unload_plugin(struct plugin_entry* np) char* error; void (*fn)() = NULL; // find and execute the exit function - fn = (void (*)())dlsym(np->handle, "pexit"); - if ((error = dlerror()) != NULL) - { - LOG("Cant not find exit method from %s : %s \n", np->pname,error); - } - else - { - // execute it - (*fn)(); - } - fn = (void(*)()) dlsym(np->handle, "__release"); + fn = (void(*)()) dlsym(np->handle, "__release__"); if ((error = dlerror()) != NULL) { LOG("Cant not release plugin %s : %s \n", np->pname,error); diff --git a/plugin_manager.h b/plugin_manager.h index 466464f..cd88530 100644 --- a/plugin_manager.h +++ b/plugin_manager.h @@ -3,13 +3,12 @@ #include #include "libs/utils.h" #include "libs/handle.h" - +#include "http_server.h" struct plugin_entry { struct plugin_entry *next; char *pname; void *handle; }; -extern config_t server_config; /* lookup: look for s in hashtab */ struct plugin_entry *plugin_lookup(char *s); /* install: put (name, defn) in hashtab */