VirtualBox

Changeset 79732 in vbox for trunk


Ignore:
Timestamp:
Jul 12, 2019 12:40:09 PM (6 years ago)
Author:
vboxsync
Message:

Main: Redoing the IDHCPServer interface, part I. bugref:9288

Location:
trunk
Files:
2 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/log.h

    r79524 r79732  
    371371    /** Main group, IDataStream. */
    372372    LOG_GROUP_MAIN_DATASTREAM,
     373    /** Main group, IDHCPConfig. */
     374    LOG_GROUP_MAIN_DHCPCONFIG,
     375    /** Main group, IDHCPGlobalConfig. */
     376    LOG_GROUP_MAIN_DHCPGLOBALCONFIG,
     377    /** Main group, IDHCPGroupCondition. */
     378    LOG_GROUP_MAIN_DHCPGROUPCONDITION,
     379    /** Main group, IDHCPGroupConfig. */
     380    LOG_GROUP_MAIN_DHCPGROUPCONFIG,
     381    /** Main group, IDHCPIndividualConfig. */
     382    LOG_GROUP_MAIN_DHCPINDIVIDUALCONFIG,
    373383    /** Main group, IDHCPServer. */
    374384    LOG_GROUP_MAIN_DHCPSERVER,
     
    892902    "MAIN_DATAMODEL", \
    893903    "MAIN_DATASTREAM", \
     904    "MAIN_DHCPCONFIG", \
     905    "MAIN_DHCPGLOBALCONFIG", \
     906    "MAIN_DHCPGROUPCONDITION", \
     907    "MAIN_DHCPGROUPCONFIG", \
     908    "MAIN_DHCPINDIVIDUALCONFIG", \
    894909    "MAIN_DHCPSERVER", \
    895910    "MAIN_DIRECTORY", \
  • trunk/include/VBox/settings.h

    r78632 r79732  
    338338{
    339339    DhcpOptValue();
    340     DhcpOptValue(const com::Utf8Str &aText, DhcpOptEncoding_T aEncoding = DhcpOptEncoding_Legacy);
    341 
    342     com::Utf8Str text;
    343     DhcpOptEncoding_T encoding;
     340    DhcpOptValue(const com::Utf8Str &aText, DHCPOptionEncoding_T aEncoding = DHCPOptionEncoding_Legacy);
     341
     342    com::Utf8Str            strValue;
     343    DHCPOptionEncoding_T    enmEncoding;
    344344};
    345345
     
    349349typedef DhcpOptionMap::const_iterator DhcpOptConstIterator;
    350350
    351 typedef struct VmNameSlotKey
    352 {
    353     VmNameSlotKey(const com::Utf8Str& aVmName, LONG aSlot);
    354 
    355     bool operator<(const VmNameSlotKey& that) const;
    356 
    357     const com::Utf8Str VmName;
    358     LONG      Slot;
    359 } VmNameSlotKey;
    360 
    361 typedef std::map<VmNameSlotKey, DhcpOptionMap> VmSlot2OptionsMap;
    362 typedef VmSlot2OptionsMap::value_type VmSlot2OptionsPair;
    363 typedef VmSlot2OptionsMap::iterator VmSlot2OptionsIterator;
    364 typedef VmSlot2OptionsMap::const_iterator VmSlot2OptionsConstIterator;
     351struct DHCPConfig
     352{
     353    DHCPConfig();
     354
     355    DhcpOptionMap           OptionMap;
     356    uint32_t                secMinLeaseTime;
     357    uint32_t                secDefaultLeaseTime;
     358    uint32_t                secMaxLeaseTime;
     359};
     360
     361struct DHCPIndividualConfig : DHCPConfig
     362{
     363    DHCPIndividualConfig();
     364
     365    com::Utf8Str            strMACAddress;
     366    com::Utf8Str            strVMName;
     367    ULONG                   uSlot;
     368    com::Utf8Str            strFixedAddress;
     369};
     370
     371typedef std::map<com::Utf8Str, DHCPIndividualConfig> DHCPIndividualConfigMap;
    365372
    366373struct DHCPServer
     
    368375    DHCPServer();
    369376
    370     com::Utf8Str    strNetworkName,
    371                     strIPAddress,
    372                     strIPLower,
    373                     strIPUpper;
    374     bool            fEnabled;
    375     DhcpOptionMap   GlobalDhcpOptions;
    376     VmSlot2OptionsMap VmSlot2OptionsM;
     377    com::Utf8Str            strNetworkName;
     378    com::Utf8Str            strIPAddress;
     379    com::Utf8Str            strIPLower;
     380    com::Utf8Str            strIPUpper;
     381    bool                    fEnabled;
     382    DHCPConfig              GlobalConfig;
     383    DHCPIndividualConfigMap IndividualConfigs;
    377384};
    378385
     
    409416
    410417    void readMachineRegistry(const xml::ElementNode &elmMachineRegistry);
    411     void readDHCPServers(const xml::ElementNode &elmDHCPServers);
    412     void readDhcpOptions(DhcpOptionMap& map, const xml::ElementNode& options);
    413418    void readNATNetworks(const xml::ElementNode &elmNATNetworks);
    414419
     
    427432    void buildUSBDeviceSources(xml::ElementNode &elmParent, const USBDeviceSourcesList &ll);
    428433    void readUSBDeviceSources(const xml::ElementNode &elmDeviceSources, USBDeviceSourcesList &ll);
     434    void buildDHCPServers(xml::ElementNode &elmDHCPServers, DHCPServersList const &ll);
     435    void buildDHCPOptions(xml::ElementNode &elmOptions, DHCPConfig const &rConfig, bool fIgnoreSubnetMask);
     436    void readDHCPServers(const xml::ElementNode &elmDHCPServers);
     437    void readDHCPOptions(DHCPConfig &rConfig, const xml::ElementNode &elmOptions, bool fIgnoreSubnetMask);
    429438    bool convertGuiProxySettings(const com::Utf8Str &strUIProxySettings);
    430439};
  • trunk/src/VBox/Main/Makefile.kmk

    r79360 r79732  
    550550        src-server/DataStreamImpl.cpp \
    551551        src-server/DHCPServerImpl.cpp \
     552        src-server/DHCPConfigImpl.cpp \
    552553        src-server/NetworkServiceRunner.cpp \
    553554        src-server/NATNetworkImpl.cpp \
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r79727 r79732  
    18241824
    18251825  <enum
    1826       name="DhcpOptEncoding"
    1827       uuid="88ea6d70-8648-4871-ba30-1f49c61cfaa2">
     1826      name="DHCPOptionEncoding"
     1827      uuid="84b6d460-2838-4682-c0d6-ef5b573ef28a">
    18281828    <const name="Legacy" value="0"/>
    1829     <const name="Hex" value="1"/>
     1829    <const name="Hex"    value="1"/>
     1830  </enum>
     1831
     1832  <enum
     1833      name="DHCPConfigScope"
     1834      uuid="151df7cd-e596-42dd-235a-b164a781c099">
     1835    <const name="Global"      value="0"><desc><link to="IDHCPServer::globalConfig"/></desc></const>
     1836    <const name="MachineNIC"  value="1"><desc><link to="IDHCPServer::individualConfigs"/></desc></const>
     1837    <const name="MAC"         value="2"><desc><link to="IDHCPServer::individualConfigs"/></desc></const>
     1838    <const name="Group"       value="3"><desc><link to="IDHCPServer::groupConfigs"/></desc></const>
     1839  </enum>
     1840
     1841  <enum
     1842    name="DHCPGroupFilterType"
     1843    uuid="0639cd66-94b7-41ef-18ac-485636e46d97"
     1844    >
     1845    <const name="MAC"                     value="0"><desc>MAC address</desc></const>
     1846    <const name="MACWildcard"             value="1"><desc>MAC address wildcard pattern.</desc></const>
     1847    <const name="vendorClassID"           value="2"><desc>Vendor class ID</desc></const>
     1848    <const name="vendorClassIDWildcard"   value="3"><desc>Vendor class ID wildcard pattern.</desc></const>
     1849    <const name="userClassID"             value="4"><desc>User class ID</desc></const>
     1850    <const name="userClassIDWildcard"     value="5"><desc>User class ID wildcard pattern.</desc></const>
    18301851  </enum>
    18311852
     
    18341855    uuid="ea2d467f-b6c2-4b9a-8eb5-6e2f275dd72e"
    18351856    wsmap="managed"
    1836     reservedMethods="1" reservedAttributes="6"
     1857    reservedMethods="0" reservedAttributes="3"
    18371858    >
    18381859    <desc>
     
    18811902
    18821903    <method name="addGlobalOption">
     1904      <desc>6.0 legacy, will be removed in 6.1.</desc>
    18831905      <param name="option" type="DhcpOpt" dir="in"/>
    18841906      <param name="value" type="wstring" dir="in" />
     
    18861908
    18871909    <method name="removeGlobalOption">
    1888       <desc>
    1889         removes the specified option
    1890         <result name="E_INVALIDARG">
    1891           invalid option id supplied
    1892         </result>
    1893       </desc>
     1910      <desc>6.0 legacy, will be removed in 6.1.</desc>
    18941911      <param name="option" type="DhcpOpt" dir="in"/>
    18951912    </method>
    18961913
    18971914    <method name="removeGlobalOptions">
    1898       <desc>
    1899         removes all global options
    1900         <result name="E_FAIL">
    1901           failed to remove global options
    1902         </result>
    1903       </desc>
     1915      <desc>Legacy interface, will be removed in 6.1.</desc>
    19041916    </method>
    19051917
    19061918    <!-- string in format: "option_id:value" -->
    1907     <attribute name="globalOptions" type="wstring" safearray="yes" readonly="yes"/>
     1919    <attribute name="globalOptions" type="wstring" safearray="yes" readonly="yes">
     1920      <desc>Legacy interface, will be removed in 6.1.</desc>
     1921    </attribute>
    19081922
    19091923    <!-- string in format: "[vm name]:slot" -->
    1910     <attribute name="vmConfigs" type="wstring" safearray="yes" readonly="yes"/>
     1924    <attribute name="vmConfigs" type="wstring" safearray="yes" readonly="yes">
     1925      <desc>Legacy interface, will be removed in 6.1.</desc>
     1926    </attribute>
     1927
     1928    <attribute name="globalConfig" type="IDHCPGlobalConfig" readonly="yes">
     1929      <desc>Global configuration that applies to all clients.</desc>
     1930    </attribute>
     1931
     1932    <attribute name="groupConfigs" type="IDHCPGroupConfig" safearray="yes" readonly="yes">
     1933      <desc>Configuration groups that applies to selected clients, selection is flexible.</desc>
     1934    </attribute>
     1935
     1936    <attribute name="individualConfigs" type="IDHCPIndividualConfig" safearray="yes" readonly="yes">
     1937      <desc>Individual NIC configurations either by MAC address or VM + NIC number.</desc>
     1938    </attribute>
    19111939
    19121940    <!-- VM-slot settings
     
    19311959    -->
    19321960    <method name="addVmSlotOption">
     1961      <desc>6.0 legacy, will be removed in 6.1.</desc>
    19331962      <param name="vmname" type="wstring" dir="in"/>
    19341963      <param name="slot" type="long" dir="in"/>
     
    19381967
    19391968    <method name="removeVmSlotOption">
    1940       <desc>
    1941         removes the specified option
    1942         <result name="E_INVALIDARG">
    1943           invalid VM, slot, or option id supplied
    1944         </result>
    1945       </desc>
     1969      <desc>6.0 legacy, will be removed in 6.1.</desc>
    19461970      <param name="vmname" type="wstring" dir="in"/>
    19471971      <param name="slot" type="long" dir="in"/>
     
    19501974
    19511975    <method name="removeVmSlotOptions">
    1952       <desc>
    1953         removes all option for the specified adapter
    1954         <result name="E_INVALIDARG">
    1955           invalid VM or slot supplied
    1956         </result>
    1957       </desc>
     1976      <desc>6.0 legacy, will be removed in 6.1.</desc>
    19581977      <param name="vmname" type="wstring" dir="in"/>
    19591978      <param name="slot" type="long" dir="in"/>
     
    19621981    <!-- returns array of strings in format: "option_id:value" for a given pair (vm, slot) -->
    19631982    <method name="getVmSlotOptions">
     1983      <desc>6.0 legacy, will be removed in 6.1.</desc>
    19641984      <param name="vmname" type="wstring" dir="in"/>
    19651985      <param name="slot" type="long" dir="in"/>
     
    19691989    <!-- Returns options by MAC address -->
    19701990    <method name="getMacOptions">
     1991      <desc>6.0 legacy, will be removed in 6.1.</desc>
    19711992      <param name="mac" type="wstring" dir="in"/>
    19721993      <param name="option" type="wstring" safearray="yes" dir="return"/>
     
    20742095    </method>
    20752096
     2097    <method name="getConfig">
     2098      <desc>
     2099        Gets or adds a configuration.
     2100      </desc>
     2101      <param name="scope"  dir="in" type="DHCPConfigScope">
     2102        <desc>The kind of configuration being sought or added.</desc>
     2103      </param>
     2104      <param name="name"   dir="in" type="wstring">
     2105        <desc>
     2106          Meaning depends on the @a scope:
     2107            - Ignored when the @a scope is <link to="DHCPConfigScope::Global"/>.
     2108            - A VM name or UUID for <link to="DHCPConfigScope::MachineNIC"/>.
     2109            - A MAC address for <link to="DHCPConfigScope::MAC"/>.
     2110            - A group name for <link to="DHCPConfigScope::Group"/>.
     2111        </desc>
     2112      </param>
     2113      <param name="slot"   dir="in" type="unsigned long">
     2114        <desc>The NIC slot when @a scope is set to <link to="DHCPConfigScope::MachineNIC"/>,
     2115          must be zero for all other scope values.
     2116        </desc>
     2117      </param>
     2118      <param name="mayAdd" dir="in" type="boolean">
     2119        <desc>
     2120          Set to @c TRUE if the configuration should be added if not found.
     2121          If set to @c FALSE the method will fail with VBOX_E_OBJECT_NOT_FOUND.
     2122        </desc>
     2123      </param>
     2124      <param name="config" dir="return" type="IDHCPConfig">
     2125        <desc>The requested configuration.</desc>
     2126      </param>
     2127    </method>
     2128
    20762129    <!-- @todo Add variant of queryLeaseByMac that goes by VM name and optionally slot. -->
    2077     <!-- @todo Add min/default/max lease time settings -->
    20782130    <!-- @todo Add lease database attribute (readonly) -->
    2079     <!-- @todo Add methods for complex group operations, that includes lists of mac address,
    2080                client ids, vendor/user class ids as selection criteria -->
    2081     <!-- @todo Add fake DHCP option for assigning fixed IP addresses.  Figure out a way to
    2082                do it for the host only trunk interface too (possible special group operation). -->
     2131
     2132  </interface>
     2133
     2134  <interface
     2135    name="IDHCPConfig" extends="$unknown"
     2136    uuid="38fdb664-f65e-4905-ee56-a8a912871bbf"
     2137    wsmap="managed"
     2138    reservedMethods="8" reservedAttributes="16"
     2139    >
     2140    <desc>
     2141      The DHCP server has several configuration levels: global, group and
     2142      individual MAC.  This interface implements the settings common to
     2143      each level.
     2144    </desc>
     2145
     2146    <attribute name="scope" type="DHCPConfigScope" readonly="yes">
     2147      <desc>
     2148        Indicates the kind of config this is (mostly for IDHCPIndividualConfig).
     2149      </desc>
     2150    </attribute>
     2151
     2152    <attribute name="minLeaseTime" type="unsigned long" readonly="no">
     2153      <desc>The minimum lease time in seconds, ignored if zero.</desc>
     2154    </attribute>
     2155    <attribute name="defaultLeaseTime" type="unsigned long" readonly="no">
     2156      <desc>The default lease time in seconds, ignored if zero.</desc>
     2157    </attribute>
     2158    <attribute name="maxLeaseTime" type="unsigned long" readonly="no">
     2159      <desc>The maximum lease time in seconds, ignored if zero.</desc>
     2160    </attribute>
     2161
     2162    <method name="setOption">
     2163      <desc>
     2164        Sets a DHCP option.
     2165      </desc>
     2166      <param name="option"    dir="in" type="DhcpOpt">
     2167        <desc>The DHCP option.</desc>
     2168      </param>
     2169      <param name="encoding"  dir="in" type="DHCPOptionEncoding">
     2170        <desc>The value encoding.</desc>
     2171      </param>
     2172      <param name="value"     dir="in" type="wstring">
     2173        <desc>The DHCP option value.  The exact format depends on the DHCP
     2174          option and should be documented in <link to="DhcpOpt"/>.
     2175        </desc>
     2176      </param>
     2177    </method>
     2178
     2179    <method name="removeOption">
     2180      <desc>Removes the given DHCP option.</desc>
     2181      <param name="option"    dir="in" type="DhcpOpt"/>
     2182    </method>
     2183
     2184    <method name="removeAllOptions">
     2185      <desc>
     2186        Removes all the options.
     2187
     2188        One exception here is the DhcpOpt_SubnetMask option in the global scope
     2189        that is linked to the <link to="IDHCPServer::networkMask"/> attribute
     2190        and therefore cannot be removed.
     2191      </desc>
     2192    </method>
     2193
     2194    <method name="getOption">
     2195      <desc>Gets the value of a single DHCP option.</desc>
     2196      <param name="option"    dir="in" type="DhcpOpt">
     2197        <desc>The DHCP option being sought.</desc>
     2198      </param>
     2199      <param name="encoding"  dir="out" type="DHCPOptionEncoding">
     2200        <desc>The value encoding.</desc>
     2201      </param>
     2202      <param name="value"     dir="return" type="wstring">
     2203        <desc>The value of the requested DHCP option.</desc>
     2204      </param>
     2205    </method>
     2206
     2207    <method name="getAllOptions">
     2208      <desc>Gets all DHCP options and their values</desc>
     2209      <param name="options"   dir="out" type="DhcpOpt" safearray="yes">
     2210        <desc>Array containing the DHCP option numbers.</desc>
     2211      </param>
     2212      <param name="encodings" dir="out" type="DHCPOptionEncoding" safearray="yes">
     2213        <desc>Array of value encodings that runs parallel to @a options.</desc>
     2214      </param>
     2215      <param name="values"    dir="return" type="wstring" safearray="yes">
     2216        <desc>Array of values that runs parallel to @a options and @a encodings.</desc>
     2217      </param>
     2218    </method>
     2219  </interface>
     2220
     2221  <interface
     2222    name="IDHCPGlobalConfig" extends="IDHCPConfig"
     2223    uuid="5d7bb1ea-27ed-4e01-3859-4302dd55f796"
     2224    wsmap="managed"
     2225    reservedMethods="4" reservedAttributes="4"
     2226    >
     2227    <desc>
     2228      The global DHCP server configuration, see <link to="IDHCPServer::globalConfig"/>.
     2229    </desc>
     2230
     2231    <attribute name="midlDoesNotLikeEmptyInterfaces" readonly="yes" type="boolean"/>
     2232  </interface>
     2233
     2234  <interface
     2235    name="IDHCPGroupCondition" extends="$unknown"
     2236    uuid="5ca9e537-5a1d-43f1-6f27-6a0db298a9a8"
     2237    wsmap="managed"
     2238    reservedMethods="3" reservedAttributes="3"
     2239    >
     2240    <attribute name="inclusive" type="boolean" readonly="no">
     2241      <desc>Whether this is an inclusive or exclusive group membership condition</desc>
     2242    </attribute>
     2243    <attribute name="type" type="DHCPGroupFilterType" readonly="no">
     2244      <desc>Defines how the <link to="IDHCPGroupCondition::value"/> is interpreted.</desc>
     2245    </attribute>
     2246    <attribute name="value" type="wstring" readonly="no">
     2247      <desc>The condition value.</desc>
     2248    </attribute>
     2249    <method name="remove">
     2250      <desc>Remove this condition from the group.</desc>
     2251    </method>
     2252  </interface>
     2253
     2254  <interface
     2255    name="IDHCPGroupConfig" extends="IDHCPConfig"
     2256    uuid="406a5eca-d032-4f65-a882-6bb626a424a5"
     2257    wsmap="managed"
     2258    reservedMethods="8" reservedAttributes="8"
     2259    >
     2260    <desc>
     2261      A configuration that applies to a group of NICs.
     2262    </desc>
     2263
     2264    <attribute name="name" type="wstring" readonly="no">
     2265      <desc>The group name.</desc>
     2266    </attribute>
     2267
     2268    <attribute name="conditions" type="IDHCPGroupCondition" safearray="yes" readonly="yes">
     2269      <desc>
     2270        Group membership conditions.
     2271
     2272        Add new conditions by calling <link to="IDHCPGroupConfig::addCondition"/>
     2273        and use <link to="IDHCPGroupCondition::remove"/> to remove.
     2274      </desc>
     2275    </attribute>
     2276
     2277    <method name="addCondition">
     2278      <param name="inclusive"  dir="in" type="boolean"/>
     2279      <param name="type"       dir="in" type="DHCPGroupFilterType"/>
     2280      <param name="value"      dir="in" type="wstring"/>
     2281    </method>
     2282
     2283  </interface>
     2284
     2285  <interface
     2286    name="IDHCPIndividualConfig" extends="IDHCPConfig"
     2287    uuid="c40c2b86-73a5-46cc-8227-93fe57d006a6"
     2288    wsmap="managed"
     2289    reservedMethods="8" reservedAttributes="8"
     2290    >
     2291    <desc>
     2292      Configuration for a single NIC, either given directly by MAC address or by
     2293      VM + adaptor slot number.
     2294    </desc>
     2295
     2296    <attribute name="MACAddress" type="wstring" readonly="yes">
     2297      <desc>
     2298        The MAC address.  If a <link to="DHCPConfigScope::MachineNIC"/> config, this
     2299        will be queried via the VM ID.
     2300      </desc>
     2301    </attribute>
     2302
     2303    <attribute name="machineId" type="uuid" mod="string" readonly="yes">
     2304      <desc>
     2305        The virtual machine ID if a <link to="DHCPConfigScope::MachineNIC"/> config,
     2306        null UUID for <link to="DHCPConfigScope::MAC"/>.
     2307      </desc>
     2308    </attribute>
     2309
     2310    <attribute name="slot" type="unsigned long" readonly="yes">
     2311      <desc>The NIC slot number of the VM if a <link to="DHCPConfigScope::MachineNIC"/> config.</desc>
     2312    </attribute>
     2313
     2314    <attribute name="fixedAddress" type="wstring" readonly="no">
     2315      <desc>Fixed IPv4 address assignment, dynamic if empty.</desc>
     2316    </attribute>
    20832317
    20842318  </interface>
  • trunk/src/VBox/Main/include/DHCPServerImpl.h

    r79644 r79732  
    3232}
    3333
     34class DHCPConfig;
     35class DHCPIndividualConfig;
    3436
    3537/**
     38 * A DHCP server for internal host-only & NAT networks.
     39 *
     40 * Old notes:
     41 *
    3642 *  for server configuration needs, it's perhaps better to use (VM,slot) pair
    3743 *  (vm-name, slot) <----> (MAC)
     
    4955{
    5056public:
     57    /** @name Constructors and destructors
     58     * @{ */
     59    DECLARE_EMPTY_CTOR_DTOR(DHCPServer)
     60    HRESULT FinalConstruct();
     61    void    FinalRelease();
    5162
    52     DECLARE_EMPTY_CTOR_DTOR(DHCPServer)
     63    HRESULT init(VirtualBox *aVirtualBox, const com::Utf8Str &aName);
     64    HRESULT init(VirtualBox *aVirtualBox, const settings::DHCPServer &data);
     65    void    uninit();
     66    /** @} */
    5367
    54     HRESULT FinalConstruct();
    55     void FinalRelease();
    56 
    57     HRESULT init(VirtualBox *aVirtualBox,
    58                  const com::Utf8Str &aName);
    59     HRESULT init(VirtualBox *aVirtualBox,
    60                  const settings::DHCPServer &data);
    61     void uninit();
    62 
    63     // Public internal methids.
     68    /** @name Public internal methods.
     69     * @{ */
    6470    HRESULT i_saveSettings(settings::DHCPServer &data);
    65     settings::DhcpOptionMap &i_findOptMapByVmNameSlot(const com::Utf8Str &aVmName, LONG Slot);
     71    /** @} */
    6672
    6773private:
    68     HRESULT encodeOption(com::Utf8Str &aEncoded, uint32_t aOptCode, const settings::DhcpOptValue &aOptValue);
    69     int addOption(settings::DhcpOptionMap &aMap, DhcpOpt_T aOption, const com::Utf8Str &aValue);
     74    /** @name IDHCPServer Properties
     75     * @{ */
     76    HRESULT getEventSource(ComPtr<IEventSource> &aEventSource) RT_OVERRIDE;
     77    HRESULT getEnabled(BOOL *aEnabled) RT_OVERRIDE;
     78    HRESULT setEnabled(BOOL aEnabled) RT_OVERRIDE;
     79    HRESULT getIPAddress(com::Utf8Str &aIPAddress) RT_OVERRIDE;
     80    HRESULT getNetworkMask(com::Utf8Str &aNetworkMask) RT_OVERRIDE;
     81    HRESULT getNetworkName(com::Utf8Str &aName) RT_OVERRIDE;
     82    HRESULT getLowerIP(com::Utf8Str &aIPAddress) RT_OVERRIDE;
     83    HRESULT getUpperIP(com::Utf8Str &aIPAddress) RT_OVERRIDE;
     84    HRESULT getGlobalOptions(std::vector<com::Utf8Str> &aGlobalOptions) RT_OVERRIDE;
     85    HRESULT getVmConfigs(std::vector<com::Utf8Str> &aVmConfigs) RT_OVERRIDE;
     86    HRESULT getMacOptions(const com::Utf8Str &aMAC, std::vector<com::Utf8Str> &aValues) RT_OVERRIDE;
     87    HRESULT setConfiguration(const com::Utf8Str &aIPAddress, const com::Utf8Str &aNetworkMask,
     88                             const com::Utf8Str &aFromIPAddress, const com::Utf8Str &aToIPAddress) RT_OVERRIDE;
     89    HRESULT getVmSlotOptions(const com::Utf8Str &aVmName, LONG aSlot, std::vector<com::Utf8Str> &aValues) RT_OVERRIDE;
     90    HRESULT getGlobalConfig(ComPtr<IDHCPGlobalConfig> &aGlobalConfig) RT_OVERRIDE;
     91    HRESULT getGroupConfigs(std::vector<ComPtr<IDHCPGroupConfig> > &aGroupConfigs) RT_OVERRIDE;
     92    HRESULT getIndividualConfigs(std::vector<ComPtr<IDHCPIndividualConfig> > &aIndividualConfigs) ;
     93    /** @} */
    7094
    71     // wrapped IDHCPServer properties
    72     HRESULT getEventSource(ComPtr<IEventSource> &aEventSource);
    73     HRESULT getEnabled(BOOL *aEnabled);
    74     HRESULT setEnabled(BOOL aEnabled);
    75     HRESULT getIPAddress(com::Utf8Str &aIPAddress);
    76     HRESULT getNetworkMask(com::Utf8Str &aNetworkMask);
    77     HRESULT getNetworkName(com::Utf8Str &aName);
    78     HRESULT getLowerIP(com::Utf8Str &aIPAddress);
    79     HRESULT getUpperIP(com::Utf8Str &aIPAddress);
    80     HRESULT getGlobalOptions(std::vector<com::Utf8Str> &aGlobalOptions);
    81     HRESULT getVmConfigs(std::vector<com::Utf8Str> &aVmConfigs);
    82     HRESULT getMacOptions(const com::Utf8Str &aMAC, std::vector<com::Utf8Str> &aValues);
    83     HRESULT setConfiguration(const com::Utf8Str &aIPAddress,
    84                              const com::Utf8Str &aNetworkMask,
    85                              const com::Utf8Str &aFromIPAddress,
    86                              const com::Utf8Str &aToIPAddress);
    87     HRESULT getVmSlotOptions(const com::Utf8Str &aVmName,
    88                              LONG aSlot,
    89                              std::vector<com::Utf8Str> &aValues);
    90 
    91     // Wrapped IDHCPServer Methods
    92     HRESULT addGlobalOption(DhcpOpt_T aOption,
    93                             const com::Utf8Str &aValue);
    94     HRESULT removeGlobalOption(DhcpOpt_T aOption);
    95     HRESULT removeGlobalOptions();
    96     HRESULT addVmSlotOption(const com::Utf8Str &aVmName,
    97                             LONG aSlot,
    98                             DhcpOpt_T aOption,
    99                             const com::Utf8Str &aValue);
    100     HRESULT removeVmSlotOption(const com::Utf8Str &aVmName,
    101                                LONG aSlot,
    102                                DhcpOpt_T aOption);
    103     HRESULT removeVmSlotOptions(const com::Utf8Str &aVmName,
    104                                 LONG aSlot);
    105     HRESULT start(const com::Utf8Str &aNetworkName,
    106                   const com::Utf8Str &aTrunkName,
    107                   const com::Utf8Str &aTrunkType);
    108     HRESULT stop();
    109     HRESULT restart();
    110     HRESULT findLeaseByMAC(const com::Utf8Str &aMac, LONG aType,
    111                            com::Utf8Str &aAddress, com::Utf8Str &aState, LONG64 *aIssued, LONG64 *aExpire) RT_OVERRIDE;
     95    /** @name IDHCPServer Methods
     96     * @{ */
     97    HRESULT addGlobalOption(DhcpOpt_T aOption, const com::Utf8Str &aValue) RT_OVERRIDE;
     98    HRESULT removeGlobalOption(DhcpOpt_T aOption) RT_OVERRIDE;
     99    HRESULT removeGlobalOptions() RT_OVERRIDE;
     100    HRESULT addVmSlotOption(const com::Utf8Str &aVmName, LONG aSlot, DhcpOpt_T aOption, const com::Utf8Str &aValue) RT_OVERRIDE;
     101    HRESULT removeVmSlotOption(const com::Utf8Str &aVmName, LONG aSlot, DhcpOpt_T aOption) RT_OVERRIDE;
     102    HRESULT removeVmSlotOptions(const com::Utf8Str &aVmName, LONG aSlot) RT_OVERRIDE;
     103    HRESULT start(const com::Utf8Str &aNetworkName, const com::Utf8Str &aTrunkName, const com::Utf8Str &aTrunkType) RT_OVERRIDE;
     104    HRESULT stop() RT_OVERRIDE;
     105    HRESULT restart() RT_OVERRIDE;
     106    HRESULT findLeaseByMAC(const com::Utf8Str &aMac, LONG aType, com::Utf8Str &aAddress, com::Utf8Str &aState,
     107                           LONG64 *aIssued, LONG64 *aExpire) RT_OVERRIDE;
     108    HRESULT getConfig(DHCPConfigScope_T aScope, const com::Utf8Str &aName, ULONG aSlot, BOOL aMayAdd,
     109                      ComPtr<IDHCPConfig> &aConfig) RT_OVERRIDE;
     110    /** @} */
    112111
    113112    /** @name Helpers
    114113     * @{  */
     114    HRESULT i_doSaveSettings();
    115115    HRESULT i_calcLeasesFilename(const com::Utf8Str &aNetwork) RT_NOEXCEPT;
     116    HRESULT i_writeDhcpdConfig(const char *pszFilename, uint32_t uMACAddressVersion) RT_NOEXCEPT;
     117
     118    HRESULT i_vmNameToIdAndValidateSlot(const com::Utf8Str &aVmName, LONG aSlot, com::Guid &idMachine);
     119    HRESULT i_vmNameAndSlotToConfig(const com::Utf8Str &a_strVmName, LONG a_uSlot, bool a_fCreateIfNeeded,
     120                                    ComObjPtr<DHCPIndividualConfig> &a_rPtrConfig);
     121
     122    HRESULT i_encode60Option(com::Utf8Str &strEncoded, DhcpOpt_T enmOption,
     123                             DHCPOptionEncoding_T enmEncoding, const com::Utf8Str &strValue);
     124    HRESULT i_getAllOptions60(DHCPConfig &aSourceConfig, std::vector<com::Utf8Str> &aValues);
     125    HRESULT i_add60Option(DHCPConfig &aTargetConfig, DhcpOpt_T aOption, const com::Utf8Str &aValue);
    116126    /** @} */
    117127
     128    /** Private data */
    118129    struct Data;
     130    /** Private data. */
    119131    Data *m;
    120     /** weak VirtualBox parent */
    121     VirtualBox *const mVirtualBox;
    122     const Utf8Str mName;
    123132};
    124133
  • trunk/src/VBox/Main/src-server/DHCPServerImpl.cpp

    r79644 r79732  
    2121*********************************************************************************************************************************/
    2222#define LOG_GROUP LOG_GROUP_MAIN_DHCPSERVER
    23 #include "NetworkServiceRunner.h"
    2423#include "DHCPServerImpl.h"
    25 #include "AutoCaller.h"
    2624#include "LoggingNew.h"
    2725
     
    3836#include <VBox/settings.h>
    3937
     38#include "AutoCaller.h"
     39#include "DHCPConfigImpl.h"
     40#include "MachineImpl.h"
     41#include "NetworkServiceRunner.h"
    4042#include "VirtualBoxImpl.h"
    4143
     
    8486{
    8587    Data()
    86         : enabled(FALSE)
    87         , router(false)
     88        : pVirtualBox(NULL)
     89        , strName()
     90        , enabled(FALSE)
     91//        , router(false)
     92        , uIndividualMACAddressVersion(1)
    8893    {
    8994        szTempConfigFileName[0] = '\0';
    9095    }
     96
     97    /** weak VirtualBox parent */
     98    VirtualBox * const  pVirtualBox;
     99    /** The DHCP server name (network).
     100     * @todo Kind of duplicated by networkName, if I understand it correctly.  */
     101    Utf8Str const       strName;
    91102
    92103    Utf8Str IPAddress;
     
    95106
    96107    BOOL enabled;
     108#if 0
     109    /** Don't quit get WTF this is about, but the old addOption method contained the
     110     * following hint: "Indirect way to understand that we're on NAT network."
     111     *
     112     * Apparently this is a busted with the new dhcpd implementation, so we don't
     113     * maintain it with the API overhaul in 6.0.12.
     114     */
    97115    bool router;
     116#endif
    98117    DHCPServerRunner dhcp;
    99 
    100     settings::DhcpOptionMap GlobalDhcpOptions;
    101     settings::VmSlot2OptionsMap VmSlot2Options;
    102118
    103119    char szTempConfigFileName[RTPATH_MAX];
     
    106122    com::Utf8Str trunkName;
    107123    com::Utf8Str trunkType;
     124
     125    /** Global configuration. */
     126    ComObjPtr<DHCPGlobalConfig> globalConfig;
     127
     128    /** Group configuration indexed by name. */
     129    std::map<com::Utf8Str, ComObjPtr<DHCPGroupConfig>> groupConfigs;
     130    /** Iterator for groupConfigs. */
     131    typedef std::map<com::Utf8Str, ComObjPtr<DHCPGroupConfig>>::iterator GroupConfigIterator;
     132
     133    /** Individual (host) configuration indexed by MAC address or VM UUID. */
     134    std::map<com::Utf8Str, ComObjPtr<DHCPIndividualConfig>> individualConfigs;
     135    /** Iterator for individualConfigs. */
     136    typedef std::map<com::Utf8Str, ComObjPtr<DHCPIndividualConfig>>::iterator IndividualConfigIterator;
     137
     138    /** Part of a lock-avoidance hack to resolve the VM ID + slot into MAC
     139     *  addresses before writing out the Dhcpd configuration file. */
     140    uint32_t uIndividualMACAddressVersion;
    108141};
    109142
     
    115148DHCPServer::DHCPServer()
    116149    : m(NULL)
    117     , mVirtualBox(NULL)
    118150{
    119151    m = new DHCPServer::Data();
     
    139171void DHCPServer::FinalRelease()
    140172{
    141     uninit ();
    142 
     173    uninit();
    143174    BaseFinalRelease();
    144175}
     
    155186        stop();
    156187
    157     unconst(mVirtualBox) = NULL;
     188    unconst(m->pVirtualBox) = NULL;
    158189}
    159190
     
    167198
    168199    /* share VirtualBox weakly (parent remains NULL so far) */
    169     unconst(mVirtualBox) = aVirtualBox;
    170 
    171     unconst(mName) = aName;
     200    unconst(m->pVirtualBox) = aVirtualBox;
     201
     202    unconst(m->strName) = aName;
    172203    m->IPAddress = "0.0.0.0";
    173     m->GlobalDhcpOptions[DhcpOpt_SubnetMask] = settings::DhcpOptValue("0.0.0.0");
    174     m->enabled = FALSE;
    175 
    176     m->lowerIP = "0.0.0.0";
    177     m->upperIP = "0.0.0.0";
    178 
    179     /* Confirm a successful initialization */
    180     autoInitSpan.setSucceeded();
    181 
    182     return S_OK;
    183 }
    184 
    185 
    186 HRESULT DHCPServer::init(VirtualBox *aVirtualBox, const settings::DHCPServer &data)
     204    m->lowerIP   = "0.0.0.0";
     205    m->upperIP   = "0.0.0.0";
     206    m->enabled   = FALSE;
     207
     208    /* Global configuration: */
     209    HRESULT hrc = m->globalConfig.createObject();
     210    if (SUCCEEDED(hrc))
     211        hrc = m->globalConfig->initWithDefaults(aVirtualBox, this);
     212
     213    /* Confirm a successful initialization or not: */
     214    if (SUCCEEDED(hrc))
     215        autoInitSpan.setSucceeded();
     216    else
     217        autoInitSpan.setFailed(hrc);
     218    return hrc;
     219}
     220
     221
     222HRESULT DHCPServer::init(VirtualBox *aVirtualBox, const settings::DHCPServer &rData)
    187223{
    188224    /* Enclose the state transition NotReady->InInit->Ready */
     
    191227
    192228    /* share VirtualBox weakly (parent remains NULL so far) */
    193     unconst(mVirtualBox) = aVirtualBox;
    194 
    195     unconst(mName) = data.strNetworkName;
    196     m->IPAddress = data.strIPAddress;
    197     m->enabled = data.fEnabled;
    198     m->lowerIP = data.strIPLower;
    199     m->upperIP = data.strIPUpper;
    200 
    201     m->GlobalDhcpOptions.clear();
    202     m->GlobalDhcpOptions.insert(data.GlobalDhcpOptions.begin(), data.GlobalDhcpOptions.end());
    203 
    204     m->VmSlot2Options.clear();
    205     m->VmSlot2Options.insert(data.VmSlot2OptionsM.begin(), data.VmSlot2OptionsM.end());
    206 
    207     autoInitSpan.setSucceeded();
    208 
    209     return S_OK;
    210 }
    211 
    212 
    213 HRESULT DHCPServer::i_saveSettings(settings::DHCPServer &data)
     229    unconst(m->pVirtualBox) = aVirtualBox;
     230
     231    unconst(m->strName) = rData.strNetworkName;
     232    m->IPAddress        = rData.strIPAddress;
     233    m->enabled          = rData.fEnabled;
     234    m->lowerIP          = rData.strIPLower;
     235    m->upperIP          = rData.strIPUpper;
     236
     237    /*
     238     * Global configuration:
     239     */
     240    HRESULT hrc = m->globalConfig.createObject();
     241    if (SUCCEEDED(hrc))
     242        hrc = m->globalConfig->initWithSettings(aVirtualBox, this, rData.GlobalConfig);
     243
     244    /*
     245     * Group configurations:
     246     */
     247
     248    /*
     249     * Individual configuration:
     250     */
     251    Assert(m->individualConfigs.size() == 0);
     252    if (SUCCEEDED(hrc))
     253    {
     254        for (settings::DHCPIndividualConfigMap::const_iterator it = rData.IndividualConfigs.begin();
     255             it != rData.IndividualConfigs.end() && SUCCEEDED(hrc); ++it)
     256        {
     257            ComObjPtr<DHCPIndividualConfig> ptrIndiCfg;
     258            com::Utf8Str                    strKey;
     259            if (!it->second.strVMName.isNotEmpty())
     260            {
     261                RTMAC MACAddress;
     262                int vrc = RTNetStrToMacAddr(it->second.strMACAddress.c_str(), &MACAddress);
     263                if (RT_FAILURE(vrc))
     264                {
     265                    LogRel(("Ignoring invalid MAC address for individual DHCP config: '%s' - %Rrc\n", it->second.strMACAddress.c_str(), vrc));
     266                    continue;
     267                }
     268
     269                vrc = strKey.printfNoThrow("%RTmac", &MACAddress);
     270                AssertRCReturn(vrc, E_OUTOFMEMORY);
     271
     272                hrc = ptrIndiCfg.createObject();
     273                if (SUCCEEDED(hrc))
     274                    hrc = ptrIndiCfg->initWithSettingsAndMACAddress(aVirtualBox, this, it->second, &MACAddress);
     275            }
     276            else
     277            {
     278                /* This ASSUMES that we're being called after the machines have been
     279                   loaded so we can resolve VM names into UUID for old settings. */
     280                com::Guid idMachine;
     281                hrc = i_vmNameToIdAndValidateSlot(it->second.strVMName, it->second.uSlot, idMachine);
     282                if (SUCCEEDED(hrc))
     283                {
     284                    hrc = ptrIndiCfg.createObject();
     285                    if (SUCCEEDED(hrc))
     286                        hrc = ptrIndiCfg->initWithSettingsAndMachineIdAndSlot(aVirtualBox, this, it->second,
     287                                                                              idMachine, it->second.uSlot,
     288                                                                              m->uIndividualMACAddressVersion - UINT32_MAX / 4);
     289                }
     290            }
     291            if (SUCCEEDED(hrc))
     292            {
     293                try
     294                {
     295                    m->individualConfigs[strKey] = ptrIndiCfg;
     296                }
     297                catch (std::bad_alloc &)
     298                {
     299                    return E_OUTOFMEMORY;
     300                }
     301            }
     302        }
     303    }
     304
     305    /* Confirm a successful initialization or not: */
     306    if (SUCCEEDED(hrc))
     307        autoInitSpan.setSucceeded();
     308    else
     309        autoInitSpan.setFailed(hrc);
     310    return hrc;
     311}
     312
     313
     314HRESULT DHCPServer::i_saveSettings(settings::DHCPServer &rData)
    214315{
    215316    AutoCaller autoCaller(this);
     
    218319    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    219320
    220     data.strNetworkName = mName;
    221     data.strIPAddress = m->IPAddress;
    222 
    223     data.fEnabled = !!m->enabled;
    224     data.strIPLower = m->lowerIP;
    225     data.strIPUpper = m->upperIP;
    226 
    227     data.GlobalDhcpOptions.clear();
    228     data.GlobalDhcpOptions.insert(m->GlobalDhcpOptions.begin(),
    229                                   m->GlobalDhcpOptions.end());
    230 
    231     data.VmSlot2OptionsM.clear();
    232     data.VmSlot2OptionsM.insert(m->VmSlot2Options.begin(),
    233                                 m->VmSlot2Options.end());
    234 
    235     return S_OK;
     321    rData.strNetworkName = m->strName;
     322    rData.strIPAddress   = m->IPAddress;
     323    rData.fEnabled       = m->enabled != FALSE;
     324    rData.strIPLower     = m->lowerIP;
     325    rData.strIPUpper     = m->upperIP;
     326
     327    /* Global configuration: */
     328    HRESULT hrc = m->globalConfig->i_saveSettings(rData.GlobalConfig);
     329
     330    /* Group configuration: */
     331
     332    /* Individual configuration: */
     333    for (Data::IndividualConfigIterator it = m->individualConfigs.begin();
     334         it != m->individualConfigs.end() && SUCCEEDED(hrc); ++it)
     335    {
     336        try
     337        {
     338            rData.IndividualConfigs[it->first] = settings::DHCPIndividualConfig();
     339        }
     340        catch (std::bad_alloc &)
     341        {
     342            return E_OUTOFMEMORY;
     343        }
     344        hrc = it->second->i_saveSettings(rData.IndividualConfigs[it->first]);
     345    }
     346
     347    return hrc;
     348}
     349
     350
     351/**
     352 * Internal worker that saves the settings after a modification was made.
     353 *
     354 * @returns COM status code.
     355 *
     356 * @note    Caller must not hold any locks!
     357 */
     358HRESULT DHCPServer::i_doSaveSettings()
     359{
     360    // save the global settings; for that we should hold only the VirtualBox lock
     361    AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
     362    return m->pVirtualBox->i_saveSettings();
    236363}
    237364
     
    239366HRESULT DHCPServer::getNetworkName(com::Utf8Str &aName)
    240367{
     368    /* The name is const, so no need to for locking. */
     369    return aName.assignEx(m->strName);
     370}
     371
     372
     373HRESULT DHCPServer::getEnabled(BOOL *aEnabled)
     374{
    241375    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    242 
    243     aName = mName;
    244     return S_OK;
    245 }
    246 
    247 
    248 HRESULT DHCPServer::getEnabled(BOOL *aEnabled)
    249 {
    250     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    251 
    252376    *aEnabled = m->enabled;
    253377    return S_OK;
     
    257381HRESULT DHCPServer::setEnabled(BOOL aEnabled)
    258382{
    259     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    260     m->enabled = aEnabled;
    261 
    262     // save the global settings; for that we should hold only the VirtualBox lock
    263     alock.release();
    264     AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
    265     HRESULT rc = mVirtualBox->i_saveSettings();
    266 
    267     return rc;
     383    {
     384        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     385        m->enabled = aEnabled;
     386    }
     387    return i_doSaveSettings();
    268388}
    269389
     
    272392{
    273393    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    274 
    275     aIPAddress = Utf8Str(m->IPAddress);
    276     return S_OK;
     394    return aIPAddress.assignEx(m->IPAddress);
    277395}
    278396
     
    280398HRESULT DHCPServer::getNetworkMask(com::Utf8Str &aNetworkMask)
    281399{
     400    return m->globalConfig->i_getNetworkMask(aNetworkMask);
     401}
     402
     403
     404HRESULT DHCPServer::getLowerIP(com::Utf8Str &aIPAddress)
     405{
    282406    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    283 
    284     aNetworkMask = m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text;
    285     return S_OK;
    286 }
    287 
    288 
    289 HRESULT DHCPServer::getLowerIP(com::Utf8Str &aIPAddress)
     407    return aIPAddress.assignEx(m->lowerIP);
     408}
     409
     410
     411HRESULT DHCPServer::getUpperIP(com::Utf8Str &aIPAddress)
    290412{
    291413    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    292 
    293     aIPAddress = Utf8Str(m->lowerIP);
    294     return S_OK;
    295 }
    296 
    297 
    298 HRESULT DHCPServer::getUpperIP(com::Utf8Str &aIPAddress)
    299 {
    300     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    301 
    302     aIPAddress = Utf8Str(m->upperIP);
    303     return S_OK;
     414    return aIPAddress.assignEx(m->upperIP);
    304415}
    305416
     
    314425    int vrc = RTNetStrToIPv4Addr(aIPAddress.c_str(), &IPAddress);
    315426    if (RT_FAILURE(vrc))
    316         return mVirtualBox->setErrorBoth(E_INVALIDARG, vrc, "Invalid server address");
     427        return setErrorBoth(E_INVALIDARG, vrc, tr("Invalid server address: %s"), aIPAddress.c_str());
    317428
    318429    vrc = RTNetStrToIPv4Addr(aNetworkMask.c_str(), &NetworkMask);
    319430    if (RT_FAILURE(vrc))
    320         return mVirtualBox->setErrorBoth(E_INVALIDARG, vrc, "Invalid netmask");
     431        return setErrorBoth(E_INVALIDARG, vrc, tr("Invalid netmask: %s"), aNetworkMask.c_str());
    321432
    322433    vrc = RTNetStrToIPv4Addr(aLowerIP.c_str(), &LowerIP);
    323434    if (RT_FAILURE(vrc))
    324         return mVirtualBox->setErrorBoth(E_INVALIDARG, vrc, "Invalid range lower address");
     435        return setErrorBoth(E_INVALIDARG, vrc, tr("Invalid range lower address: %s"), aLowerIP.c_str());
    325436
    326437    vrc = RTNetStrToIPv4Addr(aUpperIP.c_str(), &UpperIP);
    327438    if (RT_FAILURE(vrc))
    328         return mVirtualBox->setErrorBoth(E_INVALIDARG, vrc, "Invalid range upper address");
     439        return setErrorBoth(E_INVALIDARG, vrc, tr("Invalid range upper address: %s"), aUpperIP.c_str());
    329440
    330441    /*
     
    334445    vrc = RTNetMaskToPrefixIPv4(&NetworkMask, NULL);
    335446    if (RT_FAILURE(vrc))
    336         return mVirtualBox->setErrorBoth(E_INVALIDARG, vrc, "Invalid netmask");
    337 
    338     /* It's more convenient to convert to host order once */
    339     IPAddress.u = RT_N2H_U32(IPAddress.u);
     447        return setErrorBoth(E_INVALIDARG, vrc, tr("Invalid netmask: %s"), aNetworkMask.c_str());
     448
     449    /* It's more convenient to convert to host order once: */
     450    IPAddress.u   = RT_N2H_U32(IPAddress.u);
    340451    NetworkMask.u = RT_N2H_U32(NetworkMask.u);
    341     LowerIP.u = RT_N2H_U32(LowerIP.u);
    342     UpperIP.u = RT_N2H_U32(UpperIP.u);
     452    LowerIP.u     = RT_N2H_U32(LowerIP.u);
     453    UpperIP.u     = RT_N2H_U32(UpperIP.u);
    343454
    344455    /*
     
    348459        || (IPAddress.u & ~NetworkMask.u) == 0
    349460        || ((IPAddress.u & ~NetworkMask.u) | NetworkMask.u) == UINT32_C(0xffffffff))
    350         return mVirtualBox->setError(E_INVALIDARG, "Invalid server address");
     461        return setError(E_INVALIDARG, tr("Invalid server address: %s (mask %s)"), aIPAddress.c_str(), aNetworkMask.c_str());
    351462
    352463    if (   (LowerIP.u & UINT32_C(0xe0000000)) == UINT32_C(0xe0000000)
     
    354465        || (LowerIP.u & ~NetworkMask.u) == 0
    355466        || ((LowerIP.u & ~NetworkMask.u) | NetworkMask.u) == UINT32_C(0xffffffff))
    356         return mVirtualBox->setError(E_INVALIDARG, "Invalid range lower address");
     467        return setError(E_INVALIDARG, tr("Invalid range lower address: %s (mask %s)"), aLowerIP.c_str(), aNetworkMask.c_str());
    357468
    358469    if (   (UpperIP.u & UINT32_C(0xe0000000)) == UINT32_C(0xe0000000)
     
    360471        || (UpperIP.u & ~NetworkMask.u) == 0
    361472        || ((UpperIP.u & ~NetworkMask.u) | NetworkMask.u) == UINT32_C(0xffffffff))
    362         return mVirtualBox->setError(E_INVALIDARG, "Invalid range upper address");
     473        return setError(E_INVALIDARG, tr("Invalid range upper address"), aUpperIP.c_str(), aNetworkMask.c_str());
    363474
    364475    /* The range should be valid ... */
    365476    if (LowerIP.u > UpperIP.u)
    366         return mVirtualBox->setError(E_INVALIDARG, "Invalid range bounds");
     477        return setError(E_INVALIDARG, tr("Lower bound must be less or eqaul than the upper: %s vs %s"),
     478                        aLowerIP.c_str(), aUpperIP.c_str());
    367479
    368480    /* ... and shouldn't contain the server's address */
    369481    if (LowerIP.u <= IPAddress.u && IPAddress.u <= UpperIP.u)
    370         return mVirtualBox->setError(E_INVALIDARG, "Server address within range bounds");
    371 
    372     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    373     m->IPAddress = aIPAddress;
    374     m->GlobalDhcpOptions[DhcpOpt_SubnetMask] = aNetworkMask;
    375 
    376     m->lowerIP = aLowerIP;
    377     m->upperIP = aUpperIP;
    378 
    379     // save the global settings; for that we should hold only the VirtualBox lock
    380     alock.release();
    381     AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
    382     return mVirtualBox->i_saveSettings();
    383 }
    384 
    385 
    386 HRESULT DHCPServer::encodeOption(com::Utf8Str &aEncoded,
    387                                  uint32_t aOptCode,
    388                                  const settings::DhcpOptValue &aOptValue)
    389 {
    390     switch (aOptValue.encoding)
    391     {
    392         case DhcpOptEncoding_Legacy:
     482        return setError(E_INVALIDARG, tr("Server address within range bounds: %s in %s - %s"),
     483                        aIPAddress.c_str(), aLowerIP.c_str(), aUpperIP.c_str());
     484
     485    /*
     486     * Input is valid, effect the changes.
     487     */
     488    HRESULT hrc;
     489    {
     490        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     491        m->IPAddress  = aIPAddress;
     492        m->lowerIP    = aLowerIP;
     493        m->upperIP    = aUpperIP;
     494        hrc = m->globalConfig->i_setNetworkMask(aNetworkMask);
     495    }
     496    if (SUCCEEDED(hrc))
     497        hrc = i_doSaveSettings();
     498    return hrc;
     499}
     500
     501
     502/**
     503 * Used by the legacy 6.0 IDHCPServer::GetVmSlotOptions() and
     504 * IDHCPServer::GetGlobalOptions() implementations.
     505 *
     506 * New interfaces have the option number and option encoding separate from the
     507 * value.
     508 */
     509HRESULT DHCPServer::i_encode60Option(com::Utf8Str &strEncoded, DhcpOpt_T enmOption,
     510                                     DHCPOptionEncoding_T enmEncoding, const com::Utf8Str &strValue)
     511{
     512    int vrc;
     513    switch (enmEncoding)
     514    {
     515        case DHCPOptionEncoding_Legacy:
    393516        {
    394517            /*
     
    400523             *   "6:1.2.3.4 8.8.8.8" # array of ip-address
    401524             */
    402             aEncoded = Utf8StrFmt("%d:%s", aOptCode, aOptValue.text.c_str());
     525            vrc = strEncoded.printfNoThrow("%d:%s", (int)enmOption, strValue.c_str());
    403526            break;
    404527        }
    405528
    406         case DhcpOptEncoding_Hex:
     529        case DHCPOptionEncoding_Hex:
    407530        {
    408531            /*
     
    413536             *   234=68:65:6c:6c:6f:2c:20:77:6f:72:6c:64
    414537             */
    415             aEncoded = Utf8StrFmt("%d=%s", aOptCode, aOptValue.text.c_str());
     538            vrc = strEncoded.printfNoThrow("%d=%s", (int)enmOption, strValue.c_str());
    416539            break;
    417540        }
     
    424547             *   "254@42=i hope you know what this means"
    425548             */
    426             aEncoded = Utf8StrFmt("%d@%d=%s", aOptCode, (int)aOptValue.encoding,
    427                                   aOptValue.text.c_str());
     549            vrc = strEncoded.printfNoThrow("%d@%d=%s", (int)enmOption, (int)enmEncoding, strValue.c_str());
    428550            break;
    429551        }
    430552    }
    431 
    432     return S_OK;
    433 }
    434 
    435 
    436 int DHCPServer::addOption(settings::DhcpOptionMap &aMap,
    437                           DhcpOpt_T aOption, const com::Utf8Str &aValue)
    438 {
    439     settings::DhcpOptValue OptValue;
    440 
     553    return RT_SUCCESS(vrc) ? S_OK : E_OUTOFMEMORY;
     554}
     555
     556
     557/**
     558 * worker for IDHCPServer::GetGlobalOptions.
     559 */
     560HRESULT DHCPServer::i_getAllOptions60(DHCPConfig &aSourceConfig, std::vector<com::Utf8Str> &aValues)
     561{
     562    /* Get the values using the new getter: */
     563    std::vector<DhcpOpt_T>              Options;
     564    std::vector<DHCPOptionEncoding_T>   Encodings;
     565    std::vector<com::Utf8Str>           Values;
     566    HRESULT hrc = aSourceConfig.i_getAllOptions(Options, Encodings, Values);
     567    if (SUCCEEDED(hrc))
     568    {
     569        /* Encoding them using in the 6.0 style: */
     570        size_t const cValues = Values.size();
     571        aValues.resize(cValues);
     572        for (size_t i = 0; i < cValues && SUCCEEDED(hrc); i++)
     573            hrc = i_encode60Option(aValues[i], Options[i], Encodings[i], Values[i]);
     574    }
     575    return hrc;
     576}
     577
     578
     579/**
     580 * Worker for legacy <=6.0 interfaces for adding options.
     581 *
     582 * @throws std::bad_alloc
     583 */
     584HRESULT DHCPServer::i_add60Option(DHCPConfig &aTargetConfig, DhcpOpt_T aOption, const com::Utf8Str &aValue)
     585{
    441586    if (aOption != 0)
    442     {
    443         OptValue = settings::DhcpOptValue(aValue, DhcpOptEncoding_Legacy);
    444     }
     587        return aTargetConfig.i_setOption(aOption, DHCPOptionEncoding_Legacy, aValue);
     588
    445589    /*
    446590     * This is a kludge to sneak in option encoding information
    447591     * through existing API.  We use option 0 and supply the real
    448      * option/value in the same format that encodeOption() above
     592     * option/value in the same format that i_encode60Option() above
    449593     * produces for getter methods.
    450594     */
    451     else
    452     {
    453         uint8_t u8Code;
    454         char    *pszNext;
    455         int vrc = RTStrToUInt8Ex(aValue.c_str(), &pszNext, 10, &u8Code);
    456         if (!RT_SUCCESS(vrc))
     595    uint8_t u8Code;
     596    char    *pszNext;
     597    int vrc = RTStrToUInt8Ex(aValue.c_str(), &pszNext, 10, &u8Code);
     598    if (RT_FAILURE(vrc))
     599        return setErrorBoth(E_INVALIDARG, VERR_PARSE_ERROR);
     600
     601    DHCPOptionEncoding_T enmEncoding;
     602    switch (*pszNext)
     603    {
     604        case ':':           /* support legacy format too */
     605        {
     606            enmEncoding = DHCPOptionEncoding_Legacy;
     607            break;
     608        }
     609
     610        case '=':
     611        {
     612            enmEncoding = DHCPOptionEncoding_Hex;
     613            break;
     614        }
     615
     616        case '@':
     617        {
     618            uint32_t u32Enc = 0;
     619            vrc = RTStrToUInt32Ex(pszNext + 1, &pszNext, 10, &u32Enc);
     620            if (RT_FAILURE(vrc))
     621                return setErrorBoth(E_INVALIDARG, VERR_PARSE_ERROR);
     622            if (*pszNext != '=')
     623                return setErrorBoth(E_INVALIDARG, VERR_PARSE_ERROR);
     624            enmEncoding = (DHCPOptionEncoding_T)u32Enc;
     625            break;
     626        }
     627
     628        default:
    457629            return VERR_PARSE_ERROR;
    458 
    459         uint32_t u32Enc;
    460         switch (*pszNext)
    461         {
    462             case ':':           /* support legacy format too */
     630    }
     631
     632    return aTargetConfig.i_setOption(aOption, enmEncoding, com::Utf8Str(pszNext + 1));
     633}
     634
     635
     636HRESULT DHCPServer::addGlobalOption(DhcpOpt_T aOption, const com::Utf8Str &aValue)
     637{
     638    return i_add60Option(*m->globalConfig, aOption, aValue);
     639}
     640
     641
     642HRESULT DHCPServer::removeGlobalOption(DhcpOpt_T aOption)
     643{
     644    return m->globalConfig->i_removeOption(aOption);
     645}
     646
     647
     648HRESULT DHCPServer::removeGlobalOptions()
     649{
     650    return m->globalConfig->i_removeAllOptions();
     651}
     652
     653
     654HRESULT DHCPServer::getGlobalOptions(std::vector<com::Utf8Str> &aValues)
     655{
     656    return i_getAllOptions60(*m->globalConfig, aValues);
     657}
     658
     659
     660HRESULT DHCPServer::getVmConfigs(std::vector<com::Utf8Str> &aValues)
     661{
     662    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     663
     664    try
     665    {
     666        aValues.resize(m->individualConfigs.size());
     667        size_t i = 0;
     668        for (Data::IndividualConfigIterator it = m->individualConfigs.begin(); it != m->individualConfigs.end(); ++it, i++)
     669            if (it->second->i_getScope() != DHCPConfigScope_MAC)
     670                aValues[i].printf("[%RTuuid]:%d", it->second->i_getMachineId().raw(), it->second->i_getSlot());
     671            else
     672                aValues[i].printf("[%RTmac]", it->second->i_getMACAddress());
     673    }
     674    catch (std::bad_alloc &)
     675    {
     676        return E_OUTOFMEMORY;
     677    }
     678
     679    return S_OK;
     680}
     681
     682
     683HRESULT DHCPServer::i_vmNameToIdAndValidateSlot(const com::Utf8Str &aVmName, LONG aSlot, com::Guid &idMachine)
     684{
     685    if ((ULONG)aSlot <= 32)
     686    {
     687        /* Is it a UUID? */
     688        idMachine = aVmName;
     689        if (idMachine.isValid() && !idMachine.isZero())
     690            return S_OK;
     691
     692        /* No, find the VM and get it's UUID. */
     693        ComObjPtr<Machine> ptrMachine;
     694        HRESULT hrc = m->pVirtualBox->i_findMachine(aVmName, false /*fPermitInaccessible*/, true /*aSetError*/, &ptrMachine);
     695        if (SUCCEEDED(hrc))
     696            idMachine = ptrMachine->i_getId();
     697        return hrc;
     698    }
     699    return setError(E_INVALIDARG, tr("NIC slot number (%d) is out of range (0..32)"), aSlot);
     700}
     701
     702
     703/**
     704 * Translates a VM name/id and slot to an individual configuration object.
     705 *
     706 * @returns COM status code.
     707 * @param   a_strVmName         The VM name or ID.
     708 * @param   a_uSlot             The NIC slot.
     709 * @param   a_fCreateIfNeeded   Whether to create a new entry if not found.
     710 * @param   a_rPtrConfig        Where to return the config object.  It's
     711 *                              implicitly referenced, so we don't be returning
     712 *                              with any locks held.
     713 *
     714 * @note    Caller must not be holding any locks!
     715 */
     716HRESULT DHCPServer::i_vmNameAndSlotToConfig(const com::Utf8Str &a_strVmName, LONG a_uSlot, bool a_fCreateIfNeeded,
     717                                            ComObjPtr<DHCPIndividualConfig> &a_rPtrConfig)
     718{
     719    /*
     720     * Validate the slot and normalize the name into a UUID.
     721     */
     722    com::Guid idMachine;
     723    HRESULT hrc = i_vmNameToIdAndValidateSlot(a_strVmName, a_uSlot, idMachine);
     724    if (SUCCEEDED(hrc))
     725    {
     726        Utf8Str strKey;
     727        int vrc = strKey.printfNoThrow("%RTuuid/%u", idMachine.raw(), a_uSlot);
     728        if (RT_SUCCESS(vrc))
     729        {
     730            /*
     731             * Look it up.
     732             */
    463733            {
    464                 u32Enc = DhcpOptEncoding_Legacy;
    465                 break;
     734                AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     735                Data::IndividualConfigIterator it = m->individualConfigs.find(strKey);
     736                if (it != m->individualConfigs.end())
     737                {
     738                    a_rPtrConfig = it->second;
     739                    return S_OK;
     740                }
    466741            }
    467 
    468             case '=':
     742            if (a_fCreateIfNeeded)
    469743            {
    470                 u32Enc = DhcpOptEncoding_Hex;
    471                 break;
     744                /*
     745                 * Create a new slot.
     746                 */
     747                /* Instantiate the object: */
     748                hrc = a_rPtrConfig.createObject();
     749                if (SUCCEEDED(hrc))
     750                    hrc = a_rPtrConfig->initWithMachineIdAndSlot(m->pVirtualBox, this, idMachine, a_uSlot,
     751                                                                 m->uIndividualMACAddressVersion - UINT32_MAX / 4);
     752                if (SUCCEEDED(hrc))
     753                {
     754                    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     755
     756                    /* Check for creation race: */
     757                    Data::IndividualConfigIterator it = m->individualConfigs.find(strKey);
     758                    if (it != m->individualConfigs.end())
     759                    {
     760                        a_rPtrConfig.setNull();
     761                        a_rPtrConfig = it->second;
     762                        return S_OK;
     763                    }
     764
     765                    /* Add it. */
     766                    try
     767                    {
     768                        m->individualConfigs[strKey] = a_rPtrConfig;
     769                        return S_OK;
     770                    }
     771                    catch (std::bad_alloc &)
     772                    {
     773                        hrc = E_OUTOFMEMORY;
     774                    }
     775                    a_rPtrConfig.setNull();
     776                }
    472777            }
    473 
    474             case '@':
    475             {
    476                 vrc = RTStrToUInt32Ex(pszNext + 1, &pszNext, 10, &u32Enc);
    477                 if (!RT_SUCCESS(vrc))
    478                     return VERR_PARSE_ERROR;
    479                 if (*pszNext != '=')
    480                     return VERR_PARSE_ERROR;
    481                 break;
    482             }
    483 
    484             default:
    485                 return VERR_PARSE_ERROR;
    486         }
    487 
    488         aOption = (DhcpOpt_T)u8Code;
    489         OptValue = settings::DhcpOptValue(pszNext + 1, (DhcpOptEncoding_T)u32Enc);
    490     }
    491 
    492     aMap[aOption] = OptValue;
    493     return VINF_SUCCESS;
    494 }
    495 
    496 
    497 HRESULT DHCPServer::addGlobalOption(DhcpOpt_T aOption, const com::Utf8Str &aValue)
    498 {
    499     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    500 
    501     int rc = addOption(m->GlobalDhcpOptions, aOption, aValue);
    502     if (!RT_SUCCESS(rc))
    503         return E_INVALIDARG;
    504 
    505     /* Indirect way to understand that we're on NAT network */
    506     if (aOption == DhcpOpt_Router)
    507     {
    508         m->router = true;
    509     }
    510 
    511     alock.release();
    512 
    513     AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
    514     return mVirtualBox->i_saveSettings();
    515 }
    516 
    517 
    518 HRESULT DHCPServer::removeGlobalOption(DhcpOpt_T aOption)
    519 {
    520     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    521 
    522     settings::DhcpOptionMap::size_type cErased = m->GlobalDhcpOptions.erase(aOption);
    523     if (!cErased)
    524         return E_INVALIDARG;
    525 
    526     alock.release();
    527 
    528     AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
    529     return mVirtualBox->i_saveSettings();
    530 }
    531 
    532 
    533 HRESULT DHCPServer::removeGlobalOptions()
    534 {
    535     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    536     m->GlobalDhcpOptions.clear();
    537 
    538     alock.release();
    539 
    540     AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
    541     return mVirtualBox->i_saveSettings();
    542 }
    543 
    544 
    545 HRESULT DHCPServer::getGlobalOptions(std::vector<com::Utf8Str> &aValues)
    546 {
    547     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    548     aValues.resize(m->GlobalDhcpOptions.size());
    549     settings::DhcpOptionMap::const_iterator it;
    550     size_t i = 0;
    551     for (it = m->GlobalDhcpOptions.begin(); it != m->GlobalDhcpOptions.end(); ++it, ++i)
    552     {
    553         uint32_t OptCode = (*it).first;
    554         const settings::DhcpOptValue &OptValue = (*it).second;
    555 
    556         encodeOption(aValues[i], OptCode, OptValue);
    557     }
    558 
    559     return S_OK;
    560 }
    561 
    562 HRESULT DHCPServer::getVmConfigs(std::vector<com::Utf8Str> &aValues)
    563 {
    564     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    565     aValues.resize(m->VmSlot2Options.size());
    566     settings::VmSlot2OptionsMap::const_iterator it;
    567     size_t i = 0;
    568     for (it = m->VmSlot2Options.begin(); it != m->VmSlot2Options.end(); ++it, ++i)
    569     {
    570         aValues[i] = Utf8StrFmt("[%s]:%d", it->first.VmName.c_str(), it->first.Slot);
    571     }
    572 
    573     return S_OK;
    574 }
    575 
    576 
    577 HRESULT DHCPServer::addVmSlotOption(const com::Utf8Str &aVmName,
    578                                     LONG aSlot,
    579                                     DhcpOpt_T aOption,
    580                                     const com::Utf8Str &aValue)
    581 {
    582     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    583 
    584     settings::DhcpOptionMap &map = m->VmSlot2Options[settings::VmNameSlotKey(aVmName, aSlot)];
    585     int rc = addOption(map, aOption, aValue);
    586     if (!RT_SUCCESS(rc))
    587         return E_INVALIDARG;
    588 
    589     alock.release();
    590 
    591     AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
    592     return mVirtualBox->i_saveSettings();
     778            else
     779                hrc = VBOX_E_OBJECT_NOT_FOUND;
     780        }
     781        else
     782            hrc = E_OUTOFMEMORY;
     783    }
     784    return hrc;
     785}
     786
     787
     788HRESULT DHCPServer::addVmSlotOption(const com::Utf8Str &aVmName, LONG aSlot, DhcpOpt_T aOption, const com::Utf8Str &aValue)
     789{
     790    ComObjPtr<DHCPIndividualConfig> ptrConfig;
     791    HRESULT hrc = i_vmNameAndSlotToConfig(aVmName, aSlot, true, ptrConfig);
     792    if (SUCCEEDED(hrc))
     793        hrc = i_add60Option(*ptrConfig, aOption, aValue);
     794    return hrc;
    593795}
    594796
     
    596798HRESULT DHCPServer::removeVmSlotOption(const com::Utf8Str &aVmName, LONG aSlot, DhcpOpt_T aOption)
    597799{
    598     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    599     settings::DhcpOptionMap &map = i_findOptMapByVmNameSlot(aVmName, aSlot);
    600     settings::DhcpOptionMap::size_type cErased = map.erase(aOption);
    601     if (!cErased)
    602         return E_INVALIDARG;
    603 
    604     alock.release();
    605 
    606     AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
    607     return mVirtualBox->i_saveSettings();
     800    ComObjPtr<DHCPIndividualConfig> ptrConfig;
     801    HRESULT hrc = i_vmNameAndSlotToConfig(aVmName, aSlot, false, ptrConfig);
     802    if (SUCCEEDED(hrc))
     803        hrc = ptrConfig->i_removeOption(aOption);
     804    return hrc;
    608805}
    609806
     
    611808HRESULT DHCPServer::removeVmSlotOptions(const com::Utf8Str &aVmName, LONG aSlot)
    612809{
    613     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    614     settings::DhcpOptionMap &map = i_findOptMapByVmNameSlot(aVmName, aSlot);
    615     map.clear();
    616 
    617     alock.release();
    618 
    619     AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
    620     return mVirtualBox->i_saveSettings();
    621 }
    622 
    623 /**
    624  * this is mapping (vm, slot)
    625  */
    626 HRESULT DHCPServer::getVmSlotOptions(const com::Utf8Str &aVmName,
    627                                      LONG aSlot,
    628                                      std::vector<com::Utf8Str> &aValues)
    629 {
    630 
    631     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    632     settings::DhcpOptionMap &map = i_findOptMapByVmNameSlot(aVmName, aSlot);
    633     aValues.resize(map.size());
    634     size_t i = 0;
    635     settings::DhcpOptionMap::const_iterator it;
    636     for (it = map.begin(); it != map.end(); ++it, ++i)
    637     {
    638         uint32_t OptCode = (*it).first;
    639         const settings::DhcpOptValue &OptValue = (*it).second;
    640 
    641         encodeOption(aValues[i], OptCode, OptValue);
    642     }
    643 
    644     return S_OK;
     810    ComObjPtr<DHCPIndividualConfig> ptrConfig;
     811    HRESULT hrc = i_vmNameAndSlotToConfig(aVmName, aSlot, false, ptrConfig);
     812    if (SUCCEEDED(hrc))
     813        hrc = ptrConfig->i_removeAllOptions();
     814    return hrc;
     815}
     816
     817
     818HRESULT DHCPServer::getVmSlotOptions(const com::Utf8Str &aVmName, LONG aSlot, std::vector<com::Utf8Str> &aValues)
     819{
     820    ComObjPtr<DHCPIndividualConfig> ptrConfig;
     821    HRESULT hrc = i_vmNameAndSlotToConfig(aVmName, aSlot, false, ptrConfig);
     822    if (SUCCEEDED(hrc))
     823        hrc = i_getAllOptions60(*ptrConfig, aValues);
     824    else if (hrc == VBOX_E_OBJECT_NOT_FOUND)
     825    {
     826        aValues.resize(0);
     827        hrc = S_OK;
     828    }
     829    return hrc;
    645830}
    646831
     
    648833HRESULT DHCPServer::getMacOptions(const com::Utf8Str &aMAC, std::vector<com::Utf8Str> &aOption)
    649834{
    650     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    651     HRESULT hrc = S_OK;
    652     ComPtr<IMachine> machine;
    653     ComPtr<INetworkAdapter> nic;
    654     settings::VmSlot2OptionsIterator it;
    655     for(it = m->VmSlot2Options.begin(); it != m->VmSlot2Options.end(); ++it)
    656     {
    657         alock.release();
    658         hrc = mVirtualBox->FindMachine(Bstr(it->first.VmName).raw(), machine.asOutParam());
    659         alock.acquire();
    660 
    661         if (FAILED(hrc))
    662             continue;
    663 
    664         alock.release();
    665         hrc = machine->GetNetworkAdapter(it->first.Slot, nic.asOutParam());
    666         alock.acquire();
    667 
    668         if (FAILED(hrc))
    669             continue;
    670 
    671         com::Bstr mac;
    672 
    673         alock.release();
    674         hrc = nic->COMGETTER(MACAddress)(mac.asOutParam());
    675         alock.acquire();
    676 
    677         if (FAILED(hrc)) /* no MAC address ??? */
    678             break;
    679         if (!RTStrICmp(com::Utf8Str(mac).c_str(), aMAC.c_str()))
    680             return getVmSlotOptions(it->first.VmName,
    681                                     it->first.Slot,
    682                                     aOption);
    683     } /* end of for */
    684 
    685     return hrc;
    686 }
     835    RT_NOREF(aMAC, aOption);
     836    AssertFailed();
     837    return setError(E_NOTIMPL, tr("The GetMacOptions method has been discontinued as it was only supposed to be used by the DHCP server and it does not need it any more. sorry"));
     838}
     839
    687840
    688841HRESULT DHCPServer::getEventSource(ComPtr<IEventSource> &aEventSource)
     
    693846
    694847
    695 DECLINLINE(void) addOptionChild(xml::ElementNode *pParent, uint32_t OptCode, const settings::DhcpOptValue &OptValue)
    696 {
    697     xml::ElementNode *pOption = pParent->createChild("Option");
    698     pOption->setAttribute("name", OptCode);
    699     pOption->setAttribute("encoding", OptValue.encoding);
    700     pOption->setAttribute("value", OptValue.text.c_str());
     848HRESULT DHCPServer::getGlobalConfig(ComPtr<IDHCPGlobalConfig> &aGlobalConfig)
     849{
     850    /* The global configuration is immutable, so no need to lock anything here. */
     851    return m->globalConfig.queryInterfaceTo(aGlobalConfig.asOutParam());
     852}
     853
     854
     855HRESULT DHCPServer::getGroupConfigs(std::vector<ComPtr<IDHCPGroupConfig> > &aGroupConfigs)
     856{
     857    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     858#if 0 /** @todo implement group configs   */
     859
     860    try
     861    {
     862        aGroupConfigs.resize(m->groupConfigs.size());
     863    }
     864    catch (std::bad_alloc &)
     865    {
     866        return E_OUTOFMEMORY;
     867    }
     868
     869    size_t i = 0;
     870    for (Data::GroupConfigIterator it = m->groupConfigs.begin(); it != m->groupConfigs.end(); ++it)
     871    {
     872        HRESULT hrc = it->second.queryInterfaceTo(aGroupConfigs[i].asOutParam());
     873        if (FAILED(hrc))
     874            return hrc;
     875    }
     876
     877#else
     878    aGroupConfigs.resize(0);
     879#endif
     880    return S_OK;
     881}
     882
     883
     884HRESULT DHCPServer::getIndividualConfigs(std::vector<ComPtr<IDHCPIndividualConfig> > &aIndividualConfigs)
     885{
     886    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     887
     888    try
     889    {
     890        aIndividualConfigs.resize(m->individualConfigs.size());
     891    }
     892    catch (std::bad_alloc &)
     893    {
     894        return E_OUTOFMEMORY;
     895    }
     896
     897    size_t i = 0;
     898    for (Data::IndividualConfigIterator it = m->individualConfigs.begin(); it != m->individualConfigs.end(); ++it)
     899    {
     900        HRESULT hrc = it->second.queryInterfaceTo(aIndividualConfigs[i].asOutParam());
     901        if (FAILED(hrc))
     902            return hrc;
     903    }
     904
     905    return S_OK;
    701906}
    702907
     
    718923
    719924
    720 HRESULT DHCPServer::start(const com::Utf8Str &aNetworkName,
    721                           const com::Utf8Str &aTrunkName,
    722                           const com::Utf8Str &aTrunkType)
    723 {
     925/**
     926 * @throws std::bad_alloc
     927 */
     928HRESULT DHCPServer::i_writeDhcpdConfig(const char *pszFilename, uint32_t uMACAddressVersion)
     929{
     930    /*
     931     * Produce the DHCP server configuration.
     932     */
     933    xml::Document doc;
     934    try
     935    {
     936        xml::ElementNode *pElmRoot = doc.createRootElement("DHCPServer");
     937        pElmRoot->setAttribute("networkName", m->networkName);
     938        if (m->trunkName.isNotEmpty())
     939            pElmRoot->setAttribute("trunkName", m->trunkName);
     940        pElmRoot->setAttribute("trunkType", m->trunkType);
     941        pElmRoot->setAttribute("IPAddress",  m->IPAddress);
     942        pElmRoot->setAttribute("lowerIP", m->lowerIP);
     943        pElmRoot->setAttribute("upperIP", m->upperIP);
     944        pElmRoot->setAttribute("leasesFilename", m->strLeasesFilename);
     945        Utf8Str strNetworkMask;
     946        HRESULT hrc = m->globalConfig->i_getNetworkMask(strNetworkMask);
     947        if (FAILED(hrc))
     948            return hrc;
     949        pElmRoot->setAttribute("networkMask", strNetworkMask);
     950
     951        /*
     952         * Process global options
     953         */
     954        m->globalConfig->i_writeDhcpdConfig(pElmRoot->createChild("Options"));
     955
     956        /*
     957         * Groups.
     958         */
     959        //for (Data::GroupConfigIterator it = m->groupConfigs.begin(); it != m->groupConfigs.end(); ++it)
     960        //    it->second->i_writeDhcpdConfig(pElmRoot->createChild("Config"));
     961
     962        /*
     963         * Individual NIC configurations.
     964         */
     965        for (Data::IndividualConfigIterator it = m->individualConfigs.begin(); it != m->individualConfigs.end(); ++it)
     966            if (it->second->i_isMACAddressResolved(uMACAddressVersion))
     967                it->second->i_writeDhcpdConfig(pElmRoot->createChild("Config"));
     968            else
     969                LogRelFunc(("Skipping %RTuuid/%u, no MAC address.\n", it->second->i_getMachineId().raw(), it->second->i_getSlot()));
     970    }
     971    catch (std::bad_alloc &)
     972    {
     973        return E_OUTOFMEMORY;
     974    }
     975
     976    /*
     977     * Write out the document.
     978     */
     979    try
     980    {
     981        xml::XmlFileWriter writer(doc);
     982        writer.write(pszFilename, false);
     983    }
     984    catch (...)
     985    {
     986        return E_FAIL;
     987    }
     988
     989    return S_OK;
     990}
     991
     992
     993/** @todo r=bird: why do we get the network name passed in here?  it's the same
     994 *        as m->strName, isn't it? */
     995HRESULT DHCPServer::start(const com::Utf8Str &aNetworkName, const com::Utf8Str &aTrunkName, const com::Utf8Str &aTrunkType)
     996{
     997    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     998
    724999    /* Silently ignore attempts to run disabled servers. */
    7251000    if (!m->enabled)
    7261001        return S_OK;
    7271002
    728     /**
    729      * @todo: the existing code cannot handle concurrent attempts to start DHCP server.
    730      * Note that technically it may receive different parameters from different callers.
     1003    /*
     1004     * Resolve the MAC addresses.  This requires us to leave the lock.
     1005     */
     1006    uint32_t uMACAddressVersion = m->uIndividualMACAddressVersion;
     1007    if (m->individualConfigs.size() > 0)
     1008    {
     1009        m->uIndividualMACAddressVersion = uMACAddressVersion + 1;
     1010
     1011        /* Retain pointers to all the individual configuration objects so we
     1012           can safely access these after releaseing the lock: */
     1013        std::vector< ComObjPtr<DHCPIndividualConfig> > vecIndividualConfigs;
     1014        try
     1015        {
     1016            vecIndividualConfigs.resize(m->individualConfigs.size());
     1017        }
     1018        catch (std::bad_alloc &)
     1019        {
     1020            return E_OUTOFMEMORY;
     1021        }
     1022        size_t i = 0;
     1023        for (Data::IndividualConfigIterator it = m->individualConfigs.begin(); it != m->individualConfigs.end(); ++it, i++)
     1024            vecIndividualConfigs[i] = it->second;
     1025
     1026        /* Drop the lock and resolve the MAC addresses: */
     1027        alock.release();
     1028
     1029        i = vecIndividualConfigs.size();
     1030        while (i-- > 0)
     1031            vecIndividualConfigs[i]->i_resolveMACAddress(uMACAddressVersion);
     1032
     1033        /* Reacquire the lock  */
     1034        alock.acquire();
     1035        if (!m->enabled)
     1036            return S_OK;
     1037    }
     1038
     1039    /*
     1040     * Refuse to start a 2nd DHCP server instance for the same network.
     1041     */
     1042    if (m->dhcp.isRunning())
     1043        return setErrorBoth(VBOX_E_OBJECT_IN_USE, VERR_PROCESS_RUNNING,
     1044                            tr("Cannot start DHCP server because it is already running"));
     1045
     1046    /*
     1047     * Copy the startup parameters.
    7311048     */
    7321049    m->networkName = aNetworkName;
     
    7341051    m->trunkType   = aTrunkType;
    7351052    HRESULT hrc = i_calcLeasesFilename(aNetworkName);
    736     if (FAILED(hrc))
    737         return hrc;
    738 
    739     m->dhcp.resetArguments();
    740 
    741 #ifdef VBOX_WITH_DHCPD
    742 
    743     /*
    744      * Create configuration file path.
    745      */
    746     /** @todo put this next to the leases file.   */
    747     int rc = RTPathTemp(m->szTempConfigFileName, sizeof(m->szTempConfigFileName));
    748     if (RT_SUCCESS(rc))
    749         rc = RTPathAppend(m->szTempConfigFileName, sizeof(m->szTempConfigFileName), "dhcp-config-XXXXX.xml");
    750     if (RT_SUCCESS(rc))
    751         rc = RTFileCreateTemp(m->szTempConfigFileName, 0600);
    752     if (RT_FAILURE(rc))
    753     {
     1053    if (SUCCEEDED(hrc))
     1054    {
     1055        /*
     1056         * Create configuration file path and write out the configuration.
     1057         */
     1058        /** @todo put this next to the leases file.   */
     1059        int vrc = RTPathTemp(m->szTempConfigFileName, sizeof(m->szTempConfigFileName));
     1060        if (RT_SUCCESS(vrc))
     1061            vrc = RTPathAppend(m->szTempConfigFileName, sizeof(m->szTempConfigFileName), "dhcp-config-XXXXX.xml");
     1062        if (RT_SUCCESS(vrc))
     1063            vrc = RTFileCreateTemp(m->szTempConfigFileName, 0600);
     1064        if (RT_SUCCESS(vrc))
     1065        {
     1066            hrc = i_writeDhcpdConfig(m->szTempConfigFileName, uMACAddressVersion);
     1067            if (SUCCEEDED(hrc))
     1068            {
     1069                /*
     1070                 * Setup the arguments and start the DHCP server.
     1071                 */
     1072                m->dhcp.resetArguments();
     1073                vrc = m->dhcp.addArgPair(DHCPServerRunner::kDsrKeyConfig, m->szTempConfigFileName);
     1074                if (RT_SUCCESS(vrc))
     1075                    vrc = m->dhcp.addArgPair(DHCPServerRunner::kDsrKeyComment, m->networkName.c_str());
     1076                if (RT_SUCCESS(vrc))
     1077                    vrc = m->dhcp.start(true /*aKillProcessOnStop*/);
     1078                if (RT_FAILURE(vrc))
     1079                    hrc = setErrorVrc(vrc, tr("Failed to start DHCP server for '%s': %Rrc"), m->strName.c_str(), vrc);
     1080            }
     1081            if (FAILED(hrc))
     1082            {
     1083                RTFileDelete(m->szTempConfigFileName);
     1084                m->szTempConfigFileName[0] = '\0';
     1085            }
     1086        }
     1087        else
     1088        {
     1089            m->szTempConfigFileName[0] = '\0';
     1090            hrc = setErrorVrc(vrc);
     1091        }
     1092    }
     1093    return hrc;
     1094}
     1095
     1096
     1097HRESULT DHCPServer::stop(void)
     1098{
     1099    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     1100
     1101    if (m->szTempConfigFileName[0])
     1102    {
     1103        RTFileDelete(m->szTempConfigFileName);
    7541104        m->szTempConfigFileName[0] = '\0';
    755         return E_FAIL;
    756     }
    757 
    758     /*
    759      * Produce the DHCP server configuration.
    760      */
    761     xml::Document doc;
    762     xml::ElementNode *pElmRoot = doc.createRootElement("DHCPServer");
    763     pElmRoot->setAttribute("networkName", m->networkName);
    764     if (m->trunkName.isNotEmpty())
    765         pElmRoot->setAttribute("trunkName", m->trunkName);
    766     pElmRoot->setAttribute("trunkType", m->trunkType);
    767     pElmRoot->setAttribute("IPAddress",  m->IPAddress);
    768     pElmRoot->setAttribute("networkMask", m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text);
    769     pElmRoot->setAttribute("lowerIP", m->lowerIP);
    770     pElmRoot->setAttribute("upperIP", m->upperIP);
    771     pElmRoot->setAttribute("leasesFilename", m->strLeasesFilename);
    772 
    773     /* Process global options */
    774     xml::ElementNode *pOptions = pElmRoot->createChild("Options");
    775     for (settings::DhcpOptionMap::const_iterator it = m->GlobalDhcpOptions.begin(); it != m->GlobalDhcpOptions.end(); ++it)
    776         addOptionChild(pOptions, (*it).first, (*it).second);
    777 
    778     /* Process network-adapter-specific options */
    779     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    780     hrc = S_OK;
    781     ComPtr<IMachine> machine;
    782     ComPtr<INetworkAdapter> nic;
    783     settings::VmSlot2OptionsIterator it;
    784     for (it = m->VmSlot2Options.begin(); it != m->VmSlot2Options.end(); ++it)
    785     {
    786         alock.release();
    787         hrc = mVirtualBox->FindMachine(Bstr(it->first.VmName).raw(), machine.asOutParam());
    788         alock.acquire();
    789 
    790         if (FAILED(hrc))
    791             continue;
    792 
    793         alock.release();
    794         hrc = machine->GetNetworkAdapter(it->first.Slot, nic.asOutParam());
    795         alock.acquire();
    796 
    797         if (FAILED(hrc))
    798             continue;
    799 
    800         com::Bstr mac;
    801 
    802         alock.release();
    803         hrc = nic->COMGETTER(MACAddress)(mac.asOutParam());
    804         alock.acquire();
    805 
    806         if (FAILED(hrc)) /* no MAC address ??? */
    807             continue;
    808 
    809         /* Convert MAC address from XXXXXXXXXXXX to XX:XX:XX:XX:XX:XX */
    810         Utf8Str strMacWithoutColons(mac);
    811         const char *pszSrc = strMacWithoutColons.c_str();
    812         RTMAC binaryMac;
    813         if (RTStrConvertHexBytes(pszSrc, &binaryMac, sizeof(binaryMac), 0) != VINF_SUCCESS)
    814             continue;
    815         char szMac[18]; /* "XX:XX:XX:XX:XX:XX" */
    816         if (RTStrPrintHexBytes(szMac, sizeof(szMac), &binaryMac, sizeof(binaryMac), RTSTRPRINTHEXBYTES_F_SEP_COLON) != VINF_SUCCESS)
    817             continue;
    818 
    819         xml::ElementNode *pMacConfig = pElmRoot->createChild("Config");
    820         pMacConfig->setAttribute("MACAddress", szMac);
    821 
    822         com::Utf8Str encodedOption;
    823         settings::DhcpOptionMap &map = i_findOptMapByVmNameSlot(it->first.VmName, it->first.Slot);
    824         settings::DhcpOptionMap::const_iterator itAdapterOption;
    825         for (itAdapterOption = map.begin(); itAdapterOption != map.end(); ++itAdapterOption)
    826             addOptionChild(pMacConfig, (*itAdapterOption).first, (*itAdapterOption).second);
    827     }
    828 
    829     xml::XmlFileWriter writer(doc);
    830     writer.write(m->szTempConfigFileName, false);
    831 
    832     m->dhcp.addArgPair(DHCPServerRunner::kDsrKeyConfig, m->szTempConfigFileName);
    833     m->dhcp.addArgPair(DHCPServerRunner::kDsrKeyComment, m->networkName.c_str());
    834 
    835 #else /* !VBOX_WITH_DHCPD */
    836     /* Main is needed for NATNetwork */
    837     if (m->router)
    838         m->dhcp.addArgPair(NetworkServiceRunner::kpszKeyNeedMain, "on");
    839 
    840     /* Commmon Network Settings */
    841     m->dhcp.addArgPair(NetworkServiceRunner::kpszKeyNetwork, aNetworkName.c_str());
    842     if (!aTrunkName.isEmpty())
    843         m->dhcp.addArgPair(NetworkServiceRunner::kpszTrunkName, aTrunkName.c_str());
    844     m->dhcp.addArgPair(NetworkServiceRunner::kpszKeyTrunkType, aTrunkType.c_str());
    845 
    846     /* XXX: should this MAC default initialization moved to NetworkServiceRunner? */
    847     char strMAC[32];
    848     Guid guid;
    849     guid.create();
    850     RTStrPrintf (strMAC, sizeof(strMAC), "08:00:27:%02X:%02X:%02X",
    851                  guid.raw()->au8[0], guid.raw()->au8[1], guid.raw()->au8[2]);
    852     m->dhcp.addArgPair(NetworkServiceRunner::kpszMacAddress, strMAC);
    853     m->dhcp.addArgPair(NetworkServiceRunner::kpszIpAddress, m->IPAddress.c_str());
    854     m->dhcp.addArgPair(NetworkServiceRunner::kpszIpNetmask, m->GlobalDhcpOptions[DhcpOpt_SubnetMask].text.c_str());
    855     m->dhcp.addArgPair(DHCPServerRunner::kDsrKeyLowerIp, m->lowerIP.c_str());
    856     m->dhcp.addArgPair(DHCPServerRunner::kDsrKeyUpperIp, m->upperIP.c_str());
    857 #endif /* !VBOX_WITH_DHCPD */
    858 
    859     /* XXX: This parameters Dhcp Server will fetch via API */
    860     return RT_FAILURE(m->dhcp.start(!m->router /* KillProcOnExit */)) ? E_FAIL : S_OK;
    861     //m->dhcp.detachFromServer(); /* need to do this to avoid server shutdown on runner destruction */
    862 }
    863 
    864 
    865 HRESULT DHCPServer::stop(void)
    866 {
    867 #ifdef VBOX_WITH_DHCPD
    868     if (m->szTempConfigFileName[0])
    869     {
    870         RTFileDelete(m->szTempConfigFileName);
    871         m->szTempConfigFileName[0] = 0;
    872     }
    873 #endif /* VBOX_WITH_DHCPD */
    874     return RT_FAILURE(m->dhcp.stop()) ? E_FAIL : S_OK;
     1105    }
     1106
     1107    int vrc = m->dhcp.stop();
     1108    if (RT_SUCCESS(vrc))
     1109        return S_OK;
     1110    return setErrorVrc(vrc);
    8751111}
    8761112
     
    9011137    if (m->strLeasesFilename.isEmpty())
    9021138    {
    903         HRESULT hrc = i_calcLeasesFilename(m->networkName.isEmpty() ? mName : m->networkName);
     1139        HRESULT hrc = i_calcLeasesFilename(m->networkName.isEmpty() ? m->strName : m->networkName);
    9041140        if (FAILED(hrc))
    9051141            return hrc;
     
    10201256
    10211257
     1258HRESULT DHCPServer::getConfig(DHCPConfigScope_T aScope, const com::Utf8Str &aName, ULONG aSlot, BOOL aMayAdd,
     1259                              ComPtr<IDHCPConfig> &aConfig)
     1260{
     1261    if (aSlot != 0 && aScope != DHCPConfigScope_MachineNIC)
     1262        return setError(E_INVALIDARG, tr("The 'slot' argument must be zero for all but the MachineNIC scope!"));
     1263
     1264    switch (aScope)
     1265    {
     1266        case DHCPConfigScope_Global:
     1267            if (aName.isNotEmpty())
     1268                return setError(E_INVALIDARG, tr("The name must be empty or NULL for the Global scope!"));
     1269            /* No locking required here. */
     1270            return m->globalConfig.queryInterfaceTo(aConfig.asOutParam());
     1271
     1272        case DHCPConfigScope_Group:
     1273            return setError(E_NOTIMPL, tr("Groups are not yet implemented, sorry."));
     1274
     1275        case DHCPConfigScope_MachineNIC:
     1276        {
     1277            ComObjPtr<DHCPIndividualConfig> ptrIndividualConfig;
     1278            HRESULT hrc = i_vmNameAndSlotToConfig(aName, aSlot, aMayAdd != FALSE, ptrIndividualConfig);
     1279            if (SUCCEEDED(hrc))
     1280                hrc = ptrIndividualConfig.queryInterfaceTo(aConfig.asOutParam());
     1281            return hrc;
     1282        }
     1283
     1284        case DHCPConfigScope_MAC:
     1285        {
     1286            /* Check and Normalize the MAC address into a key: */
     1287            RTMAC MACAddress;
     1288            int vrc = RTNetStrToMacAddr(aName.c_str(), &MACAddress);
     1289            if (RT_SUCCESS(vrc))
     1290            {
     1291                Utf8Str strKey;
     1292                vrc = strKey.printfNoThrow("%RTmac", &MACAddress);
     1293                if (RT_SUCCESS(vrc))
     1294                {
     1295                    /* Look up the MAC address: */
     1296                    {
     1297                        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     1298                        Data::IndividualConfigIterator it = m->individualConfigs.find(strKey);
     1299                        if (it != m->individualConfigs.end())
     1300                            return it->second.queryInterfaceTo(aConfig.asOutParam());
     1301                    }
     1302                    if (aMayAdd)
     1303                    {
     1304                        /* Create a new individiual configuration: */
     1305                        ComObjPtr<DHCPIndividualConfig> ptrIndividualConfig;
     1306                        HRESULT hrc = ptrIndividualConfig.createObject();
     1307                        if (SUCCEEDED(hrc))
     1308                            hrc = ptrIndividualConfig->initWithMACAddress(m->pVirtualBox, this, &MACAddress);
     1309                        if (SUCCEEDED(hrc))
     1310                        {
     1311                            AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     1312
     1313                            /* Check for insertion race: */
     1314                            Data::IndividualConfigIterator it = m->individualConfigs.find(strKey);
     1315                            if (it != m->individualConfigs.end())
     1316                                return it->second.queryInterfaceTo(aConfig.asOutParam()); /* creation race*/
     1317
     1318                            /* Try insert it: */
     1319                            try
     1320                            {
     1321                                m->individualConfigs[strKey] = ptrIndividualConfig;
     1322                            }
     1323                            catch (std::bad_alloc &)
     1324                            {
     1325                                return E_OUTOFMEMORY;
     1326                            }
     1327                            return ptrIndividualConfig.queryInterfaceTo(aConfig.asOutParam());
     1328                        }
     1329                    }
     1330                    else
     1331                        return setError(VBOX_E_OBJECT_NOT_FOUND, tr("Found no configuration for MAC address %s"), strKey.c_str());
     1332                }
     1333                return E_OUTOFMEMORY;
     1334            }
     1335            return setErrorBoth(E_INVALIDARG, vrc, tr("Invalid MAC address: %s"), aName.c_str());
     1336        }
     1337
     1338        default:
     1339            return E_FAIL;
     1340    }
     1341}
     1342
     1343
    10221344/**
    10231345 * Calculates and updates the value of strLeasesFilename given @a aNetwork.
     
    10281350
    10291351    /* The lease file must be the same as we used the last time, so careful when changing this code. */
    1030     int vrc = m->strLeasesFilename.assignNoThrow(mVirtualBox->i_homeDir());
     1352    int vrc = m->strLeasesFilename.assignNoThrow(m->pVirtualBox->i_homeDir());
    10311353    if (RT_SUCCESS(vrc))
    10321354        vrc = RTPathAppendCxx(m->strLeasesFilename, aNetwork);
     
    10421364}
    10431365
    1044 settings::DhcpOptionMap &DHCPServer::i_findOptMapByVmNameSlot(const com::Utf8Str &aVmName,
    1045                                                               LONG aSlot)
    1046 {
    1047     return m->VmSlot2Options[settings::VmNameSlotKey(aVmName, aSlot)];
    1048 }
    1049 
  • trunk/src/VBox/Main/xml/Settings.cpp

    r78632 r79732  
    16141614 * Constructor. Needs to set sane defaults which stand the test of time.
    16151615 */
    1616 DhcpOptValue::DhcpOptValue() :
    1617     text(),
    1618     encoding(DhcpOptEncoding_Legacy)
     1616DhcpOptValue::DhcpOptValue()
     1617    : strValue()
     1618    , enmEncoding(DHCPOptionEncoding_Legacy)
    16191619{
    16201620}
     
    16231623 * Non-standard constructor.
    16241624 */
    1625 DhcpOptValue::DhcpOptValue(const com::Utf8Str &aText, DhcpOptEncoding_T aEncoding) :
    1626     text(aText),
    1627     encoding(aEncoding)
    1628 {
    1629 }
    1630 
    1631 /**
    1632  * Non-standard constructor.
    1633  */
    1634 VmNameSlotKey::VmNameSlotKey(const com::Utf8Str& aVmName, LONG aSlot) :
    1635     VmName(aVmName),
    1636     Slot(aSlot)
    1637 {
    1638 }
    1639 
    1640 /**
    1641  * Non-standard comparison operator.
    1642  */
    1643 bool VmNameSlotKey::operator< (const VmNameSlotKey& that) const
    1644 {
    1645     if (VmName == that.VmName)
    1646         return Slot < that.Slot;
    1647     else
    1648         return VmName < that.VmName;
     1625DhcpOptValue::DhcpOptValue(const com::Utf8Str &aText, DHCPOptionEncoding_T aEncoding)
     1626    : strValue(aText)
     1627    , enmEncoding(aEncoding)
     1628{
     1629}
     1630
     1631
     1632/**
     1633 * Default constructor.
     1634 */
     1635DHCPConfig::DHCPConfig()
     1636    : OptionMap()
     1637    , secMinLeaseTime(0)
     1638    , secDefaultLeaseTime(0)
     1639    , secMaxLeaseTime(0)
     1640{
     1641}
     1642
     1643/**
     1644 * Default constructor.
     1645 */
     1646DHCPIndividualConfig::DHCPIndividualConfig()
     1647    : DHCPConfig()
     1648    , strMACAddress()
     1649    , strVMName()
     1650    , uSlot(0)
     1651{
    16491652}
    16501653
     
    16521655 * Constructor. Needs to set sane defaults which stand the test of time.
    16531656 */
    1654 DHCPServer::DHCPServer() :
    1655     fEnabled(false)
     1657DHCPServer::DHCPServer()
     1658    : fEnabled(false)
    16561659{
    16571660}
     
    17051708
    17061709/**
     1710 * Builds the XML tree for the DHCP servers.
     1711 */
     1712void MainConfigFile::buildDHCPServers(xml::ElementNode &elmDHCPServers, DHCPServersList const &ll)
     1713{
     1714    for (DHCPServersList::const_iterator it = ll.begin(); it != ll.end(); ++it)
     1715    {
     1716        const DHCPServer &srv = *it;
     1717        xml::ElementNode *pElmThis = elmDHCPServers.createChild("DHCPServer");
     1718
     1719        pElmThis->setAttribute("networkName", srv.strNetworkName);
     1720        pElmThis->setAttribute("IPAddress", srv.strIPAddress);
     1721        DhcpOptConstIterator itOpt = srv.GlobalConfig.OptionMap.find(DhcpOpt_SubnetMask);
     1722        if (itOpt != srv.GlobalConfig.OptionMap.end())
     1723            pElmThis->setAttribute("networkMask", itOpt->second.strValue);
     1724        pElmThis->setAttribute("lowerIP", srv.strIPLower);
     1725        pElmThis->setAttribute("upperIP", srv.strIPUpper);
     1726        pElmThis->setAttribute("enabled", (srv.fEnabled) ? 1 : 0);        // too bad we chose 1 vs. 0 here
     1727
     1728        /* We don't want duplicate validation check of networkMask here*/
     1729        if (srv.GlobalConfig.OptionMap.size() > (itOpt != srv.GlobalConfig.OptionMap.end() ? 1 : 0))
     1730        {
     1731            xml::ElementNode *pElmOptions = pElmThis->createChild("Options");
     1732            buildDHCPOptions(*pElmOptions, srv.GlobalConfig, true);
     1733        }
     1734
     1735        if (srv.IndividualConfigs.size() > 0)
     1736        {
     1737            for (DHCPIndividualConfigMap::const_iterator itHost = srv.IndividualConfigs.begin();
     1738                 itHost != srv.IndividualConfigs.end(); ++itHost)
     1739            {
     1740                DHCPIndividualConfig const &rIndividualConfig = itHost->second;
     1741
     1742                xml::ElementNode *pElmConfig = pElmThis->createChild("Config");
     1743                if (rIndividualConfig.strMACAddress.isNotEmpty())
     1744                    pElmConfig->setAttribute("MACAddress", rIndividualConfig.strMACAddress);
     1745                if (rIndividualConfig.strVMName.isNotEmpty())
     1746                    pElmConfig->setAttribute("vm-name", rIndividualConfig.strVMName);
     1747                if (rIndividualConfig.uSlot != 0 || rIndividualConfig.strVMName.isNotEmpty())
     1748                    pElmConfig->setAttribute("slot", rIndividualConfig.strVMName);
     1749                if (rIndividualConfig.strFixedAddress.isNotEmpty())
     1750                    pElmConfig->setAttribute("fixedAddress", rIndividualConfig.strFixedAddress);
     1751                buildDHCPOptions(*pElmConfig, rIndividualConfig, false);
     1752            }
     1753        }
     1754     }
     1755}
     1756
     1757/**
     1758 * Worker for buildDHCPServers() that builds Options or Config element trees.
     1759 */
     1760void MainConfigFile::buildDHCPOptions(xml::ElementNode &elmOptions, DHCPConfig const &rConfig, bool fSkipSubnetMask)
     1761{
     1762    /* Generic (and optional) attributes on the Options or Config element: */
     1763    if (rConfig.secMinLeaseTime > 0)
     1764        elmOptions.setAttribute("secMinLeaseTime", rConfig.secMinLeaseTime);
     1765    if (rConfig.secDefaultLeaseTime > 0)
     1766        elmOptions.setAttribute("secDefaultLeaseTime", rConfig.secDefaultLeaseTime);
     1767    if (rConfig.secMaxLeaseTime > 0)
     1768        elmOptions.setAttribute("secMaxLeaseTime", rConfig.secMaxLeaseTime);
     1769
     1770    /* The DHCP options are <Option> child elements: */
     1771    for (DhcpOptConstIterator it = rConfig.OptionMap.begin(); it != rConfig.OptionMap.end(); ++it)
     1772        if (it->first != DhcpOpt_SubnetMask || !fSkipSubnetMask)
     1773        {
     1774            xml::ElementNode *pElmOption = elmOptions.createChild("Option");
     1775            pElmOption->setAttribute("name", it->first);
     1776            pElmOption->setAttribute("value", it->second.strValue);
     1777            if (it->second.enmEncoding != DHCPOptionEncoding_Legacy)
     1778                pElmOption->setAttribute("encoding", (int32_t)it->second.enmEncoding);
     1779        }
     1780}
     1781
     1782/**
    17071783 * Reads in the \<DHCPServers\> chunk.
    17081784 * @param elmDHCPServers
     
    17191795            if (   pelmServer->getAttributeValue("networkName", srv.strNetworkName)
    17201796                && pelmServer->getAttributeValue("IPAddress", srv.strIPAddress)
    1721                 && pelmServer->getAttributeValue("networkMask", srv.GlobalDhcpOptions[DhcpOpt_SubnetMask].text)
     1797                && pelmServer->getAttributeValue("networkMask", srv.GlobalConfig.OptionMap[DhcpOpt_SubnetMask].strValue)
    17221798                && pelmServer->getAttributeValue("lowerIP", srv.strIPLower)
    17231799                && pelmServer->getAttributeValue("upperIP", srv.strIPUpper)
    17241800                && pelmServer->getAttributeValue("enabled", srv.fEnabled) )
    17251801            {
    1726                 xml::NodesLoop nlOptions(*pelmServer, "Options");
    1727                 const xml::ElementNode *options;
    1728                 /* XXX: Options are in 1:1 relation to DHCPServer */
    1729 
    1730                 while ((options = nlOptions.forAllNodes()))
     1802                /* Global options: */
     1803                const xml::ElementNode *pElmOptions;
     1804                xml::NodesLoop          nlOptions(*pelmServer, "Options");
     1805                while ((pElmOptions = nlOptions.forAllNodes()) != NULL) /** @todo this loop makes no sense, there can only be one <Options> child. */
     1806                    readDHCPOptions(srv.GlobalConfig, *pElmOptions, true /*fIgnoreSubnetMask*/);
     1807
     1808                /* host specific configuration: */
     1809                xml::NodesLoop nlConfig(*pelmServer, "Config");
     1810                const xml::ElementNode *pElmConfig;
     1811                while ((pElmConfig = nlConfig.forAllNodes()) != NULL)
    17311812                {
    1732                     readDhcpOptions(srv.GlobalDhcpOptions, *options);
    1733                 } /* end of forall("Options") */
    1734                 xml::NodesLoop nlConfig(*pelmServer, "Config");
    1735                 const xml::ElementNode *cfg;
    1736                 while ((cfg = nlConfig.forAllNodes()))
    1737                 {
    1738                     com::Utf8Str strVmName;
    1739                     uint32_t u32Slot;
    1740                     cfg->getAttributeValue("vm-name", strVmName);
    1741                     cfg->getAttributeValue("slot", u32Slot);
    1742                     readDhcpOptions(srv.VmSlot2OptionsM[VmNameSlotKey(strVmName, u32Slot)], *cfg);
     1813                    com::Utf8Str strMACAddress;
     1814                    if (!pElmConfig->getAttributeValue("MACAddress", strMACAddress))
     1815                        strMACAddress.setNull();
     1816
     1817                    com::Utf8Str strVMName;
     1818                    if (!pElmConfig->getAttributeValue("vm-name", strVMName))
     1819                        strVMName.setNull();
     1820
     1821                    uint32_t uSlot;
     1822                    if (!pElmConfig->getAttributeValue("slot", uSlot))
     1823                        uSlot = 0;
     1824
     1825                    com::Utf8Str strKey;
     1826                    if (strVMName.isNotEmpty())
     1827                        strKey.printf("%s/%u", strVMName.c_str(), uSlot);
     1828                    else
     1829                        strKey.printf("%s/%u", strMACAddress.c_str(), uSlot);
     1830
     1831                    DHCPIndividualConfig &rIndividualConfig = srv.IndividualConfigs[strKey];
     1832                    rIndividualConfig.strMACAddress = strMACAddress;
     1833                    rIndividualConfig.strVMName     = strVMName;
     1834                    rIndividualConfig.uSlot         = uSlot;
     1835                    pElmConfig->getAttributeValue("fixedAddress", rIndividualConfig.strFixedAddress);
     1836
     1837                    readDHCPOptions(rIndividualConfig, *pElmConfig, false /*fIgnoreSubnetMask*/);
    17431838                }
    17441839                llDhcpServers.push_back(srv);
     
    17501845}
    17511846
    1752 void MainConfigFile::readDhcpOptions(DhcpOptionMap& map,
    1753                                      const xml::ElementNode& options)
    1754 {
    1755     xml::NodesLoop nl2(options, "Option");
    1756     const xml::ElementNode *opt;
    1757     while ((opt = nl2.forAllNodes()))
     1847/**
     1848 * Worker for readDHCPServers that reads a configuration, either global,
     1849 * group or host (VM+NIC) specific.
     1850 */
     1851void MainConfigFile::readDHCPOptions(DHCPConfig &rConfig, const xml::ElementNode &elmConfig, bool fIgnoreSubnetMask)
     1852{
     1853    /* Generic (and optional) attributes on the Options or Config element: */
     1854    if (!elmConfig.getAttributeValue("secMinLeaseTime", rConfig.secMinLeaseTime))
     1855        rConfig.secMinLeaseTime = 0;
     1856    if (!elmConfig.getAttributeValue("secDefaultLeaseTime", rConfig.secDefaultLeaseTime))
     1857        rConfig.secDefaultLeaseTime = 0;
     1858    if (!elmConfig.getAttributeValue("secMaxLeaseTime", rConfig.secMaxLeaseTime))
     1859        rConfig.secMaxLeaseTime = 0;
     1860
     1861    /* The DHCP options are <Option> child elements: */
     1862    xml::NodesLoop          nl2(elmConfig, "Option");
     1863    const xml::ElementNode *pElmOption;
     1864    while ((pElmOption = nl2.forAllNodes()) != NULL)
    17581865    {
    17591866        DhcpOpt_T OptName;
    1760         com::Utf8Str OptText;
    1761         int32_t OptEnc = DhcpOptEncoding_Legacy;
    1762 
    1763         opt->getAttributeValue("name", (uint32_t&)OptName);
    1764 
    1765         if (OptName == DhcpOpt_SubnetMask)
     1867        pElmOption->getAttributeValue("name", (uint32_t&)OptName);
     1868        if (OptName == DhcpOpt_SubnetMask && fIgnoreSubnetMask)
    17661869            continue;
    17671870
    1768         opt->getAttributeValue("value", OptText);
    1769         opt->getAttributeValue("encoding", OptEnc);
    1770 
    1771         map[OptName] = DhcpOptValue(OptText, (DhcpOptEncoding_T)OptEnc);
     1871        com::Utf8Str strValue;
     1872        pElmOption->getAttributeValue("value", strValue);
     1873
     1874        int32_t iOptEnc;
     1875        if (!pElmOption->getAttributeValue("encoding", iOptEnc))
     1876            iOptEnc = DHCPOptionEncoding_Legacy;
     1877
     1878        rConfig.OptionMap[OptName] = DhcpOptValue(strValue, (DHCPOptionEncoding_T)iOptEnc);
    17721879    } /* end of forall("Option") */
    17731880
     
    20742181    {
    20752182        DHCPServer srv;
    2076         srv.strNetworkName =
    20772183#ifdef RT_OS_WINDOWS
    2078             "HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter";
     2184        srv.strNetworkName = "HostInterfaceNetworking-VirtualBox Host-Only Ethernet Adapter";
    20792185#else
    2080             "HostInterfaceNetworking-vboxnet0";
     2186        srv.strNetworkName = "HostInterfaceNetworking-vboxnet0";
    20812187#endif
    20822188        srv.strIPAddress = "192.168.56.100";
    2083         srv.GlobalDhcpOptions[DhcpOpt_SubnetMask] = DhcpOptValue("255.255.255.0");
     2189        srv.GlobalConfig.OptionMap[DhcpOpt_SubnetMask] = DhcpOptValue("255.255.255.0");
    20842190        srv.strIPLower = "192.168.56.101";
    20852191        srv.strIPUpper = "192.168.56.254";
     
    21372243    buildMediaRegistry(*pelmGlobal, mediaRegistry);
    21382244
    2139     xml::ElementNode *pelmNetserviceRegistry = pelmGlobal->createChild("NetserviceRegistry");
    2140     xml::ElementNode *pelmDHCPServers = pelmNetserviceRegistry->createChild("DHCPServers");
    2141     for (DHCPServersList::const_iterator it = llDhcpServers.begin();
    2142          it != llDhcpServers.end();
    2143          ++it)
    2144     {
    2145         const DHCPServer &d = *it;
    2146         xml::ElementNode *pelmThis = pelmDHCPServers->createChild("DHCPServer");
    2147         DhcpOptConstIterator itOpt;
    2148         itOpt = d.GlobalDhcpOptions.find(DhcpOpt_SubnetMask);
    2149 
    2150         pelmThis->setAttribute("networkName", d.strNetworkName);
    2151         pelmThis->setAttribute("IPAddress", d.strIPAddress);
    2152         if (itOpt != d.GlobalDhcpOptions.end())
    2153             pelmThis->setAttribute("networkMask", itOpt->second.text);
    2154         pelmThis->setAttribute("lowerIP", d.strIPLower);
    2155         pelmThis->setAttribute("upperIP", d.strIPUpper);
    2156         pelmThis->setAttribute("enabled", (d.fEnabled) ? 1 : 0);        // too bad we chose 1 vs. 0 here
    2157         /* We assume that if there're only 1 element it means that */
    2158         size_t cOpt = d.GlobalDhcpOptions.size();
    2159         /* We don't want duplicate validation check of networkMask here*/
    2160         if (   (   itOpt == d.GlobalDhcpOptions.end()
    2161                 && cOpt > 0)
    2162             || cOpt > 1)
    2163         {
    2164             xml::ElementNode *pelmOptions = pelmThis->createChild("Options");
    2165             for (itOpt = d.GlobalDhcpOptions.begin();
    2166                  itOpt != d.GlobalDhcpOptions.end();
    2167                  ++itOpt)
    2168             {
    2169                 if (itOpt->first == DhcpOpt_SubnetMask)
    2170                     continue;
    2171 
    2172                 xml::ElementNode *pelmOpt = pelmOptions->createChild("Option");
    2173 
    2174                 if (!pelmOpt)
    2175                     break;
    2176 
    2177                 pelmOpt->setAttribute("name", itOpt->first);
    2178                 pelmOpt->setAttribute("value", itOpt->second.text);
    2179                 if (itOpt->second.encoding != DhcpOptEncoding_Legacy)
    2180                     pelmOpt->setAttribute("encoding", (int)itOpt->second.encoding);
    2181             }
    2182         } /* end of if */
    2183 
    2184         if (d.VmSlot2OptionsM.size() > 0)
    2185         {
    2186             VmSlot2OptionsConstIterator itVmSlot;
    2187             DhcpOptConstIterator itOpt1;
    2188             for(itVmSlot = d.VmSlot2OptionsM.begin();
    2189                 itVmSlot != d.VmSlot2OptionsM.end();
    2190                 ++itVmSlot)
    2191             {
    2192                 xml::ElementNode *pelmCfg = pelmThis->createChild("Config");
    2193                 pelmCfg->setAttribute("vm-name", itVmSlot->first.VmName);
    2194                 pelmCfg->setAttribute("slot", (int32_t)itVmSlot->first.Slot);
    2195 
    2196                 for (itOpt1 = itVmSlot->second.begin();
    2197                      itOpt1 != itVmSlot->second.end();
    2198                      ++itOpt1)
    2199                 {
    2200                     xml::ElementNode *pelmOpt = pelmCfg->createChild("Option");
    2201                     pelmOpt->setAttribute("name", itOpt1->first);
    2202                     pelmOpt->setAttribute("value", itOpt1->second.text);
    2203                     if (itOpt1->second.encoding != DhcpOptEncoding_Legacy)
    2204                         pelmOpt->setAttribute("encoding", (int)itOpt1->second.encoding);
    2205                 }
    2206             }
    2207         } /* and of if */
    2208 
    2209      }
     2245    xml::ElementNode *pelmNetServiceRegistry = pelmGlobal->createChild("NetserviceRegistry"); /** @todo r=bird: wrong capitalization of NetServiceRegistry. sigh. */
     2246    buildDHCPServers(*pelmNetServiceRegistry->createChild("DHCPServers"), llDhcpServers);
    22102247
    22112248    xml::ElementNode *pelmNATNetworks;
     
    22132250    if (!llNATNetworks.empty())
    22142251    {
    2215         pelmNATNetworks = pelmNetserviceRegistry->createChild("NATNetworks");
     2252        pelmNATNetworks = pelmNetServiceRegistry->createChild("NATNetworks");
    22162253        for (NATNetworksList::const_iterator it = llNATNetworks.begin();
    22172254             it != llNATNetworks.end();
Note: See TracChangeset for help on using the changeset viewer.

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