From 070df2be890bf430f32865b5765fa4352cceb3e8 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Wed, 5 Apr 2023 18:21:26 +0300 Subject: [PATCH] fix some network bugs; send image over other socket --- ccdfunc.c | 1 + client.c | 90 ++++++++++++---------------- cmdlnopts.c | 1 + cmdlnopts.h | 1 + locale/ru/messages.po | 28 +++++---- locale/ru/ru.po | 31 +++++----- main.c | 12 ++-- server.c | 133 +++++++++++++++++++++++++----------------- server.h | 4 +- socket.c | 71 +++++++++++++++++++--- socket.h | 4 +- 11 files changed, 228 insertions(+), 148 deletions(-) diff --git a/ccdfunc.c b/ccdfunc.c index 0a4df23..c6dc455 100644 --- a/ccdfunc.c +++ b/ccdfunc.c @@ -872,6 +872,7 @@ int ccdcaptured(IMG **imgptr){ frameformat fmt = camera->geometry; int raw_width = fmt.w / GP->hbin, raw_height = fmt.h / GP->vbin; IMG *ima = NULL; + if(*imgptr && ((*imgptr)->w != raw_width || (*imgptr)->h != raw_height)) FREE(*imgptr); if(!*imgptr){ uint16_t *img = MALLOC(uint16_t, raw_width * raw_height); DBG("\n\nAllocated image 2x%dx%d=%d", raw_width, raw_height, 2 * raw_width * raw_height); diff --git a/client.c b/client.c index ec9cc62..e45d2e6 100644 --- a/client.c +++ b/client.c @@ -19,6 +19,7 @@ // client-side functions #include #include // isnan +#include #include #include #include @@ -30,7 +31,10 @@ #include "socket.h" static char sendbuf[BUFSIZ]; -#define SENDMSG(...) do{snprintf(sendbuf, BUFSIZ-1, __VA_ARGS__); verbose(2, "\t> %s", sendbuf); sendstrmessage(sock, sendbuf); getans(sock);}while(0) +// send any message and wait any answer +#define SENDMSG(...) do{snprintf(sendbuf, BUFSIZ-1, __VA_ARGS__); verbose(2, "\t> %s", sendbuf); sendstrmessage(sock, sendbuf); getans(sock, NULL);}while(0) +// send command and wait for answer on it +#define SENDCMDW(cmd) do{strncpy(sendbuf, cmd, BUFSIZ-1); verbose(2, "\t> %s", sendbuf); sendstrmessage(sock, sendbuf); getans(sock, cmd);}while(0) static volatile atomic_int expstate = CAMERA_CAPTURE; static int xm0,ym0,xm1,ym1; // max format static int xc0,yc0,xc1,yc1; // current format @@ -41,36 +45,6 @@ static volatile atomic_int grabends = 0; static int imdatalen = 0, imbufsz = 0; #endif -/** - * check data from fd (polling function for client) - * @param fd - file descriptor - * @return 0 in case of timeout, 1 in case of fd have data, -1 if error - */ -static int canberead(int fd){ - fd_set fds; - struct timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 100; - FD_ZERO(&fds); - FD_SET(fd, &fds); - do{ - int rc = select(fd+1, &fds, NULL, NULL, &timeout); - if(rc < 0){ - if(errno != EINTR){ - LOGWARN("select()"); - WARN("select()"); - return -1; - } - continue; - } - break; - }while(1); - if(FD_ISSET(fd, &fds)){ - return 1; - } - return 0; -} - static char *readmsg(int fd){ static char buf[BUFSIZ] = {0}, line[BUFSIZ]; int curlen = strlen(buf); @@ -101,7 +75,10 @@ static char *readmsg(int fd){ static int parseans(char *ans){ if(!ans) return FALSE; //DBG("Parsing of '%s'", ans); - if(0 == strcmp(hresult2str(RESULT_BUSY), ans)) ERRX("Server busy"); + if(0 == strcmp(hresult2str(RESULT_BUSY), ans)){ + WARNX("Server busy"); + return FALSE; + } if(0 == strcmp(hresult2str(RESULT_FAIL), ans)) return TRUE; if(0 == strcmp(hresult2str(RESULT_OK), ans)) return TRUE; char *val = get_keyval(ans); // now `ans` is a key and `val` its value @@ -130,7 +107,8 @@ static int parseans(char *ans){ } // read until timeout all messages from server; return FALSE if there was no messages from server -static int getans(int sock){ +// if msg != NULL - wait for it in answer +static int getans(int sock, const char *msg){ double t0 = dtime(); char *ans = NULL; while(dtime() - t0 < ANSWER_TIMEOUT){ @@ -143,7 +121,10 @@ static int getans(int sock){ ans = s; DBG("Got from server: %s", ans); verbose(1, "\t%s", ans); - if(parseans(ans)) break; + if(parseans(ans)){ + if(msg && strncmp(ans, msg, strlen(msg))) continue; + break; + } } DBG("GETANS: timeout, ans: %s", ans); return ((ans) ? TRUE : FALSE); @@ -251,8 +232,7 @@ void client(int sock){ else GP->waitexpend = TRUE; // N>1 - wait for exp ends SENDMSG(CMD_EXPSTATE "=%d", CAMERA_CAPTURE); }else{ - double t0 = dtime(); - while(getans(sock) && dtime() - t0 < WAIT_TIMEOUT); + getans(sock, NULL); DBG("RETURN: no more data"); return; } @@ -269,7 +249,7 @@ void client(int sock){ sprintf(sendbuf, "%s", CMD_EXPSTATE); sendstrmessage(sock, sendbuf); } - if(getans(sock)){ // got next portion of data + if(getans(sock, NULL)){ // got next portion of data DBG("server message"); t0 = dtime(); if(expstate == CAMERA_ERROR){ @@ -307,18 +287,20 @@ void client(int sock){ } #ifdef IMAGEVIEW -static int grabsockfd = -1; +static int controlfd = -1; void init_grab_sock(int sock){ - grabsockfd = sock; + if(sock < 0) ERRX("Can't run without command socket"); + controlfd = sock; send_headers(sock); } static void getimage(){ - int sock = grabsockfd; + FNAME(); + int sock = controlfd; SENDMSG(CMD_IMWIDTH); SENDMSG(CMD_IMHEIGHT); - while(readmsg(sock)); // clear all incoming data - sendstrmessage(sock, CMD_GETIMAGE); // ask for image + int imsock = open_socket(FALSE, GP->imageport, TRUE); + if(imsock < 0) ERRX("getimage(): can't open image transport socket"); if(imbufsz < imdatalen){ DBG("Reallocate memory from %d to %d", imbufsz, imdatalen); ima.data = realloc(ima.data, imdatalen); @@ -327,9 +309,9 @@ static void getimage(){ double t0 = dtime(); int got = 0; while(dtime() - t0 < CLIENT_TIMEOUT){ - if(!canberead(sock)) continue; + if(!canberead(imsock)) continue; uint8_t *target = ((uint8_t*)ima.data)+got; - int rd = read(sock, target, imdatalen - got); + int rd = read(imsock, target, imdatalen - got); if(rd <= 0){ WARNX("Server disconnected"); signals(1); @@ -344,12 +326,13 @@ static void getimage(){ } } if(dtime() - t0 > CLIENT_TIMEOUT) WARNX("Timeout, image didn't received"); + close(imsock); } static void *grabnext(void _U_ *arg){ // daemon grabbing images through the net FNAME(); - if(grabsockfd < 0) return NULL; - int sock = grabsockfd; + if(controlfd < 0) return NULL; + int sock = controlfd; while(1){ DBG("WAIT"); while(grabends); // wait until image processed @@ -366,7 +349,7 @@ static void *grabnext(void _U_ *arg){ // daemon grabbing images through the net DBG("SLEEP!"); usleep(sleept); //SENDMSG(CMD_EXPSTATE); - getans(sock); + getans(sock, NULL); DBG("EXPSTATE ===> %d", expstate); if(expstate != CAMERA_CAPTURE) break; } @@ -382,16 +365,18 @@ static void *grabnext(void _U_ *arg){ // daemon grabbing images through the net static void *waitimage(void _U_ *arg){ // passive waiting for next image FNAME(); - if(grabsockfd < 0) return NULL; - int sock = grabsockfd; + if(controlfd < 0) return NULL; + int sock = controlfd; while(1){ while(grabends); // wait until image processed - getans(sock); + getans(sock, NULL); if(expstate != CAMERA_FRAMERDY){ usleep(1000); continue; } + DBG("Image can be downloaded"); getimage(); + expstate = CAMERA_IDLE; } return NULL; } @@ -400,7 +385,7 @@ static void *waitimage(void _U_ *arg){ // passive waiting for next image int sockcaptured(IMG **imgptr){ if(!imgptr) return FALSE; static pthread_t grabthread = 0; - if(grabsockfd < 0) return FALSE; + if(controlfd < 0) return FALSE; if(imgptr == (void*)-1){ // kill `grabnext` DBG("Wait for grabbing thread"); if(grabthread){ @@ -411,7 +396,7 @@ int sockcaptured(IMG **imgptr){ DBG("OK"); return FALSE; } - if(!grabthread){ // start new grab + if(!grabthread || pthread_kill(grabthread, 0)){ // start new grab if(GP->viewer){ DBG("\n\n\nStart new waiting"); if(pthread_create(&grabthread, NULL, &waitimage, NULL)){ @@ -428,7 +413,6 @@ int sockcaptured(IMG **imgptr){ }else{ // grab in process if(grabends){ // image is ready DBG("Image ready"); - grabthread = 0; if(*imgptr && (*imgptr != &ima)) free(*imgptr); *imgptr = &ima; grabends = 0; diff --git a/cmdlnopts.c b/cmdlnopts.c index 5243c9a..7f6c877 100644 --- a/cmdlnopts.c +++ b/cmdlnopts.c @@ -100,6 +100,7 @@ myoption cmdlnopts[] = { {"logfile", NEED_ARG, NULL, 0, arg_string, APTR(&G.logfile), N_("logging file name (if run as server)")}, {"path", NEED_ARG, NULL, 0, arg_string, APTR(&G.path), N_("UNIX socket name")}, {"port", NEED_ARG, NULL, 0, arg_string, APTR(&G.port), N_("local INET socket port")}, + {"imageport",NEED_ARG, NULL, 0, arg_string, APTR(&G.imageport), N_("local INET socket port to send/receive images")}, {"client", NO_ARGS, &G.client,1, arg_none, NULL, N_("run as client")}, {"viewer", NO_ARGS, &G.viewer,1, arg_none, NULL, N_("passive viewer (only get last images)")}, {"pidfile", NEED_ARG, NULL, 0, arg_string, APTR(&G.pidfile), N_("PID file (default: " DEFAULT_PID_FILE ")")}, diff --git a/cmdlnopts.h b/cmdlnopts.h index c36994f..d964b55 100644 --- a/cmdlnopts.h +++ b/cmdlnopts.h @@ -38,6 +38,7 @@ typedef struct{ char *logfile; // when run as server log here char *path; // UNIX socket name char *port; // local INET socket port + char *imageport; // port to send/receive images (by default == port+1) char *pidfile; // PID file (default: /tmp/CCD_Capture.pid) char **addhdr; // list of files from which to add header records int restart; // restart server diff --git a/locale/ru/messages.po b/locale/ru/messages.po index 739120f..ce3a2b3 100644 --- a/locale/ru/messages.po +++ b/locale/ru/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-04 18:42+0300\n" +"POT-Creation-Date: 2023-04-05 18:17+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -230,22 +230,26 @@ msgid "local INET socket port" msgstr "" #: cmdlnopts.c:103 -msgid "run as client" +msgid "local INET socket port to send/receive images" msgstr "" #: cmdlnopts.c:104 -msgid "passive viewer (only get last images)" +msgid "run as client" msgstr "" #: cmdlnopts.c:105 -msgid "PID file (default: " +msgid "passive viewer (only get last images)" msgstr "" #: cmdlnopts.c:106 +msgid "PID file (default: " +msgstr "" + +#: cmdlnopts.c:107 msgid "restart image server" msgstr "" -#: cmdlnopts.c:109 +#: cmdlnopts.c:110 msgid "Display image in OpenGL window" msgstr "" @@ -478,12 +482,12 @@ msgstr "" msgid "Can't set brightness to %g" msgstr "" -#: ccdfunc.c:724 server.c:228 +#: ccdfunc.c:724 server.c:227 #, c-format msgid "Can't set binning %dx%d" msgstr "" -#: ccdfunc.c:736 server.c:229 +#: ccdfunc.c:736 server.c:228 msgid "Can't set given geometry" msgstr "" @@ -529,7 +533,7 @@ msgstr "" msgid "Capture frame %d" msgstr "" -#: ccdfunc.c:780 ccdfunc.c:832 server.c:123 +#: ccdfunc.c:780 ccdfunc.c:832 server.c:122 msgid "Can't start exposition" msgstr "" @@ -546,20 +550,20 @@ msgid "Can't grab image" msgstr "" #. %d секунд до окончания паузы\n -#: ccdfunc.c:799 client.c:289 +#: ccdfunc.c:799 client.c:269 #, c-format msgid "%d seconds till pause ends\n" msgstr "" -#: server.c:166 +#: server.c:165 msgid "No camera device" msgstr "" -#: client.c:276 +#: client.c:256 msgid "Can't make exposition" msgstr "" -#: client.c:305 +#: client.c:285 msgid "Server timeout" msgstr "" diff --git a/locale/ru/ru.po b/locale/ru/ru.po index 6f6b6bc..0f60760 100644 --- a/locale/ru/ru.po +++ b/locale/ru/ru.po @@ -7,7 +7,7 @@ msgid "" msgstr "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" - "POT-Creation-Date: 2023-04-04 18:23+0300\n" + "POT-Creation-Date: 2023-04-05 18:17+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -22,7 +22,7 @@ msgid "%.1f seconds till exposition ends" msgstr "%.1f " #. %d секунд до окончания паузы\n -#: ccdfunc.c:799 client.c:289 +#: ccdfunc.c:799 client.c:269 #, c-format msgid "%d seconds till pause ends\n" msgstr "%d \n" @@ -117,7 +117,7 @@ msgstr " msgid "Can't init mutex!" msgstr " !" -#: client.c:276 +#: client.c:256 msgid "Can't make exposition" msgstr " " @@ -162,7 +162,7 @@ msgstr " msgid "Can't set active wheel number" msgstr " " -#: ccdfunc.c:724 server.c:228 +#: ccdfunc.c:724 server.c:227 #, c-format msgid "Can't set binning %dx%d" msgstr " %dx%d" @@ -190,7 +190,7 @@ msgstr " msgid "Can't set gain to %g" msgstr " Gain %g" -#: ccdfunc.c:736 server.c:229 +#: ccdfunc.c:736 server.c:228 msgid "Can't set given geometry" msgstr " " @@ -213,7 +213,7 @@ msgstr " msgid "Can't set wheel position %d" msgstr " %d" -#: ccdfunc.c:780 ccdfunc.c:832 server.c:123 +#: ccdfunc.c:780 ccdfunc.c:832 server.c:122 msgid "Can't start exposition" msgstr " " @@ -228,7 +228,7 @@ msgstr " msgid "Current format: %s" msgstr "" -#: cmdlnopts.c:109 +#: cmdlnopts.c:110 msgid "Display image in OpenGL window" msgstr " OpenGL" @@ -289,7 +289,7 @@ msgstr " msgid "N flushes before exposing (default: 1)" msgstr "N ( : 1)" -#: server.c:166 +#: server.c:165 msgid "No camera device" msgstr " " @@ -309,7 +309,7 @@ msgstr " msgid "Only show statistics" msgstr " " -#: cmdlnopts.c:105 +#: cmdlnopts.c:106 msgid "PID file (default: " msgstr "PID- ( : " @@ -327,7 +327,7 @@ msgstr " msgid "Readout mode: %s" msgstr " : %s" -#: client.c:305 +#: client.c:285 msgid "Server timeout" msgstr " " @@ -460,6 +460,11 @@ msgstr " msgid "local INET socket port" msgstr " " +#: cmdlnopts.c:103 +#, fuzzy +msgid "local INET socket port to send/receive images" +msgstr " " + #: cmdlnopts.c:100 msgid "logging file name (if run as server)" msgstr " ( )" @@ -521,7 +526,7 @@ msgstr " msgid "output file name" msgstr " " -#: cmdlnopts.c:104 +#: cmdlnopts.c:105 msgid "passive viewer (only get last images)" msgstr "" @@ -529,7 +534,7 @@ msgstr "" msgid "program author" msgstr " " -#: cmdlnopts.c:106 +#: cmdlnopts.c:107 msgid "restart image server" msgstr " " @@ -537,7 +542,7 @@ msgstr " msgid "rewrite output file if exists" msgstr " " -#: cmdlnopts.c:103 +#: cmdlnopts.c:104 msgid "run as client" msgstr " " diff --git a/main.c b/main.c index 3889ed2..6d8a34f 100644 --- a/main.c +++ b/main.c @@ -108,6 +108,12 @@ int main(int argc, char **argv){ if(!GP->client) isserver = TRUE; } if(GP->path && !GP->client) isserver = TRUE; + if((isserver || GP->client) && !GP->imageport){ + GP->imageport = MALLOC(char, 32); + if(!GP->port) sprintf(GP->imageport, "12345"); + else snprintf(GP->imageport, 31, "%d", 1+atoi(GP->port)); + verbose(1, "Set image port to %s", GP->imageport); + } if(GP->client && (GP->commondev || GP->focuserdev || GP->cameradev || GP->wheeldev)) ERRX("Can't be client and standalone in same time!"); if(GP->logfile){ @@ -134,8 +140,7 @@ int main(int argc, char **argv){ wheels(); camerainit = prepare_ccds(); }else{ // client mode - if(GP->path) return start_socket(isserver, GP->path, FALSE); - if(GP->port) return start_socket(isserver, GP->port, TRUE); + return start_socket(isserver); } #ifdef IMAGEVIEW if(GP->showimage){ // activate image vindow in capture or simple viewer mode @@ -169,7 +174,6 @@ int main(int argc, char **argv){ } #endif - if(GP->path) return start_socket(isserver, GP->path, FALSE); - if(GP->port) return start_socket(isserver, GP->port, TRUE); + return start_socket(isserver); } diff --git a/server.c b/server.c index 3ff36a9..b7fdc5e 100644 --- a/server.c +++ b/server.c @@ -70,7 +70,6 @@ strpair allcommands[] = { { CMD_FGOTO, "focuser position" }, { CMD_FRAMEFORMAT, "camera frame format (X0,Y0,X1,Y1)" }, { CMD_GAIN, "camera gain" }, - { CMD_GETIMAGE, "get image (binary data 2*w*h bytes)" }, { CMD_HBIN, "horizontal binning" }, { CMD_HEADERFILES, "add FITS records from these files (comma-separated list)" }, { CMD_HELP, "show this help" }, @@ -528,6 +527,7 @@ static hresult formathandler(int fd, const char *key, const char *val){ int r = camera->setgeometry(&fmt); if(!r) return RESULT_FAIL; curformat = fmt; + DBG("curformat: w=%d, h=%d", curformat.w, curformat.h); fixima(); } if(0 == strcmp(key, CMD_FRAMEMAX)) snprintf(buf, 63, CMD_FRAMEMAX "=%d,%d,%d,%d", @@ -886,14 +886,6 @@ static hresult helphandler(int fd, _U_ const char *key, _U_ const char *val){ return RESULT_SILENCE; } -// sent to client last image -static hresult imsendhandler(int fd, _U_ const char *key, _U_ const char *val){ - if(!ima.data || !ima.h || !ima.w) return RESULT_FAIL; - // send image as raw data w*h*2 - if(!sendimage(fd, ima.data, 2*ima.h*ima.w)) return RESULT_DISCONNECTED; - return RESULT_SILENCE; -} - static hresult imsizehandler(int fd, const char *key, _U_ const char *val){ char buf[64]; // send image width/height in pixels @@ -920,6 +912,10 @@ static hresult chkcam(char *val){ if(camera) return RESULT_OK; return RESULT_FAIL; } +static hresult chkcc(_U_ char *val){ // just check that camera connected + if(camera) return RESULT_OK; + return RESULT_FAIL; +} static hresult chkwhl(char *val){ if(val && CAMbusy()) return RESULT_BUSY; if(wheel) return RESULT_OK; @@ -934,31 +930,30 @@ static handleritem items[] = { {chktrue,infohandler, CMD_INFO}, {NULL, helphandler, CMD_HELP}, {NULL, restarthandler, CMD_RESTART}, - {chkcam, camlisthandler, CMD_CAMLIST}, - {chkcam, camsetNhandler, CMD_CAMDEVNO}, - {chkcam, camfanhandler, CMD_CAMFANSPD}, - {chkcam, exphandler, CMD_EXPOSITION}, - {chkcam, namehandler, CMD_FILENAME}, - {chkcam, binhandler, CMD_HBIN}, - {chkcam, binhandler, CMD_VBIN}, - {chkcam, temphandler, CMD_CAMTEMPER}, + {chkcc, camlisthandler, CMD_CAMLIST}, + {chkcc, camsetNhandler, CMD_CAMDEVNO}, + {chkcc, camfanhandler, CMD_CAMFANSPD}, + {chkcc, exphandler, CMD_EXPOSITION}, + {chkcc, namehandler, CMD_FILENAME}, + {chkcc, binhandler, CMD_HBIN}, + {chkcc, binhandler, CMD_VBIN}, + {chkcc, temphandler, CMD_CAMTEMPER}, {chkcam, shutterhandler, CMD_SHUTTER}, - {chkcam, confiohandler, CMD_CONFIO}, - {chkcam, iohandler, CMD_IO}, - {chkcam, gainhandler, CMD_GAIN}, - {chkcam, brightnesshandler, CMD_BRIGHTNESS}, - {chkcam, formathandler, CMD_FRAMEFORMAT}, - {chkcam, formathandler, CMD_FRAMEMAX}, - {chkcam, nflusheshandler, CMD_NFLUSHES}, - {NULL, expstatehandler, CMD_EXPSTATE}, - {NULL, imsendhandler, CMD_GETIMAGE}, + {chkcc, confiohandler, CMD_CONFIO}, + {chkcc, iohandler, CMD_IO}, + {chkcc, gainhandler, CMD_GAIN}, + {chkcc, brightnesshandler, CMD_BRIGHTNESS}, + {chkcc, formathandler, CMD_FRAMEFORMAT}, + {chkcc, formathandler, CMD_FRAMEMAX}, + {chkcc, nflusheshandler, CMD_NFLUSHES}, + {chkcam, expstatehandler, CMD_EXPSTATE}, {NULL, imsizehandler, CMD_IMWIDTH}, {NULL, imsizehandler, CMD_IMHEIGHT}, - {chkcam, nameprefixhandler, CMD_FILENAMEPREFIX}, - {chkcam, rewritefilehandler, CMD_REWRITE}, - {chkcam, _8bithandler, CMD_8BIT}, - {chkcam, fastspdhandler, CMD_FASTSPD}, - {chkcam, darkhandler, CMD_DARK}, + {chkcc, nameprefixhandler, CMD_FILENAMEPREFIX}, + {chkcc, rewritefilehandler, CMD_REWRITE}, + {chkcc, _8bithandler, CMD_8BIT}, + {chkcc, fastspdhandler, CMD_FASTSPD}, + {chkcc, darkhandler, CMD_DARK}, {NULL, tremainhandler, CMD_TREMAIN}, {NULL, FITSparhandler, CMD_AUTHOR}, {NULL, FITSparhandler, CMD_INSTRUMENT}, @@ -979,7 +974,20 @@ static handleritem items[] = { #define CLBUFSZ BUFSIZ -void server(int sock){ +void server(int sock, int imsock){ + DBG("sockfd=%d, imsockfd=%d", sock, imsock); + if(sock < 0) ERRX("server(): need at least command socket fd"); + if(imsock < 0) WARNX("Server run without image transport support"); + else if(listen(imsock, MAXCLIENTS) == -1){ + WARN("listen()"); + LOGWARN("listen()"); + return; + } + if(listen(sock, MAXCLIENTS) == -1){ + WARN("listen()"); + LOGWARN("listen()"); + return; + } // init everything startFocuser(&focdev); focdevini(0); @@ -987,58 +995,75 @@ void server(int sock){ wheeldevini(0); startCCD(&camdev); camdevini(0); - if(listen(sock, MAXCLIENTS) == -1){ - WARN("listen"); - LOGWARN("listen"); - return; - } // start camera thread pthread_t camthread; if(camera){ if(pthread_create(&camthread, NULL, processCAM, NULL)) ERR("pthread_create()"); } - int nfd = 1; // only one socket @start - struct pollfd poll_set[MAXCLIENTS+1]; + int nfd = 2; // only one socket @start + struct pollfd poll_set[MAXCLIENTS+2]; char buffers[MAXCLIENTS][CLBUFSZ]; // buffers for data reading bzero(poll_set, sizeof(poll_set)); // ZERO - listening server socket poll_set[0].fd = sock; poll_set[0].events = POLLIN; + poll_set[1].fd = imsock; + poll_set[1].events = POLLIN; while(1){ poll(poll_set, nfd, 1); // max timeout - 1ms + //if(imsock > -1 && canberead(imsock) > 0){ + if(imsock > -1 && (poll_set[1].revents & POLLIN)){ + //uint8_t buf[32]; + //int l = read(imsock, buf, 32); + DBG("Somebody wants an image"); + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + int client = accept(imsock, (struct sockaddr*)&addr, &len); + DBG("client=%d", client); + if(client > -1){ + DBG("client fd: %d", client); + // send image as raw data w*h*2 + if(ima.data && ima.h > 0 && ima.w > 0) + sendimage(client, ima.data, 2*ima.h*ima.w); + close(client); + DBG("%d closed", client); + }else{WARN("accept()"); DBG("disconnected");} + } if(poll_set[0].revents & POLLIN){ // check main for accept() struct sockaddr_in addr; socklen_t len = sizeof(addr); int client = accept(sock, (struct sockaddr*)&addr, &len); - DBG("New connection"); - LOGMSG("SERVER got connection, fd=%d", client); - if(nfd == MAXCLIENTS + 1){ - LOGWARN("Max amount of connections, disconnect fd=%d", client); - WARNX("Limit of connections reached"); - close(client); - }else{ - memset(&poll_set[nfd], 0, sizeof(struct pollfd)); - poll_set[nfd].fd = client; - poll_set[nfd].events = POLLIN; - ++nfd; + if(client > -1){ + DBG("New connection"); + LOGMSG("SERVER got connection, fd=%d", client); + if(nfd == MAXCLIENTS + 1){ + LOGWARN("Max amount of connections, disconnect fd=%d", client); + WARNX("Limit of connections reached"); + close(client); + }else{ + memset(&poll_set[nfd], 0, sizeof(struct pollfd)); + poll_set[nfd].fd = client; + poll_set[nfd].events = POLLIN; + ++nfd; + } } } // process some data & send messages to ALL if(camstate == CAMERA_FRAMERDY || camstate == CAMERA_ERROR){ char buff[PATH_MAX+32]; snprintf(buff, PATH_MAX, CMD_EXPSTATE "=%d", camstate); - DBG("Send %s to %d clients", buff, nfd - 1); - for(int i = 1; i < nfd; ++i) + DBG("Send %s to %d clients", buff, nfd - 2); + for(int i = 2; i < nfd; ++i) sendstrmessage(poll_set[i].fd, buff); if(camstate == CAMERA_FRAMERDY){ // send to all last file name snprintf(buff, PATH_MAX+31, CMD_LASTFNAME "=%s", lastfile); - for(int i = 1; i < nfd; ++i) + for(int i = 2; i < nfd; ++i) sendstrmessage(poll_set[i].fd, buff); } camstate = CAMERA_IDLE; } // scan connections - for(int fdidx = 1; fdidx < nfd; ++fdidx){ + for(int fdidx = 2; fdidx < nfd; ++fdidx){ if((poll_set[fdidx].revents & POLLIN) == 0) continue; int fd = poll_set[fdidx].fd; if(!processData(fd, items, buffers[fdidx-1], CLBUFSZ)){ // socket closed diff --git a/server.h b/server.h index c6e176f..97bad25 100644 --- a/server.h +++ b/server.h @@ -29,7 +29,7 @@ typedef enum{ #define TLOG_PAUSE 60. // server-side functions -void server(int fd); +void server(int fd, int imsock); char *makeabspath(const char *path, int shouldbe); // common information about everything @@ -37,8 +37,6 @@ char *makeabspath(const char *path, int shouldbe); #define CMD_HELP "help" // restart server #define CMD_RESTART "restartTheServer" -// get last exposed image -#define CMD_GETIMAGE "getimage" // get image size in pixels #define CMD_IMWIDTH "imwidth" #define CMD_IMHEIGHT "imheight" diff --git a/socket.c b/socket.c index b785305..b9d4912 100644 --- a/socket.c +++ b/socket.c @@ -17,11 +17,13 @@ */ #include // isspace +#include #include #include #include #include #include // unix socket +#include #include #include "client.h" @@ -35,13 +37,14 @@ pthread_mutex_t locmutex = PTHREAD_MUTEX_INITIALIZER; // mutex for wheel/camera/focuser functions /** - * @brief start_socket - create socket and run client or server + * @brief open_socket - create socket and open it * @param isserver - TRUE for server, FALSE for client * @param path - UNIX-socket path or local INET socket port * @param isnet - TRUE for INET socket, FALSE for UNIX - * @return 0 if OK + * @return socket FD or -1 if failed */ -int start_socket(int isserver, char *path, int isnet){ +int open_socket(int isserver, char *path, int isnet){ + DBG("isserver=%d, path=%s, isnet=%d", isserver, path, isnet); if(!path) return 1; DBG("path/port: %s", path); int sock = -1; @@ -89,6 +92,7 @@ int start_socket(int isserver, char *path, int isnet){ close(sock); sock = -1; continue; } + //fcntl(sock, F_SETFL, O_NONBLOCK); if(bind(sock, p->ai_addr, p->ai_addrlen) == -1){ WARN("bind()"); LOGWARN("bind()"); @@ -111,13 +115,30 @@ int start_socket(int isserver, char *path, int isnet){ } break; } + if(isnet) freeaddrinfo(res); + return sock; +} + +/** + * @brief start_socket - create socket and run client or server + * @param isserver - TRUE for server, FALSE for client + * @return 0 if OK + */ +int start_socket(int isserver){ + char *path = NULL; + int isnet = FALSE; + if(GP->path) path = GP->path; + else if(GP->port){ path = GP->port; isnet = TRUE; } + else ERRX("Point network port or UNIX-socket path"); + int sock = open_socket(isserver, path, isnet), imsock = -1; if(sock < 0){ LOGERR("Can't open socket"); - ERRX("Can't open socket"); + ERRX("start_socket(): can't open socket"); } - if(isnet) freeaddrinfo(res); - if(isserver) server(sock); - else{ + if(isserver){ + imsock = open_socket(TRUE, GP->imageport, TRUE); + server(sock, imsock); + }else{ #ifdef IMAGEVIEW if(GP->showimage){ if(!GP->viewer && GP->exptime < 0.00001) ERRX("Need exposition time!"); @@ -129,12 +150,16 @@ int start_socket(int isserver, char *path, int isnet){ } DBG("Close socket"); close(sock); - if(isserver) signals(0); + if(isserver){ + close(imsock); + signals(0); + } return 0; } // send image data to client int sendimage(int fd, uint16_t *data, int l){ + DBG("fd=%d, l=%d", fd, l); if(fd < 1 || !data || l < 1) return TRUE; // empty message DBG("send new image (size=%d) to fd %d", l, fd); //strncpy((char*)data, "TEST image data\n", 17); @@ -291,3 +316,33 @@ int processData(int fd, handleritem *handlers, char *buf, int buflen){ if(restofdata != buf) memmove(buf, restofdata, eptr - restofdata + 1); return TRUE; } + +/** + * check data from fd (polling function for client) + * @param fd - file descriptor + * @return 0 in case of timeout, 1 in case of fd have data, -1 if error + */ +int canberead(int fd){ + fd_set fds; + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 100; + FD_ZERO(&fds); + FD_SET(fd, &fds); + do{ + int rc = select(fd+1, &fds, NULL, NULL, &timeout); + if(rc < 0){ + if(errno != EINTR){ + LOGWARN("select()"); + WARN("select()"); + return -1; + } + continue; + } + break; + }while(1); + if(FD_ISSET(fd, &fds)){ + return 1; + } + return 0; +} diff --git a/socket.h b/socket.h index 9903ae4..f7877b0 100644 --- a/socket.h +++ b/socket.h @@ -61,10 +61,12 @@ typedef struct{ const char *key; // keyword } handleritem; -int start_socket(int server, char *path, int isnet); +int open_socket(int isserver, char *path, int isnet); +int start_socket(int server); int sendimage(int fd, uint16_t *data, int l); int sendmessage(int fd, const char *msg, int l); int sendstrmessage(int fd, const char *msg); char *get_keyval(char *keyval); int processData(int fd, handleritem *handlers, char *buf, int buflen); +int canberead(int fd);