Skip to content
ares_process.c 33.5 KiB
Newer Older
      struct server_state *server = &channel->servers[i];
      struct send_request *sendreq;
      for (sendreq = server->qhead; sendreq; sendreq = sendreq->next)
        if (sendreq->owner_query == query)
          {
            sendreq->owner_query = NULL;
            assert(sendreq->data_storage == NULL);
            if (status == ARES_SUCCESS)
              {
                /* We got a reply for this query, but this queued
                 * sendreq points into this soon-to-be-gone query's
                 * tcpbuf. Probably this means we timed out and queued
                 * the query for retransmission, then received a
                 * response before actually retransmitting. This is
                 * perfectly fine, so we want to keep the connection
                 * running smoothly if we can. But in the worst case
                 * we may have sent only some prefix of the query,
                 * with some suffix of the query left to send. Also,
                 * the buffer may be queued on multiple queues. To
                 * prevent dangling pointers to the query's tcpbuf and
                 * handle these cases, we just give such sendreqs
                 * their own copy of the query packet.
                 */
               sendreq->data_storage = malloc(sendreq->len);
               if (sendreq->data_storage != NULL)
                 {
                   memcpy(sendreq->data_storage, sendreq->data, sendreq->len);
                   sendreq->data = sendreq->data_storage;
                 }
              }
            if ((status != ARES_SUCCESS) || (sendreq->data_storage == NULL))
              {
                /* We encountered an error (probably a timeout,
                 * suggesting the DNS server we're talking to is
                 * probably unreachable, wedged, or severely
                 * overloaded) or we couldn't copy the request, so
                 * mark the connection as broken. When we get to
                 * process_broken_connections() we'll close the
                 * connection and try to re-send requests to another
                 * server.
                 */
               server->is_broken = 1;
               /* Just to be paranoid, zero out this sendreq... */
               sendreq->data = NULL;
               sendreq->len = 0;
             }
          }
    }

  /* Invoke the callback */
  query->callback(query->arg, status, query->timeouts, abuf, alen);

  /* Simple cleanup policy: if no queries are remaining, close all
   * network sockets unless STAYOPEN is set.
   */
  if (!(channel->flags & ARES_FLAG_STAYOPEN) &&
      ares__is_list_empty(&(channel->all_queries)))
    {
      for (i = 0; i < channel->nservers; i++)
        ares__close_sockets(channel, &channel->servers[i]);
}

void ares__free_query(struct query *query)
{
  /* Remove the query from all the lists in which it is linked */
  ares__remove_from_list(&(query->queries_by_qid));
  ares__remove_from_list(&(query->queries_by_timeout));
  ares__remove_from_list(&(query->queries_to_server));
  ares__remove_from_list(&(query->all_queries));
  /* Zero out some important stuff, to help catch bugs */
  query->callback = NULL;
  query->arg = NULL;
  /* Deallocate the memory associated with the query */
  free(query->tcpbuf);
  free(query->server_info);
  free(query);