//this file is part of NeoMule
//Copyright (C)2006 David Xanatos ( Xanatos@Lycos.at / http://neomule.sourceforge.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#pragma once

#ifdef NATTUNNELING // NEO: UTCP - [UserModeTCP] -- Xanatos -->

class CAbstractSocket
{
public:
	CAbstractSocket(CEMSocket* Parent) {m_Parent = Parent;}
	virtual ~CAbstractSocket() {}

	virtual	bool IsNatSocket() {return false;}
	virtual bool IsAsyncSocket()  {return false;}

	//Closes the socket.
	virtual void Close() = 0;

	//Establishes a connection to a peer socket.
	virtual BOOL Connect(LPCSTR lpszHostAddress, UINT nHostPort) = 0;
	virtual BOOL Connect(const SOCKADDR* lpSockAddr, int nSockAddrLen) = 0;

	//Receives data from the socket.
	virtual int Receive(void* lpBuf, int nBufLen, int nFlags = 0) = 0;

	//Sends data to a connected socket.
	virtual int Send(const void* lpBuf, int nBufLen, int nFlags = 0) = 0;


	//Disables Send and/or Receive calls on the socket.
	virtual BOOL ShutDown(int nHow = sends) = 0;
	enum { receives = 0, sends = 1, both = 2 };


	//Gets the address of the peer socket to which the socket is connected.
	virtual BOOL GetPeerName(SOCKADDR* lpSockAddr, int* lpSockAddrLen) = 0;

	//Gets the local name for a socket.
	//virtual BOOL GetSockName(SOCKADDR* lpSockAddr, int* lpSockAddrLen) = 0;

	//Retrieves a socket option.
	virtual BOOL GetSockOpt(int nOptionName, void* lpOptionValue, int* lpOptionLen, int nLevel = SOL_SOCKET) = 0;

	//Sets a socket option.
	virtual BOOL SetSockOpt(int nOptionName, const void* lpOptionValue, int nOptionLen, int nLevel = SOL_SOCKET) = 0;

#ifdef _DEBUG
	virtual void AssertValid() const { }
	virtual void Dump(CDumpContext& /*dc*/) const { }
#endif

protected:
	CEMSocket* m_Parent;
};

class CAsyncProxySocketLayer;
class CTCPSocket : public CAbstractSocket, public CEncryptedStreamSocket
{
public:
	CTCPSocket(CEMSocket* Parent):CAbstractSocket(Parent) 
	{
		// deadlake PROXYSUPPORT
		m_pProxyLayer = NULL;
		m_bProxyConnectFailed = false;
	}
	virtual ~CTCPSocket() {}

	virtual bool IsAsyncSocket() { return true; }

	//Notifies a listening socket that it can accept pending connection requests by calling Accept.
	virtual void OnAccept(int /*nErrorCode*/) {ASSERT(0);} // this sockets do not listen

	//Notifies a socket that the socket connected to it has closed.
	virtual void OnClose(int nErrorCode) {if(m_Parent) m_Parent->OnClose(nErrorCode);}

	//Notifies a connecting socket that the connection attempt is complete, whether successfully or in error.
	virtual void OnConnect(int nErrorCode) {if(m_Parent) m_Parent->OnConnect(nErrorCode);}

	//Notifies a listening socket that there is data to be retrieved by calling Receive.
	virtual void OnReceive(int nErrorCode) {if(m_Parent) m_Parent->OnReceive(nErrorCode);}

	//Notifies a socket that it can send data by calling Send.
	virtual void OnSend(int nErrorCode) {if(m_Parent) m_Parent->OnSend(nErrorCode);}

	//Notifies a socket that an error happend.
	virtual void OnError(int nErrorCode) {if(m_Parent) m_Parent->OnError(nErrorCode);}

	//Closes the socket.
	virtual void Close() { CEncryptedStreamSocket::Close(); }

	//Establishes a connection to a peer socket.
	virtual BOOL Connect(LPCSTR lpszHostAddress, UINT nHostPort)		{ return CEncryptedStreamSocket::Connect(lpszHostAddress, nHostPort); }
	virtual BOOL Connect(const SOCKADDR* lpSockAddr, int nSockAddrLen)  { return CEncryptedStreamSocket::Connect(lpSockAddr, nSockAddrLen); }

	//Receives data from the socket.
	virtual int Receive(void* lpBuf, int nBufLen, int nFlags = 0)		{ return CEncryptedStreamSocket::Receive(lpBuf, nBufLen, nFlags); }

	//Sends data to a connected socket.
	virtual int Send(const void* lpBuf, int nBufLen, int nFlags = 0)	{ return CEncryptedStreamSocket::Send(lpBuf, nBufLen, nFlags); }


	//Disables Send and/or Receive calls on the socket.
	BOOL ShutDown(int nHow = sends)										{ return CEncryptedStreamSocket::ShutDown(nHow); }
	enum { receives = 0, sends = 1, both = 2 };


	//Gets the address of the peer socket to which the socket is connected.
	BOOL GetPeerName(SOCKADDR* lpSockAddr, int* lpSockAddrLen)			{ return CEncryptedStreamSocket::GetPeerName(lpSockAddr, lpSockAddrLen); }

	//Gets the local name for a socket.
	//BOOL GetSockName(SOCKADDR* lpSockAddr, int* lpSockAddrLen)			{ return CEncryptedStreamSocket::GetSockName(lpSockAddr, lpSockAddrLen); }

	//Retrieves a socket option.
	BOOL GetSockOpt(int nOptionName, void* lpOptionValue, int* lpOptionLen, int nLevel = SOL_SOCKET)		{ return CEncryptedStreamSocket::GetSockOpt(nOptionName, lpOptionValue, lpOptionLen, nLevel); }

	//Sets a socket option.
	BOOL SetSockOpt(int nOptionName, const void* lpOptionValue, int nOptionLen, int nLevel = SOL_SOCKET)	{ return CEncryptedStreamSocket::SetSockOpt(nOptionName, lpOptionValue, nOptionLen, nLevel); }


	// deadlake PROXYSUPPORT
	void InitProxySupport();
	virtual void RemoveAllLayers();
	const CString GetLastProxyError() const { return m_strLastProxyError; }
	bool GetProxyConnectFailed() const { return m_bProxyConnectFailed; }

	// deadlake PROXYSUPPORT
	bool	m_bProxyConnectFailed;
	CAsyncProxySocketLayer* m_pProxyLayer;
	CString m_strLastProxyError;

protected:
	friend class CEMSocket;
	friend class CClientReqSocket;
	friend class CListenSocket;
	friend class CServerConnect;
#ifdef VOODOO // NEO: VOODOO - [UniversalPartfileInterface]
	friend class CVoodooSocket;
	friend class CVoodoo;
#endif // VOODOO // NEO: VOODOOx END

	virtual int	OnLayerCallback(const CAsyncSocketExLayer *pLayer, int nType, int nCode, WPARAM wParam, LPARAM lParam);

#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif
};

#endif //NATTUNNELING // NEO: UTCP END <-- Xanatos --