home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NNTP-1.000 / NNTP-1 / nntp.1.5.11t / xmit / get_tcp_conn.c next >
Encoding:
C/C++ Source or Header  |  1993-10-17  |  7.6 KB  |  336 lines

  1. #define USE_KEEPALIVES /* XXX should be in ../common/conf.h */
  2.  
  3. /*
  4. ** Routines to open a TCP connection
  5. **
  6. ** New version that supports the old (pre 4.2 BSD) socket calls,
  7. ** and systems with the old (pre 4.2 BSD) hostname lookup stuff.
  8. ** Compile-time options are:
  9. **
  10. **    USG        - you're on System III/V (you have my sympathies)
  11. **    NONETDB        - old hostname lookup with rhost()
  12. **    OLDSOCKET    - different args for socket() and connect()
  13. **
  14. ** Erik E. Fair <fair@ucbarpa.berkeley.edu>
  15. **
  16. */
  17.  
  18. #include "../common/conf.h"
  19. #include <sys/types.h>
  20. #include <sys/socket.h>
  21. #include <netinet/in.h>
  22. #include <ctype.h>
  23. #include <stdio.h>
  24. #include "get_tcp_conn.h"
  25. #ifndef    NONETDB
  26. #include <netdb.h>
  27. #endif    NONETDB
  28.  
  29. extern    int    errno;
  30. extern    char    *Pname;
  31. extern    char    *errmsg();
  32. #ifndef    htons
  33. extern    u_short    htons();
  34. #endif    htons
  35. #ifndef    NONETDB
  36. extern    char    *inet_ntoa();
  37. extern    u_long    inet_addr();
  38. #else
  39. /*
  40.  * inet_addr for EXCELAN (which does not have it!)
  41.  *
  42.  */
  43. u_long
  44. inet_addr(cp)
  45. register char    *cp;
  46. {
  47.     u_long val, base, n;
  48.     register char c;
  49.      u_long octet[4], *octetptr = octet;
  50. #ifndef    htonl
  51.     extern    u_long    htonl();
  52. #endif    htonl
  53. again:
  54.     /*
  55.      * Collect number up to ``.''.
  56.      * Values are specified as for C:
  57.      * 0x=hex, 0=octal, other=decimal.
  58.      */
  59.     val = 0; base = 10;
  60.     if (*cp == '0')
  61.         base = 8, cp++;
  62.     if (*cp == 'x' || *cp == 'X')
  63.         base = 16, cp++;
  64.     while (c = *cp) {
  65.         if (isdigit(c)) {
  66.             val = (val * base) + (c - '0');
  67.             cp++;
  68.             continue;
  69.         }
  70.         if (base == 16 && isxdigit(c)) {
  71.             val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
  72.             cp++;
  73.             continue;
  74.         }
  75.         break;
  76.     }
  77.     if (*cp == '.') {
  78.         /*
  79.          * Internet format:
  80.          *    a.b.c.d
  81.          *    a.b.c    (with c treated as 16-bits)
  82.          *    a.b    (with b treated as 24 bits)
  83.          */
  84.         if (octetptr >= octet + 4)
  85.             return (-1);
  86.         *octetptr++ = val, cp++;
  87.         goto again;
  88.     }
  89.     /*
  90.      * Check for trailing characters.
  91.      */
  92.     if (*cp && !isspace(*cp))
  93.         return (-1);
  94.     *octetptr++ = val;
  95.     /*
  96.      * Concoct the address according to
  97.      * the number of octet specified.
  98.      */
  99.     n = octetptr - octet;
  100.     switch (n) {
  101.  
  102.     case 1:                /* a -- 32 bits */
  103.         val = octet[0];
  104.         break;
  105.  
  106.     case 2:                /* a.b -- 8.24 bits */
  107.         val = (octet[0] << 24) | (octet[1] & 0xffffff);
  108.         break;
  109.  
  110.     case 3:                /* a.b.c -- 8.8.16 bits */
  111.         val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) |
  112.             (octet[2] & 0xffff);
  113.         break;
  114.  
  115.     case 4:                /* a.b.c.d -- 8.8.8.8 bits */
  116.         val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) |
  117.               ((octet[2] & 0xff) << 8) | (octet[3] & 0xff);
  118.         break;
  119.  
  120.     default:
  121.         return (-1);
  122.     }
  123.     val = htonl(val);
  124.     return (val);
  125. }
  126.  
  127. char *
  128. inet_ntoa(in)
  129. struct in_addr in;
  130. {
  131.     static char address[20];
  132.  
  133.     sprintf(address, "%u.%u.%u.%u",
  134.              (in.s_addr>>24)&0xff,
  135.              (in.s_addr>>16)&0xff,
  136.              (in.s_addr>>8 )&0xff,
  137.              (in.s_addr    )&0xff);
  138.     return(address);
  139. }
  140. #endif    NONETDB
  141.  
  142. #ifdef    USG
  143. void
  144. bcopy(s, d, l)
  145. register caddr_t s, d;
  146. register int l;
  147. {
  148.     while (l-- > 0)    *d++ = *s++;
  149. }
  150. #endif    USG
  151.  
  152. /*
  153. ** Take the name of an internet host in ASCII (this may either be its
  154. ** official host name or internet number (with or without enclosing
  155. ** backets [])), and return a list of internet addresses.
  156. **
  157. ** returns NULL for failure to find the host name in the local database,
  158. ** or for a bad internet address spec.
  159. */
  160. u_long **
  161. name_to_address(host)
  162. char    *host;
  163. {
  164.     static    u_long    *host_addresses[2];
  165.     static    u_long    haddr;
  166.  
  167.     if (host == (char *)NULL) {
  168.         return((u_long **)NULL);
  169.     }
  170.  
  171.     host_addresses[0] = &haddr;
  172.     host_addresses[1] = (u_long *)NULL;
  173.  
  174.     /*
  175.     ** Is this an ASCII internet address? (either of [10.0.0.78] or
  176.     ** 10.0.0.78). We get away with the second test because hostnames
  177.     ** and domain labels are not allowed to begin in numbers.
  178.     ** (cf. RFC952, RFC882).
  179.     */
  180.     if (*host == '[' || isdigit(*host)) {
  181.         char    namebuf[128];
  182.         register char    *cp = namebuf;
  183.  
  184.         /*
  185.         ** strip brackets [] or anything else we don't want.
  186.         */
  187.         while(*host != '\0' && cp < &namebuf[sizeof(namebuf)]) {
  188.             if (isdigit(*host) || *host == '.')
  189.                 *cp++ = *host++;    /* copy */
  190.             else
  191.                 host++;            /* skip */
  192.         }
  193.         *cp = '\0';
  194.         haddr = inet_addr(namebuf);
  195.         return(&host_addresses[0]);
  196.     } else {
  197. #ifdef    NONETDB
  198.         extern    u_long    rhost();
  199.  
  200.         /* lint is gonna bitch about this (comparing an unsigned?!) */
  201.         if ((haddr = rhost(&host)) == FAIL)
  202.             return((u_long **)NULL);    /* no such host */
  203.         return(&host_addresses[0]);
  204. #else
  205.         struct hostent    *hstp = gethostbyname(host);
  206.  
  207.         if (hstp == NULL) {
  208.             return((u_long **)NULL);    /* no such host */
  209.         }
  210.  
  211.         if (hstp->h_length != sizeof(u_long))
  212.             abort();    /* this is fundamental */
  213. #ifndef    h_addr
  214.         /* alignment problems (isn't dbm wonderful?) */
  215.         bcopy((caddr_t)hstp->h_addr, (caddr_t)&haddr, sizeof(haddr));
  216.         return(&host_addresses[0]);
  217. #else
  218.         return((u_long **)hstp->h_addr_list);
  219. #endif    h_addr
  220. #endif    NONETDB
  221.     }
  222. }
  223.  
  224. /*
  225. ** Get a service port number from a service name (or ASCII number)
  226. **
  227. ** Return zero if something is wrong (that's a reserved port)
  228. */
  229. #ifdef    NONETDB
  230. static struct Services {
  231.     char    *name;
  232.     u_short    port;
  233. } Services[] = {
  234.     {"nntp",    IPPORT_NNTP},        /* RFC977 */
  235.     {"smtp",    IPPORT_SMTP},        /* RFC821 */
  236.     {"name",    IPPORT_NAMESERVER},    /* RFC881, RFC882, RFC883 */
  237.     {"time",    IPPORT_TIMESERVER},    /* RFC868 */
  238.     {"echo",    IPPORT_ECHO},        /* RFC862 */
  239.     {"discard",    IPPORT_DISCARD},    /* RFC863 */
  240.     {"daytime",    IPPORT_DAYTIME},    /* RFC867 */
  241.     {"login",    IPPORT_LOGINSERVER},    /* N/A - 4BSD specific */
  242. };
  243. #endif    NONETDB
  244.  
  245. u_short
  246. gservice(serv, proto)
  247. char    *serv, *proto;
  248. {
  249.     if (serv == (char *)NULL || proto == (char *)NULL)
  250.         return((u_short)0);
  251.  
  252.     if (isdigit(*serv)) {
  253.         return(htons((u_short)(atoi(serv))));
  254.     } else {
  255. #ifdef    NONETDB
  256.         register int    i;
  257.  
  258.         for(i = 0; i < (sizeof(Services) / sizeof(struct Services)); i++) {
  259.             if (strcmp(serv, Services[i].name) == 0)
  260.                 return(htons(Services[i].port));
  261.         }
  262.         return((u_short)0);
  263. #else
  264.         struct servent    *srvp = getservbyname(serv, proto);
  265.  
  266.         if (srvp == (struct servent *)NULL)
  267.             return((u_short)0);
  268.         return((u_short)srvp->s_port);
  269. #endif    NONETDB
  270.     }
  271. }
  272.  
  273. /*
  274. ** given a host name (either name or internet address) and service name
  275. ** (or port number) (both in ASCII), give us a TCP connection to the
  276. ** requested service at the requested host (or give us FAIL).
  277. */
  278. get_tcp_conn(host, serv)
  279. char    *host, *serv;
  280. {
  281.     register int    sock;
  282.     u_long    **addrlist;
  283.     struct sockaddr_in    sadr;
  284. #ifdef    OLDSOCKET
  285.     struct sockproto    sp;
  286.  
  287.     sp.sp_family    = (u_short)AF_INET;
  288.     sp.sp_protocol    = (u_short)IPPROTO_TCP;
  289. #endif    OLDSOCKET
  290.  
  291.     if ((addrlist = name_to_address(host)) == (u_long **)NULL) {
  292.         return(NOHOST);
  293.     }
  294.  
  295.     sadr.sin_family = (u_short)AF_INET;    /* Only internet for now */
  296.     if ((sadr.sin_port = gservice(serv, "tcp")) == 0)
  297.         return(NOSERVICE);
  298.  
  299.     for(; *addrlist != (u_long *)NULL; addrlist++) {
  300.         bcopy((caddr_t)*addrlist, (caddr_t)&sadr.sin_addr,
  301.             sizeof(sadr.sin_addr));
  302.  
  303. #ifdef    OLDSOCKET
  304.         if ((sock = socket(SOCK_STREAM, &sp, (struct sockaddr *)NULL, 0)) < 0)
  305.             return(FAIL);
  306.  
  307.         if (connect(sock, (struct sockaddr *)&sadr) < 0) {
  308. #else
  309.         if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
  310.             return(FAIL);
  311.  
  312.         if (connect(sock, (struct sockaddr *)&sadr, sizeof(sadr)) < 0) {
  313. #endif    OLDSOCKET
  314.             int    e_save = errno;
  315.  
  316.             fprintf(stderr, "%s: %s [%s]: %s\n", Pname, host,
  317.                 inet_ntoa(sadr.sin_addr), errmsg(errno));
  318.             (void) close(sock);    /* dump descriptor */
  319.             errno = e_save;
  320.         } else
  321.                                     {
  322. #ifdef USE_KEEPALIVES
  323.                                       int on = 1;
  324.                                       if (setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,(char *)&on,sizeof(on)) < 0)
  325.                                        { int e_save;
  326.                                      e_save = errno;
  327.                                      fprintf(stderr,"%s: %s [%s]: setsockopt KEEPALIVE: %s\n",Pname,host,inet_ntoa(sadr.sin_addr),errmsg(errno));
  328.                                      /* don't bother erroring out, just note it and ignore it */
  329.                                        }
  330. #endif
  331.                                       return(sock);
  332.                                     }
  333.     }
  334.     return(FAIL);
  335. }
  336.