portlist.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2007, 2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id: portlist.c,v 1.13 2007/06/19 23:47:16 tbox Exp $ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <stdlib.h>
00025 
00026 #include <isc/magic.h>
00027 #include <isc/mem.h>
00028 #include <isc/mutex.h>
00029 #include <isc/net.h>
00030 #include <isc/refcount.h>
00031 #include <isc/result.h>
00032 #include <isc/string.h>
00033 #include <isc/types.h>
00034 #include <isc/util.h>
00035 
00036 #include <dns/types.h>
00037 #include <dns/portlist.h>
00038 
00039 #define DNS_PORTLIST_MAGIC      ISC_MAGIC('P','L','S','T')
00040 #define DNS_VALID_PORTLIST(p)   ISC_MAGIC_VALID(p, DNS_PORTLIST_MAGIC)
00041 
00042 typedef struct dns_element {
00043         in_port_t       port;
00044         isc_uint16_t    flags;
00045 } dns_element_t;
00046 
00047 struct dns_portlist {
00048         unsigned int    magic;
00049         isc_mem_t       *mctx;
00050         isc_refcount_t  refcount;
00051         isc_mutex_t     lock;
00052         dns_element_t   *list;
00053         unsigned int    allocated;
00054         unsigned int    active;
00055 };
00056 
00057 #define DNS_PL_INET     0x0001
00058 #define DNS_PL_INET6    0x0002
00059 #define DNS_PL_ALLOCATE 16
00060 
00061 static int
00062 compare(const void *arg1, const void *arg2) {
00063         const dns_element_t *e1 = (const dns_element_t *)arg1;
00064         const dns_element_t *e2 = (const dns_element_t *)arg2;
00065 
00066         if (e1->port < e2->port)
00067                 return (-1);
00068         if (e1->port > e2->port)
00069                 return (1);
00070         return (0);
00071 }
00072 
00073 isc_result_t
00074 dns_portlist_create(isc_mem_t *mctx, dns_portlist_t **portlistp) {
00075         dns_portlist_t *portlist;
00076         isc_result_t result;
00077 
00078         REQUIRE(portlistp != NULL && *portlistp == NULL);
00079 
00080         portlist = isc_mem_get(mctx, sizeof(*portlist));
00081         if (portlist == NULL)
00082                 return (ISC_R_NOMEMORY);
00083         result = isc_mutex_init(&portlist->lock);
00084         if (result != ISC_R_SUCCESS) {
00085                 isc_mem_put(mctx, portlist, sizeof(*portlist));
00086                 return (result);
00087         }
00088         result = isc_refcount_init(&portlist->refcount, 1);
00089         if (result != ISC_R_SUCCESS) {
00090                 DESTROYLOCK(&portlist->lock);
00091                 isc_mem_put(mctx, portlist, sizeof(*portlist));
00092                 return (result);
00093         }
00094         portlist->list = NULL;
00095         portlist->allocated = 0;
00096         portlist->active = 0;
00097         portlist->mctx = NULL;
00098         isc_mem_attach(mctx, &portlist->mctx);
00099         portlist->magic = DNS_PORTLIST_MAGIC;
00100         *portlistp = portlist;
00101         return (ISC_R_SUCCESS);
00102 }
00103 
00104 static dns_element_t *
00105 find_port(dns_element_t *list, unsigned int len, in_port_t port) {
00106         unsigned int xtry = len / 2;
00107         unsigned int min = 0;
00108         unsigned int max = len - 1;
00109         unsigned int last = len;
00110 
00111         for (;;) {
00112                 if (list[xtry].port == port)
00113                         return (&list[xtry]);
00114                 if (port > list[xtry].port) {
00115                         if (xtry == max)
00116                                 break;
00117                         min = xtry;
00118                         xtry = xtry + (max - xtry + 1) / 2;
00119                         INSIST(xtry <= max);
00120                         if (xtry == last)
00121                                 break;
00122                         last = min;
00123                 } else {
00124                         if (xtry == min)
00125                                 break;
00126                         max = xtry;
00127                         xtry = xtry - (xtry - min + 1) / 2;
00128                         INSIST(xtry >= min);
00129                         if (xtry == last)
00130                                 break;
00131                         last = max;
00132                 }
00133         }
00134         return (NULL);
00135 }
00136 
00137 isc_result_t
00138 dns_portlist_add(dns_portlist_t *portlist, int af, in_port_t port) {
00139         dns_element_t *el;
00140         isc_result_t result;
00141 
00142         REQUIRE(DNS_VALID_PORTLIST(portlist));
00143         REQUIRE(af == AF_INET || af == AF_INET6);
00144 
00145         LOCK(&portlist->lock);
00146         if (portlist->active != 0) {
00147                 el = find_port(portlist->list, portlist->active, port);
00148                 if (el != NULL) {
00149                         if (af == AF_INET)
00150                                 el->flags |= DNS_PL_INET;
00151                         else
00152                                 el->flags |= DNS_PL_INET6;
00153                         result = ISC_R_SUCCESS;
00154                         goto unlock;
00155                 }
00156         }
00157 
00158         if (portlist->allocated <= portlist->active) {
00159                 unsigned int allocated;
00160                 allocated = portlist->allocated + DNS_PL_ALLOCATE;
00161                 el = isc_mem_get(portlist->mctx, sizeof(*el) * allocated);
00162                 if (el == NULL) {
00163                         result = ISC_R_NOMEMORY;
00164                         goto unlock;
00165                 }
00166                 if (portlist->list != NULL) {
00167                         memmove(el, portlist->list,
00168                                 portlist->allocated * sizeof(*el));
00169                         isc_mem_put(portlist->mctx, portlist->list,
00170                                     portlist->allocated * sizeof(*el));
00171                 }
00172                 portlist->list = el;
00173                 portlist->allocated = allocated;
00174         }
00175         portlist->list[portlist->active].port = port;
00176         if (af == AF_INET)
00177                 portlist->list[portlist->active].flags = DNS_PL_INET;
00178         else
00179                 portlist->list[portlist->active].flags = DNS_PL_INET6;
00180         portlist->active++;
00181         qsort(portlist->list, portlist->active, sizeof(*el), compare);
00182         result = ISC_R_SUCCESS;
00183  unlock:
00184         UNLOCK(&portlist->lock);
00185         return (result);
00186 }
00187 
00188 void
00189 dns_portlist_remove(dns_portlist_t *portlist, int af, in_port_t port) {
00190         dns_element_t *el;
00191 
00192         REQUIRE(DNS_VALID_PORTLIST(portlist));
00193         REQUIRE(af == AF_INET || af == AF_INET6);
00194 
00195         LOCK(&portlist->lock);
00196         if (portlist->active != 0) {
00197                 el = find_port(portlist->list, portlist->active, port);
00198                 if (el != NULL) {
00199                         if (af == AF_INET)
00200                                 el->flags &= ~DNS_PL_INET;
00201                         else
00202                                 el->flags &= ~DNS_PL_INET6;
00203                         if (el->flags == 0) {
00204                                 *el = portlist->list[portlist->active];
00205                                 portlist->active--;
00206                                 qsort(portlist->list, portlist->active,
00207                                       sizeof(*el), compare);
00208                         }
00209                 }
00210         }
00211         UNLOCK(&portlist->lock);
00212 }
00213 
00214 isc_boolean_t
00215 dns_portlist_match(dns_portlist_t *portlist, int af, in_port_t port) {
00216         dns_element_t *el;
00217         isc_boolean_t result = ISC_FALSE;
00218 
00219         REQUIRE(DNS_VALID_PORTLIST(portlist));
00220         REQUIRE(af == AF_INET || af == AF_INET6);
00221         LOCK(&portlist->lock);
00222         if (portlist->active != 0) {
00223                 el = find_port(portlist->list, portlist->active, port);
00224                 if (el != NULL) {
00225                         if (af == AF_INET && (el->flags & DNS_PL_INET) != 0)
00226                                 result = ISC_TRUE;
00227                         if (af == AF_INET6 && (el->flags & DNS_PL_INET6) != 0)
00228                                 result = ISC_TRUE;
00229                 }
00230         }
00231         UNLOCK(&portlist->lock);
00232         return (result);
00233 }
00234 
00235 void
00236 dns_portlist_attach(dns_portlist_t *portlist, dns_portlist_t **portlistp) {
00237 
00238         REQUIRE(DNS_VALID_PORTLIST(portlist));
00239         REQUIRE(portlistp != NULL && *portlistp == NULL);
00240 
00241         isc_refcount_increment(&portlist->refcount, NULL);
00242         *portlistp = portlist;
00243 }
00244 
00245 void
00246 dns_portlist_detach(dns_portlist_t **portlistp) {
00247         dns_portlist_t *portlist;
00248         unsigned int count;
00249 
00250         REQUIRE(portlistp != NULL);
00251         portlist = *portlistp;
00252         REQUIRE(DNS_VALID_PORTLIST(portlist));
00253         *portlistp = NULL;
00254         isc_refcount_decrement(&portlist->refcount, &count);
00255         if (count == 0) {
00256                 portlist->magic = 0;
00257                 isc_refcount_destroy(&portlist->refcount);
00258                 if (portlist->list != NULL)
00259                         isc_mem_put(portlist->mctx, portlist->list,
00260                                     portlist->allocated *
00261                                     sizeof(*portlist->list));
00262                 DESTROYLOCK(&portlist->lock);
00263                 isc_mem_putanddetach(&portlist->mctx, portlist,
00264                                      sizeof(*portlist));
00265         }
00266 }

Generated on Tue Apr 28 17:40:59 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha