--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/applayerpluginsandutils/httptransportplugins/httptransporthandler/csocketreader.cpp Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,572 @@
+// Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "csocketreader.h"
+
+#include "csocket.h"
+#include "msocketcontroller.h"
+#include "minputstreamobserver.h"
+#include "httptransporthandlercommon.h"
+#include "thttptrlayerpanic.h"
+#include "chttpasyncwaiter.h"
+
+CSocketReader* CSocketReader::NewL(CSocket& aSocket, MSocketController& aController, TInt aRecvBufferSize, TBool aPriority)
+/**
+ The factory constructor.
+ @param aSocket The connected socket. This owned by the observer.
+ @param aController The socket controller that owns the socket.
+ @return A pointer to a fully constructed object.
+ @internalComponent
+*/
+ {
+ CSocketReader* self = new (ELeave) CSocketReader(aSocket, aController, aPriority);
+ CleanupStack::PushL(self);
+ self->ConstructL( aRecvBufferSize );
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+void CSocketReader::ConstructL( TInt aRecvBufferSize )
+ {
+ iBuffer.CreateL ( aRecvBufferSize );
+ }
+
+CSocketReader::~CSocketReader()
+/**
+ Destructor.
+ @internalComponent
+*/
+ {
+ __ASSERT_DEBUG( iState == EIdle || iState == EClosed, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadInputStreamState) );
+
+ //Delete the Timer Object.
+ delete iReceiveTimer;
+
+ // Cancel any outstanding requests
+ Cancel();
+ iBuffer.Close ();
+// __FLOG_CLOSE;
+ }
+
+CSocketReader::CSocketReader(CSocket& aSocket, MSocketController& aController, TBool aPriority)
+: CActive(CActive::EPriorityStandard), iSocket(aSocket), iController(aController)
+/**
+ Constructor.
+ @param aSocket The connected socket. This owned by the observer.
+ @param aController The socket controller that owns the socket.
+ @internalComponent
+*/
+ {
+ if(aPriority)
+ {
+ CActive::SetPriority(CActive::EPriorityHigh);
+ }
+ CActiveScheduler::Add(this);
+
+// __FLOG_OPEN("http", "httptransporthandler.txt");
+ }
+
+void CSocketReader::CompleteSelf()
+/**
+ Requests that the input stream complete itself. This will caused the RunL()
+ to be called by the scheduler at the next opportunity.
+ @pre The input stream is not active.
+ @post The input stream object is active and the request has been
+ completed.
+ @internalComponent
+*/
+ {
+ TRequestStatus* pStat = &iStatus;
+ User::RequestComplete(pStat, KErrNone);
+ SetActive();
+ }
+
+void CSocketReader::SocketClosed(TInt aError)
+/**
+ Notifies the input stream that the socket is closed. The input stream
+ observer is notified that the stream is closed. No more data can be received
+ from the socket.
+ @param aError The error code explaining why the socket has closed. A
+ value of KErrNone indicates that the output stream
+ observer requested that the socket be closed.
+ @pre None.
+ @post The input stream is in the Closed state.
+ @internalComponent
+*/
+ {
+ // Cancel any outstanding requests
+ Cancel();
+
+ // The socket has shutdown. Inform the input stream observer that the input
+ // stream is closed.
+ if( iObserver )
+ iObserver->InputStreamCloseInd(aError);
+
+ // Move to the Closed state
+ iState = EClosed;
+ }
+
+void CSocketReader::Suspend()
+/**
+ Notifies the input stream that it should suspend its activity.
+ @pre The input stream is not already suspended.
+ @post Any pending read is cancelled and the stream is suspended.
+ @internalComponent
+*/
+ {
+ __ASSERT_DEBUG( !iSuspended, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EInputStreamAlreadySuspended) );
+
+ // Cancel any outstanding requests
+ Cancel();
+
+#if defined (_DEBUG) && defined (_LOGGING)
+ TBuf8<KIpv6MaxAddrSize> ip;
+ TUint16 remotePort;
+ TUint16 localPort;
+ iController.ConnectionInfo(ip, remotePort, localPort);
+
+ __FLOG_0(_T8("!! Suspending input stream"));
+ __FLOG_3(_T8("-> on local port %d with %S, remote port %d"), localPort, &ip, remotePort);
+#endif
+
+ // Check to see a read requests had been issued.
+ if( iState == EReceivedData )
+ {
+ // Yep - change to the Read state so that read request is re-issued when
+ // the stream resumes.
+ iState = ERead;
+ }
+
+ // Stream is now suspended.
+ iSuspended = ETrue;
+ }
+
+void CSocketReader::Resume()
+/**
+ Notifies the input stream that it should resume its activity.
+ @pre The input stream is suspended.
+ @post The stream resumes. A read request is issued if required.
+ @internalComponent
+*/
+ {
+ __ASSERT_DEBUG( iSuspended, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EInputStreamNotSuspended) );
+
+#if defined (_DEBUG) && defined (_LOGGING)
+ TBuf8<KIpv6MaxAddrSize> ip;
+ TUint16 remotePort;
+ TUint16 localPort;
+ iController.ConnectionInfo(ip, remotePort, localPort);
+
+ __FLOG_0(_T8("!! Resumimng input stream"));
+ __FLOG_3(_T8("-> on local port %d with %S, remote port %d"), localPort, &ip, remotePort);
+#endif
+
+ // Check to see a read requests needs to be issued.
+ if( iState == ERead )
+ {
+ // Yep - self complete to get the read request issued.
+ CompleteSelf();
+ }
+
+ // Stream is no longer suspended.
+ iSuspended = EFalse;
+ }
+
+/*
+ * Methods from MInputStream
+ */
+
+void CSocketReader::Bind(MInputStreamObserver& aObserver)
+/**
+ @see MInputStream
+ @internalComponent
+*/
+ {
+ __ASSERT_DEBUG( iState == EIdle || iState == EPendingAck, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadInputStreamState) );
+
+ // Bind to the input stream observer
+ iObserver = &aObserver;
+
+ if( iState == EIdle )
+ {
+ // Move to the Read state and self complete, only if not suspended.
+ iState = ERead;
+ if( !iSuspended )
+ CompleteSelf();
+ }
+ // Otherwise, stay in the PendingAck state and wait for input stream
+ // observer to notify that it has finished with the buffer.
+ }
+
+void CSocketReader::ReceivedDataRes()
+/**
+ @see MInputStream
+ @internalComponent
+*/
+ {
+ __ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EInputStreamNotBound) );
+ __ASSERT_DEBUG( iState == EPendingAck, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadInputStreamState) );
+
+ // The input stream observer has finished with the received data buffer.
+ // Reset the buffer and prepare to read the input stream again.
+ iBuffer.Zero();
+
+ // Move to the Read state and self complete, only if not suspended.
+ iState = ERead;
+ if( !iSuspended )
+ CompleteSelf();
+ }
+
+void CSocketReader::ShutdownReq()
+/**
+ @see MInputStream
+ @internalComponent
+*/
+ {
+ __ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EInputStreamNotBound) );
+ __ASSERT_DEBUG( iState != EClosing || iState != EClosed, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadInputStreamState) );
+
+ // Cancel any outstanding requests
+ Cancel();
+
+#if defined (_DEBUG) && defined (_LOGGING)
+ TBuf8<KIpv6MaxAddrSize> ip;
+ TUint16 remotePort;
+ TUint16 localPort;
+ iController.ConnectionInfo(ip, remotePort, localPort);
+
+ __FLOG_0(_T8("!! Shutting down input stream"));
+ __FLOG_3(_T8("-> on local port %d with %S, remote port %d"), localPort, &ip, remotePort);
+#endif
+
+ // Shutdown the socket.
+ iSocket.Shutdown(iStatus);
+
+ // Move to the Closing state and go active
+ iState = EClosing;
+ SetActive();
+ }
+
+void CSocketReader::Close()
+/**
+ @see MInputStream
+ @internalComponent
+*/
+ {
+ __ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EInputStreamNotBound) );
+ __ASSERT_DEBUG( iState != EClosing || iState != EClosed, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadInputStreamState) );
+
+ // Cancel any outstanding requests
+ Cancel();
+
+#if defined (_DEBUG) && defined (_LOGGING)
+ TBuf8<KIpv6MaxAddrSize> ip;
+ TUint16 remotePort;
+ TUint16 localPort;
+ iController.ConnectionInfo(ip, remotePort, localPort);
+
+ __FLOG_0(_T8("!! Closing input stream"));
+ __FLOG_3(_T8("-> on local port %d with %S, remote port %d"), localPort, &ip, remotePort);
+#endif
+
+ // There is no need to do anything here - by informing the socket controller
+ // that the input stream is closed it will notify the output stream and then
+ // close the socket.
+
+ // Move to the Closed state
+ iState = EClosed;
+
+ // Inform the socket controller that the input stream is closed
+ iController.StreamClosed(KErrCancel, MSocketController::EInputStream);
+ }
+
+const CX509Certificate* CSocketReader::ClientCert()
+/**
+ @see MInputStream
+ @internalComponent
+*/
+ {
+ return NULL;
+ }
+
+void CSocketReader::StartReceieveTimer (TInt aTimeoutValue)
+ {
+ //Get the TimeOut Value.
+ if(aTimeoutValue > 0)
+ {
+ TInt timeoutValue = 0;
+ //Convert to Microseconds.
+ if(aTimeoutValue <= KMinTimeoutValue)
+ {
+ //Default Value is 60 Seconds
+ timeoutValue = KDefTimeoutValue;
+ }
+ else
+ {
+ timeoutValue = aTimeoutValue * KMicrovalue;
+ }
+
+ //Create and Start the HTTP timer
+ if(!iReceiveTimer)
+ {
+ iReceiveTimer = CHttpTimer::NewL(*this);
+ }
+ iReceiveTimer->After(timeoutValue);
+ }
+ }
+
+/*
+ * Methods from CActive
+ */
+
+void CSocketReader::RunL()
+/**
+ The request servicing function. Behaviour depends on the state of the input
+ stream.
+ @internalComponent
+*/
+ {
+ __ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EInputStreamNotBound) );
+
+ // Leave if the socket reported an error
+ User::LeaveIfError(iStatus.Int());
+
+ switch( iState )
+ {
+ case ERead:
+ {
+ iBuffer.Zero ();
+ // Request a read from the socket
+ iSocket.RecvOneOrMore(iBuffer, iStatus);
+
+ // Move to the Received state and go active - wait for read to complete
+ iState = EReceivedData;
+ SetActive();
+ } break;
+ case EReceivedData:
+ {
+ __OOM_LEAVE_TEST
+
+ // Received data - move to the PendingAck state and wait for observer to
+ // notify that it has finished with the buffer.
+ iState = EPendingAck;
+
+ if(iReceiveTimer)
+ {
+ iReceiveTimer->Cancel();
+ }
+
+ // Inform the observer of the received data.
+ iObserver->ReceivedDataIndL(iBuffer);
+
+#if defined (_DEBUG) && defined (_LOGGING)
+ TBuf8<KIpv6MaxAddrSize> ip;
+ TUint16 remotePort;
+ TUint16 localPort;
+ iController.ConnectionInfo(ip, remotePort, localPort);
+
+ __FLOG_4(_T8("Received %d bytes on local port %d from %S, remote port %d"), iBuffer.Length(), localPort, &ip, remotePort);
+ __FLOG_0(_T8("----------"));
+ __FLOG_HEXDUMP(iBuffer.Ptr(), iBuffer.Length());
+ __FLOG_0(_T8("----------"));
+#endif
+ } break;
+ case EClosing:
+ {
+ __OOM_LEAVE_TEST
+
+ // The socket has shutdown - move to the Closed state
+ iState = EClosed;
+
+ if(iReceiveTimer)
+ {
+ iReceiveTimer->Cancel();
+ }
+
+ // Inform the observer that the input stream is closed.
+ iObserver->InputStreamCloseInd(KErrNone);
+
+ // Inform the socket controller that the input stream is now shut
+ iController.StreamClosed(KErrNone, MSocketController::EInputStream);
+ } break;
+ case EPendingAck:
+ case EClosed:
+ case EIdle:
+ default:
+ THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadInputStreamError);
+ break;
+ }
+ }
+
+void CSocketReader::DoCancel()
+/**
+ The asynchronous request cancel function. If the input stream has requested a
+ read from the socket (ie it is in the ReceivedData state) it cancels the read
+ request.
+ @internalComponent
+*/
+ {
+ if( iState == EReceivedData )
+ {
+ // There is a pending read request - cancel it
+ iSocket.CancelRecv();
+ }
+ }
+
+TInt CSocketReader::RunError(TInt aError)
+/**
+ The asynchronous request error handler. If this has been called then the
+ read request or the socket shutdown request has failed. The socket can no
+ longer be used. The input stream observer is notified that the stream is
+ closed. No more data can be received from the socket.
+ @return A value of KErrNone.indicating that the the error has been
+ handled.
+ @pre The input stream has requested a service (a read or a shutdown)
+ from socket. The request has failed. It is either in the Read or
+ Closing state.
+ @post The input stream is in the Closed state.
+ @internalComponent
+*/
+ {
+ __ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EInputStreamNotBound) );
+
+#if defined (_DEBUG) && defined (_LOGGING)
+ TBuf8<KIpv6MaxAddrSize> ip;
+ TUint16 remotePort;
+ TUint16 localPort;
+ iController.ConnectionInfo(ip, remotePort, localPort);
+
+ __FLOG_1(_T8("!! Input stream error : %d"), aError);
+ __FLOG_3(_T8("-> Connection on local port %d with %S, remote port %d closed"), localPort, &ip, remotePort);
+#endif
+
+ // Move to the Closed state
+ iState = EClosed;
+
+ // The socket request has failed - the socket connection is broken. Need
+ // to inform the input stream observer that the input stream is closed.
+ iObserver->InputStreamCloseInd(aError);
+
+ // Inform the socket controller that the input stream is closed
+ iController.StreamClosed(aError, MSocketController::EInputStream);
+
+ return KErrNone;
+ }
+
+void CSocketReader::SecureServerReq()
+/**
+ Upgrades the socket reader to a secure socket. This is currently not supported and will result
+ in the stream being closed and KErrNotSupported sent to the observer.
+ @internalComponent
+*/
+ {
+ TRequestStatus* pStat = &iStatus;
+ User::RequestComplete(pStat, KErrNotSupported);
+ SetActive();
+ }
+
+/**
+ Resets the state to EClosed
+ @internalComponent
+*/
+void CSocketReader::Reset()
+ {
+ // Inform the connection manager that we are closing the output stream
+ // due to no memory
+ iObserver->InputStreamCloseInd ( KErrNoMemory );
+ iState = EClosed;
+ }
+
+TInt CSocketReader::ImmediateRead ( TPtrC8& aData )
+ {
+ TInt bytesToRead = iSocket.PendingBytesToRead ();
+ __FLOG_1 (_T8("Bytes to read : %d"), bytesToRead);
+ if ( bytesToRead < KErrNone )
+ return bytesToRead;
+ if ( bytesToRead > iBuffer.Size() )
+ bytesToRead = iBuffer.Size();
+
+ if ( bytesToRead > 0 )
+ {
+ // Now we know that there is some data to be read.
+ // Suspend the current AO to ensure that the AO does not trigger in between
+ // our operation.
+ Suspend();
+ CHttpAsyncWaiter *waiter = CHttpAsyncWaiter::New();
+ if ( waiter == NULL)
+ {
+ return KErrNoMemory;
+ }
+
+ // Issue a read
+ iSocket.RecvOneOrMore ( iBuffer, waiter->iStatus );
+ // Wait for the socket read completion.
+ waiter->StartAndWait();
+ TInt result = waiter->Result();
+ if( result == KErrNone )
+ {
+ aData.Set ( iBuffer );
+ // The socket reader sent the data for processing and we have to wait for the
+ // acknowledgement for the process completion, so moving the state to EPendingAck.
+ iState = EPendingAck;
+ result = bytesToRead;
+ }
+ delete waiter;
+ // Resume the current AO.
+ Resume();
+ __FLOG_1(_T8("Immediate read completes with the result = %d"), result);
+ return result;
+ }
+ return KErrNone;
+ }
+
+void CSocketReader::Restart ()
+ {
+ if ( iState == EIdle )
+ {
+ // Move to the Read state and self complete, only if not suspended.
+ iState = ERead;
+ if( !iSuspended )
+ CompleteSelf();
+ }
+ }
+
+void CSocketReader::TimeOut()
+ {
+ // Cancel any outstanding requests
+ Cancel();
+
+ iObserver->OnReceiveTimeOut();
+ }
+
+void CSocketReader::Shutdown()
+ {
+ Cancel(); // Cancel any outstanding requests
+ iSocket.ShutdownImmediate();
+
+ // The socket has shutdown - move to the Closed state
+ iState = EClosed;
+
+ if(iReceiveTimer)
+ {
+ iReceiveTimer->Cancel();
+ }
+
+ // Inform the observer that the input stream is closed.
+ iObserver->InputStreamCloseInd(KErrCancel);
+
+ // Inform the socket controller that the input stream is now shut
+ iController.StreamClosed(KErrCancel, MSocketController::EInputStream);
+ }