diff --git a/antd-config.ini b/antd-config.ini index 817ad5b..0f8ad95 100644 --- a/antd-config.ini +++ b/antd-config.ini @@ -9,8 +9,6 @@ plugins=/opt/www/lib/ plugins_ext=.so ; SQLITE database path database=/opt/www/database/ -; Website store here -htdocs=/opt/www/htdocs ; tmp dir tmpdir=/opt/www/tmp/ ; server log @@ -19,13 +17,35 @@ server_log = /var/log/antd.log error_log = /var/log/antd_error.log ; server backlocg backlog=5000 -; eable or disalbe SSL -ssl.enable=0 -; if SSL is enable, one should specify +; number of workers +workers = 4 +; if SSL is enable on one port, one should specify ; the SSL cert and key files -; ssl.cert=fullchain.pem -; ssl.key=privkey.pem -; ssl.cipher=ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256 +;Example: self signed key +; openssl genrsa -des3 -passout pass:1234 -out keypair.key 2048 +; openssl rsa -passin pass:1234 -in keypair.key -out server.key +; openssl req -new -key server.key -out server.csr +; openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt +ssl.cert=/opt/www/server.crt +ssl.key=/opt/www/server.key +ssl.cipher=ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256 + +; a configuration each port + +[PORT:443] +; Website store here +htdocs=/opt/www/htdocs +; enable or disalbe SSL +ssl.enable=1 + + +[PORT:80] +; Website store here +htdocs=/opt/www/htdocs +; enable or disalbe SSL +ssl.enable=0 + + ; This enable some plugins to be initialised at server startup [AUTOSTART] ; to start a plugin at server statup use: diff --git a/http_server.c b/http_server.c index f6d718e..30a188d 100644 --- a/http_server.c +++ b/http_server.c @@ -82,8 +82,6 @@ void destroy_config() 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); if(server_config.ssl_cipher) @@ -100,19 +98,35 @@ void destroy_config() #endif if(server_config.mimes) freedict(server_config.mimes); + if(server_config.ports) + { + chain_t it; + port_config_t* cnf; + for_each_assoc(it, server_config.ports) + { + cnf = (port_config_t*)it->value; + if(cnf && cnf->htdocs) + free(cnf->htdocs); + if(cnf->sock > 0) + { + close(cnf->sock); + } + } + freedict(server_config.ports); + } LOG("Unclosed connection: %d", server_config.connection); } static int config_handler(void *conf, const char *section, const char *name, - const char *value) + const char *value) { config_t *pconfig = (config_t *)conf; + regmatch_t port_matches[2]; + //trim(section, ' '); + //trim(value,' '); + //trim(name,' '); //char * ppath = NULL; - if (MATCH("SERVER", "port")) - { - pconfig->port = atoi(value); - } - else if (MATCH("SERVER", "plugins")) + if (MATCH("SERVER", "plugins")) { pconfig->plugins_dir = strdup(value); } @@ -124,10 +138,6 @@ static int config_handler(void *conf, const char *section, const char *name, { pconfig->db_path = strdup(value); } - else if (MATCH("SERVER", "htdocs")) - { - pconfig->htdocs = strdup(value); - } else if (MATCH("SERVER", "tmpdir")) { pconfig->tmpdir = strdup(value); @@ -155,10 +165,6 @@ static int config_handler(void *conf, const char *section, const char *name, } #endif #ifdef USE_OPENSSL - else if (MATCH("SERVER", "ssl.enable")) - { - pconfig->usessl = atoi(value); - } else if (MATCH("SERVER", "ssl.cert")) { pconfig->sslcert = strdup(value); @@ -191,6 +197,31 @@ static int config_handler(void *conf, const char *section, const char *name, { dput(pconfig->mimes,name,strdup(value)); } + else if( regex_match("PORT:\\s*([0-9]+)", section, 2, port_matches) ) + { + char buf[20]; + memset(buf, '\0', sizeof(buf)); + memcpy(buf, section + port_matches[1].rm_so, port_matches[1].rm_eo - port_matches[1].rm_so); + port_config_t* p = dvalue(pconfig->ports,buf); + if(!p) + { + p = (port_config_t*) malloc( sizeof(port_config_t)); + p->htdocs = NULL; + p->sock = -1; + dput(pconfig->ports,buf, p); + p->port = atoi(buf); + } + if(strcmp(name, "htdocs") == 0) + { + p->htdocs = strdup(value); + } + else if(strcmp(name, "ssl.enable") == 0) + { + p->usessl = atoi(value); + if(p->usessl) + pconfig->enable_ssl = 1; + } + } else { return 0; /* unknown section/name, error */ @@ -200,14 +231,23 @@ static int config_handler(void *conf, const char *section, const char *name, void init_file_system() { struct stat st; + port_config_t* pcnf; + chain_t it; if (stat(server_config.plugins_dir, &st) == -1) - mkdir(server_config.plugins_dir, 0755); + mkdirp(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); + mkdirp(server_config.db_path, 0755); + for_each_assoc(it, server_config.ports) + { + pcnf = (port_config_t*) it->value; + if (stat(pcnf->htdocs, &st) == -1) + { + mkdirp(pcnf->htdocs, 0755); + } + + } if (stat(server_config.tmpdir, &st) == -1) - mkdir(server_config.tmpdir, 0755); + mkdirp(server_config.tmpdir, 0755); else { removeAll(server_config.tmpdir, 0); @@ -215,22 +255,22 @@ void init_file_system() } void load_config(const char *file) { - server_config.port = 8888; + server_config.ports = dict(); server_config.plugins_dir = "plugins/"; server_config.plugins_ext = ".dylib"; server_config.db_path = "databases/"; - server_config.htdocs = "htdocs/"; + //server_config.htdocs = "htdocs/"; server_config.tmpdir = "tmp/"; server_config.n_workers = 4; - server_config.backlog = 100; + server_config.backlog = 1000; server_config.rules = list_init(); server_config.handlers = dict(); - server_config.maxcon = 1000; + server_config.maxcon = 100; server_config.connection = 0; server_config.errorfp = NULL; server_config.logfp = NULL; server_config.mimes = dict(); - server_config.usessl = 0; + server_config.enable_ssl = 0; server_config.sslcert = "cert.pem"; server_config.sslkey = "key.pem"; server_config.ssl_cipher = NULL; @@ -247,7 +287,7 @@ void load_config(const char *file) { LOG("Using configuration : %s", file); #ifdef USE_OPENSSL - LOG("SSL enable %d", server_config.usessl); + LOG("SSL enable %d", server_config.enable_ssl); LOG("SSL cert %s", server_config.sslcert); LOG("SSL key %s", server_config.sslkey); /*if(!server_config.ssl_cipher) @@ -257,6 +297,7 @@ void load_config(const char *file) #endif } LOG("%d mimes entries found", server_config.mimes->size); + init_file_system(); } void *accept_request(void *data) @@ -303,7 +344,7 @@ void *accept_request(void *data) // perform the ssl handshake if enabled #ifdef USE_OPENSSL int ret = -1, stat; - if (server_config.usessl == 1 && client->status == 0) + if (client->port_config->usessl == 1 && client->status == 0) { //LOG("Atttempt %d\n", client->attempt); if (SSL_accept((SSL *)client->ssl) == -1) @@ -327,10 +368,10 @@ void *accept_request(void *data) task->handle = accept_request; return task; default: - ERROR("Error performing SSL handshake %d %d %lu", stat, ret, ERR_get_error()); + ERROR("Error performing SSL handshake %d %d %s", stat, ret, ERR_error_string(ERR_get_error(), NULL)); + antd_error(rq->client, 400, "Invalid SSL request"); //server_config.connection++; ERR_print_errors_fp(stderr); - antd_error(rq->client, 400, "Invalid SSL request"); return task; } } @@ -405,7 +446,7 @@ void *resolve_request(void *data) char *newurl = NULL; char *rqp = NULL; char *oldrqp = NULL; - strcpy(path, server_config.htdocs); + strcpy(path, rq->client->port_config->htdocs); strcat(path, url); //LOG("Path is : %s", path); //if (path[strlen(path) - 1] == '/') @@ -438,7 +479,7 @@ void *resolve_request(void *data) { newurl = __s("%s/index.%s", url, it->key); memset(path, 0, sizeof(path)); - strcat(path, server_config.htdocs); + strcat(path, rq->client->port_config->htdocs); strcat(path, newurl); if (stat(path, &st) != 0) { @@ -578,11 +619,6 @@ int rule_check(const char *k, const char *v, const char *host, const char *_url, return 1; } -static void error_die(const char *sc) -{ - perror(sc); - exit(1); -} void *serve_file(void *data) { antd_request_t *rq = (antd_request_t *)data; @@ -626,23 +662,35 @@ int startup(unsigned *port) httpd = socket(PF_INET, SOCK_STREAM, 0); if (httpd == -1) - error_die("socket"); + { + ERROR("Port %d - socket: %s", *port, strerror(errno)); + return -1; + } memset(&name, 0, sizeof(name)); name.sin_family = AF_INET; name.sin_port = htons(*port); name.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0) - error_die("bind"); + { + ERROR("Port %d -bind: %s", *port, strerror(errno)); + return -1; + } if (*port == 0) /* if dynamically allocating a port */ { socklen_t namelen = sizeof(name); if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -1) - error_die("getsockname"); + { + ERROR("Port %d - getsockname: %s", *port, strerror(errno)); + return -1; + } *port = ntohs(name.sin_port); } - //LOG("back log is %d", server_config.backlog); + LOG("back log is %d", server_config.backlog); if (listen(httpd, server_config.backlog) < 0) - error_die("listen"); + { + ERROR("Port %d - listen: %s", *port, strerror(errno)); + return -1; + } return (httpd); } @@ -703,7 +751,7 @@ void *decode_request_header(void *data) // this for check if web socket is enabled // ip address dput(xheader, "REMOTE_ADDR", (void *)strdup(((antd_client_t *)rq->client)->ip)); - dput(xheader, "SERVER_PORT", (void *)__s("%d", server_config.port)); + dput(xheader, "SERVER_PORT", (void *)__s("%d", ((antd_client_t *)rq->client)->port_config->port)); //while((line = read_line(client)) && strcmp("\r\n",line)) while ((read_buf(rq->client, buf, sizeof(buf))) && strcmp("\r\n", buf)) { @@ -728,9 +776,9 @@ void *decode_request_header(void *data) //if(line) free(line); memset(buf, 0, sizeof(buf)); strcat(buf, url); - //LOG("Original query: %s", url); + LOG("Original query: %s", url); query = apply_rules(host, buf); - //LOG("Processed query: %s", query); + LOG("Processed query: %s", query); dput(rq->request, "RESOURCE_PATH", url_decode(buf)); if (query) { @@ -1242,13 +1290,6 @@ void *execute_plugin(void *data, const char *pname) return task; } -#ifdef USE_OPENSSL -int usessl() -{ - return server_config.usessl; -} -#endif - dictionary_t mimes_list() { return server_config.mimes; diff --git a/http_server.h b/http_server.h index 134bff4..29c91cc 100644 --- a/http_server.h +++ b/http_server.h @@ -27,11 +27,8 @@ void* finish_request(void*); void cat(void*, FILE *); void cannot_execute(void*); //int get_line(int, char *, int); -void not_found(void*); void* serve_file(void*); int startup(unsigned *); -void unimplemented(void*); -void badrequest(void*); int rule_check(const char*, const char*, const char* , const char* , const char* , char*); void ws_confirm_request(void*, const char*); char* post_url_decode(void* client,int len); diff --git a/httpd.c b/httpd.c index d5d4f5b..4e3ab5b 100644 --- a/httpd.c +++ b/httpd.c @@ -4,7 +4,6 @@ #include "lib/ini.h" static antd_scheduler_t scheduler; -static int server_sock = -1; #ifdef USE_OPENSSL @@ -63,23 +62,26 @@ void configure_context(SSL_CTX *ctx) LOG("Cirpher suit used: %s", suit); if (SSL_CTX_set_cipher_list(ctx, suit) != 1) { + ERROR("Fail to set ssl cirpher suit: %s", suit); ERR_print_errors_fp(stderr); exit(EXIT_FAILURE); } /* Set the key and cert */ /* use the full chain bundle of certificate */ //if (SSL_CTX_use_certificate_file(ctx, server_config->sslcert, SSL_FILETYPE_PEM) <= 0) { - if (SSL_CTX_use_certificate_chain_file(ctx, config()->sslcert) <= 0) { + if (SSL_CTX_use_certificate_chain_file(ctx, cnf->sslcert) <= 0) { + ERROR("Fail to read SSL certificate chain file: %s", cnf->sslcert); ERR_print_errors_fp(stderr); exit(EXIT_FAILURE); } - if (SSL_CTX_use_PrivateKey_file(ctx, config()->sslkey, SSL_FILETYPE_PEM) <= 0 ) { + if (SSL_CTX_use_PrivateKey_file(ctx, cnf->sslkey, SSL_FILETYPE_PEM) <= 0 ) { + ERROR("Fail to read SSL private file: %s", cnf->sslkey); ERR_print_errors_fp(stderr); exit(EXIT_FAILURE); } if (!SSL_CTX_check_private_key(ctx)) { - ERROR("Failed to validate cert"); + ERROR("Failed to validate SSL certificate"); ERR_print_errors_fp(stderr); exit(EXIT_FAILURE); } @@ -111,8 +113,6 @@ void stop_serve(int dummy) { // DEPRECATED: ERR_remove_state(0); ERR_free_strings(); #endif - if(server_sock != -1) - close(server_sock); destroy_config(); sigprocmask(SIG_UNBLOCK, &mask, NULL); } @@ -124,7 +124,6 @@ int main(int argc, char* argv[]) load_config(CONFIG_FILE); else load_config(argv[1]); - unsigned port = config()->port; int client_sock = -1; struct sockaddr_in client_name; socklen_t client_name_len = sizeof(client_name); @@ -135,8 +134,10 @@ int main(int argc, char* argv[]) signal(SIGABRT, SIG_IGN); signal(SIGINT, stop_serve); + config_t* conf = config(); + #ifdef USE_OPENSSL - if( config()->usessl == 1 ) + if( conf->enable_ssl == 1 ) { init_openssl(); ctx = create_context(); @@ -145,10 +146,36 @@ int main(int argc, char* argv[]) } #endif - server_sock = startup(&port); - LOG("httpd running on port %d", port); + // startup port + chain_t it; + port_config_t * pcnf; + int nlisten = 0; + for_each_assoc(it, conf->ports) + { + pcnf = (port_config_t*)it->value; + if(pcnf) + { + pcnf->sock = startup(&pcnf->port); + if(pcnf->sock>0) + { + nlisten++; + set_nonblock(pcnf->sock); + LOG("Listening on port %d", pcnf->port); + } + else + { + ERROR("Port %d is disabled", pcnf->port); + } + } + } + if(nlisten == 0) + { + ERROR("No port is listenned, quit!!"); + stop_serve(0); + exit(1); + } // default to 4 workers - antd_scheduler_init(&scheduler, config()->n_workers); + antd_scheduler_init(&scheduler, conf->n_workers); scheduler.validate_data = 1; scheduler.destroy_data = finish_request; // use blocking server_sock @@ -169,69 +196,99 @@ int main(int argc, char* argv[]) pthread_detach(scheduler_th); } antd_task_t* task = NULL; + + fd_set read_flags, write_flags; + // first verify if the socket is ready + struct timeval timeout; + // select + while (scheduler.status) { - client_sock = accept(server_sock,(struct sockaddr *)&client_name,&client_name_len); - if (client_sock == -1) + if(conf->connection > conf->maxcon) { + //ERROR("Reach max connection %d", conf->connection); + timeout.tv_sec = 0; + timeout.tv_usec = 5000; // 5 ms + select(0, NULL, NULL, NULL, &timeout); continue; } - // just dump the scheduler when we have a connection - 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 - */ - client->ip = NULL; - if (client_name.sin_family == AF_INET) + for_each_assoc(it, conf->ports) { - client_ip = inet_ntoa(client_name.sin_addr); - client->ip = strdup(client_ip); - LOG("Client IP: %s", client_ip); - //LOG("socket: %d\n", client_sock); + pcnf = (port_config_t*) it->value; + if(pcnf->sock > 0) + { + FD_ZERO(&read_flags); + FD_SET(pcnf->sock, &read_flags); + FD_ZERO(&write_flags); + FD_SET(pcnf->sock, &write_flags); + timeout.tv_sec = 0; + timeout.tv_usec = 5000; // 5 ms + int sel = select(pcnf->sock + 1, &read_flags, &write_flags, (fd_set *)0, &timeout); + if(sel > 0 && (FD_ISSET(pcnf->sock, &read_flags) || FD_ISSET(pcnf->sock, &write_flags))) + { + client_sock = accept(pcnf->sock,(struct sockaddr *)&client_name,&client_name_len); + if (client_sock > 0) + { + // just dump the scheduler when we have a connection + 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(); + client->port_config = pcnf; + /* + get the remote IP + */ + client->ip = NULL; + if (client_name.sin_family == AF_INET) + { + client_ip = inet_ntoa(client_name.sin_addr); + client->ip = strdup(client_ip); + LOG("Connect to client IP: %s on port:%d", client_ip, pcnf->port); + //LOG("socket: %d\n", client_sock); + } + + // set timeout to socket + set_nonblock(client_sock); + /*struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 5000; + + if (setsockopt (client_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout)) < 0) + perror("setsockopt failed\n"); + + if (setsockopt (client_sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,sizeof(timeout)) < 0) + perror("setsockopt failed\n"); + */ + client->sock = client_sock; + time(&client->last_io); + #ifdef USE_OPENSSL + client->ssl = NULL; + client->status = 0; + if(pcnf->usessl == 1) + { + client->ssl = (void*)SSL_new(ctx); + if(!client->ssl) continue; + SSL_set_fd((SSL*)client->ssl, client->sock); + + /*if (SSL_accept((SSL*)client->ssl) <= 0) { + LOG("EROOR accept\n"); + ERR_print_errors_fp(stderr); + antd_close(client); + continue; + }*/ + } + #endif + conf->connection++; + // create callback for the server + task = antd_create_task(accept_request,(void*)request, finish_request, client->last_io); + //task->type = LIGHT; + antd_add_task(&scheduler, task); + } + } + } } - - // set timeout to socket - set_nonblock(client_sock); - /*struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 5000; - - if (setsockopt (client_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout)) < 0) - perror("setsockopt failed\n"); - - if (setsockopt (client_sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,sizeof(timeout)) < 0) - perror("setsockopt failed\n"); - */ - client->sock = client_sock; - time(&client->last_io); -#ifdef USE_OPENSSL - client->ssl = NULL; - client->status = 0; - if(config()->usessl == 1) - { - client->ssl = (void*)SSL_new(ctx); - if(!client->ssl) continue; - SSL_set_fd((SSL*)client->ssl, client->sock); - - /*if (SSL_accept((SSL*)client->ssl) <= 0) { - LOG("EROOR accept\n"); - ERR_print_errors_fp(stderr); - antd_close(client); - continue; - }*/ - } -#endif - config()->connection++; - // create callback for the server - task = antd_create_task(accept_request,(void*)request, finish_request, client->last_io); - //task->type = LIGHT; - antd_add_task(&scheduler, task); } - close(server_sock); - + stop_serve(0); return(0); } diff --git a/lib/handle.c b/lib/handle.c index c7a3255..922fb87 100644 --- a/lib/handle.c +++ b/lib/handle.c @@ -1,6 +1,5 @@ #include "handle.h" #define HTML_TPL "