xref: /third_party/node/deps/cares/src/lib/ares_send.c (revision 1cb0ef41)
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_setup.h"
29
30#ifdef HAVE_NETINET_IN_H
31#  include <netinet/in.h>
32#endif
33
34#include "ares_nameser.h"
35
36#include "ares.h"
37#include "ares_dns.h"
38#include "ares_private.h"
39
40static unsigned short generate_unique_qid(ares_channel_t *channel)
41{
42  unsigned short id;
43
44  do {
45    id = ares__generate_new_id(channel->rand_state);
46  } while (ares__htable_szvp_get(channel->queries_by_qid, id, NULL));
47
48  return id;
49}
50
51ares_status_t ares_send_ex(ares_channel_t *channel, const unsigned char *qbuf,
52                           size_t qlen, ares_callback callback, void *arg,
53                           unsigned short *qid)
54{
55  struct query  *query;
56  size_t         packetsz;
57  struct timeval now = ares__tvnow();
58  ares_status_t  status;
59  unsigned short id   = generate_unique_qid(channel);
60  unsigned char *abuf = NULL;
61  size_t         alen = 0;
62
63  /* Verify that the query is at least long enough to hold the header. */
64  if (qlen < HFIXEDSZ || qlen >= (1 << 16)) {
65    callback(arg, ARES_EBADQUERY, 0, NULL, 0);
66    return ARES_EBADQUERY;
67  }
68  if (ares__slist_len(channel->servers) == 0) {
69    callback(arg, ARES_ENOSERVER, 0, NULL, 0);
70    return ARES_ENOSERVER;
71  }
72
73  /* Check query cache */
74  status = ares_qcache_fetch(channel, &now, qbuf, qlen, &abuf, &alen);
75  if (status != ARES_ENOTFOUND) {
76    /* ARES_SUCCESS means we retrieved the cache, anything else is a critical
77     * failure, all result in termination */
78    callback(arg, (int)status, 0, abuf, (int)alen);
79    ares_free(abuf);
80    return status;
81  }
82
83  /* Allocate space for query and allocated fields. */
84  query = ares_malloc(sizeof(struct query));
85  if (!query) {
86    callback(arg, ARES_ENOMEM, 0, NULL, 0);
87    return ARES_ENOMEM;
88  }
89  memset(query, 0, sizeof(*query));
90
91  query->channel = channel;
92  query->qbuf    = ares_malloc(qlen);
93  if (!query->qbuf) {
94    ares_free(query);
95    callback(arg, ARES_ENOMEM, 0, NULL, 0);
96    return ARES_ENOMEM;
97  }
98
99  query->qid             = id;
100  query->timeout.tv_sec  = 0;
101  query->timeout.tv_usec = 0;
102
103  /* Ignore first 2 bytes, assign our own query id */
104  query->qbuf[0] = (unsigned char)((id >> 8) & 0xFF);
105  query->qbuf[1] = (unsigned char)(id & 0xFF);
106  memcpy(query->qbuf + 2, qbuf + 2, qlen - 2);
107  query->qlen = qlen;
108
109  /* Fill in query arguments. */
110  query->callback = callback;
111  query->arg      = arg;
112
113  /* Initialize query status. */
114  query->try_count = 0;
115
116  packetsz = (channel->flags & ARES_FLAG_EDNS) ? channel->ednspsz : PACKETSZ;
117  query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > packetsz;
118
119  query->error_status = ARES_SUCCESS;
120  query->timeouts     = 0;
121
122  /* Initialize our list nodes. */
123  query->node_queries_by_timeout = NULL;
124  query->node_queries_to_conn    = NULL;
125
126  /* Chain the query into the list of all queries. */
127  query->node_all_queries =
128    ares__llist_insert_last(channel->all_queries, query);
129  if (query->node_all_queries == NULL) {
130    callback(arg, ARES_ENOMEM, 0, NULL, 0);
131    ares__free_query(query);
132    return ARES_ENOMEM;
133  }
134
135  /* Keep track of queries bucketed by qid, so we can process DNS
136   * responses quickly.
137   */
138  if (!ares__htable_szvp_insert(channel->queries_by_qid, query->qid, query)) {
139    callback(arg, ARES_ENOMEM, 0, NULL, 0);
140    ares__free_query(query);
141    return ARES_ENOMEM;
142  }
143
144  /* Perform the first query action. */
145
146  status = ares__send_query(query, &now);
147  if (status == ARES_SUCCESS && qid) {
148    *qid = id;
149  }
150  return status;
151}
152
153void ares_send(ares_channel_t *channel, const unsigned char *qbuf, int qlen,
154               ares_callback callback, void *arg)
155{
156  if (channel == NULL) {
157    return;
158  }
159
160  ares__channel_lock(channel);
161
162  ares_send_ex(channel, qbuf, (size_t)qlen, callback, arg, NULL);
163
164  ares__channel_unlock(channel);
165}
166
167size_t ares_queue_active_queries(ares_channel_t *channel)
168{
169  size_t len;
170
171  if (channel == NULL) {
172    return 0;
173  }
174
175  ares__channel_lock(channel);
176
177  len = ares__llist_len(channel->all_queries);
178
179  ares__channel_unlock(channel);
180
181  return len;
182}
183