// Copyright (c) 2002-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:
//
// System includes
#include <http/mhttpdatasupplier.h>
#include <httpstringconstants.h>
#include <wsp/mwspsessionheadersprovider.h>
#include <wsp/mwspcomethodcallback.h>
#include <wsp/mwspcosessioncallback.h>
#include <wsp/mwspcapabilityprovider.h>
#include <wsp/mwspcapabilityviewer.h>
#include <wsp/mwspcapabilitysetter.h>
#include <wsp/mwspaliasaddresses.h>
#include <wsp/mwspextendedmethods.h>
#include <wsp/mwspheadercodepages.h>
#include <wsp/mwspunknowncapabilities.h>
#include <wsp/wsptypes.h>
#include <wsperror.h>
#include <capcodec.h>
#include <uri8.h>
#include <http/framework/logging.h>
// Local includes
#include "tnwsswsptrhndpanic.h"
#include "mconnectioninfoprovider.h"
#include "cnwsswspcoeventdispatcher.h"
#include "cnwsswsptrhnddatasupplier.h"
#include "cnwssconnectguard.h"
#include "cnwsswsptransactioneventfilter.h"
#include "cnwsswspsessioneventfilter.h"
#include "testoom.h"
// Class signature
#include "cnwsswspcosession.h"
// Constants used in this file
const TInt KMaxUriLength = 256;
const TUint KSessDataChunkSize = 256;
const TUint KTransLUTSize = 4;
const TInt KMaxCapabilityDataSize = 256;
const TUint32 KMaxClientSDUSize = 30000;
const TUint32 KMaxServerSDUSize = 30000;
//
_LIT8(KGet, "GET");
_LIT8(KPost, "POST");
_LIT8(KHead, "HEAD");
_LIT8(KTrace, "TRACE");
_LIT8(KOptions, "OPTIONS");
_LIT8(KPut, "PUT");
_LIT8(KDelete, "DELETE");
CNwssWspCOSession* CNwssWspCOSession::NewL(RStringPool& aStringPool,
MNwssWapServer& aWapStackProvider,
MConnectionInfoProvider& aConnInfoProvider,
MSecurityPolicy& aSecurityPolicy,
MWspCOSessionCallback& aSessionCB)
{
CNwssWspCOSession* me = new(ELeave)CNwssWspCOSession(aStringPool,
aWapStackProvider,
aConnInfoProvider,
aSecurityPolicy,
aSessionCB);
CleanupStack::PushL(me);
me->ConstructL();
CleanupStack::Pop(me);
return me;
}
CNwssWspCOSession::~CNwssWspCOSession()
{
// It is important that the client correctly disconnects sessions before deleting the transport
// handler.
#ifdef _DEBUG
if( State() != CNwssWspSession::EDisconnected )
{
// WSP session could be suspended
RWSPCOConn::TSessionState state;
iWspCOSession.GetSessionState(state);
#ifndef __UNIT_TESTING__
__ASSERT_DEBUG(state == RWSPCOConn::ESuspended,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EConnectedUponDestruction));
#endif
}
#endif
if( State() != CNwssWspSession::EDisconnected )
// Ensure everything is closed down. Since we're destructing, we don't care about
// errors in this callback.
(void)SessionDisconnectedCallback();
if (iConnectGuard)
iConnectGuard->Cancel();
if (iTransEventFilter)
iTransEventFilter->Cancel();
if( iSessionEventFilter )
iSessionEventFilter->Cancel();
// Clean up
delete iCOTransTable;
delete iTransEventFilter;
delete iSessionEventFilter;
delete iEventDispatcher;
delete iCapabilityCodec;
delete iUriBuffer;
delete iSessDataBuffer;
delete iConnectGuard;
delete iOOMCallBack;
__CLOSELOG
}
CNwssWspCOSession::CNwssWspCOSession(RStringPool& aStringPool,
MNwssWapServer& aWapStackProvider,
MConnectionInfoProvider& aConnInfoProvider,
MSecurityPolicy& aSecurityPolicy,
MWspCOSessionCallback& aSessionCB)
: CNwssWspSession(aStringPool, aWapStackProvider, aConnInfoProvider, aSecurityPolicy),
iSessionCB(aSessionCB)
{
__OPENLOG("http", "nwsswsptrhnd.txt")
__LOG_TITLE("WSP Transport Handler (NWSS bindings) Log")
}
void CNwssWspCOSession::ConstructL()
{
BaseConstructL();
// Create the transaction look-up table with a default initial size. Create
// the event dispatcher and capability codec.
iCOTransTable = CNwssTransLookUpTable::NewL(KTransLUTSize);
iTransEventFilter = CNwssWspTransactionEventFilter::NewL(*iCOTransTable, *this, KTransLUTSize);
iSessionEventFilter = CNwssWspSessionEventFilter::NewL(*iCOTransTable, *this, *this);
iEventDispatcher = CNwssWspCOEventDispatcher::NewL(iWspCOSession, *iSessionEventFilter, *iTransEventFilter, *this);
iCapabilityCodec = CCapCodec::NewL();
// Create scratch buffers
iUriBuffer = HBufC::NewL(KMaxUriLength);
iSessDataBuffer = HBufC8::NewL(KSessDataChunkSize);
// Create the connect guard
iConnectGuard = CNwssConnectGuard::NewL(*this, iSessionCB);
// Create the one shot used if OOM occurs during a MethodInvoke or Connect
iOOMCallBack = new (ELeave)CAsyncCallBack(CActive::EPriorityStandard);
}
/*
* Session Invocation API.
*/
void CNwssWspCOSession::ConnectReq()
{
__LOG("Received S-Connect.req primitive")
// Set connect limbo flag. This indicates that the S-Connect.req has been
// received but not yet sent to the WAP Stack.
iInConnectLimbo = ETrue;
// All this stuff will be broken out, into different states in the parent class
// This method will just request from its parent that the connection process is
// started. The parent, as an AO, will go through the various stages in its RunL.
// That will involve calls down to this class to allow the connection to be
// completed.
InitiateProxyConnection();
}
TInt CNwssWspCOSession::OpenWspSession(const TDesC8& aRemoteHost,
RWAPConn::TPort aRemotePort,
RWAPConn::TPort aLocalPort,
TBearer aBearer,
TBool aSecureConn)
{
// Open a WSP CO connection with the WAP stack
__TESTOOMD(error, iWspCOSession.Open(iWapStackProvider.WapStack(), aRemoteHost, aRemotePort, aLocalPort, aBearer, aSecureConn));
return error;
}
TInt CNwssWspCOSession::CloseWspSession()
{
iEventDispatcher->Cancel();
iWspCOSession.CancelAll();
__TESTOOMD(stkErr, iWspCOSession.Close());
return stkErr;
}
void CNwssWspCOSession::CompleteProxyConnectionL()
{
__LOG("Sending S-Connect.req primitive")
// Obtain the client headers
MWspSessionHeadersProvider& prov = iConnInfoProvider.SessionHeadersProvider();
const TDesC8& cliHdr = prov.ClientHeaders();
__LOG("--Client session headers are:")
__DUMP("--", "--", cliHdr)
// Prepare the client's proposed capabilities
PrepareClientCapabilities();
// Request a connection to the proxy
__TESTOOMD(error, iWspCOSession.Connect(cliHdr, iCapabilityCodec));
__LOG1("--RWSPCOConn::Connect() returned with %d", error)
User::LeaveIfError(error);
// Ensure the event dispatcher is waiting for stack events
iEventDispatcher->Start();
// Unset the connect limbo flag - sent S-Connect.req to WAP Stack.
iInConnectLimbo = EFalse;
// Send the waiting method invoke (if exists)
iConnectGuard->SendMethodInvokeReq();
}
RWTLS CNwssWspCOSession::WtlsHnd()
{
return iWspCOSession.Wtls();
}
void CNwssWspCOSession::DoRunError(TInt aError)
{
// Handling from the parent class state machine's RunError.
// In all cases, this means that a ConnectReq() call in this class has failed.
// Hence, a connection will never be possible with the gateway, and we should
// indicate this to the client using DisconnectInd() to ensure their own notion of
// the session state is correct. The WTLS failure mode (aError) is indicated
// using the disconnect reason.
__ASSERT_DEBUG( iInConnectLimbo, User::Invariant() );
__LOG("Returning S-Disconnect.ind primitive")
// Convert the error code to a WSP reason
TWspReason reason = Wap::EConnectErr;
switch (aError)
{
case KWtlsErrConfigurationFailed:
__LOG("--reason: KWtlsErrConfigurationFailed")
reason = Wap::EWtlsConfigurationFailed;
break;
case KWtlsErrPhase1HandshakeFailed:
__LOG("--reason: KWtlsErrPhase1HandshakeFailed")
reason = Wap::EWtlsPhase1HandshakeFailed;
break;
case KWtlsErrPhase2HandshakeFailed:
__LOG("--reason: KWtlsErrPhase2HandshakeFailed")
reason = Wap::EWtlsPhase2HandshakeFailed;
break;
case KWtlsErrInvalidServerCert:
__LOG("--reason: KWtlsErrInvalidServerCert")
reason = Wap::EWtlsInvalidServerCert;
break;
case KWtlsErrUntrustedServerCert:
__LOG("--reason: KWtlsErrUntrustedServerCert")
reason = Wap::EWtlsUntrustedServerCert;
break;
case KWtlsErrNegotiatedConfigRejected:
__LOG("--reason: KWtlsErrNegotiatedConfigRejected")
reason = Wap::EWtlsNegotiatedConfigRejected;
break;
case KErrNoMemory:
__LOG("--reason: KErrNoMemory")
reason = Wap::EOutOfMemory;
break;
default:
;
}
// Need to send S-Disconnect.ind - should deal with an invoked method
// if it exists.
iConnectGuard->SendDisconnectInd(reason);
// Unset the connect limbo flag.
iInConnectLimbo = EFalse;
}
TBool CNwssWspCOSession::SubDoCancel()
{
// Called from the parent class DoCancel(). Cancel the outstanding requests in this class.
iEventDispatcher->Cancel();
// We don't want to return to a disconnected state after this.
return EFalse;
}
void CNwssWspCOSession::DisconnectReq(TWspReason aReason)
{
__ASSERT_DEBUG(State() != CNwssWspSession::EDisconnected,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInvalidState));
__LOG("Sending S-Disconnect.req primitive")
// Check to see if the S-Connect.req has been sent to the WAP Stack
if( iInConnectLimbo )
{
__LOG("---In connect limbo - cannot send S-Disconnect.req.")
__LOG("---Cancelling proxy connection process.")
// No, still trying to connect - cancel the proxy connection
Cancel();
// Need to send S-Disconnect.ind - should deal with an invoked method
// if it exists.
iConnectGuard->SendDisconnectInd(aReason);
// Unset the connect limbo flag.
iInConnectLimbo = EFalse;
return;
}
// Request a disconnect
__ASSERT_DEBUG(State() == CNwssWspSession::EReady,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInvalidState));
__TESTOOMD(error, iWspCOSession.Disconnect());
// Handle OOM separately - we can recover from it.
if (error == KErrNoMemory)
{
ScheduleDelayedOomDisconnect(EFalse);
return;
}
__ASSERT_ALWAYS(error == KErrNone, MapToPanic(error));
// Inform the transaction event filter that S-Disconnect.req has been sent
iTransEventFilter->SessionDisconnectRequested();
// Ensure the event dispatcher is waiting for stack events
iEventDispatcher->Start();
}
void CNwssWspCOSession::SuspendReq()
{
__LOG("Sending S-Suspend.req primitive")
// Request suspension
__TESTOOMD(error, iWspCOSession.Suspend());
__ASSERT_ALWAYS(error == KErrNone, MapToPanic(error));
// Ensure the event dispatcher is waiting for stack events
iEventDispatcher->Start();
}
void CNwssWspCOSession::ResumeReq()
{
__LOG("Sending S-Resume.req primitive")
// Obtain the (possibly updated) client headers
MWspSessionHeadersProvider& prov = iConnInfoProvider.SessionHeadersProvider();
const TDesC8& cliHdr = prov.ClientHeaders();
__LOG("--Client session headers are:")
__DUMP("--", "--", cliHdr)
// Request session resume. Needs a blank RWSPCOConn - what to do with this?
//@todo - this may require considerable work...
RWSPCOConn blankConn;
__TESTOOMD(error, iWspCOSession.Resume(blankConn, cliHdr));
__ASSERT_ALWAYS(error == KErrNone, MapToPanic(error));
// Ensure the event dispatcher is waiting for stack events
iEventDispatcher->Start();
}
/*
* Method Invocation API.
*/
void CNwssWspCOSession::MethodInvokeReq(
MWspCOMethodCallback& aMethodCallback,
RStringF aMethod,
const TUriC8& aRequestUri,
const TDesC8& aRequestHeaders,
const TDesC8& aRequestBody,
TBool aMoreData
)
{
__LOG("Sending T-MethodInvoke.req primitive")
#ifdef __DEBUG
if( aMoreData )
{
__LOG("Attempt to send T-MethodInvoke.req primitive failed because")
__LOG("Large Data Transfer is not supported in this WAP Stack.")
}
#endif
__ASSERT_ALWAYS( !aMoreData, TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::ELargeDataTransferNotSupported) );
if( iInConnectLimbo )
{
__LOG("--In connect limbo - cannot send T-MethodInvoke.req.")
__LOG("--Save information for later...")
TRAPD(error, __DEBUGTESTLEAVE \
iConnectGuard->ReceivedMethodInvokeReqL(
aMethodCallback,
aMethod,
aRequestUri,
aRequestHeaders,
aRequestBody
) );
__ASSERT_ALWAYS( error == KErrNone, TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EDeferedMethodFailed) );
return;
}
__ASSERT_ALWAYS(iWspCOSession.SubSessionHandle() != KNullHandle, TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::ESessionNotConnected));
RWAPConn::TMethod method = RWAPConn::EGet;
const TDesC8& methodName = aMethod.DesC();
__LOG1("--Method is '%S'", &methodName);
if (methodName.CompareF(KGet) == 0)
method = RWAPConn::EGet;
else if (methodName.CompareF(KPost) == 0)
method = RWAPConn::EPost;
else if (methodName.CompareF(KHead) == 0)
method = RWAPConn::EHead;
else if (methodName.CompareF(KTrace) == 0)
method = RWAPConn::ETrace;
else if (methodName.CompareF(KOptions) == 0)
method = RWAPConn::EOptions;
else if (methodName.CompareF(KPut) == 0)
method = RWAPConn::EPut;
else if (methodName.CompareF(KDelete) == 0)
method = RWAPConn::EDelete;
else
// @todo - extension methods?
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EUnknownMethod);
// Convert the URI to Unicode
__LOG1("--URI is '%S'", &(aRequestUri.UriDes()));
if (aRequestUri.UriDes().Length() > KMaxUriLength)
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EURIOverflow);
iUriBuffer->Des().Copy(aRequestUri.UriDes());
// Log headers
__LOG("--Encoded WSP header is:")
__DUMP("--", "--", aRequestHeaders)
// Log body data
__LOG("--Body data is:")
__DUMP("--", "--", aRequestBody)
// Get the next look-up table entry for the new transaction
CNwssTransLookUpTable::CNwssTransLUTEntry& entry = iCOTransTable->NewEntry();
entry.iCallback = &aMethodCallback;
// Create the WSP transaction on the WAP stack, and handle any resulting error
__TESTOOMD(error, iWspCOSession.CreateTransaction(method, *iUriBuffer, aRequestHeaders, aRequestBody, entry.iStackTrans));
__LOG1("--RWSPCOConn::CreateTransaction() returned %d", error);
// Handle OOM separately - we can recover from it.
if (error == KErrNoMemory)
{
ScheduleDelayedOomMethodAbort(*(entry.iCallback), EFalse);
return;
}
else
// But any other error is due to a client programming error, so panic
__ASSERT_ALWAYS(error == KErrNone, MapToPanic(error));
// Get the transaction ID
error = entry.iStackTrans.Id(entry.iStackTransID);
__LOG1("--RWSPCOTrans::Id() returned %d", error);
__ASSERT_ALWAYS(error == KErrNone, MapToPanic(error));
__LOG1("--Transaction Id is %d", entry.iStackTransID);
// Ensure the event dispatcher is waiting for stack events
iEventDispatcher->Start();
}
void CNwssWspCOSession::MethodInvokeDataReq(
MWspCOMethodCallback& /*aTransactionCallback*/,
const TDesC8& /*aRequestBody*/,
const TDesC8& /*aTrailerHeaders*/,
TBool /*aMoreData*/
)
{
__LOG("Attempt to send T-MethodInvokeData.req primitive failed because")
__LOG("Large Data Transfer is not supported in this WAP Stack.")
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::ELargeDataTransferNotSupported);
}
void CNwssWspCOSession::MethodAbortReq(MWspCOMethodCallback& aMethodCallback)
{
__LOG("Sending T-MethodAbort.req primitive")
// Check to see if the T-MethodInvoke.req primitive has been sent
if( iInConnectLimbo )
{
__LOG("--In connect limbo - cannot send T-MethodAbort.req.")
__LOG("--Delete waiting method")
// Send the T-MethodAbort.ind
iConnectGuard->SendMethodAbortInd();
return;
}
TBool found = EFalse;
CNwssTransLookUpTable::CNwssTransLUTEntry& lutEntry = iCOTransTable->LookUpByCallback(aMethodCallback,
found);
if (found)
{
__LOG1("--Transaction Id is %d", lutEntry.iStackTransID);
// Abort the transaction - choose an abort reason from the WSP spec since
// <wapcli.h> doesn't enumerate it :(
// Unfortunately the NWSS stack moves the state to 'Done' prematurely, so
// check for that now.
RWSPCOTrans::TState trState = RWSPCOTrans::EInit;
__TESTOOMD(stkErr, lutEntry.iStackTrans.GetState(trState));
__LOG1("--Transaction is in state %d", trState);
__LOG1("--RWSPCOTrans::GetState() returned %d", stkErr);
if (trState != RWSPCOTrans::EDone)
{
__TESTOOM(stkErr, lutEntry.iStackTrans.Abort(EUserReq));
__LOG1("--RWSPCOTrans::Abort() returned %d", stkErr);
// Ensure the event dispatcher is waiting for stack events
iEventDispatcher->Start();
}
else
{
// The NWSS stack has already received the T-MethodResult.ind for this
// transaction and it won't allow it to be aborted. But the client
// expects the T-MethodAbort.ind to 'finish' the method.
__LOG("--Cannot abort transaction, need to create T-MethodAbort.ind event");
iTransEventFilter->SendMethodAbortIndEvent(lutEntry.iStackTransID);
}
__ASSERT_ALWAYS(stkErr == KErrNone,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EFailedToAbortTrans));
}
}
void CNwssWspCOSession::MethodResultRes(
MWspCOMethodCallback& aMethodCallback,
const TDesC8& aAckHeaders
)
{
__LOG("Sending T-MethodResult.res primitive")
TBool found = EFalse;
CNwssTransLookUpTable::CNwssTransLUTEntry& lutEntry = iCOTransTable->LookUpByCallback(aMethodCallback, found);
if (found)
{
__LOG1("--Transaction Id is %d", lutEntry.iStackTransID);
// If the 'use acknowledgment headers' capability was negotiated with the
// proxy, then do so now
if (iUseAckHdrs)
{
__LOG("--Acknowledgement headers:");
__DUMP("--", "--", aAckHeaders);
__TESTOOMD(stkErr, lutEntry.iStackTrans.Acknowledge(aAckHeaders));
__LOG1("--RWSPCOTrans::Acknowledge() returned %d", stkErr);
__ASSERT_ALWAYS(stkErr == KErrNone,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EFailedToAcknowledgeTrans));
}
// Now release the transaction
__TESTOOMD(stkErr, lutEntry.iStackTrans.Release());
__LOG1("--RWSPCOTrans::Release() returned %d", stkErr);
// If release failed due to OOM, then send a MethodAbort-ind (OOM)
if (stkErr == KErrNoMemory)
{
ScheduleDelayedOomMethodAbort(*(lutEntry.iCallback), EFalse);
stkErr = KErrNone;
}
else
{
__ASSERT_ALWAYS(stkErr == KErrNone,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EFailedToReleaseTrans));
// Ensure the event dispatcher is waiting for stack events
iEventDispatcher->Start();
}
// Remove the entry from the look-up table - this deletes the data supplier object
iCOTransTable->RemoveEntry(*(lutEntry.iCallback));
}
}
void CNwssWspCOSession::MethodResultDataRes(
MWspCOMethodCallback& /*aMethodCallback*/,
const TDesC8& /*aAckHeaders*/
)
{
__LOG("Attempt to send T-MethodResultData.res primitive failed because")
__LOG("Large Data Transfer is not supported in this WAP Stack.")
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::ELargeDataTransferNotSupported);
}
void CNwssWspCOSession::PrepareClientCapabilities()
{
__LOG("--Client's Requested Capabilities:");
__LOG("----------------------------------");
// Get all the capability handles from the client
MWspCapabilityProvider& capsProv = iConnInfoProvider.CapabilityProvider();
const MWspCapabilityViewer& cliCaps = capsProv.ClientCapabilities();
// The NWSS WAP Stack doesn't support LDT, so cliMsgSize and svrMsgSize will be
// ignored. This transport handler doesn't currently support Push, so pushMOR
// will be ignored.
// Mask out all but the acknowledgement and suspend/resume capabilities -
// we don't support push yet, and the current NWSS stack doesn't support LDT.
TUint8 protOpts = cliCaps.GetProtocolOptions();
protOpts &= (Wap::EAcknowledgementHeaders | Wap::ESessionResumeFacility);
__LOG1("--Protocol options = %2x", protOpts);
// Everything else is straightforward
TUint8 methodMOR = cliCaps.GetMethodMOR();
__LOG1("--Method MOR = %d", methodMOR);
TUint32 cliSDUSize = cliCaps.GetClientSDUSize();
__LOG1("--Client SDU Size = %d", cliSDUSize);
TUint32 svrSDUSize = cliCaps.GetServerSDUSize();
__LOG1("--Server SDU Size = %d", svrSDUSize);
const MWspAliasAddresses& aliasAddrs = cliCaps.GetAliasAddresses();
const MWspExtendedMethods& extMethods = cliCaps.GetExtendedMethods();
const MWspHeaderCodePages& hdrCodePages = cliCaps.GetHeaderCodePages();
const MWspUnknownCapabilities& unknownCaps = cliCaps.GetUnknownCapabilities();
// Work around SDU size limitation in this WAP stack
if (cliSDUSize > KMaxClientSDUSize)
cliSDUSize = KMaxClientSDUSize;
if (svrSDUSize > KMaxServerSDUSize)
svrSDUSize = KMaxServerSDUSize;
// Trival ones first
iCapabilityCodec->SetMethodMOR(methodMOR);
iCapabilityCodec->SetProtocolOptions(protOpts);
iCapabilityCodec->SetClientSDUSize(cliSDUSize);
iCapabilityCodec->SetServerSDUSize(svrSDUSize);
// Alias addresses
Wap::TWspBearer bearer;
TUint16 port;
TPtrC8 address;
aliasAddrs.Start();
while (aliasAddrs.GetNext(bearer, port, address) != KErrNotFound)
{
__LOG3("--Alias Address: bearer = %d, port = %d, address = %S", bearer, port, &address);
TAliasAddress addr;
addr.SetBearer((unsigned char)bearer);
addr.SetPort(port);
TInt err = addr.SetAddress(address);
__ASSERT_DEBUG(err == KErrNone,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
err = iCapabilityCodec->AddAliasAddress(addr);
__ASSERT_DEBUG(err == KErrNone,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
}
// For the remaining non-trivial capabilities, we unfortunately have to make a copy
// of the descriptor data into a writable buffer, since the CCapCodec API mandates
// a TDes8-derived descriptor for data, even though only CCapCodec Set-fns are
// being used!
TBuf8<KMaxCapabilityDataSize> capData;
// Extended methods
TUint8 pduType;
TPtrC8 methodName;
extMethods.Start();
while (extMethods.GetNext(pduType, methodName) != KErrNotFound)
{
__LOG2("--Extended Method: pduType = %d, methodName = %S", pduType, &methodName);
__ASSERT_ALWAYS(methodName.Length() < KMaxCapabilityDataSize,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::ECapabilityOverrun));
capData.Copy(methodName);
#ifdef _DEBUG
TInt err =
#endif
iCapabilityCodec->AddExtendedMethod(capData, pduType);
__ASSERT_DEBUG(err == KErrNone,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
}
// Header code pages
TUint8 pageCode;
TPtrC8 pageName;
hdrCodePages.Start();
while (hdrCodePages.GetNext(pageCode, pageName) != KErrNotFound)
{
__LOG2("--Header Code Page: pageCode = %d, pageName = %S", pageCode, &pageName);
__ASSERT_ALWAYS(pageName.Length() < KMaxCapabilityDataSize,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::ECapabilityOverrun));
capData.Copy(pageName);
#ifdef _DEBUG
TInt err =
#endif
iCapabilityCodec->AddCodePage(capData, pageCode);
__ASSERT_DEBUG(err == KErrNone,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
}
// Unknown capabilities
TPtrC8 identifier;
TPtrC8 value;
unknownCaps.Start();
while (unknownCaps.GetNext(identifier, value) != KErrNotFound)
{
__LOG2("--Unknown Capability: identifier = %S, value = %S", &identifier, &value);
__ASSERT_ALWAYS(identifier.Length() < KMaxCapabilityDataSize,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::ECapabilityOverrun));
capData.Copy(identifier);
#ifdef _DEBUG
TInt err =
#endif
iCapabilityCodec->AddUnknownCap(capData, value);
__ASSERT_DEBUG(err == KErrNone,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
}
__LOG("----------------------------------");
}
void CNwssWspCOSession::SetNegotiatedCapabilitiesL()
{
__LOG("--Proxy's Negotiated Capabilities:");
__LOG("----------------------------------");
// Get the encoded capabilites from the session data, and pass to the codec
__DEBUGTESTLEAVE
HBufC8* encodedCaps = GetAllSessionDataLC(RWSPCOConn::ECapabilities);
__LOG("--Encoded data:");
__DUMP("--", "--", (*encodedCaps));
CCapCodec* negCapsCodec = CCapCodec::NewL(*encodedCaps);
CleanupStack::PushL(negCapsCodec);
// Get all the capability handles from the client
MWspCapabilityProvider& capsProv = iConnInfoProvider.CapabilityProvider();
MWspCapabilitySetter& negCaps = capsProv.ServerCapabilities();
negCaps.Reset(EAllCapabilities);
// Trivial ones first - keep a copy of method MOR and protocol opts (acks flag)
TUint32 protOpts;
negCapsCodec->GetProtocolOptions(protOpts);
TUint8 protOpts8 = STATIC_CAST(TUint8, protOpts);
negCaps.SetProtocolOptions(protOpts8);
__LOG1("--Protocol options = %2x", protOpts);
iUseAckHdrs = ((protOpts & Wap::EAcknowledgementHeaders) == Wap::EAcknowledgementHeaders);
//
negCapsCodec->MethodMOR(iMethodMOR);
negCaps.SetMethodMOR(iMethodMOR);
__LOG1("--Method MOR = %d", iMethodMOR);
//
// We don't support the Message size capability, but we know the client might, so
// set it to the same as the negotiated SDU size
TUint32 size;
negCapsCodec->ClientSDUSize(size);
negCaps.SetClientSDUSize(size);
negCaps.SetClientMessageSize(size);
__LOG1("--Client SDU Size = %d", size);
//
negCapsCodec->GetServerSDUSize(size);
negCaps.SetServerSDUSize(size);
negCaps.SetServerMessageSize(size);
__LOG1("--Server SDU Size = %d", size);
// Now the more complex ones - alias addresses first
TInt numAliasAddrs = 0;
negCapsCodec->NumAliasAddress(numAliasAddrs);
TInt idx = 0;
for (idx = 0; idx < numAliasAddrs; ++idx)
{
TAliasAddress address;
TInt err = negCapsCodec->GetAliasAddress(idx, address);
__ASSERT_DEBUG(err == KErrNone,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
if (!err)
{
Wap::TWspBearer bearer = Wap::EIP;
if (address.HasBearer())
bearer = (Wap::TWspBearer)address.Bearer();
TUint16 port = 0;
if (address.HasPort())
port = address.Port();
__DEBUGTESTLEAVE
negCaps.AddAliasAddressL(bearer, port, address.Address());
__LOG3("--Alias Address: bearer = %d, port = %d, address = %S", bearer, port, &(address.Address()));
}
}
// For the remaining non-trivial capabilities, we need a writable buffer to place
// certain values into. Sadly the CCapCodec API offers no means of finding out how
// big particular values need to be before calling...
TBuf8<KMaxCapabilityDataSize> capData;
// Extended methods
TInt numExtMethods = 0;
negCapsCodec->NumExtendedMethods(numExtMethods);
for (idx = 0; idx < numExtMethods; ++idx)
{
TUint8 val;
TInt err = negCapsCodec->GetExtendedMethod(idx, capData, val);
__ASSERT_DEBUG(err == KErrNone,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
if (!err)
{
__DEBUGTESTLEAVE
negCaps.AddExtendedMethodL(val, capData);
__LOG2("--Extended Method: pduType = %d, methodName = %S", val, &capData);
}
}
// Code pages
TInt numCodePages = 0;
negCapsCodec->NumCodePages(numCodePages);
for (idx = 0; idx < numCodePages; ++idx)
{
TUint8 val;
TInt err = negCapsCodec->GetCodePage(idx, capData, val);
__ASSERT_DEBUG(err == KErrNone,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
if (!err)
{
__DEBUGTESTLEAVE
negCaps.AddHeaderCodePageL(val, capData);
__LOG2("--Header Code Page: pageCode = %d, pageName = %S", val, &capData);
}
}
// Unknown capabilities
TInt numUnknownCaps = 0;
negCapsCodec->NumUnkownCap(numUnknownCaps); // sic
TBuf8<KMaxCapabilityDataSize> unknownCapVal;
for (idx = 0; idx < numUnknownCaps; ++idx)
{
TInt err = negCapsCodec->GetUnknownCap(idx, capData, unknownCapVal);
__ASSERT_DEBUG(err == KErrNone,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
if (!err)
{
__LOG2("--Unknown Capability: identifier = %S, value = %S", &unknownCapVal, &capData);
__DEBUGTESTLEAVE
negCaps.AddUnknownCapabilityL(unknownCapVal, capData);
}
}
// Cleanup
CleanupStack::PopAndDestroy(2, encodedCaps); // and negCapsCodec
__LOG("----------------------------------");
}
void CNwssWspCOSession::HandleDisconnectIndL()
{
__LOG("Received S-Disconnect.ind primitive")
// Get the disconnection reason buffer from the session data
TPckgBuf<TUint8> disconReasonBuff;
TInt stkErr = GetSessionData(disconReasonBuff, RWSPCOConn::EDisconReason);
if (stkErr == KErrNoMemory)
{
ScheduleDelayedOomDisconnect(EFalse);
return;
}
__ASSERT_ALWAYS(stkErr == KErrNone, MapToPanic(stkErr));
Wap::TWspReason disconReason = (Wap::TWspReason)disconReasonBuff();
// Get the error header/body buffers from the session data
__DEBUGTESTLEAVE
HBufC8* errorHdrs = GetAllSessionDataLC(RWSPCOConn::EErrorHeaders);
__DEBUGTESTLEAVE
HBufC8* errorBody = GetAllSessionDataLC(RWSPCOConn::EErrorBody);
// Inform the transaction event filter that S-Disconnect.ind has been received.
iTransEventFilter->SessionDisconnected();
// Do it
TWspRedirectedAddress emptyAddr;
DoSendDisconnectInd(disconReason, EFalse, emptyAddr, *errorHdrs, *errorBody);
// Clean up
CleanupStack::PopAndDestroy(2, errorHdrs);
}
void CNwssWspCOSession::DoSendDisconnectInd(Wap::TWspReason aReason,
TBool aRedirectSecurity,
TWspRedirectedAddress& aRedirectAddress,
const TDesC8& aErrorHeader,
const TDesC8& aErrorBody)
{
// Send the disconnect indication _after_ informing the parent class that we're disconnected
// This may seem to be the wrong order, but if there is any failure in the parent class to
// maintain the session state correctly (e.g. due to OOM in the WAP Stack) then the disconnect
// reason is transformed to one which indicates the state failure.
// Notify the client of the session event
TInt error = SessionDisconnectedCallback();
if (error != KErrNone)
aReason = Wap::ESessionStateFailure;
iSessionCB.DisconnectInd(aReason, aRedirectSecurity, aRedirectAddress, aErrorHeader, aErrorBody);
}
void CNwssWspCOSession::HandleSuspendIndL()
{
__LOG("Received S-Suspend.ind primitive")
// Get the suspend reason buffer from the session data
TPckgBuf<TUint8> suspendReasonBuff;
TInt stkErr = GetSessionData(suspendReasonBuff, RWSPCOConn::ESuspendReason);
if (stkErr == KErrNoMemory)
{
ScheduleDelayedOomDisconnect(EFalse);
return;
}
__ASSERT_ALWAYS(stkErr == KErrNone, MapToPanic(stkErr));
Wap::TWspReason suspendReason = (Wap::TWspReason)suspendReasonBuff();
// Notify the client of the session event
iSessionCB.SuspendInd(suspendReason);
}
void CNwssWspCOSession::HandleResumeCnfL()
{
__LOG("Received S-Resume.cnf primitive")
// Notify the client of the session event
iSessionCB.ResumeCnf();
}
void CNwssWspCOSession::HandleConnectCnfL()
{
__LOG("Received S-Connect.cnf primitive")
// Inform the client of the negotiated capabilities
__DEBUGTESTLEAVE
SetNegotiatedCapabilitiesL();
// Inform the client of the server's session headers
MWspSessionHeadersProvider& prov = iConnInfoProvider.SessionHeadersProvider();
__DEBUGTESTLEAVE
HBufC8* serverHeaders = GetAllSessionDataLC(RWSPCOConn::EServerHeaders);
prov.SetServerHeadersL(*serverHeaders);
__LOG("--Server session headers are:")
__DUMP("--", "--", (*serverHeaders))
CleanupStack::PopAndDestroy(serverHeaders);
// Resize the transaction look-up table to match the MethodMOR capability for
// the session (which might be greater than the original table size)
__DEBUGTESTLEAVE
iCOTransTable->ResizeTableL(iMethodMOR);
// Also, resize the trans Id table in the transaction filter.
__DEBUGTESTLEAVE
iTransEventFilter->ResizeTableL(iMethodMOR);
// Notify the client of the session event
iSessionCB.ConnectCnf();
}
void CNwssWspCOSession::HandleRedirectIndL()
{
__LOG("Received S-Disconnect.ind (redirection) primitive")
// Notify the client of the session event. Note that this event
// is really sent using DisconnectInd, as specified in [WSP]. The
// NWSS wap stack has simplified things by presenting it as a new
// event 'RedirectInd', which isn't defined in [WSP] at all.
// Get the redirection options buffer from the session data
TPckgBuf<TUint8> redirOptsBuff;
TInt stkErr = GetSessionData(redirOptsBuff, RWSPCOConn::ERedirectOptions);
if (stkErr == KErrNoMemory)
{
ScheduleDelayedOomDisconnect(EFalse);
return;
}
__ASSERT_ALWAYS(stkErr == KErrNone, MapToPanic(stkErr));
// Check for the permanent/temporary flag and the 'Reuse Security
// Session' flag
TBool permanentRedirect = ((redirOptsBuff() & 0x80) != 0);
TBool redirectSecurity = ((redirOptsBuff() & 0x40) != 0);
// Set the disconnect reason to temporary/permanent redirection
TWspReason disconReason = permanentRedirect?
EPermanentRedirectedProxy:
ETemporaryRedirectedProxy;
// Get the redirection address(es) buffer from the session data
__DEBUGTESTLEAVE
HBufC8* redirAddr = GetAllSessionDataLC(RWSPCOConn::ERedirectAddresses);
// Convert the descriptor into a parsed form stored in iRedirectAddr
__DEBUGTESTLEAVE
ExtractRedirectedProxyInfoL(*redirAddr);
// Don't bother with error headers or body for redirection.
// Notify the client of the session event
DoSendDisconnectInd(disconReason, redirectSecurity, iRedirectAddr,
KNullDesC8(), KNullDesC8());
// Clean up
CleanupStack::PopAndDestroy(redirAddr);
}
void CNwssWspCOSession::HandleExceptionIndL()
{
__LOG("Received E-Exception.ind primitive")
// Notify the client of the session event. Note that the exception data is
// not available from the NWSS WAP stack, so send empty data instead.
iSessionCB.ExceptionInd(KNullDesC8());
}
void CNwssWspCOSession::HandleMethodInvokeCnfL(RWSPCOTrans::TTransID aTransId)
{
__LOG("Received T-MethodInvoke.cnf primitive")
// Look-up the transaction by ID
TBool found = EFalse;
CNwssTransLookUpTable::CNwssTransLUTEntry& lutEntry = iCOTransTable->LookUpByTransId(aTransId, found);
__ASSERT_DEBUG(found,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EEventOnUnknownTransaction));
__LOG1("--Transaction Id is %d", lutEntry.iStackTransID);
// Inform the client of the transaction event
lutEntry.iCallback->MethodInvokeCnf();
}
void CNwssWspCOSession::HandleMethodResultIndL(RWSPCOTrans::TTransID aTransId)
{
__LOG("Received T-MethodResult.ind primitive")
// Look-up the transaction by ID
TBool found = EFalse;
CNwssTransLookUpTable::CNwssTransLUTEntry& lutEntry = iCOTransTable->LookUpByTransId(aTransId, found);
__ASSERT_DEBUG(found,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EEventOnUnknownTransaction));
__LOG1("--Transaction Id is %d", lutEntry.iStackTransID);
// Get the WSP status code. This is expected to be a single byte, in one buffer.
TPckgBuf<TUint8> status;
TInt stkErr = GetTransactionData(lutEntry.iStackTrans, status, RWSPCOTrans::EResultStatus);
if (stkErr == KErrNoMemory)
{
ScheduleDelayedOomMethodAbort(*(lutEntry.iCallback), EFalse);
return;
}
// Get the response headers
__DEBUGTESTLEAVE
HBufC8* respHdrs = GetAllTransactionDataLC(lutEntry.iStackTrans, RWSPCOTrans::EResultHeaders);
__LOG("--Result Header is:")
__DUMP("--", "--", (*respHdrs))
// Create a response body data supplier to stream the response body back to the
// client. Associate it with the transaction in the look-up table.
lutEntry.iResponseBodyHandler = CNwssWspTrHndDataSupplier::NewL(lutEntry.iStackTrans, *this);
// Inform the client of the transaction event
lutEntry.iCallback->MethodResultInd(status(),
*respHdrs,
*(lutEntry.iResponseBodyHandler),
EFalse);
// Clean up
CleanupStack::PopAndDestroy(respHdrs);
}
void CNwssWspCOSession::HandleAbortIndL(RWSPCOTrans::TTransID aTransId)
{
__LOG("Received T-MethodAbort.ind primitive")
// Look-up the transaction by ID
TBool found = EFalse;
CNwssTransLookUpTable::CNwssTransLUTEntry& lutEntry = iCOTransTable->LookUpByTransId(aTransId, found);
__ASSERT_DEBUG(found,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EEventOnUnknownTransaction));
__LOG1("--Transaction Id is %d", lutEntry.iStackTransID);
TInt stkErr = KErrNone;
#ifdef _DEBUG
// Check the state
RWSPCOTrans::TState trState = RWSPCOTrans::EInit;
__TESTOOM(stkErr, lutEntry.iStackTrans.GetState(trState));
__LOG1("--Transaction is in state %d", trState);
__LOG1("--RWSPCOTrans::GetState() returned %d", stkErr);
#endif
// Now release the transaction
__TESTOOM(stkErr, lutEntry.iStackTrans.Release());
__LOG1("--RWSPCOTrans::Release() returned %d", stkErr);
__ASSERT_ALWAYS(stkErr == KErrNone,
TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EFailedToReleaseTrans));
// The WAP stack can't provide abort reasons, so we use a hardcoded one.
// Inform the client of the aborted transaction
lutEntry.iCallback->MethodAbortInd(Wap::EPeerReq);
// Remove the entry from the look-up table - this deletes the data supplier object
iCOTransTable->RemoveEntry(*(lutEntry.iCallback));
}
void CNwssWspCOSession::ScheduleDelayedOomMethodAbort(MWspCOMethodCallback& aMethodToAbort,
TBool aAbortOnStack)
{
iAbortPckg.iSession = CONST_CAST(CNwssWspCOSession*, this);
iAbortPckg.iCallback = &aMethodToAbort;
iAbortPckg.iAbortOnStack = aAbortOnStack;
TCallBack delayedMethodAbortCB(CNwssWspCOSession::DelayedSendOomMethodAbort, (TAny*)(&iAbortPckg));
iOOMCallBack->Set(delayedMethodAbortCB);
iOOMCallBack->CallBack();
}
TInt CNwssWspCOSession::DelayedSendOomMethodAbort(TAny* aPtr)
{
TDelayedMethodAbortPckg* pckg = REINTERPRET_CAST(TDelayedMethodAbortPckg*, aPtr);
CNwssWspCOSession* sess = pckg->iSession;
MWspCOMethodCallback* cb = pckg->iCallback;
TBool stkAbort = pckg->iAbortOnStack;
sess->SendOomMethodAbort(*cb, stkAbort);
return KErrNone;
}
void CNwssWspCOSession::SendOomMethodAbort(MWspCOMethodCallback& aMethodToAbort, TBool /*aAbortOnStack*/)
{
// The abort reason is hardcoded to 'EOutOfMemory'.
// Inform the client of the aborted transaction
aMethodToAbort.MethodAbortInd(Wap::EOutOfMemory);
// Remove the entry from the look-up table - this deletes the data supplier object
iCOTransTable->RemoveEntry(aMethodToAbort);
}
void CNwssWspCOSession::SendOomMethodAbort(RWSPCOTrans::TTransID aTransId, TBool aAbortOnStack)
{
// Look-up the transaction by ID
TBool found = EFalse;
CNwssTransLookUpTable::CNwssTransLUTEntry& lutEntry = iCOTransTable->LookUpByTransId(aTransId, found);
if (found)
{
__LOG1("--Transaction Id is %d", lutEntry.iStackTransID);
// Re-use the other variant
SendOomMethodAbort(*(lutEntry.iCallback), aAbortOnStack);
}
#ifdef _DEBUG
else
__LOG1("--Unknown transaction Id %d - ignoring OOM method abort", aTransId);
#endif
}
void CNwssWspCOSession::ScheduleDelayedOomDisconnect(TBool aDisconnectOnStack)
{
iDisconnectPckg.iSession = CONST_CAST(CNwssWspCOSession*, this);
iDisconnectPckg.iDisconnectOnStack = aDisconnectOnStack;
TCallBack delayedDisconnectCB(CNwssWspCOSession::DelayedSendOomDisconnect, (TAny*)(&iDisconnectPckg));
iOOMCallBack->Set(delayedDisconnectCB);
iOOMCallBack->CallBack();
}
TInt CNwssWspCOSession::DelayedSendOomDisconnect(TAny* aPtr)
{
TDelayedDisconnectPckg* pckg = REINTERPRET_CAST(TDelayedDisconnectPckg*, aPtr);
CNwssWspCOSession* sess = pckg->iSession;
TBool stkDisconn = pckg->iDisconnectOnStack;
sess->SendOomDisconnect(stkDisconn);
return KErrNone;
}
void CNwssWspCOSession::SendOomDisconnect(TBool aDisconnectOnStack)
{
// First, disconnect from the stack if directed - necessary in some cases
// to keep the client and the WAP stack's session state in sync.
if (aDisconnectOnStack)
DisconnectReq(Wap::EOutOfMemory);
// Inform the transaction event filter that S-Disconnect.ind has been received.
iTransEventFilter->SessionDisconnected();
// The disconnect reason is hardcoded to 'EOutOfMemory'.
// Inform the client that the session has been disconnected
TWspRedirectedAddress emptyAddr;
DoSendDisconnectInd(Wap::EOutOfMemory, EFalse, emptyAddr, KNullDesC8(),KNullDesC8());
}
TInt CNwssWspCOSession::GetSessionData(TDes8& aBuffer,
RWSPCOConn::TSessionDataType aType)
{
__TESTOOMD(stkErr, iWspCOSession.GetSessionData(aBuffer, aType));
__LOG1("--RWSPCOConn::GetSessionData() returned %d", stkErr);
return stkErr;
}
HBufC8* CNwssWspCOSession::GetAllSessionDataLC(RWSPCOConn::TSessionDataType aType)
{
// Allocate the buffer to be returned. This will be expanded as necessary.
HBufC8* scratchBuff = HBufC8::NewLC(KSessDataChunkSize);
TPtr8 scratchPtr = scratchBuff->Des();
TPtr8 sessDataPtr = iSessDataBuffer->Des();
// Get the initial chunk of session data
__TESTOOMD(stkErr, iWspCOSession.GetSessionData(scratchPtr, aType));
__LOG1("--RWSPCOConn::GetSessionData() returned %d", stkErr);
while (stkErr == RWAPConn::EMoreData)
{
// The buffer wasn't big enough - try reallocating. This will leave if
// it fails to get a big enough chunk, and the working buffer will be
// cleaned up on the way out.
HBufC8* oldScratchBuff = scratchBuff;
__DEBUGTESTLEAVE
scratchBuff = oldScratchBuff->ReAllocL(scratchBuff->Length() +
KSessDataChunkSize);
CleanupStack::Pop(oldScratchBuff);
CleanupStack::PushL(scratchBuff);
// There's more data to extract. Use the iSessionData buffer to get the
// subsequent chunks
__TESTOOM(stkErr, iWspCOSession.GetSessionData(sessDataPtr, aType));
__LOG1("--RWSPCOConn::GetSessionData() returned %d", stkErr);
if ((stkErr == KErrNone) || (stkErr == RWAPConn::EMoreData))
{
// Got some data - append it to the scratch buffer
scratchPtr.Set(scratchBuff->Des());
scratchPtr.Append(*iSessDataBuffer);
}
}
// We don't deal with other errors from the WAP stack here - the final stkErr
// value must be KErrNone indicating the final block of session data extracted OK.
__DEBUGTESTLEAVE
User::LeaveIfError(stkErr);
return scratchBuff;
}
TInt CNwssWspCOSession::GetTransactionData(RWSPCOTrans aTransaction,
TDes8& aBuffer,
RWSPCOTrans::TDataType aType)
{
TInt bytesRemaining = 0;
__TESTOOMD(stkErr, aTransaction.GetData(aBuffer, aType, &bytesRemaining));
__LOG1("--RWSPCOTrans::GetData() returned %d", stkErr);
__ASSERT_ALWAYS(bytesRemaining == 0, TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EFailedToGetTransactionData));
return stkErr;
}
HBufC8* CNwssWspCOSession::GetAllTransactionDataLC(RWSPCOTrans aTransaction,
RWSPCOTrans::TDataType aType)
{
// Allocate the buffer to be returned. This will be expanded as necessary.
HBufC8* scratchBuff = HBufC8::NewLC(KSessDataChunkSize);
TPtr8 scratchPtr = scratchBuff->Des();
TPtr8 sessDataPtr = iSessDataBuffer->Des();
// Get the initial chunk of session data
TInt bytesRemaining = 0;
__TESTOOMD(stkErr, aTransaction.GetData(scratchPtr, aType, &bytesRemaining));
__LOG1("--RWSPCOTrans::GetData() returned %d", stkErr);
while (stkErr == RWAPConn::EMoreData)
{
// The buffer wasn't big enough - try reallocating. This will leave if
// it fails to get a big enough chunk, and the working buffer will be
// cleaned up on the way out. Try to get all the rest in one go.
HBufC8* oldScratchBuff = scratchBuff;
__DEBUGTESTLEAVE
scratchBuff = oldScratchBuff->ReAllocL(scratchBuff->Length() +
bytesRemaining);
CleanupStack::Pop(oldScratchBuff);
CleanupStack::PushL(scratchBuff);
// There's more data to extract. Use the iSessionData buffer to get the
// subsequent chunks
__TESTOOM(stkErr, aTransaction.GetData(sessDataPtr, aType, &bytesRemaining));
__LOG1("--RWSPCOTrans::GetData() returned %d", stkErr);
if ((stkErr == KErrNone) || (stkErr == RWAPConn::EMoreData))
{
// Got some data - append it to the scratch buffer
scratchPtr.Set(scratchBuff->Des());
scratchPtr.Append(*iSessDataBuffer);
}
}
// We don't deal with other errors from the WAP stack here - the final stkErr
// value must be KErrNone indicating the final block of session data extracted OK.
__DEBUGTESTLEAVE
User::LeaveIfError(stkErr);
return scratchBuff;
}
void CNwssWspCOSession::ExtractRedirectedProxyInfoL(const TDesC8& aRedirectedAddresses)
{
const TUint8 KBearerMask = 0x80;
const TUint8 KPortMask = 0x40;
const TUint8 KAddressLengthMask = 0x3F;
const TInt KPortLength = 2;
const TUint8 KBearerAny = 0x00;
const TUint8 KBearerSMS = 0x03;
const TUint8 KBearerCSD = 0x0A;
const TUint8 KBearerGPRS = 0x0B;
const TInt KByteLength = 8;
// Extract bearer and port presence and address length from first byte
TInt index = 0;
TUint8 byte = aRedirectedAddresses[index];
iRedirectAddr.iHasBearer = byte & KBearerMask;
iRedirectAddr.iHasPort = byte & KPortMask;
TInt addressLength = byte & KAddressLengthMask;
++index;
// Extract bearer and port - update the length of data
TInt dataLength = index + addressLength;
if( iRedirectAddr.iHasBearer )
{
// Bearer present - increment length
++dataLength;
}
if( iRedirectAddr.iHasPort )
{
// Port present - increase length by KPortLength
dataLength += KPortLength;
}
// Check to see if there is enough data - if not 'aRedirectedAddresses' wasn't well-formed.
if( dataLength > aRedirectedAddresses.Length() )
{
// Oops not enough data - leave
__LOG("--Redirect data is corrupt - not enough to extract an address")
__DEBUGTESTLEAVE
User::Leave(KWspErrBadRedirectedAddressData);
}
// Is there a bearer
if( iRedirectAddr.iHasBearer )
{
TUint8 bearerType = aRedirectedAddresses[index];
switch (bearerType)
{
case KBearerSMS:
{
// According to WDP spec, this is GMS network using SMS bearer
iRedirectAddr.iBearer = Wap::EWAPSMS;
__LOG("--Redirected to bearer WAPSMS");
} break;
case KBearerCSD:
case KBearerGPRS:
case KBearerAny:
{
// According to WDP spec, this is GMS network using CDS bearer
// (0x0A), or using a GPRS bearer (0x0B).
iRedirectAddr.iBearer = Wap::EIP;
#ifdef _DEBUG
if (bearerType == KBearerCSD)
__LOG("--Redirected to bearer CSD - using IPv4")
else if (bearerType == KBearerGPRS)
__LOG("--Redirected to bearer GPRS - using IPv4")
else if (bearerType == KBearerAny)
__LOG("--Redirected to bearer 'any' - using IPv4")
#endif
} break;
default:
{
// Bearer not supported - leave
__LOG("--Redirected to unknown bearer");
__DEBUGTESTLEAVE
User::Leave(KWspErrBearerNotSupported);
} break;
}
++index;
}
// Is there a port
if( iRedirectAddr.iHasPort )
{
// Get the port - this is 16 bit number...
iRedirectAddr.iPort = STATIC_CAST(TUint16, (aRedirectedAddresses[index] << KByteLength) + aRedirectedAddresses[index+1]);
__LOG1("--Redirected to port %d", iRedirectAddr.iPort)
index += KPortLength;
}
// Get the proxy address, and format according to the bearer
TPtrC8 proxyAddress = aRedirectedAddresses.Mid(index, addressLength);
if (iRedirectAddr.iBearer == Wap::EIP)
{
if (addressLength < 4)
{
// Oops not enough data - leave
__DEBUGTESTLEAVE
User::Leave(KWspErrBadRedirectedAddressData);
}
iRedirectAddr.iProxyAddress.Format(_L8("%i.%i.%i.%i"),
proxyAddress[0],
proxyAddress[1],
proxyAddress[2],
proxyAddress[3]);
}
else // do a straight copy for anything else since not sure what to expect - a phone number for SMS?
iRedirectAddr.iProxyAddress.Copy(proxyAddress);
__LOG1("--Redirected to proxy address %S", &(iRedirectAddr.iProxyAddress))
}