VirtualBox

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

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

Main: bugref:1909: Added API localization

  • 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 90828 2021-08-24 09:44:46Z vboxsync $ */
2/** @file
3 * VirtualBox Main - IDHCPConfig, IDHCPConfigGlobal, IDHCPConfigGroup, IDHCPConfigIndividual implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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 break;
892
893 default:
894 return pErrorDst->setError(E_INVALIDARG, tr("Invalid condition type: %d"), enmType);
895 }
896
897 return S_OK;
898}
899
900
901HRESULT DHCPGroupCondition::getInclusive(BOOL *aInclusive)
902{
903 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
904 *aInclusive = m_fInclusive;
905 return S_OK;
906}
907
908
909HRESULT DHCPGroupCondition::setInclusive(BOOL aInclusive)
910{
911 {
912 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
913 if ((aInclusive != FALSE) == m_fInclusive)
914 return S_OK;
915 m_fInclusive = aInclusive != FALSE;
916 }
917 return m_pParent->i_doWriteConfig();
918}
919
920
921HRESULT DHCPGroupCondition::getType(DHCPGroupConditionType_T *aType)
922{
923 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
924 *aType = m_enmType;
925 return S_OK;
926}
927
928
929HRESULT DHCPGroupCondition::setType(DHCPGroupConditionType_T aType)
930{
931 {
932 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
933 if (aType == m_enmType)
934 return S_OK;
935 HRESULT hrc = i_validateTypeAndValue(aType, m_strValue, this);
936 if (FAILED(hrc))
937 return hrc;
938 m_enmType = aType;
939 }
940 return m_pParent->i_doWriteConfig();
941}
942
943
944HRESULT DHCPGroupCondition::getValue(com::Utf8Str &aValue)
945{
946 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
947 return aValue.assignEx(m_strValue);
948}
949
950
951HRESULT DHCPGroupCondition::setValue(const com::Utf8Str &aValue)
952{
953 {
954 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
955 if (aValue == m_strValue)
956 return S_OK;
957 HRESULT hrc = i_validateTypeAndValue(m_enmType, aValue, this);
958 if (FAILED(hrc))
959 return hrc;
960 hrc = m_strValue.assignEx(aValue);
961 if (FAILED(hrc))
962 return hrc;
963 }
964 return m_pParent->i_doWriteConfig();
965}
966
967
968HRESULT DHCPGroupCondition::remove()
969{
970 return m_pParent->i_removeCondition(this);
971}
972
973
974
975/*********************************************************************************************************************************
976* DHCPGroupConfig Implementation *
977*********************************************************************************************************************************/
978#undef LOG_GROUP
979#define LOG_GROUP LOG_GROUP_MAIN_DHCPGROUPCONFIG
980
981
982HRESULT DHCPGroupConfig::initWithDefaults(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, const com::Utf8Str &a_rName)
983{
984 AutoInitSpan autoInitSpan(this);
985 AssertReturn(autoInitSpan.isOk(), E_FAIL);
986
987 Assert(m_Conditions.size() == 0);
988 HRESULT hrc = DHCPConfig::i_initWithDefaults(a_pVirtualBox, a_pParent);
989 if (SUCCEEDED(hrc))
990 hrc = m_strName.assignEx(a_rName);
991
992 if (SUCCEEDED(hrc))
993 autoInitSpan.setSucceeded();
994 else
995 autoInitSpan.setFailed(hrc);
996 return hrc;
997}
998
999
1000HRESULT DHCPGroupConfig::initWithSettings(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, const settings::DHCPGroupConfig &a_rSrc)
1001{
1002 AutoInitSpan autoInitSpan(this);
1003 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1004
1005 Assert(m_Conditions.size() == 0);
1006 HRESULT hrc = DHCPConfig::i_initWithSettings(a_pVirtualBox, a_pParent, a_rSrc);
1007 if (SUCCEEDED(hrc))
1008 hrc = m_strName.assignEx(a_rSrc.strName);
1009
1010 for (settings::DHCPGroupConditionVec::const_iterator it = a_rSrc.vecConditions.begin();
1011 it != a_rSrc.vecConditions.end() && SUCCEEDED(hrc); ++it)
1012 {
1013 ComObjPtr<DHCPGroupCondition> ptrCondition;
1014 hrc = ptrCondition.createObject();
1015 if (SUCCEEDED(hrc))
1016 {
1017 hrc = ptrCondition->initWithSettings(this, *it);
1018 if (SUCCEEDED(hrc))
1019 {
1020 try
1021 {
1022 m_Conditions.push_back(ptrCondition);
1023 }
1024 catch (std::bad_alloc &)
1025 {
1026 hrc = E_OUTOFMEMORY;
1027 }
1028 }
1029 }
1030 }
1031
1032 if (SUCCEEDED(hrc))
1033 autoInitSpan.setSucceeded();
1034 else
1035 autoInitSpan.setFailed(hrc);
1036 return hrc;
1037}
1038
1039
1040void DHCPGroupConfig::uninit()
1041{
1042 AutoUninitSpan autoUninitSpan(this);
1043 if (!autoUninitSpan.uninitDone())
1044 autoUninitSpan.setSucceeded();
1045}
1046
1047
1048HRESULT DHCPGroupConfig::i_saveSettings(settings::DHCPGroupConfig &a_rDst)
1049{
1050 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1051
1052 HRESULT hrc = DHCPConfig::i_saveSettings(a_rDst);
1053 if (SUCCEEDED(hrc))
1054 hrc = a_rDst.strName.assignEx(m_strName);
1055 if (SUCCEEDED(hrc))
1056 {
1057 size_t const cConditions = m_Conditions.size();
1058 try
1059 {
1060 a_rDst.vecConditions.resize(cConditions);
1061 }
1062 catch (std::bad_alloc &)
1063 {
1064 hrc = E_OUTOFMEMORY;
1065 }
1066
1067 for (size_t i = 0; i < cConditions && SUCCEEDED(hrc); i++)
1068 hrc = m_Conditions[i]->i_saveSettings(a_rDst.vecConditions[i]);
1069 }
1070 return hrc;
1071}
1072
1073
1074HRESULT DHCPGroupConfig::i_removeCondition(DHCPGroupCondition *a_pCondition)
1075{
1076 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1077
1078 for (ConditionsIterator it = m_Conditions.begin(); it != m_Conditions.end();)
1079 {
1080 DHCPGroupCondition *pCurCondition = *it;
1081 if (pCurCondition == a_pCondition)
1082 it = m_Conditions.erase(it);
1083 else
1084 ++it;
1085 }
1086
1087 /* Never mind if already delete, right? */
1088 return S_OK;
1089}
1090
1091
1092/**
1093 * Overridden to add a 'name' attribute and emit condition child elements.
1094 */
1095void DHCPGroupConfig::i_writeDhcpdConfig(xml::ElementNode *a_pElmGroup)
1096{
1097 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1098
1099 /* The name attribute: */
1100 a_pElmGroup->setAttribute("name", m_strName);
1101
1102 /*
1103 * Conditions:
1104 */
1105 for (ConditionsIterator it = m_Conditions.begin(); it != m_Conditions.end(); ++it)
1106 {
1107 xml::ElementNode *pElmCondition;
1108 switch ((*it)->i_getType())
1109 {
1110 case DHCPGroupConditionType_MAC:
1111 pElmCondition = a_pElmGroup->createChild("ConditionMAC");
1112 break;
1113 case DHCPGroupConditionType_MACWildcard:
1114 pElmCondition = a_pElmGroup->createChild("ConditionMACWildcard");
1115 break;
1116 case DHCPGroupConditionType_vendorClassID:
1117 pElmCondition = a_pElmGroup->createChild("ConditionVendorClassID");
1118 break;
1119 case DHCPGroupConditionType_vendorClassIDWildcard:
1120 pElmCondition = a_pElmGroup->createChild("ConditionVendorClassIDWildcard");
1121 break;
1122 case DHCPGroupConditionType_userClassID:
1123 pElmCondition = a_pElmGroup->createChild("ConditionUserClassID");
1124 break;
1125 case DHCPGroupConditionType_userClassIDWildcard:
1126 pElmCondition = a_pElmGroup->createChild("ConditionUserClassIDWildcard");
1127 break;
1128 default:
1129 AssertLogRelMsgFailed(("m_enmType=%d\n", (*it)->i_getType()));
1130 continue;
1131 }
1132 pElmCondition->setAttribute("inclusive", (*it)->i_getInclusive());
1133 pElmCondition->setAttribute("value", (*it)->i_getValue());
1134 }
1135
1136 DHCPConfig::i_writeDhcpdConfig(a_pElmGroup);
1137}
1138
1139
1140HRESULT DHCPGroupConfig::getName(com::Utf8Str &aName)
1141{
1142 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1143 return aName.assignEx(m_strName);
1144}
1145
1146
1147HRESULT DHCPGroupConfig::setName(const com::Utf8Str &aName)
1148{
1149 {
1150 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1151 if (aName == m_strName)
1152 return S_OK;
1153 HRESULT hrc = m_strName.assignEx(aName);
1154 if (FAILED(hrc))
1155 return hrc;
1156 }
1157 return i_doWriteConfig();
1158}
1159
1160
1161HRESULT DHCPGroupConfig::getConditions(std::vector<ComPtr<IDHCPGroupCondition> > &aConditions)
1162{
1163 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1164 size_t const cConditions = m_Conditions.size();
1165 try
1166 {
1167 aConditions.resize(cConditions);
1168 }
1169 catch (std::bad_alloc &)
1170 {
1171 return E_OUTOFMEMORY;
1172 }
1173 HRESULT hrc = S_OK;
1174 for (size_t i = 0; i < cConditions && SUCCEEDED(hrc); i++)
1175 hrc = m_Conditions[i].queryInterfaceTo(aConditions[i].asOutParam());
1176 return hrc;
1177}
1178
1179
1180HRESULT DHCPGroupConfig::addCondition(BOOL aInclusive, DHCPGroupConditionType_T aType, const com::Utf8Str &aValue,
1181 ComPtr<IDHCPGroupCondition> &aCondition)
1182{
1183 /*
1184 * Valdiate it.
1185 */
1186 HRESULT hrc = DHCPGroupCondition::i_validateTypeAndValue(aType, aValue, this);
1187 if (SUCCEEDED(hrc))
1188 {
1189 /*
1190 * Add it.
1191 */
1192 ComObjPtr<DHCPGroupCondition> ptrCondition;
1193 hrc = ptrCondition.createObject();
1194 if (SUCCEEDED(hrc))
1195 hrc = ptrCondition->initWithDefaults(this, aInclusive != FALSE, aType, aValue);
1196 if (SUCCEEDED(hrc))
1197 {
1198 hrc = ptrCondition.queryInterfaceTo(aCondition.asOutParam());
1199 if (SUCCEEDED(hrc))
1200 {
1201 {
1202 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1203 try
1204 {
1205 m_Conditions.push_back(ptrCondition);
1206 }
1207 catch (std::bad_alloc &)
1208 {
1209 aCondition.setNull();
1210 return E_OUTOFMEMORY;
1211 }
1212 }
1213
1214 hrc = i_doWriteConfig();
1215 if (FAILED(hrc))
1216 aCondition.setNull();
1217 }
1218 }
1219 }
1220
1221 return hrc;
1222}
1223
1224
1225HRESULT DHCPGroupConfig::removeAllConditions()
1226{
1227 {
1228 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1229 if (m_Conditions.size() == 0)
1230 return S_OK;
1231
1232 /** @todo sever the weak parent link for each entry... */
1233 m_Conditions.erase(m_Conditions.begin(), m_Conditions.end());
1234 }
1235
1236 return i_doWriteConfig();
1237}
1238
1239
1240
1241/*********************************************************************************************************************************
1242* DHCPIndividualConfig Implementation *
1243*********************************************************************************************************************************/
1244#undef LOG_GROUP
1245#define LOG_GROUP LOG_GROUP_MAIN_DHCPINDIVIDUALCONFIG
1246
1247HRESULT DHCPIndividualConfig::initWithMachineIdAndSlot(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent,
1248 com::Guid const &a_idMachine, ULONG a_uSlot, uint32_t a_uMACAddressVersion)
1249{
1250 AutoInitSpan autoInitSpan(this);
1251 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1252
1253 HRESULT hrc = DHCPConfig::i_initWithDefaults(a_pVirtualBox, a_pParent);
1254 if (SUCCEEDED(hrc))
1255 {
1256 unconst(m_enmScope) = DHCPConfigScope_MachineNIC;
1257 unconst(m_idMachine) = a_idMachine;
1258 unconst(m_uSlot) = a_uSlot;
1259 m_uMACAddressResolvedVersion = a_uMACAddressVersion;
1260
1261 autoInitSpan.setSucceeded();
1262 }
1263 return hrc;
1264}
1265
1266
1267HRESULT DHCPIndividualConfig::initWithMACAddress(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, PCRTMAC a_pMACAddress)
1268{
1269 AutoInitSpan autoInitSpan(this);
1270 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1271
1272 HRESULT hrc = DHCPConfig::i_initWithDefaults(a_pVirtualBox, a_pParent);
1273 if (SUCCEEDED(hrc))
1274 {
1275 unconst(m_enmScope) = DHCPConfigScope_MAC;
1276 unconst(m_MACAddress) = *a_pMACAddress;
1277
1278 autoInitSpan.setSucceeded();
1279 }
1280 return hrc;
1281}
1282
1283
1284HRESULT DHCPIndividualConfig::initWithSettingsAndMachineIdAndSlot(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent,
1285 settings::DHCPIndividualConfig const &rConfig,
1286 com::Guid const &a_idMachine, ULONG a_uSlot,
1287 uint32_t a_uMACAddressVersion)
1288{
1289 AutoInitSpan autoInitSpan(this);
1290 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1291
1292 HRESULT hrc = DHCPConfig::i_initWithSettings(a_pVirtualBox, a_pParent, rConfig);
1293 if (SUCCEEDED(hrc))
1294 {
1295 unconst(m_enmScope) = DHCPConfigScope_MachineNIC;
1296 unconst(m_idMachine) = a_idMachine;
1297 unconst(m_uSlot) = a_uSlot;
1298 m_uMACAddressResolvedVersion = a_uMACAddressVersion;
1299 m_strFixedAddress = rConfig.strFixedAddress;
1300
1301 autoInitSpan.setSucceeded();
1302 }
1303 return hrc;
1304}
1305
1306
1307HRESULT DHCPIndividualConfig::initWithSettingsAndMACAddress(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent,
1308 settings::DHCPIndividualConfig const &rConfig, PCRTMAC a_pMACAddress)
1309{
1310 AutoInitSpan autoInitSpan(this);
1311 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1312
1313 HRESULT hrc = DHCPConfig::i_initWithSettings(a_pVirtualBox, a_pParent, rConfig);
1314 if (SUCCEEDED(hrc))
1315 {
1316 unconst(m_enmScope) = DHCPConfigScope_MAC;
1317 unconst(m_MACAddress) = *a_pMACAddress;
1318 m_strFixedAddress = rConfig.strFixedAddress;
1319
1320 autoInitSpan.setSucceeded();
1321 }
1322 return hrc;
1323}
1324
1325
1326void DHCPIndividualConfig::uninit()
1327{
1328 AutoUninitSpan autoUninitSpan(this);
1329 if (!autoUninitSpan.uninitDone())
1330 autoUninitSpan.setSucceeded();
1331}
1332
1333
1334HRESULT DHCPIndividualConfig::i_saveSettings(settings::DHCPIndividualConfig &a_rDst)
1335{
1336 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1337
1338 a_rDst.uSlot = m_uSlot;
1339 int vrc = a_rDst.strMACAddress.printfNoThrow("%RTmac", &m_MACAddress);
1340 if (m_idMachine.isValid() && !m_idMachine.isZero() && RT_SUCCESS(vrc))
1341 vrc = a_rDst.strVMName.printfNoThrow("%RTuuid", m_idMachine.raw());
1342 if (RT_SUCCESS(vrc))
1343 vrc = a_rDst.strFixedAddress.assignNoThrow(m_strFixedAddress);
1344 if (RT_SUCCESS(vrc))
1345 return DHCPConfig::i_saveSettings(a_rDst);
1346 return E_OUTOFMEMORY;;
1347}
1348
1349
1350HRESULT DHCPIndividualConfig::getMACAddress(com::Utf8Str &aMACAddress)
1351{
1352 /* No locking needed here (the MAC address, machine UUID and NIC slot number cannot change). */
1353 RTMAC MACAddress;
1354 if (m_enmScope == DHCPConfigScope_MAC)
1355 MACAddress = m_MACAddress;
1356 else
1357 {
1358 HRESULT hrc = i_getMachineMAC(&MACAddress);
1359 if (FAILED(hrc))
1360 return hrc;
1361 }
1362
1363 /* Format the return string: */
1364 int vrc = aMACAddress.printfNoThrow("%RTmac", &MACAddress);
1365 return RT_SUCCESS(vrc) ? S_OK : E_OUTOFMEMORY;
1366}
1367
1368
1369HRESULT DHCPIndividualConfig::getMachineId(com::Guid &aId)
1370{
1371 AutoReadLock(this COMMA_LOCKVAL_SRC_POS);
1372 aId = m_idMachine;
1373 return S_OK;
1374}
1375
1376
1377HRESULT DHCPIndividualConfig::getSlot(ULONG *aSlot)
1378{
1379 AutoReadLock(this COMMA_LOCKVAL_SRC_POS);
1380 *aSlot = m_uSlot;
1381 return S_OK;
1382}
1383
1384HRESULT DHCPIndividualConfig::getFixedAddress(com::Utf8Str &aFixedAddress)
1385{
1386 AutoReadLock(this COMMA_LOCKVAL_SRC_POS);
1387 return aFixedAddress.assignEx(m_strFixedAddress);
1388}
1389
1390
1391HRESULT DHCPIndividualConfig::setFixedAddress(const com::Utf8Str &aFixedAddress)
1392{
1393 if (aFixedAddress.isNotEmpty())
1394 {
1395 RTNETADDRIPV4 AddrIgnored;
1396 int vrc = RTNetStrToIPv4Addr(aFixedAddress.c_str(), &AddrIgnored);
1397 if (RT_FAILURE(vrc))
1398 return setErrorBoth(E_INVALIDARG, vrc, tr("Invalid IPv4 address '%s': %Rrc"), aFixedAddress.c_str(), vrc);
1399 }
1400
1401 {
1402 AutoWriteLock(this COMMA_LOCKVAL_SRC_POS);
1403 m_strFixedAddress = aFixedAddress;
1404 }
1405 return i_doWriteConfig();
1406}
1407
1408
1409/**
1410 * Gets the MAC address of m_idMachine + m_uSlot.
1411 *
1412 * @returns COM status code w/ setError.
1413 * @param pMACAddress Where to return the address.
1414 *
1415 * @note Must be called without holding any DHCP related locks as that would
1416 * be lock order violation. The m_idMachine and m_uSlot values are
1417 * practically const, so we don't need any locks here anyway.
1418 */
1419HRESULT DHCPIndividualConfig::i_getMachineMAC(PRTMAC pMACAddress)
1420{
1421 ComObjPtr<Machine> ptrMachine;
1422 HRESULT hrc = m_pVirtualBox->i_findMachine(m_idMachine, false /*fPermitInaccessible*/, true /*aSetError*/, &ptrMachine);
1423 if (SUCCEEDED(hrc))
1424 {
1425 ComPtr<INetworkAdapter> ptrNetworkAdapter;
1426 hrc = ptrMachine->GetNetworkAdapter(m_uSlot, ptrNetworkAdapter.asOutParam());
1427 if (SUCCEEDED(hrc))
1428 {
1429 com::Bstr bstrMACAddress;
1430 hrc = ptrNetworkAdapter->COMGETTER(MACAddress)(bstrMACAddress.asOutParam());
1431 if (SUCCEEDED(hrc))
1432 {
1433 Utf8Str strMACAddress;
1434 try
1435 {
1436 strMACAddress = bstrMACAddress;
1437 }
1438 catch (std::bad_alloc &)
1439 {
1440 return E_OUTOFMEMORY;
1441 }
1442
1443 int vrc = RTNetStrToMacAddr(strMACAddress.c_str(), pMACAddress);
1444 if (RT_SUCCESS(vrc))
1445 hrc = S_OK;
1446 else
1447 hrc = setErrorBoth(E_FAIL, vrc, tr("INetworkAdapter returned bogus MAC address '%ls': %Rrc"),
1448 bstrMACAddress.raw(), vrc);
1449 }
1450 }
1451 }
1452 return hrc;
1453}
1454
1455
1456HRESULT DHCPIndividualConfig::i_resolveMACAddress(uint32_t uVersion)
1457{
1458 HRESULT hrc;
1459 if (m_enmScope == DHCPConfigScope_MachineNIC)
1460 {
1461 RTMAC MACAddress;
1462 hrc = i_getMachineMAC(&MACAddress);
1463 if (SUCCEEDED(hrc))
1464 {
1465 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1466 if ((int32_t)(uVersion - m_uMACAddressResolvedVersion) >= 0)
1467 {
1468 m_uMACAddressResolvedVersion = uVersion;
1469 m_MACAddress = MACAddress;
1470 }
1471 }
1472 }
1473 else
1474 hrc = S_OK;
1475 return hrc;
1476}
1477
1478
1479/**
1480 * Overridden to write out additional config.
1481 */
1482void DHCPIndividualConfig::i_writeDhcpdConfig(xml::ElementNode *pElmConfig)
1483{
1484 char szTmp[RTUUID_STR_LENGTH + 32];
1485 RTStrPrintf(szTmp, sizeof(szTmp), "%RTmac", &m_MACAddress);
1486 pElmConfig->setAttribute("MACAddress", szTmp);
1487
1488 if (m_enmScope == DHCPConfigScope_MachineNIC)
1489 {
1490 RTStrPrintf(szTmp, sizeof(szTmp), "%RTuuid/%u", m_idMachine.raw(), m_uSlot);
1491 pElmConfig->setAttribute("name", szTmp);
1492 }
1493
1494 pElmConfig->setAttribute("fixedAddress", m_strFixedAddress);
1495
1496 DHCPConfig::i_writeDhcpdConfig(pElmConfig);
1497}
1498
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