wapstack/wapmessageapi/sws/ActiveSocket.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 18 Aug 2010 10:57:47 +0300
changeset 62 8ef833fbf5aa
parent 49 f50f4094acd7
permissions -rw-r--r--
Revision: 201033 Kit: 201033

// Copyright (c) 2003-2010 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:
//
#include "OstTraceDefinitions.h"
#ifdef OST_TRACE_COMPILER_IN_USE
#include "ActiveSocketTraces.h"
#endif

#include "ActiveSocket.h"
#include <es_wsms.h>
#include "CLWSPPduHandler.h"
#include "wapmsgerr.h"
#include <wap_sock.h>
#include "WapMessageApiAgent.h"
#include "WapMsgUtils.h"

using namespace Wap;

void CActiveSocket::NewL(RSocketServ& aSocketServ, RPointerArray<CActiveSocket>& aActiveSockets, Wap::TBearer aBearer, TWapMessageType aType, MProgressNotify* aNotify, Wap::TPort aLocalPort, RConnection* aConnection)
/**
The static new function instanciates corresponding Bearers in terms of the input bearer type.
This function is used by Bound Wap APIs which listen the incoming packet to a specific port. 
@internalComponent
@released
@since v8.0
@param aSocketServ the shared RSocketServ instance used in the Wap messaging API which owns this bearer
@param aActiveSockets the bearer array used in the Wap messaging API which owns the bearer
@param aBearer  the bearer to listen on (use EAll for all bearers)
@param aType  the type of the wap message that will received
@param aNotify  the instance to be notified when a wap message is received
@param aLocalPort  the port to listen on
@param aConnection the shared connection from Wap messaging API client
*/
	{
	//Instanciate the corresponding
	switch(aBearer)
		{
		case Wap::ESMS7:
		case Wap::ESMS:
		case Wap::EWAPSMS7:
		case Wap::EWAPSMS:
			{
			CActiveSocket* me = new(ELeave) CActiveSocketSMS(aSocketServ, aNotify, aBearer, aLocalPort);
			CleanupStack::PushL(me);
			me->ConstructL(aType);
			aActiveSockets.AppendL(me);
			CleanupStack::Pop(me);
			break;
			}
		case Wap::EIP:
			{
			CActiveSocket* me = new(ELeave) CActiveSocketUDP(aSocketServ, aNotify, aBearer, aLocalPort, aConnection);
			CleanupStack::PushL(me);
			me->ConstructL(aType);
			aActiveSockets.AppendL(me);
			CleanupStack::Pop(me);
			break;
			}
		case Wap::EAll:
			{
			CActiveSocket* me = new(ELeave) CActiveSocketUDP(aSocketServ, aNotify, Wap::EIP, aLocalPort, aConnection);
			CleanupStack::PushL(me);
			me->ConstructL(aType);          
			CActiveSocket* me1 = new(ELeave) CActiveSocketSMS(aSocketServ, aNotify, Wap::ESMS, aLocalPort);
			CleanupStack::PushL(me1);
			me1->ConstructL(aType);
			aActiveSockets.ReserveL(2); // pre-allocate the memory                                           
			aActiveSockets.AppendL(me1);
			CleanupStack::Pop(me1);
			aActiveSockets.AppendL(me);
			CleanupStack::Pop(me);
			break;
			}
		default:
		    {
            OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_INTERNALS, CACTIVESOCKET_NEWL_1, "CActiveSocket::NewL Unknown Bearer Type");
			User::Leave(Wap::EBearerError);
		    }
		}
	}

void CActiveSocket::NewL(RSocketServ& aSocketServ, RPointerArray<CActiveSocket>& aActiveSockets, Wap::TBearer aBearer, TWapMessageType aType, MProgressNotify* aNotify, const TSockAddr& aRemoteAddr, RConnection* aConnection)
/**
The static new function instanciates corresponding Bearers in terms of the input bearer type.
This function is used by Fully specified Wap APIs which will open a socket with a single, named remote host. 
@internalComponent
@released
@since v8.0
@param aSocketServ the shared RSocketServ instance used in the Wap messaging API which owns this bearer
@param aActiveSockets the bearer array used in the Wap messaging API which owns the bearer
@param aBearer the bearer to listen on (use EAll for all bearers)
@param aType the type of the wap message that will received
@param aNotify the instance to be notified when a wap message is received
@param aRemoteAddr the remote host to be communicate with
@param aConnection the shared connection from Wap messaging API client
*/
	{
	//Instanciate the corresponding
	switch(aBearer)
		{
		case Wap::ESMS7:
		case Wap::ESMS:
		case Wap::EWAPSMS7:
		case Wap::EWAPSMS:
			{
			CActiveSocket* me = new(ELeave) CActiveSocketSMS(aSocketServ, aNotify, aBearer, aRemoteAddr);
			CleanupStack::PushL(me);
			me->ConstructL(aType);
            aActiveSockets.AppendL(me);
			CleanupStack::Pop(me);
			break;
			}
		case Wap::EIP:
			{
			CActiveSocket* me = new(ELeave) CActiveSocketUDP(aSocketServ, aNotify, aBearer, aRemoteAddr, aConnection);
			CleanupStack::PushL(me);
			me->ConstructL(aType);
            aActiveSockets.AppendL(me);
			CleanupStack::Pop(me);
			break;
			}
		case Wap::EAll:
			{
			CActiveSocket* me = new(ELeave) CActiveSocketUDP(aSocketServ, aNotify, aBearer, aRemoteAddr, aConnection);
			CleanupStack::PushL(me);
			me->ConstructL(aType);
			CActiveSocket* me1 = new(ELeave) CActiveSocketSMS(aSocketServ, aNotify, aBearer, aRemoteAddr);
			CleanupStack::PushL(me1);
			me1->ConstructL(aType);
            aActiveSockets.ReserveL(2); // pre-allocate the memory    
			aActiveSockets.AppendL(me1);
            CleanupStack::Pop(me1);
            aActiveSockets.AppendL(me);
            CleanupStack::Pop(me);
			break;
			}
		default:
		    {
		    OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_INTERNALS, CACTIVESOCKET_NEWL_1_1, "CActiveSocket::NewL Unknown Bearer Type");
			User::Leave(Wap::EBearerError);
		    }
		}
	}

CActiveSocket::CActiveSocket(RSocketServ& aSocketServ, Wap::TBearer aBearerType, MProgressNotify* aNotify, Wap::TPort aLocalPort)
:CActive(EPriorityStandard), iLocalAddr(0), iSocketServ(aSocketServ), iBearerType(aBearerType), iLocalPort(aLocalPort), iSocketState(ESocketIdle),iNotify(aNotify), iBuf(0,0), iRxlength(0), iBufCon(0,0)
/**
Constructor of bearer base class for Bound Wap APIs
@internalComponent
@released
@since v8.0
*/
	{
	CActiveScheduler::Add(this);
	}

CActiveSocket::CActiveSocket(RSocketServ& aSocketServ, Wap::TBearer aBearerType, MProgressNotify* aNotify, const TSockAddr& aRemoteAddr, Wap::TPort aLocalPort): CActive(EPriorityStandard), 
iRemoteAddr(aRemoteAddr), iLocalAddr(0), iSocketServ(aSocketServ), iBearerType(aBearerType), iLocalPort(aLocalPort), iSocketState(ESocketIdle), iNotify(aNotify), iBuf(0,0), iRxlength(0), iBufCon(0,0)
/**
Constructor of bearer base class for fully specified Wap APIs
@internalComponent
@released
@since v8.0
*/
	{
	CActiveScheduler::Add(this);
	}

CActiveSocket::~CActiveSocket()
/**
Destructor
@internalComponent
@released
@since v8.0
*/
	{
	Cancel();
	iSocket.Close();
	if (iMessageRecord) 
		{
		delete iMessageRecord;
		}
	}

void CActiveSocket::ConstructL(TWapMessageType aType)
/**
Second Phase Constructor
@internalComponent
@released
@param aType the type of Wap message which is received. 
@since v8.0
*/
	{
	iMessageRecord=CWapMessageRecord::NewL(aType);
	}

RSocket& CActiveSocket::Socket()
/**
To get the RSocket instance ownd by this bearer
@internalComponent
@released
@since v8.0
@returns the reference of the RSocket instance.
*/
	{
	return iSocket;
	}

Wap::TBearer CActiveSocket::GetBearerType()
/**
To get the bearer type of this bearer
@internalComponent
@released
@since v8.0
@returns the bearer type
*/
	{
	return iBearerType;
	}

TSockAddr& CActiveSocket::GetLocalAddress()
/**
To get the local address of this bearer
@internalComponent
@released
@since v8.0
@returns the lcoal address instance
*/
	{
	iSocket.LocalName(iLocalAddr);
	return iLocalAddr;
	}

TSockAddr& CActiveSocket::GetRemoteAddress()
/**
To get the remote address of the last received packet
@internalComponent
@released
@since v8.0
@returns the remote address instance
*/
	{
	return iRemoteAddr;
	}

TInt CActiveSocket::GetRemoteAddress(HBufC8*& aAddr)
/**
To get the remote address of the last received packet
@internalComponent
@released
@since v8.0
@param aAddr the remote host name
@returns KErrNone on successful completion, or one of the system error codes on failure.
*/
	{
	TRAPD(err, aAddr=iRemoteAddr.AllocL())
	if (err==KErrNone)
		{
		Wap::TPort port;
		TPtr8 des=aAddr->Des();
		TRAP(err, CSWSWapMsgUtils::AnalyseAddrL(iRemoteAddr, iBearerType, des, port))
		}
	else
		{
        OstTraceDef1(OST_TRACE_CATEGORY_DEBUG, TRACE_INTERNALS, CACTIVESOCKET_GETREMOTEADDRESS_1, "CActiveSocket::GetRemoteAddress: Alloc Memory Err=%d", err);
		}
	return err;
	}

TInt CActiveSocket::GetLocalPort(Wap::TPort& aLocalPort)
/**
To get the lcoal port of this bearer
@internalComponent
@released
@since v8.0
@param aLocalPort the local port of this bearer
@returns KErrNone on successful completion, or one of the system error codes on failure.
*/
	{
	GetLocalAddress();
	aLocalPort=Wap::TPort(iLocalAddr.Port());
	return KErrNone;
	}

TUint32 CActiveSocket::GetPduSize()
/**
To get the received Wdp Pdu length
@internalComponent
@released
@since v8.0
@returns the length of the received Wdp pdu.
*/
	{
	return iMessageRecord->GetPduSize();
	}

TWapMessageState CActiveSocket::GetDataState()
/**
To get the state of the data that is being received
@internalComponent
@released
@since v8.0
@returns the state of the data that is being received
*/
	{
	return iMessageRecord->GetDataState();
	}

void CActiveSocket::SetDataState(TWapMessageState aState)
/**
To set the state of the data that is being received
@internalComponent
@released
@since v8.0
@param aState the state of the data that is being received
*/
	{
	iMessageRecord->SetDataState(aState);
	}

TInt CActiveSocket::GetPduData(TDes8& aBuffer, TBool& aTruncated)
/**
To get the received Wdp pdu.
@internalComponent
@released
@since v8.0
@param aBuffer the buffer to read the received WDP pdu
@param aTruncated the flag to represent if the data has be truncated or not
@returns KErrNone on successful completion, or one of the system error codes on failure.
*/
	{
	return iMessageRecord->GetPduData(aBuffer, aTruncated);
	}

TInt CActiveSocket::GetWspData(TDes8& aWspHeader, TDes8& aWspBody, TUint8& aTransactionId, TWSPStatus& aStatus)
/**
To get the received Wsp header, body, tranaction ID and Wsp status.
@internalComponent
@released
@since v8.0
@param aWspHeader the buffer to read the received Wsp header
@param aWspBody the buffer to read the received Wsp body
@param aTransactionId the transaction ID of the received Wsp Message
@param aStatus the Wsp status of  the received Wsp Message
@returns KErrNone on successful completion, or one of the system error codes on failure.
*/
	{
	return iMessageRecord->GetWspData(aWspHeader, aWspBody, aTransactionId, aStatus);
	}
void CActiveSocket::UnpackPduToWspDataL()
/**
To extract the Wsp header, body, transaction ID and status from the received WDP pdu
@internalComponent
@released
@since v8.0
*/
	{
	iMessageRecord->UnpackPduToWspDataL();
	}

void CActiveSocket::CleanUpData()
	{
	TPtr8 zero(0,0);
	iBuf.Set(zero);
	iBufCon.Set(zero);
	iMessageRecord->CleanUpData();
	}

/** SMS active socket
*/
CActiveSocketSMS::CActiveSocketSMS(RSocketServ& aSocketServ, MProgressNotify* aNotify, Wap::TBearer aBearer, Wap::TPort aLocalPort)
:CActiveSocket(aSocketServ, aBearer, aNotify, aLocalPort)
/**
Constructor of SMS bearer for Bound Wap APIs
@internalComponent
@released
@since v8.0
*/
	{
	}

CActiveSocketSMS::CActiveSocketSMS(RSocketServ& aSocketServ, MProgressNotify* aNotify, Wap::TBearer aBearer, const TSockAddr& aRemoteAddr)
:CActiveSocket(aSocketServ, aBearer, aNotify, aRemoteAddr, (Wap::TPort)EWapPortUnspecified)
/**
Constructor of SMS bearer for fully specified Wap APIs
@internalComponent
@released
@since v8.0
*/
	{
	}

CActiveSocketSMS::~CActiveSocketSMS() 
/**
Destructor of SMS bearer for fully specified Wap APIs
@internalComponent
@released
@since v8.0
*/
	{
	}

void CActiveSocketSMS::ConstructL(TWapMessageType aType)
/**
Second Phase Constructor
@internalComponent
@released
@param aType the type of Wap message which is received.
@since v8.0
*/
	{
	CActiveSocket::ConstructL(aType);
	User::LeaveIfError(iSocket.Open(iSocketServ, KWAPSMSAddrFamily, KSockDatagram, KWAPSMSDatagramProtocol));
	User::LeaveIfError(iSocket.SetOpt(KWapSmsOptionNewStyleClient,KWapSmsOptionLevel, 0));
	TWapAddr wapAddr;
	wapAddr.SetWapPort(TWapPortNumber(iLocalPort));
	TInt err=iSocket.Bind(wapAddr);
	if (err==KErrInUse)
		{
		User::Leave(Wap::EPortAlreadyBound);
		}
	}

TInt CActiveSocketSMS::AwaitRecvDataSize()
/**
Read the received Wdp pdu length.
@internalComponent
@released
@since v8.0
@returns KErrNone on successful completion, or one of the system error codes on failure.
*/
	{
	TPckgBuf<TUint32>* length=iMessageRecord->GetPduSizeRef();
	iSocket.Ioctl(KSOGetLength, iStatus, length, KSolWapProv);
	iMessageRecord->SetDataState(ERequestingLength);
	iSocketState=ESocketWaitingForLength;
	SetActive();
	return KErrNone;
	}

TInt CActiveSocketSMS::Receive()
/**
Read the received Wdp pdu.
@internalComponent
@released
@since v8.0
@returns KErrNone on successful completion, or one of the system error codes on failure.
*/
	{
	TInt err=KErrNone;
	TRAP(err, iMessageRecord->CreatePduBufferL(EFalse))
	if (err!=KErrNone)
		{
		return err;
		}
	HBufC8*& pdu=iMessageRecord->GetPduPtr();
	iBuf.Set(pdu->Des());
	iSocket.RecvFrom(iBuf, iRemoteAddr, 0, iStatus);
	iMessageRecord->SetDataState(ERequestingData);
	iSocketState=ESocketWaitingForData;
	SetActive();
	return KErrNone;
	}

void CActiveSocketSMS::RunL() 
/**
Overload the CActive virtual methods
@internalComponent
@released
@since v8.0
*/
	{
	switch (iSocketState)
		{
	case ESocketWaitingForLength:
			{
			OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_INTERNALS, CACTIVESOCKETSMS_RUNL_1, "CActiveSocketSMS::RunL() ESocketWaitingForLength");
			iMessageRecord->SetDataState(EPendingLength);
			iSocketState=ESocketIdle;
			TWapNotificationInfo info(iBearerType, iStatus.Int());
			TWapNotificationInfoBuf infoBuf(info);
			iNotify->Notification(EPduLengthReceived, infoBuf);
			break;
			}
	case ESocketWaitingForData:
			{
			OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_INTERNALS, CACTIVESOCKETSMS_RUNL_2, "CActiveSocketSMS::RunL() ESocketWaitingForData");
			iMessageRecord->SetDataState(EPendingData);
			iSocketState=ESocketIdle;
			TWapNotificationInfo info(iBearerType, iStatus.Int());
			TWapNotificationInfoBuf infoBuf(info);
			iNotify->Notification(EPduReceived, infoBuf);
			iSocket.SetOpt(KWapSmsOptionOKToDeleteMessage,KWapSmsOptionLevel, 0);
			break;
			}
	default:
	    OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_INTERNALS, CACTIVESOCKETSMS_RUNL_3, "CActiveSocketSMS::RunL() Unknown State");
		}
	}
void CActiveSocketSMS::DoCancel() 
/**
Overload the CActive virtual methods
@internalComponent
@released
@since v8.0
*/
	{
	switch (iSocketState)
		{
	case ESocketWaitingForLength:
			{
			iSocket.CancelIoctl();
			break;
			}
	case ESocketWaitingForData:
			{
			iSocket.CancelRecv();
			break;
			}
	default:
	    OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_INTERNALS, CACTIVESOCKETSMS_DOCANCEL_1, "CActiveSocketSMS::DoCancel() Unknown State");	
		}
	}

//
// UDP active socket
//
CActiveSocketUDP::CActiveSocketUDP(RSocketServ& aSocketServ, MProgressNotify* aNotify, Wap::TBearer aBearer, Wap::TPort aLocalPort, RConnection* aConnection)
:CActiveSocket(aSocketServ, aBearer, aNotify, aLocalPort),iConnection(aConnection)
/**
Constructor for Bound Wap APIs
@internalComponent
@released
@since v8.0
*/
	{
	}
	
CActiveSocketUDP::CActiveSocketUDP(RSocketServ& aSocketServ, MProgressNotify* aNotify, Wap::TBearer aBearer, const TSockAddr& aRemoteAddr, RConnection* aConnection)
:CActiveSocket(aSocketServ, aBearer, aNotify, aRemoteAddr,0), iConnection(aConnection)
/**
Constructor for FullySpec Wap APIs
@internalComponent
@released
@since v8.0
*/
	{
	}

void CActiveSocketUDP::ConstructL(TWapMessageType aType)
/**
Second Phase constructor
@internalComponent
@released
@since v8.0
*/
	{
	CActiveSocket::ConstructL(aType);
	if (!iConnection)
		{
		User::LeaveIfError(iSocket.Open(iSocketServ, KAfInet, KSockDatagram, KProtocolInetUdp));
		}
	else
		{
		User::LeaveIfError(iSocket.Open(iSocketServ, KAfInet, KSockDatagram, KProtocolInetUdp, *iConnection));
		}
	TInetAddr inetAddr(iLocalPort);
	TInt err=iSocket.Bind(inetAddr);
	if (err==KErrInUse)
		{
		User::Leave(Wap::EPortAlreadyBound);
		}
	}

CActiveSocketUDP::~CActiveSocketUDP() 
/**
Destructor
@internalComponent
@released
@since v8.0
*/
	{
	}

TInt CActiveSocketUDP::AwaitRecvDataSize()
/**
Wait for Pdu data size
@internalComponent
@released
@since v8.0
*/
	{
	iRxlength=0;
	TRAPD(err, iMessageRecord->CreatePduBufferL(ETrue))
	if (err!=KErrNone)
		{
		return err;
		}
	HBufC8*& pdu=iMessageRecord->GetPduPtr();
	iBuf.Set(pdu->Des());
	iSocket.RecvFrom(iBuf, iRemoteAddr, 0, iStatus, iRxlength);
	iMessageRecord->SetDataState(ERequestingLength);
	iSocketState=ESocketWaitingForLength;
	SetActive();
	return KErrNone;	
	}

TInt CActiveSocketUDP::Receive()
/**
Receive the pdu
@internalComponent
@released
@since v8.0
*/
	{
	if(iMessageRecord->GetDataState()==EContinuous)
		{
		TRAPD(err, iMessageRecord->CreatePduBufferL(ETrue))
		if (err!=KErrNone)
			{
			return err;
			}
		HBufC8*& pdu=iMessageRecord->GetPduPtr();
		iBuf.Set(pdu->Des());
		iBuf.SetLength(iBuf.Length()+1);
		iBufCon.Set(&iBuf[iBuf.Length()-1],0,iBuf.MaxLength()-iBuf.Length());
		iBuf.SetLength(iBuf.Length()+iRxlength()-1);
		iSocket.RecvFrom(iBufCon, iRemoteAddr, KSockReadContinuation, iStatus,iRxlength);
		iMessageRecord->SetDataState(ERequestingData);
		iSocketState=ESocketWaitingForData;
		SetActive();	
		}
	else
		{
		iMessageRecord->SetDataState(ERequestingData);
		iSocketState=ESocketWaitingForData;
		iStatus = KRequestPending;
		SetActive();
		TRequestStatus* reqStatus=&iStatus;
		User::RequestComplete(reqStatus, KErrNone);
		}
	return KErrNone;
	}

void CActiveSocketUDP::RunL()
/**
RunL()
@internalComponent
@released
@since v8.0
*/
	{
	switch (iSocketState)
		{
	case ESocketWaitingForLength:
			{
			OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_INTERNALS, CACTIVESOCKETUDP_RUNL_1, "CActiveSocketUDP::RunL() ESocketWaitingForLength");        
			iMessageRecord->SetPduSize(iBuf.Length()+ iRxlength());
			if(iRxlength() > 0)
				{
				iMessageRecord->SetDataState(EContinuous);
				}
			else 
				{
				iMessageRecord->SetDataState(EPendingLength);
				}
			iSocketState=ESocketIdle;
			TWapNotificationInfo info(iBearerType, iStatus.Int());
			TWapNotificationInfoBuf infoBuf(info);
			iNotify->Notification(EPduLengthReceived, infoBuf);
			break;
			}
	case ESocketWaitingForData:
			{
			OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_INTERNALS, CACTIVESOCKETUDP_RUNL_2, "CActiveSocketUDP::RunL() ESocketWaitingForData");
			iMessageRecord->SetDataState(EPendingData);
			iSocketState=ESocketIdle;
			TWapNotificationInfo info(iBearerType, iStatus.Int());
			TWapNotificationInfoBuf infoBuf(info);
			iNotify->Notification(EPduReceived, infoBuf);
			break;
			}
	default:
	    OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_INTERNALS, CACTIVESOCKETUDP_RUNL_3, "CActiveSocketUDP::RunL() Unknown State");
		break;
		}
	}

void CActiveSocketUDP::DoCancel()
/**
Cancel the outstanding request on UDP bearer
@internalComponent
@released
@since v8.0
*/
	{
	switch (iSocketState)
		{
	case ESocketWaitingForLength:
			{
			iSocket.CancelRecv();
			break;
			}
	case ESocketWaitingForData:
			{
			break;
			}
	default:
	    OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_INTERNALS, CACTIVESOCKETUDP_DOCANCEL_1, "CActiveSocketUDP::DoCancel() Unknown State");	
		}
	}

//
//CWapMessageRecord
//
CWapMessageRecord* CWapMessageRecord::NewL(TWapMessageType aType)
/**
The static funtion to instanciate the Pdu data record
@internalComponent
@released
@since v8.0
@param aType the type of Wap message which is received.
@returns the data record instance.
*/
	{
	CWapMessageRecord* me;
	if (aType==EWapWsp)
		{
		me = new(ELeave) CWspMessageRecord();
		}
	else
		{
		me = new(ELeave) CWdpMessageRecord();
		}
	return me;
	}

CWapMessageRecord::CWapMessageRecord()
/**
Constructor
@internalComponent
@released
@since v8.0
*/
	{
	}

CWapMessageRecord::~CWapMessageRecord()
/**
Destructor
@internalComponent
@released
@since v8.0
*/
	{
	if (iPdu)
		{
		delete iPdu;
		}
	}

TWapMessageState CWapMessageRecord::GetDataState()
/**
To get the state of the data that is being received
@internalComponent
@released
@since v8.0
returns the state of the data that is being received
*/
	{
	return iState;
	}

void CWapMessageRecord::SetDataState(TWapMessageState aState)
/**
To set the state of the data that is being received
@internalComponent
@released
@since v8.0
@param the state of the data that is being received
*/
	{
	iState=aState;
	}

TPckgBuf<TUint32>* CWapMessageRecord::GetPduSizeRef()
/**
To get the buffer which is used to contain the received data length
@internalComponent
@released
@since v8.0
@returns the pointer to the buffer length
*/
	{
	return &iDataLength;
	}

void CWapMessageRecord::SetPduSize(TUint32 aLength)
	{
	iDataLength=aLength;
	}

TUint32 CWapMessageRecord::GetPduSize()
/**
To get the received wdp pdu length
@internalComponent
@released
@since v8.0
@returns the received wdp pdu length
*/
	{
	iState=EGotLength;
	return iDataLength();
	}

HBufC8*& CWapMessageRecord::GetPduPtr()
/**
To get the received wdp pdu.
@internalComponent
@released
@since v8.0
@returns the pointer the received wdp buffer
*/
	{
	return iPdu;
	}

void CWapMessageRecord::CreatePduBufferL(TBool aFixLengthFlag)
/**
create the wdp pdu buffer according to the length
@internalComponent
@released
@since v8.0
*/
	{
	if (iState==EContinuous)
		{
		iPdu = iPdu->ReAllocL(iDataLength());
		}
	else if (!aFixLengthFlag)
		{
		iPdu=HBufC8::NewL(iDataLength());
		}
	else
		{
		iPdu=HBufC8::NewL(KMaxUdpBearerDataBufferLength);
		}
	}

void CWapMessageRecord::CleanUpData()
/**
clean up the receive buffer.
@internalComponent
@released
@since v8.0
*/
	{
	if (iPdu)
		{
		delete iPdu;
		iPdu=NULL;
		}
	iDataLength.FillZ();
	iState=EIdle;
	}

//
//CWspMessageRecord methods
//
CWspMessageRecord::CWspMessageRecord()
/**
Constructor
@internalComponent
@released
@since v8.0
*/
	{
	}

CWspMessageRecord::~CWspMessageRecord()
/**
Destructor
@internalComponent
@released
@since v8.0
*/
	{
	if (iWspHeader)
		{
		delete iWspHeader;
		}
	if (iWspBody)
		{
		delete iWspBody;
		}
	}

void CWspMessageRecord::UnpackPduToWspDataL()
/**
To unpack the received wdp pdu to wsp message.
@internalComponent
@released
@since v8.0
*/
	{
	TWSPPduType type;
	CCLWSPPduHandler::UnpackWSPPduL(iPdu, type, iWspHeader, iWspBody, iTransactionId, iWspStatus);
	}

TInt CWspMessageRecord::GetWspData(TDes8& aWspHeader, TDes8& aWspBody, TUint8& aTransactionId, TWSPStatus& aWspStatus)
/**
To read the wsp message from the buffer
@internalComponent
@released
@since v8.0
@param aWspHeader the buffer to contain the wsp header
@param aWspBody the buffer to contain the wsp body
@param iTransactionId the received transaction ID
@param aWspStatus the received wsp status
@returns KErrNone on successful completion, or one of the system error codes on failure.
*/
	{
	if (!iWspHeader && !iWspBody)
		{
		// if no data, should not be here at all
        OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_INTERNALS, CWSPMESSAGERECORD_GETWSPDATA_1, "CWspMessageRecord::GetWspData() No Data Available");
		CleanUpData();
		return KErrBadDescriptor;
		}
	TInt ret=KErrNone;
	//Copy the transaction ID
	aTransactionId=iTransactionId;
	aWspStatus=iWspStatus;
	//Copy the header
	TInt bufferLength;
	if (iWspHeader)
		{
		bufferLength=aWspHeader.MaxLength();
		TPtrC8 remainHeader=iWspHeader->Mid(iHeaderOffset);
		//Client Header buffer is not long enough
		if (bufferLength<remainHeader.Length())
			{
			aWspHeader.Copy(remainHeader.Ptr(), bufferLength);
			iHeaderOffset+=bufferLength;
			iState=EReading;
			ret=Wap::EMoreData;
			}
		else
			{
			aWspHeader.Copy(remainHeader);
			iHeaderOffset=0;
			delete iWspHeader;
			iWspHeader=NULL;
			}
		}
	if (iWspBody)
		{
		//Copy the Body
		bufferLength=aWspBody.MaxLength();
		TPtrC8 remainBody=iWspBody->Mid(iBodyOffset);

		//Client Header buffer is not long enough
		if (bufferLength<remainBody.Length())
			{
			aWspBody.Copy(remainBody.Ptr(), bufferLength);
			iBodyOffset+=bufferLength;
			iState=EReading;
			ret=Wap::EMoreData;
			}
		else
			{
			aWspBody.Copy(remainBody);
			iBodyOffset=0;
			delete iWspBody;
			iWspBody=NULL;
			}
		}
	//All Wsp Data has been read.
	if (ret==KErrNone)
		{
		delete iPdu;
		iPdu=NULL;
		iDataLength.FillZ();
		iState=EIdle;
		}
	return ret;
	}

TInt CWspMessageRecord::GetPduData(TDes8& /*aBuffer*/, TBool& /*aTruncated*/)
/**
Not supported
@internalComponent
@released
@since v8.0
*/
	{//Should not be used
	return KErrNotSupported;
	}

void CWspMessageRecord::CleanUpData()
/**
To clean up the wsp related data
@internalComponent
@released
@since v8.0
*/
	{
	CWapMessageRecord::CleanUpData();
	if (iWspHeader)
		{
		delete iWspHeader;
		iWspHeader=NULL;
		}
	if (iWspBody)
		{
		delete iWspBody;
		iWspBody=NULL;
		}
	iTransactionId=0;
	iHeaderOffset=0;
	iBodyOffset=0;
	}
//
//CWspMessageRecord method
//
CWdpMessageRecord::CWdpMessageRecord()
/**
Constructor
@internalComponent
@released
@since v8.0
*/
	{
	}

CWdpMessageRecord::~CWdpMessageRecord()
/**
Destructor
@internalComponent
@released
@since v8.0
*/
	{
	}

TInt CWdpMessageRecord::GetPduData(TDes8& aBuffer, TBool& aTruncated)
/**
To read the received Wdp pdu
@internalComponent
@released
@since v8.0
@param aBuffer the buffer to contain the received wdp pdu
@param aTruncated the flag to represent if the data is truncated or not
@returns KErrNone on successful completion, or one of the system error codes on failure.
*/
	{
	if (!iPdu)
		{
		//Should not be here at all
        OstTraceDef0(OST_TRACE_CATEGORY_DEBUG, TRACE_INTERNALS, CWDPMESSAGERECORD_GETPDUDATA_1, "CWdpMessageRecord::GetPduData No Data Available");
		CleanUpData();
		return KErrBadDescriptor;
		}
	TInt ret=KErrNone;
	TInt bufLength=aBuffer.MaxLength();
	TPtrC8 remainPdu=iPdu->Mid(iPduOffset);
	if (bufLength<remainPdu.Length())
		{
		aBuffer.Copy(remainPdu.Ptr(), bufLength);
		iPduOffset+=bufLength;
		iState=EReading;
		aTruncated=ETrue;
		ret=Wap::EMoreData;
		}
	else
		{
		aBuffer.Copy(remainPdu);
		aTruncated=EFalse;
		CleanUpData();
		}
	return ret;
	}

void CWdpMessageRecord::UnpackPduToWspDataL()
/**
Not supported
@internalComponent
@released
@since v8.0
*/
	{
	//Should not be used
	User::Leave(KErrNotSupported);
	}

TInt CWdpMessageRecord::GetWspData(TDes8& /*aWspHeader*/, TDes8& /*aWspBody*/, TUint8& /*aTransactionId*/, TWSPStatus& /*aWspStatus*/)
/**
Not supported
@internalComponent
@released
@since v8.0
*/
	{
	//Should not be used
	return KErrNotSupported;
	}

void CWdpMessageRecord::CleanUpData()
/**
To clean up the wdp related data
@internalComponent
@released
@since v8.0
*/
	{
	CWapMessageRecord::CleanUpData();
	iPduOffset=0;
	}