|
|
1.1 ! root 1: ! 2: /* ! 3: * Copyright (c) 1985 Regents of the University of California. ! 4: * All rights reserved. The Berkeley software License Agreement ! 5: * specifies the terms and conditions for redistribution. ! 6: */ ! 7: ! 8: #if defined(LIBC_SCCS) && !defined(lint) ! 9: static char sccsid[] = "@(#)res_send.c 6.14 (Berkeley) 7/2/86"; ! 10: #endif LIBC_SCCS and not lint ! 11: ! 12: /* ! 13: * Send query to name server and wait for reply. ! 14: */ ! 15: ! 16: #include <sys/param.h> ! 17: #include <sys/time.h> ! 18: #include <sys/socket.h> ! 19: #include <sys/uio.h> ! 20: #include <netinet/in.h> ! 21: #include <stdio.h> ! 22: #include <errno.h> ! 23: #include <arpa/nameser.h> ! 24: #include <resolv.h> ! 25: ! 26: extern int errno; ! 27: ! 28: static int s = -1; /* socket used for communications */ ! 29: ! 30: #define KEEPOPEN (RES_USEVC|RES_STAYOPEN) ! 31: ! 32: res_send(buf, buflen, answer, anslen) ! 33: char *buf; ! 34: int buflen; ! 35: char *answer; ! 36: int anslen; ! 37: { ! 38: register int n; ! 39: int retry, v_circuit, resplen, ns; ! 40: int gotsomewhere = 0; ! 41: u_short id, len; ! 42: char *cp; ! 43: fd_set dsmask; ! 44: struct timeval timeout; ! 45: HEADER *hp = (HEADER *) buf; ! 46: HEADER *anhp = (HEADER *) answer; ! 47: struct iovec iov[2]; ! 48: int terrno = ETIMEDOUT; ! 49: ! 50: #ifdef DEBUG ! 51: if (_res.options & RES_DEBUG) { ! 52: printf("res_send()\n"); ! 53: p_query(buf); ! 54: } ! 55: #endif DEBUG ! 56: if (!(_res.options & RES_INIT)) ! 57: if (res_init() == -1) { ! 58: return(-1); ! 59: } ! 60: v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; ! 61: id = hp->id; ! 62: /* ! 63: * Send request, RETRY times, or until successful ! 64: */ ! 65: for (retry = _res.retry; retry > 0; retry--) { ! 66: for (ns = 0; ns < _res.nscount; ns++) { ! 67: #ifdef DEBUG ! 68: if (_res.options & RES_DEBUG) ! 69: printf("Querying server (# %d) address = %s\n", ns+1, ! 70: inet_ntoa(_res.nsaddr_list[ns].sin_addr.s_addr)); ! 71: #endif DEBUG ! 72: if (v_circuit) { ! 73: /* ! 74: * Use virtual circuit. ! 75: */ ! 76: if (s < 0) { ! 77: s = socket(AF_INET, SOCK_STREAM, 0); ! 78: if (s < 0) { ! 79: terrno = errno; ! 80: #ifdef DEBUG ! 81: if (_res.options & RES_DEBUG) ! 82: perror("socket failed"); ! 83: #endif DEBUG ! 84: continue; ! 85: } ! 86: if (connect(s, &(_res.nsaddr_list[ns]), ! 87: sizeof(struct sockaddr)) < 0) { ! 88: terrno = errno; ! 89: #ifdef DEBUG ! 90: if (_res.options & RES_DEBUG) ! 91: perror("connect failed"); ! 92: #endif DEBUG ! 93: (void) close(s); ! 94: s = -1; ! 95: continue; ! 96: } ! 97: } ! 98: /* ! 99: * Send length & message ! 100: */ ! 101: len = htons((u_short)buflen); ! 102: iov[0].iov_base = (caddr_t)&len; ! 103: iov[0].iov_len = sizeof(len); ! 104: iov[1].iov_base = buf; ! 105: iov[1].iov_len = buflen; ! 106: if (writev(s, iov, 2) != sizeof(len) + buflen) { ! 107: terrno = errno; ! 108: #ifdef DEBUG ! 109: if (_res.options & RES_DEBUG) ! 110: perror("write failed"); ! 111: #endif DEBUG ! 112: (void) close(s); ! 113: s = -1; ! 114: continue; ! 115: } ! 116: /* ! 117: * Receive length & response ! 118: */ ! 119: cp = answer; ! 120: len = sizeof(short); ! 121: while (len != 0 && ! 122: (n = read(s, (char *)cp, (int)len)) > 0) { ! 123: cp += n; ! 124: len -= n; ! 125: } ! 126: if (n <= 0) { ! 127: terrno = errno; ! 128: #ifdef DEBUG ! 129: if (_res.options & RES_DEBUG) ! 130: perror("read failed"); ! 131: #endif DEBUG ! 132: (void) close(s); ! 133: s = -1; ! 134: continue; ! 135: } ! 136: cp = answer; ! 137: resplen = len = ntohs(*(u_short *)cp); ! 138: while (len != 0 && ! 139: (n = read(s, (char *)cp, (int)len)) > 0) { ! 140: cp += n; ! 141: len -= n; ! 142: } ! 143: if (n <= 0) { ! 144: terrno = errno; ! 145: #ifdef DEBUG ! 146: if (_res.options & RES_DEBUG) ! 147: perror("read failed"); ! 148: #endif DEBUG ! 149: (void) close(s); ! 150: s = -1; ! 151: continue; ! 152: } ! 153: } else { ! 154: /* ! 155: * Use datagrams. ! 156: */ ! 157: if (s < 0) ! 158: s = socket(AF_INET, SOCK_DGRAM, 0); ! 159: #if BSD >= 43 ! 160: if (connect(s, &_res.nsaddr_list[ns], ! 161: sizeof(struct sockaddr)) < 0 || ! 162: send(s, buf, buflen, 0) != buflen) { ! 163: #ifdef DEBUG ! 164: if (_res.options & RES_DEBUG) ! 165: perror("connect"); ! 166: #endif DEBUG ! 167: continue; ! 168: } ! 169: #else BSD ! 170: if (sendto(s, buf, buflen, 0, &_res.nsaddr_list[ns], ! 171: sizeof(struct sockaddr)) != buflen) { ! 172: #ifdef DEBUG ! 173: if (_res.options & RES_DEBUG) ! 174: perror("sendto"); ! 175: #endif DEBUG ! 176: continue; ! 177: } ! 178: #endif BSD ! 179: /* ! 180: * Wait for reply ! 181: */ ! 182: timeout.tv_sec = (_res.retrans << (_res.retry - retry)) ! 183: / _res.nscount; ! 184: if (timeout.tv_sec <= 0) ! 185: timeout.tv_sec = 1; ! 186: timeout.tv_usec = 0; ! 187: wait: ! 188: FD_ZERO(&dsmask); ! 189: FD_SET(s, &dsmask); ! 190: n = select(s+1, &dsmask, (fd_set *)NULL, ! 191: (fd_set *)NULL, &timeout); ! 192: if (n < 0) { ! 193: #ifdef DEBUG ! 194: if (_res.options & RES_DEBUG) ! 195: perror("select"); ! 196: #endif DEBUG ! 197: continue; ! 198: } ! 199: if (n == 0) { ! 200: /* ! 201: * timeout ! 202: */ ! 203: #ifdef DEBUG ! 204: if (_res.options & RES_DEBUG) ! 205: printf("timeout\n"); ! 206: #endif DEBUG ! 207: gotsomewhere = 1; ! 208: continue; ! 209: } ! 210: if ((resplen = recv(s, answer, anslen, 0)) <= 0) { ! 211: #ifdef DEBUG ! 212: if (_res.options & RES_DEBUG) ! 213: perror("recvfrom"); ! 214: #endif DEBUG ! 215: continue; ! 216: } ! 217: gotsomewhere = 1; ! 218: if (id != anhp->id) { ! 219: /* ! 220: * response from old query, ignore it ! 221: */ ! 222: #ifdef DEBUG ! 223: if (_res.options & RES_DEBUG) { ! 224: printf("old answer:\n"); ! 225: p_query(answer); ! 226: } ! 227: #endif DEBUG ! 228: goto wait; ! 229: } ! 230: if (!(_res.options & RES_IGNTC) && anhp->tc) { ! 231: /* ! 232: * get rest of answer ! 233: */ ! 234: #ifdef DEBUG ! 235: if (_res.options & RES_DEBUG) ! 236: printf("truncated answer\n"); ! 237: #endif DEBUG ! 238: (void) close(s); ! 239: s = -1; ! 240: /* ! 241: * retry decremented on continue ! 242: * to desired starting value ! 243: */ ! 244: retry = _res.retry + 1; ! 245: v_circuit = 1; ! 246: continue; ! 247: } ! 248: } ! 249: #ifdef DEBUG ! 250: if (_res.options & RES_DEBUG) { ! 251: printf("got answer:\n"); ! 252: p_query(answer); ! 253: } ! 254: #endif DEBUG ! 255: /* ! 256: * We are going to assume that the first server is preferred ! 257: * over the rest (i.e. it is on the local machine) and only ! 258: * keep that one open. ! 259: */ ! 260: if ((_res.options & KEEPOPEN) == KEEPOPEN && ns == 0) { ! 261: return (resplen); ! 262: } else { ! 263: (void) close(s); ! 264: s = -1; ! 265: return (resplen); ! 266: } ! 267: } ! 268: } ! 269: if (s >= 0) { ! 270: (void) close(s); ! 271: s = -1; ! 272: } ! 273: if (v_circuit == 0) ! 274: if (gotsomewhere == 0) ! 275: errno = ECONNREFUSED; ! 276: else ! 277: errno = ETIMEDOUT; ! 278: else ! 279: errno = terrno; ! 280: return (-1); ! 281: } ! 282: ! 283: /* ! 284: * This routine is for closing the socket if a virtual circuit is used and ! 285: * the program wants to close it. This provides support for endhostent() ! 286: * which expects to close the socket. ! 287: * ! 288: * This routine is not expected to be user visible. ! 289: */ ! 290: _res_close() ! 291: { ! 292: if (s != -1) { ! 293: (void) close(s); ! 294: s = -1; ! 295: } ! 296: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.