mirror of
https://github.com/eddyem/small_tel.git
synced 2026-05-07 13:27:06 +03:00
some fixes
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
CC = gcc
|
CC = gcc
|
||||||
CFLAGS = -Wall -Wextra -fPIC
|
CFLAGS = -Wall -Wextra -fPIC -DEBUG
|
||||||
LDFLAGS = -lrt -pthread
|
LDFLAGS = -lrt -pthread -lusefull_macros
|
||||||
|
|
||||||
all: weather_daemon libweather.so weather_clt_example
|
all: weather_daemon libweather.so weather_clt_example
|
||||||
|
|
||||||
|
|||||||
@@ -15,27 +15,34 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#if 0
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <sys/mman.h>
|
#include <stdarg.h>
|
||||||
#include <sys/stat.h>
|
#endif
|
||||||
#include <sys/types.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdarg.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
#include "weather_data.h"
|
#include "weather_data.h"
|
||||||
|
|
||||||
|
#define DEFAULT_PID "/tmp/weather_proxy.pid"
|
||||||
|
|
||||||
#define DEAD_TMOUT 15
|
#define DEAD_TMOUT 15
|
||||||
#define RECONN_TMOUT 5
|
#define RECONN_TMOUT 5
|
||||||
#define WEAT_TMOUT 1
|
#define WEAT_TMOUT 1
|
||||||
@@ -43,20 +50,60 @@
|
|||||||
#define SHM_NAME "/weather_shm"
|
#define SHM_NAME "/weather_shm"
|
||||||
#define SEM_NAME "/weather_sem"
|
#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 shm_fd = -1;
|
||||||
|
static int forbidden = 0;
|
||||||
static sem_t *sem = NULL;
|
static sem_t *sem = NULL;
|
||||||
static weather_data_t *shared_data = NULL;
|
static weather_data_t *shared_data = NULL;
|
||||||
static volatile int running = 1;
|
static volatile int running = 1;
|
||||||
|
static glob_pars G = {0};
|
||||||
|
|
||||||
#define log_message(...) do{printf("message: "); printf(__VA_ARGS__); printf("\n");}while(0)
|
static sl_option_t opts[] = {
|
||||||
#define log_error(...) do{printf("error: "); printf(__VA_ARGS__); printf("\n");}while(0)
|
{"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) {
|
void signals(int signo){
|
||||||
if (sig == SIGTERM || sig == SIGINT) {
|
if(signo){
|
||||||
running = 0;
|
if(signals != signal(signo, SIG_IGN)) exit(signo); // function called "as is", before sig registration
|
||||||
log_message("Received signal %d, shutting down", sig);
|
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
|
umask(0); // for read-write semaphore
|
||||||
@@ -66,37 +113,34 @@ static int init_ipc(void) {
|
|||||||
// no - create new
|
// no - create new
|
||||||
shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0644);
|
shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0644);
|
||||||
if(shm_fd == -1){
|
if(shm_fd == -1){
|
||||||
log_error("shm_open (create) failed: %s", strerror(errno));
|
LOGERR("shm_open (create) failed: %s", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(ftruncate(shm_fd, sizeof(weather_data_t)) == -1){
|
if(ftruncate(shm_fd, sizeof(weather_data_t)) == -1){
|
||||||
log_error("ftruncate failed: %s", strerror(errno));
|
LOGERR("ftruncate failed: %s", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
shared_data = mmap(NULL, sizeof(weather_data_t), PROT_READ | PROT_WRITE,
|
shared_data = mmap(NULL, sizeof(weather_data_t), PROT_READ | PROT_WRITE,
|
||||||
MAP_SHARED, shm_fd, 0);
|
MAP_SHARED, shm_fd, 0);
|
||||||
if(shared_data == MAP_FAILED){
|
if(shared_data == MAP_FAILED){
|
||||||
log_error("mmap failed: %s", strerror(errno));
|
LOGERR("mmap failed: %s", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// default values to data
|
// default values to data
|
||||||
}else{
|
}else{
|
||||||
printf("Use existant SHM\n");
|
DBG("Use existant SHM\n");
|
||||||
// use existant SHM
|
|
||||||
shared_data = mmap(NULL, sizeof(weather_data_t), PROT_READ | PROT_WRITE,
|
shared_data = mmap(NULL, sizeof(weather_data_t), PROT_READ | PROT_WRITE,
|
||||||
MAP_SHARED, shm_fd, 0);
|
MAP_SHARED, shm_fd, 0);
|
||||||
if(shared_data == MAP_FAILED){
|
if(shared_data == MAP_FAILED){
|
||||||
log_error("mmap failed: %s", strerror(errno));
|
LOGERR("mmap failed: %s", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(shared_data, 0, sizeof(weather_data_t));
|
memset(shared_data, 0, sizeof(weather_data_t));
|
||||||
|
|
||||||
// create samaphore if no
|
// create samaphore if no
|
||||||
sem = sem_open(SEM_NAME, O_CREAT, 0666, 1);
|
sem = sem_open(SEM_NAME, O_CREAT, 0666, 1);
|
||||||
if(sem == SEM_FAILED){
|
if(sem == SEM_FAILED){
|
||||||
log_error("sem_open failed: %s", strerror(errno));
|
LOGERR("sem_open failed: %s", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -106,18 +150,18 @@ static int init_ipc(void) {
|
|||||||
static void cleanup_ipc(void){
|
static void cleanup_ipc(void){
|
||||||
if (sem != NULL) {
|
if (sem != NULL) {
|
||||||
sem_close(sem);
|
sem_close(sem);
|
||||||
printf("semaphore closed\n");
|
DBG("semaphore closed\n");
|
||||||
if(-1 == sem_unlink(SEM_NAME)) perror("Can't delete semaphore");
|
if(-1 == sem_unlink(SEM_NAME)) LOGERR("Can't delete semaphore");
|
||||||
}
|
}
|
||||||
if(shared_data != NULL){
|
if(shared_data != NULL){
|
||||||
printf("memory unmapped\n");
|
DBG("memory unmapped\n");
|
||||||
munmap(shared_data, sizeof(weather_data_t));
|
munmap(shared_data, sizeof(weather_data_t));
|
||||||
}
|
}
|
||||||
if(shm_fd != -1){
|
if(shm_fd != -1){
|
||||||
close(shm_fd);
|
close(shm_fd);
|
||||||
printf("close shared mem\n");
|
DBG("close shared mem\n");
|
||||||
if(shm_unlink(SHM_NAME) == -1){
|
if(shm_unlink(SHM_NAME) == -1){
|
||||||
perror("can't unlink SHM");
|
LOGERR("can't unlink SHM");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -154,137 +198,113 @@ static void parse_line(const char *line, weather_data_t *data) {
|
|||||||
data->prohibited = atoi(value);
|
data->prohibited = atoi(value);
|
||||||
} else if (strcmp(key, "TMEAS") == 0) {
|
} else if (strcmp(key, "TMEAS") == 0) {
|
||||||
data->last_update = atof(value);
|
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;
|
else if(data->weather < WEATHER_TERRIBLE) data->prohibited = 0;
|
||||||
// update all
|
// update all
|
||||||
if (sem_wait(sem) == -1) {
|
if (sem_wait(sem) == -1) {
|
||||||
log_error("sem_wait failed: %s", strerror(errno));
|
LOGWARN("sem_wait failed: %s", strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
memcpy(shared_data, data, sizeof(weather_data_t));
|
memcpy(shared_data, data, sizeof(weather_data_t));
|
||||||
sem_post(sem);
|
sem_post(sem);
|
||||||
log_message("Weather data updated");
|
LOGMSG("Weather data updated");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sock = -1;
|
static int request_weather_data(sl_sock_t *sock){
|
||||||
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 time_t tcur = 0;
|
static time_t tcur = 0;
|
||||||
|
|
||||||
char *request = "get\n";
|
char *request = "get\n";
|
||||||
time_t tnow = time(NULL);
|
time_t tnow = time(NULL);
|
||||||
if(tnow - tcur >= WEAT_TMOUT){
|
if(tnow - tcur >= WEAT_TMOUT){
|
||||||
tcur = tnow;
|
tcur = tnow;
|
||||||
}else return 1; // not now
|
}else return 1; // not now
|
||||||
|
|
||||||
printf("try to send request: '%s", request);
|
DBG("try to send request: '%s", request);
|
||||||
if (send(sock, request, strlen(request), 0) < 0) {
|
if(sl_sock_sendstrmessage(sock, request) < 1){
|
||||||
log_error("send failed: %s", strerror(errno));
|
LOGERR("Can't poll new data");
|
||||||
close(sock);
|
|
||||||
sock = -1;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void run_daemon(const char *server_ip, int port) {
|
static void run_daemon(){
|
||||||
char line[256];
|
char line[256];
|
||||||
weather_data_t new_data;
|
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));
|
memcpy(&new_data, shared_data, sizeof(weather_data_t));
|
||||||
time_t lastert = time(NULL);
|
time_t lastert = time(NULL);
|
||||||
|
|
||||||
while(running){
|
while(running){
|
||||||
time_t tnow = time(NULL);
|
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
|
if(tnow - lastert > RECONN_TMOUT){ // try to reconnect
|
||||||
log_error("Failed to request weather data, retry");
|
LOGERR("Failed to request weather data, retry");
|
||||||
if(-1 == opensock(server_ip, port)) lastert += 5;
|
if(sock) sl_sock_delete(&sock);
|
||||||
|
if(!(sock = sl_sock_run_client(stype, G.node, 4096))) lastert += 5;
|
||||||
else lastert = tnow;
|
else lastert = tnow;
|
||||||
}
|
}
|
||||||
}else lastert = tnow;
|
}else lastert = tnow;
|
||||||
|
|
||||||
while (fgets(line, sizeof(line), sock_file)) {
|
while(sl_sock_readline(sock, line, 255) > 0){
|
||||||
line[strcspn(line, "\r\n")] = '\0';
|
DBG("Parse '%s'", line);
|
||||||
printf("parse '%s'\n", line);
|
|
||||||
parse_line(line, &new_data);
|
parse_line(line, &new_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(sock);
|
sl_sock_delete(&sock); // disconnect and clear memory
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]){
|
int main(int argc, char *argv[]){
|
||||||
if (argc != 3) {
|
sl_init();
|
||||||
fprintf(stderr, "Usage: %s <server_ip> <port>\n", argv[0]);
|
sl_parseargs(&argc, &argv, opts);
|
||||||
exit(EXIT_FAILURE);
|
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");
|
||||||
}
|
}
|
||||||
|
signal(SIGTERM, signals);
|
||||||
const char *server_ip = argv[1];
|
signal(SIGINT, signals);
|
||||||
int port = atoi(argv[2]);
|
signal(SIGUSR1, SIG_IGN);
|
||||||
if (port <= 0 || port > 65535) {
|
signal(SIGUSR2, SIG_IGN);
|
||||||
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(SIGPIPE, 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){
|
if(init_ipc() != 0){
|
||||||
log_error("IPC initialization failed");
|
LOGERR("IPC initialization failed");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
run_daemon();
|
||||||
run_daemon(server_ip, port);
|
|
||||||
|
|
||||||
cleanup_ipc();
|
cleanup_ipc();
|
||||||
log_message("Weather daemon stopped");
|
LOGMSG("Daemon is dead");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user