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: }