diff -r 000000000000 -r b16258d2340f applayerpluginsandutils/httptransportplugins/httptransporthandler/csocketwriter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/applayerpluginsandutils/httptransportplugins/httptransporthandler/csocketwriter.cpp Tue Feb 02 01:09:52 2010 +0200 @@ -0,0 +1,459 @@ +// Copyright (c) 2003-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 "csocketwriter.h" + +#include "csocket.h" +#include "msocketcontroller.h" +#include "moutputstreamobserver.h" +#include "httptransporthandlercommon.h" +#include "thttptrlayerpanic.h" + +CSocketWriter* CSocketWriter::NewL(CSocket& aSocket, MSocketController& aController, 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. +*/ + { + return new (ELeave) CSocketWriter(aSocket, aController, aPriority); + } + +CSocketWriter::~CSocketWriter() +/** + Destructor. +*/ + { + __ASSERT_DEBUG( iState == EIdle || iState == EClosed, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadOutputStreamState) ); + + //Delete the Timer object. + delete iSendTimer; + + // Cancel any outstanding requests + Cancel(); + +// __FLOG_CLOSE; + } + +CSocketWriter::CSocketWriter(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. +*/ + { + if(aPriority) + { + CActive::SetPriority(CActive::EPriorityHigh); + } + CActiveScheduler::Add(this); + +// __FLOG_OPEN("http", "httptransporthandler.txt"); + } + +void CSocketWriter::SocketClosed(TInt aError) +/** + Notifies the output stream that the socket is closed. The output stream + observer is notified that the stream is closed. No more data can be sent to + the socket. + @param aError The error code explaining why the socket has closed. A + value of KErrNone indicates that the input stream + observer requested that the socket be closed. + @pre None. + @post The output stream is in the Closed state. +*/ + { + // Cancel any outstanding requests + Cancel(); + + // The socket has shutdown. Inform the output stream observer that the + // output stream is closed. + if( iObserver ) + iObserver->OutputStreamCloseInd(aError); + + // Move to the Closed state + iState = EClosed; + } + +/* + * Methods from MOutputStream + */ + +void CSocketWriter::Bind(MOutputStreamObserver& aObserver) +/** + @see MOutputStream +*/ + { + __ASSERT_DEBUG( iState == EIdle || iState == EPendingSend, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadOutputStreamState) ); + + // Bind to the output stream observer + iObserver = &aObserver; + + // Move to the PendingSend state + iState = EPendingSend; + } + +void CSocketWriter::SendDataReqL(const TDesC8& aBuffer) +/** + @see MOutputStream +*/ + { + __ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EOutputStreamNotBound) ); + __ASSERT_DEBUG( iState == EPendingSend, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadOutputStreamState) ); + + //Get the TimeOut Value. + TInt timeoutValue = iObserver->SendTimeOutVal(); + if(timeoutValue > 0) + { + + //Convert to Microseconds. + if(timeoutValue <= KMinTimeoutValue) + { + //Default Value is 60 Seconds + timeoutValue = KDefTimeoutValue; + } + else + { + timeoutValue = timeoutValue * KMicrovalue; + } + + //Create and Start the HTTP timer + if(!iSendTimer) + { + iSendTimer = CHttpTimer::NewL(*this); + } + iSendTimer->After(timeoutValue); + } + + // The output stream observer requests that the supplied buffer is sent to + // the socket. Request a write to the socket + iSocket.Send(aBuffer, iStatus); + +#if defined (_DEBUG) && defined (_LOGGING) + TBuf8 ip; + TUint16 remotePort; + TUint16 localPort; + iController.ConnectionInfo(ip, remotePort, localPort); + + __FLOG_4(_T8("Sending %d bytes on local port %d to %S, remote port %d"), aBuffer.Length(), localPort, &ip, remotePort); + __FLOG_0(_T8("----------")); + __FLOG_HEXDUMP(aBuffer.Ptr(), aBuffer.Length()); + __FLOG_0(_T8("----------")); +#endif + + // Move to the SentData and go active + iState = ESentData; + SetActive(); + } + +void CSocketWriter::ShutdownReq() +/** + @see MOutputStream +*/ + { + __ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EOutputStreamNotBound) ); + __ASSERT_DEBUG( iState != EClosing || iState != EClosed, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadOutputStreamState) ); + + // Cancel any outstanding requests + Cancel(); + +#if defined (_DEBUG) && defined (_LOGGING) + TBuf8 ip; + TUint16 remotePort; + TUint16 localPort; + iController.ConnectionInfo(ip, remotePort, localPort); + + __FLOG_0(_T8("!! Shutting down output 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 CSocketWriter::SecureClientReq(const TDesC8& aHostName) +/** + The request to upgrade the client to a secure connection. This method begins + the secure handshake required to upgrade to a secure connection. + @param aHostName The domain name of the server for checking against + the server certificates. + @pre The socket writer must be in the EPendingSend state. +*/ + { + __ASSERT_DEBUG( iState == EPendingSend, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadOutputStreamState) ); + +#if defined (_DEBUG) && defined (_LOGGING) + TBuf8 ip; + TUint16 remotePort; + TUint16 localPort; + iController.ConnectionInfo(ip, remotePort, localPort); + + __FLOG_0(_T8("!! Upgrading to secure (client) connection")); + __FLOG_3(_T8("-> on local port %d with %S, remote port %d"), localPort, &ip, remotePort); +#endif + + // Notify the controller to suspend the input stream. + iController.StreamSuspend(MSocketController::EOutputStream); + + // Store the host name as required for secure certificate domain name + // chacking. Move to the StartSecureHandshake state and self complete. + iHostName.Set(aHostName); + iState = EStartSecureHandshake; + CompleteSelf(); + } + +void CSocketWriter::Close() +/** + @see MOutputStream +*/ + { + __ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EOutputStreamNotBound) ); + __ASSERT_DEBUG( iState != EClosing || iState != EClosed, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadOutputStreamState) ); + + // Cancel any outstanding requests + Cancel(); + +#if defined (_DEBUG) && defined (_LOGGING) + TBuf8 ip; + TUint16 remotePort; + TUint16 localPort; + iController.ConnectionInfo(ip, remotePort, localPort); + + __FLOG_0(_T8("!! Closing output 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 output stream is closed it will notify the input stream and then + // close the socket. + + // Move to the Closed state + iState = EClosed; + + // Inform the socket controller that the output stream is closed + iController.StreamClosed(KErrCancel, MSocketController::EOutputStream); + } + + +const CX509Certificate* CSocketWriter::ServerCert() +/** + @see MOutputStream +*/ + { + return iSocket.ServerCert(); + } + +TInt CSocketWriter::CipherSuite(TDes8& aCipherSuite) +/** + @see MOutputStream +*/ + { + return iSocket.CipherSuite(aCipherSuite); + } + +void CSocketWriter::MOutputStream_Reserved() +/** + @see MOutputStream +*/ + { + User::Invariant(); + } + +/** + Resets the state to EClosed + @componentInternal +*/ +void CSocketWriter::Reset() + { + // Inform the connection manager that we are closing the output stream + // due to no memory + iObserver->OutputStreamCloseInd ( KErrNoMemory ); + iState = EClosed; + } + +void CSocketWriter::CompleteSelf() +/** + Requests that the socket writer complete itself. This will caused the + RunL() to be called by the scheduler at the next opportunity. + @pre The socket connector object is not active. + @post The socket connector object is active and the request has been + completed. +*/ + { + TRequestStatus* pStat = &iStatus; + User::RequestComplete(pStat, KErrNone); + SetActive(); + } + +/* + * Methods from CActive + */ + +void CSocketWriter::RunL() +/** + The request servicing function. Behaviour depends on the state of the output + stream. +*/ + { + __ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EOutputStreamNotBound) ); + + // Leave if the socket reported an error + User::LeaveIfError(iStatus.Int()); + + if(iSendTimer) + { + iSendTimer->Cancel(); + } + + switch( iState ) + { + case ESentData: + { + __OOM_LEAVE_TEST + + // The data has successfully been written to the socket - move to the + // PendingSend state. + iState = EPendingSend; + + // Inform the observer that the data has been sent. + iObserver->SendDataCnfL(); + } break; + case EClosing: + { + __OOM_LEAVE_TEST + + // The socket has shutdown - move to the Closed state + iState = EClosed; + + // Inform the observer that the output stream is closed. + iObserver->OutputStreamCloseInd(KErrNone); + + // Inform the socket controller that the output stream is closed + iController.StreamClosed(KErrNone, MSocketController::EOutputStream); + } break; + case EStartSecureHandshake: + { + // Start the secure handshake + iState = ESecureHandshakeComplete; + iSocket.UpgradeToSecureL(iStatus, iHostName); + SetActive(); + } break; + case ESecureHandshakeComplete: + { + __OOM_LEAVE_TEST + + // Secure handshake has completed successfully so inform the observer. + iState = EPendingSend; + iObserver->SecureClientCnf(); + +#if defined (_DEBUG) && defined (_LOGGING) + TBuf8 ip; + TUint16 remotePort; + TUint16 localPort; + iController.ConnectionInfo(ip, remotePort, localPort); + + __FLOG_0(_T8("!! Upgrade to secure (client) connection successful")); + __FLOG_3(_T8("-> on local port %d with %S, remote port %d"), localPort, &ip, remotePort); +#endif + + // Notify the controller to resume the input stream. + iController.StreamResume(MSocketController::EOutputStream); + } break; + case EPendingSend: + case EClosed: + case EIdle: + default: + THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadOutputStreamState); + break; + } + } + +void CSocketWriter::DoCancel() +/** + The asynchronous request cancel function. If the output stream has requested + a write to the socket (ie it is in the SentData state) this function cancels + the write request. +*/ + { + if( iState == ESentData ) + { + // There is a pending write request - cancel it + iSocket.CancelSend(); + } + else if( iState == ESecureHandshakeComplete ) + { + // Cancel the upgrade to secure connection. + iSocket.CancelUpgradeToSecure(); + } + } + +TInt CSocketWriter::RunError(TInt aError) +/** + The error handler for when RunL() leaves. If this has been called then the + write request or the socket shutdown request has failed. The socket can no + longer be used. The output stream observer is notified that the stream is + closed. No more data can be sent to the socket. + @return A value of KErrNone indicating that the the error has been + handled. + @pre The output stream has requested a service (a write or a shutdown) + from socket. The request has failed. It is either in the SentData + or Closing state. + @post The output stream is in the Closed state. +*/ + { + __ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EOutputStreamNotBound) ); + +#if defined (_DEBUG) && defined (_LOGGING) + TBuf8 ip; + TUint16 remotePort; + TUint16 localPort; + iController.ConnectionInfo(ip, remotePort, localPort); + + __FLOG_1(_T8("!! Output 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 output stream observer that the output stream is closed. + iObserver->OutputStreamCloseInd(aError); + + // Inform the socket controller that the output stream is closed + iController.StreamClosed(aError, MSocketController::EOutputStream); + + return KErrNone; + } + +void CSocketWriter::TimeOut() + { + // Cancel any outstanding requests + Cancel(); + iObserver->OnSendTimeOut(); + } + +void CSocketWriter::SetTCPCorking(TBool aValue) + { + iSocket.SetTCPCorking(aValue); + } + +