# 2.11BSD#431 - /usr/src/usr.sbin/named/tools/nslookup/send.c

##### Functions

    SendRequest       X
    SendRequest_close X

##### Variables

    nsport            X

##### Macros

    DEBUG             X
    SR                X

       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

SendRequest defined in line 86; used 1 times

- in /usr/src/usr.sbin/named/tools/nslookup/getinfo.c line 138

SendRequest_close defined in line 532; used 1 times

- in /usr/src/usr.sbin/named/tools/nslookup/subr.c line 91

#### Defined variables

nsport defined in line 63; used 2 times

- in line 117
- in /usr/src/usr.sbin/named/tools/nslookup/send.c line 117

s defined in line 55; used 42 times

- in line 154-156(3), 165-167(2), 175-176(2), 188, 194-195(2), 204, 214-215(2), 242, 252-253(2), 266, 276-278(3), 294, 302, 308, 340, 350, 363-368(2), 395-396(2), 419, 455-456(2), 470-471(2), 492-493(2), 499-501(3), 534-536(3)

sccsid defined in line 21; never used

#### Defined macros

DEBUG defined in line 60; used 19 times

- in line 59, 120, 139, 158, 171, 190, 210, 233, 248, 280, 342, 351, 371, 399, 409, 420, 437, 451, 475

SR defined in line 57; used 8 times

- in line 109, 137, 164, 287, 386, 431, 461, 503

Last modified: 1993-04-26 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 2071 |