mirror of
https://github.com/lxsang/ant-http
synced 2024-12-26 16:58:22 +01:00
fix memory leak on the new non blocking system
This commit is contained in:
parent
5477f54f60
commit
89e3d7a3f0
578
http_server.c
578
http_server.c
@ -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
|
||||||
|
@ -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
157
httpd.c
@ -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");
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
@ -1,5 +1,4 @@
|
|||||||
#include "handle.h"
|
#include "handle.h"
|
||||||
config_t server_config;
|
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
int usessl()
|
int usessl()
|
||||||
{
|
{
|
||||||
@ -134,9 +133,6 @@ int antd_close(void* src)
|
|||||||
//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;
|
||||||
|
@ -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*);
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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]);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user