home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / n / bind / bind-4.001 / bind-4~ / bind-4.9.3-BETA9 / contrib / host / send.c < prev    next >
C/C++ Source or Header  |  1994-06-22  |  17KB  |  723 lines

  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
  6.  * provided that: (1) source distributions retain this entire copyright
  7.  * notice and comment, and (2) distributions including binaries display
  8.  * the following acknowledgement:  ``This product includes software
  9.  * developed by the University of California, Berkeley and its contributors''
  10.  * in the documentation or other materials provided with the distribution
  11.  * and in all advertising materials mentioning features or use of this
  12.  * software. Neither the name of the University nor the names of its
  13.  * contributors may be used to endorse or promote products derived
  14.  * from this software without specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  */
  19.  
  20. #ifndef lint
  21. static char Version[] = "@(#)send.c    e07@nikhef.nl (Eric Wassenaar) 940622";
  22. #endif
  23.  
  24. #if defined(apollo) && defined(lint)
  25. #define __attribute(x)
  26. #endif
  27.  
  28. #include <stdio.h>
  29. #include <errno.h>
  30. #include <setjmp.h>
  31. #include <signal.h>
  32. #include <sys/time.h>
  33.  
  34. #include <sys/types.h>        /* not always automatically included */
  35. #include <sys/param.h>
  36. #include <sys/socket.h>
  37. #include <netinet/in.h>
  38.  
  39. #undef NOERROR            /* in <sys/streams.h> on solaris 2.x */
  40. #include <arpa/nameser.h>
  41. #include <resolv.h>
  42.  
  43. #include "port.h"        /* various portability definitions */
  44.  
  45. #define input            /* read-only input parameter */
  46. #define output            /* modified output parameter */
  47.  
  48. #define bitset(a,b)    (((a) & (b)) != 0)
  49. #define setalarm(n)    (void) alarm((unsigned int)n)
  50.  
  51. extern int errno;
  52. extern res_state_t _res;    /* defined in res_init.c */
  53.  
  54. static int timeout;        /* connection read timeout */
  55. static struct sockaddr from;    /* address of inbound packet */
  56.  
  57. /* extern */
  58. char *inet_ntoa        PROTO((struct in_addr));
  59.  
  60. /* send.c */
  61. #ifdef HOST_RES_SEND
  62. int res_send        PROTO((char *, int, char *, int));
  63. void _res_close        PROTO((void));
  64. static int send_stream    PROTO((struct sockaddr_in *, char *, int, char *, int));
  65. static int send_dgram    PROTO((struct sockaddr_in *, char *, int, char *, int));
  66. #endif /*HOST_RES_SEND*/
  67. static sigtype_t timer    PROTO((int));
  68. int _res_connect    PROTO((int, struct sockaddr_in *, int));
  69. int _res_write        PROTO((int, char *, int));
  70. int _res_read        PROTO((int, char *, int));
  71. static int recv_sock    PROTO((int, char *, int));
  72. void _res_setaddr    PROTO((struct sockaddr_in *, char *));
  73. void _res_perror    PROTO((char *));
  74.  
  75. #ifdef HOST_RES_SEND
  76.  
  77. /*
  78. ** RES_SEND -- Send nameserver query and retrieve answer
  79. ** -----------------------------------------------------
  80. **
  81. **    Returns:
  82. **        Length of nameserver answer buffer, if obtained.
  83. **        -1 if an error occurred (errno set appropriately).
  84. **
  85. **    This is a simplified version of the BIND 4.8.3 res_send().
  86. **    - Always use connected datagrams to get proper error messages.
  87. **    - Do not only return ETIMEDOUT or ECONNREFUSED in datagram mode,
  88. **      but also host or network unreachable status if appropriate.
  89. **    - Never leave a connection open after we got an answer.
  90. **    - No special ECONNRESET handling when using virtual circuits.
  91. **
  92. **    Note that this private version of res_send() is not only called
  93. **    directly by 'host' but also indirectly by gethostbyname() or by
  94. **    gethostbyaddr() via their resolver interface routines.
  95. */
  96.  
  97. int
  98. res_send(query, querylen, answer, anslen)
  99. input char *query;            /* address of formatted query buffer */
  100. input int querylen;            /* length of query buffer */
  101. output char *answer;            /* address of buffer to store answer */
  102. input int anslen;            /* maximum size of answer buffer */
  103. {
  104.     HEADER *bp = (HEADER *)answer;
  105.     struct sockaddr_in *sin;
  106.     int v_circuit;            /* virtual circuit or datagram switch */
  107.     int servfail[MAXNS];        /* saved failure codes per nameserver */
  108.     register int try, ns;
  109.     register int n;
  110.  
  111.     /* make sure resolver has been initialized */
  112.     if (!bitset(RES_INIT, _res.options) && res_init() == -1)
  113.         return(-1);
  114.  
  115.     if (bitset(RES_DEBUG, _res.options))
  116.     {
  117.         printf("res_send()\n");
  118.         fp_query(query, stdout);
  119.     }
  120.  
  121.     /* use virtual circuit if requested or if necessary */
  122.     v_circuit = bitset(RES_USEVC, _res.options) || (querylen > PACKETSZ);
  123.  
  124.     /* reset server failure codes */
  125.     for (n = 0; n < MAXNS; n++)
  126.         servfail[n] = 0;
  127.  
  128. /*
  129.  * Do _res.retry attempts for each of the _res.nscount addresses.
  130.  * Upon failure, the current server will be marked bad if we got
  131.  * an error condition which makes it unlikely that we will succeed
  132.  * the next time we try this server.
  133.  * Internal operating system failures, such as temporary lack of
  134.  * resources, do not fall in that category.
  135.  */
  136.     for (try = 0; try < _res.retry; try++)
  137.     {
  138.         for (ns = 0; ns < _res.nscount; ns++)
  139.         {
  140.         /* skip retry if server failed permanently */
  141.         if (servfail[ns])
  142.             continue;
  143.  
  144.         sin = &nslist(ns);
  145.         _res_setaddr(sin, (char *)NULL);
  146. retry:
  147.         if (bitset(RES_DEBUG, _res.options))
  148.             printf("Querying server (# %d) %s address = %s\n", ns+1,
  149.                 v_circuit ? "tcp" : "udp", inet_ntoa(sin->sin_addr));
  150.  
  151.         if (v_circuit)
  152.         {
  153.             /* at most one attempt per server */
  154.             try = _res.retry;
  155.  
  156.             /* connect via virtual circuit */
  157.             n = send_stream(sin, query, querylen, answer, anslen);
  158.         }
  159.         else
  160.         {
  161.             /* set datagram read timeout for recv_sock() */
  162.             timeout = (_res.retrans << try);
  163.             if (try > 0)
  164.                 timeout /= _res.nscount;
  165.             if (timeout <= 0)
  166.                 timeout = 1;
  167.  
  168.             /* connect via datagram */
  169.             n = send_dgram(sin, query, querylen, answer, anslen);
  170.  
  171.             /* check truncation; use v_circuit with same server */
  172.             if (n > 0 && bp->tc)
  173.             {
  174.                 if (bitset(RES_DEBUG, _res.options))
  175.                     (void) fprintf(stderr, "truncated answer\n");
  176.  
  177.                 if (!bitset(RES_IGNTC, _res.options))
  178.                 {
  179.                     v_circuit = 1;
  180.                     goto retry;
  181.                 }
  182.             }
  183.         }
  184.  
  185.         if (n <= 0)
  186.         {
  187.             switch (errno)
  188.             {
  189.                 case ECONNREFUSED:
  190.                 case ENETDOWN:
  191.                 case ENETUNREACH:
  192.                 case EHOSTDOWN:
  193.                 case EHOSTUNREACH:
  194.                 servfail[ns] = errno;
  195.                 break;
  196.             }
  197.  
  198.             /* try next server */
  199.             continue;
  200.         }
  201.  
  202.         if (bitset(RES_DEBUG, _res.options))
  203.         {
  204.             printf("got answer, %d bytes:\n", n);
  205.             fp_query(answer, stdout);
  206.         }
  207.  
  208.         /* we have an answer; clear possible error condition */
  209.         errno = 0;
  210.         return(n);
  211.         }
  212.     }
  213.  
  214.     /* no answer obtained; return error condition */
  215.     return(-1);
  216. }
  217.  
  218. /*
  219. ** _RES_CLOSE -- Close an open stream or dgram connection
  220. ** ------------------------------------------------------
  221. **
  222. **    Returns:
  223. **        None.
  224. */
  225.  
  226. static int srvsock = -1;    /* socket descriptor */
  227.  
  228. void
  229. _res_close()
  230. {
  231.     int save_errno = errno;        /* preserve state */
  232.  
  233.     /* close the connection if open */
  234.     if (srvsock >= 0)
  235.     {
  236.         (void) close(srvsock);
  237.         srvsock = -1;
  238.     }
  239.  
  240.     /* restore state */
  241.     errno = save_errno;
  242. }
  243.  
  244. /*
  245. ** SEND_STREAM -- Query nameserver via virtual circuit
  246. ** ---------------------------------------------------
  247. **
  248. **    Returns:
  249. **        Length of nameserver answer buffer, if obtained.
  250. **        -1 if an error occurred.
  251. **
  252. **    Note that connect() is the call that is allowed to fail
  253. **    under normal circumstances. All other failures generate
  254. **    an unconditional error message.
  255. **    Note that truncation is handled within _res_read().
  256. */
  257.  
  258. static int
  259. send_stream(addr, query, querylen, answer, anslen)
  260. input struct sockaddr_in *addr;        /* the server address to connect to */
  261. input char *query;            /* address of formatted query buffer */
  262. input int querylen;            /* length of query buffer */
  263. output char *answer;            /* address of buffer to store answer */
  264. input int anslen;            /* maximum size of answer buffer */
  265. {
  266.     register int n;
  267.  
  268. /*
  269.  * Setup a virtual circuit connection.
  270.  */
  271.     srvsock = socket(AF_INET, SOCK_STREAM, 0);
  272.     if (srvsock < 0)
  273.     {
  274.         _res_perror("socket");
  275.         return(-1);
  276.     }
  277.  
  278.     if (_res_connect(srvsock, addr, sizeof(*addr)) < 0)
  279.     {
  280.         if (bitset(RES_DEBUG, _res.options))
  281.             _res_perror("connect");
  282.         _res_close();
  283.         return(-1);
  284.     }
  285.  
  286.     if (bitset(RES_DEBUG, _res.options))
  287.         printf("connected to %s\n", inet_ntoa(addr->sin_addr));
  288.  
  289. /*
  290.  * Send the query buffer.
  291.  */
  292.     if (_res_write(srvsock, query, querylen) < 0)
  293.     {
  294.         _res_close();
  295.         return(-1);
  296.     }
  297.  
  298. /*
  299.  * Read the answer buffer.
  300.  */
  301.     n = _res_read(srvsock, answer, anslen);
  302.     if (n <= 0)
  303.     {
  304.         _res_close();
  305.         return(-1);
  306.     }
  307.  
  308. /*
  309.  * Never leave the socket open.
  310.  */
  311.     _res_close();
  312.     return(n);
  313. }
  314.  
  315. /*
  316. ** SEND_DGRAM -- Query nameserver via datagram
  317. ** -------------------------------------------
  318. **
  319. **    Returns:
  320. **        Length of nameserver answer buffer, if obtained.
  321. **        -1 if an error occurred.
  322. **
  323. **    Inputs:
  324. **        The global variable ``timeout'' should have been
  325. **        set with the desired timeout value in seconds.
  326. **
  327. **    Sending to a nameserver datagram port with no nameserver running
  328. **    will cause an ICMP port unreachable message to be returned. If the
  329. **    socket is connected, we get an ECONNREFUSED error on the next socket
  330. **    operation, and select returns if the error message is received.
  331. **    Also, we get ENETUNREACH or EHOSTUNREACH errors if appropriate.
  332. **    We thus get a proper error status before timing out.
  333. **    This method usually works only if BSD >= 43.
  334. **
  335. **    Note that send() and recvfrom() are now the calls that are allowed
  336. **    to fail under normal circumstances. All other failures generate
  337. **    an unconditional error message.
  338. */
  339.  
  340. static int
  341. send_dgram(addr, query, querylen, answer, anslen)
  342. input struct sockaddr_in *addr;        /* the server address to connect to */
  343. input char *query;            /* address of formatted query buffer */
  344. input int querylen;            /* length of query buffer */
  345. output char *answer;            /* address of buffer to store answer */
  346. input int anslen;            /* maximum size of answer buffer */
  347. {
  348.     HEADER *qp = (HEADER *)query;
  349.     HEADER *bp = (HEADER *)answer;
  350.     register int n;
  351.  
  352. /*
  353.  * Setup a connected datagram socket.
  354.  */
  355.     srvsock = socket(AF_INET, SOCK_DGRAM, 0);
  356.     if (srvsock < 0)
  357.     {
  358.         _res_perror("socket");
  359.         return(-1);
  360.     }
  361.  
  362.     if (connect(srvsock, (struct sockaddr *)addr, sizeof(*addr)) < 0)
  363.     {
  364.         _res_perror("connect");
  365.         _res_close();
  366.         return(-1);
  367.     }
  368.  
  369. /*
  370.  * Send the query buffer.
  371.  */
  372.     if (send(srvsock, query, querylen, 0) != querylen)
  373.     {
  374.         if (bitset(RES_DEBUG, _res.options))
  375.             _res_perror("send");
  376.         _res_close();
  377.         return(-1);
  378.     }
  379.  
  380. /*
  381.  * Wait for the arrival of a reply, timeout, or error message.
  382.  */
  383. wait:
  384.     n = recv_sock(srvsock, answer, anslen);
  385.     if (n <= 0)
  386.     {
  387.         if (bitset(RES_DEBUG, _res.options))
  388.             _res_perror("recvfrom");
  389.         _res_close();
  390.         return(-1);
  391.     }
  392.  
  393. /*
  394.  * Make sure it is the proper response by checking the packet id.
  395.  */
  396.     if (qp->id != bp->id)
  397.     {
  398.         if (bitset(RES_DEBUG, _res.options))
  399.         {
  400.             printf("old answer:\n");
  401.             fp_query(answer, stdout);
  402.         }
  403.         goto wait;
  404.     }
  405.  
  406. /*
  407.  * Never leave the socket open.
  408.  */
  409.     _res_close();
  410.     return(n);
  411. }
  412.  
  413. #endif /*HOST_RES_SEND*/
  414.  
  415. /*
  416. ** _RES_CONNECT -- Connect to a stream (virtual circuit) socket
  417. ** ------------------------------------------------------------
  418. **
  419. **    Returns:
  420. **        0 if successfully connected.
  421. **        -1 in case of failure or timeout.
  422. **
  423. **    Note that we use _res.retrans to override the default
  424. **    connect timeout value.
  425. */
  426.  
  427. static jmp_buf timer_buf;
  428.  
  429. static sigtype_t
  430. /*ARGSUSED*/
  431. timer(sig)
  432. int sig;
  433. {
  434.     longjmp(timer_buf, 1);
  435. }
  436.  
  437.  
  438. int
  439. _res_connect(sock, addr, addrlen)
  440. input int sock;
  441. input struct sockaddr_in *addr;        /* the server address to connect to */
  442. input int addrlen;
  443. {
  444.     if (setjmp(timer_buf) != 0)
  445.     {
  446.         errno = ETIMEDOUT;
  447.         setalarm(0);
  448.         return(-1);
  449.     }
  450.  
  451.     (void) signal(SIGALRM, timer);
  452.     setalarm(_res.retrans);
  453.  
  454.     if (connect(sock, (struct sockaddr *)addr, addrlen) < 0)
  455.     {
  456.         if (errno == EINTR)
  457.             errno = ETIMEDOUT;
  458.         setalarm(0);
  459.         return(-1);
  460.     }
  461.  
  462.     setalarm(0);
  463.     return(0);
  464. }
  465.  
  466. /*
  467. ** _RES_WRITE -- Write the query buffer via a stream socket
  468. ** --------------------------------------------------------
  469. **
  470. **    Returns:
  471. **        Length of buffer if successfully transmitted.
  472. **        -1 in case of failure (error message is issued).
  473. **
  474. **    The query is sent in two steps: first a single word with
  475. **    the length of the buffer, followed by the buffer itself.
  476. */
  477.  
  478. int
  479. _res_write(sock, buf, bufsize)
  480. input int sock;
  481. input char *buf;            /* address of formatted query buffer */
  482. input int bufsize;            /* length of query buffer */
  483. {
  484.     u_short len;
  485.  
  486. /*
  487.  * Write the length of the query buffer.
  488.  */
  489.     /* len = htons(bufsize); */
  490.     putshort((u_short)bufsize, (u_char *)&len);
  491.  
  492.     if (write(sock, (char *)&len, INT16SZ) != INT16SZ)
  493.     {
  494.         _res_perror("write query length");
  495.         return(-1);
  496.     }
  497.  
  498. /*
  499.  * Write the query buffer itself.
  500.  */
  501.     if (write(sock, buf, bufsize) != bufsize)
  502.     {
  503.         _res_perror("write query");
  504.         return(-1);
  505.     }
  506.  
  507.     return(bufsize);
  508. }
  509.  
  510. /*
  511. ** _RES_READ -- Read the answer buffer via a stream socket
  512. ** -------------------------------------------------------
  513. **
  514. **    Returns:
  515. **        Length of buffer if successfully received.
  516. **        -1 in case of failure (error message is issued).
  517. **
  518. **    The answer is read in two steps: first a single word which
  519. **    gives the length of the buffer, followed by the buffer itself.
  520. **    If the answer is too long to fit into the supplied buffer,
  521. **    only the portion that fits will be stored, the residu will be
  522. **    flushed, and the truncation flag will be set.
  523. */
  524.  
  525. int
  526. _res_read(sock, buf, bufsize)
  527. input int sock;
  528. output char *buf;            /* address of buffer to store answer */
  529. input int bufsize;            /* maximum size of answer buffer */
  530. {
  531.     u_short len;
  532.     char *buffer;
  533.     int buflen;
  534.     int reslen;
  535.     register int n;
  536.  
  537.     /* set stream timeout for recv_sock() */
  538.     timeout = 60;
  539.  
  540. /*
  541.  * Read the length of answer buffer.
  542.  */
  543.     buffer = (char *)&len;
  544.     buflen = INT16SZ;
  545.  
  546.     while (buflen > 0 && (n = recv_sock(sock, buffer, buflen)) > 0)
  547.     {
  548.         buffer += n;
  549.         buflen -= n;
  550.     }
  551.  
  552.     if (buflen != 0)
  553.     {
  554.         _res_perror("read answer length");
  555.         return(-1);
  556.     }
  557.  
  558. /*
  559.  * Terminate if length is zero.
  560.  */
  561.     /* len = ntohs(len); */
  562.     len = _getshort((u_char *)&len);
  563.  
  564.     if (len == 0)
  565.         return(0);
  566.  
  567. /*
  568.  * Check for truncation.
  569.  */
  570.     reslen = 0;
  571.     if ((int)len > bufsize)
  572.     {
  573.         reslen = len - bufsize;
  574.         len = bufsize;
  575.     }
  576.  
  577. /*
  578.  * Read the answer buffer itself.
  579.  */
  580.     buffer = buf;
  581.     buflen = len;
  582.  
  583.     while (buflen > 0 && (n = recv_sock(sock, buffer, buflen)) > 0)
  584.     {
  585.         buffer += n;
  586.         buflen -= n;
  587.     }
  588.  
  589.     if (buflen != 0)
  590.     {
  591.         _res_perror("read answer");
  592.         return(-1);
  593.     }
  594.  
  595. /*
  596.  * Discard the residu to keep connection in sync.
  597.  */
  598.     if (reslen > 0)
  599.     {
  600.         HEADER *bp = (HEADER *)buf;
  601.         char resbuf[PACKETSZ];
  602.  
  603.         buffer = resbuf;
  604.         buflen = reslen < sizeof(resbuf) ? reslen : sizeof(resbuf);
  605.  
  606.         while (reslen > 0 && (n = recv_sock(sock, buffer, buflen)) > 0)
  607.         {
  608.             reslen -= n;
  609.             buflen = reslen < sizeof(resbuf) ? reslen : sizeof(resbuf);
  610.         }
  611.  
  612.         if (reslen != 0)
  613.         {
  614.             _res_perror("read residu");
  615.             return(-1);
  616.         }
  617.  
  618.         if (bitset(RES_DEBUG, _res.options))
  619.             (void) fprintf(stderr, "response truncated\n");
  620.  
  621.         /* set truncation flag */
  622.         bp->tc = 1;
  623.     }
  624.  
  625.     return(len);
  626. }
  627.  
  628. /*
  629. ** RECV_SOCK -- Read from stream or datagram socket with timeout
  630. ** -------------------------------------------------------------
  631. **
  632. **    Returns:
  633. **        Length of buffer if successfully received.
  634. **        -1 in case of failure or timeout.
  635. **
  636. **    Inputs:
  637. **        The global variable ``timeout'' should have been
  638. **        set with the desired timeout value in seconds.
  639. **
  640. **    Outputs:
  641. **        Sets global ``from'' to the address from which we
  642. **        received the packet.
  643. */
  644.  
  645. static int
  646. recv_sock(sock, buffer, buflen)
  647. input int sock;
  648. output char *buffer;            /* current buffer address */
  649. input int buflen;            /* remaining buffer size */
  650. {
  651.     fd_set fds;
  652.     struct timeval wait;
  653.     int fromlen;
  654.     register int n;
  655.  
  656.     wait.tv_sec = timeout;
  657.     wait.tv_usec = 0;
  658.  
  659.     /* FD_ZERO(&fds); */
  660.     bzero((char *)&fds, sizeof(fds));
  661.     FD_SET(sock, &fds);
  662.  
  663.     /* wait for the arrival of data, or timeout */
  664.     n = select(FD_SETSIZE, &fds, (fd_set *)NULL, (fd_set *)NULL, &wait);
  665.     if (n <= 0)
  666.     {
  667.         if (n == 0)
  668.             errno = ETIMEDOUT;
  669.         return(-1);
  670.     }
  671.  
  672.     /* fake an error if nothing was actually read */
  673.     fromlen = sizeof(from);
  674.     n = recvfrom(sock, buffer, buflen, 0, &from, &fromlen);
  675.     if (n == 0)
  676.         errno = ECONNRESET;
  677.     return(n);
  678. }
  679.  
  680. /*
  681. ** _RES_PERROR -- Issue perror message including host info
  682. ** -------------------------------------------------------
  683. **
  684. **    Returns:
  685. **        None.
  686. **
  687. **    The address and name of the server host must be set
  688. **    in advance via _res_setaddr().
  689. */
  690.  
  691. static struct in_addr curaddr;    /* current address of server host */
  692. static char *curhost = NULL;    /* current name of server host */
  693.  
  694. void
  695. _res_setaddr(sin, host)
  696. input struct sockaddr_in *sin;        /* address of host to connect to */
  697. input char *host;            /* name of host to connect to */
  698. {
  699.     curaddr = sin->sin_addr;
  700.     curhost = host;
  701. }
  702.  
  703.  
  704. void
  705. _res_perror(message)
  706. input char *message;            /* perror message string */
  707. {
  708.     int save_errno = errno;        /* preserve state */
  709.  
  710.     /* prepend server address and name */
  711.     if (curaddr.s_addr)
  712.         (void) fprintf(stderr, "%s ", inet_ntoa(curaddr));
  713.     if (curhost)
  714.         (void) fprintf(stderr, "(%s) ", curhost);
  715.  
  716.     /* issue actual message */
  717.     errno = save_errno;
  718.     perror(message);
  719.  
  720.     /* restore state */
  721.     errno = save_errno;
  722. }
  723.