11cb0ef41Sopenharmony_ci/* MIT License
21cb0ef41Sopenharmony_ci *
31cb0ef41Sopenharmony_ci * Copyright (c) 1998 Massachusetts Institute of Technology
41cb0ef41Sopenharmony_ci * Copyright (c) The c-ares project and its contributors
51cb0ef41Sopenharmony_ci *
61cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
71cb0ef41Sopenharmony_ci * of this software and associated documentation files (the "Software"), to deal
81cb0ef41Sopenharmony_ci * in the Software without restriction, including without limitation the rights
91cb0ef41Sopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
101cb0ef41Sopenharmony_ci * copies of the Software, and to permit persons to whom the Software is
111cb0ef41Sopenharmony_ci * furnished to do so, subject to the following conditions:
121cb0ef41Sopenharmony_ci *
131cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice (including the next
141cb0ef41Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
151cb0ef41Sopenharmony_ci * Software.
161cb0ef41Sopenharmony_ci *
171cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
181cb0ef41Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
191cb0ef41Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
201cb0ef41Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
211cb0ef41Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
221cb0ef41Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
231cb0ef41Sopenharmony_ci * SOFTWARE.
241cb0ef41Sopenharmony_ci *
251cb0ef41Sopenharmony_ci * SPDX-License-Identifier: MIT
261cb0ef41Sopenharmony_ci */
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci#include "ares_setup.h"
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci#ifdef HAVE_NETINET_IN_H
311cb0ef41Sopenharmony_ci#  include <netinet/in.h>
321cb0ef41Sopenharmony_ci#endif
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci#include "ares_nameser.h"
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ci#include "ares.h"
371cb0ef41Sopenharmony_ci#include "ares_dns.h"
381cb0ef41Sopenharmony_ci#include "ares_private.h"
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_cistatic unsigned short generate_unique_qid(ares_channel_t *channel)
411cb0ef41Sopenharmony_ci{
421cb0ef41Sopenharmony_ci  unsigned short id;
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci  do {
451cb0ef41Sopenharmony_ci    id = ares__generate_new_id(channel->rand_state);
461cb0ef41Sopenharmony_ci  } while (ares__htable_szvp_get(channel->queries_by_qid, id, NULL));
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci  return id;
491cb0ef41Sopenharmony_ci}
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ciares_status_t ares_send_ex(ares_channel_t *channel, const unsigned char *qbuf,
521cb0ef41Sopenharmony_ci                           size_t qlen, ares_callback callback, void *arg,
531cb0ef41Sopenharmony_ci                           unsigned short *qid)
541cb0ef41Sopenharmony_ci{
551cb0ef41Sopenharmony_ci  struct query  *query;
561cb0ef41Sopenharmony_ci  size_t         packetsz;
571cb0ef41Sopenharmony_ci  struct timeval now = ares__tvnow();
581cb0ef41Sopenharmony_ci  ares_status_t  status;
591cb0ef41Sopenharmony_ci  unsigned short id   = generate_unique_qid(channel);
601cb0ef41Sopenharmony_ci  unsigned char *abuf = NULL;
611cb0ef41Sopenharmony_ci  size_t         alen = 0;
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci  /* Verify that the query is at least long enough to hold the header. */
641cb0ef41Sopenharmony_ci  if (qlen < HFIXEDSZ || qlen >= (1 << 16)) {
651cb0ef41Sopenharmony_ci    callback(arg, ARES_EBADQUERY, 0, NULL, 0);
661cb0ef41Sopenharmony_ci    return ARES_EBADQUERY;
671cb0ef41Sopenharmony_ci  }
681cb0ef41Sopenharmony_ci  if (ares__slist_len(channel->servers) == 0) {
691cb0ef41Sopenharmony_ci    callback(arg, ARES_ENOSERVER, 0, NULL, 0);
701cb0ef41Sopenharmony_ci    return ARES_ENOSERVER;
711cb0ef41Sopenharmony_ci  }
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci  /* Check query cache */
741cb0ef41Sopenharmony_ci  status = ares_qcache_fetch(channel, &now, qbuf, qlen, &abuf, &alen);
751cb0ef41Sopenharmony_ci  if (status != ARES_ENOTFOUND) {
761cb0ef41Sopenharmony_ci    /* ARES_SUCCESS means we retrieved the cache, anything else is a critical
771cb0ef41Sopenharmony_ci     * failure, all result in termination */
781cb0ef41Sopenharmony_ci    callback(arg, (int)status, 0, abuf, (int)alen);
791cb0ef41Sopenharmony_ci    ares_free(abuf);
801cb0ef41Sopenharmony_ci    return status;
811cb0ef41Sopenharmony_ci  }
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci  /* Allocate space for query and allocated fields. */
841cb0ef41Sopenharmony_ci  query = ares_malloc(sizeof(struct query));
851cb0ef41Sopenharmony_ci  if (!query) {
861cb0ef41Sopenharmony_ci    callback(arg, ARES_ENOMEM, 0, NULL, 0);
871cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
881cb0ef41Sopenharmony_ci  }
891cb0ef41Sopenharmony_ci  memset(query, 0, sizeof(*query));
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ci  query->channel = channel;
921cb0ef41Sopenharmony_ci  query->qbuf    = ares_malloc(qlen);
931cb0ef41Sopenharmony_ci  if (!query->qbuf) {
941cb0ef41Sopenharmony_ci    ares_free(query);
951cb0ef41Sopenharmony_ci    callback(arg, ARES_ENOMEM, 0, NULL, 0);
961cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
971cb0ef41Sopenharmony_ci  }
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci  query->qid             = id;
1001cb0ef41Sopenharmony_ci  query->timeout.tv_sec  = 0;
1011cb0ef41Sopenharmony_ci  query->timeout.tv_usec = 0;
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci  /* Ignore first 2 bytes, assign our own query id */
1041cb0ef41Sopenharmony_ci  query->qbuf[0] = (unsigned char)((id >> 8) & 0xFF);
1051cb0ef41Sopenharmony_ci  query->qbuf[1] = (unsigned char)(id & 0xFF);
1061cb0ef41Sopenharmony_ci  memcpy(query->qbuf + 2, qbuf + 2, qlen - 2);
1071cb0ef41Sopenharmony_ci  query->qlen = qlen;
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci  /* Fill in query arguments. */
1101cb0ef41Sopenharmony_ci  query->callback = callback;
1111cb0ef41Sopenharmony_ci  query->arg      = arg;
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci  /* Initialize query status. */
1141cb0ef41Sopenharmony_ci  query->try_count = 0;
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_ci  packetsz = (channel->flags & ARES_FLAG_EDNS) ? channel->ednspsz : PACKETSZ;
1171cb0ef41Sopenharmony_ci  query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > packetsz;
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci  query->error_status = ARES_SUCCESS;
1201cb0ef41Sopenharmony_ci  query->timeouts     = 0;
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci  /* Initialize our list nodes. */
1231cb0ef41Sopenharmony_ci  query->node_queries_by_timeout = NULL;
1241cb0ef41Sopenharmony_ci  query->node_queries_to_conn    = NULL;
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci  /* Chain the query into the list of all queries. */
1271cb0ef41Sopenharmony_ci  query->node_all_queries =
1281cb0ef41Sopenharmony_ci    ares__llist_insert_last(channel->all_queries, query);
1291cb0ef41Sopenharmony_ci  if (query->node_all_queries == NULL) {
1301cb0ef41Sopenharmony_ci    callback(arg, ARES_ENOMEM, 0, NULL, 0);
1311cb0ef41Sopenharmony_ci    ares__free_query(query);
1321cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
1331cb0ef41Sopenharmony_ci  }
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci  /* Keep track of queries bucketed by qid, so we can process DNS
1361cb0ef41Sopenharmony_ci   * responses quickly.
1371cb0ef41Sopenharmony_ci   */
1381cb0ef41Sopenharmony_ci  if (!ares__htable_szvp_insert(channel->queries_by_qid, query->qid, query)) {
1391cb0ef41Sopenharmony_ci    callback(arg, ARES_ENOMEM, 0, NULL, 0);
1401cb0ef41Sopenharmony_ci    ares__free_query(query);
1411cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
1421cb0ef41Sopenharmony_ci  }
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci  /* Perform the first query action. */
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci  status = ares__send_query(query, &now);
1471cb0ef41Sopenharmony_ci  if (status == ARES_SUCCESS && qid) {
1481cb0ef41Sopenharmony_ci    *qid = id;
1491cb0ef41Sopenharmony_ci  }
1501cb0ef41Sopenharmony_ci  return status;
1511cb0ef41Sopenharmony_ci}
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_civoid ares_send(ares_channel_t *channel, const unsigned char *qbuf, int qlen,
1541cb0ef41Sopenharmony_ci               ares_callback callback, void *arg)
1551cb0ef41Sopenharmony_ci{
1561cb0ef41Sopenharmony_ci  if (channel == NULL) {
1571cb0ef41Sopenharmony_ci    return;
1581cb0ef41Sopenharmony_ci  }
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci  ares__channel_lock(channel);
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_ci  ares_send_ex(channel, qbuf, (size_t)qlen, callback, arg, NULL);
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci  ares__channel_unlock(channel);
1651cb0ef41Sopenharmony_ci}
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_cisize_t ares_queue_active_queries(ares_channel_t *channel)
1681cb0ef41Sopenharmony_ci{
1691cb0ef41Sopenharmony_ci  size_t len;
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_ci  if (channel == NULL) {
1721cb0ef41Sopenharmony_ci    return 0;
1731cb0ef41Sopenharmony_ci  }
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_ci  ares__channel_lock(channel);
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci  len = ares__llist_len(channel->all_queries);
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_ci  ares__channel_unlock(channel);
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci  return len;
1821cb0ef41Sopenharmony_ci}
183