diff --git a/doxygen-awesome-css b/doxygen-awesome-css deleted file mode 160000 index 9760c30..0000000 --- a/doxygen-awesome-css +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9760c30014131f4eacb8e96f15f3869c7bc5dd8c diff --git a/include/server/server.h b/include/server/server.h index 33feda1..ba8c947 100644 --- a/include/server/server.h +++ b/include/server/server.h @@ -6,6 +6,8 @@ #include #include "utils/config.h" +#include "utils/utils.h" +#include "worker.h" /* Clients max queue */ #define CWS_SERVER_BACKLOG 128 @@ -17,38 +19,26 @@ #define CWS_SERVER_MAX_REQUEST_SIZE (16 * 1024) /* 16KB */ +#define CWS_WORKERS_NUM 6 + /* Main server loop */ extern volatile sig_atomic_t cws_server_run; -typedef enum cws_server_ret { - CWS_SERVER_OK, - CWS_SERVER_CONFIG, - CWS_SERVER_FD_ERROR, - CWS_SERVER_CLIENT_NOT_FOUND, - CWS_SERVER_CLIENT_DISCONNECTED, - CWS_SERVER_CLIENT_DISCONNECTED_ERROR, - CWS_SERVER_HTTP_PARSE_ERROR, - CWS_SERVER_GETADDRINFO_ERROR, - CWS_SERVER_SOCKET_ERROR, - CWS_SERVER_SETSOCKOPT_ERROR, - CWS_SERVER_BIND_ERROR, - CWS_SERVER_LISTEN_ERROR, - CWS_SERVER_EPOLL_ADD_ERROR, - CWS_SERVER_EPOLL_DEL_ERROR, - CWS_SERVER_FD_NONBLOCKING_ERROR, - CWS_SERVER_ACCEPT_CLIENT_ERROR, - CWS_SERVER_HASHMAP_INIT, - CWS_SERVER_MALLOC_ERROR, - CWS_SERVER_REQUEST_TOO_LARGE, - CWS_SERVER_THREADPOOL_ERROR, - CWS_SERVER_EPOLL_CREATE_ERROR, - CWS_SERVER_WORKER_ERROR, -} cws_server_ret; +typedef struct cws_server { + int epfd; + int sockfd; + cws_worker_s **workers; + cws_config_s *config; +} cws_server_s; + +cws_server_ret cws_server_setup(cws_config_s *config, cws_server_s *server); + +cws_server_ret cws_server_loop(cws_server_s *server); + +void cws_server_shutdown(cws_server_s *server); + +int cws_server_handle_new_client(int server_fd); -cws_server_ret cws_server_start(cws_config_s *config); -cws_server_ret cws_server_loop(int server_fd, cws_config_s *config); -int cws_server_handle_new_client(int server_fd, hashmap_s *clients); int cws_server_accept_client(int server_fd, struct sockaddr_storage *their_sa, socklen_t *theirsa_size); -cws_server_ret cws_fd_set_nonblocking(int sockfd); #endif diff --git a/include/server/worker.h b/include/server/worker.h index 028172b..836f353 100644 --- a/include/server/worker.h +++ b/include/server/worker.h @@ -3,25 +3,33 @@ #include #include +#include -#include "server/server.h" +#include "../utils/config.h" +#include "../utils/utils.h" + +extern volatile sig_atomic_t cws_server_run; typedef struct cws_worker { int epfd; int pipefd[2]; size_t clients_num; pthread_t thread; - hashmap_s *clients; cws_config_s *config; } cws_worker_s; -cws_worker_s **cws_worker_init(size_t workers_num, hashmap_s *clients, cws_config_s *config); +cws_worker_s **cws_worker_new(size_t workers_num, cws_config_s *config); + void cws_worker_free(cws_worker_s **workers, size_t workers_num); + void *cws_worker_loop(void *arg); -void cws_server_close_client(int epfd, int client_fd, hashmap_s *clients); +void cws_server_close_client(int epfd, int client_fd); + cws_server_ret cws_epoll_add(int epfd, int sockfd, uint32_t events); + cws_server_ret cws_epoll_del(int epfd, int sockfd); -cws_server_ret cws_server_handle_client_data(int epfd, int client_fd, hashmap_s *clients, cws_config_s *config); + +cws_server_ret cws_server_handle_client_data(int epfd, int client_fd, cws_config_s *config); #endif diff --git a/include/utils/config.h b/include/utils/config.h index 0b30ad8..7b08faf 100644 --- a/include/utils/config.h +++ b/include/utils/config.h @@ -19,6 +19,7 @@ typedef struct cws_config { } cws_config_s; cws_config_s *cws_config_init(void); + void cws_config_free(cws_config_s *config); #endif diff --git a/include/utils/utils.h b/include/utils/utils.h index 845fc73..fdb015d 100644 --- a/include/utils/utils.h +++ b/include/utils/utils.h @@ -4,6 +4,33 @@ #include #include +typedef enum cws_server_ret { + CWS_SERVER_OK, + CWS_SERVER_CONFIG, + CWS_SERVER_FD_ERROR, + CWS_SERVER_CLIENT_NOT_FOUND, + CWS_SERVER_CLIENT_DISCONNECTED, + CWS_SERVER_CLIENT_DISCONNECTED_ERROR, + CWS_SERVER_HTTP_PARSE_ERROR, + CWS_SERVER_GETADDRINFO_ERROR, + CWS_SERVER_SOCKET_ERROR, + CWS_SERVER_SETSOCKOPT_ERROR, + CWS_SERVER_BIND_ERROR, + CWS_SERVER_LISTEN_ERROR, + CWS_SERVER_EPOLL_ADD_ERROR, + CWS_SERVER_EPOLL_DEL_ERROR, + CWS_SERVER_FD_NONBLOCKING_ERROR, + CWS_SERVER_ACCEPT_CLIENT_ERROR, + CWS_SERVER_HASHMAP_INIT, + CWS_SERVER_MALLOC_ERROR, + CWS_SERVER_REQUEST_TOO_LARGE, + CWS_SERVER_THREADPOOL_ERROR, + CWS_SERVER_EPOLL_CREATE_ERROR, + CWS_SERVER_WORKER_ERROR, +} cws_server_ret; + +cws_server_ret cws_fd_set_nonblocking(int sockfd); + void cws_utils_get_client_ip(struct sockaddr_storage *sa, char *ip); /* Functions used for hash maps */ diff --git a/src/main.c b/src/main.c index d94bf2b..2b221b0 100644 --- a/src/main.c +++ b/src/main.c @@ -28,13 +28,17 @@ int main(void) { CWS_LOG_DEBUG("%s (ssl: %d)", config->virtual_hosts[i].domain, config->virtual_hosts[i].ssl); } - CWS_LOG_INFO("Running cws on http://%s:%s...", config->hostname, config->port); - int ret = cws_server_start(config); - if (ret < 0) { - CWS_LOG_ERROR("Unable to start web server"); + cws_server_s server; + cws_server_ret ret = cws_server_setup(config, &server); + if (ret != CWS_SERVER_OK) { + CWS_LOG_ERROR("Unable to setup web server"); } + CWS_LOG_INFO("Running cws on http://%s:%s...", config->hostname, config->port); + ret = cws_server_loop(&server); + CWS_LOG_INFO("Shutting down cws..."); + cws_server_shutdown(&server); cws_config_free(config); return EXIT_SUCCESS; diff --git a/src/server/server.c b/src/server/server.c index a7e4c1b..00996ea 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -11,8 +11,6 @@ #include "utils/debug.h" #include "utils/utils.h" -volatile sig_atomic_t cws_server_run = 1; - static void cws_server_setup_hints(struct addrinfo *hints, const char *hostname) { memset(hints, 0, sizeof(struct addrinfo)); @@ -28,56 +26,6 @@ static void cws_server_setup_hints(struct addrinfo *hints, const char *hostname) } } -cws_server_ret cws_server_start(cws_config_s *config) { - if (!config || !config->hostname || !config->port) { - return CWS_SERVER_CONFIG; - } - - struct addrinfo hints; - struct addrinfo *res; - - cws_server_setup_hints(&hints, config->hostname); - - int status = getaddrinfo(config->hostname, config->port, &hints, &res); - if (status != 0) { - CWS_LOG_ERROR("getaddrinfo() error: %s", gai_strerror(status)); - return CWS_SERVER_GETADDRINFO_ERROR; - } - - int server_fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (server_fd < 0) { - CWS_LOG_ERROR("socket(): %s", strerror(errno)); - return CWS_SERVER_SOCKET_ERROR; - } - - const int opt = 1; - status = setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt); - if (status != 0) { - CWS_LOG_ERROR("setsockopt(): %s", strerror(errno)); - return CWS_SERVER_SETSOCKOPT_ERROR; - } - - status = bind(server_fd, res->ai_addr, res->ai_addrlen); - if (status != 0) { - CWS_LOG_ERROR("bind(): %s", strerror(errno)); - return CWS_SERVER_BIND_ERROR; - } - - status = listen(server_fd, CWS_SERVER_BACKLOG); - if (status != 0) { - CWS_LOG_ERROR("listen(): %s", strerror(errno)); - return CWS_SERVER_LISTEN_ERROR; - } - - cws_server_ret ret = cws_server_loop(server_fd, config); - CWS_LOG_DEBUG("cws_server_loop ret: %d", ret); - - freeaddrinfo(res); - close(server_fd); - - return CWS_SERVER_OK; -} - static cws_server_ret cws_server_setup_epoll(int server_fd, int *epfd_out) { int epfd = epoll_create1(0); if (epfd < 0) { @@ -96,34 +44,73 @@ static cws_server_ret cws_server_setup_epoll(int server_fd, int *epfd_out) { return CWS_SERVER_OK; } -cws_server_ret cws_server_loop(int server_fd, cws_config_s *config) { - int epfd = 0; - cws_server_ret ret; +cws_server_ret cws_server_setup(cws_config_s *config, cws_server_s *server) { + if (!config || !config->hostname || !config->port) { + return CWS_SERVER_CONFIG; + } - ret = cws_server_setup_epoll(server_fd, &epfd); + /* Setup basic stuff */ + struct addrinfo hints; + struct addrinfo *res; + + cws_server_setup_hints(&hints, config->hostname); + + int status = getaddrinfo(config->hostname, config->port, &hints, &res); + if (status != 0) { + CWS_LOG_ERROR("getaddrinfo() error: %s", gai_strerror(status)); + return CWS_SERVER_GETADDRINFO_ERROR; + } + + server->sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (server->sockfd < 0) { + CWS_LOG_ERROR("socket(): %s", strerror(errno)); + return CWS_SERVER_SOCKET_ERROR; + } + + const int opt = 1; + status = setsockopt(server->sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt); + if (status != 0) { + CWS_LOG_ERROR("setsockopt(): %s", strerror(errno)); + return CWS_SERVER_SETSOCKOPT_ERROR; + } + + status = bind(server->sockfd, res->ai_addr, res->ai_addrlen); + if (status != 0) { + CWS_LOG_ERROR("bind(): %s", strerror(errno)); + return CWS_SERVER_BIND_ERROR; + } + + status = listen(server->sockfd, CWS_SERVER_BACKLOG); + if (status != 0) { + CWS_LOG_ERROR("listen(): %s", strerror(errno)); + return CWS_SERVER_LISTEN_ERROR; + } + + freeaddrinfo(res); + + /* Setup epoll */ + cws_server_ret ret = cws_server_setup_epoll(server->sockfd, &server->epfd); if (ret != CWS_SERVER_OK) { return ret; } - hashmap_s *clients = hm_new(my_int_hash_fn, my_int_equal_fn, my_int_free_key_fn, my_str_free_fn, sizeof(int), sizeof(char) * INET_ADDRSTRLEN); - if (clients == NULL) { - return CWS_SERVER_HASHMAP_INIT; - } - - size_t workers_num = 6; - size_t workers_index = 0; - cws_worker_s **workers = cws_worker_init(workers_num, clients, config); + /* Setup workers */ + cws_worker_s **workers = cws_worker_new(CWS_WORKERS_NUM, config); if (workers == NULL) { - hm_free(clients); return CWS_SERVER_WORKER_ERROR; } + return CWS_SERVER_OK; +} + +cws_server_ret cws_server_loop(cws_server_s *server) { struct epoll_event events[128]; memset(events, 0, sizeof(events)); int client_fd = 0; + size_t workers_index = 0; while (cws_server_run) { - int nfds = epoll_wait(epfd, events, 128, -1); + int nfds = epoll_wait(server->epfd, events, 128, -1); if (nfds < 0) { continue; @@ -134,29 +121,23 @@ cws_server_ret cws_server_loop(int server_fd, cws_config_s *config) { } for (int i = 0; i < nfds; ++i) { - if (events[i].data.fd == server_fd) { - client_fd = cws_server_handle_new_client(server_fd, clients); + if (events[i].data.fd == server->sockfd) { + client_fd = cws_server_handle_new_client(server->sockfd); if (client_fd < 0) { continue; } /* Add client to worker */ - int random = 10; - hm_set(clients, &client_fd, &random); - write(workers[workers_index]->pipefd[1], &client_fd, sizeof(int)); - workers_index = (workers_index + 1) % workers_num; + write(server->workers[workers_index]->pipefd[1], &client_fd, sizeof(int)); + workers_index = (workers_index + 1) % CWS_WORKERS_NUM; } } } - close(epfd); - cws_worker_free(workers, workers_num); - hm_free(clients); - return CWS_SERVER_OK; } -int cws_server_handle_new_client(int server_fd, hashmap_s *clients) { +int cws_server_handle_new_client(int server_fd) { struct sockaddr_storage their_sa; socklen_t theirsa_size = sizeof their_sa; char ip[INET_ADDRSTRLEN]; @@ -184,13 +165,20 @@ int cws_server_accept_client(int server_fd, struct sockaddr_storage *their_sa, s return client_fd; } -cws_server_ret cws_fd_set_nonblocking(int sockfd) { - const int status = fcntl(sockfd, F_SETFL, O_NONBLOCK); - - if (status == -1) { - CWS_LOG_ERROR("fcntl(): %s", strerror(errno)); - return CWS_SERVER_FD_NONBLOCKING_ERROR; +void cws_server_shutdown(cws_server_s *server) { + if (!server) { + return; } - return CWS_SERVER_OK; + if (server->sockfd > 0) { + sock_close(server->sockfd); + } + + if (server->epfd > 0) { + sock_close(server->epfd); + } + + if (server->workers) { + cws_worker_free(server->workers, CWS_WORKERS_NUM); + } } diff --git a/src/server/worker.c b/src/server/worker.c index a6dbd54..2cb4322 100644 --- a/src/server/worker.c +++ b/src/server/worker.c @@ -20,21 +20,21 @@ static int cws_worker_setup_epoll(cws_worker_s *worker) { cws_server_ret ret; ret = cws_fd_set_nonblocking(worker->pipefd[0]); if (ret != CWS_SERVER_OK) { - close(worker->epfd); + sock_close(worker->epfd); return -1; } ret = cws_epoll_add(worker->epfd, worker->pipefd[0], EPOLLIN); if (ret != CWS_SERVER_OK) { - close(worker->epfd); - close(worker->pipefd[0]); + sock_close(worker->epfd); + sock_close(worker->pipefd[0]); } return 0; } -cws_worker_s **cws_worker_init(size_t workers_num, hashmap_s *clients, cws_config_s *config) { +cws_worker_s **cws_worker_new(size_t workers_num, cws_config_s *config) { cws_worker_s **workers = malloc(sizeof(cws_worker_s) * workers_num); if (workers == NULL) { return NULL; @@ -55,7 +55,6 @@ cws_worker_s **cws_worker_init(size_t workers_num, hashmap_s *clients, cws_confi memset(workers[i], 0, sizeof(cws_worker_s)); workers[i]->config = config; - workers[i]->clients = clients; /* Communicate though threads */ pipe(workers[i]->pipefd); @@ -109,7 +108,7 @@ void *cws_worker_loop(void *arg) { } else { /* Handle client data */ int client_fd = events[i].data.fd; - cws_server_handle_client_data(worker->epfd, client_fd, worker->clients, worker->config); + cws_server_handle_client_data(worker->epfd, client_fd, worker->config); } } } @@ -117,14 +116,7 @@ void *cws_worker_loop(void *arg) { return NULL; } -void cws_server_close_client(int epfd, int client_fd, hashmap_s *clients) { - bucket_s *client = hm_get(clients, &client_fd); - if (client) { - cws_epoll_del(epfd, client_fd); - hm_remove(clients, &client_fd); - hm_free_bucket(client); - } -} +void cws_server_close_client(int epfd, int client_fd) { cws_epoll_del(epfd, client_fd); } cws_server_ret cws_epoll_add(int epfd, int sockfd, uint32_t events) { struct epoll_event event; @@ -186,7 +178,7 @@ static size_t cws_read_data(int sockfd, string_s **str) { return total_bytes; } -cws_server_ret cws_server_handle_client_data(int epfd, int client_fd, hashmap_s *clients, cws_config_s *config) { +cws_server_ret cws_server_handle_client_data(int epfd, int client_fd, cws_config_s *config) { /* Read data from socket */ string_s *data = NULL; size_t total_bytes = cws_read_data(client_fd, &data); @@ -194,7 +186,7 @@ cws_server_ret cws_server_handle_client_data(int epfd, int client_fd, hashmap_s if (data) { string_free(data); } - cws_server_close_client(epfd, client_fd, clients); + cws_server_close_client(epfd, client_fd); return CWS_SERVER_CLIENT_DISCONNECTED_ERROR; } @@ -204,7 +196,7 @@ cws_server_ret cws_server_handle_client_data(int epfd, int client_fd, hashmap_s string_free(data); if (request == NULL) { - cws_server_close_client(epfd, client_fd, clients); + cws_server_close_client(epfd, client_fd); return CWS_SERVER_HTTP_PARSE_ERROR; } @@ -212,7 +204,7 @@ cws_server_ret cws_server_handle_client_data(int epfd, int client_fd, hashmap_s int keepalive = cws_http_send_resource(request); cws_http_free(request); if (!keepalive) { - cws_server_close_client(epfd, client_fd, clients); + cws_server_close_client(epfd, client_fd); } return CWS_SERVER_OK; diff --git a/src/utils/utils.c b/src/utils/utils.c index d1b2777..ae5473d 100644 --- a/src/utils/utils.c +++ b/src/utils/utils.c @@ -1,10 +1,14 @@ #include "utils/utils.h" +#include +#include #include #include #include #include +volatile sig_atomic_t cws_server_run = 1; + static void cws_utils_convert_ip(int family, void *addr, char *ip, size_t ip_len) { inet_ntop(family, addr, ip, ip_len); } void cws_utils_get_client_ip(struct sockaddr_storage *sa, char *ip) { @@ -17,6 +21,16 @@ void cws_utils_get_client_ip(struct sockaddr_storage *sa, char *ip) { } } +cws_server_ret cws_fd_set_nonblocking(int sockfd) { + const int status = fcntl(sockfd, F_SETFL, O_NONBLOCK); + + if (status == -1) { + return CWS_SERVER_FD_NONBLOCKING_ERROR; + } + + return CWS_SERVER_OK; +} + unsigned int my_str_hash_fn(const void *key) { char *key_str = (char *)key; size_t key_len = strlen(key_str); @@ -55,6 +69,6 @@ bool my_int_equal_fn(const void *a, const void *b) { void my_int_free_key_fn(void *key) { int fd = *(int *)key; - close(fd); + sock_close(fd); free(key); }