home *** CD-ROM | disk | FTP | other *** search
- #define USE_KEEPALIVES /* XXX should be in ../common/conf.h */
-
- /*
- ** Routines to open a TCP connection
- **
- ** New version that supports the old (pre 4.2 BSD) socket calls,
- ** and systems with the old (pre 4.2 BSD) hostname lookup stuff.
- ** Compile-time options are:
- **
- ** USG - you're on System III/V (you have my sympathies)
- ** NONETDB - old hostname lookup with rhost()
- ** OLDSOCKET - different args for socket() and connect()
- **
- ** Erik E. Fair <fair@ucbarpa.berkeley.edu>
- **
- */
-
- #include "../common/conf.h"
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <ctype.h>
- #include <stdio.h>
- #include "get_tcp_conn.h"
- #ifndef NONETDB
- #include <netdb.h>
- #endif NONETDB
-
- extern int errno;
- extern char *Pname;
- extern char *errmsg();
- #ifndef htons
- extern u_short htons();
- #endif htons
- #ifndef NONETDB
- extern char *inet_ntoa();
- extern u_long inet_addr();
- #else
- /*
- * inet_addr for EXCELAN (which does not have it!)
- *
- */
- u_long
- inet_addr(cp)
- register char *cp;
- {
- u_long val, base, n;
- register char c;
- u_long octet[4], *octetptr = octet;
- #ifndef htonl
- extern u_long htonl();
- #endif htonl
- again:
- /*
- * Collect number up to ``.''.
- * Values are specified as for C:
- * 0x=hex, 0=octal, other=decimal.
- */
- val = 0; base = 10;
- if (*cp == '0')
- base = 8, cp++;
- if (*cp == 'x' || *cp == 'X')
- base = 16, cp++;
- while (c = *cp) {
- if (isdigit(c)) {
- val = (val * base) + (c - '0');
- cp++;
- continue;
- }
- if (base == 16 && isxdigit(c)) {
- val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
- cp++;
- continue;
- }
- break;
- }
- if (*cp == '.') {
- /*
- * Internet format:
- * a.b.c.d
- * a.b.c (with c treated as 16-bits)
- * a.b (with b treated as 24 bits)
- */
- if (octetptr >= octet + 4)
- return (-1);
- *octetptr++ = val, cp++;
- goto again;
- }
- /*
- * Check for trailing characters.
- */
- if (*cp && !isspace(*cp))
- return (-1);
- *octetptr++ = val;
- /*
- * Concoct the address according to
- * the number of octet specified.
- */
- n = octetptr - octet;
- switch (n) {
-
- case 1: /* a -- 32 bits */
- val = octet[0];
- break;
-
- case 2: /* a.b -- 8.24 bits */
- val = (octet[0] << 24) | (octet[1] & 0xffffff);
- break;
-
- case 3: /* a.b.c -- 8.8.16 bits */
- val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) |
- (octet[2] & 0xffff);
- break;
-
- case 4: /* a.b.c.d -- 8.8.8.8 bits */
- val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) |
- ((octet[2] & 0xff) << 8) | (octet[3] & 0xff);
- break;
-
- default:
- return (-1);
- }
- val = htonl(val);
- return (val);
- }
-
- char *
- inet_ntoa(in)
- struct in_addr in;
- {
- static char address[20];
-
- sprintf(address, "%u.%u.%u.%u",
- (in.s_addr>>24)&0xff,
- (in.s_addr>>16)&0xff,
- (in.s_addr>>8 )&0xff,
- (in.s_addr )&0xff);
- return(address);
- }
- #endif NONETDB
-
- #ifdef USG
- void
- bcopy(s, d, l)
- register caddr_t s, d;
- register int l;
- {
- while (l-- > 0) *d++ = *s++;
- }
- #endif USG
-
- /*
- ** Take the name of an internet host in ASCII (this may either be its
- ** official host name or internet number (with or without enclosing
- ** backets [])), and return a list of internet addresses.
- **
- ** returns NULL for failure to find the host name in the local database,
- ** or for a bad internet address spec.
- */
- u_long **
- name_to_address(host)
- char *host;
- {
- static u_long *host_addresses[2];
- static u_long haddr;
-
- if (host == (char *)NULL) {
- return((u_long **)NULL);
- }
-
- host_addresses[0] = &haddr;
- host_addresses[1] = (u_long *)NULL;
-
- /*
- ** Is this an ASCII internet address? (either of [10.0.0.78] or
- ** 10.0.0.78). We get away with the second test because hostnames
- ** and domain labels are not allowed to begin in numbers.
- ** (cf. RFC952, RFC882).
- */
- if (*host == '[' || isdigit(*host)) {
- char namebuf[128];
- register char *cp = namebuf;
-
- /*
- ** strip brackets [] or anything else we don't want.
- */
- while(*host != '\0' && cp < &namebuf[sizeof(namebuf)]) {
- if (isdigit(*host) || *host == '.')
- *cp++ = *host++; /* copy */
- else
- host++; /* skip */
- }
- *cp = '\0';
- haddr = inet_addr(namebuf);
- return(&host_addresses[0]);
- } else {
- #ifdef NONETDB
- extern u_long rhost();
-
- /* lint is gonna bitch about this (comparing an unsigned?!) */
- if ((haddr = rhost(&host)) == FAIL)
- return((u_long **)NULL); /* no such host */
- return(&host_addresses[0]);
- #else
- struct hostent *hstp = gethostbyname(host);
-
- if (hstp == NULL) {
- return((u_long **)NULL); /* no such host */
- }
-
- if (hstp->h_length != sizeof(u_long))
- abort(); /* this is fundamental */
- #ifndef h_addr
- /* alignment problems (isn't dbm wonderful?) */
- bcopy((caddr_t)hstp->h_addr, (caddr_t)&haddr, sizeof(haddr));
- return(&host_addresses[0]);
- #else
- return((u_long **)hstp->h_addr_list);
- #endif h_addr
- #endif NONETDB
- }
- }
-
- /*
- ** Get a service port number from a service name (or ASCII number)
- **
- ** Return zero if something is wrong (that's a reserved port)
- */
- #ifdef NONETDB
- static struct Services {
- char *name;
- u_short port;
- } Services[] = {
- {"nntp", IPPORT_NNTP}, /* RFC977 */
- {"smtp", IPPORT_SMTP}, /* RFC821 */
- {"name", IPPORT_NAMESERVER}, /* RFC881, RFC882, RFC883 */
- {"time", IPPORT_TIMESERVER}, /* RFC868 */
- {"echo", IPPORT_ECHO}, /* RFC862 */
- {"discard", IPPORT_DISCARD}, /* RFC863 */
- {"daytime", IPPORT_DAYTIME}, /* RFC867 */
- {"login", IPPORT_LOGINSERVER}, /* N/A - 4BSD specific */
- };
- #endif NONETDB
-
- u_short
- gservice(serv, proto)
- char *serv, *proto;
- {
- if (serv == (char *)NULL || proto == (char *)NULL)
- return((u_short)0);
-
- if (isdigit(*serv)) {
- return(htons((u_short)(atoi(serv))));
- } else {
- #ifdef NONETDB
- register int i;
-
- for(i = 0; i < (sizeof(Services) / sizeof(struct Services)); i++) {
- if (strcmp(serv, Services[i].name) == 0)
- return(htons(Services[i].port));
- }
- return((u_short)0);
- #else
- struct servent *srvp = getservbyname(serv, proto);
-
- if (srvp == (struct servent *)NULL)
- return((u_short)0);
- return((u_short)srvp->s_port);
- #endif NONETDB
- }
- }
-
- /*
- ** given a host name (either name or internet address) and service name
- ** (or port number) (both in ASCII), give us a TCP connection to the
- ** requested service at the requested host (or give us FAIL).
- */
- get_tcp_conn(host, serv)
- char *host, *serv;
- {
- register int sock;
- u_long **addrlist;
- struct sockaddr_in sadr;
- #ifdef OLDSOCKET
- struct sockproto sp;
-
- sp.sp_family = (u_short)AF_INET;
- sp.sp_protocol = (u_short)IPPROTO_TCP;
- #endif OLDSOCKET
-
- if ((addrlist = name_to_address(host)) == (u_long **)NULL) {
- return(NOHOST);
- }
-
- sadr.sin_family = (u_short)AF_INET; /* Only internet for now */
- if ((sadr.sin_port = gservice(serv, "tcp")) == 0)
- return(NOSERVICE);
-
- for(; *addrlist != (u_long *)NULL; addrlist++) {
- bcopy((caddr_t)*addrlist, (caddr_t)&sadr.sin_addr,
- sizeof(sadr.sin_addr));
-
- #ifdef OLDSOCKET
- if ((sock = socket(SOCK_STREAM, &sp, (struct sockaddr *)NULL, 0)) < 0)
- return(FAIL);
-
- if (connect(sock, (struct sockaddr *)&sadr) < 0) {
- #else
- if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
- return(FAIL);
-
- if (connect(sock, (struct sockaddr *)&sadr, sizeof(sadr)) < 0) {
- #endif OLDSOCKET
- int e_save = errno;
-
- fprintf(stderr, "%s: %s [%s]: %s\n", Pname, host,
- inet_ntoa(sadr.sin_addr), errmsg(errno));
- (void) close(sock); /* dump descriptor */
- errno = e_save;
- } else
- {
- #ifdef USE_KEEPALIVES
- int on = 1;
- if (setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,(char *)&on,sizeof(on)) < 0)
- { int e_save;
- e_save = errno;
- fprintf(stderr,"%s: %s [%s]: setsockopt KEEPALIVE: %s\n",Pname,host,inet_ntoa(sadr.sin_addr),errmsg(errno));
- /* don't bother erroring out, just note it and ignore it */
- }
- #endif
- return(sock);
- }
- }
- return(FAIL);
- }
-