ares_destroy.c (5069B)
1 /* MIT License 2 * 3 * Copyright (c) 1998 Massachusetts Institute of Technology 4 * Copyright (c) 2004 Daniel Stenberg 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 * 25 * SPDX-License-Identifier: MIT 26 */ 27 28 #include "ares_private.h" 29 #include "event/ares_event.h" 30 #include <assert.h> 31 32 void ares_destroy(ares_channel_t *channel) 33 { 34 size_t i; 35 ares_llist_node_t *node = NULL; 36 37 if (channel == NULL) { 38 return; 39 } 40 41 /* Mark as being shutdown */ 42 ares_channel_lock(channel); 43 channel->sys_up = ARES_FALSE; 44 ares_channel_unlock(channel); 45 46 /* Disable configuration change monitoring. We can't hold a lock because 47 * some cleanup routines, such as on Windows, are synchronous operations. 48 * What we've observed is a system config change event was triggered right 49 * at shutdown time and it tries to take the channel lock and the destruction 50 * waits for that event to complete before it continues so we get a channel 51 * lock deadlock at shutdown if we hold a lock during this process. */ 52 if (channel->optmask & ARES_OPT_EVENT_THREAD) { 53 ares_event_thread_t *e = channel->sock_state_cb_data; 54 if (e && e->configchg) { 55 ares_event_configchg_destroy(e->configchg); 56 e->configchg = NULL; 57 } 58 } 59 60 /* Wait for reinit thread to exit if there was one pending, can't be 61 * holding a lock as the thread may take locks. */ 62 if (channel->reinit_thread != NULL) { 63 void *rv; 64 ares_thread_join(channel->reinit_thread, &rv); 65 channel->reinit_thread = NULL; 66 } 67 68 /* Lock because callbacks will be triggered, and any system-generated 69 * callbacks need to hold a channel lock. */ 70 ares_channel_lock(channel); 71 72 /* Destroy all queries */ 73 node = ares_llist_node_first(channel->all_queries); 74 while (node != NULL) { 75 ares_llist_node_t *next = ares_llist_node_next(node); 76 ares_query_t *query = ares_llist_node_claim(node); 77 78 query->node_all_queries = NULL; 79 query->callback(query->arg, ARES_EDESTRUCTION, 0, NULL); 80 ares_free_query(query); 81 82 node = next; 83 } 84 85 ares_queue_notify_empty(channel); 86 87 #ifndef NDEBUG 88 /* Freeing the query should remove it from all the lists in which it sits, 89 * so all query lists should be empty now. 90 */ 91 assert(ares_llist_len(channel->all_queries) == 0); 92 assert(ares_htable_szvp_num_keys(channel->queries_by_qid) == 0); 93 assert(ares_slist_len(channel->queries_by_timeout) == 0); 94 #endif 95 96 ares_destroy_servers_state(channel); 97 98 #ifndef NDEBUG 99 assert(ares_htable_asvp_num_keys(channel->connnode_by_socket) == 0); 100 #endif 101 102 /* No more callbacks will be triggered after this point, unlock */ 103 ares_channel_unlock(channel); 104 105 /* Shut down the event thread */ 106 if (channel->optmask & ARES_OPT_EVENT_THREAD) { 107 ares_event_thread_destroy(channel); 108 } 109 110 if (channel->domains) { 111 for (i = 0; i < channel->ndomains; i++) { 112 ares_free(channel->domains[i]); 113 } 114 ares_free(channel->domains); 115 } 116 117 ares_llist_destroy(channel->all_queries); 118 ares_slist_destroy(channel->queries_by_timeout); 119 ares_htable_szvp_destroy(channel->queries_by_qid); 120 ares_htable_asvp_destroy(channel->connnode_by_socket); 121 122 ares_free(channel->sortlist); 123 ares_free(channel->lookups); 124 ares_free(channel->resolvconf_path); 125 ares_free(channel->hosts_path); 126 ares_destroy_rand_state(channel->rand_state); 127 128 ares_hosts_file_destroy(channel->hf); 129 130 ares_qcache_destroy(channel->qcache); 131 132 ares_channel_threading_destroy(channel); 133 134 ares_free(channel); 135 } 136 137 void ares_destroy_server(ares_server_t *server) 138 { 139 if (server == NULL) { 140 return; /* LCOV_EXCL_LINE: DefensiveCoding */ 141 } 142 143 ares_close_sockets(server); 144 ares_llist_destroy(server->connections); 145 ares_free(server); 146 } 147 148 void ares_destroy_servers_state(ares_channel_t *channel) 149 { 150 ares_slist_node_t *node; 151 152 while ((node = ares_slist_node_first(channel->servers)) != NULL) { 153 ares_server_t *server = ares_slist_node_claim(node); 154 ares_destroy_server(server); 155 } 156 157 ares_slist_destroy(channel->servers); 158 channel->servers = NULL; 159 }