|
1 // Copyright (c) 2001-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 #include "csocketreader.h" |
|
17 |
|
18 #include "csocket.h" |
|
19 #include "msocketcontroller.h" |
|
20 #include "minputstreamobserver.h" |
|
21 #include "httptransporthandlercommon.h" |
|
22 #include "thttptrlayerpanic.h" |
|
23 #include "chttpasyncwaiter.h" |
|
24 |
|
25 CSocketReader* CSocketReader::NewL(CSocket& aSocket, MSocketController& aController, TInt aRecvBufferSize, TBool aPriority) |
|
26 /** |
|
27 The factory constructor. |
|
28 @param aSocket The connected socket. This owned by the observer. |
|
29 @param aController The socket controller that owns the socket. |
|
30 @return A pointer to a fully constructed object. |
|
31 @internalComponent |
|
32 */ |
|
33 { |
|
34 CSocketReader* self = new (ELeave) CSocketReader(aSocket, aController, aPriority); |
|
35 CleanupStack::PushL(self); |
|
36 self->ConstructL( aRecvBufferSize ); |
|
37 CleanupStack::Pop(self); |
|
38 return self; |
|
39 } |
|
40 |
|
41 void CSocketReader::ConstructL( TInt aRecvBufferSize ) |
|
42 { |
|
43 iBuffer.CreateL ( aRecvBufferSize ); |
|
44 } |
|
45 |
|
46 CSocketReader::~CSocketReader() |
|
47 /** |
|
48 Destructor. |
|
49 @internalComponent |
|
50 */ |
|
51 { |
|
52 __ASSERT_DEBUG( iState == EIdle || iState == EClosed, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadInputStreamState) ); |
|
53 |
|
54 //Delete the Timer Object. |
|
55 delete iReceiveTimer; |
|
56 |
|
57 // Cancel any outstanding requests |
|
58 Cancel(); |
|
59 iBuffer.Close (); |
|
60 // __FLOG_CLOSE; |
|
61 } |
|
62 |
|
63 CSocketReader::CSocketReader(CSocket& aSocket, MSocketController& aController, TBool aPriority) |
|
64 : CActive(CActive::EPriorityStandard), iSocket(aSocket), iController(aController) |
|
65 /** |
|
66 Constructor. |
|
67 @param aSocket The connected socket. This owned by the observer. |
|
68 @param aController The socket controller that owns the socket. |
|
69 @internalComponent |
|
70 */ |
|
71 { |
|
72 if(aPriority) |
|
73 { |
|
74 CActive::SetPriority(CActive::EPriorityHigh); |
|
75 } |
|
76 CActiveScheduler::Add(this); |
|
77 |
|
78 // __FLOG_OPEN("http", "httptransporthandler.txt"); |
|
79 } |
|
80 |
|
81 void CSocketReader::CompleteSelf() |
|
82 /** |
|
83 Requests that the input stream complete itself. This will caused the RunL() |
|
84 to be called by the scheduler at the next opportunity. |
|
85 @pre The input stream is not active. |
|
86 @post The input stream object is active and the request has been |
|
87 completed. |
|
88 @internalComponent |
|
89 */ |
|
90 { |
|
91 TRequestStatus* pStat = &iStatus; |
|
92 User::RequestComplete(pStat, KErrNone); |
|
93 SetActive(); |
|
94 } |
|
95 |
|
96 void CSocketReader::SocketClosed(TInt aError) |
|
97 /** |
|
98 Notifies the input stream that the socket is closed. The input stream |
|
99 observer is notified that the stream is closed. No more data can be received |
|
100 from the socket. |
|
101 @param aError The error code explaining why the socket has closed. A |
|
102 value of KErrNone indicates that the output stream |
|
103 observer requested that the socket be closed. |
|
104 @pre None. |
|
105 @post The input stream is in the Closed state. |
|
106 @internalComponent |
|
107 */ |
|
108 { |
|
109 // Cancel any outstanding requests |
|
110 Cancel(); |
|
111 |
|
112 // The socket has shutdown. Inform the input stream observer that the input |
|
113 // stream is closed. |
|
114 if( iObserver ) |
|
115 iObserver->InputStreamCloseInd(aError); |
|
116 |
|
117 // Move to the Closed state |
|
118 iState = EClosed; |
|
119 } |
|
120 |
|
121 void CSocketReader::Suspend() |
|
122 /** |
|
123 Notifies the input stream that it should suspend its activity. |
|
124 @pre The input stream is not already suspended. |
|
125 @post Any pending read is cancelled and the stream is suspended. |
|
126 @internalComponent |
|
127 */ |
|
128 { |
|
129 __ASSERT_DEBUG( !iSuspended, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EInputStreamAlreadySuspended) ); |
|
130 |
|
131 // Cancel any outstanding requests |
|
132 Cancel(); |
|
133 |
|
134 #if defined (_DEBUG) && defined (_LOGGING) |
|
135 TBuf8<KIpv6MaxAddrSize> ip; |
|
136 TUint16 remotePort; |
|
137 TUint16 localPort; |
|
138 iController.ConnectionInfo(ip, remotePort, localPort); |
|
139 |
|
140 __FLOG_0(_T8("!! Suspending input stream")); |
|
141 __FLOG_3(_T8("-> on local port %d with %S, remote port %d"), localPort, &ip, remotePort); |
|
142 #endif |
|
143 |
|
144 // Check to see a read requests had been issued. |
|
145 if( iState == EReceivedData ) |
|
146 { |
|
147 // Yep - change to the Read state so that read request is re-issued when |
|
148 // the stream resumes. |
|
149 iState = ERead; |
|
150 } |
|
151 |
|
152 // Stream is now suspended. |
|
153 iSuspended = ETrue; |
|
154 } |
|
155 |
|
156 void CSocketReader::Resume() |
|
157 /** |
|
158 Notifies the input stream that it should resume its activity. |
|
159 @pre The input stream is suspended. |
|
160 @post The stream resumes. A read request is issued if required. |
|
161 @internalComponent |
|
162 */ |
|
163 { |
|
164 __ASSERT_DEBUG( iSuspended, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EInputStreamNotSuspended) ); |
|
165 |
|
166 #if defined (_DEBUG) && defined (_LOGGING) |
|
167 TBuf8<KIpv6MaxAddrSize> ip; |
|
168 TUint16 remotePort; |
|
169 TUint16 localPort; |
|
170 iController.ConnectionInfo(ip, remotePort, localPort); |
|
171 |
|
172 __FLOG_0(_T8("!! Resumimng input stream")); |
|
173 __FLOG_3(_T8("-> on local port %d with %S, remote port %d"), localPort, &ip, remotePort); |
|
174 #endif |
|
175 |
|
176 // Check to see a read requests needs to be issued. |
|
177 if( iState == ERead ) |
|
178 { |
|
179 // Yep - self complete to get the read request issued. |
|
180 CompleteSelf(); |
|
181 } |
|
182 |
|
183 // Stream is no longer suspended. |
|
184 iSuspended = EFalse; |
|
185 } |
|
186 |
|
187 /* |
|
188 * Methods from MInputStream |
|
189 */ |
|
190 |
|
191 void CSocketReader::Bind(MInputStreamObserver& aObserver) |
|
192 /** |
|
193 @see MInputStream |
|
194 @internalComponent |
|
195 */ |
|
196 { |
|
197 __ASSERT_DEBUG( iState == EIdle || iState == EPendingAck, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadInputStreamState) ); |
|
198 |
|
199 // Bind to the input stream observer |
|
200 iObserver = &aObserver; |
|
201 |
|
202 if( iState == EIdle ) |
|
203 { |
|
204 // Move to the Read state and self complete, only if not suspended. |
|
205 iState = ERead; |
|
206 if( !iSuspended ) |
|
207 CompleteSelf(); |
|
208 } |
|
209 // Otherwise, stay in the PendingAck state and wait for input stream |
|
210 // observer to notify that it has finished with the buffer. |
|
211 } |
|
212 |
|
213 void CSocketReader::ReceivedDataRes() |
|
214 /** |
|
215 @see MInputStream |
|
216 @internalComponent |
|
217 */ |
|
218 { |
|
219 __ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EInputStreamNotBound) ); |
|
220 __ASSERT_DEBUG( iState == EPendingAck, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadInputStreamState) ); |
|
221 |
|
222 // The input stream observer has finished with the received data buffer. |
|
223 // Reset the buffer and prepare to read the input stream again. |
|
224 iBuffer.Zero(); |
|
225 |
|
226 // Move to the Read state and self complete, only if not suspended. |
|
227 iState = ERead; |
|
228 if( !iSuspended ) |
|
229 CompleteSelf(); |
|
230 } |
|
231 |
|
232 void CSocketReader::ShutdownReq() |
|
233 /** |
|
234 @see MInputStream |
|
235 @internalComponent |
|
236 */ |
|
237 { |
|
238 __ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EInputStreamNotBound) ); |
|
239 __ASSERT_DEBUG( iState != EClosing || iState != EClosed, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadInputStreamState) ); |
|
240 |
|
241 // Cancel any outstanding requests |
|
242 Cancel(); |
|
243 |
|
244 #if defined (_DEBUG) && defined (_LOGGING) |
|
245 TBuf8<KIpv6MaxAddrSize> ip; |
|
246 TUint16 remotePort; |
|
247 TUint16 localPort; |
|
248 iController.ConnectionInfo(ip, remotePort, localPort); |
|
249 |
|
250 __FLOG_0(_T8("!! Shutting down input stream")); |
|
251 __FLOG_3(_T8("-> on local port %d with %S, remote port %d"), localPort, &ip, remotePort); |
|
252 #endif |
|
253 |
|
254 // Shutdown the socket. |
|
255 iSocket.Shutdown(iStatus); |
|
256 |
|
257 // Move to the Closing state and go active |
|
258 iState = EClosing; |
|
259 SetActive(); |
|
260 } |
|
261 |
|
262 void CSocketReader::Close() |
|
263 /** |
|
264 @see MInputStream |
|
265 @internalComponent |
|
266 */ |
|
267 { |
|
268 __ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EInputStreamNotBound) ); |
|
269 __ASSERT_DEBUG( iState != EClosing || iState != EClosed, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadInputStreamState) ); |
|
270 |
|
271 // Cancel any outstanding requests |
|
272 Cancel(); |
|
273 |
|
274 #if defined (_DEBUG) && defined (_LOGGING) |
|
275 TBuf8<KIpv6MaxAddrSize> ip; |
|
276 TUint16 remotePort; |
|
277 TUint16 localPort; |
|
278 iController.ConnectionInfo(ip, remotePort, localPort); |
|
279 |
|
280 __FLOG_0(_T8("!! Closing input stream")); |
|
281 __FLOG_3(_T8("-> on local port %d with %S, remote port %d"), localPort, &ip, remotePort); |
|
282 #endif |
|
283 |
|
284 // There is no need to do anything here - by informing the socket controller |
|
285 // that the input stream is closed it will notify the output stream and then |
|
286 // close the socket. |
|
287 |
|
288 // Move to the Closed state |
|
289 iState = EClosed; |
|
290 |
|
291 // Inform the socket controller that the input stream is closed |
|
292 iController.StreamClosed(KErrCancel, MSocketController::EInputStream); |
|
293 } |
|
294 |
|
295 const CX509Certificate* CSocketReader::ClientCert() |
|
296 /** |
|
297 @see MInputStream |
|
298 @internalComponent |
|
299 */ |
|
300 { |
|
301 return NULL; |
|
302 } |
|
303 |
|
304 void CSocketReader::StartReceieveTimer (TInt aTimeoutValue) |
|
305 { |
|
306 //Get the TimeOut Value. |
|
307 if(aTimeoutValue > 0) |
|
308 { |
|
309 TInt timeoutValue = 0; |
|
310 //Convert to Microseconds. |
|
311 if(aTimeoutValue <= KMinTimeoutValue) |
|
312 { |
|
313 //Default Value is 60 Seconds |
|
314 timeoutValue = KDefTimeoutValue; |
|
315 } |
|
316 else |
|
317 { |
|
318 timeoutValue = aTimeoutValue * KMicrovalue; |
|
319 } |
|
320 |
|
321 //Create and Start the HTTP timer |
|
322 if(!iReceiveTimer) |
|
323 { |
|
324 iReceiveTimer = CHttpTimer::NewL(*this); |
|
325 } |
|
326 iReceiveTimer->After(timeoutValue); |
|
327 } |
|
328 } |
|
329 |
|
330 /* |
|
331 * Methods from CActive |
|
332 */ |
|
333 |
|
334 void CSocketReader::RunL() |
|
335 /** |
|
336 The request servicing function. Behaviour depends on the state of the input |
|
337 stream. |
|
338 @internalComponent |
|
339 */ |
|
340 { |
|
341 __ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EInputStreamNotBound) ); |
|
342 |
|
343 // Leave if the socket reported an error |
|
344 User::LeaveIfError(iStatus.Int()); |
|
345 |
|
346 switch( iState ) |
|
347 { |
|
348 case ERead: |
|
349 { |
|
350 iBuffer.Zero (); |
|
351 // Request a read from the socket |
|
352 iSocket.RecvOneOrMore(iBuffer, iStatus); |
|
353 |
|
354 // Move to the Received state and go active - wait for read to complete |
|
355 iState = EReceivedData; |
|
356 SetActive(); |
|
357 } break; |
|
358 case EReceivedData: |
|
359 { |
|
360 __OOM_LEAVE_TEST |
|
361 |
|
362 // Received data - move to the PendingAck state and wait for observer to |
|
363 // notify that it has finished with the buffer. |
|
364 iState = EPendingAck; |
|
365 |
|
366 if(iReceiveTimer) |
|
367 { |
|
368 iReceiveTimer->Cancel(); |
|
369 } |
|
370 |
|
371 // Inform the observer of the received data. |
|
372 iObserver->ReceivedDataIndL(iBuffer); |
|
373 |
|
374 #if defined (_DEBUG) && defined (_LOGGING) |
|
375 TBuf8<KIpv6MaxAddrSize> ip; |
|
376 TUint16 remotePort; |
|
377 TUint16 localPort; |
|
378 iController.ConnectionInfo(ip, remotePort, localPort); |
|
379 |
|
380 __FLOG_4(_T8("Received %d bytes on local port %d from %S, remote port %d"), iBuffer.Length(), localPort, &ip, remotePort); |
|
381 __FLOG_0(_T8("----------")); |
|
382 __FLOG_HEXDUMP(iBuffer.Ptr(), iBuffer.Length()); |
|
383 __FLOG_0(_T8("----------")); |
|
384 #endif |
|
385 } break; |
|
386 case EClosing: |
|
387 { |
|
388 __OOM_LEAVE_TEST |
|
389 |
|
390 // The socket has shutdown - move to the Closed state |
|
391 iState = EClosed; |
|
392 |
|
393 if(iReceiveTimer) |
|
394 { |
|
395 iReceiveTimer->Cancel(); |
|
396 } |
|
397 |
|
398 // Inform the observer that the input stream is closed. |
|
399 iObserver->InputStreamCloseInd(KErrNone); |
|
400 |
|
401 // Inform the socket controller that the input stream is now shut |
|
402 iController.StreamClosed(KErrNone, MSocketController::EInputStream); |
|
403 } break; |
|
404 case EPendingAck: |
|
405 case EClosed: |
|
406 case EIdle: |
|
407 default: |
|
408 THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadInputStreamError); |
|
409 break; |
|
410 } |
|
411 } |
|
412 |
|
413 void CSocketReader::DoCancel() |
|
414 /** |
|
415 The asynchronous request cancel function. If the input stream has requested a |
|
416 read from the socket (ie it is in the ReceivedData state) it cancels the read |
|
417 request. |
|
418 @internalComponent |
|
419 */ |
|
420 { |
|
421 if( iState == EReceivedData ) |
|
422 { |
|
423 // There is a pending read request - cancel it |
|
424 iSocket.CancelRecv(); |
|
425 } |
|
426 } |
|
427 |
|
428 TInt CSocketReader::RunError(TInt aError) |
|
429 /** |
|
430 The asynchronous request error handler. If this has been called then the |
|
431 read request or the socket shutdown request has failed. The socket can no |
|
432 longer be used. The input stream observer is notified that the stream is |
|
433 closed. No more data can be received from the socket. |
|
434 @return A value of KErrNone.indicating that the the error has been |
|
435 handled. |
|
436 @pre The input stream has requested a service (a read or a shutdown) |
|
437 from socket. The request has failed. It is either in the Read or |
|
438 Closing state. |
|
439 @post The input stream is in the Closed state. |
|
440 @internalComponent |
|
441 */ |
|
442 { |
|
443 __ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EInputStreamNotBound) ); |
|
444 |
|
445 #if defined (_DEBUG) && defined (_LOGGING) |
|
446 TBuf8<KIpv6MaxAddrSize> ip; |
|
447 TUint16 remotePort; |
|
448 TUint16 localPort; |
|
449 iController.ConnectionInfo(ip, remotePort, localPort); |
|
450 |
|
451 __FLOG_1(_T8("!! Input stream error : %d"), aError); |
|
452 __FLOG_3(_T8("-> Connection on local port %d with %S, remote port %d closed"), localPort, &ip, remotePort); |
|
453 #endif |
|
454 |
|
455 // Move to the Closed state |
|
456 iState = EClosed; |
|
457 |
|
458 // The socket request has failed - the socket connection is broken. Need |
|
459 // to inform the input stream observer that the input stream is closed. |
|
460 iObserver->InputStreamCloseInd(aError); |
|
461 |
|
462 // Inform the socket controller that the input stream is closed |
|
463 iController.StreamClosed(aError, MSocketController::EInputStream); |
|
464 |
|
465 return KErrNone; |
|
466 } |
|
467 |
|
468 void CSocketReader::SecureServerReq() |
|
469 /** |
|
470 Upgrades the socket reader to a secure socket. This is currently not supported and will result |
|
471 in the stream being closed and KErrNotSupported sent to the observer. |
|
472 @internalComponent |
|
473 */ |
|
474 { |
|
475 TRequestStatus* pStat = &iStatus; |
|
476 User::RequestComplete(pStat, KErrNotSupported); |
|
477 SetActive(); |
|
478 } |
|
479 |
|
480 /** |
|
481 Resets the state to EClosed |
|
482 @internalComponent |
|
483 */ |
|
484 void CSocketReader::Reset() |
|
485 { |
|
486 // Inform the connection manager that we are closing the output stream |
|
487 // due to no memory |
|
488 iObserver->InputStreamCloseInd ( KErrNoMemory ); |
|
489 iState = EClosed; |
|
490 } |
|
491 |
|
492 TInt CSocketReader::ImmediateRead ( TPtrC8& aData ) |
|
493 { |
|
494 TInt bytesToRead = iSocket.PendingBytesToRead (); |
|
495 __FLOG_1 (_T8("Bytes to read : %d"), bytesToRead); |
|
496 if ( bytesToRead < KErrNone ) |
|
497 return bytesToRead; |
|
498 if ( bytesToRead > iBuffer.Size() ) |
|
499 bytesToRead = iBuffer.Size(); |
|
500 |
|
501 if ( bytesToRead > 0 ) |
|
502 { |
|
503 // Now we know that there is some data to be read. |
|
504 // Suspend the current AO to ensure that the AO does not trigger in between |
|
505 // our operation. |
|
506 Suspend(); |
|
507 CHttpAsyncWaiter *waiter = CHttpAsyncWaiter::New(); |
|
508 if ( waiter == NULL) |
|
509 { |
|
510 return KErrNoMemory; |
|
511 } |
|
512 |
|
513 // Issue a read |
|
514 iSocket.RecvOneOrMore ( iBuffer, waiter->iStatus ); |
|
515 // Wait for the socket read completion. |
|
516 waiter->StartAndWait(); |
|
517 TInt result = waiter->Result(); |
|
518 if( result == KErrNone ) |
|
519 { |
|
520 aData.Set ( iBuffer ); |
|
521 // The socket reader sent the data for processing and we have to wait for the |
|
522 // acknowledgement for the process completion, so moving the state to EPendingAck. |
|
523 iState = EPendingAck; |
|
524 result = bytesToRead; |
|
525 } |
|
526 delete waiter; |
|
527 // Resume the current AO. |
|
528 Resume(); |
|
529 __FLOG_1(_T8("Immediate read completes with the result = %d"), result); |
|
530 return result; |
|
531 } |
|
532 return KErrNone; |
|
533 } |
|
534 |
|
535 void CSocketReader::Restart () |
|
536 { |
|
537 if ( iState == EIdle ) |
|
538 { |
|
539 // Move to the Read state and self complete, only if not suspended. |
|
540 iState = ERead; |
|
541 if( !iSuspended ) |
|
542 CompleteSelf(); |
|
543 } |
|
544 } |
|
545 |
|
546 void CSocketReader::TimeOut() |
|
547 { |
|
548 // Cancel any outstanding requests |
|
549 Cancel(); |
|
550 |
|
551 iObserver->OnReceiveTimeOut(); |
|
552 } |
|
553 |
|
554 void CSocketReader::Shutdown() |
|
555 { |
|
556 Cancel(); // Cancel any outstanding requests |
|
557 iSocket.ShutdownImmediate(); |
|
558 |
|
559 // The socket has shutdown - move to the Closed state |
|
560 iState = EClosed; |
|
561 |
|
562 if(iReceiveTimer) |
|
563 { |
|
564 iReceiveTimer->Cancel(); |
|
565 } |
|
566 |
|
567 // Inform the observer that the input stream is closed. |
|
568 iObserver->InputStreamCloseInd(KErrCancel); |
|
569 |
|
570 // Inform the socket controller that the input stream is now shut |
|
571 iController.StreamClosed(KErrCancel, MSocketController::EInputStream); |
|
572 } |