From ad29c057ab2f2651c04782f6a1e14c9138bcb155 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Fri, 30 Jun 2023 16:10:49 +0300 Subject: [PATCH] add GPIO management over etrhernet --- SSL_sockets_GPIO/Makefile | 79 ++++++++ SSL_sockets_GPIO/Readme | 35 ++++ SSL_sockets_GPIO/build.target | 1 + SSL_sockets_GPIO/ca/gen.sh | 49 +++++ SSL_sockets_GPIO/ca_cert.pem | 1 + SSL_sockets_GPIO/client.c | 121 ++++++++++++ SSL_sockets_GPIO/client.h | 23 +++ SSL_sockets_GPIO/client_cert.pem | 1 + SSL_sockets_GPIO/client_key.pem | 1 + SSL_sockets_GPIO/cmdlnopts.c | 115 +++++++++++ SSL_sockets_GPIO/cmdlnopts.h | 52 +++++ SSL_sockets_GPIO/daemon.c | 106 ++++++++++ SSL_sockets_GPIO/daemon.h | 22 +++ SSL_sockets_GPIO/gpio.c | 199 +++++++++++++++++++ SSL_sockets_GPIO/gpio.h | 44 +++++ SSL_sockets_GPIO/main.c | 30 +++ SSL_sockets_GPIO/server.c | 153 +++++++++++++++ SSL_sockets_GPIO/server.h | 26 +++ SSL_sockets_GPIO/server_cert.pem | 1 + SSL_sockets_GPIO/server_key.pem | 1 + SSL_sockets_GPIO/sslsock.c | 272 ++++++++++++++++++++++++++ SSL_sockets_GPIO/sslsock.h | 45 +++++ SSL_sockets_GPIO/sslsosk.cflags | 1 + SSL_sockets_GPIO/sslsosk.config | 9 + SSL_sockets_GPIO/sslsosk.creator | 1 + SSL_sockets_GPIO/sslsosk.creator.user | 160 +++++++++++++++ SSL_sockets_GPIO/sslsosk.cxxflags | 1 + SSL_sockets_GPIO/sslsosk.files | 13 ++ SSL_sockets_GPIO/sslsosk.includes | 1 + 29 files changed, 1563 insertions(+) create mode 100644 SSL_sockets_GPIO/Makefile create mode 100644 SSL_sockets_GPIO/Readme create mode 100644 SSL_sockets_GPIO/build.target create mode 100755 SSL_sockets_GPIO/ca/gen.sh create mode 120000 SSL_sockets_GPIO/ca_cert.pem create mode 100644 SSL_sockets_GPIO/client.c create mode 100644 SSL_sockets_GPIO/client.h create mode 120000 SSL_sockets_GPIO/client_cert.pem create mode 120000 SSL_sockets_GPIO/client_key.pem create mode 100644 SSL_sockets_GPIO/cmdlnopts.c create mode 100644 SSL_sockets_GPIO/cmdlnopts.h create mode 100644 SSL_sockets_GPIO/daemon.c create mode 100644 SSL_sockets_GPIO/daemon.h create mode 100644 SSL_sockets_GPIO/gpio.c create mode 100644 SSL_sockets_GPIO/gpio.h create mode 100644 SSL_sockets_GPIO/main.c create mode 100644 SSL_sockets_GPIO/server.c create mode 100644 SSL_sockets_GPIO/server.h create mode 120000 SSL_sockets_GPIO/server_cert.pem create mode 120000 SSL_sockets_GPIO/server_key.pem create mode 100644 SSL_sockets_GPIO/sslsock.c create mode 100644 SSL_sockets_GPIO/sslsock.h create mode 100644 SSL_sockets_GPIO/sslsosk.cflags create mode 100644 SSL_sockets_GPIO/sslsosk.config create mode 100644 SSL_sockets_GPIO/sslsosk.creator create mode 100644 SSL_sockets_GPIO/sslsosk.creator.user create mode 100644 SSL_sockets_GPIO/sslsosk.cxxflags create mode 100644 SSL_sockets_GPIO/sslsosk.files create mode 100644 SSL_sockets_GPIO/sslsosk.includes diff --git a/SSL_sockets_GPIO/Makefile b/SSL_sockets_GPIO/Makefile new file mode 100644 index 0000000..0325361 --- /dev/null +++ b/SSL_sockets_GPIO/Makefile @@ -0,0 +1,79 @@ +# run `make DEF=...` to add extra defines +CLIENT := sslclient +SERVER := sslserver +LDFLAGS += -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all +LDFLAGS += -lusefull_macros -lssl -lcrypto -lm +DEFINES := $(DEF) -D_GNU_SOURCE -D_XOPEN_SOURCE=1111 +SOBJDIR := mkserver +COBJDIR := mkclient +CFLAGS += -O2 -Wall -Wextra -Wno-trampolines -pthread +COMMSRCS := sslsock.c daemon.c cmdlnopts.c main.c gpio.c +SSRC := server.c $(COMMSRCS) +CSRC := client.c $(COMMSRCS) +SOBJS := $(addprefix $(SOBJDIR)/, $(SSRC:%.c=%.o)) +COBJS := $(addprefix $(COBJDIR)/, $(CSRC:%.c=%.o)) +SDEPS := $(SOBJS:.o=.d) +CDEPS := $(COBJS:.o=.d) +CC = gcc + +TARGFILE := build.target + +ifeq ($(shell test -e $(TARGFILE) && echo -n yes),yes) + TARGET := $(file < $(TARGFILE)) +else + TARGET := RELEASE +endif + +ifeq ($(TARGET), DEBUG) + .DEFAULT_GOAL := debug +endif + +release: CFLAGS += -flto +release: LDFLAGS += -flto +release: $(TARGFILE) $(CLIENT) $(SERVER) + +debug: CFLAGS += -DEBUG -Werror +debug: TARGET := DEBUG +debug: $(TARGFILE) $(CLIENT) $(SERVER) + +$(TARGFILE): + @echo -e "\tTARGET: $(TARGET)\n" + @echo "$(TARGET)" > $(TARGFILE) + +$(CLIENT) : DEFINES += -DCLIENT +$(CLIENT) : $(COBJDIR) $(COBJS) + @echo -e "\tLD $(CLIENT)" + $(CC) $(COBJS) $(LDFLAGS) -o $(CLIENT) + + +$(SERVER) : DEFINES += -DSERVER +$(SERVER) : $(SOBJDIR) $(SOBJS) + @echo -e "\tLD $(SERVER)" + $(CC) $(SOBJS) $(LDFLAGS) -o $(SERVER) + +$(SOBJDIR): + @mkdir $(SOBJDIR) + +$(COBJDIR): + @mkdir $(COBJDIR) + +ifneq ($(MAKECMDGOALS),clean) +-include $(DEPS) +endif + +$(COBJDIR)/%.o: %.c + @echo -e "\tCC $<" + $(CC) -MD -c $(LDFLAGS) $(CFLAGS) $(DEFINES) -o $@ $< + +$(SOBJDIR)/%.o: %.c + @echo -e "\t\tCC $<" + $(CC) -MD -c $(LDFLAGS) $(CFLAGS) $(DEFINES) -o $@ $< + +clean: + @echo -e "\t\tCLEAN" + @rm -rf $(SOBJDIR) $(COBJDIR) $(TARGFILE) 2>/dev/null || true + +xclean: clean + @rm -f $(PROGRAM) + +.PHONY: clean xclean diff --git a/SSL_sockets_GPIO/Readme b/SSL_sockets_GPIO/Readme new file mode 100644 index 0000000..8b672a9 --- /dev/null +++ b/SSL_sockets_GPIO/Readme @@ -0,0 +1,35 @@ +Client/server GPIO monitoring using SSL-protected TCP-socket connection between client and server (check certs from both sides) + +Both client and server monitors 6 GPIO inputs and send messages "UPxx" and "DOWNxx" when button was pressed (0) or released (1). +When receiving such messages client/server check by local table correspongind outputs and change their values. If all OK, return "OK", +if not - return "FAIL". + + +Usage: sslclient [args] + + Where args are: + + -C, --command don't run client as daemon, just send given commands to server + -P, --pidfile=arg pidfile (default: /tmp/sslsock.pid) + -a, --ca=arg path to SSL ca - base cert (default:ca_cert.pem) + -c, --certificate=arg path to SSL sertificate (default: client_cert.pem) + -h, --help show this help + -k, --key=arg path to SSL key (default: client_key.pem) + -l, --logfile=arg file to save logs + -p, --port=arg port to open (default: 4444) + -s, --server=arg server IP address or name + -v, --verbose increase log verbose level (default: LOG_WARN) + + +Usage: sslserver [args] + + Where args are: + + -P, --pidfile=arg pidfile (default: /tmp/sslsock.pid) + -a, --ca=arg path to SSL ca - base cert (default:ca_cert.pem) + -c, --certificate=arg path to SSL sertificate (default: server_cert.pem) + -h, --help show this help + -k, --key=arg path to SSL key (default: server_key.pem) + -l, --logfile=arg file to save logs + -p, --port=arg port to open (default: 4444) + -v, --verbose increase log verbose level (default: LOG_WARN) diff --git a/SSL_sockets_GPIO/build.target b/SSL_sockets_GPIO/build.target new file mode 100644 index 0000000..aad9cf5 --- /dev/null +++ b/SSL_sockets_GPIO/build.target @@ -0,0 +1 @@ +RELEASE diff --git a/SSL_sockets_GPIO/ca/gen.sh b/SSL_sockets_GPIO/ca/gen.sh new file mode 100755 index 0000000..e3fee03 --- /dev/null +++ b/SSL_sockets_GPIO/ca/gen.sh @@ -0,0 +1,49 @@ +#!/bin/sh + +# https://gist.github.com/zapstar/4b51d7cfa74c7e709fcdaace19233443 +mkdir -p ca/private +chmod 700 ca/private +# NOTE: I'm using -nodes, this means that once anybody gets +# their hands on this particular key, they can become this CA. +openssl req \ + -x509 \ + -nodes \ + -days 36524 \ + -newkey rsa:4096 \ + -keyout ca/private/ca_key.pem \ + -out ca/ca_cert.pem \ + -subj "/C=RU/ST=KChR/L=Bukovo/O=SAO RAS/CN=sao.ru" + +# Create server private key and certificate request +mkdir -p server/private +chmod 700 ca/private +openssl genrsa -out server/private/server_key.pem 4096 +openssl req -new \ + -key server/private/server_key.pem \ + -out server/server.csr \ + -subj "/C=RU/ST=KChR/L=Bukovo/O=SAO RAS" + +# Create client private key and certificate request +mkdir -p client/private +chmod 700 client/private +openssl genrsa -out client/private/client_key.pem 4096 +openssl req -new \ + -key client/private/client_key.pem \ + -out client/client.csr \ + -subj "/C=RU/ST=KChR/L=Bukovo/O=SAO RAS" + +# Generate certificates +openssl x509 -req -days 36524 -in server/server.csr \ + -CA ca/ca_cert.pem -CAkey ca/private/ca_key.pem \ + -CAcreateserial -out server/server_cert.pem +openssl x509 -req -days 36524 -in client/client.csr \ + -CA ca/ca_cert.pem -CAkey ca/private/ca_key.pem \ + -CAcreateserial -out client/client_cert.pem + +# Now test both the server and the client +# On one shell, run the following +# openssl s_server -CAfile ca/ca_cert.pem -cert server/server_cert.pem -key server/private/server_key.pem -Verify 1 +# On another shell, run the following +# openssl s_client -CAfile ca/ca_cert.pem -cert client/client_cert.pem -key client/private/client_key.pem +# Once the negotiation is complete, any line you type is sent over to the other side. +# By line, I mean some text followed by a keyboard return press. diff --git a/SSL_sockets_GPIO/ca_cert.pem b/SSL_sockets_GPIO/ca_cert.pem new file mode 120000 index 0000000..8ed62b8 --- /dev/null +++ b/SSL_sockets_GPIO/ca_cert.pem @@ -0,0 +1 @@ +ca/ca/ca_cert.pem \ No newline at end of file diff --git a/SSL_sockets_GPIO/client.c b/SSL_sockets_GPIO/client.c new file mode 100644 index 0000000..898c524 --- /dev/null +++ b/SSL_sockets_GPIO/client.c @@ -0,0 +1,121 @@ +/* + * This file is part of the sslsosk project. + * Copyright 2023 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 "client.h" +#include "cmdlnopts.h" +#include "sslsock.h" +#ifdef __arm__ +#include "gpio.h" +#endif + +static int SSL_nbread(SSL *ssl, char *buf, int bufsz){ + struct pollfd fds = {0}; + int fd = SSL_get_fd(ssl); + fds.fd = fd; + fds.events = POLLIN | POLLPRI; + if(poll(&fds, 1, 1) < 0){ // wait no more than 1ms + LOGWARN("SSL_nbread(): poll() failed"); + WARNX("poll()"); + return 0; + } + if(fds.revents & (POLLIN | POLLPRI)){ + //DBG("Got info in fd #%d", fd); + int l = read_string(ssl, buf, bufsz); + //DBG("read %d bytes", l); + return l; + } + return 0; +} + +static void readssl(SSL *ssl){ + char buf[BUFSIZ]; + int bytes = SSL_nbread(ssl, buf, BUFSIZ-1); + //int bytes = read_string(ssl, buf, BUFSIZ-1); + if(bytes > 0){ + buf[bytes] = 0; + verbose(1, "Received: \"%s\"", buf); +#ifdef __arm__ + handle_message(buf); +#endif + }else if(bytes < 0){ + LOGWARN("Server disconnected or other error"); + ERRX("Disconnected"); + } +} + +static void sendcommands(SSL *ssl){ + char buf[BUFSIZ]; + char **curdata = G.commands; + if(!curdata) return; + while(*curdata){ + verbose(1, "Send: \"%s\"", *curdata); + int l = snprintf(buf, BUFSIZ-1, "%s\n", *curdata); + if(SSL_write(ssl, buf, l) <= 0) WARNX("SSL write error"); + readssl(ssl); + ++curdata; + } + double t0 = dtime(); + while(dtime() - t0 < 2.) readssl(ssl); +} + +void clientproc(SSL_CTX *ctx, int fd){ + FNAME(); + SSL *ssl; + ssl = SSL_new(ctx); + SSL_set_fd(ssl, fd); + int c = SSL_connect(ssl); + if(c < 0){ + LOGERR("SSL_connect()"); + ERRX("SSL_connect() error: %d", SSL_get_error(ssl, c)); + } + int enable = 1; + if(ioctl(fd, FIONBIO, (void *)&enable) < 0){ + LOGERR("Can't make socket nonblocking"); + ERRX("ioctl()"); + } +#ifndef __arm__ + char buf[BUFSIZ]; + double t0 = dtime(); +#endif + if(G.commands){ + sendcommands(ssl); + SSL_shutdown(ssl); + SSL_free(ssl); + return; + } + while(1){ +#ifdef __arm__ + poll_gpio(&ssl, 1); +#else + if(dtime() - t0 > 3.){ + static int ctr = 0; + const char *msgs[2] = {"UP", "DOWN"}; + int l = snprintf(buf, BUFSIZ-1, "%s18\n", msgs[ctr]); + ctr = !ctr; + verbose(1, "Send: %s", buf); + if(SSL_write(ssl, buf, l) <= 0) WARNX("SSL write error"); + t0 = dtime(); + } +#endif + readssl(ssl); + } + SSL_free(ssl); +} diff --git a/SSL_sockets_GPIO/client.h b/SSL_sockets_GPIO/client.h new file mode 100644 index 0000000..5fa2171 --- /dev/null +++ b/SSL_sockets_GPIO/client.h @@ -0,0 +1,23 @@ +/* + * This file is part of the sslsosk project. + * Copyright 2023 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 + +#include "sslsock.h" + +void clientproc(SSL_CTX *ctx, int fd); diff --git a/SSL_sockets_GPIO/client_cert.pem b/SSL_sockets_GPIO/client_cert.pem new file mode 120000 index 0000000..03d14fb --- /dev/null +++ b/SSL_sockets_GPIO/client_cert.pem @@ -0,0 +1 @@ +ca/client/client_cert.pem \ No newline at end of file diff --git a/SSL_sockets_GPIO/client_key.pem b/SSL_sockets_GPIO/client_key.pem new file mode 120000 index 0000000..08aaa7a --- /dev/null +++ b/SSL_sockets_GPIO/client_key.pem @@ -0,0 +1 @@ +ca/client/private/client_key.pem \ No newline at end of file diff --git a/SSL_sockets_GPIO/cmdlnopts.c b/SSL_sockets_GPIO/cmdlnopts.c new file mode 100644 index 0000000..3966d69 --- /dev/null +++ b/SSL_sockets_GPIO/cmdlnopts.c @@ -0,0 +1,115 @@ +/* + * This file is part of the sslsosk project. + * Copyright 2023 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" + + +/* + * here are global parameters initialisation + */ +static int help; + +#ifdef SERVER +#define DEFCERT "server_cert.pem" +#define DEFKEY "server_key.pem" +#else +#define DEFCERT "client_cert.pem" +#define DEFKEY "client_key.pem" +#endif +#define DEFCA "ca_cert.pem" + +#define DEFGPIO "/dev/gpiochip0" +// default global parameters +glob_pars G = { + .pidfile = DEFAULT_PIDFILE, + .port = DEFAULT_PORT, + .cert = DEFCERT, + .key = DEFKEY, + .ca = DEFCA, +#ifdef __arm__ + .gpiodevpath = DEFGPIO, +#endif +}; + +/* + * Define command line options by filling structure: + * name has_arg flag val type argptr help +*/ +static myoption cmdlnopts[] = { +// common options + {"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")}, + {"pidfile", NEED_ARG, NULL, 'P', arg_string, APTR(&G.pidfile), _("pidfile (default: " DEFAULT_PIDFILE ")")}, + {"certificate",NEED_ARG,NULL, 'c', arg_string, APTR(&G.cert), _("path to SSL sertificate (default: " DEFCERT ")")}, + {"key", NEED_ARG, NULL, 'k', arg_string, APTR(&G.key), _("path to SSL key (default: " DEFKEY ")")}, + {"port", NEED_ARG, NULL, 'p', arg_string, APTR(&G.port), _("port to open (default: " DEFAULT_PORT ")")}, + {"verbose", NO_ARGS, NULL, 'v', arg_none, APTR(&G.verbose), _("increase log verbose level (default: LOG_WARN)")}, + {"ca", NEED_ARG, NULL, 'a', arg_string, APTR(&G.ca), _("path to SSL ca - base cert (default:" DEFCA ")")}, +#ifdef __arm__ + {"gpiopath",NEED_ARG, NULL, 'g', arg_string, APTR(&G.gpiodevpath),_("path to GPIO device (default:" DEFGPIO ")")}, +#endif +#ifdef CLIENT + {"server", NEED_ARG, NULL, 's', arg_string, APTR(&G.serverhost), _("server IP address or name")}, + {"command", MULT_PAR, NULL, 'C', arg_string, APTR(&G.commands), _("don't run client as daemon, just send given commands to server")}, +#endif + 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 + */ +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); + if(help) showhelp(-1, cmdlnopts); + if(argc > 0){ + red("Ignored options:\n"); + for (i = 0; i < argc; i++) + printf("\t%s\n", argv[i]); + } +} + +/** + * @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/SSL_sockets_GPIO/cmdlnopts.h b/SSL_sockets_GPIO/cmdlnopts.h new file mode 100644 index 0000000..71e54ee --- /dev/null +++ b/SSL_sockets_GPIO/cmdlnopts.h @@ -0,0 +1,52 @@ +/* + * This file is part of the sslsosk project. + * Copyright 2023 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 + +// default PID filename: +#ifndef DEFAULT_PIDFILE +#define DEFAULT_PIDFILE "/tmp/sslsock.pid" +#endif +#ifndef DEFAULT_PORT +#define DEFAULT_PORT "4444" +#endif + +/* + * here are some typedef's for global data + */ +typedef struct{ + char *pidfile; // name of PID file + char *logfile; // logging to this file + char *cert; // sertificate + char *key; // key + char *port; // port number + int verbose; // logfile verbose level + char *ca; // ca +#ifdef CLIENT + char *serverhost; // server IP address + char **commands; // don't run as daemon, just send given commands to server +#endif +#ifdef __arm__ + char *gpiodevpath; // path to gpio device file +#endif +} glob_pars; + +extern glob_pars G; + +void parse_args(int argc, char **argv); +void verbose(int levl, const char *fmt, ...); diff --git a/SSL_sockets_GPIO/daemon.c b/SSL_sockets_GPIO/daemon.c new file mode 100644 index 0000000..65f2d01 --- /dev/null +++ b/SSL_sockets_GPIO/daemon.c @@ -0,0 +1,106 @@ +/* + * This file is part of the sslsosk project. + * Copyright 2023 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 // prctl +#include // wait +#include +#include + +#include "cmdlnopts.h" +#include "daemon.h" +#include "sslsock.h" + +static pid_t childpid = -1; + +void signals(int sig){ + if(childpid == 0){ + LOGWARN("Child killed with sig=%d", sig); + exit(sig); // slave process + } + // master process + if(sig){ + signal(sig, SIG_IGN); + LOGERR("Exit with signal %d", sig); + }else LOGERR("Exit"); + if(G.pidfile) unlink(G.pidfile); + exit(sig); +} + +/** + * @brief start_daemon - daemonize + * @param self - self name of process + * @return error code or 0 + */ +int start_daemon(_U_ char *self){ + // check args + int port = atoi(G.port); + if(port < 1024 || port > 65535){ + LOGERR("Wrong port value: %d", port); + return 1; + } + FILE *f = fopen(G.cert, "r"); + if(!f) ERR("Can't open certificate file %s", G.cert); + fclose(f); + f = fopen(G.key, "r"); + if(!f) ERR("Can't open certificate key file %s", G.key); + fclose(f); +#ifdef EBUG + printf("cert: %s, key: %s\n", G.cert, G.key); +#endif +#ifdef CLIENT + //DBG("server: %s", G.serverhost); + if(!G.serverhost) ERRX("Point server name"); +#endif + if(G.logfile){ + int lvl = LOGLEVEL_WARN + G.verbose; + DBG("level = %d", lvl); + if(lvl > LOGLEVEL_ANY) lvl = LOGLEVEL_ANY; + green("Log file %s @ level %d\n", G.logfile, lvl); + OPENLOG(G.logfile, lvl, 1); + } + 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 +#ifdef SERVER + check4running(self, G.pidfile); +#endif + LOGMSG("Started"); +#ifndef EBUG +#ifdef CLIENT + if(G.commands) return open_socket(); +#endif + while(1){ + childpid = fork(); + if(childpid){ // master + LOGMSG("Created child with pid %d", childpid); + wait(NULL); + LOGWARN("Child %d died", childpid); + sleep(1); // wait a little before respawn + }else{ // slave + prctl(PR_SET_PDEATHSIG, SIGTERM); // send SIGTERM to child when parent dies + break; + } + } +#endif + // parent should never reach this part of code + return open_socket(); +} diff --git a/SSL_sockets_GPIO/daemon.h b/SSL_sockets_GPIO/daemon.h new file mode 100644 index 0000000..f62cd42 --- /dev/null +++ b/SSL_sockets_GPIO/daemon.h @@ -0,0 +1,22 @@ +/* + * This file is part of the sslsosk project. + * Copyright 2023 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 + +int start_daemon(char *self); + diff --git a/SSL_sockets_GPIO/gpio.c b/SSL_sockets_GPIO/gpio.c new file mode 100644 index 0000000..ef3c6ed --- /dev/null +++ b/SSL_sockets_GPIO/gpio.c @@ -0,0 +1,199 @@ +/* + * This file is part of the sslsosk project. + * Copyright 2023 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 +#include +#include +#include +#include + +#include "cmdlnopts.h" +#include "gpio.h" + +static int gpiofd = -1; +static struct gpio_v2_line_request rq_in, rq_out; + +// inputs and outputs +static const int gpio_inputs[GPIO_IN_NUMBER] = {18, 23, 24, 25, 8, 7}; +static const int gpio_outputs[GPIO_OUT_NUMBER] = {17, 27, 22, 10, 9, 11}; + +/** + * @brief gpio_open_device - open GPIO device + * @param path - path to device + * @return device fd or -1 if error + */ +int gpio_open_device(const char *path){ + FNAME(); + gpiofd = open(path, O_RDONLY); + if(gpiofd < 0){ + LOGERR("Unabled to open %s: %s", path, strerror(errno)); + WARNX("Can't open GPIO device %s", path); + return -1; + } + struct gpiochip_info info; + + // Query GPIO chip information + if(-1 == ioctl(gpiofd, GPIO_GET_CHIPINFO_IOCTL, &info)){ + LOGERR("Unable to get chip info from ioctl: %s", strerror(errno)); + WARNX("Unable to get chip info"); + close(gpiofd); + return -1; + } + verbose(2, "Chip name: %s", info.name); + verbose(2, "Chip label: %s", info.label); + verbose(2, "Number of lines: %d", info.lines); + rq_in.fd = -1; + rq_out.fd = -1; + return gpiofd; +} + +/** + * @brief gpio_set_outputs - set output pins + * @return rq.fd or -1 if failed + */ +int gpio_setup_outputs(){ + FNAME(); + bzero(&rq_out, sizeof(rq_out)); + for(int i = 0; i < GPIO_OUT_NUMBER; ++i) + rq_out.offsets[i] = gpio_outputs[i]; + snprintf(rq_out.consumer, GPIO_MAX_NAME_SIZE-1, "outputs"); + rq_out.num_lines = GPIO_OUT_NUMBER; + rq_out.config.flags = GPIO_V2_LINE_FLAG_OUTPUT | GPIO_V2_LINE_FLAG_OPEN_DRAIN | GPIO_V2_LINE_FLAG_ACTIVE_LOW | GPIO_V2_LINE_FLAG_BIAS_DISABLED; + rq_out.config.num_attrs = 0; + if(-1 == ioctl(gpiofd, GPIO_V2_GET_LINE_IOCTL, &rq_out)){ + LOGERR("Unable setup outputs: %s", strerror(errno)); + WARNX("Can't setup outputs"); + return -1; + } + return rq_out.fd; +} + +static int gpio_setreset(int input, int set){ + int idx = -1; + for(int i = 0; i < GPIO_IN_NUMBER; ++i){ + if(gpio_inputs[i] == input){ + idx = i; break; + } + } + DBG("idx = %d", idx); + if(idx < 0 || idx > GPIO_OUT_NUMBER) return FALSE; + struct gpio_v2_line_values values; + bzero(&values, sizeof(values)); + uint64_t val = (1< -1){ + close(gpiofd); + if(rq_in.fd > -1) close(rq_in.fd); + if(rq_out.fd > -1) close(rq_out.fd); + } +} + diff --git a/SSL_sockets_GPIO/gpio.h b/SSL_sockets_GPIO/gpio.h new file mode 100644 index 0000000..f721e84 --- /dev/null +++ b/SSL_sockets_GPIO/gpio.h @@ -0,0 +1,44 @@ +/* + * This file is part of the sslsosk project. + * Copyright 2023 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 + +#include + +// GPIO polling interval - 50ms +#define GPIO_POLL_INTERVAL (0.05) + +// amount of in/out GPIO pins +#define GPIO_IN_NUMBER (6) +#define GPIO_OUT_NUMBER (6) + +// maximal GPIO number +#define GPIO_MAX_NUMBER (32) + +// 6 outputs +#define GPIO_OUT_MASK 0x3f +// 6 inputs +#define GPIO_IN_MASK 0x3f + +int gpio_open_device(const char *path); +int gpio_setup_outputs(); +int gpio_setup_inputs(); +int gpio_poll(uint32_t *up, uint32_t *down); +int gpio_set_output(int input); +int gpio_clear_output(int input); +void gpio_close(); diff --git a/SSL_sockets_GPIO/main.c b/SSL_sockets_GPIO/main.c new file mode 100644 index 0000000..30e5639 --- /dev/null +++ b/SSL_sockets_GPIO/main.c @@ -0,0 +1,30 @@ +/* + * This file is part of the sslsosk project. + * Copyright 2023 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 "daemon.h" +#include "cmdlnopts.h" + +int main(int argc, char **argv){ + char *self = argv[0]; + initial_setup(); + parse_args(argc, argv); + return start_daemon(self); +} diff --git a/SSL_sockets_GPIO/server.c b/SSL_sockets_GPIO/server.c new file mode 100644 index 0000000..2050ab3 --- /dev/null +++ b/SSL_sockets_GPIO/server.c @@ -0,0 +1,153 @@ +/* + * This file is part of the sslsosk project. + * Copyright 2023 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 "server.h" + +static const char *maxcl = "Max client number reached, connect later\n"; +static const char *sslerr = "SSL error occured\n"; + +// return 0 if client disconnected +static int handle_connection(SSL *ssl){ + char buf[1024]; + int r = read_string(ssl, buf, 1024); + if(r < 0) return 0; + int sd = SSL_get_fd(ssl); + int l = 0; + printf("Client %d msg: \"%s\"\n", sd, buf); + LOGDBG("fd=%d, message=%s", sd, buf); +#ifdef __arm__ + const char *ans = "FAIL"; + if(handle_message(buf)) ans = "OK"; + l = snprintf(buf, 1023, "%s\n", ans); +#else + l = snprintf(buf, 1023, "Hello, your FD=%d\n", sd); +#endif + if(SSL_write(ssl, buf, l) <= 0) WARNX("SSL write error"); + return 1; +} + +/** + * @brief timeouted_sslaccept - SSL_accept with timeout + * @param ssl - SSL + * @return 1 if connection ready or 0 if error + */ +static int timeouted_sslaccept(SSL *ssl){ + double t0 = dtime(); + while(dtime() - t0 < ACCEPT_TIMEOUT){ + int x = SSL_accept(ssl); + if(x < 0){ + int sslerr = SSL_get_error(ssl, x); + if(SSL_ERROR_WANT_READ == sslerr || + SSL_ERROR_WANT_WRITE == sslerr) continue; + DBG("SSL error %d", sslerr); + return FALSE; + } + else return TRUE; + } + DBG("Timeout"); + return FALSE; +} + +void serverproc(SSL_CTX *ctx, int fd){ + int enable = 1; + if(ioctl(fd, FIONBIO, (void *)&enable) < 0){ + LOGERR("Can't make socket nonblocking"); + ERRX("ioctl()"); + } + int nfd = 1; // only one listening socket @start + struct pollfd poll_set[BACKLOG+1]; + memset(poll_set, 0, sizeof(poll_set)); + poll_set[0].fd = fd; + poll_set[0].events = POLLIN | POLLPRI; + SSL *ssls[BACKLOG+1] = {0}; // !!! start from 1 - like in poll_set !!! +#ifndef __arm__ + double t0 = dtime(), tstart = t0; + int P = 0; +#endif + while(1){ +#ifdef __arm__ + poll_gpio(ssls, nfd); +#else + char buf[64]; + if(dtime() - t0 > 5. && nfd > 1){ // broadcasting messages + //DBG("send ping"); + int l = snprintf(buf, 63, "ping #%d; t=%g\n", ++P, dtime() - tstart); + for(int i = nfd-1; i > 0; --i){ + DBG("send test to fd[%d]=%d", i, poll_set[i].fd); + if(SSL_write(ssls[i], buf, l) <= 0) WARNX("SSL write error"); + } + t0 = dtime(); + } +#endif + poll(poll_set, nfd, 1); // max timeout - 1ms + // check for accept() + if(poll_set[0].revents & (POLLIN | POLLPRI)){ + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + int client = accept4(fd, (struct sockaddr*)&addr, &len, SOCK_NONBLOCK); // non-blocking for timeout of SSL_accept + DBG("Connection: %s @ %d (fd=%d)\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), client); + LOGMSG("Client %s connected to port %d (fd=%d)", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), client); + if(nfd == BACKLOG + 1){ + LOGWARN("Max amount of connections: disconnect fd=%d", client); + WARNX("Limit of connections reached"); + send(client, maxcl, sizeof(maxcl)-1, MSG_NOSIGNAL); + close(client); + }else{ + DBG("New ssl"); + SSL *ssl = SSL_new(ctx); + SSL_set_fd(ssl, client); + DBG("Accept"); + if(timeouted_sslaccept(ssl)){ + DBG("OK"); + ssls[nfd] = ssl; + bzero(&poll_set[nfd], sizeof(struct pollfd)); + poll_set[nfd].fd = client; + poll_set[nfd].events = POLLIN | POLLPRI; + DBG("nfd=%d, fd=%d, events=0x%x", nfd, poll_set[nfd].fd, poll_set[nfd].events); + ++nfd; + }else{ + LOGERR("SSL_accept()"); + WARNX("SSL_accept()"); + SSL_free(ssl); + send(client, sslerr, sizeof(sslerr)-1, MSG_NOSIGNAL); + close(client); + } + } + } + // scan connections + for(int fdidx = 1; fdidx < nfd; ++fdidx){ + if(poll_set[fdidx].revents) DBG("%d, revents=0x%x", fdidx, poll_set[fdidx].revents); + if((poll_set[fdidx].revents & (POLLIN | POLLPRI)) == 0) continue; + DBG("%d poll", fdidx); + int fd = poll_set[fdidx].fd; + if(!handle_connection(ssls[fdidx])){ // socket closed + SSL_free(ssls[fdidx]); + DBG("Client fd=%d disconnected", fd); + LOGMSG("Client fd=%d disconnected", fd); + close(fd); + if(--nfd > fdidx){ // move last FD to current position + poll_set[fdidx] = poll_set[nfd]; + ssls[fdidx] = ssls[nfd]; + } + } + } + } +} diff --git a/SSL_sockets_GPIO/server.h b/SSL_sockets_GPIO/server.h new file mode 100644 index 0000000..b8033b4 --- /dev/null +++ b/SSL_sockets_GPIO/server.h @@ -0,0 +1,26 @@ +/* + * This file is part of the sslsosk project. + * Copyright 2023 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 + +#include "sslsock.h" + +// timeout of SSL_accept (seconds) +#define ACCEPT_TIMEOUT (10.) + +void serverproc(SSL_CTX *ctx, int fd); diff --git a/SSL_sockets_GPIO/server_cert.pem b/SSL_sockets_GPIO/server_cert.pem new file mode 120000 index 0000000..da4f802 --- /dev/null +++ b/SSL_sockets_GPIO/server_cert.pem @@ -0,0 +1 @@ +ca/server/server_cert.pem \ No newline at end of file diff --git a/SSL_sockets_GPIO/server_key.pem b/SSL_sockets_GPIO/server_key.pem new file mode 120000 index 0000000..49eb60b --- /dev/null +++ b/SSL_sockets_GPIO/server_key.pem @@ -0,0 +1 @@ +ca/server/private/server_key.pem \ No newline at end of file diff --git a/SSL_sockets_GPIO/sslsock.c b/SSL_sockets_GPIO/sslsock.c new file mode 100644 index 0000000..897779a --- /dev/null +++ b/SSL_sockets_GPIO/sslsock.c @@ -0,0 +1,272 @@ +/* + * This file is part of the sslsosk project. + * Copyright 2023 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 // pthread_kill +#include +#include +#include + +#include "cmdlnopts.h" +#include "sslsock.h" +#ifdef SERVER +#include "server.h" +#else +#include "client.h" +#endif +#ifdef __arm__ +#include "gpio.h" +#endif + +#ifdef SERVER +static int OpenConn(int port){ + int sd = socket(PF_INET, SOCK_STREAM, 0); + if(sd < 0){ + LOGERR("Can't open socket"); + ERRX("socket()"); + } + int enable = 1; + // allow reuse of descriptor + if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (void *)&enable, sizeof(int)) < 0){ + LOGERR("Can't apply SO_REUSEADDR to socket"); + ERRX("setsockopt()"); + } + struct sockaddr_in addr = {0}; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + if(bind(sd, (struct sockaddr*)&addr, sizeof(addr))){ + LOGWARN("Can't bind port %d", port); + ERRX("bind()"); + } + if(listen(sd, BACKLOG)){ + LOGWARN("Can't listen()"); + ERRX("listen()"); + } + return sd; +} +#else +static int OpenConn(int port){ + FNAME(); + int sd; + struct hostent *host; + struct sockaddr_in addr; + if((host = gethostbyname(G.serverhost)) == NULL ){ + LOGWARN("gethostbyname(%s) error", G.serverhost); + ERRX("gethostbyname()"); + } + sd = socket(PF_INET, SOCK_STREAM, 0); + DBG("sd=%d", sd); + bzero(&addr, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = *(long*)(host->h_addr); + if(connect(sd, (struct sockaddr*)&addr, sizeof(addr))){ + close(sd); + LOGWARN("Can't connect to %s", G.serverhost); + ERRX("Can't connect to %s", G.serverhost); + } + return sd; +} +#endif + +static SSL_CTX* InitCTX(void){ + const SSL_METHOD *method; + SSL_CTX *ctx; + OpenSSL_add_all_algorithms(); + SSL_load_error_strings(); + method = +#ifdef CLIENT + TLS_client_method(); +#else + TLS_server_method(); +#endif + ctx = SSL_CTX_new(method); + if(!ctx){ + LOGWARN("Can't create SSL context"); + ERRX("SSL_CTX_new()"); + } + if(SSL_CTX_load_verify_locations(ctx, G.ca, NULL) != 1){ + LOGWARN("Could not set the CA file location\n"); + ERRX("Could not set the CA file location\n"); + } +#ifdef SERVER + + SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(G.ca)); +#endif + if(SSL_CTX_use_certificate_file(ctx, G.cert, SSL_FILETYPE_PEM) <= 0){ + LOGWARN("Can't use SSL certificate %s", G.cert); + ERRX("Can't use SSL certificate %s", G.cert); + } + if(SSL_CTX_use_PrivateKey_file(ctx, G.key, SSL_FILETYPE_PEM) <= 0){ + LOGWARN("Can't use SSL key %s", G.key); + ERRX("Can't use SSL key %s", G.key); + } + if(!SSL_CTX_check_private_key(ctx)){ + LOGWARN("Private key does not match the public certificate\n"); + ERRX("Private key does not match the public certificate\n"); + } + SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); +#ifdef SERVER + SSL_CTX_set_verify(ctx, // Specify that we need to verify the client as well + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + NULL); +#else + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); +#endif + SSL_CTX_set_verify_depth(ctx, 1); // We accept only certificates signed only by the CA himself + return ctx; +} + +int open_socket(){ + int fd; +#ifdef __arm__ +#ifndef SERVER + if(!G.commands){ // open devices if not client +#endif + if(-1 == gpio_open_device(G.gpiodevpath)) ERRX("Can't open GPIO device"); + if(-1 == gpio_setup_outputs() || -1 == gpio_setup_inputs()) ERRX("Can't setup GPIO"); +#ifndef SERVER + } +#endif +#endif + SSL_library_init(); + SSL_CTX *ctx = InitCTX(); + fd = OpenConn(atoi(G.port)); +#ifdef SERVER + serverproc(ctx, fd); +#else + clientproc(ctx, fd); +#endif + // newer reached +#ifdef __arm__ + gpio_close(); +#endif + close(fd); + SSL_CTX_free(ctx); + return 0; +} + +static int geterrcode(SSL *ssl, int errcode){ + int sslerr = SSL_get_error(ssl, errcode); + if(SSL_ERROR_WANT_READ == sslerr || + SSL_ERROR_WANT_WRITE == sslerr) return 0; // empty call + int sd = SSL_get_fd(ssl); + if(sslerr != SSL_ERROR_ZERO_RETURN){ + LOGERR("SSL error %d @client %d", sslerr, sd); + WARNX("SSL error %d @client %d", sslerr, sd); + } + return -1; +} + +/** + * @brief read_string - read '\n'-terminated string from SSL + * @param ssl - SSL + * @param buf - buffer for text + * @param l - max buf length (including zero) + * @return amount of bytes read or -1 if client disconnected + */ +int read_string(SSL *ssl, char *buf, int l){ + if(!ssl || l < 1) return 0; + bzero(buf, l); + int bytes = SSL_peek(ssl, buf, l); + DBG("Peek: %d (bufsz %d); buf=%s", bytes, l, buf); + if(bytes < 1){ // nothing to read or error + return geterrcode(ssl, bytes); + } + if(bytes < l && buf[bytes-1] != '\n'){ // string not ready, no buffer overfull + return -1; // wait a rest of string + } + bytes = SSL_read(ssl, buf, l); + DBG("Read: %d", bytes); + if(bytes < 1){ // error + return geterrcode(ssl, bytes); + } + buf[bytes-1] = 0; // replace '\n' with 0 + return bytes; +} + +#ifdef __arm__ +/** + * @brief getpin - get pin number from string + * @param str - received command + * @param idx - index of number in `str` + * @return number or -1 if not found + */ +static int getpin(const char *str, int idx){ + char *eptr = NULL; + const char *start = str + idx; + long x = strtol(start, &eptr, 10); + if(eptr == start) return -1; + if(x < 0 || x > GPIO_MAX_NUMBER) return -1; + return (int)x; +} + +/** + * @brief handle_message - parser or client/server messages + * @param msg - string command + */ +int handle_message(const char *msg){ + int act = -1, pin = -1, ret = FALSE; + if(strncmp(msg, "UP", 2) == 0){ + act = 1; pin = getpin(msg, 2); + }else if(strncmp(msg, "DOWN", 4) == 0){ + act = 0; pin = getpin(msg, 4); + } + DBG("message: '%s', act=%d, pin=%d", msg, act, pin); + if(act != -1 && pin != -1){ + int res = FALSE; + if(act == 1) res = gpio_set_output(pin); + else res = gpio_clear_output(pin); + if(!res) LOGERR("Can't change state according to pin %d", pin); + else{ + LOGMSG("%s gpio %d", act == 1 ? "Set" : "Reset", pin); + verbose(1, "%s gpio %d", act == 1 ? "Set" : "Reset", pin); + ret = TRUE; + } + } + return ret; +} +/** + * @brief poll_gpio - GPIO polling + * @param ssl - ssl array to write + * @param nfd - amount of descriptors (+1 - starting frol ssls[1]) + */ +void poll_gpio(SSL **ssls, int nfd){ + static double t0 = 0.; + if(dtime() - t0 < GPIO_POLL_INTERVAL) return; + char buf[64]; + uint32_t up, down; + if(gpio_poll(&up, &down) > 0){ + if(up) snprintf(buf, 63, "UP%" PRIu32 "\n", up); + else snprintf(buf, 63, "DOWN%" PRIu32 "\n", down); + int l = strlen(buf); + if(nfd == 1){ + if(SSL_write(ssls[0], buf, l) <= 0) WARNX("SSL write error"); + }else{ + for(int i = nfd-1; i > 0; --i){ + if(SSL_write(ssls[i], buf, l) <= 0){ + WARNX("SSL write error"); + } + } + } + } + t0 = dtime(); +} +#endif diff --git a/SSL_sockets_GPIO/sslsock.h b/SSL_sockets_GPIO/sslsock.h new file mode 100644 index 0000000..82515f9 --- /dev/null +++ b/SSL_sockets_GPIO/sslsock.h @@ -0,0 +1,45 @@ +/* + * This file is part of the sslsosk project. + * Copyright 2023 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 + +#include // inet_ntop +#include +#include // addrinfo +#include +#include +#include +#include +#include +#include + +#if ! defined CLIENT && ! defined SERVER +#error "Define CLIENT or SERVER before including this file" +#endif +#if defined CLIENT && defined SERVER +#error "Both CLIENT and SERVER defined" +#endif + +#define BACKLOG 10 + +int open_socket(); +int read_string(SSL *ssl, char *buf, int l); +#ifdef __arm__ +int handle_message(const char *msg); +void poll_gpio(SSL **ssls, int nfd); +#endif diff --git a/SSL_sockets_GPIO/sslsosk.cflags b/SSL_sockets_GPIO/sslsosk.cflags new file mode 100644 index 0000000..68d5165 --- /dev/null +++ b/SSL_sockets_GPIO/sslsosk.cflags @@ -0,0 +1 @@ +-std=c17 \ No newline at end of file diff --git a/SSL_sockets_GPIO/sslsosk.config b/SSL_sockets_GPIO/sslsosk.config new file mode 100644 index 0000000..dbeb595 --- /dev/null +++ b/SSL_sockets_GPIO/sslsosk.config @@ -0,0 +1,9 @@ +#define _GNU_SOURCE +#define _XOPEN_SOURCE 1111 +#define CLIENT +#define EBUG + +#define __arm__ 1 + +//#define SERVER + diff --git a/SSL_sockets_GPIO/sslsosk.creator b/SSL_sockets_GPIO/sslsosk.creator new file mode 100644 index 0000000..e94cbbd --- /dev/null +++ b/SSL_sockets_GPIO/sslsosk.creator @@ -0,0 +1 @@ +[General] diff --git a/SSL_sockets_GPIO/sslsosk.creator.user b/SSL_sockets_GPIO/sslsosk.creator.user new file mode 100644 index 0000000..59db032 --- /dev/null +++ b/SSL_sockets_GPIO/sslsosk.creator.user @@ -0,0 +1,160 @@ + + + + + + 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 + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + Desktop + {91347f2c-5221-46a7-80b1-0a054ca02f79} + 0 + 0 + 0 + + /home/eddy/Docs/SAO/WEB/SSL_Socket_snippet + + + + all + + true + GenericProjectManager.GenericMakeStep + + 1 + Сборка + Сборка + ProjectExplorer.BuildSteps.Build + + + + + clean + + true + GenericProjectManager.GenericMakeStep + + 1 + Очистка + Очистка + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + По умолчанию + GenericProjectManager.GenericBuildConfiguration + + 1 + + + 0 + Развёртывание + Развёртывание + 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/SSL_sockets_GPIO/sslsosk.cxxflags b/SSL_sockets_GPIO/sslsosk.cxxflags new file mode 100644 index 0000000..6435dfc --- /dev/null +++ b/SSL_sockets_GPIO/sslsosk.cxxflags @@ -0,0 +1 @@ +-std=c++17 \ No newline at end of file diff --git a/SSL_sockets_GPIO/sslsosk.files b/SSL_sockets_GPIO/sslsosk.files new file mode 100644 index 0000000..7c9a29d --- /dev/null +++ b/SSL_sockets_GPIO/sslsosk.files @@ -0,0 +1,13 @@ +client.c +client.h +cmdlnopts.c +cmdlnopts.h +daemon.c +daemon.h +gpio.c +gpio.h +main.c +server.c +server.h +sslsock.c +sslsock.h diff --git a/SSL_sockets_GPIO/sslsosk.includes b/SSL_sockets_GPIO/sslsosk.includes new file mode 100644 index 0000000..9c558e3 --- /dev/null +++ b/SSL_sockets_GPIO/sslsosk.includes @@ -0,0 +1 @@ +.