]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - libares/ares_process.c
need automake as a build-dep, even though we don't use most of it
[1ts-debian.git] / libares / ares_process.c
1 /* Copyright 1998 by the Massachusetts Institute of Technology.
2  *
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.
14  */
15
16 static const char rcsid[] = "$Id: ares_process.c,v 1.7 2001/03/17 16:43:36 ghudson Exp $";
17
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/uio.h>
21 #include <netinet/in.h>
22 #include <arpa/nameser.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <time.h>
28 #include <errno.h>
29 #include "ares.h"
30 #include "ares_dns.h"
31 #include "ares_private.h"
32
33 static void write_tcp_data(ares_channel channel, fd_set *write_fds,
34                            time_t now);
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,
37                              time_t now);
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);
49
50 /* Something interesting happened on the wire, or there was a timeout.
51  * See what's up and respond accordingly.
52  */
53 void ares_process(ares_channel channel, fd_set *read_fds, fd_set *write_fds)
54 {
55   time_t now;
56
57   time(&now);
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);
62 }
63
64 /* If any TCP sockets select true for writing, write out queued data
65  * we have for them.
66  */
67 static void write_tcp_data(ares_channel channel, fd_set *write_fds, time_t now)
68 {
69   struct server_state *server;
70   struct send_request *sendreq;
71   struct iovec *vec;
72   int i, n, count;
73
74   for (i = 0; i < channel->nservers; i++)
75     {
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))
80         continue;
81
82       /* Count the number of send queue items. */
83       n = 0;
84       for (sendreq = server->qhead; sendreq; sendreq = sendreq->next)
85         n++;
86
87       /* Allocate iovecs so we can send all our data at once. */
88       vec = malloc(n * sizeof(struct iovec));
89       if (vec)
90         {
91           /* Fill in the iovecs and send. */
92           n = 0;
93           for (sendreq = server->qhead; sendreq; sendreq = sendreq->next)
94             {
95               vec[n].iov_base = (char *) sendreq->data;
96               vec[n].iov_len = sendreq->len;
97               n++;
98             }
99           count = writev(server->tcp_socket, vec, n);
100           free(vec);
101           if (count < 0)
102             {
103               handle_error(channel, i, now);
104               continue;
105             }
106
107           /* Advance the send queue by as many bytes as we sent. */
108           while (count)
109             {
110               sendreq = server->qhead;
111               if (count >= sendreq->len)
112                 {
113                   count -= sendreq->len;
114                   server->qhead = sendreq->next;
115                   if (server->qhead == NULL)
116                     server->qtail = NULL;
117                   free(sendreq);
118                 }
119               else
120                 {
121                   sendreq->data += count;
122                   sendreq->len -= count;
123                   break;
124                 }
125             }
126         }
127       else
128         {
129           /* Can't allocate iovecs; just send the first request. */
130           sendreq = server->qhead;
131           count = write(server->tcp_socket, sendreq->data, sendreq->len);
132           if (count < 0)
133             {
134               handle_error(channel, i, now);
135               continue;
136             }
137
138           /* Advance the send queue by as many bytes as we sent. */
139           if (count == sendreq->len)
140             {
141               server->qhead = sendreq->next;
142               if (server->qhead == NULL)
143                 server->qtail = NULL;
144               free(sendreq);
145             }
146           else
147             {
148               sendreq->data += count;
149               sendreq->len -= count;
150             }
151         }
152     }
153 }
154
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.
158  */
159 static void read_tcp_data(ares_channel channel, fd_set *read_fds, time_t now)
160 {
161   struct server_state *server;
162   int i, count;
163
164   for (i = 0; i < channel->nservers; i++)
165     {
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))
169         continue;
170
171       if (server->tcp_lenbuf_pos != 2)
172         {
173           /* We haven't yet read a length word, so read that (or
174            * what's left to read of it).
175            */
176           count = read(server->tcp_socket,
177                        server->tcp_lenbuf + server->tcp_lenbuf_pos,
178                        2 - server->tcp_lenbuf_pos);
179           if (count <= 0)
180             {
181               handle_error(channel, i, now);
182               continue;
183             }
184
185           server->tcp_lenbuf_pos += count;
186           if (server->tcp_lenbuf_pos == 2)
187             {
188               /* We finished reading the length word.  Decode the
189                * length and allocate a buffer for the data.
190                */
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;
197             }
198         }
199       else
200         {
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);
205           if (count <= 0)
206             {
207               handle_error(channel, i, now);
208               continue;
209             }
210
211           server->tcp_buffer_pos += count;
212           if (server->tcp_buffer_pos == server->tcp_length)
213             {
214               /* We finished reading this answer; process it and
215                * prepare to read another length word.
216                */
217               process_answer(channel, server->tcp_buffer, server->tcp_length,
218                              i, 1, now);
219               free(server->tcp_buffer);
220               server->tcp_buffer = NULL;
221               server->tcp_lenbuf_pos = 0;
222             }
223         }
224     }
225 }
226
227 /* If any UDP sockets select true for reading, process them. */
228 static void read_udp_packets(ares_channel channel, fd_set *read_fds,
229                              time_t now)
230 {
231   struct server_state *server;
232   int i, count;
233   unsigned char buf[PACKETSZ + 1];
234
235   for (i = 0; i < channel->nservers; i++)
236     {
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))
240         continue;
241
242       count = recv(server->udp_socket, buf, sizeof(buf), 0);
243       if (count <= 0)
244         handle_error(channel, i, now);
245
246       process_answer(channel, buf, count, i, 0, now);
247     }
248 }
249
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)
252 {
253   struct query *query, *next;
254
255   for (query = channel->queries; query; query = next)
256     {
257       next = query->next;
258       if (query->timeout != 0 && now >= query->timeout)
259         {
260           query->error_status = ARES_ETIMEOUT;
261           next_server(channel, query, now);
262         }
263     }
264 }
265
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)
269 {
270   int id, tc, rcode;
271   struct query *query;
272
273   /* If there's no room in the answer for a header, we can't do much
274    * with it. */
275   if (alen < HFIXEDSZ)
276     return;
277
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);
282
283   /* Find the query corresponding to this packet. */
284   for (query = channel->queries; query; query = query->next)
285     {
286       if (query->qid == id)
287         break;
288     }
289   if (!query)
290     return;
291
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
294    * done so already.
295    */
296   if ((tc || alen > PACKETSZ) && !tcp && !(channel->flags & ARES_FLAG_IGNTC))
297     {
298       if (!query->using_tcp)
299         {
300           query->using_tcp = 1;
301           ares__send_query(channel, query, now);
302         }
303       return;
304     }
305
306   /* Limit alen to PACKETSZ if we aren't using TCP (only relevant if we
307    * are ignoring truncation.
308    */
309   if (alen > PACKETSZ && !tcp)
310     alen = PACKETSZ;
311
312   /* If we aren't passing through all error packets, discard packets
313    * with SERVFAIL, NOTIMP, or REFUSED response codes.
314    */
315   if (!(channel->flags & ARES_FLAG_NOCHECKRESP))
316     {
317       if (rcode == SERVFAIL || rcode == NOTIMP || rcode == REFUSED)
318         {
319           query->skip_server[whichserver] = 1;
320           if (query->server == whichserver)
321             next_server(channel, query, now);
322           return;
323         }
324       if (!same_questions(query->qbuf, query->qlen, abuf, alen))
325         {
326           if (query->server == whichserver)
327             next_server(channel, query, now);
328           return;
329         }
330     }
331
332   end_query(channel, query, ARES_SUCCESS, abuf, alen);
333 }
334
335 static void handle_error(ares_channel channel, int whichserver, time_t now)
336 {
337   struct query *query;
338
339   /* Reset communications with this server. */
340   ares__close_sockets(&channel->servers[whichserver]);
341
342   /* Tell all queries talking to this server to move on and not try
343    * this server again.
344    */
345   for (query = channel->queries; query; query = query->next)
346     {
347       if (query->server == whichserver)
348         {
349           query->skip_server[whichserver] = 1;
350           next_server(channel, query, now);
351         }
352     }
353 }
354
355 static void next_server(ares_channel channel, struct query *query, time_t now)
356 {
357   /* Advance to the next server or try. */
358   query->server++;
359   for (; query->try < channel->tries; query->try++)
360     {
361       for (; query->server < channel->nservers; query->server++)
362         {
363           if (!query->skip_server[query->server])
364             {
365               ares__send_query(channel, query, now);
366               return;
367             }
368         }
369       query->server = 0;
370
371       /* Only one try if we're using TCP. */
372       if (query->using_tcp)
373         break;
374     }
375   end_query(channel, query, query->error_status, NULL, 0);
376 }
377
378 void ares__send_query(ares_channel channel, struct query *query, time_t now)
379 {
380   struct send_request *sendreq;
381   struct server_state *server;
382
383   server = &channel->servers[query->server];
384   if (query->using_tcp)
385     {
386       /* Make sure the TCP socket for this server is set up and queue
387        * a send request.
388        */
389       if (server->tcp_socket == -1)
390         {
391           if (open_tcp_socket(channel, server) == -1)
392             {
393               query->skip_server[query->server] = 1;
394               next_server(channel, query, now);
395               return;
396             }
397         }
398       sendreq = malloc(sizeof(struct send_request));
399       if (!sendreq)
400         end_query(channel, query, ARES_ENOMEM, NULL, 0);
401       sendreq->data = query->tcpbuf;
402       sendreq->len = query->tcplen;
403       sendreq->next = NULL;
404       if (server->qtail)
405         server->qtail->next = sendreq;
406       else
407         server->qhead = sendreq;
408       server->qtail = sendreq;
409       query->timeout = 0;
410     }
411   else
412     {
413       if (server->udp_socket == -1)
414         {
415           if (open_udp_socket(channel, server) == -1)
416             {
417               query->skip_server[query->server] = 1;
418               next_server(channel, query, now);
419               return;
420             }
421         }
422       if (send(server->udp_socket, query->qbuf, query->qlen, 0) == -1)
423         {
424           query->skip_server[query->server] = 1;
425           next_server(channel, query, now);
426           return;
427         }
428       query->timeout = now
429           + ((query->try == 0) ? channel->timeout
430              : channel->timeout << query->try / channel->nservers);
431     }
432 }
433
434 static int open_tcp_socket(ares_channel channel, struct server_state *server)
435 {
436   int s, flags;
437   struct sockaddr_in sin;
438
439   /* Acquire a socket. */
440   s = socket(AF_INET, SOCK_STREAM, 0);
441   if (s == -1)
442     return -1;
443
444   /* Set the socket non-blocking. */
445   if (fcntl(s, F_GETFL, &flags) == -1)
446     {
447       close(s);
448       return -1;
449     }
450   flags &= O_NONBLOCK;
451   if (fcntl(s, F_SETFL, flags) == -1)
452     {
453       close(s);
454       return -1;
455     }
456
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)
464     {
465       close(s);
466       return -1;
467     }
468
469   server->tcp_socket = s;
470   return 0;
471 }
472
473 static int open_udp_socket(ares_channel channel, struct server_state *server)
474 {
475   int s;
476   struct sockaddr_in sin;
477
478   /* Acquire a socket. */
479   s = socket(AF_INET, SOCK_DGRAM, 0);
480   if (s == -1)
481     return -1;
482
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)
489     {
490       close(s);
491       return -1;
492     }
493
494   server->udp_socket = s;
495   return 0;
496 }
497
498 static int same_questions(const unsigned char *qbuf, int qlen,
499                           const unsigned char *abuf, int alen)
500 {
501   struct {
502     const unsigned char *p;
503     int qdcount;
504     char *name;
505     int namelen;
506     int type;
507     int dnsclass;
508   } q, a;
509   int i, j;
510
511   if (qlen < HFIXEDSZ || alen < HFIXEDSZ)
512     return 0;
513
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)
518     return 0;
519
520   /* For each question in qbuf, find it in abuf. */
521   q.p = qbuf + HFIXEDSZ;
522   for (i = 0; i < q.qdcount; i++)
523     {
524       /* Decode the question in the query. */
525       if (ares_expand_name(q.p, qbuf, qlen, &q.name, &q.namelen)
526           != ARES_SUCCESS)
527         return 0;
528       q.p += q.namelen;
529       if (q.p + QFIXEDSZ > qbuf + qlen)
530         {
531           free(q.name);
532           return 0;
533         }
534       q.type = DNS_QUESTION_TYPE(q.p);
535       q.dnsclass = DNS_QUESTION_CLASS(q.p);
536       q.p += QFIXEDSZ;
537
538       /* Search for this question in the answer. */
539       a.p = abuf + HFIXEDSZ;
540       for (j = 0; j < a.qdcount; j++)
541         {
542           /* Decode the question in the answer. */
543           if (ares_expand_name(a.p, abuf, alen, &a.name, &a.namelen)
544               != ARES_SUCCESS)
545             {
546               free(q.name);
547               return 0;
548             }
549           a.p += a.namelen;
550           if (a.p + QFIXEDSZ > abuf + alen)
551             {
552               free(q.name);
553               free(a.name);
554               return 0;
555             }
556           a.type = DNS_QUESTION_TYPE(a.p);
557           a.dnsclass = DNS_QUESTION_CLASS(a.p);
558           a.p += QFIXEDSZ;
559
560           /* Compare the decoded questions. */
561           if (strcasecmp(q.name, a.name) == 0 && q.type == a.type
562               && q.dnsclass == a.dnsclass)
563             {
564               free(a.name);
565               break;
566             }
567           free(a.name);
568         }
569
570       free(q.name);
571       if (j == a.qdcount)
572         return 0;
573     }
574   return 1;
575 }
576
577 static void end_query(ares_channel channel, struct query *query, int status,
578                       unsigned char *abuf, int alen)
579 {
580   struct query **q;
581   int i;
582
583   query->callback(query->arg, status, abuf, alen);
584   for (q = &channel->queries; *q; q = &(*q)->next)
585     {
586       if (*q == query)
587         break;
588     }
589   *q = query->next;
590   free(query->tcpbuf);
591   free(query->skip_server);
592   free(query);
593
594   /* Simple cleanup policy: if no queries are remaining, close all
595    * network sockets unless STAYOPEN is set.
596    */
597   if (!channel->queries && !(channel->flags & ARES_FLAG_STAYOPEN))
598     {
599       for (i = 0; i < channel->nservers; i++)
600         ares__close_sockets(&channel->servers[i]);
601     }
602 }