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

// According to OpenSSL Doc, the maximum size of an TLS Socket 
///#define MAX_TLS_FRAME_SIZE  16384

class TLSSocketProvider : public ISocketProvider {
    friend class TLSSocket;
    virtual class TLSSocket * NewSocket(IIoMux * const iomux, USocket * const user, class ISocketContext * socketContext, IInstanceLog * const log, ISocket * tcpSocketToUpgrade = nullptr);
protected:
    ISocketProvider * tcpSocketProvider;
public:
    TLSSocketProvider(ISocketProvider * tcpSocketProvider);
    virtual ~TLSSocketProvider();
    virtual ISocketContext * CreateSocketContext(class IInstanceLog * const log) override;
    virtual ISocket * CreateSocket(IIoMux * const iomux, USocket * const user, IInstanceLog * const log, bool useIPv6, class ISocketContext * socketContext = NULL) override;
    virtual ISocket * UpgradeToTLSSocket(class ISocket * fromTCPSocket, IIoMux * const iomux, USocket * const user, IInstanceLog * const log, class ISocketContext * socketContext = NULL) override;
};

class TLSSocket : public ISocket, public USocket, public UIoExec {
protected:
    friend class TLSSocketProvider;

    IIoMux * const iomux;
    IInstanceLog * const log;
    TLSSocketProvider * const provider;
    USocket * user;
    ISocket * tcpSocket;

    class ISocketContext * socketContext;
    class ISSLInstance * ssl;

    int state;
    unsigned tcpSending;
    int execCnt;
    bool shutDown;
    shutdownreason_t shutdownReason;
    bool isServer;
    bool createdByServer;
    char * remoteAddress;
    char * serverName;

    std::queue<byte *> sendQueue;

    byte * sendBuffer;
    size_t sendBufferSize;
    byte * recvBuffer;
    size_t recvBufferSize;
    byte * userRecvBuffer;
    size_t userRecvBufferSize;
    size_t userDataReceived;
    bool userReadPartial;
    bool recvPending;
    bool startTLSMode;

    void DoSSLHandshake();
    void DoShutdown();
    void SSLSend(const void * buf, size_t len);
    int SendSSLData();
    bool ReadSSLData();
    void ConnectionEstablished();

    bool ALPNProtocolAccepted();

    inline void UserSocketConnectComplete();
    inline void UserSocketBindResult(const char * localAddr, word localPort);
    inline void UserSocketListenResult(const char * remoteAddr, word remotePort);
    inline void UserSocketAcceptComplete();
    inline void UserSocketShutdown(shutdownreason_t reason);
    inline void UserSocketSendResult();
    inline void UserSocketRecvResult(void * buf, size_t len);
    inline void UserSocketRecvCanceled(void * buf);
    inline void UserSocketUpgradeToTLSComplete(ISocket * const socket);

public:
    TLSSocket(IIoMux * const iomux, USocket * const user, class ISocketContext * socketContext, IInstanceLog * const log, TLSSocketProvider * provider, ISocket * tcpSocketToUpgrade);
    virtual ~TLSSocket();

    void Connect(const char * address, const char * serverName = NULL) override;
    void GetLocalAddress(char * localAddr, unsigned size, word * localPort) override;
    void GetRemoteAddress(char * remoteAddr, unsigned size, word * remotePort) override;
    void Bind(const char * localAddr = NULL, word localPort = 0) override;
    void Bind(const char * localAddr, word localPort, bool reuseAddr) override;
    void Listen() override;
    void Accept(class USocket * 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;

    void SocketConnectComplete(ISocket * const socket) override;
    void SocketBindResult(ISocket * const socket, const char * localAddr, word localPort) override;
    void SocketListenResult(ISocket * const socket, const char * remoteAddr, word remotePort) override;
    void SocketAcceptComplete(ISocket * const socket) override;
    void SocketShutdown(ISocket * const socket, shutdownreason_t reason) override;
    void SocketSendResult(ISocket * const socket) override;
    void SocketRecvResult(ISocket * const socket, void * buf, size_t len) override;
    void SocketRecvCanceled(ISocket * const socket, void * buf) override;
    void IoExec(void * execContext) override;
};
