"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/lib/dns/portlist.c" (7 Sep 2020, 6352 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "portlist.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 
   13 /*! \file */
   14 
   15 #include <config.h>
   16 
   17 #include <inttypes.h>
   18 #include <stdbool.h>
   19 #include <stdlib.h>
   20 
   21 #include <isc/magic.h>
   22 #include <isc/mem.h>
   23 #include <isc/mutex.h>
   24 #include <isc/net.h>
   25 #include <isc/refcount.h>
   26 #include <isc/result.h>
   27 #include <isc/string.h>
   28 #include <isc/types.h>
   29 #include <isc/util.h>
   30 
   31 #include <dns/types.h>
   32 #include <dns/portlist.h>
   33 
   34 #define DNS_PORTLIST_MAGIC  ISC_MAGIC('P','L','S','T')
   35 #define DNS_VALID_PORTLIST(p)   ISC_MAGIC_VALID(p, DNS_PORTLIST_MAGIC)
   36 
   37 typedef struct dns_element {
   38     in_port_t   port;
   39     uint16_t    flags;
   40 } dns_element_t;
   41 
   42 struct dns_portlist {
   43     unsigned int    magic;
   44     isc_mem_t   *mctx;
   45     isc_refcount_t  refcount;
   46     isc_mutex_t lock;
   47     dns_element_t   *list;
   48     unsigned int    allocated;
   49     unsigned int    active;
   50 };
   51 
   52 #define DNS_PL_INET 0x0001
   53 #define DNS_PL_INET6    0x0002
   54 #define DNS_PL_ALLOCATE 16
   55 
   56 static int
   57 compare(const void *arg1, const void *arg2) {
   58     const dns_element_t *e1 = (const dns_element_t *)arg1;
   59     const dns_element_t *e2 = (const dns_element_t *)arg2;
   60 
   61     if (e1->port < e2->port)
   62         return (-1);
   63     if (e1->port > e2->port)
   64         return (1);
   65     return (0);
   66 }
   67 
   68 isc_result_t
   69 dns_portlist_create(isc_mem_t *mctx, dns_portlist_t **portlistp) {
   70     dns_portlist_t *portlist;
   71     isc_result_t result;
   72 
   73     REQUIRE(portlistp != NULL && *portlistp == NULL);
   74 
   75     portlist = isc_mem_get(mctx, sizeof(*portlist));
   76     if (portlist == NULL)
   77         return (ISC_R_NOMEMORY);
   78     result = isc_mutex_init(&portlist->lock);
   79     if (result != ISC_R_SUCCESS) {
   80         isc_mem_put(mctx, portlist, sizeof(*portlist));
   81         return (result);
   82     }
   83     result = isc_refcount_init(&portlist->refcount, 1);
   84     if (result != ISC_R_SUCCESS) {
   85         DESTROYLOCK(&portlist->lock);
   86         isc_mem_put(mctx, portlist, sizeof(*portlist));
   87         return (result);
   88     }
   89     portlist->list = NULL;
   90     portlist->allocated = 0;
   91     portlist->active = 0;
   92     portlist->mctx = NULL;
   93     isc_mem_attach(mctx, &portlist->mctx);
   94     portlist->magic = DNS_PORTLIST_MAGIC;
   95     *portlistp = portlist;
   96     return (ISC_R_SUCCESS);
   97 }
   98 
   99 static dns_element_t *
  100 find_port(dns_element_t *list, unsigned int len, in_port_t port) {
  101     unsigned int xtry = len / 2;
  102     unsigned int min = 0;
  103     unsigned int max = len - 1;
  104     unsigned int last = len;
  105 
  106     for (;;) {
  107         if (list[xtry].port == port)
  108             return (&list[xtry]);
  109         if (port > list[xtry].port) {
  110             if (xtry == max)
  111                 break;
  112             min = xtry;
  113             xtry = xtry + (max - xtry + 1) / 2;
  114             INSIST(xtry <= max);
  115             if (xtry == last)
  116                 break;
  117             last = min;
  118         } else {
  119             if (xtry == min)
  120                 break;
  121             max = xtry;
  122             xtry = xtry - (xtry - min + 1) / 2;
  123             INSIST(xtry >= min);
  124             if (xtry == last)
  125                 break;
  126             last = max;
  127         }
  128     }
  129     return (NULL);
  130 }
  131 
  132 isc_result_t
  133 dns_portlist_add(dns_portlist_t *portlist, int af, in_port_t port) {
  134     dns_element_t *el;
  135     isc_result_t result;
  136 
  137     REQUIRE(DNS_VALID_PORTLIST(portlist));
  138     REQUIRE(af == AF_INET || af == AF_INET6);
  139 
  140     LOCK(&portlist->lock);
  141     if (portlist->active != 0) {
  142         el = find_port(portlist->list, portlist->active, port);
  143         if (el != NULL) {
  144             if (af == AF_INET)
  145                 el->flags |= DNS_PL_INET;
  146             else
  147                 el->flags |= DNS_PL_INET6;
  148             result = ISC_R_SUCCESS;
  149             goto unlock;
  150         }
  151     }
  152 
  153     if (portlist->allocated <= portlist->active) {
  154         unsigned int allocated;
  155         allocated = portlist->allocated + DNS_PL_ALLOCATE;
  156         el = isc_mem_get(portlist->mctx, sizeof(*el) * allocated);
  157         if (el == NULL) {
  158             result = ISC_R_NOMEMORY;
  159             goto unlock;
  160         }
  161         if (portlist->list != NULL) {
  162             memmove(el, portlist->list,
  163                 portlist->allocated * sizeof(*el));
  164             isc_mem_put(portlist->mctx, portlist->list,
  165                     portlist->allocated * sizeof(*el));
  166         }
  167         portlist->list = el;
  168         portlist->allocated = allocated;
  169     }
  170     portlist->list[portlist->active].port = port;
  171     if (af == AF_INET)
  172         portlist->list[portlist->active].flags = DNS_PL_INET;
  173     else
  174         portlist->list[portlist->active].flags = DNS_PL_INET6;
  175     portlist->active++;
  176     qsort(portlist->list, portlist->active, sizeof(*el), compare);
  177     result = ISC_R_SUCCESS;
  178  unlock:
  179     UNLOCK(&portlist->lock);
  180     return (result);
  181 }
  182 
  183 void
  184 dns_portlist_remove(dns_portlist_t *portlist, int af, in_port_t port) {
  185     dns_element_t *el;
  186 
  187     REQUIRE(DNS_VALID_PORTLIST(portlist));
  188     REQUIRE(af == AF_INET || af == AF_INET6);
  189 
  190     LOCK(&portlist->lock);
  191     if (portlist->active != 0) {
  192         el = find_port(portlist->list, portlist->active, port);
  193         if (el != NULL) {
  194             if (af == AF_INET)
  195                 el->flags &= ~DNS_PL_INET;
  196             else
  197                 el->flags &= ~DNS_PL_INET6;
  198             if (el->flags == 0) {
  199                 *el = portlist->list[portlist->active];
  200                 portlist->active--;
  201                 qsort(portlist->list, portlist->active,
  202                       sizeof(*el), compare);
  203             }
  204         }
  205     }
  206     UNLOCK(&portlist->lock);
  207 }
  208 
  209 bool
  210 dns_portlist_match(dns_portlist_t *portlist, int af, in_port_t port) {
  211     dns_element_t *el;
  212     bool result = false;
  213 
  214     REQUIRE(DNS_VALID_PORTLIST(portlist));
  215     REQUIRE(af == AF_INET || af == AF_INET6);
  216     LOCK(&portlist->lock);
  217     if (portlist->active != 0) {
  218         el = find_port(portlist->list, portlist->active, port);
  219         if (el != NULL) {
  220             if (af == AF_INET && (el->flags & DNS_PL_INET) != 0)
  221                 result = true;
  222             if (af == AF_INET6 && (el->flags & DNS_PL_INET6) != 0)
  223                 result = true;
  224         }
  225     }
  226     UNLOCK(&portlist->lock);
  227     return (result);
  228 }
  229 
  230 void
  231 dns_portlist_attach(dns_portlist_t *portlist, dns_portlist_t **portlistp) {
  232 
  233     REQUIRE(DNS_VALID_PORTLIST(portlist));
  234     REQUIRE(portlistp != NULL && *portlistp == NULL);
  235 
  236     isc_refcount_increment(&portlist->refcount, NULL);
  237     *portlistp = portlist;
  238 }
  239 
  240 void
  241 dns_portlist_detach(dns_portlist_t **portlistp) {
  242     dns_portlist_t *portlist;
  243     unsigned int count;
  244 
  245     REQUIRE(portlistp != NULL);
  246     portlist = *portlistp;
  247     REQUIRE(DNS_VALID_PORTLIST(portlist));
  248     *portlistp = NULL;
  249     isc_refcount_decrement(&portlist->refcount, &count);
  250     if (count == 0) {
  251         portlist->magic = 0;
  252         isc_refcount_destroy(&portlist->refcount);
  253         if (portlist->list != NULL)
  254             isc_mem_put(portlist->mctx, portlist->list,
  255                     portlist->allocated *
  256                     sizeof(*portlist->list));
  257         DESTROYLOCK(&portlist->lock);
  258         isc_mem_putanddetach(&portlist->mctx, portlist,
  259                      sizeof(*portlist));
  260     }
  261 }