Alien-cares
view release on metacpan or search on metacpan
libcares/ares_process.c view on Meta::CPAN
}
/* Something interesting happened on the wire, or there was a timeout.
* See what's up and respond accordingly.
*/
void ares_process_fd(ares_channel channel,
ares_socket_t read_fd, /* use ARES_SOCKET_BAD or valid
file descriptors */
ares_socket_t write_fd)
{
processfds(channel, NULL, read_fd, NULL, write_fd);
}
/* Return 1 if the specified error number describes a readiness error, or 0
* otherwise. This is mostly for HP-UX, which could return EAGAIN or
* EWOULDBLOCK. See this man page
*
* http://devrsrc1.external.hp.com/STKS/cgi-bin/man2html?
* manpage=/usr/share/man/man2.Z/send.2
*/
static int try_again(int errnum)
{
#if !defined EWOULDBLOCK && !defined EAGAIN
#error "Neither EWOULDBLOCK nor EAGAIN defined"
#endif
switch (errnum)
{
#ifdef EWOULDBLOCK
case EWOULDBLOCK:
return 1;
#endif
#if defined EAGAIN && EAGAIN != EWOULDBLOCK
case EAGAIN:
return 1;
#endif
}
return 0;
}
static ares_ssize_t socket_writev(ares_channel channel, ares_socket_t s, const struct iovec * vec, int len)
{
if (channel->sock_funcs)
return channel->sock_funcs->asendv(s, vec, len, channel->sock_func_cb_data);
return writev(s, vec, len);
}
static ares_ssize_t socket_write(ares_channel channel, ares_socket_t s, const void * data, size_t len)
{
if (channel->sock_funcs)
{
struct iovec vec;
vec.iov_base = (void*)data;
vec.iov_len = len;
return channel->sock_funcs->asendv(s, &vec, 1, channel->sock_func_cb_data);
}
return swrite(s, data, len);
}
/* If any TCP sockets select true for writing, write out queued data
* we have for them.
*/
static void write_tcp_data(ares_channel channel,
fd_set *write_fds,
ares_socket_t write_fd,
struct timeval *now)
{
struct server_state *server;
struct send_request *sendreq;
struct iovec *vec;
int i;
ares_ssize_t scount;
ares_ssize_t wcount;
size_t n;
if(!write_fds && (write_fd == ARES_SOCKET_BAD))
/* no possible action */
return;
for (i = 0; i < channel->nservers; i++)
{
/* Make sure server has data to send and is selected in write_fds or
write_fd. */
server = &channel->servers[i];
if (!server->qhead || server->tcp_socket == ARES_SOCKET_BAD ||
server->is_broken)
continue;
if(write_fds) {
if(!FD_ISSET(server->tcp_socket, write_fds))
continue;
}
else {
if(server->tcp_socket != write_fd)
continue;
}
if(write_fds)
/* If there's an error and we close this socket, then open
* another with the same fd to talk to another server, then we
* don't want to think that it was the new socket that was
* ready. This is not disastrous, but is likely to result in
* extra system calls and confusion. */
FD_CLR(server->tcp_socket, write_fds);
/* Count the number of send queue items. */
n = 0;
for (sendreq = server->qhead; sendreq; sendreq = sendreq->next)
n++;
/* Allocate iovecs so we can send all our data at once. */
vec = ares_malloc(n * sizeof(struct iovec));
if (vec)
{
/* Fill in the iovecs and send. */
n = 0;
for (sendreq = server->qhead; sendreq; sendreq = sendreq->next)
{
vec[n].iov_base = (char *) sendreq->data;
vec[n].iov_len = sendreq->len;
n++;
}
wcount = socket_writev(channel, server->tcp_socket, vec, (int)n);
ares_free(vec);
if (wcount < 0)
{
if (!try_again(SOCKERRNO))
handle_error(channel, i, now);
continue;
}
/* Advance the send queue by as many bytes as we sent. */
advance_tcp_send_queue(channel, i, wcount);
}
else
{
/* Can't allocate iovecs; just send the first request. */
sendreq = server->qhead;
scount = socket_write(channel, server->tcp_socket, sendreq->data, sendreq->len);
if (scount < 0)
{
libcares/ares_process.c view on Meta::CPAN
ares_ssize_t num_bytes)
{
struct send_request *sendreq;
struct server_state *server = &channel->servers[whichserver];
while (num_bytes > 0) {
sendreq = server->qhead;
if ((size_t)num_bytes >= sendreq->len) {
num_bytes -= sendreq->len;
server->qhead = sendreq->next;
if (sendreq->data_storage)
ares_free(sendreq->data_storage);
ares_free(sendreq);
if (server->qhead == NULL) {
SOCK_STATE_CALLBACK(channel, server->tcp_socket, 1, 0);
server->qtail = NULL;
/* qhead is NULL so we cannot continue this loop */
break;
}
}
else {
sendreq->data += num_bytes;
sendreq->len -= num_bytes;
num_bytes = 0;
}
}
}
static ares_ssize_t socket_recvfrom(ares_channel channel,
ares_socket_t s,
void * data,
size_t data_len,
int flags,
struct sockaddr *from,
ares_socklen_t *from_len)
{
if (channel->sock_funcs)
return channel->sock_funcs->arecvfrom(s, data, data_len,
flags, from, from_len,
channel->sock_func_cb_data);
#ifdef HAVE_RECVFROM
return recvfrom(s, data, data_len, flags, from, from_len);
#else
return sread(s, data, data_len);
#endif
}
static ares_ssize_t socket_recv(ares_channel channel,
ares_socket_t s,
void * data,
size_t data_len)
{
if (channel->sock_funcs)
return channel->sock_funcs->arecvfrom(s, data, data_len, 0, 0, 0,
channel->sock_func_cb_data);
return sread(s, data, data_len);
}
/* If any TCP socket selects true for reading, read some data,
* allocate a buffer if we finish reading the length word, and process
* a packet if we finish reading one.
*/
static void read_tcp_data(ares_channel channel, fd_set *read_fds,
ares_socket_t read_fd, struct timeval *now)
{
struct server_state *server;
int i;
ares_ssize_t count;
if(!read_fds && (read_fd == ARES_SOCKET_BAD))
/* no possible action */
return;
for (i = 0; i < channel->nservers; i++)
{
/* Make sure the server has a socket and is selected in read_fds. */
server = &channel->servers[i];
if (server->tcp_socket == ARES_SOCKET_BAD || server->is_broken)
continue;
if(read_fds) {
if(!FD_ISSET(server->tcp_socket, read_fds))
continue;
}
else {
if(server->tcp_socket != read_fd)
continue;
}
if(read_fds)
/* If there's an error and we close this socket, then open another
* with the same fd to talk to another server, then we don't want to
* think that it was the new socket that was ready. This is not
* disastrous, but is likely to result in extra system calls and
* confusion. */
FD_CLR(server->tcp_socket, read_fds);
if (server->tcp_lenbuf_pos != 2)
{
/* We haven't yet read a length word, so read that (or
* what's left to read of it).
*/
count = socket_recv(channel, server->tcp_socket,
server->tcp_lenbuf + server->tcp_lenbuf_pos,
2 - server->tcp_lenbuf_pos);
if (count <= 0)
{
if (!(count == -1 && try_again(SOCKERRNO)))
handle_error(channel, i, now);
continue;
}
server->tcp_lenbuf_pos += (int)count;
if (server->tcp_lenbuf_pos == 2)
{
/* We finished reading the length word. Decode the
* length and allocate a buffer for the data.
*/
server->tcp_length = server->tcp_lenbuf[0] << 8
| server->tcp_lenbuf[1];
server->tcp_buffer = ares_malloc(server->tcp_length);
if (!server->tcp_buffer) {
handle_error(channel, i, now);
return; /* bail out on malloc failure. TODO: make this
function return error codes */
}
server->tcp_buffer_pos = 0;
}
}
else
{
/* Read data into the allocated buffer. */
count = socket_recv(channel, server->tcp_socket,
server->tcp_buffer + server->tcp_buffer_pos,
server->tcp_length - server->tcp_buffer_pos);
if (count <= 0)
{
if (!(count == -1 && try_again(SOCKERRNO)))
handle_error(channel, i, now);
continue;
}
server->tcp_buffer_pos += (int)count;
if (server->tcp_buffer_pos == server->tcp_length)
{
/* We finished reading this answer; process it and
* prepare to read another length word.
*/
process_answer(channel, server->tcp_buffer, server->tcp_length,
i, 1, now);
ares_free(server->tcp_buffer);
server->tcp_buffer = NULL;
server->tcp_lenbuf_pos = 0;
server->tcp_buffer_pos = 0;
}
}
}
}
/* If any UDP sockets select true for reading, process them. */
static void read_udp_packets(ares_channel channel, fd_set *read_fds,
ares_socket_t read_fd, struct timeval *now)
{
struct server_state *server;
int i;
ares_ssize_t count;
unsigned char buf[MAXENDSSZ + 1];
#ifdef HAVE_RECVFROM
ares_socklen_t fromlen;
ares_sockaddr from;
#endif
if(!read_fds && (read_fd == ARES_SOCKET_BAD))
/* no possible action */
return;
for (i = 0; i < channel->nservers; i++)
{
/* Make sure the server has a socket and is selected in read_fds. */
server = &channel->servers[i];
if (server->udp_socket == ARES_SOCKET_BAD || server->is_broken)
continue;
if(read_fds) {
if(!FD_ISSET(server->udp_socket, read_fds))
continue;
}
else {
if(server->udp_socket != read_fd)
continue;
}
if(read_fds)
/* If there's an error and we close this socket, then open
* another with the same fd to talk to another server, then we
* don't want to think that it was the new socket that was
* ready. This is not disastrous, but is likely to result in
* extra system calls and confusion. */
FD_CLR(server->udp_socket, read_fds);
/* To reduce event loop overhead, read and process as many
* packets as we can. */
do {
if (server->udp_socket == ARES_SOCKET_BAD)
count = 0;
else {
if (server->addr.family == AF_INET)
fromlen = sizeof(from.sa4);
else
fromlen = sizeof(from.sa6);
count = socket_recvfrom(channel, server->udp_socket, (void *)buf,
sizeof(buf), 0, &from.sa, &fromlen);
}
if (count == -1 && try_again(SOCKERRNO))
continue;
else if (count <= 0)
handle_error(channel, i, now);
#ifdef HAVE_RECVFROM
else if (!same_address(&from.sa, &server->addr))
/* The address the response comes from does not match the address we
* sent the request to. Someone may be attempting to perform a cache
* poisoning attack. */
break;
#endif
else
process_answer(channel, buf, (int)count, i, 0, now);
} while (count > 0);
}
}
/* If any queries have timed out, note the timeout and move them on. */
static void process_timeouts(ares_channel channel, struct timeval *now)
{
time_t t; /* the time of the timeouts we're processing */
struct query *query;
struct list_node* list_head;
( run in 0.296 second using v1.01-cache-2.11-cpan-3d66aa2751a )