From d5b71b26cc69d925d910aea50adee9c555a04b4c Mon Sep 17 00:00:00 2001 From: hama Date: Thu, 5 Mar 2015 18:03:18 +0100 Subject: [PATCH] ReTCP.* --- base/ReLogger.hpp | 2 +- base/baselocations.hpp | 1 + base/rebase.hpp | 1 + cunit/cuReDirTools.cpp | 2 +- cunit/testall.cpp | 2 +- net/ReTCP.cpp | 345 +++++++++++++++++++++++++++++++++++++++++ net/ReTCP.hpp | 11 ++ net/renet.hpp | 1 + 8 files changed, 362 insertions(+), 3 deletions(-) create mode 100644 net/ReTCP.cpp create mode 100644 net/ReTCP.hpp diff --git a/base/ReLogger.hpp b/base/ReLogger.hpp index b1e99ec..f533c2f 100644 --- a/base/ReLogger.hpp +++ b/base/ReLogger.hpp @@ -56,7 +56,7 @@ enum ReLogCategory { CAT_LIB = 0x00010000, CAT_OS = 0x00020000, CAT_FILE = 0x00040000, - CAT_PROG = 0x00080000, + CAT_PROCESS = 0x00080000, CAT_RESOURCE = 0x00100000, CAT_TEST = 0x00200000, CAT_SECURITY = 0x00400000, diff --git a/base/baselocations.hpp b/base/baselocations.hpp index 39f9eab..be56134 100644 --- a/base/baselocations.hpp +++ b/base/baselocations.hpp @@ -18,6 +18,7 @@ enum RELOC_LIB { LC_SEQARRAY = 50200, LC_HASHLIST = 50300, LC_TRAVERSER = 50400, + LC_TCP = 50500, }; enum RELOC_UDPCONNECTION { LC_UDPCONNECTION_CONSTRUCT = 50101, diff --git a/base/rebase.hpp b/base/rebase.hpp index f37379d..beed8a9 100644 --- a/base/rebase.hpp +++ b/base/rebase.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #define __LITTLE_ENDIAN__ //#define __BIG_ENDIAN__ diff --git a/cunit/cuReDirTools.cpp b/cunit/cuReDirTools.cpp index 851eec4..9eacdfd 100644 --- a/cunit/cuReDirTools.cpp +++ b/cunit/cuReDirTools.cpp @@ -72,7 +72,7 @@ private: } } void testRandom(){ - const char* argv[] = { "random", "-l10", "-s", "90", "100", + const char* argv[] = { "random", "-l20", "-s", "40", "50", NULL }; ReDirRandom(m_logger).run(-1, argv); } diff --git a/cunit/testall.cpp b/cunit/testall.cpp index 38f4fb9..666afe4 100644 --- a/cunit/testall.cpp +++ b/cunit/testall.cpp @@ -82,10 +82,10 @@ void testAll() { try { testOs(); if (s_testAll) { - testBase(); testString(); testMath(); testOs(); + testBase(); } } catch (ReException e) { fprintf(stderr, "testBase.cpp: unexpected exception: %s\n", diff --git a/net/ReTCP.cpp b/net/ReTCP.cpp new file mode 100644 index 0000000..61d20cc --- /dev/null +++ b/net/ReTCP.cpp @@ -0,0 +1,345 @@ +/* + * ReTCP.cpp + * + * Created on: 04.03.2015 + * Author: hm + */ + +#include "base/rebase.hpp" +#include "net/renet.hpp" + +enum LOCATION_DIRTOOL { + LC_LISTEN_FOR_ALL_1 = LC_TCP + 1, // 50501 + LC_LISTEN_FOR_ALL_2, // 50502 + LC_LISTEN_FOR_ALL_3, // 50503 + LC_LISTEN_FOR_ALL_4, // 50504 + LC_LISTEN_FOR_ALL_5, // 50505 + LC_LISTEN_FOR_ALL_6, // 50506 + LC_WRITE_1, // 50507 +}; + +/** + * Base class for TCP servers and clients. + */ +class ReTCPConnection { +public: + ReTCPConnection(int id, ReLogger* logger); + virtual ~ReTCPConnection(); +public: + /** + * Returns the connection id. + * @return the id + */ + inline int id() const { + return m_id; + } + /** + * Returns the connection port. + * @return the port + */ + inline int port() const { + return m_port; + } + /** + * Returns the socket (ip:port). + * @return a string describing the socket + */ + const char* socketName() const{ + return m_socketName.str(); + } + void receive(ReByteBuffer& command, ReByteBuffer& message); + void send(const char* command, const char* message, int length = -1); + /** Sets the socket handle. + * @param handle the socket handle to set + */ + inline void setHandleSocket(int handle){ + m_handleSocket = handle; + } + /** Sets the id + * @param id the id to set + */ + inline void setId(int id){ + m_id = id; + } +protected: + int m_port; + ReByteBuffer m_socketName; + ReByteBuffer m_received; + ReLogger* m_logger; + int m_handleSocket; + struct sockaddr_in m_address; + int m_id; + uint32_t m_noSent; + uint32_t m_noReceived; +}; + +class ReTCPServerConnection: public ReTCPConnection { +public: + ReTCPServerConnection(int id, ReLogger* logger); + virtual ~ReTCPServerConnection(); +public: + void handleConnection(); + +}; +/** + * Implements a multithreaded TCP server. + */ +class ReTCPServer: public ReTCPConnection { +public: + ReTCPServer(ReLogger* logger, int maxConnections = 16); + virtual ~ReTCPServer(); +public: + bool listenForAll(); +private: + ReTCPServerConnection* createConnection(int id, int socket, + struct sockaddr& address); +protected: + int m_maxConnections; + int m_countConnections; + ReTCPServerConnection** m_connections; +}; + +/** + * Implements a TCP client. + */ +class ReTCPClient: public ReTCPConnection { +public: + ReTCPClient(ReLogger* logger); + virtual ~ReTCPClient(); +}; + +/** + * Constructor. + * + * @param id an identifier for logging + * @param logger the logger for error handling + */ +ReTCPConnection::ReTCPConnection(int id, ReLogger* logger) : + m_port(0), + m_socketName(), + m_received(), + m_logger(logger), + m_handleSocket(-1), + // m_address + m_id(id), + m_noSent(0), + m_noReceived(0){ + memset(&m_address, 0, sizeof m_address); +} + +/** + * Destructor. + */ +ReTCPConnection::~ReTCPConnection() { +} + +void ReTCPConnection::receive(ReByteBuffer& command, ReByteBuffer& message){ + +} +void ReTCPConnection::send(const char* command, const char* message, + int length){ + if (length < 0) + length = strlen(message); + ReByteBuffer header; + ++m_noSent; + header.appendFix(command, -1, 8, 8, NULL).appendInt(length, "%08x"); + header.append(reinterpret_cast(&m_noSent), sizeof m_noSent); + int error = 0; +#if defined __linux__ + if (write(m_handleSocket, header.str(), header.length()) != header.length()) + error = getLastOSError(); + if (write(m_handleSocket, message, length) != length) + error = getLastOSError(); + error = error + 0; +#elif defined __WIN32__ +#endif + if (error != 0){ + error += 0; + m_logger->sayF(LOG_ERROR | CAT_NETWORK, LC_WRITE_1, + i18n("Id=$1: cannot write ($1): $2")); + //.arg.(m_id) + // .arg(error).arg(m_socketName).end(); + } +} + +/** + * Constructor. + * + * @param id an identifier for logging + * @param logger the logger for error handling + */ +ReTCPServerConnection::ReTCPServerConnection(int id, ReLogger* logger) : + ReTCPConnection(id, logger) { +} + +/** + * Destructor. + */ +ReTCPServerConnection::~ReTCPServerConnection(){ +} + +/** + * Constructor. + * + * @param logger the logger for error handling + * @param maxConnections maximal count of threads handling a connection + */ +ReTCPServer::ReTCPServer(ReLogger* logger, int maxConnections) : + ReTCPConnection(0, logger), + m_maxConnections(maxConnections), + m_countConnections(0), + m_connections(new ReTCPServerConnection*[maxConnections]) { +} + +/** + * Destructor. + */ +ReTCPServer::~ReTCPServer() { + for (int ii = 0; ii < m_countConnections; ii++) { + delete m_connections[ii]; + m_connections[ii] = NULL; + } + delete[] m_connections; + m_connections = NULL; +} + +ReTCPServerConnection* ReTCPServer::createConnection(int id, int socket, + struct sockaddr& address) { + ReTCPServerConnection* rc = NULL; + + for (int ii = 0; ii < m_maxConnections; ii++) { + if (m_connections[ii] == NULL) + m_connections[ii] = rc = new ReTCPServerConnection(id, m_logger); + else if (m_connections[ii]->id() < 0) { + rc = m_connections[ii]; + rc->setId(id); + } + } + if (rc != NULL) { + rc->setHandleSocket(socket); + rc->setAddress(address); + } + return rc; +} + + +/** + * The start routine of pthread_start + * + * This will handle the connection for each client (in an own thread). + * + * @param pConnection a void* pointer to the ReTCPServerConnection instance + * */ +void* connection_handler(void *pConnection) { + ReTCPServerConnection* connection = + reinterpret_cast(pConnection); + connection->handleConnection(); +} + + +/** + * Accepts connections and create a thread which will handle this connection. + */ +bool ReTCPServer::listenForAll() { + bool rc = false; + //Create socket + m_handleSocket = socket(AF_INET, SOCK_STREAM, 0); + if (m_handleSocket == -1) { + m_logger->sayF(LOG_ERROR | CAT_NETWORK, LC_LISTEN_FOR_ALL_1, + i18n("cannot create a socket: $1")).arg(errno).end(); + } else { + //Prepare the sockaddr_in structure + m_address.sin_family = AF_INET; + m_address.sin_addr.s_addr = INADDR_ANY; + m_address.sin_port = htons(m_port); + + //Bind + if (bind(m_handleSocket, (struct sockaddr *) &m_address, sizeof(m_address)) + < 0) { + m_logger->sayF(LOG_ERROR | CAT_NETWORK, LC_LISTEN_FOR_ALL_2, + i18n("cannot bind: $1")).arg( + errno).end(); + } else { + //Listen + listen(m_handleSocket, 3); + + //Accept and incoming connection + m_logger->sayF(LOG_INFO | CAT_NETWORK, LC_LISTEN_FOR_ALL_3, + i18n("listening on $1...")).arg(m_port).end(); + int nextId = 1; + //Accept and incoming connection + int clientSocket; + struct sockaddr addrClient; + socklen_t lengthAddr = sizeof(struct sockaddr_in); + while ((clientSocket = accept(m_handleSocket, + (struct sockaddr *) &addrClient, &lengthAddr)) != 0) { + m_logger->sayF(LOG_INFO | CAT_NETWORK, LC_LISTEN_FOR_ALL_4, + i18n("accepted: $1")).arg(m_port).end(); + if (m_countConnections >= m_maxConnections) { + // close the connection atonce: + m_logger->sayF(LOG_WARNING | CAT_NETWORK, + LC_LISTEN_FOR_ALL_5, + i18n("connection refused (too many connections): $1")) + .arg(m_port).end(); + close(clientSocket); + } else { + pthread_t sniffer_thread; + ReTCPConnection* connection = createConnection(nextId++, + clientSocket, addrClient); + + if (pthread_create(&sniffer_thread, NULL, + connection_handler, (void*) connection) < 0) { + m_logger->sayF(LOG_ERROR | CAT_PROCESS, + LC_LISTEN_FOR_ALL_6, + i18n("cannot create a thread: $1")).arg( + getLastOSError()).end(); + close(clientSocket); + } + + //Now join the thread , so that we dont terminate before the thread + //pthread_join( sniffer_thread , NULL); + puts("Handler assigned"); + } + } + + if (clientSocket < 0) { + perror("accept failed"); + return 1; + } + } + } + return rc; +} + +void ReTCPServerConnection::handleConnection() { + //Get the socket descriptor + int read_size; + char *message, client_message[2000]; +#if 0 + receive(m_received, command); + if (! m_received.startsWith("login")) +//Send some messages to the m_addrClient + message = "Greetings! I am your connection handler\n"; + write(m_handleSocket, message, strlen(message)); + + message = "Now type something and i shall repeat what you type \n"; + write(m_handleSocket, message, strlen(message)); + +//Receive a message from m_addrClient + while ((read_size = recv(sock, client_message, 2000, 0)) > 0) { + //Send the message back to m_addrClient + write(m_handleSocket, client_message, strlen(client_message)); + } + + if (read_size == 0) { + puts("Client disconnected"); + fflush(stdout); + } else if (read_size == -1) { + perror("recv failed"); + } +#endif +//Free the socket pointer + close(m_handleSocket); + m_id = -1; +} + diff --git a/net/ReTCP.hpp b/net/ReTCP.hpp new file mode 100644 index 0000000..0f7d6a1 --- /dev/null +++ b/net/ReTCP.hpp @@ -0,0 +1,11 @@ +/* + * ReTCP.hpp + * + * Created on: 04.03.2015 + * Author: hm + */ + +#ifndef NET_RETCP_HPP_ +#define NET_RETCP_HPP_ + +#endif /* NET_RETCP_HPP_ */ diff --git a/net/renet.hpp b/net/renet.hpp index ba71b75..33505cf 100644 --- a/net/renet.hpp +++ b/net/renet.hpp @@ -9,5 +9,6 @@ #define NET_RENET_HPP_ #include "net/ReUdpConnection.hpp" +#include "net/ReTCP.hpp" #endif /* NET_RENET_HPP_ */ -- 2.39.5