applayerprotocols/httpexamples/nwsswsptrhnd/CNwssWspCOSession.cpp
changeset 0 b16258d2340f
equal deleted inserted replaced
-1:000000000000 0:b16258d2340f
       
     1 // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 
       
    17 // System includes
       
    18 #include <http/mhttpdatasupplier.h>
       
    19 #include <httpstringconstants.h>
       
    20 #include <wsp/mwspsessionheadersprovider.h>
       
    21 #include <wsp/mwspcomethodcallback.h>
       
    22 #include <wsp/mwspcosessioncallback.h>
       
    23 #include <wsp/mwspcapabilityprovider.h>
       
    24 #include <wsp/mwspcapabilityviewer.h>
       
    25 #include <wsp/mwspcapabilitysetter.h>
       
    26 #include <wsp/mwspaliasaddresses.h>
       
    27 #include <wsp/mwspextendedmethods.h>
       
    28 #include <wsp/mwspheadercodepages.h>
       
    29 #include <wsp/mwspunknowncapabilities.h>
       
    30 #include <wsp/wsptypes.h>
       
    31 #include <wsperror.h>
       
    32 #include <capcodec.h>
       
    33 #include <uri8.h>
       
    34 #include <http/framework/logging.h>
       
    35 
       
    36 // Local includes
       
    37 #include "tnwsswsptrhndpanic.h"
       
    38 #include "mconnectioninfoprovider.h"
       
    39 #include "cnwsswspcoeventdispatcher.h"
       
    40 #include "cnwsswsptrhnddatasupplier.h"
       
    41 #include "cnwssconnectguard.h"
       
    42 #include "cnwsswsptransactioneventfilter.h"
       
    43 #include "cnwsswspsessioneventfilter.h"
       
    44 #include "testoom.h"
       
    45 
       
    46 // Class signature
       
    47 #include "cnwsswspcosession.h"
       
    48 
       
    49 // Constants used in this file
       
    50 const TInt KMaxUriLength = 256;
       
    51 const TUint KSessDataChunkSize = 256;
       
    52 const TUint KTransLUTSize = 4;
       
    53 const TInt KMaxCapabilityDataSize = 256;
       
    54 const TUint32 KMaxClientSDUSize = 30000;
       
    55 const TUint32 KMaxServerSDUSize = 30000;
       
    56 //
       
    57 _LIT8(KGet, "GET");
       
    58 _LIT8(KPost, "POST");
       
    59 _LIT8(KHead, "HEAD");
       
    60 _LIT8(KTrace, "TRACE");
       
    61 _LIT8(KOptions, "OPTIONS");
       
    62 _LIT8(KPut, "PUT");
       
    63 _LIT8(KDelete, "DELETE");
       
    64 
       
    65 
       
    66 CNwssWspCOSession* CNwssWspCOSession::NewL(RStringPool& aStringPool,
       
    67 										   MNwssWapServer& aWapStackProvider,
       
    68 										   MConnectionInfoProvider& aConnInfoProvider,
       
    69 										   MSecurityPolicy& aSecurityPolicy,
       
    70 										   MWspCOSessionCallback& aSessionCB)
       
    71 	{
       
    72 	CNwssWspCOSession* me = new(ELeave)CNwssWspCOSession(aStringPool,
       
    73 														 aWapStackProvider,
       
    74 														 aConnInfoProvider,
       
    75 														 aSecurityPolicy,
       
    76 														 aSessionCB);
       
    77 	CleanupStack::PushL(me);
       
    78 	me->ConstructL();
       
    79 	CleanupStack::Pop(me);
       
    80 	return me;
       
    81 	}
       
    82 
       
    83 CNwssWspCOSession::~CNwssWspCOSession()
       
    84 	{
       
    85 	// It is important that the client correctly disconnects sessions before deleting the transport
       
    86 	// handler.
       
    87 #ifdef _DEBUG
       
    88 	if( State() != CNwssWspSession::EDisconnected )
       
    89 		{
       
    90 		// WSP session could be suspended
       
    91 		RWSPCOConn::TSessionState state;
       
    92 		iWspCOSession.GetSessionState(state);
       
    93 		
       
    94 #ifndef __UNIT_TESTING__
       
    95 		__ASSERT_DEBUG(state == RWSPCOConn::ESuspended, 
       
    96 					TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EConnectedUponDestruction));
       
    97 #endif
       
    98 		}
       
    99 #endif
       
   100 
       
   101 	if( State() != CNwssWspSession::EDisconnected )
       
   102 		// Ensure everything is closed down.  Since we're destructing, we don't care about
       
   103 		// errors in this callback.
       
   104 		(void)SessionDisconnectedCallback();
       
   105 
       
   106 	if (iConnectGuard)
       
   107 		iConnectGuard->Cancel();
       
   108 	if (iTransEventFilter)
       
   109 		iTransEventFilter->Cancel();
       
   110 	if( iSessionEventFilter )
       
   111 		iSessionEventFilter->Cancel();
       
   112 	// Clean up
       
   113 
       
   114 	delete iCOTransTable;
       
   115 	delete iTransEventFilter;
       
   116 	delete iSessionEventFilter;
       
   117 	delete iEventDispatcher;
       
   118 	delete iCapabilityCodec;
       
   119 	delete iUriBuffer;
       
   120 	delete iSessDataBuffer;
       
   121 	delete iConnectGuard;
       
   122 	delete iOOMCallBack;
       
   123 	__CLOSELOG
       
   124 	}
       
   125 
       
   126 CNwssWspCOSession::CNwssWspCOSession(RStringPool& aStringPool,
       
   127 								     MNwssWapServer& aWapStackProvider,
       
   128 								     MConnectionInfoProvider& aConnInfoProvider,
       
   129 									 MSecurityPolicy& aSecurityPolicy,
       
   130 									 MWspCOSessionCallback& aSessionCB)
       
   131 	: CNwssWspSession(aStringPool, aWapStackProvider, aConnInfoProvider, aSecurityPolicy),
       
   132 	  iSessionCB(aSessionCB)
       
   133 	{
       
   134 	__OPENLOG("http", "nwsswsptrhnd.txt")
       
   135 	__LOG_TITLE("WSP Transport Handler (NWSS bindings) Log")
       
   136 	}
       
   137 
       
   138 void CNwssWspCOSession::ConstructL()
       
   139 	{
       
   140 	BaseConstructL();
       
   141 
       
   142 	// Create the transaction look-up table with a default initial size.  Create
       
   143 	// the event dispatcher and capability codec.
       
   144 	iCOTransTable = CNwssTransLookUpTable::NewL(KTransLUTSize);
       
   145 	iTransEventFilter = CNwssWspTransactionEventFilter::NewL(*iCOTransTable, *this, KTransLUTSize);
       
   146 	iSessionEventFilter = CNwssWspSessionEventFilter::NewL(*iCOTransTable, *this, *this);
       
   147 	iEventDispatcher = CNwssWspCOEventDispatcher::NewL(iWspCOSession, *iSessionEventFilter, *iTransEventFilter, *this);
       
   148 	iCapabilityCodec = CCapCodec::NewL();
       
   149 
       
   150 	// Create scratch buffers
       
   151 	iUriBuffer = HBufC::NewL(KMaxUriLength);
       
   152 	iSessDataBuffer = HBufC8::NewL(KSessDataChunkSize);
       
   153 
       
   154 	// Create the connect guard
       
   155 	iConnectGuard = CNwssConnectGuard::NewL(*this, iSessionCB);
       
   156 
       
   157 	// Create the one shot used if OOM occurs during a MethodInvoke or Connect
       
   158 	iOOMCallBack = new (ELeave)CAsyncCallBack(CActive::EPriorityStandard);
       
   159 	}
       
   160 
       
   161 
       
   162 /*
       
   163  * Session Invocation API. 
       
   164  */
       
   165 void CNwssWspCOSession::ConnectReq()
       
   166 	{
       
   167 	__LOG("Received S-Connect.req primitive")
       
   168 
       
   169 	// Set connect limbo flag. This indicates that the S-Connect.req has been
       
   170 	// received but not yet sent to the WAP Stack.
       
   171 	iInConnectLimbo = ETrue;
       
   172 
       
   173 	// All this stuff will be broken out, into different states in the parent class
       
   174 	// This method will just request from its parent that the connection process is
       
   175 	// started.  The parent, as an AO, will go through the various stages in its RunL.
       
   176 	// That will involve calls down to this class to allow the connection to be
       
   177 	// completed.
       
   178 
       
   179 	InitiateProxyConnection();
       
   180 	}
       
   181 
       
   182 TInt CNwssWspCOSession::OpenWspSession(const TDesC8& aRemoteHost,
       
   183 									   RWAPConn::TPort aRemotePort,
       
   184 									   RWAPConn::TPort aLocalPort,
       
   185 									   TBearer aBearer,
       
   186 									   TBool aSecureConn)
       
   187 	{
       
   188 	// Open a WSP CO connection with the WAP stack
       
   189 	__TESTOOMD(error, iWspCOSession.Open(iWapStackProvider.WapStack(), aRemoteHost, aRemotePort, aLocalPort, aBearer, aSecureConn));
       
   190 	return error;	  
       
   191 	}
       
   192 
       
   193 TInt CNwssWspCOSession::CloseWspSession()
       
   194 	{
       
   195 	iEventDispatcher->Cancel();
       
   196 	iWspCOSession.CancelAll();
       
   197 	__TESTOOMD(stkErr, iWspCOSession.Close());
       
   198 	return stkErr;
       
   199 	}
       
   200 
       
   201 void CNwssWspCOSession::CompleteProxyConnectionL()
       
   202 	{
       
   203 	__LOG("Sending S-Connect.req primitive")
       
   204 
       
   205 	// Obtain the client headers
       
   206 	MWspSessionHeadersProvider& prov = iConnInfoProvider.SessionHeadersProvider();
       
   207 	const TDesC8& cliHdr = prov.ClientHeaders();
       
   208 	__LOG("--Client session headers are:")
       
   209 	__DUMP("--", "--", cliHdr)
       
   210 
       
   211 	// Prepare the client's proposed capabilities
       
   212 	PrepareClientCapabilities();
       
   213 
       
   214 	// Request a connection to the proxy
       
   215 	__TESTOOMD(error, iWspCOSession.Connect(cliHdr, iCapabilityCodec));
       
   216 	__LOG1("--RWSPCOConn::Connect() returned with %d", error)
       
   217 	User::LeaveIfError(error);
       
   218 
       
   219 	// Ensure the event dispatcher is waiting for stack events
       
   220 	iEventDispatcher->Start();
       
   221 
       
   222 	// Unset the connect limbo flag - sent S-Connect.req to WAP Stack.
       
   223 	iInConnectLimbo = EFalse;
       
   224 
       
   225 	// Send the waiting method invoke (if exists)
       
   226 	iConnectGuard->SendMethodInvokeReq();
       
   227 	}
       
   228 
       
   229 RWTLS CNwssWspCOSession::WtlsHnd()
       
   230 	{
       
   231 	return iWspCOSession.Wtls();
       
   232 	}
       
   233 
       
   234 void CNwssWspCOSession::DoRunError(TInt aError)
       
   235 	{
       
   236 	// Handling from the parent class state machine's RunError.
       
   237 	// In all cases, this means that a ConnectReq() call in this class has failed.
       
   238 	// Hence, a connection will never be possible with the gateway, and we should
       
   239 	// indicate this to the client using DisconnectInd() to ensure their own notion of
       
   240 	// the session state is correct.  The WTLS failure mode (aError) is indicated
       
   241 	// using the disconnect reason.
       
   242 	__ASSERT_DEBUG( iInConnectLimbo, User::Invariant() );
       
   243 
       
   244 	__LOG("Returning S-Disconnect.ind primitive")
       
   245 
       
   246 	// Convert the error code to a WSP reason
       
   247 	TWspReason reason = Wap::EConnectErr;
       
   248 	switch (aError)
       
   249 		{
       
   250 	case KWtlsErrConfigurationFailed:
       
   251 		__LOG("--reason: KWtlsErrConfigurationFailed")
       
   252 		reason = Wap::EWtlsConfigurationFailed;
       
   253 		break;
       
   254 	case KWtlsErrPhase1HandshakeFailed:
       
   255 		__LOG("--reason: KWtlsErrPhase1HandshakeFailed")
       
   256 		reason = Wap::EWtlsPhase1HandshakeFailed;
       
   257 		break;
       
   258 	case KWtlsErrPhase2HandshakeFailed:
       
   259 		__LOG("--reason: KWtlsErrPhase2HandshakeFailed")
       
   260 		reason = Wap::EWtlsPhase2HandshakeFailed;
       
   261 		break;
       
   262 	case KWtlsErrInvalidServerCert:
       
   263 		__LOG("--reason: KWtlsErrInvalidServerCert")
       
   264 		reason = Wap::EWtlsInvalidServerCert;
       
   265 		break;
       
   266 	case KWtlsErrUntrustedServerCert:
       
   267 		__LOG("--reason: KWtlsErrUntrustedServerCert")
       
   268 		reason = Wap::EWtlsUntrustedServerCert;
       
   269 		break;
       
   270 	case KWtlsErrNegotiatedConfigRejected:
       
   271 		__LOG("--reason: KWtlsErrNegotiatedConfigRejected")
       
   272 		reason = Wap::EWtlsNegotiatedConfigRejected;
       
   273 		break;
       
   274 	case KErrNoMemory:
       
   275 		__LOG("--reason: KErrNoMemory")
       
   276 		reason = Wap::EOutOfMemory;
       
   277 		break;
       
   278 	default:
       
   279 		;
       
   280 		}
       
   281 	// Need to send S-Disconnect.ind - should deal with an invoked method
       
   282 	// if it exists.
       
   283 	iConnectGuard->SendDisconnectInd(reason);
       
   284 
       
   285 	// Unset the connect limbo flag.
       
   286 	iInConnectLimbo = EFalse;
       
   287 	}
       
   288 
       
   289 TBool CNwssWspCOSession::SubDoCancel()
       
   290 	{
       
   291 	// Called from the parent class DoCancel().  Cancel the outstanding requests in this class.
       
   292 	iEventDispatcher->Cancel();
       
   293 
       
   294 	// We don't want to return to a disconnected state after this.
       
   295 	return EFalse;
       
   296 	}
       
   297 
       
   298 void CNwssWspCOSession::DisconnectReq(TWspReason aReason)
       
   299 	{
       
   300 	__ASSERT_DEBUG(State() != CNwssWspSession::EDisconnected,
       
   301 					TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInvalidState));
       
   302 	__LOG("Sending S-Disconnect.req primitive")
       
   303 
       
   304 	// Check to see if the S-Connect.req has been sent to the WAP Stack
       
   305 	if( iInConnectLimbo )
       
   306 		{
       
   307 		__LOG("---In connect limbo - cannot send S-Disconnect.req.")
       
   308 		__LOG("---Cancelling proxy connection process.")
       
   309 		// No, still trying to connect - cancel the proxy connection
       
   310 		Cancel();
       
   311 
       
   312 		// Need to send S-Disconnect.ind - should deal with an invoked method
       
   313 		// if it exists.
       
   314 		iConnectGuard->SendDisconnectInd(aReason);
       
   315 
       
   316 		// Unset the connect limbo flag.
       
   317 		iInConnectLimbo = EFalse;
       
   318 		return;
       
   319 		}
       
   320 	// Request a disconnect
       
   321 	__ASSERT_DEBUG(State() == CNwssWspSession::EReady,
       
   322 					TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInvalidState));
       
   323 	__TESTOOMD(error, iWspCOSession.Disconnect());	  
       
   324 
       
   325 	// Handle OOM separately - we can recover from it.
       
   326 	if (error == KErrNoMemory)
       
   327 		{
       
   328 		ScheduleDelayedOomDisconnect(EFalse);
       
   329 		return;
       
   330 		}
       
   331 	__ASSERT_ALWAYS(error == KErrNone, MapToPanic(error));
       
   332 
       
   333 	// Inform the transaction event filter that S-Disconnect.req has been sent
       
   334 	iTransEventFilter->SessionDisconnectRequested();
       
   335 
       
   336 	// Ensure the event dispatcher is waiting for stack events
       
   337 	iEventDispatcher->Start();
       
   338 	}
       
   339 
       
   340 void CNwssWspCOSession::SuspendReq()
       
   341 	{
       
   342 	__LOG("Sending S-Suspend.req primitive")
       
   343 
       
   344 	// Request suspension
       
   345 	__TESTOOMD(error, iWspCOSession.Suspend());	  
       
   346 	__ASSERT_ALWAYS(error == KErrNone, MapToPanic(error));
       
   347 
       
   348 	// Ensure the event dispatcher is waiting for stack events
       
   349 	iEventDispatcher->Start();
       
   350 	}
       
   351 
       
   352 void CNwssWspCOSession::ResumeReq()
       
   353 	{
       
   354 	__LOG("Sending S-Resume.req primitive")
       
   355 
       
   356 	// Obtain the (possibly updated) client headers
       
   357 	MWspSessionHeadersProvider& prov = iConnInfoProvider.SessionHeadersProvider();
       
   358 	const TDesC8& cliHdr = prov.ClientHeaders();
       
   359 	__LOG("--Client session headers are:")
       
   360 	__DUMP("--", "--", cliHdr)
       
   361 
       
   362 	// Request session resume.  Needs a blank RWSPCOConn - what to do with this?
       
   363 	//@todo - this may require considerable work...
       
   364 	RWSPCOConn blankConn;
       
   365 	__TESTOOMD(error, iWspCOSession.Resume(blankConn, cliHdr));
       
   366 	__ASSERT_ALWAYS(error == KErrNone, MapToPanic(error));
       
   367 
       
   368 	// Ensure the event dispatcher is waiting for stack events
       
   369 	iEventDispatcher->Start();
       
   370 	}
       
   371 
       
   372 /*
       
   373  * Method Invocation API. 
       
   374  */
       
   375 
       
   376 void CNwssWspCOSession::MethodInvokeReq(
       
   377 								MWspCOMethodCallback&		aMethodCallback, 
       
   378 								RStringF					aMethod, 
       
   379 								const TUriC8&				aRequestUri, 
       
   380 								const TDesC8&				aRequestHeaders, 
       
   381 								const TDesC8&				aRequestBody,
       
   382 								TBool						aMoreData
       
   383 								)
       
   384 	{
       
   385 	__LOG("Sending T-MethodInvoke.req primitive")
       
   386 #ifdef __DEBUG
       
   387 	if( aMoreData )
       
   388 		{
       
   389 		__LOG("Attempt to send T-MethodInvoke.req primitive failed because")
       
   390 		__LOG("Large Data Transfer is not supported in this WAP Stack.")
       
   391 		}
       
   392 #endif
       
   393 	__ASSERT_ALWAYS( !aMoreData, TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::ELargeDataTransferNotSupported) );
       
   394 
       
   395 	if( iInConnectLimbo )
       
   396 		{
       
   397 		__LOG("--In connect limbo - cannot send T-MethodInvoke.req.")
       
   398 		__LOG("--Save information for later...")
       
   399 
       
   400 		TRAPD(error, __DEBUGTESTLEAVE \
       
   401 					  iConnectGuard->ReceivedMethodInvokeReqL(
       
   402 														 aMethodCallback,
       
   403 														 aMethod,
       
   404 														 aRequestUri,
       
   405 														 aRequestHeaders,
       
   406 														 aRequestBody
       
   407 														 ) );
       
   408 		__ASSERT_ALWAYS( error == KErrNone, TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EDeferedMethodFailed) );
       
   409 		return;
       
   410 		}
       
   411 
       
   412 	__ASSERT_ALWAYS(iWspCOSession.SubSessionHandle() != KNullHandle, TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::ESessionNotConnected));
       
   413 
       
   414 	RWAPConn::TMethod method = RWAPConn::EGet;
       
   415 	const TDesC8& methodName = aMethod.DesC();
       
   416 	__LOG1("--Method is '%S'", &methodName);
       
   417 	if (methodName.CompareF(KGet) == 0)
       
   418 		method = RWAPConn::EGet;
       
   419 	else if (methodName.CompareF(KPost) == 0)
       
   420 		method = RWAPConn::EPost;
       
   421 	else if (methodName.CompareF(KHead) == 0)
       
   422 		method = RWAPConn::EHead;
       
   423 	else if (methodName.CompareF(KTrace) == 0)
       
   424 		method = RWAPConn::ETrace;
       
   425 	else if (methodName.CompareF(KOptions) == 0)
       
   426 		method = RWAPConn::EOptions;
       
   427 	else if (methodName.CompareF(KPut) == 0)
       
   428 		method = RWAPConn::EPut;
       
   429 	else if (methodName.CompareF(KDelete) == 0)
       
   430 		method = RWAPConn::EDelete;
       
   431 	else
       
   432 		// @todo  -  extension methods?
       
   433 		TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EUnknownMethod);
       
   434 
       
   435 	// Convert the URI to Unicode
       
   436 	__LOG1("--URI is '%S'", &(aRequestUri.UriDes()));
       
   437 	if (aRequestUri.UriDes().Length() > KMaxUriLength)
       
   438 		TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EURIOverflow);
       
   439 	iUriBuffer->Des().Copy(aRequestUri.UriDes());
       
   440 
       
   441 	// Log headers
       
   442 	__LOG("--Encoded WSP header is:")
       
   443 	__DUMP("--", "--", aRequestHeaders)
       
   444 
       
   445 	// Log body data
       
   446 	__LOG("--Body data is:")
       
   447 	__DUMP("--", "--", aRequestBody)
       
   448 
       
   449 	// Get the next look-up table entry for the new transaction
       
   450 	CNwssTransLookUpTable::CNwssTransLUTEntry& entry = iCOTransTable->NewEntry();
       
   451 	entry.iCallback = &aMethodCallback;
       
   452 
       
   453 	// Create the WSP transaction on the WAP stack, and handle any resulting error
       
   454 	__TESTOOMD(error, iWspCOSession.CreateTransaction(method, *iUriBuffer, aRequestHeaders, aRequestBody, entry.iStackTrans));
       
   455 	__LOG1("--RWSPCOConn::CreateTransaction() returned %d", error);
       
   456 
       
   457 	// Handle OOM separately - we can recover from it.
       
   458 	if (error == KErrNoMemory)
       
   459 		{
       
   460 		ScheduleDelayedOomMethodAbort(*(entry.iCallback), EFalse);
       
   461 		return;
       
   462 		}
       
   463 	else
       
   464 		// But any other error is due to a client programming error, so panic
       
   465 		__ASSERT_ALWAYS(error == KErrNone, MapToPanic(error));
       
   466 
       
   467 	// Get the transaction ID
       
   468 	error = entry.iStackTrans.Id(entry.iStackTransID);
       
   469 	__LOG1("--RWSPCOTrans::Id() returned %d", error);
       
   470 	__ASSERT_ALWAYS(error == KErrNone, MapToPanic(error));
       
   471 	__LOG1("--Transaction Id is %d", entry.iStackTransID);
       
   472 
       
   473 	// Ensure the event dispatcher is waiting for stack events
       
   474 	iEventDispatcher->Start();
       
   475 	}
       
   476 
       
   477 void CNwssWspCOSession::MethodInvokeDataReq(
       
   478 									MWspCOMethodCallback&	/*aTransactionCallback*/,
       
   479 									const TDesC8&			/*aRequestBody*/,
       
   480 									const TDesC8&			/*aTrailerHeaders*/,
       
   481 									TBool					/*aMoreData*/
       
   482 									)	
       
   483 	{
       
   484 	__LOG("Attempt to send T-MethodInvokeData.req primitive failed because")
       
   485 	__LOG("Large Data Transfer is not supported in this WAP Stack.")
       
   486 	TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::ELargeDataTransferNotSupported);
       
   487 	}
       
   488 
       
   489 void CNwssWspCOSession::MethodAbortReq(MWspCOMethodCallback& aMethodCallback)
       
   490 	{
       
   491 	__LOG("Sending T-MethodAbort.req primitive")
       
   492 
       
   493 	// Check to see if the T-MethodInvoke.req primitive has been sent
       
   494 	if( iInConnectLimbo )
       
   495 		{
       
   496 		__LOG("--In connect limbo - cannot send T-MethodAbort.req.")
       
   497 		__LOG("--Delete waiting method")
       
   498 
       
   499 		// Send the T-MethodAbort.ind
       
   500 		iConnectGuard->SendMethodAbortInd();
       
   501 		return;
       
   502 		}
       
   503 
       
   504 	TBool found = EFalse;
       
   505 	CNwssTransLookUpTable::CNwssTransLUTEntry& lutEntry = iCOTransTable->LookUpByCallback(aMethodCallback,
       
   506 																  found);
       
   507 	if (found)
       
   508 		{
       
   509 		__LOG1("--Transaction Id is %d", lutEntry.iStackTransID);
       
   510 
       
   511 		// Abort the transaction - choose an abort reason from the WSP spec since
       
   512 		// <wapcli.h> doesn't enumerate it  :(
       
   513 		// Unfortunately the NWSS stack moves the state to 'Done' prematurely, so
       
   514 		// check for that now.
       
   515 		RWSPCOTrans::TState trState = RWSPCOTrans::EInit;
       
   516 		__TESTOOMD(stkErr, lutEntry.iStackTrans.GetState(trState));
       
   517 		__LOG1("--Transaction is in state %d", trState);
       
   518 		__LOG1("--RWSPCOTrans::GetState() returned %d", stkErr);
       
   519 		if (trState != RWSPCOTrans::EDone)
       
   520 			{
       
   521 			__TESTOOM(stkErr, lutEntry.iStackTrans.Abort(EUserReq));
       
   522 			__LOG1("--RWSPCOTrans::Abort() returned %d", stkErr);
       
   523 
       
   524 			// Ensure the event dispatcher is waiting for stack events
       
   525 			iEventDispatcher->Start();
       
   526 			}
       
   527 		else
       
   528 			{
       
   529 			// The NWSS stack has already received the T-MethodResult.ind for this
       
   530 			// transaction and it won't allow it to be aborted. But the client
       
   531 			// expects the T-MethodAbort.ind to 'finish' the method.
       
   532 			__LOG("--Cannot abort transaction, need to create T-MethodAbort.ind event");
       
   533 
       
   534 			iTransEventFilter->SendMethodAbortIndEvent(lutEntry.iStackTransID);
       
   535 			}
       
   536 		__ASSERT_ALWAYS(stkErr == KErrNone,
       
   537 			TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EFailedToAbortTrans));
       
   538 		}
       
   539 	}
       
   540 
       
   541 void CNwssWspCOSession::MethodResultRes(
       
   542 								MWspCOMethodCallback&	aMethodCallback, 
       
   543 								const TDesC8&			aAckHeaders
       
   544 								)
       
   545 	{
       
   546 	__LOG("Sending T-MethodResult.res primitive")
       
   547 	TBool found = EFalse;
       
   548 	CNwssTransLookUpTable::CNwssTransLUTEntry& lutEntry = iCOTransTable->LookUpByCallback(aMethodCallback, found);
       
   549 	if (found)
       
   550 		{
       
   551 		__LOG1("--Transaction Id is %d", lutEntry.iStackTransID);
       
   552 
       
   553 		// If the 'use acknowledgment headers' capability was negotiated with the
       
   554 		// proxy, then do so now
       
   555 		if (iUseAckHdrs)
       
   556 			{
       
   557 			__LOG("--Acknowledgement headers:");
       
   558 			__DUMP("--", "--", aAckHeaders);
       
   559 			__TESTOOMD(stkErr, lutEntry.iStackTrans.Acknowledge(aAckHeaders));
       
   560 			__LOG1("--RWSPCOTrans::Acknowledge() returned %d", stkErr);
       
   561 			__ASSERT_ALWAYS(stkErr == KErrNone,
       
   562 				TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EFailedToAcknowledgeTrans));
       
   563 			}
       
   564 
       
   565 		// Now release the transaction
       
   566 		__TESTOOMD(stkErr, lutEntry.iStackTrans.Release());
       
   567 		__LOG1("--RWSPCOTrans::Release() returned %d", stkErr);
       
   568 
       
   569 		// If release failed due to OOM, then send a MethodAbort-ind (OOM)
       
   570 		if (stkErr == KErrNoMemory)
       
   571 			{
       
   572 			ScheduleDelayedOomMethodAbort(*(lutEntry.iCallback), EFalse);
       
   573 			stkErr = KErrNone;
       
   574 			}
       
   575 		else
       
   576 			{
       
   577 			__ASSERT_ALWAYS(stkErr == KErrNone,
       
   578 				TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EFailedToReleaseTrans));
       
   579 
       
   580 			// Ensure the event dispatcher is waiting for stack events
       
   581 			iEventDispatcher->Start();
       
   582 			}
       
   583 
       
   584 		// Remove the entry from the look-up table - this deletes the data supplier object
       
   585 		iCOTransTable->RemoveEntry(*(lutEntry.iCallback));
       
   586 		}
       
   587 	}
       
   588 
       
   589 void CNwssWspCOSession::MethodResultDataRes(
       
   590 									MWspCOMethodCallback&	/*aMethodCallback*/, 
       
   591 									const TDesC8&			/*aAckHeaders*/
       
   592 									)
       
   593 	{
       
   594 	__LOG("Attempt to send T-MethodResultData.res primitive failed because")
       
   595 	__LOG("Large Data Transfer is not supported in this WAP Stack.")
       
   596 	TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::ELargeDataTransferNotSupported);
       
   597 	}
       
   598 
       
   599 void CNwssWspCOSession::PrepareClientCapabilities()
       
   600 	{
       
   601 	__LOG("--Client's Requested Capabilities:");
       
   602 	__LOG("----------------------------------");
       
   603 
       
   604 	// Get all the capability handles from the client
       
   605 	MWspCapabilityProvider& capsProv = iConnInfoProvider.CapabilityProvider();
       
   606 	const MWspCapabilityViewer& cliCaps = capsProv.ClientCapabilities();
       
   607 
       
   608 	// The NWSS WAP Stack doesn't support LDT, so cliMsgSize and svrMsgSize will be
       
   609 	// ignored.  This transport handler doesn't currently support Push, so pushMOR
       
   610 	// will be ignored.
       
   611 
       
   612 	// Mask out all but the acknowledgement and suspend/resume capabilities -
       
   613 	// we don't support push yet, and the current NWSS stack doesn't support LDT.
       
   614 	TUint8 protOpts = cliCaps.GetProtocolOptions();
       
   615 	protOpts &= (Wap::EAcknowledgementHeaders | Wap::ESessionResumeFacility);
       
   616 	__LOG1("--Protocol options = %2x", protOpts);
       
   617 
       
   618 	// Everything else is straightforward
       
   619 	TUint8 methodMOR = cliCaps.GetMethodMOR();
       
   620 	__LOG1("--Method MOR = %d", methodMOR);
       
   621 	TUint32 cliSDUSize = cliCaps.GetClientSDUSize();
       
   622 	__LOG1("--Client SDU Size = %d", cliSDUSize);
       
   623 	TUint32 svrSDUSize = cliCaps.GetServerSDUSize();
       
   624 	__LOG1("--Server SDU Size = %d", svrSDUSize);
       
   625 	const MWspAliasAddresses& aliasAddrs = cliCaps.GetAliasAddresses();
       
   626 	const MWspExtendedMethods& extMethods = cliCaps.GetExtendedMethods();
       
   627 	const MWspHeaderCodePages& hdrCodePages = cliCaps.GetHeaderCodePages();
       
   628 	const MWspUnknownCapabilities& unknownCaps = cliCaps.GetUnknownCapabilities();
       
   629 
       
   630 	// Work around SDU size limitation in this WAP stack
       
   631 	if (cliSDUSize > KMaxClientSDUSize)
       
   632 		cliSDUSize = KMaxClientSDUSize;
       
   633 	if (svrSDUSize > KMaxServerSDUSize)
       
   634 		svrSDUSize = KMaxServerSDUSize;
       
   635 
       
   636 	// Trival ones first
       
   637 	iCapabilityCodec->SetMethodMOR(methodMOR);
       
   638 	iCapabilityCodec->SetProtocolOptions(protOpts);
       
   639 	iCapabilityCodec->SetClientSDUSize(cliSDUSize);
       
   640 	iCapabilityCodec->SetServerSDUSize(svrSDUSize);
       
   641 
       
   642 	// Alias addresses
       
   643 	Wap::TWspBearer bearer;
       
   644 	TUint16 port;
       
   645 	TPtrC8 address;
       
   646 	aliasAddrs.Start();
       
   647 	while (aliasAddrs.GetNext(bearer, port, address) != KErrNotFound)
       
   648 		{
       
   649 		__LOG3("--Alias Address: bearer = %d, port = %d, address = %S", bearer, port, &address);
       
   650 		TAliasAddress addr;
       
   651 		addr.SetBearer((unsigned char)bearer);
       
   652 		addr.SetPort(port);
       
   653 		TInt err = addr.SetAddress(address);
       
   654 		__ASSERT_DEBUG(err == KErrNone,
       
   655 					   TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
       
   656 		err = iCapabilityCodec->AddAliasAddress(addr);
       
   657 		__ASSERT_DEBUG(err == KErrNone,
       
   658 					   TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
       
   659 		}
       
   660 
       
   661 	// For the remaining non-trivial capabilities, we unfortunately have to make a copy
       
   662 	// of the descriptor data into a writable buffer, since the CCapCodec API mandates
       
   663 	// a TDes8-derived descriptor for data, even though only CCapCodec Set-fns are
       
   664 	// being used!
       
   665 	TBuf8<KMaxCapabilityDataSize> capData;
       
   666 	
       
   667 	// Extended methods
       
   668 	TUint8 pduType;
       
   669 	TPtrC8 methodName;
       
   670 	extMethods.Start();
       
   671 	while (extMethods.GetNext(pduType, methodName) != KErrNotFound)
       
   672 		{
       
   673 		__LOG2("--Extended Method: pduType = %d, methodName = %S", pduType, &methodName);
       
   674 		__ASSERT_ALWAYS(methodName.Length() < KMaxCapabilityDataSize,
       
   675 						TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::ECapabilityOverrun));
       
   676 		capData.Copy(methodName);
       
   677 #ifdef _DEBUG
       
   678 		TInt err =
       
   679 #endif
       
   680 			iCapabilityCodec->AddExtendedMethod(capData, pduType);
       
   681 		__ASSERT_DEBUG(err == KErrNone,
       
   682 					   TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
       
   683 		}
       
   684 
       
   685 	// Header code pages
       
   686 	TUint8 pageCode;
       
   687 	TPtrC8 pageName;
       
   688 	hdrCodePages.Start();
       
   689 	while (hdrCodePages.GetNext(pageCode, pageName) != KErrNotFound)
       
   690 		{
       
   691 		__LOG2("--Header Code Page: pageCode = %d, pageName = %S", pageCode, &pageName);
       
   692 		__ASSERT_ALWAYS(pageName.Length() < KMaxCapabilityDataSize,
       
   693 						TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::ECapabilityOverrun));
       
   694 		capData.Copy(pageName);
       
   695 #ifdef _DEBUG
       
   696 		TInt err =
       
   697 #endif
       
   698 			iCapabilityCodec->AddCodePage(capData, pageCode);
       
   699 		__ASSERT_DEBUG(err == KErrNone,
       
   700 					   TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
       
   701 		}
       
   702 
       
   703 	// Unknown capabilities
       
   704 	TPtrC8 identifier;
       
   705 	TPtrC8 value;
       
   706 	unknownCaps.Start();
       
   707 	while (unknownCaps.GetNext(identifier, value) != KErrNotFound)
       
   708 		{
       
   709 		__LOG2("--Unknown Capability: identifier = %S, value = %S", &identifier, &value);
       
   710 		__ASSERT_ALWAYS(identifier.Length() < KMaxCapabilityDataSize,
       
   711 						TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::ECapabilityOverrun));
       
   712 		capData.Copy(identifier);
       
   713 #ifdef _DEBUG
       
   714 		TInt err =
       
   715 #endif
       
   716 			iCapabilityCodec->AddUnknownCap(capData, value);
       
   717 		__ASSERT_DEBUG(err == KErrNone,
       
   718 					   TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
       
   719 		}
       
   720 	__LOG("----------------------------------");
       
   721 	}
       
   722 
       
   723 void CNwssWspCOSession::SetNegotiatedCapabilitiesL()
       
   724 	{
       
   725 	__LOG("--Proxy's Negotiated Capabilities:");
       
   726 	__LOG("----------------------------------");
       
   727 
       
   728 	// Get the encoded capabilites from the session data, and pass to the codec
       
   729 	__DEBUGTESTLEAVE
       
   730 	HBufC8* encodedCaps = GetAllSessionDataLC(RWSPCOConn::ECapabilities);
       
   731 	__LOG("--Encoded data:");
       
   732 	__DUMP("--", "--", (*encodedCaps));
       
   733 	CCapCodec* negCapsCodec = CCapCodec::NewL(*encodedCaps);
       
   734 	CleanupStack::PushL(negCapsCodec);
       
   735 
       
   736 	// Get all the capability handles from the client
       
   737 	MWspCapabilityProvider& capsProv = iConnInfoProvider.CapabilityProvider();
       
   738 	MWspCapabilitySetter& negCaps = capsProv.ServerCapabilities();
       
   739 	negCaps.Reset(EAllCapabilities);
       
   740 
       
   741 	// Trivial ones first - keep a copy of method MOR and protocol opts (acks flag)
       
   742 	TUint32 protOpts;
       
   743 	negCapsCodec->GetProtocolOptions(protOpts);
       
   744 	TUint8 protOpts8 = STATIC_CAST(TUint8, protOpts);
       
   745 	negCaps.SetProtocolOptions(protOpts8);
       
   746 	__LOG1("--Protocol options = %2x", protOpts);
       
   747 	iUseAckHdrs = ((protOpts & Wap::EAcknowledgementHeaders) == Wap::EAcknowledgementHeaders);
       
   748 	//
       
   749 	negCapsCodec->MethodMOR(iMethodMOR);
       
   750 	negCaps.SetMethodMOR(iMethodMOR);
       
   751 	__LOG1("--Method MOR = %d", iMethodMOR);
       
   752 	//
       
   753 	// We don't support the Message size capability, but we know the client might, so
       
   754 	// set it to the same as the negotiated SDU size
       
   755 	TUint32 size;
       
   756 	negCapsCodec->ClientSDUSize(size);
       
   757 	negCaps.SetClientSDUSize(size);
       
   758 	negCaps.SetClientMessageSize(size);
       
   759 	__LOG1("--Client SDU Size = %d", size);
       
   760 	//
       
   761 	negCapsCodec->GetServerSDUSize(size);
       
   762 	negCaps.SetServerSDUSize(size);
       
   763 	negCaps.SetServerMessageSize(size);
       
   764 	__LOG1("--Server SDU Size = %d", size);
       
   765 
       
   766 	// Now the more complex ones - alias addresses first
       
   767 	TInt numAliasAddrs = 0;
       
   768 	negCapsCodec->NumAliasAddress(numAliasAddrs);
       
   769 	TInt idx = 0; 
       
   770 	for (idx = 0; idx < numAliasAddrs; ++idx)
       
   771 		{
       
   772 		TAliasAddress address;
       
   773 		TInt err = negCapsCodec->GetAliasAddress(idx, address);
       
   774 		__ASSERT_DEBUG(err == KErrNone,
       
   775 					   TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
       
   776 		if (!err)
       
   777 			{
       
   778 			Wap::TWspBearer bearer = Wap::EIP;
       
   779 			if (address.HasBearer())
       
   780 				bearer = (Wap::TWspBearer)address.Bearer();
       
   781 			TUint16 port = 0;
       
   782 			if (address.HasPort())
       
   783 				port = address.Port();
       
   784 			__DEBUGTESTLEAVE
       
   785 			negCaps.AddAliasAddressL(bearer, port, address.Address());
       
   786 			__LOG3("--Alias Address: bearer = %d, port = %d, address = %S", bearer, port, &(address.Address()));
       
   787 			}
       
   788 		}
       
   789 
       
   790 	// For the remaining non-trivial capabilities, we need a writable buffer to place
       
   791 	// certain values into.  Sadly the CCapCodec API offers no means of finding out how
       
   792 	// big particular values need to be before calling...
       
   793 	TBuf8<KMaxCapabilityDataSize> capData;
       
   794 	
       
   795 	// Extended methods
       
   796 	TInt numExtMethods = 0;
       
   797 	negCapsCodec->NumExtendedMethods(numExtMethods);
       
   798 	for (idx = 0; idx < numExtMethods; ++idx)
       
   799 		{
       
   800 		TUint8 val;
       
   801 		TInt err = negCapsCodec->GetExtendedMethod(idx, capData, val);
       
   802 		__ASSERT_DEBUG(err == KErrNone,
       
   803 					   TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
       
   804 		if (!err)
       
   805 			{
       
   806 			__DEBUGTESTLEAVE
       
   807 			negCaps.AddExtendedMethodL(val, capData);
       
   808 			__LOG2("--Extended Method: pduType = %d, methodName = %S", val, &capData);
       
   809 			}
       
   810 		}
       
   811 
       
   812 	// Code pages
       
   813 	TInt numCodePages = 0;
       
   814 	negCapsCodec->NumCodePages(numCodePages);
       
   815 	for (idx = 0; idx < numCodePages; ++idx)
       
   816 		{
       
   817 		TUint8 val;
       
   818 		TInt err = negCapsCodec->GetCodePage(idx, capData, val);
       
   819 		__ASSERT_DEBUG(err == KErrNone,
       
   820 					   TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
       
   821 		if (!err)
       
   822 			{
       
   823 			__DEBUGTESTLEAVE
       
   824 			negCaps.AddHeaderCodePageL(val, capData);
       
   825 			__LOG2("--Header Code Page: pageCode = %d, pageName = %S", val, &capData);
       
   826 			}
       
   827 		}
       
   828 
       
   829 	// Unknown capabilities
       
   830 	TInt numUnknownCaps = 0;
       
   831 	negCapsCodec->NumUnkownCap(numUnknownCaps); // sic
       
   832 	TBuf8<KMaxCapabilityDataSize> unknownCapVal;
       
   833 	for (idx = 0; idx < numUnknownCaps; ++idx)
       
   834 		{
       
   835 		TInt err = negCapsCodec->GetUnknownCap(idx, capData, unknownCapVal);
       
   836 		__ASSERT_DEBUG(err == KErrNone,
       
   837 					   TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInternalCapCodecError));
       
   838 		if (!err)
       
   839 			{
       
   840 			__LOG2("--Unknown Capability: identifier = %S, value = %S", &unknownCapVal, &capData);
       
   841 			__DEBUGTESTLEAVE
       
   842 			negCaps.AddUnknownCapabilityL(unknownCapVal, capData);
       
   843 			}
       
   844 		}
       
   845 
       
   846 	// Cleanup
       
   847 	CleanupStack::PopAndDestroy(2, encodedCaps); // and negCapsCodec
       
   848 	__LOG("----------------------------------");
       
   849 	}
       
   850 
       
   851 void CNwssWspCOSession::HandleDisconnectIndL()
       
   852 	{
       
   853 	__LOG("Received S-Disconnect.ind primitive")
       
   854 
       
   855 	// Get the disconnection reason buffer from the session data
       
   856 	TPckgBuf<TUint8> disconReasonBuff;
       
   857 	TInt stkErr = GetSessionData(disconReasonBuff, RWSPCOConn::EDisconReason);
       
   858 	if (stkErr == KErrNoMemory)
       
   859 		{
       
   860 		ScheduleDelayedOomDisconnect(EFalse);
       
   861 		return;
       
   862 		}
       
   863 	__ASSERT_ALWAYS(stkErr == KErrNone, MapToPanic(stkErr));
       
   864 	Wap::TWspReason disconReason = (Wap::TWspReason)disconReasonBuff();
       
   865 
       
   866 	// Get the error header/body buffers from the session data
       
   867 	__DEBUGTESTLEAVE
       
   868 	HBufC8* errorHdrs = GetAllSessionDataLC(RWSPCOConn::EErrorHeaders);		
       
   869 	__DEBUGTESTLEAVE
       
   870 	HBufC8* errorBody = GetAllSessionDataLC(RWSPCOConn::EErrorBody);
       
   871 
       
   872 	// Inform the transaction event filter that S-Disconnect.ind has been received.
       
   873 	iTransEventFilter->SessionDisconnected();
       
   874 
       
   875 	// Do it
       
   876 	TWspRedirectedAddress emptyAddr;
       
   877 	DoSendDisconnectInd(disconReason, EFalse, emptyAddr, *errorHdrs, *errorBody);
       
   878 
       
   879 	// Clean up
       
   880 	CleanupStack::PopAndDestroy(2, errorHdrs);
       
   881 	}
       
   882 
       
   883 void CNwssWspCOSession::DoSendDisconnectInd(Wap::TWspReason			aReason, 
       
   884 										  TBool						aRedirectSecurity, 
       
   885 										  TWspRedirectedAddress&	aRedirectAddress, 
       
   886 										  const TDesC8&				aErrorHeader, 
       
   887 										  const TDesC8&				aErrorBody)
       
   888 	{
       
   889 	// Send the disconnect indication _after_ informing the parent class that we're disconnected
       
   890 	// This may seem to be the wrong order, but if there is any failure in the parent class to
       
   891 	// maintain the session state correctly (e.g. due to OOM in the WAP Stack) then the disconnect
       
   892 	// reason is transformed to one which indicates the state failure.
       
   893 	// Notify the client of the session event
       
   894 	TInt error = SessionDisconnectedCallback();
       
   895 	if (error != KErrNone)
       
   896 		aReason = Wap::ESessionStateFailure;
       
   897 
       
   898 	iSessionCB.DisconnectInd(aReason, aRedirectSecurity, aRedirectAddress, aErrorHeader, aErrorBody);
       
   899 	}
       
   900 
       
   901 void CNwssWspCOSession::HandleSuspendIndL()
       
   902 	{
       
   903 	__LOG("Received S-Suspend.ind primitive")
       
   904 
       
   905 	// Get the suspend reason buffer from the session data
       
   906 	TPckgBuf<TUint8> suspendReasonBuff;
       
   907 	TInt stkErr = GetSessionData(suspendReasonBuff, RWSPCOConn::ESuspendReason);
       
   908 	if (stkErr == KErrNoMemory)
       
   909 		{
       
   910 		ScheduleDelayedOomDisconnect(EFalse);
       
   911 		return;
       
   912 		}
       
   913 	__ASSERT_ALWAYS(stkErr == KErrNone, MapToPanic(stkErr));
       
   914 	Wap::TWspReason suspendReason = (Wap::TWspReason)suspendReasonBuff();
       
   915 
       
   916 	// Notify the client of the session event
       
   917 	iSessionCB.SuspendInd(suspendReason);
       
   918 	}
       
   919 
       
   920 void CNwssWspCOSession::HandleResumeCnfL()
       
   921 	{
       
   922 	__LOG("Received S-Resume.cnf primitive")
       
   923 
       
   924 	// Notify the client of the session event
       
   925 	iSessionCB.ResumeCnf();
       
   926 	}
       
   927 
       
   928 void CNwssWspCOSession::HandleConnectCnfL()
       
   929 	{
       
   930 	__LOG("Received S-Connect.cnf primitive")
       
   931 
       
   932 	// Inform the client of the negotiated capabilities
       
   933 	__DEBUGTESTLEAVE
       
   934 	SetNegotiatedCapabilitiesL();
       
   935 
       
   936 	// Inform the client of the server's session headers
       
   937 	MWspSessionHeadersProvider& prov = iConnInfoProvider.SessionHeadersProvider();
       
   938 	__DEBUGTESTLEAVE
       
   939 	HBufC8* serverHeaders = GetAllSessionDataLC(RWSPCOConn::EServerHeaders);
       
   940 	prov.SetServerHeadersL(*serverHeaders);
       
   941 	__LOG("--Server session headers are:")
       
   942 	__DUMP("--", "--", (*serverHeaders))
       
   943 	CleanupStack::PopAndDestroy(serverHeaders);
       
   944 	
       
   945 	// Resize the transaction look-up table to match the MethodMOR capability for
       
   946 	// the session (which might be greater than the original table size)
       
   947 	__DEBUGTESTLEAVE
       
   948 	iCOTransTable->ResizeTableL(iMethodMOR);
       
   949 
       
   950 	// Also, resize the trans Id table in the transaction filter.
       
   951 	__DEBUGTESTLEAVE
       
   952 	iTransEventFilter->ResizeTableL(iMethodMOR);
       
   953 
       
   954 	// Notify the client of the session event
       
   955 	iSessionCB.ConnectCnf();
       
   956 	}
       
   957 
       
   958 void CNwssWspCOSession::HandleRedirectIndL()
       
   959 	{
       
   960 	__LOG("Received S-Disconnect.ind (redirection) primitive")
       
   961 
       
   962 	// Notify the client of the session event.  Note that this event
       
   963 	// is really sent using DisconnectInd, as specified in [WSP]. The
       
   964 	// NWSS wap stack has simplified things by presenting it as a new
       
   965 	// event 'RedirectInd', which isn't defined in [WSP] at all.
       
   966 
       
   967 	// Get the redirection options buffer from the session data
       
   968 	TPckgBuf<TUint8> redirOptsBuff;
       
   969 	TInt stkErr = GetSessionData(redirOptsBuff, RWSPCOConn::ERedirectOptions);
       
   970 	if (stkErr == KErrNoMemory)
       
   971 		{
       
   972 		ScheduleDelayedOomDisconnect(EFalse);
       
   973 		return;
       
   974 		}
       
   975 	__ASSERT_ALWAYS(stkErr == KErrNone, MapToPanic(stkErr));
       
   976 	
       
   977 	// Check for the permanent/temporary flag and the 'Reuse Security
       
   978 	// Session' flag
       
   979 	TBool permanentRedirect = ((redirOptsBuff() & 0x80) != 0);
       
   980 	TBool redirectSecurity  = ((redirOptsBuff() & 0x40) != 0);
       
   981 
       
   982 	// Set the disconnect reason to temporary/permanent redirection
       
   983 	TWspReason disconReason = permanentRedirect?
       
   984 							  EPermanentRedirectedProxy:
       
   985 							  ETemporaryRedirectedProxy;
       
   986 
       
   987 	// Get the redirection address(es) buffer from the session data
       
   988 	__DEBUGTESTLEAVE
       
   989 	HBufC8* redirAddr = GetAllSessionDataLC(RWSPCOConn::ERedirectAddresses);		
       
   990 
       
   991 	// Convert the descriptor into a parsed form stored in iRedirectAddr
       
   992 	__DEBUGTESTLEAVE
       
   993 	ExtractRedirectedProxyInfoL(*redirAddr);
       
   994 
       
   995 	// Don't bother with error headers or body for redirection.
       
   996 	// Notify the client of the session event
       
   997 	DoSendDisconnectInd(disconReason, redirectSecurity, iRedirectAddr,
       
   998 							 KNullDesC8(), KNullDesC8());
       
   999 	// Clean up
       
  1000 	CleanupStack::PopAndDestroy(redirAddr);
       
  1001 	}
       
  1002 
       
  1003 void CNwssWspCOSession::HandleExceptionIndL()
       
  1004 	{
       
  1005 	__LOG("Received E-Exception.ind primitive")
       
  1006 
       
  1007 	// Notify the client of the session event.  Note that the exception data is
       
  1008 	// not available from the NWSS WAP stack, so send empty data instead.
       
  1009 	iSessionCB.ExceptionInd(KNullDesC8());
       
  1010 	}
       
  1011 
       
  1012 void CNwssWspCOSession::HandleMethodInvokeCnfL(RWSPCOTrans::TTransID aTransId)
       
  1013 	{
       
  1014 	__LOG("Received T-MethodInvoke.cnf primitive")
       
  1015 
       
  1016 	// Look-up the transaction by ID
       
  1017 	TBool found = EFalse;
       
  1018 	CNwssTransLookUpTable::CNwssTransLUTEntry& lutEntry = iCOTransTable->LookUpByTransId(aTransId, found);
       
  1019 	__ASSERT_DEBUG(found,
       
  1020 			TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EEventOnUnknownTransaction));
       
  1021 	__LOG1("--Transaction Id is %d", lutEntry.iStackTransID);
       
  1022 
       
  1023 	// Inform the client of the transaction event
       
  1024 	lutEntry.iCallback->MethodInvokeCnf();
       
  1025 	}
       
  1026 
       
  1027 void CNwssWspCOSession::HandleMethodResultIndL(RWSPCOTrans::TTransID aTransId)
       
  1028 	{
       
  1029 	__LOG("Received T-MethodResult.ind primitive")
       
  1030 
       
  1031 	// Look-up the transaction by ID
       
  1032 	TBool found = EFalse;
       
  1033 	CNwssTransLookUpTable::CNwssTransLUTEntry& lutEntry = iCOTransTable->LookUpByTransId(aTransId, found);
       
  1034 	__ASSERT_DEBUG(found,
       
  1035 			TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EEventOnUnknownTransaction));
       
  1036 	__LOG1("--Transaction Id is %d", lutEntry.iStackTransID);
       
  1037 
       
  1038 	// Get the WSP status code.  This is expected to be a single byte, in one buffer.
       
  1039 	TPckgBuf<TUint8> status;
       
  1040 	TInt stkErr = GetTransactionData(lutEntry.iStackTrans, status, RWSPCOTrans::EResultStatus);
       
  1041 	if (stkErr == KErrNoMemory)
       
  1042 		{
       
  1043 		ScheduleDelayedOomMethodAbort(*(lutEntry.iCallback), EFalse);
       
  1044 		return;
       
  1045 		}
       
  1046 	
       
  1047 	// Get the response headers
       
  1048 	__DEBUGTESTLEAVE
       
  1049 	HBufC8* respHdrs = GetAllTransactionDataLC(lutEntry.iStackTrans, RWSPCOTrans::EResultHeaders);
       
  1050 	__LOG("--Result Header is:")
       
  1051 	__DUMP("--", "--", (*respHdrs))
       
  1052 
       
  1053 	// Create a response body data supplier to stream the response body back to the
       
  1054 	// client.  Associate it with the transaction in the look-up table.
       
  1055 	lutEntry.iResponseBodyHandler = CNwssWspTrHndDataSupplier::NewL(lutEntry.iStackTrans, *this);
       
  1056 
       
  1057 	// Inform the client of the transaction event
       
  1058 	lutEntry.iCallback->MethodResultInd(status(),
       
  1059 										*respHdrs,
       
  1060 										*(lutEntry.iResponseBodyHandler),
       
  1061 										EFalse);
       
  1062 
       
  1063 	// Clean up
       
  1064 	CleanupStack::PopAndDestroy(respHdrs);
       
  1065 	}
       
  1066 
       
  1067 void CNwssWspCOSession::HandleAbortIndL(RWSPCOTrans::TTransID aTransId)
       
  1068 	{
       
  1069 	__LOG("Received T-MethodAbort.ind primitive")
       
  1070 
       
  1071 	// Look-up the transaction by ID
       
  1072 	TBool found = EFalse;
       
  1073 	CNwssTransLookUpTable::CNwssTransLUTEntry& lutEntry = iCOTransTable->LookUpByTransId(aTransId, found);
       
  1074 	__ASSERT_DEBUG(found,
       
  1075 			TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EEventOnUnknownTransaction));
       
  1076 	__LOG1("--Transaction Id is %d", lutEntry.iStackTransID);
       
  1077 
       
  1078 	TInt stkErr = KErrNone;
       
  1079 #ifdef _DEBUG
       
  1080 	// Check the state
       
  1081 	RWSPCOTrans::TState trState = RWSPCOTrans::EInit;
       
  1082 	__TESTOOM(stkErr, lutEntry.iStackTrans.GetState(trState));
       
  1083 	__LOG1("--Transaction is in state %d", trState);
       
  1084 	__LOG1("--RWSPCOTrans::GetState() returned %d", stkErr);
       
  1085 #endif
       
  1086 
       
  1087 	// Now release the transaction
       
  1088 	__TESTOOM(stkErr, lutEntry.iStackTrans.Release());
       
  1089 	__LOG1("--RWSPCOTrans::Release() returned %d", stkErr);
       
  1090 	__ASSERT_ALWAYS(stkErr == KErrNone,
       
  1091 		TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EFailedToReleaseTrans));
       
  1092 
       
  1093 	// The WAP stack can't provide abort reasons, so we use a hardcoded one.
       
  1094 	// Inform the client of the aborted transaction
       
  1095 	lutEntry.iCallback->MethodAbortInd(Wap::EPeerReq);
       
  1096 
       
  1097 	// Remove the entry from the look-up table - this deletes the data supplier object
       
  1098 	iCOTransTable->RemoveEntry(*(lutEntry.iCallback));
       
  1099 	}
       
  1100 
       
  1101 void CNwssWspCOSession::ScheduleDelayedOomMethodAbort(MWspCOMethodCallback& aMethodToAbort,
       
  1102 													  TBool aAbortOnStack)
       
  1103 	{
       
  1104 	iAbortPckg.iSession  = CONST_CAST(CNwssWspCOSession*, this);
       
  1105 	iAbortPckg.iCallback = &aMethodToAbort;
       
  1106 	iAbortPckg.iAbortOnStack = aAbortOnStack;
       
  1107   	TCallBack delayedMethodAbortCB(CNwssWspCOSession::DelayedSendOomMethodAbort, (TAny*)(&iAbortPckg));
       
  1108   	iOOMCallBack->Set(delayedMethodAbortCB);
       
  1109   	iOOMCallBack->CallBack();
       
  1110 	}
       
  1111 
       
  1112 TInt CNwssWspCOSession::DelayedSendOomMethodAbort(TAny* aPtr)
       
  1113   	{
       
  1114 	TDelayedMethodAbortPckg* pckg = REINTERPRET_CAST(TDelayedMethodAbortPckg*, aPtr);
       
  1115   	CNwssWspCOSession* sess  = pckg->iSession;
       
  1116 	MWspCOMethodCallback* cb = pckg->iCallback;
       
  1117 	TBool stkAbort = pckg->iAbortOnStack;
       
  1118 	sess->SendOomMethodAbort(*cb, stkAbort);
       
  1119   	return KErrNone;
       
  1120 	}
       
  1121 
       
  1122 void CNwssWspCOSession::SendOomMethodAbort(MWspCOMethodCallback& aMethodToAbort, TBool /*aAbortOnStack*/)
       
  1123 	{
       
  1124 	// The abort reason is hardcoded to 'EOutOfMemory'.
       
  1125 	// Inform the client of the aborted transaction
       
  1126 	aMethodToAbort.MethodAbortInd(Wap::EOutOfMemory);
       
  1127 
       
  1128 	// Remove the entry from the look-up table - this deletes the data supplier object
       
  1129 	iCOTransTable->RemoveEntry(aMethodToAbort);
       
  1130 	}
       
  1131 
       
  1132 void CNwssWspCOSession::SendOomMethodAbort(RWSPCOTrans::TTransID aTransId, TBool aAbortOnStack)
       
  1133 	{
       
  1134 	// Look-up the transaction by ID
       
  1135 	TBool found = EFalse;
       
  1136 	CNwssTransLookUpTable::CNwssTransLUTEntry& lutEntry = iCOTransTable->LookUpByTransId(aTransId, found);
       
  1137 	if (found)
       
  1138 		{
       
  1139 		__LOG1("--Transaction Id is %d", lutEntry.iStackTransID);
       
  1140 
       
  1141 		// Re-use the other variant
       
  1142 		SendOomMethodAbort(*(lutEntry.iCallback), aAbortOnStack);
       
  1143 		}
       
  1144 #ifdef _DEBUG
       
  1145 	else
       
  1146 		__LOG1("--Unknown transaction Id %d - ignoring OOM method abort", aTransId);
       
  1147 #endif
       
  1148 	}
       
  1149 
       
  1150 void CNwssWspCOSession::ScheduleDelayedOomDisconnect(TBool aDisconnectOnStack)
       
  1151 	{
       
  1152 	iDisconnectPckg.iSession  = CONST_CAST(CNwssWspCOSession*, this);
       
  1153 	iDisconnectPckg.iDisconnectOnStack = aDisconnectOnStack;
       
  1154   	TCallBack delayedDisconnectCB(CNwssWspCOSession::DelayedSendOomDisconnect, (TAny*)(&iDisconnectPckg));
       
  1155   	iOOMCallBack->Set(delayedDisconnectCB);
       
  1156   	iOOMCallBack->CallBack();
       
  1157 	}
       
  1158 
       
  1159 TInt CNwssWspCOSession::DelayedSendOomDisconnect(TAny* aPtr)
       
  1160   	{
       
  1161 	TDelayedDisconnectPckg* pckg = REINTERPRET_CAST(TDelayedDisconnectPckg*, aPtr);
       
  1162   	CNwssWspCOSession* sess  = pckg->iSession;
       
  1163 	TBool stkDisconn = pckg->iDisconnectOnStack;
       
  1164 	sess->SendOomDisconnect(stkDisconn);
       
  1165   	return KErrNone;
       
  1166 	}
       
  1167 
       
  1168 void CNwssWspCOSession::SendOomDisconnect(TBool aDisconnectOnStack)
       
  1169 	{
       
  1170 	// First, disconnect from the stack if directed - necessary in some cases
       
  1171 	// to keep the client and the WAP stack's session state in sync.
       
  1172 	if (aDisconnectOnStack)
       
  1173 		DisconnectReq(Wap::EOutOfMemory);
       
  1174 
       
  1175 	// Inform the transaction event filter that S-Disconnect.ind has been received.
       
  1176 	iTransEventFilter->SessionDisconnected();
       
  1177 
       
  1178 	// The disconnect reason is hardcoded to 'EOutOfMemory'.
       
  1179 	// Inform the client that the session has been disconnected
       
  1180 	TWspRedirectedAddress emptyAddr;
       
  1181 	DoSendDisconnectInd(Wap::EOutOfMemory, EFalse, emptyAddr, KNullDesC8(),KNullDesC8());
       
  1182 	}
       
  1183 
       
  1184 TInt CNwssWspCOSession::GetSessionData(TDes8& aBuffer,
       
  1185 									   RWSPCOConn::TSessionDataType aType)
       
  1186 	{
       
  1187 	__TESTOOMD(stkErr, iWspCOSession.GetSessionData(aBuffer, aType));
       
  1188 	__LOG1("--RWSPCOConn::GetSessionData() returned %d", stkErr);
       
  1189 	return stkErr;
       
  1190 	}
       
  1191 
       
  1192 HBufC8* CNwssWspCOSession::GetAllSessionDataLC(RWSPCOConn::TSessionDataType aType)
       
  1193 	{
       
  1194 	// Allocate the buffer to be returned. This will be expanded as necessary.
       
  1195 	HBufC8* scratchBuff = HBufC8::NewLC(KSessDataChunkSize);
       
  1196 	TPtr8 scratchPtr = scratchBuff->Des();
       
  1197 	TPtr8 sessDataPtr = iSessDataBuffer->Des();
       
  1198 
       
  1199 	// Get the initial chunk of session data
       
  1200 	__TESTOOMD(stkErr, iWspCOSession.GetSessionData(scratchPtr, aType));
       
  1201 	__LOG1("--RWSPCOConn::GetSessionData() returned %d", stkErr);
       
  1202 	while (stkErr == RWAPConn::EMoreData)
       
  1203 		{
       
  1204 		// The buffer wasn't big enough - try reallocating.  This will leave if
       
  1205 		// it fails to get a big enough chunk, and the working buffer will be
       
  1206 		// cleaned up on the way out.
       
  1207 		HBufC8* oldScratchBuff = scratchBuff;
       
  1208 		__DEBUGTESTLEAVE
       
  1209 		scratchBuff = oldScratchBuff->ReAllocL(scratchBuff->Length() +
       
  1210 											   KSessDataChunkSize);
       
  1211 		CleanupStack::Pop(oldScratchBuff);
       
  1212 		CleanupStack::PushL(scratchBuff);
       
  1213 
       
  1214 		// There's more data to extract. Use the iSessionData buffer to get the
       
  1215 		// subsequent chunks
       
  1216 		__TESTOOM(stkErr, iWspCOSession.GetSessionData(sessDataPtr, aType));
       
  1217 		__LOG1("--RWSPCOConn::GetSessionData() returned %d", stkErr);
       
  1218 		if ((stkErr == KErrNone) || (stkErr == RWAPConn::EMoreData))
       
  1219 			{
       
  1220 			// Got some data - append it to the scratch buffer
       
  1221 			scratchPtr.Set(scratchBuff->Des());
       
  1222 			scratchPtr.Append(*iSessDataBuffer);
       
  1223 			}
       
  1224 		}
       
  1225 
       
  1226 	// We don't deal with other errors from the WAP stack here - the final stkErr
       
  1227 	// value must be KErrNone indicating the final block of session data extracted OK.
       
  1228 	__DEBUGTESTLEAVE
       
  1229 	User::LeaveIfError(stkErr);
       
  1230 	return scratchBuff;
       
  1231 	}
       
  1232 
       
  1233 TInt CNwssWspCOSession::GetTransactionData(RWSPCOTrans aTransaction,
       
  1234 										   TDes8& aBuffer,
       
  1235 										   RWSPCOTrans::TDataType aType)
       
  1236 	{
       
  1237 	TInt bytesRemaining = 0;
       
  1238 	__TESTOOMD(stkErr, aTransaction.GetData(aBuffer, aType, &bytesRemaining));
       
  1239 	__LOG1("--RWSPCOTrans::GetData() returned %d", stkErr);
       
  1240 	__ASSERT_ALWAYS(bytesRemaining == 0, TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EFailedToGetTransactionData));
       
  1241 	return stkErr;
       
  1242 	}
       
  1243 
       
  1244 HBufC8* CNwssWspCOSession::GetAllTransactionDataLC(RWSPCOTrans aTransaction,
       
  1245 												   RWSPCOTrans::TDataType aType)
       
  1246 	{
       
  1247 	// Allocate the buffer to be returned. This will be expanded as necessary.
       
  1248 	HBufC8* scratchBuff = HBufC8::NewLC(KSessDataChunkSize);
       
  1249 	TPtr8 scratchPtr = scratchBuff->Des();
       
  1250 	TPtr8 sessDataPtr = iSessDataBuffer->Des();
       
  1251 
       
  1252 	// Get the initial chunk of session data
       
  1253 	TInt bytesRemaining = 0;
       
  1254 	__TESTOOMD(stkErr, aTransaction.GetData(scratchPtr, aType, &bytesRemaining));
       
  1255 	__LOG1("--RWSPCOTrans::GetData() returned %d", stkErr);
       
  1256 	while (stkErr == RWAPConn::EMoreData)
       
  1257 		{
       
  1258 		// The buffer wasn't big enough - try reallocating.  This will leave if
       
  1259 		// it fails to get a big enough chunk, and the working buffer will be
       
  1260 		// cleaned up on the way out.  Try to get all the rest in one go.
       
  1261 		HBufC8* oldScratchBuff = scratchBuff;
       
  1262 		__DEBUGTESTLEAVE
       
  1263 		scratchBuff = oldScratchBuff->ReAllocL(scratchBuff->Length() +
       
  1264 											   bytesRemaining);
       
  1265 		CleanupStack::Pop(oldScratchBuff);
       
  1266 		CleanupStack::PushL(scratchBuff);
       
  1267 
       
  1268 		// There's more data to extract. Use the iSessionData buffer to get the
       
  1269 		// subsequent chunks
       
  1270 		__TESTOOM(stkErr, aTransaction.GetData(sessDataPtr, aType, &bytesRemaining));
       
  1271 		__LOG1("--RWSPCOTrans::GetData() returned %d", stkErr);
       
  1272 		if ((stkErr == KErrNone) || (stkErr == RWAPConn::EMoreData))
       
  1273 			{
       
  1274 			// Got some data - append it to the scratch buffer
       
  1275 			scratchPtr.Set(scratchBuff->Des());
       
  1276 			scratchPtr.Append(*iSessDataBuffer);
       
  1277 			}
       
  1278 		}
       
  1279 
       
  1280 	// We don't deal with other errors from the WAP stack here - the final stkErr
       
  1281 	// value must be KErrNone indicating the final block of session data extracted OK.
       
  1282 	__DEBUGTESTLEAVE
       
  1283 	User::LeaveIfError(stkErr);
       
  1284 	return scratchBuff;
       
  1285 	}
       
  1286 
       
  1287 void CNwssWspCOSession::ExtractRedirectedProxyInfoL(const TDesC8& aRedirectedAddresses)
       
  1288 	{
       
  1289 	const TUint8 KBearerMask			= 0x80;
       
  1290 	const TUint8 KPortMask				= 0x40;
       
  1291 	const TUint8 KAddressLengthMask		= 0x3F;
       
  1292 	const TInt KPortLength				= 2;
       
  1293 	const TUint8 KBearerAny				= 0x00;
       
  1294 	const TUint8 KBearerSMS				= 0x03;
       
  1295 	const TUint8 KBearerCSD				= 0x0A;
       
  1296 	const TUint8 KBearerGPRS			= 0x0B;
       
  1297 	const TInt KByteLength				= 8;
       
  1298 
       
  1299 	// Extract bearer and port presence and address length from first byte
       
  1300 	TInt index = 0;
       
  1301 	TUint8 byte = aRedirectedAddresses[index];
       
  1302 	iRedirectAddr.iHasBearer = byte & KBearerMask;
       
  1303 	iRedirectAddr.iHasPort = byte & KPortMask;
       
  1304 	TInt addressLength = byte & KAddressLengthMask;
       
  1305 
       
  1306 	++index;
       
  1307 
       
  1308 	// Extract bearer and port - update the length of data
       
  1309 	TInt dataLength = index + addressLength;
       
  1310 	if( iRedirectAddr.iHasBearer )
       
  1311 		{
       
  1312 		// Bearer present - increment length
       
  1313 		++dataLength;
       
  1314 		}
       
  1315 	if( iRedirectAddr.iHasPort )
       
  1316 		{
       
  1317 		// Port present - increase length by KPortLength
       
  1318 		dataLength += KPortLength;
       
  1319 		}
       
  1320 
       
  1321 	// Check to see if there is enough data - if not 'aRedirectedAddresses' wasn't well-formed.
       
  1322 	if( dataLength > aRedirectedAddresses.Length() )
       
  1323 		{
       
  1324 		// Oops not enough data - leave
       
  1325 		__LOG("--Redirect data is corrupt - not enough to extract an address")
       
  1326 		__DEBUGTESTLEAVE
       
  1327 		User::Leave(KWspErrBadRedirectedAddressData);
       
  1328 		}
       
  1329 
       
  1330 	// Is there a bearer
       
  1331 	if( iRedirectAddr.iHasBearer )
       
  1332 		{
       
  1333 		TUint8 bearerType = aRedirectedAddresses[index];
       
  1334 		switch (bearerType)
       
  1335 			{
       
  1336 			case KBearerSMS:
       
  1337 				{
       
  1338 				// According to WDP spec, this is GMS network using SMS bearer
       
  1339 				iRedirectAddr.iBearer = Wap::EWAPSMS;
       
  1340 				__LOG("--Redirected to bearer WAPSMS");
       
  1341 				} break;
       
  1342 			case KBearerCSD:
       
  1343 			case KBearerGPRS:
       
  1344 			case KBearerAny:
       
  1345 				{
       
  1346 				// According to WDP spec, this is GMS network using CDS bearer 
       
  1347 				// (0x0A), or using a GPRS bearer (0x0B).
       
  1348 				iRedirectAddr.iBearer = Wap::EIP;
       
  1349 #ifdef _DEBUG
       
  1350 				if (bearerType == KBearerCSD)
       
  1351 					__LOG("--Redirected to bearer CSD - using IPv4")
       
  1352 				else if (bearerType == KBearerGPRS)
       
  1353 					__LOG("--Redirected to bearer GPRS - using IPv4")
       
  1354 				else if (bearerType == KBearerAny)
       
  1355 					__LOG("--Redirected to bearer 'any' - using IPv4")
       
  1356 #endif 
       
  1357 				} break;
       
  1358 			default:
       
  1359 				{
       
  1360 				// Bearer not supported - leave
       
  1361 				__LOG("--Redirected to unknown bearer");
       
  1362 				__DEBUGTESTLEAVE
       
  1363 				User::Leave(KWspErrBearerNotSupported);
       
  1364 				} break;
       
  1365 			}
       
  1366 		++index;
       
  1367 		}
       
  1368 	// Is there a port
       
  1369 	if( iRedirectAddr.iHasPort )
       
  1370 		{
       
  1371 		// Get the port -  this is 16 bit number...
       
  1372 		iRedirectAddr.iPort = STATIC_CAST(TUint16, (aRedirectedAddresses[index] << KByteLength) + aRedirectedAddresses[index+1]);
       
  1373 		__LOG1("--Redirected to port %d", iRedirectAddr.iPort)
       
  1374 		index += KPortLength;
       
  1375 		}
       
  1376 
       
  1377 	// Get the proxy address, and format according to the bearer
       
  1378 	TPtrC8 proxyAddress = aRedirectedAddresses.Mid(index, addressLength);
       
  1379 	if (iRedirectAddr.iBearer == Wap::EIP)
       
  1380 		{
       
  1381 		if (addressLength < 4)
       
  1382 			{
       
  1383 			// Oops not enough data - leave
       
  1384 			__DEBUGTESTLEAVE
       
  1385 			User::Leave(KWspErrBadRedirectedAddressData);
       
  1386 			}
       
  1387 		iRedirectAddr.iProxyAddress.Format(_L8("%i.%i.%i.%i"),
       
  1388 											proxyAddress[0],
       
  1389 											proxyAddress[1],
       
  1390 											proxyAddress[2],
       
  1391 											proxyAddress[3]);
       
  1392 		}
       
  1393 	else // do a straight copy for anything else since not sure what to expect - a phone number for SMS?
       
  1394 		iRedirectAddr.iProxyAddress.Copy(proxyAddress);
       
  1395 
       
  1396 	__LOG1("--Redirected to proxy address %S", &(iRedirectAddr.iProxyAddress))
       
  1397 	}