#ifndef PROTOCOL_H
#define PROTOCOL_H
#include <mutex>
#include "common.h"
#include "address.h"
#include "connection.h"
#include "server.h"
enum : ErrorCode {
ERR_PROTOCOL_COMMON = ERR_SERVER,
ERR_PROTOCOL_NOT_INITIALIZED,
};
class Protocol;
class Socket {
public:
enum : unsigned int {
CHANGED = 1 << 0,
CREATED = 1 << 1,
REMOVED = 1 << 2,
WANTREAD = 1 << 3,
WANTWRITE = 1 << 4, };
Protocol &protocol;
const Connection::Handle connection;
const Server::Handle server;
const Address &address;
private:
friend class Protocol;
// these vars protected by protocol.mutex
unsigned int flags;
Socket *prev, *next;
Socket *chPrev, *chNext;
// protocol.mutex must be already locked
void setChanged(bool changed);
protected:
// protocol.mutex must be already locked
Socket(const Socket&) = delete;
Socket(
Protocol &protocol,
const Connection::Handle &connection,
const Server::Handle &server,
const Address &address );
~Socket();
public:
// thread-saef methods
void setWantRead(bool want);
void setWantWrite(bool want);
void finalize();
};
class Protocol: public Shared {
public:
typedef ::Handle<Protocol> Handle;
typedef std::recursive_mutex Mutex;
typedef std::lock_guard<Mutex> Lock;
private:
friend class Socket;
Socket *first, *last;
Socket *chFirst, *chLast;
inline void socketCheck(Socket *socket, bool mustBeChanged = false) {
assert(socket);
assert(&socket->protocol == this);
assert(!mustBeChanged || (socket->flags & Socket::CHANGED));
}
protected:
Mutex mutex;
bool allowNewConnections;
// any class derived from Protocol may access to Socket private members via these methods
// mutex must be locked before call
inline Socket* socketFirst()
{ return first; }
inline Socket* socketNext(Socket *socket)
{ socketCheck(socket); return socket->next; }
inline Socket* socketChFirst()
{ return chFirst; }
inline Socket* socketChNext(Socket *socket)
{ socketCheck(socket, true); return socket->chNext; }
inline unsigned int socketFlags(Socket *socket)
{ socketCheck(socket); return socket->flags; }
inline Socket* socketRemove(Socket *socket)
{ socketCheck(socket); Socket *next = socket->next; delete socket; return next; }
inline Socket* socketRemoveChanged(Socket *socket)
{ socketCheck(socket, true); Socket *chNext = socket->chNext; delete socket; return chNext; }
inline Socket* socketSetUnchanged(Socket *socket)
{ socketCheck(socket, true); Socket *chNext = socket->chNext; socket->setChanged(false); return chNext; }
// thread-safe methods
void connectionOpen(const Connection::Handle &connection, Socket *socket);
virtual void wakeup();
public:
// thread-safe methods
Protocol();
virtual ~Protocol();
virtual ErrorCode resolve(Address &address);
virtual ErrorCode connect(const Connection::Handle &connection, const Address &address);
virtual ErrorCode listen(const Server::Handle &server, const Address &address);
void closeAll();
};
#endif