email/imap4mtm/imaptransporthandler/src/csocketreader.cpp
changeset 0 72b543305e3a
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     1 // Copyright (c) 2006-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 "csocketreader.h"
       
    17 
       
    18 #include "csocket.h"
       
    19 #include "msocketcontroller.h"
       
    20 #include "minputstreamobserver.h"
       
    21 #include "imappaniccodes.h"
       
    22 #include "imaptransportmanagercommon.h"
       
    23 #include "cimaplogger.h"
       
    24 
       
    25 const TInt KMicroSecondsToSeconds = 1000000;
       
    26 /**
       
    27 The factory constructor.
       
    28 
       
    29 @param		aSocket		The connected socket. This owned by the observer.
       
    30 @param		aController	The socket controller that owns the socket.
       
    31 @return		A pointer to a fully constructed object.
       
    32 */
       
    33 CSocketReader* CSocketReader::NewL(CSocket& aSocket, MSocketController& aController)
       
    34 	{
       
    35 	 CSocketReader* self = new(ELeave) CSocketReader(aSocket, aController);
       
    36 	 CleanupStack::PushL(self);
       
    37 	 self->ConstructL();
       
    38 	 CleanupStack::Pop(self);
       
    39 	 return self;
       
    40 	}
       
    41 
       
    42 void CSocketReader::ConstructL()
       
    43 	{
       
    44 	iTimer = CImapObservableTimer::NewL(*this);
       
    45 	}	
       
    46 /**
       
    47 Destructor.
       
    48 */
       
    49 CSocketReader::~CSocketReader()
       
    50 	{
       
    51 	__ASSERT_DEBUG( iObserver == NULL || iState == EClosed, TImapServerPanic::ImapPanic(TImapServerPanic::EBadInputStreamState) );
       
    52 
       
    53 	// Cancel any outstanding requests
       
    54 	Cancel();
       
    55 	delete iTimer;
       
    56 	}
       
    57 
       
    58 /**
       
    59 Constructor.
       
    60 
       
    61 @param	aSocket		The connected socket. This owned by the observer.
       
    62 @param	aController	The socket controller that owns the socket.
       
    63 */
       
    64 CSocketReader::CSocketReader(CSocket& aSocket, MSocketController& aController)
       
    65 	: CActive(CActive::EPriorityStandard), iSocket(aSocket), iController(aController)
       
    66 	{
       
    67 	CActiveScheduler::Add(this);
       
    68 	}
       
    69 
       
    70 /**
       
    71 Requests that the input stream complete itself. This will caused the RunL()
       
    72 to be called by the scheduler at the next opportunity.
       
    73 
       
    74 @pre	The input stream is not active.
       
    75 @post	The input stream object is active and the request has been
       
    76 		completed.
       
    77 */
       
    78 void CSocketReader::CompleteSelf()
       
    79 	{
       
    80 	__LOG_TEXT(iLogId, "CSocketReader::CompleteSelf");
       
    81 	TRequestStatus* pStat = &iStatus;
       
    82 	User::RequestComplete(pStat, KErrNone);
       
    83 	SetActive();
       
    84 	}
       
    85 
       
    86 /**
       
    87 Notifies the input stream that the socket is closed. The input stream 
       
    88 observer is notified that the stream is closed. No more data can be received
       
    89 from the socket.
       
    90 
       
    91 @param	aError	The error code explaining why the socket has closed. A
       
    92 				value of KErrNone indicates that the output stream 
       
    93 				observer requested that the socket be closed.
       
    94 @pre	None.
       
    95 @post	The input stream is in the Closed state.
       
    96 */
       
    97 void CSocketReader::SocketClosed(TInt aError)
       
    98 	{
       
    99 	// Cancel any outstanding requests
       
   100 	Cancel();
       
   101 
       
   102 	// The socket has shutdown. Inform the input stream observer that the input
       
   103 	// stream is closed.
       
   104 	if( iObserver )
       
   105 		{
       
   106 		iObserver->InputStreamCloseInd(aError);
       
   107 		}		
       
   108 
       
   109 	// Move to the Closed state
       
   110 	SetState(EClosed);
       
   111 	}
       
   112 
       
   113 /**
       
   114 Notifies the input stream that the socket is to be suspended.
       
   115 */
       
   116 void CSocketReader::Suspend()
       
   117 	{
       
   118 	__ASSERT_DEBUG( !iSuspended, TImapServerPanic::ImapPanic(TImapServerPanic::EInputStreamAlreadySuspended) );
       
   119 
       
   120 	// Cancel any outstanding requests
       
   121 	Cancel();
       
   122 
       
   123 #if defined (_DEBUG) && defined (_LOGGING)
       
   124 	TBuf8<KIpv6MaxAddrSize> ip;
       
   125 	TUint16	remotePort;
       
   126 	TUint16 localPort;
       
   127 	iController.ConnectionInfo(ip, remotePort, localPort);
       
   128 
       
   129 	__FLOG_0(_T8("!! Suspending input stream"));
       
   130 	__FLOG_3(_T8("-> on local port %d with %S, remote port %d"), localPort, &ip, remotePort);
       
   131 #endif
       
   132 
       
   133 	// Check to see a read requests had been issued.
       
   134 	if( iState == EReceivedData )
       
   135 		{
       
   136 		// Yep - change to the Read state so that read request is re-issued when
       
   137 		// the stream resumes.
       
   138 		SetState(ERead);
       
   139 		}
       
   140 
       
   141 	// Stream is now suspended.
       
   142 	iSuspended = ETrue;
       
   143 	}
       
   144 
       
   145 /**
       
   146 Notifies the input stream that the socket is to be resumed.
       
   147 */
       
   148 void CSocketReader::Resume()
       
   149 	{
       
   150 	__ASSERT_DEBUG( iSuspended, TImapServerPanic::ImapPanic(TImapServerPanic::EInputStreamNotSuspended) );
       
   151 
       
   152 #if defined (_DEBUG) && defined (_LOGGING)
       
   153 	TBuf8<KIpv6MaxAddrSize> ip;
       
   154 	TUint16	remotePort;
       
   155 	TUint16 localPort;
       
   156 	iController.ConnectionInfo(ip, remotePort, localPort);
       
   157 
       
   158 	__FLOG_0(_T8("!! Resumimng input stream"));
       
   159 	__FLOG_3(_T8("-> on local port %d with %S, remote port %d"), localPort, &ip, remotePort);
       
   160 #endif
       
   161 
       
   162 	// Check to see a read requests needs to be issued.
       
   163 	if( iState == ERead )
       
   164 		{
       
   165 		if (!iBufferDataDelivered && iBuffer.Length() > 0)
       
   166 			{
       
   167 			// We have undelivered data in the buffer (probably caused by the Cancel() in Suspend())
       
   168 			// Deliver it now - rather than requesting more.
       
   169 			SetState(EReceivedData);
       
   170 			}		
       
   171 		
       
   172 		// Self complete to get the read request issued or to deliver the undelivered data.
       
   173 		CompleteSelf();
       
   174 		}
       
   175 
       
   176 	// Stream is no longer suspended.
       
   177 	iSuspended = EFalse;
       
   178 	}
       
   179 
       
   180 /**
       
   181 @see MInputStream
       
   182 */
       
   183 void CSocketReader::Bind(MInputStreamObserver& aObserver, TInt aLogId)
       
   184 	{
       
   185 	__ASSERT_DEBUG( iState == EIdle, TImapServerPanic::ImapPanic(TImapServerPanic::EBadInputStreamState) );
       
   186 
       
   187 	// Bind to the input stream observer
       
   188 	iObserver = &aObserver;
       
   189 	
       
   190 	iLogId = aLogId;
       
   191 	}
       
   192 
       
   193 /**
       
   194 @see MInputStream
       
   195 */
       
   196 void CSocketReader::ReadReq(TInt aIdleTime)
       
   197 	{
       
   198 	// Do we have an observer to report the incoming data to?
       
   199 	__ASSERT_DEBUG( iObserver != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EInputStreamNotBound) );
       
   200 	// Are we already reading?
       
   201 	__ASSERT_DEBUG( iState == EIdle, TImapServerPanic::ImapPanic(TImapServerPanic::EBadInputStreamState) );
       
   202 	if (aIdleTime > 0)
       
   203 		{
       
   204 		iIdleTime = aIdleTime;
       
   205 		}
       
   206 	
       
   207 	// The input stream observer has requested some data.
       
   208 	// Check whether the data in the buffer has already been delivered to an observer
       
   209 	if (iBufferDataDelivered)
       
   210 		{
       
   211 		// We don't want to deliver it twice, so zero the buffer.
       
   212 		iBuffer.Zero();
       
   213 		}
       
   214 
       
   215 	if (iSuspended)
       
   216 		{
       
   217 		// Set the start to read so that data will be requested/delivered when Resume() is called.
       
   218 		SetState(ERead);
       
   219 		}
       
   220 	else
       
   221 		{
       
   222 		// If we still have data left to deliver, then deliver it now.
       
   223 		// This can happen after a CancelRecv(), as the buffer will have been populated with data received 
       
   224 		// at the time of cancel, but will not yet have been delivered.
       
   225 		if (iBuffer.Length() > 0)
       
   226 			{
       
   227 			__LOG_TEXT(iLogId, "CSocketReader - Delivering data received prior to cancel");
       
   228 			SetState(EReceivedData);
       
   229 			}
       
   230 		// Otherwise read some more from the socket
       
   231 		else
       
   232 			{
       
   233 			SetState(ERead);
       
   234 			}
       
   235 			
       
   236 		CompleteSelf();
       
   237 		}	
       
   238 	}
       
   239 	
       
   240 /**
       
   241 @see MInputStream
       
   242 */
       
   243 TBool CSocketReader::IsReading()
       
   244 	{
       
   245 	return (iState == ERead || iState == EReceivedData);
       
   246 	}
       
   247 
       
   248 /**
       
   249 @see MInputStream
       
   250 */
       
   251 void CSocketReader::CancelReadReq()
       
   252 	{
       
   253 	__ASSERT_DEBUG( iState == EIdle || iState == ERead || iState == EReceivedData, TImapServerPanic::ImapPanic(TImapServerPanic::EBadInputStreamState) );
       
   254 	
       
   255 	iTimer->Cancel();
       
   256 	Cancel();	
       
   257 	
       
   258 	SetState(EIdle);
       
   259 	}
       
   260 
       
   261 /*
       
   262  *	Methods from CActive
       
   263  */
       
   264 
       
   265 /**
       
   266 The request servicing function. Behaviour depends on the state of the input
       
   267 stream.
       
   268 
       
   269 @leave	The function will leave if the request status is an error.
       
   270 */
       
   271 void CSocketReader::RunL()
       
   272 	{
       
   273 	__ASSERT_DEBUG( iObserver != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EInputStreamNotBound) );
       
   274 
       
   275 	__LOG_FORMAT((iLogId, "CSocketReader::RunL - State %d, Status %d", iState, iStatus.Int()));
       
   276 
       
   277 	iTimer->Cancel();
       
   278 	// Leave if the socket reported an error
       
   279 	User::LeaveIfError(iStatus.Int());
       
   280 
       
   281 	switch( iState )
       
   282 		{
       
   283 	case ERead:
       
   284 		{
       
   285 		// Request a read from the socket
       
   286 		__ASSERT_DEBUG( iBuffer.Length() == 0, TImapServerPanic::ImapPanic(TImapServerPanic::EInputStreamBufferNotEmpty) );
       
   287 		iBufferDataDelivered = EFalse;
       
   288 		iSocket.RecvOneOrMore(iBuffer, iStatus);
       
   289 
       
   290 		// Move to the Received state and go active - wait for read to complete
       
   291 		SetState(EReceivedData);
       
   292 		SetActive();		
       
   293 		if(iIdleTime > 0)
       
   294 			{
       
   295 			// The recieve from socket should complete in iIdleTime seconds.
       
   296 			iTimer->After(iIdleTime*KMicroSecondsToSeconds);
       
   297 			iIdleTime = 0;
       
   298 			}
       
   299 		} break;
       
   300 	case EReceivedData:
       
   301 		{
       
   302 		// Received data - move to the PendingAck state and wait for observer to 
       
   303 		// notify that it has finished with the buffer.
       
   304 		SetState(EIdle);
       
   305 
       
   306 		__LOG_DATA_IN(iLogId, iBuffer);
       
   307 
       
   308 		// Inform the observer of the received data.
       
   309 		iBufferDataDelivered = ETrue;
       
   310 		iObserver->ReceivedDataIndL(iBuffer);
       
   311 
       
   312 #if defined (_DEBUG) && defined (_LOGGING)
       
   313 		TBuf8<KIpv6MaxAddrSize> ip;
       
   314 		TUint16	remotePort;
       
   315 		TUint16 localPort;
       
   316 		iController.ConnectionInfo(ip, remotePort, localPort);
       
   317 	
       
   318 		__FLOG_4(_T8("Received %d bytes on local port %d from %S, remote port %d"), iBuffer.Length(), localPort, &ip, remotePort);
       
   319 		__FLOG_0(_T8("----------"));
       
   320 		__FLOG_HEXDUMP(iBuffer.Ptr(), iBuffer.Length());
       
   321 		__FLOG_0(_T8("----------"));
       
   322 #endif
       
   323 		} break;
       
   324 	case EClosing:
       
   325 		{
       
   326 		// The socket has shutdown - move to the Closed state
       
   327 		SetState(EClosed);
       
   328 
       
   329 		// Inform the observer that the input stream is closed.
       
   330 		iObserver->InputStreamCloseInd(KErrNone);
       
   331 
       
   332 		// Inform the socket controller that the input stream is now shut
       
   333 		iController.StreamClosed(KErrNone, MSocketController::EInputStream);
       
   334 		} break;
       
   335 	case EClosed:
       
   336 	case EIdle:
       
   337 	default:
       
   338 		TImapServerPanic::ImapPanic(TImapServerPanic::EBadInputStreamError);
       
   339 		break;
       
   340 		}
       
   341 	}
       
   342 
       
   343 /**
       
   344 The asynchronous request cancel function. If the input stream has requested a 
       
   345 read from the socket (ie it is in the ReceivedData state) it cancels the read
       
   346 request.
       
   347 */	
       
   348 void CSocketReader::DoCancel()
       
   349 	{
       
   350 	iTimer->Cancel();
       
   351 	if( iState == EReceivedData )
       
   352 		{
       
   353 		// There is a pending read request - cancel it
       
   354 		iSocket.CancelRecv();
       
   355 		}
       
   356 	}
       
   357 
       
   358 /**
       
   359 The asynchronous request error handler. If this has been called then the 
       
   360 read request or the socket shutdown request has failed. The socket can no 
       
   361 longer be used. The input stream observer is notified that the stream is 
       
   362 closed. No more data can be received from the socket.
       
   363 */	
       
   364 TInt CSocketReader::RunError(TInt aError)
       
   365 	{
       
   366 	CloseStreams(aError);
       
   367 
       
   368 	return KErrNone;
       
   369 	}
       
   370 
       
   371 void CSocketReader::SetState(TInputState aInputState)
       
   372 	{
       
   373 #ifdef __CSOCKETREADER_VERBOSE_LOGGING
       
   374 #ifdef __IMAP_LOGGING
       
   375 
       
   376 	_LIT8(KTxtInputStateIdle, "EIdle");
       
   377 	_LIT8(KTxtInputStateRead, "ERead");
       
   378 	_LIT8(KTxtInputStateReceivedData, "EReceivedData");
       
   379 	_LIT8(KTxtInputStateClosing, "EClosing");
       
   380 	_LIT8(KTxtInputStateClosed, "EClosed");
       
   381 	_LIT8(KTxtInputStateUnknown, "Unknown");
       
   382 				
       
   383 	TPtrC8 ptrOldState(KTxtInputStateUnknown);
       
   384 	TPtrC8 ptrNewState(KTxtInputStateUnknown);
       
   385 	
       
   386 	switch(iState)
       
   387 		{
       
   388 		case EIdle: 		ptrOldState.Set(KTxtInputStateIdle); 			break;
       
   389 		case ERead:			ptrOldState.Set(KTxtInputStateRead); 			break;
       
   390 		case EReceivedData:	ptrOldState.Set(KTxtInputStateReceivedData);	break;
       
   391 		case EClosing:		ptrOldState.Set(KTxtInputStateClosing); 		break;
       
   392 		case EClosed:		ptrOldState.Set(KTxtInputStateClosed); 			break;
       
   393 		}
       
   394 		
       
   395 	switch(aInputState)
       
   396 		{
       
   397 		case EIdle: 		ptrNewState.Set(KTxtInputStateIdle); 			break;
       
   398 		case ERead:			ptrNewState.Set(KTxtInputStateRead); 			break;
       
   399 		case EReceivedData:	ptrNewState.Set(KTxtInputStateReceivedData);	break;
       
   400 		case EClosing:		ptrNewState.Set(KTxtInputStateClosing); 		break;
       
   401 		case EClosed:		ptrNewState.Set(KTxtInputStateClosed); 			break;
       
   402 		}
       
   403 	
       
   404 	_LIT8(KLogFormat, "CSocketReader::iState %S ==> %S");
       
   405 	__LOG_FORMAT((iLogId, KLogFormat, &ptrOldState, &ptrNewState));
       
   406 	
       
   407 #endif //__IMAP_LOGGING
       
   408 #endif //__CSOCKETREADER_VERBOSE_LOGGING
       
   409 	
       
   410 	iState = aInputState;
       
   411 	}
       
   412 void CSocketReader::CloseStreams(TInt aError)
       
   413 	{
       
   414 	__ASSERT_DEBUG( iObserver != NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EInputStreamNotBound) );
       
   415 
       
   416 #if defined (_DEBUG) && defined (_LOGGING)
       
   417 	TBuf8<KIpv6MaxAddrSize> ip;
       
   418 	TUint16	remotePort;
       
   419 	TUint16 localPort;
       
   420 	iController.ConnectionInfo(ip, remotePort, localPort);
       
   421 
       
   422 	__FLOG_1(_T8("!! Input stream error : %d"), aError);
       
   423 	__FLOG_3(_T8("-> Connection on local port %d with %S, remote port %d closed"), localPort, &ip, remotePort);
       
   424 #endif
       
   425 
       
   426 	// Move to the Closed state
       
   427 	SetState(EClosed);
       
   428 
       
   429 	// The socket request has failed - the socket connection is broken. Need
       
   430 	// to inform the input stream observer that the input stream is closed.
       
   431 	
       
   432 	if (aError == KErrAbort || aError == KErrEof )
       
   433 		{
       
   434 		aError = KErrDisconnected;
       
   435 		}
       
   436 	iObserver->InputStreamCloseInd(aError);
       
   437 
       
   438 	// Inform the socket controller that the input stream is closed
       
   439 	iController.StreamClosed(aError, MSocketController::EInputStream);
       
   440 	}
       
   441 
       
   442 
       
   443 #ifdef _DEBUG
       
   444 void CSocketReader::OnTimerL(const CImapObservableTimer& aSourceTimer)
       
   445 #else
       
   446 void CSocketReader::OnTimerL(const CImapObservableTimer& /*aSourceTimer*/)
       
   447 #endif
       
   448 	{
       
   449 	__ASSERT_DEBUG(&aSourceTimer == iTimer, TImapServerPanic::ImapPanic(TImapServerPanic::ESessionUnknownTimer));
       
   450 	Cancel();
       
   451 	CloseStreams(KErrTimedOut);
       
   452 	}