datacommsserver/esockserver/ssock/ss_sap.cpp
changeset 0 dfb7c4ff071f
child 9 77effd21b2c9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/datacommsserver/esockserver/ssock/ss_sap.cpp	Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,264 @@
+// Copyright (c) 1997-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:
+//
+
+/**
+ @file SS_SAP.CPP
+*/
+
+#define SYMBIAN_NETWORKING_UPS
+
+#include <ss_std.h>
+#include <ss_glob.h>
+#include <comms-infras/ss_roles.h>
+#include <comms-infras/ss_log.h>
+#include <comms-infras/ss_subconnflow.h>
+#include <ss_protprov.h>
+#include <comms-infras/es_sap.h>
+#include <ss_sock.h>
+#include <comms-infras/ss_nodemessages_dataclient.h>
+
+#include <elements/nm_signatures.h>
+
+
+#ifdef _DEBUG
+// Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module
+// (if it could happen through user error then you should give it an explicit, documented, category + code)
+_LIT(KSpecAssert_ESockSSockss_sp, "ESockSSockss_sp.");
+#endif
+
+using namespace ESock;
+using namespace Messages;
+
+
+EXPORT_C CNetworkFlow::CNetworkFlow(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConnId, CProtocolIntfBase* aProtocolIntf)
+	: CSubConnectionFlowBase(aFactory, aSubConnId, aProtocolIntf)
+	{
+	}
+
+EXPORT_C CNetworkFlow::~CNetworkFlow()
+	{
+	if (iLowerFlow)
+		{
+		iLowerFlow->Unbind(NULL,NULL);
+		}
+	}
+void
+CNetworkFlow::SetLocalName(TSockAddr& anAddr)
+/** Sets the local name (address) of the socket service provider entity. The format
+of the data in the TSockAddr object is defined by individual protocols.
+
+@param anAddr The address
+@return Returns KErrNone if the local name is correctly set or, if this is
+not the case, an informative error number. */
+	{
+	iLocalAddressSet = ETrue;
+	iLocalAddress = anAddr;
+	
+	}
+
+TInt CNetworkFlow::SetRemName(TSockAddr& anAddr)
+/** Sets the remote name (address) of the socket service provider entity. The format
+of the data in the TSockAddr object is defined by individual protocols.
+
+@param anAddr The address
+@return Returns KErrNone if the remote name is correctly set or, if this is
+not the case, an informative error number. */
+	{
+	iRemoteAddressSet = ETrue;
+	iRemoteAddress = anAddr;
+	return KErrNone;
+	}
+
+void CNetworkFlow::UpdateDestinationAddress(const TSockAddr& aDest)
+	{
+	iRemoteAddress = aDest;
+	iRemoteAddressSet = ETrue;
+	}
+
+TUint CNetworkFlow::Write(const TDesC8& /*aDesc*/, TUint /*aOptions*/, TSockAddr* anAddr)
+/** Sends data onto the network via the protocol.
+
+Connection-oriented sockets must be in a connected state (that is ConnectComplete() has
+been called on their MSocketNotify before Write() is called).
+
+The socket server keeps track of how much data is waiting and then tries to send it all
+until the protocol tells it to hold off by returning 0 (datagram sockets) or 'less than
+all data consumed' (stream sockets) to Write(). The protocol should call CanSend() when it
+is ready to send more data.
+
+anAddr is the address to write the data to.	Connection oriented sockets always use the
+default value.
+
+@param aDesc The data to be sent.
+@param aOptions Protocol specific options.
+@param anAddr Address to write the data to.
+
+@returns For stream-oriented protocols the return value is the number of bytes actually written.
+If this is less than the length of the descriptor then the protocol should call CanSend()
+when it is ready to send more data. For datagram-oriented protocols, the write should return
+either 0 if the write cannot be completed, or the length of the descriptor if the write succeeds -
+no other values are valid. If the Write() must return 0, then it should call CanSend() when it is
+ready to send more data. If the Write() fails due to some error, then it should call Error() with
+an informative error number.
+*/
+	{
+	if (anAddr)
+		{
+		UpdateDestinationAddress(*anAddr);
+		}
+	return KErrNone;
+	}
+
+TInt CNetworkFlow::Write(RMBufChain& /*aData*/, TUint /*aOptions*/, TSockAddr* anAddr)
+/** Sends data onto the network via the protocol.
+
+Connection-oriented sockets must be in a connected state (that is ConnectComplete() has
+been called on their MSocketNotify before Write() is called).
+
+The socket server keeps track of how much data is waiting and then tries to send it all
+until the protocol tells it to hold off by returning 0 (datagram sockets) or 'less than
+all data consumed' (stream sockets) to Write(). The protocol should call CanSend() when it
+is ready to send more data.
+
+anAddr is the address to write the data to.	Connection oriented sockets always use the
+default value.
+
+@param aData The data to be sent.
+@param aOptions Protocol specific options.
+@param anAddr Address to write the data to.
+
+@returns For stream-oriented protocols the return value is the number of bytes actually written.
+If this is less than the length of the descriptor then the protocol should call CanSend()
+when it is ready to send more data. For datagram-oriented protocols, the write should return
+either 0 if the write cannot be completed, or the length of the descriptor if the write succeeds -
+no other values are valid. If the Write() must return 0, then it should call CanSend() when it is
+ready to send more data. If the Write() fails due to some error, then it should call Error() with
+an informative error number.
+*/
+	{
+	if (anAddr)
+		{
+		UpdateDestinationAddress(*anAddr);
+		}
+	return KErrNone;
+	}
+
+
+
+void CNetworkFlow::BindToL(const TCFDataClient::TBindTo& aBindTo)
+/**
+Request from control side (at network layer) to indicate that the SubConnection is
+up and running and that we should bind to a Flow below.
+
+@param aLowerFlow Flow below to bind to.
+*/
+	{
+	LOG( ESockLog::Printf(_L("CNetworkFlow %08x:\tBindTo()"), this) );
+
+	const TNodeId& commsId = aBindTo.iNodeId;
+#if defined(__GCCXML__)
+    CSubConnectionFlowBase* flow = reinterpret_cast<CSubConnectionFlowBase*>(reinterpret_cast<Messages::ANode*>(commsId.Ptr()));
+#else
+    CSubConnectionFlowBase* flow = mcfnode_cast<CSubConnectionFlowBase>(reinterpret_cast<Messages::ANode*>(commsId.Ptr()));
+#endif
+
+    if (flow==NULL)
+        {
+        __ASSERT_DEBUG(!commsId.IsNull(), User::Panic(KSpecAssert_ESockSSockss_sp, 1));
+        iSubConnectionProvider.PostMessage(Id(), TCFDataClient::TStopped(KErrDisconnected).CRef());
+        }
+
+    //flows can only be directly bound when running in the same thread
+    //Are we in the same thread?
+    __ASSERT_DEBUG(commsId.Thread() == Id().Thread(), User::Panic(KSpecAssert_ESockSSockss_sp, 2));
+
+	if (iLowerFlow && iLowerFlow->Flow() != flow )
+    	{
+    	//already bound -> unbind first.
+    	iLowerFlow->Unbind(NULL,NULL);
+    	iLowerFlow = NULL;
+    	iLowerControl = NULL;
+    	}
+    	
+    if (iLowerFlow == NULL && flow != NULL)
+        {
+        iLowerFlow = flow->GetBinderControlL();
+    	iLowerControl = iLowerFlow->GetControlL(KNullDesC8);
+    	iLowerFlow->BindL(KNullDesC8, NULL,NULL);
+        }
+	}
+
+MSessionControl* CNetworkFlow::GetControlL(TInt /*aSessionType*/,MSessionControlNotify& aSessionControlNotify)
+    {
+	__ASSERT_DEBUG(iSessionControlNotify == NULL, User::Panic(KSpecAssert_ESockSSockss_sp, 3));
+	iSessionControlNotify = &aSessionControlNotify;
+	return this;
+    }
+
+MSessionData* CNetworkFlow::BindL(MSessionDataNotify& aNotify)
+    {
+	__ASSERT_DEBUG(iSessionDataNotify == NULL, User::Panic(KSpecAssert_ESockSSockss_sp, 4));
+	iSessionDataNotify = &aNotify;
+	iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TActive().CRef());
+	return this;
+    }
+
+void CNetworkFlow::Unbind()
+    {
+    if (iSessionDataNotify)			// if not already unbound
+    	{
+    	iSessionControlNotify = NULL;
+		iSessionDataNotify = NULL;
+		if(iSubConnectionProvider.IsOpen())
+			{
+			if(iDCIdle < EIdle)
+				{
+				iDCIdle = EIdle;
+		    	ProcessDCIdleState();
+				}
+			}
+		else
+			{
+			// Legacy flows lack a SCPR to look after their destruction so need to suicide
+			delete this;
+			}
+    	}
+    }
+
+CSubConnectionFlowBase* CNetworkFlow::Flow()
+    {
+    return this;
+    }
+
+MFlowBinderControl* CNetworkFlow::DoGetBinderControlL()
+	{
+	return this;
+	}
+
+void CNetworkFlow::ProcessDCIdleState()
+	{
+#ifdef SYMBIAN_NETWORKING_UPS
+	if(iDCIdle == EIdle && !ActivityRunning())
+#else
+	if(iDCIdle == EIdle && !iNoBearerRunning)
+#endif
+		{
+		iDCIdle = EIdleSent;
+		iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TIdle().CRef());
+		}
+	}
+
+
+