diff -r 000000000000 -r af10295192d8 tcpiputils/dhcp/src/DHCPSess.cpp --- /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 +#else +#include +#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(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; iConfigureL(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 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;iESock(),static_cast(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(iConfigType)); + newInst->iDHCPServerImpl = ETrue; + } + else +#endif // SYMBIAN_NETWORKING_DHCPSERVER + newInst = new(ELeave)CDHCPIP4Control(DHCPServer()->ESock(),static_cast(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; + }