--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/datacommsserver/esockserver/ssock/ss_sapshim.cpp Thu Dec 17 09:22:25 2009 +0200
@@ -0,0 +1,2098 @@
+// 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_SAPSHIM.CPP
+*/
+
+#define SYMBIAN_NETWORKING_UPS
+#include "ss_sapshim.h"
+
+#include <ss_std.h>
+#include <ss_glob.h>
+#include <comms-infras/ss_roles.h>
+#include <comms-infras/ss_log.h>
+#include <comms-infras/ss_subconnprov.h>
+#include <comms-infras/ss_connprov.h>
+#include <ss_protprov.h>
+#include <ss_sock.h>
+#include <comms-infras/ss_protflow.h>
+#include <in_sock.h> // KAfInet
+#include <elements/nm_messages_child.h>
+#include <elements/nm_messages_peer.h>
+
+#include <comms-infras/nifif.h>
+#include <comms-infras/nifif_internal.h>
+
+#include <addressupdate.h>
+
+#include <comms-infras/ss_nodemessages_dataclient.h>
+#include <comms-infras/ss_nodemessages_flow.h>
+#include <comms-infras/ss_nodemessages_ipmessages.h>
+#include <comms-infras/ss_nodemessages_internal_esock.h>
+
+#include "ss_protopt.h"
+
+#ifdef SYMBIAN_NETWORKING_UPS
+#include <comms-infras/ss_upsaccesspointconfigext.h>
+#include <comms-infras/upsmessages.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_ESockSSocksspshm, "ESockSSocksspshm");
+#endif
+
+_LIT_SECURITY_POLICY_C1(KPolicyNetworkServices, ECapabilityNetworkServices);
+#endif
+
+using namespace ESock;
+using namespace Messages;
+using namespace MeshMachine;
+using namespace Factories;
+
+//CHostResolver specific functions this is to remove once we have app layer protocols
+//***************************************************************************************
+//also loo for iHostResolverNotify
+MLowerControl* CTransportFlowShim::GetControlL(const TDesC8& /*aProtocol*/)
+ {
+ return this;
+ }
+
+TInt CTransportFlowShim::Control(TUint aLevel, TUint aName, TDes8& aOption)
+ {
+ return iLowerControl ? iLowerControl->Control(aLevel, aName, aOption) : KErrNotReady;
+ }
+
+MLowerDataSender* CTransportFlowShim::BindL(const TDesC8& /*aProtocol*/, MUpperDataReceiver* aReceiver, MUpperControl* aControl)
+ {
+ if (aReceiver || iProvider || IsBoundToSession())
+ {
+ User::Leave(KErrInUse);
+ }
+ iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TActive().CRef());
+ iHostResolverNotify = aControl;
+ return this;
+ }
+
+void CTransportFlowShim::Unbind( MUpperDataReceiver* /*aReceiver*/, MUpperControl* aControl)
+ {
+ (void)aControl;
+ __ASSERT_DEBUG(aControl == iHostResolverNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 1));
+ __ASSERT_DEBUG(iDCIdle <= EClientsPresent, User::Panic(KSpecAssert_ESockSSocksspshm, 2));
+ iDCIdle = EIdle;
+ iHostResolverNotify = NULL;
+ if(iSubConnectionProvider.IsOpen()) // legacy flows have no control side
+ {
+ ProcessDCIdleState();
+ }
+ }
+
+MLowerDataSender::TSendResult CTransportFlowShim::Send(RMBufChain& /*aData*/)
+ {
+ __ASSERT_DEBUG(iHostResolverNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 3));
+
+ TBuf8<sizeof(TConnectionInfo)> buf;
+ if (Control(KSOLProvider, static_cast<TUint>(KSoConnectionInfo), buf) == KErrNone)
+ {
+ iHostResolverNotify->StartSending();
+ }
+ else if (!iLowerControl)
+ {
+#ifdef SYMBIAN_NETWORKING_UPS
+ TInt result = SetupForNoBearerOnSend();
+ if (result != KErrNone)
+ {
+ return TSendResult(result);
+ }
+#endif
+ __ASSERT_DEBUG(iSubConnectionProvider.IsOpen(), User::Panic(KSpecAssert_ESockSSocksspshm, 4)); // legacy flows have no control side, so must never get here
+ PostNoBearer();
+ }
+
+ return MLowerDataSender::ESendAccepted;
+ }
+//***************************************************************************************
+//End of CHostResolver specific functions also look for iHostResolverNotify to find the rest
+
+#ifndef SYMBIAN_NETWORKING_UPS
+
+//
+// Not used with UPS support - CUpsTransportFlowShim::NewL() used instead.
+//
+
+CTransportFlowShim* CTransportFlowShim::NewL(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConn, CProtocolIntfBase* aProtocolIntf)
+ {
+ return new (ELeave) CTransportFlowShim(aFactory, aSubConn, aProtocolIntf);
+ }
+
+#endif
+
+CTransportFlowShim::CTransportFlowShim(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConn, CProtocolIntfBase* aProtocolIntf)
+: CNetworkFlow(aFactory, aSubConn, aProtocolIntf), iFlowParams(TFlowParams(NULL, NULL, KUndefinedProtocol, NULL, NULL))
+ {
+ LOG_NODE_CREATE(KESockFlowTag, CTransportFlowShim)
+ }
+
+
+void CTransportFlowShim::SetSSP(CServProviderBase& aSSP)
+ {
+ __ASSERT_DEBUG(iProvider == NULL, User::Panic(KSpecAssert_ESockSSocksspshm, 5));
+ iProvider = &aSSP;
+ iProvider->SetNotify(this);
+ }
+
+CTransportFlowShim::~CTransportFlowShim()
+ {
+ // Remove ourselves from any listening control session's accept queue.
+ if(iListenerControlNotify)
+ {
+ iListenerControlNotify->DisconnectFromListener(*this);
+ }
+
+ if(!iDetaching)
+ {
+ delete iProvider;
+ iProvider = NULL;
+ }
+
+ Messages::TEBase::TError err(TEBase::TNull::Id(), KErrBindersInvalid);
+ SubConnectionError(err, EErrorAllOperations);
+
+ LOG_NODE_DESTROY(KESockFlowTag, CTransportFlowShim)
+ }
+
+void CTransportFlowShim::SetSockType(TUint aSockType)
+ {
+ if (iProvider)
+ {
+ iProvider->SetSockType(aSockType);
+ }
+ }
+
+MSessionControl* CTransportFlowShim::GetControlL(TInt aSessionType,MSessionControlNotify& aSessionControlNotify)
+ {
+ CNetworkFlow::GetControlL(aSessionType,aSessionControlNotify);
+ SetSockType(aSessionType);
+ return this;
+ }
+
+MSessionData* CTransportFlowShim::BindL(MSessionDataNotify& aNotify)
+ {
+ LOG( ESockLog::Printf(_L8("CTransportFlowShim %08x:\tBindL(aNotify 0x%08x)"), this, &aNotify) );
+
+ // The flow shim now manages custody and loading of the protocol involved.
+ // However in the case of host resolvers, until ported for the same behaviour, protocol loading is still managed by the socket.
+ if(iFlowParams.iFlowLoadsProtocol)
+ {
+ CProtocolRef * protocolReference = ProtocolManager::FindProtocolL(
+ iFlowParams.iAddrFamily,
+ iFlowParams.iSocketType,
+ iFlowParams.iProtocol);
+
+ if (protocolReference->GetFlag() & CProtocolRef::EThreePlaneCommsBased)
+ {
+ // Three plane comms protos should not be seen here. If an RSocket is opened with a supported
+ // protocol and it happens to be 3PC this point will be reached. In the case of RTP some
+ // special processing is performed (in the SCPR) in order to sort out the mess and ensure that
+ // a UDP/TCP flow is requested instead.
+ User::Leave(KErrProtocolNotReady);
+ }
+
+ // Check if the protocol is supported over sockets
+ if (!(protocolReference->Info().iServiceTypeInfo & ESocketSupport))
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ // Have the protocol loaded if not already the case and confirm it has socket support
+ protocolReference->LoadAndBindL();
+
+ __ASSERT_DEBUG(iProtocolReference == NULL, User::Panic(KSpecAssert_ESockSSocksspshm, 6));
+ iProtocolReference = protocolReference;
+
+ // Have the protocol added to the list of protocols for the session it is associated with
+ CSockSessionProxy* sessionProxy = reinterpret_cast<CSockSessionProxy*>(iFlowParams.iSessionProxy);
+ if(sessionProxy != NULL)
+ {
+ sessionProxy->AddProtocolL(iProtocolReference->Protocol());
+ }
+
+ // Fetch a new SAP from the protocol for this flow
+ if (iProvider == NULL)
+ {
+ iProvider = iProtocolReference->Protocol()->NewSAPL(iFlowParams.iSocketType);
+
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+ // Set the options iterating the RArray variable
+ SetProtocolOptions();
+#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+
+ if (iProvider)
+ {
+ iProvider->SetNotify(this);
+ }
+ }
+ }
+
+ // Now perform the binding proper
+ if (!iProvider)
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ __ASSERT_DEBUG(!iHostResolverNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 8));
+ CNetworkFlow::BindL(aNotify);
+ iProvider->SetNotify(this);
+
+ return this;
+ }
+
+void CTransportFlowShim::Unbind()
+ {
+ LOG( ESockLog::Printf(_L8("CTransportFlowShim %08x:\tUnbind()"), this) );
+
+ // Infant mortality case in which binding never completed,
+ if(iFlowParams.iProtocol == KUndefinedProtocol)
+ {
+ delete this;
+ return;
+ }
+
+ // Legacy support for host resolvers
+ if(iHostResolverNotify)
+ {
+ __ASSERT_DEBUG(!iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 9)); // can't have both HR & SAP
+
+ LOG( ESockLog::Printf(_L8("CTransportFlowShim %08x:\tUnbind(): iBearerExpected %d"), this, iBearerExpected) );
+ if (!iBearerExpected)
+ {
+ delete this;
+ }
+ else
+ {
+ iDeleteUponBearerReception = ETrue;
+ iHostResolverNotify = NULL;
+ }
+ return;
+ }
+
+ if (iProvider)
+ {
+ iProvider->SetNotify(NULL);
+
+ if (!iDetaching)
+ {
+ delete iProvider;
+ iProvider = NULL;
+ }
+ }
+
+#ifdef SYMBIAN_NETWORKING_UPS
+ // Hook for derived classes to do cleanup before unbind occurs
+ PreUnbind();
+#endif
+
+ CNetworkFlow::Unbind();
+ }
+
+ESock::CSubConnectionFlowBase& CTransportFlowShim::CloneFlowL()
+ {
+ __ASSERT_DEBUG(iProtocolIntf, User::Panic(KSpecAssert_ESockSSocksspshm, 10));
+ TDefaultFlowFactoryQuery query (iProtocolIntf->ControlProviderId(), iSubConnectionProvider.RecipientId());
+ ESock::CSubConnectionFlowBase& flow = static_cast<ESock::CSubConnectionFlowBase&>(*(Factory().CreateObjectL(query)));
+ // Legacy flows lack a control provider
+ if(iSubConnectionProvider.IsOpen())
+ {
+ TCFPeer::TJoinRequest msg(flow.Id(), TClientType(TCFClientType::EData, TCFClientType::EActive));
+ iSubConnectionProvider.PostMessage(Id(), msg);
+ }
+ return flow;
+ }
+
+void CTransportFlowShim::Start()
+ /**
+ Start a service provider.
+ */
+ {
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 11));
+ iProvider->Start();
+ }
+
+void CTransportFlowShim::LocalName(TSockAddr& anAddr) const
+/** Gets the local name (address) of the socket service provider entity. The format
+of the data in the TSockAddr object is defined by individual protocols.
+
+The local address is the address of the local machine plus a local port number.
+Generally only the port number is important, unless you have two IP interfaces,
+for example.
+
+@param anAddr The address to be filled in */
+ {
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 12));
+ iProvider->LocalName(anAddr);
+ }
+
+void CTransportFlowShim::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 */
+ {
+ CNetworkFlow::SetLocalName(anAddr);
+ PostDataClientRouted();
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 65));
+ TInt err = iProvider->SetLocalName(anAddr);
+ if (err != KErrNone)
+ {
+ // Post TError to self, which will result in SubConnectionError to
+ // be called in the TError handling. Have to fake that the message is
+ // coming from iSubConnectionProvider otherwise ReceivedL will leave.
+ RClientInterface::OpenPostMessageClose(iSubConnectionProvider.RecipientId(), Id(), TEBase::TError(err).CRef());
+ return;
+ }
+
+ SetLocalNameProcess();
+ }
+
+void CTransportFlowShim::SetLocalNameProcess()
+ {
+ TBool bearerSent = EFalse;
+ if(iFlowParams.iFlowRequestType != TFlowParams::EImplicit)
+ {
+ // For explicit sockets, TNoBearer will be sent out if it has not already
+ // been done so. This was introduced for PREQ2279, as it is necessary
+ // to lock this SAP to an interface for incoming sockets. Once locked,
+ // this ensures that any incoming packets are only accepted over the locked down
+ // interface and no other interfaces. To lock the interface down the
+ // NoBearer sequence is executed. This change will also now apply to
+ // outgoing explicit sockets. The change for outgoing explicit sockets is
+ // that the NoBearer sequence is started here instead of when receiving
+ // a NoBearer upcall from the protocol.
+
+ // Attempt to send out TNoBearer.
+ if (DoNoBearer())
+ {
+ // TNoBearer was sent out.
+ bearerSent = ETrue;
+ }
+ }
+
+ if (!bearerSent)
+ {
+ // No Bearer was already sent out earlier, or this is an implicit socket.
+ iSessionControlNotify->SetLocalNameComplete();
+ }
+ }
+
+
+TBool CTransportFlowShim::DoNoBearer()
+/**
+Do the actual no Bearer call.
+@return ETrue if the NoBearer post was actually done, EFalse otherwise
+*/
+ {
+ TInt ret = EFalse;
+ if(!iIsStopped)
+ { // Prevent sending NoBearer if DataClientStop was received
+ if (LockToConnectionInfo() != KErrNone)
+ {
+ __ASSERT_DEBUG(iSubConnectionProvider.IsOpen(), User::Panic(KSpecAssert_ESockSSocksspshm, 66));
+ PostNoBearer();
+ ret = ETrue;
+ }
+ iUseBearerErrors = EFalse;
+ ClearDataClientRoutedGuard();
+ }
+ return ret;
+ }
+
+
+
+void CTransportFlowShim::RemName(TSockAddr& anAddr) const
+/** Gets the remote name (address) of the socket service provider entity. The format
+of the data in the TSockAddr object is defined by individual protocols.
+
+A remote address is either the address you're sending data to (non connection-oriented
+sockets)* or the remote end of the connection. It is the address of the remote
+machine (your peer in the network) plus a port number.
+
+@note RemName is only meaningful if the socket server client has called Connect()
+to set up a default address for SendTo(). This function will only be called
+on the protocol if this is the case.
+
+@param anAddr The address to be filled in */
+ {
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 14));
+ iProvider->RemName(anAddr);
+ }
+
+TInt CTransportFlowShim::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. */
+ {
+ CNetworkFlow::SetRemName(anAddr);
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 15));
+ return iProvider->SetRemName(anAddr);
+ }
+
+TInt CTransportFlowShim::GetOption(TUint aLevel, TUint aName, TDes8& anOption) const
+/** Gets some protocol specific option when called by the socket server on behalf of a
+client. A protocol may pass the request down a protocol stack (to protocols it is bound
+to) using the GetOption() function of CProtocolBase.
+
+@param aLevel Option level.
+@param aName Option name.
+@param anOption Option data.
+@return System wide error code.
+*/
+ {
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 16));
+ return iProvider->GetOption(aLevel, aName, anOption);
+ }
+
+void CTransportFlowShim::Ioctl(TUint aLevel, TUint aName, TDes8* anOption)
+/** Performs some protocol specific IO control.
+
+@note If this function is called erroneously, the protocol should call Error() on the
+socket. If an Ioctl call is already outstanding, the client will be panicked with the
+value ETwoIoctls.
+
+@param aLevel Option level.
+@param aName Option name.
+@param anOption Option data.
+*/
+ {
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 17));
+ iProvider->Ioctl(aLevel, aName, anOption);
+ }
+
+void CTransportFlowShim::CancelIoctl(TUint aLevel, TUint aName)
+/** Cancels an outstanding Ioctl call. You are guaranteed only to have one outstanding
+at once.
+
+@param aLevel IOCTL level.
+@param aName IOCTL name.
+*/
+ {
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 18));
+ iProvider->CancelIoctl(aLevel, aName);
+ }
+
+TInt CTransportFlowShim::SetOption(TUint aLevel, TUint aName, const TDesC8 &anOption)
+/** Sets some protocol specific option when called by the socket server on behalf of a
+client. A protocol may pass the request down a protocol stack (to protocols it is bound
+to) using the SetOption() function of CProtocolBase.
+
+@param aLevel Option level.
+@param aName Option name.
+@param anOption Option data.
+@return System wide error code.
+*/
+ {
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 19));
+ return iProvider->SetOption(aLevel, aName, anOption);
+ }
+
+void CTransportFlowShim::ActiveOpen()
+/** Initiates a connection operation - this means that it tells the protocol to
+attempt to connect to a peer. It is called by the socket server in response
+to a connect request from a client.
+
+This version of the function has user data in the connection frame.
+
+Only ever called on connection-oriented sockets. Such a socket
+should always have both the local address and the remote address specified
+before this function is called. If this is not the case then the protocol
+should panic.
+
+When a connection has completed, the protocol should call ConnectComplete()
+on its TNotify. If an error occurs during connection the protocol should not
+call ConnectComplete() at all; instead it should call Error().
+*/
+ {
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 20));
+ iProvider->ActiveOpen();
+ }
+
+void CTransportFlowShim::ActiveOpen(const TDesC8& aConnectionData)
+/** Initiates a connection operation - this means that it tells the protocol to
+attempt to connect to a peer. It is called by the socket server in response
+to a connect request from a client.
+
+This version of the function has user data in the connection frame.
+
+Only ever called on connection-oriented sockets. Such a socket
+should always have both the local address and the remote address specified
+before this function is called. If this is not the case then the protocol
+should panic.
+
+When a connection has completed, the protocol should call ConnectComplete()
+on its TNotify. If an error occurs during connection the protocol should not
+call ConnectComplete() at all; instead it should call Error().
+
+@param aConnectionData If the protocol supports user specified connection
+data, then it will be held in this buffer. */
+ {
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 21));
+ iProvider->ActiveOpen(aConnectionData);
+ }
+
+TInt CTransportFlowShim::PassiveOpen(TUint aQueueSize)
+/** Tells the protocol to start waiting for an incoming connection request on this
+socket (i.e. port). It is called by the socket server in response to a listen
+request from a client.
+
+Only ever called on connection-oriented sockets. Such a socket
+should always have both the local address and the remote address specified
+before this function is called. If this is not the case, then the protocol
+should panic.
+
+The aQue parameter is the number of sockets which can be waiting for an outstanding
+Start after calling ConnectComplete(). The protocol should keep a count of
+sockets in this state - incrementing a variable in ConnectComplete(), and
+decrementing it in Start().
+
+When a connection has completed, the protocol should call ConnectComplete()
+on its TNotify. If an error occurs during connection the protocol should not
+call ConnectComplete() at all; instead it should call Error().
+
+@param aQueSize Size of connect queue.
+*/
+ {
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 22));
+ return iProvider->PassiveOpen(aQueueSize);
+ }
+
+TInt CTransportFlowShim::PassiveOpen(TUint aQueueSize, const TDesC8& aConnectionData)
+/** Tells the protocol to start waiting for an incoming connection request on this
+socket (i.e. port). It is called by the socket server in response to a listen
+request from a client.
+
+This version of the function has user data in the connection frame.
+
+Only ever called on connection-oriented sockets. Such a socket
+should always have both the local address and the remote address specified
+before this function is called. If this is not the case then the protocol
+should panic.
+
+The aQue parameter is the number of sockets which can be waiting for an outstanding
+Start after calling ConnectComplete(). The protocol should keep a count of
+sockets in this state - incrementing a variable in ConnectComplete(), and
+decrementing it in Start().
+
+When a connection has completed the protocol should call ConnectComplete()
+on its TNotify. If an error occurs during connection the protocol should not
+call ConnectComplete() at all; instead it should call Error().
+
+@param aQueueSize size of connect queue
+@param aConnectionData if the protocol supports user specified connection data
+then it will be held in this buffer. */
+ {
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 23));
+ return iProvider->PassiveOpen(aQueueSize, aConnectionData);
+ }
+
+void CTransportFlowShim::Shutdown(MSessionControl::TCloseType aOption)
+/** Terminates a connection (or closes a non connection-oriented socket down).
+
+The value of the option argument specifies the type of processing which will
+be required of the protocol after this function is called.
+
+Normally, when the socket server has called Shutdown() for a socket, it will
+wait for the socket to call CanClose() before destroying the CServProviderBase
+object. However, if the option argument is EImmediate, the CServProviderBase
+will be destroyed as soon as Shutdown() returns.
+
+@param option The shutdown type. */
+ {
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 24));
+ if (aOption == MSessionControl::EImmediate)
+ {
+ iShuttingDown = ETrue;
+ }
+
+ // It is possible for the provider to be null if an error occurs immediatly
+ // after socket creation before the flow is bound and the provider is received
+ // from the protocol.
+ if(iProvider)
+ {
+ iProvider->Shutdown(CServProviderBase::TCloseType(aOption));
+ }
+ }
+
+void CTransportFlowShim::Shutdown(MSessionControl::TCloseType aOption, const TDesC8& aDisconnectionData)
+/** Terminates a connection (or closes a non connection-oriented socket down).
+
+The value of the option argument specifies the type of processing which will
+be required of the protocol after this function is called.
+
+Normally, when the socket server has called Shutdown() for a socket, it will
+wait for the socket to call CanClose() before destroying the CServProviderBase
+object. However, if the option argument is EImmediate, the CServProviderBase
+will be destroyed as soon as Shutdown() returns.
+
+@param option The shutdown type.
+@param aDisconnectionData If the protocol supports disconnect data, any such
+data required will be held in this buffer. */
+ {
+ // It is possible for the provider to be null if an error occurs immediatly
+ // after socket creation before the flow is bound and the provider is received
+ // from the protocol.
+ if(iProvider)
+ {
+ iProvider->Shutdown(CServProviderBase::TCloseType(aOption), aDisconnectionData);
+ }
+ }
+
+void CTransportFlowShim::AutoBind()
+/** Specifies that the protocol should choose a local address for the service access
+point itself. */
+ {
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 25));
+ iProvider->AutoBind();
+ SetLocalNameProcess();
+
+ }
+
+TUint CTransportFlowShim::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.
+*/
+ {
+ CNetworkFlow::Write( aDesc, aOptions, anAddr);
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 26));
+ return iProvider->Write(aDesc, aOptions, anAddr);
+ }
+
+TInt CTransportFlowShim::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.
+*/
+ {
+ CNetworkFlow::Write(aData, aOptions, anAddr);
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 27));
+ return iProvider->Write(aData, aOptions, anAddr);
+ }
+
+void CTransportFlowShim::GetData(TDes8& aDesc, TUint aOptions, TSockAddr* anAddr)
+/** Gets data which the protocol has indicated is waiting in its buffers using the NewData
+up-call on the MSocketNotify.
+
+GetData() will only ever be called for as much data as the protocol has specified it can process
+using the NewData up-call.
+
+For stream oriented protocols GetData() should fill the descriptor with data from the stream. On
+a datagram protocol GetData() should copy one datagram into the descriptor and set the length of
+the descriptor. If a full datagram will not fit into the supplied descriptor, the overflow should
+be discarded.
+
+anAddr should be filled in by the protocol with the address of where the data came from.
+
+@param aDesc The buffer for data.
+@param aOptions Protocol specific options.
+@param anAddr Address where the data came from.
+*/
+ {
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 28));
+ iProvider->GetData(aDesc, aOptions, anAddr);
+ }
+
+TInt CTransportFlowShim::GetData(RMBufChain& aData, TUint aLength, TUint aOptions, TSockAddr* anAddr)
+/** Gets data which the protocol has indicated is waiting in its buffers using the NewData
+up-call on the MSocketNotify.
+
+GetData() will only ever be called for as much data as the protocol has specified it can process
+using the NewData up-call.
+
+For stream oriented protocols GetData() should fill the descriptor with data from the stream. On
+a datagram protocol GetData() should copy one datagram into the descriptor and set the length of
+the descriptor. If a full datagram will not fit into the supplied descriptor, the overflow should
+be discarded.
+
+anAddr should be filled in by the protocol with the address of where the data came from.
+
+@param aDesc The buffer for data.
+@param aOptions Protocol specific options.
+@param anAddr Address where the data came from.
+*/
+ {
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 29));
+ return iProvider->GetData(aData, aLength, aOptions, anAddr);
+ }
+
+TInt CTransportFlowShim::SecurityCheck(MProvdSecurityChecker* aChecker)
+/**
+Ask the SAP provider to perform a security policy check on the client process (default implementation).
+*/
+ {
+ // ********************************************************************
+ // NOTE: KErrNone for now, but this should be changed to KErrNotSupported to
+ // turn on strict checking and fail PRTs that have not been secured.
+ // ********************************************************************
+
+ __ASSERT_DEBUG(iProvider, User::Panic(KSpecAssert_ESockSSocksspshm, 30));
+ return iProvider->SecurityCheck(aChecker);
+ }
+
+void CTransportFlowShim::NewData(TUint aCount)
+ {
+ __ASSERT_DEBUG(iSessionDataNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 31));
+ iSessionDataNotify->NewData(aCount);
+ }
+
+void CTransportFlowShim::CanSend()
+ {
+ __ASSERT_DEBUG(iSessionDataNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 32));
+ iSessionDataNotify->CanSend();
+ }
+
+void CTransportFlowShim::ConnectComplete()
+ {
+ __ASSERT_DEBUG(iSessionControlNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 33));
+ iSessionControlNotify->ConnectComplete();
+ }
+
+void CTransportFlowShim::ConnectComplete(const TDesC8& aConnectData)
+ {
+ __ASSERT_DEBUG(iSessionControlNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 34));
+ iSessionControlNotify->ConnectComplete(aConnectData);
+ }
+
+CTransportFlowShim* CTransportFlowShim::CloneNSetSAP(CServProviderBase& aSSP)
+ {
+ //Here we can afford to create a flow directly since we know sub-connection
+ //+ protocols & flow plug-is've been already loaded while opening listenning socket
+ //this is the only case when flow joins without being created from control side
+ CTransportFlowShim* shimFlow = NULL;
+ TRAPD(ret,shimFlow = factoryobject_cast<CTransportFlowShim>(&CloneFlowL()));
+ if (ret != KErrNone)
+ {
+ Error(ret,MSessionControlNotify::EErrorCompleteConnect);
+ }
+ else
+ {
+ __ASSERT_DEBUG(shimFlow, User::Panic(KSpecAssert_ESockSSocksspshm, 35)); //otherwise we shouldn't be here
+ shimFlow->SetSSP(aSSP);
+ shimFlow->iFlowParams = iFlowParams;
+ }
+ return shimFlow;
+ }
+
+void CTransportFlowShim::ConnectComplete(CServProviderBase& aSSP)
+ {
+ CTransportFlowShim* shimFlow;
+ if ((shimFlow = CloneNSetSAP(aSSP)) != NULL)
+ {
+ __ASSERT_DEBUG(iSessionControlNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 36));
+
+ // Store a pointer to the listening control session in case we need to unbind before
+ // the passively opened socket is accepted.
+ shimFlow->iListenerControlNotify = iSessionControlNotify;
+
+ iSessionControlNotify->ConnectComplete(*shimFlow);
+ }
+ }
+
+void CTransportFlowShim::ConnectComplete(CServProviderBase& aSSP,const TDesC8& aConnectData)
+ {
+// CTransportFlowShim* shim = NULL;
+// TRAPD(ret, shim = CTransportFlowShim::NewL(aSSP, NULL, iProtocolId));
+
+ CTransportFlowShim* shimFlow;
+ if ((shimFlow = CloneNSetSAP(aSSP)) != NULL)
+ {
+ __ASSERT_DEBUG(iSessionControlNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 37));
+ iSessionControlNotify->ConnectComplete(*shimFlow, aConnectData);
+ }
+ }
+
+void CTransportFlowShim::CanClose(MSocketNotify::TDelete aDelete)
+ {
+ LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tCanClose() aDelete %d"), this, aDelete) );
+
+ if(iSessionControlNotify)
+ {
+ iDetaching = aDelete == MSocketNotify::EDetach;
+ iSessionControlNotify->CanClose(MSessionControlNotify::TDelete(aDelete));
+ if(aDelete==MSocketNotify::EDetach)
+ {
+ iProvider = NULL;
+ }
+ }
+ else
+ {
+ LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tCanClose() no control above us to notify (open was likely passive and has not been accepted yet) so simply unbinding"), this) );
+
+ // No control above us - likely cause is that we're the result of a passive open that
+ // hasn't yet been accepted.
+ Unbind();
+ }
+ }
+
+void CTransportFlowShim::CanClose(const TDesC8& aDisconnectData,MSocketNotify::TDelete aDelete)
+ {
+ LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tCanClose() aDisconnectData %08x, aDelete %d"), this, aDisconnectData.Ptr(), aDelete) );
+
+ if(iSessionControlNotify)
+ {
+ iDetaching = aDelete == MSocketNotify::EDetach;
+ iSessionControlNotify->CanClose(aDisconnectData, MSessionControlNotify::TDelete(aDelete));
+ if(aDelete==MSocketNotify::EDetach)
+ {
+ iProvider = NULL;
+ }
+ }
+ else
+ {
+ LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tCanClose() no control above us to notify (open was likely passive and has not been accepted yet) so simply unbinding"), this) );
+
+ // No control above us - likely cause is that we're the result of a passive open that
+ // hasn't yet been accepted.
+ Unbind();
+ }
+ }
+
+void CTransportFlowShim::Error(TInt anError, TUint anOperationMask)
+ {
+ LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tError() anError %d, anOperationMask %d"), this, anError, anOperationMask) );
+
+ NM_LOG((KESockServerTag, _L8("CTransportFlowShim %08x:\tSynchronous call: From=%08x To=%08x Func=Error(%d)"),
+ this, static_cast<Messages::ANode*>(this), static_cast<Messages::ANode*>(this), anError) )
+
+ if(iSessionControlNotify)
+ {
+ if (iSessionControlNotify->Error(anError, anOperationMask) != KErrNone)
+ {
+ if (iLowerFlow)
+ {
+ iLowerFlow->Unbind(NULL,NULL);
+ iLowerFlow = NULL;
+ }
+ iLowerControl = NULL;
+ }
+ }
+ else
+ {
+ LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tError() no control above us to notify (open was likely passive and has not been accepted yet) so simply unbinding"), this) );
+
+ // No control above us - likely cause is that we're the result of a passive open that
+ // hasn't yet been accepted.
+ iDetaching = MSocketNotify::EDetach;
+ Unbind();
+ }
+ }
+
+void CTransportFlowShim::Disconnect(void)
+ {
+ LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tDisconnect()"), this) );
+
+ if(iSessionControlNotify)
+ {
+ iSessionControlNotify->Disconnect();
+ }
+ else
+ {
+ LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tDisconnect() no control above us to notify (open was likely passive and has not been accepted yet) so simply unbinding"), this) );
+
+ // No control above us - likely cause is that we're the result of a passive open that
+ // hasn't yet been accepted.
+ iDetaching = MSocketNotify::EDetach;
+ Unbind();
+ }
+ }
+
+void CTransportFlowShim::Disconnect(TDesC8& aDisconnectData)
+ {
+ LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tDisconnect() aDisconnectData %08x"), this, aDisconnectData.Ptr()) );
+
+ if(iSessionControlNotify)
+ {
+ iSessionControlNotify->Disconnect(aDisconnectData);
+ }
+ else
+ {
+ LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tDisconnect() no control above us to notify (open was likely passive and has not been accepted yet) so simply unbinding"), this) );
+
+ // No control above us - likely cause is that we're the result of a passive open that
+ // hasn't yet been accepted.
+ iDetaching = MSocketNotify::EDetach;
+ Unbind();
+ }
+ }
+
+void CTransportFlowShim::IoctlComplete(TDesC8 *aBuf)
+ {
+ __ASSERT_DEBUG(iSessionControlNotify, User::Panic(KSpecAssert_ESockSSocksspshm, 38));
+ iSessionControlNotify->IoctlComplete(aBuf);
+ }
+
+void CTransportFlowShim::NoBearer(const TDesC8& aConnectionParams)
+/**
+Upcall from protocol indicating no underlying bearer for the socket.
+@param aConnectionParams Additional connection parameters from the stack, in the form of a
+human readable string. Initially, the required protocols (e.g. "protocol=ip").
+*/
+ {
+ // *** NOTE ***
+ // overridden by CUpsTransportFlowShim::NoBearer() for UPS support
+
+ (void)aConnectionParams;
+ LOG( ESockLog::ConnectionInfoPrintf(aConnectionParams, _L("CTransportFlowShim %08x:\tNoBearer()"), this) );
+
+ DoNoBearer(); // Do not care if actually posted, so no need to check return value
+
+ }
+
+void CTransportFlowShim::Bearer(const TDesC8& aConnectionInfo)
+ {
+ //we might need to translate the aConnectionInfo into "our" conn info format
+ LOG( ESockLog::ConnectionInfoPrintf(aConnectionInfo, _L("CTransportFlowShim %08x:\tBearer()"), this) );
+
+#if defined(SYMBIAN_TRACE_ENABLE)
+ const TSoIfConnectionInfo *info = REINTERPRET_CAST(const TSoIfConnectionInfo*, aConnectionInfo.Ptr());
+ NM_LOG((KESockServerTag, _L8("CTransportFlowShim %08x:\tSynchronous call: From=%08x To=%08x Func=Bearer(Iap %d, Network %d)"),
+ this, static_cast<Messages::ANode*>(this), static_cast<Messages::ANode*>(this), info->iIAPId, info->iNetworkId) )
+#endif
+
+ if (TConnectionInfo::IsLocalBearer(aConnectionInfo))
+ {
+ return;
+ }
+
+ iUseBearerErrors = ETrue;
+ LocalName(iLocalAddress);
+ iLocalAddressSet = ETrue;
+ RemName(iRemoteAddress);
+ iRemoteAddressSet = ETrue;
+ __ASSERT_DEBUG(iSubConnectionProvider.IsOpen(), User::Panic(KSpecAssert_ESockSSocksspshm, 41)); // legacy flows have no control side; should never get here
+
+ PostDataClientRouted();
+ }
+
+TInt CTransportFlowShim::LockToConnectionInfo()
+ {
+ //bind provider with the selected connection
+ // Note that the following SetOption() can result in an upcall into
+ // CTransportFlowShim::Bearer() in the same stack frame.
+ TPckgBuf<TConnectionInfo> info;
+ if (Control(KSOLProvider, static_cast<TUint>(KSoConnectionInfo), info) == KErrNone)
+ {
+ LOG(ESockLog::Printf(_L("CTransportFlowShim %08x:\tLockToConnectionInfo() Iap %d, Network %d"), this, info().iIapId, info().iNetId));
+ NM_LOG((KESockServerTag, _L8("CTransportFlowShim %08x:\tSynchronous call: From=%08x To=%08x Func=LockToConnectionInfo(Iap %d, Network %d)"),
+ this, static_cast<Messages::ANode*>(this), static_cast<Messages::ANode*>(this), info().iIapId, info().iNetId) )
+
+ TPckg<TSoIfConnectionInfo> ifInfo(iIfInfo);
+ ifInfo().iIAPId = info().iIapId;
+ ifInfo().iNetworkId = info().iNetId;
+ iProvider->SetOption(KSOLProvider, static_cast<TUint>(KSoConnectionInfo), ifInfo);
+ return KErrNone;
+ }
+ else
+ {
+ LOG(ESockLog::Printf(_L("CTransportFlowShim %08x:\tLockToConnectionInfo()"), this));
+ return KErrNotFound;
+ }
+ }
+
+void CTransportFlowShim::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aMessage)
+ {
+ if (aMessage.IsMessage<TCFDataClient::TBindTo>() && !NoBearerGuard())
+ {
+ //TODO PROD RZ
+ //This needs investigating and fixing. There are two cases for why is this needed here:
+ //(1) Bearer mobility is the only scenario for unsolicited TBindTo
+ //(hence checking the guard above). CTransportFlowShim cannot just migrate to the new, as the
+ //socket above it needs to be rebound. mobility_761220:
+ // (1) opens and starts a connection
+ // (2) opens a socket against
+ // (3) sendreceive UDP data and expects (packet colouring) that data to go via IAP4.
+ // (4) migrates to another bearer (IAP5)
+ // (5) uses the same socket (without rebinding) to sendreceive data and expects
+ // the data to go via IAP4 again (despite migrating).
+ //Talk to Ivan Kelly to find out if this is a requirement on the socket (stays connected
+ //over the old until rebound) or is this a wrong test case.
+ //If the former, ipscpr will need changing not to propagate TBindTo to its flows if they
+ //don't ask.
+ //(2) Rejoing this flow. During rejoin scenario, it's the new owner obtains its new
+ //dataclient ('this') before ('this') dataclient knowing. The rejoin procedure is make
+ //before break, hence it tries to apply the new owner, during which time the new
+ //owner starts and hence attempts to TBindTo his new child. The child hates it
+ //as it arrives from an unknown node. The rejoin protocol needs rethinking.
+ RClientInterface::OpenPostMessageClose(Id(), aSender, TCFDataClient::TBindToComplete(KErrNone).CRef());
+ return;
+ }
+ CNetworkFlow::ReceivedL(aSender, aRecipient, aMessage);
+#ifdef SYMBIAN_NETWORKING_UPS
+ // Allow derived classes to process received messages.
+ //
+ // Rationale for ProcessReceivedL() virtual:
+ // The existing idiom whereby we call CNetworkFlow::ReceivedL() up front is awkward.
+ // If we move that call into the derived class, the derived class can do its
+ // specialised processing and then decide to call this base class method for any
+ // remaining more general processing. In this case, the ProcessReceivedL() would
+ // not be required. However, CTransportFlowShim will then become unusable if
+ // instantiated on its own because the call to CNetworkFlow::ReceivedL() is not present.
+ TInt ret = ProcessReceivedL(aMessage);
+ if (ret == KErrNone || ret != KErrNotSupported)
+ {
+ return; // PREQ1116 Productisation: RE-WORK ProcessReceivedL(). Perhaps return TBool indicating whether message processed. Leave if a "real" error. Extra arguments?
+ }
+#endif
+
+ if ( aMessage.IsMessage<TEBase::TError>() )
+ {
+ SubConnectionError(static_cast<TEBase::TError&>(aMessage));
+ }
+ else if (aMessage.IsMessage<TEBase::TCancel>())
+ {
+ // TCancel can be received as a result of a Connect() being cancelled on the socket and a
+ // TBindToComplete() with an error being sent to the PRBindTo activity on our control provider.
+ }
+ else if (TEChild::ERealmId == aMessage.MessageId().Realm())
+ {
+ switch (aMessage.MessageId().MessageId())
+ {
+ case TEChild::TDestroy::EId :
+ Destroy();
+ break;
+ default:
+ //TODO - logging
+ //LOG(ESockLog::Printf(KESockMetaConnectionTag, _L("ERROR: CTransportFlowShim %08x:\tReceivedL(%s) - KErrNotSupported"), this, aMessage.Printable()));
+ __ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSocksspshm, 42)); //For debug configurations
+ User::Leave(KErrNotSupported); //For release configurations
+ }
+ }
+ else if (TCFDataClient::ERealmId == aMessage.MessageId().Realm())
+ {
+ switch (aMessage.MessageId().MessageId())
+ {
+ case TCFDataClient::TStart::EId :
+ StartFlowL(aSender);
+ break;
+ case TCFDataClient::TStop::EId :
+ StopFlow(static_cast<TCFDataClient::TStop&>(aMessage));
+ break;
+ case TCFDataClient::TProvisionConfig::EId :
+
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+ //Store the provision config message,
+ //to store the Provision config message
+ StoreProvision(static_cast<TCFDataClient::TProvisionConfig&>(aMessage));
+#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+
+ break;
+ case TCFDataClient::TCommitBindTo::EId :
+ /*TODO RZ PROD- mustn't just ignore TCommitBindTo - must implement*/
+ break;
+ case TCFDataClient::TBindTo::EId :
+ {
+ TCFDataClient::TBindTo& bindToMsg(static_cast<TCFDataClient::TBindTo&>(aMessage));
+ TRAPD(err,BindToL(bindToMsg));
+ // Ensure that TBindToComplete message gets sent before TIdle so that it gets to the destination
+ // before destroy processing.
+ RClientInterface::OpenPostMessageClose(Id(), aSender, TCFDataClient::TBindToComplete(err).CRef());
+ ProcessDCIdleState(); // in case we were waiting to send idle
+ //If we have received TDataClientStart before (when we did not yet have a bearer),
+ //we complete the start here as well
+ if (err != KErrNone)
+ {
+ //If we have received TDataClientStart before (when we did not yet have a bearer),
+ //we complete the start here as well
+ if (iStartRequest.IsOpen())
+ {
+ CompleteStart(err);
+ }
+ iBearerExpected = ETrue;
+ }
+ else
+ {
+ // If we get a TBindTo message then the TNoBearer request has succeeded
+ // and we can inform the client.
+ if (iSessionControlNotify)
+ {
+ iSessionControlNotify->SetLocalNameComplete();
+ }
+ }
+ break;
+ }
+ default:
+ //TODO - logging
+ //LOG(ESockLog::Printf(KESockMetaConnectionTag, _L("ERROR: CTransportFlowShim %08x:\tReceivedL(%s) - KErrNotSupported"), this, aMessage.Printable()));
+ __ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSocksspshm, 43)); //For debug configurations
+ User::Leave(KErrNotSupported); //For release configurations
+ }
+ }
+ else if (TCFFlow::ERealmId == aMessage.MessageId().Realm())
+ {
+ switch (aMessage.MessageId().MessageId())
+ {
+ case TCFFlow::TRejoin::EId :
+ Rejoin(static_cast<TCFFlow::TRejoin&>(aMessage));
+ break;
+ default:
+ //TODO - logging
+ //LOG(ESockLog::Printf(KESockMetaConnectionTag, _L("ERROR: CTransportFlowShim %08x:\tReceivedL(%s) - KErrNotSupported"), this, aMessage.Printable()));
+ __ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSocksspshm, 44)); //For debug configurations
+ User::Leave(KErrNotSupported); //For release configurations
+ }
+ }
+ else if (TCFInternalEsock::ERealmId == aMessage.MessageId().Realm())
+ {
+ switch (aMessage.MessageId().MessageId())
+ {
+ case TCFInternalEsock::TFlowProvision::EId :
+ iFlowParams = (static_cast<TCFInternalEsock::TFlowProvision&>(aMessage)).iFlowParams;
+ break;
+ default:
+ //TODO - logging
+ //LOG(ESockLog::Printf(KESockMetaConnectionTag, _L("ERROR: CTransportFlowShim %08x:\tReceivedL(%s) - KErrNotSupported"), this, aMessage.Printable()));
+ __ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSocksspshm, 45)); //For debug configurations
+ User::Leave(KErrNotSupported); //For release configurations
+ }
+ }
+
+//This is the case of Modulation change for a bearer.
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+ else if (TCFMessage::ERealmId == aMessage.MessageId().Realm())
+ {
+ switch (aMessage.MessageId().MessageId())
+ {
+ case TCFMessage::TTransportNotification::EId :
+ //In case of modulation change,
+ //extract the value from this message,
+ //pass it to the shim to set the options for socket.
+ SetProtocolOptions();
+ break;
+ default:
+ //TODO : Logging for error message
+ __ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSocksspshm, 46)); //For debug configurations
+ User::Leave(KErrNotSupported); //For release configurations
+ }
+ }
+#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+
+ else if ( aMessage.IsMessage<TCFPeer::TJoinComplete>() )
+ {;}
+ else if ( aMessage.IsMessage<TCFControlProvider::TBearer>() )
+ {
+ //If we have received TDataClientStart before (when we did not yet have a bearer),
+ //we complete the start here as well
+ if (iStartRequest.IsOpen())
+ {
+ CompleteStart(KErrNone);
+ }
+ LOG( ESockLog::Printf(_L8("CTransportFlowShim %08x:\tReceivedL(): TBearer: iDeleteUponBearerReception %d"), this, iDeleteUponBearerReception) );
+
+ ClearNoBearerGuard();
+ ProcessDCIdleState();
+ NoBearerCompletion(); // may delete this !
+ }
+ else
+ {
+ //TODO - logging
+ //LOG(ESockLog::Printf(KESockMetaConnectionTag, _L("ERROR: CTransportFlowShim %08x:\tReceivedL(%s) - KErrNotSupported"), this, aMessage.Printable()));
+ __ASSERT_DEBUG(EFalse, User::Panic(KSpecAssert_ESockSSocksspshm, 47)); //For debug configurations
+ User::Leave(KErrNotSupported); //For release configurations
+ }
+ }
+
+void CTransportFlowShim::NoBearerCompletion()
+ {
+ iBearerExpected = EFalse;
+ if (iDeleteUponBearerReception)
+ {
+ delete this;
+ }
+ }
+
+const TNodeId& CTransportFlowShim::NodeId() const
+ {
+ return Id();
+ }
+
+void CTransportFlowShim::CompleteStart(TInt aError)
+ {
+ if (aError==KErrNone)
+ {
+ iStartRequest.ReplyTo(Id(), TCFDataClient::TStarted().CRef());
+ iIsStarted = ETrue;
+ iIsStopped = EFalse;
+ }
+ else
+ {
+ iStartRequest.ReplyTo(Id(), TEBase::TError(TCFDataClient::TStart::Id(),aError).CRef());
+ }
+ iStartRequest.Close();
+ }
+
+void CTransportFlowShim::SubConnectionError(const TEBase::TError& errorMsg, TUint anOperationMask)
+ {
+ LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tSubConnectionError() errorMsg.iValue %d, anOperationMask %d"), this, errorMsg.iValue, anOperationMask) );
+
+ if (errorMsg.iMsgId == TCFControlProvider::TNoBearer::Id())
+ {
+ LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tSubConnectionError() - clearing no-bearer guard"), this) );
+ ClearNoBearerGuard();
+#ifdef SYMBIAN_NETWORKING_UPS
+ ProcessDCIdleState();
+#endif
+ NoBearerCompletion();
+ }
+
+ if (IsBoundToSession())
+ {
+ LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tSubConnectionError() - calling Error() function"), this) );
+ Error(errorMsg.iValue, anOperationMask);
+ }
+ else if (iHostResolverNotify)
+ {
+ LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tSubConnectionError() - passing to host resolver's Error() function"), this) );
+ iHostResolverNotify->Error(errorMsg.iValue);
+ }
+ }
+
+void CTransportFlowShim::BindToL(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.
+*/
+ {
+ //provisioning message must come before bindto in case we didn't get it after we've joined
+ //the sub-connection
+
+ NM_LOG((KESockServerTag, _L8("CTransportFlowShim %08x:\tSynchronous call: From=%08x To=%08x Func=BindToL"),
+ this, static_cast<Messages::ANode*>(this), &aBindTo.iNodeId.Node()) )
+
+ if (iShuttingDown)
+ {
+ User::Leave(KErrCancel);
+ return;
+ }
+
+ CNetworkFlow::BindToL(aBindTo);
+ if (iLowerFlow && IsBoundToSession())
+ {
+ LockToConnectionInfo();
+ LocalName(iLocalAddress);
+ iLocalAddressSet = ETrue;
+ RemName(iRemoteAddress);
+ iRemoteAddressSet = ETrue;
+ __ASSERT_DEBUG(iSubConnectionProvider.IsOpen(), User::Panic(KSpecAssert_ESockSSocksspshm, 48)); // legacy flows have no control side; should never get here
+ }
+ else if (iHostResolverNotify)
+ {//workaroud to indicate to CHostResolver we've got connection info
+ if (aBindTo.iNodeId.Ptr())
+ {
+ iHostResolverNotify->StartSending();
+ }
+ else
+ {
+ iHostResolverNotify->Error(KErrDisconnected);
+ }
+ }
+
+
+
+ }
+
+
+void CTransportFlowShim::Rejoin(const TCFFlow::TRejoin& aRejoinMessage)
+ {
+ LOG( ESockLog::Printf(_L("CTransportFlowShim %08x:\tRejoin()"), this ));
+ iSubConnectionProvider.Close();
+ iSubConnectionProvider.Open(TNodeCtxId(0, aRejoinMessage.iNodeId));
+ //If already bound there's a potential need to rebind.
+ //As the new control provider for the flow - if different than
+ //the current, rebind.
+ if (iLowerFlow)
+ {
+ PostNoBearer();
+ }
+ }
+
+void CTransportFlowShim::StartFlowL(const TRuntimeCtxId& aSender)
+ {
+ __ASSERT_DEBUG(!iIsStarted, User::Panic(KSpecAssert_ESockSSocksspshm, 49));
+ __ASSERT_DEBUG(iSubConnectionProvider.IsOpen(), User::Panic(KSpecAssert_ESockSSocksspshm, 50)); // legacy flows have no control side; should never get here
+
+ //We will wait for it and complete the start after we have received it
+ User::LeaveIfError(iStartRequest.Open(iSubConnectionProvider, aSender));
+
+ if (iDCIdle != EClientsPresent)
+ {
+ iStartRequest.ReplyTo(Id(), TEBase::TError(TCFDataClient::TStart::Id(), KErrNotReady).CRef());
+ iStartRequest.Close();
+ return;
+ }
+
+ if (iLowerFlow)
+ {
+ iStartRequest.ReplyTo(Id(), TCFDataClient::TStarted().CRef());
+ iStartRequest.Close();
+ iIsStarted = ETrue;
+ iIsStopped = EFalse;
+ return;
+ }
+
+ //We need a bearer
+ PostNoBearer(); //Ask for bearer if not requested already
+
+ }
+
+void CTransportFlowShim::StopFlow(TCFDataClient::TStop& aMessage)
+ {
+ __ASSERT_DEBUG(iIsStarted, User::Panic(KSpecAssert_ESockSSocksspshm, 51)); //Must be started now
+ __ASSERT_DEBUG(iSubConnectionProvider.IsOpen(), User::Panic(KSpecAssert_ESockSSocksspshm, 52)); // legacy flows have no control side; should never get here
+
+ // We need to error the socket if the lower protocol stack is not going to do this. Once a
+ // Bearer() upcall has been received, the lower protocol will call Error() if the connection
+ // goes down. Before this point, the lower protocol will not call Error(), so StopFlow() calls
+ // from the SCPR are used to error the socket (if the interface start fails).
+ //
+ // The main scenario is the TCP/IP stack as lower protocol which will only call Error() once it
+ // has attached a flow to a route (and hence an interface) which, in turn, only occurs once the
+ // interface is up and data has been sent over the socket. Note that opening an RSocket on an
+ // RConnection but not transferring any data will not cause the TCP/IP stack to attach the flow
+ // to the route and hence not call Error() if the interface comes down.
+
+ if (IsBoundToSession() && !iUseBearerErrors)
+ {
+ Error(aMessage.iValue, EErrorAllOperations);
+ }
+
+ if (iLowerFlow)
+ {
+ iLowerFlow->Unbind(NULL,NULL);
+ iLowerFlow = NULL;
+ }
+ iLowerControl = NULL;
+
+ iSubConnectionProvider.PostMessage(Id(), TCFDataClient::TStopped(aMessage.iValue).CRef());
+ iIsStarted = EFalse;
+ iIsStopped = ETrue;
+ }
+
+void CTransportFlowShim::InitDestroy()
+ {
+ __ASSERT_DEBUG(iDCIdle <= EClientsPresent, User::Panic(KSpecAssert_ESockSSocksspshm, 53));
+ iDCIdle = EIdle;
+
+ if(iSubConnectionProvider.IsOpen()) // legacy flows have no control side
+ {
+ ProcessDCIdleState();
+ }
+ else
+ {
+ DeleteThisFlow();
+ }
+ }
+
+void CTransportFlowShim::Destroy()
+ {
+ DeleteThisFlow();
+ }
+
+void CTransportFlowShim::PostNoBearer()
+ {
+ if (!NoBearerGuard())
+ {
+ iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TNoBearer().CRef());
+ SetNoBearerGuard();
+ }
+ }
+
+void CTransportFlowShim::PostDataClientRouted()
+ {
+ if (iLocalAddressSet && iRemoteAddressSet
+ && iRemoteAddress.Family() != KAFUnspec && !iDataClientRoutedGuard)
+ {
+ iSubConnectionProvider.PostMessage(
+ Id(),
+ TCFIPMessages::TDataClientRouted(
+ TAddrUpdate(
+ iLocalAddress,
+ iRemoteAddress,
+ iFlowParams.iProtocol,
+ iIfInfo.iIAPId)
+ ).CRef()
+ );
+ iDataClientRoutedGuard = ETrue;
+ }
+ }
+
+void CTransportFlowShim::ClearDataClientRoutedGuard()
+ {
+ iDataClientRoutedGuard = EFalse;
+ }
+
+
+/*
+Store the provision information passed from the Control side.
+@param TProvisionConfig Message recd.
+*/
+void CTransportFlowShim::StoreProvision(TCFDataClient::TProvisionConfig& aMessage)
+ {
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+ //find access point inforamtion from the message
+ iAccessPointConfig.Close();
+ iAccessPointConfig.Open(aMessage.iConfig);
+ //Find extension appended at NetMcpr and store it
+ //Presently will extract CSAPSetOpt window extensions
+ ExtractSetOptExtensions();
+#else
+ (void)aMessage;
+#endif
+ }
+/*
+Extract extensions appended to TProvisionConfig specific to IPTransport.
+*/
+void CTransportFlowShim::ExtractSetOptExtensions()
+ {
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+ //Extract TCP receive window specific provisionconfig extension.
+ iProtocolOptions = static_cast< const CSAPSetOpt*>(AccessPointConfig().FindExtension(STypeId::CreateSTypeId(CSAPSetOpt::EUid,CSAPSetOpt::ETypeId)));
+#endif
+ }
+
+#ifdef SYMBIAN_NETWORKING_UPS
+
+TBool CTransportFlowShim::ActivityRunning()
+/**
+Determine whether we are in the middle of a NoBearer activity.
+
+In other words, we are waiting for a response from a previously transmitted TNoBearer.
+
+@return ETrue if in the middle of one of this activity, else EFalse.
+*/
+ {
+ return NoBearerGuard();
+ }
+
+//
+// Default implementations of CTransportFlowShim virtuals.
+//
+
+TInt CTransportFlowShim::SetupForNoBearerOnSend()
+ {
+ return KErrNotSupported;
+ }
+
+void CTransportFlowShim::PreUnbind()
+ {
+ }
+
+TInt CTransportFlowShim::ProcessReceivedL(TSignatureBase& /*aCFMessage*/)
+ {
+ return KErrNotSupported;
+ }
+
+//
+// CUpsTransportFlowShim methods
+//
+// This class contains User Prompt Service (UPS) specific functionality.
+//
+
+CUpsTransportFlowShim* CUpsTransportFlowShim::NewL(CSubConnectionFlowFactoryBase& aFactory, const Messages::TNodeId& aSubConn, CProtocolIntfBase* aProtocolIntf)
+/**
+Create a new CUpsTransportFlowShim instanace.
+
+Note: this method replaces CTransportFlowShim::NewL() in UPS builds.
+*/
+ {
+ return new (ELeave) CUpsTransportFlowShim(aFactory, aSubConn, aProtocolIntf);
+ }
+
+TInt CUpsTransportFlowShim::SetupForNoBearerOnSend()
+/**
+Called just before a TNoBearer message is posted for Host Resolver processing.
+
+Perform the Platform Security capability check and populate the UPS Access Point Config (APC) extension.
+
+@return KErrNone or a system wide error code.
+*/
+ {
+ // For UPS, the capability check has been moved from the provider SAP to here so that
+ // the capability check result is available at the time of the NoBearer message being sent.
+ __ASSERT_DEBUG(iSecurityChecker, User::Panic(KSpecAssert_ESockSSocksspshm, 54));
+ TInt result = iSecurityChecker->CheckPolicy(KPolicyNetworkServices, "UpsTransportFlowShim (SetupForNoBearerOnSend)");
+
+ // At this point, result can contain:
+ //
+ // KErrNone Capability check passed.
+ // KErrPermissionDenied Capability check failed.
+ // KErrCompletion Special error code that instructs us not to perform any UPS check.
+ // This is a means for upper layers to disable UPS checking in circumstances
+ // where the UPS check will be catered for by a higher layer.
+ if (result != KErrCompletion)
+ {
+ if (UpsEnabled())
+ {
+ // UPS enabled - fill in the APC structure associated with TNoBearer message
+ PopulateUpsExtension(result);
+ }
+ else
+ {
+ // UPS disabled - fall back to the Platform Security check
+ if (result != KErrNone)
+ {
+ return TSendResult(result);
+ }
+ }
+ }
+ return KErrNone;
+ }
+
+void CUpsTransportFlowShim::PreUnbind()
+/**
+Called just before an unbind happens.
+
+Ensure that we cancel any running activities.
+
+(there are no activities on the data side in the formal sense - the term is used
+to describe NoBearer processing happening locally).
+*/
+ {
+ if (ActivityRunning())
+ {
+ // @TODO PREQ1116 - should we be able to have a NoBearer and a PolicyCheckRequest pending
+ // at the same time ? Should we prevent it?
+
+ // Cancel any pending NoBearer activity. This has become necessary because the UPS authorisation
+ // can cause the NoBearer activity to be pending for an indefinate period of time. When the
+ // cancel reaches the MCpr, the UPS authorisation will be cancelled and a TError will eventually
+ // be received and processed in SubConnectionError().
+ iSubConnectionProvider.PostMessage(Id(), Messages::TEBase::TCancel().CRef());
+ }
+ }
+
+TInt CUpsTransportFlowShim::SetOption(TUint aLevel, TUint aName, const TDesC8 &anOption)
+/**
+Process SetOption() requests from upper layer
+*/
+ {
+ if (aLevel == KSOLProvider)
+ {
+ if (aName == KSoOwnerInfo)
+ {
+ // Upper layer communicating process and thread id of client opening subsession.
+ __ASSERT_DEBUG(anOption.Size() == sizeof(TSoOwnerInfo), User::Panic(KSpecAssert_ESockSSocksspshm, 55));
+
+ const TSoOwnerInfo* soOwnerInfoPtr = reinterpret_cast <const TSoOwnerInfo*> (anOption.Ptr());
+ __ASSERT_DEBUG(soOwnerInfoPtr, User::Panic(KSpecAssert_ESockSSocksspshm, 56));
+
+ iThreadId = soOwnerInfoPtr->iThreadId;
+ iProcessId = soOwnerInfoPtr->iProcessId;
+ }
+ else
+ if (aName == KSoSetPlatSecApi)
+ {
+ // Upper layer communicating an 'M' class instance that can be used for retrieving
+ // process and thread id of client performing current operation.
+ __ASSERT_DEBUG(anOption.Size() == sizeof(const MPlatsecApiExt*), User::Panic(KSpecAssert_ESockSSocksspshm, 57));
+ iPlatsecIf = *reinterpret_cast <const MPlatsecApiExt* const *> (anOption.Ptr());
+ }
+
+ if (IsHostResolver())
+ {
+ // For Host Resolvers, the SetOption() is only for us to store the thread and process id,
+ // so we are complete. There is no iProvider in this case to propagate the call to.
+ __ASSERT_DEBUG(Provider() == NULL, User::Panic(KSpecAssert_ESockSSocksspshm, 58));
+ return KErrNone;
+ }
+ }
+
+ return CTransportFlowShim::SetOption(aLevel, aName, anOption);
+ }
+
+TInt CUpsTransportFlowShim::SecurityCheck(MProvdSecurityChecker* aChecker)
+/**
+Called from upper layer to ask the SAP provider to perform a security policy check
+on the client process.
+
+@param aChecker Security checker class instance
+@return KErrNone or a system wide error code
+*/
+ {
+ // Save away the security checker class so that we can perform capability checking
+ // here instead of in the TCP/IP stack.
+ //
+ // Note: iSecurityChecker can get overwritten as a result of ProtocolManager::TransferSocketL(),
+ // so don't ASSERT(iSecurityChecker == NULL).
+ iSecurityChecker = aChecker;
+
+ if (Provider())
+ {
+ // Sockets
+ __ASSERT_DEBUG(!IsHostResolver(), User::Panic(KSpecAssert_ESockSSocksspshm, 59));
+ return Provider()->SecurityCheck(aChecker);
+ }
+ else
+ {
+ // Host Resolvers
+ __ASSERT_DEBUG(IsHostResolver(), User::Panic(KSpecAssert_ESockSSocksspshm, 60));
+ return KErrNone;
+ }
+ }
+
+void CUpsTransportFlowShim::GetProcessAndThreadId(TProcessId& aProcessId, TThreadId& aThreadId) const
+/**
+Retrieve the process and thread id corresponding to the current Socket/Host Resolver request.
+
+The iProcessId and iThreadId variables contain the ids at the time of subsession open, which
+is not necessarily the same as the ids of the client performing the actual request. The
+call to iPlatsecIf->GetProcessAndThreadId() will actually go to the layer above for processing
+and retrieve the ids associated with the current pending request.
+
+@param aProcessId variable receiving process id (out)
+@param aThreadId variable receiveing thread id (out)
+@return KErrNone, else a system wide error code.
+*/
+ {
+ TInt err = KErrGeneral;
+ if (iPlatsecIf)
+ {
+ err = iPlatsecIf->GetProcessAndThreadId(aProcessId, aThreadId);
+ }
+
+ if (err != KErrNone)
+ {
+ aProcessId = iProcessId;
+ aThreadId = iThreadId;
+ }
+ }
+
+void CUpsTransportFlowShim::NoBearer(const TDesC8& aConnectionParams)
+/**
+Upcall from protocol indicating no underlying bearer for the socket.
+@param aConnectionParams Additional connection parameters from the stack, in the form of a
+human readable string. Initially, the required protocols (e.g. "protocol=ip").
+
+This method overrides CTransportFlowShim::NoBearer() for UPS specific handling.
+*/
+ {
+ (void)aConnectionParams;
+ LOG( ESockLog::Printf(_L8("CUpsTransportFlowShim %08x:\tNoBearer(%S)"), this, &aConnectionParams) );
+
+ // Perform the Platform Security check (moved from the Provider SAP to here in order to
+ // obtain the platsec result as part of UPS processing).
+
+ TInt result = iSecurityChecker->CheckPolicy(KPolicyNetworkServices, "TransportFlowShim (NoBearer)");
+
+ NM_LOG((KESockServerTag, _L8("CTransportFlowShim %08x:\tSynchronous call: From=%08x To=%08x Func=NoBearer(%S)"),
+ this, static_cast<Messages::ANode*>(this), static_cast<Messages::ANode*>(this), &aConnectionParams) )
+
+ // At this point, result can contain:
+ //
+ // KErrNone Capability check passed.
+ // KErrPermissionDenied Capability check failed.
+ // KErrCompletion Special error code that instructs us not to perform any UPS check.
+ // This is a means for upper layers to disable UPS checking in circumstances
+ // where the UPS check will be catered for by a higher layer.
+
+ TBool disableUpsCheck = (result == KErrCompletion);
+ if (!disableUpsCheck && !UpsEnabled())
+ {
+ // UPS disabled - fall back to the Platform Security check
+ if (result != KErrNone)
+ {
+ Error(result, MSocketNotify::EErrorSend | MSocketNotify::EErrorConnect);
+ return;
+ }
+ }
+
+ if(!IsStopped())
+ { // Prevent sending NoBearer if DataClientStop was received
+ ParseNoBearerParams(aConnectionParams);
+ if (iIsScoped)
+ {
+ if (!disableUpsCheck && UpsEnabled())
+ {
+ // Do not perform standard NoBearer() processing for "gratuitous" NoBearer() calls. The
+ // TCP/IP stack already has enough scope information to select an interface, but this
+ // probably will be different from the "default" implicit interface that the control side will
+ // select. The consequence is that the TransportFlowShim could end up being associated with the
+ // wrong SCpr. Note that this is not a problem introduced by UPS functionality - it exists in
+ // the Networking Subsystem anyway. The "Bearer()-only" cases in pre-UPS code do not result in
+ // the TCP/IP stack generating a NoBearer() (just a Bearer()), so the TransportFlowShim never
+ // gets associated with any SCpr. We are just replicating this behaviour for UPS functionality,
+ // by performing a TPolicyCheckRequest sequence for the sake of UPS checking, but otherwise the
+ // behaviour mirrors what is already present (i.e. does nothing else).
+ PostPolicyCheckRequest(result);
+ }
+ else
+ {
+ // If no UPS handling is required, tell the TCP/IP stack that it can go ahead and route the flow.
+ IssueScopedNoBearerResponse();
+ }
+ }
+ else
+ if (LockToConnectionInfo() != KErrNone)
+ {
+ __ASSERT_DEBUG(iSubConnectionProvider.IsOpen(), User::Panic(KSpecAssert_ESockSSocksspshm, 61)); // legacy flows have no control side; should never get here
+ // If UPS is enabled, fill in the APC structure to accompany the TNoBearer
+ // Do this even if disableUpsCheck is set so that the APC will contain KErrCompletion.
+ if (UpsEnabled())
+ {
+ PopulateUpsExtension(result);
+ }
+ PostNoBearer();
+ }
+ ClearUseBearerErrors();
+ ClearDataClientRoutedGuard();
+ }
+ else
+ {
+ // Return an error on an attempt to issue a SendTo() on an explicit socket (datagram) whose corresponding
+ // connection has gone down (BR2639). Note that the use of KErrDisconnected should NOT be documented -
+ // in future, we may wish to return the same error as the connection itself experienced.
+ Error(KErrDisconnected, MSessionControlNotify::EErrorSend);
+ }
+ }
+
+void CUpsTransportFlowShim::PopulateUpsExtension(TInt aPolicyCheckResult) const
+/**
+Populate the UPS Access Point Config structure with the required information in preparation for
+a TNoBearer message to be transmitted.
+
+@param aPolicyCheckResult result of Platform Security check
+*/
+ {
+ __ASSERT_DEBUG(iUpsExtension, User::Panic(KSpecAssert_ESockSSocksspshm, 62));
+ iUpsExtension->SetPolicyCheckResult(aPolicyCheckResult);
+
+ TProcessId processId;
+ TThreadId threadId;
+ GetProcessAndThreadId(processId, threadId);
+
+ iUpsExtension->SetProcessId(processId);
+ iUpsExtension->SetThreadId(threadId);
+
+ if (IsHostResolver())
+ {
+ // Null destination name for Host Resolvers.
+ iUpsExtension->ResetDestinationAddr();
+ iUpsExtension->SetDestinationAddrType(ETNone);
+ }
+ else
+ {
+ // @TODO PREQ1116 - something better than this cast? For example, argument to
+ // SetDestinationAddr() could become a "const TDesC8&" perhaps (without worrying about
+ // error checking) ?
+ iUpsExtension->SetDestinationAddr(static_cast<TUpsDestinationAddr>(iRemoteAddress));
+ iUpsExtension->SetDestinationAddrType(ETSockAddress);
+ }
+ }
+
+
+void CUpsTransportFlowShim::PostPolicyCheckRequest(TInt aPolicyCheckResult)
+/**
+Post a TPolicyCheckRequest message to the SCpr
+
+@param aPolicyCheckResult result of Platform Security check
+*/
+ {
+ if (!PolicyCheckRequestPending())
+ {
+ __ASSERT_DEBUG(UpsEnabled(), User::Panic(KSpecAssert_ESockSSocksspshm, 63)); // UPS should not be "short circuited" off
+
+ TProcessId processId;
+ TThreadId threadId;
+ GetProcessAndThreadId(processId, threadId);
+
+ const TPolicyCheckRequestParams params(processId, threadId, aPolicyCheckResult, static_cast<TUpsDestinationAddr>(iRemoteAddress), ETSockAddress);
+ iSubConnectionProvider.PostMessage(Id(), UpsMessage::TPolicyCheckRequest(params).CRef());
+ SetPolicyCheckRequestPending(ETrue);
+ }
+ }
+
+void CUpsTransportFlowShim::ProcessPolicyCheckResponse(const UpsMessage::TPolicyCheckResponse& aResponse)
+/**
+Process a TPolicyCheckResponse from the SCpr.
+
+If UPS authorisation was granted, prod the TCP/IP stack into re-attaching the flow (based on the original
+scope id in the socket address).
+
+@param aResponse TPolicyCheckResponse message
+*/
+ {
+ SetPolicyCheckRequestPending(EFalse);
+
+ if (iDCIdle == EIdle)
+ {
+ ProcessDCIdleState();
+ }
+ else
+ {
+ if (aResponse.iValue == KErrNone)
+ {
+ if (iIsScoped)
+ {
+ // If socket address already has a scope id, do not tell the stack to use our
+ // idea of NetworkId. If we do, our idea of the NetworkId could be a mismatch
+ // with the existing scope id, and we could end up with an SCPR which represents a
+ // different interface from the one that the TCP/IP stack has chosen based on the scope
+ // id. Use the special KNetworkIdFromAddress value for NetworkId which the TCP/IP stack
+ // recognises as meaning "attempt to attach the flow to a route, but determine the
+ // NetworkId from the socket address, as you've already indicated in the NoBearer()
+ // that you have enough information to do so".
+ //
+ // This code has become necessary due to the UPS support, which forces the
+ // TCP/IP stack to issue NoBearer() calls in circumstances where it never used to
+ // before, to give an opportunity to perform UPS authorisation.
+ IssueScopedNoBearerResponse();
+ }
+ }
+ else
+ {
+ Error(aResponse.iValue, MSocketNotify::EErrorSend | MSocketNotify::EErrorConnect);
+ }
+ }
+ }
+
+void CUpsTransportFlowShim::IssueScopedNoBearerResponse()
+/**
+After a gratuitous NoBearer() upcall has been issued to us (to allow a chance for UPS checking to occur before
+a flow is routed), issue the response to the TCP/IP stack indicating that it can now route the flow and continue.
+ */
+ {
+ TSoIfConnectionInfo info;
+ TPckg<TSoIfConnectionInfo> ifInfo(info);
+ info.iIAPId = 0;
+ info.iNetworkId = KNetworkIdFromAddress;
+ __ASSERT_DEBUG(Provider(), User::Panic(KSpecAssert_ESockSSocksspshm, 64));
+ SetIfInfo(info);
+ Provider()->SetOption(KSOLProvider, static_cast<TUint>(KSoConnectionInfo), ifInfo);
+ }
+
+void CUpsTransportFlowShim::ParseNoBearerParams(const TDesC8& aConnectionParams)
+/**
+Parse the descriptor passed in NoBearer() upcall.
+
+Main raison d'etre for this routine is to check whether the "scoped" string was
+part of the descriptor contents (indicating a "gratuitous" NoBearer()).
+
+@param aConnectionParams Argument passed in NoBearer() upcall from lower layer.
+*/
+ {
+ _LIT8(KScoped, "scoped");
+ if (aConnectionParams.Find(KScoped()) != KErrNotFound)
+ {
+ // "scoped" string signifies a "gratuitous" NoBearer(). The flow could have been routed
+ // without a NoBearer() (i.e. it was scoped enough to route it), but the NoBearer() was
+ // generated anyway so that ESock could perform UPS checking before routing it.
+ iIsScoped = ETrue;
+ }
+ else
+ {
+ iIsScoped = EFalse;
+ }
+ }
+
+TInt CUpsTransportFlowShim::ProcessReceivedL(TSignatureBase& aCFMessage)
+/*
+Process any SCpr messages specific to UPS functionality.
+
+Called from base class (CTransportFlowShim) before it attempts to process the incoming message.
+
+@param aCFMessage Message from SCpr
+@return KErrNone if we have handled the incoming message and no more processing is necessary,
+KErrNotSupported if have not handled the incoming message, else a system wide error code.
+*/
+ {
+ // Check for special UPS messages.
+ if (UpsMessage::ERealmId == aCFMessage.MessageId().Realm())
+ {
+ switch (aCFMessage.MessageId().MessageId())
+ {
+ case UpsMessage::TPolicyCheckResponse::EId :
+ {
+ // Support for UPS
+ const UpsMessage::TPolicyCheckResponse& policyCheckResponseMsg = static_cast<UpsMessage::TPolicyCheckResponse&>(aCFMessage);
+ ProcessPolicyCheckResponse(policyCheckResponseMsg);
+ return KErrNone;
+ }
+ }
+ }
+ else
+ if (TCFDataClient::ERealmId == aCFMessage.MessageId().Realm())
+ {
+ switch (aCFMessage.MessageId().MessageId())
+ {
+ case TCFDataClient::TProvisionConfig::EId :
+ {
+ // Get a pointer to the UPS Access Point Config structure. If not present, then UPS is
+ // disabled ("short circuited") and iUpsExtension remains set to NULL.
+ const TCFDataClient::TProvisionConfig& provisionMsg = static_cast<TCFDataClient::TProvisionConfig&>(aCFMessage);
+
+ iAccessPointConfig.Close();
+ iAccessPointConfig.Open(provisionMsg.iConfig);
+
+ const Meta::SMetaData* const extension = AccessPointConfig().FindExtension(
+ STypeId::CreateSTypeId(CUPSAccessPointConfigExt::EUPSAccessPointConfigUid, CUPSAccessPointConfigExt::ETypeId));
+ if (extension)
+ {
+ iUpsExtension = const_cast<CUPSAccessPointConfigExt*> (static_cast<const CUPSAccessPointConfigExt*>(extension));
+ }
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+ //
+ //Store the provision config message,
+ //to store the Provision config message
+ //which will have TCP Receive window sizes.
+ StoreProvision(static_cast<TCFDataClient::TProvisionConfig&>(aCFMessage));
+#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+
+ return KErrNone;
+ }
+ }
+ }
+ return KErrNotSupported;
+ }
+
+void CUpsTransportFlowShim::SubConnectionError(const Messages::TEBase::TError& aErrorMsg, TUint anOperationMask)
+/**
+Handle errors from SCpr
+
+@param aErrorMsg The incoming TError message
+@param anOperationMask Pending operations to be error'd.
+*/
+ {
+ if (aErrorMsg.iMsgId == UpsMessage::TPolicyCheckRequest::Id())
+ {
+ // Previously sent TPolicyCheckRequest failed.
+ SetPolicyCheckRequestPending(EFalse);
+ ProcessDCIdleState();
+ }
+
+ CTransportFlowShim::SubConnectionError(aErrorMsg, anOperationMask);
+ }
+
+TBool CUpsTransportFlowShim::ActivityRunning()
+/**
+Determine whether we are in the middle of NoBearer or PolicyCheckRequest processing.
+
+In other words, we are waiting for a response from a previously transmitted TNoBearer
+or TPolicyCheckRequest.
+
+@return ETrue if in the middle of one of this activity, else EFalse.
+*/
+ {
+ return PolicyCheckRequestPending() || CTransportFlowShim::ActivityRunning();
+ }
+
+#endif //f_NETWORKING_UPS
+
+
+
+//Register the class variable
+START_ATTRIBUTE_TABLE(CSAPSetOpt,CSAPSetOpt::EUid, CSAPSetOpt::ETypeId)
+END_ATTRIBUTE_TABLE()
+
+#ifdef SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+//Set the protocol options
+void CTransportFlowShim::SetProtocolOptions()
+ {
+ if(iProvider && iProtocolOptions)
+ {
+ for(TInt iter = 0; iter < iProtocolOptions->iOption.Count(); iter++)
+ {
+ TPtr8 optionDesProtOptVal( (TUint8*)&(iProtocolOptions->iOption[iter].iOptionValue), sizeof(TUint), sizeof(TUint) );
+ iProvider->SetOption(iProtocolOptions->iOption[iter].iOptionName,iProtocolOptions->iOption[iter].iOptionLevel, optionDesProtOptVal);
+ }
+ }
+ }
+#endif //SYMBIAN_ADAPTIVE_TCP_RECEIVE_WINDOW
+
+EXPORT_C CSAPSetOpt::CSAPSetOpt()
+ {
+ }
+
+CSAPSetOpt::~CSAPSetOpt()
+ {
+ //Free the RArray resources.
+ iOption.Close();
+ }
+
+//Add the option to the RArray variable
+EXPORT_C void CSAPSetOpt::AddProtocolOptionL(TUint aOptionName, TUint aOptionLevel, TUint aOptionValue)
+ {
+ TProtocolOption opt;
+ opt.iOptionName = aOptionName;
+ opt.iOptionLevel = aOptionLevel;
+ opt.iOptionValue = aOptionValue;
+ iOption.AppendL(opt);
+ }
+
+//Update the value for an option
+EXPORT_C void CSAPSetOpt::UpdateProtocolOption(TUint aOptionName, TUint aOptionLevel, TUint aOptionValue)
+ {
+ for(TInt i = 0; i < iOption.Count(); i++)
+ if((iOption[i].iOptionName == aOptionName) && (iOption[i].iOptionLevel == aOptionLevel))
+ iOption[i].iOptionValue = aOptionValue;
+ }
+
+
+