fix memory leak on the new non blocking system

This commit is contained in:
lxsang 2018-10-05 19:01:39 +02:00
parent 5477f54f60
commit 89e3d7a3f0
13 changed files with 461 additions and 398 deletions

View File

@ -1,52 +1,202 @@
#include "http_server.h" #include "http_server.h"
static pthread_mutex_t server_mux = PTHREAD_MUTEX_INITIALIZER; 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; int count;
char buf[BUFFLEN]; char buf[BUFFLEN];
antd_request_t* request;
antd_task_t* task;
char* token = NULL; char* token = NULL;
char* line = NULL; char* line = NULL;
request = (antd_request_t*)malloc(sizeof(*request)); antd_task_t* task;
request->client = client; antd_request_t* rq = (antd_request_t*) data;
request->request = dict();
count = read_buf(client, buf, sizeof(buf)); task = antd_create_task(NULL,(void*)rq,NULL);
task = antd_create_task(NULL,(void*)request,NULL);
task->priority++; 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; 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; line = buf;
// get the method string // get the method string
token = strsep(&line," "); token = strsep(&line," ");
if(!line) if(!line)
{ {
unknow(client); LOG("No method found\n");
unknow(rq->client);
return task; return task;
} }
trim(token,' '); trim(token,' ');
trim(line,' '); trim(line,' ');
dput(request->request, "METHOD", strdup(token)); dput(rq->request, "METHOD", strdup(token));
// get the request // get the request
token = strsep(&line, " "); token = strsep(&line, " ");
if(!line) if(!line)
{ {
unknow(client); LOG("No request found\n");
unknow(rq->client);
return task; return task;
} }
trim(token,' '); trim(token,' ');
trim(line,' '); trim(line,' ');
trim(line, '\n'); trim(line, '\n');
trim(line, '\r'); trim(line, '\r');
dput(request->request, "PROTOCOL", strdup(line)); dput(rq->request, "PROTOCOL", strdup(line));
dput(request->request, "REQUEST_QUERY", strdup(token)); dput(rq->request, "REQUEST_QUERY", strdup(token));
line = token; line = token;
token = strsep(&line, "?"); token = strsep(&line, "?");
dput(request->request, "REQUEST_PATH", strdup(token)); dput(rq->request, "REQUEST_PATH", strdup(token));
// decode request // decode request
// now return the task // now return the task
task->handle = decode_request_header; task->handle = decode_request_header;
@ -69,9 +219,6 @@ void* resolve_request(void* data)
//if (path[strlen(path) - 1] == '/') //if (path[strlen(path) - 1] == '/')
// strcat(path, "index.html"); // strcat(path, "index.html");
if (stat(path, &st) == -1) { if (stat(path, &st) == -1) {
//if(execute_plugin(rq->client,rqp,method,rq) < 0)
// not_found(client);
LOG("execute plugin \n");
free(task); free(task);
return execute_plugin(rq, rqp); return execute_plugin(rq, rqp);
} }
@ -149,9 +296,23 @@ void* finish_request(void* data)
LOG("Close request\n"); LOG("Close request\n");
antd_request_t* rq = (antd_request_t*)data; antd_request_t* rq = (antd_request_t*)data;
// free all other thing // 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); antd_close(rq->client);
free(rq); free(rq);
server_config.connection--;
LOG("Remaining connection %d\n", server_config.connection);
return NULL; return NULL;
} }
@ -225,12 +386,8 @@ int rule_check(const char*k, const char* v, const char* host, const char* _url,
free(query); free(query);
return 1; return 1;
} }
/**********************************************************************/
/* Print out an error message with perror() (for system errors; based static void error_die(const char *sc)
* on value of errno, which indicates system call errors) and exit the
* program indicating an error. */
/**********************************************************************/
void error_die(const char *sc)
{ {
perror(sc); perror(sc);
exit(1); exit(1);
@ -251,14 +408,6 @@ void* serve_file(void* data)
return task; 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 startup(unsigned *port)
{ {
int httpd = 0; int httpd = 0;
@ -322,15 +471,7 @@ char* apply_rules(const char* host, char*url)
return strdup(query_string); return strdup(query_string);
} }
/** /**
* Decode the HTTP request * Decode the HTTP request header
* 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
*/ */
void* decode_request_header(void* data) void* decode_request_header(void* data)
@ -375,7 +516,6 @@ void* decode_request_header(void* data)
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
strcat(buf,url); strcat(buf,url);
query = apply_rules(host, buf); query = apply_rules(host, buf);
LOG("BUGFGGGG is %s\n", buf);
dput(rq->request,"RESOURCE_PATH",strdup(buf)); dput(rq->request,"RESOURCE_PATH",strdup(buf));
if(query) if(query)
{ {
@ -384,7 +524,7 @@ void* decode_request_header(void* data)
free(query); free(query);
} }
if(cookie) if(cookie)
dput(request,"cookie",cookie); dput(rq->request,"COOKIE",cookie);
if(host) free(host); if(host) free(host);
// header ok, now checkmethod // header ok, now checkmethod
antd_task_t* task = antd_create_task(decode_request,(void*)rq, NULL); antd_task_t* task = antd_create_task(decode_request,(void*)rq, NULL);
@ -451,6 +591,7 @@ void* decode_post_request(void* data)
if(tmp) if(tmp)
clen = atoi(tmp); clen = atoi(tmp);
task = antd_create_task(NULL,(void*)rq, NULL); task = antd_create_task(NULL,(void*)rq, NULL);
task->priority++;
if(ctype == NULL || clen == -1) if(ctype == NULL || clen == -1)
{ {
LOG("Bad request\n"); LOG("Bad request\n");
@ -468,7 +609,8 @@ void* decode_post_request(void* data)
{ {
//printf("Multi part form : %s\n", ctype); //printf("Multi part form : %s\n", ctype);
// TODO: split this to multiple task // 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 else
{ {
@ -545,193 +687,207 @@ dictionary decode_cookie(const char* line)
token1 = strsep(&token,"="); token1 = strsep(&token,"=");
if(token1 && token && strlen(token) > 0) if(token1 && token && strlen(token) > 0)
{ {
if(dic == NULL) if(dic == NULL) dic = dict();
dic = dict(); LOG("%s: %s\n", token1, token);
dput(dic,token1,strdup(token)); dput(dic,token1,strdup(token));
} }
} }
//}
free(orgcpy); free(orgcpy);
return dic; return dic;
} }
/** /**
* Decode the multi-part form data from the POST request * Decode the multi-part form data from the POST request
* If it is a file upload, copy the file to tmp dir * 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 * boundary;
char * boundend;
char * line; char * line;
char * orgline;
char * str_copy = strdup(ctype); char * str_copy = strdup(ctype);
char* orgcpy = str_copy; char* orgcpy = str_copy;
char* token; antd_request_t* rq = (antd_request_t*) data;
char* keytoken ; antd_task_t* task = antd_create_task(NULL, (void*)rq, NULL);
char* valtoken ; task->priority++;
char* part_name; //dictionary dic = NULL;
char* part_file; 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* file_path;
char buf[BUFFLEN]; char buf[BUFFLEN];
char* field; char* field;
//dictionary dic = NULL; //dictionary dic = NULL;
FILE *fp = NULL; FILE *fp = NULL;
boundary = strsep(&str_copy,"="); //discard first part char* token, *keytoken, *valtoken;
boundary = strsep(&str_copy,"="); antd_request_t* rq = (antd_request_t*) data;
if(boundary && strlen(boundary)>0) 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(); free(line);
trim(boundary,' '); line = NULL;
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(orgcpy); if(!line || strstr(line,"Content-Disposition:") <= 0)
//return dic; {
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 * Decode a query string (GET request or POST URL encoded) to

View File

@ -7,6 +7,8 @@
#include <pthread.h> #include <pthread.h>
#include <signal.h> #include <signal.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/select.h>
#include <fcntl.h>
#include "libs/handle.h" #include "libs/handle.h"
#include "libs/scheduler.h" #include "libs/scheduler.h"
#include "plugin_manager.h" #include "plugin_manager.h"
@ -15,17 +17,16 @@
#define FORM_MULTI_PART "multipart/form-data" #define FORM_MULTI_PART "multipart/form-data"
#define PLUGIN_HANDLER "handle" #define PLUGIN_HANDLER "handle"
#define WS_MAGIC_STRING "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" #define WS_MAGIC_STRING "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
#define SERVER_STRING "Server: ant-httpd"
#define CONFIG "config.ini" #define CONFIG "config.ini"
extern config_t server_config;
config_t* config();
void destroy_config();
void* accept_request(void*); void* accept_request(void*);
void* finish_request(void*); void* finish_request(void*);
void cat(void*, FILE *); void cat(void*, FILE *);
void cannot_execute(void*); void cannot_execute(void*);
void error_die(const char *);
//int get_line(int, char *, int); //int get_line(int, char *, int);
void not_found(void*); void not_found(void*);
void* serve_file(void*); void* serve_file(void*);
@ -40,10 +41,11 @@ void* decode_request_header(void* data);
void* decode_request(void* data); void* decode_request(void* data);
void* decode_post_request(void* data); void* decode_post_request(void* data);
void* resolve_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*); dictionary decode_cookie(const char*);
char* post_data_decode(void*,int); char* post_data_decode(void*,int);
void set_nonblock(int);
void* execute_plugin(void* data, const char *path); void* execute_plugin(void* data, const char *path);
#endif #endif

157
httpd.c
View File

@ -2,11 +2,9 @@
#include <dirent.h> #include <dirent.h>
#include "http_server.h" #include "http_server.h"
#include "libs/ini.h" #include "libs/ini.h"
#include <fcntl.h>
static antd_scheduler_t scheduler; 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 #ifdef USE_OPENSSL
static int ssl_session_ctx_id = 1; static int ssl_session_ctx_id = 1;
SSL_CTX *ctx; 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)); SSL_CTX_set_session_id_context(ctx, (void *)&ssl_session_ctx_id, sizeof(ssl_session_ctx_id));
/* Set the key and cert */ /* Set the key and cert */
/* use the full chain bundle of certificate */ /* 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_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_chain_file(ctx, config()->sslcert) <= 0) {
ERR_print_errors_fp(stderr); ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE); 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); ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -74,120 +72,23 @@ void configure_context(SSL_CTX *ctx)
#endif #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) { void stop_serve(int dummy) {
UNUSED(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); antd_scheduler_destroy(&scheduler);
list_free(&(server_config.rules)); unload_all_plugin();
freedict(server_config.handlers); destroy_config();
LOG("Unclosed connection: %d\n", server_config.connection);
unload_all_plugin();
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
SSL_CTX_free(ctx); SSL_CTX_free(ctx);
#endif #endif
close(server_sock); close(server_sock);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
} }
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
@ -196,7 +97,7 @@ int main(int argc, char* argv[])
load_config(CONFIG); load_config(CONFIG);
else else
load_config(argv[1]); load_config(argv[1]);
unsigned port = server_config.port; unsigned port = config()->port;
int client_sock = -1; int client_sock = -1;
struct sockaddr_in client_name; struct sockaddr_in client_name;
socklen_t client_name_len = sizeof(client_name); socklen_t client_name_len = sizeof(client_name);
@ -208,7 +109,7 @@ int main(int argc, char* argv[])
signal(SIGINT, stop_serve); signal(SIGINT, stop_serve);
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
if( server_config.usessl == 1 ) if( config()->usessl == 1 )
{ {
init_openssl(); init_openssl();
ctx = create_context(); ctx = create_context();
@ -217,12 +118,11 @@ int main(int argc, char* argv[])
} }
#endif #endif
server_sock = startup(&port); server_sock = startup(&port);
LOG("httpd running on port %d\n", port); LOG("httpd running on port %d\n", port);
// default to 4 workers // default to 4 workers
antd_scheduler_init(&scheduler, 4); antd_scheduler_init(&scheduler, config()->n_workers);
fcntl(server_sock, F_SETFL, O_NONBLOCK); set_nonblock(server_sock);
while (scheduler.status) while (scheduler.status)
{ {
antd_task_schedule(&scheduler); antd_task_schedule(&scheduler);
@ -233,6 +133,9 @@ int main(int argc, char* argv[])
continue; continue;
} }
antd_client_t* client = (antd_client_t*)malloc(sizeof(antd_client_t)); 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 get the remote IP
*/ */
@ -242,27 +145,29 @@ int main(int argc, char* argv[])
client_ip = inet_ntoa(client_name.sin_addr); client_ip = inet_ntoa(client_name.sin_addr);
client->ip = strdup(client_ip); client->ip = strdup(client_ip);
LOG("Client IP: %s\n", client_ip); LOG("Client IP: %s\n", client_ip);
LOG("socket: %d\n", client_sock);
} }
//return &(((struct sockaddr_in6*)sa)->sin6_addr); //return &(((struct sockaddr_in6*)sa)->sin6_addr);
/* accept_request(client_sock); */ /* accept_request(client_sock); */
// set timeout to socket // set timeout to socket
struct timeval timeout; set_nonblock(client_sock);
timeout.tv_sec = 20; /*struct timeval timeout;
timeout.tv_usec = 0; timeout.tv_sec = 0;
timeout.tv_usec = 5000;
if (setsockopt (client_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout)) < 0) if (setsockopt (client_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout)) < 0)
perror("setsockopt failed\n"); perror("setsockopt failed\n");
if (setsockopt (client_sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,sizeof(timeout)) < 0) if (setsockopt (client_sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,sizeof(timeout)) < 0)
perror("setsockopt failed\n"); perror("setsockopt failed\n");
*/
client->sock = client_sock; client->sock = client_sock;
server_config.connection++; // 100 times retry connection before abort
//LOG("Unclosed connection: %d\n", server_config.connection); //LOG("Unclosed connection: %d\n", server_config->connection);
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
client->ssl = NULL; client->ssl = NULL;
if(server_config.usessl == 1) if(config()->usessl == 1)
{ {
client->ssl = (void*)SSL_new(ctx); client->ssl = (void*)SSL_new(ctx);
if(!client->ssl) continue; if(!client->ssl) continue;
@ -276,7 +181,7 @@ int main(int argc, char* argv[])
} }
#endif #endif
// create callback for the server // 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) /*if (pthread_create(&newthread , NULL,(void *(*)(void *))accept_request, (void *)client) != 0)
{ {
perror("pthread_create"); perror("pthread_create");

View File

@ -52,18 +52,25 @@ association __put_el_with_key(dictionary dic, const char* key)
if(dic == NULL) return NULL; if(dic == NULL) return NULL;
if ((np = dlookup(dic,key)) == NULL) { /* not found */ if ((np = dlookup(dic,key)) == NULL) { /* not found */
np = (association) malloc(sizeof(*np)); np = (association) malloc(sizeof(*np));
np->value = NULL;
if (np == NULL || (np->key = strdup(key)) == NULL) if (np == NULL || (np->key = strdup(key)) == NULL)
return NULL; return NULL;
hashval = hash(key, DHASHSIZE); hashval = hash(key, DHASHSIZE);
np->next = dic[hashval]; np->next = dic[hashval];
dic[hashval] = np; dic[hashval] = np;
} }
// found
return np; return np;
} }
association dput(dictionary dic,const char* key, void* value) association dput(dictionary dic,const char* key, void* value)
{ {
association np = __put_el_with_key(dic,key); 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; np->value = value;
return np; return np;
} }

View File

@ -46,6 +46,5 @@ void* dvalue(dictionary, const char*);
association dput(dictionary,const char*, void*); association dput(dictionary,const char*, void*);
int dremove(dictionary, const char*); int dremove(dictionary, const char*);
void freedict(dictionary); void freedict(dictionary);
void stest(const char* );
#endif #endif

View File

@ -1,5 +1,4 @@
#include "handle.h" #include "handle.h"
config_t server_config;
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
int usessl() int usessl()
{ {
@ -133,10 +132,7 @@ int antd_close(void* src)
#endif #endif
//printf("Close sock %d\n", source->sock); //printf("Close sock %d\n", source->sock);
int ret = close(source->sock); int ret = close(source->sock);
if(source->ip) free(source->ip); if(source->ip) free(source->ip);
// TODO remove this when using nonblocking
server_config.connection--;
LOG("Remaining connection %d\n", server_config.connection);
free(src); free(src);
src = NULL; src = NULL;
return ret; return ret;

View File

@ -15,7 +15,7 @@
#include "list.h" #include "list.h"
#include "ini.h" #include "ini.h"
#define SERVER_NAME "antd" #define SERVER_NAME "Antd"
#define IS_POST(method) (strcmp(method,"POST")== 0) #define IS_POST(method) (strcmp(method,"POST")== 0)
#define IS_GET(method) (strcmp(method,"GET")== 0) #define IS_GET(method) (strcmp(method,"GET")== 0)
#define R_STR(d,k) ((char*)dvalue(d,k)) #define R_STR(d,k) ((char*)dvalue(d,k))
@ -28,6 +28,18 @@
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
int __attribute__((weak)) usessl(); int __attribute__((weak)) usessl();
#endif #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 { typedef struct {
int port; int port;
@ -41,23 +53,13 @@ typedef struct {
int backlog; int backlog;
int maxcon; int maxcon;
int connection; int connection;
int n_workers;
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
int usessl; int usessl;
char* sslcert; char* sslcert;
char* sslkey; char* sslkey;
#endif #endif
}config_t; }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*); int response(void*, const char*);
void ctype(void*,const char*); void ctype(void*,const char*);

View File

@ -1,6 +1,6 @@
#include "plugin.h" #include "plugin.h"
plugin_header __plugin__; plugin_header_t __plugin__;
// private function // private function
void __init_plugin__(const char* pl,config_t* conf){ void __init_plugin__(const char* pl,config_t* conf){
__plugin__.name = strdup(pl); __plugin__.name = strdup(pl);
@ -40,7 +40,10 @@ int usessl()
return __plugin__.usessl; return __plugin__.usessl;
} }
#endif*/ #endif*/
plugin_header_t* meta()
{
return &__plugin__;
}
char* route(const char* repath) char* route(const char* repath)
{ {
int len = strlen(__plugin__.name) + 2; int len = strlen(__plugin__.name) + 2;
@ -74,8 +77,9 @@ char* config_dir()
return path; return path;
} }
void __release() void __release__()
{ {
destroy();
printf("Releasing plugin\n"); printf("Releasing plugin\n");
if(__plugin__.name) free(__plugin__.name); if(__plugin__.name) free(__plugin__.name);
if(__plugin__.dbpath) free(__plugin__.dbpath); if(__plugin__.dbpath) free(__plugin__.dbpath);

View File

@ -5,6 +5,7 @@
#include "dbhelper.h" #include "dbhelper.h"
#endif #endif
#include "ws.h" #include "ws.h"
#include "scheduler.h"
typedef struct { typedef struct {
char *name; char *name;
@ -15,7 +16,7 @@ typedef struct {
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
int usessl; int usessl;
#endif #endif
} plugin_header; } plugin_header_t;
@ -23,17 +24,6 @@ typedef struct {
#ifdef USE_DB #ifdef USE_DB
typedef sqlite3* sqldb; typedef sqlite3* sqldb;
#endif #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 #ifdef USE_DB
@ -47,6 +37,7 @@ char* config_dir();
/*Default function for plugin*/ /*Default function for plugin*/
// init the plugin // init the plugin
void init(); void init();
void handle(void*, const char*,const char*,dictionary); void destroy();
void __release(); void* handle(void*);
plugin_header_t* meta();
#endif #endif

View File

@ -165,6 +165,7 @@ void antd_scheduler_destroy(antd_scheduler_t* scheduler)
{ {
// free all the chains // free all the chains
stop(scheduler); stop(scheduler);
LOG("Destroy remaining queue\n");
for(int i=0; i < N_PRIORITY; i++) for(int i=0; i < N_PRIORITY; i++)
{ {
destroy_queue(scheduler->task_queue[i]); destroy_queue(scheduler->task_queue[i]);

View File

@ -145,7 +145,11 @@ char* ext(const char* file)
if(file == NULL) return NULL; if(file == NULL) return NULL;
char* str_cpy = strdup(file); char* str_cpy = strdup(file);
char* str_org = str_cpy; char* str_org = str_cpy;
if(strstr(str_cpy,".")<= 0) return strdup(""); if(strstr(str_cpy,".")<= 0)
{
free(str_org);
return NULL;
}
if(*file == '.') if(*file == '.')
trim(str_cpy,'.'); trim(str_cpy,'.');
@ -184,6 +188,7 @@ mime_t mime_from_type(const char* type)
char* mime(const char* file) char* mime(const char* file)
{ {
char * ex = ext(file); char * ex = ext(file);
if(!ex) return "application/octet-stream";
mime_t m = mime_from_ext(ex); mime_t m = mime_from_ext(ex);
if(ex) if(ex)
free(ex); free(ex);

View File

@ -31,10 +31,16 @@ struct plugin_entry *plugin_load(char *name)
if ((np = plugin_lookup(name)) == NULL) { /* not found */ if ((np = plugin_lookup(name)) == NULL) { /* not found */
np = (struct plugin_entry *) malloc(sizeof(*np)); np = (struct plugin_entry *) malloc(sizeof(*np));
if (np == NULL || (np->pname = strdup(name)) == NULL) 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->handle = plugin_from_file(name)) == NULL)
{
if(np) free(np);
return NULL; return NULL;
hashval = hash(name,HASHSIZE); }
hashval = hash(name,HASHSIZE);
np->next = plugin_table[hashval]; np->next = plugin_table[hashval];
plugin_table[hashval] = np; plugin_table[hashval] = np;
} else /* already there */ } else /* already there */
@ -53,7 +59,7 @@ void * plugin_from_file(char* name)
{ {
void *lib_handle; void *lib_handle;
char* error; 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*); void (*fn)(const char*, config_t*);
lib_handle = dlopen(path, RTLD_LAZY); lib_handle = dlopen(path, RTLD_LAZY);
if (!lib_handle) if (!lib_handle)
@ -68,7 +74,7 @@ void * plugin_from_file(char* name)
if ((error = dlerror()) != NULL) if ((error = dlerror()) != NULL)
LOG("Problem when setting data path for %s : %s \n", name,error); LOG("Problem when setting data path for %s : %s \n", name,error);
else else
(*fn)(name,&server_config); (*fn)(name,config());
if(path) if(path)
free(path); free(path);
return lib_handle; return lib_handle;
@ -79,17 +85,7 @@ void unload_plugin(struct plugin_entry* np)
char* error; char* error;
void (*fn)() = NULL; void (*fn)() = NULL;
// find and execute the exit function // find and execute the exit function
fn = (void (*)())dlsym(np->handle, "pexit"); fn = (void(*)()) dlsym(np->handle, "__release__");
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");
if ((error = dlerror()) != NULL) if ((error = dlerror()) != NULL)
{ {
LOG("Cant not release plugin %s : %s \n", np->pname,error); LOG("Cant not release plugin %s : %s \n", np->pname,error);

View File

@ -3,13 +3,12 @@
#include <dlfcn.h> #include <dlfcn.h>
#include "libs/utils.h" #include "libs/utils.h"
#include "libs/handle.h" #include "libs/handle.h"
#include "http_server.h"
struct plugin_entry { struct plugin_entry {
struct plugin_entry *next; struct plugin_entry *next;
char *pname; char *pname;
void *handle; void *handle;
}; };
extern config_t server_config;
/* lookup: look for s in hashtab */ /* lookup: look for s in hashtab */
struct plugin_entry *plugin_lookup(char *s); struct plugin_entry *plugin_lookup(char *s);
/* install: put (name, defn) in hashtab */ /* install: put (name, defn) in hashtab */