From dd9e2f557bfcb8607b182947b03b821a65f280a3 Mon Sep 17 00:00:00 2001 From: Francesco Date: Thu, 24 Apr 2025 17:24:13 +0200 Subject: [PATCH] adjust naming convention and initial config support --- .gitignore | 2 + README.md | 13 ++++--- config.yaml | 6 +++ include/client/client.h | 17 --------- include/http/http.h | 56 ++++++++++++++-------------- include/server/server.h | 62 +++++++++++++++---------------- include/utils/config.h | 7 ++++ include/utils/hashmap.h | 52 +++++++++++++------------- include/utils/utils.h | 15 +++----- meson.build | 6 ++- src/client/client.c | 40 -------------------- src/client/main.c | 15 -------- src/http/http.c | 38 +++++++++---------- src/main.c | 2 +- src/meson.build | 2 - src/server/server.c | 82 ++++++++++++++++++++--------------------- src/utils/config.c | 5 +++ src/utils/hashmap.c | 52 +++++++++++++------------- src/utils/utils.c | 8 +++- 19 files changed, 217 insertions(+), 263 deletions(-) create mode 100644 config.yaml delete mode 100644 include/client/client.h create mode 100644 include/utils/config.h delete mode 100644 src/client/client.c delete mode 100644 src/client/main.c create mode 100644 src/utils/config.c diff --git a/.gitignore b/.gitignore index fa5420a..49b6b03 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ build/ .cache/ docs/ +cert.pem +key.pem # Prerequisites *.d diff --git a/README.md b/README.md index 75b677f..0aa732d 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ will it ever be. Use it at your own risk. - [meson](https://mesonbuild.com/index.html) - [doxygen](https://www.doxygen.nl/) - Optional, just to build the docs. +- libcyaml +- libyaml-0.1 ## How to build @@ -17,7 +19,7 @@ $ cd build $ meson compile ``` -And then run `server`! +And then run `cws`! ## Docs @@ -39,11 +41,12 @@ And then open the `docs/html/index.html`. - [ ] Request parser - [x] Serve static files - [ ] Implement Keep-Alive - - [ ] Multithreading + - [ ] Multithreading to handle concurrent requests - [ ] Logging -- [ ] Advanced - - [ ] HTTPS support - - [ ] Caching +- [ ] Advanced Features + - [ ] HTTPS support with TLS + - [ ] Compression (Gzip) + - [ ] Support for virtual hosting ## Resources diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..c53c471 --- /dev/null +++ b/config.yaml @@ -0,0 +1,6 @@ +# Default config file of CWS +host: "localhost" +port: 3030 + +cert: "cert.pem" +key: "key.pem" diff --git a/include/client/client.h b/include/client/client.h deleted file mode 100644 index 4782124..0000000 --- a/include/client/client.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef CWS_CLIENT_H -#define CWS_CLIENT_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int test_client_connection(const char *hostname, const char *service); - -#endif diff --git a/include/http/http.h b/include/http/http.h index ef16279..de7adfa 100644 --- a/include/http/http.h +++ b/include/http/http.h @@ -1,33 +1,35 @@ #ifndef CWS_HTTP_H #define CWS_HTTP_H -#define WWW "../www" /**< Directory used to get html files */ +#define CWS_WWW "../www" /**< Directory used to get html files */ /** In the future I'll move conf stuff under a server struct, I can skip just because I want something that works */ -#define LOCATION_LEN 512 -#define LOCATION_PATH_LEN 1024 -#define HTTP_VERSION_LEN 8 -#define USER_AGENT_LEN 1024 -#define HOST_LEN 1024 +#define CWS_HTTP_LOCATION_LEN 512 +#define CWS_HTTP_LOCATION_PATH_LEN 1024 +#define CWS_HTTP_VERSION_LEN 8 +#define CWS_HTTP_USER_AGENT_LEN 1024 +#define CWS_HTTP_HOST_LEN 1024 -enum http_method { - GET, /**< GET method */ - POST, /**< POST method */ -}; +typedef enum cws_http_method_t { + CWS_HTTP_GET, /**< GET method */ + CWS_HTTP_POST, /**< POST method */ + CWS_HTTP_PUT, + CWS_HTTP_DELETE, +} cws_http_method; /* In the future I'll add HEAD, PUT, DELETE */ /** * @brief HTTP request struct * */ -typedef struct http { - int sockfd; /**< Socket file descriptor */ - enum http_method method; /**< HTTP request method */ - char location[LOCATION_LEN]; /**< Resource requested */ - char location_path[LOCATION_PATH_LEN]; /**< Resource path */ - char http_version[HTTP_VERSION_LEN]; /**< HTTP version */ - char user_agent[USER_AGENT_LEN]; /**< User-Agent */ - char host[HOST_LEN]; /**< Host */ -} http_t; +typedef struct cws_http_t { + int sockfd; /**< Socket file descriptor */ + cws_http_method method; /**< HTTP request method */ + char location[CWS_HTTP_LOCATION_LEN]; /**< Resource requested */ + char location_path[CWS_HTTP_LOCATION_PATH_LEN]; /**< Full resource path */ + char http_version[CWS_HTTP_VERSION_LEN]; /**< HTTP version */ + char user_agent[CWS_HTTP_USER_AGENT_LEN]; /**< User-Agent */ + char host[CWS_HTTP_HOST_LEN]; /**< Host */ +} cws_http; /* Connection */ /* Accept-Encoding */ /* Accept-Language */ @@ -35,18 +37,18 @@ typedef struct http { /** * @brief Parses a HTTP request * - * @param request_str[in] The http request sent to the server + * @param[in] request_str The http request sent to the server * @return Returns a http_t pointer to the request */ -http_t *http_parse(char *request_str, int sockfd); +cws_http *cws_http_parse(char *request_str, int sockfd); -void http_parse_method(http_t *request, const char *method); -void http_get_content_type(http_t *request, char *content_type); +void cws_http_parse_method(cws_http *request, const char *method); +void cws_http_get_content_type(cws_http *request, char *content_type); -void http_send_response(http_t *request); -void http_send_not_found(http_t *request); -void http_send_not_implemented(http_t *request); +void cws_http_send_response(cws_http *request); +void cws_http_send_not_found(cws_http *request); +void cws_http_send_not_implemented(cws_http *request); -void http_free(http_t *request); +void cws_http_free(cws_http *request); #endif \ No newline at end of file diff --git a/include/server/server.h b/include/server/server.h index 7635dc0..96aadb8 100644 --- a/include/server/server.h +++ b/include/server/server.h @@ -7,87 +7,87 @@ #include "utils/hashmap.h" /* Clients max queue */ -#define BACKLOG 10 +#define CWS_SERVER_BACKLOG 10 /* Size of the epoll_event array */ -#define EPOLL_MAXEVENTS 10 +#define CWS_SERVER_EPOLL_MAXEVENTS 10 /* Wait forever (epoll_wait()) */ -#define EPOLL_TIMEOUT -1 +#define CWS_SERVER_EPOLL_TIMEOUT -1 /** * @brief Runs the server * - * @param hostname[in] The hostname of the server (default localhost, it could be NULL) - * @param service[in] The service (found in /etc/services) or the port where to run + * @param[in] hostname The hostname of the server (default localhost, it could be NULL) + * @param[in] service The service (found in /etc/services) or the port where to run * @return 0 on success, -1 on error */ -int start_server(const char *hostname, const char *service); +int cws_server_start(const char *hostname, const char *service); /** * @brief Setups hints object * - * @param hints[out] The hints addrinfo - * @param len[in] The length of hints - * @param hostname[in] The hostname (could be NULL) + * @param[out] hints The hints addrinfo + * @param[in] len The length of hints + * @param[in] hostname The hostname (could be NULL) */ -void setup_hints(struct addrinfo *hints, size_t len, const char *hostname); +void cws_server_setup_hints(struct addrinfo *hints, size_t len, const char *hostname); /** * @brief Main server loop * - * @param sockfd[in,out] Socket of the commincation endpoint + * @param[in,out] sockfd Socket of the commincation endpoint */ -void handle_clients(int sockfd); +void cws_server_loop(int sockfd); /** * @brief Adds a file descriptor to the interest list * - * @param epfd[in] epoll file descriptor - * @param sockfd[in] The file descriptor to watch - * @param events[in] The events to follow + * @param[in] epfd epoll file descriptor + * @param[in] sockfd The file descriptor to watch + * @param[in] events The events to follow */ -void epoll_ctl_add(int epfd, int sockfd, uint32_t events); +void cws_epoll_add(int epfd, int sockfd, uint32_t events); /** * @brief Removes a file descriptor from the interest list * - * @param epfd[in] epoll file descriptor - * @param sockfd[in] The file descriptor to remove + * @param[in] epfd epoll file descriptor + * @param[in] sockfd The file descriptor to remove */ -void epoll_ctl_del(int epfd, int sockfd); +void cws_epoll_del(int epfd, int sockfd); /** * @brief Makes a file descriptor non-blocking * - * @param sockfd[in] The file descriptor to make non-blocking + * @param[in] sockfd The file descriptor to make non-blocking */ -void setnonblocking(int sockfd); +void cws_fd_set_nonblocking(int sockfd); /** * @brief Handles the new client * - * @param sockfd[in] Server's file descriptor - * @param their_sa[out] Populates the struct with client's information - * @param theirsa_size[in] Size of the struct + * @param[in] sockfd Server's file descriptor + * @param[out] their_sa Populates the struct with client's information + * @param[in] theirsa_size Size of the struct * @return Returns -1 on error or the file descriptor on success */ -int handle_new_client(int sockfd, struct sockaddr_storage *their_sa, socklen_t *theirsa_size); +int cws_server_accept_client(int sockfd, struct sockaddr_storage *their_sa, socklen_t *theirsa_size); /** * @brief Closes all the file descriptors opened * - * @param bucket[in] The hash map + * @param[in] bucket The hash map */ -void close_fds(bucket_t *bucket); +void cws_server_close_all_fds(cws_bucket *bucket); /** * @brief Disconnect a client * - * @param epfd[in] Epoll file descriptor - * @param client_fd[in] Client file descriptor - * @param bucket[in] Clients hash map + * @param[in] epfd Epoll file descriptor + * @param[in] client_fd Client file descriptor + * @param[in] bucket Clients hash map */ -void close_client(int epfd, int client_fd, bucket_t *bucket); +void cws_server_close_client(int epfd, int client_fd, cws_bucket *bucket); #endif diff --git a/include/utils/config.h b/include/utils/config.h new file mode 100644 index 0000000..05d950d --- /dev/null +++ b/include/utils/config.h @@ -0,0 +1,7 @@ +#ifndef CWS_CONFIG_H +#define CWS_CONFIG_H + +typedef struct cws_config_t { +} cws_config; + +#endif diff --git a/include/utils/hashmap.h b/include/utils/hashmap.h index c4f2c91..a8f045d 100644 --- a/include/utils/hashmap.h +++ b/include/utils/hashmap.h @@ -2,81 +2,79 @@ #define CWS_HASHMAP_H #include -#include -#include #include /* Each process on Linux can have a maximum of 1024 open file descriptors */ -#define HASHMAP_MAX_CLIENTS 1024 +#define CWS_HASHMAP_MAX_CLIENTS 1024 /** * @brief Hash map struct * */ -typedef struct bucket { +typedef struct cws_bucket_t { int sockfd; /**< Client socket descriptor */ struct sockaddr_storage sas; /**< Associated socket address */ - struct bucket *next; /**< Next node in case of collision */ - struct bucket *prev; /**< Previous node in case of collision */ -} bucket_t; + struct cws_bucket_t *next; /**< Next node in case of collision */ + struct cws_bucket_t *prev; /**< Previous node in case of collision */ +} cws_bucket; /** * @brief Calculates the hash code of a given file descriptor * - * @param sockfd[in] The file descriptor + * @param[in] sockfd The file descriptor * @return Returns the hash code */ -int hash(int sockfd); +int cws_hm_hash(int sockfd); /** * @brief Initializes the hash map * - * @param bucket[out] The hash map uninitialized + * @param[out] bucket The hash map uninitialized */ -void hm_init(bucket_t *bucket); +void cws_hm_init(cws_bucket *bucket); /** * @brief Inserts a key in the hash map * - * @param bucket[out] The hash map - * @param sockfd[in] The file descriptor (value) - * @param sas[in] The sockaddr (value) + * @param[out] bucket The hash map + * @param[in] sockfd The file descriptor (value) + * @param[in] sas The sockaddr (value) */ -void hm_push(bucket_t *bucket, int sockfd, struct sockaddr_storage *sas); +void cws_hm_push(cws_bucket *bucket, int sockfd, struct sockaddr_storage *sas); /** * @brief Removes a key from the hash map * - * @param bucket[out] The hash map - * @param sockfd[in] The key + * @param[out] bucket The hash map + * @param[in] sockfd The key */ -void hm_remove(bucket_t *bucket, int sockfd); +void cws_hm_remove(cws_bucket *bucket, int sockfd); /** * @brief Searches for a key in the hash map * - * @param bucket[in] The hash map - * @param sockfd[in] The file descriptor (key) + * @param[in] bucket The hash map + * @param[in] sockfd The file descriptor (key) * @return Returns NULL or the key pointer */ -bucket_t *hm_lookup(bucket_t *bucket, int sockfd); +cws_bucket *cws_hm_lookup(cws_bucket *bucket, int sockfd); /** * @brief Cleans the hash map * - * @param bucket[out] The hash map + * @param[out] bucket The hash map */ -void hm_free(bucket_t *bucket); +void cws_hm_free(cws_bucket *bucket); /** * @brief Checks if a file descriptor is in the bucket array (not linked list) * - * @param bucket[in] - * @param sockfd[in] + * @param[in] bucket + * @param[in] sockfd * @return true If the file descriptor is in the bucket array * @return false If the file descriptor is not in the bucket array (check with hm_lookup()) */ -bool hm_is_in_bucket_array(bucket_t *bucket, int sockfd); +bool cws_hm_is_in_bucket_array(cws_bucket *bucket, int sockfd); /** * @brief This function will add a key even if it exists (use hm_push() instead) @@ -85,6 +83,6 @@ bool hm_is_in_bucket_array(bucket_t *bucket, int sockfd); * @param sockfd * @param sas */ -void hm_insert(bucket_t *bucket, int sockfd, struct sockaddr_storage *sas); +void cws_hm_insert(cws_bucket *bucket, int sockfd, struct sockaddr_storage *sas); #endif \ No newline at end of file diff --git a/include/utils/utils.h b/include/utils/utils.h index 9d6710e..9584f9d 100644 --- a/include/utils/utils.h +++ b/include/utils/utils.h @@ -4,26 +4,23 @@ #include #include #include -#include -#include -#include #include #include /** * @brief Prints each IP address associated with a host * - * @param hostname[in] Hostname - * @param port[in] Port + * @param[in] hostname Hostname + * @param[in] port Port */ -void print_ips(const char *hostname, const char *port); +void cws_utils_print_ips(const char *hostname, const char *port); /** * @brief Retrieves the client ip from the sockaddr_storage and put it in the ip str * - * @param sa[in] The sockaddr_storage of the client - * @param ip[out] The IP of the client + * @param[in] sa The sockaddr_storage of the client + * @param[out] ip The IP of the client */ -void get_client_ip(struct sockaddr_storage *sa, char *ip); +void cws_utils_get_client_ip(struct sockaddr_storage *sa, char *ip); #endif diff --git a/meson.build b/meson.build index bc1e25c..b807b0f 100644 --- a/meson.build +++ b/meson.build @@ -4,5 +4,7 @@ subdir('src') incdir = include_directories('include') -executable('server', server, include_directories : incdir) -executable('client', client, include_directories : incdir) \ No newline at end of file +libyaml = dependency('yaml-0.1') +libcyaml = dependency('libcyaml') + +executable('cws', server, include_directories : incdir, dependencies : [libyaml, libcyaml]) diff --git a/src/client/client.c b/src/client/client.c deleted file mode 100644 index 1f933dd..0000000 --- a/src/client/client.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "client/client.h" - -#include "utils/colors.h" - -int test_client_connection(const char *hostname, const char *service) { - struct addrinfo hints; - struct addrinfo *res; - - memset(&hints, 0, sizeof hints); - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = AF_INET; - - int status = getaddrinfo(hostname, service, &hints, &res); - if (status != 0) { - fprintf(stderr, RED BOLD "[client] getaddrinfo(): %s\n" RESET, gai_strerror(status)); - exit(EXIT_FAILURE); - } - - int sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - - status = connect(sockfd, res->ai_addr, res->ai_addrlen); - if (status != 0) { - fprintf(stderr, RED BOLD "[client] connect(): %s\n" RESET, strerror(errno)); - exit(EXIT_FAILURE); - } - - char buf[4096]; - int bytes_read = recv(sockfd, buf, sizeof buf, 0); - fprintf(stdout, BLUE "[client] Read %d bytes: %s\n" RESET, bytes_read, buf); - - fprintf(stdout, "[client] => "); - fgets(buf, sizeof buf, stdin); - buf[strcspn(buf, "\n")] = '\0'; - send(sockfd, buf, strlen(buf), 0); - - freeaddrinfo(res); - close(sockfd); - - return 0; -} \ No newline at end of file diff --git a/src/client/main.c b/src/client/main.c deleted file mode 100644 index 7a8b81d..0000000 --- a/src/client/main.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "client/client.h" -#include "utils/colors.h" - -int main(int argc, char **argv) { - fprintf(stdout, BOLD GREEN "[client] Running client...\n" RESET); - - int ret = test_client_connection(argv[1], argv[2]); - if (ret < 0) { - fprintf(stderr, BOLD RED "Unable to start client\n"); - } - - return 0; -} diff --git a/src/http/http.c b/src/http/http.c index 62b4831..8008699 100644 --- a/src/http/http.c +++ b/src/http/http.c @@ -7,8 +7,8 @@ #include "utils/colors.h" -http_t *http_parse(char *request_str, int sockfd) { - http_t *request = malloc(sizeof(http_t)); +cws_http *cws_http_parse(char *request_str, int sockfd) { + cws_http *request = malloc(sizeof(cws_http)); if (request == NULL) { return NULL; } @@ -22,7 +22,7 @@ http_t *http_parse(char *request_str, int sockfd) { return NULL; } printf("[client::http] method: %s\n", pch); - http_parse_method(request, pch); + cws_http_parse_method(request, pch); /* Parse location */ pch = strtok(NULL, " "); @@ -30,14 +30,14 @@ http_t *http_parse(char *request_str, int sockfd) { return NULL; } printf("[client::http] location: %s\n", pch); - strncpy(request->location, pch, LOCATION_LEN); + strncpy(request->location, pch, CWS_HTTP_LOCATION_LEN); /* Parse location path */ /* TODO: Prevent Path Traversal */ if (strcmp(request->location, "/") == 0) { - snprintf(request->location_path, LOCATION_PATH_LEN, "%s/index.html", WWW); + snprintf(request->location_path, CWS_HTTP_LOCATION_PATH_LEN, "%s/index.html", CWS_WWW); } else { - snprintf(request->location_path, LOCATION_PATH_LEN, "%s%s", WWW, request->location); + snprintf(request->location_path, CWS_HTTP_LOCATION_PATH_LEN, "%s%s", CWS_WWW, request->location); } fprintf(stdout, "[client::http] location path: %s\n", request->location_path); @@ -47,37 +47,37 @@ http_t *http_parse(char *request_str, int sockfd) { return NULL; } printf("[client::http] version: %s\n", pch); - strncpy(request->http_version, pch, HTTP_VERSION_LEN); + strncpy(request->http_version, pch, CWS_HTTP_VERSION_LEN); /* Parse other stuff... */ return request; } -void http_parse_method(http_t *request, const char *method) { +void cws_http_parse_method(cws_http *request, const char *method) { if (strcmp(method, "GET") == 0) { - request->method = GET; + request->method = CWS_HTTP_GET; return; } if (strcmp(method, "POST") == 0) { - request->method = POST; + request->method = CWS_HTTP_POST; return; } - http_send_not_implemented(request); + cws_http_send_not_implemented(request); } -void http_send_response(http_t *request) { +void cws_http_send_response(cws_http *request) { FILE *file = fopen(request->location_path, "rb"); if (file == NULL) { /* 404 */ - http_send_not_found(request); + cws_http_send_not_found(request); return; } /* Retrieve correct Content-Type */ char content_type[1024]; - http_get_content_type(request, content_type); + cws_http_get_content_type(request, content_type); /* Retrieve file size */ fseek(file, 0, SEEK_END); @@ -111,10 +111,10 @@ void http_send_response(http_t *request) { free(file_data); } -void http_get_content_type(http_t *request, char *content_type) { +void cws_http_get_content_type(cws_http *request, char *content_type) { char *ptr = strrchr(request->location_path, '.'); if (ptr == NULL) { - http_send_not_found(request); + cws_http_send_not_found(request); return; } ptr += 1; @@ -134,7 +134,7 @@ void http_get_content_type(http_t *request, char *content_type) { snprintf(content_type, 1024, "%s/%s", ct, ptr); } -void http_send_not_implemented(http_t *request) { +void cws_http_send_not_implemented(cws_http *request) { const char response[1024] = "HTTP/1.1 501 Not Implemented\r\n" "Content-Type: text/html\r\n" @@ -152,7 +152,7 @@ void http_send_not_implemented(http_t *request) { send(request->sockfd, response, response_len, 0); } -void http_send_not_found(http_t *request) { +void cws_http_send_not_found(cws_http *request) { const char response[1024] = "HTTP/1.1 404 Not Found\r\n" "Content-Type: text/html\r\n" @@ -170,4 +170,4 @@ void http_send_not_found(http_t *request) { send(request->sockfd, response, response_len, 0); } -void http_free(http_t *request) { free(request); } +void cws_http_free(cws_http *request) { free(request); } diff --git a/src/main.c b/src/main.c index 82ae4ca..90b7e45 100644 --- a/src/main.c +++ b/src/main.c @@ -8,7 +8,7 @@ int main(int argc, char **argv) { fprintf(stdout, BOLD GREEN "[server] Running cws on http://localhost:%s...\n" RESET, default_port); - int ret = start_server(NULL, default_port); + int ret = cws_server_start(NULL, default_port); if (ret < 0) { fprintf(stderr, BOLD RED "Unable to start web server\n"); } diff --git a/src/meson.build b/src/meson.build index 12c70d7..856b031 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,5 +1,3 @@ server = files('main.c', 'server/server.c') server += files('utils/utils.c', 'utils/hashmap.c') server += files('http/http.c') - -client = files('client/main.c', 'client/client.c') \ No newline at end of file diff --git a/src/server/server.c b/src/server/server.c index ba02e9e..e73f4bd 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -16,11 +16,11 @@ #include "utils/hashmap.h" #include "utils/utils.h" -int start_server(const char *hostname, const char *service) { +int cws_server_start(const char *hostname, const char *service) { struct addrinfo hints; struct addrinfo *res; - setup_hints(&hints, sizeof hints, hostname); + cws_server_setup_hints(&hints, sizeof hints, hostname); int status = getaddrinfo(hostname, service, &hints, &res); if (status != 0) { @@ -43,13 +43,13 @@ int start_server(const char *hostname, const char *service) { exit(EXIT_FAILURE); } - status = listen(sockfd, BACKLOG); + status = listen(sockfd, CWS_SERVER_BACKLOG); if (status != 0) { fprintf(stderr, RED BOLD "[server] listen(): %s\n" RESET, gai_strerror(status)); exit(EXIT_FAILURE); } - handle_clients(sockfd); + cws_server_loop(sockfd); freeaddrinfo(res); close(sockfd); @@ -57,7 +57,7 @@ int start_server(const char *hostname, const char *service) { return 0; } -void setup_hints(struct addrinfo *hints, size_t len, const char *hostname) { +void cws_server_setup_hints(struct addrinfo *hints, size_t len, const char *hostname) { memset(hints, 0, len); /* IPv4 or IPv6 */ hints->ai_family = AF_UNSPEC; @@ -69,53 +69,53 @@ void setup_hints(struct addrinfo *hints, size_t len, const char *hostname) { } } -void handle_clients(int sockfd) { +void cws_server_loop(int sockfd) { struct sockaddr_storage their_sa; socklen_t theirsa_size = sizeof their_sa; - bucket_t clients[HASHMAP_MAX_CLIENTS]; - hm_init(clients); + cws_bucket clients[CWS_HASHMAP_MAX_CLIENTS]; + cws_hm_init(clients); int epfd = epoll_create1(0); - setnonblocking(sockfd); - epoll_ctl_add(epfd, sockfd, EPOLLIN | EPOLLET); + cws_fd_set_nonblocking(sockfd); + cws_epoll_add(epfd, sockfd, EPOLLIN | EPOLLET); - struct epoll_event *revents = malloc(EPOLL_MAXEVENTS * sizeof(struct epoll_event)); + struct epoll_event *revents = malloc(CWS_SERVER_EPOLL_MAXEVENTS * sizeof(struct epoll_event)); int client_fd; while (1) { - int nfds = epoll_wait(epfd, revents, EPOLL_MAXEVENTS, EPOLL_TIMEOUT); + int nfds = epoll_wait(epfd, revents, CWS_SERVER_EPOLL_MAXEVENTS, CWS_SERVER_EPOLL_TIMEOUT); for (int i = 0; i < nfds; ++i) { if (revents[i].data.fd == sockfd) { /* New client */ char ip[INET_ADDRSTRLEN]; - client_fd = handle_new_client(sockfd, &their_sa, &theirsa_size); - get_client_ip(&their_sa, ip); + client_fd = cws_server_accept_client(sockfd, &their_sa, &theirsa_size); + cws_utils_get_client_ip(&their_sa, ip); fprintf(stdout, BLUE "[server] Client (%s) connected\n" RESET, ip); - setnonblocking(client_fd); - epoll_ctl_add(epfd, client_fd, EPOLLIN); - hm_push(clients, client_fd, &their_sa); + cws_fd_set_nonblocking(client_fd); + cws_epoll_add(epfd, client_fd, EPOLLIN); + cws_hm_push(clients, client_fd, &their_sa); } else { char data[4096] = {0}; /* Incoming data */ client_fd = revents[i].data.fd; const ssize_t bytes_read = recv(client_fd, data, sizeof data, 0); char ip[INET_ADDRSTRLEN]; - bucket_t *client = hm_lookup(clients, client_fd); - get_client_ip(&client->sas, ip); + cws_bucket *client = cws_hm_lookup(clients, client_fd); + cws_utils_get_client_ip(&client->sas, ip); if (bytes_read == 0) { /* Client disconnected */ fprintf(stdout, BLUE "[server] Client (%s) disconnected\n" RESET, ip); - close_client(epfd, client_fd, clients); + cws_server_close_client(epfd, client_fd, clients); continue; } if (bytes_read < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) { /* Error during read, handle it (close client) */ - epoll_ctl_del(epfd, client_fd); + cws_epoll_del(epfd, client_fd); close(client_fd); } continue; @@ -124,18 +124,18 @@ void handle_clients(int sockfd) { data[bytes_read] = '\0'; /* Parse HTTP request */ - http_t *request = http_parse(data, client_fd); + cws_http *request = cws_http_parse(data, client_fd); if (request == NULL) { - close_client(epfd, client_fd, clients); - http_free(request); + cws_server_close_client(epfd, client_fd, clients); + cws_http_free(request); continue; } - http_send_response(request); + cws_http_send_response(request); fprintf(stdout, BLUE "[server] Client (%s) disconnected\n" RESET, ip); - close_client(epfd, client_fd, clients); - http_free(request); + cws_server_close_client(epfd, client_fd, clients); + cws_http_free(request); /* Clear str */ memset(data, 0, sizeof data); @@ -147,11 +147,11 @@ void handle_clients(int sockfd) { /* TODO: fix endless loop using cli args */ free(revents); close(epfd); - close_fds(clients); - hm_free(clients); + cws_server_close_all_fds(clients); + cws_hm_free(clients); } -void epoll_ctl_add(int epfd, int sockfd, uint32_t events) { +void cws_epoll_add(int epfd, int sockfd, uint32_t events) { struct epoll_event event; event.events = events; event.data.fd = sockfd; @@ -163,7 +163,7 @@ void epoll_ctl_add(int epfd, int sockfd, uint32_t events) { } } -void epoll_ctl_del(int epfd, int sockfd) { +void cws_epoll_del(int epfd, int sockfd) { const int status = epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, NULL); if (status != 0) { @@ -172,7 +172,7 @@ void epoll_ctl_del(int epfd, int sockfd) { } } -void setnonblocking(int sockfd) { +void cws_fd_set_nonblocking(int sockfd) { const int status = fcntl(sockfd, F_SETFL, O_NONBLOCK); if (status == -1) { @@ -181,7 +181,7 @@ void setnonblocking(int sockfd) { } } -int handle_new_client(int sockfd, struct sockaddr_storage *their_sa, socklen_t *theirsa_size) { +int cws_server_accept_client(int sockfd, struct sockaddr_storage *their_sa, socklen_t *theirsa_size) { const int client_fd = accept(sockfd, (struct sockaddr *)their_sa, theirsa_size); if (client_fd == -1) { @@ -194,13 +194,13 @@ int handle_new_client(int sockfd, struct sockaddr_storage *their_sa, socklen_t * return client_fd; } -void close_fds(bucket_t *bucket) { - for (size_t i = 0; i < HASHMAP_MAX_CLIENTS; ++i) { +void cws_server_close_all_fds(cws_bucket *bucket) { + for (size_t i = 0; i < CWS_HASHMAP_MAX_CLIENTS; ++i) { close(bucket[i].sockfd); if (bucket[i].next != NULL) { /* Close the fds */ - bucket_t *p = bucket[i].next; - bucket_t *next = p->next; + cws_bucket *p = bucket[i].next; + cws_bucket *next = p->next; do { close(p->sockfd); p = next; @@ -210,8 +210,8 @@ void close_fds(bucket_t *bucket) { } } -void close_client(int epfd, int client_fd, bucket_t *clients) { - epoll_ctl_del(epfd, client_fd); - hm_remove(clients, client_fd); +void cws_server_close_client(int epfd, int client_fd, cws_bucket *clients) { + cws_epoll_del(epfd, client_fd); + cws_hm_remove(clients, client_fd); close(client_fd); -} \ No newline at end of file +} diff --git a/src/utils/config.c b/src/utils/config.c new file mode 100644 index 0000000..9a3e926 --- /dev/null +++ b/src/utils/config.c @@ -0,0 +1,5 @@ +#include "utils/config.h" + +int nothing() { + return 0; +} \ No newline at end of file diff --git a/src/utils/hashmap.c b/src/utils/hashmap.c index 1916fb3..79c4005 100644 --- a/src/utils/hashmap.c +++ b/src/utils/hashmap.c @@ -1,20 +1,23 @@ #include "utils/hashmap.h" -int hash(int sockfd) { return sockfd % HASHMAP_MAX_CLIENTS; } +#include +#include -void hm_init(bucket_t *bucket) { +int cws_hm_hash(int sockfd) { return sockfd % CWS_HASHMAP_MAX_CLIENTS; } + +void cws_hm_init(cws_bucket *bucket) { /* Initialize everything to 0 for the struct, then -1 for fd and next to NULL */ - memset(bucket, 0, sizeof(bucket_t) * HASHMAP_MAX_CLIENTS); + memset(bucket, 0, sizeof(cws_bucket) * CWS_HASHMAP_MAX_CLIENTS); - for (size_t i = 0; i < HASHMAP_MAX_CLIENTS; ++i) { + for (size_t i = 0; i < CWS_HASHMAP_MAX_CLIENTS; ++i) { bucket[i].sockfd = -1; bucket[i].next = NULL; bucket[i].prev = NULL; } } -void hm_insert(bucket_t *bucket, int sockfd, struct sockaddr_storage *sas) { - int index = hash(sockfd); +void cws_hm_insert(cws_bucket *bucket, int sockfd, struct sockaddr_storage *sas) { + int index = cws_hm_hash(sockfd); if (bucket[index].sockfd == -1) { /* Current slot is empty */ @@ -23,8 +26,8 @@ void hm_insert(bucket_t *bucket, int sockfd, struct sockaddr_storage *sas) { } else { /* Append the new key to the head (not the first element because it belongs to the array) of the linked * list */ - bucket_t *p = &bucket[index]; - bucket_t *new = malloc(sizeof(bucket_t)); + cws_bucket *p = &bucket[index]; + cws_bucket *new = malloc(sizeof(cws_bucket)); new->sockfd = sockfd; new->sas = *sas; new->next = p->next; @@ -33,13 +36,12 @@ void hm_insert(bucket_t *bucket, int sockfd, struct sockaddr_storage *sas) { } } -bucket_t *hm_lookup(bucket_t *bucket, int sockfd) { - int index = hash(sockfd); +cws_bucket *cws_hm_lookup(cws_bucket *bucket, int sockfd) { + int index = cws_hm_hash(sockfd); if (bucket[index].sockfd != sockfd) { - bucket_t *p; - for (p = bucket[index].next; p != NULL && p->sockfd != sockfd; p = p->next) - ; + cws_bucket *p; + for (p = bucket[index].next; p != NULL && p->sockfd != sockfd; p = p->next); return p; } else { return &bucket[index]; @@ -48,23 +50,23 @@ bucket_t *hm_lookup(bucket_t *bucket, int sockfd) { return NULL; } -void hm_push(bucket_t *bucket, int sockfd, struct sockaddr_storage *sas) { - if (hm_lookup(bucket, sockfd) == NULL) { - hm_insert(bucket, sockfd, sas); +void cws_hm_push(cws_bucket *bucket, int sockfd, struct sockaddr_storage *sas) { + if (cws_hm_lookup(bucket, sockfd) == NULL) { + cws_hm_insert(bucket, sockfd, sas); } } -void hm_remove(bucket_t *bucket, int sockfd) { - if (hm_is_in_bucket_array(bucket, sockfd)) { +void cws_hm_remove(cws_bucket *bucket, int sockfd) { + if (cws_hm_is_in_bucket_array(bucket, sockfd)) { /* Instead of doing this I could copy the memory of the next node into the head */ - int index = hash(sockfd); + int index = cws_hm_hash(sockfd); bucket[index].sockfd = -1; return; } /* Key not in the bucket array, let's search in the linked list */ - bucket_t *p = hm_lookup(bucket, sockfd); + cws_bucket *p = cws_hm_lookup(bucket, sockfd); if (p == NULL) return; p->prev->next = p->next; if (p->next != NULL) { @@ -74,10 +76,10 @@ void hm_remove(bucket_t *bucket, int sockfd) { free(p); } -void hm_free(bucket_t *bucket) { - bucket_t *p, *next; +void cws_hm_free(cws_bucket *bucket) { + cws_bucket *p, *next; - for (size_t i = 0; i < HASHMAP_MAX_CLIENTS; ++i) { + for (size_t i = 0; i < CWS_HASHMAP_MAX_CLIENTS; ++i) { if (bucket[i].next != NULL) { /* Free the malloc */ p = bucket[i].next; @@ -91,8 +93,8 @@ void hm_free(bucket_t *bucket) { } } -bool hm_is_in_bucket_array(bucket_t *bucket, int sockfd) { - int index = hash(sockfd); +bool cws_hm_is_in_bucket_array(cws_bucket *bucket, int sockfd) { + int index = cws_hm_hash(sockfd); if (bucket[index].sockfd == sockfd) return true; return false; diff --git a/src/utils/utils.c b/src/utils/utils.c index d222732..fc3880e 100644 --- a/src/utils/utils.c +++ b/src/utils/utils.c @@ -1,8 +1,12 @@ #include "utils/utils.h" +#include +#include +#include + #include "utils/colors.h" -void print_ips(const char *hostname, const char *port) { +void cws_utils_print_ips(const char *hostname, const char *port) { struct addrinfo ai; struct addrinfo *res; @@ -35,7 +39,7 @@ void print_ips(const char *hostname, const char *port) { freeaddrinfo(res); } -void get_client_ip(struct sockaddr_storage *sa, char *ip) { +void cws_utils_get_client_ip(struct sockaddr_storage *sa, char *ip) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; inet_ntop(AF_INET, &sin->sin_addr, ip, INET_ADDRSTRLEN);