plugins/networking/winsockprt/src/wsp_resolver.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Thu, 26 Aug 2010 00:49:35 +0100
changeset 45 534b01198c2d
parent 0 7f656887cf89
permissions -rw-r--r--
Added ENotifyKeypresses and ECaptureCtrlC flags to CCommandBase. Commands can now get keypresses and handle ctrl-C via callbacks instead of having to implement custom active objects. As part of this extended the CCommandBase extension interface to MCommandExtensionsV2 for the new virtual functions KeyPressed(TUint aKeyCode, TUint aModifiers) and CtrlCPressed(). sudo now cleans up correctly by using ECaptureCtrlC.

// wsp_resolver.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 <winsock2.h>
// Prevent e32std.inl from failing to compile with "ambiguous access to overloaded function".
#define memmove _memmove
#define memset _memset
//
#include <e32math.h>
#include <in_sock.h>
#include <utf.h>
#include "wsp_resolver.h"
#include "wsp_session.h"
#include "wsp_factory.h"
#include "wsp_panic.h"
#include "wsp_log.h"


//
// Constants.
//

_LIT(KWspResolverWorkerThreadNameFormat, "WinSockPrtResolverWorkerThread_%x_%d");
const TInt  KWspResolverWorkerThreadNameLength =  64;
const TInt KWspResolverWorkerThreadStackSize = KDefaultStackSize;


//
// RWin32Socket.
//

RWin32Resolver::RWin32Resolver()
	: iNameRecordPckg(NULL, 0, 0)
	{
	}

TInt RWin32Resolver::Open(RWin32Factory& aFactory)
	{
	WSP_LOG(WspLog::Printf(_L("RWin32Resolver::Open: this: 0x%x"), this));
	return CreateSubSession(aFactory, CWin32Factory::ENewResolver);
	}

void RWin32Resolver::Close()
	{
	WSP_LOG(WspLog::Printf(_L("RWin32Resolver::Close: this: 0x%x"), this));
	RWin32SubSession::Close();
	}

TInt RWin32Resolver::GetByName(TNameRecord& aName, TRequestStatus& aStatus)
	{
	WSP_LOG(WspLog::Printf(_L("RWin32Resolver::GetByName: this: 0x%x"), this));
	iNameRecordPckg.Set(reinterpret_cast<TUint8*>(&aName), sizeof(TNameRecord),sizeof(TNameRecord));
	iWin32Message.Set(CWin32Resolver::EGetByName, iNameRecordPckg, aStatus);
	return MakeRequest(iWin32Message);
	}

TInt RWin32Resolver::GetByAddress(TNameRecord& aName, TRequestStatus& aStatus)
	{
	WSP_LOG(WspLog::Printf(_L("RWin32Resolver::GetByAddress: this: 0x%x"), this));
	iNameRecordPckg.Set(reinterpret_cast<TUint8*>(&aName), sizeof(TNameRecord),sizeof(TNameRecord));
	iWin32Message.Set(CWin32Resolver::EGetByAddress, iNameRecordPckg, aStatus);
	return MakeRequest(iWin32Message);
	}

void RWin32Resolver::Cancel()
	{
	WSP_LOG(WspLog::Printf(_L("RWin32Resolver::Cancel: this: 0x%x"), this));
	TWin32Message cancelWin32Message;
	cancelWin32Message.Set(CWin32Resolver::ECancel);
	MakeRequest(cancelWin32Message); // Throw away return code - can't do anything useful with it.
	}


//
// CWin32Resolver.
//

CWin32Resolver* CWin32Resolver::NewL(CWin32Scheduler& aScheduler)
	{
	CWin32Resolver* self = new(ELeave) CWin32Resolver(aScheduler);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

CWin32Resolver::CWin32Resolver(CWin32Scheduler& aScheduler)
	: CWin32SubSession(aScheduler)
	{
	}

void CWin32Resolver::ConstructL()
	{
	CWin32SubSession::ConstructL();
	}

CWin32Resolver::~CWin32Resolver()
	{
	}

void CWin32Resolver::Run()
	{
	iMessage->Complete(iError);
	iMessage = NULL;
	iWorkerThread.Close();
	}

void CWin32Resolver::ServiceL(TWin32Message& aMessage)
	{
	switch (aMessage.OppCode())
		{
		case EGetByName:
		case EGetByAddress:
			{
			__ASSERT_DEBUG(iMessage == NULL, Panic(EWinSockPrtCWin32ResolverMultipleRequests));
			iMessage = &aMessage;
			CreateWorkerThread();
			break;
			}
		case ECancel:
			{
			Cancel();
			break;
			}
		default:
			{
			__ASSERT_DEBUG(EFalse, Panic(EWinSockPrtInvalidResolverOppCode));
			}
		}
	}

void CWin32Resolver::Cancel()
	{
	if (iWorkerThread.Handle() && (iWorkerThread.ExitType() == EExitPending))
		{
		iWorkerThread.Kill(KErrCancel);
		iMessage->Complete(KErrCancel);
		iMessage = NULL;
		iWorkerThread.Close();
		}
	}

void CWin32Resolver::CreateWorkerThread()
	{
	TBuf<KWspResolverWorkerThreadNameLength> threadName;
	threadName.Format(KWspResolverWorkerThreadNameFormat, this, Math::Rand(iRandSeed));
	TInt err = iWorkerThread.Create(threadName, WorkerThreadStart, KWspResolverWorkerThreadStackSize, NULL, this, EOwnerThread);
	if (err == KErrNone)
		{
		iWorkerThread.Resume();
		}
	else
		{
		iMessage->Complete(err);
		}
	}


//
// CWin32Resolver worker thread methods.
//

TInt CWin32Resolver::WorkerThreadStart(TAny* aPtr)
	{
	CWin32Resolver* self = reinterpret_cast<CWin32Resolver*>(aPtr);

	switch (self->iMessage->OppCode())
		{
		case EGetByName:
			{
			self->GetByName();
			break;
			}
		case EGetByAddress:
			{
			self->GetByAddress();
			break;
			}
		case ECancel:
		default:
			{
			__ASSERT_DEBUG(EFalse, Panic(EWinSockPrtResolverInvalidWorkerThreadRequest));
			}
		}

	return KErrNone;
	}

void CWin32Resolver::GetByName()
	{
	TNameRecord& nameRecord = (TNameRecord&)*iMessage->WriteBuffer().Ptr();
	struct hostent* hp;
	HBufC8* narrowHostNameBuf = HBufC8::New(nameRecord.iName.MaxLength() + 1); // Note, this is one bigger than the size of THostName to allow for a null termination character.
	if (narrowHostNameBuf == NULL)
		{
		iError = KErrNoMemory;
		}
	else
		{
		TPtr8 narrowHostNamePtr(narrowHostNameBuf->Des());
		CnvUtfConverter::ConvertFromUnicodeToUtf8(narrowHostNamePtr, nameRecord.iName);
		hp = gethostbyname(reinterpret_cast<const char*>(narrowHostNamePtr.PtrZ()));
		delete narrowHostNameBuf;
		if (hp)
			{
			TInetAddr& addr = reinterpret_cast<TInetAddr&>(nameRecord.iAddr);
			__ASSERT_DEBUG(hp->h_addrtype == AF_INET, Panic(EWinSockPrtResolverInvalidFamily));
			addr.SetFamily(KAfInet);
			__ASSERT_DEBUG(hp->h_length == 4, Panic(EWinSockPrtResolverInvalidAddressLength));
			TUint32* address = (TUint32*)hp->h_addr_list[0];
			addr.SetAddress(htonl(*address));
			iError = KErrNone;
			}
		else
			{
			iError = KErrNotFound;
			}
		}
	
	if (!SetEvent(iEvent))
		{
		__ASSERT_DEBUG(EFalse, Panic(EWinSockPrtResolverUnexpectedSetEventError));
		}
	}

void CWin32Resolver::GetByAddress()
	{
	TNameRecord& nameRecord = (TNameRecord&)*iMessage->WriteBuffer().Ptr();
	TInetAddr& addr = reinterpret_cast<TInetAddr&>(nameRecord.iAddr);
	struct hostent* hp;
	char addressBuf[4];
	*((TUint32*)addressBuf) = htonl(addr.Address());
	hp = gethostbyaddr(addressBuf, 4, AF_INET);
	if (hp)
		{
		TPtrC8 narrowAddressPtr((TUint8*)hp->h_name, User::StringLength((TUint8*)hp->h_name));
		CnvUtfConverter::ConvertToUnicodeFromUtf8(nameRecord.iName, narrowAddressPtr);
		iError = KErrNone;
		}
	else
		{
		iError = KErrNotFound;
		}
	
	if (!SetEvent(iEvent))
		{
		__ASSERT_DEBUG(EFalse, Panic(EWinSockPrtResolverUnexpectedSetEventError));
		}
	}


//
// CWin32ResolverWrapper.
//

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

CWin32ResolverWrapper::~CWin32ResolverWrapper()
	{
	Cancel();
	iWin32Resolver.Close();
	}

CWin32ResolverWrapper::CWin32ResolverWrapper(MWin32ResolverObserver& aObserver)
	: CActive(CActive::EPriorityStandard), iObserver(aObserver)
	{
	}

void CWin32ResolverWrapper::ConstructL(RWin32Factory& aWin32Factory)
	{
	User::LeaveIfError(iWin32Resolver.Open(aWin32Factory));
	CActiveScheduler::Add(this);
	}

TInt CWin32ResolverWrapper::GetByName(TNameRecord& aName)
	{
	__ASSERT_DEBUG(!IsActive(), Panic(EWinSockPrtResolverWrapperGetByNameWhilstActive));
	TInt err = iWin32Resolver.GetByName(aName, iStatus);
	if (err == KErrNone)
		{
		SetActive();
		}
	return err;
	}

TInt CWin32ResolverWrapper::GetByAddress(TNameRecord& aName)
	{
	__ASSERT_DEBUG(!IsActive(), Panic(EWinSockPrtResolverWrapperGetByAddressWhilstActive));
	TInt err = iWin32Resolver.GetByAddress(aName, iStatus);
	if (err == KErrNone)
		{
		SetActive();
		}
	return err;
	}

void CWin32ResolverWrapper::DoCancel()
	{
	iWin32Resolver.Cancel();
	}

void CWin32ResolverWrapper::RunL()
	{
	iObserver.HandleWin32ResolverCompletion(iStatus.Int());
	}

TInt CWin32ResolverWrapper::RunError(TInt /*aError*/)
	{
	__ASSERT_DEBUG(EFalse, Panic(EWinSockPrtResolverWrapperUnexpectedRunError));
	return 0;
	}


//
// CWinSockResolver.
//

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

CWinSockResolver::~CWinSockResolver()
	{
	delete iResolverWrapper;
	}

void CWinSockResolver::CancelCurrentOperation()
	{
	iResolverWrapper->Cancel();
	}

void CWinSockResolver::GetByName(TNameRecord& aName)
	{
	iResolverWrapper->GetByName(aName);
	}

void CWinSockResolver::GetByAddress(TNameRecord& aName)
	{
	iResolverWrapper->GetByAddress(aName);
	}

void CWinSockResolver::SetHostName(TDes& /*aNameBuf*/)
	{
	// TODO:
	ASSERT(EFalse);
	}

void CWinSockResolver::GetHostName(TDes& /*aNameBuf*/)
	{
	// TODO:
	ASSERT(EFalse);
	}

void CWinSockResolver::HandleWin32ResolverCompletion(TInt aError)
	{
	iNotify->QueryComplete(aError);
	}

CWinSockResolver::CWinSockResolver()
	{
	}

void CWinSockResolver::ConstructL(RWin32Factory& aFactory)
	{
	iResolverWrapper = CWin32ResolverWrapper::NewL(*this, aFactory);
	}