|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1985, 1989 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: static char sccsid[] = "@(#)send.c 5.17 (Berkeley) 6/29/90"; ! 22: #endif /* not lint */ ! 23: ! 24: /* ! 25: ******************************************************************************* ! 26: * ! 27: * send.c -- ! 28: * ! 29: * Routine to send request packets to a name server. ! 30: * ! 31: * Based on "@(#)res_send.c 6.25 (Berkeley) 6/1/90". ! 32: * ! 33: ******************************************************************************* ! 34: */ ! 35: ! 36: ! 37: /* ! 38: * Send query to name server and wait for reply. ! 39: */ ! 40: ! 41: #include <sys/param.h> ! 42: #include <sys/time.h> ! 43: #include <sys/socket.h> ! 44: #include <sys/uio.h> ! 45: #include <netinet/in.h> ! 46: #include <stdio.h> ! 47: #include <errno.h> ! 48: #include <arpa/nameser.h> ! 49: #include <arpa/inet.h> ! 50: #include <resolv.h> ! 51: #include "res.h" ! 52: ! 53: extern int errno; ! 54: ! 55: static int s = -1; /* socket used for communications */ ! 56: ! 57: ! 58: #ifndef FD_SET ! 59: #define NFDBITS 32 ! 60: #define FD_SETSIZE 32 ! 61: #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) ! 62: #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) ! 63: #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) ! 64: #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) ! 65: #endif ! 66: ! 67: #define SR 1 /* SendRequest style */ ! 68: ! 69: #ifndef DEBUG ! 70: #define DEBUG ! 71: #endif ! 72: ! 73: unsigned short nsport = NAMESERVER_PORT; ! 74: ! 75: ! 76: ! 77: /* ! 78: ******************************************************************************* ! 79: * ! 80: * SendRequest -- ! 81: * ! 82: * Sends a request packet to a name server whose address ! 83: * is specified by the first argument and returns with ! 84: * the answer packet. ! 85: * ! 86: * Results: ! 87: * SUCCESS - the request was sent and an answer ! 88: * was received. ! 89: * TIME_OUT - the virtual circuit connection timed-out ! 90: * or a reply to a datagram wasn't received. ! 91: * ! 92: * ! 93: ******************************************************************************* ! 94: */ ! 95: ! 96: int ! 97: SendRequest(nsAddrPtr, buf, buflen, answer, anslen, trueLenPtr) ! 98: struct in_addr *nsAddrPtr; ! 99: char *buf; ! 100: int buflen; ! 101: char *answer; ! 102: u_int anslen; ! 103: int *trueLenPtr; ! 104: { ! 105: register int n; ! 106: int try, v_circuit, resplen, ns; ! 107: int gotsomewhere = 0, connected = 0; ! 108: int connreset = 0; ! 109: u_short id, len; ! 110: char *cp; ! 111: fd_set dsmask; ! 112: struct timeval timeout; ! 113: HEADER *hp = (HEADER *) buf; ! 114: HEADER *anhp = (HEADER *) answer; ! 115: struct iovec iov[2]; ! 116: int terrno = ETIMEDOUT; ! 117: char junk[512]; ! 118: ! 119: #if SR ! 120: struct sockaddr_in sin; ! 121: ! 122: if (_res.options & RES_DEBUG2) { ! 123: printf("------------\nSendRequest(), len %d\n", buflen); ! 124: Print_query(buf, buf+buflen, 1); ! 125: } ! 126: sin.sin_family = AF_INET; ! 127: sin.sin_port = htons(nsport); ! 128: sin.sin_addr = *nsAddrPtr; ! 129: #else ! 130: #ifdef DEBUG ! 131: if (_res.options & RES_DEBUG) { ! 132: printf("res_send()\n"); ! 133: p_query(buf); ! 134: } ! 135: #endif DEBUG ! 136: if (!(_res.options & RES_INIT)) ! 137: if (res_init() == -1) { ! 138: return(-1); ! 139: } ! 140: #endif /* SR */ ! 141: v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; ! 142: id = hp->id; ! 143: /* ! 144: * Send request, RETRY times, or until successful ! 145: */ ! 146: for (try = 0; try < _res.retry; try++) { ! 147: #if !SR ! 148: for (ns = 0; ns < _res.nscount; ns++) { ! 149: #ifdef DEBUG ! 150: if (_res.options & RES_DEBUG) ! 151: printf("Querying server (# %d) address = %s\n", ns+1, ! 152: inet_ntoa(_res.nsaddr_list[ns].sin_addr)); ! 153: #endif DEBUG ! 154: #endif /* !SR */ ! 155: usevc: ! 156: if (v_circuit) { ! 157: int truncated = 0; ! 158: ! 159: /* ! 160: * Use virtual circuit; ! 161: * at most one attempt per server. ! 162: */ ! 163: try = _res.retry; ! 164: if (s < 0) { ! 165: s = socket(AF_INET, SOCK_STREAM, 0); ! 166: if (s < 0) { ! 167: terrno = errno; ! 168: #ifdef DEBUG ! 169: if (_res.options & RES_DEBUG) ! 170: perror("socket (vc) failed"); ! 171: #endif DEBUG ! 172: continue; ! 173: } ! 174: #if SR ! 175: if (connect(s, &sin, ! 176: #else ! 177: if (connect(s, &(_res.nsaddr_list[ns]), ! 178: #endif ! 179: sizeof(struct sockaddr)) < 0) { ! 180: terrno = errno; ! 181: #ifdef DEBUG ! 182: if (_res.options & RES_DEBUG) ! 183: perror("connect failed"); ! 184: #endif DEBUG ! 185: (void) close(s); ! 186: s = -1; ! 187: continue; ! 188: } ! 189: } ! 190: /* ! 191: * Send length & message ! 192: */ ! 193: len = htons((u_short)buflen); ! 194: iov[0].iov_base = (caddr_t)&len; ! 195: iov[0].iov_len = sizeof(len); ! 196: iov[1].iov_base = buf; ! 197: iov[1].iov_len = buflen; ! 198: if (writev(s, iov, 2) != sizeof(len) + buflen) { ! 199: terrno = errno; ! 200: #ifdef DEBUG ! 201: if (_res.options & RES_DEBUG) ! 202: perror("write failed"); ! 203: #endif DEBUG ! 204: (void) close(s); ! 205: s = -1; ! 206: continue; ! 207: } ! 208: /* ! 209: * Receive length & response ! 210: */ ! 211: cp = answer; ! 212: len = sizeof(short); ! 213: while (len != 0 && ! 214: (n = read(s, (char *)cp, (int)len)) > 0) { ! 215: cp += n; ! 216: len -= n; ! 217: } ! 218: if (n <= 0) { ! 219: terrno = errno; ! 220: #ifdef DEBUG ! 221: if (_res.options & RES_DEBUG) ! 222: perror("read failed"); ! 223: #endif DEBUG ! 224: (void) close(s); ! 225: s = -1; ! 226: /* ! 227: * A long running process might get its TCP ! 228: * connection reset if the remote server was ! 229: * restarted. Requery the server instead of ! 230: * trying a new one. When there is only one ! 231: * server, this means that a query might work ! 232: * instead of failing. We only allow one reset ! 233: * per query to prevent looping. ! 234: */ ! 235: if (terrno == ECONNRESET && !connreset) { ! 236: connreset = 1; ! 237: ns--; ! 238: } ! 239: continue; ! 240: } ! 241: cp = answer; ! 242: if ((resplen = ntohs(*(u_short *)cp)) > anslen) { ! 243: #ifdef DEBUG ! 244: if (_res.options & RES_DEBUG) ! 245: fprintf(stderr, "response truncated\n"); ! 246: #endif DEBUG ! 247: len = anslen; ! 248: truncated = 1; ! 249: } else ! 250: len = resplen; ! 251: while (len != 0 && ! 252: (n = read(s, (char *)cp, (int)len)) > 0) { ! 253: cp += n; ! 254: len -= n; ! 255: } ! 256: if (n <= 0) { ! 257: terrno = errno; ! 258: #ifdef DEBUG ! 259: if (_res.options & RES_DEBUG) ! 260: perror("read failed"); ! 261: #endif DEBUG ! 262: (void) close(s); ! 263: s = -1; ! 264: continue; ! 265: } ! 266: if (truncated) { ! 267: /* ! 268: * Flush rest of answer ! 269: * so connection stays in synch. ! 270: */ ! 271: anhp->tc = 1; ! 272: len = resplen - anslen; ! 273: while (len != 0) { ! 274: n = (len > sizeof(junk) ? ! 275: sizeof(junk) : len); ! 276: if ((n = read(s, junk, n)) > 0) ! 277: len -= n; ! 278: else ! 279: break; ! 280: } ! 281: } ! 282: } else { ! 283: /* ! 284: * Use datagrams. ! 285: */ ! 286: if (s < 0) { ! 287: s = socket(AF_INET, SOCK_DGRAM, 0); ! 288: if (s < 0) { ! 289: terrno = errno; ! 290: #ifdef DEBUG ! 291: if (_res.options & RES_DEBUG) ! 292: perror("socket (dg) failed"); ! 293: #endif DEBUG ! 294: continue; ! 295: } ! 296: } ! 297: #if SR ! 298: /* ! 299: * Special case the send code below ! 300: * since we have just 1 server. ! 301: */ ! 302: #if BSD >= 43 ! 303: if (connected == 0) { ! 304: if (connect(s, &sin, ! 305: sizeof(struct sockaddr)) < 0) { ! 306: if (_res.options & RES_DEBUG) ! 307: perror("connect"); ! 308: continue; ! 309: } ! 310: connected = 1; ! 311: } ! 312: if (send(s, buf, buflen, 0) != buflen) { ! 313: if (_res.options & RES_DEBUG) ! 314: perror("send"); ! 315: continue; ! 316: } ! 317: #else /* BSD */ ! 318: if (sendto(s, buf, buflen, 0, &sin, ! 319: sizeof(struct sockaddr)) != buflen) { ! 320: if (_res.options & RES_DEBUG) ! 321: perror("sendto"); ! 322: continue; ! 323: } ! 324: #endif ! 325: #else /* SR */ ! 326: #if BSD >= 43 ! 327: /* ! 328: * I'm tired of answering this question, so: ! 329: * On a 4.3BSD+ machine (client and server, ! 330: * actually), sending to a nameserver datagram ! 331: * port with no nameserver will cause an ! 332: * ICMP port unreachable message to be returned. ! 333: * If our datagram socket is "connected" to the ! 334: * server, we get an ECONNREFUSED error on the next ! 335: * socket operation, and select returns if the ! 336: * error message is received. We can thus detect ! 337: * the absence of a nameserver without timing out. ! 338: * If we have sent queries to at least two servers, ! 339: * however, we don't want to remain connected, ! 340: * as we wish to receive answers from the first ! 341: * server to respond. ! 342: */ ! 343: if (_res.nscount == 1 || (try == 0 && ns == 0)) { ! 344: /* ! 345: * Don't use connect if we might ! 346: * still receive a response ! 347: * from another server. ! 348: */ ! 349: if (connected == 0) { ! 350: if (connect(s, &_res.nsaddr_list[ns], ! 351: sizeof(struct sockaddr)) < 0) { ! 352: #ifdef DEBUG ! 353: if (_res.options & RES_DEBUG) ! 354: perror("connect"); ! 355: #endif DEBUG ! 356: continue; ! 357: } ! 358: connected = 1; ! 359: } ! 360: if (send(s, buf, buflen, 0) != buflen) { ! 361: #ifdef DEBUG ! 362: if (_res.options & RES_DEBUG) ! 363: perror("send"); ! 364: #endif DEBUG ! 365: continue; ! 366: } ! 367: } else { ! 368: /* ! 369: * Disconnect if we want to listen ! 370: * for responses from more than one server. ! 371: */ ! 372: if (connected) { ! 373: (void) connect(s, &no_addr, ! 374: sizeof(no_addr)); ! 375: connected = 0; ! 376: } ! 377: #endif BSD ! 378: if (sendto(s, buf, buflen, 0, ! 379: &_res.nsaddr_list[ns], ! 380: sizeof(struct sockaddr)) != buflen) { ! 381: #ifdef DEBUG ! 382: if (_res.options & RES_DEBUG) ! 383: perror("sendto"); ! 384: #endif DEBUG ! 385: continue; ! 386: } ! 387: #if BSD >= 43 ! 388: } ! 389: #endif ! 390: #endif /* SR */ ! 391: ! 392: /* ! 393: * Wait for reply ! 394: */ ! 395: timeout.tv_sec = (_res.retrans << try); ! 396: #if !SR ! 397: if (try > 0) ! 398: timeout.tv_sec /= _res.nscount; ! 399: #endif /* SR */ ! 400: if (timeout.tv_sec <= 0) ! 401: timeout.tv_sec = 1; ! 402: timeout.tv_usec = 0; ! 403: wait: ! 404: FD_ZERO(&dsmask); ! 405: FD_SET(s, &dsmask); ! 406: n = select(s+1, &dsmask, (fd_set *)NULL, ! 407: (fd_set *)NULL, &timeout); ! 408: if (n < 0) { ! 409: #ifdef DEBUG ! 410: if (_res.options & RES_DEBUG) ! 411: perror("select"); ! 412: #endif DEBUG ! 413: continue; ! 414: } ! 415: if (n == 0) { ! 416: /* ! 417: * timeout ! 418: */ ! 419: #ifdef DEBUG ! 420: if (_res.options & RES_DEBUG) ! 421: printf("timeout (%d secs)\n", ! 422: timeout.tv_sec); ! 423: #endif DEBUG ! 424: #if BSD >= 43 ! 425: gotsomewhere = 1; ! 426: #endif ! 427: continue; ! 428: } ! 429: if ((resplen = recv(s, answer, anslen, 0)) <= 0) { ! 430: #ifdef DEBUG ! 431: if (_res.options & RES_DEBUG) ! 432: perror("recvfrom"); ! 433: #endif DEBUG ! 434: continue; ! 435: } ! 436: gotsomewhere = 1; ! 437: if (id != anhp->id) { ! 438: /* ! 439: * response from old query, ignore it ! 440: */ ! 441: #if SR ! 442: if (_res.options & RES_DEBUG2) { ! 443: printf("------------\nOld answer:\n"); ! 444: Print_query(answer, answer+resplen, 1); ! 445: } ! 446: #else ! 447: #ifdef DEBUG ! 448: if (_res.options & RES_DEBUG) { ! 449: printf("old answer:\n"); ! 450: p_query(answer); ! 451: } ! 452: #endif DEBUG ! 453: #endif ! 454: goto wait; ! 455: } ! 456: if (!(_res.options & RES_IGNTC) && anhp->tc) { ! 457: /* ! 458: * get rest of answer; ! 459: * use TCP with same server. ! 460: */ ! 461: #ifdef DEBUG ! 462: if (_res.options & RES_DEBUG) ! 463: printf("truncated answer\n"); ! 464: #endif DEBUG ! 465: (void) close(s); ! 466: s = -1; ! 467: v_circuit = 1; ! 468: goto usevc; ! 469: } ! 470: } ! 471: #if SR ! 472: if (_res.options & RES_DEBUG) { ! 473: if (_res.options & RES_DEBUG2) ! 474: printf("------------\nGot answer (%d bytes):\n", ! 475: resplen); ! 476: else ! 477: printf("------------\nGot answer:\n"); ! 478: Print_query(answer, answer+resplen, 1); ! 479: } ! 480: (void) close(s); ! 481: s = -1; ! 482: *trueLenPtr = resplen; ! 483: return (SUCCESS); ! 484: #else ! 485: #ifdef DEBUG ! 486: if (_res.options & RES_DEBUG) { ! 487: printf("got answer:\n"); ! 488: p_query(answer); ! 489: } ! 490: #endif DEBUG ! 491: /* ! 492: * If using virtual circuits, we assume that the first server ! 493: * is preferred * over the rest (i.e. it is on the local ! 494: * machine) and only keep that one open. ! 495: * If we have temporarily opened a virtual circuit, ! 496: * or if we haven't been asked to keep a socket open, ! 497: * close the socket. ! 498: */ ! 499: if ((v_circuit && ! 500: ((_res.options & RES_USEVC) == 0 || ns != 0)) || ! 501: (_res.options & RES_STAYOPEN) == 0) { ! 502: (void) close(s); ! 503: s = -1; ! 504: } ! 505: return (resplen); ! 506: } ! 507: #endif /* SR */ ! 508: } ! 509: if (s >= 0) { ! 510: (void) close(s); ! 511: s = -1; ! 512: } ! 513: #if SR ! 514: if (v_circuit == 0) ! 515: if (gotsomewhere == 0) ! 516: return NO_RESPONSE; /* no nameservers found */ ! 517: else ! 518: return TIME_OUT; /* no answer obtained */ ! 519: else ! 520: if (errno == ECONNREFUSED) ! 521: return NO_RESPONSE; ! 522: else ! 523: return ERROR; ! 524: #else ! 525: if (v_circuit == 0) ! 526: if (gotsomewhere == 0) ! 527: errno = ECONNREFUSED; /* no nameservers found */ ! 528: else ! 529: errno = ETIMEDOUT; /* no answer obtained */ ! 530: else ! 531: errno = terrno; ! 532: return (-1); ! 533: #endif ! 534: } ! 535: ! 536: /* ! 537: * This routine is for closing the socket if a virtual circuit is used and ! 538: * the program wants to close it. ! 539: * ! 540: * Called from the interrupt handler. ! 541: */ ! 542: SendRequest_close() ! 543: { ! 544: if (s != -1) { ! 545: (void) close(s); ! 546: s = -1; ! 547: } ! 548: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.