mirror of
https://github.com/eddyem/snippets_library.git
synced 2025-12-06 10:45:10 +03:00
Version 0.3.1: add sockets
This commit is contained in:
parent
54e88cfd92
commit
19c14db40b
@ -1,7 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.9)
|
cmake_minimum_required(VERSION 3.9)
|
||||||
set(PROJ usefull_macros)
|
set(PROJ usefull_macros)
|
||||||
set(MINOR_VERSION "1")
|
set(MINOR_VERSION "1")
|
||||||
set(MID_VERSION "2")
|
set(MID_VERSION "3")
|
||||||
set(MAJOR_VERSION "0")
|
set(MAJOR_VERSION "0")
|
||||||
set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}")
|
set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}")
|
||||||
|
|
||||||
|
|||||||
13
config.c
13
config.c
@ -34,7 +34,7 @@
|
|||||||
* also if `key` have several words only first saved, `value` can be long string with or without quotations
|
* also if `key` have several words only first saved, `value` can be long string with or without quotations
|
||||||
*/
|
*/
|
||||||
int sl_get_keyval(const char *pair, char key[SL_KEY_LEN], char value[SL_VAL_LEN]){
|
int sl_get_keyval(const char *pair, char key[SL_KEY_LEN], char value[SL_VAL_LEN]){
|
||||||
DBG("got pair: '%s'", pair);
|
//DBG("got pair: '%s'", pair);
|
||||||
if(!pair || !*pair) return 0; // empty line
|
if(!pair || !*pair) return 0; // empty line
|
||||||
char *kstart = sl_omitspaces(pair);
|
char *kstart = sl_omitspaces(pair);
|
||||||
if(!*kstart || *kstart == SL_COMMENT_CHAR) return 0; // only spaces
|
if(!*kstart || *kstart == SL_COMMENT_CHAR) return 0; // only spaces
|
||||||
@ -44,13 +44,13 @@ int sl_get_keyval(const char *pair, char key[SL_KEY_LEN], char value[SL_VAL_LEN]
|
|||||||
char *cmnt = strchr(kstart, SL_COMMENT_CHAR);
|
char *cmnt = strchr(kstart, SL_COMMENT_CHAR);
|
||||||
if(eq && cmnt && cmnt < eq) eq = NULL; // comment starting before equal sign
|
if(eq && cmnt && cmnt < eq) eq = NULL; // comment starting before equal sign
|
||||||
if(eq){ do{
|
if(eq){ do{
|
||||||
DBG("got equal symbol: '%s'", eq);
|
//DBG("got equal symbol: '%s'", eq);
|
||||||
char *vstart = sl_omitspaces(eq + 1);
|
char *vstart = sl_omitspaces(eq + 1);
|
||||||
if(!*vstart) break; // empty line or only spaces after `=`
|
if(!*vstart) break; // empty line or only spaces after `=`
|
||||||
char *vend = sl_omitspacesr(vstart);
|
char *vend = sl_omitspacesr(vstart);
|
||||||
size_t l = SL_VAL_LEN - 1; // truncate value to given length
|
size_t l = SL_VAL_LEN - 1; // truncate value to given length
|
||||||
if(l > (size_t)(vend - vstart)) l = vend - vstart;
|
if(l > (size_t)(vend - vstart)) l = vend - vstart;
|
||||||
DBG("l=%zd", l);
|
//DBG("l=%zd", l);
|
||||||
strncpy(value, vstart, l);
|
strncpy(value, vstart, l);
|
||||||
value[l] = 0;
|
value[l] = 0;
|
||||||
cmnt = strchr(value, SL_COMMENT_CHAR);
|
cmnt = strchr(value, SL_COMMENT_CHAR);
|
||||||
@ -59,18 +59,19 @@ int sl_get_keyval(const char *pair, char key[SL_KEY_LEN], char value[SL_VAL_LEN]
|
|||||||
*sl_omitspacesr(value) = 0;
|
*sl_omitspacesr(value) = 0;
|
||||||
}
|
}
|
||||||
if(!*value) break;
|
if(!*value) break;
|
||||||
DBG("Got value: '%s'", value);
|
//DBG("Got value: '%s'", value);
|
||||||
ret = 2;
|
ret = 2;
|
||||||
}while(0);
|
}while(0);
|
||||||
}else eq = kstart + strlen(kstart) - 1;
|
}else eq = kstart + strlen(kstart);
|
||||||
for(; kend < eq && !isspace(*kend); ++kend);
|
for(; kend < eq && !isspace(*kend); ++kend);
|
||||||
size_t l = SL_KEY_LEN - 1;
|
size_t l = SL_KEY_LEN - 1;
|
||||||
if(l > (size_t)(kend - kstart)) l = kend - kstart;
|
if(l > (size_t)(kend - kstart)) l = kend - kstart;
|
||||||
|
//DBG("kend=%c, kstart=%c, l=%zd", *kend, *kstart, l);
|
||||||
strncpy(key, kstart, l);
|
strncpy(key, kstart, l);
|
||||||
key[l] = 0;
|
key[l] = 0;
|
||||||
cmnt = strchr(key, SL_COMMENT_CHAR);
|
cmnt = strchr(key, SL_COMMENT_CHAR);
|
||||||
if(cmnt) *cmnt = 0;
|
if(cmnt) *cmnt = 0;
|
||||||
DBG("Got key: '%s'", key);
|
//DBG("Got key: '%s'", key);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,31 +16,149 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <usefull_macros.h>
|
#include <usefull_macros.h>
|
||||||
|
|
||||||
|
static sl_sock_t *s = NULL;
|
||||||
|
|
||||||
typedef struct{
|
typedef struct{
|
||||||
int help;
|
int help;
|
||||||
int verbose;
|
int verbose;
|
||||||
|
int isserver;
|
||||||
|
int isunix;
|
||||||
|
int maxclients;
|
||||||
char *logfile;
|
char *logfile;
|
||||||
|
char *node;
|
||||||
} parameters;
|
} parameters;
|
||||||
|
|
||||||
static parameters G = {0};
|
static parameters G = {
|
||||||
|
.maxclients = 2,
|
||||||
|
};
|
||||||
|
|
||||||
static sl_option_t cmdlnopts[] = {
|
static sl_option_t cmdlnopts[] = {
|
||||||
{"help", NO_ARGS, NULL, 'h', arg_int, APTR(&G.help), "show this help"},
|
{"help", NO_ARGS, NULL, 'h', arg_int, APTR(&G.help), "show this help"},
|
||||||
{"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&G.verbose), "verbose level (each -v adds 1)"},
|
{"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&G.verbose), "verbose level (each -v adds 1)"},
|
||||||
{"logfile", NEED_ARG, NULL, 'l', arg_string, APTR(&G.logfile), "log file name"},
|
{"logfile", NEED_ARG, NULL, 'l', arg_string, APTR(&G.logfile), "log file name"},
|
||||||
|
{"node", NEED_ARG, NULL, 'n', arg_string, APTR(&G.node), "node \"IP\", \"name:IP\" or path (could be \"\\0path\" for anonymous UNIX-socket)"},
|
||||||
|
{"server", NO_ARGS, NULL, 's', arg_int, APTR(&G.isserver), "create server"},
|
||||||
|
{"unixsock", NO_ARGS, NULL, 'u', arg_int, APTR(&G.isunix), "UNIX socket instead of INET"},
|
||||||
|
{"maxclients", NEED_ARG, NULL, 'm', arg_int, APTR(&G.maxclients),"max amount of clients connected to server (default: 2)"},
|
||||||
end_option
|
end_option
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void signals(int sig){
|
||||||
|
if(sig){
|
||||||
|
signal(sig, SIG_IGN);
|
||||||
|
DBG("Get signal %d, quit.\n", sig);
|
||||||
|
}
|
||||||
|
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];
|
||||||
|
if(!s) return;
|
||||||
|
do{
|
||||||
|
printf("send > ");
|
||||||
|
char *r = fgets(buf, 300, stdin);
|
||||||
|
if(r){
|
||||||
|
DBG("try");
|
||||||
|
if(-1 == sl_sock_sendstrmessage(s, buf)){
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
// flags for standard handlers
|
||||||
|
static sl_sock_int_t iflag = {0};
|
||||||
|
static sl_sock_double_t dflag = {0};
|
||||||
|
|
||||||
|
static sl_sock_hresult_e dtimeh(sl_sock_t *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);
|
||||||
|
return RESULT_SILENCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static sl_sock_hresult_e show(sl_sock_t *client, _U_ sl_sock_hitem_t *item, _U_ const char *req){
|
||||||
|
if(!G.isunix){
|
||||||
|
if(*client->IP){
|
||||||
|
printf("Client \"%s\" (fd=%d) ask for flags:\n", client->IP, client->fd);
|
||||||
|
}else printf("Can't get client's IP, flags:\n");
|
||||||
|
}else printf("Socket fd=%d asks for flags:\n", client->fd);
|
||||||
|
printf("\tiflag=%" PRId64 ", dflag=%g\n", iflag.val, dflag.val);
|
||||||
|
return RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void toomuch(int fd){
|
||||||
|
const char *m = "Try later: too much clients connected\n";
|
||||||
|
send(fd, m, sizeof(m+1), MSG_NOSIGNAL);
|
||||||
|
LOGWARN("Client fd=%d tried to connect after MAX reached", fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
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},
|
||||||
|
{show, "show", "show current flags @ server console", NULL},
|
||||||
|
{dtimeh, "dtime", "get server's UNIX time", NULL},
|
||||||
|
{NULL, NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
int main(int argc, char **argv){
|
int main(int argc, char **argv){
|
||||||
sl_init();
|
sl_init();
|
||||||
sl_parseargs(&argc, &argv, cmdlnopts);
|
sl_parseargs(&argc, &argv, cmdlnopts);
|
||||||
if(G.help) sl_showhelp(-1, cmdlnopts);
|
if(G.help) sl_showhelp(-1, cmdlnopts);
|
||||||
|
if(!G.node) ERRX("Point node");
|
||||||
|
sl_socktype_e type = (G.isunix) ? SOCKT_UNIX : SOCKT_NET;
|
||||||
|
if(G.isserver){
|
||||||
|
sl_sock_changemaxclients(G.maxclients);
|
||||||
|
sl_sock_maxclhandler(toomuch);
|
||||||
|
s = sl_sock_run_server(type, G.node, -1, handlers);
|
||||||
|
} else {
|
||||||
|
s = sl_sock_run_client(type, G.node, -1);
|
||||||
|
}
|
||||||
|
if(!s) ERRX("Can't create socket and/or run threads");
|
||||||
sl_loglevel_e lvl = G.verbose + LOGLEVEL_ERR;
|
sl_loglevel_e lvl = G.verbose + LOGLEVEL_ERR;
|
||||||
if(lvl >= LOGLEVEL_AMOUNT) lvl = LOGLEVEL_AMOUNT - 1;
|
if(lvl >= LOGLEVEL_AMOUNT) lvl = LOGLEVEL_AMOUNT - 1;
|
||||||
if(G.logfile) OPENLOG(G.logfile, lvl, 1);
|
if(G.logfile) OPENLOG(G.logfile, lvl, 1);
|
||||||
LOGMSG("hello");
|
LOGMSG("Started");
|
||||||
LOGERRADD("additional to err");
|
signal(SIGTERM, signals);
|
||||||
|
signal(SIGINT, signals);
|
||||||
|
signal(SIGQUIT, signals);
|
||||||
|
signal(SIGTSTP, SIG_IGN);
|
||||||
|
signal(SIGHUP, signals);
|
||||||
|
if(G.isserver){
|
||||||
|
//double t0 = sl_dtime();
|
||||||
|
while(s && s->connected){
|
||||||
|
if(!s->rthread){
|
||||||
|
WARNX("Server handlers thread is dead");
|
||||||
|
LOGERR("Server handlers thread is dead");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*double tn = sl_dtime();
|
||||||
|
if(tn - t0 > 10.){
|
||||||
|
sl_sock_sendall((uint8_t*)"PING\n", 5);
|
||||||
|
t0 = tn;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}else runclient(s);
|
||||||
|
LOGMSG("Ended");
|
||||||
|
DBG("Close");
|
||||||
|
sl_sock_delete(&s);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,7 @@ int main(int argc, char **argv){
|
|||||||
sl_init();
|
sl_init();
|
||||||
sl_parseargs(&argc, &argv, cmdlnopts);
|
sl_parseargs(&argc, &argv, cmdlnopts);
|
||||||
if(G.help) sl_showhelp(-1, cmdlnopts);
|
if(G.help) sl_showhelp(-1, cmdlnopts);
|
||||||
sl_ringbuffer *b = sl_RB_new(G.size);
|
sl_ringbuffer_t *b = sl_RB_new(G.size);
|
||||||
if(!b) return 1;
|
if(!b) return 1;
|
||||||
printf("Created ring buffer of %d bytes\n", G.size);
|
printf("Created ring buffer of %d bytes\n", G.size);
|
||||||
printf("Enter lines of text to fill it or type (get) to get one line from buffer\n");
|
printf("Enter lines of text to fill it or type (get) to get one line from buffer\n");
|
||||||
|
|||||||
Binary file not shown.
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-11-15 11:38+0300\n"
|
"POT-Creation-Date: 2024-12-10 17:44+0300\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@ -17,31 +17,31 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=koi8-r\n"
|
"Content-Type: text/plain; charset=koi8-r\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:225
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:226
|
||||||
msgid "Unsupported option type"
|
msgid "Unsupported option type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:228
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:229
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Wrong number format '%s'"
|
msgid "Wrong number format '%s'"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:272
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:273
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Can't open %s"
|
msgid "Can't open %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:283
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:284
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Wrong key: '%s'"
|
msgid "Wrong key: '%s'"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:289
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:290
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Key '%s' need value"
|
msgid "Key '%s' need value"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:295
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:296
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Key '%s' have no argptr!"
|
msgid "Key '%s' have no argptr!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -105,6 +105,30 @@ msgstr ""
|
|||||||
msgid "Wrong argument \"%s\" of parameter \"%s\""
|
msgid "Wrong argument \"%s\" of parameter \"%s\""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:133
|
||||||
|
msgid "Server disconnected"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:208
|
||||||
|
msgid "Can't start server handlers thread"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:245
|
||||||
|
msgid "Limit of connections reached"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. buffer overflow
|
||||||
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:319
|
||||||
|
#, c-format
|
||||||
|
msgid "Server thread: buffer overflow from \"%s\""
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. never reached
|
||||||
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:381
|
||||||
|
#, c-format
|
||||||
|
msgid "Unsupported socket type %d"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:87
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:87
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Wrong USART format \"%s\"; use NPS, where N: 5..8; P: N/E/O/1/0, S: 1/2"
|
msgid "Wrong USART format \"%s\"; use NPS, where N: 5..8; P: N/E/O/1/0, S: 1/2"
|
||||||
@ -185,6 +209,11 @@ msgid "Wrong double number format '%s'"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:416
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:416
|
||||||
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:428
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Wrong integer number format '%s'"
|
msgid "Wrong integer number format '%s'"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:432
|
||||||
|
msgid "Number out of integer limits"
|
||||||
|
msgstr ""
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
msgid ""
|
msgid ""
|
||||||
msgstr "Project-Id-Version: PACKAGE VERSION\n"
|
msgstr "Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-11-15 11:38+0300\n"
|
"POT-Creation-Date: 2024-12-10 17:44+0300\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@ -49,7 +49,7 @@ msgstr "
|
|||||||
msgid "Can't munmap"
|
msgid "Can't munmap"
|
||||||
msgstr "îÅ ÍÏÇÕ munmap"
|
msgstr "îÅ ÍÏÇÕ munmap"
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:272
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:273
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Can't open %s"
|
msgid "Can't open %s"
|
||||||
msgstr "îÅ ÍÏÇÕ ÏÔËÒÙÔØ %s"
|
msgstr "îÅ ÍÏÇÕ ÏÔËÒÙÔØ %s"
|
||||||
@ -85,6 +85,10 @@ msgstr "
|
|||||||
msgid "Can't setup console"
|
msgid "Can't setup console"
|
||||||
msgstr "îÅ ÍÏÇÕ ÎÁÓÔÒÏÉÔØ ËÏÎÓÏÌØ"
|
msgstr "îÅ ÍÏÇÕ ÎÁÓÔÒÏÉÔØ ËÏÎÓÏÌØ"
|
||||||
|
|
||||||
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:208
|
||||||
|
msgid "Can't start server handlers thread"
|
||||||
|
msgstr "îÅ ÍÏÇÕ ÚÁÐÕÓÔÉÔØ ÐÏÔÏË-ÏÂÒÁÂÏÔÞÉË ÓÅÒ×ÅÒÁ"
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:256
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:256
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Can't stat %s"
|
msgid "Can't stat %s"
|
||||||
@ -103,16 +107,20 @@ msgstr "
|
|||||||
msgid "Integer out of range"
|
msgid "Integer out of range"
|
||||||
msgstr "ãÅÌÏÅ ×ÎÅ ÄÏÐÕÓÔÉÍÏÇÏ ÄÉÁÐÁÚÏÎÁ"
|
msgstr "ãÅÌÏÅ ×ÎÅ ÄÏÐÕÓÔÉÍÏÇÏ ÄÉÁÐÁÚÏÎÁ"
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:295
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:296
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Key '%s' have no argptr!"
|
msgid "Key '%s' have no argptr!"
|
||||||
msgstr "õ ËÌÀÞÁ '%s' ÎÅÔ ÕËÁÚÁÔÅÌÑ ÎÁ ÐÅÒÅÍÅÎÎÕÀ!"
|
msgstr "õ ËÌÀÞÁ '%s' ÎÅÔ ÕËÁÚÁÔÅÌÑ ÎÁ ÐÅÒÅÍÅÎÎÕÀ!"
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:289
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:290
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Key '%s' need value"
|
msgid "Key '%s' need value"
|
||||||
msgstr "ëÌÀÞ '%s' ÔÒÅÂÕÅÔ ÚÎÁÞÅÎÉÑ"
|
msgstr "ëÌÀÞ '%s' ÔÒÅÂÕÅÔ ÚÎÁÞÅÎÉÑ"
|
||||||
|
|
||||||
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:245
|
||||||
|
msgid "Limit of connections reached"
|
||||||
|
msgstr "äÏÓÔÉÇÎÕÔ ÐÒÅÄÅÌ ÓÏÅÄÉÎÅÎÉÊ"
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:262
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:262
|
||||||
msgid "Mmap error for input"
|
msgid "Mmap error for input"
|
||||||
msgstr "ïÛÉÂËÁ mmap"
|
msgstr "ïÛÉÂËÁ mmap"
|
||||||
@ -130,14 +138,34 @@ msgstr "
|
|||||||
msgid "No filename given!"
|
msgid "No filename given!"
|
||||||
msgstr "îÅ ÚÁÄÁÎÏ ÉÍÑ ÆÁÊÌÁ!"
|
msgstr "îÅ ÚÁÄÁÎÏ ÉÍÑ ÆÁÊÌÁ!"
|
||||||
|
|
||||||
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:432
|
||||||
|
msgid "Number out of integer limits"
|
||||||
|
msgstr "þÉÓÌÏ ÚÁ ÐÒÅÄÅÌÁÍÉ int"
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:162
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:162
|
||||||
msgid "Port name is missing"
|
msgid "Port name is missing"
|
||||||
msgstr "ïÔÓÕÔÓÔ×ÕÅÔ ÉÍÑ ÐÏÒÔÁ"
|
msgstr "ïÔÓÕÔÓÔ×ÕÅÔ ÉÍÑ ÐÏÒÔÁ"
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:225
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:133
|
||||||
|
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/config.c:226
|
||||||
msgid "Unsupported option type"
|
msgid "Unsupported option type"
|
||||||
msgstr "îÅÐÏÄÄÅÒÖÉ×ÁÅÍÙÊ ÔÉÐ ÏÐÃÉÉ"
|
msgstr "îÅÐÏÄÄÅÒÖÉ×ÁÅÍÙÊ ÔÉÐ ÏÐÃÉÉ"
|
||||||
|
|
||||||
|
#. never reached
|
||||||
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:381
|
||||||
|
#, c-format
|
||||||
|
msgid "Unsupported socket type %d"
|
||||||
|
msgstr "îÅÐÏÄÄÅÒÖÉ×ÁÅÍÙÊ ÔÉÐ ÓÏËÅÔÁ %d"
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:87
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:87
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Wrong USART format \"%s\"; use NPS, where N: 5..8; P: N/E/O/1/0, S: "
|
msgid "Wrong USART format \"%s\"; use NPS, where N: 5..8; P: N/E/O/1/0, S: "
|
||||||
@ -161,16 +189,17 @@ msgid "Wrong helpstring!"
|
|||||||
msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ÆÏÒÍÁÔ ÓÔÒÏËÉ ÐÏÍÏÝÉ"
|
msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ÆÏÒÍÁÔ ÓÔÒÏËÉ ÐÏÍÏÝÉ"
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:416
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:416
|
||||||
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:428
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Wrong integer number format '%s'"
|
msgid "Wrong integer number format '%s'"
|
||||||
msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ÆÏÒÍÁÔ ÃÅÌÏÇÏ: %s"
|
msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ÆÏÒÍÁÔ ÃÅÌÏÇÏ: %s"
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:283
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:284
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Wrong key: '%s'"
|
msgid "Wrong key: '%s'"
|
||||||
msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ËÌÀÞ: %s"
|
msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ËÌÀÞ: %s"
|
||||||
|
|
||||||
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:228
|
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:229
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Wrong number format '%s'"
|
msgid "Wrong number format '%s'"
|
||||||
msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ÆÏÒÍÁÔ ÞÉÓÌÁ: %s"
|
msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ÆÏÒÍÁÔ ÞÉÓÌÁ: %s"
|
||||||
@ -189,4 +218,3 @@ msgstr "
|
|||||||
#, c-format
|
#, c-format
|
||||||
msgid "double short arguments: -%c"
|
msgid "double short arguments: -%c"
|
||||||
msgstr "ÄÕÂÌÉÒÕÀÝÉÊÓÑ ËÏÒÏÔËÉÊ ÐÁÒÁÍÅÔÒ: -%c"
|
msgstr "ÄÕÂÌÉÒÕÀÝÉÊÓÑ ËÏÒÏÔËÉÊ ÐÁÒÁÍÅÔÒ: -%c"
|
||||||
|
|
||||||
|
|||||||
48
ringbuffer.c
48
ringbuffer.c
@ -25,8 +25,8 @@
|
|||||||
* @param size - RB size
|
* @param size - RB size
|
||||||
* @return RB
|
* @return RB
|
||||||
*/
|
*/
|
||||||
sl_ringbuffer *sl_RB_new(size_t size){
|
sl_ringbuffer_t *sl_RB_new(size_t size){
|
||||||
sl_ringbuffer *b = MALLOC(sl_ringbuffer, 1);
|
sl_ringbuffer_t *b = MALLOC(sl_ringbuffer_t, 1);
|
||||||
b->data = MALLOC(uint8_t, size);
|
b->data = MALLOC(uint8_t, size);
|
||||||
pthread_mutex_init(&b->busy, NULL);
|
pthread_mutex_init(&b->busy, NULL);
|
||||||
b->head = b->tail = 0;
|
b->head = b->tail = 0;
|
||||||
@ -38,13 +38,11 @@ sl_ringbuffer *sl_RB_new(size_t size){
|
|||||||
* @brief sl_RB_delete - free ringbuffer
|
* @brief sl_RB_delete - free ringbuffer
|
||||||
* @param b - buffer to free
|
* @param b - buffer to free
|
||||||
*/
|
*/
|
||||||
void sl_RB_delete(sl_ringbuffer **b){
|
void sl_RB_delete(sl_ringbuffer_t **b){
|
||||||
if(!b || !*b) return;
|
if(!b || !*b) return;
|
||||||
sl_ringbuffer *bptr = *b;
|
sl_ringbuffer_t *bptr = *b;
|
||||||
pthread_mutex_lock(&bptr->busy);
|
|
||||||
FREE(bptr->data);
|
FREE(bptr->data);
|
||||||
*b = 0;
|
*b = 0;
|
||||||
pthread_mutex_unlock(&bptr->busy);
|
|
||||||
FREE(bptr);
|
FREE(bptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,26 +51,34 @@ void sl_RB_delete(sl_ringbuffer **b){
|
|||||||
* @param b - buffer
|
* @param b - buffer
|
||||||
* @return N
|
* @return N
|
||||||
*/
|
*/
|
||||||
static size_t datalen(sl_ringbuffer *b){
|
static size_t datalen(sl_ringbuffer_t *b){
|
||||||
if(b->tail >= b->head) return (b->tail - b->head);
|
if(b->tail >= b->head) return (b->tail - b->head);
|
||||||
else return (b->length - b->head + b->tail);
|
else return (b->length - b->head + b->tail);
|
||||||
}
|
}
|
||||||
|
|
||||||
// datalen but with blocking of RB
|
// datalen but with blocking of RB
|
||||||
size_t sl_RB_datalen(sl_ringbuffer *b){
|
size_t sl_RB_datalen(sl_ringbuffer_t *b){
|
||||||
pthread_mutex_lock(&b->busy);
|
pthread_mutex_lock(&b->busy);
|
||||||
size_t l = datalen(b);
|
size_t l = datalen(b);
|
||||||
pthread_mutex_unlock(&b->busy);
|
pthread_mutex_unlock(&b->busy);
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
pthread_mutex_unlock(&b->busy);
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief hasbyte - check if RB have given byte
|
* @brief hasbyte - check if RB have given byte
|
||||||
* @param b - rb
|
* @param b - rb
|
||||||
* @param byte - what to find
|
* @param byte - what to find
|
||||||
* @return index of byte or -1 if not found or no data
|
* @return index of byte or -1 if not found or no data
|
||||||
*/
|
*/
|
||||||
static ssize_t hasbyte(sl_ringbuffer *b, uint8_t byte){
|
static ssize_t hasbyte(sl_ringbuffer_t *b, uint8_t byte){
|
||||||
if(b->head == b->tail) return -1; // no data in buffer
|
if(b->head == b->tail) return -1; // no data in buffer
|
||||||
size_t startidx = b->head;
|
size_t startidx = b->head;
|
||||||
if(b->head > b->tail){
|
if(b->head > b->tail){
|
||||||
@ -86,19 +92,19 @@ static ssize_t hasbyte(sl_ringbuffer *b, uint8_t byte){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// hasbyte with block
|
// hasbyte with block
|
||||||
ssize_t sl_RB_hasbyte(sl_ringbuffer *b, uint8_t byte){
|
ssize_t sl_RB_hasbyte(sl_ringbuffer_t *b, uint8_t byte){
|
||||||
pthread_mutex_lock(&b->busy);
|
pthread_mutex_lock(&b->busy);
|
||||||
size_t idx = hasbyte(b, byte);
|
size_t idx = hasbyte(b, byte);
|
||||||
pthread_mutex_unlock(&b->busy);
|
pthread_mutex_unlock(&b->busy);
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
// increment head or tail
|
// increment head or tail
|
||||||
inline void incr(sl_ringbuffer *b, volatile size_t *what, size_t n){
|
inline void incr(sl_ringbuffer_t *b, volatile size_t *what, size_t n){
|
||||||
*what += n;
|
*what += n;
|
||||||
if(*what >= b->length) *what -= b->length;
|
if(*what >= b->length) *what -= b->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t rbread(sl_ringbuffer *b, uint8_t *s, size_t len){
|
static size_t rbread(sl_ringbuffer_t *b, uint8_t *s, size_t len){
|
||||||
size_t l = datalen(b);
|
size_t l = datalen(b);
|
||||||
if(!l) return 0;
|
if(!l) return 0;
|
||||||
if(l > len) l = len;
|
if(l > len) l = len;
|
||||||
@ -122,7 +128,7 @@ static size_t rbread(sl_ringbuffer *b, uint8_t *s, size_t len){
|
|||||||
* @param len - length of `s`
|
* @param len - length of `s`
|
||||||
* @return amount of bytes read
|
* @return amount of bytes read
|
||||||
*/
|
*/
|
||||||
size_t sl_RB_read(sl_ringbuffer *b, uint8_t *s, size_t len){
|
size_t sl_RB_read(sl_ringbuffer_t *b, uint8_t *s, size_t len){
|
||||||
pthread_mutex_lock(&b->busy);
|
pthread_mutex_lock(&b->busy);
|
||||||
size_t got = rbread(b, s, len);
|
size_t got = rbread(b, s, len);
|
||||||
pthread_mutex_unlock(&b->busy);
|
pthread_mutex_unlock(&b->busy);
|
||||||
@ -137,7 +143,7 @@ size_t sl_RB_read(sl_ringbuffer *b, uint8_t *s, size_t len){
|
|||||||
* @param len - length of `s`
|
* @param len - length of `s`
|
||||||
* @return amount of bytes read or -1 if `s` have insufficient size
|
* @return amount of bytes read or -1 if `s` have insufficient size
|
||||||
*/
|
*/
|
||||||
ssize_t sl_RB_readto(sl_ringbuffer *b, uint8_t byte, uint8_t *s, size_t len){
|
ssize_t sl_RB_readto(sl_ringbuffer_t *b, uint8_t byte, uint8_t *s, size_t len){
|
||||||
ssize_t got = 0;
|
ssize_t got = 0;
|
||||||
pthread_mutex_lock(&b->busy);
|
pthread_mutex_lock(&b->busy);
|
||||||
ssize_t idx = hasbyte(b, byte);
|
ssize_t idx = hasbyte(b, byte);
|
||||||
@ -160,7 +166,7 @@ ret:
|
|||||||
* @return amount of characters read or -1 if buffer too small
|
* @return amount of characters read or -1 if buffer too small
|
||||||
* !!! this function changes '\n' to 0 in `s`; `len` should include trailing '\0' too
|
* !!! this function changes '\n' to 0 in `s`; `len` should include trailing '\0' too
|
||||||
*/
|
*/
|
||||||
ssize_t sl_RB_readline(sl_ringbuffer *b, char *s, size_t len){
|
ssize_t sl_RB_readline(sl_ringbuffer_t *b, char *s, size_t len){
|
||||||
ssize_t got = 0;
|
ssize_t got = 0;
|
||||||
pthread_mutex_lock(&b->busy);
|
pthread_mutex_lock(&b->busy);
|
||||||
ssize_t idx = hasbyte(b, '\n');
|
ssize_t idx = hasbyte(b, '\n');
|
||||||
@ -184,7 +190,7 @@ ret:
|
|||||||
* @param byte - data byte
|
* @param byte - data byte
|
||||||
* @return FALSE if there's no place for `byte` in `b`
|
* @return FALSE if there's no place for `byte` in `b`
|
||||||
*/
|
*/
|
||||||
int sl_RB_putbyte(sl_ringbuffer *b, uint8_t byte){
|
int sl_RB_putbyte(sl_ringbuffer_t *b, uint8_t byte){
|
||||||
int rtn = FALSE;
|
int rtn = FALSE;
|
||||||
pthread_mutex_lock(&b->busy);
|
pthread_mutex_lock(&b->busy);
|
||||||
size_t s = datalen(b);
|
size_t s = datalen(b);
|
||||||
@ -204,11 +210,11 @@ ret:
|
|||||||
* @param len - data length
|
* @param len - data length
|
||||||
* @return amount of bytes wrote (can be less than `len`)
|
* @return amount of bytes wrote (can be less than `len`)
|
||||||
*/
|
*/
|
||||||
size_t sl_RB_write(sl_ringbuffer *b, const uint8_t *str, size_t len){
|
size_t sl_RB_write(sl_ringbuffer_t *b, const uint8_t *str, size_t len){
|
||||||
pthread_mutex_lock(&b->busy);
|
pthread_mutex_lock(&b->busy);
|
||||||
size_t r = b->length - 1 - datalen(b); // rest length
|
size_t r = b->length - 1 - datalen(b); // rest length
|
||||||
if(len > r) len = r;
|
if(len > r) len = r;
|
||||||
if(!len){ r = 0; goto ret; }
|
if(!len) goto ret;
|
||||||
size_t _1st = b->length - b->tail;
|
size_t _1st = b->length - b->tail;
|
||||||
if(_1st > len) _1st = len;
|
if(_1st > len) _1st = len;
|
||||||
memcpy(b->data + b->tail, str, _1st);
|
memcpy(b->data + b->tail, str, _1st);
|
||||||
@ -218,14 +224,14 @@ size_t sl_RB_write(sl_ringbuffer *b, const uint8_t *str, size_t len){
|
|||||||
incr(b, &b->tail, len);
|
incr(b, &b->tail, len);
|
||||||
ret:
|
ret:
|
||||||
pthread_mutex_unlock(&b->busy);
|
pthread_mutex_unlock(&b->busy);
|
||||||
return r;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief sl_RB_clearbuf - reset buffer
|
* @brief sl_RB_clearbuf - reset buffer
|
||||||
* @param b - rb
|
* @param b - rb
|
||||||
*/
|
*/
|
||||||
void sl_RB_clearbuf(sl_ringbuffer *b){
|
void sl_RB_clearbuf(sl_ringbuffer_t *b){
|
||||||
pthread_mutex_lock(&b->busy);
|
pthread_mutex_lock(&b->busy);
|
||||||
b->head = 0;
|
b->head = 0;
|
||||||
b->tail = 0;
|
b->tail = 0;
|
||||||
@ -238,7 +244,7 @@ void sl_RB_clearbuf(sl_ringbuffer *b){
|
|||||||
* @param s - string
|
* @param s - string
|
||||||
* @return amount of bytes written (strlen of s) or 0
|
* @return amount of bytes written (strlen of s) or 0
|
||||||
*/
|
*/
|
||||||
size_t sl_RB_writestr(sl_ringbuffer *b, char *s){
|
size_t sl_RB_writestr(sl_ringbuffer_t *b, char *s){
|
||||||
size_t len = strlen(s);
|
size_t len = strlen(s);
|
||||||
pthread_mutex_lock(&b->busy);
|
pthread_mutex_lock(&b->busy);
|
||||||
size_t r = b->length - 1 - datalen(b); // rest length
|
size_t r = b->length - 1 - datalen(b); // rest length
|
||||||
|
|||||||
582
socket.c
582
socket.c
@ -16,5 +16,587 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/un.h> // unix socket
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "usefull_macros.h"
|
#include "usefull_macros.h"
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sl_sock_changemaxclients - change amount of max simultaneously connected clients
|
||||||
|
* SHOULD BE run BEFORE running of server
|
||||||
|
* @param val - maximal clients number
|
||||||
|
*/
|
||||||
|
void sl_sock_changemaxclients(int val){
|
||||||
|
maxclients = val;
|
||||||
|
}
|
||||||
|
int sl_sock_getmaxclients(){ return maxclients; }
|
||||||
|
|
||||||
|
// setter of "too much clients handler"
|
||||||
|
void sl_sock_maxclhandler(sl_sock_maxclh_t h){
|
||||||
|
toomuchclients = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// text messages for `hresult`
|
||||||
|
static const char *resmessages[RESULT_AMOUNT] = {
|
||||||
|
[RESULT_OK] = "OK\n",
|
||||||
|
[RESULT_FAIL] = "FAIL\n",
|
||||||
|
[RESULT_BADKEY] = "BADKEY\n",
|
||||||
|
[RESULT_BADVAL] = "BADVAL\n",
|
||||||
|
[RESULT_SILENCE] = "",
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sl_sock_hresult2str - get string message by hresult value
|
||||||
|
* @param r - handler result
|
||||||
|
* @return string with message
|
||||||
|
*/
|
||||||
|
const char *sl_sock_hresult2str(sl_sock_hresult_e r){
|
||||||
|
if(r >= RESULT_AMOUNT) return "BADRESULT";
|
||||||
|
return resmessages[r];
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert UNIX socket name for unaddr; result should be free'd
|
||||||
|
static char *convunsname(const char *path){
|
||||||
|
char *apath = MALLOC(char, 106);
|
||||||
|
if(*path == 0){
|
||||||
|
DBG("convert name starting from 0");
|
||||||
|
apath[0] = 0;
|
||||||
|
strncpy(apath+1, path+1, 104);
|
||||||
|
}else if(strncmp("\\0", path, 2) == 0){
|
||||||
|
DBG("convert name starting from \\0");
|
||||||
|
apath[0] = 0;
|
||||||
|
strncpy(apath+1, path+2, 104);
|
||||||
|
}else strncpy(apath, path, 105);
|
||||||
|
return apath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sl_sock_delete - close socket and delete descriptor
|
||||||
|
* @param sock - pointer to socket descriptor
|
||||||
|
*/
|
||||||
|
void sl_sock_delete(sl_sock_t **sock){
|
||||||
|
if(!sock || !*sock) return;
|
||||||
|
sl_sock_t *ptr = *sock;
|
||||||
|
ptr->connected = 0;
|
||||||
|
if(ptr->rthread){
|
||||||
|
DBG("Cancel thread");
|
||||||
|
pthread_cancel(ptr->rthread);
|
||||||
|
}
|
||||||
|
DBG("close fd=%d", ptr->fd);
|
||||||
|
if(ptr->fd > -1) close(ptr->fd);
|
||||||
|
DBG("delete ring buffer");
|
||||||
|
sl_RB_delete(&ptr->buffer);
|
||||||
|
DBG("free addrinfo");
|
||||||
|
if(ptr->addrinfo) freeaddrinfo(ptr->addrinfo);
|
||||||
|
DBG("free other");
|
||||||
|
FREE(ptr->node);
|
||||||
|
FREE(ptr->service);
|
||||||
|
FREE(ptr->data);
|
||||||
|
DBG("free sock");
|
||||||
|
FREE(*sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief clientrbthread - thread to fill client's ringbuffer with incoming data
|
||||||
|
* If s->handlers is not NULL, process all incoming data HERE, you shouldn't use ringbuffer by hands!
|
||||||
|
* @param d - socket descriptor
|
||||||
|
* @return NULL
|
||||||
|
*/
|
||||||
|
static void *clientrbthread(void *d){
|
||||||
|
char buf[512];
|
||||||
|
sl_sock_t *s = (sl_sock_t*) d;
|
||||||
|
DBG("Start client read buffer thread");
|
||||||
|
while(s && s->connected){
|
||||||
|
pthread_mutex_lock(&s->mutex);
|
||||||
|
if(1 != sl_canread(s->fd)){
|
||||||
|
pthread_mutex_unlock(&s->mutex);
|
||||||
|
usleep(1000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ssize_t n = read(s->fd, buf, 511);
|
||||||
|
DBG("read %zd from %d, unlock", n, s->fd);
|
||||||
|
pthread_mutex_unlock(&s->mutex);
|
||||||
|
if(n < 1){
|
||||||
|
WARNX(_("Server disconnected"));
|
||||||
|
goto errex;
|
||||||
|
}
|
||||||
|
ssize_t got = 0;
|
||||||
|
do{
|
||||||
|
ssize_t written = sl_RB_write(s->buffer, (uint8_t*)buf + got, n-got);
|
||||||
|
//DBG("Put %zd to buffer, got=%zd, n=%zd", written, got, n);
|
||||||
|
if(got > n) return NULL;
|
||||||
|
if(written > 0) got += written;
|
||||||
|
}while(got != n);
|
||||||
|
//DBG("All messsages done");
|
||||||
|
}
|
||||||
|
errex:
|
||||||
|
s->rthread = 0;
|
||||||
|
s->connected = FALSE;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// common for server thread and `sendall`
|
||||||
|
static sl_sock_t **clients = NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sl_sock_sendall - send data to all clients connected (works only for server)
|
||||||
|
* @param data - message
|
||||||
|
* @param len - its length
|
||||||
|
* @return N of sends or -1 if no server process running
|
||||||
|
*/
|
||||||
|
int sl_sock_sendall(uint8_t *data, size_t len){
|
||||||
|
if(!clients) return -1;
|
||||||
|
int nsent = 0;
|
||||||
|
for(int i = maxclients; i > 0; --i){
|
||||||
|
if(!clients[i]) continue;
|
||||||
|
if(clients[i]->fd < 0 || !clients[i]->connected) continue;
|
||||||
|
if((ssize_t)len == sl_sock_sendbinmessage(clients[i], data, len)) ++nsent;
|
||||||
|
}
|
||||||
|
return nsent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parser of client's message
|
||||||
|
static sl_sock_hresult_e msgparser(sl_sock_t *client, char *str){
|
||||||
|
char key[SL_KEY_LEN], val[SL_VAL_LEN], *valptr;
|
||||||
|
if(!str || !*str) return RESULT_BADKEY;
|
||||||
|
int N = sl_get_keyval(str, key, val);
|
||||||
|
DBG("getval=%d, key=%s, val=%s", N, key, val);
|
||||||
|
if(N == 0) return RESULT_BADKEY;
|
||||||
|
if(N == 1) valptr = NULL;
|
||||||
|
else valptr = val;
|
||||||
|
if(0 == strcmp(key, "help")){
|
||||||
|
sl_sock_sendstrmessage(client, "\nHelp:\n");
|
||||||
|
for(sl_sock_hitem_t *h = client->handlers; h->handler; ++h){
|
||||||
|
if(h->help){
|
||||||
|
sl_sock_sendstrmessage(client, h->key);
|
||||||
|
sl_sock_sendstrmessage(client, ": ");
|
||||||
|
sl_sock_sendstrmessage(client, h->help);
|
||||||
|
sl_sock_sendbyte(client, '\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sl_sock_sendbyte(client, '\n');
|
||||||
|
return RESULT_SILENCE;
|
||||||
|
}
|
||||||
|
for(sl_sock_hitem_t *h = client->handlers; h->handler; ++h){
|
||||||
|
if(strcmp(h->key, key)) continue;
|
||||||
|
return h->handler(client, h, valptr);
|
||||||
|
}
|
||||||
|
return RESULT_BADKEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief serverrbthread - thread for standard server procedure (when user give non-NULL `handlers`)
|
||||||
|
* @param d - socket descriptor
|
||||||
|
* @return NULL
|
||||||
|
*/
|
||||||
|
static void *serverthread(void _U_ *d){
|
||||||
|
sl_sock_t *s = (sl_sock_t*) d;
|
||||||
|
if(!s || !s->handlers){
|
||||||
|
WARNX(_("Can't start server handlers thread"));
|
||||||
|
goto errex;
|
||||||
|
}
|
||||||
|
int sockfd = s->fd;
|
||||||
|
if(listen(sockfd, maxclients) == -1){
|
||||||
|
WARN("listen");
|
||||||
|
goto errex;
|
||||||
|
}
|
||||||
|
DBG("Start server handlers thread");
|
||||||
|
int nfd = 1; // only one socket @start
|
||||||
|
struct pollfd *poll_set = MALLOC(struct pollfd, maxclients+1);
|
||||||
|
clients = MALLOC(sl_sock_t*, maxclients+1);
|
||||||
|
// init default clients records
|
||||||
|
for(int i = maxclients; i > 0; --i){
|
||||||
|
DBG("fill %dth client info", i);
|
||||||
|
clients[i] = MALLOC(sl_sock_t, 1);
|
||||||
|
sl_sock_t *c = clients[i];
|
||||||
|
c->type = s->type;
|
||||||
|
if(s->node) c->node = strdup(s->node);
|
||||||
|
if(s->service) c->service = strdup(s->service);
|
||||||
|
c->handlers = s->handlers;
|
||||||
|
// fill addrinfo
|
||||||
|
c->addrinfo = MALLOC(struct addrinfo, 1);
|
||||||
|
c->addrinfo->ai_addr = MALLOC(struct sockaddr, 1);
|
||||||
|
}
|
||||||
|
// ZERO - listening server socket
|
||||||
|
poll_set[0].fd = sockfd;
|
||||||
|
poll_set[0].events = POLLIN;
|
||||||
|
while(s && s->connected){
|
||||||
|
poll(poll_set, nfd, 1);
|
||||||
|
if(poll_set[0].revents & POLLIN){ // check main for accept()
|
||||||
|
struct sockaddr a;
|
||||||
|
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);
|
||||||
|
close(client);
|
||||||
|
}else{
|
||||||
|
memset(&poll_set[nfd], 0, sizeof(struct pollfd));
|
||||||
|
poll_set[nfd].fd = client;
|
||||||
|
poll_set[nfd].events = POLLIN;
|
||||||
|
DBG("got client[%d], fd=%d", nfd, client);
|
||||||
|
sl_sock_t *c = clients[nfd];
|
||||||
|
c->fd = client;
|
||||||
|
DBG("memcpy");
|
||||||
|
memcpy(c->addrinfo->ai_addr, &a, len);
|
||||||
|
DBG("set conn flag");
|
||||||
|
c->connected = 1;
|
||||||
|
struct sockaddr_in* inaddr = (struct sockaddr_in*)&a;
|
||||||
|
if(!inet_ntop(AF_INET, &inaddr->sin_addr, c->IP, INET_ADDRSTRLEN)){
|
||||||
|
WARN("inet_ntop()");
|
||||||
|
*c->IP = 0;
|
||||||
|
}
|
||||||
|
DBG("got IP:%s", c->IP);
|
||||||
|
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
|
||||||
|
}
|
||||||
|
++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){
|
||||||
|
pthread_mutex_unlock(&c->mutex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ssize_t got = read(fd, buf, nread);
|
||||||
|
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;
|
||||||
|
--fdidx;
|
||||||
|
}else{
|
||||||
|
sl_RB_write(c->buffer, buf, got);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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);
|
||||||
|
if(got < 0){ // buffer overflow
|
||||||
|
ERRX(_("Server thread: buffer overflow from \"%s\""), c->IP);
|
||||||
|
sl_RB_clearbuf(c->buffer);
|
||||||
|
continue;
|
||||||
|
}else if(got == 0) continue;
|
||||||
|
sl_sock_hresult_e r = msgparser(c, (char*)buf);
|
||||||
|
if(r != RESULT_SILENCE) sl_sock_sendstrmessage(c, sl_sock_hresult2str(r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// clear memory
|
||||||
|
FREE(poll_set);
|
||||||
|
for(int i = maxclients; i > 0; --i){
|
||||||
|
DBG("Clear %dth client data", i);
|
||||||
|
sl_sock_t *c = clients[i];
|
||||||
|
if(c->fd > -1) close(c->fd);
|
||||||
|
if(c->buffer) sl_RB_delete(&c->buffer);
|
||||||
|
FREE(c->addrinfo->ai_addr);
|
||||||
|
FREE(c->addrinfo);
|
||||||
|
FREE(c->node);
|
||||||
|
FREE(c->service);
|
||||||
|
FREE(c);
|
||||||
|
}
|
||||||
|
FREE(clients);
|
||||||
|
errex:
|
||||||
|
s->rthread = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sl_sock_open - open socket (client or server)
|
||||||
|
* @param type - socket type
|
||||||
|
* @param path - path (for UNIX socket); for NET: ":port" for server, "server:port" for client
|
||||||
|
* @param handlers - standard handlers when read data (or NULL)
|
||||||
|
* @param bufsiz - input ring buffer size
|
||||||
|
* @param isserver - 1 for server, 0 for client
|
||||||
|
* @return socket descriptor or NULL if failed
|
||||||
|
* to create anonymous UNIX-socket you can start "path" from 0 or from string "\0"
|
||||||
|
*/
|
||||||
|
static sl_sock_t *sl_sock_open(sl_socktype_e type, const char *path, sl_sock_hitem_t *handlers, int bufsiz, int isserver){
|
||||||
|
if(!path || type >= SOCKT_AMOUNT) return NULL;
|
||||||
|
if(bufsiz < 256) bufsiz = 256;
|
||||||
|
int sock = -1;
|
||||||
|
struct addrinfo ai = {0}, *res = &ai;
|
||||||
|
struct sockaddr_un unaddr = {0};
|
||||||
|
char *str = NULL;
|
||||||
|
switch(type){
|
||||||
|
case SOCKT_UNIX:
|
||||||
|
str = convunsname(path);
|
||||||
|
if(!str) return NULL;
|
||||||
|
unaddr.sun_family = AF_UNIX;
|
||||||
|
ai.ai_addr = (struct sockaddr*) &unaddr;
|
||||||
|
ai.ai_addrlen = sizeof(unaddr);
|
||||||
|
memcpy(unaddr.sun_path, str, 106);
|
||||||
|
ai.ai_family = AF_UNIX;
|
||||||
|
ai.ai_socktype = SOCK_SEQPACKET;
|
||||||
|
break;
|
||||||
|
case SOCKT_NET:
|
||||||
|
case SOCKT_NETLOCAL:
|
||||||
|
//ai.ai_socktype = SOCK_DGRAM; // = SOCK_STREAM;
|
||||||
|
ai.ai_family = AF_INET;
|
||||||
|
if(isserver) ai.ai_flags = AI_PASSIVE;
|
||||||
|
break;
|
||||||
|
default: // never reached
|
||||||
|
WARNX(_("Unsupported socket type %d"), type);
|
||||||
|
return NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sl_sock_t *s = MALLOC(sl_sock_t, 1);
|
||||||
|
s->type = type;
|
||||||
|
s->fd = -1;
|
||||||
|
s->handlers = handlers;
|
||||||
|
s->buffer = sl_RB_new(bufsiz);
|
||||||
|
if(!s->buffer) sl_sock_delete(&s);
|
||||||
|
else{ // fill node/service
|
||||||
|
if(type == SOCKT_UNIX) s->node = str; // str now is converted path
|
||||||
|
else{
|
||||||
|
char *delim = strchr(path, ':');
|
||||||
|
if(!delim) s->service = strdup(path); // only port
|
||||||
|
else{
|
||||||
|
if(delim == path) s->service = strdup(path+1);
|
||||||
|
else{
|
||||||
|
size_t l = delim - path;
|
||||||
|
s->node = MALLOC(char, l + 1);
|
||||||
|
strncpy(s->node, path, l);
|
||||||
|
s->service = strdup(delim + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBG("socket->service=%s", s->service);
|
||||||
|
}
|
||||||
|
DBG("socket->node=%s", s->node);
|
||||||
|
}
|
||||||
|
// now try to open socket
|
||||||
|
if(type != SOCKT_UNIX){
|
||||||
|
DBG("try to get addrinfo for node '%s' and service '%s'", s->node, s->service);
|
||||||
|
char *node = s->node;
|
||||||
|
if(isserver){
|
||||||
|
if(s->type == SOCKT_NET) node = NULL; // common net server -> node==NULL
|
||||||
|
else node = "127.0.0.1"; // localhost
|
||||||
|
}
|
||||||
|
DBG("---> node '%s', service '%s'", node, s->service);
|
||||||
|
int e = getaddrinfo(node, s->service, &ai, &res);
|
||||||
|
if(e){
|
||||||
|
WARNX("getaddrinfo(): %s", gai_strerror(e));
|
||||||
|
sl_sock_delete(&s);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(struct addrinfo *p = res; p; p = p->ai_next){
|
||||||
|
if((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) continue;
|
||||||
|
DBG("Try proto %d, type %d", p->ai_protocol, p->ai_socktype);
|
||||||
|
if(isserver){
|
||||||
|
int reuseaddr = 1;
|
||||||
|
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)) == -1){
|
||||||
|
WARN("setsockopt()");
|
||||||
|
close(sock); sock = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(bind(sock, p->ai_addr, p->ai_addrlen) == -1){
|
||||||
|
WARN("bind()");
|
||||||
|
close(sock); sock = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int enable = 1;
|
||||||
|
if(ioctl(sock, FIONBIO, (void *)&enable) < 0){ // make socket nonblocking
|
||||||
|
WARN("Can't make socket non-blocked");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(connect(sock, p->ai_addr, p->ai_addrlen) == -1){
|
||||||
|
WARN("connect()");
|
||||||
|
close(sock); sock = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(sock < 0) sl_sock_delete(&s);
|
||||||
|
else{
|
||||||
|
s->fd = sock;
|
||||||
|
pthread_mutex_init(&s->mutex, NULL);
|
||||||
|
DBG("s->fd=%d, node=%s, service=%s", s->fd, s->node, s->service);
|
||||||
|
int r = -1;
|
||||||
|
if(isserver){
|
||||||
|
if(s->handlers)
|
||||||
|
r = pthread_create(&s->rthread, NULL, serverthread, (void*)s);
|
||||||
|
else r = 0;
|
||||||
|
}else{
|
||||||
|
r = pthread_create(&s->rthread, NULL, clientrbthread, (void*)s);
|
||||||
|
}
|
||||||
|
if(r){
|
||||||
|
WARN("pthread_create()");
|
||||||
|
sl_sock_delete(&s);
|
||||||
|
}else{
|
||||||
|
s->connected = TRUE;
|
||||||
|
DBG("fd=%d CONNECTED", s->fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sl_sock_run_client - try to connect to server and, socket read thread and process optional handlers
|
||||||
|
* @param type - server type
|
||||||
|
* @param path - path or address:port
|
||||||
|
* @param handlers - array with handlers
|
||||||
|
* @param bufsiz - input ring buffer size
|
||||||
|
* @return socket descriptor or NULL if failed
|
||||||
|
*/
|
||||||
|
sl_sock_t *sl_sock_run_client(sl_socktype_e type, const char *path, int bufsiz){
|
||||||
|
sl_sock_t *s = sl_sock_open(type, path, NULL, bufsiz, 0);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sl_sock_run_server - run built-in server parser
|
||||||
|
* @param type - server type
|
||||||
|
* @param path - path or port
|
||||||
|
* @param handlers - array with handlers
|
||||||
|
* @param bufsiz - input ring buffer size
|
||||||
|
* @return socket descriptor or NULL if failed
|
||||||
|
*/
|
||||||
|
sl_sock_t *sl_sock_run_server(sl_socktype_e type, const char *path, int bufsiz, sl_sock_hitem_t *handlers){
|
||||||
|
sl_sock_t *s = sl_sock_open(type, path, handlers, bufsiz, 1);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sl_sock_sendbinmessage - send binary data
|
||||||
|
* @param socket - socket
|
||||||
|
* @param msg - data
|
||||||
|
* @param l - data length
|
||||||
|
* @return amount of bytes sent or -1 in case of error
|
||||||
|
*/
|
||||||
|
ssize_t sl_sock_sendbinmessage(sl_sock_t *socket, const uint8_t *msg, size_t l){
|
||||||
|
if(!msg || l < 1) return -1;
|
||||||
|
DBG("send to fd=%d message with len=%zd (%s)", socket->fd, l, msg);
|
||||||
|
while(socket && socket->connected && !sl_canwrite(socket->fd));
|
||||||
|
if(!socket || !socket->connected) return -1;
|
||||||
|
DBG("lock");
|
||||||
|
pthread_mutex_lock(&socket->mutex);
|
||||||
|
DBG("SEND");
|
||||||
|
ssize_t r = send(socket->fd, msg, l, MSG_NOSIGNAL);
|
||||||
|
DBG("unlock");
|
||||||
|
pthread_mutex_unlock(&socket->mutex);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t sl_sock_sendstrmessage(sl_sock_t *socket, const char *msg){
|
||||||
|
if(!msg) return -1;
|
||||||
|
size_t l = strlen(msg);
|
||||||
|
return sl_sock_sendbinmessage(socket, (const uint8_t*)msg, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sl_sock_sendbyte - send one byte over socket
|
||||||
|
* @param socket - socket
|
||||||
|
* @param byte - byte to send
|
||||||
|
* @return -1 in case of error, 1 if all OK
|
||||||
|
*/
|
||||||
|
ssize_t sl_sock_sendbyte(sl_sock_t *socket, uint8_t byte){
|
||||||
|
while(socket && socket->connected && !sl_canwrite(socket->fd));
|
||||||
|
if(!socket || !socket->connected) return -1;
|
||||||
|
DBG("lock");
|
||||||
|
pthread_mutex_lock(&socket->mutex);
|
||||||
|
ssize_t r = send(socket->fd, &byte, 1, MSG_NOSIGNAL);
|
||||||
|
DBG("unlock");
|
||||||
|
pthread_mutex_unlock(&socket->mutex);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sl_sock_readline - read string line from incoming ringbuffer
|
||||||
|
* @param sock - socket
|
||||||
|
* @param str (o) - buffer to copy
|
||||||
|
* @param len - length of str
|
||||||
|
* @return amount of bytes read
|
||||||
|
*/
|
||||||
|
ssize_t sl_sock_readline(sl_sock_t *sock, char *str, size_t len){
|
||||||
|
if(!sock || !sock->buffer || !str || !len) return -1;
|
||||||
|
return sl_RB_readline(sock->buffer, str, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// default handlers - setters/getters of int64, double and string
|
||||||
|
sl_sock_hresult_e sl_sock_inthandler(sl_sock_t *client, sl_sock_hitem_t *hitem, const char *str){
|
||||||
|
char buf[128];
|
||||||
|
sl_sock_int_t *i = (sl_sock_int_t *)hitem->data;
|
||||||
|
if(!str){ // getter
|
||||||
|
snprintf(buf, 127, "%s=%" PRId64 "\n", hitem->key, i->val);
|
||||||
|
sl_sock_sendstrmessage(client, buf);
|
||||||
|
return RESULT_SILENCE;
|
||||||
|
}
|
||||||
|
long long x;
|
||||||
|
if(!sl_str2ll(&x, str)) return RESULT_BADVAL;
|
||||||
|
if(x < INT64_MIN || x > INT64_MAX) return RESULT_BADVAL;
|
||||||
|
i->val = (int64_t)x;
|
||||||
|
i->timestamp = sl_dtime();
|
||||||
|
return RESULT_OK;
|
||||||
|
}
|
||||||
|
sl_sock_hresult_e sl_sock_dblhandler(sl_sock_t *client, sl_sock_hitem_t *hitem, const char *str){
|
||||||
|
char buf[128];
|
||||||
|
sl_sock_double_t *d = (sl_sock_double_t *)hitem->data;
|
||||||
|
if(!str){ // getter
|
||||||
|
snprintf(buf, 127, "%s=%g\n", hitem->key, d->val);
|
||||||
|
sl_sock_sendstrmessage(client, buf);
|
||||||
|
return RESULT_SILENCE;
|
||||||
|
}
|
||||||
|
double dv;
|
||||||
|
if(!sl_str2d(&dv, str)) return RESULT_BADVAL;
|
||||||
|
d->val = dv;
|
||||||
|
d->timestamp = sl_dtime();
|
||||||
|
return RESULT_OK;
|
||||||
|
}
|
||||||
|
sl_sock_hresult_e sl_sock_strhandler(sl_sock_t *client, sl_sock_hitem_t *hitem, const char *str){
|
||||||
|
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);
|
||||||
|
sl_sock_sendstrmessage(client, buf);
|
||||||
|
return RESULT_SILENCE;
|
||||||
|
}
|
||||||
|
int l = strlen(str);
|
||||||
|
if(l > SL_VAL_LEN - 1) return RESULT_BADVAL;
|
||||||
|
s->len = l;
|
||||||
|
s->timestamp = sl_dtime();
|
||||||
|
memcpy(s->val, str, l);
|
||||||
|
return RESULT_OK;
|
||||||
|
}
|
||||||
|
|||||||
@ -419,6 +419,81 @@ int sl_str2ll(long long *num, const char *str){
|
|||||||
if(num) *num = res;
|
if(num) *num = res;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
int sl_str2i(int *num, const char *str){
|
||||||
|
long long res;
|
||||||
|
char *endptr;
|
||||||
|
if(!str) return FALSE;
|
||||||
|
res = strtoll(str, &endptr, 0);
|
||||||
|
if(endptr == str || *str == '\0' || *endptr != '\0'){
|
||||||
|
WARNX(_("Wrong integer number format '%s'"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if(res > INT_MAX || res < INT_MIN){
|
||||||
|
WARNX(_("Number out of integer limits"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if(num) *num = (int)res;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sl_canread - run select() for given fd
|
||||||
|
* @param fd - file descriptor
|
||||||
|
* @return -1 if EINTR, 0 if none, 1 if ready to read
|
||||||
|
*/
|
||||||
|
int sl_canread(int fd){
|
||||||
|
if(fd < 0) return -1;
|
||||||
|
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){
|
||||||
|
WARN("select()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}while(1);
|
||||||
|
if(FD_ISSET(fd, &fds)) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sl_canwrite - run select() for given fd
|
||||||
|
* @param fd - file descriptor
|
||||||
|
* @return -1 if EINTR, 0 if none, 1 if ready to write without blocking
|
||||||
|
*/
|
||||||
|
int sl_canwrite(int fd){
|
||||||
|
fd_set fds;
|
||||||
|
struct timeval timeout;
|
||||||
|
timeout.tv_sec = 0;
|
||||||
|
timeout.tv_usec = 100;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(fd, &fds);
|
||||||
|
//DBG("try ability of written to %d", fd);
|
||||||
|
do{
|
||||||
|
int rc = select(fd+1, NULL, &fds, NULL, &timeout);
|
||||||
|
if(rc < 0){
|
||||||
|
DBG("-1");
|
||||||
|
if(errno != EINTR){
|
||||||
|
LOGWARN("select()");
|
||||||
|
WARN("select()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}while(1);
|
||||||
|
if(FD_ISSET(fd, &fds)) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************\
|
/******************************************************************************\
|
||||||
* Logging to file
|
* Logging to file
|
||||||
|
|||||||
121
usefull_macros.h
121
usefull_macros.h
@ -28,6 +28,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <errno.h> // errno
|
#include <errno.h> // errno
|
||||||
|
#include <netdb.h> // struct addrinfo
|
||||||
|
#include <pthread.h>
|
||||||
#include <stdlib.h> // alloc, free
|
#include <stdlib.h> // alloc, free
|
||||||
#include <sys/types.h> // pid_t
|
#include <sys/types.h> // pid_t
|
||||||
#include <unistd.h> // pid_t
|
#include <unistd.h> // pid_t
|
||||||
@ -152,9 +154,13 @@ char *sl_omitspaces(const char *str);
|
|||||||
// omit trailing spaces
|
// omit trailing spaces
|
||||||
char *sl_omitspacesr(const char *v);
|
char *sl_omitspacesr(const char *v);
|
||||||
|
|
||||||
// convert string to double with checking
|
// convert string to double/integer with checking
|
||||||
int sl_str2d(double *num, const char *str);
|
int sl_str2d(double *num, const char *str);
|
||||||
int sl_str2ll(long long *num, const char *str);
|
int sl_str2ll(long long *num, const char *str);
|
||||||
|
int sl_str2i(int *num, const char *str);
|
||||||
|
|
||||||
|
int sl_canread(int fd);
|
||||||
|
int sl_canwrite(int fd);
|
||||||
|
|
||||||
/******************************************************************************\
|
/******************************************************************************\
|
||||||
The original term.h
|
The original term.h
|
||||||
@ -389,53 +395,114 @@ typedef struct{
|
|||||||
size_t head; // head index
|
size_t head; // head index
|
||||||
size_t tail; // tail index
|
size_t tail; // tail index
|
||||||
pthread_mutex_t busy; // mutex of buffer activity
|
pthread_mutex_t busy; // mutex of buffer activity
|
||||||
} sl_ringbuffer;
|
} sl_ringbuffer_t;
|
||||||
|
|
||||||
sl_ringbuffer *sl_RB_new(size_t size);
|
sl_ringbuffer_t *sl_RB_new(size_t size);
|
||||||
void sl_RB_delete(sl_ringbuffer **b);
|
void sl_RB_delete(sl_ringbuffer_t **b);
|
||||||
size_t sl_RB_read(sl_ringbuffer *b, uint8_t *s, size_t len);
|
size_t sl_RB_read(sl_ringbuffer_t *b, uint8_t *s, size_t len);
|
||||||
ssize_t sl_RB_readto(sl_ringbuffer *b, uint8_t byte, uint8_t *s, size_t len);
|
ssize_t sl_RB_readto(sl_ringbuffer_t *b, uint8_t byte, uint8_t *s, size_t len);
|
||||||
ssize_t sl_RB_hasbyte(sl_ringbuffer *b, uint8_t byte);
|
ssize_t sl_RB_hasbyte(sl_ringbuffer_t *b, uint8_t byte);
|
||||||
int sl_RB_putbyte(sl_ringbuffer *b, uint8_t byte);
|
int sl_RB_putbyte(sl_ringbuffer_t *b, uint8_t byte);
|
||||||
size_t sl_RB_write(sl_ringbuffer *b, const uint8_t *str, size_t len);
|
size_t sl_RB_write(sl_ringbuffer_t *b, const uint8_t *str, size_t len);
|
||||||
size_t sl_RB_datalen(sl_ringbuffer *b);
|
size_t sl_RB_datalen(sl_ringbuffer_t *b);
|
||||||
void sl_RB_clearbuf(sl_ringbuffer *b);
|
size_t sl_RB_freesize(sl_ringbuffer_t *b);
|
||||||
ssize_t sl_RB_readline(sl_ringbuffer *b, char *s, size_t len);
|
void sl_RB_clearbuf(sl_ringbuffer_t *b);
|
||||||
size_t sl_RB_writestr(sl_ringbuffer *b, char *s);
|
ssize_t sl_RB_readline(sl_ringbuffer_t *b, char *s, size_t len);
|
||||||
|
size_t sl_RB_writestr(sl_ringbuffer_t *b, char *s);
|
||||||
|
|
||||||
/******************************************************************************\
|
/******************************************************************************\
|
||||||
The original socket.h
|
The original socket.h
|
||||||
\******************************************************************************/
|
\******************************************************************************/
|
||||||
|
|
||||||
// handler result: what to send to client
|
// handler result: what to send to client
|
||||||
|
|
||||||
typedef enum{
|
typedef enum{
|
||||||
RESULT_OK, // all OK
|
RESULT_OK, // all OK
|
||||||
RESULT_FAIL, // failed running command
|
RESULT_FAIL, // failed running command
|
||||||
RESULT_BADVAL, // bad value
|
RESULT_BADVAL, // bad value
|
||||||
RESULT_BADKEY, // bad (non-existant) key
|
RESULT_BADKEY, // bad (non-existant) key
|
||||||
RESULT_SILENCE, // send nothing to client (in case of handlers which sends data by themself)
|
RESULT_SILENCE, // send nothing to client (in case of handlers which sends data by themself)
|
||||||
RESULT_NUM // total amount of enum fields
|
RESULT_AMOUNT // total amount of enum fields
|
||||||
} sl_hresult;
|
} sl_sock_hresult_e;
|
||||||
|
|
||||||
typedef sl_hresult (*sl_msghandler)(int fd, const char *key, const char *val);
|
// data types with timestamp
|
||||||
|
typedef struct{
|
||||||
|
double timestamp; // time of last change
|
||||||
|
double val;
|
||||||
|
} sl_sock_double_t;
|
||||||
|
|
||||||
typedef struct{
|
typedef struct{
|
||||||
sl_msghandler handler;
|
double timestamp; // time of last change
|
||||||
const char *key;
|
int64_t val;
|
||||||
const char *help;
|
} sl_sock_int_t;
|
||||||
} sl_handleritem;
|
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
double timestamp; // time of last change
|
||||||
|
char val[SL_VAL_LEN];
|
||||||
|
int len; // strlen of `val`
|
||||||
|
} sl_sock_string_t;
|
||||||
|
|
||||||
|
struct sl_sock_hitem;
|
||||||
|
struct sl_sock;
|
||||||
|
|
||||||
|
// socket `key` handlers
|
||||||
|
typedef sl_sock_hresult_e (*sl_sock_msghandler)(struct sl_sock *client, struct sl_sock_hitem *item, const char *val);
|
||||||
|
// handler item
|
||||||
|
typedef struct sl_sock_hitem{
|
||||||
|
sl_sock_msghandler handler; // function-handler
|
||||||
|
const char *key; // key name
|
||||||
|
const char *help; // key help
|
||||||
|
void *data; // user data (e.g. struct key-varptr-limits)
|
||||||
|
} sl_sock_hitem_t;
|
||||||
|
|
||||||
|
// socket type
|
||||||
typedef enum{
|
typedef enum{
|
||||||
SOCKT_UNIX, // UNIX socket
|
SOCKT_UNIX, // UNIX socket
|
||||||
SOCKT_NETLOCAL, // INET socket but only for localhost
|
SOCKT_NETLOCAL, // INET socket but only for localhost
|
||||||
SOCKT_NET // true INET socket
|
SOCKT_NET, // true INET socket
|
||||||
} sl_socktype;
|
SOCKT_AMOUNT // amount of types
|
||||||
|
} sl_socktype_e;
|
||||||
|
|
||||||
const char *sl_hresult2str(sl_hresult r);
|
// socket itself
|
||||||
int sl_start_socket(int isserver, int isnet, const char *path);
|
typedef struct sl_sock{
|
||||||
void sl_sendbinmessage(int fd, const uint8_t *msg, int l);
|
int fd; // file descriptor
|
||||||
void sl_sendstrmessage(int fd, const char *msg);
|
int connected; // == TRUE if connected
|
||||||
|
sl_socktype_e type; // type
|
||||||
|
sl_ringbuffer_t *buffer; // input data buffer
|
||||||
|
char *node; // original UNIX-socket path or node name for INET (NULL - localhost client or any server)
|
||||||
|
char *service; // NULL for UNIX-socket and port for INET
|
||||||
|
struct addrinfo *addrinfo; // filled addrinfo structure
|
||||||
|
void *data; // user data
|
||||||
|
pthread_mutex_t mutex; // read/write mutex
|
||||||
|
pthread_t rthread; // reading ring buffer thread for client and main server thread for server
|
||||||
|
char IP[INET_ADDRSTRLEN]; // client's IP address
|
||||||
|
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();
|
||||||
|
typedef void (*sl_sock_maxclh_t)(int fd);
|
||||||
|
void sl_sock_maxclhandler(sl_sock_maxclh_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);
|
||||||
|
ssize_t sl_sock_sendstrmessage(sl_sock_t *socket, const char *msg);
|
||||||
|
ssize_t sl_sock_readline(sl_sock_t *sock, char *str, size_t len);
|
||||||
|
int sl_sock_sendall(uint8_t *data, size_t len);
|
||||||
|
|
||||||
|
sl_sock_hresult_e sl_sock_inthandler(sl_sock_t *client, sl_sock_hitem_t *hitem, const char *str);
|
||||||
|
sl_sock_hresult_e sl_sock_dblhandler(sl_sock_t *client, sl_sock_hitem_t *hitem, const char *str);
|
||||||
|
sl_sock_hresult_e sl_sock_strhandler(sl_sock_t *client, sl_sock_hitem_t *hitem, const char *str);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user