#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