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 )