VirtualBox

Ignore:
Timestamp:
Jul 4, 2019 6:17:50 PM (6 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
131814
Message:

Dhcpd: Went over the Db and IPv4Pool code adding comments and and such. bugref:9288

File:
1 edited

Legend:

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

    r79526 r79529  
    1616 */
    1717
     18
     19/*********************************************************************************************************************************
     20*   Header Files                                                                                                                 *
     21*********************************************************************************************************************************/
    1822#include "DhcpdInternal.h"
    1923#include <iprt/errcore.h>
    20 #include <iprt/stream.h>
    2124
    2225#include "Db.h"
    2326
    2427
    25 Db::Db()
    26   : m_pConfig(NULL)
    27 {
    28     return;
    29 }
    30 
    31 
    32 Db::~Db()
    33 {
    34     /** @todo free bindings */
    35 }
    36 
    37 
    38 int Db::init(const Config *pConfig)
    39 {
    40     Binding::registerFormat();
    41 
    42     m_pConfig = pConfig;
    43 
    44     m_pool.init(pConfig->getIPv4PoolFirst(),
    45                 pConfig->getIPv4PoolLast());
    46 
    47     return VINF_SUCCESS;
    48 }
    49 
    50 
     28/*********************************************************************************************************************************
     29*   Global Variables                                                                                                             *
     30*********************************************************************************************************************************/
     31/** Indicates whether has been called successfully yet. */
    5132bool Binding::g_fFormatRegistered = false;
    5233
    5334
     35/**
     36 * Registers the ClientId format type callback ("%R[binding]").
     37 */
    5438void Binding::registerFormat()
    5539{
    56     if (g_fFormatRegistered)
    57         return;
    58 
    59     int rc = RTStrFormatTypeRegister("binding", rtStrFormat, NULL);
    60     AssertRC(rc);
    61 
    62     g_fFormatRegistered = true;
    63 }
    64 
    65 
     40    if (!g_fFormatRegistered)
     41    {
     42        int rc = RTStrFormatTypeRegister("binding", rtStrFormat, NULL);
     43        AssertRC(rc);
     44        g_fFormatRegistered = true;
     45    }
     46}
     47
     48
     49/**
     50 * @callback_method_impl{FNRTSTRFORMATTYPE, Formats ClientId via "%R[binding]".}
     51 */
    6652DECLCALLBACK(size_t)
    6753Binding::rtStrFormat(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
     
    7056                     void *pvUser)
    7157{
    72     const Binding *b = static_cast<const Binding *>(pvValue);
    73     size_t cb = 0;
    7458
    7559    AssertReturn(strcmp(pszType, "binding") == 0, 0);
     
    7963    RT_NOREF(pvUser);
    8064
     65    const Binding *b = static_cast<const Binding *>(pvValue);
    8166    if (b == NULL)
    82     {
    83         return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
    84                            "<NULL>");
    85     }
    86 
    87     cb += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
    88                       "%RTnaipv4", b->m_addr.u);
    89 
     67        return pfnOutput(pvArgOutput, RT_STR_TUPLE("<NULL>"));
     68
     69    size_t cb = RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%RTnaipv4", b->m_addr.u);
    9070    if (b->m_state == Binding::FREE)
    91     {
    92         cb += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
    93                           " free");
    94     }
     71        cb += pfnOutput(pvArgOutput, RT_STR_TUPLE(" free"));
    9572    else
    9673    {
    97         cb += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
    98                           " to %R[id], %s, valid from ",
    99                           &b->m_id, b->stateName());
     74        cb += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, " to %R[id], %s, valid from ", &b->m_id, b->stateName());
    10075
    10176        Timestamp tsIssued = b->issued();
    10277        cb += tsIssued.strFormatHelper(pfnOutput, pvArgOutput);
    10378
    104         cb += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
    105                           " for %ds until ",
    106                           b->leaseTime());
     79        cb += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, " for %ds until ", b->leaseTime());
    10780
    10881        Timestamp tsValid = b->issued();
     
    11689const char *Binding::stateName() const
    11790{
    118     switch (m_state) {
    119     case FREE:
    120         return "free";
    121     case RELEASED:
    122         return "released";
    123     case EXPIRED:
    124         return "expired";
    125     case OFFERED:
    126         return "offered";
    127     case ACKED:
    128         return "acked";
    129     default:
    130         return "released";
     91    switch (m_state)
     92    {
     93        case FREE:
     94            return "free";
     95        case RELEASED:
     96            return "released";
     97        case EXPIRED:
     98            return "expired";
     99        case OFFERED:
     100            return "offered";
     101        case ACKED:
     102            return "acked";
     103        default:
     104            AssertMsgFailed(("%d\n", m_state));
     105            return "released";
    131106    }
    132107}
     
    146121        m_state = Binding::ACKED;
    147122    else
     123    {
     124        AssertMsgFailed(("%d\n", m_state));
    148125        m_state = Binding::RELEASED;
     126    }
    149127
    150128    return *this;
     
    152130
    153131
    154 bool Binding::expire(Timestamp deadline)
     132/**
     133 * Expires the binding if it's past the specified deadline.
     134 *
     135 * @returns False if already expired, released or freed, otherwise true (i.e.
     136 *          does not indicate whether action was taken or not).
     137 * @param   tsDeadline          The expiry deadline to use.
     138 */
     139bool Binding::expire(Timestamp tsDeadline)
    155140{
    156141    if (m_state <= Binding::EXPIRED)
    157142        return false;
    158143
    159     Timestamp t = m_issued;
    160     t.addSeconds(m_secLease);
    161 
    162     if (t < deadline)
     144    Timestamp tsExpire = m_issued;
     145    tsExpire.addSeconds(m_secLease);
     146
     147    if (tsExpire < tsDeadline)
    163148    {
    164149        if (m_state == Binding::OFFERED)
     
    171156
    172157
    173 int Binding::toXML(xml::ElementNode *ndParent) const
    174 {
    175     int rc;
    176 
     158/**
     159 * Serializes the binding to XML for the lease database.
     160 *
     161 * @throw  std::bad_alloc
     162 */
     163void Binding::toXML(xml::ElementNode *pElmParent) const
     164{
    177165    /*
    178166     * Lease
    179167     */
    180     xml::ElementNode *ndLease = ndParent->createChild("Lease");
    181     if (ndLease == NULL)
    182         return VERR_GENERAL_FAILURE;
    183 
    184     /* XXX: arrange for lease to get deleted if anything below fails */
    185 
    186 
    187     ndLease->setAttribute("mac", RTCStringFmt("%RTmac", &m_id.mac()));
     168    xml::ElementNode *pElmLease = pElmParent->createChild("Lease");
     169
     170    pElmLease->setAttribute("mac", RTCStringFmt("%RTmac", &m_id.mac()));
    188171    if (m_id.id().present())
    189172    {
     
    191174        size_t cbStrId = m_id.id().value().size() * 2 + 1;
    192175        char *pszId = new char[cbStrId];
    193         rc = RTStrPrintHexBytes(pszId, cbStrId,
    194                                 &m_id.id().value().front(), m_id.id().value().size(),
    195                                 0);
    196         ndLease->setAttribute("id", pszId);
     176        int rc = RTStrPrintHexBytes(pszId, cbStrId,
     177                                    &m_id.id().value().front(), m_id.id().value().size(),
     178                                    0);
     179        AssertRC(rc);
     180        pElmLease->setAttribute("id", pszId);
    197181        delete[] pszId;
    198182    }
    199183
    200184    /* unused but we need it to keep the old code happy */
    201     ndLease->setAttribute("network", "0.0.0.0");
    202 
    203     ndLease->setAttribute("state", stateName());
    204 
     185    pElmLease->setAttribute("network", "0.0.0.0");
     186    pElmLease->setAttribute("state", stateName());
    205187
    206188    /*
    207189     * Lease/Address
    208190     */
    209     xml::ElementNode *ndAddr = ndLease->createChild("Address");
    210     ndAddr->setAttribute("value", RTCStringFmt("%RTnaipv4", m_addr.u));
    211 
     191    xml::ElementNode *pElmAddr = pElmLease->createChild("Address");
     192    pElmAddr->setAttribute("value", RTCStringFmt("%RTnaipv4", m_addr.u));
    212193
    213194    /*
    214195     * Lease/Time
    215196     */
    216     xml::ElementNode *ndTime = ndLease->createChild("Time");
    217     ndTime->setAttribute("issued", m_issued.getAbsSeconds());
    218     ndTime->setAttribute("expiration", m_secLease);
    219 
    220     return VINF_SUCCESS;
    221 }
    222 
    223 
    224 Binding *Binding::fromXML(const xml::ElementNode *ndLease)
     197    xml::ElementNode *pElmTime = pElmLease->createChild("Time");
     198    pElmTime->setAttribute("issued", m_issued.getAbsSeconds());
     199    pElmTime->setAttribute("expiration", m_secLease);
     200}
     201
     202
     203/**
     204 * Deserializes the binding from the XML lease database.
     205 *
     206 * @param   pElmLease   The "Lease" element.
     207 * @return  Pointer to the resulting binding, NULL on failure.
     208 * @throw   std::bad_alloc
     209 */
     210Binding *Binding::fromXML(const xml::ElementNode *pElmLease)
    225211{
    226212    /* Lease/@network seems to always have bogus value, ignore it. */
     
    230216     */
    231217    RTCString strMac;
    232     bool fHasMac = ndLease->getAttributeValue("mac", &strMac);
     218    bool fHasMac = pElmLease->getAttributeValue("mac", &strMac);
    233219    if (!fHasMac)
    234220        return NULL;
     
    241227    OptClientId id;
    242228    RTCString strId;
    243     bool fHasId = ndLease->getAttributeValue("id", &strId);
     229    bool fHasId = pElmLease->getAttributeValue("id", &strId);
    244230    if (fHasId)
    245231    {
     
    264250     */
    265251    RTCString strState;
    266     bool fHasState = ndLease->getAttributeValue("state", &strState);
     252    bool fHasState = pElmLease->getAttributeValue("state", &strState);
    267253
    268254    /*
    269255     * Lease/Address
    270256     */
    271     const xml::ElementNode *ndAddress = ndLease->findChildElement("Address");
     257    const xml::ElementNode *ndAddress = pElmLease->findChildElement("Address");
    272258    if (ndAddress == NULL)
    273259        return NULL;
     
    289275     * Lease/Time
    290276     */
    291     const xml::ElementNode *ndTime = ndLease->findChildElement("Time");
     277    const xml::ElementNode *ndTime = pElmLease->findChildElement("Time");
    292278    if (ndTime == NULL)
    293279        return NULL;
     
    332318
    333319
     320
     321/*********************************************************************************************************************************
     322*   Class Db Implementation                                                                                                      *
     323*********************************************************************************************************************************/
     324
     325Db::Db()
     326    : m_pConfig(NULL)
     327{
     328}
     329
     330
     331Db::~Db()
     332{
     333    /** @todo free bindings */
     334}
     335
     336
     337int Db::init(const Config *pConfig)
     338{
     339    Binding::registerFormat();
     340
     341    m_pConfig = pConfig;
     342
     343    m_pool.init(pConfig->getIPv4PoolFirst(),
     344                pConfig->getIPv4PoolLast());
     345
     346    return VINF_SUCCESS;
     347}
     348
     349
     350/**
     351 * Expire old binding (leases).
     352 */
    334353void Db::expire()
    335354{
    336355    const Timestamp now = Timestamp::now();
    337 
    338     for (bindings_t::iterator it = m_bindings.begin();
    339          it != m_bindings.end(); ++it)
     356    for (bindings_t::iterator it = m_bindings.begin(); it != m_bindings.end(); ++it)
    340357    {
    341358        Binding *b = *it;
     
    345362
    346363
     364/**
     365 * Internal worker that creates a binding for the given client, allocating new
     366 * IPv4 address for it.
     367 *
     368 * @returns Pointer to the binding.
     369 * @param   id          The client ID.
     370 */
    347371Binding *Db::createBinding(const ClientId &id)
    348372{
     373    Binding      *pBinding = NULL;
    349374    RTNETADDRIPV4 addr = m_pool.allocate();
    350     if (addr.u == 0)
    351         return NULL;
    352 
    353     Binding *b = new Binding(addr, id);
    354     m_bindings.push_front(b);
    355     return b;
    356 }
    357 
    358 
     375    if (addr.u != 0)
     376    {
     377        try
     378        {
     379            pBinding = new Binding(addr, id);
     380            m_bindings.push_front(pBinding);
     381        }
     382        catch (std::bad_alloc &)
     383        {
     384            if (pBinding)
     385                delete pBinding;
     386            /** @todo free address (no pool method for that)  */
     387        }
     388    }
     389    return pBinding;
     390}
     391
     392
     393/**
     394 * Internal worker that creates a binding to the specified IPv4 address for the
     395 * given client.
     396 *
     397 * @returns Pointer to the binding.
     398 *          NULL if the address is in use or we ran out of memory.
     399 * @param   addr        The IPv4 address.
     400 * @param   id          The client.
     401 */
    359402Binding *Db::createBinding(RTNETADDRIPV4 addr, const ClientId &id)
    360403{
     
    362405    if (!fAvailable)
    363406    {
    364         /*
     407        /** @todo
    365408         * XXX: this should not happen.  If the address is from the
    366409         * pool, which we have verified before, then either it's in
     
    376419
    377420
     421/**
     422 * Internal worker that allocates an IPv4 address for the given client, taking
     423 * the preferred address (@a addr) into account when possible and if non-zero.
     424 */
    378425Binding *Db::allocateAddress(const ClientId &id, RTNETADDRIPV4 addr)
    379426{
    380427    Assert(addr.u == 0 || addressBelongs(addr));
    381 
    382     Binding *addrBinding = NULL;
    383     Binding *freeBinding = NULL;
    384     Binding *reuseBinding = NULL;
    385428
    386429    if (addr.u != 0)
     
    394437     * addresses that can be reused.
    395438     */
    396     const Timestamp now = Timestamp::now();
    397     for (bindings_t::iterator it = m_bindings.begin();
    398          it != m_bindings.end(); ++it)
     439    Binding        *addrBinding  = NULL;
     440    Binding        *freeBinding  = NULL;
     441    Binding        *reuseBinding = NULL;
     442    const Timestamp now          = Timestamp::now();
     443    for (bindings_t::iterator it = m_bindings.begin(); it != m_bindings.end(); ++it)
    399444    {
    400445        Binding *b = *it;
     
    460505            addrBinding = createBinding(addr, id);
    461506            Assert(addrBinding != NULL);
    462             LogDHCP(("> .... creating new binding for this address %R[binding]\n",
    463                      addrBinding));
     507            LogDHCP(("> .... creating new binding for this address %R[binding]\n", addrBinding));
    464508            return addrBinding;
    465509        }
     
    467511        if (addrBinding->m_state <= Binding::EXPIRED) /* not in use */
    468512        {
    469             LogDHCP(("> .... reusing %s binding for this address\n",
    470                      addrBinding->stateName()));
     513            LogDHCP(("> .... reusing %s binding for this address\n", addrBinding->stateName()));
    471514            addrBinding->giveTo(id);
    472515            return addrBinding;
    473516        }
    474         LogDHCP(("> .... cannot reuse %s binding for this address\n",
    475                  addrBinding->stateName()));
     517        LogDHCP(("> .... cannot reuse %s binding for this address\n", addrBinding->stateName()));
    476518    }
    477519
     
    489531        idBinding = createBinding();
    490532        if (idBinding != NULL)
    491         {
    492533            LogDHCP(("> .... creating new binding\n"));
    493         }
    494534        else
    495535        {
    496536            idBinding = reuseBinding;
    497             LogDHCP(("> .... reusing %s binding %R[binding]\n",
    498                      reuseBinding->stateName(), reuseBinding));
    499         }
    500     }
    501 
    502     if (idBinding == NULL)
    503     {
    504         LogDHCP(("> .... failed to allocate binding\n"));
    505         return NULL;
     537            if (idBinding != NULL)
     538                LogDHCP(("> .... reusing %s binding %R[binding]\n", reuseBinding->stateName(), reuseBinding));
     539            else
     540            {
     541                LogDHCP(("> .... failed to allocate binding\n"));
     542                return NULL;
     543            }
     544        }
    506545    }
    507546
     
    514553
    515554
     555/**
     556 * Called by DHCPD to allocate a binding for the specified request.
     557 *
     558 * @returns Pointer to the binding, NULL on failure.
     559 * @param   req                 The DHCP request being served.
     560 */
    516561Binding *Db::allocateBinding(const DhcpClientMessage &req)
    517562{
    518563    /** @todo XXX: handle fixed address assignments */
     564
     565    /*
     566     * Get and validate the requested address (if present).
     567     */
    519568    OptRequestedAddress reqAddr(req);
    520569    if (reqAddr.present() && !addressBelongs(reqAddr.value()))
     
    532581    }
    533582
     583    /*
     584     * Allocate the address.
     585     */
    534586    const ClientId &id(req.clientId());
    535587
    536588    Binding *b = allocateAddress(id, reqAddr.value());
    537     if (b == NULL)
    538         return NULL;
    539 
    540     Assert(b->id() == id);
    541 
    542     /** @todo
    543      * XXX: handle requests for specific lease time!
    544      * XXX: old lease might not have expired yet?
    545      */
    546     // OptLeaseTime reqLeaseTime(req);
    547     b->setLeaseTime(1200);
     589    if (b != NULL)
     590    {
     591        Assert(b->id() == id);
     592
     593        /** @todo
     594         * XXX: handle requests for specific lease time!
     595         * XXX: old lease might not have expired yet?
     596         * Make lease time configurable.
     597         */
     598        // OptLeaseTime reqLeaseTime(req);
     599        b->setLeaseTime(1200);
     600    }
    548601    return b;
    549602}
    550603
    551604
    552 int Db::addBinding(Binding *newb)
    553 {
    554     if (!addressBelongs(newb->m_addr))
    555     {
    556         LogDHCP(("Binding for out of range address %RTnaipv4 ignored\n",
    557                  newb->m_addr.u));
    558         return VERR_INVALID_PARAMETER;
    559     }
    560 
    561     for (bindings_t::iterator it = m_bindings.begin();
    562          it != m_bindings.end(); ++it)
     605/**
     606 * Internal worker used by loadLease().
     607 *
     608 * @returns IPRT status code.
     609 * @param   newb                .
     610 */
     611int Db::addBinding(Binding *pNewBinding)
     612{
     613    /*
     614     * Validate the binding against the range and existing bindings.
     615     */
     616    if (!addressBelongs(pNewBinding->m_addr))
     617    {
     618        LogDHCP(("Binding for out of range address %RTnaipv4 ignored\n", pNewBinding->m_addr.u));
     619        return VERR_OUT_OF_RANGE;
     620    }
     621
     622    for (bindings_t::iterator it = m_bindings.begin(); it != m_bindings.end(); ++it)
    563623    {
    564624        Binding *b = *it;
    565625
    566         if (newb->m_addr.u == b->m_addr.u)
    567         {
    568             LogDHCP(("> ADD: %R[binding]\n", newb));
     626        if (pNewBinding->m_addr.u == b->m_addr.u)
     627        {
     628            LogDHCP(("> ADD: %R[binding]\n", pNewBinding));
    569629            LogDHCP(("> .... duplicate ip: %R[binding]\n", b));
    570             return VERR_INVALID_PARAMETER;
    571         }
    572 
    573         if (newb->m_id == b->m_id)
    574         {
    575             LogDHCP(("> ADD: %R[binding]\n", newb));
     630            return VERR_DUPLICATE;
     631        }
     632
     633        if (pNewBinding->m_id == b->m_id)
     634        {
     635            LogDHCP(("> ADD: %R[binding]\n", pNewBinding));
    576636            LogDHCP(("> .... duplicate id: %R[binding]\n", b));
    577             return VERR_INVALID_PARAMETER;
    578         }
    579     }
    580 
    581     bool ok = m_pool.allocate(newb->m_addr);
    582     if (!ok)
    583     {
    584         LogDHCP(("> ADD: failed to claim IP %R[binding]\n", newb));
    585         return VERR_INVALID_PARAMETER;
    586     }
    587 
    588     m_bindings.push_back(newb);
     637            return VERR_DUPLICATE;
     638        }
     639    }
     640
     641    /*
     642     * Allocate the address and add the binding to the list.
     643     */
     644    AssertLogRelMsgReturn(m_pool.allocate(pNewBinding->m_addr),
     645                          ("> ADD: failed to claim IP %R[binding]\n", pNewBinding),
     646                          VERR_INTERNAL_ERROR);
     647    try
     648    {
     649        m_bindings.push_back(pNewBinding);
     650    }
     651    catch (std::bad_alloc &)
     652    {
     653        return VERR_NO_MEMORY;
     654    }
    589655    return VINF_SUCCESS;
    590656}
    591657
    592658
     659/**
     660 * Called by DHCP to cancel an offset.
     661 *
     662 * @param   req                 The DHCP request.
     663 */
    593664void Db::cancelOffer(const DhcpClientMessage &req)
    594665{
     
    598669
    599670    const RTNETADDRIPV4 addr = reqAddr.value();
    600     const ClientId &id(req.clientId());
    601 
    602     for (bindings_t::iterator it = m_bindings.begin();
    603          it != m_bindings.end(); ++it)
     671    const ClientId     &id(req.clientId());
     672
     673    for (bindings_t::iterator it = m_bindings.begin(); it != m_bindings.end(); ++it)
    604674    {
    605675        Binding *b = *it;
     
    609679            if (b->state() == Binding::OFFERED)
    610680            {
     681                LogRel2(("Db::cancelOffer: cancelling %R[binding]\n", b));
    611682                b->setLeaseTime(0);
    612683                b->setState(Binding::RELEASED);
    613684            }
     685            else
     686                LogRel2(("Db::cancelOffer: not offered state: %R[binding]\n", b));
    614687            return;
    615688        }
    616689    }
    617 }
    618 
    619 
     690    LogRel2(("Db::cancelOffer: not found (%RTnaipv4, %R[id])\n", addr.u, &id));
     691}
     692
     693
     694/**
     695 * Called by DHCP to cancel an offset.
     696 *
     697 * @param   req                 The DHCP request.
     698 * @returns true if found and released, otherwise false.
     699 */
    620700bool Db::releaseBinding(const DhcpClientMessage &req)
    621701{
    622702    const RTNETADDRIPV4 addr = req.ciaddr();
    623     const ClientId &id(req.clientId());
    624 
    625     for (bindings_t::iterator it = m_bindings.begin();
    626          it != m_bindings.end(); ++it)
     703    const ClientId     &id(req.clientId());
     704
     705    for (bindings_t::iterator it = m_bindings.begin(); it != m_bindings.end(); ++it)
    627706    {
    628707        Binding *b = *it;
     
    630709        if (b->addr().u == addr.u && b->id() == id)
    631710        {
     711            LogRel2(("Db::releaseBinding: releasing %R[binding]\n", b));
    632712            b->setState(Binding::RELEASED);
    633713            return true;
     
    635715    }
    636716
     717    LogRel2(("Db::releaseBinding: not found (%RTnaipv4, %R[id])\n", addr.u, &id));
    637718    return false;
    638719}
    639720
    640721
    641 int Db::writeLeases(const RTCString &strFileName) const
    642 {
    643     LogDHCP(("writing leases to %s\n", strFileName.c_str()));
    644 
     722/**
     723 * Called by DHCPD to write out the lease database to @a strFilename.
     724 *
     725 * @returns IPRT status code.
     726 * @param   strFilename         The file to write it to.
     727 */
     728int Db::writeLeases(const RTCString &strFilename) const
     729{
     730    LogDHCP(("writing leases to %s\n", strFilename.c_str()));
     731
     732    /*
     733     * Create the document and root element.
     734     */
    645735    xml::Document doc;
    646 
    647     xml::ElementNode *root = doc.createRootElement("Leases");
    648     if (root == NULL)
    649         return VERR_INTERNAL_ERROR;
    650 
    651     root->setAttribute("version", "1.0");
    652 
    653     for (bindings_t::const_iterator it = m_bindings.begin();
    654          it != m_bindings.end(); ++it)
    655     {
    656         const Binding *b = *it;
    657         b->toXML(root);
    658     }
    659 
    660     try {
     736    try
     737    {
     738        xml::ElementNode *pElmRoot = doc.createRootElement("Leases");
     739        pElmRoot->setAttribute("version", "1.0");
     740
     741        /*
     742         * Add the leases.
     743         */
     744        for (bindings_t::const_iterator it = m_bindings.begin(); it != m_bindings.end(); ++it)
     745        {
     746            const Binding *b = *it;
     747            b->toXML(pElmRoot);
     748        }
     749    }
     750    catch (std::bad_alloc &)
     751    {
     752        return VERR_NO_MEMORY;
     753    }
     754
     755    /*
     756     * Write the document to the specified file in a safe manner (written to temporary
     757     * file, renamed to destination on success)
     758     */
     759    try
     760    {
    661761        xml::XmlFileWriter writer(doc);
    662         writer.write(strFileName.c_str(), true);
     762        writer.write(strFilename.c_str(), true /*fSafe*/);
    663763    }
    664764    catch (const xml::EIPRTFailure &e)
     
    674774    catch (...)
    675775    {
    676         LogDHCP(("Unknown exception while writing '%s'\n",
    677                  strFileName.c_str()));
    678         return VERR_GENERAL_FAILURE;
     776        LogDHCP(("Unknown exception while writing '%s'\n", strFilename.c_str()));
     777        return VERR_UNEXPECTED_EXCEPTION;
    679778    }
    680779
     
    683782
    684783
    685 int Db::loadLeases(const RTCString &strFileName)
    686 {
    687     LogDHCP(("loading leases from %s\n", strFileName.c_str()));
    688 
     784/**
     785 * Called by DHCPD to load the lease database to @a strFilename.
     786 *
     787 * @note Does not clear the database state before doing the load.
     788 *
     789 * @returns IPRT status code.
     790 * @param   strFilename         The file to load it from.
     791 */
     792int Db::loadLeases(const RTCString &strFilename)
     793{
     794    LogDHCP(("loading leases from %s\n", strFilename.c_str()));
     795
     796    /*
     797     * Load the file into an XML document.
     798     */
    689799    xml::Document doc;
    690800    try
    691801    {
    692802        xml::XmlFileParser parser;
    693         parser.read(strFileName.c_str(), doc);
     803        parser.read(strFilename.c_str(), doc);
    694804    }
    695805    catch (const xml::EIPRTFailure &e)
     
    705815    catch (...)
    706816    {
    707         LogDHCP(("Unknown exception while reading and parsing '%s'\n",
    708                  strFileName.c_str()));
    709         return VERR_GENERAL_FAILURE;
    710     }
    711 
    712     xml::ElementNode *ndRoot = doc.getRootElement();
    713     if (ndRoot == NULL || !ndRoot->nameEquals("Leases"))
    714     {
     817        LogDHCP(("Unknown exception while reading and parsing '%s'\n", strFilename.c_str()));
     818        return VERR_UNEXPECTED_EXCEPTION;
     819    }
     820
     821    /*
     822     * Check that the root element is "Leases" and process its children.
     823     */
     824    xml::ElementNode *pElmRoot = doc.getRootElement();
     825    if (!pElmRoot)
     826    {
     827        LogDHCP(("No root element in '%s'\n", strFilename.c_str()));
    715828        return VERR_NOT_FOUND;
    716829    }
    717 
    718     xml::NodesLoop it(*ndRoot);
    719     const xml::ElementNode *node;
    720     while ((node = it.forAllNodes()) != NULL)
    721     {
    722         if (!node->nameEquals("Lease"))
    723             continue;
    724 
    725         loadLease(node);
    726     }
    727 
    728     return VINF_SUCCESS;
    729 }
    730 
    731 
    732 void Db::loadLease(const xml::ElementNode *ndLease)
    733 {
    734     Binding *b = Binding::fromXML(ndLease);
    735     bool expired = b->expire();
    736 
    737     if (!expired)
    738         LogDHCP(("> LOAD: lease %R[binding]\n", b));
    739     else
    740         LogDHCP(("> LOAD: EXPIRED lease %R[binding]\n", b));
    741 
    742     addBinding(b);
    743 }
     830    if (!pElmRoot->nameEquals("Leases"))
     831    {
     832        LogDHCP(("No root element is not 'Leases' in '%s', but '%s'\n", strFilename.c_str(), pElmRoot->getName()));
     833        return VERR_NOT_FOUND;
     834    }
     835
     836    int                     rc = VINF_SUCCESS;
     837    xml::NodesLoop          it(*pElmRoot);
     838    const xml::ElementNode *pElmLease;
     839    while ((pElmLease = it.forAllNodes()) != NULL)
     840    {
     841        if (pElmLease->nameEquals("Lease"))
     842        {
     843            int rc2 = loadLease(pElmLease);
     844            if (RT_SUCCESS(rc2))
     845            { /* likely */ }
     846            else if (rc2 == VERR_NO_MEMORY)
     847                return rc2;
     848            else
     849                rc = -rc2;
     850        }
     851        else
     852            LogDHCP(("Ignoring unexpected element '%s' under 'Leases'...\n", pElmLease->getName()));
     853    }
     854
     855    return rc;
     856}
     857
     858
     859/**
     860 * Internal worker for loadLeases() that handles one 'Lease' element.
     861 *
     862 * @param   pElmLease           The 'Lease' element to handle.
     863 * @return  IPRT status code.
     864 */
     865int Db::loadLease(const xml::ElementNode *pElmLease)
     866{
     867    Binding *pBinding = NULL;
     868    try
     869    {
     870        pBinding = Binding::fromXML(pElmLease);
     871    }
     872    catch (std::bad_alloc &)
     873    {
     874        return VERR_NO_MEMORY;
     875    }
     876    if (pBinding)
     877    {
     878        bool fExpired = pBinding->expire();
     879        if (!fExpired)
     880            LogDHCP(("> LOAD: lease %R[binding]\n", pBinding));
     881        else
     882            LogDHCP(("> LOAD: EXPIRED lease %R[binding]\n", pBinding));
     883
     884        int rc = addBinding(pBinding);
     885        if (RT_FAILURE(rc))
     886            delete pBinding;
     887        return rc;
     888    }
     889    LogDHCP(("> LOAD: failed to load lease!\n"));
     890    return VERR_PARSE_ERROR;
     891}
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