2003-03-15 Roland McGrath <roland@redhat.com>
[kopensolaris-gnu/glibc.git] / resolv / res_query.c
index 92a90d6..ab4e02a 100644 (file)
@@ -85,12 +85,19 @@ static const char rcsid[] = "$BINDId: res_query.c,v 8.20 2000/02/29 05:39:12 vix
 /* Options.  Leave them on. */
 /* #undef DEBUG */
 
-#if PACKETSZ > 1024
+#if PACKETSZ > 65536
 #define MAXPACKET      PACKETSZ
 #else
-#define MAXPACKET      1024
+#define MAXPACKET      65536
 #endif
 
+#define QUERYSIZE      (HFIXEDSZ + QFIXEDSZ + MAXCDNAME + 1)
+
+static int
+__libc_res_nquerydomain(res_state statp, const char *name, const char *domain,
+                       int class, int type, u_char *answer, int anslen,
+                       u_char **answerp);
+
 /*
  * Formulate a normal query, send, and await answer.
  * Returned answer is placed in supplied buffer "answer".
@@ -102,34 +109,51 @@ static const char rcsid[] = "$BINDId: res_query.c,v 8.20 2000/02/29 05:39:12 vix
  * Caller must parse answer and determine whether it answers the question.
  */
 int
-res_nquery(res_state statp,
-          const char *name,    /* domain name */
-          int class, int type, /* class and type of query */
-          u_char *answer,      /* buffer to put answer */
-          int anslen)          /* size of answer buffer */
+__libc_res_nquery(res_state statp,
+                 const char *name,     /* domain name */
+                 int class, int type,  /* class and type of query */
+                 u_char *answer,       /* buffer to put answer */
+                 int anslen,           /* size of answer buffer */
+                 u_char **answerp)     /* if buffer needs to be enlarged */
 {
-       u_char buf[MAXPACKET];
+       u_char *buf;
        HEADER *hp = (HEADER *) answer;
-       int n;
+       int n, use_malloc = 0;
 
        hp->rcode = NOERROR;    /* default */
 
+       buf = alloca (QUERYSIZE);
+
 #ifdef DEBUG
        if (statp->options & RES_DEBUG)
                printf(";; res_query(%s, %d, %d)\n", name, class, type);
 #endif
 
        n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
-                        buf, sizeof(buf));
-       if (n <= 0) {
+                        buf, QUERYSIZE);
+       if (__builtin_expect (n <= 0, 0)) {
+               /* Retry just in case res_nmkquery failed because of too
+                  short buffer.  Shouldn't happen.  */
+               buf = malloc (MAXPACKET);
+               if (buf != NULL) {
+                       use_malloc = 1;
+                       n = res_nmkquery(statp, QUERY, name, class, type, NULL,
+                                        0, NULL, buf, MAXPACKET);
+               }               
+       }
+       if (__builtin_expect (n <= 0, 0)) {
 #ifdef DEBUG
                if (statp->options & RES_DEBUG)
                        printf(";; res_query: mkquery failed\n");
 #endif
                RES_SET_H_ERRNO(statp, NO_RECOVERY);
+               if (use_malloc)
+                       free (buf);
                return (n);
        }
-       n = res_nsend(statp, buf, n, answer, anslen);
+       n = __libc_res_nsend(statp, buf, n, answer, anslen, answerp);
+       if (use_malloc)
+               free (buf);
        if (n < 0) {
 #ifdef DEBUG
                if (statp->options & RES_DEBUG)
@@ -167,6 +191,17 @@ res_nquery(res_state statp,
        return (n);
 }
 
+int
+res_nquery(res_state statp,
+          const char *name,    /* domain name */
+          int class, int type, /* class and type of query */
+          u_char *answer,      /* buffer to put answer */
+          int anslen)          /* size of answer buffer */
+{
+       return __libc_res_nquery(statp, name, class, type, answer, anslen,
+                                NULL);
+}
+
 /*
  * Formulate a normal query, send, and retrieve answer in supplied buffer.
  * Return the size of the response on success, -1 on error.
@@ -174,11 +209,12 @@ res_nquery(res_state statp,
  * is detected.  Error code, if any, is left in H_ERRNO.
  */
 int
-res_nsearch(res_state statp,
+__libc_res_nsearch(res_state statp,
            const char *name,   /* domain name */
            int class, int type,        /* class and type of query */
            u_char *answer,     /* buffer to put answer */
-           int anslen)         /* size of answer */
+           int anslen,         /* size of answer */
+           u_char **answerp)
 {
        const char *cp, * const *domain;
        HEADER *hp = (HEADER *) answer;
@@ -200,7 +236,8 @@ res_nsearch(res_state statp,
 
        /* If there aren't any dots, it could be a user-level alias. */
        if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
-               return (res_nquery(statp, cp, class, type, answer, anslen));
+               return (__libc_res_nquery(statp, cp, class, type, answer,
+                                         anslen, answerp));
 
        /*
         * If there are enough dots in the name, let's just give it a
@@ -209,12 +246,16 @@ res_nsearch(res_state statp,
         */
        saved_herrno = -1;
        if (dots >= statp->ndots || trailing_dot) {
-               ret = res_nquerydomain(statp, name, NULL, class, type,
-                                        answer, anslen);
+               ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
+                                             answer, anslen, answerp);
                if (ret > 0 || trailing_dot)
                        return (ret);
                saved_herrno = h_errno;
                tried_as_is++;
+               if (answerp && *answerp != answer) {
+                       answer = *answerp;
+                       anslen = MAXPACKET;
+               }
        }
 
        /*
@@ -235,12 +276,17 @@ res_nsearch(res_state statp,
                            (domain[0][0] == '.' && domain[0][1] == '\0'))
                                root_on_list++;
 
-                       ret = res_nquerydomain(statp, name, *domain,
-                                              class, type,
-                                              answer, anslen);
+                       ret = __libc_res_nquerydomain(statp, name, *domain,
+                                                     class, type,
+                                                     answer, anslen, answerp);
                        if (ret > 0)
                                return (ret);
 
+                       if (answerp && *answerp != answer) {
+                               answer = *answerp;
+                               anslen = MAXPACKET;
+                       }
+
                        /*
                         * If no server present, give up.
                         * If name isn't found in this domain,
@@ -292,8 +338,8 @@ res_nsearch(res_state statp,
         * query now.
         */
        if (statp->ndots && !(tried_as_is || root_on_list)) {
-               ret = res_nquerydomain(statp, name, NULL, class, type,
-                                      answer, anslen);
+               ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
+                                             answer, anslen, answerp);
                if (ret > 0)
                        return (ret);
        }
@@ -314,17 +360,29 @@ res_nsearch(res_state statp,
        return (-1);
 }
 
+int
+res_nsearch(res_state statp,
+           const char *name,   /* domain name */
+           int class, int type,        /* class and type of query */
+           u_char *answer,     /* buffer to put answer */
+           int anslen)         /* size of answer */
+{
+       return __libc_res_nsearch(statp, name, class, type, answer,
+                                 anslen, NULL);
+}
+
 /*
  * Perform a call on res_query on the concatenation of name and domain,
  * removing a trailing dot from name if domain is NULL.
  */
-int
-res_nquerydomain(res_state statp,
+static int
+__libc_res_nquerydomain(res_state statp,
            const char *name,
            const char *domain,
            int class, int type,        /* class and type of query */
            u_char *answer,             /* buffer to put answer */
-           int anslen)         /* size of answer */
+           int anslen,                 /* size of answer */
+           u_char **answerp)
 {
        char nbuf[MAXDNAME];
        const char *longname = nbuf;
@@ -360,7 +418,20 @@ res_nquerydomain(res_state statp,
                }
                sprintf(nbuf, "%s.%s", name, domain);
        }
-       return (res_nquery(statp, longname, class, type, answer, anslen));
+       return (__libc_res_nquery(statp, longname, class, type, answer,
+                                 anslen, answerp));
+}
+
+int
+res_nquerydomain(res_state statp,
+           const char *name,
+           const char *domain,
+           int class, int type,        /* class and type of query */
+           u_char *answer,             /* buffer to put answer */
+           int anslen)         /* size of answer */
+{
+       return __libc_res_nquerydomain(statp, name, domain, class, type,
+                                      answer, anslen, NULL);
 }
 
 const char *