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 $ */
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
,