1/* MIT License 2 * 3 * Copyright (c) 2023 Brad House 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy 6 * of this software and associated documentation files (the "Software"), to deal 7 * in the Software without restriction, including without limitation the rights 8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 * copies of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 * SPDX-License-Identifier: MIT 25 */ 26#include "ares_setup.h" 27#include "ares.h" 28#include "ares_private.h" 29#include "ares__htable.h" 30#include "ares__htable_asvp.h" 31 32struct ares__htable_asvp { 33 ares__htable_asvp_val_free_t free_val; 34 ares__htable_t *hash; 35}; 36 37typedef struct { 38 ares_socket_t key; 39 void *val; 40 ares__htable_asvp_t *parent; 41} ares__htable_asvp_bucket_t; 42 43void ares__htable_asvp_destroy(ares__htable_asvp_t *htable) 44{ 45 if (htable == NULL) { 46 return; 47 } 48 49 ares__htable_destroy(htable->hash); 50 ares_free(htable); 51} 52 53static unsigned int hash_func(const void *key, unsigned int seed) 54{ 55 const ares_socket_t *arg = key; 56 return ares__htable_hash_FNV1a((const unsigned char *)arg, sizeof(*arg), 57 seed); 58} 59 60static const void *bucket_key(const void *bucket) 61{ 62 const ares__htable_asvp_bucket_t *arg = bucket; 63 return &arg->key; 64} 65 66static void bucket_free(void *bucket) 67{ 68 ares__htable_asvp_bucket_t *arg = bucket; 69 70 if (arg->parent->free_val) { 71 arg->parent->free_val(arg->val); 72 } 73 74 ares_free(arg); 75} 76 77static ares_bool_t key_eq(const void *key1, const void *key2) 78{ 79 const ares_socket_t *k1 = key1; 80 const ares_socket_t *k2 = key2; 81 82 if (*k1 == *k2) { 83 return ARES_TRUE; 84 } 85 86 return ARES_FALSE; 87} 88 89ares__htable_asvp_t * 90 ares__htable_asvp_create(ares__htable_asvp_val_free_t val_free) 91{ 92 ares__htable_asvp_t *htable = ares_malloc(sizeof(*htable)); 93 if (htable == NULL) { 94 goto fail; 95 } 96 97 htable->hash = 98 ares__htable_create(hash_func, bucket_key, bucket_free, key_eq); 99 if (htable->hash == NULL) { 100 goto fail; 101 } 102 103 htable->free_val = val_free; 104 105 return htable; 106 107fail: 108 if (htable) { 109 ares__htable_destroy(htable->hash); 110 ares_free(htable); 111 } 112 return NULL; 113} 114 115ares_socket_t *ares__htable_asvp_keys(const ares__htable_asvp_t *htable, 116 size_t *num) 117{ 118 const void **buckets = NULL; 119 size_t cnt = 0; 120 ares_socket_t *out = NULL; 121 size_t i; 122 123 if (htable == NULL || num == NULL) { 124 return NULL; 125 } 126 127 *num = 0; 128 129 buckets = ares__htable_all_buckets(htable->hash, &cnt); 130 if (buckets == NULL || cnt == 0) { 131 return NULL; 132 } 133 134 out = ares_malloc_zero(sizeof(*out) * cnt); 135 if (out == NULL) { 136 ares_free(buckets); 137 return NULL; 138 } 139 140 for (i = 0; i < cnt; i++) { 141 out[i] = ((const ares__htable_asvp_bucket_t *)buckets[i])->key; 142 } 143 144 ares_free(buckets); 145 *num = cnt; 146 return out; 147} 148 149ares_bool_t ares__htable_asvp_insert(ares__htable_asvp_t *htable, 150 ares_socket_t key, void *val) 151{ 152 ares__htable_asvp_bucket_t *bucket = NULL; 153 154 if (htable == NULL) { 155 goto fail; 156 } 157 158 bucket = ares_malloc(sizeof(*bucket)); 159 if (bucket == NULL) { 160 goto fail; 161 } 162 163 bucket->parent = htable; 164 bucket->key = key; 165 bucket->val = val; 166 167 if (!ares__htable_insert(htable->hash, bucket)) { 168 goto fail; 169 } 170 171 return ARES_TRUE; 172 173fail: 174 if (bucket) { 175 ares_free(bucket); 176 } 177 return ARES_FALSE; 178} 179 180ares_bool_t ares__htable_asvp_get(const ares__htable_asvp_t *htable, 181 ares_socket_t key, void **val) 182{ 183 ares__htable_asvp_bucket_t *bucket = NULL; 184 185 if (val) { 186 *val = NULL; 187 } 188 189 if (htable == NULL) { 190 return ARES_FALSE; 191 } 192 193 bucket = ares__htable_get(htable->hash, &key); 194 if (bucket == NULL) { 195 return ARES_FALSE; 196 } 197 198 if (val) { 199 *val = bucket->val; 200 } 201 return ARES_TRUE; 202} 203 204void *ares__htable_asvp_get_direct(const ares__htable_asvp_t *htable, 205 ares_socket_t key) 206{ 207 void *val = NULL; 208 ares__htable_asvp_get(htable, key, &val); 209 return val; 210} 211 212ares_bool_t ares__htable_asvp_remove(ares__htable_asvp_t *htable, 213 ares_socket_t key) 214{ 215 if (htable == NULL) { 216 return ARES_FALSE; 217 } 218 219 return ares__htable_remove(htable->hash, &key); 220} 221 222size_t ares__htable_asvp_num_keys(const ares__htable_asvp_t *htable) 223{ 224 if (htable == NULL) { 225 return 0; 226 } 227 return ares__htable_num_keys(htable->hash); 228} 229