2 * Copyright (C) 2004 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.4 2004/03/16 05:50:21 marka Exp $ */
22 #include <isc/magic.h>
24 #include <isc/mutex.h>
26 #include <isc/refcount.h>
27 #include <isc/result.h>
28 #include <isc/string.h>
29 #include <isc/types.h>
32 #include <dns/types.h>
33 #include <dns/portlist.h>
35 #define DNS_PORTLIST_MAGIC ISC_MAGIC('P','L','S','T')
36 #define DNS_VALID_PORTLIST(p) ISC_MAGIC_VALID(p, DNS_PORTLIST_MAGIC)
38 typedef struct dns_element {
46 isc_refcount_t refcount;
49 unsigned int allocated;
53 #define DNS_PL_INET 0x0001
54 #define DNS_PL_INET6 0x0002
55 #define DNS_PL_ALLOCATE 16
58 compare(const void *arg1, const void *arg2) {
59 const dns_element_t *e1 = (const dns_element_t *)arg1;
60 const dns_element_t *e2 = (const dns_element_t *)arg2;
62 if (e1->port < e2->port)
64 if (e1->port > e2->port)
70 dns_portlist_create(isc_mem_t *mctx, dns_portlist_t **portlistp) {
71 dns_portlist_t *portlist;
74 REQUIRE(portlistp != NULL && *portlistp == NULL);
76 portlist = isc_mem_get(mctx, sizeof(*portlist));
78 return (ISC_R_NOMEMORY);
79 result = isc_mutex_init(&portlist->lock);
80 if (result != ISC_R_SUCCESS) {
81 isc_mem_put(mctx, portlist, sizeof(*portlist));
82 UNEXPECTED_ERROR(__FILE__, __LINE__,
83 "isc_mutex_init() failed: %s",
84 isc_result_totext(result));
85 return (ISC_R_UNEXPECTED);
87 isc_refcount_init(&portlist->refcount, 1);
88 portlist->list = NULL;
89 portlist->allocated = 0;
91 portlist->mctx = NULL;
92 isc_mem_attach(mctx, &portlist->mctx);
93 portlist->magic = DNS_PORTLIST_MAGIC;
94 *portlistp = portlist;
95 return (ISC_R_SUCCESS);
98 static dns_element_t *
99 find_port(dns_element_t *list, unsigned int len, in_port_t port) {
100 unsigned int xtry = len / 2;
101 unsigned int min = 0;
102 unsigned int max = len - 1;
103 unsigned int last = len;
106 if (list[xtry].port == port)
107 return (&list[xtry]);
108 if (port > list[xtry].port) {
112 xtry = xtry + (max - xtry + 1) / 2;
121 xtry = xtry - (xtry - min + 1) / 2;
132 dns_portlist_add(dns_portlist_t *portlist, int af, in_port_t port) {
136 REQUIRE(DNS_VALID_PORTLIST(portlist));
137 REQUIRE(af == AF_INET || af == AF_INET6);
139 LOCK(&portlist->lock);
140 if (portlist->active != 0) {
141 el = find_port(portlist->list, portlist->active, port);
144 el->flags |= DNS_PL_INET;
146 el->flags |= DNS_PL_INET6;
147 result = ISC_R_SUCCESS;
152 if (portlist->allocated <= portlist->active) {
153 unsigned int allocated;
154 allocated = portlist->allocated + DNS_PL_ALLOCATE;
155 el = isc_mem_get(portlist->mctx, sizeof(*el) * allocated);
157 result = ISC_R_NOMEMORY;
160 if (portlist->list != NULL) {
161 memcpy(el, portlist->list,
162 portlist->allocated * sizeof(*el));
163 isc_mem_put(portlist->mctx, portlist->list,
164 portlist->allocated * sizeof(*el));
167 portlist->allocated = allocated;
169 portlist->list[portlist->active].port = port;
171 portlist->list[portlist->active].flags = DNS_PL_INET;
173 portlist->list[portlist->active].flags = DNS_PL_INET6;
175 qsort(portlist->list, portlist->active, sizeof(*el), compare);
176 result = ISC_R_SUCCESS;
178 UNLOCK(&portlist->lock);
183 dns_portlist_remove(dns_portlist_t *portlist, int af, in_port_t port) {
186 REQUIRE(DNS_VALID_PORTLIST(portlist));
187 REQUIRE(af == AF_INET || af == AF_INET6);
189 LOCK(&portlist->lock);
190 if (portlist->active != 0) {
191 el = find_port(portlist->list, portlist->active, port);
194 el->flags &= ~DNS_PL_INET;
196 el->flags &= ~DNS_PL_INET6;
197 if (el->flags == 0) {
198 *el = portlist->list[portlist->active];
200 qsort(portlist->list, portlist->active,
201 sizeof(*el), compare);
205 UNLOCK(&portlist->lock);
209 dns_portlist_match(dns_portlist_t *portlist, int af, in_port_t port) {
211 isc_boolean_t result = ISC_FALSE;
213 REQUIRE(DNS_VALID_PORTLIST(portlist));
214 REQUIRE(af == AF_INET || af == AF_INET6);
215 LOCK(&portlist->lock);
216 if (portlist->active != 0) {
217 el = find_port(portlist->list, portlist->active, port);
219 if (af == AF_INET && (el->flags & DNS_PL_INET) != 0)
221 if (af == AF_INET6 && (el->flags & DNS_PL_INET6) != 0)
225 UNLOCK(&portlist->lock);
230 dns_portlist_attach(dns_portlist_t *portlist, dns_portlist_t **portlistp) {
232 REQUIRE(DNS_VALID_PORTLIST(portlist));
233 REQUIRE(portlistp != NULL && *portlistp == NULL);
235 isc_refcount_increment(&portlist->refcount, NULL);
236 *portlistp = portlist;
240 dns_portlist_detach(dns_portlist_t **portlistp) {
241 dns_portlist_t *portlist;
244 REQUIRE(portlistp != NULL);
245 portlist = *portlistp;
246 REQUIRE(DNS_VALID_PORTLIST(portlist));
248 isc_refcount_decrement(&portlist->refcount, &count);
251 isc_refcount_destroy(&portlist->refcount);
252 if (portlist->list != NULL)
253 isc_mem_put(portlist->mctx, portlist->list,
254 portlist->allocated *
255 sizeof(*portlist->list));
256 DESTROYLOCK(&portlist->lock);
257 isc_mem_putanddetach(&portlist->mctx, portlist,