applayerpluginsandutils/httptransportplugins/httptransporthandler/csocketlistener.cpp
changeset 0 b16258d2340f
equal deleted inserted replaced
-1:000000000000 0:b16258d2340f
       
     1 // Copyright (c) 2003-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 "csocketlistener.h"
       
    17 
       
    18 #include "csocket.h"
       
    19 #include "msocketcontrollerfactory.h"
       
    20 #include "mcommsinfoprovider.h"
       
    21 #include "msocketlistenobserver.h"
       
    22 #include "csocketcontroller.h"
       
    23 #include "httptransporthandlercommon.h"
       
    24 #include "thttptrlayerpanic.h"
       
    25 
       
    26 const TInt KListenQSize	= 5;
       
    27 
       
    28 CSocketListener* CSocketListener::NewL(
       
    29   									  MSocketControllerFactory&	aSocketControllerFactory,
       
    30 									  MCommsInfoProvider&		aCommsInfoProvider, TBool aPriority
       
    31 									  )
       
    32 /**	
       
    33 	The factory constructor.
       
    34 	@param		aSocketControllerFactory	The socket controller factory.
       
    35 	@param		aCommsInfoProvider			The comms info provider.
       
    36 	@return		A pointer to a fully constructed object.
       
    37 */
       
    38 	{
       
    39 	return new (ELeave) CSocketListener(aSocketControllerFactory, aCommsInfoProvider, aPriority);
       
    40 	}
       
    41 
       
    42 CSocketListener::~CSocketListener()
       
    43 /**	
       
    44 	Destructor.
       
    45 */
       
    46 	{
       
    47 	// Cancel any outstanding requests
       
    48 	Cancel();
       
    49 
       
    50 	// Cleanup...
       
    51 	delete iAcceptingSocket;
       
    52 	delete iListeningSocket;
       
    53 
       
    54 //	__FLOG_CLOSE;
       
    55 	}
       
    56 
       
    57 CSocketListener::CSocketListener(
       
    58 								MSocketControllerFactory&	aSocketControllerFactory,
       
    59 								MCommsInfoProvider&			aCommsInfoProvider,
       
    60 								TBool aPriority
       
    61 								)
       
    62 : CActive(CActive::EPriorityStandard), iSocketControllerFactory(aSocketControllerFactory),
       
    63 									   iCommsInfoProvider(aCommsInfoProvider)
       
    64 /**	
       
    65 	Constructor.
       
    66 	@param		aSocketControllerFactory	The socket controller factory.
       
    67 	@param		aCommsInfoProvider			The comms info provider.
       
    68 */
       
    69 	{
       
    70 	if(aPriority)
       
    71 		{
       
    72 		CActive::SetPriority(CActive::EPriorityHigh);	
       
    73 		}
       
    74 	CActiveScheduler::Add(this);
       
    75 
       
    76 //	__FLOG_OPEN("http", "httptransporthandler.txt");
       
    77 	}
       
    78 
       
    79 void CSocketListener::Listen(MSocketListenObserver& aObserver, TUint16 aPort)
       
    80 /**	
       
    81 	The socket listener starts listening on the specified port.
       
    82 	@param		aPort	The specified listening port.
       
    83 	@pre		The socket listener is in the Idle state.
       
    84 	@post		The socket listener is not in the Idle state.
       
    85 */
       
    86 	{
       
    87 	__ASSERT_DEBUG( iState == EIdle, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadSocketListenerState) );
       
    88 
       
    89 	iObserver = &aObserver;
       
    90 	iPort = aPort;
       
    91 
       
    92 	// Move to the StartListen state and self complete
       
    93 	iState = EStartListen;
       
    94 	CompleteSelf();
       
    95 	}
       
    96 
       
    97 void CSocketListener::StopListen()
       
    98 /**	
       
    99 	The socket listener stops listening. If the socket listener is in the Idle state this
       
   100 	function will have no effect.
       
   101 	@pre		The socket listener is not in the Idle state.
       
   102 	@post		The socket listener is in the Idle state.
       
   103 */
       
   104 	{
       
   105 	if( iState != EIdle )
       
   106 		{
       
   107 		// Cancel any outstanding requests
       
   108 		Cancel();
       
   109 
       
   110 		// Call RunL() with an iStatus of KErrCancel - this will notify the observer
       
   111 		// that the listening service has stopped.
       
   112 		TRequestStatus* pStat = &iStatus;
       
   113 		User::RequestComplete(pStat, KErrCancel);
       
   114 		SetActive();
       
   115 
       
   116 		__FLOG_0(_T8("!! Listen service stopped"));
       
   117 		__FLOG_2(_T8("-> cancel listen on local port %d : expect %d error code"), iPort, iStatus.Int());
       
   118 		}
       
   119 	}
       
   120 
       
   121 void CSocketListener::CompleteSelf()
       
   122 /**	
       
   123 	Requests that the socket listener complete itself. This will cause the 
       
   124 	RunL() to be called by the scheduler at the next opportunity.
       
   125 	@pre		The socket listener object is not active.
       
   126 	@post		The socket listener object is active and the request has been
       
   127 				completed.
       
   128 */
       
   129 	{
       
   130 	TRequestStatus* pStat = &iStatus;
       
   131 	User::RequestComplete(pStat, KErrNone);
       
   132 	SetActive();
       
   133 	}
       
   134 
       
   135  /*
       
   136   * Methods from CActive
       
   137   */
       
   138 
       
   139 void CSocketListener::RunL()
       
   140 /**	
       
   141 	The request servicing function. Behaviour depends on the state of the socket
       
   142 	listener.
       
   143 */
       
   144 	{
       
   145 	// Leave if the listening socket reported an error
       
   146 	User::LeaveIfError(iStatus.Int());
       
   147 
       
   148 	switch( iState )
       
   149 		{
       
   150 	case EStartListen:
       
   151 		{
       
   152 		__ASSERT_DEBUG( iListeningSocket == NULL, User::Invariant() );
       
   153 
       
   154 		__FLOG_1(_T8("Start listen service -> on local port %d"), iPort);
       
   155 
       
   156 		// Open the listening socket on specified port
       
   157 		iListeningSocket = CSocket::NewL(iCommsInfoProvider, CSocket::EProtocolSocket);
       
   158 
       
   159 		// Start the listening service
       
   160 		User::LeaveIfError(iListeningSocket->Listen(KListenQSize, iPort));
       
   161 
       
   162 		// Move to the Listening state and self complete
       
   163 		iState = EListening;
       
   164 		CompleteSelf();
       
   165 		} break;
       
   166 	case EListening:
       
   167 		{
       
   168 		// Create a new accepting socket - marry it to the listening socket
       
   169 		iAcceptingSocket = CSocket::NewL(iCommsInfoProvider, CSocket::EBlankSocket);
       
   170 		iListeningSocket->Accept(*iAcceptingSocket, iStatus);
       
   171 
       
   172 		// Move to the Connected state and go active
       
   173 		iState = EConnected;
       
   174 		SetActive();
       
   175 		} break;
       
   176 	case EConnected:
       
   177 		{
       
   178 		__OOM_LEAVE_TEST
       
   179 
       
   180 #if defined (_DEBUG) && defined (_LOGGING)
       
   181 		TInetAddr addr;
       
   182 		iAcceptingSocket->RemoteName(addr);
       
   183 
       
   184 		TBuf<KIpv6MaxAddrSize> ip16bit;
       
   185 		addr.Output(ip16bit);
       
   186 
       
   187 		TBuf8<KIpv6MaxAddrSize> ip;
       
   188 		ip.Copy(ip16bit);
       
   189 
       
   190 		__FLOG_1(_T8("!! Listen service received connection on local port %d"), iPort);
       
   191 		__FLOG_2(_T8("-> connection with %S, remote port %d"), &ip, addr.Port());
       
   192 #endif
       
   193 
       
   194 		// A remote client has connected to the listening socket - lose ownership
       
   195 		// of the accepting socket.
       
   196 		CSocket* connectedSocket = iAcceptingSocket;
       
   197 		iAcceptingSocket = NULL;
       
   198 
       
   199 		// Create a socket controller object to own the connected socket.
       
   200 		CSocketController* socketController = iSocketControllerFactory.CreateSocketControllerLC(connectedSocket);
       
   201 
       
   202 		// Inform the socket listen observer that a TCP connection is established - 
       
   203 		// pass back the input and output stream objects.
       
   204 		iObserver->ConnectionReceivedL(socketController->InputStream(), socketController->OutputStream());
       
   205 
       
   206 		// Remove socket controller from cleanup stack - transferring ownership
       
   207 		// to the store.
       
   208 		CleanupStack::Pop(socketController);
       
   209 
       
   210 		// Add the socket controller in the store - ownership is transferred to
       
   211 		// the store.
       
   212 		iSocketControllerFactory.AddToStoreL(socketController);
       
   213 		
       
   214 		__FLOG_1(_T8("Continue listen service -> on local port %d"), iPort);
       
   215 
       
   216 		// Move to the Listening state and self complete
       
   217 		iState = EListening;
       
   218 		CompleteSelf();
       
   219 		} break;
       
   220 	case EIdle:
       
   221 	default:
       
   222 		THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadSocketListenerState);
       
   223 		break;
       
   224 		}
       
   225 	}
       
   226 
       
   227 void CSocketListener::DoCancel()
       
   228 /**	
       
   229 	The asynchronous request cancel.
       
   230 */
       
   231 	{
       
   232 	// Check state...
       
   233 	if( iState == EConnected )
       
   234 		{
       
   235 		// Need to cancel the accept request
       
   236 		iListeningSocket->CancelAccept();
       
   237 		}
       
   238 	}
       
   239 
       
   240 TInt CSocketListener::RunError(TInt aError)
       
   241 /**	
       
   242 	The request servicing error handler. This function does any necessary cleanup.
       
   243 	The socket listener is then placed in the Idle state.
       
   244 	@param		aError	The leave code.
       
   245 	@return		A value of KErrNone.if the error has been handled, any other 
       
   246 				value if it has not been handled.
       
   247 	@post		The socket listener is in the Idle state.
       
   248 */
       
   249 	{
       
   250 	__FLOG_1(_T8("!! Error : %d"), aError);
       
   251 	__FLOG_1(_T8("-> listen on local port %d failed"), iPort);
       
   252 
       
   253 	switch( iState )
       
   254 		{
       
   255 	case EConnected:
       
   256 		{
       
   257 		// Either the socket controller factory left in AddToStoreL() or in 
       
   258 		// CreateSocketControllerLC(), or the observer left in 
       
   259 		// ConnectionReceivedL() or the accept request completed with an error
       
   260 		// code - which ever just need to delete the accepting socket.
       
   261 		delete iAcceptingSocket;
       
   262 		iAcceptingSocket = NULL;
       
   263 		// Drop through to the Listening state case...
       
   264 		}
       
   265 	case EListening:
       
   266 		{
       
   267 		// Failed to open the accepting socket - do nothing except drop through
       
   268 		// to the PendingListening state case...
       
   269 		}
       
   270 	case EStartListen:
       
   271 		{
       
   272 		// In EReadyForDNS or EReadyToConnect states, KErrNotReady may be 
       
   273 		// returned by the comms call that require a connection. The RConnection
       
   274 		// that is passed in MUST be started or this error will occur. If we own
       
   275 		// the RConnection we should start the RConnection again, else if our 
       
   276 		// client own the RConnection, we just propagate the Comms error.
       
   277 		if( iCommsInfoProvider.HasConnection() && iCommsInfoProvider.OwnsConnection() && aError == KErrNotReady && iState != EConnected )
       
   278 			{
       
   279 			__FLOG_0(_T8("-> re-starting comms interface..."));
       
   280 
       
   281 			// We own the RConnection and the error is KErrNotReady
       
   282 			aError = iCommsInfoProvider.Connection().Start();
       
   283 			if( aError==KErrNone )
       
   284 				{
       
   285 				__FLOG_0(_T8("!! Re-started comms interface"));
       
   286 				__FLOG_1(_T8("-> start listen on local port %d again"), iPort);
       
   287 
       
   288 				// RConnection started successfully, try to connect again
       
   289 				CompleteSelf();
       
   290 				return KErrNone;
       
   291 				}
       
   292 #if defined (_DEBUG) && defined (_LOGGING)
       
   293 			else
       
   294 				{
       
   295 				__FLOG_1(_T8("!! Error : %d"), aError);
       
   296 				__FLOG_0(_T8("-> failed to re-start comms interface"));
       
   297 				__FLOG_1(_T8("-> listen on port %d failed"), iPort);
       
   298 				}			
       
   299 #endif
       
   300 			}
       
   301 
       
   302 		// Failed to either start the listening service or create the listening 
       
   303 		// socket - delete the listening socket.
       
   304 		delete iListeningSocket;
       
   305 		iListeningSocket = NULL;
       
   306 
       
   307 		// Move back to the Idle state.
       
   308 		iState = EIdle;
       
   309 		} break;
       
   310 	case EIdle:
       
   311 	default:
       
   312 		THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadSocketListenerState);
       
   313 		break;
       
   314 		}
       
   315 
       
   316 	// Inform the manager of the error.
       
   317 	return iObserver->HandleListenError(aError);
       
   318 	}