📄 ares_process.c
字号:
/* Copyright 1998 by the Massachusetts Institute of Technology. * * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright * notice and this permission notice appear in supporting * documentation, and that the name of M.I.T. not be used in * advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" * without express or implied warranty. * * CHANGELOG: this file has been modified by Sergio Perez Alca駃z <serpeal@upvnet.upv.es> * Departamento de Inform醫ica de Sistemas y Computadores * Universidad Polit閏nica de Valencia * Valencia (Spain) * Date: April 2003 * */#include "ares_private.h"#include "ares_dns.h"static void write_tcp_data(ares_channel channel, fd_set *write_fds, time_t now);static void read_tcp_data(ares_channel channel, fd_set *read_fds, time_t now);static void read_udp_packets(ares_channel channel, fd_set *read_fds, time_t now);static void process_timeouts(ares_channel channel, time_t now);static void process_answer(ares_channel channel, unsigned char *abuf, int alen, int whichserver, int tcp, int now);static void handle_error(ares_channel channel, int whichserver, time_t now);static void next_server(ares_channel channel, struct query *query, time_t now);static int open_tcp_socket(ares_channel channel, struct server_state *server);static int open_udp_socket(ares_channel channel, struct server_state *server);static int same_questions(const unsigned char *qbuf, int qlen, const unsigned char *abuf, int alen);static void end_query(ares_channel channel, struct query *query, int status, unsigned char *abuf, int alen);/* Something interesting happened on the wire, or there was a timeout. * See what's up and respond accordingly. */void ares_process(ares_channel channel, fd_set *read_fds, fd_set *write_fds){ time_t now; time(&now); write_tcp_data(channel, write_fds, now); read_tcp_data(channel, read_fds, now); read_udp_packets(channel, read_fds, now); process_timeouts(channel, now);}/* 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, time_t now){ struct server_state *server; struct send_request *sendreq;#ifdef HAVE_WRITEV struct iovec *vec;#endif int i, n, count; for (i = 0; i < channel->nservers; i++) { /* Make sure server has data to send and is selected in write_fds. */ server = &channel->servers[i]; if (!server->qhead || server->tcp_socket == -1 || !FD_ISSET(server->tcp_socket, write_fds)) continue; /* Count the number of send queue items. */ n = 0; for (sendreq = server->qhead; sendreq; sendreq = sendreq->next) n++;#ifdef HAVE_WRITEV /* Allocate iovecs so we can send all our data at once. */ vec = 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++; } count = writev(server->tcp_socket, vec, n); free(vec); if (count < 0) { handle_error(channel, i, now); continue; } /* Advance the send queue by as many bytes as we sent. */ while (count) { sendreq = server->qhead; if (count >= sendreq->len) { count -= sendreq->len; server->qhead = sendreq->next; if (server->qhead == NULL) server->qtail = NULL; free(sendreq); } else { sendreq->data += count; sendreq->len -= count; break; } } } else#endif /* HAVE_WRITEV */ { /* Can't allocate iovecs; just send the first request. */ sendreq = server->qhead; count = write(server->tcp_socket, (void *) sendreq->data, sendreq->len); if (count < 0) { handle_error(channel, i, now); continue; } /* Advance the send queue by as many bytes as we sent. */ if (count == sendreq->len) { server->qhead = sendreq->next; if (server->qhead == NULL) server->qtail = NULL; free(sendreq); } else { sendreq->data += count; sendreq->len -= count; } } }}/* 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, time_t now){ struct server_state *server; int i, count; 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 == -1 || !FD_ISSET(server->tcp_socket, read_fds)) continue; 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 = read(server->tcp_socket, server->tcp_lenbuf + server->tcp_lenbuf_pos, 2 - server->tcp_lenbuf_pos); if (count <= 0) { handle_error(channel, i, now); continue; } server->tcp_lenbuf_pos += 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 = malloc(server->tcp_length); if (!server->tcp_buffer) handle_error(channel, i, now); server->tcp_buffer_pos = 0; } } else { /* Read data into the allocated buffer. */ count = read(server->tcp_socket, server->tcp_buffer + server->tcp_buffer_pos, server->tcp_length - server->tcp_buffer_pos); if (count <= 0) { handle_error(channel, i, now); continue; } server->tcp_buffer_pos += 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); free(server->tcp_buffer); server->tcp_buffer = NULL; server->tcp_lenbuf_pos = 0; } } }}/* If any UDP sockets select true for reading, process them. */static void read_udp_packets(ares_channel channel, fd_set *read_fds, time_t now){ struct server_state *server; int i, count; unsigned char buf[PACKETSZ + 1]; 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 == -1 || !FD_ISSET(server->udp_socket, read_fds)) continue; count = recv(server->udp_socket, buf, sizeof(buf), 0); if (count <= 0) handle_error(channel, i, now); process_answer(channel, buf, count, i, 0, now); }}/* If any queries have timed out, note the timeout and move them on. */static void process_timeouts(ares_channel channel, time_t now){ struct query *query, *next; for (query = channel->queries; query; query = next) { next = query->next; if (query->timeout != 0 && now >= query->timeout) { query->error_status = ARES_ETIMEOUT; next_server(channel, query, now); } }}/* Handle an answer from a server. */static void process_answer(ares_channel channel, unsigned char *abuf, int alen, int whichserver, int tcp, int now){ int id, tc, rcode; struct query *query; /* If there's no room in the answer for a header, we can't do much * with it. */ if (alen < HFIXEDSZ) return; /* Grab the query ID, truncate bit, and response code from the packet. */ id = DNS_HEADER_QID(abuf); tc = DNS_HEADER_TC(abuf); rcode = DNS_HEADER_RCODE(abuf); /* Find the query corresponding to this packet. */ for (query = channel->queries; query; query = query->next) { if (query->qid == id) break; } if (!query) return; /* If we got a truncated UDP packet and are not ignoring truncation, * don't accept the packet, and switch the query to TCP if we hadn't * done so already. */ if ((tc || alen > PACKETSZ) && !tcp && !(channel->flags & ARES_FLAG_IGNTC)) { if (!query->using_tcp) { query->using_tcp = 1; ares__send_query(channel, query, now); } return; } /* Limit alen to PACKETSZ if we aren't using TCP (only relevant if we * are ignoring truncation. */ if (alen > PACKETSZ && !tcp) alen = PACKETSZ; /* If we aren't passing through all error packets, discard packets
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -