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