VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/Dhcpd/IPv4Pool.cpp@ 79859

Last change on this file since 79859 was 79568, checked in by vboxsync, 5 years ago

Dhcpd: Went over the DhcpMessage a little as well as revisiting the lease reading code in the database. Logging is LogRel() or similar, no cout, RTPrintf or similar. The debug & release loggers can both output to stderr/out/whatever as needed. bugref:9288

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.2 KB
Line 
1/* $Id: IPv4Pool.cpp 79568 2019-07-06 23:42:51Z vboxsync $ */
2/** @file
3 * DHCP server - A pool of IPv4 addresses.
4 */
5
6/*
7 * Copyright (C) 2017-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include "DhcpdInternal.h"
23#include <iprt/errcore.h>
24
25#include "IPv4Pool.h"
26
27
28int IPv4Pool::init(const IPv4Range &aRange) RT_NOEXCEPT
29{
30 AssertReturn(aRange.isValid(), VERR_INVALID_PARAMETER);
31
32 m_range = aRange;
33 try
34 {
35 m_pool.insert(m_range);
36 }
37 catch (std::bad_alloc &)
38 {
39 return VERR_NO_MEMORY;
40 }
41 return VINF_SUCCESS;
42}
43
44
45int IPv4Pool::init(RTNETADDRIPV4 aFirstAddr, RTNETADDRIPV4 aLastAddr) RT_NOEXCEPT
46{
47 return init(IPv4Range(aFirstAddr, aLastAddr));
48}
49
50
51/**
52 * Internal worker for inserting a range into the pool of available addresses.
53 *
54 * @returns IPRT status code (asserted).
55 * @param a_Range The range to insert.
56 */
57int IPv4Pool::i_insert(const IPv4Range &a_Range) RT_NOEXCEPT
58{
59 /*
60 * Check preconditions. Asserting because nobody checks the return code.
61 */
62 AssertReturn(m_range.isValid(), VERR_INVALID_STATE);
63 AssertReturn(a_Range.isValid(), VERR_INVALID_PARAMETER);
64 AssertReturn(m_range.contains(a_Range), VERR_INVALID_PARAMETER);
65
66 /*
67 * Check that the incoming range doesn't overlap with existing ranges in the pool.
68 */
69 it_t itHint = m_pool.upper_bound(IPv4Range(a_Range.LastAddr)); /* successor, insertion hint */
70#if 0 /** @todo r=bird: This code is wrong. It has no end() check for starters. Since the method is
71 * only for internal consumption, I've replaced it with a strict build assertion. */
72 if (itHint != m_pool.begin())
73 {
74 it_t prev(itHint);
75 --prev;
76 if (a_Range.FirstAddr <= prev->LastAddr)
77 {
78 LogRel(("%08x-%08x conflicts with %08x-%08x\n",
79 a_Range.FirstAddr, a_Range.LastAddr,
80 prev->FirstAddr, prev->LastAddr));
81 return VERR_INVALID_PARAMETER;
82 }
83 }
84#endif
85#ifdef VBOX_STRICT
86 for (it_t it2 = m_pool.begin(); it2 != m_pool.end(); ++it2)
87 AssertMsg(it2->LastAddr < a_Range.FirstAddr || it2->FirstAddr > a_Range.LastAddr,
88 ("%08RX32-%08RX32 conflicts with %08RX32-%08RX32\n",
89 a_Range.FirstAddr, a_Range.LastAddr, it2->FirstAddr, it2->LastAddr));
90#endif
91
92 /*
93 * No overlaps, insert it.
94 */
95 try
96 {
97 m_pool.insert(itHint, a_Range);
98 }
99 catch (std::bad_alloc &)
100 {
101 return VERR_NO_MEMORY;
102 }
103 return VINF_SUCCESS;
104}
105
106
107/**
108 * Allocates an available IPv4 address from the pool.
109 *
110 * @returns Non-zero network order IPv4 address on success, zero address
111 * (0.0.0.0) on failure.
112 */
113RTNETADDRIPV4 IPv4Pool::allocate()
114{
115 RTNETADDRIPV4 RetAddr;
116 if (!m_pool.empty())
117 {
118 /* Grab the first address in the pool: */
119 it_t itBeg = m_pool.begin();
120 RetAddr.u = RT_H2N_U32(itBeg->FirstAddr);
121
122 if (itBeg->FirstAddr == itBeg->LastAddr)
123 m_pool.erase(itBeg);
124 else
125 {
126 /* Trim the entry (re-inserting it): */
127 IPv4Range trimmed = *itBeg;
128 trimmed.FirstAddr += 1;
129 Assert(trimmed.FirstAddr <= trimmed.LastAddr);
130 m_pool.erase(itBeg);
131 try
132 {
133 m_pool.insert(trimmed);
134 }
135 catch (std::bad_alloc &)
136 {
137 /** @todo r=bird: Theortically the insert could fail with a bad_alloc and we'd
138 * drop a range of IP address. It would be nice if we could safely modify itBit
139 * without having to re-insert it. The author of this code (not bird) didn't
140 * seem to think this safe?
141 *
142 * If we want to play safe and all that, just use a AVLRU32TREE (or AVLRU64TREE
143 * if lazy) AVL tree from IPRT. Since we know exactly how it's implemented and
144 * works, there will be no uncertanties like this when using it (both here
145 * and in the i_insert validation logic). */
146 LogRelFunc(("Caught bad_alloc! We're truely buggered now!\n"));
147 }
148 }
149 }
150 else
151 RetAddr.u = 0;
152 return RetAddr;
153}
154
155
156/**
157 * Allocate the given address.
158 *
159 * @returns Success indicator.
160 * @param a_Addr The IP address to allocate (network order).
161 */
162bool IPv4Pool::allocate(RTNETADDRIPV4 a_Addr)
163{
164 /*
165 * Find the range containing a_Addr.
166 */
167 it_t it = m_pool.lower_bound(IPv4Range(a_Addr)); /* candidate range */
168 if (it != m_pool.end())
169 {
170 Assert(RT_N2H_U32(a_Addr.u) <= it->LastAddr); /* by definition of < and lower_bound */
171
172 if (it->contains(a_Addr))
173 {
174 /*
175 * Remove a_Addr from the range by way of re-insertion.
176 */
177 const IPV4HADDR haddr = RT_N2H_U32(a_Addr.u);
178 IPV4HADDR first = it->FirstAddr;
179 IPV4HADDR last = it->LastAddr;
180
181 m_pool.erase(it);
182 if (first != last)
183 {
184 if (haddr == first)
185 i_insert(++first, last);
186 else if (haddr == last)
187 i_insert(first, --last);
188 else
189 {
190 i_insert(first, haddr - 1);
191 i_insert(haddr + 1, last);
192 }
193 }
194
195 return true;
196 }
197 }
198 return false;
199}
Note: See TracBrowser for help on using the repository browser.

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