"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.16.7/lib/dns/portlist.c" (4 Sep 2020, 5977 Bytes) of package /linux/misc/dns/bind9/9.16.7/bind-9.16.7.tar.xz:


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