Annotation of 43BSDReno/lib/libc/net/res_send.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1985, 1989 Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms are permitted
        !             6:  * provided that: (1) source distributions retain this entire copyright
        !             7:  * notice and comment, and (2) distributions including binaries display
        !             8:  * the following acknowledgement:  ``This product includes software
        !             9:  * developed by the University of California, Berkeley and its contributors''
        !            10:  * in the documentation or other materials provided with the distribution
        !            11:  * and in all advertising materials mentioning features or use of this
        !            12:  * software. Neither the name of the University nor the names of its
        !            13:  * contributors may be used to endorse or promote products derived
        !            14:  * from this software without specific prior written permission.
        !            15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
        !            16:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
        !            17:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            18:  */
        !            19: 
        !            20: #if defined(LIBC_SCCS) && !defined(lint)
        !            21: static char sccsid[] = "@(#)res_send.c 6.25 (Berkeley) 6/1/90";
        !            22: #endif /* LIBC_SCCS and not lint */
        !            23: 
        !            24: /*
        !            25:  * Send query to name server and wait for reply.
        !            26:  */
        !            27: 
        !            28: #include <sys/param.h>
        !            29: #include <sys/time.h>
        !            30: #include <sys/socket.h>
        !            31: #include <sys/uio.h>
        !            32: #include <netinet/in.h>
        !            33: #include <stdio.h>
        !            34: #include <errno.h>
        !            35: #include <arpa/nameser.h>
        !            36: #include <resolv.h>
        !            37: 
        !            38: extern int errno;
        !            39: 
        !            40: static int s = -1;     /* socket used for communications */
        !            41: static struct sockaddr no_addr;
        !            42:   
        !            43: 
        !            44: #ifndef FD_SET
        !            45: #define        NFDBITS         32
        !            46: #define        FD_SETSIZE      32
        !            47: #define        FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
        !            48: #define        FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
        !            49: #define        FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
        !            50: #define FD_ZERO(p)     bzero((char *)(p), sizeof(*(p)))
        !            51: #endif
        !            52: 
        !            53: res_send(buf, buflen, answer, anslen)
        !            54:        char *buf;
        !            55:        int buflen;
        !            56:        char *answer;
        !            57:        int anslen;
        !            58: {
        !            59:        register int n;
        !            60:        int try, v_circuit, resplen, ns;
        !            61:        int gotsomewhere = 0, connected = 0;
        !            62:        int connreset = 0;
        !            63:        u_short id, len;
        !            64:        char *cp;
        !            65:        fd_set dsmask;
        !            66:        struct timeval timeout;
        !            67:        HEADER *hp = (HEADER *) buf;
        !            68:        HEADER *anhp = (HEADER *) answer;
        !            69:        struct iovec iov[2];
        !            70:        int terrno = ETIMEDOUT;
        !            71:        char junk[512];
        !            72: 
        !            73: #ifdef DEBUG
        !            74:        if (_res.options & RES_DEBUG) {
        !            75:                printf("res_send()\n");
        !            76:                p_query(buf);
        !            77:        }
        !            78: #endif DEBUG
        !            79:        if (!(_res.options & RES_INIT))
        !            80:                if (res_init() == -1) {
        !            81:                        return(-1);
        !            82:                }
        !            83:        v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
        !            84:        id = hp->id;
        !            85:        /*
        !            86:         * Send request, RETRY times, or until successful
        !            87:         */
        !            88:        for (try = 0; try < _res.retry; try++) {
        !            89:           for (ns = 0; ns < _res.nscount; ns++) {
        !            90: #ifdef DEBUG
        !            91:                if (_res.options & RES_DEBUG)
        !            92:                        printf("Querying server (# %d) address = %s\n", ns+1,
        !            93:                              inet_ntoa(_res.nsaddr_list[ns].sin_addr));
        !            94: #endif DEBUG
        !            95:        usevc:
        !            96:                if (v_circuit) {
        !            97:                        int truncated = 0;
        !            98: 
        !            99:                        /*
        !           100:                         * Use virtual circuit;
        !           101:                         * at most one attempt per server.
        !           102:                         */
        !           103:                        try = _res.retry;
        !           104:                        if (s < 0) {
        !           105:                                s = socket(AF_INET, SOCK_STREAM, 0);
        !           106:                                if (s < 0) {
        !           107:                                        terrno = errno;
        !           108: #ifdef DEBUG
        !           109:                                        if (_res.options & RES_DEBUG)
        !           110:                                            perror("socket (vc) failed");
        !           111: #endif DEBUG
        !           112:                                        continue;
        !           113:                                }
        !           114:                                if (connect(s, &(_res.nsaddr_list[ns]),
        !           115:                                   sizeof(struct sockaddr)) < 0) {
        !           116:                                        terrno = errno;
        !           117: #ifdef DEBUG
        !           118:                                        if (_res.options & RES_DEBUG)
        !           119:                                            perror("connect failed");
        !           120: #endif DEBUG
        !           121:                                        (void) close(s);
        !           122:                                        s = -1;
        !           123:                                        continue;
        !           124:                                }
        !           125:                        }
        !           126:                        /*
        !           127:                         * Send length & message
        !           128:                         */
        !           129:                        len = htons((u_short)buflen);
        !           130:                        iov[0].iov_base = (caddr_t)&len;
        !           131:                        iov[0].iov_len = sizeof(len);
        !           132:                        iov[1].iov_base = buf;
        !           133:                        iov[1].iov_len = buflen;
        !           134:                        if (writev(s, iov, 2) != sizeof(len) + buflen) {
        !           135:                                terrno = errno;
        !           136: #ifdef DEBUG
        !           137:                                if (_res.options & RES_DEBUG)
        !           138:                                        perror("write failed");
        !           139: #endif DEBUG
        !           140:                                (void) close(s);
        !           141:                                s = -1;
        !           142:                                continue;
        !           143:                        }
        !           144:                        /*
        !           145:                         * Receive length & response
        !           146:                         */
        !           147:                        cp = answer;
        !           148:                        len = sizeof(short);
        !           149:                        while (len != 0 &&
        !           150:                            (n = read(s, (char *)cp, (int)len)) > 0) {
        !           151:                                cp += n;
        !           152:                                len -= n;
        !           153:                        }
        !           154:                        if (n <= 0) {
        !           155:                                terrno = errno;
        !           156: #ifdef DEBUG
        !           157:                                if (_res.options & RES_DEBUG)
        !           158:                                        perror("read failed");
        !           159: #endif DEBUG
        !           160:                                (void) close(s);
        !           161:                                s = -1;
        !           162:                                /*
        !           163:                                 * A long running process might get its TCP
        !           164:                                 * connection reset if the remote server was
        !           165:                                 * restarted.  Requery the server instead of
        !           166:                                 * trying a new one.  When there is only one
        !           167:                                 * server, this means that a query might work
        !           168:                                 * instead of failing.  We only allow one reset
        !           169:                                 * per query to prevent looping.
        !           170:                                 */
        !           171:                                if (terrno == ECONNRESET && !connreset) {
        !           172:                                        connreset = 1;
        !           173:                                        ns--;
        !           174:                                }
        !           175:                                continue;
        !           176:                        }
        !           177:                        cp = answer;
        !           178:                        if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
        !           179: #ifdef DEBUG
        !           180:                                if (_res.options & RES_DEBUG)
        !           181:                                        fprintf(stderr, "response truncated\n");
        !           182: #endif DEBUG
        !           183:                                len = anslen;
        !           184:                                truncated = 1;
        !           185:                        } else
        !           186:                                len = resplen;
        !           187:                        while (len != 0 &&
        !           188:                           (n = read(s, (char *)cp, (int)len)) > 0) {
        !           189:                                cp += n;
        !           190:                                len -= n;
        !           191:                        }
        !           192:                        if (n <= 0) {
        !           193:                                terrno = errno;
        !           194: #ifdef DEBUG
        !           195:                                if (_res.options & RES_DEBUG)
        !           196:                                        perror("read failed");
        !           197: #endif DEBUG
        !           198:                                (void) close(s);
        !           199:                                s = -1;
        !           200:                                continue;
        !           201:                        }
        !           202:                        if (truncated) {
        !           203:                                /*
        !           204:                                 * Flush rest of answer
        !           205:                                 * so connection stays in synch.
        !           206:                                 */
        !           207:                                anhp->tc = 1;
        !           208:                                len = resplen - anslen;
        !           209:                                while (len != 0) {
        !           210:                                        n = (len > sizeof(junk) ?
        !           211:                                            sizeof(junk) : len);
        !           212:                                        if ((n = read(s, junk, n)) > 0)
        !           213:                                                len -= n;
        !           214:                                        else
        !           215:                                                break;
        !           216:                                }
        !           217:                        }
        !           218:                } else {
        !           219:                        /*
        !           220:                         * Use datagrams.
        !           221:                         */
        !           222:                        if (s < 0) {
        !           223:                                s = socket(AF_INET, SOCK_DGRAM, 0);
        !           224:                                if (s < 0) {
        !           225:                                        terrno = errno;
        !           226: #ifdef DEBUG
        !           227:                                        if (_res.options & RES_DEBUG)
        !           228:                                            perror("socket (dg) failed");
        !           229: #endif DEBUG
        !           230:                                        continue;
        !           231:                                }
        !           232:                        }
        !           233: #if    BSD >= 43
        !           234:                        /*
        !           235:                         * I'm tired of answering this question, so:
        !           236:                         * On a 4.3BSD+ machine (client and server,
        !           237:                         * actually), sending to a nameserver datagram
        !           238:                         * port with no nameserver will cause an
        !           239:                         * ICMP port unreachable message to be returned.
        !           240:                         * If our datagram socket is "connected" to the
        !           241:                         * server, we get an ECONNREFUSED error on the next
        !           242:                         * socket operation, and select returns if the
        !           243:                         * error message is received.  We can thus detect
        !           244:                         * the absence of a nameserver without timing out.
        !           245:                         * If we have sent queries to at least two servers,
        !           246:                         * however, we don't want to remain connected,
        !           247:                         * as we wish to receive answers from the first
        !           248:                         * server to respond.
        !           249:                         */
        !           250:                        if (_res.nscount == 1 || (try == 0 && ns == 0)) {
        !           251:                                /*
        !           252:                                 * Don't use connect if we might
        !           253:                                 * still receive a response
        !           254:                                 * from another server.
        !           255:                                 */
        !           256:                                if (connected == 0) {
        !           257:                                        if (connect(s, &_res.nsaddr_list[ns],
        !           258:                                            sizeof(struct sockaddr)) < 0) {
        !           259: #ifdef DEBUG
        !           260:                                                if (_res.options & RES_DEBUG)
        !           261:                                                        perror("connect");
        !           262: #endif DEBUG
        !           263:                                                continue;
        !           264:                                        }
        !           265:                                        connected = 1;
        !           266:                                }
        !           267:                                if (send(s, buf, buflen, 0) != buflen) {
        !           268: #ifdef DEBUG
        !           269:                                        if (_res.options & RES_DEBUG)
        !           270:                                                perror("send");
        !           271: #endif DEBUG
        !           272:                                        continue;
        !           273:                                }
        !           274:                        } else {
        !           275:                                /*
        !           276:                                 * Disconnect if we want to listen
        !           277:                                 * for responses from more than one server.
        !           278:                                 */
        !           279:                                if (connected) {
        !           280:                                        (void) connect(s, &no_addr,
        !           281:                                            sizeof(no_addr));
        !           282:                                        connected = 0;
        !           283:                                }
        !           284: #endif BSD
        !           285:                                if (sendto(s, buf, buflen, 0,
        !           286:                                    &_res.nsaddr_list[ns],
        !           287:                                    sizeof(struct sockaddr)) != buflen) {
        !           288: #ifdef DEBUG
        !           289:                                        if (_res.options & RES_DEBUG)
        !           290:                                                perror("sendto");
        !           291: #endif DEBUG
        !           292:                                        continue;
        !           293:                                }
        !           294: #if    BSD >= 43
        !           295:                        }
        !           296: #endif
        !           297: 
        !           298:                        /*
        !           299:                         * Wait for reply
        !           300:                         */
        !           301:                        timeout.tv_sec = (_res.retrans << try);
        !           302:                        if (try > 0)
        !           303:                                timeout.tv_sec /= _res.nscount;
        !           304:                        if (timeout.tv_sec <= 0)
        !           305:                                timeout.tv_sec = 1;
        !           306:                        timeout.tv_usec = 0;
        !           307: wait:
        !           308:                        FD_ZERO(&dsmask);
        !           309:                        FD_SET(s, &dsmask);
        !           310:                        n = select(s+1, &dsmask, (fd_set *)NULL,
        !           311:                                (fd_set *)NULL, &timeout);
        !           312:                        if (n < 0) {
        !           313: #ifdef DEBUG
        !           314:                                if (_res.options & RES_DEBUG)
        !           315:                                        perror("select");
        !           316: #endif DEBUG
        !           317:                                continue;
        !           318:                        }
        !           319:                        if (n == 0) {
        !           320:                                /*
        !           321:                                 * timeout
        !           322:                                 */
        !           323: #ifdef DEBUG
        !           324:                                if (_res.options & RES_DEBUG)
        !           325:                                        printf("timeout\n");
        !           326: #endif DEBUG
        !           327: #if BSD >= 43
        !           328:                                gotsomewhere = 1;
        !           329: #endif
        !           330:                                continue;
        !           331:                        }
        !           332:                        if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
        !           333: #ifdef DEBUG
        !           334:                                if (_res.options & RES_DEBUG)
        !           335:                                        perror("recvfrom");
        !           336: #endif DEBUG
        !           337:                                continue;
        !           338:                        }
        !           339:                        gotsomewhere = 1;
        !           340:                        if (id != anhp->id) {
        !           341:                                /*
        !           342:                                 * response from old query, ignore it
        !           343:                                 */
        !           344: #ifdef DEBUG
        !           345:                                if (_res.options & RES_DEBUG) {
        !           346:                                        printf("old answer:\n");
        !           347:                                        p_query(answer);
        !           348:                                }
        !           349: #endif DEBUG
        !           350:                                goto wait;
        !           351:                        }
        !           352:                        if (!(_res.options & RES_IGNTC) && anhp->tc) {
        !           353:                                /*
        !           354:                                 * get rest of answer;
        !           355:                                 * use TCP with same server.
        !           356:                                 */
        !           357: #ifdef DEBUG
        !           358:                                if (_res.options & RES_DEBUG)
        !           359:                                        printf("truncated answer\n");
        !           360: #endif DEBUG
        !           361:                                (void) close(s);
        !           362:                                s = -1;
        !           363:                                v_circuit = 1;
        !           364:                                goto usevc;
        !           365:                        }
        !           366:                }
        !           367: #ifdef DEBUG
        !           368:                if (_res.options & RES_DEBUG) {
        !           369:                        printf("got answer:\n");
        !           370:                        p_query(answer);
        !           371:                }
        !           372: #endif DEBUG
        !           373:                /*
        !           374:                 * If using virtual circuits, we assume that the first server
        !           375:                 * is preferred * over the rest (i.e. it is on the local
        !           376:                 * machine) and only keep that one open.
        !           377:                 * If we have temporarily opened a virtual circuit,
        !           378:                 * or if we haven't been asked to keep a socket open,
        !           379:                 * close the socket.
        !           380:                 */
        !           381:                if ((v_circuit &&
        !           382:                    ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
        !           383:                    (_res.options & RES_STAYOPEN) == 0) {
        !           384:                        (void) close(s);
        !           385:                        s = -1;
        !           386:                }
        !           387:                return (resplen);
        !           388:           }
        !           389:        }
        !           390:        if (s >= 0) {
        !           391:                (void) close(s);
        !           392:                s = -1;
        !           393:        }
        !           394:        if (v_circuit == 0)
        !           395:                if (gotsomewhere == 0)
        !           396:                        errno = ECONNREFUSED;   /* no nameservers found */
        !           397:                else
        !           398:                        errno = ETIMEDOUT;      /* no answer obtained */
        !           399:        else
        !           400:                errno = terrno;
        !           401:        return (-1);
        !           402: }
        !           403: 
        !           404: /*
        !           405:  * This routine is for closing the socket if a virtual circuit is used and
        !           406:  * the program wants to close it.  This provides support for endhostent()
        !           407:  * which expects to close the socket.
        !           408:  *
        !           409:  * This routine is not expected to be user visible.
        !           410:  */
        !           411: _res_close()
        !           412: {
        !           413:        if (s != -1) {
        !           414:                (void) close(s);
        !           415:                s = -1;
        !           416:        }
        !           417: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.