VirtualBox

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

Last change on this file since 79563 was 79563, checked in by vboxsync, 6 years ago

Dhcpd: Went over the Dhcpd and related code adding comments and doing some exception vetting. bugref:9288

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.1 KB
Line 
1/* $Id: IPv4Pool.cpp 79563 2019-07-06 01:22:56Z 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 LogDHCP(("%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 m_pool.erase(itBeg);
130 try
131 {
132 m_pool.insert(trimmed);
133 }
134 catch (std::bad_alloc &)
135 {
136 /** @todo r=bird: Theortically the insert could fail with a bad_alloc and we'd
137 * drop a range of IP address. It would be nice if we could safely modify itBit
138 * without having to re-insert it. The author of this code (not bird) didn't
139 * seem to think this safe?
140 *
141 * If we want to play safe and all that, just use a AVLRU32TREE (or AVLRU64TREE
142 * if lazy) AVL tree from IPRT. Since we know exactly how it's implemented and
143 * works, there will be no uncertanties like this when using it (both here
144 * and in the i_insert validation logic). */
145 LogRelFunc(("Caught bad_alloc! We're truely buggered now!\n"));
146 }
147 }
148 }
149 else
150 RetAddr.u = 0;
151 return RetAddr;
152}
153
154
155/**
156 * Allocate the given address.
157 *
158 * @returns Success indicator.
159 * @param a_Addr The IP address to allocate (network order).
160 */
161bool IPv4Pool::allocate(RTNETADDRIPV4 a_Addr)
162{
163 /*
164 * Find the range containing a_Addr.
165 */
166 it_t it = m_pool.lower_bound(IPv4Range(a_Addr)); /* candidate range */
167 if (it != m_pool.end())
168 {
169 Assert(RT_N2H_U32(a_Addr.u) <= it->LastAddr); /* by definition of < and lower_bound */
170
171 if (it->contains(a_Addr))
172 {
173 /*
174 * Remove a_Addr from the range by way of re-insertion.
175 */
176 const IPV4HADDR haddr = RT_N2H_U32(a_Addr.u);
177 IPV4HADDR first = it->FirstAddr;
178 IPV4HADDR last = it->LastAddr;
179
180 m_pool.erase(it);
181 if (first != last)
182 {
183 if (haddr == first)
184 i_insert(++first, last);
185 else if (haddr == last)
186 i_insert(first, --last);
187 else
188 {
189 i_insert(first, haddr - 1);
190 i_insert(haddr + 1, last);
191 }
192 }
193
194 return true;
195 }
196 }
197 return false;
198}
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