|
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 } |