diff -r 000000000000 -r b16258d2340f applayerprotocols/httpexamples/nwsswsptrhnd/CNwssWspCOSession.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/applayerprotocols/httpexamples/nwsswsptrhnd/CNwssWspCOSession.cpp Tue Feb 02 01:09:52 2010 +0200 @@ -0,0 +1,1397 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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 + // 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 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 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 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 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 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 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 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)) + }