vendor/BIND: Update to 9.5.2-P3
[dragonfly.git] / contrib / bind / lib / dns / portlist.c
blob5bc89f4829840a3b867e1833ab417eebde51defc
1 /*
2 * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: portlist.c,v 1.13 2007/06/19 23:47:16 tbox Exp $ */
20 /*! \file */
22 #include <config.h>
24 #include <stdlib.h>
26 #include <isc/magic.h>
27 #include <isc/mem.h>
28 #include <isc/mutex.h>
29 #include <isc/net.h>
30 #include <isc/refcount.h>
31 #include <isc/result.h>
32 #include <isc/string.h>
33 #include <isc/types.h>
34 #include <isc/util.h>
36 #include <dns/types.h>
37 #include <dns/portlist.h>
39 #define DNS_PORTLIST_MAGIC ISC_MAGIC('P','L','S','T')
40 #define DNS_VALID_PORTLIST(p) ISC_MAGIC_VALID(p, DNS_PORTLIST_MAGIC)
42 typedef struct dns_element {
43 in_port_t port;
44 isc_uint16_t flags;
45 } dns_element_t;
47 struct dns_portlist {
48 unsigned int magic;
49 isc_mem_t *mctx;
50 isc_refcount_t refcount;
51 isc_mutex_t lock;
52 dns_element_t *list;
53 unsigned int allocated;
54 unsigned int active;
57 #define DNS_PL_INET 0x0001
58 #define DNS_PL_INET6 0x0002
59 #define DNS_PL_ALLOCATE 16
61 static int
62 compare(const void *arg1, const void *arg2) {
63 const dns_element_t *e1 = (const dns_element_t *)arg1;
64 const dns_element_t *e2 = (const dns_element_t *)arg2;
66 if (e1->port < e2->port)
67 return (-1);
68 if (e1->port > e2->port)
69 return (1);
70 return (0);
73 isc_result_t
74 dns_portlist_create(isc_mem_t *mctx, dns_portlist_t **portlistp) {
75 dns_portlist_t *portlist;
76 isc_result_t result;
78 REQUIRE(portlistp != NULL && *portlistp == NULL);
80 portlist = isc_mem_get(mctx, sizeof(*portlist));
81 if (portlist == NULL)
82 return (ISC_R_NOMEMORY);
83 result = isc_mutex_init(&portlist->lock);
84 if (result != ISC_R_SUCCESS) {
85 isc_mem_put(mctx, portlist, sizeof(*portlist));
86 return (result);
88 result = isc_refcount_init(&portlist->refcount, 1);
89 if (result != ISC_R_SUCCESS) {
90 DESTROYLOCK(&portlist->lock);
91 isc_mem_put(mctx, portlist, sizeof(*portlist));
92 return (result);
94 portlist->list = NULL;
95 portlist->allocated = 0;
96 portlist->active = 0;
97 portlist->mctx = NULL;
98 isc_mem_attach(mctx, &portlist->mctx);
99 portlist->magic = DNS_PORTLIST_MAGIC;
100 *portlistp = portlist;
101 return (ISC_R_SUCCESS);
104 static dns_element_t *
105 find_port(dns_element_t *list, unsigned int len, in_port_t port) {
106 unsigned int xtry = len / 2;
107 unsigned int min = 0;
108 unsigned int max = len - 1;
109 unsigned int last = len;
111 for (;;) {
112 if (list[xtry].port == port)
113 return (&list[xtry]);
114 if (port > list[xtry].port) {
115 if (xtry == max)
116 break;
117 min = xtry;
118 xtry = xtry + (max - xtry + 1) / 2;
119 INSIST(xtry <= max);
120 if (xtry == last)
121 break;
122 last = min;
123 } else {
124 if (xtry == min)
125 break;
126 max = xtry;
127 xtry = xtry - (xtry - min + 1) / 2;
128 INSIST(xtry >= min);
129 if (xtry == last)
130 break;
131 last = max;
134 return (NULL);
137 isc_result_t
138 dns_portlist_add(dns_portlist_t *portlist, int af, in_port_t port) {
139 dns_element_t *el;
140 isc_result_t result;
142 REQUIRE(DNS_VALID_PORTLIST(portlist));
143 REQUIRE(af == AF_INET || af == AF_INET6);
145 LOCK(&portlist->lock);
146 if (portlist->active != 0) {
147 el = find_port(portlist->list, portlist->active, port);
148 if (el != NULL) {
149 if (af == AF_INET)
150 el->flags |= DNS_PL_INET;
151 else
152 el->flags |= DNS_PL_INET6;
153 result = ISC_R_SUCCESS;
154 goto unlock;
158 if (portlist->allocated <= portlist->active) {
159 unsigned int allocated;
160 allocated = portlist->allocated + DNS_PL_ALLOCATE;
161 el = isc_mem_get(portlist->mctx, sizeof(*el) * allocated);
162 if (el == NULL) {
163 result = ISC_R_NOMEMORY;
164 goto unlock;
166 if (portlist->list != NULL) {
167 memcpy(el, portlist->list,
168 portlist->allocated * sizeof(*el));
169 isc_mem_put(portlist->mctx, portlist->list,
170 portlist->allocated * sizeof(*el));
172 portlist->list = el;
173 portlist->allocated = allocated;
175 portlist->list[portlist->active].port = port;
176 if (af == AF_INET)
177 portlist->list[portlist->active].flags = DNS_PL_INET;
178 else
179 portlist->list[portlist->active].flags = DNS_PL_INET6;
180 portlist->active++;
181 qsort(portlist->list, portlist->active, sizeof(*el), compare);
182 result = ISC_R_SUCCESS;
183 unlock:
184 UNLOCK(&portlist->lock);
185 return (result);
188 void
189 dns_portlist_remove(dns_portlist_t *portlist, int af, in_port_t port) {
190 dns_element_t *el;
192 REQUIRE(DNS_VALID_PORTLIST(portlist));
193 REQUIRE(af == AF_INET || af == AF_INET6);
195 LOCK(&portlist->lock);
196 if (portlist->active != 0) {
197 el = find_port(portlist->list, portlist->active, port);
198 if (el != NULL) {
199 if (af == AF_INET)
200 el->flags &= ~DNS_PL_INET;
201 else
202 el->flags &= ~DNS_PL_INET6;
203 if (el->flags == 0) {
204 *el = portlist->list[portlist->active];
205 portlist->active--;
206 qsort(portlist->list, portlist->active,
207 sizeof(*el), compare);
211 UNLOCK(&portlist->lock);
214 isc_boolean_t
215 dns_portlist_match(dns_portlist_t *portlist, int af, in_port_t port) {
216 dns_element_t *el;
217 isc_boolean_t result = ISC_FALSE;
219 REQUIRE(DNS_VALID_PORTLIST(portlist));
220 REQUIRE(af == AF_INET || af == AF_INET6);
221 LOCK(&portlist->lock);
222 if (portlist->active != 0) {
223 el = find_port(portlist->list, portlist->active, port);
224 if (el != NULL) {
225 if (af == AF_INET && (el->flags & DNS_PL_INET) != 0)
226 result = ISC_TRUE;
227 if (af == AF_INET6 && (el->flags & DNS_PL_INET6) != 0)
228 result = ISC_TRUE;
231 UNLOCK(&portlist->lock);
232 return (result);
235 void
236 dns_portlist_attach(dns_portlist_t *portlist, dns_portlist_t **portlistp) {
238 REQUIRE(DNS_VALID_PORTLIST(portlist));
239 REQUIRE(portlistp != NULL && *portlistp == NULL);
241 isc_refcount_increment(&portlist->refcount, NULL);
242 *portlistp = portlist;
245 void
246 dns_portlist_detach(dns_portlist_t **portlistp) {
247 dns_portlist_t *portlist;
248 unsigned int count;
250 REQUIRE(portlistp != NULL);
251 portlist = *portlistp;
252 REQUIRE(DNS_VALID_PORTLIST(portlist));
253 *portlistp = NULL;
254 isc_refcount_decrement(&portlist->refcount, &count);
255 if (count == 0) {
256 portlist->magic = 0;
257 isc_refcount_destroy(&portlist->refcount);
258 if (portlist->list != NULL)
259 isc_mem_put(portlist->mctx, portlist->list,
260 portlist->allocated *
261 sizeof(*portlist->list));
262 DESTROYLOCK(&portlist->lock);
263 isc_mem_putanddetach(&portlist->mctx, portlist,
264 sizeof(*portlist));