• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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