1 /* $NetBSD: portlist.c,v 1.5 2014/12/10 04:37:58 christos Exp $ */
4 * Copyright (C) 2004-2007, 2014 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: portlist.c,v 1.13 2007/06/19 23:47:16 tbox Exp */
28 #include <isc/magic.h>
30 #include <isc/mutex.h>
32 #include <isc/refcount.h>
33 #include <isc/result.h>
34 #include <isc/string.h>
35 #include <isc/types.h>
38 #include <dns/types.h>
39 #include <dns/portlist.h>
41 #define DNS_PORTLIST_MAGIC ISC_MAGIC('P','L','S','T')
42 #define DNS_VALID_PORTLIST(p) ISC_MAGIC_VALID(p, DNS_PORTLIST_MAGIC)
44 typedef struct dns_element
{
52 isc_refcount_t refcount
;
55 unsigned int allocated
;
59 #define DNS_PL_INET 0x0001
60 #define DNS_PL_INET6 0x0002
61 #define DNS_PL_ALLOCATE 16
64 compare(const void *arg1
, const void *arg2
) {
65 const dns_element_t
*e1
= (const dns_element_t
*)arg1
;
66 const dns_element_t
*e2
= (const dns_element_t
*)arg2
;
68 if (e1
->port
< e2
->port
)
70 if (e1
->port
> e2
->port
)
76 dns_portlist_create(isc_mem_t
*mctx
, dns_portlist_t
**portlistp
) {
77 dns_portlist_t
*portlist
;
80 REQUIRE(portlistp
!= NULL
&& *portlistp
== NULL
);
82 portlist
= isc_mem_get(mctx
, sizeof(*portlist
));
84 return (ISC_R_NOMEMORY
);
85 result
= isc_mutex_init(&portlist
->lock
);
86 if (result
!= ISC_R_SUCCESS
) {
87 isc_mem_put(mctx
, portlist
, sizeof(*portlist
));
90 result
= isc_refcount_init(&portlist
->refcount
, 1);
91 if (result
!= ISC_R_SUCCESS
) {
92 DESTROYLOCK(&portlist
->lock
);
93 isc_mem_put(mctx
, portlist
, sizeof(*portlist
));
96 portlist
->list
= NULL
;
97 portlist
->allocated
= 0;
99 portlist
->mctx
= NULL
;
100 isc_mem_attach(mctx
, &portlist
->mctx
);
101 portlist
->magic
= DNS_PORTLIST_MAGIC
;
102 *portlistp
= portlist
;
103 return (ISC_R_SUCCESS
);
106 static dns_element_t
*
107 find_port(dns_element_t
*list
, unsigned int len
, in_port_t port
) {
108 unsigned int xtry
= len
/ 2;
109 unsigned int min
= 0;
110 unsigned int max
= len
- 1;
111 unsigned int last
= len
;
114 if (list
[xtry
].port
== port
)
115 return (&list
[xtry
]);
116 if (port
> list
[xtry
].port
) {
120 xtry
= xtry
+ (max
- xtry
+ 1) / 2;
129 xtry
= xtry
- (xtry
- min
+ 1) / 2;
140 dns_portlist_add(dns_portlist_t
*portlist
, int af
, in_port_t port
) {
144 REQUIRE(DNS_VALID_PORTLIST(portlist
));
145 REQUIRE(af
== AF_INET
|| af
== AF_INET6
);
147 LOCK(&portlist
->lock
);
148 if (portlist
->active
!= 0) {
149 el
= find_port(portlist
->list
, portlist
->active
, port
);
152 el
->flags
|= DNS_PL_INET
;
154 el
->flags
|= DNS_PL_INET6
;
155 result
= ISC_R_SUCCESS
;
160 if (portlist
->allocated
<= portlist
->active
) {
161 unsigned int allocated
;
162 allocated
= portlist
->allocated
+ DNS_PL_ALLOCATE
;
163 el
= isc_mem_get(portlist
->mctx
, sizeof(*el
) * allocated
);
165 result
= ISC_R_NOMEMORY
;
168 if (portlist
->list
!= NULL
) {
169 memmove(el
, portlist
->list
,
170 portlist
->allocated
* sizeof(*el
));
171 isc_mem_put(portlist
->mctx
, portlist
->list
,
172 portlist
->allocated
* sizeof(*el
));
175 portlist
->allocated
= allocated
;
177 portlist
->list
[portlist
->active
].port
= port
;
179 portlist
->list
[portlist
->active
].flags
= DNS_PL_INET
;
181 portlist
->list
[portlist
->active
].flags
= DNS_PL_INET6
;
183 qsort(portlist
->list
, portlist
->active
, sizeof(*el
), compare
);
184 result
= ISC_R_SUCCESS
;
186 UNLOCK(&portlist
->lock
);
191 dns_portlist_remove(dns_portlist_t
*portlist
, int af
, in_port_t port
) {
194 REQUIRE(DNS_VALID_PORTLIST(portlist
));
195 REQUIRE(af
== AF_INET
|| af
== AF_INET6
);
197 LOCK(&portlist
->lock
);
198 if (portlist
->active
!= 0) {
199 el
= find_port(portlist
->list
, portlist
->active
, port
);
202 el
->flags
&= ~DNS_PL_INET
;
204 el
->flags
&= ~DNS_PL_INET6
;
205 if (el
->flags
== 0) {
206 *el
= portlist
->list
[portlist
->active
];
208 qsort(portlist
->list
, portlist
->active
,
209 sizeof(*el
), compare
);
213 UNLOCK(&portlist
->lock
);
217 dns_portlist_match(dns_portlist_t
*portlist
, int af
, in_port_t port
) {
219 isc_boolean_t result
= ISC_FALSE
;
221 REQUIRE(DNS_VALID_PORTLIST(portlist
));
222 REQUIRE(af
== AF_INET
|| af
== AF_INET6
);
223 LOCK(&portlist
->lock
);
224 if (portlist
->active
!= 0) {
225 el
= find_port(portlist
->list
, portlist
->active
, port
);
227 if (af
== AF_INET
&& (el
->flags
& DNS_PL_INET
) != 0)
229 if (af
== AF_INET6
&& (el
->flags
& DNS_PL_INET6
) != 0)
233 UNLOCK(&portlist
->lock
);
238 dns_portlist_attach(dns_portlist_t
*portlist
, dns_portlist_t
**portlistp
) {
240 REQUIRE(DNS_VALID_PORTLIST(portlist
));
241 REQUIRE(portlistp
!= NULL
&& *portlistp
== NULL
);
243 isc_refcount_increment(&portlist
->refcount
, NULL
);
244 *portlistp
= portlist
;
248 dns_portlist_detach(dns_portlist_t
**portlistp
) {
249 dns_portlist_t
*portlist
;
252 REQUIRE(portlistp
!= NULL
);
253 portlist
= *portlistp
;
254 REQUIRE(DNS_VALID_PORTLIST(portlist
));
256 isc_refcount_decrement(&portlist
->refcount
, &count
);
259 isc_refcount_destroy(&portlist
->refcount
);
260 if (portlist
->list
!= NULL
)
261 isc_mem_put(portlist
->mctx
, portlist
->list
,
262 portlist
->allocated
*
263 sizeof(*portlist
->list
));
264 DESTROYLOCK(&portlist
->lock
);
265 isc_mem_putanddetach(&portlist
->mctx
, portlist
,