tcpiputils/dhcp/src/DHCPSess.cpp
changeset 0 af10295192d8
child 75 c1029e558ef5
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Implements a Session of a Symbian OS server for the RConfigDaemon API
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file DHCPSess.cpp
       
    20  @internalTechnology
       
    21 */
       
    22 
       
    23 #include "DHCPSess.h"
       
    24 #include "DHCPIP4Control.h"
       
    25 #include "DHCPIP6Control.h"
       
    26 #ifdef SYMBIAN_NETWORKING_DHCPSERVER
       
    27 #include "DHCPIP4ServerControl.h"
       
    28 #endif // SYMBIAN_NETWORKING_DHCPSERVER
       
    29 #include "DHCPServer.h"
       
    30 #include "DHCPDb.h"
       
    31 #ifdef SYMBIAN_NETWORKING_PLATSEC
       
    32 #include <comms-infras/rconfigdaemonmess.h>
       
    33 #else
       
    34 #include <comms-infras\cs_daemonmess.h>
       
    35 #endif
       
    36 #include "DHCP_Std.h"
       
    37 #include "NetCfgExtDhcpControl.h"
       
    38 
       
    39 CDHCPSession::~CDHCPSession()
       
    40 /**
       
    41  *
       
    42  * Destructor
       
    43  *
       
    44  * @internalTechnology
       
    45  *
       
    46  */
       
    47 	{
       
    48 	iDHCPIfs.ResetAndDestroy();
       
    49 
       
    50 	DHCPServer()->Close(this);
       
    51 	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPSession::~CDHCPSession")));
       
    52 	}
       
    53 
       
    54 CDHCPSession::CDHCPSession() :
       
    55 	iConfigType( CDHCPControl::EConfigToBeDecided )
       
    56 	{
       
    57 	}
       
    58 
       
    59 void CDHCPSession::ServiceL(const RMessage2& aMessage)
       
    60 /**
       
    61  * Called when a message is received from NIFMAN to configure
       
    62  * or query the connection
       
    63  *
       
    64  * @internalTechnology
       
    65  * @param	aMessage	Message received from the If
       
    66  * @leave Does not leave (As DHCP Server does not provide Error() method)
       
    67  */
       
    68 	{
       
    69 	TRAPD(r,DoServiceL(aMessage));
       
    70 	if (r!=KErrNone)
       
    71 		{
       
    72 		__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("Error: CDHCPSession::DoServiceL left with %d"), r));
       
    73 		if (!iMessage.IsNull())
       
    74 			iMessage.Complete(r);
       
    75 		}
       
    76 	}
       
    77 
       
    78 void CDHCPSession::DoServiceL(const RMessage2& aMessage)
       
    79 /**
       
    80  * Called when a message is received from NIFMAN to configure
       
    81  * or query the connection. We save a copy of the message so that
       
    82  * we can complete it safely later once processing is done, note we 
       
    83  * do not store cancel messages here - we only have one message stored
       
    84  * at once, and each message is completed before the next is stored.
       
    85  *
       
    86  * @internalTechnology
       
    87  * @param	aMessage	Message received from the If
       
    88  * @leave KErrNotSupported or other leave code from ConfigureL, ControL or IoctlL
       
    89  */
       
    90 	{
       
    91 	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPSession::ServiceL")));
       
    92 
       
    93 	switch (aMessage.Function())
       
    94 		{
       
    95 		case EConfigDaemonDeregister:
       
    96 		if ( iDHCPIfs.Count())
       
    97 			{
       
    98 			iDHCPIfs[0]->HandleClientRequestL(aMessage);
       
    99 			}
       
   100 		else
       
   101 			{
       
   102 			aMessage.Complete(KErrNone); //must be before the rest to avoid deadlock with ESOCK
       
   103 			}
       
   104 		break;
       
   105 		case EConfigDaemonConfigure:
       
   106 			ASSERT(iMessage.IsNull());
       
   107 			iMessage = aMessage;
       
   108 			ConfigureL(iMessage);
       
   109 			break;
       
   110 		case EConfigDaemonIoctl:
       
   111 			ASSERT(iMessage.IsNull());
       
   112 			iMessage = aMessage;
       
   113 			IoctlL(iMessage);
       
   114 			break;
       
   115 		case EConfigDaemonControl://control is used for internal 
       
   116          //NetworkConfigurationExtensionDhcp <-> Dhcp server communication
       
   117 			ControlL(aMessage);
       
   118 			break;
       
   119       	case EConfigDaemonCancel:
       
   120 			aMessage.Complete(KErrNone); //must be before the rest to avoid deadlock with ESOCK
       
   121 			for (TInt i=0 ; i < iDHCPIfs.Count() ; ++i)
       
   122 				{
       
   123 				iDHCPIfs[i]->Cancel();
       
   124 				}
       
   125 				__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPSession::Cancel completed")));
       
   126         	break;
       
   127 		default:
       
   128 			ASSERT(iMessage.IsNull());
       
   129 			iMessage = aMessage;
       
   130 			User::Leave(KErrNotSupported);
       
   131 		}
       
   132 	}
       
   133 
       
   134 void CDHCPSession::ControlL(const RMessage2& aMessage)
       
   135 /** control is used for internal 
       
   136  *  NetworkConfigurationExtensionDhcp <-> Dhcp server communication
       
   137  *
       
   138  * @internalComponent
       
   139  * @param	aMessage	Message received from the If
       
   140  */
       
   141    {
       
   142    //it could be a dynamic configuration overwriting static commDb setting
       
   143    //in case we are to decide wheter to start with IP address acquisition or info only
       
   144    TUint optionName = aMessage.Int1();
       
   145    switch (optionName)
       
   146 		{
       
   147 		case KConnControlConfigureNoIPAddress:
       
   148 			iConfigType = CDHCPControl::EConfigNoIPAddress;
       
   149 			aMessage.Complete(KErrNone);
       
   150 			break;
       
   151 		case KConnControlConfigureIPAddress:
       
   152 			iConfigType = CDHCPControl::EConfigIPAddress;
       
   153 			aMessage.Complete(KErrNone);
       
   154 			break;
       
   155 		default:
       
   156 			{
       
   157 			User::Leave(KErrNotSupported);
       
   158 			}
       
   159 		};
       
   160    }
       
   161 
       
   162 void CDHCPSession::IoctlL(const RMessage2& aMessage)
       
   163 /**
       
   164  * Extracts data from the message to
       
   165  * determine which CDHCPIf to query for the DHCP 
       
   166  * server address that has configured its interface
       
   167  *
       
   168  * @internalComponent
       
   169  * @leave KErrNotReady, or leave code in HandleClientRequestL
       
   170  */
       
   171 	{
       
   172 	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPSession::Ioctl")));
       
   173 
       
   174 #ifdef __DHCP_HEAP_CHECK_CONTROL
       
   175     if(aMessage.Int1() & KDhcpMemDbgIoctl & ~KConnWriteUserDataBit)
       
   176     	{
       
   177 		HandleHeapDebug(aMessage);
       
   178 		return;
       
   179 		}
       
   180 #endif
       
   181 	if (iDHCPIfs.Count())
       
   182 		{
       
   183 		// Send messages to the first control object.
       
   184 		//  (corresponding to the first value in the IfNetworks commsdat field).
       
   185 		//
       
   186 		// This means having IfNetworks "ip,ip6" will allow the client only to call Ioctls on IP4 DHCP
       
   187 		//      .. and ..    IfNetworks "ip6,ip" will allow the client only to call Ioctls on IP6 DHCP
       
   188 		//
       
   189 		// Specifically addressing IP4 and IP6 Ioctls will require rework to the config daemon interface in nifman
       
   190 		//
       
   191 		iDHCPIfs[0]->HandleClientRequestL(aMessage);
       
   192 		}
       
   193 	else
       
   194 		{
       
   195 		User::Leave(KErrNotReady);
       
   196 		}
       
   197 	}
       
   198 	
       
   199 void CDHCPSession::HandleHeapDebug(const RMessage2& aMessage)
       
   200 /**
       
   201   * Receives client requests for Heap Debug.
       
   202   * 
       
   203   * Heap Debug Ioctl messages are handled at session level. That allows debug command to be issued
       
   204   * immediately after creation of te session.
       
   205   * @internalTechnology
       
   206   */
       
   207 	{
       
   208 //-- perform heap control from the client side.
       
   209 //-- Enabled for debug builds only.
       
   210 #ifdef __DHCP_HEAP_CHECK_CONTROL
       
   211 	TUint optionName = aMessage.Int1();
       
   212 	TInt length      = aMessage.Int3();
       
   213     TInt nResult     = KErrNone;
       
   214 
       
   215     if(optionName & KDhcpMemDbgIoctl & ~KConnWriteUserDataBit)
       
   216     	{
       
   217     
       
   218         //-- the parameter should be TUint and it is a heap debug control parameter
       
   219         //-- usually it is a counter. 
       
   220         if(length > static_cast<TInt>(sizeof(TUint)))
       
   221         	{
       
   222             nResult = KErrArgument; //-- wrong parameter type
       
   223             }
       
   224         else
       
   225         	{
       
   226             //-- read IOCTL parameter
       
   227             TDhcpMemDbgParamBuf ctlParamBuf;
       
   228             aMessage.Read(2, ctlParamBuf);
       
   229             TInt ctlParam = ctlParamBuf();
       
   230 
       
   231             //-- perform IOCTL heap control functon
       
   232             switch(optionName & ~KDhcpMemDbgIoctl)
       
   233             	{
       
   234                 case KDHCP_DbgMarkHeap:    
       
   235                     //-- Mark the start of heap cell checking for the current thread's heap
       
   236                     __UHEAP_MARK;
       
   237                     nResult = KErrNone;
       
   238                 	break; 
       
   239 
       
   240                 case KDHCP_DbgCheckHeap:   
       
   241                     //-- Check the current number of allocated heap cells for the current thread's heap. 
       
   242                     //-- ctlParam is the expected number of allocated cells at the current nested level 
       
   243                     __UHEAP_CHECK(ctlParam);
       
   244                     nResult = KErrNone;
       
   245                 	break; 
       
   246 
       
   247                 case KDHCP_DbgMarkEnd:
       
   248                     //-- Mark the end of heap cell checking at the current nested level for the current thread's heap
       
   249                     //-- ctlParam is the number of allocated heap cells expected.
       
   250                     __UHEAP_MARKENDC(ctlParam);
       
   251                     nResult = KErrNone;
       
   252                 	break; 
       
   253 
       
   254                 case KDHCP_DbgFailNext:
       
   255                     //-- Simulate a heap allocation failure for the current thread's heap.
       
   256                     //-- ctlParam is the rate of failure. If <= 0, reset.
       
   257                     if(ctlParam <= 0)
       
   258                       __UHEAP_RESET;
       
   259                     else
       
   260                       __UHEAP_FAILNEXT(ctlParam);
       
   261                     nResult = KErrNone;
       
   262                 	break; 
       
   263 
       
   264                 case KDHCP_DbgFlags:
       
   265                     //-- Simulate different error conditions in DHCP server
       
   266 					CDHCPServer::DebugFlags() = ctlParam;
       
   267                     nResult = KErrNone;
       
   268                 	break; 
       
   269                   
       
   270                 default:
       
   271                     nResult = KErrArgument; //-- wrong function
       
   272            	 	}//switch
       
   273         	}//if(length > sizeof(TUint))
       
   274 
       
   275         aMessage.Complete(nResult);
       
   276     	}
       
   277 #else
       
   278 	aMessage.Complete(KErrNotSupported);
       
   279 #endif
       
   280 
       
   281 	}
       
   282 
       
   283 void CDHCPSession::ConfigureL(const RMessage2& aMessage)
       
   284 /**
       
   285  * Starts dhcp configuration for
       
   286  * the connection specified in the RMessage.
       
   287  *
       
   288  * @internalComponent
       
   289  * @Leave KErrNoMemory If new connection object memory allocation or
       
   290  * startup of object fails.
       
   291  */
       
   292 	{
       
   293 	__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("CDHCPSession::Configure")));
       
   294 
       
   295 	if (iDHCPIfs.Count())
       
   296 		{
       
   297 		User::Leave(KErrInUse);
       
   298 		}
       
   299 	else
       
   300 		{
       
   301 		TConnectionInfoBuf configInfo;
       
   302 		aMessage.Read(0, configInfo);
       
   303 		CreateControlL(configInfo);
       
   304 
       
   305 		// if this leaves, then the client is notified by the connection
       
   306 		// start failing (presumably with KErrNoMemory), however there will
       
   307 		// be a null pointer for the state machine. No probs, we just
       
   308 		// make sure that any client ioctl requests following their
       
   309 		// failed connection attempt, start as safe by checking the state machine ptr
       
   310 		// before handling the client request
       
   311 
       
   312 		// We only care about the completion status of the first control object,
       
   313 		//  because this is the only one who can accept ioctls later.
       
   314 		//
       
   315 		// This means that with IfNetworks "ip,ip6", connection start will wait for completion of IP4 DHCP
       
   316 		//     .. and ..        IfNetworks "ip6,ip", connection start will wait for completion of IP6 DHCP
       
   317 		//
       
   318 		// It also means having IfNetworks "ip,ip6" will allow the client only to call Ioctls on IP4 DHCP
       
   319 		//        .. and ..     IfNetworks "ip6,ip" will allow the client only to call Ioctls on IP6 DHCP
       
   320 		//
       
   321 		// Specifically addressing IP4 and IP6 Ioctls will require rework to the config daemon interface in nifman
       
   322 		//
       
   323 		// So only send a message (for completion purposes) to the last control
       
   324 		//  object that we create.
       
   325 		//
       
   326 		if(iDHCPIfs.Count())
       
   327 			{
       
   328 			iDHCPIfs[0]->ConfigureL(configInfo(), &aMessage);
       
   329 			for(TInt i=1; i<iDHCPIfs.Count(); ++i)
       
   330 				{
       
   331 				iDHCPIfs[i]->ConfigureL(configInfo(), 0);
       
   332 				}
       
   333 			}
       
   334 		}
       
   335 	}
       
   336 
       
   337 void CDHCPSession::CreateControlL(const TConnectionInfoBuf& aConfigInfo)
       
   338 /**
       
   339   * Create the control objects to handle configuration for the connection.
       
   340   *
       
   341   * @note In the future when IPv6 support is added, this function will have to
       
   342   * read commDB to find out how to create control object
       
   343   *
       
   344   * @internalTechnology
       
   345   */
       
   346 	{
       
   347 	CDHCPDb dhcpDb( aConfigInfo().iIapId );
       
   348 	RArray<int> families;
       
   349 	CleanupClosePushL(families);
       
   350 	dhcpDb.GetAddressFamiliesL(families);
       
   351 #ifdef SYMBIAN_NETWORKING_DHCPSERVER	
       
   352 	TBool IsServerImpl = EFalse;	
       
   353 #endif // SYMBIAN_NETWORKING_DHCPSERVER					
       
   354 	TInt iMax=families.Count();
       
   355 	for(TInt i=0;i<iMax;++i)
       
   356 		{
       
   357 		CDHCPControl * newInst = NULL;  // assigned to null to avoid 'used before initialised' warning from smart armv5 compiler for default case switch
       
   358 		switch ( families[i] )
       
   359 			{
       
   360 			case KAfInet6:
       
   361 				newInst = new(ELeave)CDHCPIP6Control(DHCPServer()->ESock(),static_cast<CDHCPControl::TConfigType>(iConfigType));
       
   362 				break;
       
   363 			case KAfInet:
       
   364 #ifdef SYMBIAN_NETWORKING_DHCPSERVER
       
   365 				// Check if the DHCP server implementation is to be used.
       
   366 				// If CheckIfDHCPServerImplEnabledL() leaves while reading the commsdat entries,
       
   367 				// then we assume we dont require DHCP server implementation			
       
   368 				TRAPD(err, IsServerImpl = dhcpDb.CheckIfDHCPServerImplEnabledL());
       
   369 							
       
   370 				if(IsServerImpl && err == KErrNone)
       
   371 					{
       
   372 					newInst = new(ELeave)CDHCPIP4ServerControl(DHCPServer()->ESock(),static_cast<CDHCPControl::TConfigType>(iConfigType));
       
   373 					newInst->iDHCPServerImpl = ETrue;
       
   374 					}
       
   375 				else
       
   376 #endif // SYMBIAN_NETWORKING_DHCPSERVER				
       
   377 				newInst = new(ELeave)CDHCPIP4Control(DHCPServer()->ESock(),static_cast<CDHCPControl::TConfigType>(iConfigType));
       
   378 				break;
       
   379 			default:
       
   380 				__CFLOG_VAR((KLogSubSysDHCP, KLogCode, _L8("Unrecognised address family %d on interface. Aborting."), families[i]));
       
   381 				User::Leave( KErrNotSupported );
       
   382 			};
       
   383 		CleanupStack::PushL(newInst); // in case the array push fails
       
   384 		iDHCPIfs.AppendL(newInst); // give new object to array
       
   385 		CleanupStack::Pop(newInst); // now owned by array so remove from cleanup stack
       
   386 		}
       
   387 	families.Close();// R class objects should call close before destruction to free allocated resources
       
   388 	CleanupStack::PopAndDestroy(&families);
       
   389 	return;
       
   390 	}