1 /* Copyright 1998 by the Massachusetts Institute of Technology.
3 * Permission to use, copy, modify, and distribute this
4 * software and its documentation for any purpose and without
5 * fee is hereby granted, provided that the above copyright
6 * notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting
8 * documentation, and that the name of M.I.T. not be used in
9 * advertising or publicity pertaining to distribution of the
10 * software without specific, written prior permission.
11 * M.I.T. makes no representations about the suitability of
12 * this software for any purpose. It is provided "as is"
13 * without express or implied warranty.
16 static const char rcsid[] = "$Id: ares_process.c,v 1.7 2001/03/17 16:43:36 ghudson Exp $";
18 #include <sys/types.h>
19 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/nameser.h>
31 #include "ares_private.h"
33 static void write_tcp_data(ares_channel channel, fd_set *write_fds,
35 static void read_tcp_data(ares_channel channel, fd_set *read_fds, time_t now);
36 static void read_udp_packets(ares_channel channel, fd_set *read_fds,
38 static void process_timeouts(ares_channel channel, time_t now);
39 static void process_answer(ares_channel channel, unsigned char *abuf,
40 int alen, int whichserver, int tcp, int now);
41 static void handle_error(ares_channel channel, int whichserver, time_t now);
42 static void next_server(ares_channel channel, struct query *query, time_t now);
43 static int open_tcp_socket(ares_channel channel, struct server_state *server);
44 static int open_udp_socket(ares_channel channel, struct server_state *server);
45 static int same_questions(const unsigned char *qbuf, int qlen,
46 const unsigned char *abuf, int alen);
47 static void end_query(ares_channel channel, struct query *query, int status,
48 unsigned char *abuf, int alen);
50 /* Something interesting happened on the wire, or there was a timeout.
51 * See what's up and respond accordingly.
53 void ares_process(ares_channel channel, fd_set *read_fds, fd_set *write_fds)
58 write_tcp_data(channel, write_fds, now);
59 read_tcp_data(channel, read_fds, now);
60 read_udp_packets(channel, read_fds, now);
61 process_timeouts(channel, now);
64 /* If any TCP sockets select true for writing, write out queued data
67 static void write_tcp_data(ares_channel channel, fd_set *write_fds, time_t now)
69 struct server_state *server;
70 struct send_request *sendreq;
74 for (i = 0; i < channel->nservers; i++)
76 /* Make sure server has data to send and is selected in write_fds. */
77 server = &channel->servers[i];
78 if (!server->qhead || server->tcp_socket == -1
79 || !FD_ISSET(server->tcp_socket, write_fds))
82 /* Count the number of send queue items. */
84 for (sendreq = server->qhead; sendreq; sendreq = sendreq->next)
87 /* Allocate iovecs so we can send all our data at once. */
88 vec = malloc(n * sizeof(struct iovec));
91 /* Fill in the iovecs and send. */
93 for (sendreq = server->qhead; sendreq; sendreq = sendreq->next)
95 vec[n].iov_base = (char *) sendreq->data;
96 vec[n].iov_len = sendreq->len;
99 count = writev(server->tcp_socket, vec, n);
103 handle_error(channel, i, now);
107 /* Advance the send queue by as many bytes as we sent. */
110 sendreq = server->qhead;
111 if (count >= sendreq->len)
113 count -= sendreq->len;
114 server->qhead = sendreq->next;
115 if (server->qhead == NULL)
116 server->qtail = NULL;
121 sendreq->data += count;
122 sendreq->len -= count;
129 /* Can't allocate iovecs; just send the first request. */
130 sendreq = server->qhead;
131 count = write(server->tcp_socket, sendreq->data, sendreq->len);
134 handle_error(channel, i, now);
138 /* Advance the send queue by as many bytes as we sent. */
139 if (count == sendreq->len)
141 server->qhead = sendreq->next;
142 if (server->qhead == NULL)
143 server->qtail = NULL;
148 sendreq->data += count;
149 sendreq->len -= count;
155 /* If any TCP socket selects true for reading, read some data,
156 * allocate a buffer if we finish reading the length word, and process
157 * a packet if we finish reading one.
159 static void read_tcp_data(ares_channel channel, fd_set *read_fds, time_t now)
161 struct server_state *server;
164 for (i = 0; i < channel->nservers; i++)
166 /* Make sure the server has a socket and is selected in read_fds. */
167 server = &channel->servers[i];
168 if (server->tcp_socket == -1 || !FD_ISSET(server->tcp_socket, read_fds))
171 if (server->tcp_lenbuf_pos != 2)
173 /* We haven't yet read a length word, so read that (or
174 * what's left to read of it).
176 count = read(server->tcp_socket,
177 server->tcp_lenbuf + server->tcp_lenbuf_pos,
178 2 - server->tcp_lenbuf_pos);
181 handle_error(channel, i, now);
185 server->tcp_lenbuf_pos += count;
186 if (server->tcp_lenbuf_pos == 2)
188 /* We finished reading the length word. Decode the
189 * length and allocate a buffer for the data.
191 server->tcp_length = server->tcp_lenbuf[0] << 8
192 | server->tcp_lenbuf[1];
193 server->tcp_buffer = malloc(server->tcp_length);
194 if (!server->tcp_buffer)
195 handle_error(channel, i, now);
196 server->tcp_buffer_pos = 0;
201 /* Read data into the allocated buffer. */
202 count = read(server->tcp_socket,
203 server->tcp_buffer + server->tcp_buffer_pos,
204 server->tcp_length - server->tcp_buffer_pos);
207 handle_error(channel, i, now);
211 server->tcp_buffer_pos += count;
212 if (server->tcp_buffer_pos == server->tcp_length)
214 /* We finished reading this answer; process it and
215 * prepare to read another length word.
217 process_answer(channel, server->tcp_buffer, server->tcp_length,
219 free(server->tcp_buffer);
220 server->tcp_buffer = NULL;
221 server->tcp_lenbuf_pos = 0;
227 /* If any UDP sockets select true for reading, process them. */
228 static void read_udp_packets(ares_channel channel, fd_set *read_fds,
231 struct server_state *server;
233 unsigned char buf[PACKETSZ + 1];
235 for (i = 0; i < channel->nservers; i++)
237 /* Make sure the server has a socket and is selected in read_fds. */
238 server = &channel->servers[i];
239 if (server->udp_socket == -1 || !FD_ISSET(server->udp_socket, read_fds))
242 count = recv(server->udp_socket, buf, sizeof(buf), 0);
244 handle_error(channel, i, now);
246 process_answer(channel, buf, count, i, 0, now);
250 /* If any queries have timed out, note the timeout and move them on. */
251 static void process_timeouts(ares_channel channel, time_t now)
253 struct query *query, *next;
255 for (query = channel->queries; query; query = next)
258 if (query->timeout != 0 && now >= query->timeout)
260 query->error_status = ARES_ETIMEOUT;
261 next_server(channel, query, now);
266 /* Handle an answer from a server. */
267 static void process_answer(ares_channel channel, unsigned char *abuf,
268 int alen, int whichserver, int tcp, int now)
273 /* If there's no room in the answer for a header, we can't do much
278 /* Grab the query ID, truncate bit, and response code from the packet. */
279 id = DNS_HEADER_QID(abuf);
280 tc = DNS_HEADER_TC(abuf);
281 rcode = DNS_HEADER_RCODE(abuf);
283 /* Find the query corresponding to this packet. */
284 for (query = channel->queries; query; query = query->next)
286 if (query->qid == id)
292 /* If we got a truncated UDP packet and are not ignoring truncation,
293 * don't accept the packet, and switch the query to TCP if we hadn't
296 if ((tc || alen > PACKETSZ) && !tcp && !(channel->flags & ARES_FLAG_IGNTC))
298 if (!query->using_tcp)
300 query->using_tcp = 1;
301 ares__send_query(channel, query, now);
306 /* Limit alen to PACKETSZ if we aren't using TCP (only relevant if we
307 * are ignoring truncation.
309 if (alen > PACKETSZ && !tcp)
312 /* If we aren't passing through all error packets, discard packets
313 * with SERVFAIL, NOTIMP, or REFUSED response codes.
315 if (!(channel->flags & ARES_FLAG_NOCHECKRESP))
317 if (rcode == SERVFAIL || rcode == NOTIMP || rcode == REFUSED)
319 query->skip_server[whichserver] = 1;
320 if (query->server == whichserver)
321 next_server(channel, query, now);
324 if (!same_questions(query->qbuf, query->qlen, abuf, alen))
326 if (query->server == whichserver)
327 next_server(channel, query, now);
332 end_query(channel, query, ARES_SUCCESS, abuf, alen);
335 static void handle_error(ares_channel channel, int whichserver, time_t now)
339 /* Reset communications with this server. */
340 ares__close_sockets(&channel->servers[whichserver]);
342 /* Tell all queries talking to this server to move on and not try
345 for (query = channel->queries; query; query = query->next)
347 if (query->server == whichserver)
349 query->skip_server[whichserver] = 1;
350 next_server(channel, query, now);
355 static void next_server(ares_channel channel, struct query *query, time_t now)
357 /* Advance to the next server or try. */
359 for (; query->try < channel->tries; query->try++)
361 for (; query->server < channel->nservers; query->server++)
363 if (!query->skip_server[query->server])
365 ares__send_query(channel, query, now);
371 /* Only one try if we're using TCP. */
372 if (query->using_tcp)
375 end_query(channel, query, query->error_status, NULL, 0);
378 void ares__send_query(ares_channel channel, struct query *query, time_t now)
380 struct send_request *sendreq;
381 struct server_state *server;
383 server = &channel->servers[query->server];
384 if (query->using_tcp)
386 /* Make sure the TCP socket for this server is set up and queue
389 if (server->tcp_socket == -1)
391 if (open_tcp_socket(channel, server) == -1)
393 query->skip_server[query->server] = 1;
394 next_server(channel, query, now);
398 sendreq = malloc(sizeof(struct send_request));
400 end_query(channel, query, ARES_ENOMEM, NULL, 0);
401 sendreq->data = query->tcpbuf;
402 sendreq->len = query->tcplen;
403 sendreq->next = NULL;
405 server->qtail->next = sendreq;
407 server->qhead = sendreq;
408 server->qtail = sendreq;
413 if (server->udp_socket == -1)
415 if (open_udp_socket(channel, server) == -1)
417 query->skip_server[query->server] = 1;
418 next_server(channel, query, now);
422 if (send(server->udp_socket, query->qbuf, query->qlen, 0) == -1)
424 query->skip_server[query->server] = 1;
425 next_server(channel, query, now);
429 + ((query->try == 0) ? channel->timeout
430 : channel->timeout << query->try / channel->nservers);
434 static int open_tcp_socket(ares_channel channel, struct server_state *server)
437 struct sockaddr_in sin;
439 /* Acquire a socket. */
440 s = socket(AF_INET, SOCK_STREAM, 0);
444 /* Set the socket non-blocking. */
445 if (fcntl(s, F_GETFL, &flags) == -1)
451 if (fcntl(s, F_SETFL, flags) == -1)
457 /* Connect to the server. */
458 memset(&sin, 0, sizeof(sin));
459 sin.sin_family = AF_INET;
460 sin.sin_addr = server->addr;
461 sin.sin_port = channel->tcp_port;
462 if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == -1
463 && errno != EINPROGRESS)
469 server->tcp_socket = s;
473 static int open_udp_socket(ares_channel channel, struct server_state *server)
476 struct sockaddr_in sin;
478 /* Acquire a socket. */
479 s = socket(AF_INET, SOCK_DGRAM, 0);
483 /* Connect to the server. */
484 memset(&sin, 0, sizeof(sin));
485 sin.sin_family = AF_INET;
486 sin.sin_addr = server->addr;
487 sin.sin_port = channel->udp_port;
488 if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == -1)
494 server->udp_socket = s;
498 static int same_questions(const unsigned char *qbuf, int qlen,
499 const unsigned char *abuf, int alen)
502 const unsigned char *p;
511 if (qlen < HFIXEDSZ || alen < HFIXEDSZ)
514 /* Extract qdcount from the request and reply buffers and compare them. */
515 q.qdcount = DNS_HEADER_QDCOUNT(qbuf);
516 a.qdcount = DNS_HEADER_QDCOUNT(abuf);
517 if (q.qdcount != a.qdcount)
520 /* For each question in qbuf, find it in abuf. */
521 q.p = qbuf + HFIXEDSZ;
522 for (i = 0; i < q.qdcount; i++)
524 /* Decode the question in the query. */
525 if (ares_expand_name(q.p, qbuf, qlen, &q.name, &q.namelen)
529 if (q.p + QFIXEDSZ > qbuf + qlen)
534 q.type = DNS_QUESTION_TYPE(q.p);
535 q.dnsclass = DNS_QUESTION_CLASS(q.p);
538 /* Search for this question in the answer. */
539 a.p = abuf + HFIXEDSZ;
540 for (j = 0; j < a.qdcount; j++)
542 /* Decode the question in the answer. */
543 if (ares_expand_name(a.p, abuf, alen, &a.name, &a.namelen)
550 if (a.p + QFIXEDSZ > abuf + alen)
556 a.type = DNS_QUESTION_TYPE(a.p);
557 a.dnsclass = DNS_QUESTION_CLASS(a.p);
560 /* Compare the decoded questions. */
561 if (strcasecmp(q.name, a.name) == 0 && q.type == a.type
562 && q.dnsclass == a.dnsclass)
577 static void end_query(ares_channel channel, struct query *query, int status,
578 unsigned char *abuf, int alen)
583 query->callback(query->arg, status, abuf, alen);
584 for (q = &channel->queries; *q; q = &(*q)->next)
591 free(query->skip_server);
594 /* Simple cleanup policy: if no queries are remaining, close all
595 * network sockets unless STAYOPEN is set.
597 if (!channel->queries && !(channel->flags & ARES_FLAG_STAYOPEN))
599 for (i = 0; i < channel->nservers; i++)
600 ares__close_sockets(&channel->servers[i]);