/src/c-ares/src/lib/ares_close_sockets.c
Line | Count | Source |
1 | | /* MIT License |
2 | | * |
3 | | * Copyright (c) 1998 Massachusetts Institute of Technology |
4 | | * Copyright (c) The c-ares project and its contributors |
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 <assert.h> |
30 | | |
31 | | static void ares_requeue_queries(ares_conn_t *conn, |
32 | | ares_status_t requeue_status) |
33 | 0 | { |
34 | 0 | ares_query_t *query; |
35 | 0 | ares_timeval_t now; |
36 | |
|
37 | 0 | ares_tvnow(&now); |
38 | |
|
39 | 0 | while ((query = ares_llist_first_val(conn->queries_to_conn)) != NULL) { |
40 | 0 | ares_requeue_query(query, &now, requeue_status, ARES_TRUE, NULL, NULL); |
41 | 0 | } |
42 | 0 | } |
43 | | |
44 | | void ares_close_connection(ares_conn_t *conn, ares_status_t requeue_status) |
45 | 0 | { |
46 | 0 | ares_server_t *server = conn->server; |
47 | 0 | ares_channel_t *channel = server->channel; |
48 | | |
49 | | /* Unlink */ |
50 | 0 | ares_llist_node_claim( |
51 | 0 | ares_htable_asvp_get_direct(channel->connnode_by_socket, conn->fd)); |
52 | 0 | ares_htable_asvp_remove(channel->connnode_by_socket, conn->fd); |
53 | |
|
54 | 0 | if (conn->flags & ARES_CONN_FLAG_TCP) { |
55 | 0 | server->tcp_conn = NULL; |
56 | 0 | } |
57 | |
|
58 | 0 | ares_buf_destroy(conn->in_buf); |
59 | 0 | ares_buf_destroy(conn->out_buf); |
60 | | |
61 | | /* Requeue queries to other connections */ |
62 | 0 | ares_requeue_queries(conn, requeue_status); |
63 | |
|
64 | 0 | ares_llist_destroy(conn->queries_to_conn); |
65 | |
|
66 | 0 | ares_conn_sock_state_cb_update(conn, ARES_CONN_STATE_NONE); |
67 | |
|
68 | 0 | ares_socket_close(channel, conn->fd); |
69 | |
|
70 | 0 | ares_free(conn); |
71 | 0 | } |
72 | | |
73 | | void ares_close_sockets(ares_server_t *server) |
74 | 26.3k | { |
75 | 26.3k | ares_llist_node_t *node; |
76 | | |
77 | 26.3k | while ((node = ares_llist_node_first(server->connections)) != NULL) { |
78 | 0 | ares_conn_t *conn = ares_llist_node_val(node); |
79 | 0 | ares_close_connection(conn, ARES_SUCCESS); |
80 | 0 | } |
81 | 26.3k | } |
82 | | |
83 | | void ares_check_cleanup_conns(const ares_channel_t *channel) |
84 | 0 | { |
85 | 0 | ares_slist_node_t *snode; |
86 | |
|
87 | 0 | if (channel == NULL) { |
88 | 0 | return; /* LCOV_EXCL_LINE: DefensiveCoding */ |
89 | 0 | } |
90 | | |
91 | | /* Iterate across each server */ |
92 | 0 | for (snode = ares_slist_node_first(channel->servers); snode != NULL; |
93 | 0 | snode = ares_slist_node_next(snode)) { |
94 | 0 | ares_server_t *server = ares_slist_node_val(snode); |
95 | 0 | ares_llist_node_t *cnode; |
96 | | |
97 | | /* Iterate across each connection */ |
98 | 0 | cnode = ares_llist_node_first(server->connections); |
99 | 0 | while (cnode != NULL) { |
100 | 0 | ares_llist_node_t *next = ares_llist_node_next(cnode); |
101 | 0 | ares_conn_t *conn = ares_llist_node_val(cnode); |
102 | 0 | ares_bool_t do_cleanup = ARES_FALSE; |
103 | 0 | cnode = next; |
104 | | |
105 | | /* Has connections, not eligible */ |
106 | 0 | if (ares_llist_len(conn->queries_to_conn)) { |
107 | 0 | continue; |
108 | 0 | } |
109 | | |
110 | | /* If we are configured not to stay open, close it out */ |
111 | 0 | if (!(channel->flags & ARES_FLAG_STAYOPEN)) { |
112 | 0 | do_cleanup = ARES_TRUE; |
113 | 0 | } |
114 | | |
115 | | /* If the connection has been retired for new queries, close it out once |
116 | | * idle. Resetting the connection (and specifically the source port |
117 | | * number) can help resolve situations where packets are being dropped. |
118 | | */ |
119 | 0 | if (conn->flags & ARES_CONN_FLAG_NONEW) { |
120 | 0 | do_cleanup = ARES_TRUE; |
121 | 0 | } |
122 | | |
123 | | /* If the udp connection hit its max queries, always close it */ |
124 | 0 | if (!(conn->flags & ARES_CONN_FLAG_TCP) && channel->udp_max_queries > 0 && |
125 | 0 | conn->total_queries >= channel->udp_max_queries) { |
126 | 0 | do_cleanup = ARES_TRUE; |
127 | 0 | } |
128 | |
|
129 | 0 | if (!do_cleanup) { |
130 | 0 | continue; |
131 | 0 | } |
132 | | |
133 | | /* Clean it up */ |
134 | 0 | ares_close_connection(conn, ARES_SUCCESS); |
135 | 0 | } |
136 | 0 | } |
137 | 0 | } |