b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews/*
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Copyright (C) 2003-2007, 2014, 2016 Internet Systems Consortium, Inc. ("ISC")
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews *
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * This Source Code Form is subject to the terms of the Mozilla Public
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * License, v. 2.0. If a copy of the MPL was not distributed with this
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * file, You can obtain one at http://mozilla.org/MPL/2.0/.
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews */
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
70e5a7403f0e0a3bd292b8287c5fed5772c15270Automatic Updater/* $Id: portlist.c,v 1.13 2007/06/19 23:47:16 tbox Exp $ */
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein/*! \file */
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
c7817270552b2faab56466b89731b6f290b352a4Mark Andrews#include <config.h>
c7817270552b2faab56466b89731b6f290b352a4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews#include <stdlib.h>
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews#include <isc/magic.h>
12040a4f5c29f430cc3e0ced6b912b8cf7f5d301Mark Andrews#include <isc/mem.h>
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews#include <isc/mutex.h>
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews#include <isc/net.h>
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews#include <isc/refcount.h>
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews#include <isc/result.h>
12040a4f5c29f430cc3e0ced6b912b8cf7f5d301Mark Andrews#include <isc/string.h>
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews#include <isc/types.h>
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews#include <isc/util.h>
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews#include <dns/types.h>
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews#include <dns/portlist.h>
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews#define DNS_PORTLIST_MAGIC ISC_MAGIC('P','L','S','T')
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews#define DNS_VALID_PORTLIST(p) ISC_MAGIC_VALID(p, DNS_PORTLIST_MAGIC)
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewstypedef struct dns_element {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews in_port_t port;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews isc_uint16_t flags;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews} dns_element_t;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsstruct dns_portlist {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews unsigned int magic;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews isc_mem_t *mctx;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews isc_refcount_t refcount;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews isc_mutex_t lock;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews dns_element_t *list;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews unsigned int allocated;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews unsigned int active;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews};
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews#define DNS_PL_INET 0x0001
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews#define DNS_PL_INET6 0x0002
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews#define DNS_PL_ALLOCATE 16
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsstatic int
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewscompare(const void *arg1, const void *arg2) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews const dns_element_t *e1 = (const dns_element_t *)arg1;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews const dns_element_t *e2 = (const dns_element_t *)arg2;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (e1->port < e2->port)
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews return (-1);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (e1->port > e2->port)
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews return (1);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews return (0);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews}
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsisc_result_t
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsdns_portlist_create(isc_mem_t *mctx, dns_portlist_t **portlistp) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews dns_portlist_t *portlist;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews isc_result_t result;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews REQUIRE(portlistp != NULL && *portlistp == NULL);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews portlist = isc_mem_get(mctx, sizeof(*portlist));
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (portlist == NULL)
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews return (ISC_R_NOMEMORY);
431a83fb29482c5170b3e4026e59bb14849a6707Tinderbox User result = isc_mutex_init(&portlist->lock);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (result != ISC_R_SUCCESS) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews isc_mem_put(mctx, portlist, sizeof(*portlist));
18d0b5e54be891a1aa938c165b6d439859121ec8Mark Andrews return (result);
18d0b5e54be891a1aa938c165b6d439859121ec8Mark Andrews }
18d0b5e54be891a1aa938c165b6d439859121ec8Mark Andrews result = isc_refcount_init(&portlist->refcount, 1);
18d0b5e54be891a1aa938c165b6d439859121ec8Mark Andrews if (result != ISC_R_SUCCESS) {
18d0b5e54be891a1aa938c165b6d439859121ec8Mark Andrews DESTROYLOCK(&portlist->lock);
18d0b5e54be891a1aa938c165b6d439859121ec8Mark Andrews isc_mem_put(mctx, portlist, sizeof(*portlist));
18d0b5e54be891a1aa938c165b6d439859121ec8Mark Andrews return (result);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews }
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews portlist->list = NULL;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews portlist->allocated = 0;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews portlist->active = 0;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews portlist->mctx = NULL;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews isc_mem_attach(mctx, &portlist->mctx);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews portlist->magic = DNS_PORTLIST_MAGIC;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews *portlistp = portlist;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews return (ISC_R_SUCCESS);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews}
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsstatic dns_element_t *
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsfind_port(dns_element_t *list, unsigned int len, in_port_t port) {
c480adf955c40816c50a0ca4a3b4683f8340825aMark Andrews unsigned int xtry = len / 2;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews unsigned int min = 0;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews unsigned int max = len - 1;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews unsigned int last = len;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
1676408640d8283c9f17eec0b183e1302ea7fd70Mark Andrews for (;;) {
c480adf955c40816c50a0ca4a3b4683f8340825aMark Andrews if (list[xtry].port == port)
c480adf955c40816c50a0ca4a3b4683f8340825aMark Andrews return (&list[xtry]);
431a83fb29482c5170b3e4026e59bb14849a6707Tinderbox User if (port > list[xtry].port) {
c480adf955c40816c50a0ca4a3b4683f8340825aMark Andrews if (xtry == max)
1676408640d8283c9f17eec0b183e1302ea7fd70Mark Andrews break;
c480adf955c40816c50a0ca4a3b4683f8340825aMark Andrews min = xtry;
c480adf955c40816c50a0ca4a3b4683f8340825aMark Andrews xtry = xtry + (max - xtry + 1) / 2;
c480adf955c40816c50a0ca4a3b4683f8340825aMark Andrews INSIST(xtry <= max);
c480adf955c40816c50a0ca4a3b4683f8340825aMark Andrews if (xtry == last)
1676408640d8283c9f17eec0b183e1302ea7fd70Mark Andrews break;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews last = min;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews } else {
c480adf955c40816c50a0ca4a3b4683f8340825aMark Andrews if (xtry == min)
1676408640d8283c9f17eec0b183e1302ea7fd70Mark Andrews break;
c480adf955c40816c50a0ca4a3b4683f8340825aMark Andrews max = xtry;
c480adf955c40816c50a0ca4a3b4683f8340825aMark Andrews xtry = xtry - (xtry - min + 1) / 2;
c480adf955c40816c50a0ca4a3b4683f8340825aMark Andrews INSIST(xtry >= min);
c480adf955c40816c50a0ca4a3b4683f8340825aMark Andrews if (xtry == last)
1676408640d8283c9f17eec0b183e1302ea7fd70Mark Andrews break;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews last = max;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews }
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews }
1676408640d8283c9f17eec0b183e1302ea7fd70Mark Andrews return (NULL);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews}
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsisc_result_t
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsdns_portlist_add(dns_portlist_t *portlist, int af, in_port_t port) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews dns_element_t *el;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews isc_result_t result;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews REQUIRE(DNS_VALID_PORTLIST(portlist));
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews REQUIRE(af == AF_INET || af == AF_INET6);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews LOCK(&portlist->lock);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (portlist->active != 0) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews el = find_port(portlist->list, portlist->active, port);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (el != NULL) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (af == AF_INET)
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews el->flags |= DNS_PL_INET;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews else
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews el->flags |= DNS_PL_INET6;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews result = ISC_R_SUCCESS;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews goto unlock;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews }
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews }
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (portlist->allocated <= portlist->active) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews unsigned int allocated;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews allocated = portlist->allocated + DNS_PL_ALLOCATE;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews el = isc_mem_get(portlist->mctx, sizeof(*el) * allocated);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (el == NULL) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews result = ISC_R_NOMEMORY;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews goto unlock;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews }
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (portlist->list != NULL) {
e851ea826066ac5a5b01c2c23218faa0273a12e8Evan Hunt memmove(el, portlist->list,
431a83fb29482c5170b3e4026e59bb14849a6707Tinderbox User portlist->allocated * sizeof(*el));
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews isc_mem_put(portlist->mctx, portlist->list,
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews portlist->allocated * sizeof(*el));
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews }
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews portlist->list = el;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews portlist->allocated = allocated;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews }
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews portlist->list[portlist->active].port = port;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (af == AF_INET)
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews portlist->list[portlist->active].flags = DNS_PL_INET;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews else
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews portlist->list[portlist->active].flags = DNS_PL_INET6;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews portlist->active++;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews qsort(portlist->list, portlist->active, sizeof(*el), compare);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews result = ISC_R_SUCCESS;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews unlock:
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews UNLOCK(&portlist->lock);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews return (result);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews}
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsvoid
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsdns_portlist_remove(dns_portlist_t *portlist, int af, in_port_t port) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews dns_element_t *el;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews REQUIRE(DNS_VALID_PORTLIST(portlist));
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews REQUIRE(af == AF_INET || af == AF_INET6);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews LOCK(&portlist->lock);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (portlist->active != 0) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews el = find_port(portlist->list, portlist->active, port);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (el != NULL) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (af == AF_INET)
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews el->flags &= ~DNS_PL_INET;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews else
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews el->flags &= ~DNS_PL_INET6;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (el->flags == 0) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews *el = portlist->list[portlist->active];
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews portlist->active--;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews qsort(portlist->list, portlist->active,
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews sizeof(*el), compare);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews }
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews }
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews }
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews UNLOCK(&portlist->lock);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews}
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsisc_boolean_t
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsdns_portlist_match(dns_portlist_t *portlist, int af, in_port_t port) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews dns_element_t *el;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews isc_boolean_t result = ISC_FALSE;
431a83fb29482c5170b3e4026e59bb14849a6707Tinderbox User
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews REQUIRE(DNS_VALID_PORTLIST(portlist));
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews REQUIRE(af == AF_INET || af == AF_INET6);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews LOCK(&portlist->lock);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (portlist->active != 0) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews el = find_port(portlist->list, portlist->active, port);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (el != NULL) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (af == AF_INET && (el->flags & DNS_PL_INET) != 0)
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews result = ISC_TRUE;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (af == AF_INET6 && (el->flags & DNS_PL_INET6) != 0)
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews result = ISC_TRUE;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews }
431a83fb29482c5170b3e4026e59bb14849a6707Tinderbox User }
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews UNLOCK(&portlist->lock);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews return (result);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews}
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsvoid
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsdns_portlist_attach(dns_portlist_t *portlist, dns_portlist_t **portlistp) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews REQUIRE(DNS_VALID_PORTLIST(portlist));
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews REQUIRE(portlistp != NULL && *portlistp == NULL);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews isc_refcount_increment(&portlist->refcount, NULL);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews *portlistp = portlist;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews}
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsvoid
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrewsdns_portlist_detach(dns_portlist_t **portlistp) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews dns_portlist_t *portlist;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews unsigned int count;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews REQUIRE(portlistp != NULL);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews portlist = *portlistp;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews REQUIRE(DNS_VALID_PORTLIST(portlist));
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews *portlistp = NULL;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews isc_refcount_decrement(&portlist->refcount, &count);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (count == 0) {
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews portlist->magic = 0;
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews isc_refcount_destroy(&portlist->refcount);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews if (portlist->list != NULL)
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews isc_mem_put(portlist->mctx, portlist->list,
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews portlist->allocated *
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews sizeof(*portlist->list));
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews DESTROYLOCK(&portlist->lock);
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews isc_mem_putanddetach(&portlist->mctx, portlist,
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews sizeof(*portlist));
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews }
b312748a11d27fe387984973ba79975a9d6863c4Mark Andrews}