applayerpluginsandutils/httptransportplugins/httptransporthandler/csocketwriter.cpp
changeset 0 b16258d2340f
child 5 337070b4fa18
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 "csocketwriter.h"
       
    17 
       
    18 #include "csocket.h"
       
    19 #include "msocketcontroller.h"
       
    20 #include "moutputstreamobserver.h"
       
    21 #include "httptransporthandlercommon.h"
       
    22 #include "thttptrlayerpanic.h"
       
    23 
       
    24 CSocketWriter* CSocketWriter::NewL(CSocket& aSocket, MSocketController& aController, TBool aPriority)
       
    25 /**	
       
    26 	The factory constructor.
       
    27 	@param		aSocket		The connected socket. This owned by the observer.
       
    28 	@param		aController	The socket controller that owns the socket.
       
    29 	@return		A pointer to a fully constructed object.
       
    30 */
       
    31 	{
       
    32 	return new (ELeave) CSocketWriter(aSocket, aController, aPriority);
       
    33 	}
       
    34 
       
    35 CSocketWriter::~CSocketWriter()
       
    36 /**	
       
    37 	Destructor.
       
    38 */
       
    39 	{
       
    40 	__ASSERT_DEBUG( iState == EIdle || iState == EClosed, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadOutputStreamState) );
       
    41     
       
    42 	//Delete the Timer object.
       
    43 	delete iSendTimer;
       
    44 
       
    45 	// Cancel any outstanding requests
       
    46 	Cancel();
       
    47 
       
    48 //	__FLOG_CLOSE;
       
    49 	}
       
    50 
       
    51 CSocketWriter::CSocketWriter(CSocket& aSocket, MSocketController& aController, TBool aPriority)
       
    52 : CActive(CActive::EPriorityStandard), iSocket(aSocket), iController(aController)
       
    53 /**	
       
    54 	Constructor.
       
    55 	@param		aSocket		The connected socket. This owned by the observer.
       
    56 	@param		aController	The socket controller that owns the socket.
       
    57 */
       
    58 	{
       
    59 	if(aPriority) 
       
    60 		{
       
    61 		CActive::SetPriority(CActive::EPriorityHigh);	
       
    62 		}
       
    63 	CActiveScheduler::Add(this);
       
    64 
       
    65 //	__FLOG_OPEN("http", "httptransporthandler.txt");
       
    66 	}
       
    67 
       
    68 void CSocketWriter::SocketClosed(TInt aError)
       
    69 /**	
       
    70 	Notifies the output stream that the socket is closed. The output stream 
       
    71 	observer is notified that the stream is closed. No more data can be sent to
       
    72 	the socket.
       
    73 	@param		aError	The error code explaining why the socket has closed. A
       
    74 						value of KErrNone indicates that the input stream 
       
    75 						observer requested that the socket be closed.
       
    76 	@pre		None.
       
    77 	@post		The output stream is in the Closed state.
       
    78 */
       
    79 	{
       
    80 	// Cancel any outstanding requests
       
    81 	Cancel();
       
    82 
       
    83 	// The socket has shutdown. Inform the output stream observer that the 
       
    84 	// output stream is closed.
       
    85 	if( iObserver )
       
    86 		iObserver->OutputStreamCloseInd(aError);
       
    87 
       
    88 	// Move to the Closed state
       
    89 	iState = EClosed;
       
    90 	}
       
    91 
       
    92 /*
       
    93  *	Methods from MOutputStream
       
    94  */
       
    95 
       
    96 void CSocketWriter::Bind(MOutputStreamObserver& aObserver)
       
    97 /**	
       
    98 	@see		MOutputStream
       
    99 */
       
   100 	{
       
   101 	__ASSERT_DEBUG( iState == EIdle || iState == EPendingSend, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadOutputStreamState) );
       
   102 
       
   103 	// Bind to the output stream observer
       
   104 	iObserver = &aObserver;
       
   105 
       
   106 	// Move to the PendingSend state
       
   107 	iState = EPendingSend;
       
   108 	}
       
   109 
       
   110 void CSocketWriter::SendDataReqL(const TDesC8& aBuffer)
       
   111 /**	
       
   112 	@see		MOutputStream
       
   113 */
       
   114 	{
       
   115 	__ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EOutputStreamNotBound) );
       
   116 	__ASSERT_DEBUG( iState == EPendingSend, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadOutputStreamState) );
       
   117     
       
   118 	//Get the TimeOut Value.
       
   119 	TInt timeoutValue = iObserver->SendTimeOutVal();
       
   120 	if(timeoutValue > 0)
       
   121 		{
       
   122 		
       
   123 		//Convert to Microseconds.
       
   124 		if(timeoutValue <= KMinTimeoutValue)
       
   125 			{
       
   126 			//Default Value is 60 Seconds
       
   127 			timeoutValue = KDefTimeoutValue;
       
   128 			}
       
   129 		else
       
   130 			{
       
   131 			timeoutValue = timeoutValue * KMicrovalue;
       
   132 			}
       
   133 		
       
   134 		//Create and Start the HTTP timer
       
   135 		if(!iSendTimer)
       
   136 			{
       
   137 			iSendTimer = CHttpTimer::NewL(*this);
       
   138 			}
       
   139 		iSendTimer->After(timeoutValue);
       
   140 		}
       
   141 
       
   142 	// The output stream observer requests that the supplied buffer is sent to
       
   143 	// the socket. Request a write to the socket
       
   144 	iSocket.Send(aBuffer, iStatus);
       
   145 
       
   146 #if defined (_DEBUG) && defined (_LOGGING)
       
   147 	TBuf8<KIpv6MaxAddrSize> ip;
       
   148 	TUint16	remotePort;
       
   149 	TUint16 localPort;
       
   150 	iController.ConnectionInfo(ip, remotePort, localPort);
       
   151 
       
   152 	__FLOG_4(_T8("Sending %d bytes on local port %d to %S, remote port %d"), aBuffer.Length(), localPort, &ip, remotePort);
       
   153 	__FLOG_0(_T8("----------"));
       
   154 	__FLOG_HEXDUMP(aBuffer.Ptr(), aBuffer.Length());
       
   155 	__FLOG_0(_T8("----------"));
       
   156 #endif
       
   157 
       
   158 	// Move to the SentData and go active
       
   159 	iState = ESentData;
       
   160 	SetActive();
       
   161 	}
       
   162 
       
   163 void CSocketWriter::ShutdownReq()
       
   164 /**	
       
   165 	@see		MOutputStream
       
   166 */
       
   167 	{
       
   168 	__ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EOutputStreamNotBound) );
       
   169 	__ASSERT_DEBUG( iState != EClosing || iState != EClosed, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadOutputStreamState) );
       
   170 
       
   171 	// Cancel any outstanding requests
       
   172 	Cancel();
       
   173 	
       
   174 #if defined (_DEBUG) && defined (_LOGGING)
       
   175 	TBuf8<KIpv6MaxAddrSize> ip;
       
   176 	TUint16	remotePort;
       
   177 	TUint16 localPort;
       
   178 	iController.ConnectionInfo(ip, remotePort, localPort);
       
   179 
       
   180 	__FLOG_0(_T8("!! Shutting down output stream"));
       
   181 	__FLOG_3(_T8("-> on local port %d with %S, remote port %d"), localPort, &ip, remotePort);
       
   182 #endif
       
   183 	
       
   184 	// Shutdown the socket
       
   185 	iSocket.Shutdown(iStatus);
       
   186 
       
   187 	// Move to the Closing state and go active
       
   188 	iState = EClosing;
       
   189 	SetActive();
       
   190 	}
       
   191 
       
   192 void CSocketWriter::SecureClientReq(const TDesC8& aHostName)
       
   193 /**
       
   194 	The request to upgrade the client to a secure connection. This method begins
       
   195 	the secure handshake required to upgrade to a secure connection.
       
   196 	@param		aHostName	The domain name of the server for checking against 
       
   197 							the server certificates.
       
   198 	@pre		The socket writer must be in the EPendingSend state.
       
   199 */
       
   200 	{
       
   201 	__ASSERT_DEBUG( iState == EPendingSend, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadOutputStreamState) );
       
   202 
       
   203 #if defined (_DEBUG) && defined (_LOGGING)
       
   204 	TBuf8<KIpv6MaxAddrSize> ip;
       
   205 	TUint16	remotePort;
       
   206 	TUint16 localPort;
       
   207 	iController.ConnectionInfo(ip, remotePort, localPort);
       
   208 
       
   209 	__FLOG_0(_T8("!! Upgrading to secure (client) connection"));
       
   210 	__FLOG_3(_T8("-> on local port %d with %S, remote port %d"), localPort, &ip, remotePort);
       
   211 #endif
       
   212 
       
   213 	// Notify the controller to suspend the input stream.
       
   214 	iController.StreamSuspend(MSocketController::EOutputStream);
       
   215 	
       
   216 	// Store the host name as required for secure certificate domain name 
       
   217 	// chacking. Move to the StartSecureHandshake state and self complete.
       
   218 	iHostName.Set(aHostName);
       
   219 	iState = EStartSecureHandshake;
       
   220 	CompleteSelf();
       
   221 	}
       
   222 
       
   223 void CSocketWriter::Close()
       
   224 /**	
       
   225 	@see		MOutputStream
       
   226 */
       
   227 	{
       
   228 	__ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EOutputStreamNotBound) );
       
   229 	__ASSERT_DEBUG( iState != EClosing || iState != EClosed, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadOutputStreamState) );
       
   230 
       
   231 	// Cancel any outstanding requests
       
   232 	Cancel();
       
   233 
       
   234 #if defined (_DEBUG) && defined (_LOGGING)
       
   235 	TBuf8<KIpv6MaxAddrSize> ip;
       
   236 	TUint16	remotePort;
       
   237 	TUint16 localPort;
       
   238 	iController.ConnectionInfo(ip, remotePort, localPort);
       
   239 
       
   240 	__FLOG_0(_T8("!! Closing output stream"));
       
   241 	__FLOG_3(_T8("-> on local port %d with %S, remote port %d"), localPort, &ip, remotePort);
       
   242 #endif
       
   243 
       
   244 	// There is no need to do anything here - by informing the socket controller
       
   245 	// that the output stream is closed it will notify the input stream and then
       
   246 	// close the socket.
       
   247 
       
   248 	// Move to the Closed state
       
   249 	iState = EClosed;
       
   250 
       
   251 	// Inform the socket controller that the output stream is closed
       
   252 	iController.StreamClosed(KErrCancel, MSocketController::EOutputStream);
       
   253 	}
       
   254 
       
   255 
       
   256 const CX509Certificate* CSocketWriter::ServerCert()
       
   257 /**	
       
   258 	@see		MOutputStream
       
   259 */
       
   260 	{
       
   261 	return iSocket.ServerCert();
       
   262 	}
       
   263 	
       
   264 TInt CSocketWriter::CipherSuite(TDes8& aCipherSuite)
       
   265 /**	
       
   266 	@see		MOutputStream
       
   267 */
       
   268 	{
       
   269 	return iSocket.CipherSuite(aCipherSuite);
       
   270 	}
       
   271 
       
   272 void CSocketWriter::MOutputStream_Reserved()
       
   273 /**	
       
   274 	@see		MOutputStream
       
   275 */
       
   276 	{
       
   277 	User::Invariant();
       
   278 	}
       
   279 	
       
   280 /**
       
   281 	Resets the state to EClosed
       
   282 	@componentInternal
       
   283 */
       
   284 void CSocketWriter::Reset()
       
   285 	{
       
   286 	// Inform the connection manager that we are closing the output stream 
       
   287 	// due to no memory
       
   288 	iObserver->OutputStreamCloseInd ( KErrNoMemory );
       
   289 	iState = EClosed;	
       
   290 	}
       
   291 
       
   292 void CSocketWriter::CompleteSelf()
       
   293 /**	
       
   294 	Requests that the socket writer complete itself. This will caused the 
       
   295 	RunL() to be called by the scheduler at the next opportunity.
       
   296 	@pre		The socket connector object is not active.
       
   297 	@post		The socket connector object is active and the request has been
       
   298 				completed.
       
   299 */
       
   300 	{
       
   301 	TRequestStatus* pStat = &iStatus;
       
   302 	User::RequestComplete(pStat, KErrNone);
       
   303 	SetActive();
       
   304 	}
       
   305 
       
   306 /*
       
   307  * Methods from CActive
       
   308  */
       
   309 
       
   310 void CSocketWriter::RunL()
       
   311 /**	
       
   312 	The request servicing function. Behaviour depends on the state of the output
       
   313 	stream.
       
   314 */
       
   315 	{
       
   316 	__ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EOutputStreamNotBound) );
       
   317 
       
   318 	// Leave if the socket reported an error
       
   319 	User::LeaveIfError(iStatus.Int());
       
   320     
       
   321 	if(iSendTimer)
       
   322 		{
       
   323 		iSendTimer->Cancel();
       
   324 		}
       
   325 
       
   326 	switch( iState )
       
   327 		{
       
   328 	case ESentData:
       
   329 		{
       
   330 		__OOM_LEAVE_TEST
       
   331 
       
   332 		// The data has successfully been written to the socket - move to the 
       
   333 		// PendingSend state. 
       
   334 		iState = EPendingSend;
       
   335 
       
   336 		// Inform the observer that the data has been sent.
       
   337 		iObserver->SendDataCnfL();
       
   338 		} break;
       
   339 	case EClosing:
       
   340 		{
       
   341 		__OOM_LEAVE_TEST
       
   342 
       
   343 		// The socket has shutdown - move to the Closed state
       
   344 		iState = EClosed;
       
   345 
       
   346 		// Inform the observer that the output stream is closed.
       
   347 		iObserver->OutputStreamCloseInd(KErrNone);
       
   348 
       
   349 		// Inform the socket controller that the output stream is closed
       
   350 		iController.StreamClosed(KErrNone, MSocketController::EOutputStream);
       
   351 		} break;
       
   352 	case EStartSecureHandshake:
       
   353 		{
       
   354 		// Start the secure handshake
       
   355 		iState = ESecureHandshakeComplete;
       
   356 		iSocket.UpgradeToSecureL(iStatus, iHostName);
       
   357 		SetActive();
       
   358 		} break;
       
   359 	case ESecureHandshakeComplete:
       
   360 		{
       
   361 		__OOM_LEAVE_TEST
       
   362 
       
   363 		// Secure handshake has completed successfully so inform the observer.
       
   364 		iState = EPendingSend;
       
   365 		iObserver->SecureClientCnf();
       
   366 
       
   367 #if defined (_DEBUG) && defined (_LOGGING)
       
   368 		TBuf8<KIpv6MaxAddrSize> ip;
       
   369 		TUint16	remotePort;
       
   370 		TUint16 localPort;
       
   371 		iController.ConnectionInfo(ip, remotePort, localPort);
       
   372 
       
   373 		__FLOG_0(_T8("!! Upgrade to secure (client) connection successful"));
       
   374 		__FLOG_3(_T8("-> on local port %d with %S, remote port %d"), localPort, &ip, remotePort);
       
   375 #endif
       
   376 
       
   377 		// Notify the controller to resume the input stream.
       
   378 		iController.StreamResume(MSocketController::EOutputStream);
       
   379 		} break;
       
   380 	case EPendingSend:
       
   381 	case EClosed:
       
   382 	case EIdle:
       
   383 	default:
       
   384 		THttpTrLayerPanic::Panic(THttpTrLayerPanic::EBadOutputStreamState);
       
   385 		break;
       
   386 		}
       
   387 	}
       
   388 
       
   389 void CSocketWriter::DoCancel()
       
   390 /**	
       
   391 	The asynchronous request cancel function. If the output stream has requested
       
   392 	a write to the socket (ie it is in the SentData state) this function cancels
       
   393 	the write request.
       
   394 */
       
   395 	{
       
   396 	if( iState == ESentData )
       
   397 		{
       
   398 		// There is a pending write request - cancel it
       
   399 		iSocket.CancelSend();
       
   400 		}
       
   401 	else if( iState == ESecureHandshakeComplete )
       
   402 		{
       
   403 		// Cancel the upgrade to secure connection.
       
   404 		iSocket.CancelUpgradeToSecure();
       
   405 		}
       
   406 	}
       
   407 
       
   408 TInt CSocketWriter::RunError(TInt aError)
       
   409 /**	
       
   410 	The error handler for when RunL() leaves. If this has been called then the 
       
   411 	write request or the socket shutdown request has failed. The socket can no 
       
   412 	longer be used. The output stream observer is notified that the stream is 
       
   413 	closed. No more data can be sent to the socket.
       
   414 	@return		A value of KErrNone indicating that the the error has been 
       
   415 				handled.
       
   416 	@pre		The output stream has requested a service (a write or a shutdown) 
       
   417 				from socket. The request has failed. It is either in the SentData
       
   418 				or Closing state.
       
   419 	@post		The output stream is in the Closed state.
       
   420 */
       
   421 	{
       
   422 	__ASSERT_DEBUG( iObserver != NULL, THttpTrLayerPanic::Panic(THttpTrLayerPanic::EOutputStreamNotBound) );
       
   423 
       
   424 #if defined (_DEBUG) && defined (_LOGGING)
       
   425 	TBuf8<KIpv6MaxAddrSize> ip;
       
   426 	TUint16	remotePort;
       
   427 	TUint16 localPort;
       
   428 	iController.ConnectionInfo(ip, remotePort, localPort);
       
   429 
       
   430 	__FLOG_1(_T8("!! Output stream error : %d"), aError);
       
   431 	__FLOG_3(_T8("-> Connection on local port %d with %S, remote port %d closed"), localPort, &ip, remotePort);
       
   432 #endif
       
   433 
       
   434 	// Move to the Closed state
       
   435 	iState = EClosed;
       
   436 
       
   437 	// The socket request has failed - the socket connection is broken. Need
       
   438 	// to inform the output stream observer that the output stream is closed.
       
   439 	iObserver->OutputStreamCloseInd(aError);
       
   440 
       
   441 	// Inform the socket controller that the output stream is closed
       
   442 	iController.StreamClosed(aError, MSocketController::EOutputStream);
       
   443 
       
   444 	return KErrNone;
       
   445 	}
       
   446 
       
   447 void CSocketWriter::TimeOut()
       
   448 	{
       
   449 	// Cancel any outstanding requests
       
   450 	Cancel();
       
   451 	iObserver->OnSendTimeOut();
       
   452 	}
       
   453 
       
   454 void CSocketWriter::SetTCPCorking(TBool aValue)
       
   455     {
       
   456     iSocket.SetTCPCorking(aValue);
       
   457     }
       
   458 
       
   459