VirtualBox

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

Last change on this file since 49516 was 49516, checked in by vboxsync, 12 years ago

Introduce option "--need-main(-M) on|off" in network services to emphosize whether network service need to establish connection with Main (by default this optiois off).

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

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