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

ares_process.c File Reference

#include "ares_private.h"
#include "ares_dns.h"

Include dependency graph for ares_process.c:

Go to the source code of this file.

Functions

void write_tcp_data (ares_channel channel, fd_set *write_fds, time_t now)
void read_tcp_data (ares_channel channel, fd_set *read_fds, time_t now)
void read_udp_packets (ares_channel channel, fd_set *read_fds, time_t now)
void process_timeouts (ares_channel channel, time_t now)
void process_answer (ares_channel channel, unsigned char *abuf, int alen, int whichserver, int tcp, int now)
void handle_error (ares_channel channel, int whichserver, time_t now)
void next_server (ares_channel channel, struct query *query, time_t now)
int open_tcp_socket (ares_channel channel, struct server_state *server)
int open_udp_socket (ares_channel channel, struct server_state *server)
int same_questions (const unsigned char *qbuf, int qlen, const unsigned char *abuf, int alen)
void end_query (ares_channel channel, struct query *query, int status, unsigned char *abuf, int alen)
void ares_process (ares_channel channel, fd_set *read_fds, fd_set *write_fds)
void ares__send_query (ares_channel channel, struct query *query, time_t now)


Function Documentation

void ares__send_query ares_channel  channel,
struct query query,
time_t  now
 

Definition at line 375 of file ares_process.c.

References ares_channel, ARES_ENOMEM, end_query(), malloc, next_server(), ares_channeldata::nservers, NULL, open_tcp_socket(), open_udp_socket(), query::qbuf, query::qlen, query::server, ares_channeldata::servers, query::skip_server, query::tcpbuf, query::tcplen, ares_channeldata::timeout, query::timeout, query::try, and query::using_tcp.

Referenced by ares_send(), next_server(), and process_answer().

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 }

Here is the call graph for this function:

void ares_process ares_channel  channel,
fd_set read_fds,
fd_set write_fds
 

Definition at line 46 of file ares_process.c.

References ares_channel, process_timeouts(), read_tcp_data(), read_udp_packets(), time, and write_tcp_data().

Referenced by dns_client(), and gethostbynameaddr().

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 }

Here is the call graph for this function:

void end_query ares_channel  channel,
struct query query,
int  status,
unsigned char *  abuf,
int  alen
[static]
 

Definition at line 592 of file ares_process.c.

References ares__close_sockets(), ares_channel, ARES_FLAG_STAYOPEN, query::arg, query::callback, ares_channeldata::flags, free, query::next, ares_channeldata::nservers, ares_channeldata::queries, ares_channeldata::servers, query::skip_server, status, and query::tcpbuf.

Referenced by ares__send_query(), next_server(), and process_answer().

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 }

Here is the call graph for this function:

void handle_error ares_channel  channel,
int  whichserver,
time_t  now
[static]
 

Definition at line 332 of file ares_process.c.

References ares__close_sockets(), ares_channel, query::next, next_server(), ares_channeldata::queries, and ares_channeldata::servers.

Referenced by read_tcp_data(), read_udp_packets(), and write_tcp_data().

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 }

Here is the call graph for this function:

void next_server ares_channel  channel,
struct query query,
time_t  now
[static]
 

Definition at line 352 of file ares_process.c.

References ares__send_query(), ares_channel, end_query(), query::error_status, ares_channeldata::nservers, NULL, query::server, query::skip_server, ares_channeldata::tries, query::try, and query::using_tcp.

Referenced by ares__send_query(), handle_error(), process_answer(), and process_timeouts().

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 }

Here is the call graph for this function:

int open_tcp_socket ares_channel  channel,
struct server_state server
[static]
 

Definition at line 432 of file ares_process.c.

References server_state::addr, AF_INET, ares_channel, FIONBIO, lwip_ioctl(), O_NONBLOCK, sockaddr_in::sin_addr, sockaddr_in::sin_family, sockaddr_in::sin_port, SOCK_STREAM, ares_channeldata::tcp_port, server_state::tcp_socket, and u32_t.

Referenced by ares__send_query().

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 }

Here is the call graph for this function:

int open_udp_socket ares_channel  channel,
struct server_state server
[static]
 

Definition at line 488 of file ares_process.c.

References server_state::addr, AF_INET, ares_channel, sockaddr_in::sin_addr, sockaddr_in::sin_family, sockaddr_in::sin_port, SOCK_DGRAM, ares_channeldata::udp_port, and server_state::udp_socket.

Referenced by ares__send_query().

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 }

void process_answer ares_channel  channel,
unsigned char *  abuf,
int  alen,
int  whichserver,
int  tcp,
int  now
[static]
 

Definition at line 264 of file ares_process.c.

References ares__send_query(), ares_channel, ARES_FLAG_IGNTC, ARES_FLAG_NOCHECKRESP, ARES_SUCCESS, DNS_HEADER_QID, DNS_HEADER_RCODE, DNS_HEADER_TC, end_query(), ares_channeldata::flags, HFIXEDSZ, query::next, next_server(), NOTIMP, PACKETSZ, ares_channeldata::queries, REFUSED, same_questions(), and SERVFAIL.

Referenced by read_tcp_data(), and read_udp_packets().

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 }

Here is the call graph for this function:

void process_timeouts ares_channel  channel,
time_t  now
[static]
 

Definition at line 248 of file ares_process.c.

References ares_channel, ARES_ETIMEOUT, fsdata_file::next, next, next_server(), and ares_channeldata::queries.

Referenced by ares_process().

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 }

Here is the call graph for this function:

void read_tcp_data ares_channel  channel,
fd_set read_fds,
time_t  now
[static]
 

Definition at line 156 of file ares_process.c.

References ares_channel, FD_ISSET, free, handle_error(), malloc, ares_channeldata::nservers, NULL, process_answer(), and ares_channeldata::servers.

Referenced by ares_process().

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 }

Here is the call graph for this function:

void read_udp_packets ares_channel  channel,
fd_set read_fds,
time_t  now
[static]
 

Definition at line 225 of file ares_process.c.

References ares_channel, FD_ISSET, handle_error(), ares_channeldata::nservers, PACKETSZ, process_answer(), and ares_channeldata::servers.

Referenced by ares_process().

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 }

Here is the call graph for this function:

int same_questions const unsigned char *  qbuf,
int  qlen,
const unsigned char *  abuf,
int  alen
[static]
 

Definition at line 513 of file ares_process.c.

References ares_expand_name(), ARES_SUCCESS, DNS_HEADER_QDCOUNT, DNS_QUESTION_CLASS, DNS_QUESTION_TYPE, free, HFIXEDSZ, name, QFIXEDSZ, and strcasecmp.

Referenced by process_answer().

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 }

Here is the call graph for this function:

void write_tcp_data ares_channel  channel,
fd_set write_fds,
time_t  now
[static]
 

Definition at line 60 of file ares_process.c.

References ares_channel, FD_ISSET, free, handle_error(), malloc, ares_channeldata::nservers, NULL, and ares_channeldata::servers.

Referenced by ares_process().

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 }

Here is the call graph for this function:


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