PageRenderTime 70ms CodeModel.GetById 21ms app.highlight 44ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bind9/lib/dns/portlist.c

https://bitbucket.org/freebsd/freebsd-head/
C | 266 lines | 217 code | 31 blank | 18 comment | 74 complexity | 8e9b0e6fb00e1669a00da25913577ca1 MD5 | raw file
  1/*
  2 * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
  3 * Copyright (C) 2003  Internet Software Consortium.
  4 *
  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.
  8 *
  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.
 16 */
 17
 18/* $Id: portlist.c,v 1.13 2007/06/19 23:47:16 tbox Exp $ */
 19
 20/*! \file */
 21
 22#include <config.h>
 23
 24#include <stdlib.h>
 25
 26#include <isc/magic.h>
 27#include <isc/mem.h>
 28#include <isc/mutex.h>
 29#include <isc/net.h>
 30#include <isc/refcount.h>
 31#include <isc/result.h>
 32#include <isc/string.h>
 33#include <isc/types.h>
 34#include <isc/util.h>
 35
 36#include <dns/types.h>
 37#include <dns/portlist.h>
 38
 39#define DNS_PORTLIST_MAGIC	ISC_MAGIC('P','L','S','T')
 40#define DNS_VALID_PORTLIST(p)	ISC_MAGIC_VALID(p, DNS_PORTLIST_MAGIC)
 41
 42typedef struct dns_element {
 43	in_port_t	port;
 44	isc_uint16_t	flags;
 45} dns_element_t;
 46
 47struct dns_portlist {
 48	unsigned int	magic;
 49	isc_mem_t	*mctx;
 50	isc_refcount_t	refcount;
 51	isc_mutex_t	lock;
 52	dns_element_t 	*list;
 53	unsigned int	allocated;
 54	unsigned int	active;
 55};
 56
 57#define DNS_PL_INET	0x0001
 58#define DNS_PL_INET6	0x0002
 59#define DNS_PL_ALLOCATE	16
 60
 61static int
 62compare(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;
 65
 66	if (e1->port < e2->port)
 67		return (-1);
 68	if (e1->port > e2->port)
 69		return (1);
 70	return (0);
 71}
 72
 73isc_result_t
 74dns_portlist_create(isc_mem_t *mctx, dns_portlist_t **portlistp) {
 75	dns_portlist_t *portlist;
 76	isc_result_t result;
 77
 78	REQUIRE(portlistp != NULL && *portlistp == NULL);
 79
 80	portlist = isc_mem_get(mctx, sizeof(*portlist));
 81	if (portlist == NULL)
 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));
 86		return (result);
 87	}
 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));
 92		return (result);
 93	}
 94	portlist->list = NULL;
 95	portlist->allocated = 0;
 96	portlist->active = 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);
102}
103
104static dns_element_t *
105find_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;
110
111	for (;;) {
112		if (list[xtry].port == port)
113			return (&list[xtry]);
114	        if (port > list[xtry].port) {
115			if (xtry == max)
116				break;
117			min = xtry;
118			xtry = xtry + (max - xtry + 1) / 2;
119			INSIST(xtry <= max);
120			if (xtry == last)
121				break;
122			last = min;
123		} else {
124			if (xtry == min)
125				break;
126			max = xtry;
127			xtry = xtry - (xtry - min + 1) / 2;
128			INSIST(xtry >= min);
129			if (xtry == last)
130				break;
131			last = max;
132		}
133	}
134	return (NULL);
135}
136
137isc_result_t
138dns_portlist_add(dns_portlist_t *portlist, int af, in_port_t port) {
139	dns_element_t *el;
140	isc_result_t result;
141
142	REQUIRE(DNS_VALID_PORTLIST(portlist));
143	REQUIRE(af == AF_INET || af == AF_INET6);
144
145	LOCK(&portlist->lock);
146	if (portlist->active != 0) {
147		el = find_port(portlist->list, portlist->active, port);
148		if (el != NULL) {
149			if (af == AF_INET)
150				el->flags |= DNS_PL_INET;
151			else
152				el->flags |= DNS_PL_INET6;
153			result = ISC_R_SUCCESS;
154			goto unlock;
155		}
156	}
157
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);
162		if (el == NULL) {
163			result = ISC_R_NOMEMORY;
164			goto unlock;
165		}
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));
171		}
172		portlist->list = el;
173		portlist->allocated = allocated;
174	}
175	portlist->list[portlist->active].port = port;
176	if (af == AF_INET)
177		portlist->list[portlist->active].flags = DNS_PL_INET;
178	else
179		portlist->list[portlist->active].flags = DNS_PL_INET6;
180	portlist->active++;
181	qsort(portlist->list, portlist->active, sizeof(*el), compare);
182	result = ISC_R_SUCCESS;
183 unlock:
184	UNLOCK(&portlist->lock);
185	return (result);
186}
187
188void
189dns_portlist_remove(dns_portlist_t *portlist, int af, in_port_t port) {
190	dns_element_t *el;
191
192	REQUIRE(DNS_VALID_PORTLIST(portlist));
193	REQUIRE(af == AF_INET || af == AF_INET6);
194
195	LOCK(&portlist->lock);
196	if (portlist->active != 0) {
197		el = find_port(portlist->list, portlist->active, port);
198		if (el != NULL) {
199			if (af == AF_INET)
200				el->flags &= ~DNS_PL_INET;
201			else
202				el->flags &= ~DNS_PL_INET6;
203			if (el->flags == 0) {
204				*el = portlist->list[portlist->active];
205				portlist->active--;
206				qsort(portlist->list, portlist->active,
207				      sizeof(*el), compare);
208			}
209		}
210	}
211	UNLOCK(&portlist->lock);
212}
213
214isc_boolean_t
215dns_portlist_match(dns_portlist_t *portlist, int af, in_port_t port) {
216	dns_element_t *el;
217	isc_boolean_t result = ISC_FALSE;
218	
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);
224		if (el != NULL) {
225			if (af == AF_INET && (el->flags & DNS_PL_INET) != 0)
226				result = ISC_TRUE;
227			if (af == AF_INET6 && (el->flags & DNS_PL_INET6) != 0)
228				result = ISC_TRUE;
229		}
230	}	
231	UNLOCK(&portlist->lock);
232	return (result);
233}
234
235void
236dns_portlist_attach(dns_portlist_t *portlist, dns_portlist_t **portlistp) {
237
238	REQUIRE(DNS_VALID_PORTLIST(portlist));
239	REQUIRE(portlistp != NULL && *portlistp == NULL);
240
241	isc_refcount_increment(&portlist->refcount, NULL);
242	*portlistp = portlist;
243}
244
245void
246dns_portlist_detach(dns_portlist_t **portlistp) {
247	dns_portlist_t *portlist;
248	unsigned int count;
249
250	REQUIRE(portlistp != NULL);
251	portlist = *portlistp;
252	REQUIRE(DNS_VALID_PORTLIST(portlist));
253	*portlistp = NULL;
254	isc_refcount_decrement(&portlist->refcount, &count);
255	if (count == 0) {
256		portlist->magic = 0;
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,
264				     sizeof(*portlist));
265	}
266}