From 5acd1cd97db5d8e281e72d6715847f63ed4da241 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Fri, 10 Apr 2026 15:52:55 +0300 Subject: [PATCH] some fixes --- Daemons/weather_proxy/Makefile | 4 +- Daemons/weather_proxy/weather_clt_example.c | 4 +- Daemons/weather_proxy/weather_daemon.c | 278 +++++++++++--------- 3 files changed, 153 insertions(+), 133 deletions(-) diff --git a/Daemons/weather_proxy/Makefile b/Daemons/weather_proxy/Makefile index 286d3a0..5463b8f 100644 --- a/Daemons/weather_proxy/Makefile +++ b/Daemons/weather_proxy/Makefile @@ -1,6 +1,6 @@ CC = gcc -CFLAGS = -Wall -Wextra -fPIC -LDFLAGS = -lrt -pthread +CFLAGS = -Wall -Wextra -fPIC -DEBUG +LDFLAGS = -lrt -pthread -lusefull_macros all: weather_daemon libweather.so weather_clt_example diff --git a/Daemons/weather_proxy/weather_clt_example.c b/Daemons/weather_proxy/weather_clt_example.c index 7b50fa3..3fd9519 100644 --- a/Daemons/weather_proxy/weather_clt_example.c +++ b/Daemons/weather_proxy/weather_clt_example.c @@ -21,10 +21,10 @@ int main() { weather_data_t wd; - if (get_weather_data(&wd) == 0) { + if(get_weather_data(&wd) == 0){ printf("Weather: %d, Max wind: %.1f, Wind: %.1f, Temp: %.1f; updated @%zd\n", wd.weather, wd.windmax, wd.wind, wd.exttemp, wd.last_update); - } else { + }else{ fprintf(stderr, "Failed to get weather data\n"); } return 0; diff --git a/Daemons/weather_proxy/weather_daemon.c b/Daemons/weather_proxy/weather_daemon.c index a292d92..6498f16 100644 --- a/Daemons/weather_proxy/weather_daemon.c +++ b/Daemons/weather_proxy/weather_daemon.c @@ -15,27 +15,34 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - -#include +#if 0 #include -#include -#include #include -#include #include #include #include -#include -#include -#include +#include +#endif + #include #include #include +#include +#include +#include +#include +#include +#include +#include #include -#include +#include + +#include #include "weather_data.h" +#define DEFAULT_PID "/tmp/weather_proxy.pid" + #define DEAD_TMOUT 15 #define RECONN_TMOUT 5 #define WEAT_TMOUT 1 @@ -43,81 +50,118 @@ #define SHM_NAME "/weather_shm" #define SEM_NAME "/weather_sem" +typedef struct{ + char *node; // node of server + int isunix; // use UNIX-sockets instead of net + char *logfile; // logfile name + int verb; // verbocity level + char *pidfile; // pidfile name +} glob_pars; + +static pid_t childpid; static int shm_fd = -1; +static int forbidden = 0; static sem_t *sem = NULL; static weather_data_t *shared_data = NULL; static volatile int running = 1; +static glob_pars G = {0}; -#define log_message(...) do{printf("message: "); printf(__VA_ARGS__); printf("\n");}while(0) -#define log_error(...) do{printf("error: "); printf(__VA_ARGS__); printf("\n");}while(0) +static sl_option_t opts[] = { + {"node", NEED_ARG, NULL, 'n', arg_string, APTR(&G.node), "node to connect (host:port or UNIX socket name)"}, + {"logfile", NEED_ARG, NULL, 'l', arg_string, APTR(&G.logfile), "save logs to file"}, + {"pidfile", NEED_ARG, NULL, 'p', arg_string, APTR(&G.pidfile), "pidfile name (default: " DEFAULT_PID ")"}, + {"isunix", NO_ARGS, NULL, 'u', arg_string, APTR(&G.isunix), "use UNIX socket instead of network"}, + {"verbose", NO_ARGS, NULL, 'v', arg_int, APTR(&G.verb), "verbose level (each -v increases)"}, + end_option +}; -static void signal_handler(int sig) { - if (sig == SIGTERM || sig == SIGINT) { - running = 0; - log_message("Received signal %d, shutting down", sig); +void signals(int signo){ + if(signo){ + if(signals != signal(signo, SIG_IGN)) exit(signo); // function called "as is", before sig registration + if(childpid == 0){ // child -> test USR1/USR2 + LOGDBG("Child gotta signal %d", signo); + if(signo == SIGUSR1){ + forbidden = 1; + LOGMSG("Got signal `observations forbidden`"); + signal(signo, signals); + return; + }else if(signo == SIGUSR2){ + forbidden = 0; + LOGMSG("Got signal `observations permitted`"); + signal(signo, signals); + return; + } + } } + if(childpid){ // master + LOGERR("Main process exits with status %d", signo); + if(G.pidfile) unlink(G.pidfile); + exit(1); + }else{ // child + LOGERR("Killed with status %d", signo); + running = 0; // let make cleanup + } + sleep(1); + exit(signo); // force exit if stubs } -static int init_ipc(void) { +static int init_ipc(void){ umask(0); // for read-write semaphore shm_fd = shm_open(SHM_NAME, O_RDWR, 0644); // try to open existant SHM - if (shm_fd == -1) { + if(shm_fd == -1){ printf("Create new shared memory\n"); // no - create new shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0644); - if (shm_fd == -1) { - log_error("shm_open (create) failed: %s", strerror(errno)); + if(shm_fd == -1){ + LOGERR("shm_open (create) failed: %s", strerror(errno)); return -1; } - if (ftruncate(shm_fd, sizeof(weather_data_t)) == -1) { - log_error("ftruncate failed: %s", strerror(errno)); + if(ftruncate(shm_fd, sizeof(weather_data_t)) == -1){ + LOGERR("ftruncate failed: %s", strerror(errno)); return -1; } shared_data = mmap(NULL, sizeof(weather_data_t), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); - if (shared_data == MAP_FAILED) { - log_error("mmap failed: %s", strerror(errno)); + if(shared_data == MAP_FAILED){ + LOGERR("mmap failed: %s", strerror(errno)); return -1; } // default values to data - } else { - printf("Use existant SHM\n"); - // use existant SHM + }else{ + DBG("Use existant SHM\n"); shared_data = mmap(NULL, sizeof(weather_data_t), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); - if (shared_data == MAP_FAILED) { - log_error("mmap failed: %s", strerror(errno)); + if(shared_data == MAP_FAILED){ + LOGERR("mmap failed: %s", strerror(errno)); return -1; } } - memset(shared_data, 0, sizeof(weather_data_t)); - // create samaphore if no sem = sem_open(SEM_NAME, O_CREAT, 0666, 1); - if (sem == SEM_FAILED) { - log_error("sem_open failed: %s", strerror(errno)); + if(sem == SEM_FAILED){ + LOGERR("sem_open failed: %s", strerror(errno)); return -1; } return 0; } // free IPC -static void cleanup_ipc(void) { +static void cleanup_ipc(void){ if (sem != NULL) { sem_close(sem); - printf("semaphore closed\n"); - if(-1 == sem_unlink(SEM_NAME)) perror("Can't delete semaphore"); + DBG("semaphore closed\n"); + if(-1 == sem_unlink(SEM_NAME)) LOGERR("Can't delete semaphore"); } - if (shared_data != NULL) { - printf("memory unmapped\n"); + if(shared_data != NULL){ + DBG("memory unmapped\n"); munmap(shared_data, sizeof(weather_data_t)); } - if (shm_fd != -1) { + if(shm_fd != -1){ close(shm_fd); - printf("close shared mem\n"); - if (shm_unlink(SHM_NAME) == -1) { - perror("can't unlink SHM"); + DBG("close shared mem\n"); + if(shm_unlink(SHM_NAME) == -1){ + LOGERR("can't unlink SHM"); } } } @@ -154,137 +198,113 @@ static void parse_line(const char *line, weather_data_t *data) { data->prohibited = atoi(value); } else if (strcmp(key, "TMEAS") == 0) { data->last_update = atof(value); - if(data->weather == WEATHER_PROHIBITED) data->prohibited = 1; + if(data->weather == WEATHER_PROHIBITED || forbidden) data->prohibited = 1; else if(data->weather < WEATHER_TERRIBLE) data->prohibited = 0; // update all if (sem_wait(sem) == -1) { - log_error("sem_wait failed: %s", strerror(errno)); + LOGWARN("sem_wait failed: %s", strerror(errno)); } else { memcpy(shared_data, data, sizeof(weather_data_t)); sem_post(sem); - log_message("Weather data updated"); + LOGMSG("Weather data updated"); } } } } -static int sock = -1; -static FILE *sock_file = NULL; - -static int opensock(const char *server_ip, int port){ - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { - log_error("socket creation failed: %s", strerror(errno)); - return -1; - } - - struct sockaddr_in server_addr; - server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(port); - if (inet_pton(AF_INET, server_ip, &server_addr.sin_addr) <= 0) { - log_error("invalid address: %s", server_ip); - close(sock); - sock = -1; - return -1; - } - - if (connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { - log_error("connect failed: %s", strerror(errno)); - close(sock); - sock = -1; - return -1; - } - - int flags = fcntl(sock, F_GETFL, 0); - if (flags == -1){ - perror("fcntl F_GETFL"); - }else{ - if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) perror("fcntl F_SETFL"); - } - - sock_file = fdopen(sock, "r"); - if (!sock_file) { - log_error("fdopen failed: %s", strerror(errno)); - close(sock); - sock = -1; - return -1; - } - - return 0; -} - -static int request_weather_data() { +static int request_weather_data(sl_sock_t *sock){ static time_t tcur = 0; - char *request = "get\n"; time_t tnow = time(NULL); if(tnow - tcur >= WEAT_TMOUT){ tcur = tnow; }else return 1; // not now - printf("try to send request: '%s", request); - if (send(sock, request, strlen(request), 0) < 0) { - log_error("send failed: %s", strerror(errno)); - close(sock); - sock = -1; + DBG("try to send request: '%s", request); + if(sl_sock_sendstrmessage(sock, request) < 1){ + LOGERR("Can't poll new data"); return -1; } - return 0; } -static void run_daemon(const char *server_ip, int port) { +static void run_daemon(){ char line[256]; weather_data_t new_data; - opensock(server_ip, port); // just try: in case of error reopen next time + sl_socktype_e stype = (G.isunix) ? SOCKT_UNIX : SOCKT_NET; + DBG("Try to connect to %s", G.node); + sl_sock_t *sock = sl_sock_run_client(stype, G.node, 4096); + if(!sock){ + DBG("Can't connect"); + LOGERR("Can't connect to meteodaemon over socket with node %s", G.node); + return; + } memcpy(&new_data, shared_data, sizeof(weather_data_t)); time_t lastert = time(NULL); - while (running) { + + while(running){ time_t tnow = time(NULL); - if (-1 == sock || request_weather_data() == -1) { + if(!sock || request_weather_data(sock) == -1){ if(tnow - lastert > RECONN_TMOUT){ // try to reconnect - log_error("Failed to request weather data, retry"); - if(-1 == opensock(server_ip, port)) lastert += 5; + LOGERR("Failed to request weather data, retry"); + if(sock) sl_sock_delete(&sock); + if(!(sock = sl_sock_run_client(stype, G.node, 4096))) lastert += 5; else lastert = tnow; } }else lastert = tnow; - while (fgets(line, sizeof(line), sock_file)) { - line[strcspn(line, "\r\n")] = '\0'; - printf("parse '%s'\n", line); + while(sl_sock_readline(sock, line, 255) > 0){ + DBG("Parse '%s'", line); parse_line(line, &new_data); } } - close(sock); + sl_sock_delete(&sock); // disconnect and clear memory } -int main(int argc, char *argv[]) { - if (argc != 3) { - fprintf(stderr, "Usage: %s \n", argv[0]); - exit(EXIT_FAILURE); +int main(int argc, char *argv[]){ + sl_init(); + sl_parseargs(&argc, &argv, opts); + if(!G.node) ERRX("Point node to connect"); + sl_check4running(NULL, G.pidfile); + if(G.logfile){ + sl_loglevel_e lvl = LOGLEVEL_ERR + G.verb; + if(lvl >= LOGLEVEL_AMOUNT) lvl = LOGLEVEL_AMOUNT - 1; + DBG("Loglevel: %d", lvl); + if(!OPENLOG(G.logfile, lvl, 1)) ERRX("Can't open log file %s", G.logfile); + LOGMSG("Started"); } - - const char *server_ip = argv[1]; - int port = atoi(argv[2]); - if (port <= 0 || port > 65535) { - fprintf(stderr, "Invalid port\n"); - exit(EXIT_FAILURE); - } - - log_message("Starting weather daemon, server %s:%d", server_ip, port); - - signal(SIGTERM, signal_handler); - signal(SIGINT, signal_handler); + signal(SIGTERM, signals); + signal(SIGINT, signals); + signal(SIGUSR1, SIG_IGN); + signal(SIGUSR2, SIG_IGN); signal(SIGPIPE, SIG_IGN); +#ifndef EBUG + sl_daemonize(); + while(1){ // guard for dead processes + childpid = fork(); + if(childpid){ + LOGDBG("create child with PID %d\n", childpid); + DBG("Created child with PID %d\n", childpid); + wait(NULL); + WARNX("Child %d died\n", childpid); + LOGWARN("Child %d died\n", childpid); + sleep(1); + }else{ + prctl(PR_SET_PDEATHSIG, SIGTERM); // send SIGTERM to child when parent dies + break; // go out to normal functional + } + } +#endif + // react for USRx only in child + signal(SIGUSR1, signals); + signal(SIGUSR2, signals); - if (init_ipc() != 0) { - log_error("IPC initialization failed"); + if(init_ipc() != 0){ + LOGERR("IPC initialization failed"); exit(EXIT_FAILURE); } - - run_daemon(server_ip, port); - + run_daemon(); cleanup_ipc(); - log_message("Weather daemon stopped"); + LOGMSG("Daemon is dead"); return 0; }