diff options
| -rw-r--r-- | Makefile | 23 | ||||
| -rw-r--r-- | README | 28 | ||||
| -rw-r--r-- | btasktd.1 | 6 | ||||
| -rw-r--r-- | btasktd.c | 96 | ||||
| -rw-r--r-- | lib/logger/Makefile | 54 | ||||
| -rw-r--r-- | lib/logger/logger.c | 78 | ||||
| -rw-r--r-- | lib/logger/logger.h | 21 |
7 files changed, 280 insertions, 26 deletions
@@ -2,9 +2,11 @@ # # SPDX-License-Identifier: BSD-2-Clause +# all 3 values commented, using make's default or export CC # CC = cc -fno-caret-diagnostics -fno-color-diagnostics -CC = gcc -fno-diagnostics-show-caret -fdiagnostics-color=never +# CC = gcc -fno-diagnostics-show-caret -fdiagnostics-color=never # CC = gcc + CFLAGS = -Wall -Wextra -pedantic -std=c99 # DEBUG = -g @@ -36,17 +38,24 @@ dist: bzip2 > $(DIST_NAME).tar.bz2 clean: - rm -f $(MAINBINARIES) *.o *.test tags + $(MAKE) -C $(LIBSDIR)/logger clean + rm -f $(MAINBINARIES) *.o *.test tags $(DIST_NAME) rebuild: clean all .c.o: - $(CC) $(DEBUG) $(CFLAGS) -c $< -o $@ + $(CC) $(DEBUG) $(CFLAGS) -I$(LIBSDIR) -c $< -o $@ + +LIBSDIR = ./lib +LDFLAGS = -L$(LIBSDIR)/logger +$(LIBSDIR)/logger/liblogger.a: + $(MAKE) -C $(LIBSDIR)/logger BTASKTD_OBJECTS = btasktd.o cliflags.o codes.o -BTASKTD_LIBS = -lc +BTASKTD_LIBDEPS = $(LIBSDIR)/logger/liblogger.a +BTASKTD_LIBS = -lc -llogger -btasktd: $(BTASKTD_OBJECTS) - $(CC) $(DEBUG) $(CFLAGS) $(STATIC) $(BTASKTD_OBJECTS) -o $@ \ - $(BTASKTD_LIBS) +btasktd: $(BTASKTD_OBJECTS) $(BTASKTD_LIBDEPS) + $(CC) $(DEBUG) $(CFLAGS) $(STATIC) $(LDFLAGS) \ + $(BTASKTD_OBJECTS) -o $@ $(BTASKTD_LIBS) @@ -19,3 +19,31 @@ BUILD DEPENDENCIES RUNTIME DEPENDENCIES ------------------------------------------------------------------------- * OS Kernel + +------------------------------------------------------------------------- +QUICK START +------------------------------------------------------------------------- +There is no even MVP yet, just an echo server. + +Try: + + $ make + $ ./btasktd -u 2 -p 5500 -b + +Then: + + $ telnet 127.0.0.1 5500 + +If can open two more terminals, in them also: + + $ telnet 127.0.0.1 5500 + +There should be error response for last and working echo server for +2 others. To stop: + + $ pkill -2 btasktd + +To allow more users change ``2'' after ``-u'' to other number, to +change port change ``5500'' to your port. + +For more info please read the program's man page. @@ -1,4 +1,4 @@ -.Dd September 19, 2026 +.Dd October 1, 2026 .Dt BTASKTD 1 .Os . @@ -9,7 +9,7 @@ .Sh SYNOPSIS .Nm .BK -words -.Op Fl \&Vh +.Op Fl \&Vhb .Op Fl p Ar port .Op Fl u Ar users .Ek @@ -24,6 +24,8 @@ The options are as follows: Show version .It Fl h Show help message +.It Fl b +Run server as daemon (in background) .It Fl p Ar port Set port for server to listen to .It Fl u Ar users @@ -40,13 +40,14 @@ #include <unistd.h> #include <errno.h> #include <signal.h> +#include <logger/logger.h> #include "cliflags.h" #include "codes.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" \ + "Usage: btasktd [-Vhb] [-p port] [-u users]\n" \ "For more info read the program's man page\n" #define BTASKTD_VERSION_STR \ @@ -132,7 +133,7 @@ send_to_client(int fd, const char *s) int len = strlen(s); int code = send(fd, s, len, 0); if (-1 == code) - perror("send"); + logger_perror("send"); } static void @@ -162,16 +163,21 @@ handle_accept(struct btasktd *this) socklen_t addrlen = sizeof(user_addr); int fd = accept(this->fd, (struct sockaddr*)&user_addr, &addrlen); if (-1 == fd) { - perror("accept"); + logger_perror("accept"); return; } set_nonblock(fd); idx = find_free_user(this->users, this->users_cnt); if (-1 == idx) { + logger_log(log_lvl_warning, + "rejected user connection because " + "working at users limit\n"); send_response_code(fd, CODE_503_SERVICE_UNAVAILABLE); close(fd); return; } + logger_log(log_lvl_info, + "new connection successfully accepted\n"); this->users[idx].fd = fd; this->users[idx].bi = 0; } @@ -217,7 +223,7 @@ handle_user(struct btasktd *this, int id) reset_user(pu); return; } else if (-1 == valread) { - perror("recv"); + logger_perror("recv"); close(pu->fd); reset_user(pu); return; @@ -239,22 +245,54 @@ bye_all_clients(struct btasktd *this) } } -static volatile int last_sig = 0; +static volatile sig_atomic_t last_sig = 0; static void handle_sigint(int sig) { signal(sig, handle_sigint); - fprintf(stderr, "Caught signal %d, shutting down...\n", sig); + logger_log(log_lvl_info, + "Caught signal %d, shutting down...\n", sig); last_sig = SIGINT; } +static void +make_me_daemon(void) +{ + int fd = open("/dev/null", O_RDWR), pid; + if (fd < 0) { + logger_perror("open"); + exit(1); + } + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + chdir("/"); + if (fd > 2) + close(fd); + pid = fork(); + if (pid < 0) { + logger_perror("fork"); + exit(1); + } else if (pid > 0) { + exit(0); + } + setsid(); + pid = fork(); + if (pid < 0) { + logger_perror("fork"); + exit(1); + } else if (pid > 0) { + exit(0); + } +} + int main(int argc, char **argv) { struct btasktd server; int server_fd, opt = 1, res, port, passed_flags = 1, users_cnt; - int max_fd; + int is_daemon = 0, max_fd; struct user *users = NULL; int i; struct sockaddr_in addr = {0}; @@ -262,6 +300,7 @@ main(int argc, char **argv) struct bool_flag_val bool_res; fd_set readfds; + bool_res = extract_bool_flag('V', argc, argv); if (fvr_ok == bool_res.code && bool_res.data) { printf("btasktd version %s\n", BTASKTD_VERSION_STR); @@ -274,6 +313,13 @@ main(int argc, char **argv) return 0; } + bool_res = extract_bool_flag('b', argc, argv); + if (fvr_ok == bool_res.code && bool_res.data) { + is_daemon = 1; + } + + logger_init("btasktd", is_daemon); + int_res = extract_int_flag('p', argc, argv); switch (int_res.code) { case fvr_not_found: @@ -301,7 +347,8 @@ main(int argc, char **argv) # ifdef BTASKTD_DEFAULT_USERS_CNT users_cnt = BTASKTD_DEFAULT_USERS_CNT; # else - fprintf(stderr, "No users count specified!\n"); + fprintf(stderr, + "No users count specified!\n"); passed_flags = 0; # endif break; @@ -313,18 +360,23 @@ main(int argc, char **argv) case fvr_invalid: fprintf(stderr, "Invalid users count!\n"); return 1; - break; } + logger_init("btasktd", is_daemon); + if (!passed_flags) { + logger_log(log_lvl_err, + "FATAL: didn't passed flags check\n"); fprintf(stderr, "-\n"); fprint_help(stderr); + logger_close(); return 1; } users = (struct user*)calloc(users_cnt, sizeof(struct user)); if (NULL == users) { - fprintf(stderr, "No memory!\n"); + logger_log(log_lvl_err, "No memory!\n"); + logger_close(); return 1; } for (i = 0; i < users_cnt; i++) { @@ -333,8 +385,9 @@ main(int argc, char **argv) server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd < 0) { + logger_perror("socket"); free(users); - perror("socket"); + logger_close(); return 1; } addr.sin_family = AF_INET; @@ -345,21 +398,24 @@ main(int argc, char **argv) if (0 != res) { close(server_fd); free(users); - perror("setsockopt"); + logger_perror("setsockopt"); + logger_close(); return 1; } res = bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)); if (0 != res) { close(server_fd); free(users); - perror("bind"); + logger_perror("bind"); + logger_close(); return 1; } res = listen(server_fd, BTASKTD_QUEUE_LEN); if (0 != res) { close(server_fd); free(users); - perror("listen"); + logger_perror("listen"); + logger_close(); return 1; } @@ -368,7 +424,12 @@ main(int argc, char **argv) server.fd = server_fd; server.users_cnt = users_cnt; server.users = users; - printf("btaskt server btasktd started on port %d\n", port); + + if (is_daemon) + make_me_daemon(); + logger_log(log_lvl_info, + "btaskt server btasktd started on port %d. pid - %d\n", + port, getpid()); signal(SIGINT, handle_sigint); @@ -393,7 +454,7 @@ main(int argc, char **argv) break; } } else { - perror("select"); + logger_perror("select"); } continue; } else if (0 == res) { @@ -410,7 +471,8 @@ main(int argc, char **argv) } } - printf("btaskt server btasktd stopped\n"); + logger_log(log_lvl_info, "btaskt server btasktd stopped\n"); + logger_close(); close(server_fd); free(users); return 0; diff --git a/lib/logger/Makefile b/lib/logger/Makefile new file mode 100644 index 0000000..e5e7682 --- /dev/null +++ b/lib/logger/Makefile @@ -0,0 +1,54 @@ +# Copyright (c) 2026, Mr. Goblin +# +# SPDX-License-Identifier: BSD-2-Clause + +# all 3 values commented, using make's default or export CC +# CC = cc -fno-caret-diagnostics -fno-color-diagnostics +# CC = gcc -fno-diagnostics-show-caret -fdiagnostics-color=never +# CC = gcc + +CFLAGS = -Wall -Wextra -pedantic -std=gnu89 +ARFLAGS = rcs + +# DEBUG = -g +# DEBUG = -ggdb +DEBUG = + +# STATIC = -static +STATIC = -static -s +# STATIC = + +PROG_NAME=liblogger +VER=0.0.0 +DIST_NAME=$(PROG_NAME)-$(VER) + + +MAINBINARIES = liblogger.a + +.SUFFIXES: +.SUFFIXES: .c .o +.PHONY: all clean dist ctags rebuild + +all: $(MAINBINARIES) + +ctags: + ctags *.c *.h *.cpp *.hpp + +dist: + git archive --format=tar --prefix=$(DIST_NAME)/ HEAD | \ + bzip2 > $(DIST_NAME).tar.bz2 + +clean: + rm -f $(MAINBINARIES) *.o *.test tags $(DIST_NAME) + +rebuild: clean all + +.c.o: + $(CC) $(DEBUG) $(CFLAGS) -c $< -o $@ + + +LIBLOGGER_OBJECTS = logger.o +LIBLOGGER_LIBS = -lc + +liblogger.a: $(LIBLOGGER_OBJECTS) + $(AR) $(ARFLAGS) $@ $(LIBLOGGER_OBJECTS) diff --git a/lib/logger/logger.c b/lib/logger/logger.c new file mode 100644 index 0000000..64a6754 --- /dev/null +++ b/lib/logger/logger.c @@ -0,0 +1,78 @@ +#include <syslog.h> +#include <stdarg.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include "logger.h" + +static int use_syslog = 0; + +void +logger_init(const char *name, int daemon_flag) +{ + use_syslog = daemon_flag; + if (use_syslog) + openlog(name, LOG_PID, LOG_DAEMON); +} + +void +logger_close(void) +{ + if (use_syslog) + closelog(); +} + +void +logger_log(enum logger_lvl level, const char *format, ...) +{ + int saved_errno = errno; + va_list vargs; + va_start(vargs, format); + if (use_syslog) { + switch (level) { + case log_lvl_info: + vsyslog(LOG_INFO, format, vargs); + break; + case log_lvl_warning: + vsyslog(LOG_WARNING, format, vargs); + break; + case log_lvl_err: + vsyslog(LOG_ERR, format, vargs); + break; + } + } else { + FILE *f = NULL; + switch (level) { + case log_lvl_info: + f = stdout; + fprintf(f, "[INFO] "); + break; + case log_lvl_warning: + f = stderr; + fprintf(f, "[WARNING] "); + break; + case log_lvl_err: + f = stderr; + fprintf(f, "[ERROR] "); + break; + default: + f = stderr; + fprintf(f, "[UNKNOWN] "); + break; + } + vfprintf(f, format, vargs); + } + errno = saved_errno; +} + +void +logger_perror(const char *s) +{ + int saved_errno = errno; + if (use_syslog) { + syslog(LOG_ERR, "%s: %s\n", s, strerror(errno)); + } else { + perror(s); + } + errno = saved_errno; +} diff --git a/lib/logger/logger.h b/lib/logger/logger.h new file mode 100644 index 0000000..6c9ed7d --- /dev/null +++ b/lib/logger/logger.h @@ -0,0 +1,21 @@ +#ifndef LIB_LOGGER_H_SENTRY +#define LIB_LOGGER_H_SENTRY +#ifdef __cplusplus +extern "C" { +#endif + +enum logger_lvl { + log_lvl_info, + log_lvl_warning, + log_lvl_err +}; + +void logger_init(const char *name, int daemon_flag); +void logger_close(void); +void logger_log(enum logger_lvl, const char *format, ...); +void logger_perror(const char *s); + +#ifdef __cplusplus +} +#endif +#endif /* LIB_LOGGER_H_SENTRY */ |
