|
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 } |