Blob Blame Raw
#ifndef SOCKET_H
#define SOCKET_H


#include <cassert>

#include <atomic>
#include <condition_variable>

#include "utils.h"


#define MAX_ADDR_SIZE 256



enum State: int {
	STATE_NONE,
	STATE_OPENING,
	STATE_INITIALIZING,
	STATE_RESOLVING,
	STATE_CONNECTING,
	STATE_OPEN,
	STATE_CLOSE_REQ,
	STATE_CLOSING_CONNECTIONS,
	STATE_CLOSING,
	STATE_CLOSED,
	STATE_FINISHED,
	STATE_DESTROYED
};


class Protocol;
class Connection;
class Server;


class Socket {
private:
	friend class Protocol;
	friend class Connection;
	friend class Server;
	
	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;
	Socket *prev, *next;
	Socket *queueNext;
	int sockId;
	State stateLocal;
	
	std::atomic<unsigned int> events;
	
	struct OpenLock {
		Socket &socket;
		const bool success;
		OpenLock(Socket &socket, Protocol &protocol, void *address, size_t addressSize):
			socket(socket), success(socket.openBegin(protocol, address, addressSize)) { }
		~OpenLock()
			{ if (success) socket.openEnd(); }
	};
	
	bool openBegin(Protocol &protocol, void *address, size_t addressSize);
	void openEnd();
	
	void initSocket(int sockId);
	void enqueue();
	void updateEvents(bool wantRead, bool wantWrite);
	void wantState(State state, bool error);
	
	void destroy();
	
public:
	typedef      QueueMISO<Socket, &Socket::queueNext> Queue;
	friend class QueueMISO<Socket, &Socket::queueNext>;
	friend class ChainFuncs<Socket, &Socket::queueNext>;
	
public:
	Socket();
	virtual ~Socket();
	
	void closeReq();
	void close(bool error);
	void closeWait(unsigned long long timeoutUs = 0, bool withReq = true, bool error = true);
	
private:
	virtual void handleState() = 0;
	virtual void handleEvents(unsigned int events) = 0;
	
protected:
	virtual void onOpeningError();
	virtual void onOpen(const void *address, size_t addressSize);
	virtual void onCloseReqested();
	virtual void onClose(bool error);
};


#endif