VirtualBox

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

Last change on this file since 54314 was 54314, checked in by vboxsync, 10 years ago

Main/DHCPServerImpl: for DHCP options keep not just the text
representation, but also encoding of that text representation.

When XML settings are read, interpret old format, without explicit
"encoding" attribute, as legacy encoding where we are expected to know
the actual format of the option from the option code itself. When
writing legacy options, write them in old format.

This is in preparation for using "de:ad:be:ef" hex-encoded option
values for non-standard options which format we can't know a priory.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.7 KB
Line 
1/* $Id: DHCPServerImpl.cpp 54314 2015-02-19 21:32:18Z vboxsync $ */
2
3/** @file
4 *
5 * VirtualBox COM class implementation
6 */
7
8/*
9 * Copyright (C) 2006-2013 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() : enabled(FALSE) {}
43
44 Bstr IPAddress;
45 Bstr lowerIP;
46 Bstr upperIP;
47
48 BOOL enabled;
49 DHCPServerRunner dhcp;
50
51 DhcpOptionMap GlobalDhcpOptions;
52 VmSlot2OptionsMap VmSlot2Options;
53};
54
55
56DHCPServer::DHCPServer()
57 : m(NULL), mVirtualBox(NULL)
58{
59 m = new DHCPServer::Data();
60}
61
62
63DHCPServer::~DHCPServer()
64{
65 if (m)
66 {
67 delete m;
68 m = NULL;
69 }
70}
71
72
73HRESULT DHCPServer::FinalConstruct()
74{
75 return BaseFinalConstruct();
76}
77
78
79void DHCPServer::FinalRelease()
80{
81 uninit ();
82
83 BaseFinalRelease();
84}
85
86
87void DHCPServer::uninit()
88{
89 /* Enclose the state transition Ready->InUninit->NotReady */
90 AutoUninitSpan autoUninitSpan(this);
91 if (autoUninitSpan.uninitDone())
92 return;
93
94 unconst(mVirtualBox) = NULL;
95}
96
97
98HRESULT DHCPServer::init(VirtualBox *aVirtualBox, IN_BSTR aName)
99{
100 AssertReturn(aName != NULL, E_INVALIDARG);
101
102 AutoInitSpan autoInitSpan(this);
103 AssertReturn(autoInitSpan.isOk(), E_FAIL);
104
105 /* share VirtualBox weakly (parent remains NULL so far) */
106 unconst(mVirtualBox) = aVirtualBox;
107
108 unconst(mName) = aName;
109 m->IPAddress = "0.0.0.0";
110 m->GlobalDhcpOptions[DhcpOpt_SubnetMask] = DhcpOptValue("0.0.0.0");
111 m->enabled = FALSE;
112
113 m->lowerIP = "0.0.0.0";
114 m->upperIP = "0.0.0.0";
115
116 /* Confirm a successful initialization */
117 autoInitSpan.setSucceeded();
118
119 return S_OK;
120}
121
122
123HRESULT DHCPServer::init(VirtualBox *aVirtualBox,
124 const settings::DHCPServer &data)
125{
126 /* Enclose the state transition NotReady->InInit->Ready */
127 AutoInitSpan autoInitSpan(this);
128 AssertReturn(autoInitSpan.isOk(), E_FAIL);
129
130 /* share VirtualBox weakly (parent remains NULL so far) */
131 unconst(mVirtualBox) = aVirtualBox;
132
133 unconst(mName) = data.strNetworkName;
134 m->IPAddress = data.strIPAddress;
135 m->enabled = data.fEnabled;
136 m->lowerIP = data.strIPLower;
137 m->upperIP = data.strIPUpper;
138
139 m->GlobalDhcpOptions.clear();
140 m->GlobalDhcpOptions.insert(data.GlobalDhcpOptions.begin(),
141 data.GlobalDhcpOptions.end());
142
143 m->VmSlot2Options.clear();
144 m->VmSlot2Options.insert(data.VmSlot2OptionsM.begin(),
145 data.VmSlot2OptionsM.end());
146
147 autoInitSpan.setSucceeded();
148
149 return S_OK;
150}
151
152
153HRESULT DHCPServer::i_saveSettings(settings::DHCPServer &data)
154{
155 AutoCaller autoCaller(this);
156 if (FAILED(autoCaller.rc())) return autoCaller.rc();
157
158 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
159
160 data.strNetworkName = mName;
161 data.strIPAddress = m->IPAddress;
162
163 data.fEnabled = !!m->enabled;
164 data.strIPLower = m->lowerIP;
165 data.strIPUpper = m->upperIP;
166
167 data.GlobalDhcpOptions.clear();
168 data.GlobalDhcpOptions.insert(m->GlobalDhcpOptions.begin(),
169 m->GlobalDhcpOptions.end());
170
171 data.VmSlot2OptionsM.clear();
172 data.VmSlot2OptionsM.insert(m->VmSlot2Options.begin(),
173 m->VmSlot2Options.end());
174
175 return S_OK;
176}
177
178
179HRESULT DHCPServer::getNetworkName(com::Utf8Str &aName)
180{
181 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
182
183 aName = mName;
184 return S_OK;
185}
186
187
188HRESULT DHCPServer::getEnabled(BOOL *aEnabled)
189{
190 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
191
192 *aEnabled = m->enabled;
193 return S_OK;
194}
195
196
197HRESULT DHCPServer::setEnabled(BOOL aEnabled)
198{
199 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
200 m->enabled = aEnabled;
201
202 // save the global settings; for that we should hold only the VirtualBox lock
203 alock.release();
204 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
205 HRESULT rc = mVirtualBox->i_saveSettings();
206
207 return rc;
208}
209
210
211HRESULT DHCPServer::getIPAddress(com::Utf8Str &aIPAddress)
212{
213 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
214
215 aIPAddress = Utf8Str(m->IPAddress);
216 return S_OK;
217}
218
219
220HRESULT DHCPServer::getNetworkMask(com::Utf8Str &aNetworkMask)
221{
222 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
223
224 aNetworkMask = m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text;
225 return S_OK;
226}
227
228
229HRESULT DHCPServer::getLowerIP(com::Utf8Str &aIPAddress)
230{
231 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
232
233 aIPAddress = Utf8Str(m->lowerIP);
234 return S_OK;
235}
236
237
238HRESULT DHCPServer::getUpperIP(com::Utf8Str &aIPAddress)
239{
240 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
241
242 aIPAddress = Utf8Str(m->upperIP);
243 return S_OK;
244}
245
246
247HRESULT DHCPServer::setConfiguration(const com::Utf8Str &aIPAddress,
248 const com::Utf8Str &aNetworkMask,
249 const com::Utf8Str &aLowerIP,
250 const com::Utf8Str &aUpperIP)
251{
252 AssertReturn(!aIPAddress.isEmpty(), E_INVALIDARG);
253 AssertReturn(!aNetworkMask.isEmpty(), E_INVALIDARG);
254 AssertReturn(!aLowerIP.isEmpty(), E_INVALIDARG);
255 AssertReturn(!aUpperIP.isEmpty(), E_INVALIDARG);
256
257 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
258 m->IPAddress = aIPAddress;
259 m->GlobalDhcpOptions[DhcpOpt_SubnetMask] = aNetworkMask;
260
261 m->lowerIP = aLowerIP;
262 m->upperIP = aUpperIP;
263
264 // save the global settings; for that we should hold only the VirtualBox lock
265 alock.release();
266 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
267 return mVirtualBox->i_saveSettings();
268}
269
270
271HRESULT DHCPServer::addGlobalOption(DhcpOpt_T aOption, const com::Utf8Str &aValue)
272{
273 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
274
275 m->GlobalDhcpOptions[aOption] = aValue;
276
277 /* Indirect way to understand that we're on NAT network */
278 if (aOption == DhcpOpt_Router)
279 m->dhcp.setOption(NetworkServiceRunner::kNsrKeyNeedMain, "on");
280
281 alock.release();
282
283 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
284 return mVirtualBox->i_saveSettings();
285}
286
287
288HRESULT DHCPServer::getGlobalOptions(std::vector<com::Utf8Str> &aValue)
289{
290 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
291 aValue.resize(m->GlobalDhcpOptions.size());
292 DhcpOptionMap::const_iterator it;
293 size_t i = 0;
294 for (it = m->GlobalDhcpOptions.begin(); it != m->GlobalDhcpOptions.end(); ++it, ++i)
295 {
296 uint32_t OptCode = (*it).first;
297 const DhcpOptValue &OptValue = (*it).second;
298
299 // XXX: TODO: factor out and share with getVmSlotOptions()
300 if (OptValue.encoding == DhcpOptValue::LEGACY)
301 aValue[i] = Utf8StrFmt("%d:%s", OptCode, OptValue.text.c_str());
302 }
303
304 return S_OK;
305}
306
307HRESULT DHCPServer::getVmConfigs(std::vector<com::Utf8Str> &aValue)
308{
309 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
310 aValue.resize(m->VmSlot2Options.size());
311 VmSlot2OptionsMap::const_iterator it;
312 size_t i = 0;
313 for (it = m->VmSlot2Options.begin(); it != m->VmSlot2Options.end(); ++it, ++i)
314 {
315 aValue[i] = Utf8StrFmt("[%s]:%d", it->first.VmName.c_str(), it->first.Slot);
316 }
317
318 return S_OK;
319}
320
321
322HRESULT DHCPServer::addVmSlotOption(const com::Utf8Str &aVmName,
323 LONG aSlot,
324 DhcpOpt_T aOption,
325 const com::Utf8Str &aValue)
326{
327 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
328 m->VmSlot2Options[settings::VmNameSlotKey(aVmName, aSlot)][aOption] = aValue;
329 alock.release();
330
331 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
332 return mVirtualBox->i_saveSettings();
333}
334
335
336HRESULT DHCPServer::removeVmSlotOptions(const com::Utf8Str &aVmName, LONG aSlot)
337{
338 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
339 DhcpOptionMap& map = i_findOptMapByVmNameSlot(aVmName, aSlot);
340 map.clear();
341
342 alock.release();
343
344 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
345 return mVirtualBox->i_saveSettings();
346}
347
348/**
349 * this is mapping (vm, slot)
350 */
351HRESULT DHCPServer::getVmSlotOptions(const com::Utf8Str &aVmName,
352 LONG aSlot,
353 std::vector<com::Utf8Str> &aValues)
354{
355
356 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
357 DhcpOptionMap& map = i_findOptMapByVmNameSlot(aVmName, aSlot);
358 aValues.resize(map.size());
359 size_t i = 0;
360 DhcpOptionMap::const_iterator it;
361 for (it = map.begin(); it != map.end(); ++it, ++i)
362 {
363 uint32_t OptCode = (*it).first;
364 const DhcpOptValue &OptValue = (*it).second;
365
366 // XXX: TODO: factor out and share with getGlobalOptions()
367 if (OptValue.encoding == DhcpOptValue::LEGACY)
368 aValues[i] = com::Utf8StrFmt("%d:%s", OptCode, OptValue.text.c_str());
369 }
370
371 return S_OK;
372}
373
374
375HRESULT DHCPServer::getMacOptions(const com::Utf8Str &aMAC, std::vector<com::Utf8Str> &aOption)
376{
377 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
378 HRESULT hrc = S_OK;
379 ComPtr<IMachine> machine;
380 ComPtr<INetworkAdapter> nic;
381 VmSlot2OptionsIterator it;
382 for(it = m->VmSlot2Options.begin(); it != m->VmSlot2Options.end(); ++it)
383 {
384 alock.release();
385 hrc = mVirtualBox->FindMachine(Bstr(it->first.VmName).raw(), machine.asOutParam());
386 alock.acquire();
387
388 if (FAILED(hrc))
389 continue;
390
391 alock.release();
392 hrc = machine->GetNetworkAdapter(it->first.Slot, nic.asOutParam());
393 alock.acquire();
394
395 if (FAILED(hrc))
396 continue;
397
398 com::Bstr mac;
399
400 alock.release();
401 hrc = nic->COMGETTER(MACAddress)(mac.asOutParam());
402 alock.acquire();
403
404 if (FAILED(hrc)) /* no MAC address ??? */
405 break;
406 if (!RTStrICmp(com::Utf8Str(mac).c_str(), aMAC.c_str()))
407 return getVmSlotOptions(it->first.VmName,
408 it->first.Slot,
409 aOption);
410 } /* end of for */
411
412 return hrc;
413}
414
415HRESULT DHCPServer::getEventSource(ComPtr<IEventSource> &aEventSource)
416{
417 NOREF(aEventSource);
418 ReturnComNotImplemented();
419}
420
421
422HRESULT DHCPServer::start(const com::Utf8Str &aNetworkName,
423 const com::Utf8Str &aTrunkName,
424 const com::Utf8Str &aTrunkType)
425{
426 /* Silently ignore attempts to run disabled servers. */
427 if (!m->enabled)
428 return S_OK;
429
430 /* Commmon Network Settings */
431 m->dhcp.setOption(NetworkServiceRunner::kNsrKeyNetwork, aNetworkName.c_str());
432
433 if (!aTrunkName.isEmpty())
434 m->dhcp.setOption(NetworkServiceRunner::kNsrTrunkName, aTrunkName.c_str());
435
436 m->dhcp.setOption(NetworkServiceRunner::kNsrKeyTrunkType, aTrunkType.c_str());
437
438 /* XXX: should this MAC default initialization moved to NetworkServiceRunner? */
439 char strMAC[32];
440 Guid guid;
441 guid.create();
442 RTStrPrintf (strMAC, sizeof(strMAC), "08:00:27:%02X:%02X:%02X",
443 guid.raw()->au8[0],
444 guid.raw()->au8[1],
445 guid.raw()->au8[2]);
446 m->dhcp.setOption(NetworkServiceRunner::kNsrMacAddress, strMAC);
447 m->dhcp.setOption(NetworkServiceRunner::kNsrIpAddress, Utf8Str(m->IPAddress).c_str());
448 m->dhcp.setOption(NetworkServiceRunner::kNsrIpNetmask, Utf8Str(m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text).c_str());
449 m->dhcp.setOption(DHCPServerRunner::kDsrKeyLowerIp, Utf8Str(m->lowerIP).c_str());
450 m->dhcp.setOption(DHCPServerRunner::kDsrKeyUpperIp, Utf8Str(m->upperIP).c_str());
451
452 /* XXX: This parameters Dhcp Server will fetch via API */
453 return RT_FAILURE(m->dhcp.start()) ? E_FAIL : S_OK;
454 //m->dhcp.detachFromServer(); /* need to do this to avoid server shutdown on runner destruction */
455}
456
457
458HRESULT DHCPServer::stop (void)
459{
460 return RT_FAILURE(m->dhcp.stop()) ? E_FAIL : S_OK;
461}
462
463
464DhcpOptionMap& DHCPServer::i_findOptMapByVmNameSlot(const com::Utf8Str& aVmName,
465 LONG aSlot)
466{
467 return m->VmSlot2Options[settings::VmNameSlotKey(aVmName, aSlot)];
468}
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