diff options
Diffstat (limited to 'btasktd.c')
| -rw-r--r-- | btasktd.c | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/btasktd.c b/btasktd.c new file mode 100644 index 0000000..81100bf --- /dev/null +++ b/btasktd.c @@ -0,0 +1,186 @@ +/*- + * Copyright (c) 2026, Mr. Goblin + * + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <netinet/in.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include "cliflags.h" + +#define BTASKTD_HELP_STR \ + "Copyright (c) 2026 Mr. Goblin\n" \ + "btasktd - task tracking TCP-server\n" \ + "Usage: btasktd [-Vh] [-p port] [-u users]\n" \ + "For more info read program's man page\n" + +#define BTASKTD_VERSION_STR \ + "0.0.0" + +#ifndef BTASKTD_QUEUE_LEN +# define BTASKTD_QUEUE_LEN 16 +#endif + +static void +fprint_help(FILE *f) +{ + fputs(BTASKTD_HELP_STR, f); +} + +static void +set_nonblock(int fd) +{ + int fflags = fcntl(fd, F_GETFL); + fcntl(fd, F_SETFL, fflags|O_NONBLOCK); +} + +int +main(int argc, char **argv) +{ + int server_fd, opt = 1, res, port, passed_flags = 1, users_cnt; + int *users = NULL; + struct sockaddr_in addr = {0}; + struct int_flag_val int_res; + struct bool_flag_val show_ver, show_help; + + show_ver = extract_bool_flag('V', argc, argv); + if (fvr_ok == show_ver.code && show_ver.data) { + printf("btasktd version %s\n", BTASKTD_VERSION_STR); + return 0; + } + + show_help = extract_bool_flag('h', argc, argv); + if (show_help.code == fvr_ok && show_help.data) { + fprint_help(stdout); + return 0; + } + + int_res = extract_int_flag('p', argc, argv); + switch (int_res.code) { + case fvr_not_found: +# ifdef BTASKTD_DEFAULT_PORT + port = BTASKTD_DEFAULT_PORT; +# else + fputs("No port specified!\n", stderr); + passed_flags = 0; +# endif + break; + case fvr_ok: + port = int_res.data; + if (port > 0) + break; + /* fallthrough */ + case fvr_invalid: + fputs("Invalid port!\n", stderr); + return 1; + break; + } + + int_res = extract_int_flag('u', argc, argv); + switch (int_res.code) { + case fvr_not_found: +# ifdef BTASKTD_DEFAULT_USERS_CNT + users_cnt = BTASKTD_DEFAULT_USERS_CNT; +# else + fputs("No users count specified!\n", stderr); + passed_flags = 0; +# endif + break; + case fvr_ok: + users_cnt = int_res.data; + if (users_cnt > 0) + break; + /* fallthrough */ + case fvr_invalid: + fputs("Invalid users count!\n", stderr); + return 1; + break; + } + + if (!passed_flags) { + fputs("-\n", stderr); + fprint_help(stderr); + return 1; + } + + users = (int*)malloc(users_cnt * sizeof(int)); + if (NULL == users) { + fputs("No memory!\n", stderr); + return 1; + } + + server_fd = socket(AF_INET, SOCK_STREAM, 0); + if (server_fd < 0) { + free(users); + perror("socket"); + return 1; + } + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + res = bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)); + if (0 != res) { + close(server_fd); + free(users); + perror("bind"); + return 1; + } + res = listen(server_fd, BTASKTD_QUEUE_LEN); + if (0 != res) { + close(server_fd); + free(users); + perror("listen"); + return 1; + } + res = setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, + &opt, sizeof(opt)); + if (0 != res) { + close(server_fd); + free(users); + perror("setsockopt"); + return 1; + } + + set_nonblock(server_fd); + printf("btaskt server btasktd started on port %d\n", port); + + /* main loop here */ + + printf("btaskt server btasktd stopped\n"); + close(server_fd); + free(users); + return 0; +} |
