--- /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 <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))
+ }