Alien-cares

 view release on metacpan or  search on metacpan

libcares/ares_process.c  view on Meta::CPAN


  server = &channel->servers[whichserver];

  /* Reset communications with this server. */
  ares__close_sockets(channel, server);

  /* Tell all queries talking to this server to move on and not try this
   * server again. We steal the current list of queries that were in-flight to
   * this server, since when we call next_server this can cause the queries to
   * be re-sent to this server, which will re-insert these queries in that
   * same server->queries_to_server list.
   */
  ares__init_list_head(&list_head);
  swap_lists(&list_head, &(server->queries_to_server));
  for (list_node = list_head.next; list_node != &list_head; )
    {
      query = list_node->data;
      list_node = list_node->next;  /* in case the query gets deleted */
      assert(query->server == whichserver);
      skip_server(channel, query, whichserver);
      next_server(channel, query, now);
    }
  /* Each query should have removed itself from our temporary list as
   * it re-sent itself or finished up...
   */
  assert(ares__is_list_empty(&list_head));
}

static void skip_server(ares_channel channel, struct query *query,
                        int whichserver)
{
  /* The given server gave us problems with this query, so if we have the
   * luxury of using other servers, then let's skip the potentially broken
   * server and just use the others. If we only have one server and we need to
   * retry then we should just go ahead and re-use that server, since it's our
   * only hope; perhaps we just got unlucky, and retrying will work (eg, the
   * server timed out our TCP connection just as we were sending another
   * request).
   */
  if (channel->nservers > 1)
    {
      query->server_info[whichserver].skip_server = 1;
    }
}

static void next_server(ares_channel channel, struct query *query,
                        struct timeval *now)
{
  /* We need to try each server channel->tries times. We have channel->nservers
   * servers to try. In total, we need to do channel->nservers * channel->tries
   * attempts. Use query->try to remember how many times we already attempted
   * this query. Use modular arithmetic to find the next server to try. */
  while (++(query->try_count) < (channel->nservers * channel->tries))
    {
      struct server_state *server;

      /* Move on to the next server. */
      query->server = (query->server + 1) % channel->nservers;
      server = &channel->servers[query->server];

      /* We don't want to use this server if (1) we decided this connection is
       * broken, and thus about to be closed, (2) we've decided to skip this
       * server because of earlier errors we encountered, or (3) we already
       * sent this query over this exact connection.
       */
      if (!server->is_broken &&
           !query->server_info[query->server].skip_server &&
           !(query->using_tcp &&
             (query->server_info[query->server].tcp_connection_generation ==
              server->tcp_connection_generation)))
        {
           ares__send_query(channel, query, now);
           return;
        }

      /* You might think that with TCP we only need one try. However, even
       * when using TCP, servers can time-out our connection just as we're
       * sending a request, or close our connection because they die, or never
       * send us a reply because they get wedged or tickle a bug that drops
       * our request.
       */
    }

  /* If we are here, all attempts to perform query failed. */
  end_query(channel, query, query->error_status, NULL, 0);
}

void ares__send_query(ares_channel channel, struct query *query,
                      struct timeval *now)
{
  struct send_request *sendreq;
  struct server_state *server;
  int timeplus;

  server = &channel->servers[query->server];
  if (query->using_tcp)
    {
      /* Make sure the TCP socket for this server is set up and queue
       * a send request.
       */
      if (server->tcp_socket == ARES_SOCKET_BAD)
        {
          if (open_tcp_socket(channel, server) == -1)
            {
              skip_server(channel, query, query->server);
              next_server(channel, query, now);
              return;
            }
        }
      sendreq = ares_malloc(sizeof(struct send_request));
      if (!sendreq)
        {
        end_query(channel, query, ARES_ENOMEM, NULL, 0);
          return;
        }
      memset(sendreq, 0, sizeof(struct send_request));
      /* To make the common case fast, we avoid copies by using the query's
       * tcpbuf for as long as the query is alive. In the rare case where the
       * query ends while it's queued for transmission, then we give the
       * sendreq its own copy of the request packet and put it in
       * sendreq->data_storage.
       */



( run in 0.785 second using v1.01-cache-2.11-cpan-e1769b4cff6 )