Alien-cares

 view release on metacpan or  search on metacpan

libcares/ares_process.c  view on Meta::CPAN

      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.
       */
      sendreq->data_storage = NULL;
      sendreq->data = query->tcpbuf;
      sendreq->len = query->tcplen;
      sendreq->owner_query = query;
      sendreq->next = NULL;
      if (server->qtail)
        server->qtail->next = sendreq;
      else
        {
          SOCK_STATE_CALLBACK(channel, server->tcp_socket, 1, 1);
          server->qhead = sendreq;
        }
      server->qtail = sendreq;
      query->server_info[query->server].tcp_connection_generation =
        server->tcp_connection_generation;
    }
  else
    {
      if (server->udp_socket == ARES_SOCKET_BAD)
        {
          if (open_udp_socket(channel, server) == -1)
            {
              skip_server(channel, query, query->server);
              next_server(channel, query, now);
              return;
            }
        }
      if (socket_write(channel, server->udp_socket, query->qbuf, query->qlen) == -1)
        {
          /* FIXME: Handle EAGAIN here since it likely can happen. */
          skip_server(channel, query, query->server);
          next_server(channel, query, now);
          return;
        }
    }

    /* For each trip through the entire server list, double the channel's
     * assigned timeout, avoiding overflow.  If channel->timeout is negative,
     * leave it as-is, even though that should be impossible here.
     */
    timeplus = channel->timeout;
    {
      /* How many times do we want to double it?  Presume sane values here. */
      const int shift = query->try_count / channel->nservers;

      /* Is there enough room to shift timeplus left that many times?
       *
       * To find out, confirm that all of the bits we'll shift away are zero.
       * Stop considering a shift if we get to the point where we could shift
       * a 1 into the sign bit (i.e. when shift is within two of the bit
       * count).
       *
       * This has the side benefit of leaving negative numbers unchanged.
       */
      if(shift <= (int)(sizeof(int) * CHAR_BIT - 1)
         && (timeplus >> (sizeof(int) * CHAR_BIT - 1 - shift)) == 0)



( run in 0.805 second using v1.01-cache-2.11-cpan-df04353d9ac )