Changeset 79529 in vbox for trunk/src/VBox/NetworkServices/Dhcpd/Db.cpp
- Timestamp:
- Jul 4, 2019 6:17:50 PM (6 years ago)
- svn:sync-xref-src-repo-rev:
- 131814
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/NetworkServices/Dhcpd/Db.cpp
r79526 r79529 16 16 */ 17 17 18 19 /********************************************************************************************************************************* 20 * Header Files * 21 *********************************************************************************************************************************/ 18 22 #include "DhcpdInternal.h" 19 23 #include <iprt/errcore.h> 20 #include <iprt/stream.h>21 24 22 25 #include "Db.h" 23 26 24 27 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. */ 51 32 bool Binding::g_fFormatRegistered = false; 52 33 53 34 35 /** 36 * Registers the ClientId format type callback ("%R[binding]"). 37 */ 54 38 void Binding::registerFormat() 55 39 { 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 */ 66 52 DECLCALLBACK(size_t) 67 53 Binding::rtStrFormat(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, … … 70 56 void *pvUser) 71 57 { 72 const Binding *b = static_cast<const Binding *>(pvValue);73 size_t cb = 0;74 58 75 59 AssertReturn(strcmp(pszType, "binding") == 0, 0); … … 79 63 RT_NOREF(pvUser); 80 64 65 const Binding *b = static_cast<const Binding *>(pvValue); 81 66 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); 90 70 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")); 95 72 else 96 73 { 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()); 100 75 101 76 Timestamp tsIssued = b->issued(); 102 77 cb += tsIssued.strFormatHelper(pfnOutput, pvArgOutput); 103 78 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()); 107 80 108 81 Timestamp tsValid = b->issued(); … … 116 89 const char *Binding::stateName() const 117 90 { 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"; 131 106 } 132 107 } … … 146 121 m_state = Binding::ACKED; 147 122 else 123 { 124 AssertMsgFailed(("%d\n", m_state)); 148 125 m_state = Binding::RELEASED; 126 } 149 127 150 128 return *this; … … 152 130 153 131 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 */ 139 bool Binding::expire(Timestamp tsDeadline) 155 140 { 156 141 if (m_state <= Binding::EXPIRED) 157 142 return false; 158 143 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) 163 148 { 164 149 if (m_state == Binding::OFFERED) … … 171 156 172 157 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 */ 163 void Binding::toXML(xml::ElementNode *pElmParent) const 164 { 177 165 /* 178 166 * Lease 179 167 */ 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())); 188 171 if (m_id.id().present()) 189 172 { … … 191 174 size_t cbStrId = m_id.id().value().size() * 2 + 1; 192 175 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); 197 181 delete[] pszId; 198 182 } 199 183 200 184 /* 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()); 205 187 206 188 /* 207 189 * Lease/Address 208 190 */ 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)); 212 193 213 194 /* 214 195 * Lease/Time 215 196 */ 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 */ 210 Binding *Binding::fromXML(const xml::ElementNode *pElmLease) 225 211 { 226 212 /* Lease/@network seems to always have bogus value, ignore it. */ … … 230 216 */ 231 217 RTCString strMac; 232 bool fHasMac = ndLease->getAttributeValue("mac", &strMac);218 bool fHasMac = pElmLease->getAttributeValue("mac", &strMac); 233 219 if (!fHasMac) 234 220 return NULL; … … 241 227 OptClientId id; 242 228 RTCString strId; 243 bool fHasId = ndLease->getAttributeValue("id", &strId);229 bool fHasId = pElmLease->getAttributeValue("id", &strId); 244 230 if (fHasId) 245 231 { … … 264 250 */ 265 251 RTCString strState; 266 bool fHasState = ndLease->getAttributeValue("state", &strState);252 bool fHasState = pElmLease->getAttributeValue("state", &strState); 267 253 268 254 /* 269 255 * Lease/Address 270 256 */ 271 const xml::ElementNode *ndAddress = ndLease->findChildElement("Address");257 const xml::ElementNode *ndAddress = pElmLease->findChildElement("Address"); 272 258 if (ndAddress == NULL) 273 259 return NULL; … … 289 275 * Lease/Time 290 276 */ 291 const xml::ElementNode *ndTime = ndLease->findChildElement("Time");277 const xml::ElementNode *ndTime = pElmLease->findChildElement("Time"); 292 278 if (ndTime == NULL) 293 279 return NULL; … … 332 318 333 319 320 321 /********************************************************************************************************************************* 322 * Class Db Implementation * 323 *********************************************************************************************************************************/ 324 325 Db::Db() 326 : m_pConfig(NULL) 327 { 328 } 329 330 331 Db::~Db() 332 { 333 /** @todo free bindings */ 334 } 335 336 337 int 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 */ 334 353 void Db::expire() 335 354 { 336 355 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) 340 357 { 341 358 Binding *b = *it; … … 345 362 346 363 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 */ 347 371 Binding *Db::createBinding(const ClientId &id) 348 372 { 373 Binding *pBinding = NULL; 349 374 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 */ 359 402 Binding *Db::createBinding(RTNETADDRIPV4 addr, const ClientId &id) 360 403 { … … 362 405 if (!fAvailable) 363 406 { 364 /* 407 /** @todo 365 408 * XXX: this should not happen. If the address is from the 366 409 * pool, which we have verified before, then either it's in … … 376 419 377 420 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 */ 378 425 Binding *Db::allocateAddress(const ClientId &id, RTNETADDRIPV4 addr) 379 426 { 380 427 Assert(addr.u == 0 || addressBelongs(addr)); 381 382 Binding *addrBinding = NULL;383 Binding *freeBinding = NULL;384 Binding *reuseBinding = NULL;385 428 386 429 if (addr.u != 0) … … 394 437 * addresses that can be reused. 395 438 */ 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) 399 444 { 400 445 Binding *b = *it; … … 460 505 addrBinding = createBinding(addr, id); 461 506 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)); 464 508 return addrBinding; 465 509 } … … 467 511 if (addrBinding->m_state <= Binding::EXPIRED) /* not in use */ 468 512 { 469 LogDHCP(("> .... reusing %s binding for this address\n", 470 addrBinding->stateName())); 513 LogDHCP(("> .... reusing %s binding for this address\n", addrBinding->stateName())); 471 514 addrBinding->giveTo(id); 472 515 return addrBinding; 473 516 } 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())); 476 518 } 477 519 … … 489 531 idBinding = createBinding(); 490 532 if (idBinding != NULL) 491 {492 533 LogDHCP(("> .... creating new binding\n")); 493 }494 534 else 495 535 { 496 536 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 } 506 545 } 507 546 … … 514 553 515 554 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 */ 516 561 Binding *Db::allocateBinding(const DhcpClientMessage &req) 517 562 { 518 563 /** @todo XXX: handle fixed address assignments */ 564 565 /* 566 * Get and validate the requested address (if present). 567 */ 519 568 OptRequestedAddress reqAddr(req); 520 569 if (reqAddr.present() && !addressBelongs(reqAddr.value())) … … 532 581 } 533 582 583 /* 584 * Allocate the address. 585 */ 534 586 const ClientId &id(req.clientId()); 535 587 536 588 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 } 548 601 return b; 549 602 } 550 603 551 604 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 */ 611 int 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) 563 623 { 564 624 Binding *b = *it; 565 625 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)); 569 629 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)); 576 636 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 } 589 655 return VINF_SUCCESS; 590 656 } 591 657 592 658 659 /** 660 * Called by DHCP to cancel an offset. 661 * 662 * @param req The DHCP request. 663 */ 593 664 void Db::cancelOffer(const DhcpClientMessage &req) 594 665 { … … 598 669 599 670 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) 604 674 { 605 675 Binding *b = *it; … … 609 679 if (b->state() == Binding::OFFERED) 610 680 { 681 LogRel2(("Db::cancelOffer: cancelling %R[binding]\n", b)); 611 682 b->setLeaseTime(0); 612 683 b->setState(Binding::RELEASED); 613 684 } 685 else 686 LogRel2(("Db::cancelOffer: not offered state: %R[binding]\n", b)); 614 687 return; 615 688 } 616 689 } 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 */ 620 700 bool Db::releaseBinding(const DhcpClientMessage &req) 621 701 { 622 702 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) 627 706 { 628 707 Binding *b = *it; … … 630 709 if (b->addr().u == addr.u && b->id() == id) 631 710 { 711 LogRel2(("Db::releaseBinding: releasing %R[binding]\n", b)); 632 712 b->setState(Binding::RELEASED); 633 713 return true; … … 635 715 } 636 716 717 LogRel2(("Db::releaseBinding: not found (%RTnaipv4, %R[id])\n", addr.u, &id)); 637 718 return false; 638 719 } 639 720 640 721 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 */ 728 int 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 */ 645 735 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 { 661 761 xml::XmlFileWriter writer(doc); 662 writer.write(strFile Name.c_str(), true);762 writer.write(strFilename.c_str(), true /*fSafe*/); 663 763 } 664 764 catch (const xml::EIPRTFailure &e) … … 674 774 catch (...) 675 775 { 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; 679 778 } 680 779 … … 683 782 684 783 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 */ 792 int 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 */ 689 799 xml::Document doc; 690 800 try 691 801 { 692 802 xml::XmlFileParser parser; 693 parser.read(strFile Name.c_str(), doc);803 parser.read(strFilename.c_str(), doc); 694 804 } 695 805 catch (const xml::EIPRTFailure &e) … … 705 815 catch (...) 706 816 { 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())); 715 828 return VERR_NOT_FOUND; 716 829 } 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 */ 865 int 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.