VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/DHCPConfigImpl.cpp@ 94722

Last change on this file since 94722 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.3 KB
Line 
1/* $Id: DHCPConfigImpl.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VirtualBox Main - IDHCPConfig, IDHCPConfigGlobal, IDHCPConfigGroup, IDHCPConfigIndividual implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_MAIN_DHCPCONFIG
23#include "DHCPConfigImpl.h"
24#include "LoggingNew.h"
25
26#include <iprt/ctype.h>
27#include <iprt/errcore.h>
28#include <iprt/net.h>
29#include <iprt/cpp/utils.h>
30#include <iprt/cpp/xml.h>
31
32#include <VBox/com/array.h>
33#include <VBox/settings.h>
34
35#include "AutoCaller.h"
36#include "DHCPServerImpl.h"
37#include "MachineImpl.h"
38#include "VirtualBoxImpl.h"
39
40#include "../../NetworkServices/Dhcpd/DhcpOptions.h"
41
42
43
44/*********************************************************************************************************************************
45* DHCPConfig Implementation *
46*********************************************************************************************************************************/
47
48HRESULT DHCPConfig::i_initWithDefaults(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent)
49{
50 unconst(m_pVirtualBox) = a_pVirtualBox;
51 unconst(m_pParent) = a_pParent;
52 return S_OK;
53}
54
55
56HRESULT DHCPConfig::i_initWithSettings(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, const settings::DHCPConfig &rConfig)
57{
58 unconst(m_pVirtualBox) = a_pVirtualBox;
59 unconst(m_pParent) = a_pParent;
60
61 m_secMinLeaseTime = rConfig.secMinLeaseTime;
62 m_secDefaultLeaseTime = rConfig.secDefaultLeaseTime;
63 m_secMaxLeaseTime = rConfig.secMaxLeaseTime;
64
65 /*
66 * The two option list:
67 */
68 struct
69 {
70 const char *psz;
71 std::vector<DHCPOption_T> *pDst;
72 } aStr2Vec[] =
73 {
74 { rConfig.strForcedOptions.c_str(), &m_vecForcedOptions },
75 { rConfig.strSuppressedOptions.c_str(), &m_vecSuppressedOptions },
76 };
77 for (size_t i = 0; i < RT_ELEMENTS(aStr2Vec); i++)
78 {
79 Assert(aStr2Vec[i].pDst->size() == 0);
80 const char *psz = RTStrStripL(aStr2Vec[i].psz);
81 while (*psz != '\0')
82 {
83 uint8_t bOpt;
84 char *pszNext;
85 int vrc = RTStrToUInt8Ex(psz, &pszNext, 10, &bOpt);
86 if ( vrc == VINF_SUCCESS
87 || vrc == VWRN_TRAILING_SPACES
88 || vrc == VWRN_TRAILING_CHARS)
89 {
90 try
91 {
92 aStr2Vec[i].pDst->push_back((DHCPOption_T)bOpt);
93 }
94 catch (std::bad_alloc &)
95 {
96 return E_OUTOFMEMORY;
97 }
98 }
99 else
100 {
101 LogRelFunc(("Trouble at offset %#zu converting '%s' to a DHCPOption_T vector (vrc=%Rrc)! Ignornig the remainder.\n",
102 psz - aStr2Vec[i].psz, aStr2Vec[i].psz, vrc));
103 break;
104 }
105 psz = RTStrStripL(pszNext);
106 }
107 }
108
109 /*
110 * The option map:
111 */
112 for (settings::DhcpOptionMap::const_iterator it = rConfig.mapOptions.begin(); it != rConfig.mapOptions.end(); ++it)
113 {
114 try
115 {
116 m_OptionMap[it->first] = settings::DhcpOptValue(it->second.strValue, it->second.enmEncoding);
117 }
118 catch (std::bad_alloc &)
119 {
120 return E_OUTOFMEMORY;
121 }
122 }
123
124 return S_OK;
125}
126
127
128HRESULT DHCPConfig::i_saveSettings(settings::DHCPConfig &a_rDst)
129{
130 /* lease times */
131 a_rDst.secMinLeaseTime = m_secMinLeaseTime;
132 a_rDst.secDefaultLeaseTime = m_secDefaultLeaseTime;
133 a_rDst.secMaxLeaseTime = m_secMaxLeaseTime;
134
135 /* Forced and suppressed vectors: */
136 try
137 {
138 a_rDst.strForcedOptions.setNull();
139 for (size_t i = 0; i < m_vecForcedOptions.size(); i++)
140 a_rDst.strForcedOptions.appendPrintf(i ? " %d" : "%d", m_vecForcedOptions[i]);
141
142 a_rDst.strSuppressedOptions.setNull();
143 for (size_t i = 0; i < m_vecSuppressedOptions.size(); i++)
144 a_rDst.strSuppressedOptions.appendPrintf(i ? " %d" : "%d", m_vecSuppressedOptions[i]);
145 }
146 catch (std::bad_alloc &)
147 {
148 return E_OUTOFMEMORY;
149 }
150
151
152 /* Options: */
153 try
154 {
155 a_rDst.mapOptions = m_OptionMap;
156 }
157 catch (std::bad_alloc &)
158 {
159 return E_OUTOFMEMORY;
160 }
161 return S_OK;
162}
163
164
165HRESULT DHCPConfig::i_getScope(DHCPConfigScope_T *aScope)
166{
167 /* No locking needed. */
168 *aScope = m_enmScope;
169 return S_OK;
170}
171
172
173HRESULT DHCPConfig::i_getMinLeaseTime(ULONG *aMinLeaseTime)
174{
175 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
176 *aMinLeaseTime = m_secMinLeaseTime;
177 return S_OK;
178}
179
180
181HRESULT DHCPConfig::i_setMinLeaseTime(ULONG aMinLeaseTime)
182{
183 {
184 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
185 m_secMinLeaseTime = aMinLeaseTime;
186 }
187 return i_doWriteConfig();
188}
189
190
191HRESULT DHCPConfig::i_getDefaultLeaseTime(ULONG *aDefaultLeaseTime)
192{
193 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
194 *aDefaultLeaseTime = m_secDefaultLeaseTime;
195 return S_OK;
196}
197
198
199HRESULT DHCPConfig::i_setDefaultLeaseTime(ULONG aDefaultLeaseTime)
200{
201 {
202 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
203 m_secDefaultLeaseTime = aDefaultLeaseTime;
204 }
205 return i_doWriteConfig();
206}
207
208
209HRESULT DHCPConfig::i_getMaxLeaseTime(ULONG *aMaxLeaseTime)
210{
211 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
212 *aMaxLeaseTime = m_secMaxLeaseTime;
213 return S_OK;
214}
215
216
217HRESULT DHCPConfig::i_setMaxLeaseTime(ULONG aMaxLeaseTime)
218{
219 {
220 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
221 m_secMaxLeaseTime = aMaxLeaseTime;
222 }
223 return i_doWriteConfig();
224}
225
226
227HRESULT DHCPConfig::i_getForcedOptions(std::vector<DHCPOption_T> &aOptions)
228{
229 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
230 try
231 {
232 aOptions = m_vecForcedOptions;
233 }
234 catch (std::bad_alloc &)
235 {
236 return E_OUTOFMEMORY;
237 }
238 return S_OK;
239}
240
241
242HRESULT DHCPConfig::i_setForcedOptions(const std::vector<DHCPOption_T> &aOptions)
243{
244 /*
245 * Validate the options.
246 */
247 try
248 {
249 std::map<DHCPOption_T, bool> mapDuplicates;
250 for (size_t i = 0; i < aOptions.size(); i++)
251 {
252 DHCPOption_T enmOpt = aOptions[i];
253 if ((int)enmOpt > 0 && (int)enmOpt < 255)
254 {
255 if (mapDuplicates.find(enmOpt) == mapDuplicates.end())
256 mapDuplicates[enmOpt] = true;
257 else
258 return m_pHack->setError(E_INVALIDARG, tr("Duplicate option value: %d"), (int)enmOpt);
259 }
260 else
261 return m_pHack->setError(E_INVALIDARG, tr("Invalid option value: %d"), (int)enmOpt);
262 }
263 }
264 catch (std::bad_alloc &)
265 {
266 return E_OUTOFMEMORY;
267 }
268
269 /*
270 * Do the updating.
271 */
272 {
273 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
274
275 /* Actually changed? */
276 if (m_vecForcedOptions.size() == aOptions.size())
277 {
278 ssize_t i = (ssize_t)m_vecForcedOptions.size();
279 while (i-- > 0)
280 if (m_vecForcedOptions[(size_t)i] != aOptions[(size_t)i])
281 break;
282 if (i < 0)
283 return S_OK;
284 }
285
286 /* Copy over the changes: */
287 try
288 {
289 m_vecForcedOptions = aOptions;
290 }
291 catch (std::bad_alloc &)
292 {
293 return E_OUTOFMEMORY;
294 }
295 }
296
297 return i_doWriteConfig();
298}
299
300
301HRESULT DHCPConfig::i_getSuppressedOptions(std::vector<DHCPOption_T> &aOptions)
302{
303 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
304 try
305 {
306 aOptions = m_vecSuppressedOptions;
307 }
308 catch (std::bad_alloc &)
309 {
310 return E_OUTOFMEMORY;
311 }
312 return S_OK;
313}
314
315
316HRESULT DHCPConfig::i_setSuppressedOptions(const std::vector<DHCPOption_T> &aOptions)
317{
318 /*
319 * Validate and normalize it.
320 */
321 std::map<DHCPOption_T, bool> mapNormalized;
322 try
323 {
324 for (size_t i = 0; i < aOptions.size(); i++)
325 {
326 DHCPOption_T enmOpt = aOptions[i];
327 if ((int)enmOpt > 0 && (int)enmOpt < 255)
328 mapNormalized[enmOpt] = true;
329 else
330 return m_pHack->setError(E_INVALIDARG, tr("Invalid option value: %d"), (int)enmOpt);
331 }
332 }
333 catch (std::bad_alloc &)
334 {
335 return E_OUTOFMEMORY;
336 }
337
338 /*
339 * Do the updating.
340 */
341 {
342 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
343
344 /* Actually changed? */
345 if (m_vecSuppressedOptions.size() == mapNormalized.size())
346 {
347 size_t i = 0;
348 for (std::map<DHCPOption_T, bool>::const_iterator itMap = mapNormalized.begin();; ++itMap, i++)
349 {
350 if (itMap == mapNormalized.end())
351 return S_OK; /* no change */
352 if (itMap->first != m_vecSuppressedOptions[i])
353 break;
354 }
355 }
356
357 /* Copy over the changes: */
358 try
359 {
360 m_vecSuppressedOptions.resize(mapNormalized.size());
361 size_t i = 0;
362 for (std::map<DHCPOption_T, bool>::const_iterator itMap = mapNormalized.begin();
363 itMap != mapNormalized.end(); ++itMap, i++)
364 m_vecSuppressedOptions[i] = itMap->first;
365 }
366 catch (std::bad_alloc &)
367 {
368 return E_OUTOFMEMORY;
369 }
370 }
371
372 return i_doWriteConfig();
373}
374
375
376HRESULT DHCPConfig::i_setOption(DHCPOption_T aOption, DHCPOptionEncoding_T aEncoding, const com::Utf8Str &aValue)
377{
378 /*
379 * Validate the option as there is no point in allowing the user to set
380 * something that the DHCP server does not grok. It will only lead to
381 * startup failures an no DHCP. We share this code with the server.
382 */
383 DhcpOption *pParsed = NULL;
384 int rc = VINF_SUCCESS;
385 try
386 {
387 pParsed = DhcpOption::parse((uint8_t)aOption, aEncoding, aValue.c_str(), &rc);
388 }
389 catch (std::bad_alloc &)
390 {
391 return E_OUTOFMEMORY;
392 }
393 if (pParsed)
394 {
395 delete pParsed;
396
397 /*
398 * Add/change it.
399 */
400 {
401 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
402 try
403 {
404 m_OptionMap[aOption] = settings::DhcpOptValue(aValue, aEncoding);
405 }
406 catch (std::bad_alloc &)
407 {
408 return E_OUTOFMEMORY;
409 }
410 }
411 i_doWriteConfig();
412 return S_OK;
413 }
414
415 if (rc == VERR_WRONG_TYPE)
416 return m_pHack->setError(E_INVALIDARG, tr("Unsupported encoding %d (option %d, value %s)"),
417 (int)aEncoding, (int)aOption, aValue.c_str());
418 if (rc == VERR_NOT_SUPPORTED)
419 return m_pHack->setError(E_INVALIDARG, tr("Unsupported option %d (encoding %d, value %s)"),
420 (int)aOption, (int)aEncoding, aValue.c_str());
421 return m_pHack->setError(E_INVALIDARG, tr("Malformed option %d value '%s' (encoding %d, rc=%Rrc)"),
422 (int)aOption, aValue.c_str(), (int)aEncoding, rc);
423}
424
425
426HRESULT DHCPConfig::i_removeOption(DHCPOption_T aOption)
427{
428 {
429 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
430 settings::DhcpOptionMap::iterator it = m_OptionMap.find(aOption);
431 if (it != m_OptionMap.end())
432 m_OptionMap.erase(it);
433 else
434 return m_pHack->setError(VBOX_E_OBJECT_NOT_FOUND, tr("DHCP option %u was not found"), aOption);
435 }
436 return i_doWriteConfig();
437}
438
439
440HRESULT DHCPConfig::i_removeAllOptions()
441{
442 {
443 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
444 m_OptionMap.erase(m_OptionMap.begin(), m_OptionMap.end());
445 }
446 return i_doWriteConfig();
447}
448
449
450HRESULT DHCPConfig::i_getOption(DHCPOption_T aOption, DHCPOptionEncoding_T *aEncoding, com::Utf8Str &aValue)
451{
452 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
453 settings::DhcpOptionMap::const_iterator it = m_OptionMap.find(aOption);
454 if (it != m_OptionMap.end())
455 {
456 *aEncoding = it->second.enmEncoding;
457 return aValue.assignEx(it->second.strValue);
458 }
459 return m_pHack->setError(VBOX_E_OBJECT_NOT_FOUND, tr("DHCP option %u was not found"), aOption);
460}
461
462
463HRESULT DHCPConfig::i_getAllOptions(std::vector<DHCPOption_T> &aOptions, std::vector<DHCPOptionEncoding_T> &aEncodings,
464 std::vector<com::Utf8Str> &aValues)
465{
466 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
467 try
468 {
469 aOptions.resize(m_OptionMap.size());
470 aEncodings.resize(m_OptionMap.size());
471 aValues.resize(m_OptionMap.size());
472 size_t i = 0;
473 for (settings::DhcpOptionMap::iterator it = m_OptionMap.begin(); it != m_OptionMap.end(); ++it, i++)
474 {
475 aOptions[i] = it->first;
476 aEncodings[i] = it->second.enmEncoding;
477 aValues[i] = it->second.strValue;
478 }
479 }
480 catch (std::bad_alloc &)
481 {
482 return E_OUTOFMEMORY;
483 }
484 return S_OK;
485}
486
487
488HRESULT DHCPConfig::i_remove()
489{
490 return m_pParent->i_removeConfig(this, m_enmScope);
491}
492
493
494
495/**
496 * Causes the global VirtualBox configuration file to be written
497 *
498 * @returns COM status code.
499 *
500 * @note Must hold no locks when this is called!
501 * @note Public because DHCPGroupCondition needs to call it too.
502 */
503HRESULT DHCPConfig::i_doWriteConfig()
504{
505 AssertPtrReturn(m_pVirtualBox, E_FAIL);
506
507 AutoWriteLock alock(m_pVirtualBox COMMA_LOCKVAL_SRC_POS);
508 return m_pVirtualBox->i_saveSettings();
509}
510
511
512/**
513 * Produces the Dhcpd configuration.
514 *
515 * The base class only saves DHCP options.
516 *
517 * @param pElmConfig The element where to put the configuration.
518 * @throws std::bad_alloc
519 */
520void DHCPConfig::i_writeDhcpdConfig(xml::ElementNode *pElmConfig)
521{
522 if (m_secMinLeaseTime > 0 )
523 pElmConfig->setAttribute("secMinLeaseTime", (uint32_t)m_secMinLeaseTime);
524 if (m_secDefaultLeaseTime > 0 )
525 pElmConfig->setAttribute("secDefaultLeaseTime", (uint32_t)m_secDefaultLeaseTime);
526 if (m_secMaxLeaseTime > 0 )
527 pElmConfig->setAttribute("secMaxLeaseTime", (uint32_t)m_secMaxLeaseTime);
528
529 struct
530 {
531 const char *pszElement;
532 std::vector<DHCPOption_T> *pVec;
533 } aVec2Elm[] = { { "ForcedOption", &m_vecForcedOptions }, { "SuppressedOption", &m_vecSuppressedOptions }, };
534 for (size_t i = 0; i < RT_ELEMENTS(aVec2Elm); i++)
535 for (std::vector<DHCPOption_T>::const_iterator it = aVec2Elm[i].pVec->begin(); it != aVec2Elm[i].pVec->end(); ++it)
536 {
537 xml::ElementNode *pElmChild = pElmConfig->createChild(aVec2Elm[i].pszElement);
538 pElmChild->setAttribute("name", (int)*it);
539 }
540
541 for (settings::DhcpOptionMap::const_iterator it = m_OptionMap.begin(); it != m_OptionMap.end(); ++it)
542 {
543 xml::ElementNode *pElmOption = pElmConfig->createChild("Option");
544 pElmOption->setAttribute("name", (int)it->first);
545 pElmOption->setAttribute("encoding", it->second.enmEncoding);
546 pElmOption->setAttribute("value", it->second.strValue);
547 }
548}
549
550
551
552/*********************************************************************************************************************************
553* DHCPGlobalConfig Implementation *
554*********************************************************************************************************************************/
555#undef LOG_GROUP
556#define LOG_GROUP LOG_GROUP_MAIN_DHCPGLOBALCONFIG
557
558HRESULT DHCPGlobalConfig::initWithDefaults(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent)
559{
560 AutoInitSpan autoInitSpan(this);
561 AssertReturn(autoInitSpan.isOk(), E_FAIL);
562
563 HRESULT hrc = DHCPConfig::i_initWithDefaults(a_pVirtualBox, a_pParent);
564 if (SUCCEEDED(hrc))
565 hrc = i_setOption(DHCPOption_SubnetMask, DHCPOptionEncoding_Normal, "0.0.0.0");
566
567 if (SUCCEEDED(hrc))
568 autoInitSpan.setSucceeded();
569 return hrc;
570}
571
572
573HRESULT DHCPGlobalConfig::initWithSettings(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, const settings::DHCPConfig &rConfig)
574{
575 AutoInitSpan autoInitSpan(this);
576 AssertReturn(autoInitSpan.isOk(), E_FAIL);
577
578 HRESULT hrc = DHCPConfig::i_initWithSettings(a_pVirtualBox, a_pParent, rConfig);
579 if (SUCCEEDED(hrc))
580 autoInitSpan.setSucceeded();
581 else
582 autoInitSpan.setFailed(hrc);
583 return hrc;
584}
585
586
587void DHCPGlobalConfig::uninit()
588{
589 AutoUninitSpan autoUninitSpan(this);
590 if (!autoUninitSpan.uninitDone())
591 autoUninitSpan.setSucceeded();
592}
593
594
595HRESULT DHCPGlobalConfig::i_saveSettings(settings::DHCPConfig &a_rDst)
596{
597 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
598
599 return DHCPConfig::i_saveSettings(a_rDst);
600}
601
602
603/**
604 * For getting the network mask option value (IDHCPServer::netmask attrib).
605 *
606 * @returns COM status code.
607 * @param a_rDst Where to return it.
608 * @throws nothing
609 */
610HRESULT DHCPGlobalConfig::i_getNetworkMask(com::Utf8Str &a_rDst)
611{
612 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
613 settings::DhcpOptionMap::const_iterator it = m_OptionMap.find(DHCPOption_SubnetMask);
614 if (it != m_OptionMap.end())
615 {
616 if (it->second.enmEncoding == DHCPOptionEncoding_Normal)
617 return a_rDst.assignEx(it->second.strValue);
618 return setError(VBOX_E_OBJECT_NOT_FOUND, tr("DHCP option DHCPOption_SubnetMask is not in a legacy encoding"));
619 }
620 return setError(VBOX_E_OBJECT_NOT_FOUND, tr("DHCP option DHCPOption_SubnetMask was not found"));
621}
622
623
624/**
625 * For setting the network mask option value (IDHCPServer::netmask attrib).
626 *
627 * @returns COM status code.
628 * @param a_rSrc The new value.
629 * @throws nothing
630 */
631HRESULT DHCPGlobalConfig::i_setNetworkMask(const com::Utf8Str &a_rSrc)
632{
633 /* Validate it before setting it: */
634 RTNETADDRIPV4 AddrIgnored;
635 int vrc = RTNetStrToIPv4Addr(a_rSrc.c_str(), &AddrIgnored);
636 if (RT_FAILURE(vrc))
637 return setErrorBoth(E_INVALIDARG, vrc, tr("Invalid IPv4 netmask '%s': %Rrc"), a_rSrc.c_str(), vrc);
638
639 return i_setOption(DHCPOption_SubnetMask, DHCPOptionEncoding_Normal, a_rSrc);
640}
641
642
643/**
644 * Overriden to ensure the sanity of the DHCPOption_SubnetMask option.
645 */
646HRESULT DHCPGlobalConfig::i_setOption(DHCPOption_T aOption, DHCPOptionEncoding_T aEncoding, const com::Utf8Str &aValue)
647{
648 if (aOption != DHCPOption_SubnetMask || aEncoding == DHCPOptionEncoding_Normal)
649 return DHCPConfig::i_setOption(aOption, aEncoding, aValue);
650 return setError(E_FAIL, tr("DHCPOption_SubnetMask must use DHCPOptionEncoding_Normal as it is reflected by IDHCPServer::networkMask"));
651}
652
653
654/**
655 * Overriden to ensure the sanity of the DHCPOption_SubnetMask option.
656 */
657HRESULT DHCPGlobalConfig::i_removeOption(DHCPOption_T aOption)
658{
659 if (aOption != DHCPOption_SubnetMask)
660 return DHCPConfig::i_removeOption(aOption);
661 return setError(E_FAIL, tr("DHCPOption_SubnetMask cannot be removed as it reflects IDHCPServer::networkMask"));
662}
663
664
665/**
666 * Overriden to preserve the DHCPOption_SubnetMask option.
667 */
668HRESULT DHCPGlobalConfig::i_removeAllOptions()
669{
670 {
671 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
672 settings::DhcpOptionMap::iterator it = m_OptionMap.find(DHCPOption_SubnetMask);
673 m_OptionMap.erase(m_OptionMap.begin(), it);
674 if (it != m_OptionMap.end())
675 {
676 ++it;
677 if (it != m_OptionMap.end())
678 m_OptionMap.erase(it, m_OptionMap.end());
679 }
680 }
681
682 return i_doWriteConfig();
683}
684
685
686/**
687 * Overriden to prevent removal.
688 */
689HRESULT DHCPGlobalConfig::i_remove()
690{
691 return setError(E_ACCESSDENIED, tr("Cannot delete the global config"));
692}
693
694
695
696/*********************************************************************************************************************************
697* DHCPGroupCondition Implementation *
698*********************************************************************************************************************************/
699#undef LOG_GROUP
700#define LOG_GROUP LOG_GROUP_MAIN_DHCPGROUPCONDITION
701
702HRESULT DHCPGroupCondition::initWithDefaults(DHCPGroupConfig *a_pParent, bool a_fInclusive, DHCPGroupConditionType_T a_enmType,
703 const com::Utf8Str a_strValue)
704{
705 AutoInitSpan autoInitSpan(this);
706 AssertReturn(autoInitSpan.isOk(), E_FAIL);
707
708 m_pParent = a_pParent;
709 m_fInclusive = a_fInclusive;
710 m_enmType = a_enmType;
711 HRESULT hrc = m_strValue.assignEx(a_strValue);
712
713 if (SUCCEEDED(hrc))
714 autoInitSpan.setSucceeded();
715 else
716 autoInitSpan.setFailed(hrc);
717 return hrc;
718}
719
720
721HRESULT DHCPGroupCondition::initWithSettings(DHCPGroupConfig *a_pParent, const settings::DHCPGroupCondition &a_rSrc)
722{
723 return initWithDefaults(a_pParent, a_rSrc.fInclusive, a_rSrc.enmType, a_rSrc.strValue);
724}
725
726
727void DHCPGroupCondition::uninit()
728{
729 AutoUninitSpan autoUninitSpan(this);
730 if (!autoUninitSpan.uninitDone())
731 autoUninitSpan.setSucceeded();
732}
733
734
735HRESULT DHCPGroupCondition::i_saveSettings(settings::DHCPGroupCondition &a_rDst)
736{
737 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
738
739 a_rDst.fInclusive = m_fInclusive;
740 a_rDst.enmType = m_enmType;
741 return a_rDst.strValue.assignEx(m_strValue);
742}
743
744
745/**
746 * Worker for validating the condition value according to the given type.
747 *
748 * @returns COM status code.
749 * @param enmType The condition type.
750 * @param strValue The condition value.
751 * @param pErrorDst The object to use for reporting errors.
752 */
753/*static*/ HRESULT DHCPGroupCondition::i_validateTypeAndValue(DHCPGroupConditionType_T enmType, com::Utf8Str const &strValue,
754 VirtualBoxBase *pErrorDst)
755{
756 switch (enmType)
757 {
758 case DHCPGroupConditionType_MAC:
759 {
760 RTMAC MACAddress;
761 int vrc = RTNetStrToMacAddr(strValue.c_str(), &MACAddress);
762 if (RT_SUCCESS(vrc))
763 return S_OK;
764 return pErrorDst->setError(E_INVALIDARG, tr("Not a valid MAC address: %s"), strValue.c_str());
765 }
766
767 case DHCPGroupConditionType_MACWildcard:
768 {
769 /* This must be colon separated double xdigit bytes. Single bytes
770 shorthand or raw hexstrings won't match anything. For reasons of
771 simplicity, '?' can only be used to match xdigits, '*' must match 1+
772 chars. */
773 /** @todo test this properly... */
774 const char *psz = strValue.c_str();
775 size_t off = 0;
776 unsigned cPairsLeft = 6;
777 bool fSeenAsterisk = false;
778 for (;;)
779 {
780 char ch = psz[off++];
781 if (RT_C_IS_XDIGIT(ch) || ch == '?')
782 {
783 ch = psz[off++];
784 if (RT_C_IS_XDIGIT(ch) || ch == '?')
785 {
786 ch = psz[off++];
787 cPairsLeft -= 1;
788 if (cPairsLeft == 0)
789 {
790 if (!ch)
791 return S_OK;
792 return pErrorDst->setError(E_INVALIDARG,
793 tr("Trailing chars in MAC wildcard address: %s (offset %zu)"),
794 psz, off - 1);
795 }
796 if (ch == ':' || ch == '*')
797 continue;
798 if (ch == '\0' && fSeenAsterisk)
799 return S_OK;
800 return pErrorDst->setError(E_INVALIDARG,
801 tr("Malformed MAC wildcard address: %s (offset %zu)"),
802 psz, off - 1);
803 }
804
805 if (ch == '*')
806 {
807 fSeenAsterisk = true;
808 do
809 ch = psz[off++];
810 while (ch == '*');
811 if (ch == '\0')
812 return S_OK;
813 cPairsLeft -= 1;
814 if (cPairsLeft == 0)
815 return pErrorDst->setError(E_INVALIDARG,
816 tr("Trailing chars in MAC wildcard address: %s (offset %zu)"),
817 psz, off - 1);
818 if (ch == ':')
819 continue;
820 }
821 else
822 return pErrorDst->setError(E_INVALIDARG, tr("Malformed MAC wildcard address: %s (offset %zu)"),
823 psz, off - 1);
824 }
825 else if (ch == '*')
826 {
827 fSeenAsterisk = true;
828 do
829 ch = psz[off++];
830 while (ch == '*');
831 if (ch == '\0')
832 return S_OK;
833 if (ch == ':')
834 {
835 cPairsLeft -= 1;
836 if (cPairsLeft == 0)
837 return pErrorDst->setError(E_INVALIDARG,
838 tr("Trailing chars in MAC wildcard address: %s (offset %zu)"),
839 psz, off - 1);
840 continue;
841 }
842
843 }
844 else
845 return pErrorDst->setError(E_INVALIDARG, tr("Malformed MAC wildcard address: %s (offset %zu)"),
846 psz, off - 1);
847
848 /* Pick up after '*' in the two cases above: ch is not ':' or '\0'. */
849 Assert(ch != ':' && ch != '\0');
850 if (RT_C_IS_XDIGIT(ch) || ch == '?')
851 {
852 ch = psz[off++];
853 if (RT_C_IS_XDIGIT(ch) || ch == '?' || ch == '*')
854 {
855 off -= 2;
856 continue;
857 }
858 if (ch == ':')
859 {
860 ch = psz[off++];
861 if (ch == '\0')
862 return S_OK;
863 cPairsLeft -= 1;
864 if (cPairsLeft == 0)
865 return pErrorDst->setError(E_INVALIDARG,
866 tr("Trailing chars in MAC wildcard address: %s (offset %zu)"),
867 psz, off - 1);
868 continue;
869 }
870 if (ch == '\0')
871 return S_OK;
872 return pErrorDst->setError(E_INVALIDARG,
873 tr("Trailing chars in MAC wildcard address: %s (offset %zu)"),
874 psz, off - 1);
875 }
876 return pErrorDst->setError(E_INVALIDARG,
877 tr("Malformed MAC wildcard address: %s (offset %zu)"),
878 psz, off - 1);
879 }
880 break;
881 }
882
883 case DHCPGroupConditionType_vendorClassID:
884 case DHCPGroupConditionType_vendorClassIDWildcard:
885 case DHCPGroupConditionType_userClassID:
886 case DHCPGroupConditionType_userClassIDWildcard:
887 if (strValue.length() == 0)
888 return pErrorDst->setError(E_INVALIDARG, tr("Value cannot be empty"));
889 if (strValue.length() < 255)
890 return pErrorDst->setError(E_INVALIDARG, tr("Value is too long: %zu bytes", "", strValue.length()),
891 strValue.length());
892 break;
893
894 default:
895 return pErrorDst->setError(E_INVALIDARG, tr("Invalid condition type: %d"), enmType);
896 }
897
898 return S_OK;
899}
900
901
902HRESULT DHCPGroupCondition::getInclusive(BOOL *aInclusive)
903{
904 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
905 *aInclusive = m_fInclusive;
906 return S_OK;
907}
908
909
910HRESULT DHCPGroupCondition::setInclusive(BOOL aInclusive)
911{
912 {
913 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
914 if ((aInclusive != FALSE) == m_fInclusive)
915 return S_OK;
916 m_fInclusive = aInclusive != FALSE;
917 }
918 return m_pParent->i_doWriteConfig();
919}
920
921
922HRESULT DHCPGroupCondition::getType(DHCPGroupConditionType_T *aType)
923{
924 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
925 *aType = m_enmType;
926 return S_OK;
927}
928
929
930HRESULT DHCPGroupCondition::setType(DHCPGroupConditionType_T aType)
931{
932 {
933 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
934 if (aType == m_enmType)
935 return S_OK;
936 HRESULT hrc = i_validateTypeAndValue(aType, m_strValue, this);
937 if (FAILED(hrc))
938 return hrc;
939 m_enmType = aType;
940 }
941 return m_pParent->i_doWriteConfig();
942}
943
944
945HRESULT DHCPGroupCondition::getValue(com::Utf8Str &aValue)
946{
947 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
948 return aValue.assignEx(m_strValue);
949}
950
951
952HRESULT DHCPGroupCondition::setValue(const com::Utf8Str &aValue)
953{
954 {
955 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
956 if (aValue == m_strValue)
957 return S_OK;
958 HRESULT hrc = i_validateTypeAndValue(m_enmType, aValue, this);
959 if (FAILED(hrc))
960 return hrc;
961 hrc = m_strValue.assignEx(aValue);
962 if (FAILED(hrc))
963 return hrc;
964 }
965 return m_pParent->i_doWriteConfig();
966}
967
968
969HRESULT DHCPGroupCondition::remove()
970{
971 return m_pParent->i_removeCondition(this);
972}
973
974
975
976/*********************************************************************************************************************************
977* DHCPGroupConfig Implementation *
978*********************************************************************************************************************************/
979#undef LOG_GROUP
980#define LOG_GROUP LOG_GROUP_MAIN_DHCPGROUPCONFIG
981
982
983HRESULT DHCPGroupConfig::initWithDefaults(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, const com::Utf8Str &a_rName)
984{
985 AutoInitSpan autoInitSpan(this);
986 AssertReturn(autoInitSpan.isOk(), E_FAIL);
987
988 Assert(m_Conditions.size() == 0);
989 HRESULT hrc = DHCPConfig::i_initWithDefaults(a_pVirtualBox, a_pParent);
990 if (SUCCEEDED(hrc))
991 hrc = m_strName.assignEx(a_rName);
992
993 if (SUCCEEDED(hrc))
994 autoInitSpan.setSucceeded();
995 else
996 autoInitSpan.setFailed(hrc);
997 return hrc;
998}
999
1000
1001HRESULT DHCPGroupConfig::initWithSettings(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, const settings::DHCPGroupConfig &a_rSrc)
1002{
1003 AutoInitSpan autoInitSpan(this);
1004 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1005
1006 Assert(m_Conditions.size() == 0);
1007 HRESULT hrc = DHCPConfig::i_initWithSettings(a_pVirtualBox, a_pParent, a_rSrc);
1008 if (SUCCEEDED(hrc))
1009 hrc = m_strName.assignEx(a_rSrc.strName);
1010
1011 for (settings::DHCPGroupConditionVec::const_iterator it = a_rSrc.vecConditions.begin();
1012 it != a_rSrc.vecConditions.end() && SUCCEEDED(hrc); ++it)
1013 {
1014 ComObjPtr<DHCPGroupCondition> ptrCondition;
1015 hrc = ptrCondition.createObject();
1016 if (SUCCEEDED(hrc))
1017 {
1018 hrc = ptrCondition->initWithSettings(this, *it);
1019 if (SUCCEEDED(hrc))
1020 {
1021 try
1022 {
1023 m_Conditions.push_back(ptrCondition);
1024 }
1025 catch (std::bad_alloc &)
1026 {
1027 hrc = E_OUTOFMEMORY;
1028 }
1029 }
1030 }
1031 }
1032
1033 if (SUCCEEDED(hrc))
1034 autoInitSpan.setSucceeded();
1035 else
1036 autoInitSpan.setFailed(hrc);
1037 return hrc;
1038}
1039
1040
1041void DHCPGroupConfig::uninit()
1042{
1043 AutoUninitSpan autoUninitSpan(this);
1044 if (!autoUninitSpan.uninitDone())
1045 autoUninitSpan.setSucceeded();
1046}
1047
1048
1049HRESULT DHCPGroupConfig::i_saveSettings(settings::DHCPGroupConfig &a_rDst)
1050{
1051 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1052
1053 HRESULT hrc = DHCPConfig::i_saveSettings(a_rDst);
1054 if (SUCCEEDED(hrc))
1055 hrc = a_rDst.strName.assignEx(m_strName);
1056 if (SUCCEEDED(hrc))
1057 {
1058 size_t const cConditions = m_Conditions.size();
1059 try
1060 {
1061 a_rDst.vecConditions.resize(cConditions);
1062 }
1063 catch (std::bad_alloc &)
1064 {
1065 hrc = E_OUTOFMEMORY;
1066 }
1067
1068 for (size_t i = 0; i < cConditions && SUCCEEDED(hrc); i++)
1069 hrc = m_Conditions[i]->i_saveSettings(a_rDst.vecConditions[i]);
1070 }
1071 return hrc;
1072}
1073
1074
1075HRESULT DHCPGroupConfig::i_removeCondition(DHCPGroupCondition *a_pCondition)
1076{
1077 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1078
1079 for (ConditionsIterator it = m_Conditions.begin(); it != m_Conditions.end();)
1080 {
1081 DHCPGroupCondition *pCurCondition = *it;
1082 if (pCurCondition == a_pCondition)
1083 it = m_Conditions.erase(it);
1084 else
1085 ++it;
1086 }
1087
1088 /* Never mind if already delete, right? */
1089 return S_OK;
1090}
1091
1092
1093/**
1094 * Overridden to add a 'name' attribute and emit condition child elements.
1095 */
1096void DHCPGroupConfig::i_writeDhcpdConfig(xml::ElementNode *a_pElmGroup)
1097{
1098 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1099
1100 /* The name attribute: */
1101 a_pElmGroup->setAttribute("name", m_strName);
1102
1103 /*
1104 * Conditions:
1105 */
1106 for (ConditionsIterator it = m_Conditions.begin(); it != m_Conditions.end(); ++it)
1107 {
1108 xml::ElementNode *pElmCondition;
1109 switch ((*it)->i_getType())
1110 {
1111 case DHCPGroupConditionType_MAC:
1112 pElmCondition = a_pElmGroup->createChild("ConditionMAC");
1113 break;
1114 case DHCPGroupConditionType_MACWildcard:
1115 pElmCondition = a_pElmGroup->createChild("ConditionMACWildcard");
1116 break;
1117 case DHCPGroupConditionType_vendorClassID:
1118 pElmCondition = a_pElmGroup->createChild("ConditionVendorClassID");
1119 break;
1120 case DHCPGroupConditionType_vendorClassIDWildcard:
1121 pElmCondition = a_pElmGroup->createChild("ConditionVendorClassIDWildcard");
1122 break;
1123 case DHCPGroupConditionType_userClassID:
1124 pElmCondition = a_pElmGroup->createChild("ConditionUserClassID");
1125 break;
1126 case DHCPGroupConditionType_userClassIDWildcard:
1127 pElmCondition = a_pElmGroup->createChild("ConditionUserClassIDWildcard");
1128 break;
1129 default:
1130 AssertLogRelMsgFailed(("m_enmType=%d\n", (*it)->i_getType()));
1131 continue;
1132 }
1133 pElmCondition->setAttribute("inclusive", (*it)->i_getInclusive());
1134 pElmCondition->setAttribute("value", (*it)->i_getValue());
1135 }
1136
1137 DHCPConfig::i_writeDhcpdConfig(a_pElmGroup);
1138}
1139
1140
1141HRESULT DHCPGroupConfig::getName(com::Utf8Str &aName)
1142{
1143 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1144 return aName.assignEx(m_strName);
1145}
1146
1147
1148HRESULT DHCPGroupConfig::setName(const com::Utf8Str &aName)
1149{
1150 {
1151 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1152 if (aName == m_strName)
1153 return S_OK;
1154 HRESULT hrc = m_strName.assignEx(aName);
1155 if (FAILED(hrc))
1156 return hrc;
1157 }
1158 return i_doWriteConfig();
1159}
1160
1161
1162HRESULT DHCPGroupConfig::getConditions(std::vector<ComPtr<IDHCPGroupCondition> > &aConditions)
1163{
1164 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1165 size_t const cConditions = m_Conditions.size();
1166 try
1167 {
1168 aConditions.resize(cConditions);
1169 }
1170 catch (std::bad_alloc &)
1171 {
1172 return E_OUTOFMEMORY;
1173 }
1174 HRESULT hrc = S_OK;
1175 for (size_t i = 0; i < cConditions && SUCCEEDED(hrc); i++)
1176 hrc = m_Conditions[i].queryInterfaceTo(aConditions[i].asOutParam());
1177 return hrc;
1178}
1179
1180
1181HRESULT DHCPGroupConfig::addCondition(BOOL aInclusive, DHCPGroupConditionType_T aType, const com::Utf8Str &aValue,
1182 ComPtr<IDHCPGroupCondition> &aCondition)
1183{
1184 /*
1185 * Valdiate it.
1186 */
1187 HRESULT hrc = DHCPGroupCondition::i_validateTypeAndValue(aType, aValue, this);
1188 if (SUCCEEDED(hrc))
1189 {
1190 /*
1191 * Add it.
1192 */
1193 ComObjPtr<DHCPGroupCondition> ptrCondition;
1194 hrc = ptrCondition.createObject();
1195 if (SUCCEEDED(hrc))
1196 hrc = ptrCondition->initWithDefaults(this, aInclusive != FALSE, aType, aValue);
1197 if (SUCCEEDED(hrc))
1198 {
1199 hrc = ptrCondition.queryInterfaceTo(aCondition.asOutParam());
1200 if (SUCCEEDED(hrc))
1201 {
1202 {
1203 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1204 try
1205 {
1206 m_Conditions.push_back(ptrCondition);
1207 }
1208 catch (std::bad_alloc &)
1209 {
1210 aCondition.setNull();
1211 return E_OUTOFMEMORY;
1212 }
1213 }
1214
1215 hrc = i_doWriteConfig();
1216 if (FAILED(hrc))
1217 aCondition.setNull();
1218 }
1219 }
1220 }
1221
1222 return hrc;
1223}
1224
1225
1226HRESULT DHCPGroupConfig::removeAllConditions()
1227{
1228 {
1229 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1230 if (m_Conditions.size() == 0)
1231 return S_OK;
1232
1233 /** @todo sever the weak parent link for each entry... */
1234 m_Conditions.erase(m_Conditions.begin(), m_Conditions.end());
1235 }
1236
1237 return i_doWriteConfig();
1238}
1239
1240
1241
1242/*********************************************************************************************************************************
1243* DHCPIndividualConfig Implementation *
1244*********************************************************************************************************************************/
1245#undef LOG_GROUP
1246#define LOG_GROUP LOG_GROUP_MAIN_DHCPINDIVIDUALCONFIG
1247
1248HRESULT DHCPIndividualConfig::initWithMachineIdAndSlot(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent,
1249 com::Guid const &a_idMachine, ULONG a_uSlot, uint32_t a_uMACAddressVersion)
1250{
1251 AutoInitSpan autoInitSpan(this);
1252 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1253
1254 HRESULT hrc = DHCPConfig::i_initWithDefaults(a_pVirtualBox, a_pParent);
1255 if (SUCCEEDED(hrc))
1256 {
1257 unconst(m_enmScope) = DHCPConfigScope_MachineNIC;
1258 unconst(m_idMachine) = a_idMachine;
1259 unconst(m_uSlot) = a_uSlot;
1260 m_uMACAddressResolvedVersion = a_uMACAddressVersion;
1261
1262 autoInitSpan.setSucceeded();
1263 }
1264 return hrc;
1265}
1266
1267
1268HRESULT DHCPIndividualConfig::initWithMACAddress(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, PCRTMAC a_pMACAddress)
1269{
1270 AutoInitSpan autoInitSpan(this);
1271 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1272
1273 HRESULT hrc = DHCPConfig::i_initWithDefaults(a_pVirtualBox, a_pParent);
1274 if (SUCCEEDED(hrc))
1275 {
1276 unconst(m_enmScope) = DHCPConfigScope_MAC;
1277 unconst(m_MACAddress) = *a_pMACAddress;
1278
1279 autoInitSpan.setSucceeded();
1280 }
1281 return hrc;
1282}
1283
1284
1285HRESULT DHCPIndividualConfig::initWithSettingsAndMachineIdAndSlot(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent,
1286 settings::DHCPIndividualConfig const &rConfig,
1287 com::Guid const &a_idMachine, ULONG a_uSlot,
1288 uint32_t a_uMACAddressVersion)
1289{
1290 AutoInitSpan autoInitSpan(this);
1291 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1292
1293 HRESULT hrc = DHCPConfig::i_initWithSettings(a_pVirtualBox, a_pParent, rConfig);
1294 if (SUCCEEDED(hrc))
1295 {
1296 unconst(m_enmScope) = DHCPConfigScope_MachineNIC;
1297 unconst(m_idMachine) = a_idMachine;
1298 unconst(m_uSlot) = a_uSlot;
1299 m_uMACAddressResolvedVersion = a_uMACAddressVersion;
1300 m_strFixedAddress = rConfig.strFixedAddress;
1301
1302 autoInitSpan.setSucceeded();
1303 }
1304 return hrc;
1305}
1306
1307
1308HRESULT DHCPIndividualConfig::initWithSettingsAndMACAddress(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent,
1309 settings::DHCPIndividualConfig const &rConfig, PCRTMAC a_pMACAddress)
1310{
1311 AutoInitSpan autoInitSpan(this);
1312 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1313
1314 HRESULT hrc = DHCPConfig::i_initWithSettings(a_pVirtualBox, a_pParent, rConfig);
1315 if (SUCCEEDED(hrc))
1316 {
1317 unconst(m_enmScope) = DHCPConfigScope_MAC;
1318 unconst(m_MACAddress) = *a_pMACAddress;
1319 m_strFixedAddress = rConfig.strFixedAddress;
1320
1321 autoInitSpan.setSucceeded();
1322 }
1323 return hrc;
1324}
1325
1326
1327void DHCPIndividualConfig::uninit()
1328{
1329 AutoUninitSpan autoUninitSpan(this);
1330 if (!autoUninitSpan.uninitDone())
1331 autoUninitSpan.setSucceeded();
1332}
1333
1334
1335HRESULT DHCPIndividualConfig::i_saveSettings(settings::DHCPIndividualConfig &a_rDst)
1336{
1337 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1338
1339 a_rDst.uSlot = m_uSlot;
1340 int vrc = a_rDst.strMACAddress.printfNoThrow("%RTmac", &m_MACAddress);
1341 if (m_idMachine.isValid() && !m_idMachine.isZero() && RT_SUCCESS(vrc))
1342 vrc = a_rDst.strVMName.printfNoThrow("%RTuuid", m_idMachine.raw());
1343 if (RT_SUCCESS(vrc))
1344 vrc = a_rDst.strFixedAddress.assignNoThrow(m_strFixedAddress);
1345 if (RT_SUCCESS(vrc))
1346 return DHCPConfig::i_saveSettings(a_rDst);
1347 return E_OUTOFMEMORY;;
1348}
1349
1350
1351HRESULT DHCPIndividualConfig::getMACAddress(com::Utf8Str &aMACAddress)
1352{
1353 /* No locking needed here (the MAC address, machine UUID and NIC slot number cannot change). */
1354 RTMAC MACAddress;
1355 if (m_enmScope == DHCPConfigScope_MAC)
1356 MACAddress = m_MACAddress;
1357 else
1358 {
1359 HRESULT hrc = i_getMachineMAC(&MACAddress);
1360 if (FAILED(hrc))
1361 return hrc;
1362 }
1363
1364 /* Format the return string: */
1365 int vrc = aMACAddress.printfNoThrow("%RTmac", &MACAddress);
1366 return RT_SUCCESS(vrc) ? S_OK : E_OUTOFMEMORY;
1367}
1368
1369
1370HRESULT DHCPIndividualConfig::getMachineId(com::Guid &aId)
1371{
1372 AutoReadLock(this COMMA_LOCKVAL_SRC_POS);
1373 aId = m_idMachine;
1374 return S_OK;
1375}
1376
1377
1378HRESULT DHCPIndividualConfig::getSlot(ULONG *aSlot)
1379{
1380 AutoReadLock(this COMMA_LOCKVAL_SRC_POS);
1381 *aSlot = m_uSlot;
1382 return S_OK;
1383}
1384
1385HRESULT DHCPIndividualConfig::getFixedAddress(com::Utf8Str &aFixedAddress)
1386{
1387 AutoReadLock(this COMMA_LOCKVAL_SRC_POS);
1388 return aFixedAddress.assignEx(m_strFixedAddress);
1389}
1390
1391
1392HRESULT DHCPIndividualConfig::setFixedAddress(const com::Utf8Str &aFixedAddress)
1393{
1394 if (aFixedAddress.isNotEmpty())
1395 {
1396 RTNETADDRIPV4 AddrIgnored;
1397 int vrc = RTNetStrToIPv4Addr(aFixedAddress.c_str(), &AddrIgnored);
1398 if (RT_FAILURE(vrc))
1399 return setErrorBoth(E_INVALIDARG, vrc, tr("Invalid IPv4 address '%s': %Rrc"), aFixedAddress.c_str(), vrc);
1400 }
1401
1402 {
1403 AutoWriteLock(this COMMA_LOCKVAL_SRC_POS);
1404 m_strFixedAddress = aFixedAddress;
1405 }
1406 return i_doWriteConfig();
1407}
1408
1409
1410/**
1411 * Gets the MAC address of m_idMachine + m_uSlot.
1412 *
1413 * @returns COM status code w/ setError.
1414 * @param pMACAddress Where to return the address.
1415 *
1416 * @note Must be called without holding any DHCP related locks as that would
1417 * be lock order violation. The m_idMachine and m_uSlot values are
1418 * practically const, so we don't need any locks here anyway.
1419 */
1420HRESULT DHCPIndividualConfig::i_getMachineMAC(PRTMAC pMACAddress)
1421{
1422 ComObjPtr<Machine> ptrMachine;
1423 HRESULT hrc = m_pVirtualBox->i_findMachine(m_idMachine, false /*fPermitInaccessible*/, true /*aSetError*/, &ptrMachine);
1424 if (SUCCEEDED(hrc))
1425 {
1426 ComPtr<INetworkAdapter> ptrNetworkAdapter;
1427 hrc = ptrMachine->GetNetworkAdapter(m_uSlot, ptrNetworkAdapter.asOutParam());
1428 if (SUCCEEDED(hrc))
1429 {
1430 com::Bstr bstrMACAddress;
1431 hrc = ptrNetworkAdapter->COMGETTER(MACAddress)(bstrMACAddress.asOutParam());
1432 if (SUCCEEDED(hrc))
1433 {
1434 Utf8Str strMACAddress;
1435 try
1436 {
1437 strMACAddress = bstrMACAddress;
1438 }
1439 catch (std::bad_alloc &)
1440 {
1441 return E_OUTOFMEMORY;
1442 }
1443
1444 int vrc = RTNetStrToMacAddr(strMACAddress.c_str(), pMACAddress);
1445 if (RT_SUCCESS(vrc))
1446 hrc = S_OK;
1447 else
1448 hrc = setErrorBoth(E_FAIL, vrc, tr("INetworkAdapter returned bogus MAC address '%ls': %Rrc"),
1449 bstrMACAddress.raw(), vrc);
1450 }
1451 }
1452 }
1453 return hrc;
1454}
1455
1456
1457HRESULT DHCPIndividualConfig::i_resolveMACAddress(uint32_t uVersion)
1458{
1459 HRESULT hrc;
1460 if (m_enmScope == DHCPConfigScope_MachineNIC)
1461 {
1462 RTMAC MACAddress;
1463 hrc = i_getMachineMAC(&MACAddress);
1464 if (SUCCEEDED(hrc))
1465 {
1466 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1467 if ((int32_t)(uVersion - m_uMACAddressResolvedVersion) >= 0)
1468 {
1469 m_uMACAddressResolvedVersion = uVersion;
1470 m_MACAddress = MACAddress;
1471 }
1472 }
1473 }
1474 else
1475 hrc = S_OK;
1476 return hrc;
1477}
1478
1479
1480/**
1481 * Overridden to write out additional config.
1482 */
1483void DHCPIndividualConfig::i_writeDhcpdConfig(xml::ElementNode *pElmConfig)
1484{
1485 char szTmp[RTUUID_STR_LENGTH + 32];
1486 RTStrPrintf(szTmp, sizeof(szTmp), "%RTmac", &m_MACAddress);
1487 pElmConfig->setAttribute("MACAddress", szTmp);
1488
1489 if (m_enmScope == DHCPConfigScope_MachineNIC)
1490 {
1491 RTStrPrintf(szTmp, sizeof(szTmp), "%RTuuid/%u", m_idMachine.raw(), m_uSlot);
1492 pElmConfig->setAttribute("name", szTmp);
1493 }
1494
1495 pElmConfig->setAttribute("fixedAddress", m_strFixedAddress);
1496
1497 DHCPConfig::i_writeDhcpdConfig(pElmConfig);
1498}
1499
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