/*- * 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 #include #include #include #include #include #include #include #include #include #include #ifndef BTASKTD_QUEUE_LEN # define QUEUE_LEN 16 #endif enum flag_val_res { fvr_not_found = -1, fvr_min = fvr_not_found, fvr_ok = 0, fvr_invalid, fvr_max = fvr_invalid }; struct str_flag_val { enum flag_val_res code; char *data; }; struct int_flag_val { enum flag_val_res code; int data; }; /* -f the_str */ static struct str_flag_val extract_str_flag(char flagletter, int argc, char **argv) { struct str_flag_val res = {0}; char flagstr[3] = { '-', ' ', '\0' }; int i; flagstr[1] = flagletter; for (i = 1; i < argc; i++) if (0 == strcmp(flagstr, argv[i])) break; if (i >= argc) { res.code = fvr_not_found; } else if (i == argc-1) { res.code = fvr_invalid; } else { res.code = fvr_ok; res.data = argv[i+1]; } return res; } /* -f number */ static struct int_flag_val extract_int_flag(char flagletter, int argc, char **argv) { struct int_flag_val res; struct str_flag_val strres = extract_str_flag(flagletter, argc, argv); char *endptr; res.code = strres.code; if (res.code != fvr_ok) { return res; } res.data = strtol(strres.data, &endptr, 10); if (*endptr != '\0') res.code = fvr_invalid; return res; } int main(int argc, char **argv) { int server_fd, opt = 1, res, flags, port; struct sockaddr_in addr = {0}; struct int_flag_val port_res = extract_int_flag('p', argc, argv); switch (port_res.code) { case fvr_not_found: # ifdef BTASKTD_DEFAULT_PORT port = BTASKTD_DEFAULT_PORT; # else fputs("No port specified!\n", stderr); return 1; # endif break; case fvr_invalid: fputs("Invalid port!\n", stderr); return 1; case fvr_ok: port = port_res.data; } server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd < 0) { 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); perror("bind"); return 1; } res = listen(server_fd, QUEUE_LEN); if (0 != res) { close(server_fd); perror("listen"); return 1; } res = setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); if (0 != res) { close(server_fd); perror("setsockopt"); return 1; } flags = fcntl(server_fd, F_GETFL); fcntl(server_fd, F_SETFL, flags|O_NONBLOCK); printf("btaskt server btasktd started on port %d\n", port); /* main loop here */ printf("btaskt server btasktd stopped\n"); close(server_fd); return 0; }