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

Defined variables

no_addr defined in line 34; used 2 times
s defined in line 33; used 35 times
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
FD_SETSIZE defined in line 39; never used
FD_ZERO defined in line 43; used 1 times
KEEPOPEN defined in line 46; used 2 times
  • in line 328(2)
NFDBITS defined in line 38; used 6 times
Last modified: 1994-06-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3864
Valid CSS Valid XHTML 1.0 Strict