Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

ares_process.c

Go to the documentation of this file.
00001 /* Copyright 1998 by the Massachusetts Institute of Technology.
00002  *
00003  * Permission to use, copy, modify, and distribute this
00004  * software and its documentation for any purpose and without
00005  * fee is hereby granted, provided that the above copyright
00006  * notice appear in all copies and that both that copyright
00007  * notice and this permission notice appear in supporting
00008  * documentation, and that the name of M.I.T. not be used in
00009  * advertising or publicity pertaining to distribution of the
00010  * software without specific, written prior permission.
00011  * M.I.T. makes no representations about the suitability of
00012  * this software for any purpose.  It is provided "as is"
00013  * without express or implied warranty.
00014  *
00015  * CHANGELOG: this file has been modified by Sergio Perez Alcañiz <serpeal@disca.upv.es> 
00016  *            Departamento de Informática de Sistemas y Computadores          
00017  *            Universidad Politécnica de Valencia                             
00018  *            Valencia (Spain)    
00019  *            Date: April 2003                                          
00020  *
00021  */
00022 
00023 #include "ares_private.h"
00024 #include "ares_dns.h"
00025 
00026 static void write_tcp_data(ares_channel channel, fd_set *write_fds,
00027                            time_t now);
00028 static void read_tcp_data(ares_channel channel, fd_set *read_fds, time_t now);
00029 static void read_udp_packets(ares_channel channel, fd_set *read_fds,
00030                              time_t now);
00031 static void process_timeouts(ares_channel channel, time_t now);
00032 static void process_answer(ares_channel channel, unsigned char *abuf,
00033                            int alen, int whichserver, int tcp, int now);
00034 static void handle_error(ares_channel channel, int whichserver, time_t now);
00035 static void next_server(ares_channel channel, struct query *query, time_t now);
00036 static int open_tcp_socket(ares_channel channel, struct server_state *server);
00037 static int open_udp_socket(ares_channel channel, struct server_state *server);
00038 static int same_questions(const unsigned char *qbuf, int qlen,
00039                           const unsigned char *abuf, int alen);
00040 static void end_query(ares_channel channel, struct query *query, int status,
00041                       unsigned char *abuf, int alen);
00042 
00043 /* Something interesting happened on the wire, or there was a timeout.
00044  * See what's up and respond accordingly.
00045  */
00046 void ares_process(ares_channel channel, fd_set *read_fds, fd_set *write_fds)
00047 {
00048   time_t now;
00049 
00050   time(&now);
00051   write_tcp_data(channel, write_fds, now);
00052   read_tcp_data(channel, read_fds, now);
00053   read_udp_packets(channel, read_fds, now);
00054   process_timeouts(channel, now);
00055 }
00056 
00057 /* If any TCP sockets select true for writing, write out queued data
00058  * we have for them.
00059  */
00060 static void write_tcp_data(ares_channel channel, fd_set *write_fds, time_t now)
00061 {
00062   struct server_state *server;
00063   struct send_request *sendreq;
00064 #ifdef HAVE_WRITEV
00065   struct iovec *vec;
00066 #endif
00067   int i, n, count;
00068 
00069   for (i = 0; i < channel->nservers; i++)
00070     {
00071       /* Make sure server has data to send and is selected in write_fds. */
00072       server = &channel->servers[i];
00073       if (!server->qhead || server->tcp_socket == -1
00074           || !FD_ISSET(server->tcp_socket, write_fds))
00075         continue;
00076 
00077       /* Count the number of send queue items. */
00078       n = 0;
00079       for (sendreq = server->qhead; sendreq; sendreq = sendreq->next)
00080         n++;
00081 
00082 #ifdef HAVE_WRITEV
00083       /* Allocate iovecs so we can send all our data at once. */
00084       vec = malloc(n * sizeof(struct iovec));
00085       if (vec)
00086         {
00087           /* Fill in the iovecs and send. */
00088           n = 0;
00089           for (sendreq = server->qhead; sendreq; sendreq = sendreq->next)
00090             {
00091               vec[n].iov_base = (char *) sendreq->data;
00092               vec[n].iov_len = sendreq->len;
00093               n++;
00094             }
00095           count = writev(server->tcp_socket, vec, n);
00096           free(vec);
00097           if (count < 0)
00098             {
00099               handle_error(channel, i, now);
00100               continue;
00101             }
00102 
00103           /* Advance the send queue by as many bytes as we sent. */
00104           while (count)
00105             {
00106               sendreq = server->qhead;
00107               if (count >= sendreq->len)
00108                 {
00109                   count -= sendreq->len;
00110                   server->qhead = sendreq->next;
00111                   if (server->qhead == NULL)
00112                     server->qtail = NULL;
00113                   free(sendreq);
00114                 }
00115               else
00116                 {
00117                   sendreq->data += count;
00118                   sendreq->len -= count;
00119                   break;
00120                 }
00121             }
00122         }
00123       else
00124 #endif /* HAVE_WRITEV */
00125         {
00126           /* Can't allocate iovecs; just send the first request. */
00127           sendreq = server->qhead;
00128           count = write(server->tcp_socket, (void *) sendreq->data, sendreq->len);
00129           if (count < 0)
00130             {
00131               handle_error(channel, i, now);
00132               continue;
00133             }
00134 
00135           /* Advance the send queue by as many bytes as we sent. */
00136           if (count == sendreq->len)
00137             {
00138               server->qhead = sendreq->next;
00139               if (server->qhead == NULL)
00140                 server->qtail = NULL;
00141               free(sendreq);
00142             }
00143           else
00144             {
00145               sendreq->data += count;
00146               sendreq->len -= count;
00147             }
00148         }
00149     }
00150 }
00151 
00152 /* If any TCP socket selects true for reading, read some data,
00153  * allocate a buffer if we finish reading the length word, and process
00154  * a packet if we finish reading one.
00155  */
00156 static void read_tcp_data(ares_channel channel, fd_set *read_fds, time_t now)
00157 {
00158   struct server_state *server;
00159   int i, count;
00160 
00161   for (i = 0; i < channel->nservers; i++)
00162     {
00163       /* Make sure the server has a socket and is selected in read_fds. */
00164       server = &channel->servers[i];
00165       if (server->tcp_socket == -1 || !FD_ISSET(server->tcp_socket, read_fds))
00166         continue;
00167 
00168       if (server->tcp_lenbuf_pos != 2)
00169         {
00170           /* We haven't yet read a length word, so read that (or
00171            * what's left to read of it).
00172            */
00173           count = read(server->tcp_socket,
00174                        server->tcp_lenbuf + server->tcp_lenbuf_pos,
00175                        2 - server->tcp_lenbuf_pos);
00176           if (count <= 0)
00177             {
00178               handle_error(channel, i, now);
00179               continue;
00180             }
00181 
00182           server->tcp_lenbuf_pos += count;
00183           if (server->tcp_lenbuf_pos == 2)
00184             {
00185               /* We finished reading the length word.  Decode the
00186                * length and allocate a buffer for the data.
00187                */
00188               server->tcp_length = server->tcp_lenbuf[0] << 8
00189                 | server->tcp_lenbuf[1];
00190               server->tcp_buffer = malloc(server->tcp_length);
00191               if (!server->tcp_buffer)
00192                 handle_error(channel, i, now);
00193               server->tcp_buffer_pos = 0;
00194             }
00195         }
00196       else
00197         {
00198           /* Read data into the allocated buffer. */
00199           count = read(server->tcp_socket,
00200                        server->tcp_buffer + server->tcp_buffer_pos,
00201                        server->tcp_length - server->tcp_buffer_pos);
00202           if (count <= 0)
00203             {
00204               handle_error(channel, i, now);
00205               continue;
00206             }
00207 
00208           server->tcp_buffer_pos += count;
00209           if (server->tcp_buffer_pos == server->tcp_length)
00210             {
00211               /* We finished reading this answer; process it and
00212                * prepare to read another length word.
00213                */
00214               process_answer(channel, server->tcp_buffer, server->tcp_length,
00215                              i, 1, now);
00216               free(server->tcp_buffer);
00217               server->tcp_buffer = NULL;
00218               server->tcp_lenbuf_pos = 0;
00219             }
00220         }
00221     }
00222 }
00223 
00224 /* If any UDP sockets select true for reading, process them. */
00225 static void read_udp_packets(ares_channel channel, fd_set *read_fds,
00226                              time_t now)
00227 {
00228   struct server_state *server;
00229   int i, count;
00230   unsigned char buf[PACKETSZ + 1];
00231 
00232   for (i = 0; i < channel->nservers; i++)
00233     {
00234       /* Make sure the server has a socket and is selected in read_fds. */
00235       server = &channel->servers[i];
00236       if (server->udp_socket == -1 || !FD_ISSET(server->udp_socket, read_fds))
00237         continue;
00238 
00239       count = recv(server->udp_socket, buf, sizeof(buf), 0);
00240       if (count <= 0)
00241         handle_error(channel, i, now);
00242 
00243       process_answer(channel, buf, count, i, 0, now);
00244     }
00245 }
00246 
00247 /* If any queries have timed out, note the timeout and move them on. */
00248 static void process_timeouts(ares_channel channel, time_t now)
00249 {
00250   struct query *query, *next;
00251 
00252   for (query = channel->queries; query; query = next)
00253     {
00254       next = query->next;
00255       if (query->timeout != 0 && now >= query->timeout)
00256         {
00257           query->error_status = ARES_ETIMEOUT;
00258           next_server(channel, query, now);
00259         }
00260     }
00261 }
00262 
00263 /* Handle an answer from a server. */
00264 static void process_answer(ares_channel channel, unsigned char *abuf,
00265                            int alen, int whichserver, int tcp, int now)
00266 {
00267   int id, tc, rcode;
00268   struct query *query;
00269 
00270   /* If there's no room in the answer for a header, we can't do much
00271    * with it. */
00272   if (alen < HFIXEDSZ)
00273     return;
00274 
00275   /* Grab the query ID, truncate bit, and response code from the packet. */
00276   id = DNS_HEADER_QID(abuf);
00277   tc = DNS_HEADER_TC(abuf);
00278   rcode = DNS_HEADER_RCODE(abuf);
00279 
00280   /* Find the query corresponding to this packet. */
00281   for (query = channel->queries; query; query = query->next)
00282     {
00283       if (query->qid == id)
00284         break;
00285     }
00286   if (!query)
00287     return;
00288 
00289   /* If we got a truncated UDP packet and are not ignoring truncation,
00290    * don't accept the packet, and switch the query to TCP if we hadn't
00291    * done so already.
00292    */
00293   if ((tc || alen > PACKETSZ) && !tcp && !(channel->flags & ARES_FLAG_IGNTC))
00294     {
00295       if (!query->using_tcp)
00296         {
00297           query->using_tcp = 1;
00298           ares__send_query(channel, query, now);
00299         }
00300       return;
00301     }
00302 
00303   /* Limit alen to PACKETSZ if we aren't using TCP (only relevant if we
00304    * are ignoring truncation.
00305    */
00306   if (alen > PACKETSZ && !tcp)
00307     alen = PACKETSZ;
00308 
00309   /* If we aren't passing through all error packets, discard packets
00310    * with SERVFAIL, NOTIMP, or REFUSED response codes.
00311    */
00312   if (!(channel->flags & ARES_FLAG_NOCHECKRESP))
00313     {
00314       if (rcode == SERVFAIL || rcode == NOTIMP || rcode == REFUSED)
00315         {
00316           query->skip_server[whichserver] = 1;
00317           if (query->server == whichserver)
00318             next_server(channel, query, now);
00319           return;
00320         }
00321       if (!same_questions(query->qbuf, query->qlen, abuf, alen))
00322         {
00323           if (query->server == whichserver)
00324             next_server(channel, query, now);
00325           return;
00326         }
00327     }
00328 
00329   end_query(channel, query, ARES_SUCCESS, abuf, alen);
00330 }
00331 
00332 static void handle_error(ares_channel channel, int whichserver, time_t now)
00333 {
00334   struct query *query;
00335 
00336   /* Reset communications with this server. */
00337   ares__close_sockets(&channel->servers[whichserver]);
00338 
00339   /* Tell all queries talking to this server to move on and not try
00340    * this server again.
00341    */
00342   for (query = channel->queries; query; query = query->next)
00343     {
00344       if (query->server == whichserver)
00345         {
00346           query->skip_server[whichserver] = 1;
00347           next_server(channel, query, now);
00348         }
00349     }
00350 }
00351 
00352 static void next_server(ares_channel channel, struct query *query, time_t now)
00353 {
00354   /* Advance to the next server or try. */
00355   query->server++;
00356   for (; query->try < channel->tries; query->try++)
00357     {
00358       for (; query->server < channel->nservers; query->server++)
00359         {
00360           if (!query->skip_server[query->server])
00361             {
00362               ares__send_query(channel, query, now);
00363               return;
00364             }
00365         }
00366       query->server = 0;
00367 
00368       /* Only one try if we're using TCP. */
00369       if (query->using_tcp)
00370         break;
00371     }
00372   end_query(channel, query, query->error_status, NULL, 0);
00373 }
00374 
00375 void ares__send_query(ares_channel channel, struct query *query, time_t now)
00376 {
00377   struct send_request *sendreq;
00378   struct server_state *server;
00379 
00380   server = &channel->servers[query->server];
00381 
00382   if (query->using_tcp)
00383     {
00384       /* Make sure the TCP socket for this server is set up and queue
00385        * a send request.
00386        */
00387       if (server->tcp_socket == -1)
00388         {
00389           if (open_tcp_socket(channel, server) == -1)
00390             {
00391               query->skip_server[query->server] = 1;
00392               next_server(channel, query, now);
00393               return;
00394             }
00395         }
00396       sendreq = malloc(sizeof(struct send_request));
00397       if (!sendreq)
00398         end_query(channel, query, ARES_ENOMEM, NULL, 0);
00399       sendreq->data = query->tcpbuf;
00400       sendreq->len = query->tcplen;
00401       sendreq->next = NULL;
00402       if (server->qtail)
00403         server->qtail->next = sendreq;
00404       else
00405         server->qhead = sendreq;
00406       server->qtail = sendreq;
00407       query->timeout = 0;
00408     }
00409   else
00410     {
00411       if (server->udp_socket == -1)
00412         {
00413           if (open_udp_socket(channel, server) == -1)
00414             {
00415               query->skip_server[query->server] = 1;
00416               next_server(channel, query, now);
00417               return;
00418             }
00419         }
00420       if (send(server->udp_socket, (void *) query->qbuf, query->qlen, 0) == -1)
00421         {
00422           query->skip_server[query->server] = 1;
00423           next_server(channel, query, now);
00424           return;
00425         }
00426       query->timeout = now
00427           + ((query->try == 0) ? channel->timeout
00428              : channel->timeout << query->try / channel->nservers);
00429     }
00430 }
00431 
00432 static int open_tcp_socket(ares_channel channel, struct server_state *server)
00433 {
00434   int s;
00435   struct sockaddr_in sin;
00436 
00437   /* Acquire a socket. */
00438   s = socket(AF_INET, SOCK_STREAM, 0);
00439   if (s == -1)
00440     return -1;
00441 
00442   /* Set the socket non-blocking. */
00443 #ifdef __LWIP_SOCKETS_H__
00444   {
00445           u32_t on = 1;
00446           if (lwip_ioctl(s, FIONBIO, &on))
00447           {
00448                   close(s);
00449                   return -1;
00450           }
00451   }
00452 #else
00453   {
00454   int flags;
00455 
00456   if (fcntl(s, F_GETFL, &flags) == -1)
00457     {
00458       close(s);
00459       return -1;
00460     }
00461   flags &= O_NONBLOCK;
00462   if (fcntl(s, F_SETFL, flags) == -1)
00463     {
00464       close(s);
00465       return -1;
00466     }
00467   }
00468 #endif
00469 
00470   /* Connect to the server. */
00471   memset(&sin, 0, sizeof(sin));
00472   sin.sin_family = AF_INET;
00473 
00474   sin.sin_addr = server->addr;
00475 
00476   sin.sin_port = channel->tcp_port;
00477   if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == -1
00478       && errno != EINPROGRESS)
00479     {
00480       close(s);
00481       return -1;
00482     }
00483 
00484   server->tcp_socket = s;
00485   return 0;
00486 }
00487 
00488 static int open_udp_socket(ares_channel channel, struct server_state *server)
00489 {
00490   int s;
00491   struct sockaddr_in sin;
00492 
00493   /* Acquire a socket. */
00494   s = socket(AF_INET, SOCK_DGRAM, 0);
00495   if (s == -1)
00496     return -1;
00497 
00498   /* Connect to the server. */
00499   memset(&sin, 0, sizeof(sin));
00500   sin.sin_family = AF_INET;
00501   sin.sin_addr = server->addr;
00502   sin.sin_port = channel->udp_port;
00503   if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == -1)
00504     {
00505       close(s);
00506       return -1;
00507     }
00508 
00509   server->udp_socket = s;
00510   return 0;
00511 }
00512 
00513 static int same_questions(const unsigned char *qbuf, int qlen,
00514                           const unsigned char *abuf, int alen)
00515 {
00516   struct {
00517     const unsigned char *p;
00518     int qdcount;
00519     char *name;
00520     int namelen;
00521     int type;
00522     int dnsclass;
00523   } q, a;
00524   int i, j;
00525 
00526   if (qlen < HFIXEDSZ || alen < HFIXEDSZ)
00527     return 0;
00528 
00529   /* Extract qdcount from the request and reply buffers and compare them. */
00530   q.qdcount = DNS_HEADER_QDCOUNT(qbuf);
00531   a.qdcount = DNS_HEADER_QDCOUNT(abuf);
00532   if (q.qdcount != a.qdcount)
00533     return 0;
00534 
00535   /* For each question in qbuf, find it in abuf. */
00536   q.p = qbuf + HFIXEDSZ;
00537   for (i = 0; i < q.qdcount; i++)
00538     {
00539       /* Decode the question in the query. */
00540       if (ares_expand_name(q.p, qbuf, qlen, &q.name, &q.namelen)
00541           != ARES_SUCCESS)
00542         return 0;
00543       q.p += q.namelen;
00544       if (q.p + QFIXEDSZ > qbuf + qlen)
00545         {
00546           free(q.name);
00547           return 0;
00548         }
00549       q.type = DNS_QUESTION_TYPE(q.p);
00550       q.dnsclass = DNS_QUESTION_CLASS(q.p);
00551       q.p += QFIXEDSZ;
00552 
00553       /* Search for this question in the answer. */
00554       a.p = abuf + HFIXEDSZ;
00555       for (j = 0; j < a.qdcount; j++)
00556         {
00557           /* Decode the question in the answer. */
00558           if (ares_expand_name(a.p, abuf, alen, &a.name, &a.namelen)
00559               != ARES_SUCCESS)
00560             {
00561               free(q.name);
00562               return 0;
00563             }
00564           a.p += a.namelen;
00565           if (a.p + QFIXEDSZ > abuf + alen)
00566             {
00567               free(q.name);
00568               free(a.name);
00569               return 0;
00570             }
00571           a.type = DNS_QUESTION_TYPE(a.p);
00572           a.dnsclass = DNS_QUESTION_CLASS(a.p);
00573           a.p += QFIXEDSZ;
00574 
00575           /* Compare the decoded questions. */
00576           if (strcasecmp(q.name, a.name) == 0 && q.type == a.type
00577               && q.dnsclass == a.dnsclass)
00578             {
00579               free(a.name);
00580               break;
00581             }
00582           free(a.name);
00583         }
00584 
00585       free(q.name);
00586       if (j == a.qdcount)
00587         return 0;
00588     }
00589   return 1;
00590 }
00591 
00592 static void end_query(ares_channel channel, struct query *query, int status,
00593                       unsigned char *abuf, int alen)
00594 {
00595   struct query **q;
00596   int i;
00597 
00598   query->callback(query->arg, status, abuf, alen);
00599   for (q = &channel->queries; *q; q = &(*q)->next)
00600     {
00601       if (*q == query)
00602         break;
00603     }
00604   *q = query->next;
00605   free(query->tcpbuf);
00606   free(query->skip_server);
00607   free(query);
00608 
00609   /* Simple cleanup policy: if no queries are remaining, close all
00610    * network sockets unless STAYOPEN is set.
00611    */
00612   if (!channel->queries && !(channel->flags & ARES_FLAG_STAYOPEN))
00613     {
00614       for (i = 0; i < channel->nservers; i++)
00615         ares__close_sockets(&channel->servers[i]);
00616     }
00617 }

Generated on Wed Jan 14 12:58:56 2004 for RTL-lwIP-0.4 by doxygen 1.3.4