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
};
+/**
+ * Constructor.
+ *
+ * @param logger the logger for error handling
+ */
+ReSocketAddress::ReSocketAddress(ReLogger* logger) :
+ m_preferredFamily(AF_INET),
+ m_family(-1),
+ // m_addr;
+ m_port(0),
+ m_logger(logger),
+ // m_ip
+ m_name() {
+ memset(&m_addr, 0, sizeof m_addr);
+ memset(&m_ip, 0, sizeof m_ip);
+}
+/**
+ * Destructor.
+ */
+ReSocketAddress::~ReSocketAddress() {
+}
/**
- * Base class for TCP servers and clients.
+ * Sets the data from symbolic values.
*/
-class ReTCPConnection {
-public:
- ReTCPConnection(int id, ReLogger* logger);
- virtual ~ReTCPConnection();
-public:
- /**
- * Returns the connection id.
- * @return the id
- */
- inline int id() const {
- return m_id;
- }
- /**
- * Returns the connection port.
- * @return the port
- */
- inline int port() const {
- return m_port;
- }
- /**
- * Returns the socket (ip:port).
- * @return a string describing the socket
- */
- const char* socketName() const{
- return m_socketName.str();
- }
- void receive(ReByteBuffer& command, ReByteBuffer& message);
- void send(const char* command, const char* message, int length = -1);
- /** Sets the socket handle.
- * @param handle the socket handle to set
- */
- inline void setHandleSocket(int handle){
- m_handleSocket = handle;
- }
- /** Sets the id
- * @param id the id to set
- */
- inline void setId(int id){
- m_id = id;
+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_logger->sayF(LOG_ERROR | CAT_NETWORK, LC_SOCKET_ADDR_SET_1,
+ i18n("getaddrinfo($1) failed: $2")).arg(ip).arg(errno).end();
}
-protected:
- int m_port;
- ReByteBuffer m_socketName;
- ReByteBuffer m_received;
- ReLogger* m_logger;
- int m_handleSocket;
- struct sockaddr_in m_address;
- int m_id;
- uint32_t m_noSent;
- uint32_t m_noReceived;
-};
-class ReTCPServerConnection: public ReTCPConnection {
-public:
- ReTCPServerConnection(int id, ReLogger* logger);
- virtual ~ReTCPServerConnection();
-public:
- void handleConnection();
+ struct addrinfo* ptr;
+ bool hasIP4 = false;
+ bool hasIP6 = false;
-};
-/**
- * Implements a multithreaded TCP server.
- */
-class ReTCPServer: public ReTCPConnection {
-public:
- ReTCPServer(ReLogger* logger, int maxConnections = 16);
- virtual ~ReTCPServer();
-public:
- bool listenForAll();
-private:
- ReTCPServerConnection* createConnection(int id, int socket,
- struct sockaddr& address);
-protected:
- int m_maxConnections;
- int m_countConnections;
- ReTCPServerConnection** m_connections;
-};
+ // 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;
+ m_addr.m_addr4 = *(struct sockaddr_in *) ptr->ai_addr;
+ hasIP4 = true;
+ inet_ntop(ptr->ai_family, &m_addr.m_addr4.sin_addr, m_ip,
+ sizeof m_ip);
+ } else if (!hasIP6 && ptr->ai_family == AF_INET6) {
+ m_family = AF_INET6;
+ m_addr.m_addr6 = *(struct sockaddr_in6 *) ptr->ai_addr;
+ hasIP6 = true;
+ inet_ntop(ptr->ai_family, &m_addr.m_addr6.sin6_addr, 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);
+}
/**
- * Implements a TCP client.
+ * 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
*/
-class ReTCPClient: public ReTCPConnection {
-public:
- ReTCPClient(ReLogger* logger);
- virtual ~ReTCPClient();
-};
+bool ReTCPClient::connect(const char* ip, int port) {
+ bool rc = false;
+ struct hostent* peer;
+ int length = sizeof(struct in_addr);
+ // domain name (or numerical address)?
+ if (isdigit(ip[0]) || strchr(ip, ':') != NULL) {
+ peer = gethostbyaddr(ip, length, AF_INET);
+ }
+ if (peer == NULL) {
+ peer = gethostbyname(ip);
+ }
+ if (peer == NULL) {
+ peer = gethostbyaddr(ip, length, AF_INET);
+ }
+ if (peer == NULL) {
+ m_logger->sayF(LOG_ERROR | CAT_NETWORK, LC_CONNECT_1,
+ i18n("Id=$1: cannot write ($1): $2"));
+ } else {
+ struct in_addr** addr_list;
+ m_peerName.setLength(0);
+ addr_list = (struct in_addr **) peer->h_addr_list;
+ for (int ii = 0; addr_list[ii] != NULL; ii++) {
+ m_peerName.append((const char*) inet_ntoa(*addr_list[ii]), -1);
+ }
+ }
+}
/**
* Constructor.
* @param logger the logger for error handling
*/
ReTCPConnection::ReTCPConnection(int id, ReLogger* logger) :
- m_port(0),
- m_socketName(),
+ ReSocketAddress(logger),
+ m_peerName(),
m_received(),
m_logger(logger),
m_handleSocket(-1),
- // m_address
m_id(id),
- m_noSent(0),
- m_noReceived(0){
- memset(&m_address, 0, sizeof m_address);
+ m_noSent(0),
+ m_noReceived(0) {
}
/**
*/
ReTCPConnection::~ReTCPConnection() {
}
+/**
+ * Finishes the connection (in both directions) and frees the resouces.
+ */
+void ReTCPConnection::close(){
+ if (m_handleSocket >= 0){
+ ::close(m_handleSocket);
+ m_handleSocket = -1;
+ }
+}
-void ReTCPConnection::receive(ReByteBuffer& command, ReByteBuffer& message){
+/**
+ * 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);
+}
+void ReTCPConnection::receive(ReByteBuffer& command, ReByteBuffer& message) {
+ command.setLength(8);
+ int received = recv(m_handleSocket, command.buffer(), 8, 0);
}
void ReTCPConnection::send(const char* command, const char* message,
- int length){
+ int length) {
if (length < 0)
length = strlen(message);
ReByteBuffer header;
error = error + 0;
#elif defined __WIN32__
#endif
- if (error != 0){
+ if (error != 0) {
error += 0;
m_logger->sayF(LOG_ERROR | CAT_NETWORK, LC_WRITE_1,
- i18n("Id=$1: cannot write ($1): $2"));
+ i18n("Id=$1: cannot write ($1): $2"));
//.arg.(m_id)
- // .arg(error).arg(m_socketName).end();
+ // .arg(error).arg(m_peerName).end();
}
}
* @param id an identifier for logging
* @param logger the logger for error handling
*/
-ReTCPServerConnection::ReTCPServerConnection(int id, ReLogger* logger) :
- ReTCPConnection(id, logger) {
+ReTCPServerConnection::ReTCPServerConnection(int id, ReLogger* logger,
+ ReTCPServer* server) :
+ ReTCPConnection(id, logger),
+ m_server(server){
}
/**
* Destructor.
*/
-ReTCPServerConnection::~ReTCPServerConnection(){
+ReTCPServerConnection::~ReTCPServerConnection() {
+}
+
+/**
+ * Serves the commands of a single connection (in a single thread).
+ */
+void ReTCPServerConnection::handleConnection() {
+ //Get the socket descriptor
+ int read_size;
+ 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){
+ m_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);
+ 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
*/
-ReTCPServer::ReTCPServer(ReLogger* logger, int maxConnections) :
+ReTCPServer::ReTCPServer(int port, class ReNetCommandHandler& commandHandler,
+ ReLogger* logger, int maxConnections) :
ReTCPConnection(0, logger),
m_maxConnections(maxConnections),
m_countConnections(0),
- m_connections(new ReTCPServerConnection*[maxConnections]) {
+ m_connections(new ReTCPServerConnection*[maxConnections]),
+ m_handler(commandHandler) {
+ m_port = port;
+ memset(m_connections, 0, maxConnections * sizeof *m_connections);
}
/**
delete[] m_connections;
m_connections = NULL;
}
-
-ReTCPServerConnection* ReTCPServer::createConnection(int id, int socket,
- struct sockaddr& address) {
+/**
+ * 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; ii < m_maxConnections; ii++) {
+ for (int ii = 0; rc == NULL && ii < m_maxConnections; ii++) {
if (m_connections[ii] == NULL)
- m_connections[ii] = rc = new ReTCPServerConnection(id, m_logger);
+ m_connections[ii] = rc = new ReTCPServerConnection(id, m_logger, this);
else if (m_connections[ii]->id() < 0) {
rc = m_connections[ii];
rc->setId(id);
}
}
if (rc != NULL) {
- rc->setHandleSocket(socket);
- rc->setAddress(address);
+ 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;
}
-
/**
* The start routine of pthread_start
*
*
* @param pConnection a void* pointer to the ReTCPServerConnection instance
* */
-void* connection_handler(void *pConnection) {
+static void* connection_handler(void *pConnection) {
ReTCPServerConnection* connection =
reinterpret_cast<ReTCPServerConnection*>(pConnection);
connection->handleConnection();
}
-
/**
* Accepts connections and create a thread which will handle this connection.
*/
bool ReTCPServer::listenForAll() {
bool rc = false;
- //Create socket
- m_handleSocket = socket(AF_INET, SOCK_STREAM, 0);
+ struct addrinfo hints;
+ struct addrinfo* addrInfo;
+
+ // 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 {
- //Prepare the sockaddr_in structure
- m_address.sin_family = AF_INET;
- m_address.sin_addr.s_addr = INADDR_ANY;
- m_address.sin_port = htons(m_port);
-
- //Bind
- if (bind(m_handleSocket, (struct sockaddr *) &m_address, sizeof(m_address))
- < 0) {
+ 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, &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 {
+ i18n("cannot bind: $1")).arg(errno).end();
+ else {
//Listen
- listen(m_handleSocket, 3);
+ 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,
LC_LISTEN_FOR_ALL_5,
i18n("connection refused (too many connections): $1"))
.arg(m_port).end();
- close(clientSocket);
+ ::close(clientSocket);
} else {
pthread_t sniffer_thread;
ReTCPConnection* connection = createConnection(nextId++,
LC_LISTEN_FOR_ALL_6,
i18n("cannot create a thread: $1")).arg(
getLastOSError()).end();
- close(clientSocket);
+ ::close(clientSocket);
+ clientSocket = -1;
}
//Now join the thread , so that we dont terminate before the thread
puts("Handler assigned");
}
}
-
if (clientSocket < 0) {
perror("accept failed");
return 1;
return rc;
}
-void ReTCPServerConnection::handleConnection() {
- //Get the socket descriptor
- int read_size;
- char *message, client_message[2000];
-#if 0
- receive(m_received, command);
- if (! m_received.startsWith("login"))
-//Send some messages to the m_addrClient
- message = "Greetings! I am your connection handler\n";
- write(m_handleSocket, message, strlen(message));
-
- message = "Now type something and i shall repeat what you type \n";
- write(m_handleSocket, message, strlen(message));
+/**
+ * Constructor.
+ */
+ReNetCommandHandler::ReNetCommandHandler() :
+ m_nextHandler(NULL) {
+}
-//Receive a message from m_addrClient
- while ((read_size = recv(sock, client_message, 2000, 0)) > 0) {
- //Send the message back to m_addrClient
- write(m_handleSocket, client_message, strlen(client_message));
- }
+/**
+ * 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);
+}
- if (read_size == 0) {
- puts("Client disconnected");
- fflush(stdout);
- } else if (read_size == -1) {
- perror("recv failed");
- }
-#endif
-//Free the socket pointer
- close(m_handleSocket);
- m_id = -1;
+/**
+ * Constructor.
+ *
+ * @param port port for listening
+ * @param logger logger for error handling
+ */
+ReTCPEchoServer::ReTCPEchoServer(int port, ReLogger* logger) :
+ ReTCPServer(port, *this, logger),
+ ReNetCommandHandler() {
+}
+/**
+ * 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<br>
+ * PS_PROCESSED: command successfully processed<br>
+ * PS_FAILED: command processed, error occurred<br>
+ * 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("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;
+};
/*
* ReTCP.hpp
*
- * Created on: 04.03.2015
- * Author: hm
+ * License: Public domain
+ * Do what you want.
+ * No warranties and disclaimer of any damages.
+ * The latest sources: https://github.com/republib
*/
#ifndef NET_RETCP_HPP_
#define NET_RETCP_HPP_
+/**
+ * Administrates the internal data of an ip address, usable for IP4 and IP6.
+ */
+class ReSocketAddress {
+public:
+ ReSocketAddress(ReLogger* logger);
+ virtual ~ReSocketAddress();
+public:
+ /**
+ * Returns the ip address, e.g. "192.168.2.1".
+ * @return a string with the ip address (IP4 or IP6)
+ */
+ const char* ip() const {
+ return m_ip;
+ }
+ /**
+ * Returns the connection port.
+ * @return the port
+ */
+ inline int port() const {
+ return m_port;
+ }
+ /**
+ * Returns the socket name ("<ip>:<port>").
+ * @return a string describing the socket, e.g. "192.168.2.1:443"
+ */
+ const char* name() const {
+ return m_name.str();
+ }
+ void setAddress(const char* ip, int port);
+ /** Sets the preferred IP family type (
+ * @param type AF_INET (for IP4) or AF_INET6 (for IP6)
+ */
+ inline void setPreferredFamily(int family) {
+ m_preferredFamily = family;
+ }
+protected:
+ //@ if both families are available this family will be chosen.
+ //@ AF_INET (for IP4) or AF_INET6 (for IP6)
+ int m_preferredFamily;
+ //@ AF_INET (for IP4) or AF_INET6 (for IP6)
+ int m_family;
+ union {
+ //@ IP4 variant:
+ struct sockaddr_in m_addr4;
+ //@ IP6 variant:
+ struct sockaddr_in6 m_addr6;
+ } m_addr;
+ int m_port;
+ ReLogger* m_logger;
+ char m_ip[INET6_ADDRSTRLEN + 1];
+ ReByteBuffer m_name;
+};
+
+/**
+ * Base class for TCP servers and clients.
+ */
+class ReTCPConnection: public ReSocketAddress {
+public:
+ ReTCPConnection(int id, ReLogger* logger);
+ virtual ~ReTCPConnection();
+public:
+ void close();
+ /**
+ * Returns the connection id.
+ * @return the id
+ */
+ inline int id() const {
+ return m_id;
+ }
+ void receive(ReByteBuffer& command, ReByteBuffer& message);
+ void send(const char* command, const char* message, int length = -1);
+ void setConnectedAddress(int family, const char* ip, int port);
+ /** Sets the socket handle.
+ * @param handle the socket handle to set
+ */
+ inline void setHandleSocket(int handle) {
+ m_handleSocket = handle;
+ }
+ /** Sets the id
+ * @param id the id to set
+ */
+ inline void setId(int id) {
+ m_id = id;
+ }
+protected:
+ ReByteBuffer m_peerName;
+ ReByteBuffer m_received;
+ ReLogger* m_logger;
+ int m_handleSocket;
+ int m_id;
+ uint32_t m_noSent;
+ uint32_t m_noReceived;
+};
+
+/**
+ * Implements a TCP client.
+ */
+class ReTCPClient: public ReTCPConnection {
+public:
+ ReTCPClient(ReLogger* logger);
+ virtual ~ReTCPClient();
+public:
+ bool connect(const char* ip, int port);
+};
+
+class ReTCPServer;
+/**
+ * Implements a single server connection to a client (in a single thread).
+ */
+class ReTCPServerConnection: public ReTCPConnection {
+public:
+ ReTCPServerConnection(int id, ReLogger* logger, ReTCPServer* server);
+ virtual ~ReTCPServerConnection();
+public:
+ void handleConnection();
+private:
+ ReTCPServer* m_server;
+};
+class ReNetCommandHandler;
+/**
+ * Implements a multithreaded TCP server.
+ */
+class ReTCPServer: public ReTCPConnection {
+public:
+ ReTCPServer(int port, class ReNetCommandHandler& commandHandler,
+ ReLogger* logger, int maxConnections = 16);
+ virtual ~ReTCPServer();
+public:
+ /** Returns the command handler.
+ * @return the handler for the incoming messages
+ */
+ inline ReNetCommandHandler& handler(){
+ return m_handler;
+ }
+ bool listenForAll();
+private:
+ ReTCPServerConnection* createConnection(int id, int handleSocket,
+ const struct sockaddr& address);
+
+protected:
+ int m_maxConnections;
+ int m_countConnections;
+ ReTCPServerConnection** m_connections;
+ ReNetCommandHandler& m_handler;
+};
+
+/**
+ * An abstract base class of a handler which processes the incoming TCP commands.
+ */
+class ReNetCommandHandler {
+public:
+ enum ProcessingState {
+ PS_UNDEF, // undefined value
+ PS_UNKNOWN, // command not recognized
+ PS_PROCESSED, // task has been successfully handled
+ PS_FAILED, // task has been handled, error occurred
+ PS_STOP, // no further processing should be done
+ };
+public:
+ ReNetCommandHandler();
+ /** Destructor.
+ */
+ virtual ~ReNetCommandHandler(){
+ }
+public:
+ void addHandler(ReNetCommandHandler* handler);
+ /** Processes the command from the TCP channel.
+ * @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<br>
+ * PS_PROCESSED: command successfully processed<br>
+ * PS_FAILED: command processed, error occurred<br>
+ * PS_ABORT: connection should be finished
+ */
+ virtual ProcessingState handleNetCommand(ReByteBuffer& command,
+ ReByteBuffer& data, ReTCPConnection* connection) = 0;
+
+protected:
+ ReNetCommandHandler* m_nextHandler;
+};
+class ReTCPEchoServer : public ReTCPServer, public ReNetCommandHandler {
+public:
+ ReTCPEchoServer(int port, ReLogger* logger);
+ virtual ~ReTCPEchoServer();
+public:
+ virtual ProcessingState handleNetCommand(ReByteBuffer& command,
+ ReByteBuffer& data, ReTCPConnection* connection);
+};
#endif /* NET_RETCP_HPP_ */