fixed disconnect bug

This commit is contained in:
eddyem 2017-04-25 11:02:35 +03:00
parent 0bc09f95b1
commit e7aaa20af0
6 changed files with 89 additions and 51 deletions

View File

@ -30,7 +30,7 @@
* here are global parameters initialisation * here are global parameters initialisation
*/ */
int help; int help;
glob_pars G; static glob_pars G;
#define DEFAULT_COMDEV "/dev/ttyUSB0" #define DEFAULT_COMDEV "/dev/ttyUSB0"
// DEFAULTS // DEFAULTS

View File

@ -235,6 +235,7 @@ void store_fits(char *name, datarecord *data){
fits_report_error(stderr, status); fits_report_error(stderr, status);
} }
if(data){ if(data){
putlog("add boltwood's data");
DBG("Boltwood data"); DBG("Boltwood data");
// now the file copied -> add header from Boltwood's sensor // now the file copied -> add header from Boltwood's sensor
while(data->varname){ while(data->varname){
@ -263,6 +264,7 @@ ret:
} }
// as cfitsio removes old file instead of trunkate it, we need to refresh inotify every time! // 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 if(chdir(oldwd)){ // return back to BD root directory
putlog("Can't chdir");
ERR("Can't chdir"); ERR("Can't chdir");
}; };
} }

View File

@ -30,6 +30,8 @@ void signals(int signo){
exit(signo); exit(signo);
} }
glob_pars *G; // global - for socket.c
int main(int argc, char **argv){ int main(int argc, char **argv){
initial_setup(); initial_setup();
signal(SIGTERM, signals); // kill (-15) - quit signal(SIGTERM, signals); // kill (-15) - quit
@ -37,10 +39,11 @@ int main(int argc, char **argv){
signal(SIGINT, signals); // ctrl+C - quit signal(SIGINT, signals); // ctrl+C - quit
signal(SIGQUIT, signals); // ctrl+\ - quit signal(SIGQUIT, signals); // ctrl+\ - quit
signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z 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->server) ERRX(_("Please, specify server name"));
if(!G->filename) ERRX(_("Please, specify the name of input FITS file")); if(!G->filename) ERRX(_("Please, specify the name of input FITS file"));
if(G->logfile) openlogfile(G->logfile); if(G->logfile) openlogfile(G->logfile);
daemonize(G); DBG("Opened, try to daemonize");
daemonize();
return 0; return 0;
} }

View File

@ -150,37 +150,43 @@ ewhile:
/** /**
* wait for answer from socket * wait for answer from socket
* @param sock - socket fd * @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){ static int waittoread(int sock){
fd_set fds; fd_set fds, efds;
struct timeval timeout; struct timeval timeout;
int rc; int rc;
timeout.tv_sec = 0; timeout.tv_sec = 0;
timeout.tv_usec = 100000; // wait not more than 100ms timeout.tv_usec = 100000; // wait not more than 100ms
FD_ZERO(&fds); FD_ZERO(&fds);
FD_ZERO(&efds);
FD_SET(sock, &fds); FD_SET(sock, &fds);
FD_SET(sock, &efds);
do{ do{
rc = select(sock+1, &fds, NULL, NULL, &timeout); rc = select(sock+1, &fds, NULL, &efds, &timeout);
if(rc < 0){ if(rc < 0){
if(errno != EINTR){ if(errno != EINTR){
putlog("Server not available");
WARN("select()"); WARN("select()");
return 0; return -1;
} }
continue; continue;
} }
break; break;
}while(1); }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; return 0;
} }
/** /**
* Open given FITS file, check it and add to inotify * Open given FITS file, check it and add to inotify
* THREAD UNSAFE!!! * THREAD UNSAFE!!!
* @return inotify file descriptor * @return inotify file descriptor
*/ */
int watch_fits(char *name){ int watch_fits(char *name){
FNAME();
static int fd = -1, wd = -1; static int fd = -1, wd = -1;
if(fd > 0 && wd > 0){ if(fd > 0 && wd > 0){
inotify_rm_watch(fd, wd); inotify_rm_watch(fd, wd);
@ -215,6 +221,7 @@ int watch_fits(char *name){
* test if user can write something to path & make CWD * test if user can write something to path & make CWD
*/ */
static void test_path(char *path){ static void test_path(char *path){
FNAME();
if(path){ if(path){
if(chdir(path)){ if(chdir(path)){
putlog("Can't chdir(%s)", 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"); 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 * Client daemon itself
* If sock < 0 try to reconnect after every image saving
* @param FITSpath - path to file watched * @param FITSpath - path to file watched
* @param infd - inotify file descriptor * @param infd - inotify file descriptor
* @param sock - socket's file descriptor * @param sock - socket's file descriptor
*/ */
static void client_(char *FITSpath, int infd, int sock){ static void client_(char *FITSpath, int infd, int sock){
if(sock < 0) return;
size_t Bufsiz = BUFLEN; size_t Bufsiz = BUFLEN;
char *recvBuff = MALLOC(char, Bufsiz); char *recvBuff = MALLOC(char, Bufsiz);
datarecord *last_good_msrment = NULL; datarecord *last_good_msrment = NULL;
@ -250,6 +299,7 @@ static void client_(char *FITSpath, int infd, int sock){
Bufsiz += 1024; Bufsiz += 1024;
recvBuff = realloc(recvBuff, Bufsiz); recvBuff = realloc(recvBuff, Bufsiz);
if(!recvBuff){ if(!recvBuff){
putlog("realloc() error");
WARN("realloc()"); WARN("realloc()");
return; return;
} }
@ -265,7 +315,7 @@ static void client_(char *FITSpath, int infd, int sock){
continue; continue;
putlog("poll() error"); putlog("poll() error");
ERR("poll()"); ERR("poll()");
return; return; // not reached
} }
if(poll_num > 0){ if(poll_num > 0){
DBG("changed?"); DBG("changed?");
@ -292,18 +342,24 @@ static void client_(char *FITSpath, int infd, int sock){
} }
} }
fds.fd = watch_fits(FITSpath); 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; size_t offset = 0;
do{ do{
rlc(offset); rlc(offset);
ssize_t n = read(sock, &recvBuff[offset], Bufsiz - offset); ssize_t n = read(sock, &recvBuff[offset], Bufsiz - offset);
if(!n){ if(!n){
putlog("socket disconnected"); putlog("nothing to read?");
offset = 0;
break; break;
} }
if(n < 0){ if(n < 0){
offset = 0;
putlog("read() error"); putlog("read() error");
WARN("read"); WARN("read");
break; break;
@ -312,8 +368,8 @@ static void client_(char *FITSpath, int infd, int sock){
}while(waittoread(sock)); }while(waittoread(sock));
if(!offset){ if(!offset){
putlog("socket disconnected"); putlog("socket disconnected");
WARN("Socket closed\n"); sock = -1;
return; continue;
} }
rlc(offset); rlc(offset);
recvBuff[offset] = 0; recvBuff[offset] = 0;
@ -325,10 +381,14 @@ static void client_(char *FITSpath, int infd, int sock){
/** /**
* Connect to socket and run daemon service * Connect to socket and run daemon service
*/ */
void daemonize(glob_pars *G){ void daemonize(){
FNAME();
char resolved_path[PATH_MAX]; char resolved_path[PATH_MAX];
// get full path to FITS file // 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 // open FITS file & add it to inotify
int fd = watch_fits(G->filename); int fd = watch_fits(G->filename);
// CD to archive directory if user wants // CD to archive directory if user wants
@ -336,6 +396,7 @@ void daemonize(glob_pars *G){
minstoragetime = G->min_storage_time; minstoragetime = G->min_storage_time;
// run fork before socket opening to prevent daemon's death if there's no network // run fork before socket opening to prevent daemon's death if there's no network
#ifndef EBUG #ifndef EBUG
putlog("daemonize");
if(daemon(1, 0)){ if(daemon(1, 0)){
putlog("daemon() error"); putlog("daemon() error");
ERR("daemon()"); ERR("daemon()");
@ -355,40 +416,8 @@ void daemonize(glob_pars *G){
} }
} }
#endif #endif
int sock = -1; int sock = try_to_connect();
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);
client_(resolved_path, fd, sock); client_(resolved_path, fd, sock);
close(sock); if(sock > 0) close(sock);
signals(0); signals(0);
} }

View File

@ -45,7 +45,9 @@ typedef struct{
bdata data; // data itself bdata data; // data itself
} datarecord; } datarecord;
void daemonize(glob_pars *G); extern glob_pars *G; // from main.c
void daemonize();
int watch_fits(char *name); int watch_fits(char *name);
#endif // __SOCKET_H__ #endif // __SOCKET_H__

View File

@ -394,6 +394,7 @@ time_t log_open_time = 0;
* if failed show warning message * if failed show warning message
*/ */
void openlogfile(char *name){ void openlogfile(char *name){
FNAME();
if(!name){ if(!name){
WARNX(_("Need filename")); WARNX(_("Need filename"));
return; return;
@ -405,6 +406,7 @@ void openlogfile(char *name){
} }
log_open_time = time(NULL); log_open_time = time(NULL);
logname = name; logname = name;
DBG("log file %s opened, time: %ld", name, log_open_time);
} }
/** /**