From eb6a202c71c5bc3f1bab394157009a3edd5146bb Mon Sep 17 00:00:00 2001 From: Carl Klemm Date: Mon, 10 Jun 2019 17:20:56 +0200 Subject: [PATCH 01/10] bcst: now forwarded to clients --- CMakeLists.txt | 15 +++++++++++++++ main.cpp | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..fddaee1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 2.4) + + +project(serialmultiplexer) + +set(SRC_FILES main.cpp serial_io.cpp Socket.cpp ) +set(LIBS -pthread ) + +add_executable(${PROJECT_NAME} ${SRC_FILES}) + +target_link_libraries( ${PROJECT_NAME} ${LIBS}) +set_target_properties( ${PROJECT_NAME} PROPERTIES COMPILE_FLAGS -m64 LINK_FLAGS -m64) +add_definitions(" -std=c++11 -Wall ") + +install(TARGETS serialmultiplexer RUNTIME DESTINATION bin) diff --git a/main.cpp b/main.cpp index de71444..03c1972 100644 --- a/main.cpp +++ b/main.cpp @@ -229,10 +229,10 @@ int main(int argc, char* argv[]) if(config.verbose) { std::cout<<"bcst: "; - for( int j = 6; j < reclen; j++ )std::cout<send(inBuffer+6, reclen-6); + for(unsigned int j = 0; j < clientSockets.size(); j++) if(i != j) clientSockets[j]->send(inBuffer, reclen); } else if(strncmp( inBuffer, "reinitsp", 8) == 0 && serial != -1) From bc40ddbd9fe33d07f13bc607bfe9baa72bd746a8 Mon Sep 17 00:00:00 2001 From: Carl Klemm Date: Sat, 8 Feb 2020 21:53:09 +0100 Subject: [PATCH 02/10] fixed SIGPIPE killing program --- CMakeLists.txt | 2 +- main.cpp | 148 ++++++++++++++----------------------------------- 2 files changed, 43 insertions(+), 107 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fddaee1..6c8e3e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,6 @@ add_executable(${PROJECT_NAME} ${SRC_FILES}) target_link_libraries( ${PROJECT_NAME} ${LIBS}) set_target_properties( ${PROJECT_NAME} PROPERTIES COMPILE_FLAGS -m64 LINK_FLAGS -m64) -add_definitions(" -std=c++11 -Wall ") +add_definitions(" -std=c++11 -Wall -O2") install(TARGETS serialmultiplexer RUNTIME DESTINATION bin) diff --git a/main.cpp b/main.cpp index 03c1972..9897fb6 100644 --- a/main.cpp +++ b/main.cpp @@ -14,25 +14,18 @@ #include "serial_io.h" #include "Socket.h" +#include "clienthandler.h" -#define VERSION "v0.5" +#define VERSION "v0.6" volatile bool stop = false; volatile bool resettSerialPort = false; -struct epoll_event ev; void intHandler(int sig) { stop = true; } -void alarmHandler(int sig) -{ - resettSerialPort = true; - signal(sig, alarmHandler); - alarm(600); -} - static void printUsage() { std::cout<<"usage mulitplexer [option]\n\ @@ -103,18 +96,22 @@ static int parseCmdArgs(int argc, char** argv, Config *config) return 0; } -void acceptThreadFunction( TCPServerSocket* servSock, std::vector* clientSockets, std::mutex* clientSocketsMutex, int pollQue ) +void acceptThreadFunction( TCPServerSocket* servSock, std::vector* clients, std::mutex* clientsMutex, int pollQue ) { while(!stop) { TCPSocket* newSock = servSock->accept(); if(newSock != nullptr) { - clientSocketsMutex->lock(); - clientSockets->push_back(newSock); // Wait for a client to connect - clientSocketsMutex->unlock(); + clientsMutex->lock(); + clients->push_back(ClientHandler(newSock)); // Wait for a client to connect + struct epoll_event ev; + ev.events = EPOLLIN; + ev.data.fd = clients->size()-1; + clientsMutex->unlock(); epoll_ctl(pollQue, EPOLL_CTL_ADD, newSock->getFD(), &ev); - clientSockets->back()->send("UVOS serial multiplexer " VERSION "\n", sizeof("UVOS serial multiplexer " VERSION "\n")-1); + char welcomeMesg[] = "UVOS serial multiplexer " VERSION "\n"; + clients->back().write(welcomeMesg, sizeof(welcomeMesg)-1); std::cout<<"got client\n"; } std::this_thread::sleep_for(std::chrono::seconds(1)); @@ -148,7 +145,6 @@ int main(int argc, char* argv[]) std::cout<<"UVOS serial mulitplexer "< clientSockets; + std::mutex clientsMutex; + std::vector clients; std::thread* acceptThread; TCPServerSocket* servSock; @@ -176,7 +174,7 @@ int main(int argc, char* argv[]) { servSock = new TCPServerSocket(config.port, 5, true); // Server Socket object servSock->setBlocking(false); - acceptThread = new std::thread(acceptThreadFunction, servSock, &clientSockets, &clientSocketsMutex, pollQue); + acceptThread = new std::thread(acceptThreadFunction, servSock, &clients, &clientsMutex, pollQue); } catch(SocketException &e) { @@ -184,114 +182,52 @@ int main(int argc, char* argv[]) return 1; } - char buffer[4096]; - signal(SIGINT, intHandler); signal(SIGTERM, intHandler); - signal(SIGALRM, alarmHandler); - - if(config.reinit) alarm(600); - + signal(SIGPIPE, SIG_IGN); //ignore SIGPIPE std::cout<<"starting loop\n"; while(!stop) { - epoll_wait(pollQue, &ev, 1, 2000); - int readlen = sRead(serial, buffer, 4096); - for(unsigned int i = 0; i < clientSockets.size(); i++) + struct epoll_event ev; + if( epoll_wait(pollQue, &ev, 1, 2000) == 1) { - clientSocketsMutex.lock(); - try + if(ev.data.fd != -1) { - if(readlen > 0) + int i = ev.data.fd; + std::cout<<"client poll\n"; + clientsMutex.lock(); + if(ev.events & EPOLLIN) clients[i].run(&clients, serial, config.verbose); + if((ev.events & (EPOLLHUP | EPOLLERR)) || clients[i].isDisconnected()) { - if(config.verbose) - { - std::cout<<"bcst: "; - for( int j = 0; j < readlen; j++ )std::cout<send(buffer, readlen); + clients[i].cleanUp(); + clients.erase(clients.begin()+i); + std::cout<<"client "<recv(inBuffer, 4096); - if( reclen > 0 ) + clientsMutex.unlock(); + } + else + { + char buffer[4096]; + int readlen = sRead(serial, buffer, 4096); + if(config.verbose) { - if(config.verbose) - { - std::cout<<"rec: "; - for( int j = 0; j < reclen; j++ )std::cout<send(inBuffer, reclen); - - } - else if(strncmp( inBuffer, "reinitsp", 8) == 0 && serial != -1) - { - if(serialport_set_config(serial, config.baud) == 0) - { - char response[] = "reinit serial port succsesfull\n"; - std::cerr<send(response, sizeof(response)); - } - else - { - char response[] = "reinit serial port failed!\n"; - std::cerr<send(response, sizeof(response)); - } - } - else - { - if(config.verbose) - { - std::cout<<"wrote \""; - for( int j = 0; j < reclen; j++ )std::cout<cleanUp(); - clientSockets.erase(clientSockets.begin()+i); - i--; - if(i < 0) i=0; + client.write(buffer, readlen); } } - catch(SocketException &e) - { - std::cout<cleanUp(); - clientSockets.erase(clientSockets.begin()+i); - i--; - if(i < 0) i=0; - } - clientSocketsMutex.unlock(); - } - if(resettSerialPort) - { - close(serial); - serial = openSerialPort(config); - resettSerialPort = false; } } acceptThread->join(); delete acceptThread; - for(unsigned int i = 0; i < clientSockets.size(); i++) clientSockets[i]->cleanUp(); + for(ClientHandler& client : clients) client.cleanUp(); servSock->cleanUp(); delete servSock; return 0; From 15216f7f3a32861ec2faf30f5c449728db1ef569 Mon Sep 17 00:00:00 2001 From: Carl Klemm Date: Sat, 8 Feb 2020 21:53:53 +0100 Subject: [PATCH 03/10] bumped version to v 0.7 --- main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.cpp b/main.cpp index 9897fb6..bb63c82 100644 --- a/main.cpp +++ b/main.cpp @@ -16,7 +16,7 @@ #include "Socket.h" #include "clienthandler.h" -#define VERSION "v0.6" +#define VERSION "v0.7" volatile bool stop = false; volatile bool resettSerialPort = false; From 84dd4bc30a1116be181edc102275658bb4106a12 Mon Sep 17 00:00:00 2001 From: uvos Date: Sat, 2 Oct 2021 14:22:00 +0200 Subject: [PATCH 04/10] fix race bug --- CMakeLists.txt | 2 +- main.cpp | 68 ++++++++++++++++++++++++++++++++++++-------------- serial_io.cpp | 10 +++++--- serial_io.h | 17 +++++++++++-- 4 files changed, 71 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c8e3e7..fad427c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,6 @@ add_executable(${PROJECT_NAME} ${SRC_FILES}) target_link_libraries( ${PROJECT_NAME} ${LIBS}) set_target_properties( ${PROJECT_NAME} PROPERTIES COMPILE_FLAGS -m64 LINK_FLAGS -m64) -add_definitions(" -std=c++11 -Wall -O2") +add_definitions(" -std=c++11 -Wall -O2 -g") install(TARGETS serialmultiplexer RUNTIME DESTINATION bin) diff --git a/main.cpp b/main.cpp index bb63c82..d72bc84 100644 --- a/main.cpp +++ b/main.cpp @@ -18,8 +18,7 @@ #define VERSION "v0.7" -volatile bool stop = false; -volatile bool resettSerialPort = false; +sig_atomic_t stop = false; void intHandler(int sig) { @@ -136,21 +135,32 @@ int openSerialPort(const Config& config) return serial; } +void serialConnect(const Config& config, int* serial) +{ + if(*serial != -1) + close(*serial); + std::cout<<"Using serial port: "< clients; + int serial = openSerialPort(config); if(!config.noSerial) { - std::cout<<"Using serial port: "< clients; + else + { + std::cout<<"Sinkless mode\n"; + } std::thread* acceptThread; TCPServerSocket* servSock; @@ -172,7 +182,7 @@ int main(int argc, char* argv[]) std::cout<<"opening TCP socket on port "<setBlocking(false); acceptThread = new std::thread(acceptThreadFunction, servSock, &clients, &clientsMutex, pollQue); } @@ -184,21 +194,27 @@ int main(int argc, char* argv[]) signal(SIGINT, intHandler); signal(SIGTERM, intHandler); - signal(SIGPIPE, SIG_IGN); //ignore SIGPIPE + signal(SIGPIPE, SIG_IGN); std::cout<<"starting loop\n"; while(!stop) { struct epoll_event ev; - if( epoll_wait(pollQue, &ev, 1, 2000) == 1) + if(epoll_wait(pollQue, &ev, 1, 2000) == 1) { if(ev.data.fd != -1) { - int i = ev.data.fd; - std::cout<<"client poll\n"; clientsMutex.lock(); - if(ev.events & EPOLLIN) clients[i].run(&clients, serial, config.verbose); + int i = ev.data.fd; + if(abs(i) >= clients.size()) + { + clientsMutex.unlock(); + continue; + } + std::cout<<"client poll\n"; + if(ev.events & EPOLLIN) + clients[i].run(&clients, serial, config.verbose); if((ev.events & (EPOLLHUP | EPOLLERR)) || clients[i].isDisconnected()) { clients[i].cleanUp(); @@ -210,24 +226,38 @@ int main(int argc, char* argv[]) else { char buffer[4096]; - int readlen = sRead(serial, buffer, 4096); + ssize_t readlen = sRead(serial, buffer, 4096); + if(readlen < 0 && (errno != EAGAIN || errno != EWOULDBLOCK)) + { + std::cout<<"Serial port error reconnecting\n"; + serialConnect(config, &serial); + } if(config.verbose) { std::cout<<"Sending \""; - for(size_t i = 0; i < readlen; ++i) std::cout<join(); delete acceptThread; - for(ClientHandler& client : clients) client.cleanUp(); + for(ClientHandler& client : clients) + client.cleanUp(); servSock->cleanUp(); delete servSock; return 0; diff --git a/serial_io.cpp b/serial_io.cpp index 34e57a6..317fb3c 100644 --- a/serial_io.cpp +++ b/serial_io.cpp @@ -1,13 +1,15 @@ #include "serial_io.h" -void sWrite(int port, char string[], size_t length) +ssize_t sWrite(int port, char string[], size_t length) { - if(port != -1) write(port, string, length); + if(port != -1) return write(port, string, length); + else return 0; } -void sWrite(int port, const char string[], size_t length) +ssize_t sWrite(int port, const char string[], size_t length) { - if(port != -1) write(port, string, length); + if(port != -1) return write(port, string, length); + else return 0; } ssize_t sRead(int port, void *buf, size_t count) diff --git a/serial_io.h b/serial_io.h index 844e74e..f0c99b3 100644 --- a/serial_io.h +++ b/serial_io.h @@ -6,13 +6,14 @@ #ifdef __cplusplus #include +#include #endif #define BAUDRATE B38400 -void sWrite(int port, char string[], size_t length); +ssize_t sWrite(int port, char string[], size_t length); -void sWrite(int port, const char string[], size_t length); +ssize_t sWrite(int port, const char string[], size_t length); ssize_t sRead(int port, void *buf, size_t count); @@ -24,5 +25,17 @@ int serialport_set_config(int fd, int baud); int serialport_init(const char* device, int baud = BAUDRATE, bool block = false); +#ifdef __cplusplus +class serialIoException: public std::runtime_error +{ + public: + int fd; + int errorNumber; + serialIoException(int fd_, int errorNumber_): + std::runtime_error("file descriptor error, fd: " + std::to_string(fd_) + " errno: " + std::to_string(errorNumber_) + "\n"), fd(fd_), errorNumber(errorNumber_) + {} +}; +#endif + #endif // SERIAL_H From 6f418f3c8f6f517c0815e6d4a01d6b9a29044a39 Mon Sep 17 00:00:00 2001 From: uvos Date: Sat, 2 Oct 2021 19:09:14 +0200 Subject: [PATCH 05/10] i am an idiot --- main.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/main.cpp b/main.cpp index d72bc84..d73431e 100644 --- a/main.cpp +++ b/main.cpp @@ -106,10 +106,10 @@ void acceptThreadFunction( TCPServerSocket* servSock, std::vectorpush_back(ClientHandler(newSock)); // Wait for a client to connect struct epoll_event ev; ev.events = EPOLLIN; - ev.data.fd = clients->size()-1; + ev.data.fd = newSock->getFD(); clientsMutex->unlock(); epoll_ctl(pollQue, EPOLL_CTL_ADD, newSock->getFD(), &ev); - char welcomeMesg[] = "UVOS serial multiplexer " VERSION "\n"; + char welcomeMesg[] = "UVOS serial multiplexer " VERSION "\n"; clients->back().write(welcomeMesg, sizeof(welcomeMesg)-1); std::cout<<"got client\n"; } @@ -205,21 +205,19 @@ int main(int argc, char* argv[]) { if(ev.data.fd != -1) { - clientsMutex.lock(); - int i = ev.data.fd; - if(abs(i) >= clients.size()) - { - clientsMutex.unlock(); + std::vector::iterator client = + std::find(clients.begin(), clients.end(), ev.data.fd); + if(client == clients.end()) continue; - } + clientsMutex.lock(); std::cout<<"client poll\n"; if(ev.events & EPOLLIN) - clients[i].run(&clients, serial, config.verbose); - if((ev.events & (EPOLLHUP | EPOLLERR)) || clients[i].isDisconnected()) + client->run(&clients, serial, config.verbose); + if((ev.events & (EPOLLHUP | EPOLLERR)) || client->isDisconnected()) { - clients[i].cleanUp(); - clients.erase(clients.begin()+i); - std::cout<<"client "<cleanUp(); + clients.erase(client); + std::cout<<"client disconnected\n"; } clientsMutex.unlock(); } From 3c5834e2069514567d93c1cde9bf16d053e3729f Mon Sep 17 00:00:00 2001 From: uvos Date: Fri, 14 Jan 2022 18:40:00 +0100 Subject: [PATCH 06/10] add missing files --- clienthandler.cpp | 0 clienthandler.h | 125 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 clienthandler.cpp create mode 100644 clienthandler.h diff --git a/clienthandler.cpp b/clienthandler.cpp new file mode 100644 index 0000000..e69de29 diff --git a/clienthandler.h b/clienthandler.h new file mode 100644 index 0000000..e8eedbb --- /dev/null +++ b/clienthandler.h @@ -0,0 +1,125 @@ +#pragma once + +#include +#include +#include +#include +#include "Socket.h" +#include "serial_io.h" + +class ClientHandler +{ +private: + bool _isBroadcasting = false; + CommunicatingSocket *_socket; + bool _disconnected = false; + + +public: + + void cleanUp(); + ClientHandler(CommunicatingSocket * const socket); + ~ClientHandler(); + bool operator==(int fd); + bool operator!=(int fd); + bool operator==(ClientHandler& other); + bool operator!=(ClientHandler& other); + bool isDisconnected(); + bool run(std::vector* clients, int serial, bool verbose = false); + void write(const char* buffer, const size_t len); + void dropData(); +}; + +ClientHandler::ClientHandler(CommunicatingSocket * const socket): _socket(socket) +{} + +ClientHandler::~ClientHandler() +{ +} + +void ClientHandler::cleanUp() +{ + _socket->cleanUp(); + delete _socket; +} + +void ClientHandler::dropData() +{ + std::array buffer; + while(_socket->recv(buffer.data(), 4096) > 0); +} + +bool ClientHandler::run(std::vector* clients, int serial, bool verbose) +{ + std::array buffer; + int reclen = 0; + try + { + reclen = _socket->recv(buffer.data(), 4096); + if(verbose) std::cout<<"Recived "< 0) + { + if(!_isBroadcasting && reclen >= 5 && strncmp( buffer.data(), "bcst:", 5) == 0) _isBroadcasting = true; + + if(_isBroadcasting) + { + if(verbose) std::cout<<"Boradcasting "<send(buffer, len); + } + catch (SocketException &e) + { + std::cout<getFD(); +} + + +bool ClientHandler::operator!=(int fd) +{ + return fd != _socket->getFD(); +} + +bool ClientHandler::operator==(ClientHandler& other) +{ + return _socket->getFD() == other._socket->getFD(); +} + + +bool ClientHandler::operator!=(ClientHandler& other) +{ + return !(operator==(other)); +} From 977e7fb4f987f7d992b40d1b579f1a961cb27120 Mon Sep 17 00:00:00 2001 From: uvos Date: Wed, 21 Dec 2022 22:20:27 +0100 Subject: [PATCH 07/10] up cmake version to silence warning --- CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fad427c..c8a7a61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,4 @@ -cmake_minimum_required(VERSION 2.4) - - +cmake_minimum_required(VERSION 3.0) project(serialmultiplexer) set(SRC_FILES main.cpp serial_io.cpp Socket.cpp ) From 2ec88114c61dcb0e6253aa3d8312ff5364c79080 Mon Sep 17 00:00:00 2001 From: uvos Date: Wed, 21 Dec 2022 23:38:14 +0100 Subject: [PATCH 08/10] dont force 64bit --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c8a7a61..02917e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,6 @@ set(LIBS -pthread ) add_executable(${PROJECT_NAME} ${SRC_FILES}) target_link_libraries( ${PROJECT_NAME} ${LIBS}) -set_target_properties( ${PROJECT_NAME} PROPERTIES COMPILE_FLAGS -m64 LINK_FLAGS -m64) add_definitions(" -std=c++11 -Wall -O2 -g") install(TARGETS serialmultiplexer RUNTIME DESTINATION bin) From 229932b2746df38d582b13d35fedf40541445def Mon Sep 17 00:00:00 2001 From: uvos Date: Tue, 22 Aug 2023 11:27:21 +0200 Subject: [PATCH 09/10] make serial handling more robust to hw errors --- main.cpp | 51 ++++++++++++++++++++++++++++++++++++++++----------- serial_io.h | 3 ++- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/main.cpp b/main.cpp index d73431e..7ebae46 100644 --- a/main.cpp +++ b/main.cpp @@ -77,7 +77,6 @@ static int parseCmdArgs(int argc, char** argv, Config *config) { config->noSerial=true; } - else if (std::string(argv[i]) == "-r" || std::string(argv[i]) == "--rates") { printRates(); @@ -135,12 +134,32 @@ int openSerialPort(const Config& config) return serial; } -void serialConnect(const Config& config, int* serial) +int serialPortReconnect(Config& config, std::string err) { - if(*serial != -1) - close(*serial); - std::cout<<"Using serial port: "<run(&clients, serial, config.verbose); + { + try + { + client->run(&clients, serial, config.verbose); + } + catch(serialIoException& ex) + { + close(serial); + serialPortReconnect(config, ex.what()); + } + } if((ev.events & (EPOLLHUP | EPOLLERR)) || client->isDisconnected()) { client->cleanUp(); @@ -227,8 +256,8 @@ int main(int argc, char* argv[]) ssize_t readlen = sRead(serial, buffer, 4096); if(readlen < 0 && (errno != EAGAIN || errno != EWOULDBLOCK)) { - std::cout<<"Serial port error reconnecting\n"; - serialConnect(config, &serial); + close(serial); + serialPortReconnect(config, strerror(errno)); } if(config.verbose) { diff --git a/serial_io.h b/serial_io.h index f0c99b3..0e78d0f 100644 --- a/serial_io.h +++ b/serial_io.h @@ -7,6 +7,7 @@ #ifdef __cplusplus #include #include +#include #endif #define BAUDRATE B38400 @@ -32,7 +33,7 @@ class serialIoException: public std::runtime_error int fd; int errorNumber; serialIoException(int fd_, int errorNumber_): - std::runtime_error("file descriptor error, fd: " + std::to_string(fd_) + " errno: " + std::to_string(errorNumber_) + "\n"), fd(fd_), errorNumber(errorNumber_) + std::runtime_error("file descriptor error, fd: " + std::to_string(fd_) + " error: " + strerror(errorNumber_) + "\n"), fd(fd_), errorNumber(errorNumber_) {} }; #endif From 56d5798cb12035e2165c0518e4310847ecd93fde Mon Sep 17 00:00:00 2001 From: uvos Date: Thu, 31 Aug 2023 00:05:03 +0200 Subject: [PATCH 10/10] Dont exit on serial port failure --- main.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/main.cpp b/main.cpp index 7ebae46..6a5fe2f 100644 --- a/main.cpp +++ b/main.cpp @@ -124,10 +124,7 @@ int openSerialPort(const Config& config) std::cout<<"Opeing serial port: "<