tcpiputils/dnd/src/dns_sock.cpp
changeset 0 af10295192d8
child 53 7e41d162e158
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcpiputils/dnd/src/dns_sock.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,1365 @@
+// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "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:
+// dns_sock.cpp - the main client module of the DNS.
+//
+
+#include <e32math.h>
+#include <networking/dnd_err.h>
+#include <in_sock.h>
+#include "dns_sock.h"
+#include "message.h"
+#include "inet6log.h"
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY 
+#include <es_enum.h>
+#endif
+
+
+/**
+* Max number of consecutive RunL() calls with error condition.
+* When this limit is exceeded, the socket it closed.
+*/
+const TUint KSocketErrorLimit = 20;
+
+//seeds cannot be negative number. Need mask to seed to positive number.
+const TInt KNegativeNumberMask = -1;
+
+//
+// TRequestQueue
+// *************
+//
+class TRequestQueue : public TDblQue<TDnsRequest>
+	{
+public:
+	// Construct an empty request queue
+	TRequestQueue();
+	// Construct new request queue and MOVE all requests from another into it
+	TRequestQueue(TRequestQueue &);
+	// Remove the first request from a queue, return NULL if queue is empty
+	TDnsRequest *Remove();
+	};
+
+
+TRequestQueue::TRequestQueue()
+	: TDblQue<TDnsRequest>(_FOFF(TDnsRequest, iQueueLink))
+	{
+	}
+
+TRequestQueue::TRequestQueue(TRequestQueue &aQueue)
+	: TDblQue<TDnsRequest>(_FOFF(TDnsRequest, iQueueLink))
+	{
+	if (aQueue.IsEmpty())
+		Reset();
+	else
+		{
+		iHead = aQueue.iHead;
+		iHead.iPrev->iNext = &iHead;
+		iHead.iNext->iPrev = &iHead;
+		}
+	aQueue.Reset();
+	}
+
+TDnsRequest *TRequestQueue::Remove()
+	{
+	if (!IsEmpty())
+		{
+		TDnsRequest *rq = First();
+		rq->iQueueLink.Deque();
+		return rq;
+		}
+	return NULL;
+	}
+
+class CDnsSocketReader;
+
+// CDnsSocketWriter
+// ****************
+// Internal "hidden" class to do all the work
+class CDnsSocketWriter : public CActive
+    {
+	CDnsSocketWriter(CDnsSocket &aMaster);
+public:
+	~CDnsSocketWriter();
+	void ConstructL();
+
+	// Create a basic (UDP) reader/writer (not activated)
+	static CDnsSocketWriter *NewL(CDnsSocket &aMaster, TInt aTTL);
+	// Create a TCP writer/reader (not activated)
+	static CDnsSocketWriter *NewTcpL(CDnsSocket &aMaster, const TInetAddr &aServer, TInt aTTL);
+	// Create a TCP listening writer/reader (not activated)
+	static CDnsSocketWriter *NewTcpListenL(CDnsSocket &aMaster, TInt aTTL);
+
+	// Test if a address matches current connection
+	TBool Match(const TInetAddr &aServer) const;
+
+	// (Re)Queue the request for processing with new ID
+	void Queue(TDnsRequest &aRequest, const TInt aId = -1);
+	// Cancel the request and dequeue it
+	void Remove(TDnsRequest &aRequest);
+	// Change the bind port (and address if specified)
+	void SetBind(const TInetAddr &aBind);
+	// Set hoplimit for for transmitted packets.
+	void SetHoplimit(const TInt aTTL);
+	 // Open and activate the UDP socket for DNS traffic (unless already done)
+	TInt ActivateSocket();
+	// Process socket errors
+	TInt HandleError(TInt aReason, const TInetAddr *aServer = NULL);
+	// Close and deactivate the UDP socket for DNS traffic
+	void DeactivateSocket(TInt aReason); 
+	// Handle receive compeleted, keep receiver active
+	void RunReader(const TMsgBuf &aMsg, const TInetAddr &aFrom);
+	// Handle send completed, keep sender active (if work to do)
+	void RunWriter(TRequestStatus &aStatus);
+ 	//seed id generator
+ 	TInt64 SeedIdGenerator(TInt64 aSequence);
+	// Return a reference to the RSocket
+	inline RSocket &Socket() { return iSocket; }
+	inline TBool IsTCP() const { return iTCP != 0; }
+	inline TBool IsListen() const { return iListen != 0; }
+	inline TBool IsOpened() const { return iOpened; }
+	inline void ResetErrorCount() { iErrorCount = 0;}
+	// A link chain used by the CDnsSocket to keep track of multiple writers
+	CDnsSocketWriter *iNext;
+	
+private:
+	void RunL();
+	void DoCancel();
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY	
+	TBool CanUseConnection();
+#endif
+
+	CDnsSocket &iMaster;		//< The connection to the CDnsSocket owning this
+	RSocket iSocket;			//< The DNS socket
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY 
+	RConnection iAttachedConn;	//< The connection on which the DNS socket may be opened on
+#endif		
+	TUint iDeactivateCount;		//< Count number of deactivations (needed in reply processing)
+	TUint iErrorCount;			//< Count number of consecutive errors in RunL (read and write)
+	TUint iListen;				//< = 1, if socket is listening TCP socket, waiting on accept.
+	TUint iTCP;					//< = 1, if socket is a connected TCP socket
+	TUint iOpened:1;			//< = 1, if the socket is open
+	TUint iRunWriter:1;			//< = 1, if executing RunWriter (callback safeguard)
+	TUint iRunReader:1;			//< = 1, if executing RunReader (callback safeguard)	
+	TInt iTTL;					//< The TTL/Hoplimit to be used
+	TInt64 iSequence;			//< Used in computing the ID value for the queries
+	TBuf8<KDnsMaxMessage> iOutMsg;	//< For sending the outgoing message
+	TInetAddr iBind;			//< Address/Port to bind the socket.
+	TInetAddr iTo;				//< Filled with the destination address of the query
+	TRequestQueue iSendQueue;	//< Requests waiting to be sent
+	TRequestQueue iWaitQueue;	//< Requests waiting for a reply
+	TDnsRequest *iSending;		//< The request currently being sent, if non-NULL
+	CDnsSocketReader *iReader;	//< The reader object
+	};
+
+void TDnsRequest::Cancel()
+	{
+	CDnsSocketWriter *const writer = iQueueLink.Writer();
+	if (writer)
+		writer->Remove(*this);
+	}
+
+
+// CDnsSocketReader
+// ****************
+// Internal "hidden" class for hanlding asynchronous reading
+class CDnsSocketReader : public CActive
+	{
+	friend class CDnsSocketWriter;
+public:
+	CDnsSocketReader(CDnsSocketWriter &aWriter);
+	~CDnsSocketReader();
+	void ConstructL(TUint aDnsMaxMessage);
+	void Activate();
+
+private:
+	void RunL();
+	void DoCancel();
+
+	CDnsSocketWriter &iWriter;
+	TUint iReadLength:1;
+	TInetAddr iFrom;		//< Filled with source address of a received packet
+	HBufC8 *iInMsg;			//< The real allocated buffer
+	TInt iAllocatedLength;	//< The real max length of the buffer
+	TPtr8 iBuf;				//< The current receive buffer
+	};
+
+CDnsSocketWriter::CDnsSocketWriter(CDnsSocket &aMaster) : CActive(0), iMaster(aMaster)
+	{
+	LOG(Log::Printf(_L("CDnsSocketWriter[%u]::CDnsSocketWriter([%u])"), this, &aMaster));
+	CActiveScheduler::Add(this);
+
+	TTime seed;
+	seed.UniversalTime();
+	iSequence = seed.Int64();
+	}
+
+void CDnsSocketWriter::ConstructL()
+	{
+	iReader = new (ELeave) CDnsSocketReader(*this);
+	iReader->ConstructL(iMaster.iMaxDnsMessage);
+	}
+
+
+CDnsSocketWriter *CDnsSocketWriter::NewL(CDnsSocket &aMaster, TInt aTTL)
+	{
+	CDnsSocketWriter *const writer = new (ELeave) CDnsSocketWriter(aMaster);
+	CleanupStack::PushL(writer);
+	writer->iTTL = aTTL;
+	writer->ConstructL();
+	CleanupStack::Pop();
+	return writer;
+	}
+
+CDnsSocketWriter *CDnsSocketWriter::NewTcpL(CDnsSocket &aMaster, const TInetAddr &aServer, TInt aTTL)
+	{
+	CDnsSocketWriter *const writer = NewL(aMaster, aTTL);
+	// Note: with TCP iTo is dummy!
+	writer->iTo = aServer;
+	writer->iTCP = 1;
+	return writer;
+	}
+
+CDnsSocketWriter *CDnsSocketWriter::NewTcpListenL(CDnsSocket &aMaster, TInt aTTL)
+	{
+	CDnsSocketWriter *const writer = NewL(aMaster, aTTL);
+	writer->iTCP = 1;
+	writer->iListen = 1;
+	return writer;
+	}
+
+
+
+CDnsSocketWriter::~CDnsSocketWriter()
+	{
+	// As this class is managed by CDnsSocket, it is impossible
+	// to get here if IsActive(), or with requests in any queue.
+	// (DeactivateSocket is ALWAYS called before destructor)
+	//
+	ASSERT(!IsActive());
+	ASSERT(iSendQueue.IsEmpty());
+	ASSERT(iWaitQueue.IsEmpty());
+
+	delete iReader;
+
+	Cancel();	// should not be needed...
+	if (IsAdded())
+		Deque();
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY		
+	iAttachedConn.Close();
+#endif	
+	LOG(Log::Printf(_L("CDnsSocketWriter[%u]::~CDnsSocketWriter()"), this));
+	}
+
+TBool CDnsSocketWriter::Match(const TInetAddr &aServer) const
+	{
+	// The match applies only to connected TCP readers/writers
+	return iTCP && !iListen && aServer.CmpAddr(iTo) && aServer.Scope() == iTo.Scope();
+	}
+
+//
+// RunReader
+//
+void CDnsSocketWriter::RunReader(const TMsgBuf &aMsg, const TInetAddr &aFrom)
+	{
+	if (iRunReader)
+		return;
+	iRunReader = 1;
+#ifdef _LOG
+		{
+		TBuf<50> tmp;
+		aFrom.OutputWithScope(tmp);
+		Log::Printf(_L("CDnsSocketWriter[%u]::RunReader() read %d bytes from %S#%d"), this, (TInt)aMsg.Length(),
+			&tmp, aFrom.Port());
+		}
+#endif
+	if (aMsg.Length() >= TInt(sizeof(TDndHeader)))
+		{
+		const TDndHeader &hdr = aMsg.Header();
+		const TUint16 id = (TUint16)hdr.ID();
+
+		if (hdr.QR())
+			{
+			//
+			// This is a reply message, match it with
+			// a waiting request, if any...
+			//
+			// Things get somewhat tricky, because almost anything
+			// can happen inside the Reply (like DeactivateSocket,
+			// ActivateSocketL, removal of any requests, requeing
+			// for sent, etc...
+			// Grab the current list into separate list. Note, that
+			// Query or Reply callbacks are allowed to remove entries
+			// from this temporary queue (the TDnsRequest::Cancel and
+			// CDnsSocket::Redmove() still work correctly--they don't
+			// care which chain the request belongs!),
+			TRequestQueue reply(iWaitQueue);
+			TUint mark = iDeactivateCount;
+			TDnsRequest *rq;
+			for (;;)
+				{
+				rq = reply.Remove();
+				if (rq == NULL)
+					{
+					// Didn't match any request, punt it into Query()
+					iMaster.Query(aMsg, aFrom, iSocket);
+					break;
+					}
+				iWaitQueue.AddLast(*rq);
+				if (rq->iId == id && rq->Reply(iMaster, aMsg, aFrom))
+					break;
+				}
+			if (iDeactivateCount == mark)
+				{
+				//
+				// No socket shutdown occurred, just reinsert remaining requests
+				//
+				while ((rq = reply.Remove()) != NULL)
+					iWaitQueue.AddLast(*rq);
+				}
+			else
+				{
+				//
+				// Socket was shut within Reply, all requests
+				// should have been cancelled then...
+				//
+				while ((rq = reply.Remove()) != NULL)
+					{
+					rq->iQueueLink.SetWriter(NULL);
+					rq->Abort(iMaster, KErrCancel);
+					}
+				}
+			}
+		else
+			{
+			//
+			// Not a reply message, let the derived
+			// class decide on how to deal with it.
+			//
+			iMaster.Query(aMsg, aFrom, iSocket);
+			}
+		}
+
+	iRunReader = 0;
+ 	if (iOpened ) 	// still open for business?
+		{
+		// Start a new read
+		iReader->Activate();
+		}
+	}
+
+void CDnsSocketWriter::Queue(TDnsRequest &aRequest, TInt aId)
+	{
+	aRequest.Cancel();
+	//
+	// Assign a new random ID for the request
+	//
+	if (aId < 0)
+ 		{
+ 		TInt64 seed = SeedIdGenerator(iSequence);
+ 		if(seed<0)
+ 		seed = seed *(KNegativeNumberMask);
+ 		aRequest.iId = (TUint16)(Math::Rand(seed) >> 8);
+ 		}
+	else
+		aRequest.iId = (TUint16)aId;
+	aRequest.iQueueLink.SetWriter(this);
+
+	iSendQueue.AddLast(aRequest);
+	LOG(Log::Printf(_L("\t\tDNS session [%u] Queued for send with ID=%d"), (TInt)&aRequest, (TInt)aRequest.iId));
+	if (!IsActive())
+		RunWriter(iStatus);
+	}
+
+
+void CDnsSocketWriter::SetBind(const TInetAddr &aBind)
+	{
+	iBind = aBind;
+	}
+
+void CDnsSocketWriter::SetHoplimit(const TInt aTTL)
+	{
+	if (aTTL != iTTL)
+		{
+		iTTL = aTTL;
+		iSocket.SetOpt(KSoIp6UnicastHops, KSolInetIp, iTTL);
+		iSocket.SetOpt(KSoIp6MulticastHops, KSolInetIp, iTTL);
+		}
+	}
+
+TInt CDnsSocketWriter::ActivateSocket()
+	{
+ 	if (iOpened) 
+		return KErrNone;		// Nothing to do if already opened
+
+	iErrorCount = 0;
+#ifndef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY 	
+	TInt err = 
+		iListen ? iSocket.Open(iMaster.iSS) :
+		iTCP ? iSocket.Open(iMaster.iSS, KAfInet, KSockStream, KProtocolInetTcp) :
+		iSocket.Open(iMaster.iSS, KAfInet, KSockDatagram, KProtocolInetUdp);
+#else			
+	TInt err = KErrNone;
+	if (iListen)
+		{
+		err = iSocket.Open(iMaster.iSS);	
+		}
+	else
+		{		
+		TUint addrFamily = iTCP ? KSockStream : KSockDatagram;
+		TUint protocol = iTCP ? KProtocolInetTcp : KProtocolInetUdp;
+		if (CanUseConnection())
+			{
+			err = iSocket.Open(iMaster.iSS, KAfInet, addrFamily, protocol, iAttachedConn);
+			}
+		else
+			{
+			err = iSocket.Open(iMaster.iSS, KAfInet, addrFamily, protocol);	
+			}			
+		}
+#endif			
+#ifdef _LOG
+	// Initialize for LOG prints
+	TBuf<50> tmp;
+	iBind.OutputWithScope(tmp);
+#endif
+	if (err == KErrNone)
+		{
+		if (iListen || (err = iSocket.Bind(iBind)) == KErrNone)
+			{
+			iOpened = 1;
+			if (iListen)
+				{
+				LOG(Log::Printf(_L("CDnsSocketWriter[%u]::ActivateSocketL() listening %S#%d"), this, &tmp, iBind.Port()));
+				iMaster.iListener.Accept(iSocket, iStatus);
+				SetActive();
+				}
+			else
+				{
+				iSocket.SetOpt(KSoIp6UnicastHops, KSolInetIp, iTTL);
+				iSocket.SetOpt(KSoIp6MulticastHops, KSolInetIp, iTTL);
+				if (iTCP)
+					{
+#ifdef _LOG
+					TBuf<50> dst;
+					iTo.OutputWithScope(dst);
+					Log::Printf(_L("CDnsSocketWriter[%u]::ActivateSocketL() TCP connect src=%S#%d dst=%S#%d"), this,
+						&tmp, iBind.Port(),
+						&dst, iTo.Port());
+#endif
+					iSocket.Connect(iTo, iStatus);
+					SetActive();
+					}
+				else
+					{
+					LOG(Log::Printf(_L("CDnsSocketWriter[%u]::ActivateSocketL() UDP %S#%d"), this, &tmp, iBind.Port()));
+					iSocket.SetOpt(KSoUdpReceiveICMPError, KSolInetUdp, 1);
+					if (!iRunReader)
+						iReader->Activate();
+					}
+				}
+			return KErrNone;
+			}
+		iSocket.Close();
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY		
+		iAttachedConn.Close();
+#endif		
+		}
+	// Should probably be logged in release too!
+	LOG(Log::Printf(_L("CDnsSocketWriter[%u]::ActivateSocketL() bind=%S#%d (or open) failed %d"), this, &tmp, iBind.Port(), err));
+	return err;
+	}
+
+
+/**
+* Decides on action when the socket returns an error status. Not all
+* errors are fatal errors, which require a reset of the socket.
+*
+* @param aReason	the error code from the socket (iStatus)
+* @param aServer	the dns server address, if known (only for Send errors)
+*
+* @return
+* @li	= 1, Error fully processed, Don't activate anything
+* @li	= 0, Error handled, keep CActive running
+*/
+TInt CDnsSocketWriter::HandleError(TInt aReason, const TInetAddr *aServer)
+	{
+	if (++iErrorCount > KSocketErrorLimit)
+		{
+		// Too many consecutive errors, deactivate to reset
+		LOG(Log::Printf(_L("CDnsSocketWriter[%u]::HandleError(%d) Too many (%d) consecutive errors"), this, aReason, iErrorCount));
+		DeactivateSocket(aReason);
+		return 1;
+		}
+	if (IsTCP())
+		{
+		// Any error on TCP socket means that it is "dead",
+		// and we must close the socket to recover!
+		DeactivateSocket(KErrDndServerUnusable);
+		return 1;
+		}
+	// The error state should automaticly clear with datagram
+	// sockets, but in some releases it does not. Issue a
+	// dummy KSOSelectLastError, which in some cases also
+	// clears the error code from socket server. (Note: the
+	// option parameter is dummy, the error is actually
+	// returned as a return value of GetOpt, very bizarre
+	// -- msa)
+	TInt socket_err = iSocket.GetOpt(KSOSelectLastError, KSOLSocket, socket_err);
+	(void)socket_err;	// shut down compiler warning about unreference variable.
+
+	if (aServer == NULL)
+		{
+		// The only errors on receive side, that we can do something about, are
+		// the ICMP errors for some server (other errors are ignored).
+		// Try to find out the server.
+		TPckgBuf<TSoInetLastErr> opt;
+		if (iSocket.GetOpt(KSoInetLastError, KSolInetIp, opt) == KErrNone)
+			{
+#ifdef _LOG
+			TBuf<50> src;
+			TBuf<50> dst;
+			TBuf<50> err;
+			opt().iSrcAddr.OutputWithScope(src);
+			opt().iDstAddr.OutputWithScope(dst);
+			opt().iErrAddr.OutputWithScope(err);
+			Log::Printf(_L("CDnsSocketWriter[%u]::HandleError(%d) last=%d, icmp(%d,%d) src=%S dst=%S err=%S"),
+				this, aReason, opt().iStatus, opt().iErrType, opt().iErrCode, &src, &dst, &err);
+#endif
+			if (opt().iStatus != aReason)
+				return 0;		// Error does not match the ICMP last error, just ignore.
+
+			aServer = &opt().iDstAddr;
+			}
+		else
+			{
+			DeactivateSocket(KErrDndServerUnusable);
+			return 1;
+			}			
+		}
+
+	// aServer possibly identifies a DNS server with which
+	// we have some communication problems. Declare this
+	// server unusable for all queries currently using it.
+	const TUint mark = iDeactivateCount;
+	iMaster.Error(*aServer, aReason);
+	// If shutdown occurred within above call, then
+	// this return must not try to reactivate the
+	// reader or writer.
+	return (mark != iDeactivateCount);
+	}
+
+void CDnsSocketWriter::DeactivateSocket(TInt aReason)
+	{
+	LOG(Log::Printf(_L("CDnsSocketWriter[%u]::DeactivateSocket() Entry"), this));
+	if (!iOpened )
+	    {
+	    LOG(Log::Printf(_L("CDnsSocketWriter[%u]::DeactivateSocket() return without action"), this));
+		return;			// Nothing to do if not open
+	    }
+	// Grab current set of requests away, so that
+	// potentially newly entered requests won't
+	// get affected by this...
+	//
+	TRequestQueue send(iSendQueue);
+	TRequestQueue wait(iWaitQueue);
+	//
+	// Cancel all activity
+	//
+//	LOG(Log::Printf(_L("CDnsSocketWriter[%u]::DeactivateSocket() iReader->Cancel()"), this));
+	iReader->Cancel();
+//	LOG(Log::Printf(_L("CDnsSocketWriter[%u]::DeactivateSocket() Cancel()"), this));
+	Cancel();
+//	LOG(Log::Printf(_L("CDnsSocketWriter[%u]::DeactivateSocket() iSocket.Close()"), this));
+	//
+	// Shut down the sessions
+	//
+	iOpened = 0;
+	iSocket.Close();
+	iDeactivateCount += 1;
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY	
+	iAttachedConn.Close();
+#endif	
+	//
+	// Remove and abort all requests
+	//
+	TDnsRequest *rq;
+	while ((rq = send.Remove()) != NULL)
+		{
+		rq->iQueueLink.SetWriter(0);
+		rq->Abort(iMaster, aReason);
+		}
+	while ((rq = wait.Remove()) != NULL)
+		{
+		rq->iQueueLink.SetWriter(0);
+		rq->Abort(iMaster, aReason);
+		}
+	LOG(Log::Printf(_L("CDnsSocketWriter[%u]::DeactivateSocket() complete"), this));
+	}
+
+//
+// CDnsSocketWriter::Remove
+// ************************
+void CDnsSocketWriter::Remove(TDnsRequest &aQuery)
+	{
+	//
+	// Must not be called for request that is not queued
+	//
+	ASSERT(aQuery.iQueueLink.Writer() == this);
+	aQuery.iQueueLink.Deque();
+	aQuery.iQueueLink.SetWriter(0);
+
+	if (iSending == &aQuery)
+		{
+		iSending = NULL;
+		// If IsActive() == FALSE, then this Remove is actually
+		// called from the Build() callback!
+		if (IsActive())
+			{
+			Cancel();
+			// There can be other queries waiting
+			// for writer..
+			RunWriter(iStatus);
+			}
+		}
+	}
+
+void CDnsSocketWriter::RunL()
+	{
+	const TInt result = iStatus.Int();
+	LOG(Log::Printf(_L("--> CDnsSocketWriter[%u]::RunL() -start- iStatus=%d"), this, result));
+#ifdef _LOG
+	TBuf<50> tmp;
+	iTo.OutputWithScope(tmp);
+#endif
+	for (;;)	// ...just for easy exits..
+		{
+		if (result)
+			{
+			LOG(Log::Printf(_L("CDnsSocketWriter[%u]::RunL() Error on %S#%d"), this, &tmp, iTo.Port()));
+			}
+		else
+			ResetErrorCount();
+		if (iListen)
+			{
+			//
+			// Keep listening active, allocate a new reader/writer to listen
+			//
+			CDnsSocketWriter *writer = NULL;
+			TRAPD(err,
+				writer = CDnsSocketWriter::NewTcpListenL(iMaster, iTTL);
+				err = iMaster.AddSecondaryWriter(writer));
+			if (err != KErrNone)
+				{
+				// Cannot start new accept for some reason, reject the current accept and
+				// reinitialize the current writer to wait a new accept instead
+				iMaster.DeleteWriter(writer, err);	// <-- safe to call with writer == NULL
+				// Reactivate this socket for listening instead (iListen remains set)
+				LOG(Log::Printf(_L("CDnsSocketWriter[%u]::RunL() Failed (%d) to activate new Accept() to=%S#%d"),
+					this, err, &tmp, iTo.Port()));
+				DeactivateSocket(err);
+				ActivateSocket();
+				break;
+				}
+			// Succesful Accept, update iTo to the address and port of the
+			// remote end.
+			iListen = 0;
+			iSocket.RemoteName(iTo);
+			LOG(iTo.OutputWithScope(tmp));
+			LOG(Log::Printf(_L("CDnsSocketWriter[%u]::RunL() Listen accepted to=%S#%d"), this, &tmp, iTo.Port()));
+			if (!iReader->IsActive())
+				iReader->Activate();
+			}
+		if (iSending)
+			{
+			LOG(Log::Printf(_L("\t\tDNS session [%u] Sent to=%S#%d ID=%d"), iSending, &tmp, iTo.Port(), (TInt)iSending->Id()));
+			TDnsRequest *query = iSending;
+			iSending = NULL;
+			if (result == KErrNone)
+				query->Sent(iMaster);
+			else if (HandleError(result, &iTo))
+				break;
+			}
+		else if (result && HandleError(result))	// Error that cannot be associated with specific sending (does it ever happen?)
+			break;
+		// Keep writer busy, if not already active.
+		if (!IsActive())
+			RunWriter(iStatus);
+		break;	// ** NOT REAL LOOP, ALWAYS EXIT AT END **
+		}
+	LOG(Log::Printf(_L("<-- CDnsSocketWriter[%u]::RunL() -exit- iStatus=%d"), this, iStatus.Int()));
+	}
+
+void CDnsSocketWriter::RunWriter(TRequestStatus &aStatus)
+	{
+	if (iRunWriter)
+		return;		// This is a callback from Build, return
+	iRunWriter = 1;
+	//
+	// Pick next query to be served
+	// ****************************
+	//
+	iSending = iSendQueue.Remove();
+	while ( iSending != NULL)
+		{
+		iWaitQueue.AddLast(*iSending);
+		// Before calling Build, the message is reset into
+		// initial state:
+		TPtr8 payload((TUint8 *)iOutMsg.Ptr(), iOutMsg.MaxLength());
+		if (iTCP)
+			payload.Set((TUint8 *)payload.Ptr()+2, 0, payload.MaxLength()-2);
+		TMsgBuf &buf = TMsgBuf::Cast(payload);
+		buf.SetLength(sizeof(TDndHeader));
+		buf.Header().Init(iSending->iId);
+		// If Build fails, request(s) are simply moved
+		// into iWaitQueue to wait for further actions.
+		// (If iSending becomes NULL in Build, then Build has Removed the
+		// request--do not start write)
+		// Note: if receive buffer > KDnsMaxMessage, then it requests EDNS0. Don't
+		// request EDNS0, if TCP is being used (report receive buffer = 0).
+		if (iSending->Build(iMaster, buf, iTo, iTCP ? 0 : iReader->iAllocatedLength) && iOpened && iSending)
+			{
+			const TInt len = buf.Length();
+			if (iTCP)
+				{
+				// Patch in the length
+				TUint8 *const p = (TUint8 *)iOutMsg.Ptr();
+				p[1] = (TUint8)len;
+				p[0] = (TUint8)(len >> 8);
+				iOutMsg.SetLength(len+2);
+				}
+			else
+				{
+				iOutMsg.SetLength(len);
+				}
+#ifdef _LOG
+			TBuf<50> tmp;
+			iTo.OutputWithScope(tmp);
+			Log::Printf(_L("\t\tDNS session [%u] Send to=%S#%d %d bytes (TCP=%d)"), iSending, &tmp, iTo.Port(), iOutMsg.Length(), (TInt)iTCP);
+#endif
+			if (iTCP)
+				{
+				iSocket.Write(iOutMsg, aStatus);
+				if (!iReader->IsActive())
+					iReader->Activate();
+				}
+			else
+				iSocket.SendTo(iOutMsg, iTo, 0, aStatus);
+			SetActive();
+			break;
+			}
+		}
+	iRunWriter = 0;
+	}
+
+void CDnsSocketWriter::DoCancel()
+	{
+	LOG(Log::Printf(_L("CDnsSocketWriter[%u]::DoCancel()"), this));
+	if (iListen)
+		{
+		iMaster.iListener.CancelAll();
+		iListen = 0;
+		}
+	else
+		{
+		iSocket.CancelWrite();
+		iSending = NULL;
+		}
+	}
+	
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+TBool CDnsSocketWriter::CanUseConnection()
+	{	
+	TInt err = iAttachedConn.Open(iMaster.iSS);
+	if (KErrNone != err)
+        	{
+	        LOG(Log::Printf(_L("CDnsSocketWriter[%u]::CanUseConnection() error opening connection: %d"), this, err));
+	        return EFalse;
+        	}
+
+	    TUint noConnections = 0;
+	    err = iAttachedConn.EnumerateConnections(noConnections);
+	    if (KErrNone != err)
+        	{
+	        LOG(Log::Printf(_L("CDnsSocketWriter[%u]::CanUseConnection() error enumerating connections: %d"), this, err));
+        	return EFalse;
+	        }
+	LOG(Log::Printf(_L("CDnsSocketWriter[%u]::CanUseConnection() no of connections: %u"), this, noConnections));
+
+    if (noConnections > 0)
+        {
+        TPckgBuf<TConnectionInfo> info;
+        TConnectionInfo currentInfo;
+        TBool foundConnection = EFalse;
+        for(TInt i=1; i<=noConnections; i++)
+            {
+            if (KErrNone != iAttachedConn.GetConnectionInfo(i, info))
+                {
+                return EFalse;
+                }
+            currentInfo = info();
+
+            LOG(Log::Printf(_L("CDnsSocketWriter[%u]::CanUseConnection() currentInfo.NetId = %d "), this, currentInfo.iNetId));
+            LOG(Log::Printf(_L("CDnsSocketWriter[%u]::CanUseConnection() iMaster.iNetworkId = %d "), this, iMaster.iNetworkId));
+            if(currentInfo.iNetId == iMaster.iNetworkId)
+                {
+                foundConnection = ETrue;
+                break;
+                }
+            }
+
+        if ((foundConnection) && (KErrNone == iAttachedConn.Attach(info, RConnection::EAttachTypeNormal)))
+            {
+            LOG(Log::Printf(_L("CDnsSocketWriter[%u]::CanUseConnection() attached to existing connection at IAP: [%d] Network: [%d]"), this, info().iIapId, info().iNetId));
+            return ETrue;
+            }
+        else
+            {
+            LOG(Log::Printf(_L("CDnsSocketWriter[%u]::CanUseConnection() could not find any connection matching the Network: [%d]"), this, iMaster.iNetworkId));
+            return EFalse;
+            }
+        }
+
+    return EFalse;
+     }
+#endif
+
+// CDnsSocketReader
+// ****************
+CDnsSocketReader::CDnsSocketReader(CDnsSocketWriter &aWriter) : CActive(0), iWriter(aWriter), iBuf(0,0)
+	{
+	LOG(Log::Printf(_L("CDnsSocketReader[%u]::CDnsSocketReader()"), this));
+	CActiveScheduler::Add(this);
+	}
+
+void CDnsSocketReader::ConstructL(TUint aDnsMaxMessage)
+	{
+	//
+	// Any reader MUST have a buffer of capacity at least KDnsMaxMessage
+	// octets. If this cannot be allocated, cancel the reader (leave!).
+	//
+	const TUint len = aDnsMaxMessage > (TUint)KDnsMaxMessage ? aDnsMaxMessage : KDnsMaxMessage;
+	iInMsg = HBufC8::NewMaxL(len);
+	iAllocatedLength = len;
+	}
+
+CDnsSocketReader::~CDnsSocketReader()
+	{
+	ASSERT(!IsActive());
+	delete iInMsg;
+	if (IsAdded())
+		Deque();
+	LOG(Log::Printf(_L("CDnsSocketReader[%u]::~CDnsSocketReader()"), this));
+	}
+
+void CDnsSocketReader::Activate()
+	{
+	if (IsActive())
+		return;	// Do nothing, if already active!
+
+	if (iWriter.IsTCP())
+		{
+		LOG(Log::Printf(_L("CDnsSocketReader[%u]::Activate() TCP"), this));
+		// Initialize iFrom for connected socket, if not yet done.
+		// (only for debugging purposes, no other functionality at momemnt)
+		if (iFrom.IsUnspecified())
+			iWriter.Socket().RemoteName(iFrom);
+		iReadLength = 1;
+		iBuf.Set((TUint8 *)iInMsg->Ptr(), 0, 2);
+		iWriter.Socket().Read(iBuf, iStatus);
+		}
+	else
+		{
+		LOG(Log::Printf(_L("CDnsSocketReader[%u]::Activate() UDP"), this));
+		iReadLength = 0;
+		iBuf.Set(iInMsg->Des());
+		iWriter.Socket().RecvFrom(iBuf, iFrom, 0, iStatus);
+		}
+	SetActive();
+	}
+
+
+void CDnsSocketReader::RunL()
+	{
+	LOG(Log::Printf(_L("--> CDnsSocketReader[%u]::RunL() -start- iStatus=%d"), this, iStatus.Int()));
+	if (iStatus.Int())
+		{
+		LOG(Log::Printf(_L("CDnsSocketReader[%u]::RunL() error=%d"), this, iStatus.Int()));
+		if (iWriter.HandleError(iStatus.Int()) == 0)
+			{
+			// Need to re-issue previous request
+			if (iWriter.IsTCP())
+				iWriter.Socket().Read(iBuf, iStatus);
+			else
+				iWriter.Socket().RecvFrom(iBuf, iFrom, 0, iStatus);
+			LOG(Log::Printf(_L("CDnsSocketReader[%u]::RunL() soft error, restarted last read (TCP=%d)"), this, (TInt)iWriter.IsTCP()));
+			SetActive();
+			}
+		}
+	else if (iReadLength)
+		{
+		iWriter.ResetErrorCount();
+		iReadLength = 0;
+		const TUint8 *p = (TUint8 *)iInMsg->Ptr();
+		const TInt len = p[0] << 8 | p[1];
+		if (iAllocatedLength < len)
+			{
+			// Oops, the current buffer is too short for the packet.
+			delete iInMsg;
+			iAllocatedLength = len;
+			iInMsg = HBufC8::New(len);
+			}
+		if (iInMsg == NULL)
+			iWriter.DeactivateSocket(KErrNoMemory);
+		else
+			{
+			iBuf.Set((TUint8 *)iInMsg->Ptr(), 0, len);
+			iWriter.Socket().Read(iBuf, iStatus);
+			SetActive();
+			}
+		}
+	else
+		{
+		iWriter.ResetErrorCount();
+		iWriter.RunReader(TMsgBuf::Cast(iBuf), iFrom);
+		}
+	LOG(Log::Printf(_L("<-- CDnsSocketReader[%u]::RunL() -exit- iStatus=%d"), this, iStatus.Int()));
+	}
+
+void CDnsSocketReader::DoCancel()
+	{
+	LOG(Log::Printf(_L("CDnsSocketReader[%u]::DoCancel()"), this));
+	iWriter.Socket().CancelRead();
+	}
+
+// CDnsSocket
+// **********
+//
+CDnsSocket::CDnsSocket(TUint aMaxDnsMessage) : iMaxDnsMessage(aMaxDnsMessage)
+	{
+	LOG(Log::Printf(_L("CDnsSocket[%u]::CDnsSocket()"), this));
+	}
+
+void CDnsSocket::ConstructL()
+	{
+	// Allocate the primary reader/writer for UDP
+	iWriter = CDnsSocketWriter::NewL(*this, -1);
+	iWriter->iNext=NULL;
+	}
+
+CDnsSocket::~CDnsSocket()
+	{
+	DeactivateSocket(KErrCancel);
+
+	while (iWriter)
+		{
+		CDnsSocketWriter *const writer = iWriter;
+		iWriter = iWriter->iNext;
+		delete writer;
+		}
+	LOG(Log::Printf(_L("CDnsSocket[%u]::~CDnsSocket() completed"), this));
+	}
+
+RSocket &CDnsSocket::Socket()
+	{
+	return iWriter->Socket();
+	}
+
+/**
+// Open the DNS socket and start listening incoming
+// packets. The socket is bound to current "bind"
+// address and port, which default to NONE and 0.
+//
+// Does nothing, if socket is already active
+//
+// Leaves, if socket cannot be activated
+*/
+void CDnsSocket::ActivateSocketL(TUint aNetworkId)
+	{
+	LOG(Log::Printf(_L("CDnsSocket[%u]::ActivateSocketL([NetId = %d])"), this, aNetworkId));
+
+	if (iConnected && IsOpened())
+		{
+	   LOG(Log::Printf(_L("CDnsSocket[%u]::ActivateSocketL([NetId = %d]) return without action"), this, aNetworkId));
+ 	    return;        // Already connected, nothing to do
+ 	    }
+
+	User::LeaveIfError(iSS.Connect());
+	iConnected = 1;
+	iNetworkId = aNetworkId;
+
+	const TInt ret = iWriter->ActivateSocket();
+	if (ret != KErrNone)
+		{
+		DeactivateSocket(ret);
+		User::Leave(ret);
+		}
+	}
+
+/**
+// Change the current bind address and activate the
+// DNS socket. If socket is already active, the bind
+// address is set, but will only take effect after
+// deactivation and next activate.
+//
+// Does nothing, if socket is already active.
+//
+// Leaves if socket cannot be activated.
+//
+// @param	aBind	specify the address and port for
+//					received packets (also the source
+//					address and port for any sent
+//					messages).
+*/
+void CDnsSocket::ActivateSocketL(const TInetAddr &aBind)
+	{
+#ifdef _LOG
+	TBuf<50> tmp;
+	aBind.OutputWithScope(tmp);
+	Log::Printf(_L("CDnsSocket[%u]::ActivateSocketL([%S#%d])"), this, &tmp, aBind.Port());
+#endif
+	iWriter->SetBind(aBind);
+	ActivateSocketL();
+	}
+
+/**
+// Activate the TCP listening socket.
+//
+// This will automaticly cancel any previsous listens.
+//
+// Leaves if listening cannot be activated.
+//
+// @param	aBind	specify the address and port for
+//					received connections.
+// @param	aTTL	specify the TTL for accepted connections
+*/
+void CDnsSocket::ActivateListenL(const TInetAddr &aBind, TInt aTTL = -1)
+	{
+#ifdef _LOG
+	TBuf<50> tmp;
+	aBind.OutputWithScope(tmp);
+	Log::Printf(_L("CDnsSocket[%u]::ActivateListenL([%S#%d])"), this, &tmp, aBind.Port());
+#endif
+	ActivateSocketL();	// First, make sure normal socket is up and running.
+	//
+	// Abort pending listens, if any
+	//
+	CDnsSocketWriter **head = &iWriter->iNext;
+	while (*head != NULL)
+		{
+		CDnsSocketWriter *writer = *head;
+		if (writer->IsListen())
+			{
+			*head = writer->iNext;
+			// Note: IsListen() writers should never have any
+			// queued requests, so no Abort() callbacks will
+			// occur and thus, we don't need to worry about
+			// re-entries into CDnsSocket via callbacks!
+			writer->DeactivateSocket(KErrCancel);
+			delete writer;
+			}
+		else
+			head = &writer->iNext;
+		}
+
+	if (iListening)
+		iListener.Close();
+	TInetAddr bind(aBind);	// Needed only because RSocket::Bind wants non-const argument! ARRGHH!
+	User::LeaveIfError(iListener.Open(iSS, KAfInet, KSockStream, KProtocolInetTcp));
+	iListening = 1;			// Socket opened.
+	User::LeaveIfError(iListener.Bind(bind));
+	(void)iListener.SetOpt(KSoIp6UnicastHops, KSolInetIp, aTTL);
+	(void)iListener.SetOpt(KSoUserSocket, KSolInetIp, 0);
+	User::LeaveIfError(iListener.Listen(10));
+
+	//
+	// Create and append a new socket writer waiting for listen accept
+	//
+	(void)AddSecondaryWriter(CDnsSocketWriter::NewTcpListenL(*this, aTTL));
+	}
+
+/**
+// Close the socket and socket server session, if they
+// were open. Abort all queued requests with the specifiec
+// reason.
+//
+// @param aReason
+//	the abort reason that is passed to any requests which
+//	are removed from the system (see TDnsRequest::Abort)
+//					
+*/
+void CDnsSocket::DeactivateSocket(TInt aReason)
+	{
+	// Need to grab the list away, because
+	// re-activation might occur via callbacks.
+	//
+	CDnsSocketWriter *writer = iWriter->iNext;
+	iWriter->iNext = NULL;
+
+	iWriter->DeactivateSocket(aReason);
+	while (writer)
+		{
+		CDnsSocketWriter *tmp = writer;
+		writer = tmp->iNext;
+		tmp->DeactivateSocket(aReason);
+		delete tmp;
+		}
+	// Oops... Should not close if re-activated ---FIX!
+	if (iListening)
+		{
+		iListening = 0;
+		iListener.Close();
+		}
+
+	// Oops... Should not close if re-activated ---FIX!
+	if (iConnected)
+		{
+		iConnected = 0;
+		iSS.Close();
+		}
+	}
+
+void CDnsSocket::SetHoplimit(const TInt aTTL)
+	/**
+	* Set TTL for for transmitted packets.
+	*
+	* The socket must be activated (open) when this is called. The set TTL
+	* is used as is for both unicast and multicast. The value -1 selects
+	* the system defaults.
+	*
+	* The set TTL will remain in effect for the primary writer until
+	* changed again.
+	* 
+	* @param	aTTL	The TTL
+	*/
+	{
+	iWriter->SetHoplimit(aTTL);
+	}
+
+/**
+// Queue a request for sending. The request may get following
+// "callbacks":
+// @li	TDnsRequest::Build,
+//			just before a request is ready to be sent, build
+//			the outgoing packet into specified message buffer
+// @li	TDnsRequest::Sent,
+//			the packet has been sent to the interface
+// @li	TDnsRequest::Reply,
+//			a DNS reply packet matching the request id has
+//			been received. Need to test whether rest of the
+//			packet matches the request, and if so, handle
+//			it.
+// @li	TDnsRequest::Abort,
+//			request is being aborted (usually DNS socket
+//			is being deactivated).
+//
+// @param aRequest	the request to be queued
+// @param aId		the request id
+//	@li	-1 (< 0),
+//		the default if parameter is omitted. The queue
+//		method will assign random id automatically.
+//	@li >= 0,
+//		16 bits of this value is used as id.		
+*/
+void CDnsSocket::Queue(TDnsRequest &aRequest, const TInt aId)
+	{
+	iWriter->Queue(aRequest, aId);
+	}
+
+
+// Queue a request for sending with a specific socket
+//
+TInt CDnsSocket::Queue(TDnsRequest &aRequest, const RSocket &aSocket, const TInt aId)
+	{
+	for (CDnsSocketWriter *writer = iWriter; writer != NULL; writer = writer->iNext)
+		{
+		if (&aSocket == &writer->Socket())
+			{
+			// Found it!
+			writer->Queue(aRequest, aId);
+			return KErrNone;
+			}
+		}
+	return KErrNotFound;
+	}
+
+
+/**
+// Queue a request for sending with TCP.
+//
+// @param aRequest to be queued
+// @param aServer The address and port of the DNS server
+// @param aId of the request, if >= 0. If < 0, then a new random ID is generated
+// @param aTTL of the connection (= -1, the default, requests the system default). This is
+// only effective if the connection is created.
+//
+// @return KErrNone, if queued successfully, or error code if failed.
+*/
+TInt CDnsSocket::Queue(TDnsRequest &aRequest, const TInetAddr &aServer, const TInt aId,  const TInt aTTL)
+	{
+	//
+	// Locate or create connected Socket reader/writer instance
+	//
+	CDnsSocketWriter *writer = iWriter->iNext;
+	while (writer != NULL)
+		{
+		if (writer->Match(aServer))
+			{
+			// A writer already exists
+			writer->Queue(aRequest, aId);
+			return KErrNone;
+			}
+		else
+		    {
+            //iWriter = iWriter->iNext;
+            writer = writer->iNext;
+            //do we need to return?
+		    }
+		}
+	//
+	// Create and append a new connected socket writer
+	//
+	TRAPD(err, writer = CDnsSocketWriter::NewTcpL(*this, aServer, aTTL));
+	if (writer)
+		{
+		err = AddSecondaryWriter(writer);
+		if (err == KErrNone)
+			writer->Queue(aRequest, aId);
+		else
+			DeleteWriter(writer, err);
+		}
+	return err;
+	}
+
+/**
+// Abort whatever the request is currently doing and reque
+// it for new send (eventually, a call to DnsRequest::Build
+// should happen). This preserves the old id of the request.
+//
+// If a request is not currently queued, this does an implicit
+// Queue. (a new id is generated).
+//
+// @param aRequest	the request to be resent.
+*/
+void CDnsSocket::ReSend(TDnsRequest &aRequest)
+	{
+	Queue(aRequest, aRequest.IsQueued() ? aRequest.Id() : -1);
+	}
+
+/**
+// Add and activate a new secondary writer/reader unit.
+//
+// Insert a newly created and constructed reader/writer unit
+// to the system and activate it. The secondearies are inserted
+// into the iWriter chaing after the first primary unit, which
+// always exists, as long as CDnsSocket exists.
+//
+// @param aWriter	The reader/writer instance
+//
+// @return KErrNone, if succesfully activated, and an error code otherwise
+*/
+TInt CDnsSocket::AddSecondaryWriter(CDnsSocketWriter *aWriter)
+	{
+	ASSERT(iWriter != NULL);		// Primary must always exist!
+	ASSERT(aWriter != NULL);		// Silly caller, program error
+	if (aWriter == NULL)			// Test again (for release version)
+		return KErrArgument;		// Should really not happen!
+	ASSERT(aWriter->iNext == NULL);	// The new writer should be just created
+
+	// Insert the new unit after the primary reader/writer, and
+	// before all previous secondary units (as the placement in
+	// chain should not matter--this is just simplest to do).
+	aWriter->iNext = iWriter->iNext;
+	iWriter->iNext = aWriter;
+	return aWriter->ActivateSocket();
+	}
+
+/**
+// Deactivate and delete a writer instance.
+//
+// Deactivate the writer, remove it from the list of writers
+// (if present), and delete it.
+//
+// @param aWriter	The reader/writer to be deleted
+// @param aReason	The reason (passed to any requests that are aborted because of this)
+*/
+void CDnsSocket::DeleteWriter(CDnsSocketWriter *aWriter, TInt aReason)
+	{
+	// Allow call with NULL, as normal delete does
+	if (aWriter == NULL)
+		return;
+
+	// Primary writer must not be deleted with this function!
+	ASSERT(aWriter != iWriter);
+	if (aWriter != iWriter)
+		return;
+
+	// Remove instance from the writer chain (allow
+	// case where the aWriter is not in the chain!)
+
+	CDnsSocketWriter **head = &iWriter->iNext;
+	while (*head != NULL)
+		{
+		CDnsSocketWriter *const writer = *head;
+		if (writer == aWriter)
+			{
+			*head = writer->iNext;
+			break;
+			}
+		else
+			head = &writer->iNext;
+		}
+
+	// Note: Deactivate call may cause the CDnsSocket to be deleted,
+	// thus it is important that this no longer references it and
+	// that the writer has already been removed from the list before
+	// this!
+	aWriter->DeactivateSocket(aReason);
+	delete aWriter;	// a detached instance can now be deleted
+	}
+
+
+TBool CDnsSocket::IsOpened() const
+	{
+	return iWriter ? iWriter->IsOpened() : EFalse;
+	}
+
+TInt64 CDnsSocketWriter::SeedIdGenerator(TInt64 aSequence)
+/*
+* Function to generate seed for which will be passed to generate another level of sequence number
+* The requirement came due the fact that microsoft DNS sequence where gussed. 
+* Seed generation is divided into two levels of generation. 
+*/
+	{
+	TInt64 operand = Math::Random() % 5;
+
+	//Generation of random number secure ID which should be mathematically operated with the 
+	//Seed. The generation will make guess difficult. Secure ID should not be negative so there is
+	//an extra check done to make it positive number.
+	TInt64 secureId;	
+	secureId = Math::Random();
+	if(secureId < 0)
+	secureId = secureId * (KNegativeNumberMask);
+
+	switch(operand)
+		{
+		case 1:
+		return (secureId + aSequence);
+						
+		case 2:
+		return (aSequence - secureId);
+		
+ 		default:
+		return (secureId * aSequence);
+			
+		};//end of switch
+	}//end of function