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.3.72.6 2006/08/25 05:25:50 marka Exp $ */
24 #include <isc/magic.h>
26 #include <isc/mutex.h>
28 #include <isc/refcount.h>
29 #include <isc/result.h>
30 #include <isc/string.h>
31 #include <isc/types.h>
34 #include <dns/types.h>
35 #include <dns/portlist.h>
37 #define DNS_PORTLIST_MAGIC ISC_MAGIC('P','L','S','T')
38 #define DNS_VALID_PORTLIST(p) ISC_MAGIC_VALID(p, DNS_PORTLIST_MAGIC)
40 typedef struct dns_element {
48 isc_refcount_t refcount;
51 unsigned int allocated;
55 #define DNS_PL_INET 0x0001
56 #define DNS_PL_INET6 0x0002
57 #define DNS_PL_ALLOCATE 16
60 compare(const void *arg1, const void *arg2) {
61 const dns_element_t *e1 = (const dns_element_t *)arg1;
62 const dns_element_t *e2 = (const dns_element_t *)arg2;
64 if (e1->port < e2->port)
66 if (e1->port > e2->port)
72 dns_portlist_create(isc_mem_t *mctx, dns_portlist_t **portlistp) {
73 dns_portlist_t *portlist;
76 REQUIRE(portlistp != NULL && *portlistp == NULL);
78 portlist = isc_mem_get(mctx, sizeof(*portlist));
80 return (ISC_R_NOMEMORY);
81 result = isc_mutex_init(&portlist->lock);
82 if (result != ISC_R_SUCCESS) {
83 isc_mem_put(mctx, portlist, sizeof(*portlist));
84 UNEXPECTED_ERROR(__FILE__, __LINE__,
85 "isc_mutex_init() failed: %s",
86 isc_result_totext(result));
87 return (ISC_R_UNEXPECTED);
89 isc_refcount_init(&portlist->refcount, 1);
90 portlist->list = NULL;
91 portlist->allocated = 0;
93 portlist->mctx = NULL;
94 isc_mem_attach(mctx, &portlist->mctx);
95 portlist->magic = DNS_PORTLIST_MAGIC;
96 *portlistp = portlist;
97 return (ISC_R_SUCCESS);
100 static dns_element_t *
101 find_port(dns_element_t *list, unsigned int len, in_port_t port) {
102 unsigned int xtry = len / 2;
103 unsigned int min = 0;
104 unsigned int max = len - 1;
105 unsigned int last = len;
108 if (list[xtry].port == port)
109 return (&list[xtry]);
110 if (port > list[xtry].port) {
114 xtry = xtry + (max - xtry + 1) / 2;
123 xtry = xtry - (xtry - min + 1) / 2;
134 dns_portlist_add(dns_portlist_t *portlist, int af, in_port_t port) {
138 REQUIRE(DNS_VALID_PORTLIST(portlist));
139 REQUIRE(af == AF_INET || af == AF_INET6);
141 LOCK(&portlist->lock);
142 if (portlist->active != 0) {
143 el = find_port(portlist->list, portlist->active, port);
146 el->flags |= DNS_PL_INET;
148 el->flags |= DNS_PL_INET6;
149 result = ISC_R_SUCCESS;
154 if (portlist->allocated <= portlist->active) {
155 unsigned int allocated;
156 allocated = portlist->allocated + DNS_PL_ALLOCATE;
157 el = isc_mem_get(portlist->mctx, sizeof(*el) * allocated);
159 result = ISC_R_NOMEMORY;
162 if (portlist->list != NULL) {
163 memcpy(el, portlist->list,
164 portlist->allocated * sizeof(*el));
165 isc_mem_put(portlist->mctx, portlist->list,
166 portlist->allocated * sizeof(*el));
169 portlist->allocated = allocated;
171 portlist->list[portlist->active].port = port;
173 portlist->list[portlist->active].flags = DNS_PL_INET;
175 portlist->list[portlist->active].flags = DNS_PL_INET6;
177 qsort(portlist->list, portlist->active, sizeof(*el), compare);
178 result = ISC_R_SUCCESS;
180 UNLOCK(&portlist->lock);
185 dns_portlist_remove(dns_portlist_t *portlist, int af, in_port_t port) {
188 REQUIRE(DNS_VALID_PORTLIST(portlist));
189 REQUIRE(af == AF_INET || af == AF_INET6);
191 LOCK(&portlist->lock);
192 if (portlist->active != 0) {
193 el = find_port(portlist->list, portlist->active, port);
196 el->flags &= ~DNS_PL_INET;
198 el->flags &= ~DNS_PL_INET6;
199 if (el->flags == 0) {
200 *el = portlist->list[portlist->active];
202 qsort(portlist->list, portlist->active,
203 sizeof(*el), compare);
207 UNLOCK(&portlist->lock);
211 dns_portlist_match(dns_portlist_t *portlist, int af, in_port_t port) {
213 isc_boolean_t result = ISC_FALSE;
215 REQUIRE(DNS_VALID_PORTLIST(portlist));
216 REQUIRE(af == AF_INET || af == AF_INET6);
217 LOCK(&portlist->lock);
218 if (portlist->active != 0) {
219 el = find_port(portlist->list, portlist->active, port);
221 if (af == AF_INET && (el->flags & DNS_PL_INET) != 0)
223 if (af == AF_INET6 && (el->flags & DNS_PL_INET6) != 0)
227 UNLOCK(&portlist->lock);
232 dns_portlist_attach(dns_portlist_t *portlist, dns_portlist_t **portlistp) {
234 REQUIRE(DNS_VALID_PORTLIST(portlist));
235 REQUIRE(portlistp != NULL && *portlistp == NULL);
237 isc_refcount_increment(&portlist->refcount, NULL);
238 *portlistp = portlist;
242 dns_portlist_detach(dns_portlist_t **portlistp) {
243 dns_portlist_t *portlist;
246 REQUIRE(portlistp != NULL);
247 portlist = *portlistp;
248 REQUIRE(DNS_VALID_PORTLIST(portlist));
250 isc_refcount_decrement(&portlist->refcount, &count);
253 isc_refcount_destroy(&portlist->refcount);
254 if (portlist->list != NULL)
255 isc_mem_put(portlist->mctx, portlist->list,
256 portlist->allocated *
257 sizeof(*portlist->list));
258 DESTROYLOCK(&portlist->lock);
259 isc_mem_putanddetach(&portlist->mctx, portlist,