// wsp_provider.cpp
// 
// Copyright (c) 2002 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
// 
// Initial Contributors:
// Accenture - Initial contribution
//


#include "wsp_provider.h"
#include "wsp_factory.h"
#include "wsp_socket.h"
#include "wsp_panic.h"
#include "wsp_log.h"


//
// Constants.
//

const TInt KReceiveBufferSize = 4096;


//
// CWinSockProviderBase.
//

CWinSockProviderBase::CWinSockProviderBase(RWin32Factory& aWin32Factory)
	: iWin32Factory(aWin32Factory), iWinSockWriteBuffer(NULL, 0)
	{
	}

CWinSockProviderBase::~CWinSockProviderBase()
	{
	delete iSendSocketWrapper;
	delete iReceiveSocketWrapper;
	delete iReceiveBuffer;
	delete iSendBuffer;
	iWin32Socket.Close();
	}

void CWinSockProviderBase::ConstructL()
	{
	iSendSocketWrapper = CWin32SocketWrapper::NewL(*this, iWin32Socket);
	iReceiveSocketWrapper = CWin32SocketWrapper::NewL(*this, iWin32Socket);
	iReceiveBuffer = HBufC8::NewL(KReceiveBufferSize);
	iWinSockWriteBuffer.Set(iReceiveBuffer->Des());
	}

TInt CWinSockProviderBase::FillSendBuffer(const TDesC8& aDataToSend)
	{
	if (iSendBuffer)
		{
		if (iSendBuffer->Des().MaxLength() < aDataToSend.Length())
			{
			iSendBuffer = iSendBuffer->ReAlloc(aDataToSend.Length());
			if (iSendBuffer == NULL)
				{
				return KErrNoMemory;
				}
			}
		*iSendBuffer = aDataToSend;
		}
	else
		{
		iSendBuffer = aDataToSend.Alloc();
		if (iSendBuffer == NULL)
			{
			return KErrNoMemory;
			}
		}
	return KErrNone;
	}

TInt CWinSockProviderBase::SetRemName(TSockAddr& anAddr)
	{
	WSP_LOG(WspLog::Write(_L("CWinSockProviderBase::SetRemName")));
	iRemoteAddr = anAddr;
	return KErrNone;
	}

void CWinSockProviderBase::LocalName(TSockAddr& anAddr)const
	{
	WSP_LOG(WspLog::Write(_L("CWinSockProviderBase::LocalName")));
	iWin32Socket.GetSocketName(static_cast<TInetAddr&>(anAddr)); // Throw away error code.
	}

TInt CWinSockProviderBase::SetLocalName(TSockAddr& anAddr)
	{
	WSP_LOG(WspLog::Write(_L("CWinSockProviderBase::SetLocalName")));
	return iWin32Socket.Bind(anAddr);
	}

void CWinSockProviderBase::AutoBind( void )
	{
	WSP_LOG(WspLog::Write(_L("CWinSockProviderBase::AutoBind")));
	}

TInt CWinSockProviderBase::GetOption(TUint /*aLevel*/, TUint /*aName*/, TDes8& /*anOption*/)const
	{
	return KErrNotSupported;
	}

TInt CWinSockProviderBase::SetOption(TUint /*aLevel*/, TUint /*aName*/, const TDesC8& /*anOption*/)
	{
	return KErrNotSupported;
	}

void CWinSockProviderBase::Ioctl(TUint /*aLevel*/, TUint /*aName*/, TDes8* /*anOption*/)
	{
	iSocket->Error(KErrNotSupported, MSocketNotify::EErrorIoctl);
	}

void CWinSockProviderBase::CancelIoctl(TUint /*aLevel*/, TUint /*aName*/)
	{
	}

TInt CWinSockProviderBase::PassiveOpen(TUint /*aQue*/, const TDesC8& /*aConnectionData*/)
	{
	__ASSERT_DEBUG(EFalse, Panic(EWinSockPrtUnexpectedActivePassiveOpenWithConnectionData));
	return 0;
	}

void CWinSockProviderBase::Shutdown(TCloseType /*option*/, const TDesC8& /*aDisconnectData*/)
	{
	__ASSERT_DEBUG(EFalse, Panic(EWinSockPrtUnexpectedActiveShutdownWithConnectionData));
	}

void CWinSockProviderBase::ActiveOpen(const TDesC8& /*aConnectionData*/)
	{
	__ASSERT_DEBUG(EFalse, Panic(EWinSockPrtUnexpectedActiveOpenCallWithConnectionData));
	}

void CWinSockProviderBase::Shutdown(TCloseType aType)
	{
	WSP_LOG(WspLog::Write(_L("CWinSockProviderBase::Shutdown")));
	if (aType != EImmediate)
		{
		iSocket->CanClose();
		}
	}


//
// CWinSockTcpProvider.
//

CWinSockTcpProvider* CWinSockTcpProvider::NewL(RWin32Factory& aWin32Factory)
	{
	CWinSockTcpProvider* self = new(ELeave) CWinSockTcpProvider(aWin32Factory);
	CleanupStack::PushL(self);
	self->ConstructL(RWin32Socket::ETcp);
	CleanupStack::Pop(self);
	return self;
	}

CWinSockTcpProvider* CWinSockTcpProvider::NewBlankLC(RWin32Factory& aWin32Factory)
	{
	CWinSockTcpProvider* self = new(ELeave) CWinSockTcpProvider(aWin32Factory);
	CleanupStack::PushL(self);
	self->ConstructL(RWin32Socket::EBlank);
	return self;
	}

CWinSockTcpProvider::CWinSockTcpProvider(RWin32Factory& aWin32Factory)
	: CWinSockProviderBase(aWin32Factory)
	{
	}

void CWinSockTcpProvider::ConstructL(RWin32Socket::TType aType)
	{
	User::LeaveIfError(iWin32Socket.Open(iWin32Factory, aType));
	iConnectSocketWrapper = CWin32SocketWrapper::NewL(*this, iWin32Socket);
	iAcceptSocketWrapper = CWin32SocketWrapper::NewL(*this, iWin32Socket);
	CWinSockProviderBase::ConstructL();
	}

CWinSockTcpProvider::~CWinSockTcpProvider()
	{
	delete iConnectSocketWrapper;
	delete iAcceptSocketWrapper;
	delete iAcceptSap;
	}

void CWinSockTcpProvider::RemName(TSockAddr& anAddr) const
	{
	WSP_LOG(WspLog::Write(_L("CWinSockTcpProvider::RemName")));
	iWin32Socket.GetPeerName(static_cast<TInetAddr&>(anAddr)); // Throw away error code.
	}

TUint CWinSockTcpProvider::Write(const TDesC8& aDesc, TUint /*options*/, TSockAddr* /*anAddr*/)
	{
	WSP_LOG(WspLog::Printf(_L("CWinSockTcpProvider::Write: writing %d bytes"), aDesc.Length()));
	WSP_RAW_LOG(WspLog::WriteRawOutbound(aDesc));
	if (iSendSocketWrapper->IsActive())
		{
		return 0;
		}

	TInt err = FillSendBuffer(aDesc);
	if (err)
		{
		iSocket->Error(err, MSocketNotify::EErrorSend);
		return 0;
		}
	iSendSocketWrapper->Send(*iSendBuffer);
	return iSendBuffer->Length();
	}

void CWinSockTcpProvider::GetData(TDes8& aDesc, TUint /*aOptions*/, TSockAddr* /*anAddr*/)
	{
	WSP_LOG(WspLog::Write(_L("CWinSockTcpProvider::GetData")));
	TInt esockBufferSize = aDesc.Length();
	if (esockBufferSize >= iEsockReadBuffer.Length())
		{
		WSP_LOG(WspLog::Printf(_L("\tCopying all %d bytes up to ESock"), iEsockReadBuffer.Length()));
		aDesc.Copy(iEsockReadBuffer);
		StartReceive();
		}
	else
		{
		WSP_LOG(WspLog::Printf(_L("\tESock buffer size: %d, available data: %d"), esockBufferSize, iEsockReadBuffer.Length()));
		aDesc.Copy(iEsockReadBuffer.Left(esockBufferSize));
		iEsockReadBuffer.Set(iEsockReadBuffer.Right(iEsockReadBuffer.Length() - esockBufferSize));
		}

	WSP_RAW_LOG(WspLog::WriteRawInbound(aDesc));
	}

void CWinSockTcpProvider::Start()
	{
	if (iListeningSap)
		{
		iListeningSap->HandleListeningSapStarted();
		iListeningSap = NULL;
		}
	}

void CWinSockTcpProvider::ActiveOpen()
	{
	WSP_LOG(WspLog::Write(_L("CWinSockTcpProvider::ActiveOpen")));
	TInt err = iConnectSocketWrapper->Connect(iRemoteAddr);
	if (err)
		{
		iSocket->Error(err, MSocketNotify::EErrorConnect);
		}
	}

TInt CWinSockTcpProvider::PassiveOpen(TUint aQue)
	{
	WSP_LOG(WspLog::Write(_L("CWinSockTcpProvider::PassiveOpen")));
	TRAPD(err, DoPassiveOpenL(aQue));
	return err;
	}

TInt CWinSockTcpProvider::GetOption(TUint aLevel, TUint aName, TDes8& anOption) const
	{
	if (aLevel == KSolInetTcp)
		{
		switch (aName)
			{
			case KSoTcpNoDelay:
				{
				BOOL bOptVal = FALSE;
				TInt length = sizeof(BOOL);
				TInt err = iWin32Socket.GetOption(IPPROTO_TCP, TCP_NODELAY, (char*)&bOptVal, &length);
				if (err == KErrNone)
					{
					TPckg<TInt> intPackage(bOptVal);
					anOption.Copy(intPackage);
					}
				return err;
				}
			}
		}

	return CWinSockProviderBase::GetOption(aLevel, aName, anOption);
	}

TInt CWinSockTcpProvider::SetOption(TUint aLevel, TUint aName, const TDesC8& anOption)
	{
	if (aLevel == KSolInetTcp)
		{
		switch (aName)
			{
			case KSoTcpNoDelay:
				{
				TPckgC<TInt> intPackage(0);
				intPackage.Set(anOption);
				BOOL bOptVal = intPackage();
				return iWin32Socket.SetOption(IPPROTO_TCP, TCP_NODELAY, (char*)&bOptVal, sizeof(BOOL));
				}
			}
		}

	return CWinSockProviderBase::SetOption(aLevel, aName, anOption);
	}

void CWinSockTcpProvider::HandleWin32SocketCompletion(TRequestType aRequestType, TInt aError)
	{
	switch (aRequestType)
		{
		case MWin32SocketObserver::EConnect:
			{
			WSP_LOG(WspLog::Printf(_L("CWinSockTcpProvider::HandleWin32SocketCompletion: EConnect, error: %d"), aError));
			if (aError)
				{
				iSocket->Error(aError, MSocketNotify::EErrorConnect);
				}
			else
				{
				StartReceive();
				if (iSocket)
					{
					iSocket->ConnectComplete();
					}
				}
			break;
			}
		case MWin32SocketObserver::ESend:
			{
			WSP_LOG(WspLog::Printf(_L("CWinSockTcpProvider::HandleWin32SocketCompletion: ESend, error: %d"), aError));
			if (iSocket)
				{
				if (aError)
					{
					iSocket->Error(aError, MSocketNotify::EErrorSend);
					}
				else
					{
					iSocket->CanSend();
					}
				}
			break;
			}
		case MWin32SocketObserver::EReceive:
			{
			WSP_LOG(WspLog::Printf(_L("CWinSockTcpProvider::HandleWin32SocketCompletion: EReceive, error: %d"), aError));
			if (aError)
				{
				if (iSocket)
					{
					iSocket->Error(aError, MSocketNotify::EErrorRecv);
					}
				}
			else
				{
				iEsockReadBuffer.Set(iWinSockWriteBuffer);
				TInt receivedBytes = iEsockReadBuffer.Length();
				WSP_LOG(WspLog::Printf(_L("\t %d bytes received"), receivedBytes));
				if (iSocket)
					{
					if (receivedBytes)
						{
						iSocket->NewData(receivedBytes);
						}
					else
						{
						iSocket->NewData(KNewDataEndofData);
						}
					}
				}
			break;
			}
		case MWin32SocketObserver::EAccept:
			{
			WSP_LOG(WspLog::Printf(_L("CWinSockTcpProvider::HandleWin32SocketCompletion: EAccept, error: %d"), aError));
			iAcceptSap->StartReceive();
			CWinSockProviderBase& acceptSap = *iAcceptSap;
			iAcceptSap = NULL;	// This pointer will be reused when our HandleListeningSapStarted gets, which may be as a result of the next CSocket::ConnectComplete call.
			iSocket->ConnectComplete(acceptSap);
			break;
			}
		case MWin32SocketObserver::ESendTo:
		case MWin32SocketObserver::EReceiveFrom:
		default:
			{
			__ASSERT_DEBUG(EFalse, Panic(EWinSockPrtInvalidTcpSocketRequestType));
			}
		}
	}

void CWinSockTcpProvider::DoPassiveOpenL(TUint aQue)
	{
	__ASSERT_DEBUG(iAcceptSap == NULL, Panic(EWinSockPrtCWinSockTcpProviderDoPassiveOpenLAcceptSapNotNull));
	CWinSockTcpProvider* acceptSap = CWinSockTcpProvider::NewBlankLC(iWin32Factory);
	acceptSap->SetListeningSap(*this);
	User::LeaveIfError(iWin32Socket.Listen(aQue));
	User::LeaveIfError(iAcceptSocketWrapper->Accept(acceptSap->iWin32Socket));
	CleanupStack::Pop(acceptSap);
	iAcceptSap = acceptSap;
	}

void CWinSockTcpProvider::StartReceive()
	{
	iWinSockWriteBuffer.Zero();
	iReceiveSocketWrapper->Receive(iWinSockWriteBuffer);
	}

void CWinSockTcpProvider::SetListeningSap(CWinSockTcpProvider& aListeningSap)
	{
	__ASSERT_DEBUG(iListeningSap == NULL, Panic(EWinSockPrtCWinSockTcpProviderSetListeningSapAlreadySet));
	iListeningSap = &aListeningSap;
	}

void CWinSockTcpProvider::HandleListeningSapStarted()
	{
	__ASSERT_DEBUG(iAcceptSap == NULL, Panic(EWinSockPrtCWinSockTcpProviderStartAcceptSapNotNull));
	CWinSockTcpProvider* acceptSap = CWinSockTcpProvider::NewBlankLC(iWin32Factory);
	acceptSap->SetListeningSap(*this);
	User::LeaveIfError(iAcceptSocketWrapper->Accept(acceptSap->iWin32Socket));
	CleanupStack::Pop(acceptSap);
	iAcceptSap = acceptSap;
	}


//
// CWinSockUdpProvider.
//

CWinSockUdpProvider* CWinSockUdpProvider::NewL(RWin32Factory& aWin32Factory)
	{
	CWinSockUdpProvider* self = new(ELeave) CWinSockUdpProvider(aWin32Factory);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

TInt CWinSockUdpProvider::SetLocalName(TSockAddr& anAddr)
	{
	TInt err = CWinSockProviderBase::SetLocalName(anAddr);
	if (err == KErrNone)
		{
		iReceiveSocketWrapper->ReceiveFrom(iWinSockWriteBuffer, iReceiveFromAddress);
		}
	return err;
	}

void CWinSockUdpProvider::RemName(TSockAddr& anAddr) const
	{
	anAddr = iRemoteAddr;
	}

TUint CWinSockUdpProvider::Write(const TDesC8& aDesc, TUint /*options*/, TSockAddr* anAddr)
	{
	WSP_LOG(WspLog::Printf(_L("CWinSockUdpProvider::Write: writing %d bytes"), aDesc.Length()));
	WSP_RAW_LOG(WspLog::WriteRawOutbound(aDesc));
	if (iSendSocketWrapper->IsActive())
		{
		return 0;
		}
	TInt err = FillSendBuffer(aDesc);
	if (err)
		{
		iSocket->Error(err, MSocketNotify::EErrorSend);
		return 0;
		}
	if (anAddr)
		{
		iSendSocketWrapper->SendTo(*iSendBuffer, *anAddr);
		}
	else
		{
		iSendSocketWrapper->SendTo(*iSendBuffer, iRemoteAddr);
		}
	return iSendBuffer->Length();
	}

void CWinSockUdpProvider::GetData(TDes8 &aDesc, TUint /*aOptions*/, TSockAddr* anAddr)
	{
	WSP_LOG(WspLog::Write(_L("CWinSockUdpProvider::GetData")));
	TInt esockBufferSize = aDesc.Length();
	if (esockBufferSize >= iEsockReadBuffer.Length())
		{
		WSP_LOG(WspLog::Printf(_L("\tCopying all %d bytes up to ESock"), iEsockReadBuffer.Length()));
		aDesc.Copy(iEsockReadBuffer);
		}
	else
		{
		WSP_LOG(WspLog::Printf(_L("\tESock buffer size: %d, available data: %d"), esockBufferSize, iEsockReadBuffer.Length()));
		aDesc.Copy(iEsockReadBuffer.Left(esockBufferSize)); // Throw away remainder.
		}

	WSP_RAW_LOG(WspLog::WriteRawInbound(aDesc));

	if (anAddr)
		{
		anAddr->Copy(iReceiveFromAddress);
		}
	iWinSockWriteBuffer.Zero();
	iReceiveSocketWrapper->ReceiveFrom(iWinSockWriteBuffer, iReceiveFromAddress);
	}

void CWinSockUdpProvider::Start()
	{
	}

void CWinSockUdpProvider::ActiveOpen(void)
	{
	__ASSERT_DEBUG(EFalse, Panic(EWinSockPrtCWinSockUdpProviderActiveOpenUnexpectedCall));
	}

TInt CWinSockUdpProvider::PassiveOpen(TUint /*aQue*/)
	{
	__ASSERT_DEBUG(EFalse, Panic(EWinSockPrtCWinSockUdpProviderPassiveOpenUnexpectedCall));
	return 0;
	}

void CWinSockUdpProvider::HandleWin32SocketCompletion(TRequestType aRequestType, TInt aError)
	{
	switch (aRequestType)
		{
		case MWin32SocketObserver::ESendTo:
			{
			WSP_LOG(WspLog::Printf(_L("CWinSockUdpProvider::HandleWin32SocketCompletion: ESendTo, error: %d"), aError));
			if (aError)
				{
				iSocket->Error(aError, MSocketNotify::EErrorSend);
				}
			else
				{
				iSocket->CanSend();
				}
			break;
			}
		case MWin32SocketObserver::EReceiveFrom:
			{
			WSP_LOG(WspLog::Printf(_L("CWinSockUdpProvider::HandleWin32SocketCompletion: EReceiveFrom, error: %d"), aError));
			if (aError)
				{
				iSocket->Error(aError, MSocketNotify::EErrorRecv);
				}
			else
				{
				iEsockReadBuffer.Set(iWinSockWriteBuffer);
				WSP_LOG(WspLog::Printf(_L("\t %d bytes received"), iEsockReadBuffer.Length()));
				iSocket->NewData(1);
				}
			break;
			}
		case MWin32SocketObserver::EConnect:
		case MWin32SocketObserver::ESend:
		case MWin32SocketObserver::EReceive:
		case MWin32SocketObserver::EAccept:
		default:
			{
			__ASSERT_DEBUG(EFalse, Panic(EWinSockPrtInvalidUdpSocketRequestType));
			}
		}
	}

CWinSockUdpProvider::~CWinSockUdpProvider()
	{
	}

CWinSockUdpProvider::CWinSockUdpProvider(RWin32Factory& aWin32Factory)
	: CWinSockProviderBase(aWin32Factory)
	{
	}

void CWinSockUdpProvider::ConstructL()
	{
	User::LeaveIfError(iWin32Socket.Open(iWin32Factory, RWin32Socket::EUdp));
	CWinSockProviderBase::ConstructL();
	}
