tcpiputils/dhcp/src/DHCPSess.cpp
changeset 0 af10295192d8
child 75 c1029e558ef5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcpiputils/dhcp/src/DHCPSess.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,390 @@
+// 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:
+// Implements a Session of a Symbian OS server for the RConfigDaemon API
+// 
+//
+
+/**
+ @file DHCPSess.cpp
+ @internalTechnology
+*/
+
+#include "DHCPSess.h"
+#include "DHCPIP4Control.h"
+#include "DHCPIP6Control.h"
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER
+#include "DHCPIP4ServerControl.h"
+#endif // SYMBIAN_NETWORKING_DHCPSERVER
+#include "DHCPServer.h"
+#include "DHCPDb.h"
+#ifdef SYMBIAN_NETWORKING_PLATSEC
+#include <comms-infras/rconfigdaemonmess.h>
+#else
+#include <comms-infras\cs_daemonmess.h>
+#endif
+#include "DHCP_Std.h"
+#include "NetCfgExtDhcpControl.h"
+
+CDHCPSession::~CDHCPSession()
+/**
+ *
+ * Destructor
+ *
+ * @internalTechnology
+ *
+ */
+	{
+	iDHCPIfs.ResetAndDestroy();
+
+	DHCPServer()->Close(this);
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPSession::~CDHCPSession")));
+	}
+
+CDHCPSession::CDHCPSession() :
+	iConfigType( CDHCPControl::EConfigToBeDecided )
+	{
+	}
+
+void CDHCPSession::ServiceL(const RMessage2& aMessage)
+/**
+ * Called when a message is received from NIFMAN to configure
+ * or query the connection
+ *
+ * @internalTechnology
+ * @param	aMessage	Message received from the If
+ * @leave Does not leave (As DHCP Server does not provide Error() method)
+ */
+	{
+	TRAPD(r,DoServiceL(aMessage));
+	if (r!=KErrNone)
+		{
+		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("Error: CDHCPSession::DoServiceL left with %d"), r));
+		if (!iMessage.IsNull())
+			iMessage.Complete(r);
+		}
+	}
+
+void CDHCPSession::DoServiceL(const RMessage2& aMessage)
+/**
+ * Called when a message is received from NIFMAN to configure
+ * or query the connection. We save a copy of the message so that
+ * we can complete it safely later once processing is done, note we 
+ * do not store cancel messages here - we only have one message stored
+ * at once, and each message is completed before the next is stored.
+ *
+ * @internalTechnology
+ * @param	aMessage	Message received from the If
+ * @leave KErrNotSupported or other leave code from ConfigureL, ControL or IoctlL
+ */
+	{
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPSession::ServiceL")));
+
+	switch (aMessage.Function())
+		{
+		case EConfigDaemonDeregister:
+		if ( iDHCPIfs.Count())
+			{
+			iDHCPIfs[0]->HandleClientRequestL(aMessage);
+			}
+		else
+			{
+			aMessage.Complete(KErrNone); //must be before the rest to avoid deadlock with ESOCK
+			}
+		break;
+		case EConfigDaemonConfigure:
+			ASSERT(iMessage.IsNull());
+			iMessage = aMessage;
+			ConfigureL(iMessage);
+			break;
+		case EConfigDaemonIoctl:
+			ASSERT(iMessage.IsNull());
+			iMessage = aMessage;
+			IoctlL(iMessage);
+			break;
+		case EConfigDaemonControl://control is used for internal 
+         //NetworkConfigurationExtensionDhcp <-> Dhcp server communication
+			ControlL(aMessage);
+			break;
+      	case EConfigDaemonCancel:
+			aMessage.Complete(KErrNone); //must be before the rest to avoid deadlock with ESOCK
+			for (TInt i=0 ; i < iDHCPIfs.Count() ; ++i)
+				{
+				iDHCPIfs[i]->Cancel();
+				}
+				__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPSession::Cancel completed")));
+        	break;
+		default:
+			ASSERT(iMessage.IsNull());
+			iMessage = aMessage;
+			User::Leave(KErrNotSupported);
+		}
+	}
+
+void CDHCPSession::ControlL(const RMessage2& aMessage)
+/** control is used for internal 
+ *  NetworkConfigurationExtensionDhcp <-> Dhcp server communication
+ *
+ * @internalComponent
+ * @param	aMessage	Message received from the If
+ */
+   {
+   //it could be a dynamic configuration overwriting static commDb setting
+   //in case we are to decide wheter to start with IP address acquisition or info only
+   TUint optionName = aMessage.Int1();
+   switch (optionName)
+		{
+		case KConnControlConfigureNoIPAddress:
+			iConfigType = CDHCPControl::EConfigNoIPAddress;
+			aMessage.Complete(KErrNone);
+			break;
+		case KConnControlConfigureIPAddress:
+			iConfigType = CDHCPControl::EConfigIPAddress;
+			aMessage.Complete(KErrNone);
+			break;
+		default:
+			{
+			User::Leave(KErrNotSupported);
+			}
+		};
+   }
+
+void CDHCPSession::IoctlL(const RMessage2& aMessage)
+/**
+ * Extracts data from the message to
+ * determine which CDHCPIf to query for the DHCP 
+ * server address that has configured its interface
+ *
+ * @internalComponent
+ * @leave KErrNotReady, or leave code in HandleClientRequestL
+ */
+	{
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPSession::Ioctl")));
+
+#ifdef __DHCP_HEAP_CHECK_CONTROL
+    if(aMessage.Int1() & KDhcpMemDbgIoctl & ~KConnWriteUserDataBit)
+    	{
+		HandleHeapDebug(aMessage);
+		return;
+		}
+#endif
+	if (iDHCPIfs.Count())
+		{
+		// Send messages to the first control object.
+		//  (corresponding to the first value in the IfNetworks commsdat field).
+		//
+		// This means having IfNetworks "ip,ip6" will allow the client only to call Ioctls on IP4 DHCP
+		//      .. and ..    IfNetworks "ip6,ip" will allow the client only to call Ioctls on IP6 DHCP
+		//
+		// Specifically addressing IP4 and IP6 Ioctls will require rework to the config daemon interface in nifman
+		//
+		iDHCPIfs[0]->HandleClientRequestL(aMessage);
+		}
+	else
+		{
+		User::Leave(KErrNotReady);
+		}
+	}
+	
+void CDHCPSession::HandleHeapDebug(const RMessage2& aMessage)
+/**
+  * Receives client requests for Heap Debug.
+  * 
+  * Heap Debug Ioctl messages are handled at session level. That allows debug command to be issued
+  * immediately after creation of te session.
+  * @internalTechnology
+  */
+	{
+//-- perform heap control from the client side.
+//-- Enabled for debug builds only.
+#ifdef __DHCP_HEAP_CHECK_CONTROL
+	TUint optionName = aMessage.Int1();
+	TInt length      = aMessage.Int3();
+    TInt nResult     = KErrNone;
+
+    if(optionName & KDhcpMemDbgIoctl & ~KConnWriteUserDataBit)
+    	{
+    
+        //-- the parameter should be TUint and it is a heap debug control parameter
+        //-- usually it is a counter. 
+        if(length > static_cast<TInt>(sizeof(TUint)))
+        	{
+            nResult = KErrArgument; //-- wrong parameter type
+            }
+        else
+        	{
+            //-- read IOCTL parameter
+            TDhcpMemDbgParamBuf ctlParamBuf;
+            aMessage.Read(2, ctlParamBuf);
+            TInt ctlParam = ctlParamBuf();
+
+            //-- perform IOCTL heap control functon
+            switch(optionName & ~KDhcpMemDbgIoctl)
+            	{
+                case KDHCP_DbgMarkHeap:    
+                    //-- Mark the start of heap cell checking for the current thread's heap
+                    __UHEAP_MARK;
+                    nResult = KErrNone;
+                	break; 
+
+                case KDHCP_DbgCheckHeap:   
+                    //-- Check the current number of allocated heap cells for the current thread's heap. 
+                    //-- ctlParam is the expected number of allocated cells at the current nested level 
+                    __UHEAP_CHECK(ctlParam);
+                    nResult = KErrNone;
+                	break; 
+
+                case KDHCP_DbgMarkEnd:
+                    //-- Mark the end of heap cell checking at the current nested level for the current thread's heap
+                    //-- ctlParam is the number of allocated heap cells expected.
+                    __UHEAP_MARKENDC(ctlParam);
+                    nResult = KErrNone;
+                	break; 
+
+                case KDHCP_DbgFailNext:
+                    //-- Simulate a heap allocation failure for the current thread's heap.
+                    //-- ctlParam is the rate of failure. If <= 0, reset.
+                    if(ctlParam <= 0)
+                      __UHEAP_RESET;
+                    else
+                      __UHEAP_FAILNEXT(ctlParam);
+                    nResult = KErrNone;
+                	break; 
+
+                case KDHCP_DbgFlags:
+                    //-- Simulate different error conditions in DHCP server
+					CDHCPServer::DebugFlags() = ctlParam;
+                    nResult = KErrNone;
+                	break; 
+                  
+                default:
+                    nResult = KErrArgument; //-- wrong function
+           	 	}//switch
+        	}//if(length > sizeof(TUint))
+
+        aMessage.Complete(nResult);
+    	}
+#else
+	aMessage.Complete(KErrNotSupported);
+#endif
+
+	}
+
+void CDHCPSession::ConfigureL(const RMessage2& aMessage)
+/**
+ * Starts dhcp configuration for
+ * the connection specified in the RMessage.
+ *
+ * @internalComponent
+ * @Leave KErrNoMemory If new connection object memory allocation or
+ * startup of object fails.
+ */
+	{
+	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPSession::Configure")));
+
+	if (iDHCPIfs.Count())
+		{
+		User::Leave(KErrInUse);
+		}
+	else
+		{
+		TConnectionInfoBuf configInfo;
+		aMessage.Read(0, configInfo);
+		CreateControlL(configInfo);
+
+		// if this leaves, then the client is notified by the connection
+		// start failing (presumably with KErrNoMemory), however there will
+		// be a null pointer for the state machine. No probs, we just
+		// make sure that any client ioctl requests following their
+		// failed connection attempt, start as safe by checking the state machine ptr
+		// before handling the client request
+
+		// We only care about the completion status of the first control object,
+		//  because this is the only one who can accept ioctls later.
+		//
+		// This means that with IfNetworks "ip,ip6", connection start will wait for completion of IP4 DHCP
+		//     .. and ..        IfNetworks "ip6,ip", connection start will wait for completion of IP6 DHCP
+		//
+		// It also means having IfNetworks "ip,ip6" will allow the client only to call Ioctls on IP4 DHCP
+		//        .. and ..     IfNetworks "ip6,ip" will allow the client only to call Ioctls on IP6 DHCP
+		//
+		// Specifically addressing IP4 and IP6 Ioctls will require rework to the config daemon interface in nifman
+		//
+		// So only send a message (for completion purposes) to the last control
+		//  object that we create.
+		//
+		if(iDHCPIfs.Count())
+			{
+			iDHCPIfs[0]->ConfigureL(configInfo(), &aMessage);
+			for(TInt i=1; i<iDHCPIfs.Count(); ++i)
+				{
+				iDHCPIfs[i]->ConfigureL(configInfo(), 0);
+				}
+			}
+		}
+	}
+
+void CDHCPSession::CreateControlL(const TConnectionInfoBuf& aConfigInfo)
+/**
+  * Create the control objects to handle configuration for the connection.
+  *
+  * @note In the future when IPv6 support is added, this function will have to
+  * read commDB to find out how to create control object
+  *
+  * @internalTechnology
+  */
+	{
+	CDHCPDb dhcpDb( aConfigInfo().iIapId );
+	RArray<int> families;
+	CleanupClosePushL(families);
+	dhcpDb.GetAddressFamiliesL(families);
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER	
+	TBool IsServerImpl = EFalse;	
+#endif // SYMBIAN_NETWORKING_DHCPSERVER					
+	TInt iMax=families.Count();
+	for(TInt i=0;i<iMax;++i)
+		{
+		CDHCPControl * newInst = NULL;  // assigned to null to avoid 'used before initialised' warning from smart armv5 compiler for default case switch
+		switch ( families[i] )
+			{
+			case KAfInet6:
+				newInst = new(ELeave)CDHCPIP6Control(DHCPServer()->ESock(),static_cast<CDHCPControl::TConfigType>(iConfigType));
+				break;
+			case KAfInet:
+#ifdef SYMBIAN_NETWORKING_DHCPSERVER
+				// Check if the DHCP server implementation is to be used.
+				// If CheckIfDHCPServerImplEnabledL() leaves while reading the commsdat entries,
+				// then we assume we dont require DHCP server implementation			
+				TRAPD(err, IsServerImpl = dhcpDb.CheckIfDHCPServerImplEnabledL());
+							
+				if(IsServerImpl && err == KErrNone)
+					{
+					newInst = new(ELeave)CDHCPIP4ServerControl(DHCPServer()->ESock(),static_cast<CDHCPControl::TConfigType>(iConfigType));
+					newInst->iDHCPServerImpl = ETrue;
+					}
+				else
+#endif // SYMBIAN_NETWORKING_DHCPSERVER				
+				newInst = new(ELeave)CDHCPIP4Control(DHCPServer()->ESock(),static_cast<CDHCPControl::TConfigType>(iConfigType));
+				break;
+			default:
+				__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("Unrecognised address family %d on interface. Aborting."), families[i]));
+				User::Leave( KErrNotSupported );
+			};
+		CleanupStack::PushL(newInst); // in case the array push fails
+		iDHCPIfs.AppendL(newInst); // give new object to array
+		CleanupStack::Pop(newInst); // now owned by array so remove from cleanup stack
+		}
+	families.Close();// R class objects should call close before destruction to free allocated resources
+	CleanupStack::PopAndDestroy(&families);
+	return;
+	}