installationservices/switestfw/test/sntpclient/sntpclientengine.cpp
changeset 0 ba25891c3a9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/installationservices/switestfw/test/sntpclient/sntpclientengine.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,296 @@
+/*
+* Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "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:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+
+#include "sntpclientengine.h"
+#include "util.h"
+
+// 40 second timeout on operations
+#define SNTP_ENGINE_TIMEOUT 40000000 
+
+// NTP port
+
+#define SNTP_REMOTE_PORT 123
+
+_LIT(KNTPEpochDate,"19000000:");
+
+/* The simplest possible NTP request */
+
+static const TUint8 sntpRequest[48] = {
+	0x23, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00 };
+	
+/* The main engine of the SNTP client */
+
+CSNTPClient* CSNTPClient::NewL(TCommandLineArgs& aArgs)
+	{
+	CSNTPClient* self = CSNTPClient::NewLC(aArgs);
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+CSNTPClient* CSNTPClient::NewLC(TCommandLineArgs& aArgs)
+	{
+	CSNTPClient* self = new (ELeave) CSNTPClient(aArgs);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+	
+TSNTPClientState CSNTPClient::State()
+	{
+	return iState;
+	}
+	
+void CSNTPClient::Start()
+	{
+	
+	iState = EStateResolve;
+	iResolver.GetByName(*(iArgs.iServers[iServerIndex]), iNameEntry, iStatus);
+	SetActive();
+	iTimer->After(SNTP_ENGINE_TIMEOUT);
+	
+	}
+	
+CSNTPClient::~CSNTPClient()
+	{
+	Cancel();
+	iResolver.Close();
+	iSock.Close();
+	iSockServ.Close();
+	
+	delete iTimer;
+	}
+	
+CSNTPClient::CSNTPClient(TCommandLineArgs& aArgs)
+	: CActive(EPriorityStandard), iArgs(aArgs)
+	{
+	}
+	
+void CSNTPClient::ConstructL()
+	{
+	User::LeaveIfError(iSockServ.Connect());
+	User::LeaveIfError(iSock.Open(iSockServ, KAfInet, KSockDatagram, KProtocolInetUdp));
+	User::LeaveIfError(iResolver.Open(iSockServ, KAfInet, KProtocolInetUdp));
+	
+	iTimer = CTimeOutTimer::NewL(EPriorityHigh, *this);
+	CActiveScheduler::Add(this);
+	}
+	
+void CSNTPClient::RunL()
+	{
+	
+	if (iStatus.Int() < 0)
+		{
+		User::Leave(iStatus.Int());
+		}
+
+	switch (iState)
+		{
+	
+	case EStateResolve:
+		iTimer->Cancel();
+		iBuffer.Zero();
+		iBuffer.Append(sntpRequest, 48);
+	
+		// set the port on the address
+		iNameEntry().iAddr.SetPort(SNTP_REMOTE_PORT);
+	
+		iState = EStateWrite;
+		iSock.SendTo(iBuffer, iNameEntry().iAddr, 0, iStatus);
+		SetActive();
+		iTimer->After(SNTP_ENGINE_TIMEOUT);
+		break;
+	
+	case EStateWrite:
+		iTimer->Cancel();
+		iState = EStateRead;
+		iBuffer.Zero();
+		iSock.RecvFrom(iBuffer, iNameEntry().iAddr, 0, iStatus);
+		SetActive();
+		iTimer->After(SNTP_ENGINE_TIMEOUT);
+		break;
+		
+	case EStateRead:
+		{
+		iTimer->Cancel();
+		SetTimeL();
+		iStatus = KRequestPending;
+		iState = EStateComplete;
+		TRequestStatus* status = &iStatus;
+		SetActive();
+		User::RequestComplete(status, KErrNone);
+		break;
+		}
+		
+	case EStateComplete:
+		CActiveScheduler::Stop();
+		// done
+		break;
+		
+	default:
+		// wuh oh. BC break!
+		User::Leave(KErrArgument);
+		break;
+		
+		}
+	
+	}
+	
+void CSNTPClient::DoCancel()
+	{
+	
+	iTimer->Cancel();
+
+	switch (iState)
+		{
+	case EStateResolve:
+		iResolver.Cancel();
+		break;
+	case EStateWrite:
+		iSock.CancelSend();
+		break;
+	case EStateRead:
+		iSock.CancelRecv();
+		break;
+		}
+		
+	}
+	
+	
+TInt CSNTPClient::RunError(TInt /* aError */)
+	{
+	// The current server didn't work, lets try the next if available.
+	iTimer->Cancel();
+	
+	if (++iServerIndex < iArgs.iServers.Count())
+		{
+		Start();
+		}
+	else
+		{
+		iState = EStateFailed;
+		CActiveScheduler::Stop();
+		}
+	return KErrNone;
+	}
+	
+void CSNTPClient::TimerExpired()
+	{
+	Cancel();
+	
+	// The current server didn't work, lets try the next if available.
+	
+	if (++iServerIndex < iArgs.iServers.Count())
+		{
+		Start();
+		}
+	else
+		{
+		iState = EStateAborted;
+		CActiveScheduler::Stop();
+		}
+	}
+	
+void CSNTPClient::SetTimeL()
+	{
+	
+	TUint32 timestamp(0);
+	
+	/* Use the seconds from the transmit time field 
+	   TO DO:
+	      + Implement proper differential here
+	 */
+	
+	for (TInt i = 40; i < 44; ++i)
+		{
+		timestamp = (timestamp << 8) + iBuffer[i];
+		}
+	
+	// Obtain the time, including the specified timezone offset
+	
+	TTimeIntervalMinutes mins(timestamp / 60);
+	TTimeIntervalSeconds secs(timestamp % 60);
+	
+	TTime ntpTime;
+	User::LeaveIfError(ntpTime.Set(KNTPEpochDate));
+	ntpTime += mins;
+	ntpTime += secs;
+	
+	// Apply offset and (possibly) daylight savings time
+	
+	TTimeIntervalHours hours;
+	
+	if (iArgs.iApplyDaylightSavings && Util::DaylightSavingsAppliesL(ntpTime))
+		{
+		hours = iArgs.iOffset + 1;
+		}
+	else
+		{
+		hours = iArgs.iOffset;
+		}
+		
+	ntpTime += hours;
+	
+	User::LeaveIfError(User::SetHomeTime(ntpTime));
+	
+	}
+	
+	
+/* Timeout handler for read/write operations */
+
+CTimeOutTimer::CTimeOutTimer(const TInt aPriority)
+    : CTimer(aPriority)
+    {
+    }
+
+CTimeOutTimer::~CTimeOutTimer()
+    {
+	Cancel();
+    }
+
+CTimeOutTimer* CTimeOutTimer::NewL(const TInt aPriority, MTimeOutNotify& aTimeOutNotify)
+    {
+    CTimeOutTimer *p = new (ELeave) CTimeOutTimer(aPriority);
+    CleanupStack::PushL(p);
+	p->ConstructL(aTimeOutNotify);
+	CleanupStack::Pop();
+    return p;
+    }
+
+void CTimeOutTimer::ConstructL(MTimeOutNotify &aTimeOutNotify)
+    {
+	iNotify=&aTimeOutNotify;
+	CTimer::ConstructL();
+    CActiveScheduler::Add(this);
+    }
+
+void CTimeOutTimer::RunL()
+// Timer request has completed, so notify the timer's owner
+    {
+	iNotify->TimerExpired();
+	}