///////////////////////////////////////////////////////////////////////////////
/// @file deTCPConnection.cpp
///
/// @brief 
///
/// @author trajar
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Jun 2002
/// @author trajar
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

#include "deNetWinsock.hpp"
#include "deTCPConnection.hpp"
#include "deTCPConnectionBin.hpp"
#include "deTCPConnectionProvider.hpp"
#include "deThreadPool.hpp"
#include "deServer.hpp"
#include "dePacket.hpp"

#ifdef	_DEBUG
 #include	<crtdbg.h> 
 #define new new(_NORMAL_BLOCK,__FILE__, __LINE__)
#endif

void CALLBACK	OnRecvComplete( DWORD	dwError,
								DWORD	dwBytesTransferred,
								LPWSAOVERLAPPED lpOverlapped,
								DWORD	dwFlags );

//-------------------------------------------------------------------------
// posts WSARecv buffers
//-------------------------------------------------------------------------
int PostWSARecv( int pPosts, deTCPConnection * pConn, deTCPConnectionBin * pBin )
{
	deASSERT( pConn );
	deASSERT( pBin );

	int iRet = 0;

	if( !pConn->IsReady() )
		return -1;

	for( int i=0; i<pPosts; i++ )
	{
		// post some more recieve commands
		deTCPOVERLAPPED *	over = new deTCPOVERLAPPED();
		DWORD				Size  = 0;
		DWORD				Flags = 0;
		SOCKET				s = pConn->GetConnectionInfo().hSocket;

		// fill out overlapped structure
		over->bCompleted		= false;
		over->bSuccessful		= false;
		over->dwFlags			= 0;
		over->dwOrgSize			= 0;
		over->hSocket			= s;
		over->iNumBuffers		= 1;
		over->Buffer			= pBin->GetFreeBuffer();
		over->pBin				= pBin;
		over->pConn				= pConn;
		
		// queue an I/O operation
		iRet = WSARecv(	s, &over->Buffer, 1, &Size, &Flags, (LPWSAOVERLAPPED)over, OnRecvComplete );

		if( iRet == SOCKET_ERROR )
		{
			iRet = WSAGetLastError();

			if( iRet != WSA_IO_PENDING )
			{
				// something went wrong
				NET_LOG_ERROR( CODE_WINSOCK_ERROR );

				// push the buffer back on since we don't need it
				pBin->AddBuffer( over->Buffer );

				// try to reset the connection
				if( over->pConn->IsReady() )
				{
					if( over->pConn->AttemptReset( NULL ) != CODE_OK )
					{
						// setup lost structure
						deConnectionLost lost;
						lost.pConn		= pConn;
						lost.Reason		= deConnectionLost::REASON_CONN_LOCAL_ERROR;

						// create packet
						dePacket::PacketHeader header;
						header.Flags		= 0;
						header.ID			= 0;
						header.LocalID		= 0;
						header.NetMsgID		= deNetMsg::MSG_CONNECTION_LOST;
						header.Recipient	= pConn->GetOwner()->GetNetHandle();
						header.Sender		= pConn->GetOwner()->GetNetHandle();
						header.Size			= sizeof( deConnectionLost );
						header.SubID		= 0;
						header.TotalSize	= sizeof( deConnectionLost );
						header.Type			= 0;
						dePacket packet = dePacket( header, &lost, NULL );

						// setup net msg
						deNetMsg msg = deNetMsg( &packet );

						// send msg
						pConn->GetOwner()->HandleNetMsg( &msg );

						// delete overlapped
						SAFE_DELETE( over );

						break;
					}
				}
			}
			else
			{
				// clear it 
				iRet = 0;
			}
		}
	}

	return iRet;
}

//-------------------------------------------------------------------------
// callback routine - OnRecvComplete
//-------------------------------------------------------------------------
void CALLBACK	OnRecvComplete( DWORD	dwError,
								DWORD	dwBytesTransferred,
								LPWSAOVERLAPPED lpOverlapped,
								DWORD	dwFlags )
{
	deTCPOVERLAPPED * myOverlapped = reinterpret_cast<deTCPOVERLAPPED*>(lpOverlapped);
	deASSERT( myOverlapped );
	deASSERT( myOverlapped->pConn );
	deASSERT( myOverlapped->pBin );

	int i		= 0;
	int iRet	= 0;

	if( dwBytesTransferred > deConnection::GetMaxPacketSize() )
	{
		NET_LOG( "** WSARec BytesTransferred > MaxPacketSize **\n" );
	}

	if( dwBytesTransferred > 0 && dwError == 0 )
	{
		// set size
		DWORD	iSize = dwBytesTransferred;
		BYTE *	pData = NULL;	

		deASSERT( iSize <= deConnection::GetMaxPacketSize() );

		// allocate space
		pData = new BYTE[iSize];

		memcpy( pData, myOverlapped->Buffer.buf, iSize );

		// make packet
		dePacket packet = dePacket( pData );

		// clear mem
		SAFE_DELETE_ARRAY( pData );

		// set packet info
		myOverlapped->pConn->RecievePacket( &packet );

		myOverlapped->bCompleted	= true;
		myOverlapped->bSuccessful	= true;
	}
	else
	{
		NET_LOG_ERROR( CODE_WINSOCK_ERROR );

		myOverlapped->bCompleted	= true;
		myOverlapped->bSuccessful	= false;
	}

	// put the buffer(s) back on the stack
	myOverlapped->pBin->AddBuffer( myOverlapped->Buffer );

	// post another buffer
	iRet = PostWSARecv( 1, myOverlapped->pConn, myOverlapped->pBin );

	// release mem
	SAFE_DELETE( myOverlapped );
}

//-------------------------------------------------------------------------
// callback routine - OnSendComplete
//-------------------------------------------------------------------------
void CALLBACK	OnSendComplete( DWORD	dwError,
								DWORD	dwBytesTransferred,
								LPWSAOVERLAPPED lpOverlapped,
								DWORD	dwFlags )
{
	deTCPOVERLAPPED * myOverlapped = reinterpret_cast<deTCPOVERLAPPED*>(lpOverlapped);
	deASSERT( myOverlapped );
	deASSERT( myOverlapped->pConn );

	int iRet = 0;
	int	i	 = 0;

	if( dwBytesTransferred == myOverlapped->dwOrgSize && !dwError )
	{
		myOverlapped->bCompleted	= true;
		myOverlapped->bSuccessful	= true;
	}
	else
	{
		NET_LOG_ERROR( CODE_WINSOCK_ERROR );

		myOverlapped->bCompleted	= true;
		myOverlapped->bSuccessful	= false;		

		/*
		// send it again
		eNetError r = myOverlapped->pConn->Send(	myOverlapped->iNetMsgID,
													myOverlapped->Buffer.buf, 
													myOverlapped->dwOrgSize, 
													myOverlapped->dwFlags );
		
		if( r != CODE_OK )
		{
			if( CODE_OK != myOverlapped->pConn->AttemptReset( NULL ) )
			{
				// setup lost structure
				deConnectionLost lost;
				lost.pConn		= myOverlapped->pConn;
				lost.Reason		= deConnectionLost::REASON_CONN_LOCAL_ERROR;

				// create packet
				dePacket::PacketHeader header;
				header.Flags		= 0;
				header.ID			= 0;
				header.LocalID		= 0;
				header.NetMsgID		= deNetMsg::MSG_CONNECTION_LOST;
				header.Recipient	= myOverlapped->pConn->GetOwner()->GetNetHandle();
				header.Sender		= myOverlapped->pConn->GetOwner()->GetNetHandle();
				header.Size			= sizeof( deConnectionLost );
				header.SubID		= 0;
				header.TotalSize	= sizeof( deConnectionLost );
				header.Type			= 0;
				dePacket packet = dePacket( header, &lost, NULL );

				// setup net msg
				deNetMsg msg = deNetMsg( &packet );

				// send msg
				myOverlapped->pConn->GetOwner()->HandleNetMsg( &msg );
			}
		}
		*/
	}

	// release pending send
	myOverlapped->pConn->ReleasePendingTCPSend( myOverlapped );
}
/*
//-------------------------------------------------------------------------
// callback routine - OnAcceptComplete
//-------------------------------------------------------------------------
int CALLBACK	OnAcceptComplete(	WSABUF	*	lpCallerID,
									WSABUF	*	lpCallerData,
									LPQOS		lpSQOS,
									LPQOS		lpGQOS,
									WSABUF	*	lpCalleeId,
									WSABUF	*	lpCalleeData,
									GROUP FAR *	group,
									DWORD		dwCallbackData )
{
	// returns either CF_ACCEPT or CF_REJECT
	deTCPConnection   * conn  = reinterpret_cast<deTCPConnection*>(dwCallbackData);

	deConnection::deConnectionReply	  *	reply	= reinterpret_cast<deConnection::deConnectionReply*>(lpCalleeData);
	deConnection::deConnectionRequest *	request = reinterpret_cast<deConnection::deConnectionRequest*>(lpCallerData);

	if( reply && request )
	{
		reply->hRemoteUser		= conn->GetOwner()->GetNetHandle();
		reply->iRemoteUserType	= conn->GetOwner()->GetNetType();
		reply->RemoteAddress	= conn->GetConnDesc()->m_LocalAddress;

		NET_LOG( "Accepted new connection from " );
		NET_LOG( request->Address.GetAddressIPStr() );
		NET_LOG( "\n" );

		return CF_ACCEPT;
	}
	else
		return CF_REJECT;
}
*/

DWORD  ListenThread( void * pInfo )
{
	// get calling connection
	deTCPConnection * conn		= *( reinterpret_cast<deTCPConnection**>(pInfo) );
	deASSERT( conn );

	// lock connection
	conn->GetSynchObject()->Lock( NULL );

	SOCKET			listener	= conn->GetConnectionInfo().hSocket;
	SOCKET			newConn		= NULL;
	SOCKADDR_IN		newAddress;
	deNetAddress	listenerAddress = conn->GetConnDesc()->m_LocalAddress;
	eNetError		r = CODE_OK;
	deServer *		server		= NULL;

	// unlock connection
	conn->GetSynchObject()->Unlock();

	int iRet	= 0;
	
	while( 1 )
	{
		int iSize	= sizeof(SOCKADDR_IN);

		newConn		= accept(	listener,
								(sockaddr*)&newAddress, &iSize );
		
		if( newConn == INVALID_SOCKET )
		{
			// is it because the connection was closed?
			if( conn->IsReady() )
			{
				iRet = WSAGetLastError();
				NET_LOG_ERROR( CODE_WINSOCK_ERROR );

				if( iRet == WSAEINTR ||				// inerupted?
					iRet == WSAENETDOWN ||			// net down?
					iRet == WSANOTINITIALISED ||	// invalid socket?
					iRet == WSAEINVAL ||			// invalid arg?
					iRet == WSAENOTSOCK ||			// not a socket?
					iRet == WSAEOPNOTSUPP )			// option not supported?
				{
					// these are fatal errors, get out of here
					//NET_LOG( "** Fatal error accepting new socket! **\n" );
					break;
				}

				NET_LOG( "** Error accepting new socket... Continuing... **\n" );
			}
			else
			{
				NET_LOG( ">> Connection Closed - Closing Listening Thread <<\n" );
				break;
			}
		}
		else
		{
			bool bAcceptNew = false;

			// new connection!
			NET_LOG( "-- Recieved New Socket Connection --\n" );

			server = static_cast<deServer*>(conn->GetOwner());

			if( server )
			{
				deConnection *		conn	= NULL;
				deConnectionDesc *	desc	= NULL;
				deTCPConnection	*	tcpConn	= NULL;

				// create a new connection
				r = deTCPConnectionProvider::GetMgr()->CreateConnection(	&conn,
																			&newConn,
																			NULL );

				if( r == CODE_OK )
				{
					deASSERT( conn );
					tcpConn = static_cast<deTCPConnection*>( conn );
					deASSERT( tcpConn );

					desc = const_cast<deConnectionDesc*>( tcpConn->GetConnDesc() );
					deASSERT( desc );
					
					deConnectionHandshake hand;

					// recieve handshake
					iRet = recv( tcpConn->GetConnectionInfo().hSocket, (char*)&hand, sizeof(deConnectionHandshake), NULL );

					if( iRet == SOCKET_ERROR )
					{
						NET_LOG_ERROR( CODE_WINSOCK_ERROR );
						return CODE_WINSOCK_ERROR;
					}

					// set up deNetAddress
					char strIP[16];
					strcpy( strIP, inet_ntoa( newAddress.sin_addr ) );

					// save connection desc
					desc->m_RemoteAddress = deNetAddress(	newAddress.sin_addr.s_addr,
															newAddress.sin_port,
															strIP,	
															strIP );

					desc->m_iRemoteUserType	= hand.iUserType;

					// ask the server
					r = server->AddClient( tcpConn );

					// send info to remote
					hand.bRequestReturnID	= false;
					hand.hAssignedID		= tcpConn->GetOwner()->GenerateNetID();
					hand.hNetID				= tcpConn->GetOwner()->GetNetHandle();
					hand.iConnectionType	= tcpConn->GetType();
					hand.iUserType			= tcpConn->GetOwner()->GetNetType();

					// set connection info
					desc->m_hRemoteUser		= hand.hAssignedID;
					
					// send it!
					iRet = send( tcpConn->GetConnectionInfo().hSocket, (char*)&hand, sizeof(deConnectionHandshake), NULL );

					if( iRet == SOCKET_ERROR )
					{
						NET_LOG_ERROR( CODE_WINSOCK_ERROR );
						return CODE_WINSOCK_ERROR;
					}

					// add it to an available bin
					deTCPConnectionProvider::GetMgr()->AddConnectionToBins( tcpConn );
				}
				else
				{
					NET_LOG_ERROR( r );
				}
				
				bAcceptNew	= r == CODE_OK;					
			}

			std::string	strNewConn = "";

#ifdef _DEBUG
			if( bAcceptNew )
			{
				// new connection accepted!
				strNewConn += ">> Connected to ";
				strNewConn += conn->GetConnDesc()->m_RemoteAddress.GetAddressIPStr();
				strNewConn += " <<\n";
				NET_LOG( strNewConn.c_str() );
			}
			else
			{
				// connection rejected
				strNewConn += ">> Connection from ";
				strNewConn += conn->GetConnDesc()->m_RemoteAddress.GetAddressIPStr();
				strNewConn += " was rejected <<\n";
				NET_LOG( strNewConn.c_str() );
			}
#endif
		}
	}

	NET_LOG( ">> Done listening on socket <<\n" );

	return 0;
}

//-------------------------------------------------------------------------
//-------------------------------------------------------------------------

// static declaration
//-------------------------------------------------------

inline deTCPConnection::deTCPConnection( void )
{
	m_Type						= TYPE_TCP;
	m_ConnectionInfo.gGroup		= NULL;
	m_ConnectionInfo.hEvent		= NULL;
	m_ConnectionInfo.hSocket	= INVALID_SOCKET;
}

inline deTCPConnection::~deTCPConnection( void )
{
	// ?
}

void deTCPConnection::ReleasePendingTCPSend( deTCPOVERLAPPED * pOver )
{
	if( pOver == NULL )
		return;
	else
	{
		// ensure this is thread-safe and locked
		ENSURE_LOCK( this, this->GetSynchObject() );

		aPendingTCPSends::iterator itr = m_aPendingTCPSends.begin();
		while( itr != NULL && itr != m_aPendingTCPSends.end() )
		{
			if( (*itr) == pOver )
			{
				SAFE_DELETE_ARRAY( pOver->Buffer.buf );
				SAFE_DELETE( pOver );
				m_aPendingTCPSends.erase( itr );
				break;
			}
			
			++itr;
		}		
	}
}

eNetError deTCPConnection::OnBindAsServer( DWORD dwFlags )
{
	eNetError	r		= CODE_OK;
	int			iRet	= 0;
	int			iSize	= sizeof(struct sockaddr);	

	// set up connection info
	m_ConnectionInfo.address.sin_family			= PF_INET;
	m_ConnectionInfo.address.sin_port			= htons(deNet_GetPort());
	m_ConnectionInfo.address.sin_addr.s_addr	= INADDR_ANY;
	
	// bind socket
	iRet = bind(	m_ConnectionInfo.hSocket, 
					(LPSOCKADDR)&m_ConnectionInfo.address,
					iSize );

	if( iRet )
	{
		// error!
		NET_LOG_ERROR( CODE_WINSOCK_ERROR );

		// release any socket info
		Disconnect();

		return CODE_WINSOCK_ERROR;
	}

	iRet = listen(	m_ConnectionInfo.hSocket, 3 );

	if( iRet )
	{
		// error!
		NET_LOG_ERROR( CODE_WINSOCK_ERROR );

		// release any socket info
		Disconnect();

		return CODE_WINSOCK_ERROR;
	}

	deTCPConnection * conn = this;

	// set up thread to handle new conns
	if( !deThreadPool::GetMgr()->ActivateIdleThread(	ListenThread,
													&conn, sizeof(deTCPConnection*),
													NULL, true ) )
	{
		NET_LOG( "** Unable to create thread! **\n" );
		return CODE_RESOURCE_ERROR;
	}
	else
	{
		/*
		// add it to the bins
		r = deTCPConnectionProvider::GetMgr()->AddConnectionToBins( this );		
		return r;
		*/

		return CODE_OK;
	}
}

eNetError deTCPConnection::OnConnectTo( deNetAddress * pAddress )
{
	eNetError	r		= CODE_OK;
	int			iRet	= 0;

	DWORD dwAddress = pAddress->GetAddressIP();
	
	m_ConnectionInfo.address.sin_family	= AF_INET;
	m_ConnectionInfo.address.sin_port	= pAddress->GetPort();
	m_ConnectionInfo.address.sin_addr	= *((in_addr*)&dwAddress);

	// connect to the remote server
	iRet = connect(	m_ConnectionInfo.hSocket,
					(sockaddr*)&m_ConnectionInfo.address,
					sizeof(sockaddr) );

	if( iRet == SOCKET_ERROR )
	{
		// error!
		m_ConnectionDesc.m_hRemoteUser		= DN_INVALID_NETID;
		m_ConnectionDesc.m_RemoteAddress	= deNetAddress();
		m_ConnectionDesc.m_iRemoteUserType	= -1;

		NET_LOG_ERROR( CODE_WINSOCK_ERROR );
		return CODE_WINSOCK_ERROR;
	}
	else
	{
		// set up deNetAddress
		char strIP[16];
		char strName[16];
		in_addr tmpAddr;
		tmpAddr.s_addr = m_ConnectionInfo.address.sin_addr.s_addr;
		GetHostName( strName );
		strcpy( strIP, inet_ntoa( tmpAddr ) );

		// save connection desc
		m_ConnectionDesc.m_LocalAddress = deNetAddress(	GetHostAddress(),
														htons(DN_DEFAULT_PORT),
														strIP,	
														strName );

		// save remote address
		m_ConnectionDesc.m_RemoteAddress = *pAddress;

		// send info to remote
		deConnectionHandshake hand;
		hand.bRequestReturnID	= true;
		hand.hAssignedID		= DN_INVALID_NETID;
		hand.hNetID				= DN_INVALID_NETID;
		hand.iConnectionType	= m_Type;
		hand.iUserType			= GetOwner()->GetNetType();

		// send it!
		iRet = send( m_ConnectionInfo.hSocket, (char*)&hand, sizeof(deConnectionHandshake), NULL );

		if( iRet == SOCKET_ERROR )
		{
			NET_LOG_ERROR( CODE_WINSOCK_ERROR );
			return CODE_WINSOCK_ERROR;
		}

		// recieve handshake
		iRet = recv( m_ConnectionInfo.hSocket, (char*)&hand, sizeof(deConnectionHandshake), NULL );

		if( iRet == SOCKET_ERROR )
		{
			NET_LOG_ERROR( CODE_WINSOCK_ERROR );
			return CODE_WINSOCK_ERROR;
		}

		// get remote info
		GetOwner()->AssignNetHandle( hand.hAssignedID );
		m_ConnectionDesc.m_iRemoteUserType	= hand.iUserType;
		m_ConnectionDesc.m_hRemoteUser		= hand.hNetID;

		// add it to a connection bin
		r = deTCPConnectionProvider::GetMgr()->AddConnectionToBins( this );

#ifdef _DEBUG
		if( r == CODE_OK )
		{
			std::string strMsg = "";
			strMsg += ">> Connected to ";
			strMsg += m_ConnectionDesc.m_RemoteAddress.GetAddressIPStr();
			strMsg += " <<\n";
			NET_LOG( strMsg.c_str() );
		}
#endif
		
		return r;
	}
};

eNetError deTCPConnection::OnDisconnect( DWORD dwFlags )
{
	int		iRet = 0;
	int		iNum = 0;
	char 	buff[4096];

	if( m_ConnectionInfo.hSocket == INVALID_SOCKET )
		return CODE_OK;

	
	if( dwFlags & deConnection::FLAG_FORCE_DISCONNECT == 0 )
	{
		// shut down all sending functionality
		iRet = shutdown(	m_ConnectionInfo.hSocket,
							1 // stop all sends 
						);
		if( iRet == SOCKET_ERROR )
		{
			iRet = WSAGetLastError();

			if( iRet != WSAENOTSOCK && iRet != WSAECONNRESET )
			{
				// error!
				NET_LOG_ERROR( CODE_WINSOCK_ERROR );
				NET_LOG( "** Error shutting down socket... may be listening? **\n" );
			}
		}

		// clear rec buffer
		iNum = 1;
		while( iNum > 0 )
		{
			iNum = recv( m_ConnectionInfo.hSocket, buff, 4096, 0 );
		}
	}

	// finally, close the socket
	iRet = closesocket( m_ConnectionInfo.hSocket );
	if( iRet == SOCKET_ERROR )
	{
		iRet = WSAGetLastError();

		if( iRet != WSAENOTSOCK && iRet != WSAECONNRESET )
		{
			// error!
			NET_LOG_ERROR( CODE_WINSOCK_ERROR );
		}
	}

	// release all tcp send overlapped info
	aPendingTCPSends::iterator itr = m_aPendingTCPSends.begin();
	while( itr != NULL && itr != m_aPendingTCPSends.end() )
	{
		SAFE_DELETE_ARRAY( (*itr)->Buffer.buf );
		SAFE_DELETE( (*itr) );
		++itr;
	}

	// clear it
	m_aPendingTCPSends.clear();

	m_ConnectionInfo.hSocket = INVALID_SOCKET;

	return CODE_OK;
};

eNetError deTCPConnection::OnAttemptReset( DWORD dwFlags )
{
	return CODE_GENERIC_ERROR;
}

eNetError deTCPConnection::OnRecieve( DWORD dwFlags )
{
	return CODE_OK;
}

eNetError deTCPConnection::OnSend( WORD pNetMsgID, const void * pBuff, DWORD iSize, DWORD dwFlags )
{
	static unsigned int iCounter = 0;

	deASSERT( pBuff );
	deASSERT( iSize > 0 );

	deTCPOVERLAPPED	*	myOverlapped = new deTCPOVERLAPPED();
	DWORD				dwSent;

	// set up winsock buffer
	myOverlapped->Buffer.len = iSize;
	myOverlapped->Buffer.buf = new char[iSize];
	memcpy( myOverlapped->Buffer.buf, pBuff, iSize );
	
	/*
	// add delimeter
	char * delim	= myOverlapped->Buffer.buf + iSize;
	delim			= "\0";
	*/

	// set up overlapped i/o request
	myOverlapped->dwOrgSize		= iSize;
	myOverlapped->hSocket		= m_ConnectionInfo.hSocket;
	myOverlapped->iNumBuffers	= 1;
	myOverlapped->bCompleted	= false;
	myOverlapped->bSuccessful	= false;
	myOverlapped->dwFlags		= 0;
	myOverlapped->pConn			= this;
	myOverlapped->iNetMsgID		= pNetMsgID;
		
	int iRet = WSASend( m_ConnectionInfo.hSocket, 
						&myOverlapped->Buffer, 1, 
						&dwSent,
						MSG_DONTROUTE,
						(LPWSAOVERLAPPED)(myOverlapped),
						OnSendComplete );

	if( iRet == SOCKET_ERROR )
	{
		iRet = WSAGetLastError();

		if( iRet != WSA_IO_PENDING )
		{
			NET_LOG_ERROR( CODE_WINSOCK_ERROR );

			// clear mem
			SAFE_DELETE_ARRAY( myOverlapped->Buffer.buf );
			SAFE_DELETE( myOverlapped );
			
			return CODE_INVALID_CONNECTION;
		}
	}

	// add to pending sends
	m_aPendingTCPSends.push_back( myOverlapped );

	return CODE_OK;
}
