From 9b22b9fb86aef68023f88a48b47e6f5002830b3b Mon Sep 17 00:00:00 2001 From: tomoya-honda Date: Wed, 5 Feb 2025 02:07:59 +0000 Subject: [PATCH 01/17] Use Makefile symbols --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index df72073..3a91848 100644 --- a/Makefile +++ b/Makefile @@ -6,10 +6,10 @@ CFLAGS = -Wall -Wextra -Wpedantic -O2 all: server client server: server.o utils.o - $(CC) $(CFLAGS) -o server server.o utils.o + $(CC) $(CFLAGS) -o $@ $^ client: client.o utils.o - $(CC) $(CFLAGS) -o client client.o utils.o + $(CC) $(CFLAGS) -o $@ $^ %.o: %.c $(CC) $(CFLAGS) -c $< From b46fa801e88726f61ca804ef659ee27252bab3cb Mon Sep 17 00:00:00 2001 From: tomoya-honda Date: Wed, 5 Feb 2025 02:24:48 +0000 Subject: [PATCH 02/17] Use fputs instead of puts for error messages --- client.c | 8 ++++---- server.c | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/client.c b/client.c index 2be325c..57bdae5 100644 --- a/client.c +++ b/client.c @@ -25,7 +25,7 @@ int main(int argc, char **argv) int socket_fd; if ((socket_fd = create_connected_socket(argv[1], argv[2])) == -1) { - puts("Failed to create a connected socket\n"); + fputs("Failed to create a connected socket\n", stderr); exit(1); } @@ -37,7 +37,7 @@ int main(int argc, char **argv) // Check if fgets() reached EOF if (feof(stdin)) { - puts("EOF detected\n"); + puts("EOF detected"); break; } else @@ -84,7 +84,7 @@ int main(int argc, char **argv) } else if (received_bytes == 0) { - puts("Connection closed by server\n"); + puts("Connection closed by server"); close_with_retry(socket_fd); exit(1); } @@ -187,7 +187,7 @@ int create_connected_socket(const char *ip, const char *port_str) } else { - puts("Reached the unreachable"); + fputs("Reached the unreachable\n", stderr); return -1; } diff --git a/server.c b/server.c index df54b25..de4446b 100644 --- a/server.c +++ b/server.c @@ -56,7 +56,7 @@ int main(int argc, char **argv) init_socket_manager(&listen_socket_manager, MAX_LISTENS); if (create_listen_sockets(argv[1], &listen_socket_manager) == -1) { - puts("Failed to create listen sockets\n"); + fputs("Failed to create listen sockets\n", stderr); exit_code = 1; goto cleanup; } @@ -74,7 +74,7 @@ int main(int argc, char **argv) // Add the listen sockets to the epoll instance if (add_listen_sockets_to_epoll(epoll_fd, &listen_socket_manager) == -1) { - puts("Failed to add listen sockets to epoll\n"); + fputs("Failed to add listen sockets to epoll\n", stderr); exit_code = 1; goto cleanup; } @@ -90,7 +90,7 @@ int main(int argc, char **argv) // Add the pipe to the epoll instance if (add_pipe_to_epoll(epoll_fd) == -1) { - puts("Failed to add pipe to epoll\n"); + fputs("Failed to add pipe to epoll\n", stderr); exit_code = 1; goto cleanup; } @@ -255,7 +255,7 @@ int create_listen_sockets(const char *port_str, SocketManager *listen_socket_man if (listen_socket_manager->top == listen_socket_manager->max_size - 1) { - puts("server: failed to bind any sockets\n"); + fputs("server: failed to bind any sockets\n", stderr); return -1; } @@ -440,7 +440,7 @@ int handle_new_connection(int listen_socket_fd, int epoll_fd, SocketManager *cli // Fulfilled the maximum number of clients if (add_socket(client_socket_manager, conn_socket_fd) == -1) { - puts("No more room for clients\n"); + puts("No more room for clients"); close_with_retry(conn_socket_fd); return 0; } @@ -507,7 +507,7 @@ int handle_client(SocketData *client_socket_data, struct epoll_event event) } else if (received_bytes == 0) { - puts("Connection closed\n"); + puts("Connection closed"); return 0; } else From ae99da8a1dab232a0fa12bc822df5648360209bb Mon Sep 17 00:00:00 2001 From: tomoya-honda Date: Wed, 5 Feb 2025 02:31:05 +0000 Subject: [PATCH 03/17] Rename variable is_ipvx to ipvx_result to avoid confusion with boolean --- client.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client.c b/client.c index 57bdae5..aa80500 100644 --- a/client.c +++ b/client.c @@ -123,9 +123,9 @@ int create_connected_socket(const char *ip, const char *port_str) struct sockaddr_in6 server_addr6; memset(&server_addr4, 0, sizeof(server_addr4)); memset(&server_addr6, 0, sizeof(server_addr6)); - int is_ipv4 = inet_pton(PF_INET, ip, &server_addr4.sin_addr); - int is_ipv6 = inet_pton(PF_INET6, ip, &server_addr6.sin6_addr); - if (is_ipv4 <= 0 && is_ipv6 <= 0) + int ipv4_result = inet_pton(PF_INET, ip, &server_addr4.sin_addr); + int ipv6_result = inet_pton(PF_INET6, ip, &server_addr6.sin6_addr); + if (ipv4_result <= 0 && ipv6_result <= 0) { printf("Invalid IP address: %s\n", ip); return -1; @@ -141,7 +141,7 @@ int create_connected_socket(const char *ip, const char *port_str) // Create a socket and connect to the server int socket_fd; - if (is_ipv4 == 1) + if (ipv4_result == 1) { if ((socket_fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { @@ -163,7 +163,7 @@ int create_connected_socket(const char *ip, const char *port_str) return -1; } } - else if (is_ipv6 == 1) + else if (ipv6_result == 1) { if ((socket_fd = socket(PF_INET6, SOCK_STREAM, 0)) == -1) { From a5e468397e4f49aa80930e6586597eb01f51927a Mon Sep 17 00:00:00 2001 From: tomoya-honda Date: Wed, 5 Feb 2025 03:04:06 +0000 Subject: [PATCH 04/17] Modify socket manager initialization --- server.c | 24 ++++++++++++------------ utils.c | 4 +++- utils.h | 2 +- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/server.c b/server.c index de4446b..ee7df07 100644 --- a/server.c +++ b/server.c @@ -32,8 +32,8 @@ int main(int argc, char **argv) { // Declare variables that need to be cleaned up later int epoll_fd = -1; - SocketManager listen_socket_manager; - SocketManager client_socket_manager; + SocketManager *listen_socket_manager = NULL; + SocketManager *client_socket_manager = NULL; int exit_code = 0; // Check if the port number is provided @@ -53,8 +53,8 @@ int main(int argc, char **argv) } // Create listen sockets - init_socket_manager(&listen_socket_manager, MAX_LISTENS); - if (create_listen_sockets(argv[1], &listen_socket_manager) == -1) + listen_socket_manager = new_socket_manager(MAX_LISTENS); + if (create_listen_sockets(argv[1], listen_socket_manager) == -1) { fputs("Failed to create listen sockets\n", stderr); exit_code = 1; @@ -72,7 +72,7 @@ int main(int argc, char **argv) } // Add the listen sockets to the epoll instance - if (add_listen_sockets_to_epoll(epoll_fd, &listen_socket_manager) == -1) + if (add_listen_sockets_to_epoll(epoll_fd, listen_socket_manager) == -1) { fputs("Failed to add listen sockets to epoll\n", stderr); exit_code = 1; @@ -98,7 +98,7 @@ int main(int argc, char **argv) puts("Monitoring for events..."); struct epoll_event events[MAX_EVENTS]; - init_socket_manager(&client_socket_manager, MAX_CLIENTS); + client_socket_manager = new_socket_manager(MAX_CLIENTS); while (1) { // Wait for events indefinitely @@ -118,22 +118,22 @@ int main(int argc, char **argv) { SocketData *socket_data; // Check if the event is for the listen socket - if ((socket_data = find_socket(&listen_socket_manager, events[i].data.fd)) != NULL) + if ((socket_data = find_socket(listen_socket_manager, events[i].data.fd)) != NULL) { - if ((handle_new_connection(socket_data->socket_fd, epoll_fd, &client_socket_manager)) == -1) + if ((handle_new_connection(socket_data->socket_fd, epoll_fd, client_socket_manager)) == -1) { exit_code = 1; goto cleanup; } } // Check if the event is for a client socket - else if ((socket_data = find_socket(&client_socket_manager, events[i].data.fd)) != NULL) + else if ((socket_data = find_socket(client_socket_manager, events[i].data.fd)) != NULL) { if (handle_client(socket_data, events[i]) <= 0) { // The server itself does not exit even if the processing with the client ends abnormally. close_with_retry(socket_data->socket_fd); - remove_socket(&client_socket_manager, socket_data->socket_fd); + remove_socket(client_socket_manager, socket_data->socket_fd); } } // Check if the event is for the pipe @@ -165,8 +165,8 @@ int main(int argc, char **argv) { close_with_retry(epoll_fd); } - close_all_sockets(&client_socket_manager); - close_all_sockets(&listen_socket_manager); + close_all_sockets(client_socket_manager); + close_all_sockets(listen_socket_manager); close_with_retry(pipe_fds[0]); close_with_retry(pipe_fds[1]); diff --git a/utils.c b/utils.c index a476f4d..d18ddb1 100644 --- a/utils.c +++ b/utils.c @@ -6,8 +6,9 @@ #include "utils.h" -void init_socket_manager(SocketManager *manager, int max_size) +SocketManager *new_socket_manager(int max_size) { + SocketManager *manager = (SocketManager *)malloc(sizeof(SocketManager)); manager->sockets = (SocketData *)malloc(max_size * sizeof(SocketData)); manager->free_indices = (int *)malloc(max_size * sizeof(int)); manager->max_size = max_size; @@ -18,6 +19,7 @@ void init_socket_manager(SocketManager *manager, int max_size) manager->sockets[i].socket_fd = -1; manager->free_indices[i] = i; } + return manager; } SocketData *find_socket(SocketManager *manager, int socket_fd) diff --git a/utils.h b/utils.h index f3d1640..7822e6d 100644 --- a/utils.h +++ b/utils.h @@ -19,7 +19,7 @@ typedef struct int top; } SocketManager; -void init_socket_manager(SocketManager *manager, int max_size); +SocketManager *new_socket_manager(int max_size); SocketData *find_socket(SocketManager *manager, int socket_fd); int add_socket(SocketManager *manager, int socket_fd); int remove_socket(SocketManager *manager, int socket_fd); From 05d304ac7dcb429551dcfefbf0330509afe74f52 Mon Sep 17 00:00:00 2001 From: tomoya-honda Date: Wed, 5 Feb 2025 03:08:01 +0000 Subject: [PATCH 05/17] Modify socket manager cleanup --- server.c | 4 ++-- utils.c | 3 +-- utils.h | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/server.c b/server.c index ee7df07..bc88380 100644 --- a/server.c +++ b/server.c @@ -165,8 +165,8 @@ int main(int argc, char **argv) { close_with_retry(epoll_fd); } - close_all_sockets(client_socket_manager); - close_all_sockets(listen_socket_manager); + free_socket_manager(client_socket_manager); + free_socket_manager(listen_socket_manager); close_with_retry(pipe_fds[0]); close_with_retry(pipe_fds[1]); diff --git a/utils.c b/utils.c index d18ddb1..a17866d 100644 --- a/utils.c +++ b/utils.c @@ -59,7 +59,7 @@ int remove_socket(SocketManager *manager, int socket_fd) return -1; } -int close_all_sockets(SocketManager *manager) +void free_socket_manager(SocketManager *manager) { for (int i = 0; i < manager->max_size; i++) { @@ -70,7 +70,6 @@ int close_all_sockets(SocketManager *manager) } free(manager->sockets); free(manager->free_indices); - return 0; } int parse_port(const char *port_str) diff --git a/utils.h b/utils.h index 7822e6d..5508b21 100644 --- a/utils.h +++ b/utils.h @@ -23,7 +23,7 @@ SocketManager *new_socket_manager(int max_size); SocketData *find_socket(SocketManager *manager, int socket_fd); int add_socket(SocketManager *manager, int socket_fd); int remove_socket(SocketManager *manager, int socket_fd); -int close_all_sockets(SocketManager *manager); +void free_socket_manager(SocketManager *manager); int parse_port(const char *port_str); int close_with_retry(int fd); From 9c3a8b503026e158c9d19ee170005df54c54de19 Mon Sep 17 00:00:00 2001 From: tomoya-honda Date: Wed, 5 Feb 2025 03:15:00 +0000 Subject: [PATCH 06/17] Modify add_socket() return value --- server.c | 2 +- utils.c | 6 +++--- utils.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/server.c b/server.c index bc88380..04698d4 100644 --- a/server.c +++ b/server.c @@ -438,7 +438,7 @@ int handle_new_connection(int listen_socket_fd, int epoll_fd, SocketManager *cli } // Fulfilled the maximum number of clients - if (add_socket(client_socket_manager, conn_socket_fd) == -1) + if (add_socket(client_socket_manager, conn_socket_fd) == NULL) { puts("No more room for clients"); close_with_retry(conn_socket_fd); diff --git a/utils.c b/utils.c index a17866d..10eae97 100644 --- a/utils.c +++ b/utils.c @@ -34,15 +34,15 @@ SocketData *find_socket(SocketManager *manager, int socket_fd) return NULL; } -int add_socket(SocketManager *manager, int socket_fd) +SocketData *add_socket(SocketManager *manager, int socket_fd) { if (manager->top < 0) { - return -1; + return NULL; } int index = manager->free_indices[manager->top--]; manager->sockets[index].socket_fd = socket_fd; - return index; + return &manager->sockets[index]; } int remove_socket(SocketManager *manager, int socket_fd) diff --git a/utils.h b/utils.h index 5508b21..0f98a9c 100644 --- a/utils.h +++ b/utils.h @@ -21,7 +21,7 @@ typedef struct SocketManager *new_socket_manager(int max_size); SocketData *find_socket(SocketManager *manager, int socket_fd); -int add_socket(SocketManager *manager, int socket_fd); +SocketData *add_socket(SocketManager *manager, int socket_fd); int remove_socket(SocketManager *manager, int socket_fd); void free_socket_manager(SocketManager *manager); From 4e51db477465c3af302b1f23283ac4a4ebbd6bbf Mon Sep 17 00:00:00 2001 From: tomoya-honda Date: Wed, 5 Feb 2025 04:50:53 +0000 Subject: [PATCH 07/17] Fix some minors --- server.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/server.c b/server.c index 04698d4..2f68f6d 100644 --- a/server.c +++ b/server.c @@ -170,11 +170,7 @@ int main(int argc, char **argv) close_with_retry(pipe_fds[0]); close_with_retry(pipe_fds[1]); - if (exit_code != 0) - { - exit(exit_code); - } - return 0; + return exit_code; } /** @@ -245,7 +241,7 @@ int create_listen_sockets(const char *port_str, SocketManager *listen_socket_man { perror("server: listen()"); close_with_retry(listen_socket_fd); - return -1; + continue; } add_socket(listen_socket_manager, listen_socket_fd); From c761ffd79dcecfe271b3b97489f6cbebef7888c3 Mon Sep 17 00:00:00 2001 From: tomoya-honda Date: Wed, 5 Feb 2025 04:59:44 +0000 Subject: [PATCH 08/17] Add get_socket_count() --- server.c | 2 +- utils.c | 5 +++++ utils.h | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/server.c b/server.c index 2f68f6d..02b46b5 100644 --- a/server.c +++ b/server.c @@ -249,7 +249,7 @@ int create_listen_sockets(const char *port_str, SocketManager *listen_socket_man freeaddrinfo(res0); - if (listen_socket_manager->top == listen_socket_manager->max_size - 1) + if (get_socket_count(listen_socket_manager) == 0) { fputs("server: failed to bind any sockets\n", stderr); return -1; diff --git a/utils.c b/utils.c index 10eae97..11b6f53 100644 --- a/utils.c +++ b/utils.c @@ -45,6 +45,11 @@ SocketData *add_socket(SocketManager *manager, int socket_fd) return &manager->sockets[index]; } +int get_socket_count(SocketManager *manager) +{ + return (manager->max_size - 1) - manager->top; +} + int remove_socket(SocketManager *manager, int socket_fd) { for (int i = 0; i < manager->max_size; i++) diff --git a/utils.h b/utils.h index 0f98a9c..e0c6a31 100644 --- a/utils.h +++ b/utils.h @@ -22,6 +22,7 @@ typedef struct SocketManager *new_socket_manager(int max_size); SocketData *find_socket(SocketManager *manager, int socket_fd); SocketData *add_socket(SocketManager *manager, int socket_fd); +int get_socket_count(SocketManager *manager); int remove_socket(SocketManager *manager, int socket_fd); void free_socket_manager(SocketManager *manager); From baf095b1b0ccefc8996b811059b94865d73689f6 Mon Sep 17 00:00:00 2001 From: tomoya-honda Date: Wed, 5 Feb 2025 05:23:40 +0000 Subject: [PATCH 09/17] Ensure cleanup process works correctly in all scenarios --- server.c | 12 +++++++++--- utils.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/server.c b/server.c index 02b46b5..0df565f 100644 --- a/server.c +++ b/server.c @@ -19,7 +19,7 @@ #define MAX_CLIENTS 30 #define MAX_EVENTS 10 -int pipe_fds[2]; +int pipe_fds[2] = {-1, -1}; int create_listen_sockets(const char *port_str, SocketManager *listen_socket_manager); int add_listen_sockets_to_epoll(int epoll_fd, SocketManager *listen_socket_manager); @@ -161,14 +161,20 @@ int main(int argc, char **argv) } cleanup: + if (pipe_fds[0] != -1) + { + close_with_retry(pipe_fds[0]); + } + if (pipe_fds[1] != -1) + { + close_with_retry(pipe_fds[1]); + } if (epoll_fd != -1) { close_with_retry(epoll_fd); } free_socket_manager(client_socket_manager); free_socket_manager(listen_socket_manager); - close_with_retry(pipe_fds[0]); - close_with_retry(pipe_fds[1]); return exit_code; } diff --git a/utils.c b/utils.c index 11b6f53..d3b92dc 100644 --- a/utils.c +++ b/utils.c @@ -9,8 +9,27 @@ SocketManager *new_socket_manager(int max_size) { SocketManager *manager = (SocketManager *)malloc(sizeof(SocketManager)); + if (manager == NULL) + { + perror("malloc(sizeof(SocketManager))"); + return NULL; + } + manager->sockets = (SocketData *)malloc(max_size * sizeof(SocketData)); + if (manager->sockets == NULL) + { + perror("malloc(max_size * sizeof(SocketData))"); + free(manager); + return NULL; + } manager->free_indices = (int *)malloc(max_size * sizeof(int)); + if (manager->free_indices == NULL) + { + perror("malloc(max_size * sizeof(int))"); + free(manager->sockets); + free(manager); + return NULL; + } manager->max_size = max_size; manager->top = max_size - 1; @@ -24,6 +43,11 @@ SocketManager *new_socket_manager(int max_size) SocketData *find_socket(SocketManager *manager, int socket_fd) { + if (manager == NULL) + { + return NULL; + } + for (int i = 0; i < manager->max_size; i++) { if (manager->sockets[i].socket_fd == socket_fd) @@ -36,6 +60,11 @@ SocketData *find_socket(SocketManager *manager, int socket_fd) SocketData *add_socket(SocketManager *manager, int socket_fd) { + if (manager == NULL) + { + return NULL; + } + if (manager->top < 0) { return NULL; @@ -47,11 +76,20 @@ SocketData *add_socket(SocketManager *manager, int socket_fd) int get_socket_count(SocketManager *manager) { + if (manager == NULL) + { + return -1; + } return (manager->max_size - 1) - manager->top; } int remove_socket(SocketManager *manager, int socket_fd) { + if (manager == NULL) + { + return -1; + } + for (int i = 0; i < manager->max_size; i++) { if (manager->sockets[i].socket_fd == socket_fd) @@ -66,6 +104,11 @@ int remove_socket(SocketManager *manager, int socket_fd) void free_socket_manager(SocketManager *manager) { + if (manager == NULL) + { + return; + } + for (int i = 0; i < manager->max_size; i++) { if (manager->sockets[i].socket_fd != -1) @@ -75,6 +118,7 @@ void free_socket_manager(SocketManager *manager) } free(manager->sockets); free(manager->free_indices); + free(manager); } int parse_port(const char *port_str) From 7c7cebe8293256fd902b72f69461577698931415 Mon Sep 17 00:00:00 2001 From: tomoya-honda Date: Wed, 5 Feb 2025 05:31:57 +0000 Subject: [PATCH 10/17] Add print_client_info() --- server.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/server.c b/server.c index 0df565f..d6a9148 100644 --- a/server.c +++ b/server.c @@ -25,6 +25,7 @@ int create_listen_sockets(const char *port_str, SocketManager *listen_socket_man int add_listen_sockets_to_epoll(int epoll_fd, SocketManager *listen_socket_manager); int add_pipe_to_epoll(int epoll_fd); int handle_new_connection(int listen_socket_fd, int epoll_fd, SocketManager *client_socket_manager); +int print_client_info(struct sockaddr_storage *client_addr); int handle_client(SocketData *client_socket_data, struct epoll_event event); void handle_sigint(int sig); @@ -457,10 +458,32 @@ int handle_new_connection(int listen_socket_fd, int epoll_fd, SocketManager *cli return -1; } + if (print_client_info(&client_addr) == -1) + { + perror("server: print_client_info()"); + close_with_retry(conn_socket_fd); + return -1; + } + + return 0; +} + +/** + * @brief Print the client information. + * + * This function prints the IP address and port number of the client. + * + * @param[in] client_addr The client address information. + * @return The status of the client information printing. + * @retval 0 The client information was successfully printed. + * @retval -1 An error occurred during the process. + */ +int print_client_info(struct sockaddr_storage *client_addr) +{ char client_ip[INET6_ADDRSTRLEN]; - if (client_addr.ss_family == PF_INET) + if (client_addr->ss_family == PF_INET) { - struct sockaddr_in *client_addr4 = (struct sockaddr_in *)&client_addr; + struct sockaddr_in *client_addr4 = (struct sockaddr_in *)client_addr; if (inet_ntop(PF_INET, &client_addr4->sin_addr, client_ip, sizeof(client_ip)) == NULL) { perror("server: inet_ntop(PF_INET)"); @@ -468,9 +491,9 @@ int handle_new_connection(int listen_socket_fd, int epoll_fd, SocketManager *cli } printf("Connection from %s, %d\n", client_ip, ntohs(client_addr4->sin_port)); } - else if (client_addr.ss_family == PF_INET6) + else if (client_addr->ss_family == PF_INET6) { - struct sockaddr_in6 *client_addr6 = (struct sockaddr_in6 *)&client_addr; + struct sockaddr_in6 *client_addr6 = (struct sockaddr_in6 *)client_addr; if (inet_ntop(PF_INET6, &client_addr6->sin6_addr, client_ip, sizeof(client_ip)) == NULL) { perror("server: inet_ntop(PF_INET6)"); From dd999cc11fa31d4aa5183feb18f2b11ac01ce6e1 Mon Sep 17 00:00:00 2001 From: tomoya-honda Date: Wed, 5 Feb 2025 06:09:25 +0000 Subject: [PATCH 11/17] Refactor connection handling to unify IPv4 and IPv6 processing --- client.c | 77 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/client.c b/client.c index aa80500..3e3ab6e 100644 --- a/client.c +++ b/client.c @@ -11,6 +11,7 @@ #define BUFFER_SIZE 256 int create_connected_socket(const char *ip, const char *port); +int connect_to_server(int protocol_family, struct sockaddr *server_addr, socklen_t server_addr_len, int port); int main(int argc, char **argv) { @@ -143,47 +144,11 @@ int create_connected_socket(const char *ip, const char *port_str) int socket_fd; if (ipv4_result == 1) { - if ((socket_fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) - { - perror("client: socket()"); - return -1; - } - - server_addr4.sin_family = PF_INET; - server_addr4.sin_port = htons(port); - - while (connect(socket_fd, (struct sockaddr *)&server_addr4, sizeof(server_addr4)) == -1) - { - if (errno == EINTR) - { - continue; - } - perror("client: connect() using IPv4"); - close_with_retry(socket_fd); - return -1; - } + socket_fd = connect_to_server(PF_INET, (struct sockaddr *)&server_addr4, sizeof(server_addr4), port); } else if (ipv6_result == 1) { - if ((socket_fd = socket(PF_INET6, SOCK_STREAM, 0)) == -1) - { - perror("client: socket() using IPv6"); - return -1; - } - - server_addr6.sin6_family = PF_INET6; - server_addr6.sin6_port = htons(port); - - while (connect(socket_fd, (struct sockaddr *)&server_addr6, sizeof(server_addr6)) == -1) - { - if (errno == EINTR) - { - continue; - } - perror("client: connect() using IPv6"); - close_with_retry(socket_fd); - return -1; - } + socket_fd = connect_to_server(PF_INET6, (struct sockaddr *)&server_addr6, sizeof(server_addr6), port); } else { @@ -194,3 +159,39 @@ int create_connected_socket(const char *ip, const char *port_str) printf("Connected to %s, %d\n", ip, port); return socket_fd; } + +int connect_to_server(int protocol_family, struct sockaddr *server_addr, socklen_t server_addr_len, int port) +{ + int socket_fd; + if ((socket_fd = socket(protocol_family, SOCK_STREAM, 0)) == -1) + { + perror("client: socket()"); + return -1; + } + + if (protocol_family == PF_INET) + { + struct sockaddr_in *server_addr4 = (struct sockaddr_in *)server_addr; + server_addr4->sin_family = PF_INET; + server_addr4->sin_port = htons(port); + } + else if (protocol_family == PF_INET6) + { + struct sockaddr_in6 *server_addr6 = (struct sockaddr_in6 *)server_addr; + server_addr6->sin6_family = PF_INET6; + server_addr6->sin6_port = htons(port); + } + + while (connect(socket_fd, server_addr, server_addr_len) == -1) + { + if (errno == EINTR) + { + continue; + } + perror("client: connect()"); + close_with_retry(socket_fd); + return -1; + } + + return socket_fd; +} From cff4b9c11a7cdb4c6a6c7fd5d792a68068accef0 Mon Sep 17 00:00:00 2001 From: tomoya-honda Date: Wed, 5 Feb 2025 08:27:42 +0000 Subject: [PATCH 12/17] Set MSG_NOSIGNAL to send() not to generate SIGPIPE --- server.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server.c b/server.c index d6a9148..4a95872 100644 --- a/server.c +++ b/server.c @@ -550,7 +550,8 @@ int handle_client(SocketData *client_socket_data, struct epoll_event event) if (event.events & EPOLLOUT) { ssize_t sent_bytes; - if ((sent_bytes = send(client_socket_data->socket_fd, client_socket_data->buffer, strlen(client_socket_data->buffer), 0)) >= 0) + // Set MSG_NOSIGNAL to prevent the server from crashing when the client disconnects + if ((sent_bytes = send(client_socket_data->socket_fd, client_socket_data->buffer, strlen(client_socket_data->buffer), MSG_NOSIGNAL)) >= 0) { memmove(client_socket_data->buffer, client_socket_data->buffer + sent_bytes, strlen(client_socket_data->buffer) - sent_bytes); client_socket_data->buffer[strlen(client_socket_data->buffer) - sent_bytes] = '\0'; From 0abfd62b0f78c966ed23ff3ef0a712d61403d752 Mon Sep 17 00:00:00 2001 From: tomoya-honda Date: Thu, 6 Feb 2025 03:20:28 +0000 Subject: [PATCH 13/17] Store a pointer in event.data.ptr for O(1) lookup --- server.c | 18 ++++++++++++------ utils.c | 4 +++- utils.h | 12 ++++++++++-- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/server.c b/server.c index 4a95872..08dc2a8 100644 --- a/server.c +++ b/server.c @@ -117,9 +117,9 @@ int main(int argc, char **argv) for (int i = 0; i < nfds; i++) { - SocketData *socket_data; + SocketData *socket_data = events[i].data.ptr; // Check if the event is for the listen socket - if ((socket_data = find_socket(listen_socket_manager, events[i].data.fd)) != NULL) + if (socket_data->type == LISTEN_SOCKET) { if ((handle_new_connection(socket_data->socket_fd, epoll_fd, client_socket_manager)) == -1) { @@ -128,7 +128,7 @@ int main(int argc, char **argv) } } // Check if the event is for a client socket - else if ((socket_data = find_socket(client_socket_manager, events[i].data.fd)) != NULL) + else if (socket_data->type == CLIENT_SOCKET) { if (handle_client(socket_data, events[i]) <= 0) { @@ -138,7 +138,7 @@ int main(int argc, char **argv) } } // Check if the event is for the pipe - else if (events[i].data.fd == pipe_fds[0]) + else if (socket_data->type == SIGNAL_PIPE) { int sig; while (read(pipe_fds[0], &sig, sizeof(sig)) == -1) @@ -251,7 +251,7 @@ int create_listen_sockets(const char *port_str, SocketManager *listen_socket_man continue; } - add_socket(listen_socket_manager, listen_socket_fd); + add_socket(listen_socket_manager, LISTEN_SOCKET, listen_socket_fd); } freeaddrinfo(res0); @@ -313,6 +313,7 @@ int add_listen_sockets_to_epoll(int epoll_fd, SocketManager *listen_socket_manag // Add the listen socket to the epoll instance event.events = EPOLLIN; event.data.fd = listen_socket_fd; + event.data.ptr = &listen_socket_manager->sockets[i]; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_socket_fd, &event) == -1) { perror("server: epoll_ctl()"); @@ -373,6 +374,9 @@ int add_pipe_to_epoll(int epoll_fd) struct epoll_event event; event.events = EPOLLIN; event.data.fd = pipe_fds[0]; + SocketData *pipe_data = (SocketData *)malloc(sizeof(SocketData)); + pipe_data->type = SIGNAL_PIPE; + event.data.ptr = pipe_data; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pipe_fds[0], &event) == -1) { perror("server: epoll_ctl()"); @@ -441,7 +445,8 @@ int handle_new_connection(int listen_socket_fd, int epoll_fd, SocketManager *cli } // Fulfilled the maximum number of clients - if (add_socket(client_socket_manager, conn_socket_fd) == NULL) + SocketData *conn_socket_data = NULL; + if ((conn_socket_data = add_socket(client_socket_manager, CLIENT_SOCKET, conn_socket_fd)) == NULL) { puts("No more room for clients"); close_with_retry(conn_socket_fd); @@ -451,6 +456,7 @@ int handle_new_connection(int listen_socket_fd, int epoll_fd, SocketManager *cli struct epoll_event event; event.events = EPOLLIN | EPOLLOUT; event.data.fd = conn_socket_fd; + event.data.ptr = conn_socket_data; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_socket_fd, &event) == -1) { perror("server: epoll_ctl()"); diff --git a/utils.c b/utils.c index d3b92dc..44ff867 100644 --- a/utils.c +++ b/utils.c @@ -41,6 +41,7 @@ SocketManager *new_socket_manager(int max_size) return manager; } +// NO USE SocketData *find_socket(SocketManager *manager, int socket_fd) { if (manager == NULL) @@ -58,7 +59,7 @@ SocketData *find_socket(SocketManager *manager, int socket_fd) return NULL; } -SocketData *add_socket(SocketManager *manager, int socket_fd) +SocketData *add_socket(SocketManager *manager, SocketType type, int socket_fd) { if (manager == NULL) { @@ -70,6 +71,7 @@ SocketData *add_socket(SocketManager *manager, int socket_fd) return NULL; } int index = manager->free_indices[manager->top--]; + manager->sockets[index].type = type; manager->sockets[index].socket_fd = socket_fd; return &manager->sockets[index]; } diff --git a/utils.h b/utils.h index e0c6a31..0a4f291 100644 --- a/utils.h +++ b/utils.h @@ -5,8 +5,16 @@ #define BUFFER_SIZE 256 +typedef enum +{ + LISTEN_SOCKET, + CLIENT_SOCKET, + SIGNAL_PIPE, +} SocketType; + typedef struct { + SocketType type; int socket_fd; char buffer[BUFFER_SIZE]; // TODO: Use dynamic memory allocation for the buffer } SocketData; @@ -20,8 +28,8 @@ typedef struct } SocketManager; SocketManager *new_socket_manager(int max_size); -SocketData *find_socket(SocketManager *manager, int socket_fd); -SocketData *add_socket(SocketManager *manager, int socket_fd); +SocketData *find_socket(SocketManager *manager, int socket_fd); // NO USE +SocketData *add_socket(SocketManager *manager, SocketType type, int socket_fd); int get_socket_count(SocketManager *manager); int remove_socket(SocketManager *manager, int socket_fd); void free_socket_manager(SocketManager *manager); From 014e1724de99524217ce69faf8b26653a26370bb Mon Sep 17 00:00:00 2001 From: tomoya-honda Date: Thu, 6 Feb 2025 03:31:02 +0000 Subject: [PATCH 14/17] Modify to shutdown after closing all connections --- server.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/server.c b/server.c index 08dc2a8..3da6ffb 100644 --- a/server.c +++ b/server.c @@ -18,8 +18,10 @@ #define MAX_LISTENS 20 #define MAX_CLIENTS 30 #define MAX_EVENTS 10 +#define EPOLL_TIMEOUT_MILLISECONDS 5000 int pipe_fds[2] = {-1, -1}; +volatile sig_atomic_t sigint_received = 0; int create_listen_sockets(const char *port_str, SocketManager *listen_socket_manager); int add_listen_sockets_to_epoll(int epoll_fd, SocketManager *listen_socket_manager); @@ -103,7 +105,7 @@ int main(int argc, char **argv) while (1) { // Wait for events indefinitely - int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); + int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, EPOLL_TIMEOUT_MILLISECONDS); if (nfds == -1) { if (errno == EINTR) @@ -154,11 +156,21 @@ int main(int argc, char **argv) if (sig == SIGINT) { - puts("Received SIGINT, exiting..."); - goto cleanup; + puts("Received SIGINT, closing all connections..."); + free_socket_manager(client_socket_manager); + client_socket_manager = NULL; + free_socket_manager(listen_socket_manager); + listen_socket_manager = NULL; } } } + + // Check if SIGINT was received and all connections are closed + if (sigint_received == 1 && listen_socket_manager == NULL && client_socket_manager == NULL) + { + puts("All connections closed, exiting..."); + break; + } } cleanup: @@ -594,4 +606,5 @@ void handle_sigint(int sig) perror("server: write()"); exit(1); } + sigint_received = 1; } From 0f8875e71307d68cb7fd20dc5d4a5a279255c955 Mon Sep 17 00:00:00 2001 From: tomoya-honda Date: Thu, 6 Feb 2025 03:38:03 +0000 Subject: [PATCH 15/17] Set shutdown timeout --- server.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/server.c b/server.c index 3da6ffb..b1c61de 100644 --- a/server.c +++ b/server.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "utils.h" @@ -18,7 +19,8 @@ #define MAX_LISTENS 20 #define MAX_CLIENTS 30 #define MAX_EVENTS 10 -#define EPOLL_TIMEOUT_MILLISECONDS 5000 +#define EPOLL_TIMEOUT_MILLISECONDS 1000 +#define SHUTDOWN_TIMEOUT_SECONDS 10 int pipe_fds[2] = {-1, -1}; volatile sig_atomic_t sigint_received = 0; @@ -38,6 +40,7 @@ int main(int argc, char **argv) SocketManager *listen_socket_manager = NULL; SocketManager *client_socket_manager = NULL; int exit_code = 0; + time_t shutdown_start_time = 0; // Check if the port number is provided if (argc != 2) @@ -161,6 +164,14 @@ int main(int argc, char **argv) client_socket_manager = NULL; free_socket_manager(listen_socket_manager); listen_socket_manager = NULL; + + shutdown_start_time = time(NULL); + if (shutdown_start_time == -1) + { + perror("server: time()"); + exit_code = 1; + goto cleanup; + } } } } @@ -171,6 +182,24 @@ int main(int argc, char **argv) puts("All connections closed, exiting..."); break; } + + // Check if shutdown timeout has elapsed + if (shutdown_start_time != 0) + { + time_t current_time = time(NULL); + if (current_time == -1) + { + perror("server: time()"); + exit_code = 1; + goto cleanup; + } + + if (current_time - shutdown_start_time >= SHUTDOWN_TIMEOUT_SECONDS) + { + puts("Shutdown timeout elapsed, exiting..."); + break; + } + } } cleanup: From 88f7fb0e55ad1583062d22bce4f90659e2c20689 Mon Sep 17 00:00:00 2001 From: tomoya-honda Date: Thu, 6 Feb 2025 06:24:58 +0000 Subject: [PATCH 16/17] Add buffer_start & buffer_end to SocketData to manage buffer efficiently --- server.c | 28 +++++++++++++++++++++++----- utils.c | 2 ++ utils.h | 2 ++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/server.c b/server.c index b1c61de..f998c18 100644 --- a/server.c +++ b/server.c @@ -571,11 +571,18 @@ int handle_client(SocketData *client_socket_data, struct epoll_event event) // Check if the client socket is ready to read if (event.events & EPOLLIN) { + // Check if there is space in the buffer + size_t available_size = BUFFER_SIZE - client_socket_data->buffer_end; + if (available_size == 0) + { + return 1; + } + ssize_t received_bytes; - if ((received_bytes = recv(client_socket_data->socket_fd, client_socket_data->buffer, BUFFER_SIZE - 1, 0)) > 0) + if ((received_bytes = recv(client_socket_data->socket_fd, client_socket_data->buffer + client_socket_data->buffer_end, available_size, 0)) > 0) { printf("received_bytes: %ld (fd: %d)\n", received_bytes, client_socket_data->socket_fd); - client_socket_data->buffer[received_bytes] = '\0'; // Null-terminate the string + client_socket_data->buffer_end += received_bytes; } else if (received_bytes == 0) { @@ -596,12 +603,23 @@ int handle_client(SocketData *client_socket_data, struct epoll_event event) // Check if the client socket is ready to write if (event.events & EPOLLOUT) { + // Check if there is pending data to send + size_t pending_size = client_socket_data->buffer_end - client_socket_data->buffer_start; + if (pending_size == 0) + { + return 1; + } + ssize_t sent_bytes; // Set MSG_NOSIGNAL to prevent the server from crashing when the client disconnects - if ((sent_bytes = send(client_socket_data->socket_fd, client_socket_data->buffer, strlen(client_socket_data->buffer), MSG_NOSIGNAL)) >= 0) + if ((sent_bytes = send(client_socket_data->socket_fd, client_socket_data->buffer + client_socket_data->buffer_start, pending_size, MSG_NOSIGNAL)) >= 0) { - memmove(client_socket_data->buffer, client_socket_data->buffer + sent_bytes, strlen(client_socket_data->buffer) - sent_bytes); - client_socket_data->buffer[strlen(client_socket_data->buffer) - sent_bytes] = '\0'; + client_socket_data->buffer_start += sent_bytes; + if (client_socket_data->buffer_start == client_socket_data->buffer_end) + { + client_socket_data->buffer_start = 0; + client_socket_data->buffer_end = 0; + } } else { diff --git a/utils.c b/utils.c index 44ff867..9a26e45 100644 --- a/utils.c +++ b/utils.c @@ -73,6 +73,8 @@ SocketData *add_socket(SocketManager *manager, SocketType type, int socket_fd) int index = manager->free_indices[manager->top--]; manager->sockets[index].type = type; manager->sockets[index].socket_fd = socket_fd; + manager->sockets[index].buffer_start = 0; + manager->sockets[index].buffer_end = 0; return &manager->sockets[index]; } diff --git a/utils.h b/utils.h index 0a4f291..0124c3e 100644 --- a/utils.h +++ b/utils.h @@ -17,6 +17,8 @@ typedef struct SocketType type; int socket_fd; char buffer[BUFFER_SIZE]; // TODO: Use dynamic memory allocation for the buffer + size_t buffer_start; + size_t buffer_end; } SocketData; typedef struct From 287fac9a646d6ac9941a4f43bb99fd1351da3f3b Mon Sep 17 00:00:00 2001 From: tomoya-honda Date: Thu, 6 Feb 2025 06:46:52 +0000 Subject: [PATCH 17/17] Remove unused functions --- utils.c | 18 ------------------ utils.h | 1 - 2 files changed, 19 deletions(-) diff --git a/utils.c b/utils.c index 9a26e45..6cc59d1 100644 --- a/utils.c +++ b/utils.c @@ -41,24 +41,6 @@ SocketManager *new_socket_manager(int max_size) return manager; } -// NO USE -SocketData *find_socket(SocketManager *manager, int socket_fd) -{ - if (manager == NULL) - { - return NULL; - } - - for (int i = 0; i < manager->max_size; i++) - { - if (manager->sockets[i].socket_fd == socket_fd) - { - return &manager->sockets[i]; - } - } - return NULL; -} - SocketData *add_socket(SocketManager *manager, SocketType type, int socket_fd) { if (manager == NULL) diff --git a/utils.h b/utils.h index 0124c3e..af93e68 100644 --- a/utils.h +++ b/utils.h @@ -30,7 +30,6 @@ typedef struct } SocketManager; SocketManager *new_socket_manager(int max_size); -SocketData *find_socket(SocketManager *manager, int socket_fd); // NO USE SocketData *add_socket(SocketManager *manager, SocketType type, int socket_fd); int get_socket_count(SocketManager *manager); int remove_socket(SocketManager *manager, int socket_fd);