
/*---------------------------------------------------------------------------*/
/* udsocket.h                                                               */
/* copyright (c) innovaphone 2015                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

// Socket-Status defines
#define SST_CLOSED					0
#define	SST_OPENED					1
#define SST_CONNECTION_INITIATED	2
#define SST_CONNECTED				3
#define SST_DO_SHUTDOWN				4

#define SST_BIND_START              5
#define SST_BIND_DONE               6
#define SST_LISTEN                  7
#define SST_NEED_ACCEPT             8

class UDSocketContext : public ISocketContext {
public:
};

class UDSocketProvider : public ISocketProvider {
    friend class UDSocket;
    virtual class UDSocket * NewSocket(IIoMux * const iomux, USocket * const user, IInstanceLog * const log);
public:
    virtual ISocketContext * CreateSocketContext(class IInstanceLog * const log) override;
    virtual ISocket * CreateSocket(IIoMux * const iomux, USocket * const user, class IInstanceLog * const log, bool useIPv6 /* ignored */, class ISocketContext * socketContext = NULL /* ignored */) override;
};

class UDSocket : public ISocket, public UIoContext, public UIoExec {
protected:
    IIoMux * const iomux;
    IInstanceLog * const log;
    UDSocketProvider * const provider;
    USocket * user;
    int socketStatus;

    std::queue<struct UDSSendBuffer *> sendQueue;

    void * recvBuf;
    size_t recvBufLen;
    size_t recvBufAlreadyRead;
    bool recvBufReadPartial;
    int execCnt;
    bool shutDown;
    shutdownreason_t shutdownReason;
    bool isServer;
    int remoteFD;

    void AddNewSendBuffer(const void * buf, size_t len);
    bool SendQueuedData();
    bool ReceiveData();
    bool DoAccept();
    void DoShutdown();

    virtual void FDNotify(bool notifyRX, bool notifyTX) {};

    inline void UserSocketConnectComplete();
    inline void UserSocketBindResult(const char * localAddr, word localPort);
    inline void UserSocketListenResult(const char * remoteAddr, word remotePort);
    inline void UserSocketAcceptComplete(USocket * const remoteUser, UDSocket * remoteSocket);
    inline void UserSocketShutdown(shutdownreason_t reason);
    inline void UserSocketSendResult();
    inline void UserSocketRecvResult(void * buf, size_t len);
    inline void UserSocketRecvCanceled(void * buf);

public:
    UDSocket(IIoMux * const iomux, USocket * const user, class IInstanceLog * const log, UDSocketProvider * provider);
    virtual ~UDSocket();
    virtual void OpenSocket();

    void Connect(const char *address, const char * serverName = NULL) override;
    void Bind(const char * localAddr = NULL, word localPort = 0 /* ignored */) override;
    void Listen() override;
    void Accept(USocket * const remoteUser) override;
    void Shutdown() override;
    void Send(const void * buf, size_t len) override;
    void Recv(void * buf, size_t len, bool recvPartial = false) override;
    void SetUser(class USocket * const user, bool * createdByServer, const char ** remoteAddress, const char ** serverName) override { this->user = user; }

    void IoContextNotify(bool indRX, bool indTX) override;
    void IoExec(void * context) override;
};
