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

Defined functions

Defined variables

nsport defined in line 63; used 2 times
s defined in line 55; used 42 times
sccsid defined in line 21; never used

Defined macros

DEBUG defined in line 60; used 19 times
SR defined in line 57; used 8 times
Last modified: 1993-04-26
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4215
Valid CSS Valid XHTML 1.0 Strict