//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 -->
#include "AbstractSocket.h"
#include "Neo/NeoDebugC.h" // NEO: ND - [NeoDebug]

#pragma pack(1)
struct sUserModeTCPConfig{
	sUserModeTCPConfig(uint32 IP, uint16 Port)
	{
		TargetIP = IP;
		TargetPort = Port;
		Version = 0;
		MaxSegmentSize = 0;
		MaxUploadBufferSize = 0;
		MaxDownlaodBufferSize = 0;
	}
	uint32	TargetIP;
	uint16	TargetPort;
	uint8	Version;
	uint32	MaxSegmentSize;
	uint32	MaxUploadBufferSize;
	uint32	MaxDownlaodBufferSize;
};
#pragma pack()

#pragma pack(1)
struct sTransferBufferEntry{
	sTransferBufferEntry(uint32 size, const BYTE* data, uint32 Nr)
	{
		uSize = size;
		pBuffer = new BYTE[uSize];
		memcpy(pBuffer,data,size);
		uSequenceNr = Nr;
		uSendCount = 0;
		uSendTime = 0;
	}
	~sTransferBufferEntry() { delete [] pBuffer; }

	BYTE*	pBuffer;		// buffered data
	uint32	uSize;			// data size, <= max segment size
	uint32	uSequenceNr;	// segment sequence number
	uint8	uSendCount;		// we will not try resending the packet for ever just a few times
	uint32	uSendTime;		// time when we send the packet for the RTT and resend timeout
};
// Note to uSequenceNr: Normal TCP uses here the number if the first byte in the segment
//						This implementation uses an linear sequencing what is much easyer to handle 
//						and allows us to ACK segments out of order what is usefull for congestion control
//						An other reason is that assuming 1KB large segments we can transfer 4 TB without a wrap arund, 
//							so at all no sequence number wrap arund implementation is needed
#pragma pack()

typedef CRBMap<uint32,sTransferBufferEntry*> TransferBuffer;


///////////////////////////////////////////////////////////////////////////////
// CUDPSocketWnd

/*class CNATSocketWnd : public CWnd
{
// Construction
public:
	CNATSocketWnd() {m_pOwner = NULL; m_timer = 0;}
	CNATSocket* m_pOwner;

protected:
	DECLARE_MESSAGE_MAP()
	afx_msg int  OnCreate(LPCREATESTRUCT lpCreateStruct);
	afx_msg void OnDestroy();
	afx_msg void OnTimer(UINT nIDEvent);

	//afx_msg LRESULT OnCloseSocket(WPARAM wParam,LPARAM lParam);

private:
	uint32 m_timer;
};*/


///////////////////////////////////////////////////////////////////////////////
// CNATSocket

class CNATSocket : public CAbstractSocket
{
public:
	CNATSocket(CEMSocket* Parent);
	virtual ~CNATSocket();

	virtual	bool IsNatSocket() {return true;}

	// set new User Mode TCP Sonfigurations
	void SetConfig(sUserModeTCPConfig* UserModeTCPConfig);
	bool IsConfig()	{return m_UserModeTCPConfig != NULL;}

	//Notification Functions
	//----------------------

	//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	// Note: This function *MUST* be called form the main thread !!!
	////////////////////////////////////////////////////////////////

	//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);}


	//Operations
	//----------

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

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

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

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


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

	bool IsShutDown() {return (m_ShutDown & 0x04) == 0x04;}


	//Attributes
	//----------

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

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

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

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


protected:
	//friend class CNATSocketWnd;
	friend class CClientUDPSocket;
	friend class CListenSocket;
	friend class CEMSocket;
	friend class CUpDownClient;

	void ProcessDataPacket(const BYTE* packet, UINT size);
	void ProcessAckPacket(const BYTE* packet, UINT size);

#ifdef ISPBYPASS // NEO: SUC - [SafeUCPCommunication]
	void Secure(const byte* pKey, const uint8 uLen, uint8 Side);
	bool IsSecure() {return uKeyLength > 0;}
	byte* GetInputKey() {return abyInputKey;}
	void SendPacketUDP(Packet* packet);
#endif // ISPBYPASS // NEO: SUC END

	void CheckForTimeOut();

	sUserModeTCPConfig* m_UserModeTCPConfig; // our general settings
	uint32 GetTargetIP() {return m_UserModeTCPConfig ? m_UserModeTCPConfig->TargetIP : 0;}
	uint16 GetTargetPort() {return m_UserModeTCPConfig ? m_UserModeTCPConfig->TargetPort : 0;}

	//CNATSocketWnd m_natwnd;

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

private:
	void TryToSend();
	void SendBufferedSegment(sTransferBufferEntry* BufferEntry);

	void SendAckPacket(uint32 uSequenceNr);
	
	void ShrinkCongestionWindow(/*uint16 uAcknowledgeSegments = 0*/);

	//UpStream
	//--------
	CCriticalSection2 m_UpLocker; // NEO: ND - [NeoDebug]

	uint32 m_uEstimatedRTT; // connection latency time (from pasket send to recive ack)
	uint32 m_uTimeOutDeviation; // diviation ouf our rtt based timeout vlaues
	uint32 m_uActualTimeOut; // currently computed timeout value
#if defined(REGULAR_TCP)
	uint8  m_uDuplicatedACKCount; // count dupplicated ack's if we recive 3 it means we must resend the next segment (Fast Retransmission)
#endif

	uint32 m_uCongestionWindow; // our estimated congestion window
	uint32 m_uAdvertisedWindow; // the window size advertised in the last recived ACK
	uint32 m_uCongestionThreshold; // used for slow start and fast recovery
	uint32 m_uPendingWindowSize; // the amount of segments currently being on the network

	uint32 m_uLastSentSequenceNr; // number of last sent segment
	uint32 m_uUplaodBufferSize;
	TransferBuffer m_UplaodBuffer;	// Note: unfortunatly the CRBMap does not have a FindFirstKeyBefoure function 
									//	so for the uplaod buffer I reverse the map direction by using mapkey = UINT_MAX-key ;)

	//DowmStream
	//----------
	CCriticalSection2 m_DownLocker; // NEO: ND - [NeoDebug]

	uint32 m_uLastByteRcvd;
	uint32 m_uNextByteRead;

	uint32 m_uLastAcknowledgeSequenceNr; // last sequence number completly pased to the CEMsocket
#if defined(REGULAR_TCP)
	bool   m_bSegmentMissing;
#endif
	uint32 m_uCurrentSegmentPosition; // the CEMsocket may recive only a part of the current segment
	uint32 m_uDownloadBufferSize;
	TransferBuffer m_DownloadBuffer;


	//Attributes
	uint8  m_ShutDown;

#ifdef ISPBYPASS // NEO: SUC - [SafeUCPCommunication]
	byte* abyInputKey;
	byte* abyOutputKey;
	uint8 uKeyLength;
#endif // ISPBYPASS // NEO: SUC END
};

enum nat_log_event
{
	NLE_RECIVED, // incomming packet
	NLE_SENT, // outgoing packet
	NLE_READ, // data read from download buffer
	NLE_WRITE, // data wroten to upload buffer
	NLE_CONFIGURE, // changed configuration
	NLE_FUNCTION, // called function
	NLE_RESULT, // result to above line
	NLE_STATE, // internal state information
	NLE_OTHER, // other output
};
inline void NATTrace(uint32 address,nat_log_event event, char* name, char* fmt, ...);

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