From: J. Hamatoma Date: Sat, 14 Dec 2013 23:54:44 +0000 (+0100) Subject: dayly work X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=7caef6d5af3c94075278c77d28e44313e70d732b;p=reqt dayly work --- diff --git a/rplcore/rplcontainer.cpp b/rplcore/rplcontainer.cpp index 875570c..afe61ea 100644 --- a/rplcore/rplcontainer.cpp +++ b/rplcore/rplcontainer.cpp @@ -63,6 +63,13 @@ RplContainer::RplContainer(size_t sizeHint) : m_readPosition(NULL) { } + +/** + * @brief Destructor. + */ +RplContainer::~RplContainer(){ +} + /** * @brief Adds an type to the type list. * diff --git a/rplcore/rplcontainer.hpp b/rplcore/rplcontainer.hpp index 1289f4c..99bc3bc 100644 --- a/rplcore/rplcontainer.hpp +++ b/rplcore/rplcontainer.hpp @@ -29,6 +29,12 @@ public: static const char* MAGIC_1; public: RplContainer(size_t sizeHint); + virtual ~RplContainer(); +private: + // No copy constructor: no implementation! + RplContainer(const RplContainer& source); + // Prohibits assignment operator: no implementation! + RplContainer& operator =(const RplContainer& source); public: // Building the container: void addType(type_tag_t tag); diff --git a/rplcore/rplcore.hpp b/rplcore/rplcore.hpp index e966f34..2938394 100644 --- a/rplcore/rplcore.hpp +++ b/rplcore/rplcore.hpp @@ -33,5 +33,6 @@ typedef unsigned char uint8_t; #include "rplcontainer.hpp" #include "rplstring.hpp" #include "rplconfig.hpp" +#include "rplterminator.hpp" #endif // RPLCORE_HPP diff --git a/rplcore/rpllogger.cpp b/rplcore/rpllogger.cpp index 6d6f20a..d3181aa 100644 --- a/rplcore/rpllogger.cpp +++ b/rplcore/rpllogger.cpp @@ -181,6 +181,36 @@ char RplLogger::getPrefixOfLevel(RplLoggerLevel level) const { } return rc; } + +/** + * @brief Tests whether at least one appender is active for a given level. + * + * @param level level to test + * @return false: all appenders are not activated by this level
+ * true: otherwise + */ +bool RplLogger::isActive(RplLoggerLevel level) const{ + bool rc = false; + for (size_t ix = 0; ! rc && ix < m_countAppenders; ix++){ + RplAppender* appender = m_appenders[ix]; + if (appender->isActive(level)) + rc = true; + } + return rc; +} + +/** + * @brief Sets the log level for all appenders. + * + * @param level level to set + */ +void RplLogger::setLevel(RplLoggerLevel level){ + for (size_t ix = 0; ix < m_countAppenders; ix++){ + RplAppender* appender = m_appenders[ix]; + appender->setLevel(level); + } +} + /** * @brief Returns the standard prefix of a logging line. * diff --git a/rplcore/rpllogger.hpp b/rplcore/rpllogger.hpp index c01d94e..3c0af24 100644 --- a/rplcore/rpllogger.hpp +++ b/rplcore/rpllogger.hpp @@ -32,6 +32,12 @@ class RplAppender public: RplAppender(const QByteArray& name); virtual ~RplAppender(); +private: + // No copy constructor: no implementation! + RplAppender(const RplAppender& source); + // Prohibits assignment operator: no implementation! + RplAppender& operator =(const RplAppender& source); +public: virtual void log(RplLoggerLevel level, int location, const char* message, RplLogger* logger) = 0; bool isActive(RplLoggerLevel level); @@ -61,6 +67,11 @@ private: public: RplLogger(); virtual ~RplLogger(); +private: + // No copy constructor: no implementation! + RplLogger(const RplLogger& source); + // Prohibits assignment operator: no implementation! + RplLogger& operator =(const RplLogger& source); public: bool log(RplLoggerLevel level, int location, const char* message); bool log(RplLoggerLevel level, int location, const QByteArray& message); @@ -74,6 +85,8 @@ public: QByteArray buildStdPrefix(RplLoggerLevel level, int location); const QByteArray& getStdPrefix(RplLoggerLevel level, int location); char getPrefixOfLevel(RplLoggerLevel level) const; + bool isActive(RplLoggerLevel level) const; + void setLevel(RplLoggerLevel level); private: // the assigned appenders: RplAppender* m_appenders[16]; diff --git a/rplcore/rplterminator.cpp b/rplcore/rplterminator.cpp new file mode 100644 index 0000000..41dd99f --- /dev/null +++ b/rplcore/rplterminator.cpp @@ -0,0 +1,73 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. + */ +#include "rplcore.hpp" + +enum { + LOC_CAUSE_TERMINATION_1 = RPL_FIRST_OF(RPLMODULE_TERMINATOR), // 901 +}; + +/** + * @class RplTerminator rplterminator.hpp "rplcore/rplterminator.hpp" + * + * @brief Implements a thread stopper. + * + * Allows to terminate a thread avoiding unfreeing resources, deadlocks etc. + * + * The application must create one instance of a RplTerminator. + * All threads gets this instance and call them periodically if the application should stop. + * If yes they finish their work, frees the resources and stop. + * + */ + +/** + * @brief Constructor. + * @param logger NULL or the logger. Used to protocol the termination + */ +RplTerminator::RplTerminator(RplLogger* logger) : + m_stop(false), + m_logger(logger) +{ +} + +/** + * @brief Destructor. + */ +RplTerminator::~RplTerminator(){ +} + +/** + * @brief Defines the stop of all threads. + * + * @param reason the reason of the termination. Will be logged (if a logger is defined) + * @param file NULL or the file of the caller. Normally set with __FILE__ + * @param lineNo 0 or the line number of the caller. Normally set with __LINE__ + * @param level log level + * @param location 0 or the location of the caller + */ +void RplTerminator::causeTermination(const char* reason, const char* file, + int lineNo, RplLoggerLevel level, int location){ + if (m_logger != NULL){ + QByteArray message(reason); + if (file != NULL){ + message.append(" [").append(file).append(lineNo).append("]"); + } + m_logger->log(level, location == 0 ? LOC_CAUSE_TERMINATION_1 : location, + message); + } + m_stop = true; +} + +/** + * @brief Tests whether the thread should be stopped. + * @return true: the thread should be stopped.
+ * false: otherwise + */ +bool RplTerminator::isStopped() const{ + return m_stop; +} + diff --git a/rplcore/rplterminator.hpp b/rplcore/rplterminator.hpp new file mode 100644 index 0000000..25e5fca --- /dev/null +++ b/rplcore/rplterminator.hpp @@ -0,0 +1,30 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. + */ +#ifndef RPLTERMINATOR_HPP +#define RPLTERMINATOR_HPP + +class RplTerminator +{ +public: + RplTerminator(RplLogger* logger = NULL); + virtual ~RplTerminator(); +private: + // No copy constructor: no implementation! + RplTerminator(const RplTerminator& source); + // Prohibits assignment operator: no implementation! + RplTerminator& operator =(const RplTerminator& source); +public: + void causeTermination(const char* reason, const char* file = NULL, + int lineNo = 0, RplLoggerLevel level = LOG_ERROR, int location = 0); + bool isStopped() const; +private: + bool m_stop; + RplLogger* m_logger; +}; + +#endif // RPLTERMINATOR_HPP diff --git a/rplcore/rpltest.hpp b/rplcore/rpltest.hpp index 95fc248..142459f 100644 --- a/rplcore/rpltest.hpp +++ b/rplcore/rpltest.hpp @@ -18,6 +18,11 @@ class RplTest public: RplTest(const char* name); virtual ~RplTest(); +private: + // No copy constructor: no implementation! + RplTest(const RplTest& source); + // Prohibits assignment operator: no implementation! + RplTest& operator =(const RplTest& source); public: bool assertEquals(int expected, int current, const char* file, int lineNo); bool assertEquals(const char* expected, const char* current, diff --git a/rplmath/rplenigma.hpp b/rplmath/rplenigma.hpp index 0b7709f..e2ed1d3 100644 --- a/rplmath/rplenigma.hpp +++ b/rplmath/rplenigma.hpp @@ -28,6 +28,11 @@ protected: public: RplEnigma(RplRandom* random = NULL); virtual ~RplEnigma(); +private: + // No copy constructor: no implementation! + RplEnigma(const RplEnigma& source); + // Prohibits assignment operator: no implementation! + RplEnigma& operator =(const RplEnigma& source); public: void encode(char* data, int size, const char* charSet, QByteArray& cache); void decode(char* data, int size, const char* charSet, QByteArray& cache); diff --git a/rplmath/rplmath.hpp b/rplmath/rplmath.hpp index a3702d9..8613802 100644 --- a/rplmath/rplmath.hpp +++ b/rplmath/rplmath.hpp @@ -8,7 +8,7 @@ #ifndef RPLMATH_HPP #define RPLMATH_HPP -#ifndef RPLCORE_HPPP +#ifndef RPLCORE_HPP #include "rplcore/rplcore.hpp" #endif #include "rplrandom.hpp" diff --git a/rplmath/rplrandom.cpp b/rplmath/rplrandom.cpp index 390c1e9..dc5eb90 100644 --- a/rplmath/rplrandom.cpp +++ b/rplmath/rplrandom.cpp @@ -59,10 +59,10 @@ void RplRandom::xorSeed(u_int64_t seed){ * * @return a pseudo random value 0..255 */ -u_int8_t RplRandom::nextByte(){ +quint8 RplRandom::nextByte(){ u_int64_t value = nextInt64(); // forget the last 3 bits: - u_int8_t rc = (u_int8_t) (value >> 3) % 256; + quint8 rc = (quint8) (value >> 3) % 256; return rc; } diff --git a/rplmath/rplrandom.hpp b/rplmath/rplrandom.hpp index aa08466..e90a020 100644 --- a/rplmath/rplrandom.hpp +++ b/rplmath/rplrandom.hpp @@ -7,11 +7,16 @@ class RplRandom public: RplRandom(); virtual ~RplRandom(); +private: + // No copy constructor: no implementation! + RplRandom(const RplRandom& source); + // Prohibits assignment operator: no implementation! + RplRandom& operator =(const RplRandom& source); public: virtual u_int64_t nextInt64(); virtual void setSeed(u_int64_t seed); void xorSeed(u_int64_t seed); - u_int8_t nextByte(); + quint8 nextByte(); int nextInt(int minValue, int maxValue); QByteArray nextString(int length = 8, char minChar = ' ', char maxChar = 127); QByteArray nextString(int length, char* charSet); diff --git a/rplnet/rplnet.hpp b/rplnet/rplnet.hpp index a7eecd0..2f2fe11 100644 --- a/rplnet/rplnet.hpp +++ b/rplnet/rplnet.hpp @@ -5,15 +5,19 @@ * You also can use the licence from http://www.wtfpl.net/. * The original sources can be found on https://github.com/republib. */ -#ifndef RPLUTIL_HPP -#define RPLUTIL_HPP +#ifndef RPLNET_HPP +#define RPLNET_HPP #include #include #include - #include #include +//includes implicite rplcore.hpp: +#include "../rplmath/rplmath.hpp" +#include "rpltcppeer.hpp" #include "rpltcpserver.hpp" -#endif // RPLUTIL_HPP +#include "rpltcpclient.hpp" + +#endif // RPLNET_HPP diff --git a/rplnet/rpltcpclient.cpp b/rplnet/rpltcpclient.cpp new file mode 100644 index 0000000..adbb54b --- /dev/null +++ b/rplnet/rpltcpclient.cpp @@ -0,0 +1,127 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. + */ +#include "rplnet.hpp" + +enum { + LOC_1 = RPL_FIRST_OF(RPLMODULE_TCPCLIENT), // 701 +}; + +/** @class RplTcpClient rpltcpclient.hpp "rplnet/rpltcpclient.hpp" + * + * Implements a TCP client. + * + * Use the protocol defined at RplTcpServer. + */ +/** + * @brief Constructor. + * + * @param ip server ip + * @param port server port + * @param thread current thread. Used for sleep() + * @param terminator NULL or for controlled termination + * @param logger a logger + */ +RplTcpClient::RplTcpClient(const char* ip, int port, QThread* thread, + RplTerminator* terminator, RplLogger* logger) : + m_peer(new RplTcpPeer(ip, port, thread, terminator, logger)) +{ + if (ip != NULL && port != 0) + setRemoteAddress(ip, port); +} + +/** + * @brief Destructor. + */ +RplTcpClient::~RplTcpClient(){ + delete m_peer; + m_peer = NULL; +} + +void RplTcpClient::setRemoteAddress(const char* ip, int port){ + QTcpSocket* socket = (QTcpSocket*) m_peer->getSocket(); + delete socket; + if (ip == NULL || port == 0) + m_peer->setSocket(NULL); + else{ + socket = new QTcpSocket(); + m_peer->setSocket(socket); + socket->connectToHost(QString(ip), port); + } +} + +/** + * @brief Returns the peer info. + * @return the peer info + */ +RplTcpPeer* RplTcpClient::getPeer() const{ + return m_peer; +} + +/** @class RplClientThread rpltcpclient.hpp "rplnet/rpltcpclient.hpp" + * + * @brief Implements a thread usable for a tcp client. + * + * Each RplTcpPeer needs a thread. Therefore this class provides all things + * needed for a RplTcpClient which uses a RplTcpPeer. + */ + +/** + * @brief Constructor. + * + * @param ip NULL or the ip of the server, e.g. "localhost" or "127.0.0.1" + * @param port 0 or the port of the server + * @param logger the logger. If NULL a default logger will be used + */ +RplClientThread::RplClientThread(const char* ip, int port, RplLogger* logger) : + m_client(NULL), + m_logger(logger), + m_ownsLogger(logger == NULL) +{ + if (logger == NULL){ + m_logger = new RplLogger(); + m_logger->buildStandardAppender("client"); + m_logger->setLevel(LOG_DEBUG); + } + m_client = new RplTcpClient(ip, port, this, NULL, logger); +} +/** + * @brief Destructor. + */ +RplClientThread::~RplClientThread(){ + delete m_client; + m_client = NULL; + if (m_ownsLogger){ + delete m_logger; + m_logger = NULL; + } +} +/** + * @brief Returns the peer which can be used for sending and receiving messages. + * + * @return the peer + */ +RplTcpPeer* RplClientThread::getPeer() const{ + return m_client->getPeer(); +} + +/** + * @brief Returns the logger of the thread. + * @return the logger + */ +RplLogger* RplClientThread::getLogger() const{ + return m_logger; +} + +/** + * @brief Contains the main method of the thread. + * + * Calls doIt() for the real things. + */ +void RplClientThread::run(){ + doIt(); +} diff --git a/rplnet/rpltcpclient.hpp b/rplnet/rpltcpclient.hpp new file mode 100644 index 0000000..0f11817 --- /dev/null +++ b/rplnet/rpltcpclient.hpp @@ -0,0 +1,59 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. + */ +#ifndef RPLTCPCLIENT_HPP +#define RPLTCPCLIENT_HPP + +class RplTcpClient +{ +public: + RplTcpClient(const char* ip, int port, QThread* thread, + RplTerminator* terminator, RplLogger* logger = NULL); + virtual ~RplTcpClient(); +private: + // No copy constructor: no implementation! + RplTcpClient(const RplTcpClient& source); + // Prohibits assignment operator: no implementation! + RplTcpClient& operator =(const RplTcpClient& source); +public: + RplTcpPeer* getPeer() const; +private: + void setRemoteAddress(const char* ip, int port); +private: + RplTcpPeer* m_peer; +}; + +class RplClientThread : public QThread { +public: + RplClientThread(const char* ip, int port, RplLogger* logger = NULL); + virtual ~RplClientThread(); +private: + // No copy constructor: no implementation! + RplClientThread(const RplClientThread& source); + // Prohibits the assignment operator. Not implemented! + RplClientThread& operator=(const RplClientThread& source); +public: + /** + * @brief Does the main task of the thread. + * + * Will be called from QThread::run(). + * The implementations of this abstract method should be call getPeer() + * to send and receive messages. + */ + virtual void doIt() = 0; + RplTcpPeer* getPeer() const; + RplLogger* getLogger() const; +private: + virtual void run(); +protected: + RplTcpClient* m_client; + RplLogger* m_logger; +private: + bool m_ownsLogger; +}; + +#endif // RPLTCPCLIENT_HPP diff --git a/rplnet/rpltcppeer.cpp b/rplnet/rpltcppeer.cpp new file mode 100644 index 0000000..e1e3edb --- /dev/null +++ b/rplnet/rpltcppeer.cpp @@ -0,0 +1,279 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. + */ +#include "rplnet.hpp" + +enum { + LOC_SEND_1 = RPL_FIRST_OF(RPLMODULE_TCPPEER), // 801 + LOC_READ_BYTES_1, + LOC_READ_BYTES_2, + LOC_READ_BYTES_3, +}; + +static int s_dummy = 0; + +/** @class RplTcpNode rpltcpnode.hpp "rplnet/rpltcpnode.hpp" + * + * @brief Implement the common things for TCP server and client. + * + * The communication is done with the following protocol: + *
    + *
  • The data is transmitted via TCP.
  • + *
  • The data exchange is done with info units. + *
  • Each info unit contains a header and the data.
  • + *
+ * The format of the header: + *
FLAGS [SALT] COMMAND SIZE
+ * 
+ *
    + *
  • FLAGS (1 byte): a XOR sum of the flags defined in RplTcpNode::flag_t.
  • + *
  • SALT (4 byte): a random value. Controls the encryption. Only available if FLAG_ENCRYPT is set.
  • + *
  • COMMAND (5 byte): define the task to do (client to server) or the answer (server to client). + *
  • SIZE (2 or 4 byte): the size of the data behind the header. 4 bytes if FLAG_4_BYTE_SIZE is set.
  • + *
+ * + */ + +/** + * @brief Creates an instance of a RplTcpPeer. + * + * @param ip NULL or the ip address, e.g. "localhost" or "192.168.2.1" + * @param port 0 or port + * @param thread the current thread. Used for sleep() + * @param terminator NULL or for controlled thread termination + * @param logger logger. If Null the global logger will be taken (not thread safe!) + * @return a instance of RplTcpPeer + */ +RplTcpPeer* RplTcpPeer::createPeer(const char* ip, int port, QThread* thread, + RplTerminator* terminator, RplLogger* logger){ + return new RplTcpPeer(ip, port, thread, terminator, logger); +} + +/** + * @brief RplTcpNode::RplTcpNode + * + * @param ip NULL or the ip address, e.g. "localhost" or "192.168.2.1" + * @param port 0 or port + * @param thread the current thread. Used for sleep() + * @param terminator NULL or for controlled thread termination + * @param logger logger. If Null the global logger will be taken (not thread safe!) + */ +RplTcpPeer::RplTcpPeer(const char* ip, int port, QThread* thread, + RplTerminator* terminator, RplLogger* logger) : + m_ip(ip), + m_port(port), + m_socket(NULL), + m_logger(logger == NULL ? RplLogger::globalLogger() : logger), + m_thread(thread), + m_random(), + m_terminator(terminator) +{ + // Simulate a true random with time, and addresses from stack and code segment: + m_random.setSeed(time(NULL) + ((qint64) this << 8) + ((qint64) &s_dummy << 16) + ((qint64) &createPeer << 24)); +} + +/** + * @brief Destructor. + */ +RplTcpPeer::~RplTcpPeer(){ + +} + +/** + * @brief Sends a message via TCP. + * + * @param flags a sum of FLAGS_... constants + * @param command defines the content of the message + * @param data NULL or additional data + * @return true: success
+ * false: error occurred + */ +bool RplTcpPeer::send(qint8 flags, const char* command, const QByteArray& data){ + bool rc = false; + QByteArray header; + header.reserve(16); + header.append((char) flags); + if (flags & FLAG_ENCRYPT){ + header.append((char) m_random.nextByte()); + header.append((char) m_random.nextByte()); + header.append((char) m_random.nextByte()); + header.append((char) m_random.nextByte()); + } + unsigned int length = data.length(); + header.append(char (length % 256)); + header.append(char ((length >> 8) % 256)); + if (flags & FLAG_4_BYTE_SIZE){ + header.append(char ((length >> 16) % 256)); + header.append(char ((length >> 24) % 256)); + } + length = strlen(command); + header.append(command, length < 5 ? length : 5); + while (length++ < 5){ + header.append(' '); + } + qint64 written = m_socket->write(header.constData(), header.length()); + qint64 written2 = m_socket->write(data); + int count = 0; + if (written != header.length() || written2 != data.length()){ + int endTime = time(NULL) + m_timeout; + // wait until the data are sent or timeout or external termination: + while(m_socket->bytesToWrite() > 0){ + m_thread->msleep(1); + if (++count % 20 == 0){ + if (m_terminator == NULL || m_terminator->isStopped() + || time(NULL) > endTime) + break; + } + } + } + if (m_logger->isActive(LOG_DEBUG)) + m_logger->logv(LOG_DEBUG, LOC_SEND_1, "send %s-%d: %s len=%d loops=%d %s", + m_ip.constData(), m_port, command, data.length(), count, + RplString::hexDump((const void*) data.constData(), 16, 16).constData()); + return rc; +} + +/** + * @brief Reads an amount of bytes with a timeout. + * + * @param bytes count of bytes to read + * @param maxTime IN/OUT: last time the read must be ready + * @param loops IN/OUT: number of sleeps + * + * @return "": read not successful: timeout or termination or error
+ * otherwise: the read bytes + */ +QByteArray RplTcpPeer::readBytes(int bytes, time_t maxTime, int& loops){ + QAbstractSocket* socket = getSocket(); + bool success = true; + qint64 bytes64 = bytes; + while(socket->bytesAvailable() < bytes64){ + if (loops == 0) + maxTime = time(NULL) + m_timeout; + if (++loops % 20 == 0){ + if (time(NULL) > maxTime){ + m_logger->logv(LOG_ERROR, LOC_READ_BYTES_1, "receive: timeout (%d)", m_timeout); + success = false; + break; + } else if (m_terminator != NULL && m_terminator->isStopped()){ + m_logger->log(LOG_ERROR, LOC_READ_BYTES_2, "receive: stopped"); + success = false; + break; + } + } + } + QByteArray rc; + if (success){ + rc = socket->read(bytes); + if (rc.length() != bytes){ + m_logger->logv(LOG_ERROR, LOC_READ_BYTES_3, "receive: too few bytes: %d of %d", + rc.length(), bytes); + } + } + return rc; +} + +int getInt(const QByteArray& data, int offset, int size){ + int rc = ((int)(unsigned char) data.at(offset++)); + while (--size > 0){ + rc = rc * 256 + (unsigned char) data.at(offset++); + } + return rc; +} + +/** + * @brief Receives a message via TCP. + * + * @param command OUT: defines the content of the read message + * @param data OUT: "" or additional data + * @return true: success
+ * false: error occurred + */ +bool RplTcpPeer::receive(QByteArray& command, QByteArray& data){ + bool rc = true; + command.clear(); + data.clear(); + QByteArray header; + header.reserve(16); + int minHeaderSize = 8; + int loops = 0; + time_t maxTime = 0; + quint8 flags = 0; + header = readBytes(minHeaderSize, maxTime, loops); + if (header.length() > 0){ + flags = header.at(0); + int headerSize = minHeaderSize; + if ((flags & FLAG_4_BYTE_SIZE) != 0) + headerSize += 2; + if ((flags & FLAG_ENCRYPT) != 0) + headerSize += 4; + if (headerSize != minHeaderSize){ + QByteArray restHeader = readBytes(headerSize - minHeaderSize, maxTime, loops); + if (restHeader.length() == 0) + header.clear(); + else + header.append(restHeader); + } + } + rc = header.length() > 0; + if (rc){ + int offset = (flags & FLAG_ENCRYPT) == 0 ? 6 : 8; + int size = (flags & FLAG_4_BYTE_SIZE) == 0 ? 4 : 2; + int dataLength = getInt(header, offset, size); + command = header.mid(offset - 5, 5); + data = readBytes(dataLength, maxTime, loops); + rc = data.length() == dataLength; + } + return rc; + +} + +/** + * @brief Sends a message and receives an answer message via TCP. + * + * @param flags a sum of FLAGS_... constants + * @param command defines the content of the message to send + * @param data NULL or additional data + * @param size 0 or the size of data + * @param answer OUT: the command of the answer + * @param answerData OUT: "" or additional data of the answer + * @return true: success
+ * false: error occurred + */ +bool RplTcpPeer::sendAndReceive(quint8 flags, char command [4], + QByteArray* data, QByteArray& answer, QByteArray& answerData){ + answer.clear(); + answerData.clear(); + bool rc = send(flags, command, data == NULL ? QByteArray("") : *data); + if (rc) + rc = receive(answer, answerData); + return rc; +} + +/** + * @brief Sets the socket. + * + * @param socket the socket to set + */ +void RplTcpPeer::setSocket(QAbstractSocket* socket){ + m_socket = socket; + //if (socket != NULL) + //connect( m_socket, SIGNAL(readyRead()), SLOT(readTcpData()) ); +} + +void RplTcpPeer::readTcpData(){ + +} + +/** + * @brief Returns the socket. + * + * @return the socket + */ +QAbstractSocket* RplTcpPeer::getSocket() const{ + return m_socket; +} diff --git a/rplnet/rpltcppeer.hpp b/rplnet/rpltcppeer.hpp new file mode 100644 index 0000000..6b36acd --- /dev/null +++ b/rplnet/rpltcppeer.hpp @@ -0,0 +1,73 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. + */ +#ifndef RPLTCPPEER_HPP +#define RPLTCPPEER_HPP + +#ifndef RPLNET_HPP +#include "rplnet.hpp" +#endif + +class RplTcpPeer : public QObject +{ + Q_OBJECT +public: + enum { + ///> standard behaviour + FLAG_UNDEF, + ///> if set: the size field is 4 byte (max. 4 GByte) instead of 2 byte (64kByte) + FLAG_4_BYTE_SIZE = 1, + ///> if set the data are compressed by the gzip algorithm + FLAG_GZIP = 2, + ///> if set the data are encrypted. In front of the size field a 4 byte salt field exists. + ///> In this case all data behind the salt field are encrypted. + FLAG_ENCRYPT = 4, + ///> connection initialization of + } flag_t; +public: + static RplTcpPeer* createPeer(const char* ip, int port, QThread* thread, + RplTerminator* terminator, RplLogger* logger = NULL); +public: + RplTcpPeer(const char* ip, int port, QThread* thread, RplTerminator* terminator, RplLogger* logger = NULL); + virtual ~RplTcpPeer(); +private: + // No copy constructor: no implementation! + RplTcpPeer(const RplTcpPeer& source); + // No assignment operator: no implementation! + RplTcpPeer& operator =(const RplTcpPeer& source); +public: + virtual bool send(qint8 flags, const char* command, const QByteArray& data); + virtual bool receive(QByteArray& command, QByteArray& data); + virtual bool sendAndReceive(quint8 flags, char command [4], + QByteArray* data, QByteArray& answer, QByteArray& answerData); + void setSocket(QAbstractSocket* socket); + QAbstractSocket* getSocket() const; +private: + QByteArray readBytes(int bytes, time_t maxTime, int& loops); + +public: + void readTcpData(); + +private: + QByteArray m_ip; + int m_port; + QAbstractSocket* m_socket; + RplLogger* m_logger; + QByteArray m_received; + int m_expected; + QThread* m_thread; + // Only used for salt generation: + RplRandom m_random; + ///> true: the read/write operation is done + bool m_ready; + ///> maximum allowed time for sending/receiving one message + int m_timeout; + ///> for controlled termination + RplTerminator* m_terminator; +}; + +#endif // RPLTCPPEER_HPP diff --git a/rplnet/rpltcpserver.cpp b/rplnet/rpltcpserver.cpp index d2a1904..1ace63e 100644 --- a/rplnet/rpltcpserver.cpp +++ b/rplnet/rpltcpserver.cpp @@ -7,6 +7,10 @@ */ #include "rplnet.hpp" +enum { + LOC_1 = RPL_FIRST_OF(RPLMODULE_TCPSERVER), // 601 +}; + /** @class RplTcpThread rpltcpserver.hpp "rplcore/rpltcpserver.hpp" * * @brief Serves one connection of a multihreaded TCP server. @@ -81,15 +85,25 @@ qintptr RplTcpThread::getSocketDescriptor() const{ * @brief Constructor. * * @param taskHandler this handler reads from the tcp and interprets the content + * @param logger NULL or logger * @param parent NULL or the parent which deletes the childen */ -RplTcpServer::RplTcpServer(RplTaskHandler* taskHandler, QObject *parent) : +RplTcpServer::RplTcpServer(RplTaskHandler* taskHandler, QThread* thread, RplLogger* logger, QObject *parent) : QTcpServer(parent), m_taskHandler(taskHandler), - m_threadId(0) + m_threadId(0), + m_peer(NULL) { } +/** + * @brief Returns the peer info. + * @return the peer info + */ +RplTcpPeer* RplTcpServer::getPeer() const{ + return m_peer; +} + /** * @brief The slot handling a new tcp connection. * @@ -98,7 +112,7 @@ RplTcpServer::RplTcpServer(RplTaskHandler* taskHandler, QObject *parent) : void RplTcpServer::incomingConnection(qintptr socketDescriptor) { RplTcpThread *thread = createThread(socketDescriptor, ++m_threadId, m_taskHandler); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + QTcpServer::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start(); } diff --git a/rplnet/rpltcpserver.hpp b/rplnet/rpltcpserver.hpp index a4146fe..84e2246 100644 --- a/rplnet/rpltcpserver.hpp +++ b/rplnet/rpltcpserver.hpp @@ -9,29 +9,10 @@ #define RPLTCPSERVER_HPP // the sources generated from QT include this file directly: -#ifndef RPLCORE_HPP -#include -#include -#include -#include -#include +#ifndef RPLNET_HPP +#include "rplnet.hpp" #endif -/** - * @brief Portable header for a data unit. - * - * This header has a fix size makes it easy to process info from a socket. - */ -class RplNetHeader{ -public: - RplNetHeader() { - memset(this, 0, sizeof *this); - } - char m_application[2]; ///< defines the task manager which is responsible to process the data unit - char m_command[2]; ///< specifies the meaning of the data unit - char m_size[8]; ///< the size of the data unit as hexadecimal number with 8 digits -}; - class RplTaskHandler { public: @@ -77,6 +58,12 @@ class RplTcpThread : public QThread { public: RplTcpThread(qintptr socketDescriptor, int threadId, RplTaskHandler* handler); virtual ~RplTcpThread(); +private: + // No copy constructor: no implementation! + RplTcpThread(const RplTcpThread& source); + // No assignment operator: no implementation! + RplTcpThread& operator=(const RplTcpThread& source); +public: void run(); int getThreadId() const; RplTaskHandler* getTaskHandler() const; @@ -94,12 +81,19 @@ private: qintptr m_socketDescriptor; }; -class RplTcpServer : public QTcpServer +class RplTcpPeer; +class RplTcpServer : public QTcpServer, public RplTerminator { Q_OBJECT public: - explicit RplTcpServer(RplTaskHandler* taskHandler, QObject *parent = 0); + explicit RplTcpServer(RplTaskHandler* taskHandler, QThread* thread, RplLogger* logger = NULL, QObject *parent = 0); +private: + // No copy constructor: no implementation! + RplTcpServer(const RplTcpServer& source); + // No assignment operator: no implementation! + RplTcpServer& operator=(const RplTcpServer& source); public: + RplTcpPeer* getPeer() const; bool handleTask(); /** * Creates a thread derived from RplTcpThread. @@ -113,6 +107,7 @@ protected slots: private: RplTaskHandler* m_taskHandler; int m_threadId; + RplTcpPeer* m_peer; }; #endif // RPLTCPSERVER_HPP