m_readPosition(NULL)
{
}
+
+/**
+ * @brief Destructor.
+ */
+RplContainer::~RplContainer(){
+}
+
/**
* @brief Adds an type to the type list.
*
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);
#include "rplcontainer.hpp"
#include "rplstring.hpp"
#include "rplconfig.hpp"
+#include "rplterminator.hpp"
#endif // RPLCORE_HPP
}
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<br>
+ * 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.
*
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);
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);
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];
--- /dev/null
+/*
+ * 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 <code>RplTerminator</code>.
+ * 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 <code>__FILE__</code>
+ * @param lineNo 0 or the line number of the caller. Normally set with <code>__LINE__</code>
+ * @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.<br>
+ * false: otherwise
+ */
+bool RplTerminator::isStopped() const{
+ return m_stop;
+}
+
--- /dev/null
+/*
+ * 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
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,
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);
#ifndef RPLMATH_HPP
#define RPLMATH_HPP
-#ifndef RPLCORE_HPPP
+#ifndef RPLCORE_HPP
#include "rplcore/rplcore.hpp"
#endif
#include "rplrandom.hpp"
*
* @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;
}
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);
* 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 <QThread>
#include <QAbstractSocket>
#include <QTcpSocket>
-
#include <QTcpServer>
#include <QThread>
+//includes implicite rplcore.hpp:
+#include "../rplmath/rplmath.hpp"
+#include "rpltcppeer.hpp"
#include "rpltcpserver.hpp"
-#endif // RPLUTIL_HPP
+#include "rpltcpclient.hpp"
+
+#endif // RPLNET_HPP
--- /dev/null
+/*
+ * 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 <code>RplTcpServer</code>.
+ */
+/**
+ * @brief Constructor.
+ *
+ * @param ip server ip
+ * @param port server port
+ * @param thread current thread. Used for <code>sleep()</code>
+ * @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 <code>RplTcpPeer</code> needs a thread. Therefore this class provides all things
+ * needed for a <code>RplTcpClient</code> which uses a <code>RplTcpPeer</code>.
+ */
+
+/**
+ * @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 <code>doIt()</code> for the real things.
+ */
+void RplClientThread::run(){
+ doIt();
+}
--- /dev/null
+/*
+ * 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 <code>QThread::run()</code>.
+ * The implementations of this abstract method should be call <code>getPeer()</code>
+ * 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
--- /dev/null
+/*
+ * 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:
+ * <ul>
+ * <li>The data is transmitted via TCP.</li>
+ * <li>The data exchange is done with <b>info units</b>.
+ * <li>Each info unit contains a header and the data.</li>
+ * </ul>
+ * The format of the header:
+ *<pre>FLAGS [SALT] COMMAND SIZE
+ * </pre>
+ * <ul>
+ * <li>FLAGS (1 byte): a XOR sum of the flags defined in <code>RplTcpNode::flag_t.</li>
+ * <li>SALT (4 byte): a random value. Controls the encryption. Only available if <code>FLAG_ENCRYPT</code> is set.</li>
+ * <li>COMMAND (5 byte): define the task to do (client to server) or the answer (server to client).
+ * <li>SIZE (2 or 4 byte): the size of the data behind the header. 4 bytes if <code>FLAG_4_BYTE_SIZE</code> is set.</li>
+ * </ul>
+ *
+ */
+
+/**
+ * @brief Creates an instance of a <code>RplTcpPeer</code>.
+ *
+ * @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 <code>RplTcpPeer</code>
+ */
+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<br>
+ * 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<br>
+ * 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<br>
+ * 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 <code>data</code>
+ * @param answer OUT: the command of the answer
+ * @param answerData OUT: "" or additional data of the answer
+ * @return true: success<br>
+ * 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;
+}
--- /dev/null
+/*
+ * 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
*/
#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.
* @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.
*
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();
}
#define RPLTCPSERVER_HPP
// the sources generated from QT include this file directly:
-#ifndef RPLCORE_HPP
-#include <string.h>
-#include <QAbstractSocket>
-#include <QThread>
-#include <QTcpServer>
-#include <QTcpSocket>
+#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:
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;
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.
private:
RplTaskHandler* m_taskHandler;
int m_threadId;
+ RplTcpPeer* m_peer;
};
#endif // RPLTCPSERVER_HPP