diff --git a/CMakeLists.txt b/CMakeLists.txt index 67cc5ff..5398c4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 4.0) set(PROJ usefull_macros) -set(MINOR_VERSION "4") +set(MINOR_VERSION "5") set(MID_VERSION "3") set(MAJOR_VERSION "0") set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}") @@ -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) diff --git a/Changelog b/Changelog index 47eb83c..ec9dea2 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,18 @@ +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: diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 9a2daef..e168602 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -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) diff --git a/examples/options.c b/examples/options.c index bf355b7..1642da0 100644 --- a/examples/options.c +++ b/examples/options.c @@ -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(); diff --git a/locale/ru/LC_MESSAGES/usefull_macros.mo b/locale/ru/LC_MESSAGES/usefull_macros.mo index e0c1c4b..900529a 100644 Binary files a/locale/ru/LC_MESSAGES/usefull_macros.mo and b/locale/ru/LC_MESSAGES/usefull_macros.mo differ diff --git a/locale/ru/messages.po b/locale/ru/messages.po index f3cd849..51651b7 100644 --- a/locale/ru/messages.po +++ b/locale/ru/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-03-04 09:05+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 \n" "Language-Team: LANGUAGE \n" @@ -117,39 +117,39 @@ msgstr "" msgid "Wrong argument \"%s\" of parameter \"%s\"" msgstr "" -#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:154 +#: /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:441 +#: /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:513 +#: /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:557 -#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:558 +#: /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:572 +#: /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:584 +#: /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:681 +#: /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 "" diff --git a/locale/ru/ru.po b/locale/ru/ru.po index 2621218..a99b630 100644 --- a/locale/ru/ru.po +++ b/locale/ru/ru.po @@ -7,7 +7,7 @@ msgid "" msgstr "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" - "POT-Creation-Date: 2026-03-04 09:01+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 \n" "Language-Team: LANGUAGE \n" @@ -116,40 +116,40 @@ msgstr "%s: msgid "Wrong argument \"%s\" of parameter \"%s\"" msgstr "Неправильный аргумент \"%s\" параметра \"%s\"" -#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:154 +#: /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:441 +#: /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:513 +#: /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:557 -#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:558 +#: /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:572 +#: /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:584 +#: /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:681 +#: /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 diff --git a/socket.c b/socket.c index 9b9900a..e54f9d0 100644 --- a/socket.c +++ b/socket.c @@ -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,28 +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, socklen_t *nbytes){ - char *apath = MALLOC(char, UNIX_SOCK_PATH_MAX); - socklen_t len = 0; - if(*path == 0){ - DBG("convert name starting from 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_delete - close socket and delete descriptor * @param sock - pointer to socket descriptor @@ -635,104 +613,110 @@ 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; - printf("OPen\n"); +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(bufsiz < 256) bufsiz = 256; + 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}; - ai.ai_socktype = SOCK_STREAM; + ai.ai_socktype = ai_socktype; switch(type){ - case SOCKT_UNIX: + case SOCKT_UNIX: + { DBG("SOCKT_UNIX"); - { - char *str = convunsname(path, &ai.ai_addrlen); - DBG("path+1: %s", str+1); - if(!str) return NULL; - 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; - } - break; - case SOCKT_NET: - case SOCKT_NETLOCAL: - if(isserver){ - ai.ai_flags = AI_PASSIVE; - //ai.ai_family = AF_INET; - }// else - ai.ai_family = AF_UNSPEC; // not AF_INET for client as there maybe problems with IPv6 - break; - default: // never reached - WARNX(_("Unsupported socket type %d"), type); - return NULL; - break; + 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(path); // str now is path copy - else{ - char *delim = strchr((char*)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; + 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; @@ -760,26 +744,74 @@ static sl_sock_t *sl_sock_open(sl_socktype_e type, const char *path, sl_sock_hit break; } if(type != SOCKT_UNIX) freeaddrinfo(res); // don't forget to free memory allocated with getaddrinfo - 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; + 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; } @@ -793,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; } @@ -806,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; } diff --git a/term2.c b/term2.c index 0c17720..790c3aa 100644 --- a/term2.c +++ b/term2.c @@ -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 */ diff --git a/usefull_macros.c b/usefull_macros.c index c31ef0c..6a46ba4 100644 --- a/usefull_macros.c +++ b/usefull_macros.c @@ -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; diff --git a/usefull_macros.h b/usefull_macros.h index 6172e19..eebf855 100644 --- a/usefull_macros.h +++ b/usefull_macros.h @@ -22,11 +22,7 @@ #pragma once #include -#ifdef SL_USE_OLD_TTY -#include // termios -#else #include -#endif #include // errno #include // struct addrinfo @@ -167,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 @@ -481,7 +460,7 @@ typedef enum{ struct sl_sock; // opent socket and return its file descriptor -int sl_sock_getfd(sl_socktype_e type, const char *path); +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)