diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..02917e2 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.0) +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}) +add_definitions(" -std=c++11 -Wall -O2 -g") + +install(TARGETS serialmultiplexer RUNTIME DESTINATION bin) 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)); +} diff --git a/main.cpp b/main.cpp index de71444..6a5fe2f 100644 --- a/main.cpp +++ b/main.cpp @@ -14,25 +14,17 @@ #include "serial_io.h" #include "Socket.h" +#include "clienthandler.h" -#define VERSION "v0.5" +#define VERSION "v0.7" -volatile bool stop = false; -volatile bool resettSerialPort = false; -struct epoll_event ev; +sig_atomic_t stop = false; 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\ @@ -85,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(); @@ -103,18 +94,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 = newSock->getFD(); + 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)); @@ -129,44 +124,73 @@ int openSerialPort(const Config& config) std::cout<<"Opeing serial port: "< clients; + int serial = openSerialPort(config); if(!config.noSerial) { - std::cout<<"Using serial port: "< clientSockets; + else + { + std::cout<<"Sinkless mode\n"; + } std::thread* acceptThread; TCPServerSocket* servSock; @@ -174,9 +198,9 @@ int main(int argc, char* argv[]) std::cout<<"opening TCP socket on port "<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 +208,80 @@ 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); 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) + 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) { - if(config.verbose) + try { - std::cout<<"bcst: "; - for( int j = 0; j < readlen; j++ )std::cout<run(&clients, serial, config.verbose); + } + catch(serialIoException& ex) + { + close(serial); + serialPortReconnect(config, ex.what()); } - clientSockets[i]->send(buffer, readlen); } - - char inBuffer[4096]; - int reclen = clientSockets[i]->recv(inBuffer, 4096); - if( reclen > 0 ) + if((ev.events & (EPOLLHUP | EPOLLERR)) || client->isDisconnected()) { - if(config.verbose) + client->cleanUp(); + clients.erase(client); + std::cout<<"client disconnected\n"; + } + clientsMutex.unlock(); + } + else + { + char buffer[4096]; + ssize_t readlen = sRead(serial, buffer, 4096); + if(readlen < 0 && (errno != EAGAIN || errno != EWOULDBLOCK)) + { + close(serial); + serialPortReconnect(config, strerror(errno)); + } + if(config.verbose) + { + std::cout<<"Sending \""; + for(ssize_t i = 0; i < readlen; ++i) { - std::cout<<"rec: "; - for( int j = 0; j < reclen; j++ )std::cout<send(inBuffer+6, reclen-6); - - } - 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)); - } + if(buffer[i] == '\n') + std::cout<<"\\n"; else - { - char response[] = "reinit serial port failed!\n"; - std::cerr<send(response, sizeof(response)); - } + std::cout<cleanUp(); - clientSockets.erase(clientSockets.begin()+i); - i--; - if(i < 0) i=0; + client.write(buffer, readlen); } + clientsMutex.unlock(); } - 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; 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..0e78d0f 100644 --- a/serial_io.h +++ b/serial_io.h @@ -6,13 +6,15 @@ #ifdef __cplusplus #include +#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 +26,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_) + " error: " + strerror(errorNumber_) + "\n"), fd(fd_), errorNumber(errorNumber_) + {} +}; +#endif + #endif // SERIAL_H