VirtualBox

Ignore:
Timestamp:
Jul 5, 2019 10:59:01 AM (6 years ago)
Author:
vboxsync
Message:

Dhcpd: Went over the Config code adding comments, eliminating unnecessary copying (xml string getting, ++) and such. bugref:9288

Location:
trunk/src/VBox/NetworkServices/Dhcpd
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/NetworkServices/Dhcpd/Config.cpp

    r79524 r79553  
    1616 */
    1717
     18
     19/*********************************************************************************************************************************
     20*   Header Files                                                                                                                 *
     21*********************************************************************************************************************************/
    1822#include "DhcpdInternal.h"
    19 #include "Config.h"
    2023
    2124#include <iprt/ctype.h>
     
    2730#include <iprt/uuid.h>
    2831
    29 #include <VBox/com/com.h>
    30 
    31 #include <iostream>
    32 
     32#include <VBox/com/com.h>       /* For log initialization. */
     33
     34#include "Config.h"
     35
     36
     37/**
     38 * Configuration file exception.
     39 */
    3340class ConfigFileError
    34   : public RTCError
     41    : public RTCError
    3542{
    3643public:
    37     ConfigFileError(const char *pszMessage)
    38       : RTCError(pszMessage) {}
     44#if 0 /* This just confuses the compiler. */
     45    ConfigFileError(const char *a_pszMessage)
     46        : RTCError(a_pszMessage)
     47    {}
     48#endif
     49
     50    ConfigFileError(const char *a_pszMsgFmt, ...)
     51        : RTCError((char *)NULL)
     52    {
     53        va_list va;
     54        va_start(va, a_pszMsgFmt);
     55        m_strMsg.printfV(a_pszMsgFmt, va);
     56        va_end(va);
     57    }
    3958
    4059    ConfigFileError(const RTCString &a_rstrMessage)
    41       : RTCError(a_rstrMessage) {}
     60        : RTCError(a_rstrMessage)
     61    {}
    4262};
    4363
    4464
     65/**
     66 * Private default constructor, external users use factor methods.
     67 */
    4568Config::Config()
    46   : m_strHome(),
    47     m_strNetwork(),
    48     m_strBaseName(),
    49     m_strTrunk(),
    50     m_enmTrunkType(kIntNetTrunkType_Invalid),
    51     m_MacAddress(),
    52     m_IPv4Address(),
    53     m_IPv4Netmask(),
    54     m_IPv4PoolFirst(),
    55     m_IPv4PoolLast(),
    56     m_GlobalOptions(),
    57     m_VMMap()
    58 {
    59     return;
    60 }
    61 
    62 
    63 int Config::init()
    64 {
    65     int rc;
    66 
    67     rc = homeInit();
    68     if (RT_FAILURE(rc))
    69         return rc;
    70 
    71     return VINF_SUCCESS;
    72 }
    73 
    74 
    75 int Config::homeInit()
    76 {
    77     /* pathname of ~/.VirtualBox or equivalent */
     69    : m_strHome()
     70    , m_strNetwork()
     71    , m_strBaseName()
     72    , m_strTrunk()
     73    , m_enmTrunkType(kIntNetTrunkType_Invalid)
     74    , m_MacAddress()
     75    , m_IPv4Address()
     76    , m_IPv4Netmask()
     77    , m_IPv4PoolFirst()
     78    , m_IPv4PoolLast()
     79    , m_GlobalOptions()
     80    , m_VMMap()
     81{
     82}
     83
     84
     85/**
     86 * Initializes the object.
     87 *
     88 * @returns IPRT status code.
     89 */
     90int Config::i_init()
     91{
     92    return i_homeInit();
     93}
     94
     95
     96/**
     97 * Initializes the m_strHome member with the path to ~/.VirtualBox or equivalent.
     98 *
     99 * @returns IPRT status code.
     100 * @todo Too many init functions?
     101 */
     102int Config::i_homeInit()
     103{
    78104    char szHome[RTPATH_MAX];
    79105    int rc = com::GetVBoxUserHomeDirectory(szHome, sizeof(szHome), false);
    80     if (RT_FAILURE(rc))
    81     {
    82         LogDHCP(("unable to find VirtualBox home directory: %Rrs", rc));
    83         return rc;
    84     }
    85 
    86     m_strHome.assign(szHome);
    87     return VINF_SUCCESS;
    88 }
    89 
    90 
    91 void Config::setNetwork(const RTCString &aStrNetwork)
     106    if (RT_SUCCESS(rc))
     107        rc = m_strHome.assignNoThrow(szHome);
     108    else
     109    {
     110        LogFunc(("unable to locate the VirtualBox home directory: %Rrc", rc)); /* no release log at this point. */
     111        RTMsgError("unable to locate the VirtualBox home directory: %Rrs", rc);
     112    }
     113    return rc;
     114}
     115
     116
     117/**
     118 * Internal worker for the public factory methods that creates an instance and
     119 * calls i_init() on it.
     120 *
     121 * @returns Config instance on success, NULL on failure.
     122 */
     123/*static*/ Config *Config::i_createInstanceAndCallInit()
     124{
     125    Config *pConfig;
     126    try
     127    {
     128        pConfig = new Config();
     129    }
     130    catch (std::bad_alloc &)
     131    {
     132        return NULL;
     133    }
     134
     135    int rc = pConfig->i_init();
     136    if (RT_SUCCESS(rc))
     137        return pConfig;
     138    delete pConfig;
     139    return NULL;
     140}
     141
     142
     143/**
     144 * Internal network name (m_strNetwork) setter.
     145 *
     146 * Can only be called once.  Will also invoke i_sanitizeBaseName to update
     147 * m_strBaseName.
     148 *
     149 * @throws std::bad_alloc
     150 */
     151void Config::i_setNetwork(const RTCString &aStrNetwork)
    92152{
    93153    AssertReturnVoid(m_strNetwork.isEmpty());
    94154
    95155    m_strNetwork = aStrNetwork;
    96     sanitizeBaseName();
    97 }
    98 
    99 
    100 /*
     156    i_sanitizeBaseName();
     157}
     158
     159
     160/**
     161 * Interal worker for i_setNetwork() that sets m_strBaseName to sanitized the
     162 * version of m_strNetwork suitable for use as a path component.
     163 */
     164void Config::i_sanitizeBaseName()
     165{
     166    if (m_strNetwork.isNotEmpty())
     167    {
     168        m_strBaseName = m_strNetwork;
     169
     170/** @todo make IPRT function for this.   */
     171        char ch;
     172#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
     173        static const char s_szIllegals[] = "/\\\"*:<>?|\t\v\n\r\f\a\b"; /** @todo all control chars... */
     174        for (char *psz = m_strBaseName.mutableRaw(); (ch = *psz) != '\0'; ++psz)
     175            if (strchr(s_szIllegals, ch))
     176                *psz = '_';
     177#else
     178        for (char *psz = m_strBaseName.mutableRaw(); (ch = *psz) != '\0'; ++psz)
     179            if (RTPATH_IS_SEP(ch))
     180                *psz = '_';
     181#endif
     182        m_strBaseName.jolt(); /* Not really necessary, but it's protocol. */
     183    }
     184    else
     185        m_strBaseName.setNull();
     186}
     187
     188
     189/**
     190 * Worker for i_complete() that initializes the release log of the process.
     191 *
    101192 * Requires network name to be known as the log file name depends on
    102193 * it.  Alternatively, consider passing the log file name via the
    103194 * command line?
    104  */
    105 int Config::logInit()
     195 *
     196 * @todo make the log file directly configurable?
     197 */
     198int Config::i_logInit()
    106199{
    107200    if (m_strHome.isEmpty() || m_strBaseName.isEmpty())
     
    124217        if (*p != '_' && !RT_C_IS_ALNUM(*p))
    125218            *p = '_';
    126 
    127219
    128220    int rc = com::VBoxLogRelCreate("DHCP Server",
     
    146238
    147239
    148 int Config::complete()
    149 {
    150     int rc;
    151 
     240/**
     241 * Post process and validate the configuration after it has been loaded.
     242 */
     243int Config::i_complete()
     244{
    152245    if (m_strNetwork.isEmpty())
    153246    {
     
    156249    }
    157250
    158     logInit();
     251    i_logInit();
    159252
    160253    bool fMACGenerated = false;
     
    164257    {
    165258        RTUUID Uuid;
    166         RTUuidCreate(&Uuid);
     259        int rc = RTUuidCreate(&Uuid);
     260        AssertReturn(rc, rc);
    167261
    168262        m_MacAddress.au8[0] = 0x08;
     
    193287    /* valid netmask */
    194288    int cPrefixBits;
    195     rc = RTNetMaskToPrefixIPv4(&m_IPv4Netmask, &cPrefixBits);
     289    int rc = RTNetMaskToPrefixIPv4(&m_IPv4Netmask, &cPrefixBits);
    196290    if (RT_FAILURE(rc) || cPrefixBits == 0)
    197291    {
     
    226320    /* our own address is not inside the pool */
    227321    if (   RT_N2H_U32(m_IPv4PoolFirst.u) <= RT_N2H_U32(m_IPv4Address.u)
    228         && RT_N2H_U32(m_IPv4Address.u)  <= RT_N2H_U32(m_IPv4PoolLast.u))
     322        && RT_N2H_U32(m_IPv4Address.u)   <= RT_N2H_U32(m_IPv4PoolLast.u))
    229323    {
    230324        LogDHCP(("server address inside the pool range %RTnaipv4 - %RTnaipv4: %RTnaipv4\n",
     
    242336
    243337
    244 Config *Config::hardcoded()
    245 {
    246     int rc;
    247 
    248     std::unique_ptr<Config> config(new Config());
    249     rc = config->init();
    250     if (RT_FAILURE(rc))
     338/*static*/ Config *Config::hardcoded()
     339{
     340    std::unique_ptr<Config> config(i_createInstanceAndCallInit());
     341    AssertReturn(config.get() != NULL, NULL);
     342    try
     343    {
     344        config->i_setNetwork("HostInterfaceNetworking-vboxnet0");
     345        config->m_strTrunk.assign("vboxnet0");
     346    }
     347    catch (std::bad_alloc &)
     348    {
    251349        return NULL;
    252 
    253     config->setNetwork("HostInterfaceNetworking-vboxnet0");
    254     config->m_strTrunk.assign("vboxnet0");
     350    }
    255351    config->m_enmTrunkType = kIntNetTrunkType_NetFlt;
    256352
     
    263359
    264360
    265     config->m_IPv4Address.u = RT_H2N_U32_C(0xc0a838fe); /* 192.168.56.254 */
    266     config->m_IPv4Netmask.u = RT_H2N_U32_C(0xffffff00); /* 255.255.255.0 */
     361    config->m_IPv4Address.u     = RT_H2N_U32_C(0xc0a838fe); /* 192.168.56.254 */
     362    config->m_IPv4Netmask.u     = RT_H2N_U32_C(0xffffff00); /* 255.255.255.0 */
    267363
    268364    /* flip to test naks */
    269365#if 1
    270     config->m_IPv4PoolFirst.u = RT_H2N_U32_C(0xc0a8385a); /* 192.168.56.90 */
    271     config->m_IPv4PoolLast.u = RT_H2N_U32_C(0xc0a83863); /* 192.168.56.99 */
     366    config->m_IPv4PoolFirst.u   = RT_H2N_U32_C(0xc0a8385a); /* 192.168.56.90 */
     367    config->m_IPv4PoolLast.u    = RT_H2N_U32_C(0xc0a83863); /* 192.168.56.99 */
    272368#else
    273     config->m_IPv4PoolFirst.u = RT_H2N_U32_C(0xc0a838c9); /* 192.168.56.201 */
    274     config->m_IPv4PoolLast.u = RT_H2N_U32_C(0xc0a838dc); /* 192.168.56.220 */
     369    config->m_IPv4PoolFirst.u   = RT_H2N_U32_C(0xc0a838c9); /* 192.168.56.201 */
     370    config->m_IPv4PoolLast.u    = RT_H2N_U32_C(0xc0a838dc); /* 192.168.56.220 */
    275371#endif
    276372
    277     rc = config->complete();
     373    int rc = config->i_complete();
    278374    AssertRCReturn(rc, NULL);
    279375
     
    282378
    283379
    284 /* compatibility with old VBoxNetDHCP */
    285 static const RTGETOPTDEF g_aCompatOptions[] =
    286 {
    287     { "--ip-address",     'i',   RTGETOPT_REQ_IPV4ADDR },
    288     { "--lower-ip",       'l',   RTGETOPT_REQ_IPV4ADDR },
    289     { "--mac-address",    'a',   RTGETOPT_REQ_MACADDR },
    290     { "--need-main",      'M',   RTGETOPT_REQ_BOOL },
    291     { "--netmask",        'm',   RTGETOPT_REQ_IPV4ADDR },
    292     { "--network",        'n',   RTGETOPT_REQ_STRING },
    293     { "--trunk-name",     't',   RTGETOPT_REQ_STRING },
    294     { "--trunk-type",     'T',   RTGETOPT_REQ_STRING },
    295     { "--upper-ip",       'u',   RTGETOPT_REQ_IPV4ADDR },
    296 };
    297 
    298 
    299 Config *Config::compat(int argc, char **argv)
    300 {
     380
     381/*static*/ Config *Config::compat(int argc, char **argv)
     382{
     383    /* compatibility with old VBoxNetDHCP */
     384    static const RTGETOPTDEF s_aCompatOptions[] =
     385    {
     386        { "--ip-address",     'i',   RTGETOPT_REQ_IPV4ADDR },
     387        { "--lower-ip",       'l',   RTGETOPT_REQ_IPV4ADDR },
     388        { "--mac-address",    'a',   RTGETOPT_REQ_MACADDR },
     389        { "--need-main",      'M',   RTGETOPT_REQ_BOOL },
     390        { "--netmask",        'm',   RTGETOPT_REQ_IPV4ADDR },
     391        { "--network",        'n',   RTGETOPT_REQ_STRING },
     392        { "--trunk-name",     't',   RTGETOPT_REQ_STRING },
     393        { "--trunk-type",     'T',   RTGETOPT_REQ_STRING },
     394        { "--upper-ip",       'u',   RTGETOPT_REQ_IPV4ADDR },
     395    };
     396
    301397    RTGETOPTSTATE State;
    302     int rc;
    303 
    304     rc = RTGetOptInit(&State, argc, argv,
    305                       g_aCompatOptions, RT_ELEMENTS(g_aCompatOptions), 1,
    306                       RTGETOPTINIT_FLAGS_NO_STD_OPTS);
     398    int rc = RTGetOptInit(&State, argc, argv, s_aCompatOptions, RT_ELEMENTS(s_aCompatOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
    307399    AssertRCReturn(rc, NULL);
    308400
    309     std::unique_ptr<Config> config(new Config());
    310     rc = config->init();
    311     if (RT_FAILURE(rc))
    312         return NULL;
     401    std::unique_ptr<Config> config(i_createInstanceAndCallInit());
     402    AssertReturn(config.get() != NULL, NULL);
    313403
    314404    for (;;)
    315405    {
    316         RTGETOPTUNION Val;
    317 
    318         rc = RTGetOpt(&State, &Val);
     406        RTGETOPTUNION ValueUnion;
     407        rc = RTGetOpt(&State, &ValueUnion);
    319408        if (rc == 0)            /* done */
    320409            break;
     
    330419                    return NULL;
    331420                }
    332                 config->m_MacAddress = Val.MacAddr;
     421                config->m_MacAddress = ValueUnion.MacAddr;
    333422                break;
    334423
     
    339428                    return NULL;
    340429                }
    341                 config->m_IPv4Address = Val.IPv4Addr;
     430                config->m_IPv4Address = ValueUnion.IPv4Addr;
    342431                break;
    343432
     
    348437                    return NULL;
    349438                }
    350                 config->m_IPv4PoolFirst = Val.IPv4Addr;
     439                config->m_IPv4PoolFirst = ValueUnion.IPv4Addr;
    351440                break;
    352441
     
    361450                    return NULL;
    362451                }
    363                 config->m_IPv4Netmask = Val.IPv4Addr;
     452                config->m_IPv4Netmask = ValueUnion.IPv4Addr;
    364453                break;
    365454
     
    370459                    return NULL;
    371460                }
    372                 config->setNetwork(Val.psz);
     461                config->i_setNetwork(ValueUnion.psz);
    373462                break;
    374463
     
    379468                    return NULL;
    380469                }
    381                 config->m_strTrunk.assign(Val.psz);
     470                config->m_strTrunk.assign(ValueUnion.psz);
    382471                break;
    383472
     
    388477                    return NULL;
    389478                }
    390                 else if (strcmp(Val.psz, "none") == 0)
     479                else if (strcmp(ValueUnion.psz, "none") == 0)
    391480                    config->m_enmTrunkType = kIntNetTrunkType_None;
    392                 else if (strcmp(Val.psz, "whatever") == 0)
     481                else if (strcmp(ValueUnion.psz, "whatever") == 0)
    393482                    config->m_enmTrunkType = kIntNetTrunkType_WhateverNone;
    394                 else if (strcmp(Val.psz, "netflt") == 0)
     483                else if (strcmp(ValueUnion.psz, "netflt") == 0)
    395484                    config->m_enmTrunkType = kIntNetTrunkType_NetFlt;
    396                 else if (strcmp(Val.psz, "netadp") == 0)
     485                else if (strcmp(ValueUnion.psz, "netadp") == 0)
    397486                    config->m_enmTrunkType = kIntNetTrunkType_NetAdp;
    398487                else
    399488                {
    400                     RTMsgError("Unknown trunk type '%s'", Val.psz);
     489                    RTMsgError("Unknown trunk type '%s'", ValueUnion.psz);
    401490                    return NULL;
    402491                }
     
    409498                    return NULL;
    410499                }
    411                 config->m_IPv4PoolLast = Val.IPv4Addr;
     500                config->m_IPv4PoolLast = ValueUnion.IPv4Addr;
    412501                break;
    413502
    414503            case VINF_GETOPT_NOT_OPTION:
    415                 RTMsgError("%s: Unexpected command line argument", Val.psz);
     504                RTMsgError("%s: Unexpected command line argument", ValueUnion.psz);
    416505                return NULL;
    417506
    418507            default:
    419                 RTGetOptPrintError(rc, &Val);
     508                RTGetOptPrintError(rc, &ValueUnion);
    420509                return NULL;
    421510        }
    422511    }
    423512
    424     rc = config->complete();
     513    rc = config->i_complete();
    425514    if (RT_FAILURE(rc))
    426515        return NULL;
     
    430519
    431520
     521Config *Config::create(int argc, char **argv)
     522{
    432523#define DHCPD_GETOPT_COMMENT 256 /* No short option for --comment */
    433 static const RTGETOPTDEF g_aOptions[] =
    434 {
    435     { "--config",       'c',                  RTGETOPT_REQ_STRING },
    436     { "--comment",      DHCPD_GETOPT_COMMENT, RTGETOPT_REQ_STRING }
    437 };
    438 
    439 
    440 Config *Config::create(int argc, char **argv)
    441 {
     524    static const RTGETOPTDEF s_aOptions[] =
     525    {
     526        { "--config",       'c',                  RTGETOPT_REQ_STRING },
     527        { "--comment",      DHCPD_GETOPT_COMMENT, RTGETOPT_REQ_STRING }
     528    };
     529
    442530    RTGETOPTSTATE State;
    443     int rc;
    444 
    445     rc = RTGetOptInit(&State, argc, argv,
    446                       g_aOptions, RT_ELEMENTS(g_aOptions), 1,
    447                       RTGETOPTINIT_FLAGS_NO_STD_OPTS);
     531    int rc = RTGetOptInit(&State, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
    448532    AssertRCReturn(rc, NULL);
    449533
    450534    std::unique_ptr<Config> config;
     535
    451536    for (;;)
    452537    {
    453         RTGETOPTUNION Val;
    454 
    455         rc = RTGetOpt(&State, &Val);
     538        RTGETOPTUNION ValueUnion;
     539        rc = RTGetOpt(&State, &ValueUnion);
    456540        if (rc == 0)            /* done */
    457541            break;
     
    462546                if (config.get() != NULL)
    463547                {
    464                     printf("Duplicate option: --config '%s'\n", Val.psz);
     548                    RTMsgError("Duplicate option: --config '%s'\n", ValueUnion.psz);
    465549                    return NULL;
    466550                }
    467551
    468                 printf("reading config from %s\n", Val.psz);
    469                 config.reset(Config::read(Val.psz));
     552                RTMsgInfo("reading config from '%s'...\n", ValueUnion.psz);
     553                config.reset(Config::i_read(ValueUnion.psz));
    470554                if (config.get() == NULL)
    471555                    return NULL;
    472 
    473556                break;
    474557
     
    481564
    482565            case VINF_GETOPT_NOT_OPTION:
    483                 RTMsgError("Unexpected command line argument: '%s'", Val.psz);
     566                RTMsgError("Unexpected command line argument: '%s'", ValueUnion.psz);
    484567                return NULL;
    485568
    486569            default:
    487                 RTGetOptPrintError(rc, &Val);
     570                RTGetOptPrintError(rc, &ValueUnion);
    488571                return NULL;
    489572        }
    490573    }
    491574
    492     if (config.get() == NULL)
     575    if (config.get() != NULL)
     576    {
     577        rc = config->i_complete();
     578        if (RT_SUCCESS(rc))
     579            return config.release();
     580    }
     581    else
     582        RTMsgError("No configuration file specified (--config file)!\n");
     583    return NULL;
     584}
     585
     586
     587/**
     588 *
     589 * @note The release log has is not operational when this method is called.
     590 */
     591Config *Config::i_read(const char *pszFileName)
     592{
     593    if (pszFileName == NULL || pszFileName[0] == '\0')
     594    {
     595        RTMsgError("Empty configuration filename");
    493596        return NULL;
    494 
    495     rc = config->complete();
    496     if (RT_FAILURE(rc))
    497         return NULL;
    498 
    499     return config.release();
    500 }
    501 
    502 
    503 Config *Config::read(const char *pszFileName)
    504 {
    505     int rc;
    506 
    507     if (pszFileName == NULL || pszFileName[0] == '\0')
    508         return NULL;
     597    }
    509598
    510599    xml::Document doc;
     
    516605    catch (const xml::EIPRTFailure &e)
    517606    {
    518         LogDHCP(("%s\n", e.what()));
     607        LogFunc(("%s\n", e.what()));
     608        RTMsgError("%s\n", e.what());
    519609        return NULL;
    520610    }
    521611    catch (const RTCError &e)
    522612    {
    523         LogDHCP(("%s\n", e.what()));
     613        LogFunc(("%s\n", e.what()));
     614        RTMsgError("%s\n", e.what());
    524615        return NULL;
    525616    }
    526617    catch (...)
    527618    {
    528         LogDHCP(("Unknown exception while reading and parsing '%s'\n",
    529                  pszFileName));
     619        LogFunc(("Unknown exception while reading and parsing '%s'\n", pszFileName));
     620        RTMsgError("Unknown exception while reading and parsing '%s'\n", pszFileName);
    530621        return NULL;
    531622    }
    532623
    533     std::unique_ptr<Config> config(new Config());
    534     rc = config->init();
    535     if (RT_FAILURE(rc))
     624    std::unique_ptr<Config> config(i_createInstanceAndCallInit());
     625    AssertReturn(config.get() != NULL, NULL);
     626
     627    try
     628    {
     629        config->i_parseConfig(doc.getRootElement());
     630    }
     631    catch (const RTCError &e)
     632    {
     633        LogFunc(("%s\n", e.what()));
     634        RTMsgError("%s\n", e.what());
    536635        return NULL;
    537 
    538     try
    539     {
    540         config->parseConfig(doc.getRootElement());
    541     }
    542     catch (const RTCError &e)
    543     {
    544         LogDHCP(("%s\n", e.what()));
     636    }
     637    catch (...)
     638    {
     639        LogFunc(("Unexpected exception\n"));
     640        RTMsgError("Unexpected exception\n");
    545641        return NULL;
    546642    }
    547     catch (...)
    548     {
    549         LogDHCP(("Unexpected exception\n"));
    550         return NULL;
    551     }
    552643
    553644    return config.release();
     
    555646
    556647
    557 void Config::parseConfig(const xml::ElementNode *root)
    558 {
    559     if (root == NULL)
     648/**
     649 * Internal worker for i_read() that parses the root element and everything
     650 * below it.
     651 *
     652 * @throws stuff.
     653 */
     654void Config::i_parseConfig(const xml::ElementNode *pElmRoot)
     655{
     656    /*
     657     * Check the root element and call i_parseServer to do real work.
     658     */
     659    if (pElmRoot == NULL)
    560660        throw ConfigFileError("Empty config file");
    561661
    562     /*
    563      * XXX: NAMESPACE API IS COMPLETELY BROKEN, SO IGNORE IT FOR NOW
    564      */
    565     if (!root->nameEquals("DHCPServer"))
    566     {
    567         const char *name = root->getName();
    568         throw ConfigFileError(RTCStringFmt("Unexpected root element \"%s\"",
    569                                            name ? name : "(null)"));
    570     }
    571 
    572     parseServer(root);
    573 
     662    /** @todo XXX: NAMESPACE API IS COMPLETELY BROKEN, SO IGNORE IT FOR NOW */
     663
     664    if (!pElmRoot->nameEquals("DHCPServer"))
     665        throw ConfigFileError("Unexpected root element '%s'", pElmRoot->getName());
     666
     667    i_parseServer(pElmRoot);
     668
     669#if 0 /** @todo convert to LogRel2 stuff */
    574670    // XXX: debug
    575671    for (optmap_t::const_iterator it = m_GlobalOptions.begin(); it != m_GlobalOptions.end(); ++it) {
     
    590686        std::cout << std::endl;
    591687    }
    592 }
    593 
    594 
    595 static void getIPv4AddrAttribute(const xml::ElementNode *pNode, const char *pcszAttrName,
    596                                  RTNETADDRIPV4 *pAddr)
    597 {
    598     RTCString strAddr;
    599     bool fHasAttr = pNode->getAttributeValue(pcszAttrName, &strAddr);
    600     if (!fHasAttr)
    601         throw ConfigFileError(RTCStringFmt("%s attribute missing",
    602                                            pcszAttrName));
    603 
    604     int rc = RTNetStrToIPv4Addr(strAddr.c_str(), pAddr);
    605     if (RT_FAILURE(rc))
    606         throw ConfigFileError(RTCStringFmt("%s attribute invalid",
    607                                            pcszAttrName));
    608 }
    609 
    610 
    611 void Config::parseServer(const xml::ElementNode *server)
     688#endif
     689}
     690
     691
     692/**
     693 * Internal worker for parsing the elements under /DHCPServer/.
     694 *
     695 * @param   pElmServer          The DHCPServer element.
     696 * @throws  ConfigFileError
     697 */
     698void Config::i_parseServer(const xml::ElementNode *pElmServer)
    612699{
    613700    /*
    614      * DHCPServer attributes
     701     * <DHCPServer> attributes
    615702     */
    616     RTCString strNetworkName;
    617     bool fHasNetworkName = server->getAttributeValue("networkName", &strNetworkName);
    618     if (!fHasNetworkName)
     703    const char *pszNetworkName;
     704    if (pElmServer->getAttributeValue("networkName", &pszNetworkName))
     705        i_setNetwork(pszNetworkName);
     706    else
    619707        throw ConfigFileError("DHCPServer/@networkName missing");
    620 
    621     setNetwork(strNetworkName);
    622 
    623     RTCString strTrunkType;
    624     if (!server->getAttributeValue("trunkType", &strTrunkType))
     708    /** @todo log file override.  */
     709    /** @todo log level (dhcpd group flags).  */
     710    /** @todo log flags.  */
     711    /** @todo control logging to stderr/out.  */
     712    /** @todo if we like we could open the release log now.   */
     713
     714    const char *pszTrunkType;
     715    if (!pElmServer->getAttributeValue("trunkType", &pszTrunkType))
    625716        throw ConfigFileError("DHCPServer/@trunkType missing");
    626     if (strTrunkType == "none")
     717    if (strcmp(pszTrunkType, "none") == 0)
    627718        m_enmTrunkType = kIntNetTrunkType_None;
    628     else if (strTrunkType == "whatever")
     719    else if (strcmp(pszTrunkType, "whatever") == 0)
    629720        m_enmTrunkType = kIntNetTrunkType_WhateverNone;
    630     else if (strTrunkType == "netflt")
     721    else if (strcmp(pszTrunkType, "netflt") == 0)
    631722        m_enmTrunkType = kIntNetTrunkType_NetFlt;
    632     else if (strTrunkType == "netadp")
     723    else if (strcmp(pszTrunkType, "netadp") == 0)
    633724        m_enmTrunkType = kIntNetTrunkType_NetAdp;
    634725    else
    635         throw ConfigFileError(RTCStringFmt("Invalid DHCPServer/@trunkType value: %s", strTrunkType.c_str()));
     726        throw ConfigFileError("Invalid DHCPServer/@trunkType value: %s", pszTrunkType);
    636727
    637728    if (   m_enmTrunkType == kIntNetTrunkType_NetFlt
    638729        || m_enmTrunkType == kIntNetTrunkType_NetAdp)
    639730    {
    640         RTCString strTrunk;
    641         if (!server->getAttributeValue("trunkName", &strTrunk))
     731        if (!pElmServer->getAttributeValue("trunkName", &m_strTrunk))
    642732            throw ConfigFileError("DHCPServer/@trunkName missing");
    643         m_strTrunk = strTrunk;
    644733    }
    645734    else
    646735        m_strTrunk = "";
    647736
    648     getIPv4AddrAttribute(server, "IPAddress", &m_IPv4Address);
    649     getIPv4AddrAttribute(server, "networkMask", &m_IPv4Netmask);
    650     getIPv4AddrAttribute(server, "lowerIP", &m_IPv4PoolFirst);
    651     getIPv4AddrAttribute(server, "upperIP", &m_IPv4PoolLast);
     737    i_getIPv4AddrAttribute(pElmServer, "IPAddress", &m_IPv4Address);
     738    i_getIPv4AddrAttribute(pElmServer, "networkMask", &m_IPv4Netmask);
     739    i_getIPv4AddrAttribute(pElmServer, "lowerIP", &m_IPv4PoolFirst);
     740    i_getIPv4AddrAttribute(pElmServer, "upperIP", &m_IPv4PoolLast);
    652741
    653742    /*
    654      * DHCPServer children
     743     * <DHCPServer> children
    655744     */
    656     xml::NodesLoop it(*server);
    657     const xml::ElementNode *node;
    658     while ((node = it.forAllNodes()) != NULL)
     745    xml::NodesLoop it(*pElmServer);
     746    const xml::ElementNode *pElmChild;
     747    while ((pElmChild = it.forAllNodes()) != NULL)
    659748    {
    660749        /*
    661750         * Global options
    662751         */
    663         if (node->nameEquals("Options"))
    664         {
    665             parseGlobalOptions(node);
    666         }
    667 
     752        if (pElmChild->nameEquals("Options"))
     753            i_parseGlobalOptions(pElmChild);
    668754        /*
    669755         * Per-VM configuration
    670756         */
    671         else if (node->nameEquals("Config"))
    672         {
    673             parseVMConfig(node);
    674         }
    675     }
    676 }
    677 
    678 
    679 void Config::parseGlobalOptions(const xml::ElementNode *options)
     757        else if (pElmChild->nameEquals("Config"))
     758            i_parseVMConfig(pElmChild);
     759        else
     760            LogDHCP(("Ignoring unexpected DHCPServer child: %s\n", pElmChild->getName()));
     761    }
     762}
     763
     764
     765/**
     766 * Internal worker for parsing the elements under /DHCPServer/Options/.
     767 *
     768 * @param   pElmServer          The <Options> element.
     769 * @throws  ConfigFileError
     770 */
     771void Config::i_parseGlobalOptions(const xml::ElementNode *options)
    680772{
    681773    xml::NodesLoop it(*options);
    682     const xml::ElementNode *node;
    683     while ((node = it.forAllNodes()) != NULL)
    684     {
    685         if (node->nameEquals("Option"))
    686         {
    687             parseOption(node, m_GlobalOptions);
    688         }
     774    const xml::ElementNode *pElmChild;
     775    while ((pElmChild = it.forAllNodes()) != NULL)
     776    {
     777        if (pElmChild->nameEquals("Option"))
     778            i_parseOption(pElmChild, m_GlobalOptions);
    689779        else
    690         {
    691             throw ConfigFileError(RTCStringFmt("Unexpected element \"%s\"",
    692                                                node->getName()));
    693         }
    694     }
    695 }
    696 
    697 
    698 /**
     780            throw ConfigFileError("Unexpected element <%s>", pElmChild->getName());
     781    }
     782}
     783
     784
     785/**
     786 * Internal worker for parsing the elements under /DHCPServer/Config/.
     787 *
    699788 * VM Config entries are generated automatically from VirtualBox.xml
    700789 * with the MAC fetched from the VM config.  The client id is nowhere
    701790 * in the picture there, so VM config is indexed with plain RTMAC, not
    702791 * ClientId (also see getOptions below).
    703  */
    704 void Config::parseVMConfig(const xml::ElementNode *config)
    705 {
    706     RTMAC mac;
    707     int rc;
    708 
    709     RTCString strMac;
    710     bool fHasMac = config->getAttributeValue("MACAddress", &strMac);
    711     if (!fHasMac)
    712         throw ConfigFileError(RTCStringFmt("Config missing MACAddress attribute"));
    713 
    714     rc = parseMACAddress(mac, strMac);
    715     if (RT_FAILURE(rc))
    716     {
    717         throw ConfigFileError(RTCStringFmt("Malformed MACAddress attribute \"%s\"",
    718                                            strMac.c_str()));
    719     }
    720 
    721     vmmap_t::iterator vmit( m_VMMap.find(mac) );
     792 *
     793 * @param   pElmServer          The <Config> element.
     794 * @throws  ConfigFileError
     795 */
     796void Config::i_parseVMConfig(const xml::ElementNode *pElmConfig)
     797{
     798    /*
     799     * Attributes:
     800     */
     801    /* The MAC address: */
     802    RTMAC MacAddr;
     803    i_getMacAddressAttribute(pElmConfig, "MACAddress", &MacAddr);
     804
     805    vmmap_t::iterator vmit( m_VMMap.find(MacAddr) );
    722806    if (vmit != m_VMMap.end())
    723     {
    724         throw ConfigFileError(RTCStringFmt("Duplicate Config for MACAddress \"%s\"",
    725                                            strMac.c_str()));
    726     }
    727 
    728     optmap_t &vmopts = m_VMMap[mac];
    729 
    730     xml::NodesLoop it(*config);
    731     const xml::ElementNode *node;
    732     while ((node = it.forAllNodes()) != NULL)
    733         if (node->nameEquals("Option"))
    734             parseOption(node, vmopts);
     807        throw ConfigFileError("Duplicate Config for MACAddress %RTmac", &MacAddr);
     808
     809    optmap_t &vmopts = m_VMMap[MacAddr];
     810
     811    /* Name - optional: */
     812    const char *pszName = NULL;
     813    if (pElmConfig->getAttributeValue("name", &pszName))
     814    {
     815        /** @todo */
     816    }
     817
     818    /* Fixed IP address assignment - optional: */
     819    if (pElmConfig->findAttribute("FixedIPAddress") != NULL)
     820    {
     821        /** @todo */
     822    }
     823
     824    /*
     825     * Process the children.
     826     */
     827    xml::NodesLoop it(*pElmConfig);
     828    const xml::ElementNode *pElmChild;
     829    while ((pElmChild = it.forAllNodes()) != NULL)
     830        if (pElmChild->nameEquals("Option"))
     831            i_parseOption(pElmChild, vmopts);
    735832        else
    736             throw ConfigFileError(RTCStringFmt("Unexpected element \"%s\"",
    737                                                node->getName()));
    738 }
    739 
    740 
    741 int Config::parseMACAddress(RTMAC &aMac, const RTCString &aStr)
    742 {
    743     RTMAC mac;
    744     int rc;
    745 
    746     rc = RTNetStrToMacAddr(aStr.c_str(), &mac);
    747     if (RT_FAILURE(rc))
    748         return rc;
    749     if (rc == VWRN_TRAILING_CHARS)
    750         return VERR_INVALID_PARAMETER;
    751 
    752     aMac = mac;
    753     return VINF_SUCCESS;
    754 }
    755 
    756 
    757 int Config::parseClientId(OptClientId &aId, const RTCString &aStr)
    758 {
    759     RT_NOREF(aId, aStr);
    760     return VERR_GENERAL_FAILURE;
    761 }
    762 
    763 
    764 /**
    765  * Parse <Option/> element and add the option to the specified optmap.
    766  */
    767 void Config::parseOption(const xml::ElementNode *option, optmap_t &optmap)
    768 {
    769     int rc;
     833            throw ConfigFileError("Unexpected element '%s' under '%s'", pElmChild->getName(), pElmConfig->getName());
     834}
     835
     836
     837/**
     838 * Internal worker for parsing <Option> elements found under
     839 * /DHCPServer/Options/ and /DHCPServer/Config/
     840 *
     841 * @param   pElmServer          The <Option> element.
     842 * @param   optmap              The option map to add the option to.
     843 * @throws  ConfigFileError
     844 */
     845void Config::i_parseOption(const xml::ElementNode *pElmOption, optmap_t &optmap)
     846{
     847    /* The 'name' attribute: */
     848    const char *pszName;
     849    if (!pElmOption->getAttributeValue("name", &pszName))
     850        throw ConfigFileError("missing option name");
    770851
    771852    uint8_t u8Opt;
    772     RTCString strName;
    773     bool fHasName = option->getAttributeValue("name", &strName);
    774     if (fHasName)
    775     {
    776         const char *pcszName = strName.c_str();
    777 
    778         rc = RTStrToUInt8Full(pcszName, 10, &u8Opt);
     853    int rc = RTStrToUInt8Full(pszName, 10, &u8Opt);
     854    if (rc != VINF_SUCCESS) /* no warnings either */
     855        throw ConfigFileError("Bad option name '%s'", pszName);
     856
     857    /* The opional 'encoding' attribute: */
     858    uint32_t u32Enc = 0;        /* XXX: DhcpOptEncoding_Legacy */
     859    const char *pszEncoding;
     860    if (pElmOption->getAttributeValue("encoding", &pszEncoding))
     861    {
     862        rc = RTStrToUInt32Full(pszEncoding, 10, &u32Enc);
    779863        if (rc != VINF_SUCCESS) /* no warnings either */
    780             throw ConfigFileError(RTCStringFmt("Bad option \"%s\"", pcszName));
    781 
    782     }
    783     else
    784         throw ConfigFileError("missing option name");
    785 
    786 
    787     uint32_t u32Enc = 0;        /* XXX: DhcpOptEncoding_Legacy */
    788     RTCString strEncoding;
    789     bool fHasEncoding = option->getAttributeValue("encoding", &strEncoding);
    790     if (fHasEncoding)
    791     {
    792         const char *pcszEnc = strEncoding.c_str();
    793 
    794         rc = RTStrToUInt32Full(pcszEnc, 10, &u32Enc);
    795         if (rc != VINF_SUCCESS) /* no warnings either */
    796             throw ConfigFileError(RTCStringFmt("Bad encoding \"%s\"", pcszEnc));
     864            throw ConfigFileError("Bad option encoding '%s'", pszEncoding);
    797865
    798866        switch (u32Enc)
    799867        {
    800         case 0:                 /* XXX: DhcpOptEncoding_Legacy */
    801         case 1:                 /* XXX: DhcpOptEncoding_Hex */
    802             break;
    803         default:
    804             throw ConfigFileError(RTCStringFmt("Unknown encoding \"%s\"", pcszEnc));
     868            case 0:                 /* XXX: DhcpOptEncoding_Legacy */
     869            case 1:                 /* XXX: DhcpOptEncoding_Hex */
     870                break;
     871            default:
     872                throw ConfigFileError("Unknown encoding '%s'", pszEncoding);
    805873        }
    806874    }
    807875
    808 
    809     /* value may be omitted for OptNoValue options like rapid commit */
    810     RTCString strValue;
    811     option->getAttributeValue("value", &strValue);
    812 
    813     /* XXX: TODO: encoding, handle hex */
    814     DhcpOption *opt = DhcpOption::parse(u8Opt, u32Enc, strValue.c_str());
     876    /* The 'value' attribute. May be omitted for OptNoValue options like rapid commit. */
     877    const char *pszValue;
     878    if (!pElmOption->getAttributeValue("value", &pszValue))
     879        pszValue = "";
     880
     881    /** @todo XXX: TODO: encoding, handle hex */
     882    DhcpOption *opt = DhcpOption::parse(u8Opt, u32Enc, pszValue);
    815883    if (opt == NULL)
    816         throw ConfigFileError(RTCStringFmt("Bad option \"%s\"", strName.c_str()));
    817 
     884        throw ConfigFileError("Bad option '%s' (encoding %u): '%s' ", pszName, u32Enc, pszValue ? pszValue : "");
     885
     886    /* Add it to the map: */
    818887    optmap << opt;
    819888}
     
    821890
    822891/**
    823  * Set m_strBaseName to sanitized version of m_strNetwork that can be
    824  * used in a path component.
    825  */
    826 void Config::sanitizeBaseName()
    827 {
    828     if (m_strNetwork.isNotEmpty())
    829     {
    830         m_strBaseName = m_strNetwork;
    831 
    832         char ch;
    833 #if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
    834         static const char s_szIllegals[] = "/\\\"*:<>?|\t\v\n\r\f\a\b"; /** @todo all control chars... */
    835         for (char *psz = m_strBaseName.mutableRaw(); (ch = *psz) != '\0'; ++psz)
    836             if (strchr(s_szIllegals, ch))
    837                 *psz = '_';
    838 #else
    839         for (char *psz = m_strBaseName.mutableRaw(); (ch = *psz) != '\0'; ++psz)
    840             if (RTPATH_IS_SEP(ch))
    841                 *psz = '_';
    842 #endif
    843         m_strBaseName.jolt(); /* Not really necessary, but it's protocol. */
     892 * Helper for retrieving a IPv4 attribute.
     893 *
     894 * @param   pElm            The element to get the attribute from.
     895 * @param   pszAttrName     The name of the attribute
     896 * @param   pAddr           Where to return the address.
     897 * @throws  ConfigFileError
     898 */
     899/*static*/ void Config::i_getIPv4AddrAttribute(const xml::ElementNode *pElm, const char *pszAttrName, PRTNETADDRIPV4 pAddr)
     900{
     901    const char *pszAttrValue;
     902    if (pElm->getAttributeValue(pszAttrName, &pszAttrValue))
     903    {
     904        int rc = RTNetStrToIPv4Addr(pszAttrValue, pAddr);
     905        if (RT_SUCCESS(rc))
     906            return;
     907        throw ConfigFileError("%s attribute %s is not a valid IPv4 address: '%s' -> %Rrc",
     908                              pElm->getName(), pszAttrName, pszAttrValue, rc);
    844909    }
    845910    else
    846         m_strBaseName.setNull();
    847 }
    848 
    849 
    850 optmap_t Config::getOptions(const OptParameterRequest &reqOpts,
    851                             const ClientId &id,
    852                             const OptVendorClassId &vendor) const
    853 {
    854     optmap_t optmap;
    855 
     911        throw ConfigFileError("Required %s attribute missing on element %s", pszAttrName, pElm->getName());
     912}
     913
     914
     915/**
     916 * Helper for retrieving a MAC address attribute.
     917 *
     918 * @param   pElm            The element to get the attribute from.
     919 * @param   pszAttrName     The name of the attribute
     920 * @param   pMacAddr        Where to return the MAC address.
     921 * @throws  ConfigFileError
     922 */
     923/*static*/ void Config::i_getMacAddressAttribute(const xml::ElementNode *pElm, const char *pszAttrName, PRTMAC pMacAddr)
     924{
     925    const char *pszAttrValue;
     926    if (pElm->getAttributeValue(pszAttrName, &pszAttrValue))
     927    {
     928        int rc = RTNetStrToMacAddr(pszAttrValue, pMacAddr);
     929        if (RT_SUCCESS(rc) && rc != VWRN_TRAILING_CHARS)
     930            return;
     931        throw ConfigFileError("%s attribute %s is not a valid MAC address: '%s' -> %Rrc",
     932                              pElm->getName(), pszAttrName, pszAttrValue, rc);
     933    }
     934    else
     935        throw ConfigFileError("Required %s attribute missing on element %s", pszAttrName, pElm->getName());
     936}
     937
     938
     939/**
     940 * Method used by DHCPD to assemble a list of options for the client.
     941 *
     942 * @returns a_rRetOpts for convenience
     943 * @param   a_rRetOpts      Where to put the requested options.
     944 * @param   reqOpts         The requested options.
     945 * @param   id              The client ID.
     946 * @param   idVendorClass   The vendor class ID.
     947 * @param   idUserClass     The user class ID.
     948 */
     949optmap_t &Config::getOptions(optmap_t &a_rRetOpts, const OptParameterRequest &reqOpts, const ClientId &id,
     950                             const OptVendorClassId &idVendorClass /*= OptVendorClassId()*/,
     951                             const OptUserClassId &idUserClass /*= OptUserClassId()*/) const
     952{
    856953    const optmap_t *vmopts = NULL;
    857954    vmmap_t::const_iterator vmit( m_VMMap.find(id.mac()) );
     
    859956        vmopts = &vmit->second;
    860957
    861     RT_NOREF(vendor); /* not yet */
    862 
    863 
    864     optmap << new OptSubnetMask(m_IPv4Netmask);
     958    RT_NOREF(idVendorClass, idUserClass); /* not yet */
     959
     960    a_rRetOpts << new OptSubnetMask(m_IPv4Netmask);
    865961
    866962    const OptParameterRequest::value_t& reqValue = reqOpts.value();
     
    868964    {
    869965        uint8_t optreq = *itOptReq;
    870         std::cout << ">>> requested option " << (int)optreq << std::endl;
     966        LogRel2((">>> requested option %d (%#x)\n", optreq, optreq));
    871967
    872968        if (optreq == OptSubnetMask::optcode)
    873969        {
    874             std::cout << "... always supplied" << std::endl;
     970            LogRel2(("... always supplied\n"));
    875971            continue;
    876972        }
     
    881977            if (it != vmopts->end())
    882978            {
    883                 optmap << it->second;
    884                 std::cout << "... found in VM options" << std::endl;
     979                a_rRetOpts << it->second;
     980                LogRel2(("... found in VM options\n"));
    885981                continue;
    886982            }
     
    890986        if (it != m_GlobalOptions.end())
    891987        {
    892             optmap << it->second;
    893             std::cout << "... found in global options" << std::endl;
     988            a_rRetOpts << it->second;
     989            LogRel2(("... found in global options\n"));
    894990            continue;
    895991        }
    896992
    897         // std::cout << "... not found" << std::endl;
    898     }
    899 
    900 
    901     /* XXX: testing ... */
     993        LogRel3(("... not found\n"));
     994    }
     995
     996
     997#if 0 /* bird disabled this as it looks dubious and testing only. */
     998    /** @todo XXX: testing ... */
    902999    if (vmopts != NULL)
    9031000    {
    904         for (optmap_t::const_iterator it = vmopts->begin(); it != vmopts->end(); ++it) {
     1001        for (optmap_t::const_iterator it = vmopts->begin(); it != vmopts->end(); ++it)
     1002        {
    9051003            std::shared_ptr<DhcpOption> opt(it->second);
    906             if (optmap.count(opt->optcode()) == 0 && opt->optcode() > 127)
     1004            if (a_rRetOpts.count(opt->optcode()) == 0 && opt->optcode() > 127)
    9071005            {
    908                 optmap << opt;
    909                 std::cout << "... forcing VM option " << (int)opt->optcode() << std::endl;
     1006                a_rRetOpts << opt;
     1007                LogRel2(("... forcing VM option %d (%#x)\n", opt->optcode(), opt->optcode()));
    9101008            }
    9111009        }
    9121010    }
    9131011
    914     for (optmap_t::const_iterator it = m_GlobalOptions.begin(); it != m_GlobalOptions.end(); ++it) {
     1012    for (optmap_t::const_iterator it = m_GlobalOptions.begin(); it != m_GlobalOptions.end(); ++it)
     1013    {
    9151014        std::shared_ptr<DhcpOption> opt(it->second);
    916         if (optmap.count(opt->optcode()) == 0 && opt->optcode() > 127)
     1015        if (a_rRetOpts.count(opt->optcode()) == 0 && opt->optcode() > 127)
    9171016        {
    918             optmap << opt;
    919             std::cout << "... forcing global option " << (int)opt->optcode() << std::endl;
     1017            a_rRetOpts << opt;
     1018            LogRel2(("... forcing global option %d (%#x)", opt->optcode(), opt->optcode()));
    9201019        }
    9211020    }
    922 
    923     return optmap;
    924 }
     1021#endif
     1022
     1023    return a_rRetOpts;
     1024}
  • trunk/src/VBox/NetworkServices/Dhcpd/Config.h

    r79524 r79553  
    3030#include <VBox/intnet.h>
    3131
    32 
    3332#include "DhcpOptions.h"
    3433#include "ClientId.h"
    3534
    3635
     36/**
     37 * DHCP server configuration.
     38 */
    3739class Config
    3840{
    39     /** XXX: TODO: also store fixed address assignments, etc? */
     41    /** @todo XXX: also store fixed address assignments, etc? */
    4042    typedef std::map<RTMAC, optmap_t> vmmap_t;
    4143
    42     RTCString m_strHome;   /* path of ~/.VirtualBox or equivalent */
     44    RTCString       m_strHome;          /**< path of ~/.VirtualBox or equivalent, */
    4345
    44     RTCString m_strNetwork;
    45     RTCString m_strBaseName; /* m_strNetwork sanitized to be usable in a path component */
     46    RTCString       m_strNetwork;       /**< The name of the internal network the DHCP server is connected to. */
     47    RTCString       m_strBaseName;      /**< m_strNetwork sanitized to be usable in a path component. */
    4648
    47     RTCString m_strTrunk;
    48     INTNETTRUNKTYPE m_enmTrunkType;
     49    RTCString       m_strTrunk;         /**< The trunk name of the internal network. */
     50    INTNETTRUNKTYPE m_enmTrunkType;     /**< The trunk type of the internal network. */
    4951
    50     RTMAC m_MacAddress;
     52    RTMAC           m_MacAddress;       /**< The MAC address for the DHCP server. */
    5153
    52     RTNETADDRIPV4 m_IPv4Address;
    53     RTNETADDRIPV4 m_IPv4Netmask;
     54    RTNETADDRIPV4   m_IPv4Address;      /**< The IPv4 address of the DHCP server. */
     55    RTNETADDRIPV4   m_IPv4Netmask;      /**< The IPv4 netmask for the DHCP server. */
    5456
    55     RTNETADDRIPV4 m_IPv4PoolFirst;
    56     RTNETADDRIPV4 m_IPv4PoolLast;
     57    RTNETADDRIPV4   m_IPv4PoolFirst;    /**< The first IPv4 address in the pool. */
     58    RTNETADDRIPV4   m_IPv4PoolLast;     /**< The last IPV4 address in the pool (inclusive like all other 'last' variables). */
    5759
    58     optmap_t m_GlobalOptions;
    59     vmmap_t m_VMMap;
     60
     61    optmap_t        m_GlobalOptions;    /**< Global DHCP option. */
     62    vmmap_t         m_VMMap;            /**< Per MAC address (VM) DHCP options. */
     63    /** @todo r=bird: optmap_t is too narrow for adding configuration options such
     64     *        as max-lease-time, min-lease-time, default-lease-time and such like
     65     *        that does not translate directly to any specific DHCP option. */
     66    /** @todo r=bird: Additionally, I'd like to have a more generic option groups
     67     *        that fits inbetween m_VMMap (mac based) and m_GlobalOptions.
     68     *        Pattern/wildcard matching on MAC address, possibly also client ID,
     69     *        vendor class and user class, including simple lists of these. */
    6070
    6171private:
    6272    Config();
    6373
    64     int init();
    65     int homeInit();
    66     int logInit();
    67     int complete();
    68 
    69 public: /* factory methods */
    70     static Config *hardcoded();                   /* for testing */
    71     static Config *create(int argc, char **argv); /* --config */
    72     static Config *compat(int argc, char **argv); /* old VBoxNetDHCP flags */
    73 
    74 public: /* accessors */
    75     const RTCString &getHome() const { return m_strHome; }
    76 
    77     const RTCString &getNetwork() const { return m_strNetwork; }
    78     void setNetwork(const RTCString &aStrNetwork);
    79 
    80     const RTCString &getBaseName() const { return m_strBaseName; }
    81     const RTCString &getTrunk() const { return m_strTrunk; }
    82     INTNETTRUNKTYPE getTrunkType() const { return m_enmTrunkType; }
    83 
    84     const RTMAC &getMacAddress() const { return m_MacAddress; }
    85 
    86     RTNETADDRIPV4 getIPv4Address() const { return m_IPv4Address; }
    87     RTNETADDRIPV4 getIPv4Netmask() const { return m_IPv4Netmask; }
    88 
    89     RTNETADDRIPV4 getIPv4PoolFirst() const { return m_IPv4PoolFirst; }
    90     RTNETADDRIPV4 getIPv4PoolLast() const { return m_IPv4PoolLast; }
     74    int                 i_init();
     75    int                 i_homeInit();
     76    static Config      *i_createInstanceAndCallInit();
     77    int                 i_logInit();
     78    int                 i_complete();
    9179
    9280public:
    93     optmap_t getOptions(const OptParameterRequest &reqOpts, const ClientId &id,
    94                         const OptVendorClassId &vendor = OptVendorClassId()) const;
     81    /** @name Factory methods
     82     * @{ */
     83    static Config      *hardcoded();                   /**< For testing. */
     84    static Config      *create(int argc, char **argv); /**< --config */
     85    static Config      *compat(int argc, char **argv); /**< Old VBoxNetDHCP command line parsing. */
     86    /** @} */
     87
     88    /** @name Accessors
     89     * @{ */
     90    const RTCString    &getHome() const             { return m_strHome; }
     91
     92    const RTCString    &getNetwork() const          { return m_strNetwork; }
     93
     94    const RTCString    &getBaseName() const         { return m_strBaseName; }
     95    const RTCString    &getTrunk() const            { return m_strTrunk; }
     96    INTNETTRUNKTYPE     getTrunkType() const        { return m_enmTrunkType; }
     97
     98    const RTMAC        &getMacAddress() const       { return m_MacAddress; }
     99
     100    RTNETADDRIPV4       getIPv4Address() const      { return m_IPv4Address; }
     101    RTNETADDRIPV4       getIPv4Netmask() const      { return m_IPv4Netmask; }
     102
     103    RTNETADDRIPV4       getIPv4PoolFirst() const    { return m_IPv4PoolFirst; }
     104    RTNETADDRIPV4       getIPv4PoolLast() const     { return m_IPv4PoolLast; }
     105    /** @} */
     106
     107    optmap_t           &getOptions(optmap_t &a_rRetOpts, const OptParameterRequest &reqOpts, const ClientId &id,
     108                                   const OptVendorClassId &idVendorClass = OptVendorClassId(),
     109                                   const OptUserClassId &idUserClass = OptUserClassId()) const;
    95110
    96111private:
    97     static Config *read(const char *pszFileName);
    98     void parseConfig(const xml::ElementNode *root);
    99     void parseServer(const xml::ElementNode *server);
    100     void parseGlobalOptions(const xml::ElementNode *options);
    101     void parseVMConfig(const xml::ElementNode *config);
    102     void parseOption(const xml::ElementNode *option, optmap_t &optmap);
     112    /** @name Configuration file reading and parsing
     113     * @{ */
     114    static Config      *i_read(const char *pszFileName);
     115    void                i_parseConfig(const xml::ElementNode *root);
     116    void                i_parseServer(const xml::ElementNode *server);
     117    void                i_parseGlobalOptions(const xml::ElementNode *options);
     118    void                i_parseVMConfig(const xml::ElementNode *config);
     119    void                i_parseOption(const xml::ElementNode *option, optmap_t &optmap);
    103120
    104     int parseMACAddress(RTMAC &aMac, const RTCString &aStr);
    105     int parseClientId(OptClientId &aId, const RTCString &aStr);
     121    static void         i_getIPv4AddrAttribute(const xml::ElementNode *pElm, const char *pcszAttrName, PRTNETADDRIPV4 pAddr);
     122    static void         i_getMacAddressAttribute(const xml::ElementNode *pElm, const char *pszAttrName, PRTMAC pMacAddr);
     123    /** @} */
    106124
    107     void sanitizeBaseName();
     125    void                i_setNetwork(const RTCString &aStrNetwork);
     126    void                i_sanitizeBaseName();
    108127};
    109128
  • trunk/src/VBox/NetworkServices/Dhcpd/DHCPD.cpp

    r79524 r79553  
    3636        return VERR_INVALID_STATE;
    3737
     38    /** @todo r=bird: This must be configurable so main can read the database and
     39     * fish assignments out of it.  (That's the most efficient and accurate way of
     40     * figuring  out the IP address of a VM.) */
     41
    3842    /* leases file name */
    3943    m_strLeasesFileName = pConfig->getHome();
     
    171175
    172176    OptParameterRequest optlist(req);
    173     reply->addOptions(m_pConfig->getOptions(optlist, req.clientId()));
     177    optmap_t replyOptions;
     178    reply->addOptions(m_pConfig->getOptions(replyOptions, optlist, req.clientId()));
    174179
    175180    // reply->maybeUnicast(req); /* XXX: we reject ciaddr != 0 above */
     
    209214
    210215    OptParameterRequest optlist(req);
    211     ack->addOptions(m_pConfig->getOptions(optlist, req.clientId()));
     216    optmap_t replyOptions;
     217    ack->addOptions(m_pConfig->getOptions(replyOptions, optlist, req.clientId()));
    212218
    213219    ack->addOption(OptMessage("Ok, ok, here it is"));
     
    236242        return NULL;
    237243
    238     optmap_t info(m_pConfig->getOptions(params, req.clientId()));
     244    optmap_t info;
     245    m_pConfig->getOptions(info, params, req.clientId());
    239246    if (info.empty())
    240247        return NULL;
  • trunk/src/VBox/NetworkServices/Dhcpd/DhcpOptions.h

    r79524 r79553  
    608608
    609609
    610 /*
    611  * Define the DHCP options we want to use.
     610/** @name The DHCP options types.
     611 * @{
    612612 */
    613613typedef OptValue<1, RTNETADDRIPV4>      OptSubnetMask;
     
    636636typedef OptString<66>                   OptTFTPServer;   /* when overloaded */
    637637typedef OptString<67>                   OptBootFileName; /* when overloaded */
     638typedef OptList<77, uint8_t>            OptUserClassId;
    638639typedef OptNoValue<80>                  OptRapidCommit;  /* RFC4039 */
     640/** @} */
    639641
    640642#endif /* !VBOX_INCLUDED_SRC_Dhcpd_DhcpOptions_h */
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