From 9c25e62c0a6f1a60e03e188e218fe71e8d5aceb7 Mon Sep 17 00:00:00 2001 From: DanyLE Date: Mon, 11 Mar 2024 22:35:35 +0100 Subject: [PATCH] feat(v2.0.0): Improvement + add IPv6 support - fix: scheduler causes segmentfault when exiting the server - Add support for IPv6 protocol --- configure.ac | 2 +- http_server.c | 70 ++++++++++++++++++++++++++++++++++++++++--------- http_server.h | 2 +- httpd.c | 23 +++++++++++----- lib/handle.h | 7 +++++ lib/scheduler.c | 47 +++++++++++++++++++-------------- 6 files changed, 111 insertions(+), 40 deletions(-) diff --git a/configure.ac b/configure.ac index acea77d..4425697 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ # initialise autoconf and set up some basic information about the program we’re packaging -AC_INIT([antd], [1.0.6b], [xsang.le@gmail.com]) +AC_INIT([antd], [2.0.0], [xsang.le@gmail.com]) # We’re going to use automake for this project AM_INIT_AUTOMAKE([subdir-objects]) diff --git a/http_server.c b/http_server.c index 43d99b8..361371a 100644 --- a/http_server.c +++ b/http_server.c @@ -31,6 +31,13 @@ #define HEADER_MAX_SIZE 8192 +typedef union +{ + struct sockaddr_in6 addr6; + struct sockaddr_in addr4; +} antd_server_sockaddr_t; + + // define all basic mime here static mime_t _mimes[] = { {"image/bmp", "bmp"}, @@ -52,6 +59,7 @@ static mime_t _mimes[] = { static pthread_mutex_t server_mux = PTHREAD_MUTEX_INITIALIZER; config_t server_config; + config_t *config() { return &server_config; @@ -259,6 +267,7 @@ static int config_handler(void *conf, const char *section, const char *name, p->htdocs = NULL; p->plugins = NULL; p->sock = -1; + p->type = ANTD_PROTO_ALL; p->rules = dict_n(1); dput(pconfig->ports, buf, p); p->port = atoi(buf); @@ -290,6 +299,21 @@ static int config_handler(void *conf, const char *section, const char *name, if (p->usessl) pconfig->enable_ssl = 1; } + else if(strcmp(name, "protocol") == 0) + { + if(strcmp(value, "ipv4") == 0) + { + p->type = ANTD_PROTO_IP_4; + } + else if(strcmp(value, "ipv6") == 0) + { + p->type = ANTD_PROTO_IP_6; + } + else + { + ERROR("Unknown IP protocol setting %s. Enable both.", value); + } + } else { // other thing should be rules @@ -366,7 +390,7 @@ void load_config(const char *file) server_config.db_path = strdup("databases/"); // server_config.htdocs = "htdocs/"; server_config.tmpdir = strdup("/tmp/"); - server_config.stat_fifo_path = strdup("/var/run/antd_stat"); + server_config.stat_fifo_path = strdup(""); server_config.n_workers = 4; server_config.backlog = 1000; server_config.handlers = dict(); @@ -792,27 +816,42 @@ void *serve_file(void *data) return task; } -int startup(unsigned *port) +int startup(unsigned *port, int ipv6) { int httpd = 0; - struct sockaddr_in name; - httpd = socket(PF_INET, SOCK_STREAM, 0); + antd_server_sockaddr_t name; + memset(&name, 0, sizeof(name)); + struct sockaddr *ptr; + // TODO: allow to set listen address + if(ipv6) + { + name.addr6.sin6_port = htons(*port); + name.addr6.sin6_family = AF_INET6; + name.addr6.sin6_addr = in6addr_any; + httpd = socket(AF_INET6, SOCK_STREAM, 0); + ptr = (struct sockaddr *) & name.addr6; + } + else + { + name.addr4.sin_port = htons(*port); + name.addr4.sin_family = AF_INET; + name.addr4.sin_addr.s_addr = htonl(INADDR_ANY); + httpd = socket(AF_INET, SOCK_STREAM, 0); + ptr = (struct sockaddr *) & name.addr4; + } + if (httpd == -1) { ERROR("Port %d - socket: %s", *port, strerror(errno)); return -1; } - + if (setsockopt(httpd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) == -1) { ERROR("Unable to set reuse address on port %d - setsockopt: %s", *port, strerror(errno)); } - 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) + if (bind(httpd, ptr, sizeof(name)) < 0) { ERROR("Port %d -bind: %s", *port, strerror(errno)); return -1; @@ -825,15 +864,22 @@ int startup(unsigned *port) ERROR("Port %d - getsockname: %s", *port, strerror(errno)); return -1; } - *port = ntohs(name.sin_port); + if(ipv6) + { + *port = ntohs(name.addr6.sin6_port); + } + else + { + *port = ntohs(name.addr4.sin_port); + } } - LOG("back log is %d", server_config.backlog); if (listen(httpd, server_config.backlog) < 0) { ERROR("Port %d - listen: %s", *port, strerror(errno)); return -1; } + LOG("%s Listen on port %d", ipv6?"IPv6":"IPv4", *port ); return (httpd); } diff --git a/http_server.h b/http_server.h index 0a85968..948031c 100644 --- a/http_server.h +++ b/http_server.h @@ -21,7 +21,7 @@ void cat(void *, FILE *); void cannot_execute(void *); //int get_line(int, char *, int); void *serve_file(void *); -int startup(unsigned *); +int startup(unsigned *, int); 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 35d31de..ec5f34f 100644 --- a/httpd.c +++ b/httpd.c @@ -165,7 +165,7 @@ static void stop_serve(int dummy) sigprocmask(SIG_UNBLOCK, &mask, NULL); } -static void antd_monitor(port_config_t *pcnf) +static void antd_monitor(port_config_t *pcnf, int sock) { antd_task_t *task = NULL; int client_sock = -1; @@ -173,9 +173,9 @@ static void antd_monitor(port_config_t *pcnf) socklen_t client_name_len = sizeof(client_name); char *client_ip = NULL; config_t *conf = config(); - if (pcnf->sock > 0) + if (sock > 0) { - client_sock = accept(pcnf->sock, (struct sockaddr *)&client_name, &client_name_len); + client_sock = accept(sock, (struct sockaddr *)&client_name, &client_name_len); if (client_sock > 0) { // just dump the scheduler when we have a connection @@ -332,6 +332,9 @@ int main(int argc, char *argv[]) int status, maxfd = 0; int nlisten = 0; // load the config first +#ifdef VERSION + LOG("Antd server version: " VERSION); +#endif if (argc == 1) load_config(CONFIG_FILE); else @@ -379,12 +382,18 @@ int main(int argc, char *argv[]) pcnf = (port_config_t *)it->value; if (pcnf) { - pcnf->sock = startup(&pcnf->port); + if(pcnf->type == ANTD_PROTO_IP_4) + { + pcnf->sock = startup(&pcnf->port,0); + } + else + { + pcnf->sock = startup(&pcnf->port,1); + } if (pcnf->sock > 0) { set_nonblock(pcnf->sock); FD_SET(pcnf->sock, &master_set); - LOG("Listening on port %d", pcnf->port); maxfd = pcnf->sock > maxfd ? pcnf->sock : maxfd; nlisten++; } @@ -396,7 +405,7 @@ int main(int argc, char *argv[]) } if (nlisten == 0) { - ERROR("No port is listenned, quit!!"); + ERROR("No port is listened, quit!!"); stop_serve(0); exit(1); } @@ -441,7 +450,7 @@ int main(int argc, char *argv[]) pcnf = (port_config_t *)it->value; if (pcnf && pcnf->sock > 0 && FD_ISSET(pcnf->sock, &working_set)) { - antd_monitor(pcnf); + antd_monitor(pcnf, pcnf->sock); } } } diff --git a/lib/handle.h b/lib/handle.h index 9094b75..c06af1f 100644 --- a/lib/handle.h +++ b/lib/handle.h @@ -40,6 +40,12 @@ typedef enum ANTD_CNONE } antd_compress_t; +typedef enum { + ANTD_PROTO_IP_4, + ANTD_PROTO_IP_6, + ANTD_PROTO_ALL +} antd_proto_t; + //extern config_t server_config; typedef struct @@ -49,6 +55,7 @@ typedef struct char *htdocs; char* plugins; int sock; + antd_proto_t type; dictionary_t rules; } port_config_t; diff --git a/lib/scheduler.c b/lib/scheduler.c index 0cc2c47..28853ec 100644 --- a/lib/scheduler.c +++ b/lib/scheduler.c @@ -12,7 +12,7 @@ #include "bst.h" #define MAX_VALIDITY_INTERVAL 30 -#define MAX_FIFO_NAME_SZ 255 +#define MAX_NAME_SZ 255 // callback definition struct _antd_callback_t @@ -70,7 +70,9 @@ struct _antd_scheduler_t int n_workers; int pending_task; int id_allocator; - char stat_fifo[MAX_FIFO_NAME_SZ]; + char stat_fifo[MAX_NAME_SZ]; + char sched_name[MAX_NAME_SZ]; + char worker_hub[MAX_NAME_SZ]; int stat_fd; pthread_t stat_tid; }; @@ -122,13 +124,14 @@ static void stop(antd_scheduler_t *scheduler) pthread_join(scheduler->workers[i].tid, NULL); if (scheduler->workers) free(scheduler->workers); - (void)pthread_cancel(scheduler->stat_tid); + if(scheduler->stat_tid) + (void)pthread_cancel(scheduler->stat_tid); // destroy all the mutex pthread_mutex_destroy(&scheduler->scheduler_lock); pthread_mutex_destroy(&scheduler->worker_lock); pthread_mutex_destroy(&scheduler->pending_lock); - sem_unlink("scheduler"); - sem_unlink("worker"); + sem_unlink(scheduler->sched_name); + sem_unlink(scheduler->worker_hub); sem_close(scheduler->scheduler_sem); sem_close(scheduler->worker_sem); } @@ -257,25 +260,25 @@ static void antd_task_dump(int fd, antd_task_t* task, char* buffer) } int ret; // send statistic on task data - snprintf(buffer, MAX_FIFO_NAME_SZ, "---- Task %d created at: %lu ----\n", task->id, task->stamp); + snprintf(buffer, MAX_NAME_SZ, "---- Task %d created at: %lu ----\n", task->id, task->stamp); ret = write(fd, buffer, strlen(buffer)); // send statistic on task data - snprintf(buffer, MAX_FIFO_NAME_SZ, "Access time: %lu\nn", (unsigned long)task->access_time); + snprintf(buffer, MAX_NAME_SZ, "Access time: %lu\nn", (unsigned long)task->access_time); ret = write(fd, buffer, strlen(buffer)); - snprintf(buffer, MAX_FIFO_NAME_SZ, "Current time: %lu\n", (unsigned long)time(NULL)); + snprintf(buffer, MAX_NAME_SZ, "Current time: %lu\n", (unsigned long)time(NULL)); ret = write(fd, buffer, strlen(buffer)); if (task->handle) { - snprintf(buffer, MAX_FIFO_NAME_SZ, "Has handle: yes\n"); + snprintf(buffer, MAX_NAME_SZ, "Has handle: yes\n"); ret = write(fd, buffer, strlen(buffer)); } if (task->callback) { - snprintf(buffer, MAX_FIFO_NAME_SZ, "Has callback: yes\n"); + snprintf(buffer, MAX_NAME_SZ, "Has callback: yes\n"); ret = write(fd, buffer, strlen(buffer)); } UNUSED(ret); @@ -297,7 +300,7 @@ static void *statistic(antd_scheduler_t *scheduler) { struct pollfd pfd; int ret; - char buffer[MAX_FIFO_NAME_SZ]; + char buffer[MAX_NAME_SZ]; void *argc[2]; while (scheduler->status) { @@ -336,7 +339,7 @@ static void *statistic(antd_scheduler_t *scheduler) { pthread_mutex_lock(&scheduler->scheduler_lock); // write statistic data - snprintf(buffer, MAX_FIFO_NAME_SZ, "Pending task: %d. Detail:\n", scheduler->pending_task); + snprintf(buffer, MAX_NAME_SZ, "Pending task: %d. Detail:\n", scheduler->pending_task); ret = write(scheduler->stat_fd, buffer, strlen(buffer)); bst_for_each(scheduler->task_queue, print_static_info, argc, 2); @@ -346,7 +349,7 @@ static void *statistic(antd_scheduler_t *scheduler) // write worker current task for (int i = 0; i < scheduler->n_workers; i++) { - snprintf(buffer, MAX_FIFO_NAME_SZ, "Worker: %d. Detail:\n", i); + snprintf(buffer, MAX_NAME_SZ, "Worker: %d. Detail:\n", i); ret = write(scheduler->stat_fd, buffer, strlen(buffer)); if(scheduler->workers[i].current_task) { @@ -407,20 +410,25 @@ antd_scheduler_t *antd_scheduler_init(int n, const char *stat_name) scheduler->pending_task = 0; scheduler->stat_fd = -1; scheduler->id_allocator = 0; - (void)memset(scheduler->stat_fifo, 0, MAX_FIFO_NAME_SZ); + scheduler->stat_tid = 0; + int pid = getpid(); + snprintf(scheduler->sched_name,MAX_NAME_SZ, "scheduler.%d",pid); + snprintf(scheduler->worker_hub,MAX_NAME_SZ, "worker.%d",pid); + (void)memset(scheduler->stat_fifo, 0, MAX_NAME_SZ); if (stat_name) { - (void)strncpy(scheduler->stat_fifo, stat_name, MAX_FIFO_NAME_SZ - 1); + (void)strncpy(scheduler->stat_fifo, stat_name, MAX_NAME_SZ - 1); } // init semaphore - scheduler->scheduler_sem = sem_open("scheduler", O_CREAT, 0600, 0); + + scheduler->scheduler_sem = sem_open(scheduler->sched_name, O_CREAT, 0644, 0); if (scheduler->scheduler_sem == SEM_FAILED) { - ERROR("Cannot open semaphore for scheduler"); + ERROR("Cannot open semaphore for scheduler: %s", strerror(errno)); free(scheduler); return NULL; } - scheduler->worker_sem = sem_open("worker", O_CREAT, 0600, 0); + scheduler->worker_sem = sem_open(scheduler->worker_hub, O_CREAT, 0600, 0); if (!scheduler->worker_sem) { ERROR("Cannot open semaphore for workers"); @@ -467,13 +475,14 @@ antd_scheduler_t *antd_scheduler_init(int n, const char *stat_name) // create the fifo file if (mkfifo(scheduler->stat_fifo, 0666) == -1) { - ERROR("Unable to create statictis FIFO %s: %s", scheduler->stat_fifo, strerror(errno)); + ERROR("Unable to create statistic FIFO %s: %s", scheduler->stat_fifo, strerror(errno)); } else { if (pthread_create(&scheduler->stat_tid, NULL, (void *(*)(void *))statistic, scheduler) != 0) { ERROR("pthread_create: cannot create statistic thread: %s", strerror(errno)); + scheduler->stat_tid = 0; } } }