From e7aaa20af06c34b59b3dacef4f6fbb9bb57041c2 Mon Sep 17 00:00:00 2001 From: eddyem Date: Tue, 25 Apr 2017 11:02:35 +0300 Subject: [PATCH] fixed disconnect bug --- allsky_logger/cmdlnopts.c | 2 +- allsky_logger/imfunctions.c | 2 + allsky_logger/main.c | 7 +- allsky_logger/socket.c | 123 ++++++++++++++++++++------------- allsky_logger/socket.h | 4 +- allsky_logger/usefull_macros.c | 2 + 6 files changed, 89 insertions(+), 51 deletions(-) diff --git a/allsky_logger/cmdlnopts.c b/allsky_logger/cmdlnopts.c index 94258a9..7e6702a 100644 --- a/allsky_logger/cmdlnopts.c +++ b/allsky_logger/cmdlnopts.c @@ -30,7 +30,7 @@ * here are global parameters initialisation */ int help; -glob_pars G; +static glob_pars G; #define DEFAULT_COMDEV "/dev/ttyUSB0" // DEFAULTS diff --git a/allsky_logger/imfunctions.c b/allsky_logger/imfunctions.c index 11aeba8..61cf076 100644 --- a/allsky_logger/imfunctions.c +++ b/allsky_logger/imfunctions.c @@ -235,6 +235,7 @@ void store_fits(char *name, datarecord *data){ fits_report_error(stderr, status); } if(data){ + putlog("add boltwood's data"); DBG("Boltwood data"); // now the file copied -> add header from Boltwood's sensor while(data->varname){ @@ -263,6 +264,7 @@ ret: } // as cfitsio removes old file instead of trunkate it, we need to refresh inotify every time! if(chdir(oldwd)){ // return back to BD root directory + putlog("Can't chdir"); ERR("Can't chdir"); }; } diff --git a/allsky_logger/main.c b/allsky_logger/main.c index 92c8ad7..8437840 100644 --- a/allsky_logger/main.c +++ b/allsky_logger/main.c @@ -30,6 +30,8 @@ void signals(int signo){ exit(signo); } +glob_pars *G; // global - for socket.c + int main(int argc, char **argv){ initial_setup(); signal(SIGTERM, signals); // kill (-15) - quit @@ -37,10 +39,11 @@ int main(int argc, char **argv){ signal(SIGINT, signals); // ctrl+C - quit signal(SIGQUIT, signals); // ctrl+\ - quit signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z - glob_pars *G = parse_args(argc, argv); + G = parse_args(argc, argv); if(!G->server) ERRX(_("Please, specify server name")); if(!G->filename) ERRX(_("Please, specify the name of input FITS file")); if(G->logfile) openlogfile(G->logfile); - daemonize(G); + DBG("Opened, try to daemonize"); + daemonize(); return 0; } diff --git a/allsky_logger/socket.c b/allsky_logger/socket.c index 17f37e6..36275f3 100644 --- a/allsky_logger/socket.c +++ b/allsky_logger/socket.c @@ -150,37 +150,43 @@ ewhile: /** * wait for answer from socket * @param sock - socket fd - * @return 0 in case of error or timeout, 1 in case of socket ready + * @return 0 if data is absent, 1 in case of socket ready, -1 if socket closed or error occured */ static int waittoread(int sock){ - fd_set fds; + fd_set fds, efds; struct timeval timeout; int rc; timeout.tv_sec = 0; timeout.tv_usec = 100000; // wait not more than 100ms FD_ZERO(&fds); + FD_ZERO(&efds); FD_SET(sock, &fds); + FD_SET(sock, &efds); do{ - rc = select(sock+1, &fds, NULL, NULL, &timeout); + rc = select(sock+1, &fds, NULL, &efds, &timeout); if(rc < 0){ if(errno != EINTR){ + putlog("Server not available"); WARN("select()"); - return 0; + return -1; } continue; } break; }while(1); - if(FD_ISSET(sock, &fds)) return 1; + if(FD_ISSET(sock, &fds)) return 1; + if(FD_ISSET(sock, &efds)) return -1; // exception - socket closed return 0; } + /** * Open given FITS file, check it and add to inotify * THREAD UNSAFE!!! * @return inotify file descriptor */ int watch_fits(char *name){ + FNAME(); static int fd = -1, wd = -1; if(fd > 0 && wd > 0){ inotify_rm_watch(fd, wd); @@ -215,6 +221,7 @@ int watch_fits(char *name){ * test if user can write something to path & make CWD */ static void test_path(char *path){ + FNAME(); if(path){ if(chdir(path)){ putlog("Can't chdir(%s)", path); @@ -228,14 +235,56 @@ static void test_path(char *path){ DBG("OK, user can write to given path"); } +/** + * try to connect to Boltwood's server + * @return file descriptor of opened socket or -1 + */ +static int try_to_connect(){ + int sock = -1; + struct addrinfo hints, *res, *p; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + putlog("Try to connect to %s:%s", G->server, G->port); + if(getaddrinfo(G->server, G->port, &hints, &res) != 0){ + putlog("getaddrinfo()"); + return -1; + } + struct sockaddr_in *ia = (struct sockaddr_in*)res->ai_addr; + char str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(ia->sin_addr), str, INET_ADDRSTRLEN); + DBG("canonname: %s, port: %u, addr: %s\n", res->ai_canonname, ntohs(ia->sin_port), str); + // loop through all the results and bind to the first we can + for(p = res; p != NULL; p = p->ai_next){ + if((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){ + WARN("socket"); + continue; + } + if(connect(sock, p->ai_addr, p->ai_addrlen) == -1){ + WARN("connect()"); + close(sock); + continue; + } + break; // if we get here, we have a successfull connection + } + if(p == NULL || sock < 0){ + putlog("failed to bind socket"); + return -1; + } + freeaddrinfo(res); + putlog("Connection established"); + return sock; +} + /** * Client daemon itself + * If sock < 0 try to reconnect after every image saving * @param FITSpath - path to file watched * @param infd - inotify file descriptor * @param sock - socket's file descriptor */ static void client_(char *FITSpath, int infd, int sock){ - if(sock < 0) return; size_t Bufsiz = BUFLEN; char *recvBuff = MALLOC(char, Bufsiz); datarecord *last_good_msrment = NULL; @@ -250,6 +299,7 @@ static void client_(char *FITSpath, int infd, int sock){ Bufsiz += 1024; recvBuff = realloc(recvBuff, Bufsiz); if(!recvBuff){ + putlog("realloc() error"); WARN("realloc()"); return; } @@ -265,7 +315,7 @@ static void client_(char *FITSpath, int infd, int sock){ continue; putlog("poll() error"); ERR("poll()"); - return; + return; // not reached } if(poll_num > 0){ DBG("changed?"); @@ -292,18 +342,24 @@ static void client_(char *FITSpath, int infd, int sock){ } } fds.fd = watch_fits(FITSpath); + if(sock < 0) sock = try_to_connect(); // try to reconnect if disconnected } } - if(!waittoread(sock)) continue; + if(sock < 0) continue; + int rd = waittoread(sock); + if(rd < 0) sock = -1; // signal that socket disconnected & we need to try to connect + if(rd < 1) continue; size_t offset = 0; do{ rlc(offset); ssize_t n = read(sock, &recvBuff[offset], Bufsiz - offset); if(!n){ - putlog("socket disconnected"); + putlog("nothing to read?"); + offset = 0; break; } if(n < 0){ + offset = 0; putlog("read() error"); WARN("read"); break; @@ -312,8 +368,8 @@ static void client_(char *FITSpath, int infd, int sock){ }while(waittoread(sock)); if(!offset){ putlog("socket disconnected"); - WARN("Socket closed\n"); - return; + sock = -1; + continue; } rlc(offset); recvBuff[offset] = 0; @@ -325,10 +381,14 @@ static void client_(char *FITSpath, int infd, int sock){ /** * Connect to socket and run daemon service */ -void daemonize(glob_pars *G){ +void daemonize(){ + FNAME(); char resolved_path[PATH_MAX]; // get full path to FITS file - if(!realpath(G->filename, resolved_path)) ERR("realpath()"); + if(!realpath(G->filename, resolved_path)){ + putlog("realpath() error"); + ERR("realpath()"); + } // open FITS file & add it to inotify int fd = watch_fits(G->filename); // CD to archive directory if user wants @@ -336,6 +396,7 @@ void daemonize(glob_pars *G){ minstoragetime = G->min_storage_time; // run fork before socket opening to prevent daemon's death if there's no network #ifndef EBUG + putlog("daemonize"); if(daemon(1, 0)){ putlog("daemon() error"); ERR("daemon()"); @@ -355,40 +416,8 @@ void daemonize(glob_pars *G){ } } #endif - int sock = -1; - struct addrinfo hints, *res, *p; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE; - DBG("connect to %s:%s", G->server, G->port); - if(getaddrinfo(G->server, G->port, &hints, &res) != 0){ - ERR("getaddrinfo"); - } - struct sockaddr_in *ia = (struct sockaddr_in*)res->ai_addr; - char str[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &(ia->sin_addr), str, INET_ADDRSTRLEN); - DBG("canonname: %s, port: %u, addr: %s\n", res->ai_canonname, ntohs(ia->sin_port), str); - // loop through all the results and bind to the first we can - for(p = res; p != NULL; p = p->ai_next){ - if((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){ - WARN("socket"); - continue; - } - if(connect(sock, p->ai_addr, p->ai_addrlen) == -1){ - WARN("connect()"); - close(sock); - continue; - } - break; // if we get here, we have a successfull connection - } - if(p == NULL){ - putlog("failed to bind socket"); - // looped off the end of the list with no successful bind - ERRX("failed to bind socket"); - } - freeaddrinfo(res); + int sock = try_to_connect(); client_(resolved_path, fd, sock); - close(sock); + if(sock > 0) close(sock); signals(0); } diff --git a/allsky_logger/socket.h b/allsky_logger/socket.h index a8c6923..a681c3d 100644 --- a/allsky_logger/socket.h +++ b/allsky_logger/socket.h @@ -45,7 +45,9 @@ typedef struct{ bdata data; // data itself } datarecord; -void daemonize(glob_pars *G); +extern glob_pars *G; // from main.c + +void daemonize(); int watch_fits(char *name); #endif // __SOCKET_H__ diff --git a/allsky_logger/usefull_macros.c b/allsky_logger/usefull_macros.c index 8be27ed..67ab386 100644 --- a/allsky_logger/usefull_macros.c +++ b/allsky_logger/usefull_macros.c @@ -394,6 +394,7 @@ time_t log_open_time = 0; * if failed show warning message */ void openlogfile(char *name){ + FNAME(); if(!name){ WARNX(_("Need filename")); return; @@ -405,6 +406,7 @@ void openlogfile(char *name){ } log_open_time = time(NULL); logname = name; + DBG("log file %s opened, time: %ld", name, log_open_time); } /**