From 9e2bfe445640a5690f8cbabde86f8158cc7a4ba5 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Mon, 16 Dec 2024 11:41:33 +0300 Subject: [PATCH] version 0.3.2 --- CMakeLists.txt | 2 +- TODO | 1 - examples/clientserver.c | 98 +++++++++++++++---- locale/ru/LC_MESSAGES/usefull_macros.mo | Bin 4824 -> 4692 bytes locale/ru/messages.po | 28 ++++-- locale/ru/ru.po | 29 +++--- ringbuffer.c | 18 +++- socket.c | 124 ++++++++++++++++-------- usefull_macros.h | 16 ++- 9 files changed, 223 insertions(+), 93 deletions(-) delete mode 100644 TODO diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c61f5a..6ef60a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.9) set(PROJ usefull_macros) -set(MINOR_VERSION "1") +set(MINOR_VERSION "2") set(MID_VERSION "3") set(MAJOR_VERSION "0") set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}") diff --git a/TODO b/TODO deleted file mode 100644 index 9469638..0000000 --- a/TODO +++ /dev/null @@ -1 +0,0 @@ -BUG in commandline options: '?' don't work! diff --git a/examples/clientserver.c b/examples/clientserver.c index f57defe..0fa77a5 100644 --- a/examples/clientserver.c +++ b/examples/clientserver.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include static sl_sock_t *s = NULL; @@ -48,38 +50,70 @@ static sl_option_t cmdlnopts[] = { end_option }; +static sl_ringbuffer_t *rb = NULL; +static char rbuf[BUFSIZ], tbuf[BUFSIZ]; + void signals(int sig){ if(sig){ signal(sig, SIG_IGN); DBG("Get signal %d, quit.\n", sig); + LOGERR("Exit with status %d", sig); + }else LOGERR("Exit"); + if(rb){ + while(sl_RB_readline(rb, rbuf, BUFSIZ-1)){ // show all recent messages from server + printf("server > %s\n", rbuf); + } + sl_RB_delete(&rb); } - LOGERR("Exit with status %d", sig); sl_restore_con(); if(s) sl_sock_delete(&s); exit(sig); } static void runclient(sl_sock_t *s){ - char buf[300]; + rb = sl_RB_new(BUFSIZ * 4); if(!s) return; do{ - printf("send > "); - char *r = fgets(buf, 300, stdin); - if(r){ + while(sl_RB_readline(rb, rbuf, BUFSIZ-1)){ // show all recent messages from server + printf("server > %s\n", rbuf); + } + printf("send > "); fflush(stdout); + int c, k = 0; + while (k < BUFSIZ-1){ + ssize_t got = sl_sock_readline(s, rbuf, BUFSIZ); + if(got > 0){ + DBG("GOT %zd", got); + if(k == 0){ printf("\nserver > %s\nsend > ", rbuf); fflush(stdout); }// user didn't type anything -> show server messages + else sl_RB_writestr(rb, rbuf); + } else if(got < 0){ DBG("disc"); signals(0);} + if(!s || !s->connected){ DBG("DISC"); signals(0); } + c = sl_read_con(); + if(!c) continue; + if(c == '\b' || c == 127){ // use DEL and BACKSPACE to erase previous symbol + if(k){ + --k; + printf("\b \b"); + } + }else{ + if(c == EOF) break; + tbuf[k++] = c; + printf("%c", c); + } + fflush(stdout); + if(c == '\n') break; + } + tbuf[k] = 0; + DBG("Your str: _%s_", tbuf); + if(c == EOF) break; + if(k >= BUFSIZ-1) ERRX("Congrats! You caused buffer overflow!"); + if(k){ DBG("try"); - if(-1 == sl_sock_sendstrmessage(s, buf)){ + if(-1 == sl_sock_sendstrmessage(s, tbuf)){ WARNX("Error send"); return; } DBG("OK"); }else break; - ssize_t got = 0; - double t0 = sl_dtime(); - do{ - got = sl_sock_readline(s, buf, 299); - if(got > 0) printf("server > %s\n", buf); - }while(s && s->connected && (got > 0 || sl_dtime() - t0 < 0.3)); - if(got < 0) break; } while(s && s->connected); WARNX("Ctrl+D or disconnected"); } @@ -87,11 +121,12 @@ static void runclient(sl_sock_t *s){ // flags for standard handlers static sl_sock_int_t iflag = {0}; static sl_sock_double_t dflag = {0}; +static sl_sock_string_t sflag = {0}; -static sl_sock_hresult_e dtimeh(sl_sock_t *client, _U_ sl_sock_hitem_t *item, _U_ const char *req){ +static sl_sock_hresult_e dtimeh(sl_sock_t _U_ *client, _U_ sl_sock_hitem_t *item, _U_ const char *req){ char buf[32]; snprintf(buf, 31, "UNIXT=%.2f\n", sl_dtime()); - sl_sock_sendstrmessage(client, buf); + sl_sock_sendall((uint8_t*)buf, strlen(buf)); return RESULT_SILENCE; } @@ -105,17 +140,41 @@ static sl_sock_hresult_e show(sl_sock_t *client, _U_ sl_sock_hitem_t *item, _U_ return RESULT_OK; } +// Too much clients handler static void toomuch(int fd){ - const char *m = "Try later: too much clients connected\n"; - send(fd, m, sizeof(m+1), MSG_NOSIGNAL); + const char m[] = "Try later: too much clients connected\n"; + send(fd, m, sizeof(m)-1, MSG_NOSIGNAL); + shutdown(fd, SHUT_WR); + DBG("shutdown, wait"); + double t0 = sl_dtime(); + uint8_t buf[8]; + while(sl_dtime() - t0 < 11.){ + if(sl_canread(fd)){ + ssize_t got = read(fd, buf, 8); + DBG("Got=%zd", got); + if(got < 1) break; + } + } + DBG("Disc after %gs", sl_dtime() - t0); LOGWARN("Client fd=%d tried to connect after MAX reached", fd); } +// new connections handler +static void connected(sl_sock_t *c){ + if(c->type == SOCKT_UNIX) LOGMSG("New client fd=%d connected", c->fd); + else LOGMSG("New client fd=%d, IP=%s connected", c->fd, c->IP); +} +// disconnected handler +static void disconnected(sl_sock_t *c){ + if(c->type == SOCKT_UNIX) LOGMSG("Disconnected client fd=%d", c->fd); + else LOGMSG("Disconnected client fd=%d, IP=%s", c->fd, c->IP); +} static sl_sock_hitem_t handlers[] = { {sl_sock_inthandler, "int", "set/get integer flag", (void*)&iflag}, {sl_sock_dblhandler, "dbl", "set/get double flag", (void*)&dflag}, + {sl_sock_strhandler, "str", "set/get string variable", (void*)&sflag}, {show, "show", "show current flags @ server console", NULL}, - {dtimeh, "dtime", "get server's UNIX time", NULL}, + {dtimeh, "dtime", "get server's UNIX time for all clients connected", NULL}, {NULL, NULL, NULL, NULL} }; @@ -128,8 +187,11 @@ int main(int argc, char **argv){ if(G.isserver){ sl_sock_changemaxclients(G.maxclients); sl_sock_maxclhandler(toomuch); + sl_sock_connhandler(connected); + sl_sock_dischandler(disconnected); s = sl_sock_run_server(type, G.node, -1, handlers); } else { + sl_setup_con(); s = sl_sock_run_client(type, G.node, -1); } if(!s) ERRX("Can't create socket and/or run threads"); diff --git a/locale/ru/LC_MESSAGES/usefull_macros.mo b/locale/ru/LC_MESSAGES/usefull_macros.mo index 83e41d1fcd6d017605fa56947e203c3d22213711..556123d410f28ec9bf35fa6934000623dd98573a 100644 GIT binary patch delta 867 zcmXxiPe@cz6vy#1^ZfHl%Xwos&S*I4jN{A{Mp}U(PSPJKh74Dtf*S=zg#IktjkIai zrk4b+3Tfdkn2m}pG=vrr2~&iNphZZ~LP}is{f*OwJD+>synEic=iYD0QljuZT(xAh zEWMTfIAC@SKL+`stvO~XT*ol}K)rW}&FEE`MKFUg9K?E@z*9JjQCz?#e2$H{dOR=K zI|gTXP{Q;0tMWoqwOKp!3@T6_J8=v>e1cl{0+q-rD)2Tc!LOD7|6&Vsx5lgk6R3?0 zVXGAg$UuP>PywEycJvyxqjkKAB}`(h)~pS4s6-|)jt{W`eN;j#sCb*G1U^^%jS;Hs zx@NR02ELgFjL0qjhF!9K;OH;T3#|ckvT; zV~q2;hj*}`h06@`_#Q8zN4<3iZs2WP#0&TVd+`Xh^X%#4MEh}(`6Eo=A$DSvawvWd z&*BU!{!_e)8x7Qdn!z6)+``e2*+qPX1GtOYfydWW`XN*T^QeSYFo(N%9m5=O9?ztJ!z`fl#X06M7T;2OT(3(f|Me delta 998 zcmX}qOK1~87{KvKHho#!Xe*{_)osk9sVxzo5J3(2pcSbk1oYrRX%<0CAZnyONVN(* z8zOiRrPzxK8biP+Mvn>=CanjN>PbXzTJRu<`2TjR1GB%GeSG`PH}fv=KA8X1;VCLw zKfRlN$)(gzoOg4fy*88z;~VV2A1Lp6JW6$85Be~Mt1*E~aTMF|0tRNnDR(C<)y{6Ca=#XHXKGM~V9r zC6Sh9#~}LhlsnGgFb|HlI6uCRG3Il)4cnJE&-Y@Ic@ZVyZzu`;!7aG1)%iYw5#|@M z52tZEYCMQd>`xSvm>*^^!9Z3#hllVtZpI<%E@$B~9>6LNpsSrSViaZNBPfaHa2y|E z00$^T2oosr$8ar9;Sj#^Qh)hT>oTQw;4ZWX6i3271M;mL#;|N~4+Cjb=YIQL*W8u0HZjjaXmrKTXcW*MC&84&E*^}Ay@sXH$;+$nM&2Y~;ojGq> z+03Zv51#Rt?>2sI9=xM#^{cw3pPBV5x>6t4PweaCn5kddqYBpabNxbB=udUU)TR1F V{hITdDWBWn3RQ2U{Kz}){tIfplJ)=q diff --git a/locale/ru/messages.po b/locale/ru/messages.po index d9a2fac..5f7e43e 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: 2024-12-10 17:44+0300\n" +"POT-Creation-Date: 2024-12-16 11:25+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -105,26 +105,38 @@ msgstr "" msgid "Wrong argument \"%s\" of parameter \"%s\"" msgstr "" -#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:133 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:148 msgid "Server disconnected" msgstr "" -#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:208 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:223 msgid "Can't start server handlers thread" msgstr "" -#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:245 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:285 msgid "Limit of connections reached" msgstr "" -#. buffer overflow -#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:319 +#. check for RB overflow +#. -1 - buffer empty (can't be), -2 - buffer overflow +#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:325 #, c-format -msgid "Server thread: buffer overflow from \"%s\"" +msgid "Server thread: ring buffer overflow for fd=%d" +msgstr "" + +#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:339 +#, c-format +msgid "Server thread: can't write data to ringbuffer: overflow from fd=%d" +msgstr "" + +#. buffer overflow +#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:351 +#, c-format +msgid "Server thread: buffer overflow from fd=%d" msgstr "" #. never reached -#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:381 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:416 #, c-format msgid "Unsupported socket type %d" msgstr "" diff --git a/locale/ru/ru.po b/locale/ru/ru.po index 07f3beb..64a3589 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: 2024-12-10 17:44+0300\n" + "POT-Creation-Date: 2024-12-13 09:10+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -85,7 +85,7 @@ msgstr " msgid "Can't setup console" msgstr "Не могу настроить консоль" -#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:208 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:223 msgid "Can't start server handlers thread" msgstr "Не могу запустить поток-обработчик сервера" @@ -117,7 +117,7 @@ msgstr " msgid "Key '%s' need value" msgstr "Ключ '%s' требует значения" -#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:245 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:285 msgid "Limit of connections reached" msgstr "Достигнут предел соединений" @@ -146,22 +146,29 @@ msgstr " msgid "Port name is missing" msgstr "Отсутствует имя порта" -#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:133 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:148 msgid "Server disconnected" msgstr "Сервер отключен" #. buffer overflow -#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:319 -#, c-format -msgid "Server thread: buffer overflow from \"%s\"" -msgstr "Поток сервера: переполнение буфера от \"%s\"" +#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:351 +msgid "Server thread: buffer overflow from fd=%d" +msgstr "Поток сервера: переполнение буфера от fd=%d" + +#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:339 +msgid "Server thread: can't write data to ringbuffer, overflow from fd=%d" +msgstr "Поток сервера: не могу сохранить данные в кольцевом буфере, переполнение от fd=%d" + +#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:325 +msgid "Server thread: ring buffer overflow for fd=%d" +msgstr "Поток сервера: переполнение буфера от fd=%d" #: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:226 msgid "Unsupported option type" msgstr "Неподдерживаемый тип опции" #. never reached -#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:381 +#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:416 #, c-format msgid "Unsupported socket type %d" msgstr "Неподдерживаемый тип сокета %d" @@ -170,8 +177,8 @@ msgstr " #, c-format msgid "Wrong USART format \"%s\"; use NPS, where N: 5..8; P: N/E/O/1/0, S: " "1/2" -msgstr "Неправильный формат USART \"%s\"; нужен NPS, где N: 5..8; P: N/E/" - "O/1/0, S: 1/2" +msgstr "Неправильный формат USART \"%s\"; нужен NPS, где N: 5..8; P: N/E/O/" + "1/0, S: 1/2" #: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:494 #, c-format diff --git a/ringbuffer.c b/ringbuffer.c index 9ba1d2f..fd5379a 100644 --- a/ringbuffer.c +++ b/ringbuffer.c @@ -17,6 +17,7 @@ */ #include +#include #include #include "usefull_macros.h" @@ -67,7 +68,7 @@ size_t sl_RB_datalen(sl_ringbuffer_t *b){ // size of free space in buffer size_t sl_RB_freesize(sl_ringbuffer_t *b){ pthread_mutex_lock(&b->busy); - size_t l = b->length - datalen(b); + size_t l = b->length - datalen(b) - 1; pthread_mutex_unlock(&b->busy); return l; } @@ -76,7 +77,7 @@ size_t sl_RB_freesize(sl_ringbuffer_t *b){ * @brief hasbyte - check if RB have given byte * @param b - rb * @param byte - what to find - * @return index of byte or -1 if not found or no data + * @return index of byte, -2 if not found or -1 if no data in buffer */ static ssize_t hasbyte(sl_ringbuffer_t *b, uint8_t byte){ if(b->head == b->tail) return -1; // no data in buffer @@ -88,7 +89,7 @@ static ssize_t hasbyte(sl_ringbuffer_t *b, uint8_t byte){ } for(size_t found = startidx; found < b->tail; ++found) if(b->data[found] == byte) return found; - return -1; + return -2; } // hasbyte with block @@ -163,14 +164,18 @@ ret: * @param b - rb * @param s - string buffer * @param len - length of `s` - * @return amount of characters read or -1 if buffer too small + * @return amount of characters read or -2 if buffer overflow * !!! this function changes '\n' to 0 in `s`; `len` should include trailing '\0' too */ ssize_t sl_RB_readline(sl_ringbuffer_t *b, char *s, size_t len){ ssize_t got = 0; pthread_mutex_lock(&b->busy); ssize_t idx = hasbyte(b, '\n'); - if(idx < 0) goto ret; + if(idx < 0){ + if(idx == -1) idx = 0; // buffer is empty - return 0; else return error + goto ret; + } + DBG("Got newline -> read"); size_t partlen = idx + 1 - b->head; // now calculate length of new data portion if((size_t)idx < b->head) partlen += b->length; @@ -179,6 +184,7 @@ ssize_t sl_RB_readline(sl_ringbuffer_t *b, char *s, size_t len){ got = rbread(b, (uint8_t*)s, partlen); s[partlen - 1] = 0; // substitute '\n' with trailing zero } + DBG("read: '%s'", s); ret: pthread_mutex_unlock(&b->busy); return got; @@ -213,6 +219,7 @@ ret: size_t sl_RB_write(sl_ringbuffer_t *b, const uint8_t *str, size_t len){ pthread_mutex_lock(&b->busy); size_t r = b->length - 1 - datalen(b); // rest length + DBG("rest: %zd, need: %zd", r, len); if(len > r) len = r; if(!len) goto ret; size_t _1st = b->length - b->tail; @@ -248,6 +255,7 @@ size_t sl_RB_writestr(sl_ringbuffer_t *b, char *s){ size_t len = strlen(s); pthread_mutex_lock(&b->busy); size_t r = b->length - 1 - datalen(b); // rest length + if(s[len-1] != '\n') s[len++] = '\n'; if(len > r){ len = 0; goto ret; } // insufficient space - don't even try to write a part size_t _1st = b->length - b->tail; if(_1st > len) _1st = len; diff --git a/socket.c b/socket.c index 0bdcaa9..4ab3861 100644 --- a/socket.c +++ b/socket.c @@ -32,7 +32,11 @@ // max clients amount static int maxclients = 32; // too much clients handler; it is running for client connected with number>maxclients (before closing its fd) -static sl_sock_maxclh_t toomuchclients = NULL; +static sl_sock_maxclh_t toomuch_handler = NULL; +// new client connected handler; it will be run each new connection +static sl_sock_connh_t newconnect_handler = NULL; +// client disconnected handler +static sl_sock_disch_t disconnect_handler = NULL; /** * @brief sl_sock_changemaxclients - change amount of max simultaneously connected clients @@ -44,9 +48,18 @@ void sl_sock_changemaxclients(int val){ } int sl_sock_getmaxclients(){ return maxclients; } -// setter of "too much clients handler" +// in each next function changed default handlers you can set h to NULL to remove your handler +// setter of "too much clients" handler void sl_sock_maxclhandler(sl_sock_maxclh_t h){ - toomuchclients = h; + toomuch_handler = h; +} +// setter of "new client connected" handler +void sl_sock_connhandler(sl_sock_connh_t h){ + newconnect_handler = h; +} +// setter of "client disconnected" handler +void sl_sock_dischandler(sl_sock_disch_t h){ + disconnect_handler = h; } // text messages for `hresult` @@ -116,8 +129,9 @@ void sl_sock_delete(sl_sock_t **sock){ * @return NULL */ static void *clientrbthread(void *d){ - char buf[512]; sl_sock_t *s = (sl_sock_t*) d; + size_t buflen = s->buffer->length; + char *buf = MALLOC(char, buflen); DBG("Start client read buffer thread"); while(s && s->connected){ pthread_mutex_lock(&s->mutex); @@ -126,8 +140,9 @@ static void *clientrbthread(void *d){ usleep(1000); continue; } - ssize_t n = read(s->fd, buf, 511); - DBG("read %zd from %d, unlock", n, s->fd); + ssize_t n = read(s->fd, buf, buflen); + //DBG("read %zd from fd=%d, unlock", n, s->fd); + //DBG("buf=%s", buf); pthread_mutex_unlock(&s->mutex); if(n < 1){ WARNX(_("Server disconnected")); @@ -233,6 +248,32 @@ static void *serverthread(void _U_ *d){ // ZERO - listening server socket poll_set[0].fd = sockfd; poll_set[0].events = POLLIN; + // disconnect client + void disconnect_(sl_sock_t *c, int N){ + DBG("client \"%s\" (fd=%d) disconnected", c->IP, c->fd); + if(disconnect_handler) disconnect_handler(c); + pthread_mutex_lock(&c->mutex); + DBG("close fd %d", c->fd); + c->connected = 0; + close(c->fd); + sl_RB_clearbuf(c->buffer); + // now move all data of last client to disconnected + if(nfd > 2 && N != nfd - 1){ // don't move the only or the last + DBG("lock fd=%d", clients[nfd-1]->fd); + pthread_mutex_lock(&clients[nfd-1]->mutex); + clients[N] = clients[nfd-1]; + clients[nfd-1] = c; + DBG("unlock fd=%d", clients[N]->fd); + pthread_mutex_unlock(&clients[N]->mutex); // now N is nfd-1 + poll_set[N] = poll_set[nfd - 1]; + } + DBG("unlock fd=%d", c->fd); + pthread_mutex_unlock(&c->mutex); + --nfd; + } + // allocate buffer with size not less than RB size + size_t bufsize = s->buffer->length; // as RB should be 1 byte less, this is OK + uint8_t *buf = MALLOC(uint8_t, bufsize); while(s && s->connected){ poll(poll_set, nfd, 1); if(poll_set[0].revents & POLLIN){ // check main for accept() @@ -240,10 +281,9 @@ static void *serverthread(void _U_ *d){ socklen_t len = sizeof(struct sockaddr); int client = accept(sockfd, &a, &len); DBG("New connection, nfd=%d, len=%d", nfd, len); - LOGMSG("SERVER got connection, fd=%d", client); if(nfd == maxclients + 1){ WARNX(_("Limit of connections reached")); - if(toomuchclients) toomuchclients(client); + if(toomuch_handler) toomuch_handler(client); close(client); }else{ memset(&poll_set[nfd], 0, sizeof(struct pollfd)); @@ -262,6 +302,7 @@ static void *serverthread(void _U_ *d){ *c->IP = 0; } DBG("got IP:%s", c->IP); + if(newconnect_handler) newconnect_handler(c); if(!c->buffer){ // allocate memory for client's ringbuffer DBG("allocate ringbuffer"); c->buffer = sl_RB_new(s->buffer->length); // the same size as for master @@ -269,55 +310,47 @@ static void *serverthread(void _U_ *d){ ++nfd; } } -#define SBUFSZ (SL_KEY_LEN+SL_VAL_LEN+2) - uint8_t buf[SBUFSZ]; // scan connections for(int fdidx = 1; fdidx < nfd; ++fdidx){ if((poll_set[fdidx].revents & POLLIN) == 0) continue; int fd = poll_set[fdidx].fd; sl_sock_t *c = clients[fdidx]; pthread_mutex_lock(&c->mutex); - int nread = sl_RB_freesize(c->buffer); - if(nread > SBUFSZ) nread = SBUFSZ; - else if(nread < 1){ + size_t nread = sl_RB_freesize(c->buffer); + if(nread > bufsize) nread = bufsize; + else if(nread < 1){ // no space in ringbuffer pthread_mutex_unlock(&c->mutex); + // check for RB overflow + if(sl_RB_hasbyte(c->buffer, '\n') < 0){ // -1 - buffer empty (can't be), -2 - buffer overflow + WARNX(_("Server thread: ring buffer overflow for fd=%d"), fd); + disconnect_(c, fdidx); + --fdidx; + } continue; } ssize_t got = read(fd, buf, nread); + DBG("can read %zd bytes, got %zd bytes, buf=_%s_", nread, got, buf); pthread_mutex_unlock(&c->mutex); if(got <= 0){ // client disconnected - DBG("client \"%s\" (fd=%d) disconnected", c->IP, fd); - pthread_mutex_lock(&c->mutex); - DBG("close fd %d", fd); - c->connected = 0; - close(fd); - sl_RB_clearbuf(c->buffer); - // now move all data of last client to disconnected - if(nfd > 2 && fdidx != nfd - 1){ // don't move the only or the last - DBG("lock fd=%d", clients[nfd-1]->fd); - pthread_mutex_lock(&clients[nfd-1]->mutex); - clients[fdidx] = clients[nfd-1]; - clients[nfd-1] = c; - DBG("unlock fd=%d", clients[fdidx]->fd); - pthread_mutex_unlock(&clients[fdidx]->mutex); // now fdidx is nfd-1 - poll_set[fdidx] = poll_set[nfd - 1]; - } - DBG("unlock fd=%d", c->fd); - pthread_mutex_unlock(&c->mutex); - --nfd; + disconnect_(c, fdidx); --fdidx; }else{ - sl_RB_write(c->buffer, buf, got); + if(sl_RB_write(c->buffer, buf, got) < (size_t) got){ + WARNX(_("Server thread: can't write data to ringbuffer: overflow from fd=%d"), fd); + disconnect_(c, fdidx); + --fdidx; + } } } // and now check all incoming buffers for(int fdidx = 1; fdidx < nfd; ++fdidx){ sl_sock_t *c = clients[fdidx]; if(!c->connected) continue; - ssize_t got = sl_RB_readline(c->buffer, (char*)buf, SBUFSZ); + ssize_t got = sl_RB_readline(c->buffer, (char*)buf, bufsize); if(got < 0){ // buffer overflow - ERRX(_("Server thread: buffer overflow from \"%s\""), c->IP); - sl_RB_clearbuf(c->buffer); + WARNX(_("Server thread: buffer overflow from fd=%d"), c->fd); + disconnect_(c, fdidx); + --fdidx; continue; }else if(got == 0) continue; sl_sock_hresult_e r = msgparser(c, (char*)buf); @@ -325,6 +358,7 @@ static void *serverthread(void _U_ *d){ } } // clear memory + FREE(buf); FREE(poll_set); for(int i = maxclients; i > 0; --i){ DBG("Clear %dth client data", i); @@ -360,6 +394,7 @@ static sl_sock_t *sl_sock_open(sl_socktype_e type, const char *path, sl_sock_hit struct addrinfo ai = {0}, *res = &ai; struct sockaddr_un unaddr = {0}; char *str = NULL; + ai.ai_socktype = SOCK_STREAM; switch(type){ case SOCKT_UNIX: str = convunsname(path); @@ -369,7 +404,7 @@ static sl_sock_t *sl_sock_open(sl_socktype_e type, const char *path, sl_sock_hit ai.ai_addrlen = sizeof(unaddr); memcpy(unaddr.sun_path, str, 106); ai.ai_family = AF_UNIX; - ai.ai_socktype = SOCK_SEQPACKET; + //ai.ai_socktype = SOCK_SEQPACKET; break; case SOCKT_NET: case SOCKT_NETLOCAL: @@ -514,10 +549,18 @@ ssize_t sl_sock_sendbinmessage(sl_sock_t *socket, const uint8_t *msg, size_t l){ DBG("lock"); pthread_mutex_lock(&socket->mutex); DBG("SEND"); - ssize_t r = send(socket->fd, msg, l, MSG_NOSIGNAL); + ssize_t sent = 0; + do{ + ssize_t r = send(socket->fd, msg+sent, l, MSG_NOSIGNAL); + if(r < 0){ + sent = -1; + break; + }else sent += r; + DBG("sent %zd bytes", r); + } while((size_t)sent != l); DBG("unlock"); pthread_mutex_unlock(&socket->mutex); - return r; + return sent; } ssize_t sl_sock_sendstrmessage(sl_sock_t *socket, const char *msg){ @@ -589,7 +632,7 @@ sl_sock_hresult_e sl_sock_strhandler(sl_sock_t *client, sl_sock_hitem_t *hitem, char buf[SL_VAL_LEN + SL_KEY_LEN + 3]; sl_sock_string_t *s = (sl_sock_string_t*) hitem->data; if(!str){ // getter - sprintf(buf, "%s=%s\n", hitem->key, s->val); + snprintf(buf, SL_VAL_LEN + SL_KEY_LEN + 2, "%s=%s\n", hitem->key, s->val); sl_sock_sendstrmessage(client, buf); return RESULT_SILENCE; } @@ -598,5 +641,6 @@ sl_sock_hresult_e sl_sock_strhandler(sl_sock_t *client, sl_sock_hitem_t *hitem, s->len = l; s->timestamp = sl_dtime(); memcpy(s->val, str, l); + s->val[l] = 0; return RESULT_OK; } diff --git a/usefull_macros.h b/usefull_macros.h index 3014ca1..15d89e4 100644 --- a/usefull_macros.h +++ b/usefull_macros.h @@ -478,23 +478,21 @@ typedef struct sl_sock{ sl_sock_hitem_t *handlers; // if non-NULL, run handler's thread when opened } sl_sock_t; -#if 0 -// connected client descriptor -typedef struct sl_sock_client{ - sl_sock_t *socket; // socket file descriptor - const char *IP; // IP address formatted string - void *res; // user data -} sl_sock_client_t; -#endif - const char *sl_sock_hresult2str(sl_sock_hresult_e r); void sl_sock_delete(sl_sock_t **sock); sl_sock_t *sl_sock_run_client(sl_socktype_e type, const char *path, int bufsiz); sl_sock_t *sl_sock_run_server(sl_socktype_e type, const char *path, int bufsiz, sl_sock_hitem_t *handlers); void sl_sock_changemaxclients(int val); int sl_sock_getmaxclients(); +// max clients handler typedef void (*sl_sock_maxclh_t)(int fd); void sl_sock_maxclhandler(sl_sock_maxclh_t h); +// new client connected handler +typedef void (*sl_sock_connh_t)(sl_sock_t *s); +void sl_sock_connhandler(sl_sock_connh_t h); +// client disconnected handler +typedef void (*sl_sock_disch_t)(sl_sock_t *s); +void sl_sock_dischandler(sl_sock_disch_t h); ssize_t sl_sock_sendbinmessage(sl_sock_t *socket, const uint8_t *msg, size_t l); ssize_t sl_sock_sendbyte(sl_sock_t *socket, uint8_t byte);