portset.c revision 290001
1/*
2 * Copyright (C) 2008  Internet Systems Consortium, Inc. ("ISC")
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* $Id: portset.c,v 1.4 2008/06/24 23:24:35 marka Exp $ */
18
19/*! \file */
20
21#include <config.h>
22
23#include <isc/mem.h>
24#include <isc/portset.h>
25#include <isc/string.h>
26#include <isc/types.h>
27#include <isc/util.h>
28
29#define ISC_PORTSET_BUFSIZE (65536 / (sizeof(isc_uint32_t) * 8))
30
31/*%
32 * Internal representation of portset.  It's an array of 32-bit integers, each
33 * bit corresponding to a single port in the ascending order.  For example,
34 * the second most significant bit of buf[0] corresponds to port 1.
35 */
36struct isc_portset {
37	unsigned int nports;	/*%< number of ports in the set */
38	isc_uint32_t buf[ISC_PORTSET_BUFSIZE];
39};
40
41static inline isc_boolean_t
42portset_isset(isc_portset_t *portset, in_port_t port) {
43	return (ISC_TF((portset->buf[port >> 5] & (1 << (port & 31))) != 0));
44}
45
46static inline void
47portset_add(isc_portset_t *portset, in_port_t port) {
48	if (!portset_isset(portset, port)) {
49		portset->nports++;
50		portset->buf[port >> 5] |= (1 << (port & 31));
51	}
52}
53
54static inline void
55portset_remove(isc_portset_t *portset, in_port_t port) {
56	if (portset_isset(portset, port)) {
57		portset->nports--;
58		portset->buf[port >> 5] &= ~(1 << (port & 31));
59	}
60}
61
62isc_result_t
63isc_portset_create(isc_mem_t *mctx, isc_portset_t **portsetp) {
64	isc_portset_t *portset;
65
66	REQUIRE(portsetp != NULL && *portsetp == NULL);
67
68	portset = isc_mem_get(mctx, sizeof(*portset));
69	if (portset == NULL)
70		return (ISC_R_NOMEMORY);
71
72	/* Make the set 'empty' by default */
73	memset(portset, 0, sizeof(*portset));
74	*portsetp = portset;
75
76	return (ISC_R_SUCCESS);
77}
78
79void
80isc_portset_destroy(isc_mem_t *mctx, isc_portset_t **portsetp) {
81	isc_portset_t *portset;
82
83	REQUIRE(portsetp != NULL);
84	portset = *portsetp;
85
86	isc_mem_put(mctx, portset, sizeof(*portset));
87}
88
89isc_boolean_t
90isc_portset_isset(isc_portset_t *portset, in_port_t port) {
91	REQUIRE(portset != NULL);
92
93	return (portset_isset(portset, port));
94}
95
96unsigned int
97isc_portset_nports(isc_portset_t *portset) {
98	REQUIRE(portset != NULL);
99
100	return (portset->nports);
101}
102
103void
104isc_portset_add(isc_portset_t *portset, in_port_t port) {
105	REQUIRE(portset != NULL);
106
107	portset_add(portset, port);
108}
109
110void
111isc_portset_remove(isc_portset_t *portset, in_port_t port) {
112	portset_remove(portset, port);
113}
114
115void
116isc_portset_addrange(isc_portset_t *portset, in_port_t port_lo,
117		     in_port_t port_hi)
118{
119	in_port_t p;
120
121	REQUIRE(portset != NULL);
122	REQUIRE(port_lo <= port_hi);
123
124	p = port_lo;
125	do {
126		portset_add(portset, p);
127	} while (p++ < port_hi);
128}
129
130void
131isc_portset_removerange(isc_portset_t *portset, in_port_t port_lo,
132			in_port_t port_hi)
133{
134	in_port_t p;
135
136	REQUIRE(portset != NULL);
137	REQUIRE(port_lo <= port_hi);
138
139	p = port_lo;
140	do {
141		portset_remove(portset, p);
142	} while (p++ < port_hi);
143}
144