applayerpluginsandutils/httptransportplugins/httptransporthandler/csocketlistener.cpp
changeset 0 b16258d2340f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/applayerpluginsandutils/httptransportplugins/httptransporthandler/csocketlistener.cpp	Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,318 @@
+// 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 "csocketlistener.h"
+
+#include "csocket.h"
+#include "msocketcontrollerfactory.h"
+#include "mcommsinfoprovider.h"
+#include "msocketlistenobserver.h"
+#include "csocketcontroller.h"
+#include "httptransporthandlercommon.h"
+#include "thttptrlayerpanic.h"
+
+const TInt KListenQSize	= 5;
+
+CSocketListener* CSocketListener::NewL(
+  									  MSocketControllerFactory&	aSocketControllerFactory,
+									  MCommsInfoProvider&		aCommsInfoProvider, TBool aPriority
+									  )
+/**	
+	The factory constructor.
+	@param		aSocketControllerFactory	The socket controller factory.
+	@param		aCommsInfoProvider			The comms info provider.
+	@return		A pointer to a fully constructed object.
+*/
+	{
+	return new (ELeave) CSocketListener(aSocketControllerFactory, aCommsInfoProvider, aPriority);
+	}
+
+CSocketListener::~CSocketListener()
+/**	
+	Destructor.
+*/
+	{
+	// Cancel any outstanding requests
+	Cancel();
+
+	// Cleanup...
+	delete iAcceptingSocket;
+	delete iListeningSocket;
+
+//	__FLOG_CLOSE;
+	}
+
+CSocketListener::CSocketListener(
+								MSocketControllerFactory&	aSocketControllerFactory,
+								MCommsInfoProvider&			aCommsInfoProvider,
+								TBool aPriority
+								)
+: CActive(CActive::EPriorityStandard), iSocketControllerFactory(aSocketControllerFactory),
+									   iCommsInfoProvider(aCommsInfoProvider)
+/**	
+	Constructor.
+	@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 CSocketListener::Listen(MSocketListenObserver& aObserver, TUint16 aPort)
+/**	
+	The socket listener starts listening on the specified port.
+	@param		aPort	The specified listening port.
+	@pre		The socket listener is in the Idle state.
+	@post		The socket listener is not in the Idle state.
+*/
+	{
+	__ASSERT_DEBUG( iState == EIdle, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadSocketListenerState) );
+
+	iObserver = &aObserver;
+	iPort = aPort;
+
+	// Move to the StartListen state and self complete
+	iState = EStartListen;
+	CompleteSelf();
+	}
+
+void CSocketListener::StopListen()
+/**	
+	The socket listener stops listening. If the socket listener is in the Idle state this
+	function will have no effect.
+	@pre		The socket listener is not in the Idle state.
+	@post		The socket listener is in the Idle state.
+*/
+	{
+	if( iState != EIdle )
+		{
+		// Cancel any outstanding requests
+		Cancel();
+
+		// Call RunL() with an iStatus of KErrCancel - this will notify the observer
+		// that the listening service has stopped.
+		TRequestStatus* pStat = &iStatus;
+		User::RequestComplete(pStat, KErrCancel);
+		SetActive();
+
+		__FLOG_0(_T8("!! Listen service stopped"));
+		__FLOG_2(_T8("-> cancel listen on local port %d : expect %d error code"), iPort, iStatus.Int());
+		}
+	}
+
+void CSocketListener::CompleteSelf()
+/**	
+	Requests that the socket listener complete itself. This will cause the 
+	RunL() to be called by the scheduler at the next opportunity.
+	@pre		The socket listener object is not active.
+	@post		The socket listener object is active and the request has been
+				completed.
+*/
+	{
+	TRequestStatus* pStat = &iStatus;
+	User::RequestComplete(pStat, KErrNone);
+	SetActive();
+	}
+
+ /*
+  * Methods from CActive
+  */
+
+void CSocketListener::RunL()
+/**	
+	The request servicing function. Behaviour depends on the state of the socket
+	listener.
+*/
+	{
+	// Leave if the listening socket reported an error
+	User::LeaveIfError(iStatus.Int());
+
+	switch( iState )
+		{
+	case EStartListen:
+		{
+		__ASSERT_DEBUG( iListeningSocket == NULL, User::Invariant() );
+
+		__FLOG_1(_T8("Start listen service -> on local port %d"), iPort);
+
+		// Open the listening socket on specified port
+		iListeningSocket = CSocket::NewL(iCommsInfoProvider, CSocket::EProtocolSocket);
+
+		// Start the listening service
+		User::LeaveIfError(iListeningSocket->Listen(KListenQSize, iPort));
+
+		// Move to the Listening state and self complete
+		iState = EListening;
+		CompleteSelf();
+		} break;
+	case EListening:
+		{
+		// Create a new accepting socket - marry it to the listening socket
+		iAcceptingSocket = CSocket::NewL(iCommsInfoProvider, CSocket::EBlankSocket);
+		iListeningSocket->Accept(*iAcceptingSocket, iStatus);
+
+		// Move to the Connected state and go active
+		iState = EConnected;
+		SetActive();
+		} break;
+	case EConnected:
+		{
+		__OOM_LEAVE_TEST
+
+#if defined (_DEBUG) && defined (_LOGGING)
+		TInetAddr addr;
+		iAcceptingSocket->RemoteName(addr);
+
+		TBuf<KIpv6MaxAddrSize> ip16bit;
+		addr.Output(ip16bit);
+
+		TBuf8<KIpv6MaxAddrSize> ip;
+		ip.Copy(ip16bit);
+
+		__FLOG_1(_T8("!! Listen service received connection on local port %d"), iPort);
+		__FLOG_2(_T8("-> connection with %S, remote port %d"), &ip, addr.Port());
+#endif
+
+		// A remote client has connected to the listening socket - lose ownership
+		// of the accepting socket.
+		CSocket* connectedSocket = iAcceptingSocket;
+		iAcceptingSocket = NULL;
+
+		// Create a socket controller object to own the connected socket.
+		CSocketController* socketController = iSocketControllerFactory.CreateSocketControllerLC(connectedSocket);
+
+		// Inform the socket listen observer that a TCP connection is established - 
+		// pass back the input and output stream objects.
+		iObserver->ConnectionReceivedL(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);
+		
+		__FLOG_1(_T8("Continue listen service -> on local port %d"), iPort);
+
+		// Move to the Listening state and self complete
+		iState = EListening;
+		CompleteSelf();
+		} break;
+	case EIdle:
+	default:
+		THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadSocketListenerState);
+		break;
+		}
+	}
+
+void CSocketListener::DoCancel()
+/**	
+	The asynchronous request cancel.
+*/
+	{
+	// Check state...
+	if( iState == EConnected )
+		{
+		// Need to cancel the accept request
+		iListeningSocket->CancelAccept();
+		}
+	}
+
+TInt CSocketListener::RunError(TInt aError)
+/**	
+	The request servicing error handler. This function does any necessary cleanup.
+	The socket listener is then placed in the Idle state.
+	@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 listener is in the Idle state.
+*/
+	{
+	__FLOG_1(_T8("!! Error : %d"), aError);
+	__FLOG_1(_T8("-> listen on local port %d failed"), iPort);
+
+	switch( iState )
+		{
+	case EConnected:
+		{
+		// Either the socket controller factory left in AddToStoreL() or in 
+		// CreateSocketControllerLC(), or the observer left in 
+		// ConnectionReceivedL() or the accept request completed with an error
+		// code - which ever just need to delete the accepting socket.
+		delete iAcceptingSocket;
+		iAcceptingSocket = NULL;
+		// Drop through to the Listening state case...
+		}
+	case EListening:
+		{
+		// Failed to open the accepting socket - do nothing except drop through
+		// to the PendingListening state case...
+		}
+	case EStartListen:
+		{
+		// 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 && iState != EConnected )
+			{
+			__FLOG_0(_T8("-> re-starting comms interface..."));
+
+			// We own the RConnection and the error is KErrNotReady
+			aError = iCommsInfoProvider.Connection().Start();
+			if( aError==KErrNone )
+				{
+				__FLOG_0(_T8("!! Re-started comms interface"));
+				__FLOG_1(_T8("-> start listen on local port %d again"), iPort);
+
+				// RConnection started successfully, try to connect again
+				CompleteSelf();
+				return KErrNone;
+				}
+#if defined (_DEBUG) && defined (_LOGGING)
+			else
+				{
+				__FLOG_1(_T8("!! Error : %d"), aError);
+				__FLOG_0(_T8("-> failed to re-start comms interface"));
+				__FLOG_1(_T8("-> listen on port %d failed"), iPort);
+				}			
+#endif
+			}
+
+		// Failed to either start the listening service or create the listening 
+		// socket - delete the listening socket.
+		delete iListeningSocket;
+		iListeningSocket = NULL;
+
+		// Move back to the Idle state.
+		iState = EIdle;
+		} break;
+	case EIdle:
+	default:
+		THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadSocketListenerState);
+		break;
+		}
+
+	// Inform the manager of the error.
+	return iObserver->HandleListenError(aError);
+	}