VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageDHCPServer.cpp@ 46967

Last change on this file since 46967 was 46967, checked in by vboxsync, 11 years ago

frontends: haven't find right construction, casted forcebly.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.7 KB
Line 
1/* $Id: VBoxManageDHCPServer.cpp 46967 2013-07-04 06:10:29Z vboxsync $ */
2/** @file
3 * VBoxManage - Implementation of dhcpserver command.
4 */
5
6/*
7 * Copyright (C) 2006-2010 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* Header Files *
20*******************************************************************************/
21#ifndef VBOX_ONLY_DOCS
22#include <VBox/com/com.h>
23#include <VBox/com/array.h>
24#include <VBox/com/ErrorInfo.h>
25#include <VBox/com/errorprint.h>
26#include <VBox/com/VirtualBox.h>
27#endif /* !VBOX_ONLY_DOCS */
28
29#include <iprt/cidr.h>
30#include <iprt/param.h>
31#include <iprt/path.h>
32#include <iprt/stream.h>
33#include <iprt/string.h>
34#include <iprt/net.h>
35#include <iprt/getopt.h>
36#include <iprt/ctype.h>
37
38#include <VBox/log.h>
39
40#include "VBoxManage.h"
41
42#include <string>
43#include <vector>
44#include <map>
45
46#ifndef VBOX_ONLY_DOCS
47using namespace com;
48
49typedef enum enMainOpCodes
50{
51 OP_ADD = 1000,
52 OP_REMOVE,
53 OP_MODIFY
54} OPCODE;
55
56typedef std::map<DhcpOpt_T, std::string> DhcpOptMap;
57typedef DhcpOptMap::iterator DhcpOptIterator;
58typedef DhcpOptMap::value_type DhcpOptValuePair;
59
60struct VmNameSlotKey;
61typedef struct VmNameSlotKey VmNameSlotKey;
62
63struct VmNameSlotKey
64{
65 std::string VmName;
66 uint8_t u8Slot;
67
68 VmNameSlotKey(std::string aVmName, uint8_t aSlot) :
69 VmName(aVmName),
70 u8Slot(aSlot) {}
71
72 bool operator< (const VmNameSlotKey& that) const
73 {
74 if (VmName == that.VmName)
75 return u8Slot < that.u8Slot;
76 else
77 return VmName < that.VmName;
78 }
79};
80
81typedef std::map<VmNameSlotKey, DhcpOptMap> VmSlot2OptionsM;
82typedef VmSlot2OptionsM::iterator VmSlot2OptionsIterator;
83typedef VmSlot2OptionsM::value_type VmSlot2OptionsPair;
84
85typedef std::vector<VmNameSlotKey> VmConfigs;
86
87static const RTGETOPTDEF g_aDHCPIPOptions[]
88 = {
89 { "--netname", 't', RTGETOPT_REQ_STRING }, /* we use 't' instead of 'n' to avoid
90 * 1. the misspelled "-enable" long option to be treated as 'e' (for -enable) + 'n' (for -netname) + "<the_rest_opt>" (for net name)
91 * 2. the misspelled "-netmask" to be treated as 'n' (for -netname) + "<the_rest_opt>" (for net name)
92 */
93 { "-netname", 't', RTGETOPT_REQ_STRING }, // deprecated (if removed check below)
94 { "--ifname", 'f', RTGETOPT_REQ_STRING }, /* we use 'f' instead of 'i' to avoid
95 * 1. the misspelled "-disable" long option to be treated as 'd' (for -disable) + 'i' (for -ifname) + "<the_rest_opt>" (for if name)
96 */
97 { "-ifname", 'f', RTGETOPT_REQ_STRING }, // deprecated
98 { "--ip", 'a', RTGETOPT_REQ_STRING },
99 { "-ip", 'a', RTGETOPT_REQ_STRING }, // deprecated
100 { "--netmask", 'm', RTGETOPT_REQ_STRING },
101 { "-netmask", 'm', RTGETOPT_REQ_STRING }, // deprecated
102 { "--lowerip", 'l', RTGETOPT_REQ_STRING },
103 { "-lowerip", 'l', RTGETOPT_REQ_STRING }, // deprecated
104 { "--upperip", 'u', RTGETOPT_REQ_STRING },
105 { "-upperip", 'u', RTGETOPT_REQ_STRING }, // deprecated
106 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
107 { "-enable", 'e', RTGETOPT_REQ_NOTHING }, // deprecated
108 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
109 { "-disable", 'd', RTGETOPT_REQ_NOTHING }, // deprecated
110 { "--options", 'o', RTGETOPT_REQ_NOTHING },
111 {"--vm", 'n', RTGETOPT_REQ_STRING}, /* only with -o */
112 {"--slot", 's', RTGETOPT_REQ_UINT8}, /* only with -o and -n */
113 {"--id", 'i', RTGETOPT_REQ_UINT8}, /* only with -o */
114 {"--value", 'p', RTGETOPT_REQ_STRING} /* only with -i */
115
116 };
117
118static int handleOp(HandlerArg *a, OPCODE enmCode, int iStart, int *pcProcessed)
119{
120 if (a->argc - iStart < 2)
121 return errorSyntax(USAGE_DHCPSERVER, "Not enough parameters");
122
123 int index = iStart;
124 HRESULT rc;
125 bool fOptionsRead = false;
126 bool fVmOptionRead = false;
127
128 const char *pszVmName = NULL;
129 const char *pNetName = NULL;
130 const char *pIfName = NULL;
131 const char * pIp = NULL;
132 const char * pNetmask = NULL;
133 const char * pLowerIp = NULL;
134 const char * pUpperIp = NULL;
135
136 uint8_t u8OptId = -1;
137 uint8_t u8Slot = -1;
138
139 int enable = -1;
140
141 DhcpOptMap GlobalDhcpOptions;
142 VmSlot2OptionsM VmSlot2Options;
143 VmConfigs VmConfigs2Delete;
144
145 int c;
146 RTGETOPTUNION ValueUnion;
147 RTGETOPTSTATE GetState;
148 RTGetOptInit(&GetState,
149 a->argc,
150 a->argv,
151 g_aDHCPIPOptions,
152 enmCode != OP_REMOVE ? RT_ELEMENTS(g_aDHCPIPOptions) : 4, /* we use only --netname and --ifname for remove*/
153 index,
154 RTGETOPTINIT_FLAGS_NO_STD_OPTS);
155 while ((c = RTGetOpt(&GetState, &ValueUnion)))
156 {
157 switch (c)
158 {
159 case 't': // --netname
160 if(pNetName)
161 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --netname once.");
162 else if (pIfName)
163 return errorSyntax(USAGE_DHCPSERVER, "You can either use a --netname or --ifname for identifying the DHCP server.");
164 else
165 {
166 pNetName = ValueUnion.psz;
167 }
168 break;
169 case 'f': // --ifname
170 if(pIfName)
171 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --ifname once.");
172 else if (pNetName)
173 return errorSyntax(USAGE_DHCPSERVER, "You can either use a --netname or --ipname for identifying the DHCP server.");
174 else
175 {
176 pIfName = ValueUnion.psz;
177 }
178 break;
179 case 'a': // -ip
180 if(pIp)
181 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --ip once.");
182 else
183 {
184 pIp = ValueUnion.psz;
185 }
186 break;
187 case 'm': // --netmask
188 if(pNetmask)
189 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --netmask once.");
190 else
191 {
192 pNetmask = ValueUnion.psz;
193 }
194 break;
195 case 'l': // --lowerip
196 if(pLowerIp)
197 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --lowerip once.");
198 else
199 {
200 pLowerIp = ValueUnion.psz;
201 }
202 break;
203 case 'u': // --upperip
204 if(pUpperIp)
205 return errorSyntax(USAGE_DHCPSERVER, "You can only specify --upperip once.");
206 else
207 {
208 pUpperIp = ValueUnion.psz;
209 }
210 break;
211 case 'e': // --enable
212 if(enable >= 0)
213 return errorSyntax(USAGE_DHCPSERVER, "You can specify either --enable or --disable once.");
214 else
215 {
216 enable = 1;
217 }
218 break;
219 case 'd': // --disable
220 if(enable >= 0)
221 return errorSyntax(USAGE_DHCPSERVER, "You can specify either --enable or --disable once.");
222 else
223 {
224 enable = 0;
225 }
226 break;
227 case VINF_GETOPT_NOT_OPTION:
228 return errorSyntax(USAGE_DHCPSERVER, "unhandled parameter: %s", ValueUnion.psz);
229 break;
230
231 case 'o': // --options
232 {
233 // {"--vm", 'n', RTGETOPT_REQ_STRING}, /* only with -o */
234 // {"--slot", 's', RTGETOPT_REQ_UINT8}, /* only with -o and -n*/
235 // {"--id", 'i', RTGETOPT_REQ_UINT8}, /* only with -o */
236 // {"--value", 'p', RTGETOPT_REQ_STRING} /* only with -i */
237 if (fOptionsRead)
238 return errorSyntax(USAGE_DHCPSERVER,
239 "previos option edition wasn't finished");
240 fOptionsRead = true;
241 fVmOptionRead = false; /* we want specify new global or vm option*/
242 u8Slot = (uint8_t)~0;
243 u8OptId = (uint8_t)~0;
244 pszVmName = NULL;
245 } /* end of --options */
246 break;
247
248 case 'n': // --vm-name
249 {
250 if (fVmOptionRead)
251 return errorSyntax(USAGE_DHCPSERVER,
252 "previous vm option edition wasn't finished");
253 else
254 fVmOptionRead = true;
255 u8Slot = (uint8_t)~0; /* clear slor */
256 pszVmName = RTStrDup(ValueUnion.psz);
257 }
258 break; /* end of --vm-name */
259
260 case 's': // --slot
261 {
262 if (!fVmOptionRead)
263 return errorSyntax(USAGE_DHCPSERVER,
264 "vm name wasn't specified");
265
266 u8Slot = ValueUnion.u8;
267 }
268 break; /* end of --slot */
269
270 case 'i': // --id
271 {
272 if (!fOptionsRead)
273 return errorSyntax(USAGE_DHCPSERVER,
274 "-o wasn't found");
275
276 u8OptId = ValueUnion.u8;
277 }
278 break; /* end of --id */
279
280 case 'p': // --value
281 {
282 if (!fOptionsRead)
283 return errorSyntax(USAGE_DHCPSERVER,
284 "-o wasn't found");
285
286 if (u8OptId == (uint8_t)~0)
287 return errorSyntax(USAGE_DHCPSERVER,
288 "--id wasn't found");
289 if ( fVmOptionRead
290 && u8Slot == (uint8_t)~0)
291 return errorSyntax(USAGE_DHCPSERVER,
292 "--slot wasn't found");
293
294 DhcpOptMap& map = (fVmOptionRead ?
295 VmSlot2Options[
296 VmNameSlotKey::VmNameSlotKey(pszVmName,
297 u8Slot)]
298 : GlobalDhcpOptions);
299 std::string strVal = ValueUnion.psz;
300 map.insert(DhcpOptValuePair((DhcpOpt_T)u8OptId, strVal));
301
302 }
303 break; // --end of value
304
305 default:
306 if (c > 0)
307 {
308 if (RT_C_IS_GRAPH(c))
309 return errorSyntax(USAGE_DHCPSERVER, "unhandled option: -%c", c);
310 else
311 return errorSyntax(USAGE_DHCPSERVER, "unhandled option: %i", c);
312 }
313 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
314 return errorSyntax(USAGE_DHCPSERVER, "unknown option: %s", ValueUnion.psz);
315 else if (ValueUnion.pDef)
316 return errorSyntax(USAGE_DHCPSERVER, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
317 else
318 return errorSyntax(USAGE_DHCPSERVER, "%Rrs", c);
319 }
320 }
321
322 if(! pNetName && !pIfName)
323 return errorSyntax(USAGE_DHCPSERVER, "You need to specify either --netname or --ifname to identify the DHCP server");
324
325 if( enmCode != OP_REMOVE
326 && GlobalDhcpOptions.size() == 0
327 && VmSlot2Options.size() == 0)
328 {
329 if(enable < 0 || pIp || pNetmask || pLowerIp || pUpperIp)
330 {
331 if(!pIp)
332 return errorSyntax(USAGE_DHCPSERVER, "You need to specify --ip option");
333
334 if(!pNetmask)
335 return errorSyntax(USAGE_DHCPSERVER, "You need to specify --netmask option");
336
337 if(!pLowerIp)
338 return errorSyntax(USAGE_DHCPSERVER, "You need to specify --lowerip option");
339
340 if(!pUpperIp)
341 return errorSyntax(USAGE_DHCPSERVER, "You need to specify --upperip option");
342 }
343 }
344
345 Bstr NetName;
346 if(!pNetName)
347 {
348 ComPtr<IHost> host;
349 CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
350
351 ComPtr<IHostNetworkInterface> hif;
352 CHECK_ERROR(host, FindHostNetworkInterfaceByName(Bstr(pIfName).mutableRaw(), hif.asOutParam()));
353 if (FAILED(rc))
354 return errorArgument("Could not find interface '%s'", pIfName);
355
356 CHECK_ERROR(hif, COMGETTER(NetworkName) (NetName.asOutParam()));
357 if (FAILED(rc))
358 return errorArgument("Could not get network name for the interface '%s'", pIfName);
359 }
360 else
361 {
362 NetName = Bstr(pNetName);
363 }
364
365 ComPtr<IDHCPServer> svr;
366 rc = a->virtualBox->FindDHCPServerByNetworkName(NetName.mutableRaw(), svr.asOutParam());
367 if(enmCode == OP_ADD)
368 {
369 if (SUCCEEDED(rc))
370 return errorArgument("DHCP server already exists");
371
372 CHECK_ERROR(a->virtualBox, CreateDHCPServer(NetName.mutableRaw(), svr.asOutParam()));
373 if (FAILED(rc))
374 return errorArgument("Failed to create the DHCP server");
375 }
376 else if (FAILED(rc))
377 {
378 return errorArgument("DHCP server does not exist");
379 }
380
381 if(enmCode != OP_REMOVE)
382 {
383 if (pIp || pNetmask || pLowerIp || pUpperIp)
384 {
385 CHECK_ERROR(svr, SetConfiguration (
386 Bstr(pIp).mutableRaw(),
387 Bstr(pNetmask).mutableRaw(),
388 Bstr(pLowerIp).mutableRaw(),
389 Bstr(pUpperIp).mutableRaw()));
390 if(FAILED(rc))
391 return errorArgument("Failed to set configuration");
392 }
393
394 if(enable >= 0)
395 {
396 CHECK_ERROR(svr, COMSETTER(Enabled) ((BOOL)enable));
397 }
398
399 /* option processing */
400 DhcpOptIterator itOpt;
401 VmSlot2OptionsIterator it;
402
403 /* Global Options */
404 for(itOpt = GlobalDhcpOptions.begin();
405 itOpt != GlobalDhcpOptions.end();
406 ++itOpt)
407 {
408 CHECK_ERROR(svr,
409 AddGlobalOption(
410 itOpt->first,
411 com::Bstr(itOpt->second.c_str()).raw()));
412 }
413
414 /* heh, vm slot options. */
415
416 for (it = VmSlot2Options.begin();
417 it != VmSlot2Options.end();
418 ++it)
419 {
420 for(itOpt = it->second.begin();
421 itOpt != it->second.end();
422 ++itOpt)
423 {
424 CHECK_ERROR(svr,
425 AddVmSlotOption(Bstr(it->first.VmName.c_str()).raw(),
426 it->first.u8Slot,
427 itOpt->first,
428 com::Bstr(itOpt->second.c_str()).raw()));
429 }
430 }
431 }
432 else
433 {
434 CHECK_ERROR(a->virtualBox, RemoveDHCPServer(svr));
435 if(FAILED(rc))
436 return errorArgument("Failed to remove server");
437 }
438
439 return 0;
440}
441
442
443int handleDHCPServer(HandlerArg *a)
444{
445 if (a->argc < 1)
446 return errorSyntax(USAGE_DHCPSERVER, "Not enough parameters");
447
448 int result;
449 int cProcessed;
450 if (strcmp(a->argv[0], "modify") == 0)
451 result = handleOp(a, OP_MODIFY, 1, &cProcessed);
452 else if (strcmp(a->argv[0], "add") == 0)
453 result = handleOp(a, OP_ADD, 1, &cProcessed);
454 else if (strcmp(a->argv[0], "remove") == 0)
455 result = handleOp(a, OP_REMOVE, 1, &cProcessed);
456 else
457 result = errorSyntax(USAGE_DHCPSERVER, "Invalid parameter '%s'", Utf8Str(a->argv[0]).c_str());
458
459 return result;
460}
461
462#endif /* !VBOX_ONLY_DOCS */
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