#include #include #include #include #include #include #include #include #include #include "client.h" #include "connection.h" #include "event_loop.h" #include "server.h" #include "utils.h" /* * Data */ static bool _to_work = true; static int _sig_fd = -1; static int _server_fd = -1; static bool _is_server = false; /* * Private API */ // Parse command line arguments and check if mandatory ones are present. // Parameters: // - argc // - argv // Returns: // - true on success // - false on failure bool parse_cli_args(int argc, char** argv) { if (argc < 2) { return false; } int key_length, value_length; int i = 1; char first_sym; while (i < argc) { key_length = strlen(argv[i] + 1); first_sym = argv[i][0]; if (key_length != 1 || (first_sym != '+' && first_sym != '-')) { fprintf(stderr, "[!] Argument '%s' is discarded\n", argv[i]); return false; } // flag if (first_sym == '+') { cli_arg_set(argv[i] + 1, argv[i] + 1); i++; continue; } // argument if (i + 1 >= argc) { fprintf(stderr, "[!] Argument '%s' misses a value\n", argv[i]); return false; } value_length = strlen(argv[i + 1]); if (value_length < 1) { fprintf(stderr, "[!] Argument '%s' has empty value\n", argv[i]); return false; } cli_arg_set(argv[i] + 1, argv[i + 1]); i += 2; } bool required_args_present = true; required_args_present &= cli_arg_get("M") ? true : false; required_args_present &= cli_arg_get("A") ? true : false; required_args_present &= cli_arg_get("P") ? true : false; required_args_present &= cli_arg_get("E") ? true : false; if (!required_args_present) { fprintf(stderr, "[!] Some required arguments are missing\n"); return false; } const char *mode = cli_arg_get("M"); if (strcmp(mode, "server") && strcmp(mode, "client")) { fprintf(stderr, "[!] Unknown mode '%s'\n", mode); return false; } _is_server = !strcmp(mode, "server"); flag_verbose = cli_arg_get("V") ? 1 : 0; if (flag_verbose) { fprintf(stdout, "[I] Being verbose\n"); fprintf(stdout, "[I] - Mode ------ %s\n", cli_arg_get("M")); fprintf(stdout, "[I] - Address --- %s:%d\n", cli_arg_get("A"), atoi(cli_arg_get("P"))); fprintf(stdout, "[I] - Extension - %s\n", cli_arg_get("E")); } return true; } // Initialize signals. // Returns: // - true on success // Remarks: // - loop_init() must be called before this one static bool signals_init() { sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGTERM); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGQUIT); if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) { fprintf(stderr, "[!] sigprocmask failed: %d\n", errno); return false; } _sig_fd = signalfd( -1, &mask, SFD_NONBLOCK ); if (_sig_fd == -1) { fprintf(stderr, "[!] signalfd failed: %d\n", errno); return false; } struct epoll_event ev; ev.data.fd = _sig_fd; ev.events = EPOLLIN; bool loop_res = loop_ctl( EPOLL_CTL_ADD, _sig_fd, &ev ); if (!loop_res) { close(_sig_fd); fprintf(stderr, "[!] loop_ctl failed\n"); return false; } return true; } // Finalize signals. static void signals_deinit() { close(_sig_fd); } // Initialize the server. // Returns: // - true on success static bool server_init() { _server_fd = server_open(cli_arg_get("A"), atoi(cli_arg_get("P"))); if (_server_fd == -1) { return false; } struct epoll_event ev; ev.data.fd = _server_fd; ev.events = EPOLLIN; bool loop_res = loop_ctl( EPOLL_CTL_ADD, _server_fd, &ev ); if (!loop_res) { server_close(); fprintf(stderr, "[!] loop_ctl failed\n"); return false; } return true; } // Finalize the server. static void server_deinit() { server_close(); } /* * Callbacks and main */ // This callback is called by loop_wait when event happens. static void on_fd_event(int fd, uint32_t events) { // Termination if (fd == _sig_fd) { _to_work = false; } // Server event else if (fd == _server_fd) { if (!server_event(_server_fd, events)) { fprintf(stderr, "[!] server_event failed\n"); _to_work = false; } } // Connection event else if (connection_is_socket_managed(fd)) { connection_event(fd, events); } // Client event else if (client_event(fd, events)) { // nothing here } else { fprintf(stderr, "[!] Event has happened on an unknown file descriptor\n"); } } int main(int argc, char **argv) { // Initialization if (!parse_cli_args(argc, argv)) { print_usage_text(); return 1; } if (!loop_init(on_fd_event)) { return 1; } if (!signals_init()) { loop_deinit(); return 1; } if (_is_server) { if (!server_init()) { signals_deinit(); loop_deinit(); return 1; } } else { if (!client_init()) { signals_deinit(); loop_deinit(); return 1; } } // Loop while (_to_work) { if (!loop_wait()) { fprintf(stderr, "[!] loop_wait returns false, stopping...\n"); break; } fprintf(stderr, "--- loop ---\n"); } // Termination if (_is_server) { server_close(); } else { client_deinit(); } connection_cleanup(); signals_deinit(); loop_deinit(); return 0; }