Blob Blame Raw
#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