#ifndef TCP_H
#define TCP_H
#include <atomic>
#include <thread>
#include <vector>
#include <list>
#include <mutex>
#include "error.h"
enum : ErrorCode {
ERR_TCP_COMMON = ERR_TCP,
ERR_TCP_RESOLVE_FAILED,
ERR_TCP_BAD_ADDRESS,
ERR_TCP_BAD_HANDLER,
ERR_TCP_CONNECTION_FAILED,
ERR_TCP_CONNECTION_LOST,
ERR_TCP_LISTEN_FAILED,
ERR_TCP_LISTEN_LOST,
};
namespace Tcp {
enum Status {
STATUS_NONE,
STATUS_OPEN,
STATUS_CLOSED,
STATUS_LOST,
};
typedef int SockId;
class Address {
public:
unsigned char ip[4];
unsigned short port;
inline Address():
ip(), port() { }
inline Address(unsigned char ip0, unsigned char ip1, unsigned char ip2, unsigned char ip3, unsigned short port):
port(port) { ip[0] = ip0, ip[1] = ip1, ip[2] = ip2, ip[3] = ip3; }
inline Address(unsigned char *ip, unsigned short port):
Address(ip[0], ip[1], ip[2], ip[3], port) { }
inline bool isValidIp() const
{ return ip[0] || ip[1] || ip[2] || ip[3]; }
inline bool isValidPort() const
{ return port; }
inline bool isValid() const
{ return isValidIp() && isValidPort(); }
ErrorCode resolve(const char *addrString);
};
class Connection {
private:
Status status;
ErrorCode lastError;
SockId sockId;
Address remoteAddr;
std::atomic<bool> stopping;
Connection(const Connection&) = delete;
Connection& operator=(const Connection&) = delete;
public:
Connection();
Connection(SockId sockId, const Address &remoteAddr);
~Connection();
inline Status getStatus() const
{ return status; }
ErrorCode getLastError() const
{ return lastError; }
inline SockId getSockId() const
{ return sockId; }
inline const Address& getRemoteAddr() const
{ return remoteAddr; }
inline void stop()
{ stopping = true; }
inline bool check() {
if (stopping) close(ERR_TCP_CONNECTION_LOST);
return status == STATUS_OPEN;
}
bool open(const Address &remoteAddr);
void close(ErrorCode errorCode = ERR_NONE);
bool read(void *data, size_t size);
bool write(const void *data, size_t size);
};
class Handler {
public:
virtual ~Handler();
virtual void handleTcpConnection(Connection &connection) = 0;
};
class Server {
public:
struct ConnDesc {
Connection *connection;
std::thread *thread;
};
typedef std::list<ConnDesc> ConnList;
typedef std::vector<ConnDesc> ConnVector;
private:
Status status;
ErrorCode lastError;
SockId sockId;
Address localAddr;
Handler *handler;
std::thread *thread;
std::atomic<bool> stopping;
std::mutex connectionsMutex;
ConnList connections;
ConnVector connectionsFinished;
Server(const Server&) = delete;
Server& operator=(const Server&) = delete;
void cleanConnections();
void handleConnection(ConnList::iterator iter);
void listen();
public:
Server();
~Server();
inline Status getStatus() const
{ return status; }
ErrorCode getLastError() const
{ return lastError; }
inline SockId getSockId() const
{ return sockId; }
inline const Address& getLocalAddr() const
{ return localAddr; }
inline Handler* getHandler() const
{ return handler; }
inline bool check()
{ return !stopping && status == STATUS_OPEN; }
bool start(const Address &localAddr, Handler *handler);
void join();
void stop();
};
} // Tcp
#endif