Blob Blame Raw
#ifndef CONNECTION_H
#define CONNECTION_H


#include <cassert>

#include <atomic>
#include <condition_variable>

#include "utils.h"


#define MAX_ADDR_SIZE 256


class Protocol;
class Server;


class Root {
public:
	virtual ~Root() { }
};


class Connection: public Root {
public:
	enum State: int {
		STATE_NONE,
		STATE_OPENING,
		STATE_INITIALIZING,
		STATE_RESOLVING,
		STATE_CONNECTING,
		STATE_OPEN,
		STATE_CLOSE_REQ,
		STATE_CLOSING,
		STATE_CLOSED,
		STATE_FINISHED
	};
	
	struct Task {
		void *data;
		size_t size;
		size_t completion;
		bool watch;
		Task *next;
		
		inline explicit Task(
			void *data = nullptr,
			size_t size = 0,
			size_t completion = 0,
			bool watch = false,
			Task *next = nullptr
		):
			data(data), size(size), completion(completion), watch(watch), next(next)
			{ assert(!!data == !!size); }
	};
	
	typedef CounteredQueueMISO<Task, &Task::next> TaskQueue;
	
private:
	friend class Protocol;
	
	std::atomic<State> state;
	std::atomic<State> stateWanted;
	ReadProtector stateProtector;
	std::atomic<bool> enqueued;
	std::atomic<bool> error;
	
	std::atomic<int> closeWaiters;
	std::atomic<int> finishWaiters;
	std::condition_variable closeCondition;
	
	unsigned char address[MAX_ADDR_SIZE];
	size_t addressSize;
	
	Protocol *protocol;
	Server *server;
	Connection *prev, *next;
	Connection *srvPrev, *srvNext;
	Connection *queueNext;
	int sockId;
	State stateLocal;
	bool errorLocal;
	
	std::atomic<unsigned int> events;
	TaskQueue readQueue;
	TaskQueue writeQueue;
	
	void wantState(State state, bool error);
	
public:
	typedef      QueueMISO<Connection, &Connection::queueNext> Queue;
	friend class QueueMISO<Connection, &Connection::queueNext>;
	friend class ChainFuncs<Connection, &Connection::queueNext>;
	
public:
	Connection();
	virtual ~Connection();
	
	bool open(Protocol &protocol, void *address, size_t addressSize, int sockId = -1, Server *server = nullptr);
	void closeReq();
	void close(bool error);
	void closeWait(unsigned long long timeoutUs = 0, bool withReq = true, bool error = true);
	
	bool read(Task &task);
	bool write(Task &task);
	
protected:
	virtual void onOpeningError();
	virtual void onOpen(const void *address, size_t addressSize);
	virtual bool onReadReady(Task &task, bool error);
	virtual bool onWriteReady(Task &task, bool error);
	virtual void onCloseReqested();
	virtual void onClose(bool error);
};


#endif