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
ares_destroy(ares_channel_t * channel)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
ares_destroy_server(ares_server_t * server)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
ares_destroy_servers_state(ares_channel_t * channel)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 }
160