applayerpluginsandutils/httptransportplugins/httptransporthandler/csocket.cpp
changeset 0 b16258d2340f
child 7 337070b4fa18
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/applayerpluginsandutils/httptransportplugins/httptransporthandler/csocket.cpp	Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,410 @@
+// 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 "csocket.h"
+#include "chttpsecuresocket.h"
+#include "mcommsinfoprovider.h"
+#include "thttptrlayerpanic.h"
+
+#include  <http/rhttpconnectioninfo.h>
+#include <httpsocketconstants.h>
+#include <in6_opt.h> 
+
+const TInt KDefaultFlags		= 0;
+const TInt KTcpTriggeredKeepAlive	= 2;
+const TInt KSocketRecvBufSize = 16 * 1024;
+const TInt KSocketSendBufSize = 16 * 1024;
+const TInt KSocketDefaultSendBufSize = 4 * 1024;
+
+CSocket* CSocket::NewL(MCommsInfoProvider& aCommsInfoProvider, TSocketType aSocketType)
+/**	
+	The factory constructor.
+	@param		aCommsInfoProvider	The comms info provider object.
+	@param		aSocketType			The type of the socket.
+	@return		A pointer to a fully constructed object.
+*/
+	{
+	CSocket* self = new (ELeave) CSocket(aCommsInfoProvider);
+	CleanupStack::PushL(self);
+	self->ConstructL(aSocketType);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CSocket::~CSocket()
+/**
+	Destructor.
+*/
+	{
+	// Close socket and notify the socket status observer
+	if( iSecureSocketController )
+		delete iSecureSocketController;
+	else
+		iSocket.Close();
+	}
+
+CSocket::CSocket(MCommsInfoProvider& aCommsInfoProvider)
+: CBase(), iCommsInfoProvider(aCommsInfoProvider)
+/**	
+	Constructor.
+	@param		aCommsInfoProvider	The comms info provider object.
+*/
+	{
+	}
+
+void CSocket::ConstructL(TSocketType aSocketType)
+/**	
+	Second phase constructor.
+	@param		aSocketType	The type of the socket.
+*/
+	{
+	switch( aSocketType )
+		{
+	case EProtocolSocket:
+		{
+		if ( iCommsInfoProvider.HasConnection() )
+			{
+			// Open a protocol socket with a RConnection
+			User::LeaveIfError(iSocket.Open(
+										   iCommsInfoProvider.SocketServer(),
+										   iCommsInfoProvider.ProtocolDescription().iAddrFamily, 
+										   iCommsInfoProvider.ProtocolDescription().iSockType, 
+										   iCommsInfoProvider.ProtocolDescription().iProtocol,
+										   iCommsInfoProvider.Connection()
+										   ));				
+			}
+		else
+			{
+			// Open a protocol socket without a RConnection, we don't need one ( Loopback address )
+			User::LeaveIfError(iSocket.Open(
+										   iCommsInfoProvider.SocketServer(),
+										   iCommsInfoProvider.ProtocolDescription().iAddrFamily, 
+										   iCommsInfoProvider.ProtocolDescription().iSockType, 
+										   iCommsInfoProvider.ProtocolDescription().iProtocol
+										   ));											
+			}
+		} break;
+	case EBlankSocket:
+		{
+		// Open a blank socket
+		User::LeaveIfError(iSocket.Open(iCommsInfoProvider.SocketServer()));
+		} break;
+	default:
+		User::Invariant();
+		}
+	TInt id = iCommsInfoProvider.SessionId();
+	if(id>=0) 
+		{
+		// set socket option
+		iSocket.SetOpt(KSOHttpSessionId, KSOLHttpSessionInfo, id);
+		iSocket.SetOpt(KSoTcpKeepAlive, KSolInetTcp, KTcpTriggeredKeepAlive);
+		}
+	if(aSocketType != EBlankSocket)
+	    {
+	    iSocket.SetOpt(KSoTcpNoDelay,KSolInetTcp,1);  // Disable the nagle.
+        iSocket.SetOpt(KSORecvBuf, KSOLSocket, KSocketRecvBufSize); // Set the socket recv buf to be 16K
+	    }
+	}
+
+TInt CSocket::Listen(TUint aQSize, TUint16 aPort)
+/**	
+	Start the listen service. The socket is bound to the local port specified by
+	aPort. The listen service is then started. The aQSize argument specifies the
+	number of connections that can be received simultaneously, awaiting to be 
+	accepted.
+	@param		aQSize		The length of the listening queue.
+	@param		aPort		The local port number on which to listen.
+	@return		A value of KErrNone if the listen service was successfully 
+				started.
+*/
+	{
+	// Bind the socket to the port
+	TSockAddr addr;
+	addr.SetPort(aPort);
+
+	TInt error = iSocket.Bind(addr);
+
+	if( error == KErrNone )
+		{
+		// Start the listening service
+		error = iSocket.Listen(aQSize);
+		}
+	return error;
+	}
+
+void CSocket::Accept(CSocket& aBlankSocket, TRequestStatus& aStatus)
+/**	
+	Start asynchronous accept service. The socket should have had the listening
+	service started. When a connection has been received, the blank socket will
+	be given the connection. The request status is completed either when a 
+	connection is received or an error has occured - this is reflected in the 
+	value of the request status.
+	@param		aBlankSocket	The blank socket which will be given the 
+								connection if one is received.
+	@param		aStatus			The request status that is completed when the
+								accept service completes.
+*/
+	{
+	if( iSecureSocketController )
+		{
+		// Secure socket do not support secure listening
+		aStatus=KRequestPending;
+		TRequestStatus* pStat = &aStatus;
+		User::RequestComplete(pStat, KErrNotSupported);
+		}
+	else
+		iSocket.Accept(aBlankSocket.iSocket, aStatus);
+	}
+
+void CSocket::CancelAccept()
+/**	
+	Cancel the accept service.
+*/
+	{
+	iSocket.CancelAccept();
+	}
+
+void CSocket::Connect(TInetAddr& aAddr, TRequestStatus& aStatus)
+/**	
+	Start asynchronous connect service. The address contains the IP address and
+	port with which a tcp connection should be established with. The request 
+	status is completed either when a connection has been established or an error
+	has occurred - this is reflected in the value of the request status.
+	@param		aAddr	The IP address and port of the remote host.
+	@param		aStatus	The request status that is completed when the connect 
+						service completes.
+*/
+	{
+	iSocket.Connect(aAddr, aStatus);
+	}
+
+void CSocket::CancelConnect()
+/**	
+	Cancel the connect service.
+*/
+	{
+	iSocket.CancelConnect();
+	}
+
+void CSocket::RecvOneOrMore(TDes8& aBuffer, TRequestStatus& aStatus)
+/**	
+	Receive data from socket asynchronously. Any data received by the socket is 
+	placed in the buffer supplied by aBuffer. The request status is completed 
+	either when data has been received or an error has occurred - this is 
+	reflected in the value of the request status.
+	@param		aBuffer	The buffer where any received data is placed.	
+	@param		aStatus	The request status that is completed when the receive 
+						service completes.
+*/
+	{
+	if( iSecureSocketController )
+		// aFlags not used for secure sockets
+		iSecureSocketController->RecvOneOrMore(aBuffer, aStatus, iBytesReceived);
+	else
+		iSocket.RecvOneOrMore(aBuffer, KDefaultFlags, aStatus, iBytesReceived);
+	}
+
+void CSocket::CancelRecv()
+/**	
+	Cancel the receive service.
+*/
+	{
+	if( iSecureSocketController )
+		iSecureSocketController->CancelRecv();
+	else
+		iSocket.CancelRecv();
+	}
+
+void CSocket::Send(const TDesC8& aBuffer, TRequestStatus& aStatus)
+/**	
+	Send data to the socket asynchronously. The data in the supplied buffer is 
+	sent to the socket. The request status is completed either when data has 
+	been sent or an error has occurred - this is reflected in the value of the
+	request status.
+	@param		aBuffer	The buffer containing the data to be sent.
+	@param		aStatus	The request status that is completed when the send 
+						service completes.
+*/
+	{
+	if( iSecureSocketController )
+		iSecureSocketController->Send(aBuffer, aStatus);
+	else
+		iSocket.Write(aBuffer, aStatus);
+	}
+
+void CSocket::CancelSend()
+/**	
+	Cancel the send service.
+*/
+	{
+	if( iSecureSocketController )
+		iSecureSocketController->CancelSend();
+	else
+		iSocket.CancelWrite();
+	}
+
+void CSocket::Shutdown(TRequestStatus& aStatus)
+/**	
+	Shutdown the connection asynchronously. Any pending receive or send requests
+	are allowed to complete before the connection is shutdown. The request 
+	status is completed when either the connection has shutdown or an error has
+	occurred - this is reflected in the value of the request status. This request
+	cannot be cancelled. This method does not apply to secure connections. The
+	request will complete with KErrNotSupported if used with a secure connection.
+	@param		aStatus	The request status that is completed when the shutdown 
+						service completes.
+*/
+	{
+	if( iSecureSocketController )
+		{
+		// Not supported with secure connections
+		aStatus=KRequestPending;
+		TRequestStatus* pStat = &aStatus;
+		User::RequestComplete(pStat, KErrNotSupported);
+		}
+	else
+		iSocket.Shutdown(RSocket::ENormal, aStatus);
+	}
+	
+void CSocket::ShutdownImmediate()
+/**	
+	Shutdown the connection synchronously. This method will shutdown the socket
+	connection immediately using the abortive closing functionality. This method
+	has no effect with secure connections.
+*/
+	{
+	if( iSecureSocketController==NULL )
+		{
+		TRequestStatus shutdownStatus = KRequestPending;
+		iSocket.Shutdown(RSocket::EImmediate, shutdownStatus);
+		User::WaitForRequest(shutdownStatus);
+		}
+	}
+
+void CSocket::RemoteName(TInetAddr& aAddr)
+/**	
+	Get the remote host name. The IP address and port of the remote host is set
+	in the output argument.
+	@param		aAddr	The output argument where the IP address and port of the
+						remote host is placed.
+*/
+	{
+	iSocket.RemoteName(aAddr);
+	}
+
+void CSocket::LocalName(TInetAddr& aAddr)
+/**	
+	Get the local socket name. The IP address and port of the local socket is 
+	set in the output argument.
+	@param		aAddr	The output argument where the IP address and port of the
+						local socket is placed.
+*/
+	{
+	iSocket.LocalName(aAddr);
+	}
+
+const CX509Certificate* CSocket::ServerCert()
+ /**
+ 	Get the Server Certificate for this socket session.
+	@return		A Certificate with the certificate information. This may be 
+				NULL if the information is not available.
+ */
+ 	{
+ 	if( iSecureSocketController )
+		{
+		return iSecureSocketController->ServerCert();
+		}
+	return NULL;
+ 	}
+ 	
+	
+TInt CSocket::CipherSuite(TDes8& aCipherSuite)
+/**
+	Get the current Cipher Suite for this socket session.
+	@param		aCiptherSuite	A descriptor which will be filled with the cipher suite. 
+								This is a 2 digit code as defined by RFC 2246. 
+	@return		An error code. KErrNone on sucess. KErrNotSupported if this socket session is not secure.
+*/
+	{
+	if (iSecureSocketController)
+		return iSecureSocketController->CipherSuite(aCipherSuite);
+	//else
+	return KErrNotSupported;
+	}
+
+void CSocket::UpgradeToSecureL(TRequestStatus& aStatus, const TDesC8& aHostName)
+/**
+	Asynchronous request to upgrade the socket to a secure socket.
+	@param	aStatus The request status, this will complete with KErrNone on the successful
+					upgrade to a secure connection.
+	@param	aHostName The host name of the server used for domain name checking
+*/
+	{
+	// Check that the socket is already a secure one.
+	if( iSecureSocketController )
+		{
+		// The socket connection is already secure, simply complete the request
+		aStatus=KRequestPending;
+		TRequestStatus* pStat = &aStatus;
+		User::RequestComplete(pStat, KErrNone);
+		}
+	else
+		{
+		// Create the secure socket controller and start the secure handshake
+		TRAPD(error, iSecureSocketController = CHttpSecureSocket::NewL(iSocket, iCommsInfoProvider));
+		if (error == KErrNotFound || error == KEComErrNoInterfaceIdentified)
+			User::Leave(KErrNotSupported);
+		else if (error != KErrNone)
+			User::Leave(error);
+		iSecureSocketController->StartSecureHandshakeL(aStatus, aHostName);
+		}
+	}
+
+void CSocket::CancelUpgradeToSecure()
+/**
+	Cancel the upgrade to a secure connection.
+*/
+	{
+	if( iSecureSocketController )
+		iSecureSocketController->CancelHandshake();
+	}
+
+TInt CSocket::PendingBytesToRead ()
+	{
+    if ( iSecureSocketController )
+		    return iSecureSocketController->PendingBytesToRead ();
+	TInt bytesToRead;
+	TInt err = iSocket.GetOpt ( KSOReadBytesPending, KSOLSocket, bytesToRead );
+	if ( err == KErrNone )
+		return bytesToRead;
+	return err;
+	}
+	
+void CSocket::SetTCPCorking(TBool aValue)
+    {
+    if(aValue)
+    	{
+    	iSocket.SetOpt(KSoTcpNoDelay,KSolInetTcp,0);  // Disable the nagle.
+      iSocket.SetOpt(KSOSendBuf, KSOLSocket, KSocketSendBufSize);
+      }
+    else
+    	{
+    	iSocket.SetOpt(KSoTcpNoDelay,KSolInetTcp,1);  // Disable the nagle.
+      iSocket.SetOpt(KSOSendBuf, KSOLSocket, KSocketDefaultSendBufSize);        
+      }
+    
+    iSocket.SetOpt(KSoTcpCork, KSolInetTcp, aValue);       
+    
+    }