Blame ares_process.c

Packit 514978
Packit 514978
/* Copyright 1998 by the Massachusetts Institute of Technology.
Packit 514978
 * Copyright (C) 2004-2017 by Daniel Stenberg
Packit 514978
 *
Packit 514978
 * Permission to use, copy, modify, and distribute this
Packit 514978
 * software and its documentation for any purpose and without
Packit 514978
 * fee is hereby granted, provided that the above copyright
Packit 514978
 * notice appear in all copies and that both that copyright
Packit 514978
 * notice and this permission notice appear in supporting
Packit 514978
 * documentation, and that the name of M.I.T. not be used in
Packit 514978
 * advertising or publicity pertaining to distribution of the
Packit 514978
 * software without specific, written prior permission.
Packit 514978
 * M.I.T. makes no representations about the suitability of
Packit 514978
 * this software for any purpose.  It is provided "as is"
Packit 514978
 * without express or implied warranty.
Packit 514978
 */
Packit 514978
Packit 514978
#include "ares_setup.h"
Packit 514978
Packit 514978
#ifdef HAVE_SYS_UIO_H
Packit 514978
#  include <sys/uio.h>
Packit 514978
#endif
Packit 514978
#ifdef HAVE_NETINET_IN_H
Packit 514978
#  include <netinet/in.h>
Packit 514978
#endif
Packit 514978
#ifdef HAVE_NETINET_TCP_H
Packit 514978
#  include <netinet/tcp.h>
Packit 514978
#endif
Packit 514978
#ifdef HAVE_NETDB_H
Packit 514978
#  include <netdb.h>
Packit 514978
#endif
Packit 514978
#ifdef HAVE_ARPA_INET_H
Packit 514978
#  include <arpa/inet.h>
Packit 514978
#endif
Packit 514978
#ifdef HAVE_ARPA_NAMESER_H
Packit 514978
#  include <arpa/nameser.h>
Packit 514978
#else
Packit 514978
#  include "nameser.h"
Packit 514978
#endif
Packit 514978
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
Packit 514978
#  include <arpa/nameser_compat.h>
Packit 514978
#endif
Packit 514978
Packit 514978
#ifdef HAVE_STRINGS_H
Packit 514978
#  include <strings.h>
Packit 514978
#endif
Packit 514978
#ifdef HAVE_SYS_IOCTL_H
Packit 514978
#  include <sys/ioctl.h>
Packit 514978
#endif
Packit 514978
#ifdef NETWARE
Packit 514978
#  include <sys/filio.h>
Packit 514978
#endif
Packit 514978
Packit 514978
#include <assert.h>
Packit 514978
#include <fcntl.h>
Packit 514978
Packit 514978
#include "ares.h"
Packit 514978
#include "ares_dns.h"
Packit 514978
#include "ares_nowarn.h"
Packit 514978
#include "ares_private.h"
Packit 514978
Packit 514978
Packit 514978
static int try_again(int errnum);
Packit 514978
static void write_tcp_data(ares_channel channel, fd_set *write_fds,
Packit 514978
                           ares_socket_t write_fd, struct timeval *now);
Packit 514978
static void read_tcp_data(ares_channel channel, fd_set *read_fds,
Packit 514978
                          ares_socket_t read_fd, struct timeval *now);
Packit 514978
static void read_udp_packets(ares_channel channel, fd_set *read_fds,
Packit 514978
                             ares_socket_t read_fd, struct timeval *now);
Packit 514978
static void advance_tcp_send_queue(ares_channel channel, int whichserver,
Packit 514978
                                   ares_ssize_t num_bytes);
Packit 514978
static void process_timeouts(ares_channel channel, struct timeval *now);
Packit 514978
static void process_broken_connections(ares_channel channel,
Packit 514978
                                       struct timeval *now);
Packit 514978
static void process_answer(ares_channel channel, unsigned char *abuf,
Packit 514978
                           int alen, int whichserver, int tcp,
Packit 514978
                           struct timeval *now);
Packit 514978
static void handle_error(ares_channel channel, int whichserver,
Packit 514978
                         struct timeval *now);
Packit 514978
static void skip_server(ares_channel channel, struct query *query,
Packit 514978
                        int whichserver);
Packit 514978
static void next_server(ares_channel channel, struct query *query,
Packit 514978
                        struct timeval *now);
Packit 514978
static int open_tcp_socket(ares_channel channel, struct server_state *server);
Packit 514978
static int open_udp_socket(ares_channel channel, struct server_state *server);
Packit 514978
static int same_questions(const unsigned char *qbuf, int qlen,
Packit 514978
                          const unsigned char *abuf, int alen);
Packit 514978
static int same_address(struct sockaddr *sa, struct ares_addr *aa);
Packit 514978
static void end_query(ares_channel channel, struct query *query, int status,
Packit 514978
                      unsigned char *abuf, int alen);
Packit 514978
Packit 514978
/* return true if now is exactly check time or later */
Packit 514978
int ares__timedout(struct timeval *now,
Packit 514978
                   struct timeval *check)
Packit 514978
{
Packit 514978
  long secs = (now->tv_sec - check->tv_sec);
Packit 514978
Packit 514978
  if(secs > 0)
Packit 514978
    return 1; /* yes, timed out */
Packit 514978
  if(secs < 0)
Packit 514978
    return 0; /* nope, not timed out */
Packit 514978
Packit 514978
  /* if the full seconds were identical, check the sub second parts */
Packit 514978
  return (now->tv_usec - check->tv_usec >= 0);
Packit 514978
}
Packit 514978
Packit 514978
/* add the specific number of milliseconds to the time in the first argument */
Packit 514978
static void timeadd(struct timeval *now, int millisecs)
Packit 514978
{
Packit 514978
  now->tv_sec += millisecs/1000;
Packit 514978
  now->tv_usec += (millisecs%1000)*1000;
Packit 514978
Packit 514978
  if(now->tv_usec >= 1000000) {
Packit 514978
    ++(now->tv_sec);
Packit 514978
    now->tv_usec -= 1000000;
Packit 514978
  }
Packit 514978
}
Packit 514978
Packit 514978
/*
Packit 514978
 * generic process function
Packit 514978
 */
Packit 514978
static void processfds(ares_channel channel,
Packit 514978
                       fd_set *read_fds, ares_socket_t read_fd,
Packit 514978
                       fd_set *write_fds, ares_socket_t write_fd)
Packit 514978
{
Packit 514978
  struct timeval now = ares__tvnow();
Packit 514978
Packit 514978
  write_tcp_data(channel, write_fds, write_fd, &now;;
Packit 514978
  read_tcp_data(channel, read_fds, read_fd, &now;;
Packit 514978
  read_udp_packets(channel, read_fds, read_fd, &now;;
Packit 514978
  process_timeouts(channel, &now;;
Packit 514978
  process_broken_connections(channel, &now;;
Packit 514978
}
Packit 514978
Packit 514978
/* Something interesting happened on the wire, or there was a timeout.
Packit 514978
 * See what's up and respond accordingly.
Packit 514978
 */
Packit 514978
void ares_process(ares_channel channel, fd_set *read_fds, fd_set *write_fds)
Packit 514978
{
Packit 514978
  processfds(channel, read_fds, ARES_SOCKET_BAD, write_fds, ARES_SOCKET_BAD);
Packit 514978
}
Packit 514978
Packit 514978
/* Something interesting happened on the wire, or there was a timeout.
Packit 514978
 * See what's up and respond accordingly.
Packit 514978
 */
Packit 514978
void ares_process_fd(ares_channel channel,
Packit 514978
                     ares_socket_t read_fd, /* use ARES_SOCKET_BAD or valid
Packit 514978
                                               file descriptors */
Packit 514978
                     ares_socket_t write_fd)
Packit 514978
{
Packit 514978
  processfds(channel, NULL, read_fd, NULL, write_fd);
Packit 514978
}
Packit 514978
Packit 514978
Packit 514978
/* Return 1 if the specified error number describes a readiness error, or 0
Packit 514978
 * otherwise. This is mostly for HP-UX, which could return EAGAIN or
Packit 514978
 * EWOULDBLOCK. See this man page
Packit 514978
 *
Packit 514978
 * http://devrsrc1.external.hp.com/STKS/cgi-bin/man2html?
Packit 514978
 *     manpage=/usr/share/man/man2.Z/send.2
Packit 514978
 */
Packit 514978
static int try_again(int errnum)
Packit 514978
{
Packit 514978
#if !defined EWOULDBLOCK && !defined EAGAIN
Packit 514978
#error "Neither EWOULDBLOCK nor EAGAIN defined"
Packit 514978
#endif
Packit 514978
  switch (errnum)
Packit 514978
    {
Packit 514978
#ifdef EWOULDBLOCK
Packit 514978
    case EWOULDBLOCK:
Packit 514978
      return 1;
Packit 514978
#endif
Packit 514978
#if defined EAGAIN && EAGAIN != EWOULDBLOCK
Packit 514978
    case EAGAIN:
Packit 514978
      return 1;
Packit 514978
#endif
Packit 514978
    }
Packit 514978
  return 0;
Packit 514978
}
Packit 514978
Packit 514978
static ares_ssize_t socket_writev(ares_channel channel, ares_socket_t s, const struct iovec * vec, int len)
Packit 514978
{
Packit 514978
  if (channel->sock_funcs)
Packit 514978
    return channel->sock_funcs->asendv(s, vec, len, channel->sock_func_cb_data);
Packit 514978
Packit 514978
  return writev(s, vec, len);
Packit 514978
}
Packit 514978
Packit 514978
static ares_ssize_t socket_write(ares_channel channel, ares_socket_t s, const void * data, size_t len)
Packit 514978
{
Packit 514978
  if (channel->sock_funcs)
Packit 514978
    {
Packit 514978
      struct iovec vec;
Packit 514978
      vec.iov_base = (void*)data;
Packit 514978
      vec.iov_len = len;
Packit 514978
      return channel->sock_funcs->asendv(s, &vec, 1, channel->sock_func_cb_data);
Packit 514978
    }
Packit 514978
  return swrite(s, data, len);
Packit 514978
}
Packit 514978
Packit 514978
/* If any TCP sockets select true for writing, write out queued data
Packit 514978
 * we have for them.
Packit 514978
 */
Packit 514978
static void write_tcp_data(ares_channel channel,
Packit 514978
                           fd_set *write_fds,
Packit 514978
                           ares_socket_t write_fd,
Packit 514978
                           struct timeval *now)
Packit 514978
{
Packit 514978
  struct server_state *server;
Packit 514978
  struct send_request *sendreq;
Packit 514978
  struct iovec *vec;
Packit 514978
  int i;
Packit 514978
  ares_ssize_t scount;
Packit 514978
  ares_ssize_t wcount;
Packit 514978
  size_t n;
Packit 514978
Packit 514978
  if(!write_fds && (write_fd == ARES_SOCKET_BAD))
Packit 514978
    /* no possible action */
Packit 514978
    return;
Packit 514978
Packit 514978
  for (i = 0; i < channel->nservers; i++)
Packit 514978
    {
Packit 514978
      /* Make sure server has data to send and is selected in write_fds or
Packit 514978
         write_fd. */
Packit 514978
      server = &channel->servers[i];
Packit 514978
      if (!server->qhead || server->tcp_socket == ARES_SOCKET_BAD ||
Packit 514978
          server->is_broken)
Packit 514978
        continue;
Packit 514978
Packit 514978
      if(write_fds) {
Packit 514978
        if(!FD_ISSET(server->tcp_socket, write_fds))
Packit 514978
          continue;
Packit 514978
      }
Packit 514978
      else {
Packit 514978
        if(server->tcp_socket != write_fd)
Packit 514978
          continue;
Packit 514978
      }
Packit 514978
Packit 514978
      if(write_fds)
Packit 514978
        /* If there's an error and we close this socket, then open
Packit 514978
         * another with the same fd to talk to another server, then we
Packit 514978
         * don't want to think that it was the new socket that was
Packit 514978
         * ready. This is not disastrous, but is likely to result in
Packit 514978
         * extra system calls and confusion. */
Packit 514978
        FD_CLR(server->tcp_socket, write_fds);
Packit 514978
Packit 514978
      /* Count the number of send queue items. */
Packit 514978
      n = 0;
Packit 514978
      for (sendreq = server->qhead; sendreq; sendreq = sendreq->next)
Packit 514978
        n++;
Packit 514978
Packit 514978
      /* Allocate iovecs so we can send all our data at once. */
Packit 514978
      vec = ares_malloc(n * sizeof(struct iovec));
Packit 514978
      if (vec)
Packit 514978
        {
Packit 514978
          /* Fill in the iovecs and send. */
Packit 514978
          n = 0;
Packit 514978
          for (sendreq = server->qhead; sendreq; sendreq = sendreq->next)
Packit 514978
            {
Packit 514978
              vec[n].iov_base = (char *) sendreq->data;
Packit 514978
              vec[n].iov_len = sendreq->len;
Packit 514978
              n++;
Packit 514978
            }
Packit 514978
          wcount = socket_writev(channel, server->tcp_socket, vec, (int)n);
Packit 514978
          ares_free(vec);
Packit 514978
          if (wcount < 0)
Packit 514978
            {
Packit 514978
              if (!try_again(SOCKERRNO))
Packit 514978
                handle_error(channel, i, now);
Packit 514978
              continue;
Packit 514978
            }
Packit 514978
Packit 514978
          /* Advance the send queue by as many bytes as we sent. */
Packit 514978
          advance_tcp_send_queue(channel, i, wcount);
Packit 514978
        }
Packit 514978
      else
Packit 514978
        {
Packit 514978
          /* Can't allocate iovecs; just send the first request. */
Packit 514978
          sendreq = server->qhead;
Packit 514978
Packit 514978
          scount = socket_write(channel, server->tcp_socket, sendreq->data, sendreq->len);
Packit 514978
          if (scount < 0)
Packit 514978
            {
Packit 514978
              if (!try_again(SOCKERRNO))
Packit 514978
                handle_error(channel, i, now);
Packit 514978
              continue;
Packit 514978
            }
Packit 514978
Packit 514978
          /* Advance the send queue by as many bytes as we sent. */
Packit 514978
          advance_tcp_send_queue(channel, i, scount);
Packit 514978
        }
Packit 514978
    }
Packit 514978
}
Packit 514978
Packit 514978
/* Consume the given number of bytes from the head of the TCP send queue. */
Packit 514978
static void advance_tcp_send_queue(ares_channel channel, int whichserver,
Packit 514978
                                   ares_ssize_t num_bytes)
Packit 514978
{
Packit 514978
  struct send_request *sendreq;
Packit 514978
  struct server_state *server = &channel->servers[whichserver];
Packit 514978
  while (num_bytes > 0) {
Packit 514978
    sendreq = server->qhead;
Packit 514978
    if ((size_t)num_bytes >= sendreq->len) {
Packit 514978
      num_bytes -= sendreq->len;
Packit 514978
      server->qhead = sendreq->next;
Packit 514978
      if (sendreq->data_storage)
Packit 514978
        ares_free(sendreq->data_storage);
Packit 514978
      ares_free(sendreq);
Packit 514978
      if (server->qhead == NULL) {
Packit 514978
        SOCK_STATE_CALLBACK(channel, server->tcp_socket, 1, 0);
Packit 514978
        server->qtail = NULL;
Packit 514978
Packit 514978
        /* qhead is NULL so we cannot continue this loop */
Packit 514978
        break;
Packit 514978
      }
Packit 514978
    }
Packit 514978
    else {
Packit 514978
      sendreq->data += num_bytes;
Packit 514978
      sendreq->len -= num_bytes;
Packit 514978
      num_bytes = 0;
Packit 514978
    }
Packit 514978
  }
Packit 514978
}
Packit 514978
Packit 514978
static ares_ssize_t socket_recvfrom(ares_channel channel,
Packit 514978
   ares_socket_t s,
Packit 514978
   void * data,
Packit 514978
   size_t data_len,
Packit 514978
   int flags,
Packit 514978
   struct sockaddr *from,
Packit 514978
   ares_socklen_t *from_len)
Packit 514978
{
Packit 514978
   if (channel->sock_funcs)
Packit 514978
      return channel->sock_funcs->arecvfrom(s, data, data_len,
Packit 514978
	 flags, from, from_len,
Packit 514978
	 channel->sock_func_cb_data);
Packit 514978
Packit 514978
#ifdef HAVE_RECVFROM
Packit 514978
   return recvfrom(s, data, data_len, flags, from, from_len);
Packit 514978
#else
Packit 514978
   return sread(s, data, data_len);
Packit 514978
#endif
Packit 514978
}
Packit 514978
Packit 514978
static ares_ssize_t socket_recv(ares_channel channel,
Packit 514978
   ares_socket_t s,
Packit 514978
   void * data,
Packit 514978
   size_t data_len)
Packit 514978
{
Packit 514978
   if (channel->sock_funcs)
Packit 514978
      return channel->sock_funcs->arecvfrom(s, data, data_len, 0, 0, 0,
Packit 514978
	 channel->sock_func_cb_data);
Packit 514978
Packit 514978
   return sread(s, data, data_len);
Packit 514978
}
Packit 514978
Packit 514978
/* If any TCP socket selects true for reading, read some data,
Packit 514978
 * allocate a buffer if we finish reading the length word, and process
Packit 514978
 * a packet if we finish reading one.
Packit 514978
 */
Packit 514978
static void read_tcp_data(ares_channel channel, fd_set *read_fds,
Packit 514978
                          ares_socket_t read_fd, struct timeval *now)
Packit 514978
{
Packit 514978
  struct server_state *server;
Packit 514978
  int i;
Packit 514978
  ares_ssize_t count;
Packit 514978
Packit 514978
  if(!read_fds && (read_fd == ARES_SOCKET_BAD))
Packit 514978
    /* no possible action */
Packit 514978
    return;
Packit 514978
Packit 514978
  for (i = 0; i < channel->nservers; i++)
Packit 514978
    {
Packit 514978
      /* Make sure the server has a socket and is selected in read_fds. */
Packit 514978
      server = &channel->servers[i];
Packit 514978
      if (server->tcp_socket == ARES_SOCKET_BAD || server->is_broken)
Packit 514978
        continue;
Packit 514978
Packit 514978
      if(read_fds) {
Packit 514978
        if(!FD_ISSET(server->tcp_socket, read_fds))
Packit 514978
          continue;
Packit 514978
      }
Packit 514978
      else {
Packit 514978
        if(server->tcp_socket != read_fd)
Packit 514978
          continue;
Packit 514978
      }
Packit 514978
Packit 514978
      if(read_fds)
Packit 514978
        /* If there's an error and we close this socket, then open another
Packit 514978
         * with the same fd to talk to another server, then we don't want to
Packit 514978
         * think that it was the new socket that was ready. This is not
Packit 514978
         * disastrous, but is likely to result in extra system calls and
Packit 514978
         * confusion. */
Packit 514978
        FD_CLR(server->tcp_socket, read_fds);
Packit 514978
Packit 514978
      if (server->tcp_lenbuf_pos != 2)
Packit 514978
        {
Packit 514978
          /* We haven't yet read a length word, so read that (or
Packit 514978
           * what's left to read of it).
Packit 514978
           */
Packit 514978
          count = socket_recv(channel, server->tcp_socket,
Packit 514978
			      server->tcp_lenbuf + server->tcp_lenbuf_pos,
Packit 514978
			      2 - server->tcp_lenbuf_pos);
Packit 514978
          if (count <= 0)
Packit 514978
            {
Packit 514978
              if (!(count == -1 && try_again(SOCKERRNO)))
Packit 514978
                handle_error(channel, i, now);
Packit 514978
              continue;
Packit 514978
            }
Packit 514978
Packit 514978
          server->tcp_lenbuf_pos += (int)count;
Packit 514978
          if (server->tcp_lenbuf_pos == 2)
Packit 514978
            {
Packit 514978
              /* We finished reading the length word.  Decode the
Packit 514978
               * length and allocate a buffer for the data.
Packit 514978
               */
Packit 514978
              server->tcp_length = server->tcp_lenbuf[0] << 8
Packit 514978
                | server->tcp_lenbuf[1];
Packit 514978
              server->tcp_buffer = ares_malloc(server->tcp_length);
Packit 514978
              if (!server->tcp_buffer) {
Packit 514978
                handle_error(channel, i, now);
Packit 514978
                return; /* bail out on malloc failure. TODO: make this
Packit 514978
                           function return error codes */
Packit 514978
              }
Packit 514978
              server->tcp_buffer_pos = 0;
Packit 514978
            }
Packit 514978
        }
Packit 514978
      else
Packit 514978
        {
Packit 514978
          /* Read data into the allocated buffer. */
Packit 514978
          count = socket_recv(channel, server->tcp_socket,
Packit 514978
			      server->tcp_buffer + server->tcp_buffer_pos,
Packit 514978
			      server->tcp_length - server->tcp_buffer_pos);
Packit 514978
          if (count <= 0)
Packit 514978
            {
Packit 514978
              if (!(count == -1 && try_again(SOCKERRNO)))
Packit 514978
                handle_error(channel, i, now);
Packit 514978
              continue;
Packit 514978
            }
Packit 514978
Packit 514978
          server->tcp_buffer_pos += (int)count;
Packit 514978
          if (server->tcp_buffer_pos == server->tcp_length)
Packit 514978
            {
Packit 514978
              /* We finished reading this answer; process it and
Packit 514978
               * prepare to read another length word.
Packit 514978
               */
Packit 514978
              process_answer(channel, server->tcp_buffer, server->tcp_length,
Packit 514978
                             i, 1, now);
Packit 514978
              ares_free(server->tcp_buffer);
Packit 514978
              server->tcp_buffer = NULL;
Packit 514978
              server->tcp_lenbuf_pos = 0;
Packit 514978
              server->tcp_buffer_pos = 0;
Packit 514978
            }
Packit 514978
        }
Packit 514978
    }
Packit 514978
}
Packit 514978
Packit 514978
/* If any UDP sockets select true for reading, process them. */
Packit 514978
static void read_udp_packets(ares_channel channel, fd_set *read_fds,
Packit 514978
                             ares_socket_t read_fd, struct timeval *now)
Packit 514978
{
Packit 514978
  struct server_state *server;
Packit 514978
  int i;
Packit 514978
  ares_ssize_t count;
Packit 514978
  unsigned char buf[MAXENDSSZ + 1];
Packit 514978
#ifdef HAVE_RECVFROM
Packit 514978
  ares_socklen_t fromlen;
Packit 514978
  union {
Packit 514978
    struct sockaddr     sa;
Packit 514978
    struct sockaddr_in  sa4;
Packit 514978
    struct sockaddr_in6 sa6;
Packit 514978
  } from;
Packit 514978
#endif
Packit 514978
Packit 514978
  if(!read_fds && (read_fd == ARES_SOCKET_BAD))
Packit 514978
    /* no possible action */
Packit 514978
    return;
Packit 514978
Packit 514978
  for (i = 0; i < channel->nservers; i++)
Packit 514978
    {
Packit 514978
      /* Make sure the server has a socket and is selected in read_fds. */
Packit 514978
      server = &channel->servers[i];
Packit 514978
Packit 514978
      if (server->udp_socket == ARES_SOCKET_BAD || server->is_broken)
Packit 514978
        continue;
Packit 514978
Packit 514978
      if(read_fds) {
Packit 514978
        if(!FD_ISSET(server->udp_socket, read_fds))
Packit 514978
          continue;
Packit 514978
      }
Packit 514978
      else {
Packit 514978
        if(server->udp_socket != read_fd)
Packit 514978
          continue;
Packit 514978
      }
Packit 514978
Packit 514978
      if(read_fds)
Packit 514978
        /* If there's an error and we close this socket, then open
Packit 514978
         * another with the same fd to talk to another server, then we
Packit 514978
         * don't want to think that it was the new socket that was
Packit 514978
         * ready. This is not disastrous, but is likely to result in
Packit 514978
         * extra system calls and confusion. */
Packit 514978
        FD_CLR(server->udp_socket, read_fds);
Packit 514978
Packit 514978
      /* To reduce event loop overhead, read and process as many
Packit 514978
       * packets as we can. */
Packit 514978
      do {
Packit 514978
        if (server->udp_socket == ARES_SOCKET_BAD)
Packit 514978
          count = 0;
Packit 514978
Packit 514978
        else {
Packit 514978
          if (server->addr.family == AF_INET)
Packit 514978
            fromlen = sizeof(from.sa4);
Packit 514978
          else
Packit 514978
            fromlen = sizeof(from.sa6);
Packit 514978
          count = socket_recvfrom(channel, server->udp_socket, (void *)buf,
Packit 514978
                                  sizeof(buf), 0, &from.sa, &fromlen);
Packit 514978
        }
Packit 514978
Packit 514978
        if (count == -1 && try_again(SOCKERRNO))
Packit 514978
          continue;
Packit 514978
        else if (count <= 0)
Packit 514978
          handle_error(channel, i, now);
Packit 514978
#ifdef HAVE_RECVFROM
Packit 514978
        else if (!same_address(&from.sa, &server->addr))
Packit 514978
          /* The address the response comes from does not match the address we
Packit 514978
           * sent the request to. Someone may be attempting to perform a cache
Packit 514978
           * poisoning attack. */
Packit 514978
          break;
Packit 514978
#endif
Packit 514978
        else
Packit 514978
          process_answer(channel, buf, (int)count, i, 0, now);
Packit 514978
       } while (count > 0);
Packit 514978
    }
Packit 514978
}
Packit 514978
Packit 514978
/* If any queries have timed out, note the timeout and move them on. */
Packit 514978
static void process_timeouts(ares_channel channel, struct timeval *now)
Packit 514978
{
Packit 514978
  time_t t;  /* the time of the timeouts we're processing */
Packit 514978
  struct query *query;
Packit 514978
  struct list_node* list_head;
Packit 514978
  struct list_node* list_node;
Packit 514978
Packit 514978
  /* Process all the timeouts that have fired since the last time we processed
Packit 514978
   * timeouts. If things are going well, then we'll have hundreds/thousands of
Packit 514978
   * queries that fall into future buckets, and only a handful of requests
Packit 514978
   * that fall into the "now" bucket, so this should be quite quick.
Packit 514978
   */
Packit 514978
  for (t = channel->last_timeout_processed; t <= now->tv_sec; t++)
Packit 514978
    {
Packit 514978
      list_head = &(channel->queries_by_timeout[t % ARES_TIMEOUT_TABLE_SIZE]);
Packit 514978
      for (list_node = list_head->next; list_node != list_head; )
Packit 514978
        {
Packit 514978
          query = list_node->data;
Packit 514978
          list_node = list_node->next;  /* in case the query gets deleted */
Packit 514978
          if (query->timeout.tv_sec && ares__timedout(now, &query->timeout))
Packit 514978
            {
Packit 514978
              query->error_status = ARES_ETIMEOUT;
Packit 514978
              ++query->timeouts;
Packit 514978
              next_server(channel, query, now);
Packit 514978
            }
Packit 514978
        }
Packit 514978
     }
Packit 514978
  channel->last_timeout_processed = now->tv_sec;
Packit 514978
}
Packit 514978
Packit 514978
/* Handle an answer from a server. */
Packit 514978
static void process_answer(ares_channel channel, unsigned char *abuf,
Packit 514978
                           int alen, int whichserver, int tcp,
Packit 514978
                           struct timeval *now)
Packit 514978
{
Packit 514978
  int tc, rcode, packetsz;
Packit 514978
  unsigned short id;
Packit 514978
  struct query *query;
Packit 514978
  struct list_node* list_head;
Packit 514978
  struct list_node* list_node;
Packit 514978
Packit 514978
  /* If there's no room in the answer for a header, we can't do much
Packit 514978
   * with it. */
Packit 514978
  if (alen < HFIXEDSZ)
Packit 514978
    return;
Packit 514978
Packit 514978
  /* Grab the query ID, truncate bit, and response code from the packet. */
Packit 514978
  id = DNS_HEADER_QID(abuf);
Packit 514978
  tc = DNS_HEADER_TC(abuf);
Packit 514978
  rcode = DNS_HEADER_RCODE(abuf);
Packit 514978
Packit 514978
  /* Find the query corresponding to this packet. The queries are
Packit 514978
   * hashed/bucketed by query id, so this lookup should be quick.  Note that
Packit 514978
   * both the query id and the questions must be the same; when the query id
Packit 514978
   * wraps around we can have multiple outstanding queries with the same query
Packit 514978
   * id, so we need to check both the id and question.
Packit 514978
   */
Packit 514978
  query = NULL;
Packit 514978
  list_head = &(channel->queries_by_qid[id % ARES_QID_TABLE_SIZE]);
Packit 514978
  for (list_node = list_head->next; list_node != list_head;
Packit 514978
       list_node = list_node->next)
Packit 514978
    {
Packit 514978
      struct query *q = list_node->data;
Packit 514978
      if ((q->qid == id) && same_questions(q->qbuf, q->qlen, abuf, alen))
Packit 514978
        {
Packit 514978
          query = q;
Packit 514978
          break;
Packit 514978
        }
Packit 514978
    }
Packit 514978
  if (!query)
Packit 514978
    return;
Packit 514978
Packit 514978
  packetsz = PACKETSZ;
Packit 514978
  /* If we use EDNS and server answers with one of these RCODES, the protocol
Packit 514978
   * extension is not understood by the responder. We must retry the query
Packit 514978
   * without EDNS enabled.
Packit 514978
   */
Packit 514978
  if (channel->flags & ARES_FLAG_EDNS)
Packit 514978
  {
Packit 514978
      packetsz = channel->ednspsz;
Packit 514978
      if (rcode == NOTIMP || rcode == FORMERR || rcode == SERVFAIL)
Packit 514978
      {
Packit 514978
          int qlen = (query->tcplen - 2) - EDNSFIXEDSZ;
Packit 514978
          channel->flags ^= ARES_FLAG_EDNS;
Packit 514978
          query->tcplen -= EDNSFIXEDSZ;
Packit 514978
          query->qlen -= EDNSFIXEDSZ;
Packit 514978
          query->tcpbuf[0] = (unsigned char)((qlen >> 8) & 0xff);
Packit 514978
          query->tcpbuf[1] = (unsigned char)(qlen & 0xff);
Packit 514978
          DNS_HEADER_SET_ARCOUNT(query->tcpbuf + 2, 0);
Packit 514978
          query->tcpbuf = ares_realloc(query->tcpbuf, query->tcplen);
Packit 514978
          query->qbuf = query->tcpbuf + 2;
Packit 514978
          ares__send_query(channel, query, now);
Packit 514978
          return;
Packit 514978
      }
Packit 514978
  }
Packit 514978
Packit 514978
  /* If we got a truncated UDP packet and are not ignoring truncation,
Packit 514978
   * don't accept the packet, and switch the query to TCP if we hadn't
Packit 514978
   * done so already.
Packit 514978
   */
Packit 514978
  if ((tc || alen > packetsz) && !tcp && !(channel->flags & ARES_FLAG_IGNTC))
Packit 514978
    {
Packit 514978
      if (!query->using_tcp)
Packit 514978
        {
Packit 514978
          query->using_tcp = 1;
Packit 514978
          ares__send_query(channel, query, now);
Packit 514978
        }
Packit 514978
      return;
Packit 514978
    }
Packit 514978
Packit 514978
  /* Limit alen to PACKETSZ if we aren't using TCP (only relevant if we
Packit 514978
   * are ignoring truncation.
Packit 514978
   */
Packit 514978
  if (alen > packetsz && !tcp)
Packit 514978
      alen = packetsz;
Packit 514978
Packit 514978
  /* If we aren't passing through all error packets, discard packets
Packit 514978
   * with SERVFAIL, NOTIMP, or REFUSED response codes.
Packit 514978
   */
Packit 514978
  if (!(channel->flags & ARES_FLAG_NOCHECKRESP))
Packit 514978
    {
Packit 514978
      if (rcode == SERVFAIL || rcode == NOTIMP || rcode == REFUSED)
Packit 514978
        {
Packit 514978
          skip_server(channel, query, whichserver);
Packit 514978
          if (query->server == whichserver)
Packit 514978
            next_server(channel, query, now);
Packit 514978
          return;
Packit 514978
        }
Packit 514978
    }
Packit 514978
Packit 514978
  end_query(channel, query, ARES_SUCCESS, abuf, alen);
Packit 514978
}
Packit 514978
Packit 514978
/* Close all the connections that are no longer usable. */
Packit 514978
static void process_broken_connections(ares_channel channel,
Packit 514978
                                       struct timeval *now)
Packit 514978
{
Packit 514978
  int i;
Packit 514978
  for (i = 0; i < channel->nservers; i++)
Packit 514978
    {
Packit 514978
      struct server_state *server = &channel->servers[i];
Packit 514978
      if (server->is_broken)
Packit 514978
        {
Packit 514978
          handle_error(channel, i, now);
Packit 514978
        }
Packit 514978
    }
Packit 514978
}
Packit 514978
Packit 514978
/* Swap the contents of two lists */
Packit 514978
static void swap_lists(struct list_node* head_a,
Packit 514978
                       struct list_node* head_b)
Packit 514978
{
Packit 514978
  int is_a_empty = ares__is_list_empty(head_a);
Packit 514978
  int is_b_empty = ares__is_list_empty(head_b);
Packit 514978
  struct list_node old_a = *head_a;
Packit 514978
  struct list_node old_b = *head_b;
Packit 514978
Packit 514978
  if (is_a_empty) {
Packit 514978
    ares__init_list_head(head_b);
Packit 514978
  } else {
Packit 514978
    *head_b = old_a;
Packit 514978
    old_a.next->prev = head_b;
Packit 514978
    old_a.prev->next = head_b;
Packit 514978
  }
Packit 514978
  if (is_b_empty) {
Packit 514978
    ares__init_list_head(head_a);
Packit 514978
  } else {
Packit 514978
    *head_a = old_b;
Packit 514978
    old_b.next->prev = head_a;
Packit 514978
    old_b.prev->next = head_a;
Packit 514978
  }
Packit 514978
}
Packit 514978
Packit 514978
static void handle_error(ares_channel channel, int whichserver,
Packit 514978
                         struct timeval *now)
Packit 514978
{
Packit 514978
  struct server_state *server;
Packit 514978
  struct query *query;
Packit 514978
  struct list_node list_head;
Packit 514978
  struct list_node* list_node;
Packit 514978
Packit 514978
  server = &channel->servers[whichserver];
Packit 514978
Packit 514978
  /* Reset communications with this server. */
Packit 514978
  ares__close_sockets(channel, server);
Packit 514978
Packit 514978
  /* Tell all queries talking to this server to move on and not try this
Packit 514978
   * server again. We steal the current list of queries that were in-flight to
Packit 514978
   * this server, since when we call next_server this can cause the queries to
Packit 514978
   * be re-sent to this server, which will re-insert these queries in that
Packit 514978
   * same server->queries_to_server list.
Packit 514978
   */
Packit 514978
  ares__init_list_head(&list_head);
Packit 514978
  swap_lists(&list_head, &(server->queries_to_server));
Packit 514978
  for (list_node = list_head.next; list_node != &list_head; )
Packit 514978
    {
Packit 514978
      query = list_node->data;
Packit 514978
      list_node = list_node->next;  /* in case the query gets deleted */
Packit 514978
      assert(query->server == whichserver);
Packit 514978
      skip_server(channel, query, whichserver);
Packit 514978
      next_server(channel, query, now);
Packit 514978
    }
Packit 514978
  /* Each query should have removed itself from our temporary list as
Packit 514978
   * it re-sent itself or finished up...
Packit 514978
   */
Packit 514978
  assert(ares__is_list_empty(&list_head));
Packit 514978
}
Packit 514978
Packit 514978
static void skip_server(ares_channel channel, struct query *query,
Packit 514978
                        int whichserver)
Packit 514978
{
Packit 514978
  /* The given server gave us problems with this query, so if we have the
Packit 514978
   * luxury of using other servers, then let's skip the potentially broken
Packit 514978
   * server and just use the others. If we only have one server and we need to
Packit 514978
   * retry then we should just go ahead and re-use that server, since it's our
Packit 514978
   * only hope; perhaps we just got unlucky, and retrying will work (eg, the
Packit 514978
   * server timed out our TCP connection just as we were sending another
Packit 514978
   * request).
Packit 514978
   */
Packit 514978
  if (channel->nservers > 1)
Packit 514978
    {
Packit 514978
      query->server_info[whichserver].skip_server = 1;
Packit 514978
    }
Packit 514978
}
Packit 514978
Packit 514978
static void next_server(ares_channel channel, struct query *query,
Packit 514978
                        struct timeval *now)
Packit 514978
{
Packit 514978
  /* We need to try each server channel->tries times. We have channel->nservers
Packit 514978
   * servers to try. In total, we need to do channel->nservers * channel->tries
Packit 514978
   * attempts. Use query->try to remember how many times we already attempted
Packit 514978
   * this query. Use modular arithmetic to find the next server to try. */
Packit 514978
  while (++(query->try_count) < (channel->nservers * channel->tries))
Packit 514978
    {
Packit 514978
      struct server_state *server;
Packit 514978
Packit 514978
      /* Move on to the next server. */
Packit 514978
      query->server = (query->server + 1) % channel->nservers;
Packit 514978
      server = &channel->servers[query->server];
Packit 514978
Packit 514978
      /* We don't want to use this server if (1) we decided this connection is
Packit 514978
       * broken, and thus about to be closed, (2) we've decided to skip this
Packit 514978
       * server because of earlier errors we encountered, or (3) we already
Packit 514978
       * sent this query over this exact connection.
Packit 514978
       */
Packit 514978
      if (!server->is_broken &&
Packit 514978
           !query->server_info[query->server].skip_server &&
Packit 514978
           !(query->using_tcp &&
Packit 514978
             (query->server_info[query->server].tcp_connection_generation ==
Packit 514978
              server->tcp_connection_generation)))
Packit 514978
        {
Packit 514978
           ares__send_query(channel, query, now);
Packit 514978
           return;
Packit 514978
        }
Packit 514978
Packit 514978
      /* You might think that with TCP we only need one try. However, even
Packit 514978
       * when using TCP, servers can time-out our connection just as we're
Packit 514978
       * sending a request, or close our connection because they die, or never
Packit 514978
       * send us a reply because they get wedged or tickle a bug that drops
Packit 514978
       * our request.
Packit 514978
       */
Packit 514978
    }
Packit 514978
Packit 514978
  /* If we are here, all attempts to perform query failed. */
Packit 514978
  end_query(channel, query, query->error_status, NULL, 0);
Packit 514978
}
Packit 514978
Packit 514978
void ares__send_query(ares_channel channel, struct query *query,
Packit 514978
                      struct timeval *now)
Packit 514978
{
Packit 514978
  struct send_request *sendreq;
Packit 514978
  struct server_state *server;
Packit 514978
  int timeplus;
Packit 514978
Packit 514978
  server = &channel->servers[query->server];
Packit 514978
  if (query->using_tcp)
Packit 514978
    {
Packit 514978
      /* Make sure the TCP socket for this server is set up and queue
Packit 514978
       * a send request.
Packit 514978
       */
Packit 514978
      if (server->tcp_socket == ARES_SOCKET_BAD)
Packit 514978
        {
Packit 514978
          if (open_tcp_socket(channel, server) == -1)
Packit 514978
            {
Packit 514978
              skip_server(channel, query, query->server);
Packit 514978
              next_server(channel, query, now);
Packit 514978
              return;
Packit 514978
            }
Packit 514978
        }
Packit 514978
      sendreq = ares_malloc(sizeof(struct send_request));
Packit 514978
      if (!sendreq)
Packit 514978
        {
Packit 514978
        end_query(channel, query, ARES_ENOMEM, NULL, 0);
Packit 514978
          return;
Packit 514978
        }
Packit 514978
      memset(sendreq, 0, sizeof(struct send_request));
Packit 514978
      /* To make the common case fast, we avoid copies by using the query's
Packit 514978
       * tcpbuf for as long as the query is alive. In the rare case where the
Packit 514978
       * query ends while it's queued for transmission, then we give the
Packit 514978
       * sendreq its own copy of the request packet and put it in
Packit 514978
       * sendreq->data_storage.
Packit 514978
       */
Packit 514978
      sendreq->data_storage = NULL;
Packit 514978
      sendreq->data = query->tcpbuf;
Packit 514978
      sendreq->len = query->tcplen;
Packit 514978
      sendreq->owner_query = query;
Packit 514978
      sendreq->next = NULL;
Packit 514978
      if (server->qtail)
Packit 514978
        server->qtail->next = sendreq;
Packit 514978
      else
Packit 514978
        {
Packit 514978
          SOCK_STATE_CALLBACK(channel, server->tcp_socket, 1, 1);
Packit 514978
          server->qhead = sendreq;
Packit 514978
        }
Packit 514978
      server->qtail = sendreq;
Packit 514978
      query->server_info[query->server].tcp_connection_generation =
Packit 514978
        server->tcp_connection_generation;
Packit 514978
    }
Packit 514978
  else
Packit 514978
    {
Packit 514978
      if (server->udp_socket == ARES_SOCKET_BAD)
Packit 514978
        {
Packit 514978
          if (open_udp_socket(channel, server) == -1)
Packit 514978
            {
Packit 514978
              skip_server(channel, query, query->server);
Packit 514978
              next_server(channel, query, now);
Packit 514978
              return;
Packit 514978
            }
Packit 514978
        }
Packit 514978
      if (socket_write(channel, server->udp_socket, query->qbuf, query->qlen) == -1)
Packit 514978
        {
Packit 514978
          /* FIXME: Handle EAGAIN here since it likely can happen. */
Packit 514978
          skip_server(channel, query, query->server);
Packit 514978
          next_server(channel, query, now);
Packit 514978
          return;
Packit 514978
        }
Packit 514978
    }
Packit 514978
    timeplus = channel->timeout << (query->try_count / channel->nservers);
Packit 514978
    timeplus = (timeplus * (9 + (rand () & 7))) / 16;
Packit 514978
    query->timeout = *now;
Packit 514978
    timeadd(&query->timeout, timeplus);
Packit 514978
    /* Keep track of queries bucketed by timeout, so we can process
Packit 514978
     * timeout events quickly.
Packit 514978
     */
Packit 514978
    ares__remove_from_list(&(query->queries_by_timeout));
Packit 514978
    ares__insert_in_list(
Packit 514978
        &(query->queries_by_timeout),
Packit 514978
        &(channel->queries_by_timeout[query->timeout.tv_sec %
Packit 514978
                                      ARES_TIMEOUT_TABLE_SIZE]));
Packit 514978
Packit 514978
    /* Keep track of queries bucketed by server, so we can process server
Packit 514978
     * errors quickly.
Packit 514978
     */
Packit 514978
    ares__remove_from_list(&(query->queries_to_server));
Packit 514978
    ares__insert_in_list(&(query->queries_to_server),
Packit 514978
                         &(server->queries_to_server));
Packit 514978
}
Packit 514978
Packit 514978
/*
Packit 514978
 * setsocknonblock sets the given socket to either blocking or non-blocking
Packit 514978
 * mode based on the 'nonblock' boolean argument. This function is highly
Packit 514978
 * portable.
Packit 514978
 */
Packit 514978
static int setsocknonblock(ares_socket_t sockfd,    /* operate on this */
Packit 514978
                           int nonblock   /* TRUE or FALSE */)
Packit 514978
{
Packit 514978
#if defined(USE_BLOCKING_SOCKETS)
Packit 514978
Packit 514978
  return 0; /* returns success */
Packit 514978
Packit 514978
#elif defined(HAVE_FCNTL_O_NONBLOCK)
Packit 514978
Packit 514978
  /* most recent unix versions */
Packit 514978
  int flags;
Packit 514978
  flags = fcntl(sockfd, F_GETFL, 0);
Packit 514978
  if (FALSE != nonblock)
Packit 514978
    return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
Packit 514978
  else
Packit 514978
    return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));  /* LCOV_EXCL_LINE */
Packit 514978
Packit 514978
#elif defined(HAVE_IOCTL_FIONBIO)
Packit 514978
Packit 514978
  /* older unix versions */
Packit 514978
  int flags = nonblock ? 1 : 0;
Packit 514978
  return ioctl(sockfd, FIONBIO, &flags);
Packit 514978
Packit 514978
#elif defined(HAVE_IOCTLSOCKET_FIONBIO)
Packit 514978
Packit 514978
#ifdef WATT32
Packit 514978
  char flags = nonblock ? 1 : 0;
Packit 514978
#else
Packit 514978
  /* Windows */
Packit 514978
  unsigned long flags = nonblock ? 1UL : 0UL;
Packit 514978
#endif
Packit 514978
  return ioctlsocket(sockfd, FIONBIO, &flags);
Packit 514978
Packit 514978
#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO)
Packit 514978
Packit 514978
  /* Amiga */
Packit 514978
  long flags = nonblock ? 1L : 0L;
Packit 514978
  return IoctlSocket(sockfd, FIONBIO, flags);
Packit 514978
Packit 514978
#elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK)
Packit 514978
Packit 514978
  /* BeOS */
Packit 514978
  long b = nonblock ? 1L : 0L;
Packit 514978
  return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
Packit 514978
Packit 514978
#else
Packit 514978
#  error "no non-blocking method was found/used/set"
Packit 514978
#endif
Packit 514978
}
Packit 514978
Packit 514978
static int configure_socket(ares_socket_t s, int family, ares_channel channel)
Packit 514978
{
Packit 514978
  union {
Packit 514978
    struct sockaddr     sa;
Packit 514978
    struct sockaddr_in  sa4;
Packit 514978
    struct sockaddr_in6 sa6;
Packit 514978
  } local;
Packit 514978
Packit 514978
  /* do not set options for user-managed sockets */
Packit 514978
  if (channel->sock_funcs)
Packit 514978
    return 0;
Packit 514978
Packit 514978
  (void)setsocknonblock(s, TRUE);
Packit 514978
Packit 514978
#if defined(FD_CLOEXEC) && !defined(MSDOS)
Packit 514978
  /* Configure the socket fd as close-on-exec. */
Packit 514978
  if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1)
Packit 514978
    return -1;  /* LCOV_EXCL_LINE */
Packit 514978
#endif
Packit 514978
Packit 514978
  /* Set the socket's send and receive buffer sizes. */
Packit 514978
  if ((channel->socket_send_buffer_size > 0) &&
Packit 514978
      setsockopt(s, SOL_SOCKET, SO_SNDBUF,
Packit 514978
                 (void *)&channel->socket_send_buffer_size,
Packit 514978
                 sizeof(channel->socket_send_buffer_size)) == -1)
Packit 514978
    return -1;
Packit 514978
Packit 514978
  if ((channel->socket_receive_buffer_size > 0) &&
Packit 514978
      setsockopt(s, SOL_SOCKET, SO_RCVBUF,
Packit 514978
                 (void *)&channel->socket_receive_buffer_size,
Packit 514978
                 sizeof(channel->socket_receive_buffer_size)) == -1)
Packit 514978
    return -1;
Packit 514978
Packit 514978
#ifdef SO_BINDTODEVICE
Packit 514978
  if (channel->local_dev_name[0]) {
Packit 514978
    if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
Packit 514978
                   channel->local_dev_name, sizeof(channel->local_dev_name))) {
Packit 514978
      /* Only root can do this, and usually not fatal if it doesn't work, so */
Packit 514978
      /* just continue on. */
Packit 514978
    }
Packit 514978
  }
Packit 514978
#endif
Packit 514978
Packit 514978
  if (family == AF_INET) {
Packit 514978
    if (channel->local_ip4) {
Packit 514978
      memset(&local.sa4, 0, sizeof(local.sa4));
Packit 514978
      local.sa4.sin_family = AF_INET;
Packit 514978
      local.sa4.sin_addr.s_addr = htonl(channel->local_ip4);
Packit 514978
      if (bind(s, &local.sa, sizeof(local.sa4)) < 0)
Packit 514978
        return -1;
Packit 514978
    }
Packit 514978
  }
Packit 514978
  else if (family == AF_INET6) {
Packit 514978
    if (memcmp(channel->local_ip6, &ares_in6addr_any,
Packit 514978
               sizeof(channel->local_ip6)) != 0) {
Packit 514978
      memset(&local.sa6, 0, sizeof(local.sa6));
Packit 514978
      local.sa6.sin6_family = AF_INET6;
Packit 514978
      memcpy(&local.sa6.sin6_addr, channel->local_ip6,
Packit 514978
             sizeof(channel->local_ip6));
Packit 514978
      if (bind(s, &local.sa, sizeof(local.sa6)) < 0)
Packit 514978
        return -1;
Packit 514978
    }
Packit 514978
  }
Packit 514978
Packit 514978
  return 0;
Packit 514978
}
Packit 514978
Packit 514978
static ares_socket_t open_socket(ares_channel channel, int af, int type, int protocol)
Packit 514978
{
Packit 514978
  if (channel->sock_funcs != 0)
Packit 514978
    return channel->sock_funcs->asocket(af,
Packit 514978
                                        type,
Packit 514978
                                        protocol,
Packit 514978
                                        channel->sock_func_cb_data);
Packit 514978
Packit 514978
  return socket(af, type, protocol);
Packit 514978
}
Packit 514978
Packit 514978
static int connect_socket(ares_channel channel, ares_socket_t sockfd,
Packit 514978
			  const struct sockaddr * addr,
Packit 514978
	                  ares_socklen_t addrlen)
Packit 514978
{
Packit 514978
   if (channel->sock_funcs != 0)
Packit 514978
      return channel->sock_funcs->aconnect(sockfd,
Packit 514978
	                                   addr,
Packit 514978
	                                   addrlen,
Packit 514978
	                                   channel->sock_func_cb_data);
Packit 514978
Packit 514978
   return connect(sockfd, addr, addrlen);
Packit 514978
}
Packit 514978
Packit 514978
static int open_tcp_socket(ares_channel channel, struct server_state *server)
Packit 514978
{
Packit 514978
  ares_socket_t s;
Packit 514978
  int opt;
Packit 514978
  ares_socklen_t salen;
Packit 514978
  union {
Packit 514978
    struct sockaddr_in  sa4;
Packit 514978
    struct sockaddr_in6 sa6;
Packit 514978
  } saddr;
Packit 514978
  struct sockaddr *sa;
Packit 514978
Packit 514978
  switch (server->addr.family)
Packit 514978
    {
Packit 514978
      case AF_INET:
Packit 514978
        sa = (void *)&saddr.sa4;
Packit 514978
        salen = sizeof(saddr.sa4);
Packit 514978
        memset(sa, 0, salen);
Packit 514978
        saddr.sa4.sin_family = AF_INET;
Packit 514978
        if (server->addr.tcp_port) {
Packit 514978
          saddr.sa4.sin_port = aresx_sitous(server->addr.tcp_port);
Packit 514978
        } else {
Packit 514978
          saddr.sa4.sin_port = aresx_sitous(channel->tcp_port);
Packit 514978
        }
Packit 514978
        memcpy(&saddr.sa4.sin_addr, &server->addr.addrV4,
Packit 514978
               sizeof(server->addr.addrV4));
Packit 514978
        break;
Packit 514978
      case AF_INET6:
Packit 514978
        sa = (void *)&saddr.sa6;
Packit 514978
        salen = sizeof(saddr.sa6);
Packit 514978
        memset(sa, 0, salen);
Packit 514978
        saddr.sa6.sin6_family = AF_INET6;
Packit 514978
        if (server->addr.tcp_port) {
Packit 514978
          saddr.sa6.sin6_port = aresx_sitous(server->addr.tcp_port);
Packit 514978
        } else {
Packit 514978
          saddr.sa6.sin6_port = aresx_sitous(channel->tcp_port);
Packit 514978
        }
Packit 514978
        memcpy(&saddr.sa6.sin6_addr, &server->addr.addrV6,
Packit 514978
               sizeof(server->addr.addrV6));
Packit 514978
        break;
Packit 514978
      default:
Packit 514978
        return -1;  /* LCOV_EXCL_LINE */
Packit 514978
    }
Packit 514978
Packit 514978
  /* Acquire a socket. */
Packit 514978
  s = open_socket(channel, server->addr.family, SOCK_STREAM, 0);
Packit 514978
  if (s == ARES_SOCKET_BAD)
Packit 514978
    return -1;
Packit 514978
Packit 514978
  /* Configure it. */
Packit 514978
  if (configure_socket(s, server->addr.family, channel) < 0)
Packit 514978
    {
Packit 514978
       ares__socket_close(channel, s);
Packit 514978
       return -1;
Packit 514978
    }
Packit 514978
Packit 514978
#ifdef TCP_NODELAY
Packit 514978
  /*
Packit 514978
   * Disable the Nagle algorithm (only relevant for TCP sockets, and thus not
Packit 514978
   * in configure_socket). In general, in DNS lookups we're pretty much
Packit 514978
   * interested in firing off a single request and then waiting for a reply,
Packit 514978
   * so batching isn't very interesting.
Packit 514978
   */
Packit 514978
  opt = 1;
Packit 514978
  if (channel->sock_funcs == 0
Packit 514978
     &&
Packit 514978
     setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
Packit 514978
                (void *)&opt, sizeof(opt)) == -1)
Packit 514978
    {
Packit 514978
       ares__socket_close(channel, s);
Packit 514978
       return -1;
Packit 514978
    }
Packit 514978
#endif
Packit 514978
Packit 514978
  if (channel->sock_config_cb)
Packit 514978
    {
Packit 514978
      int err = channel->sock_config_cb(s, SOCK_STREAM,
Packit 514978
                                        channel->sock_config_cb_data);
Packit 514978
      if (err < 0)
Packit 514978
        {
Packit 514978
          ares__socket_close(channel, s);
Packit 514978
          return err;
Packit 514978
        }
Packit 514978
    }
Packit 514978
Packit 514978
  /* Connect to the server. */
Packit 514978
  if (connect_socket(channel, s, sa, salen) == -1)
Packit 514978
    {
Packit 514978
      int err = SOCKERRNO;
Packit 514978
Packit 514978
      if (err != EINPROGRESS && err != EWOULDBLOCK)
Packit 514978
        {
Packit 514978
          ares__socket_close(channel, s);
Packit 514978
          return -1;
Packit 514978
        }
Packit 514978
    }
Packit 514978
Packit 514978
  if (channel->sock_create_cb)
Packit 514978
    {
Packit 514978
      int err = channel->sock_create_cb(s, SOCK_STREAM,
Packit 514978
                                        channel->sock_create_cb_data);
Packit 514978
      if (err < 0)
Packit 514978
        {
Packit 514978
          ares__socket_close(channel, s);
Packit 514978
          return err;
Packit 514978
        }
Packit 514978
    }
Packit 514978
Packit 514978
  SOCK_STATE_CALLBACK(channel, s, 1, 0);
Packit 514978
  server->tcp_buffer_pos = 0;
Packit 514978
  server->tcp_socket = s;
Packit 514978
  server->tcp_connection_generation = ++channel->tcp_connection_generation;
Packit 514978
  return 0;
Packit 514978
}
Packit 514978
Packit 514978
static int open_udp_socket(ares_channel channel, struct server_state *server)
Packit 514978
{
Packit 514978
  ares_socket_t s;
Packit 514978
  ares_socklen_t salen;
Packit 514978
  union {
Packit 514978
    struct sockaddr_in  sa4;
Packit 514978
    struct sockaddr_in6 sa6;
Packit 514978
  } saddr;
Packit 514978
  struct sockaddr *sa;
Packit 514978
Packit 514978
  switch (server->addr.family)
Packit 514978
    {
Packit 514978
      case AF_INET:
Packit 514978
        sa = (void *)&saddr.sa4;
Packit 514978
        salen = sizeof(saddr.sa4);
Packit 514978
        memset(sa, 0, salen);
Packit 514978
        saddr.sa4.sin_family = AF_INET;
Packit 514978
        if (server->addr.udp_port) {
Packit 514978
          saddr.sa4.sin_port = aresx_sitous(server->addr.udp_port);
Packit 514978
        } else {
Packit 514978
          saddr.sa4.sin_port = aresx_sitous(channel->udp_port);
Packit 514978
        }
Packit 514978
        memcpy(&saddr.sa4.sin_addr, &server->addr.addrV4,
Packit 514978
               sizeof(server->addr.addrV4));
Packit 514978
        break;
Packit 514978
      case AF_INET6:
Packit 514978
        sa = (void *)&saddr.sa6;
Packit 514978
        salen = sizeof(saddr.sa6);
Packit 514978
        memset(sa, 0, salen);
Packit 514978
        saddr.sa6.sin6_family = AF_INET6;
Packit 514978
        if (server->addr.udp_port) {
Packit 514978
          saddr.sa6.sin6_port = aresx_sitous(server->addr.udp_port);
Packit 514978
        } else {
Packit 514978
          saddr.sa6.sin6_port = aresx_sitous(channel->udp_port);
Packit 514978
        }
Packit 514978
        memcpy(&saddr.sa6.sin6_addr, &server->addr.addrV6,
Packit 514978
               sizeof(server->addr.addrV6));
Packit 514978
        break;
Packit 514978
      default:
Packit 514978
        return -1;  /* LCOV_EXCL_LINE */
Packit 514978
    }
Packit 514978
Packit 514978
  /* Acquire a socket. */
Packit 514978
  s = open_socket(channel, server->addr.family, SOCK_DGRAM, 0);
Packit 514978
  if (s == ARES_SOCKET_BAD)
Packit 514978
    return -1;
Packit 514978
Packit 514978
  /* Set the socket non-blocking. */
Packit 514978
  if (configure_socket(s, server->addr.family, channel) < 0)
Packit 514978
    {
Packit 514978
       ares__socket_close(channel, s);
Packit 514978
       return -1;
Packit 514978
    }
Packit 514978
Packit 514978
  if (channel->sock_config_cb)
Packit 514978
    {
Packit 514978
      int err = channel->sock_config_cb(s, SOCK_DGRAM,
Packit 514978
                                        channel->sock_config_cb_data);
Packit 514978
      if (err < 0)
Packit 514978
        {
Packit 514978
          ares__socket_close(channel, s);
Packit 514978
          return err;
Packit 514978
        }
Packit 514978
    }
Packit 514978
Packit 514978
  /* Connect to the server. */
Packit 514978
  if (connect_socket(channel, s, sa, salen) == -1)
Packit 514978
    {
Packit 514978
      int err = SOCKERRNO;
Packit 514978
Packit 514978
      if (err != EINPROGRESS && err != EWOULDBLOCK)
Packit 514978
        {
Packit 514978
          ares__socket_close(channel, s);
Packit 514978
          return -1;
Packit 514978
        }
Packit 514978
    }
Packit 514978
Packit 514978
  if (channel->sock_create_cb)
Packit 514978
    {
Packit 514978
      int err = channel->sock_create_cb(s, SOCK_DGRAM,
Packit 514978
                                        channel->sock_create_cb_data);
Packit 514978
      if (err < 0)
Packit 514978
        {
Packit 514978
          ares__socket_close(channel, s);
Packit 514978
          return err;
Packit 514978
        }
Packit 514978
    }
Packit 514978
Packit 514978
  SOCK_STATE_CALLBACK(channel, s, 1, 0);
Packit 514978
Packit 514978
  server->udp_socket = s;
Packit 514978
  return 0;
Packit 514978
}
Packit 514978
Packit 514978
static int same_questions(const unsigned char *qbuf, int qlen,
Packit 514978
                          const unsigned char *abuf, int alen)
Packit 514978
{
Packit 514978
  struct {
Packit 514978
    const unsigned char *p;
Packit 514978
    int qdcount;
Packit 514978
    char *name;
Packit 514978
    long namelen;
Packit 514978
    int type;
Packit 514978
    int dnsclass;
Packit 514978
  } q, a;
Packit 514978
  int i, j;
Packit 514978
Packit 514978
  if (qlen < HFIXEDSZ || alen < HFIXEDSZ)
Packit 514978
    return 0;
Packit 514978
Packit 514978
  /* Extract qdcount from the request and reply buffers and compare them. */
Packit 514978
  q.qdcount = DNS_HEADER_QDCOUNT(qbuf);
Packit 514978
  a.qdcount = DNS_HEADER_QDCOUNT(abuf);
Packit 514978
  if (q.qdcount != a.qdcount)
Packit 514978
    return 0;
Packit 514978
Packit 514978
  /* For each question in qbuf, find it in abuf. */
Packit 514978
  q.p = qbuf + HFIXEDSZ;
Packit 514978
  for (i = 0; i < q.qdcount; i++)
Packit 514978
    {
Packit 514978
      /* Decode the question in the query. */
Packit 514978
      if (ares_expand_name(q.p, qbuf, qlen, &q.name, &q.namelen)
Packit 514978
          != ARES_SUCCESS)
Packit 514978
        return 0;
Packit 514978
      q.p += q.namelen;
Packit 514978
      if (q.p + QFIXEDSZ > qbuf + qlen)
Packit 514978
        {
Packit 514978
          ares_free(q.name);
Packit 514978
          return 0;
Packit 514978
        }
Packit 514978
      q.type = DNS_QUESTION_TYPE(q.p);
Packit 514978
      q.dnsclass = DNS_QUESTION_CLASS(q.p);
Packit 514978
      q.p += QFIXEDSZ;
Packit 514978
Packit 514978
      /* Search for this question in the answer. */
Packit 514978
      a.p = abuf + HFIXEDSZ;
Packit 514978
      for (j = 0; j < a.qdcount; j++)
Packit 514978
        {
Packit 514978
          /* Decode the question in the answer. */
Packit 514978
          if (ares_expand_name(a.p, abuf, alen, &a.name, &a.namelen)
Packit 514978
              != ARES_SUCCESS)
Packit 514978
            {
Packit 514978
              ares_free(q.name);
Packit 514978
              return 0;
Packit 514978
            }
Packit 514978
          a.p += a.namelen;
Packit 514978
          if (a.p + QFIXEDSZ > abuf + alen)
Packit 514978
            {
Packit 514978
              ares_free(q.name);
Packit 514978
              ares_free(a.name);
Packit 514978
              return 0;
Packit 514978
            }
Packit 514978
          a.type = DNS_QUESTION_TYPE(a.p);
Packit 514978
          a.dnsclass = DNS_QUESTION_CLASS(a.p);
Packit 514978
          a.p += QFIXEDSZ;
Packit 514978
Packit 514978
          /* Compare the decoded questions. */
Packit 514978
          if (strcasecmp(q.name, a.name) == 0 && q.type == a.type
Packit 514978
              && q.dnsclass == a.dnsclass)
Packit 514978
            {
Packit 514978
              ares_free(a.name);
Packit 514978
              break;
Packit 514978
            }
Packit 514978
          ares_free(a.name);
Packit 514978
        }
Packit 514978
Packit 514978
      ares_free(q.name);
Packit 514978
      if (j == a.qdcount)
Packit 514978
        return 0;
Packit 514978
    }
Packit 514978
  return 1;
Packit 514978
}
Packit 514978
Packit 514978
static int same_address(struct sockaddr *sa, struct ares_addr *aa)
Packit 514978
{
Packit 514978
  void *addr1;
Packit 514978
  void *addr2;
Packit 514978
Packit 514978
  if (sa->sa_family == aa->family)
Packit 514978
    {
Packit 514978
      switch (aa->family)
Packit 514978
        {
Packit 514978
          case AF_INET:
Packit 514978
            addr1 = &aa->addrV4;
Packit 514978
            addr2 = &((struct sockaddr_in *)sa)->sin_addr;
Packit 514978
            if (memcmp(addr1, addr2, sizeof(aa->addrV4)) == 0)
Packit 514978
              return 1; /* match */
Packit 514978
            break;
Packit 514978
          case AF_INET6:
Packit 514978
            addr1 = &aa->addrV6;
Packit 514978
            addr2 = &((struct sockaddr_in6 *)sa)->sin6_addr;
Packit 514978
            if (memcmp(addr1, addr2, sizeof(aa->addrV6)) == 0)
Packit 514978
              return 1; /* match */
Packit 514978
            break;
Packit 514978
          default:
Packit 514978
            break;  /* LCOV_EXCL_LINE */
Packit 514978
        }
Packit 514978
    }
Packit 514978
  return 0; /* different */
Packit 514978
}
Packit 514978
Packit 514978
static void end_query (ares_channel channel, struct query *query, int status,
Packit 514978
                       unsigned char *abuf, int alen)
Packit 514978
{
Packit 514978
  int i;
Packit 514978
Packit 514978
  /* First we check to see if this query ended while one of our send
Packit 514978
   * queues still has pointers to it.
Packit 514978
   */
Packit 514978
  for (i = 0; i < channel->nservers; i++)
Packit 514978
    {
Packit 514978
      struct server_state *server = &channel->servers[i];
Packit 514978
      struct send_request *sendreq;
Packit 514978
      for (sendreq = server->qhead; sendreq; sendreq = sendreq->next)
Packit 514978
        if (sendreq->owner_query == query)
Packit 514978
          {
Packit 514978
            sendreq->owner_query = NULL;
Packit 514978
            assert(sendreq->data_storage == NULL);
Packit 514978
            if (status == ARES_SUCCESS)
Packit 514978
              {
Packit 514978
                /* We got a reply for this query, but this queued sendreq
Packit 514978
                 * points into this soon-to-be-gone query's tcpbuf. Probably
Packit 514978
                 * this means we timed out and queued the query for
Packit 514978
                 * retransmission, then received a response before actually
Packit 514978
                 * retransmitting. This is perfectly fine, so we want to keep
Packit 514978
                 * the connection running smoothly if we can. But in the worst
Packit 514978
                 * case we may have sent only some prefix of the query, with
Packit 514978
                 * some suffix of the query left to send. Also, the buffer may
Packit 514978
                 * be queued on multiple queues. To prevent dangling pointers
Packit 514978
                 * to the query's tcpbuf and handle these cases, we just give
Packit 514978
                 * such sendreqs their own copy of the query packet.
Packit 514978
                 */
Packit 514978
               sendreq->data_storage = ares_malloc(sendreq->len);
Packit 514978
               if (sendreq->data_storage != NULL)
Packit 514978
                 {
Packit 514978
                   memcpy(sendreq->data_storage, sendreq->data, sendreq->len);
Packit 514978
                   sendreq->data = sendreq->data_storage;
Packit 514978
                 }
Packit 514978
              }
Packit 514978
            if ((status != ARES_SUCCESS) || (sendreq->data_storage == NULL))
Packit 514978
              {
Packit 514978
                /* We encountered an error (probably a timeout, suggesting the
Packit 514978
                 * DNS server we're talking to is probably unreachable,
Packit 514978
                 * wedged, or severely overloaded) or we couldn't copy the
Packit 514978
                 * request, so mark the connection as broken. When we get to
Packit 514978
                 * process_broken_connections() we'll close the connection and
Packit 514978
                 * try to re-send requests to another server.
Packit 514978
                 */
Packit 514978
               server->is_broken = 1;
Packit 514978
               /* Just to be paranoid, zero out this sendreq... */
Packit 514978
               sendreq->data = NULL;
Packit 514978
               sendreq->len = 0;
Packit 514978
             }
Packit 514978
          }
Packit 514978
    }
Packit 514978
Packit 514978
  /* Invoke the callback */
Packit 514978
  query->callback(query->arg, status, query->timeouts, abuf, alen);
Packit 514978
  ares__free_query(query);
Packit 514978
Packit 514978
  /* Simple cleanup policy: if no queries are remaining, close all network
Packit 514978
   * sockets unless STAYOPEN is set.
Packit 514978
   */
Packit 514978
  if (!(channel->flags & ARES_FLAG_STAYOPEN) &&
Packit 514978
      ares__is_list_empty(&(channel->all_queries)))
Packit 514978
    {
Packit 514978
      for (i = 0; i < channel->nservers; i++)
Packit 514978
        ares__close_sockets(channel, &channel->servers[i]);
Packit 514978
    }
Packit 514978
}
Packit 514978
Packit 514978
void ares__free_query(struct query *query)
Packit 514978
{
Packit 514978
  /* Remove the query from all the lists in which it is linked */
Packit 514978
  ares__remove_from_list(&(query->queries_by_qid));
Packit 514978
  ares__remove_from_list(&(query->queries_by_timeout));
Packit 514978
  ares__remove_from_list(&(query->queries_to_server));
Packit 514978
  ares__remove_from_list(&(query->all_queries));
Packit 514978
  /* Zero out some important stuff, to help catch bugs */
Packit 514978
  query->callback = NULL;
Packit 514978
  query->arg = NULL;
Packit 514978
  /* Deallocate the memory associated with the query */
Packit 514978
  ares_free(query->tcpbuf);
Packit 514978
  ares_free(query->server_info);
Packit 514978
  ares_free(query);
Packit 514978
}
Packit 514978
Packit 514978
void ares__socket_close(ares_channel channel, ares_socket_t s)
Packit 514978
{
Packit 514978
  if (channel->sock_funcs)
Packit 514978
    channel->sock_funcs->aclose(s, channel->sock_func_cb_data);
Packit 514978
  else
Packit 514978
    sclose(s);
Packit 514978
}