From 76a1ec0e81221fb54f93f85004d05ad5b30c5c21 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Fri, 11 Mar 2022 17:01:59 +0300 Subject: [PATCH] add socket snippet --- Socket_CAN/socketcan0 | 4 + Socket_snippet/Makefile | 45 +++++ Socket_snippet/Readme.md | 7 + Socket_snippet/client.c | 120 +++++++++++++ Socket_snippet/client.h | 26 +++ Socket_snippet/cmdlnopts.c | 83 +++++++++ Socket_snippet/cmdlnopts.h | 40 +++++ Socket_snippet/main.c | 108 ++++++++++++ Socket_snippet/server.c | 150 +++++++++++++++++ Socket_snippet/server.h | 26 +++ Socket_snippet/socket | Bin 0 -> 27376 bytes Socket_snippet/socket.c | 213 ++++++++++++++++++++++++ Socket_snippet/socket.h | 56 +++++++ Socket_snippet/socksnippet.cflags | 1 + Socket_snippet/socksnippet.config | 6 + Socket_snippet/socksnippet.creator | 1 + Socket_snippet/socksnippet.creator.user | 163 ++++++++++++++++++ Socket_snippet/socksnippet.cxxflags | 1 + Socket_snippet/socksnippet.files | 9 + Socket_snippet/socksnippet.includes | 1 + Socket_snippet/testcommands | 11 ++ 21 files changed, 1071 insertions(+) create mode 100755 Socket_CAN/socketcan0 create mode 100644 Socket_snippet/Makefile create mode 100644 Socket_snippet/Readme.md create mode 100644 Socket_snippet/client.c create mode 100644 Socket_snippet/client.h create mode 100644 Socket_snippet/cmdlnopts.c create mode 100644 Socket_snippet/cmdlnopts.h create mode 100644 Socket_snippet/main.c create mode 100644 Socket_snippet/server.c create mode 100644 Socket_snippet/server.h create mode 100755 Socket_snippet/socket create mode 100644 Socket_snippet/socket.c create mode 100644 Socket_snippet/socket.h create mode 100644 Socket_snippet/socksnippet.cflags create mode 100644 Socket_snippet/socksnippet.config create mode 100644 Socket_snippet/socksnippet.creator create mode 100644 Socket_snippet/socksnippet.creator.user create mode 100644 Socket_snippet/socksnippet.cxxflags create mode 100644 Socket_snippet/socksnippet.files create mode 100644 Socket_snippet/socksnippet.includes create mode 100644 Socket_snippet/testcommands diff --git a/Socket_CAN/socketcan0 b/Socket_CAN/socketcan0 new file mode 100755 index 0000000..8f28a6d --- /dev/null +++ b/Socket_CAN/socketcan0 @@ -0,0 +1,4 @@ +#!/bin/sh + +ip link set can0 type can bitrate 100000 triple-sampling on +ifconfig can0 up diff --git a/Socket_snippet/Makefile b/Socket_snippet/Makefile new file mode 100644 index 0000000..e67b9e9 --- /dev/null +++ b/Socket_snippet/Makefile @@ -0,0 +1,45 @@ +# run `make DEF=...` to add extra defines +PROGRAM := socket +LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all +LDFLAGS += -lusefull_macros -lm -L/usr/local/lib/ +SRCS := $(wildcard *.c) +DEFINES := $(DEF) -D_GNU_SOURCE -D_XOPEN_SOURCE=1111 +OBJDIR := mk +CFLAGS += -O3 -Wno-trampolines -std=gnu99 +OBJS := $(addprefix $(OBJDIR)/, $(SRCS:%.c=%.o)) +DEPS := $(OBJS:.o=.d) +CC = gcc +#CXX = g++ + + +all : $(PROGRAM) + +debug: CFLAGS += -DEBUG -Werror -Wall -Wextra +debug: all + +$(OBJS): $(OBJDIR) + +$(PROGRAM) : $(OBJS) + @echo -e "\t\tLD $(PROGRAM)" + $(CC) $(OBJS) $(LDFLAGS) -o $(PROGRAM) + +$(OBJDIR): + mkdir $(OBJDIR) + +ifneq ($(MAKECMDGOALS),clean) +-include $(DEPS) +endif + +$(OBJDIR)/%.o: %.c + @echo -e "\t\tCC $<" + $(CC) $< -MD -c $(CFLAGS) $(DEFINES) -o $@ + +clean: + @echo -e "\t\tCLEAN" + @rm -f $(OBJS) $(DEPS) + @rmdir $(OBJDIR) 2>/dev/null || true + +xclean: clean + @rm -f $(PROGRAM) + +.PHONY: clean xclean diff --git a/Socket_snippet/Readme.md b/Socket_snippet/Readme.md new file mode 100644 index 0000000..3af0afd --- /dev/null +++ b/Socket_snippet/Readme.md @@ -0,0 +1,7 @@ +Socket server and client snippet +================================ + +This snippet allows to create some utilities than can be run both in client or server mode. +The sockets are **local** TCP or UNIX sockets. Server-side polling use `poll()`. + +The pieces of user code may be in comments marked `USERCODE` \ No newline at end of file diff --git a/Socket_snippet/client.c b/Socket_snippet/client.c new file mode 100644 index 0000000..d50e5e5 --- /dev/null +++ b/Socket_snippet/client.c @@ -0,0 +1,120 @@ +/* + * This file is part of the socksnippet project. + * Copyright 2022 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +// client-side functions +#include +#include +#include +#include + +#include "client.h" +#include "socket.h" + +/** + * @brief processData - process here some actions and make messages for server + * @param buf (o) - buffer for answer + * @param l - max length of buf + * @return amount of answer bytes + */ +static int process_data(char *buf, int l){ + if(!buf || !l) return 0; + /* USERCODE: get here some data to send */ + static double t0 = 0.; + if(dtime() - t0 > 1.){ + t0 = dtime(); + // send random commands each 1 second + int x = rand() % 600; + const char *cmd = NULL; + if(x < 100) cmd = "time"; + else if(x < 200) cmd = "getval1"; + else if(x < 300) cmd = "getval2"; + else if(x < 400) cmd = "ping"; + if(cmd) snprintf(buf, l, "%s", cmd); + else{ + if(x < 500) snprintf(buf, l, "setval1=%d", rand() & 0xff); + else snprintf(buf, l, "setval2=%d", rand() & 0xff); + } + return strlen(buf); + } + return 0; +} + +/** + * @brief process_server_message - parse messages from server and make an answer + * @param buf (io) - incoming message (the answer will be in this buffer) + * @param l - buff max length + * @return amount of answer bytes + */ +static int process_server_message(char *buf, int l){ + /* USERCODE inside this funtion */ + if(!buf || !l) return 0; + // just show on screen + green("SERVER send: %s\n", buf); + return 0; +} + + +/** + * check data from fd (polling function for client) + * @param fd - file descriptor + * @return 0 in case of timeout, 1 in case of fd have data, -1 if error + */ +static int canberead(int fd){ + fd_set fds; + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 100; + FD_ZERO(&fds); + FD_SET(fd, &fds); + do{ + int rc = select(fd+1, &fds, NULL, NULL, &timeout); + if(rc < 0){ + if(errno != EINTR){ + LOGWARN("select()"); + WARN("select()"); + return -1; + } + continue; + } + break; + }while(1); + if(FD_ISSET(fd, &fds)){ + //DBG("FD_ISSET"); + return 1; + } + return 0; +} + +void client(int sock){ + char buf[BUFLEN]; + while(1){ + int l = process_data(buf, BUFLEN-1); + if(l) sendmessage(sock, buf, l); + if(1 != canberead(sock)) continue; + int n = read(sock, buf, BUFLEN-1); + if(n == 0){ + WARNX("Server disconnected"); + signals(0); + } + buf[n] = 0; + DBG("Got from server: %s", buf); + LOGMSG("Got from server: %s", buf); + l = process_server_message(buf, n); + if(l) sendmessage(sock, buf, l); + } +} diff --git a/Socket_snippet/client.h b/Socket_snippet/client.h new file mode 100644 index 0000000..0ce68fc --- /dev/null +++ b/Socket_snippet/client.h @@ -0,0 +1,26 @@ +/* + * This file is part of the socksnippet project. + * Copyright 2022 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#ifndef CLIENT_H__ +#define CLIENT_H__ + +// client-side functions +void client(int fd); + +#endif // CLIENT_H__ diff --git a/Socket_snippet/cmdlnopts.c b/Socket_snippet/cmdlnopts.c new file mode 100644 index 0000000..f106d49 --- /dev/null +++ b/Socket_snippet/cmdlnopts.c @@ -0,0 +1,83 @@ +/* + * This file is part of the socksnippet project. + * Copyright 2022 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "cmdlnopts.h" +#include "usefull_macros.h" + +// default PID filename: +#define DEFAULT_PIDFILE "/tmp/usbsock.pid" + +static int help; +static glob_pars G = { + .pidfile = DEFAULT_PIDFILE, +}; +glob_pars *GP = &G; + +/* + * Define command line options by filling structure: + * name has_arg flag val type argptr help +*/ +static myoption cmdlnopts[] = { + {"help", NO_ARGS, NULL, 'h', arg_int, APTR(&help), _("show this help")}, + {"logfile", NEED_ARG, NULL, 'l', arg_string, APTR(&G.logfile), _("file to save logs (default: none)")}, + {"pidfile", NEED_ARG, NULL, 'p', arg_string, APTR(&G.pidfile), _("pidfile (default: " DEFAULT_PIDFILE ")")}, + {"client", NO_ARGS, NULL, 'c', arg_int, APTR(&G.client), _("run as client")}, + {"path", NEED_ARG, NULL, 'N', arg_string, APTR(&G.path), _("UNIX socket path/name (start from \\0 for no files)")}, + {"port", NEED_ARG, NULL, 'P', arg_string, APTR(&G.port), _("port to connect (for local TCP socket)")}, + {"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&G.verbose), _("increase log verbose level (default: LOG_WARN) and messages (default: none)")}, + end_option +}; + +/** + * Parse command line options and return dynamically allocated structure + * to global parameters + * @param argc - copy of argc from main + * @param argv - copy of argv from main + * @return allocated structure with global parameters + */ +void parse_args(int argc, char **argv){ + int i; + size_t hlen = 1024; + char helpstring[1024], *hptr = helpstring; + snprintf(hptr, hlen, "Usage: %%s [args]\n\n\tWhere args are:\n"); + // format of help: "Usage: progname [args]\n" + change_helpstring(helpstring); + // parse arguments + parseargs(&argc, &argv, cmdlnopts); + for(i = 0; i < argc; i++) + printf("Ignore parameter\t%s\n", argv[i]); + if(help) showhelp(-1, cmdlnopts); +} + +/** + * @brief verbose - print additional messages depending of G.verbose (add '\n' at end) + * @param levl - message level + * @param fmt - message + */ +void verbose(int levl, const char *fmt, ...){ + va_list ar; + if(levl > G.verbose) return; + va_start(ar, fmt); + vprintf(fmt, ar); + va_end(ar); + printf("\n"); +} diff --git a/Socket_snippet/cmdlnopts.h b/Socket_snippet/cmdlnopts.h new file mode 100644 index 0000000..da8945f --- /dev/null +++ b/Socket_snippet/cmdlnopts.h @@ -0,0 +1,40 @@ +/* + * This file is part of the socksnippet project. + * Copyright 2022 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#ifndef CMDLNOPTS_H__ +#define CMDLNOPTS_H__ + +/* + * here are some typedef's for global data + */ +typedef struct{ + char *pidfile; // name of PID file + char *logfile; // logging to this file + char *path; // path to UNIX-socket file + char *port; // local TCP socket port + int verbose; // verbose level: for messages & logging + int client; // ==1 if application runs in client mode +} glob_pars; + +extern glob_pars *GP; + +void parse_args(int argc, char **argv); +void verbose(int levl, const char *fmt, ...); + +#endif // CMDLNOPTS_H__ diff --git a/Socket_snippet/main.c b/Socket_snippet/main.c new file mode 100644 index 0000000..8f75fa8 --- /dev/null +++ b/Socket_snippet/main.c @@ -0,0 +1,108 @@ +/* + * This file is part of the socksnippet project. + * Copyright 2022 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "cmdlnopts.h" +#include "socket.h" + +static pid_t childpid = 0; +static int isserver = 1; + +void signals(int sig){ + if(childpid){ // slave process + DBG("Child killed with sig=%d", sig); + LOGWARN("Child killed with sig=%d", sig); + exit(sig); + } + // master process + DBG("Master process"); + if(sig){ + DBG("Exit with signal %d", sig); + signal(sig, SIG_IGN); + LOGERR("Exit with signal %d", sig); + }else LOGERR("Exit"); + if(GP->pidfile && isserver){ + DBG("Unlink pid file"); + unlink(GP->pidfile); + } + exit(sig); +} + +int main(int argc, char **argv){ + char *self = strdup(argv[0]); + initial_setup(); + parse_args(argc, argv); + if(GP->logfile){ + int lvl = LOGLEVEL_WARN + GP->verbose; + DBG("level = %d", lvl); + if(lvl > LOGLEVEL_ANY) lvl = LOGLEVEL_ANY; + verbose(1, "Log file %s @ level %d\n", GP->logfile, lvl); + OPENLOG(GP->logfile, lvl, 1); + if(!globlog) WARNX("Can't create log file"); + } + if(GP->client) isserver = 0; + if(GP->port){ + if(GP->path){ + WARNX("Options `port` and `path` can't be used together! Point `port` for TCP socket or `path` for UNIX."); + return 1; + } + int port = atoi(GP->port); + if(port < PORTN_MIN || port > PORTN_MAX){ + WARNX("Wrong port value: %d", port); + return 1; + } + }else if(!GP->path) ERRX("You should point option `port` or `path`!"); + + if(isserver) check4running(self, GP->pidfile); + // signal reactions: + signal(SIGTERM, signals); // kill (-15) - quit + signal(SIGHUP, SIG_IGN); // hup - ignore + signal(SIGINT, signals); // ctrl+C - quit + signal(SIGQUIT, signals); // ctrl+\ - quit + signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z + LOGMSG("Started"); +#ifndef EBUG + if(isserver){ + unsigned int pause = 5; + while(1){ + childpid = fork(); + if(childpid){ // master + double t0 = dtime(); + LOGMSG("Created child with pid %d", childpid); + wait(NULL); + LOGWARN("Child %d died", childpid); + if(dtime() - t0 < 1.) pause += 5; + else pause = 1; + if(pause > 900) pause = 900; + sleep(pause); // wait a little before respawn + }else{ // slave + prctl(PR_SET_PDEATHSIG, SIGTERM); // send SIGTERM to child when parent dies + break; + } + } + } +#endif + if(GP->path) return start_socket(isserver, GP->path, FALSE); + if(GP->port) return start_socket(isserver, GP->port, TRUE); +} diff --git a/Socket_snippet/server.c b/Socket_snippet/server.c new file mode 100644 index 0000000..8f38bc0 --- /dev/null +++ b/Socket_snippet/server.c @@ -0,0 +1,150 @@ +/* + * This file is part of the socksnippet project. + * Copyright 2022 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "server.h" +#include "socket.h" + +// server-side functions + +// command handlers +hresult pinghandler(int fd, _U_ const char *key, _U_ const char *val){ + sendstrmessage(fd, "PING"); + return RESULT_SILENCE; +} + +static int sendtime = 0; +hresult timehandler(_U_ int fd, _U_ const char *key, _U_ const char *val){ + sendtime = 1; + return RESULT_OK; +} + +static int value1 = 0, value2 = 0; +hresult valsethandler(_U_ int fd, const char *key, const char *val){ + if(!val || !*val) return RESULT_BADVAL; + int i = atoi(val); + if(i < -65535 || i > 65535) return RESULT_BADVAL; + if(strcmp(key, "setval1") == 0) value1 = i; + else value2 = i; + return RESULT_OK; +} +hresult valgethandler(int fd, const char *key, _U_ const char *val){ + char buf[32]; + if(strcmp(key, "getval1") == 0) snprintf(buf, 32, "VAL1=%d", value1); + else snprintf(buf, 32, "VAL2=%d", value2); + sendstrmessage(fd, buf); + return RESULT_SILENCE; +} + +/* +hresult handler(_U_ int fd, _U_ const char *key, _U_ const char *val){ + ; +} +*/ + +static handleritem items[] = { + {pinghandler, "ping"}, + {timehandler, "time"}, + {valsethandler, "setval1"}, + {valsethandler, "setval2"}, + {valgethandler, "getval1"}, + {valgethandler, "getval2"}, + {NULL, NULL}, +}; + +/** + * @brief processData - process here some actions and make messages for all clients + * @param buf (o) - buffer for answer + * @param l - max length of buf + * @return amount of answer bytes + */ +static int process_data(char *buf, int l){ + if(!buf || !l) return 0; + /* USERCODE: get here some data to send all clients */ + if(sendtime){ + snprintf(buf, l, "TIME=%.2f", dtime()); + sendtime = 0; + return strlen(buf); + } + return 0; +} + +#define CLBUFSZ BUFSIZ + +void server(int sock){ + if(listen(sock, MAXCLIENTS) == -1){ + WARN("listen"); + LOGWARN("listen"); + return; + } + int nfd = 1; // only one socket @start + struct pollfd poll_set[MAXCLIENTS+1]; + char buffers[MAXCLIENTS][CLBUFSZ]; // buffers for data reading + bzero(poll_set, sizeof(poll_set)); + // ZERO - listening server socket + poll_set[0].fd = sock; + poll_set[0].events = POLLIN; + while(1){ + poll(poll_set, nfd, 1); // max timeout - 1ms + if(poll_set[0].revents & POLLIN){ // check main for accept() + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + int client = accept(sock, (struct sockaddr*)&addr, &len); + DBG("New connection"); + LOGMSG("SERVER got connection, fd=%d", client); + if(nfd == MAXCLIENTS + 1){ + LOGWARN("Max amount of connections, disconnect fd=%d", client); + WARNX("Limit of connections reached"); + close(client); + }else{ + memset(&poll_set[nfd], 0, sizeof(struct pollfd)); + poll_set[nfd].fd = client; + poll_set[nfd].events = POLLIN; + ++nfd; + } + } + char buff[BUFLEN]; + int l = 0; + // process some data & send messages to ALL + if((l = process_data(buff, BUFLEN-1))){ + DBG("Send to %d clients", nfd - 1); + for(int i = 1; i < nfd; ++i) + sendmessage(poll_set[i].fd, buff, l); + } + // scan connections + for(int fdidx = 1; fdidx < nfd; ++fdidx){ + if((poll_set[fdidx].revents & POLLIN) == 0) continue; + int fd = poll_set[fdidx].fd; + if(!processData(fd, items, buffers[fdidx-1], CLBUFSZ)){ // socket closed + DBG("Client fd=%d disconnected", fd); + LOGMSG("SERVER client fd=%d disconnected", fd); + buffers[fdidx-1][0] = 0; // clear rest of data in buffer + close(fd); + // move last FD to current position + poll_set[fdidx] = poll_set[nfd - 1]; + --nfd; + } + } + } +} diff --git a/Socket_snippet/server.h b/Socket_snippet/server.h new file mode 100644 index 0000000..3cef966 --- /dev/null +++ b/Socket_snippet/server.h @@ -0,0 +1,26 @@ +/* + * This file is part of the socksnippet project. + * Copyright 2022 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#ifndef SERVER_H__ +#define SERVER_H__ + +// server-side functions +void server(int fd); + +#endif // SERVER_H__ diff --git a/Socket_snippet/socket b/Socket_snippet/socket new file mode 100755 index 0000000000000000000000000000000000000000..0d179027b445873ba3dc9b6b3ed4b687b01590d8 GIT binary patch literal 27376 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 R$VmF. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include // isspace +#include +#include +#include +#include +#include // unix socket +#include + +#include "cmdlnopts.h" +#include "client.h" +#include "server.h" +#include "socket.h" + +/** + * @brief start_socket - create socket and run client or server + * @param isserver - TRUE for server, FALSE for client + * @param path - UNIX-socket path or local INET socket port + * @param isnet - TRUE for INET socket, FALSE for UNIX + * @return 0 if OK + */ +int start_socket(int isserver, char *path, int isnet){ + if(!path) return 1; + DBG("path/port: %s", path); + int sock = -1; + struct addrinfo hints = {0}, *res; + struct sockaddr_un unaddr = {0}; + if(isnet){ + DBG("Network socket"); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + if(getaddrinfo("127.0.0.1", path, &hints, &res) != 0){ + ERR("getaddrinfo"); + } + }else{ + DBG("UNIX socket"); + char apath[128]; + if(*path == 0){ + DBG("convert name"); + apath[0] = 0; + strncpy(apath+1, path+1, 126); + }else if(strncmp("\\0", path, 2) == 0){ + DBG("convert name"); + apath[0] = 0; + strncpy(apath+1, path+2, 126); + }else strcpy(apath, path); + unaddr.sun_family = AF_UNIX; + hints.ai_addr = (struct sockaddr*) &unaddr; + hints.ai_addrlen = sizeof(unaddr); + memcpy(unaddr.sun_path, apath, 106); // if sun_path[0] == 0 we don't create a file + hints.ai_family = AF_UNIX; + hints.ai_socktype = SOCK_SEQPACKET; + res = &hints; + } + for(struct addrinfo *p = res; p; p = p->ai_next){ + if((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0){ // or SOCK_STREAM? + LOGWARN("socket()"); + WARN("socket()"); + continue; + } + if(isserver){ + int reuseaddr = 1; + if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)) == -1){ + LOGWARN("setsockopt()"); + WARN("setsockopt()"); + close(sock); sock = -1; + continue; + } + if(bind(sock, p->ai_addr, p->ai_addrlen) == -1){ + LOGWARN("bind()"); + WARN("bind()"); + close(sock); sock = -1; + continue; + } + int enable = 1; + if(ioctl(sock, FIONBIO, (void *)&enable) < 0){ // make socket nonblocking + LOGERR("Can't make socket nonblocking"); + ERRX("ioctl()"); + } + }else{ + if(connect(sock, p->ai_addr, p->ai_addrlen) == -1){ + LOGWARN("connect()"); + WARN("connect()"); + close(sock); sock = -1; + } + } + break; + } + if(sock < 0){ + LOGERR("Can't open socket"); + ERRX("Can't open socket"); + } + if(isnet) freeaddrinfo(res); + if(isserver) server(sock); + else client(sock); + close(sock); + signals(0); + return 0; +} + +// simple wrapper over write: add missed newline and log data +void sendmessage(int fd, const char *msg, int l){ + if(fd < 1 || !msg || l < 1) return; + DBG("send to fd %d: %s [%d]", fd, msg, l); + char *tmpbuf = MALLOC(char, l+1); + memcpy(tmpbuf, msg, l); + if(msg[l-1] != '\n') tmpbuf[l++] = '\n'; + if(l != write(fd, tmpbuf, l)){ + LOGWARN("write()"); + WARN("write()"); + }else{ + if(globlog){ // logging turned ON + tmpbuf[l-1] = 0; // remove trailing '\n' for logging + LOGMSG("SEND to fd %d: %s", fd, tmpbuf); + } + } + FREE(tmpbuf); +} +void sendstrmessage(int fd, const char *msg){ + if(fd < 1 || !msg) return; + int l = strlen(msg); + sendmessage(fd, msg, l); +} + +// text messages for `hresult` +static const char *resmessages[] = { + [RESULT_OK] = "OK", + [RESULT_FAIL] = "FAIL", + [RESULT_BADKEY] = "BADKEY", + [RESULT_BADVAL] = "BADVAL", + [RESULT_SILENCE] = "", +}; + +const char *hresult2str(hresult r){ + if(r >= RESULT_NUM) return "BADRESULT"; + return resmessages[r]; +} + +// parse string of data (command or key=val) +// the CONTENT of buffer `str` WILL BE BROKEN! +static void parsestring(int fd, handleritem *handlers, char *str){ + if(fd < 1 || !handlers || !handlers->key || !str || !*str) return; + DBG("Got string %s", str); + // remove starting spaces in key + while(isspace(*str)) ++str; + char *val = strchr(str, '='); + if(val){ // get value: remove starting spaces in val + *val++ = 0; + while(isspace(*val)) ++val; + } + // remove trailing spaces in key + char *e = str + strlen(str) - 1; // last key symbol + while(isspace(*e) && e > str) --e; + e[1] = 0; + // now we have key (`str`) and val (or NULL) + DBG("key=%s, val=%s", str, val); + for(handleritem *h = handlers; h->handler; ++h){ + if(strcmp(str, h->key) == 0){ // found command + if(h->handler){ + hresult r = h->handler(fd, str, val); + sendstrmessage(fd, hresult2str(r)); + }else sendstrmessage(fd, resmessages[RESULT_FAIL]); + return; + } + } + sendstrmessage(fd, resmessages[RESULT_BADKEY]); +} + +/** + * @brief processData - read (if available) data from fd and run processing, sending to fd messages for each command + * @param fd - socket file descriptor + * @param handlers - NULL-terminated array of handlers + * @param buf (io) - zero-terminated buffer for storing rest of data (without newline), its content will be changed + * @param buflen - its length + * @return FALSE if client closed (nothing to read) + */ +int processData(int fd, handleritem *handlers, char *buf, int buflen){ + int curlen = strlen(buf); + if(curlen == buflen-1) curlen = 0; // buffer overflow - clear old content + ssize_t rd = read(fd, buf + curlen, buflen-1 - curlen); + if(rd <= 0) return FALSE; + DBG("got %s[%zd] from %d", buf, rd, fd); + char *restofdata = buf, *eptr = buf + curlen + rd; + *eptr = 0; + do{ + char *nl = strchr(restofdata, '\n'); + if(!nl) break; + *nl++ = 0; + parsestring(fd, handlers, restofdata); + restofdata = nl; + DBG("rest of data: %s", restofdata); + }while(1); + if(restofdata != buf) memmove(buf, restofdata, eptr - restofdata + 1); + return TRUE; +} diff --git a/Socket_snippet/socket.h b/Socket_snippet/socket.h new file mode 100644 index 0000000..ecd6e3f --- /dev/null +++ b/Socket_snippet/socket.h @@ -0,0 +1,56 @@ +/* + * This file is part of the socksnippet project. + * Copyright 2022 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#ifndef SERSOCK_H__ +#define SERSOCK_H__ + +// max & min TCP socket port number +#define PORTN_MAX (65535) +#define PORTN_MIN (1024) + +#define BUFLEN (1024) +// Max amount of connections +#define MAXCLIENTS (30) + +typedef enum{ + RESULT_OK, // all OK + RESULT_FAIL, // failed running command + RESULT_BADVAL, // bad key's value + RESULT_BADKEY, // bad key + RESULT_SILENCE, // send nothing to client + RESULT_NUM +} hresult; + +const char *hresult2str(hresult r); + +// fd - socket fd to send private messages, key, val - key and its value +typedef hresult (*mesghandler)(int fd, const char *key, const char *val); + +typedef struct{ + mesghandler handler; + const char *key; +} handleritem; + +int start_socket(int server, char *path, int isnet); +void sendmessage(int fd, const char *msg, int l); +void sendstrmessage(int fd, const char *msg); + +int processData(int fd, handleritem *handlers, char *buf, int buflen); + +#endif // SERSOCK_H__ diff --git a/Socket_snippet/socksnippet.cflags b/Socket_snippet/socksnippet.cflags new file mode 100644 index 0000000..68d5165 --- /dev/null +++ b/Socket_snippet/socksnippet.cflags @@ -0,0 +1 @@ +-std=c17 \ No newline at end of file diff --git a/Socket_snippet/socksnippet.config b/Socket_snippet/socksnippet.config new file mode 100644 index 0000000..c49fee0 --- /dev/null +++ b/Socket_snippet/socksnippet.config @@ -0,0 +1,6 @@ +// Add predefined macros for your project here. For example: +// #define THE_ANSWER 42 +#define EBUG +#define _GNU_SOURCE +#define _XOPEN_SOURCE=1111 + diff --git a/Socket_snippet/socksnippet.creator b/Socket_snippet/socksnippet.creator new file mode 100644 index 0000000..e94cbbd --- /dev/null +++ b/Socket_snippet/socksnippet.creator @@ -0,0 +1 @@ +[General] diff --git a/Socket_snippet/socksnippet.creator.user b/Socket_snippet/socksnippet.creator.user new file mode 100644 index 0000000..2810e57 --- /dev/null +++ b/Socket_snippet/socksnippet.creator.user @@ -0,0 +1,163 @@ + + + + + + EnvironmentId + {cf63021e-ef53-49b0-b03b-2f2570cdf3b6} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + KOI8-R + false + 4 + false + 80 + true + true + 1 + false + false + false + 1 + true + true + 0 + 8 + true + false + 2 + true + true + true + *.md, *.MD, Makefile + true + true + + + + ProjectExplorer.Project.PluginSettings + + + true + true + Builtin.DefaultTidyAndClazy + 4 + + + + true + + + true + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + Desktop + {91347f2c-5221-46a7-80b1-0a054ca02f79} + 0 + 0 + 0 + + /home/eddy/Docs/SAO/ELECTRONICS/CAN_controller/Socket_CANserver + + + + all + + true + GenericProjectManager.GenericMakeStep + + 1 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + + clean + + true + GenericProjectManager.GenericMakeStep + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Default + GenericProjectManager.GenericBuildConfiguration + + 1 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + 2 + + ProjectExplorer.CustomExecutableRunConfiguration + + false + true + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + diff --git a/Socket_snippet/socksnippet.cxxflags b/Socket_snippet/socksnippet.cxxflags new file mode 100644 index 0000000..6435dfc --- /dev/null +++ b/Socket_snippet/socksnippet.cxxflags @@ -0,0 +1 @@ +-std=c++17 \ No newline at end of file diff --git a/Socket_snippet/socksnippet.files b/Socket_snippet/socksnippet.files new file mode 100644 index 0000000..60feb38 --- /dev/null +++ b/Socket_snippet/socksnippet.files @@ -0,0 +1,9 @@ +client.c +client.h +cmdlnopts.c +cmdlnopts.h +main.c +server.c +server.h +socket.c +socket.h diff --git a/Socket_snippet/socksnippet.includes b/Socket_snippet/socksnippet.includes new file mode 100644 index 0000000..9c558e3 --- /dev/null +++ b/Socket_snippet/socksnippet.includes @@ -0,0 +1 @@ +. diff --git a/Socket_snippet/testcommands b/Socket_snippet/testcommands new file mode 100644 index 0000000..4adb552 --- /dev/null +++ b/Socket_snippet/testcommands @@ -0,0 +1,11 @@ + time + getval1 + setval1 = 56 + getval2 + setval2 = 189 + getval1 = asdf + getval2 = 000000asdffd fdassdf fda + time + a + getval1 +getval2