From 2d993c823ad8c43a58f5e5fc8cb03c17f2890f29 Mon Sep 17 00:00:00 2001 From: Hamatoma Date: Wed, 18 Mar 2015 22:43:53 +0100 Subject: [PATCH] dirtool tcp up- and download --- base/ReByteBuffer.cpp | 24 +- base/ReByteBuffer.hpp | 1 + cunit/cuReByteBuffer.cpp | 48 ++ cunit/cuReTCP.cpp | 2 +- cunit/testall.cpp | 1 + net/ReTCP.cpp | 1286 +++++++++++++++++++------------------- os/ReDirTools.cpp | 196 +++--- os/ReDirTools.hpp | 4 + 8 files changed, 834 insertions(+), 728 deletions(-) diff --git a/base/ReByteBuffer.cpp b/base/ReByteBuffer.cpp index 9d19ff3..045d37e 100644 --- a/base/ReByteBuffer.cpp +++ b/base/ReByteBuffer.cpp @@ -235,7 +235,7 @@ ReByteBuffer& ReByteBuffer::appendDump(const char* data, size_t length, int maxL if (! isBinary) append(data, length); else - appendHexDump(data, length / 5); + appendHexDump(data, min(length, maxLength / 5)).reduceLength(); return *this; } /** @@ -675,6 +675,28 @@ int ReByteBuffer::indexOf(const Byte* toFind, size_t toFindLength, int start, } return rc; } +/** + * Tests whether the instance is a prefix of a given string. + * + * @param source the string to inspect + * @param length the length of the string
+ * -1: strlen(source) + * @param ignoreCase true: the test is case insensitive + * @param minLength the substring (instance) must have at least this length + * for a positive test + * @return truethe instance is a prefix of the source + * and the length is at least minLength bytes + */ +bool ReByteBuffer::isPrefixOf(const char* source, size_t length, + bool ignoreCase, int minLength){ + if (length == (size_t) -1) + length = strlen(source); + bool rc = length >= m_length && m_length <= length; + if (rc) + rc = equals(source, m_length, ignoreCase); + return rc; +} + /** @brief Searches revers for a byte sequence in the internal buffer. * * Finds the last occurrence of a byte sequence in a given range. diff --git a/base/ReByteBuffer.hpp b/base/ReByteBuffer.hpp index 3a4012f..461ec69 100644 --- a/base/ReByteBuffer.hpp +++ b/base/ReByteBuffer.hpp @@ -177,6 +177,7 @@ public: bool insert(size_t ix, const Byte* source, size_t length) { return splice(ix, 0, source, length); } + bool isPrefixOf(const char* source, size_t length = -1, bool ignoreCase = false, int minLength = 0); /** Returns the last character. * @return '\0': empty buffer
* otherwise: the last character diff --git a/cunit/cuReByteBuffer.cpp b/cunit/cuReByteBuffer.cpp index aa10b29..cbb0697 100644 --- a/cunit/cuReByteBuffer.cpp +++ b/cunit/cuReByteBuffer.cpp @@ -16,6 +16,7 @@ public: } private: void run() { + testAppendDump(); testAppendFix(); testEnsureLastChar(); testLastChar(); @@ -47,6 +48,53 @@ private: testSplice(); testReplace(); } + void testIsPrefixOf(){ + ReByteBuffer buffer; + // predefined length (of source): + // case sensitive, same size + checkT(buffer.set("aBc").isPrefixOf("aBc")); + // case sensitive, shorter + checkT(buffer.set("aB").isPrefixOf("aBc")); + checkF(buffer.set("ab").isPrefixOf("aBc")); + // case sensitive, longer + checkF(buffer.set("aBcd").isPrefixOf("aBc")); + + // given length (of source): + // case sensitive, same size + checkT(buffer.set("aBc").isPrefixOf("aBcd", 3)); + // case sensitive, shorter + checkT(buffer.set("aB").isPrefixOf("aBcd", 3)); + checkF(buffer.set("ab").isPrefixOf("aBcd", 3)); + // case sensitive, longer + checkF(buffer.set("aBcd").isPrefixOf("aBcd", 3)); + + + // case insensitive, same size + checkT(buffer.set("aBc").isPrefixOf("abc", -1, true)); + // case sensitive, shorter + checkT(buffer.set("aB").isPrefixOf("abc", -1, true)); + // case sensitive, longer + checkF(buffer.set("aBcd").isPrefixOf("abc", -1, true)); + + // minSize: + checkT(buffer.set("aBc").isPrefixOf("abcd", -1, true, 2)); + checkF(buffer.set("aB").isPrefixOf("abc", -1, true, 3)); + } + void testAppendDump(){ + ReByteBuffer buffer; + // true ASCII: + buffer.appendDump("abc"); + checkEqu("abc", buffer.str()); + buffer.setLength(0).appendDump("abcdefg", -1, 4); + checkEqu("abcd", buffer.str()); + buffer.setLength(0).appendDump("a\tb\nc\rd"); + checkEqu("a\tb\nc\rd", buffer.str()); + // binary: + int64_t ii = 0x12345678abcdefll; + buffer.setLength(0).appendDump(reinterpret_cast(&ii), sizeof ii, 40); + checkEqu("0000: ef cd ab 78 56 34 12 00 | ...xV4.. ", + buffer.str()); + } void testAppendFix() { ReByteBuffer buffer; // maxLength exceeded diff --git a/cunit/cuReTCP.cpp b/cunit/cuReTCP.cpp index e3960d4..dc9aa22 100644 --- a/cunit/cuReTCP.cpp +++ b/cunit/cuReTCP.cpp @@ -111,7 +111,7 @@ private: pool.startThread(new TCPThread("echo")); pool.startThread(new TCPThread("upload")); pool.startThread(new TCPThread("download")); - pool.waitForAlmostAll(1, 20000); + pool.waitForAlmostAll(1, 20); ReTCPStopClient stopper(&logger); stopper.stopServer(s_port); } diff --git a/cunit/testall.cpp b/cunit/testall.cpp index f23ee46..d4c8cd1 100644 --- a/cunit/testall.cpp +++ b/cunit/testall.cpp @@ -85,6 +85,7 @@ void testMath() { } void testAll() { try { + testBase(); testNet(); if (s_testAll) { testString(); diff --git a/net/ReTCP.cpp b/net/ReTCP.cpp index a1a2cf0..acd5871 100644 --- a/net/ReTCP.cpp +++ b/net/ReTCP.cpp @@ -1,652 +1,652 @@ -/* - * 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 - LC_CONNECT_1, // 50508 - LC_SOCKET_ADDR_SET_1, // 50509 - LC_LISTEN_FOR_ALL_7, // 50510 - LC_HANDLE_CONNECTION_1, // 50511 - LC_RECEIVE_1, // 50512 - LC_RECEIVE_2, // 50513 - LC_RECEIVE_3, // 50514 - LC_RECEIVE_4, // 50515 - LC_CONNECT_2, // 50516 - LC_CONNECT_3, // 50517 - LC_TCP_CONNECTION_1, // 50518 - LC_WRITE_2, // 50519 - LC_RECEIVE_5, // 50520 -}; - -#if defined __WIN32__ -bool ReTCPConnection::isGlobalInitialized = false; -#endif - -/** - * Constructor. - * - * @param logger the logger for error handling - */ -ReSocketAddress::ReSocketAddress(ReLoggerOwner* loggerOwner) : - m_preferredFamily(AF_INET), - m_family(-1), - m_port(0), - m_loggerOwner(loggerOwner), - // m_ip - m_name() { - memset(&m_ip, 0, sizeof m_ip); -} -/** - * Destructor. - */ -ReSocketAddress::~ReSocketAddress() { -} -void addressToString(struct addrinfo& addr, char* ip, size_t ipSize) { - if (addr.ai_family == AF_INET) { - inet_ntop(addr.ai_family, (struct sockaddr_in *) addr.ai_addr, ip, - ipSize); - } else if (addr.ai_family == AF_INET6) { - inet_ntop(addr.ai_family, (struct sockaddr_in6 *) addr.ai_addr, ip, - ipSize); - } -} -/** - * Sets the data from symbolic values. - */ -void ReSocketAddress::setAddress(const char* ip, int port) { - struct addrinfo hints; - struct addrinfo* infoList; - int status; - m_port = port; - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version - hints.ai_socktype = SOCK_STREAM; - - if ((status = getaddrinfo(ip, NULL, &hints, &infoList)) != 0) { - m_loggerOwner->logger()->sayF(LOG_ERROR | CAT_NETWORK, - LC_SOCKET_ADDR_SET_1, i18n("getaddrinfo($1) failed: $2")).arg(ip) - .arg(errno).end(); - } - - struct addrinfo* ptr; - bool hasIP4 = false; - bool hasIP6 = false; - - // Search for a available ip address - // if more than one are available, prefer m_preferredFamily: - m_ip[0] = '\0'; - for (ptr = infoList; ptr != NULL; ptr = ptr->ai_next) { - // different fields in IPv4 and IPv6: - if (!hasIP4 && ptr->ai_family == AF_INET) { - m_family = AF_INET; - hasIP4 = true; - } else if (!hasIP6 && ptr->ai_family == AF_INET6) { - m_family = AF_INET6; - hasIP6 = true; - } - addressToString(*ptr, m_ip, sizeof m_ip); - if (ptr->ai_family == m_preferredFamily) - break; - } - // free the linked list - freeaddrinfo(infoList); - if (m_ip[0] == '\0') - m_name.setLength(0); - else - m_name.set(m_ip).appendChar(':').appendInt(port); -} - -/** - * Constructor. - * - * @param logger logger for the error handling - */ +/* + * 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 + LC_CONNECT_1, // 50508 + LC_SOCKET_ADDR_SET_1, // 50509 + LC_LISTEN_FOR_ALL_7, // 50510 + LC_HANDLE_CONNECTION_1, // 50511 + LC_RECEIVE_1, // 50512 + LC_RECEIVE_2, // 50513 + LC_RECEIVE_3, // 50514 + LC_RECEIVE_4, // 50515 + LC_CONNECT_2, // 50516 + LC_CONNECT_3, // 50517 + LC_TCP_CONNECTION_1, // 50518 + LC_WRITE_2, // 50519 + LC_RECEIVE_5, // 50520 +}; + +#if defined __WIN32__ +bool ReTCPConnection::isGlobalInitialized = false; +#endif + +/** + * Constructor. + * + * @param logger the logger for error handling + */ +ReSocketAddress::ReSocketAddress(ReLoggerOwner* loggerOwner) : + m_preferredFamily(AF_INET), + m_family(-1), + m_port(0), + m_loggerOwner(loggerOwner), + // m_ip + m_name() { + memset(&m_ip, 0, sizeof m_ip); +} +/** + * Destructor. + */ +ReSocketAddress::~ReSocketAddress() { +} +void addressToString(struct addrinfo& addr, char* ip, size_t ipSize) { + if (addr.ai_family == AF_INET) { + inet_ntop(addr.ai_family, (struct sockaddr_in *) addr.ai_addr, ip, + ipSize); + } else if (addr.ai_family == AF_INET6) { + inet_ntop(addr.ai_family, (struct sockaddr_in6 *) addr.ai_addr, ip, + ipSize); + } +} +/** + * Sets the data from symbolic values. + */ +void ReSocketAddress::setAddress(const char* ip, int port) { + struct addrinfo hints; + struct addrinfo* infoList; + int status; + m_port = port; + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version + hints.ai_socktype = SOCK_STREAM; + + if ((status = getaddrinfo(ip, NULL, &hints, &infoList)) != 0) { + m_loggerOwner->logger()->sayF(LOG_ERROR | CAT_NETWORK, + LC_SOCKET_ADDR_SET_1, i18n("getaddrinfo($1) failed: $2")).arg(ip) + .arg(errno).end(); + } + + struct addrinfo* ptr; + bool hasIP4 = false; + bool hasIP6 = false; + + // Search for a available ip address + // if more than one are available, prefer m_preferredFamily: + m_ip[0] = '\0'; + for (ptr = infoList; ptr != NULL; ptr = ptr->ai_next) { + // different fields in IPv4 and IPv6: + if (!hasIP4 && ptr->ai_family == AF_INET) { + m_family = AF_INET; + hasIP4 = true; + } else if (!hasIP6 && ptr->ai_family == AF_INET6) { + m_family = AF_INET6; + hasIP6 = true; + } + addressToString(*ptr, m_ip, sizeof m_ip); + if (ptr->ai_family == m_preferredFamily) + break; + } + // free the linked list + freeaddrinfo(infoList); + if (m_ip[0] == '\0') + m_name.setLength(0); + else + m_name.set(m_ip).appendChar(':').appendInt(port); +} + +/** + * Constructor. + * + * @param logger logger for the error handling + */ #pragma warning( push ) #pragma warning( disable : 4355 ) -ReTCPClient::ReTCPClient(ReLogger* logger) : - ReTCPConnection(-1, this), - m_logger(logger) { -#pragma warning( pop ) -} -/** - * Destructor. - */ -ReTCPClient::~ReTCPClient() { -} -/** - * Connects a client with the server. - * - * @param ip domain address ("denic.de") or ip address ("192.168.2.1") - * @param port port number: 1..65535 - */ -bool ReTCPClient::connect(const char* ip, int port) { - bool rc = false; - struct addrinfo hints; - struct addrinfo* addr = NULL; - - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - - getaddrinfo(ip, ReByteBuffer("").appendInt(port).str(), &hints, &addr); - if (addr == NULL) { - m_logger->sayF(LOG_ERROR | CAT_NETWORK, LC_CONNECT_1, - i18n("ip not reachable: $1")).arg(ip).end(); - } else { - addressToString(*addr, m_ip, sizeof m_ip); - m_peerName.set(m_ip).appendChar(':').appendInt(port); - m_port = port; - if ((m_handleSocket = socket(addr->ai_family, addr->ai_socktype, - addr->ai_protocol)) < 0) - m_logger->sayF(LOG_ERROR | CAT_NETWORK, LC_CONNECT_2, - i18n("socket() failed ($1): $2")).arg(errno).arg(m_peerName).end(); - else if (::connect(m_handleSocket, addr->ai_addr, addr->ai_addrlen) - != 0) - m_logger->sayF(LOG_ERROR | CAT_NETWORK, LC_CONNECT_3, - i18n("connect() failed ($1): $2")).arg(errno).arg(m_peerName) - .end(); - else - rc = true; - } - return rc; -} - -/** - * Returns the logger. - * - * @param the logger for error handling - */ -ReLogger* ReTCPClient::logger() { - return m_logger; -} - -/** - * Constructor. - * - * @param id an identifier for logging - * @param logger the logger for error handling - */ -ReTCPConnection::ReTCPConnection(int id, ReLoggerOwner* loggerOwner) : - ReSocketAddress(loggerOwner), - m_peerName(), - m_received(), - m_handleSocket(-1), - m_id(id), - m_noSent(0), - m_noReceived(0) { -#if defined __WIN32__ - WSADATA wsaData; - if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { - loggerOwner->logger()->sayF(LOG_ERROR | CAT_NETWORK, LC_TCP_CONNECTION_1, - i18n("WSAStartup() failed: $1")).arg(errno).arg(getLastOSError()).end(); - throw ReException("WSAStartup() failed"); - } -#endif -} - -/** - * Destructor. - */ -ReTCPConnection::~ReTCPConnection() { -} -/** - * Finishes the connection (in both directions) and frees the resouces. - */ -void ReTCPConnection::close() { - if (m_handleSocket >= 0) { - reCloseSocket(m_handleSocket); - m_handleSocket = -1; - } -} - -/** - * Frees the global resources. - */ -void ReTCPConnection::globalClose() { -#if defined __WIN32__ - WSACleanup(); -#endif -} - -/** - * Sets the address given by a family and a string like "192.168.0.1:22". - * - * @param family AF_INET or AF_INET6 - * @param ip the string describing the address, e.g. "192.168.0.1" - * @param port the port of the peer - */ -void ReTCPConnection::setConnectedAddress(int family, const char* ip, - int port) { - m_family = family; - m_name = ip; - m_port = port; - int length = strlen(ip); - memcpy(m_ip, ip, length); - m_ip[length] = '\0'; - m_name.appendChar(':').appendInt(port); -} - -/** - * Receives a message. - * - * @param command OUT: the received command - * @param data OUT: the received data - */ -void ReTCPConnection::receive(ReByteBuffer& command, ReByteBuffer& data) { - command.setLength(8); - int received = recv(m_handleSocket, command.buffer(), 8, 0); - if (received != 8) { - m_loggerOwner->logger()->sayF(LOG_ERROR | CAT_NETWORK, LC_RECEIVE_1, - i18n("cannot receive ($1): $2 [$3]")).arg(errno).arg(received).arg( - m_peerName).end(); - } else { - int flags = 0; - int length = 0; - int found; - if ((found = sscanf(command.str(), "%8x", &length)) != 1 - || (flags = (length >> 24)) > 256 || (length &= 0xffffff) < 8) { - m_loggerOwner->logger()->sayF(LOG_ERROR | CAT_NETWORK, LC_RECEIVE_2, - i18n("wrong format: $1 [$2]")).arg(command).arg(m_peerName).end(); - } else { - data.setLength(length); - int readBytes = 0; - int rest = length; - char* buf = data.buffer(); - int rounds = 0; - while (readBytes < length) { - rounds++; - received = recv(m_handleSocket, buf, rest, 0); - if (received > 0) { - buf += received; - rest -= received; - readBytes += received; - } else if (received == 0) { - data.setLength(readBytes); - break; - } else { - m_loggerOwner->logger()->sayF(LOG_ERROR | CAT_NETWORK, - LC_RECEIVE_3, i18n("cannot receive ($1): $2 [$3]")).arg( - errno).arg(received).arg(m_peerName).end(); - break; - } - } - if (rounds) - rounds += 0; - if (readBytes < length) { - m_loggerOwner->logger()->sayF(LOG_ERROR | CAT_NETWORK, - LC_RECEIVE_4, i18n("too few bytes read: $1/$2 [$3]")).arg( - readBytes).arg(received).arg(m_peerName).end(); - } else { - m_loggerOwner->logger()->sayF(LOG_DEBUG | CAT_NETWORK, LC_RECEIVE_5, - i18n("received: $1 bytes in $2 round(s) [$3]: $4")).arg(length).arg(rounds).arg( - m_peerName).arg(ReByteBuffer().appendDump(data.str(), data.length(), 80).str()).end(); - } - command.setLength(0); - if (readBytes >= 8) { - command.append(data.str(), 8); - data.remove(0, 8); - } - } - } -} -/** - * Sends a command with (or without) data to the peer. - * - * @param command the command to send - * @param data the data to send - */ -void ReTCPConnection::send(const char* command, const char* data, int length) { - if (data == NULL) - length = 0; - else if (length < 0) - length = strlen(data); - m_toSend.ensureSize(length + 16); - ++m_noSent; - m_toSend.setLength(0); - int flags = 0x7b; - length += 8; - m_toSend.appendInt(length | (flags << 24), "%08x"); - m_toSend.appendFix(command, -1, 8, 8, NULL); - m_toSend.append(data, length); - length += 8; - int sent = 0; - int rest = length; - const char* buf = m_toSend.str(); - int rounds = 0; - while (rest > 0) { - rounds++; - if ((sent = ::send(m_handleSocket, buf, rest, 0)) > 0) { - buf += sent; - rest -= sent; - } else { - m_loggerOwner->logger()->sayF(LOG_ERROR | CAT_NETWORK, LC_WRITE_1, - i18n("cannot send ($1): $2")).arg(errno).arg(m_peerName).end(); - break; - } - } - if (rest == 0) - m_loggerOwner->logger()->sayF(LOG_DEBUG | CAT_NETWORK, LC_WRITE_2, - i18n("sent: $1 bytes in $2 round(s): $3")).arg(length).arg(rounds) - .arg(ReByteBuffer().appendDump(data, length, 80).str()).end(); -} - -/** - * Constructor. - * - * @param id an identifier for logging - * @param logger the logger for error handling - */ +ReTCPClient::ReTCPClient(ReLogger* logger) : + ReTCPConnection(-1, this), + m_logger(logger) { +#pragma warning( pop ) +} +/** + * Destructor. + */ +ReTCPClient::~ReTCPClient() { +} +/** + * Connects a client with the server. + * + * @param ip domain address ("denic.de") or ip address ("192.168.2.1") + * @param port port number: 1..65535 + */ +bool ReTCPClient::connect(const char* ip, int port) { + bool rc = false; + struct addrinfo hints; + struct addrinfo* addr = NULL; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + getaddrinfo(ip, ReByteBuffer("").appendInt(port).str(), &hints, &addr); + if (addr == NULL) { + m_logger->sayF(LOG_ERROR | CAT_NETWORK, LC_CONNECT_1, + i18n("ip not reachable: $1")).arg(ip).end(); + } else { + addressToString(*addr, m_ip, sizeof m_ip); + m_peerName.set(m_ip).appendChar(':').appendInt(port); + m_port = port; + if ((m_handleSocket = socket(addr->ai_family, addr->ai_socktype, + addr->ai_protocol)) < 0) + m_logger->sayF(LOG_ERROR | CAT_NETWORK, LC_CONNECT_2, + i18n("socket() failed ($1): $2")).arg(errno).arg(m_peerName).end(); + else if (::connect(m_handleSocket, addr->ai_addr, addr->ai_addrlen) + != 0) + m_logger->sayF(LOG_ERROR | CAT_NETWORK, LC_CONNECT_3, + i18n("connect() failed ($1): $2")).arg(errno).arg(m_peerName) + .end(); + else + rc = true; + } + return rc; +} + +/** + * Returns the logger. + * + * @param the logger for error handling + */ +ReLogger* ReTCPClient::logger() { + return m_logger; +} + +/** + * Constructor. + * + * @param id an identifier for logging + * @param logger the logger for error handling + */ +ReTCPConnection::ReTCPConnection(int id, ReLoggerOwner* loggerOwner) : + ReSocketAddress(loggerOwner), + m_peerName(), + m_received(), + m_handleSocket(-1), + m_id(id), + m_noSent(0), + m_noReceived(0) { +#if defined __WIN32__ + WSADATA wsaData; + if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { + loggerOwner->logger()->sayF(LOG_ERROR | CAT_NETWORK, LC_TCP_CONNECTION_1, + i18n("WSAStartup() failed: $1")).arg(errno).arg(getLastOSError()).end(); + throw ReException("WSAStartup() failed"); + } +#endif +} + +/** + * Destructor. + */ +ReTCPConnection::~ReTCPConnection() { +} +/** + * Finishes the connection (in both directions) and frees the resouces. + */ +void ReTCPConnection::close() { + if (m_handleSocket >= 0) { + reCloseSocket(m_handleSocket); + m_handleSocket = -1; + } +} + +/** + * Frees the global resources. + */ +void ReTCPConnection::globalClose() { +#if defined __WIN32__ + WSACleanup(); +#endif +} + +/** + * Sets the address given by a family and a string like "192.168.0.1:22". + * + * @param family AF_INET or AF_INET6 + * @param ip the string describing the address, e.g. "192.168.0.1" + * @param port the port of the peer + */ +void ReTCPConnection::setConnectedAddress(int family, const char* ip, + int port) { + m_family = family; + m_name = ip; + m_port = port; + int length = strlen(ip); + memcpy(m_ip, ip, length); + m_ip[length] = '\0'; + m_name.appendChar(':').appendInt(port); +} + +/** + * Receives a message. + * + * @param command OUT: the received command + * @param data OUT: the received data + */ +void ReTCPConnection::receive(ReByteBuffer& command, ReByteBuffer& data) { + command.setLength(8); + int received = recv(m_handleSocket, command.buffer(), 8, 0); + if (received != 8) { + m_loggerOwner->logger()->sayF(LOG_ERROR | CAT_NETWORK, LC_RECEIVE_1, + i18n("cannot receive ($1): $2 [$3]")).arg(errno).arg(received).arg( + m_peerName).end(); + } else { + int flags = 0; + int length = 0; + int found; + if ((found = sscanf(command.str(), "%8x", &length)) != 1 + || (flags = (length >> 24)) > 256 || (length &= 0xffffff) < 8) { + m_loggerOwner->logger()->sayF(LOG_ERROR | CAT_NETWORK, LC_RECEIVE_2, + i18n("wrong format: $1 [$2]")).arg(command).arg(m_peerName).end(); + } else { + data.setLength(length); + int readBytes = 0; + int rest = length; + char* buf = data.buffer(); + int rounds = 0; + while (readBytes < length) { + rounds++; + received = recv(m_handleSocket, buf, rest, 0); + if (received > 0) { + buf += received; + rest -= received; + readBytes += received; + } else if (received == 0) { + data.setLength(readBytes); + break; + } else { + m_loggerOwner->logger()->sayF(LOG_ERROR | CAT_NETWORK, + LC_RECEIVE_3, i18n("cannot receive ($1): $2 [$3]")).arg( + errno).arg(received).arg(m_peerName).end(); + break; + } + } + if (rounds) + rounds += 0; + if (readBytes < length) { + m_loggerOwner->logger()->sayF(LOG_ERROR | CAT_NETWORK, + LC_RECEIVE_4, i18n("too few bytes read: $1/$2 [$3]")).arg( + readBytes).arg(received).arg(m_peerName).end(); + } else { + m_loggerOwner->logger()->sayF(LOG_DEBUG | CAT_NETWORK, LC_RECEIVE_5, + i18n("received: $1 bytes in $2 round(s) [$3]: $4")).arg(length).arg(rounds).arg( + m_peerName).arg(ReByteBuffer().appendDump(data.str(), data.length(), 80).str()).end(); + } + command.setLength(0); + if (readBytes >= 8) { + command.append(data.str(), 8); + data.remove(0, 8); + } + } + } +} +/** + * Sends a command with (or without) data to the peer. + * + * @param command the command to send + * @param data the data to send + */ +void ReTCPConnection::send(const char* command, const char* data, int length) { + if (data == NULL) + length = 0; + else if (length < 0) + length = strlen(data); + m_toSend.ensureSize(length + 16); + ++m_noSent; + m_toSend.setLength(0); + int flags = 0x7b; + length += 8; + m_toSend.appendInt(length | (flags << 24), "%08x"); + m_toSend.appendFix(command, -1, 8, 8, NULL); + m_toSend.append(data, length); + length += 8; + int sent = 0; + int rest = length; + const char* buf = m_toSend.str(); + int rounds = 0; + while (rest > 0) { + rounds++; + if ((sent = ::send(m_handleSocket, buf, rest, 0)) > 0) { + buf += sent; + rest -= sent; + } else { + m_loggerOwner->logger()->sayF(LOG_ERROR | CAT_NETWORK, LC_WRITE_1, + i18n("cannot send ($1): $2")).arg(errno).arg(m_peerName).end(); + break; + } + } + if (rest == 0) + m_loggerOwner->logger()->sayF(LOG_DEBUG | CAT_NETWORK, LC_WRITE_2, + i18n("sent: $1 bytes in $2 round(s): $3")).arg(length).arg(rounds) + .arg(ReByteBuffer().appendDump(data, length, 80).str()).end(); +} + +/** + * Constructor. + * + * @param id an identifier for logging + * @param logger the logger for error handling + */ #pragma warning( push ) #pragma warning( disable : 4355 ) -ReTCPServerConnection::ReTCPServerConnection(int id, ReTCPServer* server) : - ReTCPConnection(id, this), - ReThread(true), - m_server(server) { +ReTCPServerConnection::ReTCPServerConnection(int id, ReTCPServer* server) : + ReTCPConnection(id, this), + ReThread(true), + m_server(server) { #pragma warning( pop ) -} - -/** - * Destructor. - */ -ReTCPServerConnection::~ReTCPServerConnection() { -} - -/** - * Serves the commands of a single connection (in a single thread). - */ -void ReTCPServerConnection::run() { - ReByteBuffer command; - ReNetCommandHandler::ProcessingState rc = ReNetCommandHandler::PS_UNDEF; - do { - receive(command, m_received); - rc = m_server->handler().handleNetCommand(command, m_received, this); - if (rc == ReNetCommandHandler::PS_UNKNOWN) { - logger()->sayF(LOG_ERROR | CAT_NETWORK, LC_HANDLE_CONNECTION_1, - i18n("unknown command: $1 length: $2")).arg(command).arg( - m_received.length()).end(); - } - } while (rc != ReNetCommandHandler::PS_STOP && ! m_shouldStop); - if (rc != ReNetCommandHandler::PS_STOP) - m_pool->setShouldStop(); - close(); - m_id = -1; -} - -/** - * Constructor. - * - * @param port the port for listening - * @param commandHandler a handler which can process the incoming commands. - * May be NULL - * @param logger the logger for error handling - * @param maxConnections maximal count of threads handling a connection - */ +} + +/** + * Destructor. + */ +ReTCPServerConnection::~ReTCPServerConnection() { +} + +/** + * Serves the commands of a single connection (in a single thread). + */ +void ReTCPServerConnection::run() { + ReByteBuffer command; + ReNetCommandHandler::ProcessingState rc = ReNetCommandHandler::PS_UNDEF; + do { + receive(command, m_received); + rc = m_server->handler().handleNetCommand(command, m_received, this); + if (rc == ReNetCommandHandler::PS_UNKNOWN) { + logger()->sayF(LOG_ERROR | CAT_NETWORK, LC_HANDLE_CONNECTION_1, + i18n("unknown command: $1 length: $2")).arg(command).arg( + m_received.length()).end(); + } + } while (rc != ReNetCommandHandler::PS_STOP && ! m_shouldStop); + if (rc != ReNetCommandHandler::PS_STOP) + m_pool->setShouldStop(); + close(); + m_id = -1; +} + +/** + * Constructor. + * + * @param port the port for listening + * @param commandHandler a handler which can process the incoming commands. + * May be NULL + * @param logger the logger for error handling + * @param maxConnections maximal count of threads handling a connection + */ #pragma warning( push ) #pragma warning( disable : 4355 ) -ReTCPServer::ReTCPServer(int port, class ReNetCommandHandler& commandHandler, - ReLogger* logger, int maxConnections) : - ReTCPConnection(0, this), - m_maxConnections(maxConnections), - m_countConnections(0), - m_connections(new ReTCPServerConnection*[maxConnections]), - m_handler(commandHandler), - m_logger(logger) { -#pragma warning( pop ) - m_port = port; - memset(m_connections, 0, maxConnections * sizeof *m_connections); -} - -/** - * 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; -} -/** - * Creates a server connection. - * - * @param id the connection identifier - * @param handleSocket the handle of the read/write channel - * @address the data about the client connection (ip, port) - */ -ReTCPServerConnection* ReTCPServer::createConnection(int id, int handleSocket, - const struct sockaddr& address) { - ReTCPServerConnection* rc = NULL; - for (int ii = 0; rc == NULL && ii < m_maxConnections; ii++) { - if (m_connections[ii] == NULL) - m_connections[ii] = rc = new ReTCPServerConnection(id, this); - else if (m_connections[ii]->id() < 0) { - rc = m_connections[ii]; - rc->setId(id); - } - } - if (rc != NULL) { - rc->setHandleSocket(handleSocket); - char ip[INET6_ADDRSTRLEN]; - inet_ntop(address.sa_family, - address.sa_family == AF_INET ? - (void *) &(((struct sockaddr_in*) &address)->sin_addr) : - (void *) &(((struct sockaddr_in6*) &address)->sin6_addr), ip, - sizeof ip); - int port = - address.sa_family == AF_INET ? - (int) ntohs(((struct sockaddr_in*) &address)->sin_port) : - (int) ntohl(((struct sockaddr_in6*) &address)->sin6_port); - rc->setConnectedAddress(address.sa_family, ip, port); - } - return rc; -} - -/** - * Accepts connections and create a thread which will handle this connection. - */ -bool ReTCPServer::listenForAll() { - bool rc = false; - struct addrinfo hints; - struct addrinfo* addrInfo; - ReThreadPool pool(m_maxConnections + 1, m_logger); - -// first, load up address structs with getaddrinfo(): - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE; // fill in my IP for me - - memcpy(m_ip, "0.0.0.0", 8); - m_name.set(m_ip).appendChar(':').appendInt(m_port); - getaddrinfo(NULL, ReByteBuffer().appendInt(m_port).str(), &hints, - &addrInfo); - m_family = addrInfo->ai_family; -// make a socket: - m_handleSocket = socket(addrInfo->ai_family, addrInfo->ai_socktype, - addrInfo->ai_protocol); - 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 { - int yes = 1; - // Avoid the "Address already in use" error message of finished processes - // that are still waiting for the release by the kernel: - if (setsockopt(m_handleSocket, SOL_SOCKET, SO_REUSEADDR, - reinterpret_cast(&yes), sizeof(int)) == -1) { - m_logger->sayF(LOG_WARNING | CAT_NETWORK, LC_LISTEN_FOR_ALL_7, - i18n("setsockopt() failed: $1")).arg(errno).end(); - // this error is not fatal, continue! - } - // bind it to the port we passed in to getaddrinfo(): - if (bind(m_handleSocket, addrInfo->ai_addr, addrInfo->ai_addrlen) != 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, - m_maxConnections < 16 ? m_maxConnections : 16); - - //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) { - if (! pool.shouldStop()) { - 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 at once: - m_logger->sayF(LOG_WARNING | CAT_NETWORK, - LC_LISTEN_FOR_ALL_5, - i18n( - "connection refused (too many connections): $1")) - .arg(m_port).end(); - reCloseSocket(clientSocket); - } else { - ReTCPServerConnection* connection = createConnection( - nextId++, clientSocket, addrClient); - - if (!pool.startThread(connection)) { - m_logger->sayF(LOG_ERROR | CAT_PROCESS, - LC_LISTEN_FOR_ALL_6, - i18n("cannot create a thread: $1")).arg( - getLastOSError()).end(); - reCloseSocket(clientSocket); - clientSocket = -1; - } - } - } - } - if (pool.shouldStop()) { - m_logger->say(LOG_INFO | CAT_PROCESS, LC_LISTEN_FOR_ALL_7, - i18n("stop request received")); - } - } - } - return rc; -} - -/** - * Returns the logger. - * - * @param the logger for error handling - */ -ReLogger* ReTCPServer::logger() { - return m_logger; -} - -/** - * Constructor. - */ -ReNetCommandHandler::ReNetCommandHandler() : - m_nextHandler(NULL) { -} - -/** - * Adds a handler at the end of the handler chain. - */ -void ReNetCommandHandler::addHandler(ReNetCommandHandler* handler) { - if (m_nextHandler == NULL) - m_nextHandler = handler; - else - m_nextHandler->addHandler(handler); -} - -/** - * Constructor. - * - * @param port port for listening - * @param logger logger for error handling - */ +ReTCPServer::ReTCPServer(int port, class ReNetCommandHandler& commandHandler, + ReLogger* logger, int maxConnections) : + ReTCPConnection(0, this), + m_maxConnections(maxConnections), + m_countConnections(0), + m_connections(new ReTCPServerConnection*[maxConnections]), + m_handler(commandHandler), + m_logger(logger) { +#pragma warning( pop ) + m_port = port; + memset(m_connections, 0, maxConnections * sizeof *m_connections); +} + +/** + * 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; +} +/** + * Creates a server connection. + * + * @param id the connection identifier + * @param handleSocket the handle of the read/write channel + * @address the data about the client connection (ip, port) + */ +ReTCPServerConnection* ReTCPServer::createConnection(int id, int handleSocket, + const struct sockaddr& address) { + ReTCPServerConnection* rc = NULL; + for (int ii = 0; rc == NULL && ii < m_maxConnections; ii++) { + if (m_connections[ii] == NULL) + m_connections[ii] = rc = new ReTCPServerConnection(id, this); + else if (m_connections[ii]->id() < 0) { + rc = m_connections[ii]; + rc->setId(id); + } + } + if (rc != NULL) { + rc->setHandleSocket(handleSocket); + char ip[INET6_ADDRSTRLEN]; + inet_ntop(address.sa_family, + address.sa_family == AF_INET ? + (void *) &(((struct sockaddr_in*) &address)->sin_addr) : + (void *) &(((struct sockaddr_in6*) &address)->sin6_addr), ip, + sizeof ip); + int port = + address.sa_family == AF_INET ? + (int) ntohs(((struct sockaddr_in*) &address)->sin_port) : + (int) ntohl(((struct sockaddr_in6*) &address)->sin6_port); + rc->setConnectedAddress(address.sa_family, ip, port); + } + return rc; +} + +/** + * Accepts connections and create a thread which will handle this connection. + */ +bool ReTCPServer::listenForAll() { + bool rc = false; + struct addrinfo hints; + struct addrinfo* addrInfo; + ReThreadPool pool(m_maxConnections + 1, m_logger); + +// first, load up address structs with getaddrinfo(): + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; // fill in my IP for me + + memcpy(m_ip, "0.0.0.0", 8); + m_name.set(m_ip).appendChar(':').appendInt(m_port); + getaddrinfo(NULL, ReByteBuffer().appendInt(m_port).str(), &hints, + &addrInfo); + m_family = addrInfo->ai_family; +// make a socket: + m_handleSocket = socket(addrInfo->ai_family, addrInfo->ai_socktype, + addrInfo->ai_protocol); + 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 { + int yes = 1; + // Avoid the "Address already in use" error message of finished processes + // that are still waiting for the release by the kernel: + if (setsockopt(m_handleSocket, SOL_SOCKET, SO_REUSEADDR, + reinterpret_cast(&yes), sizeof(int)) == -1) { + m_logger->sayF(LOG_WARNING | CAT_NETWORK, LC_LISTEN_FOR_ALL_7, + i18n("setsockopt() failed: $1")).arg(errno).end(); + // this error is not fatal, continue! + } + // bind it to the port we passed in to getaddrinfo(): + if (bind(m_handleSocket, addrInfo->ai_addr, addrInfo->ai_addrlen) != 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, + m_maxConnections < 16 ? m_maxConnections : 16); + + //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) { + if (! pool.shouldStop()) { + 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 at once: + m_logger->sayF(LOG_WARNING | CAT_NETWORK, + LC_LISTEN_FOR_ALL_5, + i18n( + "connection refused (too many connections): $1")) + .arg(m_port).end(); + reCloseSocket(clientSocket); + } else { + ReTCPServerConnection* connection = createConnection( + nextId++, clientSocket, addrClient); + + if (!pool.startThread(connection)) { + m_logger->sayF(LOG_ERROR | CAT_PROCESS, + LC_LISTEN_FOR_ALL_6, + i18n("cannot create a thread: $1")).arg( + getLastOSError()).end(); + reCloseSocket(clientSocket); + clientSocket = -1; + } + } + } + } + if (pool.shouldStop()) { + m_logger->say(LOG_INFO | CAT_PROCESS, LC_LISTEN_FOR_ALL_7, + i18n("stop request received")); + } + } + } + return rc; +} + +/** + * Returns the logger. + * + * @param the logger for error handling + */ +ReLogger* ReTCPServer::logger() { + return m_logger; +} + +/** + * Constructor. + */ +ReNetCommandHandler::ReNetCommandHandler() : + m_nextHandler(NULL) { +} + +/** + * Adds a handler at the end of the handler chain. + */ +void ReNetCommandHandler::addHandler(ReNetCommandHandler* handler) { + if (m_nextHandler == NULL) + m_nextHandler = handler; + else + m_nextHandler->addHandler(handler); +} + +/** + * Constructor. + * + * @param port port for listening + * @param logger logger for error handling + */ #pragma warning( push ) #pragma warning( disable : 4355 ) -ReTCPEchoServer::ReTCPEchoServer(int port, ReLogger* logger) : - ReTCPServer(port, *this, logger), - ReNetCommandHandler() { -#pragma warning( pop ) -} -/** - * Destructor. - */ -ReTCPEchoServer::~ReTCPEchoServer() { -} - -/** - * Handler for the commands "echo", "localtim" and "stop". - * - * @param command a string describing what do to - * @param data data of the command, may be empty - * @param connection the connection which can be used for answers - * @result PS_UNKNOWN: command is not known
- * PS_PROCESSED: command successfully processed
- * PS_FAILED: command processed, error occurred
- * PS_ABORT: connection should be finished - */ -ReNetCommandHandler::ProcessingState ReTCPEchoServer::handleNetCommand( - ReByteBuffer& command, ReByteBuffer& data, ReTCPConnection* connection) { - ProcessingState rc = PS_UNDEF; - if (command.equals("echo ")) { - connection->send("Echo", data.str(), data.length()); - rc = PS_PROCESSED; - } else if (command.equals("strlen ")) { - m_toSend.setLength(0).appendInt(data.length()); - connection->send("Strlen ", m_toSend.str(), m_toSend.length()); - rc = PS_PROCESSED; - } else if (command.equals("filldata")) { - int length = atol(data.str()); - if (m_toSend.length() != length || !m_toSend.startsWith("xxxxx")) - m_toSend.setLength(0).appendChar('x', length); - connection->send("Filldata", m_toSend.str(), m_toSend.length()); - rc = PS_PROCESSED; - } else if (command.equals("localtim")) { - time_t now2 = time(NULL); - struct tm* now = localtime(&now2); - char buffer[128]; - strftime(buffer, sizeof buffer, "%y.%m.%d %H:%M:%S", now); - connection->send("Localtim", buffer, strlen(buffer)); - rc = PS_PROCESSED; - } else if (command.equals("stop ")) { - rc = PS_STOP; - } else { - rc = PS_UNKNOWN; - if (m_nextHandler != NULL) - rc = m_nextHandler->handleNetCommand(command, data, connection); - } - return rc; -} - -/** - * Constructor. - */ -ReTCPStopClient::ReTCPStopClient(ReLogger* logger) : - ReTCPClient(logger) { -} -/** - * Destructor. - */ -ReTCPStopClient::~ReTCPStopClient() { -} - -void ReTCPStopClient::stopServer(int port, const char* ip) { - connect(ip, port); - send("stop", NULL); -} +ReTCPEchoServer::ReTCPEchoServer(int port, ReLogger* logger) : + ReTCPServer(port, *this, logger), + ReNetCommandHandler() { +#pragma warning( pop ) +} +/** + * Destructor. + */ +ReTCPEchoServer::~ReTCPEchoServer() { +} + +/** + * Handler for the commands "echo", "localtim" and "stop". + * + * @param command a string describing what do to + * @param data data of the command, may be empty + * @param connection the connection which can be used for answers + * @result PS_UNKNOWN: command is not known
+ * PS_PROCESSED: command successfully processed
+ * PS_FAILED: command processed, error occurred
+ * PS_ABORT: connection should be finished + */ +ReNetCommandHandler::ProcessingState ReTCPEchoServer::handleNetCommand( + ReByteBuffer& command, ReByteBuffer& data, ReTCPConnection* connection) { + ProcessingState rc = PS_UNDEF; + if (command.equals("echo ")) { + connection->send("Echo", data.str(), data.length()); + rc = PS_PROCESSED; + } else if (command.equals("strlen ")) { + m_toSend.setLength(0).appendInt(data.length()); + connection->send("Strlen ", m_toSend.str(), m_toSend.length()); + rc = PS_PROCESSED; + } else if (command.equals("filldata")) { + int length = atol(data.str()); + if (m_toSend.length() != length || !m_toSend.startsWith("xxxxx")) + m_toSend.setLength(0).appendChar('x', length); + connection->send("Filldata", m_toSend.str(), m_toSend.length()); + rc = PS_PROCESSED; + } else if (command.equals("localtim")) { + time_t now2 = time(NULL); + struct tm* now = localtime(&now2); + char buffer[128]; + strftime(buffer, sizeof buffer, "%y.%m.%d %H:%M:%S", now); + connection->send("Localtim", buffer, strlen(buffer)); + rc = PS_PROCESSED; + } else if (command.equals("stop ")) { + rc = PS_STOP; + } else { + rc = PS_UNKNOWN; + if (m_nextHandler != NULL) + rc = m_nextHandler->handleNetCommand(command, data, connection); + } + return rc; +} + +/** + * Constructor. + */ +ReTCPStopClient::ReTCPStopClient(ReLogger* logger) : + ReTCPClient(logger) { +} +/** + * Destructor. + */ +ReTCPStopClient::~ReTCPStopClient() { +} + +void ReTCPStopClient::stopServer(int port, const char* ip) { + connect(ip, port); + send("stop", NULL); +} diff --git a/os/ReDirTools.cpp b/os/ReDirTools.cpp index eb5b261..553c9b4 100644 --- a/os/ReDirTools.cpp +++ b/os/ReDirTools.cpp @@ -139,8 +139,9 @@ const char* s_syncExamples[] = { const char* s_tcpUsage[] = { ": tcp [] [ ...]", " test tool for network test", ":", " server", - " client [ []]", + " client [ [ []]]", " : URL of the server", " : number of messages to send", + " : 'upload', 'download' or 'mixed'", NULL }; const char* s_tcpExamples[] = { "dirtool tcp -p 5555 server", "dirtool tcp -p 5555 client localhost 10000 10", @@ -983,25 +984,25 @@ ReDirBatch::ReDirBatch(ReLogger* logger) : m_isExe(false) { // standard short options: D d O o P p T t v y Z z m_programArgs.addString("first", - i18n("defines the first line of the output"), '1', "first-line", true, + i18n("defines the first line of the output"), '1', "first-line", true, #if defined __linux__ - "#! /bin/sh" + "#! /bin/sh" #elif defined __WIN32__ - "rem this batch is created by dirtool" + "rem this batch is created by dirtool" #endif -) ; + ); m_programArgs.addString("arguments", i18n("template for the output line.\n" - "Possible placeholders: (e.g. e:\\data\\sample.txt)\n" - " !full!: e:\\data\\sample.txt\n" - " !path!: e:\\data\\\n" - " !basename!: sample.txt\n" - " !name!: sample\n" - " !ext!: .txt\n" - "example: --arguments='echo !basename! in !path! found'"), 'a', - "arguments", false, NULL); + "Possible placeholders: (e.g. e:\\data\\sample.txt)\n" + " !full!: e:\\data\\sample.txt\n" + " !path!: e:\\data\\\n" + " !basename!: sample.txt\n" + " !name!: sample\n" + " !ext!: .txt\n" + "example: --arguments='echo !basename! in !path! found'"), 'a', + "arguments", false, NULL); m_programArgs.addString("script", - i18n("name of the script (starts each output line)"), 'c', "script", - false, NULL); + i18n("name of the script (starts each output line)"), 'c', "script", + false, NULL); #if defined __WIN32__ m_programArgs.addBool("isexe", i18n("supresses the starting 'call' of each output line" @@ -1079,7 +1080,7 @@ void ReDirBatch::doIt() { #elif defined __WIN32__ static const char* prefix = "rem "; #endif - printSummary(prefix); + printSummary (prefix); } /** @@ -1833,7 +1834,7 @@ void ReDirTouch::processDir(ReDirStatus_t* entry) { static bool isAbsoluteTime(ReFileTime_t& time) { #if defined __linux__ - static struct tm year1980 = { 0, 0, 0, 1, 1 - 1, 1980 - 1900 }; + static struct tm year1980 = {0, 0, 0, 1, 1 - 1, 1980 - 1900}; static time_t time1980 = mktime(&year1980); return time.tv_sec >= time1980; #elif defined __WIN32__ @@ -2077,47 +2078,47 @@ bool ReDirSync::copyFile(const char* source, ReFileProperties_t* properties, struct stat info; if (properties == NULL) { if (stat(source, &info) == 0) - properties = &info; + properties = &info; else { if (logger != NULL) - logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_1, - i18n("could not find: $1 (errno: $2)")).arg(source).arg( - errno).end(); + logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_1, + i18n("could not find: $1 (errno: $2)")).arg(source).arg( + errno).end(); } } FILE* fpSource = fopen(source, "rb"); if (fpSource == NULL) { if (logger != NULL) - logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_2, - i18n("cannot open $1 (errno: $2)")).arg(source).arg(errno).end(); + logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_2, + i18n("cannot open $1 (errno: $2)")).arg(source).arg(errno).end(); } else { ReFileSize_t size = - properties == NULL ? 0x7fffffff : properties->st_size; + properties == NULL ? 0x7fffffff : properties->st_size; FILE* fpTarget = fopen(target, "w"); if (fpTarget == NULL) { if (logger != NULL) - logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_3, - i18n("cannot open $1 (errno: $2)")).arg(target).arg(errno) - .end(); + logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_3, + i18n("cannot open $1 (errno: $2)")).arg(target).arg(errno) + .end(); } else { while (size > 0) { size_t blockSize = buffer.capacity(); if ((int) blockSize > size) - blockSize = size; + blockSize = size; if (fread(buffer.buffer(), blockSize, 1, fpSource) != 1) { if (logger != NULL) - logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_5, - i18n("cannot read $1 (errno: $2)")).arg(source).arg( - errno).end(); + logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_5, + i18n("cannot read $1 (errno: $2)")).arg(source).arg( + errno).end(); break; } size_t written; if ((written = fwrite(buffer.buffer(), 1, blockSize, fpTarget)) - != blockSize) { + != blockSize) { if (logger != NULL) - logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_6, - i18n("cannot write $1 [$2] (errno: $3)")).arg( - target).arg(written).arg(errno).end(); + logger->sayF(LOG_ERROR | CAT_FILE, LC_COPY_FILE_6, + i18n("cannot write $1 [$2] (errno: $3)")).arg( + target).arg(written).arg(errno).end(); break; } size -= blockSize; @@ -2125,7 +2126,7 @@ bool ReDirSync::copyFile(const char* source, ReFileProperties_t* properties, rc = size == 0ll; fclose(fpTarget); if (properties != NULL) - setProperties(target, properties, logger); + setProperties(target, properties, logger); } fclose(fpSource); } @@ -2158,24 +2159,24 @@ bool ReDirSync::setProperties(const char* fullName, times[1].tv_usec = properties->st_mtim.tv_nsec / 1000; if (utimes(fullName, times) != 0) { if (logger != NULL) - logger->sayF(LOG_ERROR | CAT_FILE, LC_SET_PROPERTIES_1, - i18n("cannot change file times: $1 (errno: $2)")).arg(fullName) - .arg(errno).end(); + logger->sayF(LOG_ERROR | CAT_FILE, LC_SET_PROPERTIES_1, + i18n("cannot change file times: $1 (errno: $2)")).arg(fullName) + .arg(errno).end(); rc = false; } int rights = properties->st_mode & (S_IRWXO | S_IRWXG | S_IRWXU); if (chmod(fullName, rights) != 0) { if (logger != NULL) - logger->sayF(LOG_ERROR | CAT_FILE, LC_SET_PROPERTIES_2, - i18n("cannot change file modes: $1 (errno: $2)")).arg(fullName) - .arg(errno).end(); + logger->sayF(LOG_ERROR | CAT_FILE, LC_SET_PROPERTIES_2, + i18n("cannot change file modes: $1 (errno: $2)")).arg(fullName) + .arg(errno).end(); rc = false; } if (chown(fullName, properties->st_uid, properties->st_gid) != 0) { if (logger != NULL) - logger->sayF(LOG_ERROR | CAT_FILE, LC_SET_PROPERTIES_3, - i18n("cannot change file owner: $1 (errno: $2)")).arg(fullName) - .arg(errno).end(); + logger->sayF(LOG_ERROR | CAT_FILE, LC_SET_PROPERTIES_3, + i18n("cannot change file owner: $1 (errno: $2)")).arg(fullName) + .arg(errno).end(); rc = false; } #endif @@ -2375,49 +2376,77 @@ void ReDirTCP::doIt() { int port = m_programArgs.getInt("port"); int bufferSize = m_programArgs.getInt("size") * 1024; - const char* command = m_programArgs.arg(0); - if (_stricmp(command, "server") == 0) { + ReByteBuffer command = m_programArgs.arg(0); + if (command.isPrefixOf("server", -1, true)) { ReTCPEchoServer server(port, m_logger); server.listenForAll(); - } else if (_stricmp(command, "client") == 0) { + } else if (command.isPrefixOf("client", -1, true)) { const char* ip = m_programArgs.arg(1); + ReByteBuffer direction("download"); int rounds = 10; int interval = 5; - if (m_programArgs.argCount() > 2) - rounds = atoi(m_programArgs.arg(2)); + if (m_programArgs.argCount() > 2) { + direction = m_programArgs.arg(2); + if (!direction.isPrefixOf("download", -1, true) + && !direction.isPrefixOf("upload", -1, true) + && !direction.isPrefixOf("mixed", -1, true)) + help( + "unknown direction: $1 (use 'download', 'upload' or 'mixed')", + direction.str()); + } if (m_programArgs.argCount() > 3) - interval = atoi(m_programArgs.arg(3)); - ReTCPClient client(m_logger); - if (client.connect(ip, port)) { - time_t start = time(NULL); - ReByteBuffer message; + rounds = atoi(m_programArgs.arg(3)); + if (m_programArgs.argCount() > 4) + interval = atoi(m_programArgs.arg(4)); + if (tolower(direction.at(0)) == 'm') + runMixedClient(ip, port, rounds, interval, bufferSize); + else + runOneThreadClient(ip, port, rounds, interval, bufferSize, + tolower(direction.at(0)) == 'u'); + } else + help("unknown subcommand: $1", command.str()); + +} +void ReDirTCP::runMixedClient(const char* ip, int port, int rounds, + int interval, int bufferSize) { + help("not implemented: mixed"); +} +void ReDirTCP::runOneThreadClient(const char* ip, int port, int rounds, + int interval, int bufferSize, bool upload) { + ReTCPClient client(m_logger); + if (client.connect(ip, port)) { + time_t start = time(NULL); + const char* command = upload ? "strlen" : "filldata"; + ReByteBuffer message; + if (upload) + message.appendInt(bufferSize); + else message.appendChar('x', bufferSize); - time_t lastPrint = start; - int64_t size = 0; - int duration = 0; - for (int ii = 0; ii < rounds; ii++) { - client.send("strlen", message.str(), message.length()); - size += message.length(); - time_t now = time(NULL); - if (now >= lastPrint + interval) { - duration = int(now - start); - printf("%2d: %9.3f MiByte %8.3f kiByte/sec\n", ii, - size / 1024.0 / 1024, (double) size / duration / 1024); - lastPrint = now; - } + time_t lastPrint = start; + int64_t size = 0; + int duration = 0; + ReByteBuffer answer, data; + for (int ii = 0; ii < rounds; ii++) { + client.send(command, message.str(), message.length()); + client.receive(answer, data); + size += message.length() + data.length(); + time_t now = time(NULL); + if (now >= lastPrint + interval) { + duration = int(now - start); + printf("%2d: %9.3f MiByte %8.3f kiByte/sec %s\n", ii, + size / 1024.0 / 1024, (double) size / duration / 1024, + upload ? "up" : "down"); + lastPrint = now; } - duration = int(time(NULL) - start); - if (duration == 0) - duration = 1; - printf("%2d: %9.3f MiByte %8.3f kiByte/sec\n", rounds, - size / 1024.0 / 1024, (double) size / duration / 1024); - } - } else - help("unknown subcommand: $1", command); + duration = int(time(NULL) - start); + if (duration == 0) + duration = 1; + printf("%2d: %9.3f MiByte %8.3f kiByte %s/sec %s\n", rounds, + size / 1024.0 / 1024, (double) size / duration / 1024, upload ? "up" : "down"); + } } - /** * Constructor. * @@ -2425,20 +2454,21 @@ void ReDirTCP::doIt() { */ ReDirWhich::ReDirWhich(ReLogger* logger) : ReTool(s_batchUsage, s_batchExamples, 0, 0, 0, true, logger) { - // no standard options: +// no standard options: m_programArgs.addBool("all", i18n("all files will be found, not only the first"), 'a', "all", false); m_programArgs.addString("list", i18n("a path list (separator see option 'separator'"), 'l', "list", - false, NULL); + false, + NULL); m_programArgs.addString("separator", - i18n("separator between the path elements"), 's', "separator", false, + i18n("separator between the path elements"), 's', "separator", false, #if defined __linux__ - ":" + ":" #elif defined __WIN32__ - ";" + ";" #endif -) ; + ); m_programArgs.addString("variable", i18n("variable with the path list"), 'v', "variable", false, "PATH"); m_hasStandardArgs = false; diff --git a/os/ReDirTools.hpp b/os/ReDirTools.hpp index 0b52e5c..3623a0a 100644 --- a/os/ReDirTools.hpp +++ b/os/ReDirTools.hpp @@ -290,6 +290,10 @@ public: ReDirTCP(ReLogger* logger); protected: virtual void doIt(); +private: + void runMixedClient(const char* ip, int port, int rounds, int interval, int bufferSize); + void runOneThreadClient(const char* ip, int port, int rounds, + int interval, int bufferSize, bool upload); }; /** -- 2.39.5