2 * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and 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.6.18.5 2006/08/25 05:25:51 marka Exp $ */
26 #include <isc/magic.h>
28 #include <isc/mutex.h>
30 #include <isc/refcount.h>
31 #include <isc/result.h>
32 #include <isc/string.h>
33 #include <isc/types.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 {
50 isc_refcount_t refcount;
53 unsigned int allocated;
57 #define DNS_PL_INET 0x0001
58 #define DNS_PL_INET6 0x0002
59 #define DNS_PL_ALLOCATE 16
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)
68 if (e1->port > e2->port)
74 dns_portlist_create(isc_mem_t *mctx, dns_portlist_t **portlistp) {
75 dns_portlist_t *portlist;
78 REQUIRE(portlistp != NULL && *portlistp == NULL);
80 portlist = isc_mem_get(mctx, sizeof(*portlist));
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));
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));
94 portlist->list = NULL;
95 portlist->allocated = 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;
112 if (list[xtry].port == port)
113 return (&list[xtry]);
114 if (port > list[xtry].port) {
118 xtry = xtry + (max - xtry + 1) / 2;
127 xtry = xtry - (xtry - min + 1) / 2;
138 dns_portlist_add(dns_portlist_t *portlist, int af, in_port_t port) {
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);
150 el->flags |= DNS_PL_INET;
152 el->flags |= DNS_PL_INET6;
153 result = ISC_R_SUCCESS;
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);
163 result = ISC_R_NOMEMORY;
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));
173 portlist->allocated = allocated;
175 portlist->list[portlist->active].port = port;
177 portlist->list[portlist->active].flags = DNS_PL_INET;
179 portlist->list[portlist->active].flags = DNS_PL_INET6;
181 qsort(portlist->list, portlist->active, sizeof(*el), compare);
182 result = ISC_R_SUCCESS;
184 UNLOCK(&portlist->lock);
189 dns_portlist_remove(dns_portlist_t *portlist, int af, in_port_t port) {
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);
200 el->flags &= ~DNS_PL_INET;
202 el->flags &= ~DNS_PL_INET6;
203 if (el->flags == 0) {
204 *el = portlist->list[portlist->active];
206 qsort(portlist->list, portlist->active,
207 sizeof(*el), compare);
211 UNLOCK(&portlist->lock);
215 dns_portlist_match(dns_portlist_t *portlist, int af, in_port_t port) {
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);
225 if (af == AF_INET && (el->flags & DNS_PL_INET) != 0)
227 if (af == AF_INET6 && (el->flags & DNS_PL_INET6) != 0)
231 UNLOCK(&portlist->lock);
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;
246 dns_portlist_detach(dns_portlist_t **portlistp) {
247 dns_portlist_t *portlist;
250 REQUIRE(portlistp != NULL);
251 portlist = *portlistp;
252 REQUIRE(DNS_VALID_PORTLIST(portlist));
254 isc_refcount_decrement(&portlist->refcount, &count);
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,