diff -r 000000000000 -r b16258d2340f applayerpluginsandutils/httptransportplugins/httptransporthandler/csocketconnector.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/applayerpluginsandutils/httptransportplugins/httptransporthandler/csocketconnector.cpp Tue Feb 02 01:09:52 2010 +0200 @@ -0,0 +1,433 @@ +// 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 "csocketconnector.h" + +#include "csocket.h" +#include "msocketconnectobserver.h" +#include "msocketconnectorstore.h" +#include "msocketcontrollerfactory.h" +#include "mcommsinfoprovider.h" +#include "csocketcontroller.h" +#include "httptransporthandlercommon.h" +#include "thttptrlayerpanic.h" + +#if defined (_DEBUG) && defined (_LOGGING) +const TInt KHostNameSize = 126; +#endif + +CSocketConnector* CSocketConnector::NewL( + MSocketConnectorStore& aStore, + MSocketControllerFactory& aSocketControllerFactory, + MCommsInfoProvider& aCommsInfoProvider, TBool aPriority + ) +/** + The factory constructor. + @param aStore The socket connector store. + @param aSocketControllerFactory The socket controller factory. + @param aCommsInfoProvider The comms info provider. + @return A pointer to a fully constructed object. +*/ + { + return new (ELeave) CSocketConnector(aStore, aSocketControllerFactory, aCommsInfoProvider,aPriority); + } + +CSocketConnector::~CSocketConnector() +/** + Destructor. +*/ + { + // Cancel any outstanding requests + Cancel(); + + // Cleanup... + delete iHost; + delete iConnectingSocket; + iHostResolver.Close(); + +// __FLOG_CLOSE; + } + +CSocketConnector::CSocketConnector( + MSocketConnectorStore& aStore, + MSocketControllerFactory& aSocketControllerFactory, + MCommsInfoProvider& aCommsInfoProvider, + TBool aPriority + ) +: CActive(aPriority ? CActive::EPriorityHigh : CActive::EPriorityStandard), iStore(aStore), + iSocketControllerFactory(aSocketControllerFactory), + iCommsInfoProvider(aCommsInfoProvider) +/** + Constructor. + @param aStore The socket connector store. + @param aSocketControllerFactory The socket controller factory. + @param aCommsInfoProvider The comms info provider. +*/ { + if(aPriority) + { + CActive::SetPriority(CActive::EPriorityHigh); + } + + CActiveScheduler::Add(this); + +// __FLOG_OPEN("http", "httptransporthandler.txt"); + } + +void CSocketConnector::ConnectL(MSocketConnectObserver& aObserver, const TDesC8& aRemoteHost, TUint16 aRemotePort, TInetAddr* aRemoteAddress) +/** + Start connection to specified remote host. The socket connector starts + connecting to the specified remote host on the specified port. + @param aRemoteHost The host name/IP address of the remote host + @param aRemotePort The port number of the remote host + @pre The socket connector is in the Idle state. + @post The socket connector is not in the Idle state. +*/ + { + __ASSERT_DEBUG( iState == EIdle, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadSocketConnectorState) ); + + // Set the observer + iObserver = &aObserver; + + // Copy the remote host IP address and port + iHost = HBufC::NewL(aRemoteHost.Length()); + iHost->Des().Copy(aRemoteHost); + iPort = aRemotePort; + + // Move to the PendingDNSLookup state and self complete. + if(aRemoteAddress == NULL) + { + // Address is unknown / DNS lookup is needed + iState = EPendingDNSLookup; + } + else + { + // Address is know. No lookup is needed. Just go and connect. + iHostDnsEntry().iAddr = *aRemoteAddress; + iState = EConnecting; + } + CompleteSelf(); + } + +void CSocketConnector::CompleteSelf() +/** + Requests that the socket connector 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(); + } + +void CSocketConnector::Suicide() +/** + The socket connector is finished, it needs to remove itself from the store + and self-destruct. +*/ + { + // Inform store that connection is complete and then suicide. + iStore.ConnectionCompleted(*this); + delete this; + } + +/* + * Methods from MSocketConnector + */ + +void CSocketConnector::StopConnect() +/** + @see MSocketConnector +*/ + { + // Cancel any outstanding requests. + Cancel(); + +#if defined (_DEBUG) && defined (_LOGGING) + TBuf8 host; + host.Copy((*iHost).Left(KHostNameSize)); //just get the KHostNameSize characters + + __FLOG_0(_T8("!! Stopping connection")); + __FLOG_1(_T8("-> connect to host %S stopped"), &host); +#endif + + Suicide(); + } + +void CSocketConnector::MSocketConnector_Reserved() +/** + @see MSocketConnector +*/ + { + User::Invariant(); + } + +/* + * Methods from CActive + */ + +void CSocketConnector::RunL() +/** + The request servicing function. Behaviour depends on the state of the socket + connector. +*/ + { + // Leave if there has been an error + User::LeaveIfError(iStatus.Int()); + + switch( iState ) + { + case EPendingDNSLookup: + { +#if defined (_DEBUG) && defined (_LOGGING) + TBuf8 host; + host.Copy((*iHost).Left(KHostNameSize)); //just get the KHostNameSize characters + + __FLOG_1(_T8("Doing DNS lookup -> searching for host %S"), &host); +#endif + + __OOM_LEAVE_TEST + + if ( iCommsInfoProvider.HasConnection() ) + { + // Open the host resolver session with the preffered connection + User::LeaveIfError(iHostResolver.Open( + iCommsInfoProvider.SocketServer(), + iCommsInfoProvider.ProtocolDescription().iAddrFamily, + KProtocolInetUdp, + iCommsInfoProvider.Connection() + )); + } + else + { + // Open the host resolver session with no connection + User::LeaveIfError(iHostResolver.Open( + iCommsInfoProvider.SocketServer(), + iCommsInfoProvider.ProtocolDescription().iAddrFamily, + KProtocolInetUdp + )); + } + + // Start the DNS lookup for the remote host name. + iHostResolver.GetByName(*iHost, iHostDnsEntry, iStatus); + + // Move to the Connecting state and go active + iState = EConnecting; + SetActive(); + } break; + case EConnecting: + { + __OOM_LEAVE_TEST + + // DNS lookup successful - form the internet address object + iAddress = TInetAddr(iHostDnsEntry().iAddr); + iAddress.SetPort(iPort); + +#if defined (_DEBUG) && defined (_LOGGING) + TBuf8 host; + host.Copy((*iHost).Left(KHostNameSize)); //just get the KHostNameSize characters + + TBuf ip16bit; + iAddress.Output(ip16bit); + + TBuf8 ip; + ip.Copy(ip16bit); + + __FLOG_2(_T8("DNS lookup complete -> host %S has IP address %S"), &host, &ip); +#endif + + // Start a default RConnection, if one is not started and not local loopback address + if ( !iCommsInfoProvider.HasConnection() && !iAddress.IsLoopback() ) + { + iCommsInfoProvider.StartDefaultCommsConnectionL (); + } + + // Create the connecting socket + iConnectingSocket = CSocket::NewL(iCommsInfoProvider, CSocket::EProtocolSocket); + + // Start connecting to the remote client + iConnectingSocket->Connect(iAddress, iStatus); + + __FLOG_2(_T8("Connecting -> to host %S on IP address %S"), &host, &ip); + + // Move to the Connected state and go active + iState = EConnected; + SetActive(); + } break; + case EConnected: + { + __OOM_LEAVE_TEST + +#if defined (_DEBUG) && defined (_LOGGING) + TBuf8 host; + host.Copy((*iHost).Left(KHostNameSize)); //just get the KHostNameSize characters + + TInetAddr addr; + iConnectingSocket->RemoteName(addr); + + TBuf ip16bit; + addr.Output(ip16bit); + + TBuf8 ip; + ip.Copy(ip16bit); + + TInetAddr local; + iConnectingSocket->LocalName(local); + + __FLOG_1(_T8("!! Connection with host %S established"), &host); + __FLOG_3(_T8("-> on local port %d with %S, remote port %d"), local.Port(), &ip, addr.Port()); +#endif + + // A connection has been made with the remote client - lose ownership of + // the connecting socket. + CSocket* connectedSocket = iConnectingSocket; + iConnectingSocket = NULL; + + // Create a socket controller object to own the connected socket. + CSocketController* socketController = iSocketControllerFactory.CreateSocketControllerLC(connectedSocket, *iHost, iPort, iAddress); + + // Inform the socket connect observer that a TCP connection is established - + // pass back the input and output stream objects. + iObserver->ConnectionMadeL(socketController->InputStream(), socketController->OutputStream()); + + // Remove socket controller from cleanup stack - transferring ownership + // to the store. + CleanupStack::Pop(socketController); + + // Add the socket controller in the store - ownership is transferred to + // the store. + iSocketControllerFactory.AddToStoreL(socketController); + + // Socket connector is finished - suicide. + Suicide(); + } break; + case EIdle: + default: + THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadSocketConnectorState); + break; + } + } + +void CSocketConnector::DoCancel() +/** + The asynchronous request cancel. +*/ + { + // Check state + switch( iState ) + { + case EConnecting: + { + // DNS lookup is pending - cancel + iHostResolver.Cancel(); + } break; + case EConnected: + { + if( iConnectingSocket ) + { + // Connection is pending - cancel and delete the socket + iConnectingSocket->CancelConnect(); + delete iConnectingSocket; + iConnectingSocket = NULL; + } + } break; + case EIdle: + case EPendingDNSLookup: + default: + // Do nothing... + break; + } + } + +TInt CSocketConnector::RunError(TInt aError) +/** + The error handler for when RunL() leaves. This function does any necessary + cleanup. The socket connector is then set to suicide. + @param aError The leave code. + @return A value of KErrNone.if the error has been handled, any other + value if it has not been handled. + @post The socket connector is in the Suicide state. +*/ + { +#if defined (_DEBUG) && defined (_LOGGING) + TBuf8 host; + host.Copy((*iHost).Left(KHostNameSize)); //just get the KHostNameSize characters + + __FLOG_1(_T8("!! Error : %d"), aError); + __FLOG_1(_T8("-> connect to host %S failed"), &host); +#endif + + TInt errorToPropagate = aError; + TInt error = KErrNone; + + switch( iState ) + { + case EPendingDNSLookup: + case EConnecting: + { + // In EReadyForDNS or EReadyToConnect states, KErrNotReady may be + // returned by the comms call that require a connection. The RConnection + // that is passed in MUST be started or this error will occur. If we own + // the RConnection we should start the RConnection again, else if our + // client own the RConnection, we just propagate the Comms error. + if( iCommsInfoProvider.HasConnection() && iCommsInfoProvider.OwnsConnection() && aError == KErrNotReady ) + { + __FLOG_0(_T8("-> re-starting comms interface...")); + + // We own the RConnection and the error is KErrNotReady + errorToPropagate = iCommsInfoProvider.Connection().Start(); + + if( errorToPropagate == KErrNone ) + { + __FLOG_0(_T8("!! Re-started comms interface")); + __FLOG_1(_T8("-> try connecting to host %S again"), &host); + + // RConnection started successfully, try to connect again + CompleteSelf(); + return KErrNone; + } +#if defined (_DEBUG) && defined (_LOGGING) + else + { + __FLOG_1(_T8("!! Error : %d"), errorToPropagate); + __FLOG_0(_T8("-> failed to re-start comms interface")); + __FLOG_1(_T8("-> connect to host %S failed"), &host); + } +#endif + } + // Opening the connecting socket has failed or the DNS lookup completed + // with an error code - suicide after notifying the observer - do nothing + // except drop through to the Connected state case... + } + case EConnected: + { + // Either the socket controller factory left in AddToStoreL() or in + // CreateSocketControllerLC(), or the observer left in ConnectionMadeL() + // or the connect request completed with an error code. Inform the + // observer of the error. + error = iObserver->HandleConnectError(errorToPropagate); + } break; + case EIdle: + default: + THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadSocketConnectorState); + break; + } + + Suicide(); + + return error; + }