Back to index

opendkim  2.6.6
ar.c
Go to the documentation of this file.
00001 /*
00002 **  Copyright (c) 2004-2009 Sendmail, Inc. and its suppliers.
00003 **    All rights reserved.
00004 **
00005 **  Copyright (c) 2009-2012, The OpenDKIM Project.  All rights reserved.
00006 */
00007 
00008 #ifndef lint
00009 static char ar_c_id[] = "@(#)$Id: ar.c,v 1.12 2010/10/04 21:20:47 cm-msk Exp $";
00010 #endif /* !lint */
00011 
00012 /* OS stuff */
00013 #if HPUX11
00014 # define _XOPEN_SOURCE_EXTENDED
00015 #endif /* HPUX11 */
00016 
00017 #include "build-config.h"
00018 
00019 /* system includes */
00020 #include <sys/param.h>
00021 #include <sys/types.h>
00022 #if SOLARIS > 20700
00023 # include <iso/limits_iso.h>
00024 #endif /* SOLARIS > 20700 */
00025 #include <sys/socket.h>
00026 #include <sys/time.h>
00027 #include <sys/uio.h>
00028 #include <netinet/in.h>
00029 #include <arpa/inet.h>
00030 #include <arpa/nameser.h>
00031 #include <ctype.h>
00032 #include <resolv.h>
00033 #include <netdb.h>
00034 #ifdef HAVE_STDBOOL_H
00035 # include <stdbool.h>
00036 #endif /* HAVE_STDBOOL_H */
00037 #include <stdlib.h>
00038 #include <time.h>
00039 #include <errno.h>
00040 #include <unistd.h>
00041 #include <pthread.h>
00042 #include <assert.h>
00043 #include <signal.h>
00044 #include <string.h>
00045 #include <syslog.h>
00046 #include <stdio.h>
00047 
00048 /* important macros */
00049 #define AR_MAXHOSTNAMELEN   256
00050 
00051 #define       ARDEBUGOUT    "/var/tmp/ardebug.out"
00052 
00053 #define       BUFRSZ        1024
00054 
00055 #ifndef MAXPACKET
00056 # define MAXPACKET   8192
00057 #endif /* ! MAXPACKET */
00058 
00059 #define QUERYLIMIT   32768
00060 
00061 #ifndef MAX
00062 # define MAX(x,y)    ((x) > (y) ? (x) : (y))
00063 #endif /* ! MAX */
00064 
00065 #ifndef MIN
00066 # define MIN(x,y)    ((x) < (y) ? (x) : (y))
00067 #endif /* ! MIN */
00068 
00069 #ifndef MSG_WAITALL
00070 # define MSG_WAITALL 0
00071 #endif /* ! MSG_WAITALL */
00072 
00073 #if defined(__RES) && (__RES >= 19940415)
00074 # define RES_UNC_T          char *
00075 #else /* __RES && __RES >= 19940415 */
00076 # define RES_UNC_T          unsigned char *
00077 #endif /* __RES && __RES >= 19940415 */
00078 
00079 /* ar includes */
00080 #include "async-resolv.h"
00081 #include "ar-socket.h"
00082 #include "ar-strl.h"
00083 #include "manual.h"
00084 
00085 /*
00086 **  DATA TYPES
00087 */
00088 
00089 struct ar_query
00090 {
00091        int                  q_depth;
00092        int                  q_flags;
00093        int                  q_class;
00094        int                  q_type;
00095        int                  q_id;
00096        int                  q_tries;
00097        size_t               q_buflen;
00098        size_t               q_replylen;
00099        int *                q_errno;
00100        unsigned char *             q_buf;
00101        pthread_cond_t              q_reply;
00102        pthread_mutex_t             q_lock;
00103        struct ar_query *    q_next;
00104        struct timeval              q_timeout;
00105        struct timeval              q_sent;
00106        char                 q_name[AR_MAXHOSTNAMELEN + 1];
00107 };
00108 
00109 #ifdef AF_INET6
00110 typedef struct sockaddr_storage SOCKADDR;
00111 #else /* AF_INET6 */
00112 typedef struct sockaddr SOCKADDR;
00113 #endif /* AF_INET6 */
00114 
00115 struct ar_libhandle
00116 {
00117        int                  ar_drun;
00118        int                  ar_partwrite;
00119        int                  ar_fullwrite;
00120        int                  ar_nsfd;
00121        int                  ar_nsfdpf;
00122        int                  ar_control[2];
00123        int                  ar_nscount;
00124        int                  ar_nsidx;
00125        int                  ar_deaderrno;
00126        int                  ar_resend;
00127        int                  ar_retries;
00128        u_int                ar_flags;
00129        size_t               ar_tcpmsglen;
00130        size_t               ar_tcpbuflen;
00131        size_t               ar_tcpbufidx;
00132        size_t               ar_writelen;
00133        size_t               ar_querybuflen;
00134        pthread_t            ar_dispatcher;
00135        pthread_mutex_t             ar_lock;
00136        unsigned char *             ar_querybuf;
00137        unsigned char *             ar_tcpbuf;
00138        SOCKADDR *           ar_nsaddrs;
00139        AR_SOCKET_SET        ar_css;              /* client socket set */
00140        AR_SOCKET_SET        ar_dss;              /* dispatcher socket set */
00141        void *               (*ar_malloc) (void *closure, size_t nbytes);
00142        void                 (*ar_free) (void *closure, void *p);
00143        void *               ar_closure;
00144        struct ar_query *    ar_pending;   /* to be sent (queue head) */
00145        struct ar_query *    ar_pendingtail;      /* to be sent (queue tail) */
00146        struct ar_query *    ar_queries;   /* awaiting replies (head) */
00147        struct ar_query *    ar_queriestail;      /* awaiting replies (tail) */
00148        struct ar_query *    ar_recycle;   /* recyclable queries */
00149        struct iovec         ar_iovec[2];  /* I/O vector */
00150        struct timeval              ar_retry;     /* retry interval */
00151        struct timeval              ar_deadsince; /* when we lost all service */
00152        struct timeval              ar_revivify;  /* how long to play dead */
00153        struct __res_state   ar_res;              /* resolver data */
00154 };
00155 
00156 /*
00157 **  DEFINITIONS
00158 */
00159 
00160 #define       QUERY_INFINIWAIT     0x01          /* infinite wait */
00161 #define       QUERY_REPLY          0x02          /* reply stored */
00162 #define       QUERY_NOREPLY        0x04          /* query expired */
00163 #define       QUERY_ERROR          0x08          /* error sending */
00164 #define       QUERY_RESEND         0x10          /* resend pending */
00165 
00166 /*
00167 **  PROTOTYPES
00168 */
00169 
00170 static void *ar_malloc(AR_LIB, size_t);
00171 static void ar_free(AR_LIB lib, void *ptr);
00172 static int ar_res_init(AR_LIB);
00173 
00174 /*
00175 **  GLOBALS
00176 */
00177 
00178 #ifdef ARDEBUG
00179 static FILE *debugout;
00180 #endif /* ARDEBUG */
00181 
00182 /*
00183 **  ========================= PRIVATE FUNCTIONS =========================
00184 */
00185 
00186 #ifdef ARDEBUG
00187 /*
00188 **  AR_DEBUG_INIT -- set up debugging output
00189 **
00190 **  Parameters:
00191 **     None.
00192 **
00193 **  Return value:
00194 **     None.
00195 */
00196 
00197 static void
00198 ar_debug_init(void)
00199 {
00200        debugout = fopen(ARDEBUGOUT, "w");
00201        if (debugout != NULL)
00202               setlinebuf(debugout);
00203 }
00204 
00205 /*
00206 **  AR_DEBUG_STOP -- close debugging output
00207 **
00208 **  Parameters:
00209 **     None.
00210 **
00211 **  Return value:
00212 **     None.
00213 */
00214 
00215 static void
00216 ar_debug_stop(void)
00217 {
00218        fclose(debugout);
00219 }
00220 /*
00221 **  AR_DEBUG_LOCKINIT -- print lock information
00222 **
00223 **  Parameters:
00224 **     lock -- lock to be created
00225 **     attr -- lock attributes
00226 **     line -- line number where this was called
00227 **
00228 **  Return value:
00229 **     See pthread_mutex_lock().
00230 */
00231 
00232 static int
00233 ar_debug_lockinit(pthread_mutex_t *lock, pthread_mutexattr_t *attr, int line)
00234 {
00235        fprintf(debugout, "%d: %lu: mutex_init(%p, %p)\n", line,
00236                pthread_self(), lock, attr);
00237 
00238        return pthread_mutex_init(lock, attr);
00239 }
00240 
00241 /*
00242 **  AR_DEBUG_LOCK -- print lock information
00243 **
00244 **  Parameters:
00245 **     lock -- lock to be retrieved
00246 **     line -- line number where this was called
00247 **
00248 **  Return value:
00249 **     See pthread_mutex_lock().
00250 */
00251 
00252 static int
00253 ar_debug_lock(pthread_mutex_t *lock, int line)
00254 {
00255        int ret;
00256 
00257        fprintf(debugout, "%d: %lu: lock(%p)\n", line,
00258                pthread_self(), lock);
00259 
00260        ret = pthread_mutex_lock(lock);
00261 
00262        fprintf(debugout, "%d: %lu: lock acquired\n", line, pthread_self());
00263 
00264        return ret;
00265 }
00266 
00267 /*
00268 **  AR_DEBUG_UNLOCK -- print unlock information
00269 **
00270 **  Parameters:
00271 **     lock -- lock to be released
00272 **     line -- line number where this was called
00273 **
00274 **  Return value:
00275 **     See pthread_mutex_unlock().
00276 */
00277 
00278 static int
00279 ar_debug_unlock(pthread_mutex_t *lock, int line)
00280 {
00281        fprintf(debugout, "%d: %lu: unlock(%p)\n", line,
00282                pthread_self(), lock);
00283 
00284        return pthread_mutex_unlock(lock);
00285 }
00286 
00287 /*
00288 **  AR_DEBUG_SIGNAL -- signal condition
00289 **
00290 **  Parameters:
00291 **     cond -- condition to be signaled
00292 **     line -- line number where this was called
00293 **
00294 **  Return value:
00295 **     See pthread_mutex_unlock().
00296 */
00297 
00298 static int
00299 ar_debug_signal(pthread_cond_t *cond, int line)
00300 {
00301        fprintf(debugout, "%d: %lu: signal(%p)\n", line,
00302                pthread_self(), cond);
00303 
00304        return pthread_cond_signal(cond);
00305 }
00306 
00307 /*
00308 **  AR_DEBUG_CONDWAIT -- wait for a condition
00309 **
00310 **  Parameters:
00311 **     cond -- condition variable
00312 **     lock -- mutex
00313 **     line -- line number
00314 **
00315 **  Return value:
00316 **     See pthread_cond_wait().
00317 */
00318 
00319 static int
00320 ar_debug_condwait(pthread_cond_t *cond, pthread_mutex_t *lock, int line)
00321 {
00322        int ret;
00323 
00324        fprintf(debugout, "%d: %lu: wait(%p, %p)\n", line,
00325                pthread_self(), cond, lock);
00326 
00327        ret = pthread_cond_wait(cond, lock);
00328 
00329        fprintf(debugout, "%d: %lu: signal received\n", cond, lock);
00330 
00331        return ret;
00332 }
00333 
00334 /*
00335 **  AR_DEBUG_CONDTIMEDWAIT -- wait for a condition with timeout
00336 **
00337 **  Parameters:
00338 **     cond -- condition variable
00339 **     lock -- mutex
00340 **     timeout -- timeout
00341 **     line -- line number
00342 **
00343 **  Return value:
00344 **     See pthread_cond_timedwait().
00345 */
00346 
00347 static int
00348 ar_debug_condtimedwait(pthread_cond_t *cond, pthread_mutex_t *lock,
00349                        struct timespec *timeout, int line)
00350 {
00351        int ret;
00352 
00353        fprintf(debugout, "%d: %lu: timedwait(%p, %p, %p)\n", line,
00354                pthread_self(), cond, lock, timeout);
00355 
00356        ret = pthread_cond_timedwait(cond, lock, timeout);
00357 
00358        fprintf(debugout, "%d: %lu: %s\n", line, pthread_self(),
00359                ret == ETIMEDOUT ? "timeout" : "signal received");
00360 
00361        return ret;
00362 }
00363 
00364 # define pthread_cond_signal(x)           ar_debug_signal((x), __LINE__)
00365 # define pthread_cond_timedwait(x,y,z)    ar_debug_condtimedwait((x), (y), (z), __LINE__)
00366 # define pthread_cond_wait(x,y)           ar_debug_condwait((x), (y), __LINE__)
00367 # define pthread_mutex_init(x,y)   ar_debug_lockinit((x), (y), __LINE__)
00368 # define pthread_mutex_lock(x)            ar_debug_lock((x), __LINE__)
00369 # define pthread_mutex_unlock(x)   ar_debug_unlock((x), __LINE__)
00370 #endif /* ARDEBUG */
00371 
00372 /*
00373 **  AR_MALLOC -- allocate memory
00374 **
00375 **  Parameters:
00376 **     lib -- library handle
00377 **     bytes -- how many bytes to get
00378 **
00379 **  Return value:
00380 **     Pointer to newly available memory, or NULL on error.
00381 */
00382 
00383 static void *
00384 ar_malloc(AR_LIB lib, size_t bytes)
00385 {
00386        assert(lib != NULL);
00387 
00388        if (lib->ar_malloc != NULL)
00389               return lib->ar_malloc(lib->ar_closure, bytes);
00390        else
00391               return malloc(bytes);
00392 }
00393 
00394 /*
00395 **  AR_FREE -- release memory
00396 **
00397 **  Parameters:
00398 **     lib -- library handle
00399 **     ptr -- pointer to memory to release
00400 **
00401 **  Return value:
00402 **     None.
00403 */
00404 
00405 static void
00406 ar_free(AR_LIB lib, void *ptr)
00407 {
00408        assert(lib != NULL);
00409        assert(ptr != NULL);
00410 
00411        if (lib->ar_free != NULL)
00412               lib->ar_free(lib->ar_closure, ptr);
00413        else
00414               free(ptr);
00415 }
00416 
00417 /*
00418 **  AR_SMASHQUEUE -- smash everything in a list of queue handles
00419 **
00420 **  Parameters:
00421 **     q -- query at the head of the list to clobber
00422 **
00423 **  Return value:
00424 **     None.
00425 **
00426 **  Notes:
00427 **     Very destructive.
00428 */
00429 
00430 static void
00431 ar_smashqueue(AR_LIB lib, AR_QUERY q)
00432 {
00433        AR_QUERY cur;
00434        AR_QUERY next;
00435 
00436        assert(lib != NULL);
00437 
00438        if (q == NULL)
00439               return;
00440 
00441        cur = q;
00442        while (cur != NULL)
00443        {
00444               next = cur->q_next;
00445 
00446               ar_free(lib, cur);
00447 
00448               cur = next;
00449        }
00450 }
00451 
00452 /*
00453 **  AR_TIMELEFT -- given a start time and a duration, see how much is left
00454 **
00455 **  Parameters:
00456 **     start -- start time
00457 **     length -- run time
00458 **     remain -- how much time is left (updated)
00459 **
00460 **  Return value:
00461 **     None.
00462 **
00463 **  Notes:
00464 **     If "start" is NULL, "length" is taken to be the end time.
00465 */
00466 
00467 static void
00468 ar_timeleft(struct timeval *start, struct timeval *length,
00469             struct timeval *remain)
00470 {
00471        struct timeval now;
00472        struct timeval end;
00473 
00474        assert(length != NULL);
00475        assert(remain != NULL);
00476 
00477        (void) gettimeofday(&now, NULL);
00478 
00479        if (start == NULL)
00480        {
00481               memcpy(&end, length, sizeof end);
00482        }
00483        else
00484        {
00485               end.tv_sec = start->tv_sec + length->tv_sec;
00486               end.tv_usec = start->tv_usec + length->tv_usec;
00487               end.tv_sec += end.tv_usec / 1000000;
00488               end.tv_usec = end.tv_usec % 1000000;
00489        }
00490 
00491        if (now.tv_sec > end.tv_sec ||
00492            (now.tv_sec == end.tv_sec && now.tv_usec > end.tv_usec))
00493        {
00494               remain->tv_sec = 0;
00495               remain->tv_usec = 0;
00496        }
00497        else
00498        {
00499               remain->tv_sec = end.tv_sec - now.tv_sec;
00500               if (end.tv_usec < now.tv_usec)
00501               {
00502                      remain->tv_sec--;
00503                      remain->tv_usec = end.tv_usec - now.tv_usec + 1000000;
00504               }
00505               else
00506               {
00507                      remain->tv_usec = end.tv_usec - now.tv_usec;
00508               }
00509        }
00510 }
00511 
00512 /*
00513 **  AR_ELAPSED -- determine whether or not a certain amount of time has
00514 **                elapsed
00515 **
00516 **  Parameters:
00517 **     start -- start time
00518 **     length -- run time
00519 **
00520 **  Return value:
00521 **     TRUE iff length has elapsed since start.
00522 */
00523 
00524 static _Bool
00525 ar_elapsed(struct timeval *start, struct timeval *length)
00526 {
00527        struct timeval now;
00528        struct timeval tmp;
00529 
00530        assert(start != NULL);
00531        assert(length != NULL);
00532 
00533        (void) gettimeofday(&now, NULL);
00534 
00535        tmp.tv_sec = start->tv_sec + length->tv_sec;
00536        tmp.tv_usec = start->tv_usec + length->tv_usec;
00537        if (tmp.tv_usec >= 1000000)
00538        {
00539               tmp.tv_usec -= 1000000;
00540               tmp.tv_sec += 1;
00541        }
00542 
00543        if (tmp.tv_sec < now.tv_sec ||
00544            (tmp.tv_sec == now.tv_sec && tmp.tv_usec < now.tv_usec))
00545               return TRUE;
00546 
00547        return FALSE;
00548 }
00549 
00550 /*
00551 **  AR_UNDOT -- remove a trailing dot if there is one
00552 **
00553 **  Parameters:
00554 **     str -- string to modify
00555 **
00556 **  Return value:
00557 **     None.
00558 */
00559 
00560 static void
00561 ar_undot(char *str)
00562 {
00563        char *p;
00564 
00565        assert(str != NULL);
00566 
00567        for (p = str; *p != '\0'; p++)
00568        {
00569               if (*p == '.' && *(p + 1) == '\0')
00570               {
00571                      *p = '\0';
00572                      break;
00573               }
00574        }
00575 }
00576 
00577 /*
00578 **  AR_EXPIRED -- see if a query has expired
00579 **
00580 **  Parameters:
00581 **     q -- query being checked
00582 **
00583 **  Return value:
00584 **     1 if the query has expired, 0 otherwise
00585 */
00586 
00587 static int
00588 ar_expired(AR_QUERY q)
00589 {
00590        struct timeval now;
00591 
00592        assert(q != NULL);
00593 
00594        if (q->q_timeout.tv_sec == 0 || (q->q_flags & QUERY_INFINIWAIT) != 0)
00595               return 0;
00596 
00597        (void) gettimeofday(&now, NULL);
00598 
00599        if (q->q_timeout.tv_sec < now.tv_sec)
00600               return 1;
00601 
00602        if (q->q_timeout.tv_sec == now.tv_sec &&
00603            q->q_timeout.tv_usec < now.tv_usec)
00604               return 1;
00605 
00606        return 0;
00607 }
00608 
00609 /*
00610 **  AR_ALLDEAD -- mark all pending and active queries dead
00611 **
00612 **  Parameters:
00613 **     lib -- library handle
00614 **
00615 **  Return value:
00616 **     None.
00617 */
00618 
00619 static void
00620 ar_alldead(AR_LIB lib)
00621 {
00622        AR_QUERY q;
00623 
00624        assert(lib != NULL);
00625 
00626        if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
00627               syslog(LOG_DEBUG, "arlib: marking all queries dead");
00628 
00629        /* tack the pending list to the end of the active list */
00630        if (lib->ar_pending != NULL)
00631        {
00632               if (lib->ar_queriestail != NULL)
00633               {
00634                      lib->ar_queriestail->q_next = lib->ar_pending;
00635               }
00636               else
00637               {
00638                      lib->ar_queries = lib->ar_pending;
00639               }
00640 
00641               lib->ar_queriestail = lib->ar_pendingtail;
00642 
00643               lib->ar_pending = NULL;
00644               lib->ar_pendingtail = NULL;
00645        }
00646 
00647        /* mark everything with QUERY_ERROR and wake them all up */
00648        for (q = lib->ar_queries; q != NULL; q = q->q_next)
00649        {
00650               pthread_mutex_lock(&q->q_lock);
00651 
00652               q->q_flags |= QUERY_ERROR;
00653               if (q->q_errno != NULL)
00654                      *q->q_errno = QUERY_ERRNO_SERVICE;
00655 
00656               if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
00657                      syslog(LOG_DEBUG, "arlib: signaling %p", q);
00658 
00659               pthread_cond_signal(&q->q_reply);
00660               pthread_mutex_unlock(&q->q_lock);
00661        }
00662 }
00663 
00664 /*
00665 **  AR_REQUERY -- position an active query at the front of the pending queue
00666 **
00667 **  Parameters:
00668 **     lib -- library handle
00669 **     query -- query to send
00670 **
00671 **  Return value:
00672 **     None.
00673 **
00674 **  Notes:
00675 **     Presumes the caller has acquired a lock on the "lib" handle.
00676 */
00677 
00678 static void
00679 ar_requery(AR_LIB lib, AR_QUERY query)
00680 {
00681        AR_QUERY q;
00682        AR_QUERY last;
00683 
00684        assert(lib != NULL);
00685        assert(query != NULL);
00686 
00687        if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
00688               syslog(LOG_DEBUG, "arlib: requerying %p", query);
00689 
00690        /* remove from active queries */
00691        for (q = lib->ar_queries, last = NULL;
00692             q != NULL;
00693             last = q, q = q->q_next)
00694        {
00695               if (query == q)
00696               {
00697                      if (last == NULL)
00698                      {
00699                             lib->ar_queries = q->q_next;
00700                             if (lib->ar_queries == NULL)
00701                                    lib->ar_queriestail = NULL;
00702 
00703                      }
00704                      else
00705                      {
00706                             last->q_next = q->q_next;
00707                             if (lib->ar_queriestail == q)
00708                                    lib->ar_queriestail = last;
00709                      }
00710 
00711                      if ((q->q_flags & QUERY_RESEND) != 0)
00712                             lib->ar_resend--;
00713               }
00714        }
00715 
00716        /* insert at front of pending queue */
00717        if (lib->ar_pending == NULL)
00718        {
00719               lib->ar_pending = query;
00720               lib->ar_pendingtail = query;
00721               query->q_next = NULL;
00722        }
00723        else
00724        {
00725               query->q_next = lib->ar_pending;
00726               lib->ar_pending = query;
00727        }
00728 }
00729 
00730 /*
00731 **  AR_REQUEUE -- arrange to re-send everything after a reconnect
00732 **
00733 **  Parameters:
00734 **     lib -- library handle
00735 **
00736 **  Return value:
00737 **     None.
00738 **
00739 **  Notes:
00740 **     Jobs to retry get priority over currently pending jobs.
00741 **     Presumes the caller holds the lock in the library handle.
00742 */
00743 
00744 static void
00745 ar_requeue(AR_LIB lib)
00746 {
00747        assert(lib != NULL);
00748 
00749        if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
00750               syslog(LOG_DEBUG, "arlib: requeueing everything");
00751 
00752        if (lib->ar_queries != NULL)
00753        {
00754               int status;
00755               fd_set wfds;
00756               AR_QUERY x = NULL;
00757               struct timeval stimeout;
00758 
00759               if (lib->ar_pending != NULL)
00760               {
00761                      lib->ar_queriestail->q_next = lib->ar_pending;
00762               }
00763               else
00764               {
00765                      lib->ar_pendingtail = lib->ar_queriestail;
00766               }
00767 
00768               lib->ar_pending = lib->ar_queries;
00769 
00770               lib->ar_queries = NULL;
00771               lib->ar_queriestail = NULL;
00772 
00773               ar_socket_reset(lib->ar_dss);
00774               ar_socket_add(lib->ar_dss, lib->ar_control[0],
00775                             AR_SOCKET_EVENT_WRITE);
00776               status = ar_socket_wait(lib->ar_dss, 0);
00777               if (status == 1)
00778                      (void) write(lib->ar_control[0], &x, sizeof x);
00779        }
00780 }
00781 
00782 /*
00783 **  AR_RECONNECT -- reconnect when TCP service dies
00784 **
00785 **  Parameters:
00786 **     lib -- library handle
00787 **
00788 **  Return value:
00789 **     TRUE iff reconnect was successful.
00790 **
00791 **  Notes:
00792 **     If reconnection was impossible, all queries are marked with
00793 **     QUERY_ERROR and signalled immediately.  ar_flags is marked with
00794 **     AR_FLAG_DEAD, preventing further calls to ar_addquery().
00795 **     Assumes the caller holds ar_lock.
00796 */
00797 
00798 static _Bool
00799 ar_reconnect(AR_LIB lib)
00800 {
00801        int c;
00802        int saveerrno;
00803        int nsnum;
00804        int socklen;
00805        struct sockaddr *sa;
00806 
00807        assert(lib != NULL);
00808 
00809        if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
00810               syslog(LOG_DEBUG, "arlib: attempting reconnect");
00811 
00812        if ((lib->ar_flags & AR_FLAG_RECONNECT) == 0)
00813               return TRUE;
00814 
00815        if ((lib->ar_flags & AR_FLAG_USETCP) == 0)
00816        {
00817               ar_requeue(lib);
00818               lib->ar_flags &= ~AR_FLAG_RECONNECT;
00819               return TRUE;
00820        }
00821 
00822        close(lib->ar_nsfd);
00823        lib->ar_nsfd = -1;
00824        lib->ar_nsfdpf = -1;
00825        lib->ar_partwrite = 0;
00826        lib->ar_fullwrite = 0;
00827 
00828        /* try to connect to someone */
00829        for (c = 0; c < lib->ar_nscount; c++)
00830        {
00831               nsnum = (c + lib->ar_nsidx) % lib->ar_nscount;
00832 
00833               sa = (struct sockaddr *) &lib->ar_nsaddrs[nsnum];
00834 
00835 #ifdef AF_INET6
00836               if (sa->sa_family == AF_INET6)
00837                      socklen = sizeof(struct sockaddr_in6);
00838               else
00839                      socklen = sizeof(struct sockaddr_in);
00840 #else /* AF_INET6 */
00841               socklen = sizeof(struct sockaddr_in);
00842 #endif /* AF_INET6 */
00843 
00844               lib->ar_nsfd = socket(sa->sa_family, SOCK_STREAM, 0);
00845               if (lib->ar_nsfd == -1)
00846               {
00847                      if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
00848                      {
00849                             syslog(LOG_DEBUG, "arlib: socket(): %s",
00850                                    strerror(errno));
00851                      }
00852 
00853                      continue;
00854               }
00855 
00856               lib->ar_nsfdpf = sa->sa_family;
00857 
00858               if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
00859               {
00860                      uint32_t addr;
00861                      struct sockaddr_in *si;
00862 
00863                      si = (struct sockaddr_in *) sa;
00864                      addr = si->sin_addr.s_addr;
00865                      syslog(LOG_DEBUG,
00866                             "arlib: trying nameserver %d.%d.%d.%d",
00867                             (addr >> 24), (addr >> 16) & 0xff,
00868                             (addr >> 8) & 0xff, addr & 0xff);
00869               }
00870 
00871               if (connect(lib->ar_nsfd, sa, socklen) == 0)
00872               {
00873                      if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
00874                             syslog(LOG_DEBUG, "arlib: connected");
00875 
00876                      lib->ar_flags &= ~AR_FLAG_RECONNECT;
00877                      ar_requeue(lib);
00878                      return TRUE;
00879               }
00880 
00881               if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
00882               {
00883                      syslog(LOG_DEBUG, "arlib: connect(): %s",
00884                             strerror(errno));
00885               }
00886 
00887               close(lib->ar_nsfd);
00888               lib->ar_nsfd = -1;
00889               lib->ar_nsfdpf = -1;
00890        }
00891 
00892        saveerrno = errno;
00893 
00894        /* unable to reconnect; arrange to terminate */
00895        if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
00896               syslog(LOG_DEBUG, "arlib: failed to reconnect");
00897        ar_alldead(lib);
00898        (void) gettimeofday(&lib->ar_deadsince, NULL);
00899        lib->ar_flags |= AR_FLAG_DEAD;
00900        lib->ar_deaderrno = saveerrno;
00901 
00902        return FALSE;
00903 }
00904 
00905 /*
00906 **  AR_SENDQUERY -- send a query
00907 **
00908 **  Parameters:
00909 **     lib -- library handle
00910 **     query -- query to send
00911 **
00912 **  Return value:
00913 **     TRUE iff the message was able to be sent.
00914 **
00915 **  Notes:
00916 **     Caller must already hold the query-specific lock.
00917 */
00918 
00919 static _Bool
00920 ar_sendquery(AR_LIB lib, AR_QUERY query)
00921 {
00922        size_t n;
00923        HEADER hdr;
00924 
00925        assert(lib != NULL);
00926        assert(query != NULL);
00927 
00928        if (lib->ar_retries > 0 && query->q_tries == lib->ar_retries)
00929        {
00930               if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
00931               {
00932                      syslog(LOG_DEBUG, "arlib: %p retry count exceeded",
00933                             query);
00934               }
00935 
00936               query->q_flags |= QUERY_ERROR;
00937               if (query->q_errno != NULL)
00938                      *query->q_errno = QUERY_ERRNO_RETRIES;
00939               pthread_cond_signal(&query->q_reply);
00940               return FALSE;
00941        }
00942        
00943        for (;;)
00944        {
00945 #if (defined(__RES) && (__RES <= 19960801))
00946               n = res_mkquery(QUERY, query->q_name, query->q_class,
00947                               query->q_type, NULL, 0, NULL, lib->ar_querybuf,
00948                               lib->ar_querybuflen);
00949 #else /* defined(__RES) && (__RES <= 19960801) */
00950               n = res_nmkquery(&lib->ar_res, QUERY, query->q_name,
00951                                query->q_class, query->q_type, NULL, 0,
00952                                NULL, lib->ar_querybuf, lib->ar_querybuflen);
00953 #endif /* defined(__RES) && (__RES <= 19960801) */
00954 
00955               if (n != (size_t) -1)
00956               {
00957                      lib->ar_writelen = n;
00958                      break;
00959               }
00960 
00961               if (lib->ar_querybuflen >= QUERYLIMIT)
00962               {
00963                      query->q_flags |= QUERY_ERROR;
00964                      if (query->q_errno != NULL)
00965                             *query->q_errno = QUERY_ERRNO_TOOBIG;
00966                      pthread_cond_signal(&query->q_reply);
00967                      return FALSE;
00968               }
00969 
00970               ar_free(lib, lib->ar_querybuf);
00971               lib->ar_querybuflen *= 2;
00972               lib->ar_querybuf = ar_malloc(lib, lib->ar_querybuflen);
00973        }
00974 
00975        memcpy(&hdr, lib->ar_querybuf, sizeof hdr);
00976        query->q_id = hdr.id;
00977 
00978 #ifdef DEBUG
00979        printf("*** SEND '%s' class=%d type=%d id=%d time=%d\n", query->q_name,
00980               query->q_class, query->q_type, hdr.id, time(NULL));
00981 #endif /* DEBUG */
00982 
00983        if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
00984        {
00985               syslog(LOG_DEBUG, "arlib: sending %p '%s' id=%d", query,
00986                      query->q_name, query->q_id);
00987        }
00988 
00989        /* send it */
00990        if ((lib->ar_flags & AR_FLAG_USETCP) != 0)
00991        {
00992               u_short len;
00993 
00994               len = htons(n);
00995               lib->ar_iovec[0].iov_base = (void *) &len;
00996               lib->ar_iovec[0].iov_len = sizeof len;
00997               lib->ar_iovec[1].iov_base = (void *) lib->ar_querybuf;
00998               lib->ar_iovec[1].iov_len = lib->ar_writelen;
00999 
01000               n = writev(lib->ar_nsfd, lib->ar_iovec, 2);
01001 
01002               lib->ar_fullwrite = lib->ar_iovec[0].iov_len + lib->ar_iovec[1].iov_len;
01003        }
01004        else
01005        {
01006               int nsnum;
01007               int socklen;
01008               struct sockaddr *sa;
01009 
01010               nsnum = query->q_tries % lib->ar_nscount;
01011 
01012               sa = (struct sockaddr *) &lib->ar_nsaddrs[nsnum];
01013 
01014               /* change to the right family if needed */
01015               if (sa->sa_family != lib->ar_nsfdpf)
01016               {
01017                      close(lib->ar_nsfd);
01018                      lib->ar_nsfdpf = -1;
01019 
01020                      lib->ar_nsfd = socket(sa->sa_family,
01021                                            SOCK_DGRAM, 0);
01022                      if (lib->ar_nsfd != -1)
01023                             lib->ar_nsfdpf = sa->sa_family;
01024               }
01025 
01026 #ifdef AF_INET6
01027               if (sa->sa_family == AF_INET6)
01028                      socklen = sizeof(struct sockaddr_in6);
01029               else
01030                      socklen = sizeof(struct sockaddr_in);
01031 #else /* AF_INET */
01032               socklen = sizeof(struct sockaddr_in);
01033 #endif /* AF_INET */
01034 
01035               n = sendto(lib->ar_nsfd, lib->ar_querybuf,
01036                          lib->ar_writelen, 0, sa, socklen);
01037 
01038               lib->ar_fullwrite = lib->ar_writelen;
01039        }
01040 
01041        if (n == (size_t) -1)
01042        {
01043               if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
01044               {
01045                      syslog(LOG_DEBUG, "arlib: %p sendto/writev failed: %s",
01046                             query, strerror(errno));
01047               }
01048 
01049               lib->ar_flags |= AR_FLAG_RECONNECT;
01050               query->q_flags |= QUERY_ERROR;
01051               if (query->q_errno != NULL)
01052                      *query->q_errno = errno;
01053               pthread_cond_signal(&query->q_reply);
01054               return FALSE;
01055        }
01056        else
01057        {
01058               lib->ar_partwrite = n;
01059        }
01060 
01061        query->q_tries += 1;
01062        (void) gettimeofday(&query->q_sent, NULL);
01063 
01064        return TRUE;
01065 }
01066 
01067 /*
01068 **  AR_ANSCOUNT -- count received answers
01069 **
01070 **  Parameters:
01071 **     buf -- pointer to a packet
01072 **     len -- bytes available at "buf"
01073 **
01074 **  Return value:
01075 **     Count of actual answers (may be smaller than ancount).
01076 */
01077 
01078 static int
01079 ar_anscount(unsigned char *buf, size_t len)
01080 {
01081        int ret = 0;
01082        uint16_t qdcount;
01083        uint16_t ancount;
01084        uint16_t class;
01085        uint16_t type;
01086        uint16_t rrsize;
01087        uint32_t ttl;
01088        int n;
01089        unsigned char *cp;
01090        unsigned char *eom;
01091        HEADER *hdr;
01092        unsigned char name[AR_MAXHOSTNAMELEN + 1];
01093 
01094        assert(buf != NULL);
01095 
01096        hdr = (HEADER *) buf;
01097        cp = buf + HFIXEDSZ;
01098        eom = buf + len;
01099 
01100        qdcount = ntohs((unsigned short) hdr->qdcount);
01101        ancount = ntohs((unsigned short) hdr->ancount);
01102 
01103        for (; qdcount > 0; qdcount--)
01104        {
01105               if ((n = dn_skipname(cp, eom)) < 0)
01106                      break;
01107               cp += n;
01108 
01109               if (cp + INT16SZ + INT16SZ > eom)
01110                      break;
01111 
01112               GETSHORT(type, cp);
01113               GETSHORT(class, cp);
01114        }
01115 
01116        if (qdcount > 0)
01117               return 0;
01118 
01119        if (ancount == 0)
01120               return 0;
01121 
01122        /*
01123        **  Extract the data from the first TXT answer.
01124        */
01125 
01126        while (--ancount > 0 && cp < eom)
01127        {
01128               /* grab the label, even though we know what we asked... */
01129               if ((n = dn_expand((unsigned char *) buf, eom, cp,
01130                                  (RES_UNC_T) name, sizeof name)) < 0)
01131                      return ret;
01132 
01133               /* ...and move past it */
01134               cp += n;
01135 
01136               /* extract the type and class */
01137               if (cp + INT16SZ + INT16SZ + INT32SZ > eom)
01138                      return ret;
01139 
01140               GETSHORT(type, cp);
01141               GETSHORT(class, cp);
01142               GETLONG(ttl, cp);
01143 
01144               /* get payload length */
01145               if (cp + INT16SZ > eom)
01146                      return ret;
01147 
01148               GETSHORT(rrsize, cp);
01149 
01150               /* is it not all there? */
01151               if (cp + rrsize > eom)
01152                      return ret;
01153 
01154               /* it is; count the reply */
01155               ret++;
01156               cp += rrsize;
01157        }
01158 
01159        return ret;
01160 }
01161 
01162 /*
01163 **  AR_DISPATCHER -- dispatcher thread
01164 **
01165 **  Parameters:
01166 **     tp -- thread pointer; miscellaneous data set up at init time
01167 **
01168 **  Return value:
01169 **     Always NULL.
01170 */
01171 
01172 static void *
01173 ar_dispatcher(void *tp)
01174 {
01175        _Bool usetimeout;
01176        _Bool reconnect;
01177        int status;
01178        int to;
01179        size_t r;
01180        AR_LIB lib;
01181        AR_QUERY q;
01182        u_char *buf;
01183        struct timeval timeout;
01184        struct timeval timeleft;
01185        sigset_t set;
01186 
01187        assert(tp != NULL);
01188 
01189        lib = tp;
01190 
01191        pthread_mutex_lock(&lib->ar_lock);
01192 
01193        lib->ar_resend = 0;
01194 
01195        /* block signals that should be caught elsewhere */
01196        sigemptyset(&set);
01197        sigaddset(&set, SIGHUP);
01198        sigaddset(&set, SIGTERM);
01199        sigaddset(&set, SIGINT);
01200        pthread_sigmask(SIG_BLOCK, &set, NULL);
01201 
01202        if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
01203               syslog(LOG_DEBUG, "arlib: dispatcher starting");
01204 
01205        for (;;)
01206        {
01207 #ifdef ARDEBUG
01208               /* truncate tracing output if everything is synched up */
01209               if (lib->ar_pending == NULL && lib->ar_queries == NULL)
01210               {
01211                      rewind(debugout);
01212                      ftruncate(fileno(debugout), 0);
01213               }
01214 #endif /* ARDEBUG */
01215 
01216               /* if we're dead, see if it's time to revivify */
01217               if ((lib->ar_flags & AR_FLAG_DEAD) != 0)
01218               {
01219                      if (ar_elapsed(&lib->ar_deadsince,
01220                                     &lib->ar_revivify))
01221                      {
01222                             if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
01223                             {
01224                                    syslog(LOG_DEBUG,
01225                                           "arlib: dispatcher revivifying");
01226                             }
01227                             lib->ar_flags &= ~AR_FLAG_DEAD;
01228                      }
01229               }
01230 
01231               /* attempt to reconnect if needed */
01232               if ((lib->ar_flags & AR_FLAG_DEAD) == 0 &&
01233                   (lib->ar_nsfd == -1 ||
01234                    (lib->ar_flags & AR_FLAG_RECONNECT) != 0))
01235                      (void) ar_reconnect(lib);
01236 
01237               /* check on the control descriptor and the NS descriptor */
01238               ar_socket_reset(lib->ar_dss);
01239 
01240               ar_socket_add(lib->ar_dss, lib->ar_control[1],
01241                             AR_SOCKET_EVENT_READ);
01242 
01243               if ((lib->ar_pending != NULL || lib->ar_resend > 0) ||
01244                   lib->ar_partwrite < lib->ar_fullwrite)
01245               {
01246                      ar_socket_add(lib->ar_dss, lib->ar_nsfd,
01247                                    AR_SOCKET_EVENT_WRITE);
01248               }
01249 
01250               if (lib->ar_nsfd != -1)
01251               {
01252                      ar_socket_add(lib->ar_dss, lib->ar_nsfd,
01253                                    AR_SOCKET_EVENT_READ);
01254               }
01255 
01256               /* determine how long to wait */
01257               if ((lib->ar_flags & AR_FLAG_DEAD) != 0)
01258                      timeout.tv_sec = AR_DEFREVIVIFY;
01259               else
01260                      timeout.tv_sec = AR_MAXTIMEOUT;
01261               timeout.tv_usec = 0;
01262 
01263               usetimeout = (lib->ar_queries != NULL);
01264 
01265               for (q = lib->ar_queries; q != NULL; q = q->q_next)
01266               {
01267                      /* skip queries for which we're no longer waiting */
01268                      if ((q->q_flags & (QUERY_ERROR|QUERY_REPLY|QUERY_NOREPLY)) != 0)
01269                             continue;
01270 
01271                      /* check for absolute timeout */
01272                      if (q->q_timeout.tv_sec != 0 &&
01273                          (q->q_flags & QUERY_INFINIWAIT) == 0)
01274                      {
01275                             ar_timeleft(NULL, &q->q_timeout, &timeleft);
01276                             if (timeleft.tv_sec < timeout.tv_sec ||
01277                                 (timeleft.tv_sec == timeout.tv_sec &&
01278                                  timeleft.tv_usec < timeout.tv_usec))
01279                             {
01280                                    memcpy(&timeout, &timeleft,
01281                                           sizeof timeout);
01282                             }
01283                      }
01284 
01285                      /* check for re-send timeout */
01286                      ar_timeleft(&q->q_sent, &lib->ar_retry, &timeleft);
01287                      if (timeleft.tv_sec < timeout.tv_sec ||
01288                          (timeleft.tv_sec == timeout.tv_sec &&
01289                           timeleft.tv_usec < timeout.tv_usec))
01290                             memcpy(&timeout, &timeleft, sizeof timeout);
01291               }
01292 
01293               pthread_mutex_unlock(&lib->ar_lock);
01294 
01295               to = 1000 * timeout.tv_sec + timeout.tv_usec / 1000;
01296 
01297               if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
01298               {
01299                      if (usetimeout)
01300                      {
01301                             syslog(LOG_DEBUG,
01302                                    "arlib: dispatcher pausing (%u.%06us)",
01303                                    timeout.tv_sec, timeout.tv_usec);
01304                      }
01305                      else
01306                      {
01307                             syslog(LOG_DEBUG, "arlib: dispatcher pausing");
01308                      }
01309               }
01310 
01311               /* XXX -- effect a poll if we knew there was more pending */
01312               status = ar_socket_wait(lib->ar_dss, usetimeout ? to : -1);
01313               if (status == -1)
01314               {
01315                      if (errno == EINTR)
01316                      {
01317                             pthread_mutex_lock(&lib->ar_lock);
01318                             continue;
01319                      }
01320                      else
01321                      {
01322                             assert(status >= 0);
01323                      }
01324               }
01325 
01326               buf = NULL;
01327 
01328               /* read what's available from the nameserver for dispatch */
01329               if (lib->ar_nsfd != -1 &&
01330                   ar_socket_check(lib->ar_dss, lib->ar_nsfd,
01331                                   AR_SOCKET_EVENT_READ) == 1)
01332               {
01333                      if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
01334                             syslog(LOG_DEBUG, "arlib: reply received");
01335 
01336                      if ((lib->ar_flags & AR_FLAG_USETCP) == 0)
01337                      {
01338                             r = recvfrom(lib->ar_nsfd, lib->ar_querybuf,
01339                                          lib->ar_querybuflen, 0, NULL,
01340                                          NULL);
01341 
01342                             if (r == (size_t) -1)
01343                             {
01344                                    pthread_mutex_lock(&lib->ar_lock);
01345                                    continue;
01346                             }
01347 
01348                             buf = lib->ar_querybuf;
01349                      }
01350                      else if (lib->ar_tcpmsglen == 0)
01351                      {
01352                             uint16_t len;
01353                             _Bool err = FALSE;
01354 
01355                             /* get the length */
01356                             len = 0;
01357                             r = recvfrom(lib->ar_nsfd, &len, sizeof len,
01358                                          MSG_WAITALL, NULL, NULL);
01359 
01360                             if (r == (size_t) -1)
01361                             {
01362                                    if (errno == EINTR)
01363                                    {
01364                                           pthread_mutex_lock(&lib->ar_lock);
01365                                           continue;
01366                                    }
01367                                    else
01368                                    {
01369                                           err = TRUE;
01370                                    }
01371                             }
01372                             else if (r == 0)
01373                             {
01374                                    err = TRUE;
01375                             }
01376                             else if (r < sizeof len)
01377                             {
01378                                    pthread_mutex_lock(&lib->ar_lock);
01379                                    continue;
01380                             }
01381 
01382                             if (err)
01383                             {
01384                                    pthread_mutex_lock(&lib->ar_lock);
01385 
01386                                    /* request a reconnect */
01387                                    lib->ar_flags |= AR_FLAG_RECONNECT;
01388 
01389                                    /* arrange to re-send everything */
01390                                    ar_requeue(lib);
01391 
01392                                    continue;
01393                             }
01394 
01395                             lib->ar_tcpmsglen = ntohs(len);
01396                             lib->ar_tcpbufidx = 0;
01397 
01398                             /* allocate a buffer */
01399                             if (lib->ar_tcpbuf == NULL ||
01400                                 lib->ar_tcpbuflen < ntohs(len))
01401                             {
01402                                    if (lib->ar_tcpbuf != NULL)
01403                                    {
01404                                           ar_free(lib, lib->ar_tcpbuf);
01405                                           lib->ar_tcpbuf = NULL;
01406                                    }
01407 
01408                                    lib->ar_tcpbuf = ar_malloc(lib,
01409                                                               ntohs(len));
01410                                    lib->ar_tcpbuflen = ntohs(len);
01411                             }
01412                      }
01413                      else
01414                      {
01415                             _Bool err = FALSE;
01416                             size_t rem;
01417                             ssize_t part;
01418                             u_char *where;
01419 
01420                             where = lib->ar_tcpbuf + lib->ar_tcpbufidx;
01421                             rem = lib->ar_tcpmsglen - lib->ar_tcpbufidx;
01422 
01423                             /* grab next chunk (may be in pieces) */
01424                             r = 0;
01425 
01426                             while (lib->ar_tcpbufidx < lib->ar_tcpmsglen)
01427                             {
01428                                    part = recvfrom(lib->ar_nsfd,
01429                                                    where, rem,
01430                                                    0, NULL, NULL);
01431 
01432                                    if (part == 0 || part == (size_t) -1)
01433                                    {
01434                                           if (errno == EINTR)
01435                                                  continue;
01436 
01437                                           err = TRUE;
01438                                           break;
01439                                    }
01440 
01441 
01442                                    r += part;
01443                                    where += part;
01444                                    lib->ar_tcpbufidx += part;
01445                             }
01446 
01447                             if (err)
01448                             {
01449                                    pthread_mutex_lock(&lib->ar_lock);
01450 
01451                                    /* request a reconnect */
01452                                    lib->ar_flags |= AR_FLAG_RECONNECT;
01453 
01454                                    /* arrange to re-send everything */
01455                                    ar_requeue(lib);
01456 
01457                                    continue;
01458                             }
01459 
01460                             if (lib->ar_tcpbufidx == lib->ar_tcpmsglen)
01461                             {
01462                                    buf = lib->ar_tcpbuf;
01463                                    r = lib->ar_tcpmsglen;
01464                             }
01465                      }
01466               }
01467 
01468               pthread_mutex_lock(&lib->ar_lock);
01469 
01470               if (buf != NULL)            /* something to parse */
01471               {
01472                      _Bool requeued = FALSE;
01473                      HEADER hdr;
01474 
01475                      if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
01476                      {
01477                             syslog(LOG_DEBUG,
01478                                    "arlib: full reply received");
01479                      }
01480 
01481                      /* reset TCP read mode */
01482                      lib->ar_tcpmsglen = 0;
01483 
01484                      /* truncate extra data */
01485                      if (r > MAXPACKET)
01486                             r = MAXPACKET;
01487 
01488                      /* copy header */
01489                      memcpy(&hdr, buf, sizeof hdr);
01490 
01491                      /* check for truncation in UDP mode */
01492                      if (hdr.rcode == NOERROR && hdr.tc &&
01493                          (lib->ar_flags & AR_FLAG_USETCP) == 0 &&
01494                          ((lib->ar_flags & AR_FLAG_TRUNCCHECK) == 0 ||
01495                           ar_anscount(buf, r) == 0))
01496                      {
01497                             if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
01498                             {
01499                                    syslog(LOG_DEBUG,
01500                                           "arlib: truncation detected");
01501                             }
01502 
01503                             /* request a reconnect */
01504                             lib->ar_flags |= AR_FLAG_USETCP;
01505                             lib->ar_flags |= AR_FLAG_RECONNECT;
01506 
01507                             /* arrange to re-send everything */
01508                             ar_requeue(lib);
01509 
01510                             continue;
01511                      }
01512 
01513                      /* find the matching query */
01514                      for (q = lib->ar_queries;
01515                           q != NULL;
01516                           q = q->q_next)
01517                      {
01518                             pthread_mutex_lock(&q->q_lock);
01519                             if (q->q_id == hdr.id)
01520                             {
01521                                    pthread_mutex_unlock(&q->q_lock);
01522                                    break;
01523                             }
01524                             pthread_mutex_unlock(&q->q_lock);
01525                      }
01526 
01527 #ifdef DEBUG
01528                      printf("*** RECEIVE id=%d time=%d\n", hdr.id,
01529                             time(NULL));
01530 #endif /* DEBUG */
01531 
01532                      if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
01533                      {
01534                             if (q != NULL)
01535                             {
01536                                    syslog(LOG_DEBUG,
01537                                           "arlib: %p (id %d) reply received",
01538                                           q, q->q_id);
01539                             }
01540                             else
01541                             {
01542                                    syslog(LOG_DEBUG,
01543                                           "arlib: abandoned reply %d received",
01544                                           hdr.id);
01545                             }
01546                      }
01547 
01548                      /* don't recurse if user buffer is too small */
01549                      if (q != NULL && r > q->q_buflen)
01550                             q->q_depth = 0;
01551 
01552                      /* check CNAME and depth */
01553                      if (q != NULL && q->q_depth > 0)
01554                      {
01555                             int n;
01556                             int class;
01557                             int type;
01558                             int qdcount;
01559                             int ancount;
01560                             size_t anslen;
01561                             u_char *cp;
01562                             u_char *eom;
01563 
01564                             anslen = r;
01565                             cp = (u_char *) buf + HFIXEDSZ;
01566                             eom = (u_char *) buf + anslen;
01567 
01568                             qdcount = ntohs((unsigned short) hdr.qdcount);
01569                             ancount = ntohs((unsigned short) hdr.ancount);
01570 
01571                             for (; qdcount > 0; qdcount--)
01572                             {
01573                                    if ((n = dn_skipname(cp, eom)) < 0)
01574                                           break;
01575                                    cp += n;
01576 
01577                                    if (cp + INT16SZ + INT16SZ > eom)
01578                                           break;
01579 
01580                                    GETSHORT(type, cp);
01581                                    GETSHORT(class, cp);
01582                             }
01583 
01584                             if (hdr.rcode == NOERROR || ancount == 0)
01585                             {
01586                                    if ((n = dn_skipname(cp, eom)) < 0)
01587                                           continue;
01588                                    cp += n;
01589 
01590                                    GETSHORT(type, cp);
01591                                    GETSHORT(class, cp);
01592                                    cp += INT32SZ;
01593 
01594                                    /* CNAME found; recurse */
01595                                    if (type == T_CNAME)
01596                                    {
01597                                           char cname[AR_MAXHOSTNAMELEN + 1];
01598 
01599                                           GETSHORT(n, cp);
01600 
01601                                           memset(cname, '\0',
01602                                                  sizeof cname);
01603                                           (void) dn_expand(buf, eom, cp,
01604                                                            cname,
01605                                                            AR_MAXHOSTNAMELEN);
01606                                           q->q_depth--;
01607                                           ar_undot(cname);
01608                                           strlcpy(q->q_name, cname,
01609                                                   sizeof q->q_name);
01610                                           if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
01611                                           {
01612                                                  syslog(LOG_DEBUG,
01613                                                         "arlib: %p reply was CNAME, requerying",
01614                                                         q);
01615                                           }
01616                                           ar_requery(lib, q);
01617                                           requeued = TRUE;
01618                                    }
01619                             }
01620                      }
01621 
01622                      /* pack up the reply */
01623                      if (q != NULL && !requeued)
01624                      {
01625                             pthread_mutex_lock(&q->q_lock);
01626                             memcpy(q->q_buf, buf, MIN(r, q->q_buflen));
01627                             q->q_flags |= QUERY_REPLY;
01628                             q->q_replylen = r;
01629                             if ((q->q_flags & QUERY_RESEND) != 0)
01630                                    lib->ar_resend--;
01631                             if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
01632                             {
01633                                    syslog(LOG_DEBUG,
01634                                           "arlib: %p signaling", q);
01635                             }
01636                             pthread_cond_signal(&q->q_reply);
01637                             pthread_mutex_unlock(&q->q_lock);
01638                      }
01639               }
01640 
01641               /* control socket messages (new work, resend requests) */
01642               if (ar_socket_check(lib->ar_dss, lib->ar_control[1],
01643                                   AR_SOCKET_EVENT_READ) == 1)
01644               {
01645                      size_t rlen;
01646                      AR_QUERY q;
01647                      
01648                      if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
01649                             syslog(LOG_DEBUG, "arlib: control socket");
01650 
01651                      rlen = read(lib->ar_control[1], &q, sizeof q);
01652                      if (rlen == 0)
01653                      {
01654                             pthread_mutex_unlock(&lib->ar_lock);
01655                             return NULL;
01656                      }
01657 
01658                      /* specific resend request */
01659                      if (q != NULL && (q->q_flags & QUERY_RESEND) == 0)
01660                      {
01661                             if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
01662                             {
01663                                    syslog(LOG_DEBUG,
01664                                           "arlib: resend %p request", q);
01665                             }
01666 
01667                             q->q_flags |= QUERY_RESEND;
01668                             lib->ar_resend++;
01669                      }
01670               }
01671 
01672               /* take another run at any incomplete writev() we have going */
01673               if (lib->ar_nsfd != -1 &&
01674                   lib->ar_partwrite < lib->ar_fullwrite &&
01675                   ar_socket_check(lib->ar_dss, lib->ar_nsfd,
01676                                   AR_SOCKET_EVENT_WRITE) == 1)
01677               {
01678                      int c;
01679                      size_t n;
01680                      struct iovec io[2];
01681 
01682                      memcpy(&io, &lib->ar_iovec, sizeof io);
01683                      n = lib->ar_partwrite;
01684 
01685                      for (c = 0; c < 2; c++)
01686                      {
01687                             if (io[c].iov_len > (unsigned int) n)
01688                             {
01689                                    io[c].iov_base = (char *) io[c].iov_base + n;
01690                                    io[c].iov_len -= n;
01691                                    break;
01692                             }
01693 
01694                             n -= (int) io[c].iov_len;
01695                             io[c].iov_len = 0;
01696                      }
01697 
01698                      n = writev(lib->ar_nsfd, io, 2);
01699                      if (n == -1)
01700                      {
01701                             /* request a reconnect */
01702                             lib->ar_flags |= AR_FLAG_RECONNECT;
01703 
01704                             /* arrange to re-send everything */
01705                             ar_requeue(lib);
01706                      }
01707                      else
01708                      {
01709                             lib->ar_partwrite += n;
01710                      }
01711 
01712                      continue;
01713               }
01714 
01715               /* send any pending queries */
01716               if (lib->ar_nsfd != -1 &&
01717                   ar_socket_check(lib->ar_dss, lib->ar_nsfd,
01718                                   AR_SOCKET_EVENT_WRITE) == 1 &&
01719                   lib->ar_pending != NULL)
01720               {
01721                      _Bool sent;
01722 
01723                      /* reset read state if there's nothing outstanding */
01724                      if (lib->ar_queries == NULL)
01725                             lib->ar_tcpmsglen = 0;
01726 
01727                      for (q = lib->ar_pending; q != NULL; q = q->q_next)
01728                      {
01729                             sent = FALSE;
01730 
01731                             q = lib->ar_pending;
01732 
01733                             lib->ar_pending = q->q_next;
01734                             if (lib->ar_pending == NULL)
01735                                    lib->ar_pendingtail = NULL;
01736 
01737                             q->q_next = NULL;
01738 
01739                             /* make and write the query */
01740                             pthread_mutex_lock(&q->q_lock);
01741                             sent = ar_sendquery(lib, q);
01742                             if (!sent)
01743                             {
01744                                    lib->ar_flags |= AR_FLAG_RECONNECT;
01745                                    if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
01746                                    {
01747                                           syslog(LOG_DEBUG,
01748                                                  "arlib: send failed, requesting reconnect");
01749                                    }
01750                             }
01751                             pthread_mutex_unlock(&q->q_lock);
01752 
01753                             if (sent)
01754                             {
01755                                    /* add it to the active queries list */
01756                                    if (lib->ar_queriestail == NULL)
01757                                    {
01758                                           lib->ar_queries = q;
01759                                           lib->ar_queriestail = q;
01760                                    }
01761                                    else
01762                                    {
01763                                           lib->ar_queriestail->q_next = q;
01764                                           lib->ar_queriestail = q;
01765                                    }
01766                             }
01767 
01768                             ar_socket_reset(lib->ar_dss);
01769                             ar_socket_add(lib->ar_dss, lib->ar_nsfd,
01770                                           AR_SOCKET_EVENT_WRITE);
01771 
01772                             status = ar_socket_wait(lib->ar_dss, 0);
01773 
01774                             if (status != 1)
01775                                    break;
01776                      }
01777               }
01778 
01779               /* send any queued resends */
01780               if (lib->ar_resend > 0 && lib->ar_nsfd != -1 &&
01781                   ar_socket_check(lib->ar_dss, lib->ar_nsfd,
01782                                   AR_SOCKET_EVENT_WRITE) == 1)
01783               {
01784                      for (q = lib->ar_queries;
01785                           q != NULL && lib->ar_resend > 0;
01786                           q = q->q_next)
01787                      {
01788                             pthread_mutex_lock(&q->q_lock);
01789                             if ((q->q_flags & QUERY_RESEND) != 0)
01790                             {
01791                                    if (!ar_sendquery(lib, q))
01792                                           lib->ar_flags |= AR_FLAG_RECONNECT;
01793                                    q->q_flags &= ~QUERY_RESEND;
01794                                    lib->ar_resend--;
01795                             }
01796                             pthread_mutex_unlock(&q->q_lock);
01797 
01798                             ar_socket_reset(lib->ar_dss);
01799                             ar_socket_add(lib->ar_dss, lib->ar_nsfd,
01800                                           AR_SOCKET_EVENT_WRITE);
01801                             status = ar_socket_wait(lib->ar_dss, 0);
01802                             if (status != 1)
01803                                    break;
01804                      }
01805               }
01806 
01807               /* look through active queries for timeouts */
01808               for (q = lib->ar_queries; q != NULL; q = q->q_next)
01809               {
01810                      pthread_mutex_lock(&q->q_lock);
01811                      if ((q->q_flags & (QUERY_NOREPLY|QUERY_REPLY)) == 0 &&
01812                          ar_expired(q))
01813                      {
01814                             if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
01815                             {
01816                                    syslog(LOG_DEBUG, "arlib: expiring %p",
01817                                           q);
01818                             }
01819                             q->q_flags |= QUERY_NOREPLY;
01820                             pthread_cond_signal(&q->q_reply);
01821                      }
01822                      pthread_mutex_unlock(&q->q_lock);
01823               }
01824 
01825               /* look through what's left for retries */
01826               for (q = lib->ar_queries; q != NULL; q = q->q_next)
01827               {
01828                      /* bail if ar_sendquery() would block */
01829                      if (lib->ar_nsfd == -1)
01830                             break;
01831 
01832                      ar_socket_reset(lib->ar_dss);
01833                      ar_socket_add(lib->ar_dss, lib->ar_nsfd,
01834                                    AR_SOCKET_EVENT_WRITE);
01835                      if (ar_socket_check(lib->ar_dss, lib->ar_nsfd,
01836                                          AR_SOCKET_EVENT_WRITE) != 1)
01837                             break;
01838 
01839                      pthread_mutex_lock(&q->q_lock);
01840                      if (ar_elapsed(&q->q_sent, &lib->ar_retry))
01841                      {
01842                             if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
01843                             {
01844                                    syslog(LOG_DEBUG, "arlib: retrying %p",
01845                                           q);
01846                             }
01847 
01848                             if (!ar_sendquery(lib, q))
01849                                    lib->ar_flags |= AR_FLAG_RECONNECT;
01850                      }
01851                      pthread_mutex_unlock(&q->q_lock);
01852               }
01853        }
01854 
01855        return NULL;
01856 }
01857 
01858 /*
01859 **  AR_RES_INIT -- res_init()/res_ninit() wrapper
01860 **
01861 **  Parameters:
01862 **     None.
01863 **
01864 **  Return value:
01865 **     0 on success, -1 on failure.
01866 */
01867 
01868 static int
01869 ar_res_init(AR_LIB new)
01870 {
01871 #if !defined(AR_RES_MANUAL) && !defined(AF_INET6)
01872        int c;
01873 #endif /* !defined(AR_RES_MANUAL) && !defined(AF_INET6) */
01874        size_t bytes;
01875        SOCKADDR *sa;
01876 
01877        assert(new != NULL);
01878 
01879        h_errno = NETDB_SUCCESS;
01880 
01881        memset(&new->ar_res, '\0', sizeof new->ar_res);
01882 
01883        /*
01884        **  We'll trust that res_init()/res_ninit() will give us things
01885        **  like NS counts and retransmission times, but can't always rely
01886        **  on it for the nameservers.
01887        */
01888 
01889 #if (defined(__RES) && (__RES <= 19960801))
01890        /* old-school (bind4) */
01891        res_init();
01892        memcpy(&new->ar_res, &_res, sizeof new->ar_res);
01893 #else /* defined(__RES) && (__RES <= 19960801) */
01894        /* new-school (bind8 and up) */
01895        (void) res_ninit(&new->ar_res);
01896 #endif /* defined(__RES) && (__RES <= 19960801) */
01897 
01898        new->ar_nscount = new->ar_res.nscount;
01899        new->ar_retry.tv_sec = new->ar_res.retrans;
01900        new->ar_retry.tv_usec = 0;
01901        new->ar_retries = new->ar_res.retry;
01902 
01903        if (new->ar_nscount == 0)
01904               new->ar_nscount = MAXNS;
01905 
01906        bytes = sizeof(SOCKADDR) * new->ar_nscount;
01907        if (new->ar_malloc != NULL)
01908        {
01909               new->ar_nsaddrs = (SOCKADDR *) new->ar_malloc(new->ar_closure,
01910                                                             bytes);
01911        }
01912        else
01913        {
01914               new->ar_nsaddrs = (SOCKADDR *) malloc(bytes);
01915        }
01916 
01917        if (new->ar_nsaddrs == NULL)
01918               return -1;
01919 
01920        memset(new->ar_nsaddrs, '\0', sizeof(SOCKADDR) * new->ar_res.nscount);
01921 
01922 #if defined(AR_RES_MANUAL) || defined(AF_INET6)
01923        ar_res_parse(&new->ar_nscount, new->ar_nsaddrs,
01924                     &new->ar_retries, &new->ar_retry.tv_sec);
01925 #else /* defined(AR_RES_MANUAL) || defined(AF_INET6) */
01926        memcpy(new->ar_nsaddrs, &new->ar_res.nsaddr_list,
01927               sizeof(SOCKADDR) * new->ar_res.nscount);
01928 
01929        /* an address of 0 (INADDR_ANY) should become INADDR_LOOPBACK */
01930        for (c = 0; c < new->ar_nscount; c++)
01931        {
01932               sa = (SOCKADDR *) &new->ar_nsaddrs[c];
01933               if (sa->sa_family == AF_INET)
01934               {
01935                      struct sockaddr_in *sin;
01936 
01937                      sin = (struct sockaddr_in *) sa;
01938 
01939                      if (sin->sin_addr.s_addr == INADDR_ANY)
01940                             sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
01941               }
01942        }
01943 #endif /* defined(AR_RES_MANUAL) || defined(AF_INET6) */
01944 
01945        return 0;
01946 }
01947 
01948 /*
01949 **  ========================= PUBLIC FUNCTIONS =========================
01950 */
01951 
01952 /*
01953 **  AR_INIT -- instantiate the service
01954 **
01955 **  Parameters:
01956 **     user_malloc -- malloc() replacement function
01957 **     user_free -- free() replacement function
01958 **     user_closure -- memory closure to be used for library allocations
01959 **     flags -- flags
01960 **
01961 **  Return value:
01962 **     An AR_LIB handle on success, NULL on failure (check errno)
01963 */
01964 
01965 AR_LIB
01966 ar_init(ar_malloc_t user_malloc, ar_free_t user_free, void *user_closure,
01967         int flags)
01968 {
01969        int status;
01970        int c;
01971        AR_LIB new;
01972        struct sockaddr *sa;
01973 
01974 #define TMP_MALLOC(x)       (user_malloc == NULL ? malloc((x)) \
01975                                           : user_malloc(user_closure, ((x))));
01976 #define TMP_FREE(x)  (user_free == NULL ? free((x)) \
01977                                         : user_free(user_closure, ((x))));
01978 #define       TMP_CLOSE(x)  if ((x) != -1) \
01979                             close((x));
01980                             
01981        new = TMP_MALLOC(sizeof(struct ar_libhandle));
01982        if (new == NULL)
01983               return NULL;
01984 
01985        new->ar_dss = ar_socket_init(0);
01986        if (new->ar_dss == NULL)
01987        {
01988               free(new);
01989               return NULL;
01990        }
01991 
01992        new->ar_css = ar_socket_init(0);
01993        if (new->ar_css == NULL)
01994        {
01995               ar_socket_free(new->ar_dss);
01996               free(new);
01997               return NULL;
01998        }
01999 
02000        new->ar_malloc = user_malloc;
02001        new->ar_free = user_free;
02002        new->ar_closure = user_closure;
02003        new->ar_flags = flags;
02004        new->ar_drun = 0;
02005        new->ar_nsfd = -1;
02006        new->ar_nsfdpf = -1;
02007        new->ar_tcpbuflen = 0;
02008        new->ar_tcpmsglen = 0;
02009        new->ar_tcpbufidx = 0;
02010        new->ar_tcpbuf = NULL;
02011        new->ar_pending = NULL;
02012        new->ar_pendingtail = NULL;
02013        new->ar_queries = NULL;
02014        new->ar_queriestail = NULL;
02015        new->ar_recycle = NULL;
02016        new->ar_querybuflen = HFIXEDSZ + MAXPACKET;
02017        new->ar_control[0] = -1;
02018        new->ar_control[1] = -1;
02019        new->ar_nsidx = 0;
02020        new->ar_writelen = 0;
02021        new->ar_partwrite = 0;
02022        new->ar_fullwrite = 0;
02023        new->ar_deadsince.tv_sec = 0;
02024        new->ar_deadsince.tv_usec = 0;
02025        new->ar_revivify.tv_sec = AR_DEFREVIVIFY;
02026        new->ar_revivify.tv_usec = 0;
02027 
02028        if (ar_res_init(new) != 0)
02029        {
02030               TMP_FREE(new);
02031               return NULL;
02032        }
02033 
02034        if (socketpair(AF_UNIX, SOCK_STREAM, 0, new->ar_control) != 0)
02035        {
02036               TMP_FREE(new);
02037               return NULL;
02038        }
02039 
02040        /* establish socket; connect if necessary */
02041        for (c = 0; c < new->ar_nscount; c++)
02042        {
02043               sa = (struct sockaddr *) &new->ar_nsaddrs[c];
02044 
02045               if ((new->ar_flags & AR_FLAG_USETCP) == 0)       /* UDP */
02046               {
02047                      new->ar_nsfd = socket(sa->sa_family, SOCK_DGRAM, 0);
02048                      if (new->ar_nsfd != -1)
02049                      {
02050                             new->ar_nsfdpf = sa->sa_family;
02051                             break;
02052                      }
02053               }
02054               else                                      /* TCP */
02055               {
02056                      int socklen;
02057 
02058                      new->ar_nsfd = socket(sa->sa_family, SOCK_STREAM, 0);
02059                      if (new->ar_nsfd == -1)
02060                             continue;
02061 #ifdef AF_INET6
02062                      if (sa->sa_family == AF_INET6)
02063                             socklen = sizeof(struct sockaddr_in6);
02064                      else
02065                             socklen = sizeof(struct sockaddr_in);
02066 #else /* AF_INET */
02067                      socklen = sizeof(struct sockaddr_in);
02068 #endif /* AF_INET */
02069 
02070                      if (connect(new->ar_nsfd, sa, socklen) == 0)
02071                      {
02072                             new->ar_nsfdpf = sa->sa_family;
02073                             break;
02074                      }
02075 
02076                      close(new->ar_nsfd);
02077                      new->ar_nsfd = -1;
02078               }
02079        }
02080 
02081        if (new->ar_nsfd == -1)
02082        {
02083               TMP_CLOSE(new->ar_control[0]);
02084               TMP_CLOSE(new->ar_control[1]);
02085               TMP_FREE(new);
02086               return NULL;
02087        }
02088 
02089        new->ar_querybuf = TMP_MALLOC(new->ar_querybuflen);
02090        if (new->ar_querybuf == NULL)
02091        {
02092               TMP_CLOSE(new->ar_control[0]);
02093               TMP_CLOSE(new->ar_control[1]);
02094               TMP_CLOSE(new->ar_nsfd);
02095               TMP_FREE(new->ar_nsaddrs);
02096               TMP_FREE(new);
02097               return NULL;
02098        }
02099 
02100 #ifdef ARDEBUG
02101        ar_debug_init();
02102 #endif /* ARDEBUG */
02103 
02104        (void) pthread_mutex_init(&new->ar_lock, NULL);
02105 
02106        return new;
02107 }
02108 
02109 /*
02110 **  AR_SHUTDOWN -- terminate an instance of the service
02111 **
02112 **  Parameters:
02113 **     lib -- library handle
02114 **
02115 **  Return value:
02116 **     0 on success, or an errno on failure.
02117 */
02118 
02119 int
02120 ar_shutdown(AR_LIB lib)
02121 {
02122        int status;
02123 
02124        assert(lib != NULL);
02125 
02126        close(lib->ar_control[0]);
02127 
02128        if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
02129               syslog(LOG_DEBUG, "arlib: shutting down");
02130 
02131        status = 0;
02132 
02133        if (lib->ar_drun != 0)
02134               status = pthread_join(lib->ar_dispatcher, NULL);
02135 
02136        if (status == 0)
02137        {
02138               void *closure;
02139               void (*user_free)(void *, void *);
02140 
02141               close(lib->ar_nsfd);
02142               close(lib->ar_control[1]);
02143               pthread_mutex_destroy(&lib->ar_lock);
02144 
02145               ar_smashqueue(lib, lib->ar_pending);
02146               ar_smashqueue(lib, lib->ar_queries);
02147               ar_smashqueue(lib, lib->ar_recycle);
02148 
02149               if (lib->ar_tcpbuf != NULL)
02150                      ar_free(lib, lib->ar_tcpbuf);
02151               ar_free(lib, lib->ar_querybuf);
02152               ar_free(lib, lib->ar_nsaddrs);
02153 
02154               closure = lib->ar_closure;
02155               user_free = lib->ar_free;
02156 
02157               ar_socket_free(lib->ar_css);
02158               ar_socket_free(lib->ar_dss);
02159 
02160               if (user_free != NULL)
02161                      user_free(closure, lib);
02162               else
02163                      free(lib);
02164        }
02165 
02166 #ifdef ARDEBUG
02167        ar_debug_stop();
02168 #endif /* ARDEBUG */
02169 
02170        return status;
02171 }
02172 
02173 /*
02174 **  AR_SETRETRY -- set retry interval
02175 **
02176 **  Parameters:
02177 **     lib -- library handle
02178 **     new -- new retry interval (may be NULL);
02179 **     old -- current retry interval (returned; may be NULL)
02180 **
02181 **  Return value:
02182 **     None.
02183 */
02184 
02185 void
02186 ar_setretry(AR_LIB lib, struct timeval *new, struct timeval *old)
02187 {
02188        assert(lib != NULL);
02189 
02190        if (old != NULL)
02191               memcpy(old, &lib->ar_retry, sizeof lib->ar_retry);
02192 
02193        if (new != NULL)
02194               memcpy(&lib->ar_retry, new, sizeof lib->ar_retry);
02195 }
02196 
02197 /*
02198 **  AR_SETMAXRETRY -- set max retry count
02199 **
02200 **  Parameters:
02201 **     lib -- library handle
02202 **     new -- new value (or -1 to leave unchanged)
02203 **     old -- current value (returned; may be NULL)
02204 **
02205 **  Return value:
02206 **     None.
02207 */
02208 
02209 void
02210 ar_setmaxretry(AR_LIB lib, int new, int *old)
02211 {
02212        assert(lib != NULL);
02213 
02214        if (old != NULL)
02215               *old = lib->ar_retries;
02216 
02217        if (new != -1)
02218               lib->ar_retries = new;
02219 }
02220 
02221 /*
02222 **  AR_POKE -- poke the dispatcher
02223 **
02224 **  Parameters:
02225 **     lib -- AR library handle
02226 **
02227 **  Return value:
02228 **     Bytes written to the dispatcher control socket (i.e. the return from
02229 **     write(2)).
02230 **
02231 **  Notes:
02232 **     Write a four-byte NULL to the control descriptor to indicate
02233 **     to the dispatcher there's general work to do.  This will cause
02234 **     it to check its "pending" list for work to do and dispatch it.
02235 **     If the descriptor is not writeable, we don't much care because
02236 **     that means the pipe is full of messages already which will wake
02237 **     up the dispatcher anyway.
02238 */
02239 
02240 static size_t
02241 ar_poke(AR_LIB lib)
02242 {
02243        int maxfd;
02244        int status;
02245        size_t wlen;
02246        AR_QUERY x = NULL;
02247 
02248        assert(lib != NULL);
02249 
02250        wlen = sizeof x;
02251 
02252        ar_socket_reset(lib->ar_css);
02253        ar_socket_add(lib->ar_css, lib->ar_control[0], AR_SOCKET_EVENT_WRITE);
02254        status = ar_socket_wait(lib->ar_css, 0);
02255        if (status == 1)
02256               wlen = write(lib->ar_control[0], &x, sizeof x);
02257        else if (status == -1)
02258               wlen = (size_t) -1;
02259 
02260        return wlen;
02261 }
02262 
02263 /*
02264 **  AR_ADDQUERY -- add a query for processing
02265 **
02266 **  Parameters:
02267 **     lib -- library handle
02268 **     name -- name of the query to be submitted
02269 **     class -- class of the query to be submitted
02270 **     type -- type of the query to be submitted
02271 **     depth -- chase CNAMEs to this depth (0 == don't)
02272 **     buf -- buffer into which to write the result
02273 **     buflen -- bytes available at "buf"
02274 **     err -- pointer to an int which should receive errno on send errors
02275 **     timeout -- timeout (or NULL)
02276 **
02277 **  Return value:
02278 **     NULL -- error; see errno and/or the value returned in err
02279 **     otherwise, an AR_QUERY handle
02280 */
02281 
02282 AR_QUERY
02283 ar_addquery(AR_LIB lib, char *name, int class, int type, int depth,
02284             unsigned char *buf, size_t buflen, int *err,
02285             struct timeval *timeout)
02286 {
02287        char prev;
02288        int status;
02289        size_t wlen;
02290        AR_QUERY q;
02291        char *p;
02292 
02293        assert(lib != NULL);
02294        assert(name != NULL);
02295 
02296        /*
02297        **  Sanity-check the name.  Look for invalid characters or patterns
02298        **  that will make res_mkquery() return -1 for reasons other than
02299        **  "buffer too short".
02300        **
02301        **  In particular, look for:
02302        **     - non-ASCII characters
02303        **     - non-printable characters
02304        **     - things that start with "."
02305        **     - things that contain adjacent "."s
02306        */
02307 
02308        wlen = 0;
02309        prev = '\0';
02310        for (p = name; *p != '\0'; p++)
02311        {
02312               if (!isascii(*p) || !isprint(*p) ||
02313                   (*p == '.' && (prev == '.' || prev == '\0')))
02314               {
02315                      if (err != NULL)
02316                             *err = EINVAL;
02317                      errno = EINVAL;
02318                      return NULL;
02319               }
02320 
02321               prev = *p;
02322        }
02323 
02324        /* sanity-check the timeout, if provided */
02325        if (timeout != NULL)
02326        {
02327               if (timeout->tv_sec < 0 || timeout->tv_sec > AR_MAXTIMEOUT ||
02328                   timeout->tv_usec < 0 || timeout->tv_usec >= 1000000)
02329               {
02330                      if (err != NULL)
02331                             *err = EINVAL;
02332                      errno = EINVAL;
02333                      return NULL;
02334               }
02335        }
02336 
02337        pthread_mutex_lock(&lib->ar_lock);
02338 
02339        /* start the dispatcher if it's not already running */
02340        if (lib->ar_drun == 0)
02341        {
02342               status = pthread_create(&lib->ar_dispatcher, NULL,
02343                                       ar_dispatcher, lib);
02344               if (status != 0)
02345               {
02346                      if (err != NULL)
02347                             *err = status;
02348                      errno = status;
02349                      pthread_mutex_unlock(&lib->ar_lock);
02350                      return NULL;
02351               }
02352 
02353               lib->ar_drun = 1;
02354        }
02355 
02356        if ((lib->ar_flags & AR_FLAG_DEAD) != 0)
02357        {
02358               if (err != NULL)
02359                      *err = lib->ar_deaderrno;
02360               errno = lib->ar_deaderrno;
02361               pthread_mutex_unlock(&lib->ar_lock);
02362               return NULL;
02363        }
02364 
02365        if (lib->ar_recycle != NULL)
02366        {
02367               q = lib->ar_recycle;
02368               lib->ar_recycle = q->q_next;
02369               pthread_mutex_unlock(&lib->ar_lock);
02370        }
02371        else
02372        {
02373               pthread_mutex_unlock(&lib->ar_lock);
02374               q = ar_malloc(lib, sizeof(struct ar_query));
02375               if (q == NULL)
02376               {
02377                      if (err != NULL)
02378                             *err = errno;
02379                      return NULL;
02380               }
02381               memset(q, '\0', sizeof(struct ar_query));
02382               pthread_mutex_init(&q->q_lock, NULL);
02383               pthread_cond_init(&q->q_reply, NULL);
02384        }
02385 
02386        /* construct the query */
02387        q->q_class = class;
02388        q->q_type = type;
02389        q->q_flags = 0;
02390        q->q_depth = depth;
02391        q->q_errno = err;
02392        q->q_next = NULL;
02393        q->q_buf = buf;
02394        q->q_buflen = buflen;
02395        q->q_tries = 0;
02396        if (timeout == NULL)
02397        {
02398               q->q_flags |= QUERY_INFINIWAIT;
02399               q->q_timeout.tv_sec = 0;
02400               q->q_timeout.tv_usec = 0;
02401        }
02402        else
02403        {
02404               (void) gettimeofday(&q->q_timeout, NULL);
02405               q->q_timeout.tv_sec += timeout->tv_sec;
02406               q->q_timeout.tv_usec += timeout->tv_usec;
02407               if (q->q_timeout.tv_usec >= 1000000)
02408               {
02409                      q->q_timeout.tv_sec += 1;
02410                      q->q_timeout.tv_usec -= 1000000;
02411               }
02412        }
02413        strlcpy(q->q_name, name, sizeof q->q_name);
02414 
02415        /* enqueue the query and signal the dispatcher */
02416        pthread_mutex_lock(&lib->ar_lock);
02417        if (lib->ar_pending == NULL)
02418        {
02419               lib->ar_pending = q;
02420               lib->ar_pendingtail = q;
02421        }
02422        else
02423        {
02424               lib->ar_pendingtail->q_next = q;
02425               lib->ar_pendingtail = q;
02426        }
02427 
02428        wlen = ar_poke(lib);
02429 
02430        if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
02431        {
02432               syslog(LOG_DEBUG, "arlib: added query %p %d/%d '%s'",
02433                      q, q->q_class, q->q_type, q->q_name);
02434        }
02435 
02436        pthread_mutex_unlock(&lib->ar_lock);
02437 
02438        switch (wlen)
02439        {
02440          case sizeof q:
02441               return q;
02442 
02443          default:
02444               ar_recycle(lib, q);
02445               return NULL;
02446        }
02447 }
02448 
02449 /*
02450 **  AR_CANCELQUERY -- cancel a pending query
02451 **
02452 **  Parameters:
02453 **     lib -- library handle
02454 **     query -- AR_QUERY handle which should be terminated
02455 **
02456 **  Return value:
02457 **     0 -- cancel successful
02458 **     1 -- cancel not successful (record not found)
02459 */
02460 
02461 int
02462 ar_cancelquery(AR_LIB lib, AR_QUERY query)
02463 {
02464        AR_QUERY q;
02465        AR_QUERY last;
02466 
02467        assert(lib != NULL);
02468        assert(query != NULL);
02469 
02470        pthread_mutex_lock(&lib->ar_lock);
02471 
02472        if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
02473               syslog(LOG_DEBUG, "arlib: canceling query %p", query);
02474 
02475        /* first, look in pending queries */
02476        for (q = lib->ar_pending, last = NULL;
02477             q != NULL;
02478             last = q, q = q->q_next)
02479        {
02480               if (query == q)
02481               {
02482                      if (last == NULL)
02483                      {
02484                             lib->ar_pending = q->q_next;
02485                             if (lib->ar_pending == NULL)
02486                                    lib->ar_pendingtail = NULL;
02487                      }
02488                      else
02489                      {
02490                             last->q_next = q->q_next;
02491                             if (lib->ar_pendingtail == q)
02492                                    lib->ar_pendingtail = last;
02493                      }
02494 
02495                      q->q_next = lib->ar_recycle;
02496                      if ((q->q_flags & QUERY_RESEND) != 0)
02497                             lib->ar_resend--;
02498                      lib->ar_recycle = q;
02499 
02500                      pthread_mutex_unlock(&lib->ar_lock);
02501                      return 0;
02502               }
02503        }
02504        
02505        /* next, look in active queries */
02506        for (q = lib->ar_queries, last = NULL;
02507             q != NULL;
02508             last = q, q = q->q_next)
02509        {
02510               if (query == q)
02511               {
02512                      if (last == NULL)
02513                      {
02514                             lib->ar_queries = q->q_next;
02515                             if (lib->ar_queries == NULL)
02516                                    lib->ar_queriestail = NULL;
02517 
02518                      }
02519                      else
02520                      {
02521                             last->q_next = q->q_next;
02522                             if (lib->ar_queriestail == q)
02523                                    lib->ar_queriestail = last;
02524                      }
02525 
02526                      q->q_next = lib->ar_recycle;
02527                      if ((q->q_flags & QUERY_RESEND) != 0)
02528                             lib->ar_resend--;
02529                      lib->ar_recycle = q;
02530 
02531                      pthread_mutex_unlock(&lib->ar_lock);
02532                      return 0;
02533               }
02534        }
02535 
02536        pthread_mutex_unlock(&lib->ar_lock);
02537 
02538        if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
02539               syslog(LOG_DEBUG, "arlib: cancel failed for query %p", query);
02540 
02541        return 1;
02542 }
02543 
02544 /*
02545 **  AR_WAITREPLY -- go to sleep waiting for a reply
02546 **
02547 **  Parameters:
02548 **     lib -- library handle
02549 **     query -- AR_QUERY handle of interest
02550 **     len -- length of the received reply (returned)
02551 **     timeout -- timeout for the wait, or NULL to wait for the query
02552 **                to time out
02553 **
02554 **  Return value:
02555 **     AR_STAT_SUCCESS -- success; reply available
02556 **     AR_STAT_NOREPLY -- timeout; no reply available yet
02557 **     AR_STAT_EXPIRED -- timeout; query expired
02558 **     AR_STAT_ERROR -- error; see errno
02559 **
02560 **  Notes:
02561 **     If *len is greater than the size of the buffer provided when
02562 **     ar_addquery() was called, then there was some data truncated
02563 **     because the buffer was not big enough to receive the whole reply.
02564 **     The caller should resubmit with a larger buffer.
02565 */
02566 
02567 int
02568 ar_waitreply(AR_LIB lib, AR_QUERY query, size_t *len, struct timeval *timeout)
02569 {
02570        _Bool infinite;
02571        _Bool maintimeout = FALSE;
02572        int status;
02573        struct timespec until;
02574        struct timeval now;
02575 
02576        assert(lib != NULL);
02577        assert(query != NULL);
02578 
02579        if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
02580               syslog(LOG_DEBUG, "arlib: waiting for query %p", query);
02581 
02582        pthread_mutex_lock(&query->q_lock);
02583 
02584        if ((query->q_flags & QUERY_REPLY) != 0)
02585        {
02586               if (len != NULL)
02587                      *len = query->q_replylen;
02588               pthread_mutex_unlock(&query->q_lock);
02589 
02590               if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
02591               {
02592                      syslog(LOG_DEBUG, "arlib: wait for %p successful",
02593                             query);
02594               }
02595 
02596               return AR_STAT_SUCCESS;
02597        }
02598        else if ((query->q_flags & QUERY_ERROR) != 0)
02599        {
02600               pthread_mutex_unlock(&query->q_lock);
02601 
02602               if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
02603               {
02604                      syslog(LOG_DEBUG, "arlib: wait for %p error [1]",
02605                             query);
02606               }
02607 
02608               return AR_STAT_ERROR;
02609        }
02610        else if ((query->q_flags & QUERY_NOREPLY) != 0)
02611        {
02612               if (query->q_errno != NULL)
02613                      *query->q_errno = ETIMEDOUT;
02614               pthread_mutex_unlock(&query->q_lock);
02615 
02616               if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
02617               {
02618                      syslog(LOG_DEBUG, "arlib: wait for %p expired",
02619                             query);
02620               }
02621 
02622               return AR_STAT_EXPIRED;
02623        }
02624 
02625        /*
02626        **  Pick the soonest of:
02627        **  - timeout specified above
02628        **  - timeout specified on the query
02629        **  - forever
02630        */
02631 
02632        (void) gettimeofday(&now, NULL);
02633        infinite = FALSE;
02634        until.tv_sec = 0;
02635        until.tv_nsec = 0;
02636 
02637        if (timeout == NULL && (query->q_flags & QUERY_INFINIWAIT) != 0)
02638        {
02639               infinite = TRUE;
02640        }
02641        else
02642        {
02643               /* if a timeout was specified above */
02644               if (timeout != NULL)
02645               {
02646                      until.tv_sec = now.tv_sec + timeout->tv_sec;
02647                      until.tv_nsec = now.tv_usec + timeout->tv_usec;
02648                      if (until.tv_nsec >= 1000000)
02649                      {
02650                             until.tv_sec += 1;
02651                             until.tv_nsec -= 1000000;
02652                      }
02653                      until.tv_nsec *= 1000;
02654               }
02655 
02656               /* if a timeout was specified on the query */
02657               if ((query->q_flags & QUERY_INFINIWAIT) == 0)
02658               {
02659                      if (until.tv_sec == 0 ||
02660                          until.tv_sec > query->q_timeout.tv_sec ||
02661                          (until.tv_sec == query->q_timeout.tv_sec &&
02662                           until.tv_nsec > query->q_timeout.tv_usec * 1000))
02663                      {
02664                             until.tv_sec = query->q_timeout.tv_sec;
02665                             until.tv_nsec = query->q_timeout.tv_usec * 1000;
02666                             maintimeout = TRUE;
02667                      }
02668               }
02669        }
02670 
02671        while ((query->q_flags & (QUERY_REPLY|QUERY_NOREPLY|QUERY_ERROR)) == 0)
02672        {
02673               if (infinite)
02674               {
02675                      status = pthread_cond_wait(&query->q_reply,
02676                                                 &query->q_lock);
02677               }
02678               else
02679               {
02680                      status = pthread_cond_timedwait(&query->q_reply,
02681                                                      &query->q_lock,
02682                                                      &until);
02683                      if (status == ETIMEDOUT)
02684                             break;
02685               }
02686        }
02687 
02688        /* recheck flags */
02689        if ((query->q_flags & QUERY_ERROR) != 0)
02690        {
02691               pthread_mutex_unlock(&query->q_lock);
02692 
02693               if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
02694               {
02695                      syslog(LOG_DEBUG, "arlib: wait for %p error [2]",
02696                             query);
02697               }
02698 
02699               return AR_STAT_ERROR;
02700        }
02701        else if ((query->q_flags & QUERY_REPLY) == 0)
02702        {
02703               if (maintimeout && query->q_errno != NULL)
02704                      *query->q_errno = ETIMEDOUT;
02705               pthread_mutex_unlock(&query->q_lock);
02706 
02707               if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
02708               {
02709                      syslog(LOG_DEBUG, "arlib: wait for %p timeout (%s)",
02710                             query, maintimeout ? "expired" : "no reply");
02711               }
02712 
02713               return (maintimeout ? AR_STAT_EXPIRED : AR_STAT_NOREPLY);
02714        }
02715 
02716        if (len != NULL)
02717               *len = query->q_replylen;
02718        pthread_mutex_unlock(&query->q_lock);
02719 
02720        if ((lib->ar_flags & AR_FLAG_TRACELOGGING) != 0)
02721               syslog(LOG_DEBUG, "arlib: wait for %p succeeded", query);
02722 
02723        return AR_STAT_SUCCESS;
02724 }
02725 
02726 /*
02727 **  AR_RECYCLE -- recycle a query when the caller is done with it
02728 **
02729 **  Parameters:
02730 **     lib -- library handle
02731 **     query -- AR_QUERY handle to recycle
02732 **
02733 **  Return value:
02734 **     None.
02735 */
02736 
02737 void
02738 ar_recycle(AR_LIB lib, AR_QUERY query)
02739 {
02740        assert(lib != NULL);
02741        assert(query != NULL);
02742 
02743        pthread_mutex_lock(&lib->ar_lock);
02744        query->q_next = lib->ar_recycle;
02745        lib->ar_recycle = query;
02746        pthread_mutex_unlock(&lib->ar_lock);
02747 }
02748 
02749 /*
02750 **  AR_RESEND -- enqueue re-sending of a pending request
02751 **
02752 **  Parameters:
02753 **     lib -- library handle
02754 **     query -- query to re-send
02755 **
02756 **  Return value:
02757 **     0 on success, -1 on failure.
02758 */
02759 
02760 int
02761 ar_resend(AR_LIB lib, AR_QUERY query)
02762 {
02763        size_t wlen;
02764 
02765        assert(lib != NULL);
02766        assert(query != NULL);
02767 
02768        wlen = write(lib->ar_control[1], query, sizeof query);
02769        return (wlen == 4 ? 0 : -1);
02770 }
02771 
02772 /*
02773 **  AR_STRERROR -- translate an error code
02774 **
02775 **  Parameters:
02776 **     err -- error code
02777 **
02778 **  Return value:
02779 **     Pointer to a text string which represents that error code.
02780 */
02781 
02782 char *
02783 ar_strerror(int err)
02784 {
02785        switch (err)
02786        {
02787          case QUERY_ERRNO_RETRIES:
02788               return "Too many retries";
02789 
02790          case QUERY_ERRNO_TOOBIG:
02791               return "Unable to construct query";
02792 
02793          default:
02794               return strerror(errno);
02795        }
02796 }
02797 
02798 /*
02799 **  AR_RESOLVCONF -- parse a resolv.conf file for nameservers to use
02800 **
02801 **  Parameters:
02802 **     ar -- AR_LIB handle to update
02803 **     file -- path to access
02804 **
02805 **  Return value:
02806 **     0 -- success
02807 **     !0 -- an error occurred; check errno
02808 **
02809 **  Notes:
02810 **     Parse errors are not reported.
02811 **
02812 **     The default set is not modified if no "nameserver" lines are found.
02813 */
02814 
02815 int
02816 ar_resolvconf(AR_LIB ar, char *file)
02817 {
02818        int af;
02819        int n = 0;
02820        FILE *f;
02821        char *p;
02822        char *sp;
02823        SOCKADDR *news;
02824        struct sockaddr_in s4;
02825 #ifdef AF_INET6
02826        struct sockaddr_in6 s6;
02827 #endif /* AF_INET6 */
02828        char buf[BUFRSZ];
02829 
02830        assert(ar != NULL);
02831        assert(file != NULL);
02832 
02833        f = fopen(file, "r");
02834        if (f == NULL)
02835               return -1;
02836 
02837        memset(buf, '\0', sizeof buf);
02838 
02839        while (fgets(buf, sizeof buf - 1, f) != NULL)
02840        {
02841               sp = NULL;
02842 
02843               for (p = buf; *p != '\0'; p++)
02844               {
02845                      if (sp == NULL && isspace(*p))
02846                             sp = p;
02847 
02848                      if (*p == '#' || *p == '\n')
02849                      {
02850                             *p = '\0';
02851                             break;
02852                      }
02853               }
02854 
02855               if (sp != NULL)
02856                      *sp = '\0';
02857 
02858               if (strcasecmp(buf, "nameserver") != 0)
02859                      continue;
02860 
02861               af = -1;
02862               if (inet_pton(AF_INET, sp + 1, &s4.sin_addr.s_addr) == 0)
02863                      af = AF_INET;
02864 #ifdef AF_INET6
02865               else if (inet_pton(AF_INET6, sp + 1,
02866                        &s6.sin6_addr.s6_addr) == 0)
02867                      af = AF_INET6;
02868 #endif /* AF_INET6 */
02869 
02870               if (af == -1)
02871                      continue;
02872 
02873               if (n == 0)
02874               {
02875                      news = (SOCKADDR *) malloc(MAXNS * sizeof(SOCKADDR));
02876                      if (news == NULL)
02877                      {
02878                             fclose(f);
02879                             return -1;
02880                      }
02881 
02882                      free(ar->ar_nsaddrs);
02883                      ar->ar_nsaddrs = news;
02884               }
02885 
02886               if (af == AF_INET)
02887               {
02888                      s4.sin_family = AF_INET;
02889 #ifdef HAVE_SIN_LEN
02890                      s4.sin_len = sizeof s4;
02891 #endif /* HAVE_SIN_LEN */
02892                      memcpy(&news[n], &s4, sizeof s4);
02893               }
02894 #ifdef AF_INET6
02895               else if (af == AF_INET6)
02896               {
02897                      s6.sin6_family = AF_INET6;
02898 # ifdef HAVE_SIN6_LEN
02899                      s6.sin6_len = sizeof s6;
02900 # endif /* HAVE_SIN6_LEN */
02901                      memcpy(&news[n], &s6, sizeof s6);
02902               }
02903 #endif /* AF_INET6 */
02904 
02905               n++;
02906               if (n == MAXNS)
02907                      break;
02908        }
02909 
02910        ar->ar_nscount = n;
02911 
02912        fclose(f);
02913 
02914        return 0;
02915 }