Annotation of 43BSDReno/lib/libc/net/res_send.c, revision 1.1.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.