4 Commits

13 changed files with 543 additions and 323 deletions

View File

@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 4.0)
set(PROJ usefull_macros)
set(MINOR_VERSION "3")
set(MINOR_VERSION "5")
set(MID_VERSION "3")
set(MAJOR_VERSION "0")
set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}")
@@ -8,7 +8,7 @@ set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}")
project(${PROJ} VERSION ${VERSION} LANGUAGES C)
# default flags
set(CMAKE_C_FLAGS "${CFLAGS} -O2")
set(CMAKE_C_FLAGS "${CFLAGS} -O2 -pedantic-errors")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS}")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -Wextra -Wall -Werror -W")
set(CMAKE_COLOR_MAKEFILE ON)
@@ -51,16 +51,6 @@ message("Build type: ${CMAKE_BUILD_TYPE}")
# here is one of two variants: all .c in directory or .c files in list
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SOURCES)
get_filename_component(term_c ${CMAKE_CURRENT_SOURCE_DIR}/term.c ABSOLUTE)
if(DEFINED USE_OLD_TTY OR DEFINED SL_USE_OLD_TTY)
get_filename_component(term_c ${CMAKE_CURRENT_SOURCE_DIR}/term2.c ABSOLUTE)
add_definitions(-DSL_USE_OLD_TTY)
endif()
message("remove ${term_c}")
list(REMOVE_ITEM SOURCES ${term_c})
# directory should contain dir locale/ru for gettext translations
set(LCPATH ${CMAKE_SOURCE_DIR}/locale/ru)
if(NOT DEFINED LOCALEDIR)

View File

@@ -1,3 +1,27 @@
Wed Mar 4 14:18:15 MSK 2026
VERSION 0.3.4:
- fixed wrong UNIX-sockets names
- code changed for `-pedantic-errors`
VERSION 0.3.5
- add int sl_sock_open(sl_socktype_e type, const char *path, int isserver, int ai_socktype);
open socket, bind or connect it and return descriptor
- deprecation of SL_USE_OLD_TTY
- add int sl_tty_fdescr(const char *comdev, const char *format, int speed, int exclusive)
open and configure serial port and return descriptor
- remove both fields `struct termios2` from `sl_tty_t`
- add int sl_tty_setformat(sl_tty_t *d, const char *format)
change default format "8N1" to given
Thu Nov 6 11:25:07 MSK 2025
VERSION 0.3.4:
add data type:
- sl_sock_keyno_t - number of key (like key[keyno] = val) using in sl_sock_hitem_t.data
add functions:
- sl_sock_keyno_init - init keyno (or use macro SL_SOCK_KEYNO_DEFAUL in assignment)
- sl_sock_keyno_check - return -1 if there's no keyno, else return its value
New functional listed in examples/clientserver.c introducing key `flags` that allows to work with bit flags as a whole or by bits like flags[1]=1, flags21=0, flags{31} or flags(14)...
Wed Sep 10 14:19:24 MSK 2025
(still version 0.3.3: I forgot to add changelog last commits)
- fixed minor bugs and memory leaks

View File

@@ -2,8 +2,10 @@ cmake_minimum_required(VERSION 3.9)
project(examples)
# common includes & library
include_directories(../)
link_libraries(usefull_macros)
#include_directories(../)
#link_libraries(usefull_macros)
link_libraries(${CMAKE_BINARY_DIR}/libusefull_macros.so)
include_directories(${CMAKE_SOURCE_DIR})
# exe list
add_executable(helloworld helloworld.c)

View File

@@ -122,6 +122,7 @@ static void runclient(sl_sock_t *s){
static sl_sock_int_t iflag = {0};
static sl_sock_double_t dflag = {0};
static sl_sock_string_t sflag = {0};
static uint32_t bitflags = 0;
static sl_sock_hresult_e dtimeh(sl_sock_t _U_ *client, _U_ sl_sock_hitem_t *item, _U_ const char *req){
char buf[32];
@@ -169,6 +170,7 @@ 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);
}
// default (unknown key) handler
static sl_sock_hresult_e defhandler(struct sl_sock *s, const char *str){
if(!s || !str) return RESULT_FAIL;
sl_sock_sendstrmessage(s, "You entered wrong command:\n```\n");
@@ -176,6 +178,33 @@ static sl_sock_hresult_e defhandler(struct sl_sock *s, const char *str){
sl_sock_sendstrmessage(s, "\n```\nTry \"help\"\n");
return RESULT_SILENCE;
}
// if we use this macro, there's no need to run `sl_sock_keyno_init` later
static sl_sock_keyno_t kph_number = SL_SOCK_KEYNO_DEFAULT;
// handler for key with optional parameter number
static sl_sock_hresult_e keyparhandler(struct sl_sock *s, sl_sock_hitem_t *item, const char *req){
if(!item->data) return RESULT_FAIL;
char buf[1024];
int no = sl_sock_keyno_check((sl_sock_keyno_t*)item->data);
long long newval = -1;
if(req){
if(!sl_str2ll(&newval, req) || newval < 0 || newval > 0xffffffff) return RESULT_BADVAL;
}
printf("no = %d\n", no);
if(no < 0){ // flags as a whole
if(req) bitflags = (uint32_t)newval;
snprintf(buf, 1023, "flags = 0x%08X\n", bitflags);
sl_sock_sendstrmessage(s, buf);
}else if(no < 32){ // bit access
int bitmask = 1 << no;
if(req){
if(newval) bitflags |= bitmask;
else bitflags &= ~bitmask;
}
snprintf(buf, 1023, "flags[%d] = %d\n", no, bitflags & bitmask ? 1 : 0);
sl_sock_sendstrmessage(s, buf);
}else return RESULT_BADKEY;
return RESULT_SILENCE;
}
static sl_sock_hitem_t handlers[] = {
{sl_sock_inthandler, "int", "set/get integer flag", (void*)&iflag},
@@ -183,6 +212,7 @@ static sl_sock_hitem_t handlers[] = {
{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 for all clients connected", NULL},
{keyparhandler, "flags", "set/get bit flags as whole (flags=val) or by bits (flags[bit]=val)", (void*)&kph_number},
{NULL, NULL, NULL, NULL}
};
@@ -193,10 +223,13 @@ int main(int argc, char **argv){
if(!G.node) ERRX("Point node");
sl_socktype_e type = (G.isunix) ? SOCKT_UNIX : SOCKT_NET;
if(G.isserver){
//sl_sock_keyno_init(&kph_number); // don't forget to init first or use macro in initialisation
s = sl_sock_run_server(type, G.node, -1, handlers);
DBG("Server started");
} else {
sl_setup_con();
s = sl_sock_run_client(type, G.node, -1);
DBG("Client started");
}
if(!s) ERRX("Can't create socket and/or run threads");
if(G.isserver){

View File

@@ -48,8 +48,13 @@ void signals(int sig){
LOGERR("Exit with status %d", sig);
if(GP && GP->pidfile) // remove unnesessary PID file
unlink(GP->pidfile);
DBG("restore console");
sl_restore_con();
if(dev) sl_tty_close(&dev);
if(dev){
DBG("Close serial device");
sl_tty_close(&dev);
}
DBG("OK, exit");
exit(sig);
}
@@ -100,13 +105,17 @@ int main(int argc, char *argv[]){
printf("String so2=%s\n", GP->so2);
}
if(GP->device){
LOGDBG("Try to open serial %s", GP->device);
LOGMSG("Try to open serial %s at speed %d", GP->device, GP->speed);
dev = sl_tty_new(GP->device, GP->speed, 4096);
if(dev) dev = sl_tty_open(dev, GP->exclusive);
if(!dev){
LOGERR("Can't open %s with speed %d. Exit.", GP->device, GP->speed);
signals(0);
}
if(GP->speed != dev->speed){
LOGERR("Can't set exact speed! Opened %s at speed %d", dev->portname, dev->speed);
ERRX("Can't set speed %d (try %d)", GP->speed, dev->speed);
}
}
if(!dev) return 0;
sl_setup_con();

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 12:08+0300\n"
"POT-Creation-Date: 2026-03-04 17:48+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -77,79 +77,79 @@ msgstr ""
msgid "Can't use multiple args with arg_none!"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:267
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:268
#, c-format
msgid "double long arguments: --%s"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:273
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:274
#, c-format
msgid "double short arguments: -%c"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:343
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:347
#, c-format
msgid "Need argument with %s type\n"
msgstr ""
#. print only one message
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:435
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:439
msgid "sl_showhelp(): option index out of range"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:441
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:445
#, c-format
msgid "Usage: %s [arguments]\n"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:528
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:535
#, c-format
msgid "Wrong parameter: %s"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:532
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:539
#, c-format
msgid "%s: need argument!"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:536
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:543
#, c-format
msgid "Wrong argument \"%s\" of parameter \"%s\""
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:147
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:132
msgid "Server disconnected"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:385
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:419
msgid "Can't start server handlers thread"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:454
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:491
msgid "Limit of connections reached"
msgstr ""
#. check for RB overflow
#. -1 - buffer empty (can't be), -2 - buffer overflow
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:498
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:499
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:535
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:536
#, c-format
msgid "Server thread: ring buffer overflow for fd=%d"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:513
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:550
#, 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:525
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:562
#, c-format
msgid "Server thread: buffer overflow from fd=%d"
msgstr ""
#. never reached
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:615
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:714
#, c-format
msgid "Unsupported socket type %d"
msgstr ""
@@ -159,37 +159,43 @@ msgstr ""
msgid "Wrong USART format \"%s\"; use NPS, where N: 5..8; P: N/E/O/1/0, S: 1/2"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:102
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:105
#, c-format
msgid "Can't use port %s"
msgstr ""
#. Get settings
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:106
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:111
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:130
msgid "Can't get old TTY settings"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:119
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:124
msgid "Can't apply new TTY settings"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:124
#, c-format
msgid "Can't set speed %d, got ispeed=%d, ospeed=%d"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:130
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:136
msgid "Can't do exclusive open"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:162
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:175
msgid "Port name is missing"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:168
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:183
msgid "Need non-zero buffer for TTY device"
msgstr ""
#. Get settings
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:219
msgid "Can't get current TTY settings"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:222
#, c-format
msgid "Can't set exact speed %d"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:194
msgid "Can't open /dev/random"
msgstr ""
@@ -224,6 +230,6 @@ msgstr ""
msgid "Can't munmap"
msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:347
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:331
msgid "Can't setup console"
msgstr ""

View File

@@ -7,7 +7,7 @@
msgid ""
msgstr "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 12:08+0300\n"
"POT-Creation-Date: 2026-03-04 17:30+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -33,7 +33,7 @@ msgstr "sl_conf_showhelp():
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:322
#, c-format
msgid "Configuration file options (format: key=value):\n"
msgstr ""
msgstr "ïÐÃÉÉ ËÏÎÆÉÇÕÒÁÃÉÏÎÎÏÇÏ ÆÁÊÌÁ (ÆÏÒÍÁÔ: ËÌÀÞ=ÚÎÁÞÅÎÉÅ):\n"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/daemon.c:69
#, c-format
@@ -76,80 +76,80 @@ msgstr "
msgid "Can't use multiple args with arg_none!"
msgstr "íÁÓÓÉ× ÐÁÒÁÍÅÔÒÏ× ÎÅ ÍÏÖÅÔ ÉÍÅÔØ ÔÉÐ arg_none!"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:267
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:268
#, c-format
msgid "double long arguments: --%s"
msgstr "ÄÕÂÌÉÒÕÀÝÉÊÓÑ ÄÌÉÎÎÙÊ ÐÁÒÁÍÅÔÒ: --%s"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:273
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:274
#, c-format
msgid "double short arguments: -%c"
msgstr "ÄÕÂÌÉÒÕÀÝÉÊÓÑ ËÏÒÏÔËÉÊ ÐÁÒÁÍÅÔÒ: -%c"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:343
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:347
#, c-format
msgid "Need argument with %s type\n"
msgstr "îÅÏÂÈÏÄÉÍ ÁÒÇÕÍÅÎÔ Ó ÔÉÐÏÍ %s\n"
#. print only one message
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:435
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:439
msgid "sl_showhelp(): option index out of range"
msgstr "sl_showhelp(): ÉÎÄÅËÓ ÏÐÃÉÉ ×ÎÅ ÄÏÐÕÓÔÉÍÏÇÏ ÄÉÁÐÁÚÏÎÁ"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:441
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:445
#, c-format
msgid "Usage: %s [arguments]\n"
msgstr "éÓÐÏÌØÚÏ×ÁÎÉÅ: %s [ÁÒÇÕÍÅÎÔÙ]\n"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:528
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:535
#, c-format
msgid "Wrong parameter: %s"
msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ÐÁÒÁÍÅÔÒ: %s"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:532
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:539
#, c-format
msgid "%s: need argument!"
msgstr "%s: ÎÅÏÂÈÏÄÉÍ ÁÒÇÕÍÅÎÔ!"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:536
#: /home/eddy/Docs/SAO/C_diff/snippets_library/parseargs.c:543
#, c-format
msgid "Wrong argument \"%s\" of parameter \"%s\""
msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ÁÒÇÕÍÅÎÔ \"%s\" ÐÁÒÁÍÅÔÒÁ \"%s\""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:147
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:132
msgid "Server disconnected"
msgstr "óÅÒ×ÅÒ ÏÔËÌÀÞÅÎ"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:385
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:419
msgid "Can't start server handlers thread"
msgstr "îÅ ÍÏÇÕ ÚÁÐÕÓÔÉÔØ ÐÏÔÏË-ÏÂÒÁÂÏÔÞÉË ÓÅÒ×ÅÒÁ"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:454
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:491
msgid "Limit of connections reached"
msgstr "äÏÓÔÉÇÎÕÔ ÐÒÅÄÅÌ ÓÏÅÄÉÎÅÎÉÊ"
#. check for RB overflow
#. -1 - buffer empty (can't be), -2 - buffer overflow
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:498
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:499
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:535
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:536
#, c-format
msgid "Server thread: ring buffer overflow for fd=%d"
msgstr "ðÏÔÏË ÓÅÒ×ÅÒÁ: ÐÅÒÅÐÏÌÎÅÎÉÅ ÂÕÆÅÒÁ ÏÔ fd=%d"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:513
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:550
#, c-format
msgid "Server thread: can't write data to ringbuffer: overflow from fd=%d"
msgstr "ðÏÔÏË ÓÅÒ×ÅÒÁ: ÎÅ ÍÏÇÕ ÓÏÈÒÁÎÉÔØ ÄÁÎÎÙÅ × ËÏÌØÃÅ×ÏÍ ÂÕÆÅÒÅ, "
"ÐÅÒÅÐÏÌÎÅÎÉÅ ÏÔ fd=%d"
#. buffer overflow
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:525
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:562
#, c-format
msgid "Server thread: buffer overflow from fd=%d"
msgstr "ðÏÔÏË ÓÅÒ×ÅÒÁ: ÐÅÒÅÐÏÌÎÅÎÉÅ ÂÕÆÅÒÁ ÏÔ fd=%d"
#. never reached
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:615
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:714
#, c-format
msgid "Unsupported socket type %d"
msgstr "îÅÐÏÄÄÅÒÖÉ×ÁÅÍÙÊ ÔÉÐ ÓÏËÅÔÁ %d"
@@ -161,37 +161,44 @@ msgid "Wrong USART format \"%s\"; use NPS, where N: 5..8; P: N/E/O/1/0, S: "
msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ÆÏÒÍÁÔ USART \"%s\"; ÎÕÖÅÎ NPS, ÇÄÅ N: 5..8; P: N/E/O/"
"1/0, S: 1/2"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:102
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:105
#, c-format
msgid "Can't use port %s"
msgstr "îÅ ÍÏÇÕ ÉÓÐÏÌØÚÏ×ÁÔØ ÐÏÒÔ %s"
#. Get settings
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:106
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:111
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:130
msgid "Can't get old TTY settings"
msgstr "îÅ ÍÏÇÕ ÐÏÌÕÞÉÔØ ÄÅÊÓÔ×ÕÀÝÉÅ ÎÁÓÔÒÏÊËÉ ÐÏÒÔÁ"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:119
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:124
msgid "Can't apply new TTY settings"
msgstr "îÅ ÍÏÇÕ ÓÍÅÎÉÔØ ÎÁÓÔÒÏÊËÉ ÐÏÒÔÁ"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:124
#, c-format
msgid "Can't set speed %d, got ispeed=%d, ospeed=%d"
msgstr "îÅ ÍÏÇÕ ÓÍÅÎÉÔØ ÓËÏÒÏÓÔØ ÎÁ %d; ispeed=%d, ospeed=%d"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:130
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:136
msgid "Can't do exclusive open"
msgstr "îÅ ÍÏÇÕ ÐÅÒÅ×ÅÓÔÉ ÐÏÒÔ × ÜËÓËÌÀÚÉ×ÎÙÊ ÒÅÖÉÍ"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:162
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:175
msgid "Port name is missing"
msgstr "ïÔÓÕÔÓÔ×ÕÅÔ ÉÍÑ ÐÏÒÔÁ"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:168
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:183
msgid "Need non-zero buffer for TTY device"
msgstr "äÌÑ ÐÏÓÌÅÄÏ×ÁÔÅÌØÎÏÇÏ ÕÓÔÒÏÊÓÔ×Á ÔÒÅÂÕÅÔÓÑ ÂÕÆÅÒ ÎÅÎÕÌÅ×ÏÇÏ ÒÁÚÍÅÒÁ"
#. Get settings
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:219
#, fuzzy
msgid "Can't get current TTY settings"
msgstr "îÅ ÍÏÇÕ ÐÏÌÕÞÉÔØ ÄÅÊÓÔ×ÕÀÝÉÅ ÎÁÓÔÒÏÊËÉ ÐÏÒÔÁ"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/term2.c:222
#, fuzzy, c-format
msgid "Can't set exact speed %d"
msgstr "îÅ ÍÏÇÕ ×ÙÐÏÌÎÉÔØ stat %s"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:194
msgid "Can't open /dev/random"
msgstr "îÅ ÍÏÇÕ ÏÔËÒÙÔØ /dev/random"
@@ -226,6 +233,8 @@ msgstr "
msgid "Can't munmap"
msgstr "îÅ ÍÏÇÕ munmap"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:347
#: /home/eddy/Docs/SAO/C_diff/snippets_library/usefull_macros.c:331
msgid "Can't setup console"
msgstr "îÅ ÍÏÇÕ ÎÁÓÔÒÏÉÔØ ËÏÎÓÏÌØ"
#, c-format

View File

@@ -191,6 +191,18 @@ void *get_aptr(void *paptr, sl_argtype_e type){
return aptr[i - 1];
}
static int cmpstringp(const void *p1, const void *p2){
if(!p1 || !p2) return 0;
const char *str1 = * (char * const *) p1, *str2 = * (char * const *) p2;
if(!str1 && !str2) return 0;
else if(!str1) return 1;
else if(!str2) return -1;
return strcmp(str1, str2);
}
static int cmpcharp(const void *p1, const void *p2){
return (int)(*(char * const)p1 - *(char *const)p2);
}
/**
* @brief sl_parseargs_hf - parse arguments with user help funtion
* @param argc - amount of arguments
@@ -246,17 +258,6 @@ void sl_parseargs_hf(int *argc, char ***argv, sl_option_t *options, void (*helpf
}
}
// sort all lists & check for repeating
int cmpstringp(const void *p1, const void *p2){
if(!p1 || !p2) return 0;
const char *str1 = * (char * const *) p1, *str2 = * (char * const *) p2;
if(!str1 && !str2) return 0;
else if(!str1) return 1;
else if(!str2) return -1;
return strcmp(str1, str2);
}
int cmpcharp(const void *p1, const void *p2){
return (int)(*(char * const)p1 - *(char *const)p2);
}
qsort(longlist, optsize, sizeof(char *), cmpstringp);
qsort(shortlist,optsize, sizeof(char), cmpcharp);
char *prevl = longlist[0], prevshrt = shortlist[0];
@@ -336,7 +337,10 @@ void sl_parseargs_hf(int *argc, char ***argv, sl_option_t *options, void (*helpf
type = "string";
break;
case arg_function:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
result = ((sl_argfn_t)aptr)(optarg);
#pragma GCC diagnostic pop
break;
}
if(!result){
@@ -460,6 +464,49 @@ void sl_showhelp(int oindex, sl_option_t *options){
exit(-1);
}
static int findsubopt(char *par, sl_suboption_t *so){
int idx = 0;
if(!par) return -1;
while(so[idx].name){
if(strcasecmp(par, so[idx].name) == 0) return idx;
++idx;
}
return -1; // badarg
}
static int opt_setarg(sl_suboption_t *so, int idx, char *val){
sl_suboption_t *soptr = &so[idx];
int result = FALSE;
void *aptr = soptr->argptr;
switch(soptr->type){
default:
case arg_none:
if(soptr->argptr) *((int*)aptr) += 1; // increment value
result = TRUE;
break;
case arg_int:
result = myatoll(aptr, val, arg_int);
break;
case arg_longlong:
result = myatoll(aptr, val, arg_longlong);
break;
case arg_double:
result = myatod(aptr, val, arg_double);
break;
case arg_float:
result = myatod(aptr, val, arg_float);
break;
case arg_string:
result = (*((void**)aptr) = (void*)strdup(val)) != NULL;
break;
case arg_function:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
result = ((sl_argfn_t)aptr)(val);
#pragma GCC diagnostic pop
break;
}
return result;
}
/**
* @brief sl_get_suboption - get suboptions from parameter string
* @param str - parameter string
@@ -467,46 +514,6 @@ void sl_showhelp(int oindex, sl_option_t *options){
* @return TRUE if all OK
*/
int sl_get_suboption(char *str, sl_suboption_t *opt){
int findsubopt(char *par, sl_suboption_t *so){
int idx = 0;
if(!par) return -1;
while(so[idx].name){
if(strcasecmp(par, so[idx].name) == 0) return idx;
++idx;
}
return -1; // badarg
}
int opt_setarg(sl_suboption_t *so, int idx, char *val){
sl_suboption_t *soptr = &so[idx];
int result = FALSE;
void *aptr = soptr->argptr;
switch(soptr->type){
default:
case arg_none:
if(soptr->argptr) *((int*)aptr) += 1; // increment value
result = TRUE;
break;
case arg_int:
result = myatoll(aptr, val, arg_int);
break;
case arg_longlong:
result = myatoll(aptr, val, arg_longlong);
break;
case arg_double:
result = myatod(aptr, val, arg_double);
break;
case arg_float:
result = myatod(aptr, val, arg_float);
break;
case arg_string:
result = (*((void**)aptr) = (void*)strdup(val)) != NULL;
break;
case arg_function:
result = ((sl_argfn_t)aptr)(val);
break;
}
return result;
}
char *tok;
int ret = FALSE;
char *tmpbuf;

356
socket.c
View File

@@ -16,8 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <ctype.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <inttypes.h>
#include <netdb.h>
#include <poll.h>
#include <stdio.h>
@@ -25,7 +26,6 @@
#include <strings.h>
#include <sys/ioctl.h>
#include <sys/un.h> // unix socket
#include <inttypes.h>
#include <unistd.h>
#include "usefull_macros.h"
@@ -48,7 +48,7 @@ int sl_sock_getmaxclients(sl_sock_t *sock){
void sl_sock_maxclhandler(sl_sock_t *sock, void (*h)(int)){
if(sock) sock->toomuch_handler = h;
}
// setter of "new client connected" handler
// setter of "new client connected" han;dler
void sl_sock_connhandler(sl_sock_t *sock, int(*h)(struct sl_sock*)){
if(sock) sock->newconnect_handler = h;
}
@@ -80,21 +80,6 @@ const char *sl_sock_hresult2str(sl_sock_hresult_e r){
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
@@ -345,10 +330,59 @@ static sl_sock_hresult_e msgparser(sl_sock_t *client, char *str){
sl_sock_sendbyte(client, '\n');
return RESULT_SILENCE;
}
// check for strict params like `key=val`
for(sl_sock_hitem_t *h = client->handlers; h->handler; ++h){
if(strcmp(h->key, key)) continue;
if(h->data){
sl_sock_keyno_t *kn = (sl_sock_keyno_t*)h->data;
if(-1 == isinf(kn->magick)) kn->n = -1; // no value number
}
return h->handler(client, h, valptr);
}
// now check for optional key's number like key0=val, key[1]=val, key(2)=val or key{3}=val
int keylen = strlen(key);
char *numstart = NULL;
const char *bra = "([{", *ket = ")]}";
char *found = strchr((char*)ket, key[keylen - 1]);
DBG("found=%s", found);
if(found){
char *keyend = strchr(key, bra[found - ket]); // find starting bracket
DBG("keyend=%s", keyend);
if(keyend){
numstart = keyend + 1;
keylen = keyend - key;
}
}else{ // maybe this is key123=val ?
numstart = &key[keylen-1];
while(numstart > key && isdigit(*numstart)) --numstart;
if(numstart == &key[keylen-1]) numstart = NULL;
else{
keylen = (++numstart) - key;
DBG("numstart=%s", numstart);
}
}
if(numstart){
char *eptr;
long long LL = strtoll(numstart, &eptr, 0);
DBG("LL=%lld, len=%d", LL, keylen);
if(eptr != numstart && LL >= 0 && LL <= INT_MAX){
int parno = (int)LL;
for(sl_sock_hitem_t *h = client->handlers; h->handler; ++h){
if(strncmp(h->key, key, keylen)) continue; // now search only in first `keylen` bytes
DBG("found %s", h->key);
if(h->data){
sl_sock_keyno_t *kn = (sl_sock_keyno_t*)h->data;
if(-1 == isinf(kn->magick)){
kn->n = parno;
DBG("run handler, parno=%d", parno);
return h->handler(client, h, valptr);
}
}
DBG("NO data");
break;
}
}
}
if(client->defmsg_handler) return client->defmsg_handler(client, str);
return RESULT_BADKEY;
}
@@ -413,7 +447,9 @@ static void *serverthread(void _U_ *d){
// ZERO - listening server socket
poll_set[0].fd = sockfd;
poll_set[0].events = POLLIN;
// disconnect client
// disconnect client (no way to make this function non-nested)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
void disconnect_(sl_sock_t *c, int N){
DBG("Disconnect client \"%s\" (fd=%d)", c->IP, c->fd);
if(s->disconnect_handler) s->disconnect_handler(c);
@@ -440,6 +476,7 @@ static void *serverthread(void _U_ *d){
pthread_mutex_unlock(&c->mutex);
--nfd;
}
#pragma GCC diagnostic pop
// 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);
@@ -576,98 +613,111 @@ errex:
return NULL;
}
// convert UNIX socket name for unaddr; result should be free'd
static char *convunsname(const char *path, socklen_t *nbytes){
char *apath = MALLOC(char, UNIX_SOCK_PATH_MAX);
socklen_t len = 0;
if(*path == 0 || *path == '@'){
DBG("convert name starting from %s", (*path == 0) ? "\\0" : "@");
apath[0] = 0;
strncpy(apath+1, path+1, UNIX_SOCK_PATH_MAX-2);
len = 1 + strlen(path+1);
}else if(strncmp("\\0", path, 2) == 0){
DBG("convert name starting from \\0");
apath[0] = 0;
strncpy(apath+1, path+2, UNIX_SOCK_PATH_MAX-2);
len = 1 + strlen(path+2);
}else{
strncpy(apath, path, UNIX_SOCK_PATH_MAX-1);
len = strlen(path);
}
if(nbytes) *nbytes = len + sizeof(sa_family_t); // amount of bytes for `bind()` (parameter `len`)
return apath;
}
/**
* @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"
* @brief mknodeservice - break `path` into node name and port for INET socket
* @param path (i) - path like "node:service"
* @param node (o) - pointer to `char *` - node name
* @param service (o) - pointer to `char *` - port ("service")
*/
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;
static void mknodeservice(const char *path, char **node, char **service){
if(!path || !node || !service) return;
char *delim = strchr((char*)path, ':');
if(!delim) *service = strdup(path); // only port
else{
if(delim == path) *service = strdup(path+1);
else{
size_t l = delim - path;
*node = MALLOC(char, l + 1);
strncpy(*node, path, l);
*service = strdup(delim + 1);
}
}
}
/**
* @brief sl_sock_open - open socket, run bind or connect and return its file descriptor
* @param type - socket type
* @param path - path to UNIX-socket, port or "host:port" for INET-socket
* @param isserver - 1 for server, 0 for client
* @param socktype - custom socket type or "<1" for default (SOCK_STREAM)
* @return file descriptor or -1 if can't open
*/
int sl_sock_open(sl_socktype_e type, const char *path, int isserver, int ai_socktype){
FNAME();
if(!path || type >= SOCKT_AMOUNT) return -1;
if(ai_socktype < 1) ai_socktype = SOCK_STREAM;
int sock = -1;
struct addrinfo ai = {0}, *res = &ai;
struct sockaddr_un unaddr = {0};
char *str = NULL;
ai.ai_socktype = SOCK_STREAM;
ai.ai_socktype = ai_socktype;
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;
case SOCKT_UNIX:
{
DBG("SOCKT_UNIX");
char *str = convunsname(path, &ai.ai_addrlen);
DBG("path+1: %s", str+1);
if(!str) return -1;
unaddr.sun_family = AF_UNIX;
ai.ai_addr = (struct sockaddr*) &unaddr;
memcpy(unaddr.sun_path, str, UNIX_SOCK_PATH_MAX);
FREE(str); // don't forget!
ai.ai_family = AF_UNIX;
//ai.ai_socktype = SOCK_SEQPACKET;
}
sl_sock_t *s = MALLOC(sl_sock_t, 1);
s->type = type;
s->fd = -1;
s->maxclients = SL_DEF_MAXCLIENTS;
s->handlers = handlers;
s->buffer = sl_RB_new(bufsiz);
if(!s->buffer){
sl_sock_delete(&s);
return NULL;
}else{ // fill node/service
if(type == SOCKT_UNIX) s->node = strdup(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);
break;
case SOCKT_NET:
case SOCKT_NETLOCAL:
{
DBG("SOCKT_%s", (type == SOCKT_NET) ? "NET" : "NETLOCAL");
char *node = NULL, *service = NULL;
mknodeservice(path, &node, &service);
if(isserver){
if(!s->node){
DBG("Socket type now is SOCKT_NET");
s->type = SOCKT_NET;
}
if(s->type == SOCKT_NETLOCAL){
DBG("SOCKT_NETLOCAL: change `node` to localhost");
FREE(s->node);
s->node = strdup("127.0.0.1"); // localhost
ai.ai_flags = AI_PASSIVE;
if(type == SOCKT_NETLOCAL){
FREE(node);
node = strdup("127.0.0.1");
}
}
DBG("---> node '%s', service '%s'", s->node, s->service);
int e = getaddrinfo(s->node, s->service, &ai, &res);
ai.ai_family = AF_UNSPEC; // not AF_INET for client as there maybe problems with IPv6
int e = getaddrinfo(node, service, &ai, &res);
if(e){
WARNX("getaddrinfo(): %s", gai_strerror(e));
sl_sock_delete(&s);
return NULL;
return -1;
}
FREE(node);
FREE(service);
}
break;
default: // never reached
WARNX(_("Unsupported socket type %d"), type);
return -1;
break;
}
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((sock = socket(p->ai_family, p->ai_socktype|SOCK_NONBLOCK, p->ai_protocol)) < 0) continue;
DBG("Try proto %d, type %d, socktype %d", p->ai_protocol, p->ai_socktype, p->ai_socktype);
if(isserver){
int reuseaddr = 1;
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)) == -1){
@@ -688,30 +738,80 @@ static sl_sock_t *sl_sock_open(sl_socktype_e type, const char *path, sl_sock_hit
if(connect(sock, p->ai_addr, p->ai_addrlen) == -1){
WARN("connect()");
close(sock); sock = -1;
continue;
}
}
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(type != SOCKT_UNIX) freeaddrinfo(res); // don't forget to free memory allocated with getaddrinfo
return sock;
}
/**
* @brief sl_sock_run - open socket and run thread (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_run(sl_socktype_e type, const char *path, sl_sock_hitem_t *handlers, int bufsiz, int isserver){
FNAME();
if(bufsiz < 256) bufsiz = 256;
int sock = sl_sock_open(type, path, isserver, 0);
if(sock < 0) return NULL;
sl_sock_t *s = MALLOC(sl_sock_t, 1);
s->type = type;
s->fd = -1;
s->maxclients = SL_DEF_MAXCLIENTS;
s->handlers = handlers;
s->buffer = sl_RB_new(bufsiz);
if(!s->buffer){
sl_sock_delete(&s);
return NULL;
}else{ // fill node/service
if(type == SOCKT_UNIX) s->node = strdup(path); // str now is path copy
else{
mknodeservice(path, &s->node, &s->service);
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);
if(isserver){
if(s->handlers || s->defmsg_handler)
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);
if(!s->node){
DBG("Socket type now is SOCKT_NET");
s->type = SOCKT_NET;
}
if(s->type == SOCKT_NETLOCAL){
DBG("SOCKT_NETLOCAL: change `node` to localhost");
FREE(s->node);
s->node = strdup("127.0.0.1"); // localhost
}
}
DBG("---> node '%s', service '%s'", s->node, s->service);
}
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 || s->defmsg_handler)
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;
}
@@ -725,7 +825,7 @@ static sl_sock_t *sl_sock_open(sl_socktype_e type, const char *path, sl_sock_hit
* @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);
sl_sock_t *s = sl_sock_run(type, path, NULL, bufsiz, 0);
return s;
}
@@ -738,7 +838,7 @@ sl_sock_t *sl_sock_run_client(sl_socktype_e type, const char *path, int bufsiz){
* @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);
sl_sock_t *s = sl_sock_run(type, path, handlers, bufsiz, 1);
return s;
}
@@ -826,6 +926,7 @@ ssize_t sl_sock_readline(sl_sock_t *sock, char *str, size_t len){
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(!i) return RESULT_FAIL;
if(!str){ // getter
snprintf(buf, 127, "%s=%" PRId64 "\n", hitem->key, i->val);
sl_sock_sendstrmessage(client, buf);
@@ -841,6 +942,7 @@ sl_sock_hresult_e sl_sock_inthandler(sl_sock_t *client, sl_sock_hitem_t *hitem,
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(!d) return RESULT_FAIL;
if(!str){ // getter
snprintf(buf, 127, "%s=%g\n", hitem->key, d->val);
sl_sock_sendstrmessage(client, buf);
@@ -855,6 +957,7 @@ sl_sock_hresult_e sl_sock_dblhandler(sl_sock_t *client, sl_sock_hitem_t *hitem,
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(!s) return RESULT_FAIL;
if(!str){ // getter
snprintf(buf, SL_VAL_LEN + SL_KEY_LEN + 2, "%s=%s\n", hitem->key, s->val);
sl_sock_sendstrmessage(client, buf);
@@ -868,3 +971,24 @@ sl_sock_hresult_e sl_sock_strhandler(sl_sock_t *client, sl_sock_hitem_t *hitem,
s->val[l] = 0;
return RESULT_OK;
}
/**
* @brief sl_sock_keyno_init - init k->magick and k-> to default values
* @param k - key's number value
*/
void sl_sock_keyno_init(sl_sock_keyno_t* k){
if(!k) return;
k->magick = -INFINITY;
k->n = -1;
}
/**
* @brief sl_sock_keyno_check - check if this is a really `sl_sock_keyno_t`
* @param k - pointer to check
* @return k.n or -1 if failed
*/
int sl_sock_keyno_check(sl_sock_keyno_t* k){
DBG("magick=%g (%d)", k->magick, isinf(k->magick));
if(!k || -1 != isinf(k->magick)) return -1;
DBG("k->n=%d", k->n);
return k->n;
}

113
term2.c
View File

@@ -89,47 +89,57 @@ someerr:
}
/**
* @brief tty_init - open & setup terminal
* @param descr (io) - port descriptor
* !!! default settings are "8N1".
* !!! If you want other, set it like `descr->format = "7O2"` between `sl_tty_new` and `sl_tty_open`
* @return 0 if all OK, last error code or 1
* @brief sl_tty_fdescr - open terminal device and give it's file descriptor
* @param comdev - path to device
* @param speed - baudrate
* @param exclusive - ==1 for exclusive open
* @return fd or -1 in case of error
*/
static int tty_init(sl_tty_t *descr){
int sl_tty_fdescr(const char *comdev, const char *format, int speed, int exclusive){
if(!comdev || speed < 1) return -1;
tcflag_t flags;
if(!parse_format(descr->format, &flags)) return 1;
if((descr->comfd = open(descr->portname, O_RDWR|O_NOCTTY)) < 0){
WARN(_("Can't use port %s"), descr->portname);
return globErr ? globErr : 1;
if(!parse_format(format, &flags)) return -1;
DBG("open");
int comfd = open(comdev, O_RDWR|O_NOCTTY);
if(comfd < 0){
WARN(_("Can't use port %s"), comdev);
return -1;
}
if(ioctl(descr->comfd, TCGETS2, &descr->oldtty)){ // Get settings
DBG("fd=%d", comfd);
struct termios2 newtty;
if(ioctl(comfd, TCGETS2, &newtty)){ // Get settings
WARN(_("Can't get old TTY settings"));
return globErr ? globErr : 1;
return -1;
}
descr->tty = descr->oldtty;
descr->tty.c_lflag = 0; // ~(ICANON | ECHO | ECHOE | ISIG)
descr->tty.c_iflag = 0; // don't do any changes in input stream
descr->tty.c_oflag = 0; // don't do any changes in output stream
descr->tty.c_cflag = BOTHER | flags | CREAD | CLOCAL; // other speed, user format, RW, ignore line ctrl
descr->tty.c_ispeed = descr->speed;
descr->tty.c_ospeed = descr->speed;
descr->tty.c_cc[VMIN] = 0; // non-canonical mode
descr->tty.c_cc[VTIME] = 5;
if(ioctl(descr->comfd, TCSETS2, &descr->tty)){
DBG("change termios flags");
newtty.c_lflag = 0; // ~(ICANON | ECHO | ECHOE | ISIG)
newtty.c_iflag = 0; // don't do any changes in input stream
newtty.c_oflag = 0; // don't do any changes in output stream
newtty.c_cflag = BOTHER | flags | CREAD | CLOCAL; // other speed, user format, RW, ignore line ctrl
newtty.c_ispeed = speed;
newtty.c_ospeed = speed;
newtty.c_cc[VMIN] = 0; // non-canonical mode
newtty.c_cc[VTIME] = 1;
if(ioctl(comfd, TCSETS2, &newtty)){
WARN(_("Can't apply new TTY settings"));
return globErr ? globErr : 1;
close(comfd);
return -1;
}
ioctl(descr->comfd, TCGETS2, &descr->tty);
if(descr->tty.c_ispeed != (speed_t)descr->speed || descr->tty.c_ospeed != (speed_t)descr->speed){
WARN(_("Can't set speed %d, got ispeed=%d, ospeed=%d"), descr->speed, descr->tty.c_ispeed, descr->tty.c_ospeed);
descr->speed = descr->tty.c_ispeed;
DBG("OK, check");
if(ioctl(comfd, TCGETS2, &newtty)){ // Get settings
WARN(_("Can't get old TTY settings"));
return -1;
}
// make exclusive open
if(descr->exclusive){
if(ioctl(descr->comfd, TIOCEXCL)){
if(exclusive){
DBG("make exclusive");
if(ioctl(comfd, TIOCEXCL)){
WARN(_("Can't do exclusive open"));
}}
return 0;
close(comfd);
return -1;
}
}
DBG("device %s opened", comdev);
return comfd;
}
/**
@@ -138,13 +148,16 @@ static int tty_init(sl_tty_t *descr){
void sl_tty_close(sl_tty_t **descr){
if(descr == NULL || *descr == NULL) return;
sl_tty_t *d = *descr;
if(d->comfd){
ioctl(d->comfd, TCSETS2, &d->oldtty); // return TTY to previous state
if(d->comfd > -1){
DBG("close");
close(d->comfd);
}
DBG("Free mem");
FREE(d->portname);
FREE(d->buf);
FREE(d->format);
FREE(*descr);
DBG("tty closed");
}
/**
@@ -164,6 +177,8 @@ sl_tty_t *sl_tty_new(char *comdev, int speed, size_t bufsz){
if(bufsz){
descr->buf = MALLOC(char, bufsz+1);
descr->bufsz = bufsz;
descr->comfd = -1;
DBG("sl_tty_t created");
return descr;
}else WARNX(_("Need non-zero buffer for TTY device"));
}
@@ -172,6 +187,20 @@ sl_tty_t *sl_tty_new(char *comdev, int speed, size_t bufsz){
return NULL;
}
/**
* @brief sl_tty_setformat - set format for just created tty object
* @param d - descriptor created with sl_tty_new
* @param format - string like "7O2" (maybe NULL for default, 8N1)
* @return FALSE if format is wrong
*/
int sl_tty_setformat(sl_tty_t *d, const char *format){
if(!d) return FALSE;
if(!format) return TRUE; // default format
if(!parse_format(format, NULL)) return FALSE;
d->format = strdup(format);
return TRUE;
}
/**
* @brief sl_tty_open - init & open tty device
* @param d - already filled structure (with new_tty or by hands)
@@ -182,13 +211,27 @@ sl_tty_t *sl_tty_open(sl_tty_t *d, int exclusive){
if(!d || !d->portname) return NULL;
if(exclusive) d->exclusive = TRUE;
else d->exclusive = FALSE;
if(tty_init(d)) return NULL;
DBG("ex: %d", exclusive);
int comfd = sl_tty_fdescr(d->portname, d->format, d->speed, d->exclusive);
if(comfd < 0) return NULL;
struct termios2 tty;
if(ioctl(comfd, TCGETS2, &tty)){ // Get settings
WARN(_("Can't get current TTY settings"));
}else{
if(d->speed != (int)tty.c_ispeed || d->speed != (int)tty.c_ospeed){
WARNX(_("Can't set exact speed %d"), d->speed);
d->speed = (int)tty.c_ispeed;
}
}
d->comfd = comfd;
DBG("sl_tty_t ready");
return d;
}
static struct timeval tvdefault = {.tv_sec = 0, .tv_usec = 5000};
/**
* @brief sl_tty_tmout - set timeout for select() on reading
* // WARNING! This function changes timeout for ALL opened ports!
* @param usec - microseconds of timeout
* @return -1 if usec < 0, 0 if all OK
*/

View File

@@ -308,22 +308,14 @@ char *sl_omitspacesr(const char *v){
* BE CAREFULL! These functions aren't thread-safe!
\******************************************************************************/
// console flags
#ifndef SL_USE_OLD_TTY
static struct termios2 oldt, newt;
#else
static struct termios oldt, newt;
#endif
static int console_changed = 0;
/**
* @brief sl_restore_con - restore console to default mode
*/
void sl_restore_con(){
if(console_changed)
#ifndef SL_USE_OLD_TTY
ioctl(STDIN_FILENO, TCSETS2, &oldt);
#else
tcsetattr(STDIN_FILENO, TCSANOW, &oldt); // return terminal to previous state
#endif
console_changed = 0;
}
@@ -332,24 +324,12 @@ void sl_restore_con(){
*/
void sl_setup_con(){
if(console_changed) return;
#ifndef SL_USE_OLD_TTY
ioctl(STDIN_FILENO, TCGETS2, &oldt);
#else
tcgetattr(STDIN_FILENO, &oldt);
#endif
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
#ifndef SL_USE_OLD_TTY
if(ioctl(STDIN_FILENO, TCSETS2, &newt)){
#else
if(tcsetattr(STDIN_FILENO, TCSANOW, &newt) < 0){
#endif
WARN(_("Can't setup console"));
#ifndef SL_USE_OLD_TTY
ioctl(STDIN_FILENO, TCSETS2, &oldt);
#else
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
#endif
signals(1); //quit?
}
console_changed = 1;

View File

@@ -22,11 +22,7 @@
#pragma once
#include <stdio.h>
#ifdef SL_USE_OLD_TTY
#include <termios.h> // termios
#else
#include <asm-generic/termbits.h>
#endif
#include <errno.h> // errno
#include <netdb.h> // struct addrinfo
@@ -36,6 +32,7 @@
#include <unistd.h> // pid_t
// just for different purposes
#include <limits.h>
#include <math.h> // inf/isinf
#include <stdint.h>
#if defined GETTEXT
@@ -166,42 +163,25 @@ int sl_canwrite(int fd);
/******************************************************************************\
The original term.h
\******************************************************************************/
#ifdef SL_USE_OLD_TTY
typedef struct {
char *portname; // device filename (should be freed before structure freeing)
int speed; // baudrate in human-readable format
tcflag_t baudrate; // baudrate (B...)
struct termios oldtty; // TTY flags for previous port settings
struct termios tty; // TTY flags for current settings
int comfd; // TTY file descriptor
char *buf; // buffer for data read
size_t bufsz; // size of buf
size_t buflen; // length of data read into buf
int exclusive; // should device be exclusive opened
} sl_tty_t;
tcflag_t sl_tty_convspd(int speed);
#else
typedef struct {
char *portname; // device filename (should be freed before structure freeing)
int speed; // baudrate in human-readable format
char *format; // format like 8N1
struct termios2 oldtty; // TTY flags for previous port settings
struct termios2 tty; // TTY flags for current settings
int comfd; // TTY file descriptor
char *buf; // buffer for data read
size_t bufsz; // size of buf
size_t buflen; // length of data read into buf
int exclusive; // should device be exclusive opened
} sl_tty_t;
#endif
void sl_tty_close(sl_tty_t **descr);
int sl_tty_fdescr(const char *comdev, const char *format, int speed, int exclusive);
sl_tty_t *sl_tty_new(char *comdev, int speed, size_t bufsz);
int sl_tty_setformat(sl_tty_t *d, const char *format);
sl_tty_t *sl_tty_open(sl_tty_t *d, int exclusive);
int sl_tty_read(sl_tty_t *descr);
int sl_tty_tmout(double usec);
int sl_tty_read(sl_tty_t *descr);
int sl_tty_write(int comfd, const char *buff, size_t length);
void sl_tty_close(sl_tty_t **descr);
/******************************************************************************\
Logging
@@ -417,6 +397,8 @@ size_t sl_RB_writestr(sl_ringbuffer_t *b, char *s);
/******************************************************************************\
The original socket.h
\******************************************************************************/
// max length (including trailing '\0') of UNIX socket path
#define UNIX_SOCK_PATH_MAX 108
// handler result: what to send to client
typedef enum{
@@ -445,6 +427,15 @@ typedef struct{
int len; // strlen of `val`
} sl_sock_string_t;
// optional keyword number like key[12] = 500
typedef struct{
double magick; // -Inf - to distinguish it from sl_sock_*_t
int n; // if n < 0 there was no any number in `key`
} sl_sock_keyno_t;
#define SL_SOCK_KEYNO_DEFAULT {.magick = -INFINITY, .n = -1}
void sl_sock_keyno_init(sl_sock_keyno_t*);
int sl_sock_keyno_check(sl_sock_keyno_t*);
struct sl_sock_hitem;
struct sl_sock;
@@ -468,6 +459,9 @@ typedef enum{
struct sl_sock;
// opent socket and return its file descriptor
int sl_sock_open(sl_socktype_e type, const char *path, int isserver, int ai_socktype);
// default max clients amount
#define SL_DEF_MAXCLIENTS (32)
// custom socket handlers: connect/disconnect/etc
@@ -535,4 +529,3 @@ int sl_sock_sendall(sl_sock_t *sock, 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);