networkprotocols/iphook/inhook6/src/posthook.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/networkprotocols/iphook/inhook6/src/posthook.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,381 @@
+// Copyright (c) 2004-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:
+// posthook.cpp - Base class for post hooks (implementation)
+//
+
+#include <e32std.h>
+#include <e32base.h>
+
+#include "posthook.h"
+
+EXPORT_C CProtocolPosthook::~CProtocolPosthook()
+	/**
+	* Destructor
+	*
+	* If this object is still attached to the network layer,
+	* the attachement and all bindings to the network layer
+	* from this protocol object are cancelled.
+	*/
+	{
+	if (iNetwork != NULL)
+		{
+		CProtocolInet6Binder *const prt = iNetwork->Protocol();
+		iNetwork = NULL;
+		prt->Unbind(this);
+		if (iBindToNet)
+			prt->Close();
+		}
+	}
+
+EXPORT_C void CProtocolPosthook::BindL(CProtocolBase* aProtocol, TUint aId)
+	/**
+	* Handles network layer binds.
+	*
+	* This function handles the network layer detection and posthook
+	* chaining binds. The processing is based on the following
+	* "well known" id values:
+	*
+	* - MIp6Hook::BindPostHook() (for outbound posthook chaining)
+	* - MIp6Hook::BindPreHook() (for inbound posthook chaining)
+	* - #KProtocolInet6Ip (aProtocol must be network instance)
+	* - #KProtocolInetIp (aProtocol must be network instance, deprecated)
+	*
+	* If the aId does not match any of the above, the BindL is
+	* silently ignored (just return happens). This is quite OK,
+	* there is no need to generate an error in such case.
+	*
+	* This network layer detection is only used in a configuration, where
+	* this protocol is bound from the network layer (ip6). Such configuration
+	* will keep this protocol module installed whenever the network is loaded.
+@verbatim
+[yourposthook]
+filename= yourposthook.prt
+index= 1
+bindfrom= ip6
+@endverbatim
+	*
+	* @note
+	*	This protocol can be loaded even if network is not. If the
+	*	protocol provides a SAP functionality, an application can
+	*	open a socket to this protocol without the network layer
+	*	being started.
+	*
+	* The derived class <b>only</b> needs to override the default
+	* implementation if it appears as a target of "bindto" directive
+	* in a ESK file of another protocol (except the network layer),
+	* <b>and if</b> the implementation needs to store a reference
+	* to this protocol. In such case the BindL could be, for example:
+@code
+	CProtocolBase *iAnother;
+
+	CProtocolDerivedHook::BindL(CProtocolBase *aProtocol, TUint aId)
+		{
+		if (aId == your_special_binding_protocol)
+			{
+			// handle your bind
+			iAnother = aProtocol;
+			}
+		// The default should always be called,
+		CProtocolPosthook::BindL(aProtocol, aId);
+		}
+@endcode
+	* @param aProtocol	The protocol binding to this.
+	* @param aId		The bind id.
+	*/
+	{
+	if (iNetwork == NULL &&	// Only the first network bind is accepted here
+		(aId == KProtocolInet6Ip || aId == KProtocolInetIp))
+		{
+		// Make sure the aProtocol is really the network layer: require
+		// that the aId the is same as the one defined in protocol
+		// description.
+		TServerProtocolDesc info;
+		aProtocol->Identify(&info);
+		if (info.iProtocol == aId)
+			{
+			//
+			// Hook is loaded via a bindto from network layer
+			//
+			iNetwork = ((CProtocolInet6Binder *)aProtocol)->NetworkService();
+			NetworkAttachedL();
+			return;
+			}
+		}
+	if (aId == MIp6Hook::BindPostHook())
+		{
+		// Maintain outbound post hook chaining
+		iPostHook = aProtocol;
+		return;
+		}
+	if (aId == MIp6Hook::BindPreHook())
+		{
+		// Maintain inbound post hook chaining
+		iInboundHook = aProtocol;
+		return;
+		}
+	}
+
+EXPORT_C void CProtocolPosthook::Unbind(CProtocolBase *aProtocol, TUint aId)
+	/**
+	* Handles network layer unbinds.
+	*
+	* This function handles the network layer unbind and posthook
+	* chaining unbinds. The processing is based on the following
+	* "well known" bind id values:
+	*
+	* - MIp6Hook::BindPostHook()  (for outbound posthook chaining)
+	* - MIp6Hook::BindPreHook() (for inbound posthook chaining)
+	* - #KProtocolInet6Ip (for the network intance)
+	* - #KProtocolInetIp (for network instance, deprecated)
+	* - 0 (unbind all)
+	*
+	* If the aId does not match any of the above, the Unbind is
+	* silently ignored (just return happens). This is quite OK,
+	* there is no need to generate an error in such case.
+	*
+	* The derived class needs to override the default implementation
+	* only if it is bound from another protocol (except the network layer)
+	* and if class also overrode the CProtocolPosthook::BindL and saved
+	* a pointer to this protocol. For example:
+@code
+	CProtocolDerivedHook::Unbind(CProtocolBase *aProtocol, TUint aId)
+		{
+		if (iAnother == aProtocol &&
+			(aId == 0 || aId == your_special_binding_protocol))
+			{
+			// handle your unbind
+			iAnotherProtocol = NULL;
+			}
+		// The default should always be called,
+		CProtocolPosthook::Unbind(aProtocol, aId);
+		}
+@endcode	
+	* @param aProtocol	The protocol unbinding from this.
+	* @param aId		The bind id.
+	*/
+	{
+	if (!iBindToNet &&
+		iNetwork != NULL &&
+		iNetwork->Protocol() == aProtocol && 
+		(aId == 0 || aId == KProtocolInet6Ip || aId == KProtocolInetIp))
+		{
+		NetworkDetached();
+		iNetwork = 0;
+		}
+	if (iPostHook == aProtocol && (aId == 0 || aId == MIp6Hook::BindPostHook()))
+		iPostHook = 0;
+	if (iInboundHook == aProtocol && (aId == 0 || aId == MIp6Hook::BindPostHook()+1))
+		iInboundHook = 0;
+	}
+
+// CProtocolPosthook::DoBindToL
+// ****************************
+
+EXPORT_C TInt CProtocolPosthook::DoBindToL(CProtocolBase *aProtocol)
+	/**
+	* Handle network layer bindto.
+	*
+	* Performs the BindToL processing for the network detection.
+	* This network layer detection is only used in a configuration,
+	* where the "bindto" list of this protocol includes the network
+	* layer (ip6). In this configuration, the network layer
+	* stays installed whenever this protocol is loaded.
+	*
+	* @note
+	*	Network can be loaded without this protocol being loaded.
+	*
+	* @param aProtocol	The protocol to bind to.
+	* @return KErrNone or the id of the protocol.
+	*  - KErrNone (= 0),
+	*	 BindTo processed (it was the network bind, NetworkAttachedL has
+	*	 been called.)
+	*  - protocol id ( != 0) from the aProtocol, which was not the network
+	*
+	* @note
+	*	The protocol id is TUint. However, this method is defined
+	*	to return TInt  The function should be considered to return
+	*	TUint and any non-zero value means that the protocol was not
+	*	the network. [returning TInt instead of TUint is a mistake].
+	*
+	* This function exists for derived classes that override the default
+	* BindToL for their own processing. See ::BindToL for example.
+	*/
+	{
+	TServerProtocolDesc info;
+	aProtocol->Identify(&info);
+	const TUint id = info.iProtocol;
+	if (iNetwork == NULL && (id == KProtocolInetIp || id == KProtocolInet6Ip))
+		{
+		iNetwork = ((CProtocolInet6Binder *)aProtocol)->NetworkService();
+		aProtocol->Open();
+		iBindToNet = 1;	// Network layer bind via BindTo.
+		// Note: when the hook binds to network, NetworkDetached is never
+		// called, because network can never exit before this hook, the
+		// event never happens while this hook is running.
+		NetworkAttachedL();
+		return KErrNone;
+		}
+	return id;
+	}
+
+// CProtocolPosthook::BindToL
+// **************************
+EXPORT_C void CProtocolPosthook::BindToL(CProtocolBase *aProtocol)
+	/**
+	* The default implementation.
+	*
+	* This implemenation only handles the network bind and leaves
+	* with #KErrNotSupported if the protocol is not the network
+	* instance.
+	*
+	* If the "bindto" list of this protocol can have other protocols
+	* than the network (ip6), then the derived class must implement the
+	* support for it. For example
+@code
+	CProtocolDerivedHook::BindToL(CProtocolBase *aProtocol)
+		{
+		const TInt id = DoBindToL(aProtocol);
+		if (id == (TInt)your_special_protocol)
+			{
+			//
+			if (iBindTo)
+				iBindTo->Close();
+			iBindTo = aProtocol;
+			iBindTo->Open();
+			// Destructor must issue Close, if iBindTo is non-NULL
+			}
+		else if (id != KErrNone)
+			User::Leave(KErrNotSupported);
+		}
+@endcode
+	*/
+	{
+	if (DoBindToL(aProtocol) != KErrNone)
+		User::Leave(KErrNotSupported);
+	}
+
+EXPORT_C TInt CProtocolPosthook::Send(RMBufChain &aPacket, CProtocolBase* aSrc)
+	/**
+	* Send packet to the next protocol.
+	*
+	* Send passes the outbound packet to the next post-processing hook
+	* (#iPostHook).
+	* The derived post-processing hook can ímplement own Send, After
+	* processing the packet, it would normally call CProtocolPosthook::Send
+	* to pass the packet forward (note that the information block is
+	* RMBufSendInfo and the attached flow context (RFlowContext)
+	* <b>must be closed</b>, if the packet is deleted):
+@code
+	TInt CProtocolDerivedHook::Send(RMBufChain &aPacket, CProtocolBase *aSrc)
+		{
+		...
+		// Do own packet processing
+
+		if (packet_is_dropped)
+			{
+			RMBufSendInfo *info = RMBufSendPacket::PeekInfoInChain(aPacket);
+			if (info)
+				info->iFlow.Close();
+			aPacket.Free();
+			return 1;
+			}
+		else
+			return CProtocolPosthook::Send(aPacket, aSrc);
+		}
+@endcode
+	* Hook will receive and pass forward the outbound packets only if
+	* it has a binding to the network layer as a post-processinghook:
+@code
+	NetworkService()->BindL(this, MIp6Hook::BindPostHook());
+@endcode
+	*
+	* @note
+	*	The network layer currently sends packets with aSrc == NULL.
+	*	This may change in future (the network instance is used
+	*	instead).
+	*
+	* If hook is configured to receive packets to Send function from some
+	* other protocol than the network layer, then it can use the aSrc to
+	* detect this and <b>NOT</B> call this default implementation for such
+	* packets (unless it intends to inject them to the outbound packet
+	* stream).
+	*
+	* Hook will receive outbound packets from the network layer only if
+	* it binds as post-processing hook.
+	*
+	* @param aPacket	The outbound packet.
+	* @param aSrc		The originating protocol (or NULL).
+	*
+	* @pre	RMBufSendPacket::PeekInfoInChain(aPacket).iFlow.IsOpen()
+	*/
+	{
+	if (iPostHook)
+		return iPostHook->Send(aPacket, aSrc);
+
+	//
+	// Nobody to forward, consume the packet
+	//
+	RMBufSendInfo *info = RMBufSendPacket::PeekInfoInChain(aPacket);
+	if (info)
+		info->iFlow.Close();
+	aPacket.Free();
+	return 1;
+	}
+
+EXPORT_C void CProtocolPosthook::Process(RMBufChain &aPacket, CProtocolBase* aSrc)
+	/**
+	* Process incoming packet.
+	*
+	* Process passes the inbound packet to the next pre-processing hook
+	* (#iInboundHook).
+	* The derived pre-processing hook can implement own Process. After processing
+	* the packet, it would normally call CProtocolPosthook::Process to pass
+	* the packet forward (note that the information block is the basic RMBufPktInfo).
+@code
+	TInt CProtocolDerivedHook::Process(RMBufChain &aPacket, CProtocolBase *aSrc)
+		{
+		// Do own packet processing.
+
+		RMBufPktInfo *info = RMBufPacketBase::PeekInfoInChain(aPacket);
+		...
+		if (packet_is_dropped)
+			aPacket.Free();
+		else
+			CProtocolPosthook::Process(aPacket, aSrc);
+		}
+@endcode
+	* Hook will receive and pass forward inbound packets only if it has
+	* bound as pre-processing hook:
+@code
+	NetworkService()->BindL(this, MIp6Hook::BindPreHook());
+@endcode
+	*
+	* @note
+	*	For inbound packets, the aSrc is the NIF object (derived from
+	*	CNifIfBase and not from CProtocolBase.).
+	* @note
+	*	The implementation <b>SHOULD NOT</b> change the aSrc. But, if it
+	*	does change the source, the new source must also be a NIF pointer,
+	*	and that NIF must also be known to the TCP/IP stack.
+	*
+	* @param aPacket	The inbound packet
+	* @param aSrc		The originating NIF
+	*/
+	{
+	if (iInboundHook)
+		iInboundHook->Process(aPacket, aSrc);
+	else
+		aPacket.Free();
+	}
+