# 2.11BSD#431 - /usr/src/lib/libc/net/res_send.c

##### Functions

    _res_close        X
    res_send          X

##### Macros

    FD_CLR            X
    FD_ISSET          X
    FD_SET            X
    FD_SETSIZE        X
    FD_ZERO           X
    KEEPOPEN          X
    NFDBITS           X

       1: /*
       2:  * Copyright (c) 1985 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 this notice is preserved and that due credit is given
       7:  * to the University of California at Berkeley. The name of the University
       8:  * may not be used to endorse or promote products derived from this
       9:  * software without specific prior written permission. This software
      10:  * is provided ``as is'' without express or implied warranty.
      11:  */
      12:
      13: #if defined(LIBC_SCCS) && !defined(lint)
      14: static char sccsid[] = "@(#)res_send.c	6.19.1 (Berkeley) 6/27/94";
      15: #endif /* LIBC_SCCS and not lint */
      16:
      17: /*
      18:  * Send query to name server and wait for reply.
      19:  */
      20:
      21: #include <sys/param.h>
      22: #include <sys/time.h>
      23: #include <sys/socket.h>
      24: #include <sys/uio.h>
      25: #include <netinet/in.h>
      26: #include <stdio.h>
      27: #include <errno.h>
      28: #include <arpa/nameser.h>
      29: #include <resolv.h>
      30:
      31: extern int errno;
      32:
      33: static int s = -1;  /* socket used for communications */
      34: static struct sockaddr no_addr;
      35:
      36:
      37: #ifndef FD_SET
      38: #define NFDBITS     32
      39: #define FD_SETSIZE  32
      40: #define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
      41: #define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
      42: #define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
      43: #define FD_ZERO(p)  bzero((char *)(p), sizeof(*(p)))
      44: #endif
      45:
      46: #define KEEPOPEN (RES_USEVC|RES_STAYOPEN)
      47:
      48: res_send(buf, buflen, answer, anslen)
      49:     char *buf;
      50:     int buflen;
      51:     char *answer;
      52:     int anslen;
      53: {
      54:     register int n;
      55:     int retry, v_circuit, resplen, ns;
      56:     int gotsomewhere = 0, connected = 0;
      57:     u_short id, len;
      58:     char *cp;
      59:     fd_set dsmask;
      60:     struct timeval timeout;
      61:     HEADER *hp = (HEADER *) buf;
      62:     HEADER *anhp = (HEADER *) answer;
      63:     struct iovec iov[2];
      64:     int terrno = ETIMEDOUT;
      65:     char junk[16];
      66:
      67: #ifdef DEBUG
      68:     if (_res.options & RES_DEBUG) {
      69:         printf("res_send()\n");
      70:         p_query(buf);
      71:     }
      72: #endif DEBUG
      73:     if (!(_res.options & RES_INIT))
      74:         if (res_init() == -1) {
      75:             return(-1);
      76:         }
      77:     v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
      78:     id = hp->id;
      79:     /*
      80: 	 * Send request, RETRY times, or until successful
      81: 	 */
      82:     for (retry = _res.retry; retry > 0; retry--) {
      83:        for (ns = 0; ns < _res.nscount; ns++) {
      84: #ifdef DEBUG
      85:         if (_res.options & RES_DEBUG)
      86:             printf("Querying server (# %d) address = %s\n", ns+1,
      87:                   inet_ntoa(_res.nsaddr_list[ns].sin_addr));
      88: #endif DEBUG
      89:         if (v_circuit) {
      90:             int truncated = 0;
      91:
      92:             /*
      93: 			 * Use virtual circuit.
      94: 			 */
      95:             if (s < 0) {
      96:                 s = socket(AF_INET, SOCK_STREAM, 0);
      97:                 if (s < 0) {
      98:                     terrno = errno;
      99: #ifdef DEBUG
     100:                     if (_res.options & RES_DEBUG)
     101:                         perror("socket failed");
     102: #endif DEBUG
     103:                     continue;
     104:                 }
     105:                 if (connect(s, &(_res.nsaddr_list[ns]),
     106:                    sizeof(struct sockaddr)) < 0) {
     107:                     terrno = errno;
     108: #ifdef DEBUG
     109:                     if (_res.options & RES_DEBUG)
     110:                         perror("connect failed");
     111: #endif DEBUG
     112:                     (void) close(s);
     113:                     s = -1;
     114:                     continue;
     115:                 }
     116:             }
     117:             /*
     118: 			 * Send length & message
     119: 			 */
     120:             len = htons((u_short)buflen);
     121:             iov[0].iov_base = (caddr_t)&len;
     122:             iov[0].iov_len = sizeof(len);
     123:             iov[1].iov_base = buf;
     124:             iov[1].iov_len = buflen;
     125:             if (writev(s, iov, 2) != sizeof(len) + buflen) {
     126:                 terrno = errno;
     127: #ifdef DEBUG
     128:                 if (_res.options & RES_DEBUG)
     129:                     perror("write failed");
     130: #endif DEBUG
     131:                 (void) close(s);
     132:                 s = -1;
     133:                 continue;
     134:             }
     135:             /*
     136: 			 * Receive length & response
     137: 			 */
     138:             cp = answer;
     139:             len = sizeof(short);
     140:             while (len != 0 &&
     141:                 (n = read(s, (char *)cp, (int)len)) > 0) {
     142:                 cp += n;
     143:                 len -= n;
     144:             }
     145:             if (n <= 0) {
     146:                 terrno = errno;
     147: #ifdef DEBUG
     148:                 if (_res.options & RES_DEBUG)
     149:                     perror("read failed");
     150: #endif DEBUG
     151:                 (void) close(s);
     152:                 s = -1;
     153:                 continue;
     154:             }
     155:             cp = answer;
     156:             if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
     157: #ifdef DEBUG
     158:                 if (_res.options & RES_DEBUG)
     159:                     fprintf(stderr, "response truncated\n");
     160: #endif DEBUG
     161:                 len = anslen;
     162:                 truncated = 1;
     163:             } else
     164:                 len = resplen;
     165:             while (len != 0 &&
     166:                (n = read(s, (char *)cp, (int)len)) > 0) {
     167:                 cp += n;
     168:                 len -= n;
     169:             }
     170:             if (n <= 0) {
     171:                 terrno = errno;
     172: #ifdef DEBUG
     173:                 if (_res.options & RES_DEBUG)
     174:                     perror("read failed");
     175: #endif DEBUG
     176:                 (void) close(s);
     177:                 s = -1;
     178:                 continue;
     179:             }
     180:             if (truncated) {
     181:                 /*
     182: 				 * Flush rest of answer
     183: 				 * so connection stays in synch.
     184: 				 */
     185:                 anhp->tc = 1;
     186:                 len = resplen - anslen;
     187:                 while (len != 0) {
     188:                     n = (len > sizeof(junk) ?
     189:                         sizeof(junk) : len);
     190:                     if ((n = read(s, junk, n)) > 0)
     191:                         len -= n;
     192:                     else
     193:                         break;
     194:                 }
     195:             }
     196:         } else {
     197:             /*
     198: 			 * Use datagrams.
     199: 			 */
     200:             if (s < 0)
     201:                 s = socket(AF_INET, SOCK_DGRAM, 0);
     202: #if BSD >= 43
     203:             if (_res.nscount == 1 || retry == _res.retry) {
     204:                 /*
     205: 				 * Don't use connect if we might
     206: 				 * still receive a response
     207: 				 * from another server.
     208: 				 */
     209:                 if (connected == 0) {
     210:                     if (connect(s, &_res.nsaddr_list[ns],
     211:                         sizeof(struct sockaddr)) < 0) {
     212: #ifdef DEBUG
     213:                         if (_res.options & RES_DEBUG)
     214:                             perror("connect");
     215: #endif DEBUG
     216:                         continue;
     217:                     }
     218:                     connected = 1;
     219:                 }
     220:                 if (send(s, buf, buflen, 0) != buflen) {
     221: #ifdef DEBUG
     222:                     if (_res.options & RES_DEBUG)
     223:                         perror("send");
     224: #endif DEBUG
     225:                     continue;
     226:                 }
     227:             } else
     228: #endif BSD
     229:             if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns],
     230:                 sizeof(struct sockaddr)) != buflen) {
     231: #ifdef DEBUG
     232:                 if (_res.options & RES_DEBUG)
     233:                     perror("sendto");
     234: #endif DEBUG
     235:                 continue;
     236:             }
     237:
     238:             /*
     239: 			 * Wait for reply
     240: 			 */
     241:             timeout.tv_sec = (_res.retrans << (_res.retry - retry))
     242:                 / _res.nscount;
     243:             if (timeout.tv_sec <= 0)
     244:                 timeout.tv_sec = 1;
     245:             timeout.tv_usec = 0;
     246: wait:
     247:             FD_ZERO(&dsmask);
     248:             FD_SET(s, &dsmask);
     249:             n = select(s+1, &dsmask, (fd_set *)NULL,
     250:                 (fd_set *)NULL, &timeout);
     251:             if (n < 0) {
     252: #ifdef DEBUG
     253:                 if (_res.options & RES_DEBUG)
     254:                     perror("select");
     255: #endif DEBUG
     256:                 continue;
     257:             }
     258:             if (n == 0) {
     259:                 /*
     260: 				 * timeout
     261: 				 */
     262: #ifdef DEBUG
     263:                 if (_res.options & RES_DEBUG)
     264:                     printf("timeout\n");
     265: #endif DEBUG
     266:                 /*
     267: 				 * Disconnect if we want to listen
     268: 				 * for responses from more than one server.
     269: 				 */
     270:                 if (_res.nscount > 1 && connected) {
     271:                     (void) connect(s, &no_addr,
     272:                         sizeof(no_addr));
     273:                     connected = 0;
     274:                 }
     275:                 gotsomewhere = 1;
     276:                 continue;
     277:             }
     278:             if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
     279: #ifdef DEBUG
     280:                 if (_res.options & RES_DEBUG)
     281:                     perror("recvfrom");
     282: #endif DEBUG
     283:                 continue;
     284:             }
     285:             gotsomewhere = 1;
     286:             if (id != anhp->id) {
     287:                 /*
     288: 				 * response from old query, ignore it
     289: 				 */
     290: #ifdef DEBUG
     291:                 if (_res.options & RES_DEBUG) {
     292:                     printf("old answer:\n");
     293:                     p_query(answer);
     294:                 }
     295: #endif DEBUG
     296:                 goto wait;
     297:             }
     298:             if (!(_res.options & RES_IGNTC) && anhp->tc) {
     299:                 /*
     300: 				 * get rest of answer
     301: 				 */
     302: #ifdef DEBUG
     303:                 if (_res.options & RES_DEBUG)
     304:                     printf("truncated answer\n");
     305: #endif DEBUG
     306:                 (void) close(s);
     307:                 s = -1;
     308:                 /*
     309: 				 * retry decremented on continue
     310: 				 * to desired starting value
     311: 				 */
     312:                 retry = _res.retry + 1;
     313:                 v_circuit = 1;
     314:                 continue;
     315:             }
     316:         }
     317: #ifdef DEBUG
     318:         if (_res.options & RES_DEBUG) {
     319:             printf("got answer:\n");
     320:             p_query(answer);
     321:         }
     322: #endif DEBUG
     323:         /*
     324: 		 * We are going to assume that the first server is preferred
     325: 		 * over the rest (i.e. it is on the local machine) and only
     326: 		 * keep that one open.
     327: 		 */
     328:         if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) {
     329:             return (resplen);
     330:         } else {
     331:             (void) close(s);
     332:             s = -1;
     333:             return (resplen);
     334:         }
     335:        }
     336:     }
     337:     if (s >= 0) {
     338:         (void) close(s);
     339:         s = -1;
     340:     }
     341:     if (v_circuit == 0)
     342:         if (gotsomewhere == 0)
     343:             errno = ECONNREFUSED;
     344:         else
     345:             errno = ETIMEDOUT;
     346:     else
     347:         errno = terrno;
     348:     return (-1);
     349: }
     350:
     351: /*
     352:  * This routine is for closing the socket if a virtual circuit is used and
     353:  * the program wants to close it.  This provides support for endhostent()
     354:  * which expects to close the socket.
     355:  *
     356:  * This routine is not expected to be user visible.
     357:  */
     358: _res_close()
     359: {
     360:     if (s != -1) {
     361:         (void) close(s);
     362:         s = -1;
     363:     }
     364: }

#### Defined functions

_res_close defined in line 358; used 1 times

- in /usr/src/lib/libc/net/named/sethostent.c line 25

res_send defined in line 48; used 2 times

- in /usr/src/lib/libc/net/res_query.c line 74
- in /usr/src/usr.sbin/named/tools/nstest.c line 343

#### Defined variables

no_addr defined in line 34; used 2 times

- in line 271-272(2)

s defined in line 33; used 35 times

- in line 95-97(3), 105, 112-113(2), 125, 131-132(2), 141, 151-152(2), 166, 176-177(2), 190, 200-201(2), 210, 220, 229, 248-249(2), 271, 278, 306-307(2), 331-339(5), 360-362(3)

sccsid defined in line 14; never used

#### Defined macros

FD_CLR defined in line 41; never used
FD_ISSET defined in line 42; never used
FD_SET defined in line 40; used 2 times

- in line 37, 248

FD_SETSIZE defined in line 39; never used
FD_ZERO defined in line 43; used 1 times

- in line 247

KEEPOPEN defined in line 46; used 2 times

- in line 328(2)

NFDBITS defined in line 38; used 6 times

- in line 40-42(6)

Last modified: 1994-06-27 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1337 |