VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/DHCPServerImpl.cpp@ 63503

Last change on this file since 63503 was 61009, checked in by vboxsync, 9 years ago

Main: big settings cleanup and writing optimization. Moved constructors/equality/default checks into the .cpp file, and write only settings which aren't at the default value. Greatly reduces the effort needed to write everything out, especially when a lot of snapshots have to be dealt with. Move the storage controllers to the hardware settings, where they always belonged. No change to the XML file (yet). Lots of settings related cleanups in the API code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.9 KB
Line 
1/* $Id: DHCPServerImpl.cpp 61009 2016-05-17 17:18:29Z vboxsync $ */
2
3/** @file
4 *
5 * VirtualBox COM class implementation
6 */
7
8/*
9 * Copyright (C) 2006-2016 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#include <string>
21#include "NetworkServiceRunner.h"
22#include "DHCPServerImpl.h"
23#include "AutoCaller.h"
24#include "Logging.h"
25
26#include <iprt/cpp/utils.h>
27
28#include <VBox/com/array.h>
29#include <VBox/settings.h>
30
31#include "VirtualBoxImpl.h"
32
33// constructor / destructor
34/////////////////////////////////////////////////////////////////////////////
35const std::string DHCPServerRunner::kDsrKeyGateway = "--gateway";
36const std::string DHCPServerRunner::kDsrKeyLowerIp = "--lower-ip";
37const std::string DHCPServerRunner::kDsrKeyUpperIp = "--upper-ip";
38
39
40struct DHCPServer::Data
41{
42 Data()
43 : enabled(FALSE)
44 , router(false)
45 {}
46
47 Bstr IPAddress;
48 Bstr lowerIP;
49 Bstr upperIP;
50
51 BOOL enabled;
52 bool router;
53 DHCPServerRunner dhcp;
54
55 settings::DhcpOptionMap GlobalDhcpOptions;
56 settings::VmSlot2OptionsMap VmSlot2Options;
57};
58
59
60DHCPServer::DHCPServer()
61 : m(NULL)
62 , mVirtualBox(NULL)
63{
64 m = new DHCPServer::Data();
65}
66
67
68DHCPServer::~DHCPServer()
69{
70 if (m)
71 {
72 delete m;
73 m = NULL;
74 }
75}
76
77
78HRESULT DHCPServer::FinalConstruct()
79{
80 return BaseFinalConstruct();
81}
82
83
84void DHCPServer::FinalRelease()
85{
86 uninit ();
87
88 BaseFinalRelease();
89}
90
91
92void DHCPServer::uninit()
93{
94 /* Enclose the state transition Ready->InUninit->NotReady */
95 AutoUninitSpan autoUninitSpan(this);
96 if (autoUninitSpan.uninitDone())
97 return;
98
99 unconst(mVirtualBox) = NULL;
100}
101
102
103HRESULT DHCPServer::init(VirtualBox *aVirtualBox, IN_BSTR aName)
104{
105 AssertReturn(aName != NULL, E_INVALIDARG);
106
107 AutoInitSpan autoInitSpan(this);
108 AssertReturn(autoInitSpan.isOk(), E_FAIL);
109
110 /* share VirtualBox weakly (parent remains NULL so far) */
111 unconst(mVirtualBox) = aVirtualBox;
112
113 unconst(mName) = aName;
114 m->IPAddress = "0.0.0.0";
115 m->GlobalDhcpOptions[DhcpOpt_SubnetMask] = settings::DhcpOptValue("0.0.0.0");
116 m->enabled = FALSE;
117
118 m->lowerIP = "0.0.0.0";
119 m->upperIP = "0.0.0.0";
120
121 /* Confirm a successful initialization */
122 autoInitSpan.setSucceeded();
123
124 return S_OK;
125}
126
127
128HRESULT DHCPServer::init(VirtualBox *aVirtualBox,
129 const settings::DHCPServer &data)
130{
131 /* Enclose the state transition NotReady->InInit->Ready */
132 AutoInitSpan autoInitSpan(this);
133 AssertReturn(autoInitSpan.isOk(), E_FAIL);
134
135 /* share VirtualBox weakly (parent remains NULL so far) */
136 unconst(mVirtualBox) = aVirtualBox;
137
138 unconst(mName) = data.strNetworkName;
139 m->IPAddress = data.strIPAddress;
140 m->enabled = data.fEnabled;
141 m->lowerIP = data.strIPLower;
142 m->upperIP = data.strIPUpper;
143
144 m->GlobalDhcpOptions.clear();
145 m->GlobalDhcpOptions.insert(data.GlobalDhcpOptions.begin(),
146 data.GlobalDhcpOptions.end());
147
148 m->VmSlot2Options.clear();
149 m->VmSlot2Options.insert(data.VmSlot2OptionsM.begin(),
150 data.VmSlot2OptionsM.end());
151
152 autoInitSpan.setSucceeded();
153
154 return S_OK;
155}
156
157
158HRESULT DHCPServer::i_saveSettings(settings::DHCPServer &data)
159{
160 AutoCaller autoCaller(this);
161 if (FAILED(autoCaller.rc())) return autoCaller.rc();
162
163 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
164
165 data.strNetworkName = mName;
166 data.strIPAddress = m->IPAddress;
167
168 data.fEnabled = !!m->enabled;
169 data.strIPLower = m->lowerIP;
170 data.strIPUpper = m->upperIP;
171
172 data.GlobalDhcpOptions.clear();
173 data.GlobalDhcpOptions.insert(m->GlobalDhcpOptions.begin(),
174 m->GlobalDhcpOptions.end());
175
176 data.VmSlot2OptionsM.clear();
177 data.VmSlot2OptionsM.insert(m->VmSlot2Options.begin(),
178 m->VmSlot2Options.end());
179
180 return S_OK;
181}
182
183
184HRESULT DHCPServer::getNetworkName(com::Utf8Str &aName)
185{
186 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
187
188 aName = mName;
189 return S_OK;
190}
191
192
193HRESULT DHCPServer::getEnabled(BOOL *aEnabled)
194{
195 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
196
197 *aEnabled = m->enabled;
198 return S_OK;
199}
200
201
202HRESULT DHCPServer::setEnabled(BOOL aEnabled)
203{
204 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
205 m->enabled = aEnabled;
206
207 // save the global settings; for that we should hold only the VirtualBox lock
208 alock.release();
209 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
210 HRESULT rc = mVirtualBox->i_saveSettings();
211
212 return rc;
213}
214
215
216HRESULT DHCPServer::getIPAddress(com::Utf8Str &aIPAddress)
217{
218 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
219
220 aIPAddress = Utf8Str(m->IPAddress);
221 return S_OK;
222}
223
224
225HRESULT DHCPServer::getNetworkMask(com::Utf8Str &aNetworkMask)
226{
227 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
228
229 aNetworkMask = m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text;
230 return S_OK;
231}
232
233
234HRESULT DHCPServer::getLowerIP(com::Utf8Str &aIPAddress)
235{
236 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
237
238 aIPAddress = Utf8Str(m->lowerIP);
239 return S_OK;
240}
241
242
243HRESULT DHCPServer::getUpperIP(com::Utf8Str &aIPAddress)
244{
245 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
246
247 aIPAddress = Utf8Str(m->upperIP);
248 return S_OK;
249}
250
251
252HRESULT DHCPServer::setConfiguration(const com::Utf8Str &aIPAddress,
253 const com::Utf8Str &aNetworkMask,
254 const com::Utf8Str &aLowerIP,
255 const com::Utf8Str &aUpperIP)
256{
257 AssertReturn(!aIPAddress.isEmpty(), E_INVALIDARG);
258 AssertReturn(!aNetworkMask.isEmpty(), E_INVALIDARG);
259 AssertReturn(!aLowerIP.isEmpty(), E_INVALIDARG);
260 AssertReturn(!aUpperIP.isEmpty(), E_INVALIDARG);
261
262 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
263 m->IPAddress = aIPAddress;
264 m->GlobalDhcpOptions[DhcpOpt_SubnetMask] = aNetworkMask;
265
266 m->lowerIP = aLowerIP;
267 m->upperIP = aUpperIP;
268
269 // save the global settings; for that we should hold only the VirtualBox lock
270 alock.release();
271 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
272 return mVirtualBox->i_saveSettings();
273}
274
275
276HRESULT DHCPServer::encodeOption(com::Utf8Str &aEncoded,
277 uint32_t aOptCode,
278 const settings::DhcpOptValue &aOptValue)
279{
280 switch (aOptValue.encoding)
281 {
282 case DhcpOptEncoding_Legacy:
283 {
284 /*
285 * This is original encoding which assumed that for each
286 * option we know its format and so we know how option
287 * "value" text is to be interpreted.
288 *
289 * "2:10800" # integer 32
290 * "6:1.2.3.4 8.8.8.8" # array of ip-address
291 */
292 aEncoded = Utf8StrFmt("%d:%s", aOptCode, aOptValue.text.c_str());
293 break;
294 }
295
296 case DhcpOptEncoding_Hex:
297 {
298 /*
299 * This is a bypass for any option - preformatted value as
300 * hex string with no semantic involved in formatting the
301 * value for the DHCP reply.
302 *
303 * 234=68:65:6c:6c:6f:2c:20:77:6f:72:6c:64
304 */
305 aEncoded = Utf8StrFmt("%d=%s", aOptCode, aOptValue.text.c_str());
306 break;
307 }
308
309 default:
310 {
311 /*
312 * Try to be forward compatible.
313 *
314 * "254@42=i hope you know what this means"
315 */
316 aEncoded = Utf8StrFmt("%d@%d=%s", aOptCode, (int)aOptValue.encoding,
317 aOptValue.text.c_str());
318 break;
319 }
320 }
321
322 return S_OK;
323}
324
325
326int DHCPServer::addOption(settings::DhcpOptionMap &aMap,
327 DhcpOpt_T aOption, const com::Utf8Str &aValue)
328{
329 settings::DhcpOptValue OptValue;
330
331 if (aOption != 0)
332 {
333 OptValue = settings::DhcpOptValue(aValue, DhcpOptEncoding_Legacy);
334 }
335 /*
336 * This is a kludge to sneak in option encoding information
337 * through existing API. We use option 0 and supply the real
338 * option/value in the same format that encodeOption() above
339 * produces for getter methods.
340 */
341 else
342 {
343 uint8_t u8Code;
344 uint32_t u32Enc;
345 char *pszNext;
346 int rc;
347
348 rc = RTStrToUInt8Ex(aValue.c_str(), &pszNext, 10, &u8Code);
349 if (!RT_SUCCESS(rc))
350 return VERR_PARSE_ERROR;
351
352 switch (*pszNext)
353 {
354 case ':': /* support legacy format too */
355 {
356 u32Enc = DhcpOptEncoding_Legacy;
357 break;
358 }
359
360 case '=':
361 {
362 u32Enc = DhcpOptEncoding_Hex;
363 break;
364 }
365
366 case '@':
367 {
368 rc = RTStrToUInt32Ex(pszNext + 1, &pszNext, 10, &u32Enc);
369 if (!RT_SUCCESS(rc))
370 return VERR_PARSE_ERROR;
371 if (*pszNext != '=')
372 return VERR_PARSE_ERROR;
373 break;
374 }
375
376 default:
377 return VERR_PARSE_ERROR;
378 }
379
380 aOption = (DhcpOpt_T)u8Code;
381 OptValue = settings::DhcpOptValue(pszNext + 1, (DhcpOptEncoding_T)u32Enc);
382 }
383
384 aMap[aOption] = OptValue;
385 return VINF_SUCCESS;
386}
387
388
389HRESULT DHCPServer::addGlobalOption(DhcpOpt_T aOption, const com::Utf8Str &aValue)
390{
391 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
392
393 int rc = addOption(m->GlobalDhcpOptions, aOption, aValue);
394 if (!RT_SUCCESS(rc))
395 return E_INVALIDARG;
396
397 /* Indirect way to understand that we're on NAT network */
398 if (aOption == DhcpOpt_Router)
399 {
400 m->dhcp.setOption(NetworkServiceRunner::kNsrKeyNeedMain, "on");
401 m->router = true;
402 }
403
404 alock.release();
405
406 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
407 return mVirtualBox->i_saveSettings();
408}
409
410
411HRESULT DHCPServer::getGlobalOptions(std::vector<com::Utf8Str> &aValues)
412{
413 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
414 aValues.resize(m->GlobalDhcpOptions.size());
415 settings::DhcpOptionMap::const_iterator it;
416 size_t i = 0;
417 for (it = m->GlobalDhcpOptions.begin(); it != m->GlobalDhcpOptions.end(); ++it, ++i)
418 {
419 uint32_t OptCode = (*it).first;
420 const settings::DhcpOptValue &OptValue = (*it).second;
421
422 encodeOption(aValues[i], OptCode, OptValue);
423 }
424
425 return S_OK;
426}
427
428HRESULT DHCPServer::getVmConfigs(std::vector<com::Utf8Str> &aValues)
429{
430 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
431 aValues.resize(m->VmSlot2Options.size());
432 settings::VmSlot2OptionsMap::const_iterator it;
433 size_t i = 0;
434 for (it = m->VmSlot2Options.begin(); it != m->VmSlot2Options.end(); ++it, ++i)
435 {
436 aValues[i] = Utf8StrFmt("[%s]:%d", it->first.VmName.c_str(), it->first.Slot);
437 }
438
439 return S_OK;
440}
441
442
443HRESULT DHCPServer::addVmSlotOption(const com::Utf8Str &aVmName,
444 LONG aSlot,
445 DhcpOpt_T aOption,
446 const com::Utf8Str &aValue)
447{
448 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
449
450 settings::DhcpOptionMap &map = m->VmSlot2Options[settings::VmNameSlotKey(aVmName, aSlot)];
451 int rc = addOption(map, aOption, aValue);
452 if (!RT_SUCCESS(rc))
453 return E_INVALIDARG;
454
455 alock.release();
456
457 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
458 return mVirtualBox->i_saveSettings();
459}
460
461
462HRESULT DHCPServer::removeVmSlotOptions(const com::Utf8Str &aVmName, LONG aSlot)
463{
464 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
465 settings::DhcpOptionMap &map = i_findOptMapByVmNameSlot(aVmName, aSlot);
466 map.clear();
467
468 alock.release();
469
470 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
471 return mVirtualBox->i_saveSettings();
472}
473
474/**
475 * this is mapping (vm, slot)
476 */
477HRESULT DHCPServer::getVmSlotOptions(const com::Utf8Str &aVmName,
478 LONG aSlot,
479 std::vector<com::Utf8Str> &aValues)
480{
481
482 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
483 settings::DhcpOptionMap &map = i_findOptMapByVmNameSlot(aVmName, aSlot);
484 aValues.resize(map.size());
485 size_t i = 0;
486 settings::DhcpOptionMap::const_iterator it;
487 for (it = map.begin(); it != map.end(); ++it, ++i)
488 {
489 uint32_t OptCode = (*it).first;
490 const settings::DhcpOptValue &OptValue = (*it).second;
491
492 encodeOption(aValues[i], OptCode, OptValue);
493 }
494
495 return S_OK;
496}
497
498
499HRESULT DHCPServer::getMacOptions(const com::Utf8Str &aMAC, std::vector<com::Utf8Str> &aOption)
500{
501 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
502 HRESULT hrc = S_OK;
503 ComPtr<IMachine> machine;
504 ComPtr<INetworkAdapter> nic;
505 settings::VmSlot2OptionsIterator it;
506 for(it = m->VmSlot2Options.begin(); it != m->VmSlot2Options.end(); ++it)
507 {
508 alock.release();
509 hrc = mVirtualBox->FindMachine(Bstr(it->first.VmName).raw(), machine.asOutParam());
510 alock.acquire();
511
512 if (FAILED(hrc))
513 continue;
514
515 alock.release();
516 hrc = machine->GetNetworkAdapter(it->first.Slot, nic.asOutParam());
517 alock.acquire();
518
519 if (FAILED(hrc))
520 continue;
521
522 com::Bstr mac;
523
524 alock.release();
525 hrc = nic->COMGETTER(MACAddress)(mac.asOutParam());
526 alock.acquire();
527
528 if (FAILED(hrc)) /* no MAC address ??? */
529 break;
530 if (!RTStrICmp(com::Utf8Str(mac).c_str(), aMAC.c_str()))
531 return getVmSlotOptions(it->first.VmName,
532 it->first.Slot,
533 aOption);
534 } /* end of for */
535
536 return hrc;
537}
538
539HRESULT DHCPServer::getEventSource(ComPtr<IEventSource> &aEventSource)
540{
541 NOREF(aEventSource);
542 ReturnComNotImplemented();
543}
544
545
546HRESULT DHCPServer::start(const com::Utf8Str &aNetworkName,
547 const com::Utf8Str &aTrunkName,
548 const com::Utf8Str &aTrunkType)
549{
550 /* Silently ignore attempts to run disabled servers. */
551 if (!m->enabled)
552 return S_OK;
553
554 /* Commmon Network Settings */
555 m->dhcp.setOption(NetworkServiceRunner::kNsrKeyNetwork, aNetworkName.c_str());
556
557 if (!aTrunkName.isEmpty())
558 m->dhcp.setOption(NetworkServiceRunner::kNsrTrunkName, aTrunkName.c_str());
559
560 m->dhcp.setOption(NetworkServiceRunner::kNsrKeyTrunkType, aTrunkType.c_str());
561
562 /* XXX: should this MAC default initialization moved to NetworkServiceRunner? */
563 char strMAC[32];
564 Guid guid;
565 guid.create();
566 RTStrPrintf (strMAC, sizeof(strMAC), "08:00:27:%02X:%02X:%02X",
567 guid.raw()->au8[0],
568 guid.raw()->au8[1],
569 guid.raw()->au8[2]);
570 m->dhcp.setOption(NetworkServiceRunner::kNsrMacAddress, strMAC);
571 m->dhcp.setOption(NetworkServiceRunner::kNsrIpAddress, Utf8Str(m->IPAddress).c_str());
572 m->dhcp.setOption(NetworkServiceRunner::kNsrIpNetmask, Utf8Str(m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text).c_str());
573 m->dhcp.setOption(DHCPServerRunner::kDsrKeyLowerIp, Utf8Str(m->lowerIP).c_str());
574 m->dhcp.setOption(DHCPServerRunner::kDsrKeyUpperIp, Utf8Str(m->upperIP).c_str());
575
576 /* XXX: This parameters Dhcp Server will fetch via API */
577 return RT_FAILURE(m->dhcp.start(!m->router /* KillProcOnExit */)) ? E_FAIL : S_OK;
578 //m->dhcp.detachFromServer(); /* need to do this to avoid server shutdown on runner destruction */
579}
580
581
582HRESULT DHCPServer::stop (void)
583{
584 return RT_FAILURE(m->dhcp.stop()) ? E_FAIL : S_OK;
585}
586
587
588settings::DhcpOptionMap &DHCPServer::i_findOptMapByVmNameSlot(const com::Utf8Str &aVmName,
589 LONG aSlot)
590{
591 return m->VmSlot2Options[settings::VmNameSlotKey(aVmName, aSlot)];
592}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette