580 lines
13 KiB
C++
580 lines
13 KiB
C++
/*********************************************************************
|
|
Project : GUSI - Grand Unified Socket Interface
|
|
File : GUSINetDB.cp - Convert internet names to adresses
|
|
Author : Matthias Neeracher
|
|
|
|
This file was derived from the socket library by
|
|
|
|
Charlie Reiman <creiman@ncsa.uiuc.edu> and
|
|
Tom Milligan <milligan@madhaus.utcs.utoronto.ca>
|
|
|
|
Language : MPW C++
|
|
|
|
$Log$
|
|
Revision 1.1 1998/08/18 14:52:38 jack
|
|
Putting Python-specific GUSI modifications under CVS.
|
|
|
|
Revision 1.3 1994/08/10 00:07:30 neeri
|
|
Sanitized for universal headers.
|
|
|
|
Revision 1.2 1994/05/01 23:43:31 neeri
|
|
getservbyname() without /etc/services would fail.
|
|
|
|
Revision 1.1 1994/02/25 02:29:36 neeri
|
|
Initial revision
|
|
|
|
Revision 0.5 1993/10/31 00:00:00 neeri
|
|
Deferred opening of resolver
|
|
|
|
Revision 0.4 1993/07/29 00:00:00 neeri
|
|
Real getservent code (adapted from Sak Wathanasin)
|
|
|
|
Revision 0.3 1993/01/19 00:00:00 neeri
|
|
Can't set aliases to NULL.
|
|
|
|
Revision 0.2 1992/11/21 00:00:00 neeri
|
|
Remove force_active
|
|
|
|
Revision 0.1 1992/09/14 00:00:00 neeri
|
|
Maybe it works, maybe it doesn't
|
|
|
|
*********************************************************************/
|
|
|
|
#include "GUSIINET_P.h"
|
|
|
|
#include "TFileSpec.h"
|
|
#include "Folders.h"
|
|
#include "PLStringFuncs.h"
|
|
|
|
#ifdef __MWERKS__
|
|
//
|
|
// I disapprove of the way dnr.c is written
|
|
// This disapproval gets stronger with every version
|
|
//
|
|
#include "dnr.c"
|
|
#pragma require_prototypes reset
|
|
#pragma cplusplus reset
|
|
#endif
|
|
|
|
#if GENERATING68K
|
|
#pragma segment GUSIINET
|
|
#endif
|
|
|
|
static pascal void DNRDone(struct hostInfo *, Boolean * done)
|
|
{
|
|
*done = true;
|
|
}
|
|
|
|
#if GENERATINGCFM
|
|
RoutineDescriptor uDNRDone =
|
|
BUILD_ROUTINE_DESCRIPTOR(uppResultProcInfo, DNRDone);
|
|
#else
|
|
#define uDNRDone DNRDone
|
|
#endif
|
|
|
|
int h_errno;
|
|
|
|
/*
|
|
* Gethostbyname and gethostbyaddr each return a pointer to an
|
|
* object with the following structure describing an Internet
|
|
* host referenced by name or by address, respectively. This
|
|
* structure contains the information obtained from the MacTCP
|
|
* name server.
|
|
*
|
|
* struct hostent
|
|
* {
|
|
* char *h_name;
|
|
* char **h_aliases;
|
|
* int h_addrtype;
|
|
* int h_length;
|
|
* char **h_addr_list;
|
|
* };
|
|
* #define h_addr h_addr_list[0]
|
|
*
|
|
* The members of this structure are:
|
|
*
|
|
* h_name Official name of the host.
|
|
*
|
|
* h_aliases A zero terminated array of alternate names for the host.
|
|
*
|
|
* h_addrtype The type of address being returned; always AF_INET.
|
|
*
|
|
* h_length The length, in bytes, of the address.
|
|
*
|
|
* h_addr_list A zero terminated array of network addresses for the host.
|
|
*
|
|
* Error return status from gethostbyname and gethostbyaddr is
|
|
* indicated by return of a null pointer. The external integer
|
|
* h_errno may then be checked to see whether this is a
|
|
* temporary failure or an invalid or unknown host. The
|
|
* routine herror can be used to print an error message
|
|
* describing the failure. If its argument string is non-NULL,
|
|
* it is printed, followed by a colon and a space. The error
|
|
* message is printed with a trailing newline.
|
|
*
|
|
* h_errno can have the following values:
|
|
*
|
|
* HOST_NOT_FOUND No such host is known.
|
|
*
|
|
* TRY_AGAIN This is usually a temporary error and
|
|
* means that the local server did not
|
|
* receive a response from an authoritative
|
|
* server. A retry at some later time may
|
|
* succeed.
|
|
*
|
|
* NO_RECOVERY Some unexpected server failure was encountered.
|
|
* This is a non-recoverable error.
|
|
*
|
|
* NO_DATA The requested name is valid but does not
|
|
* have an IP address; this is not a
|
|
* temporary error. This means that the name
|
|
* is known to the name server but there is
|
|
* no address associated with this name.
|
|
* Another type of request to the name server
|
|
* using this domain name will result in an
|
|
* answer; for example, a mail-forwarder may
|
|
* be registered for this domain.
|
|
* (NOT GENERATED BY THIS IMPLEMENTATION)
|
|
*/
|
|
|
|
static struct hostInfo macHost;
|
|
|
|
#define MAXALIASES 0
|
|
static char *aliasPtrs[MAXALIASES+1] = {NULL};
|
|
static ip_addr *addrPtrs[NUM_ALT_ADDRS+1];
|
|
|
|
static struct hostent unixHost =
|
|
{
|
|
macHost.cname,
|
|
aliasPtrs,
|
|
AF_INET,
|
|
sizeof(ip_addr),
|
|
(char **) addrPtrs
|
|
};
|
|
|
|
inline struct in_addr make_in_addr(ip_addr addr)
|
|
{
|
|
struct in_addr res;
|
|
|
|
res.s_addr = addr;
|
|
|
|
return res;
|
|
}
|
|
|
|
struct hostent * gethostbyname(char *name)
|
|
{
|
|
Boolean done;
|
|
int i;
|
|
|
|
if (!strcmp(name, "localhost")) {
|
|
in_addr ipaddr;
|
|
|
|
ipaddr = make_in_addr(ip_addr(gethostid()));
|
|
|
|
if (ipaddr.s_addr)
|
|
return gethostbyaddr((char *) &ipaddr, sizeof(in_addr), AF_INET);
|
|
|
|
h_errno = HOST_NOT_FOUND;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
if (INETSockets.Resolver()) {
|
|
h_errno = NO_RECOVERY;
|
|
return NULL;
|
|
}
|
|
|
|
for (i=0; i<NUM_ALT_ADDRS; i++)
|
|
macHost.addr[i] = 0;
|
|
|
|
done = false;
|
|
|
|
if (StrToAddr(name, &macHost, ResultUPP(&uDNRDone), (char *) &done) == cacheFault)
|
|
SPINP(!done,SP_NAME,0L);
|
|
|
|
switch (macHost.rtnCode) {
|
|
case noErr: break;
|
|
|
|
case nameSyntaxErr: h_errno = HOST_NOT_FOUND; return(NULL);
|
|
case cacheFault: h_errno = NO_RECOVERY; return(NULL);
|
|
case noResultProc: h_errno = NO_RECOVERY; return(NULL);
|
|
case noNameServer: h_errno = HOST_NOT_FOUND; return(NULL);
|
|
case authNameErr: h_errno = HOST_NOT_FOUND; return(NULL);
|
|
case noAnsErr: h_errno = TRY_AGAIN; return(NULL);
|
|
case dnrErr: h_errno = NO_RECOVERY; return(NULL);
|
|
case outOfMemory: h_errno = TRY_AGAIN; return(NULL);
|
|
default: h_errno = NO_RECOVERY; return(NULL);
|
|
}
|
|
|
|
/* was the 'name' an IP address? */
|
|
if (macHost.cname[0] == 0) {
|
|
h_errno = HOST_NOT_FOUND;
|
|
return(NULL);
|
|
}
|
|
|
|
/* for some reason there is a dot at the end of the name */
|
|
i = int(strlen(macHost.cname)) - 1;
|
|
if (macHost.cname[i] == '.')
|
|
macHost.cname[i] = 0;
|
|
|
|
for (i=0; i<NUM_ALT_ADDRS && macHost.addr[i]!=0; i++)
|
|
addrPtrs[i] = (ip_addr *) &macHost.addr[i];
|
|
|
|
addrPtrs[i] = NULL;
|
|
|
|
return &unixHost;
|
|
}
|
|
|
|
struct hostent * gethostbyaddr(const char *addrP, int, int)
|
|
{
|
|
Boolean done;
|
|
int i;
|
|
|
|
if (INETSockets.Resolver()) {
|
|
h_errno = NO_RECOVERY;
|
|
return NULL;
|
|
}
|
|
|
|
for (i=0; i<NUM_ALT_ADDRS; i++)
|
|
macHost.addr[i] = 0;
|
|
|
|
done = false;
|
|
|
|
ip_addr addr = FIX_LOOPBACK(*(ip_addr *)addrP);
|
|
|
|
if (AddrToName(addr, &macHost, ResultUPP(&uDNRDone), (char *) &done) == cacheFault)
|
|
SPINP(!done,SP_ADDR,0L);
|
|
|
|
switch (macHost.rtnCode) {
|
|
case noErr: break;
|
|
|
|
case cacheFault: h_errno = NO_RECOVERY; return(NULL);
|
|
case noNameServer: h_errno = HOST_NOT_FOUND; return(NULL);
|
|
case authNameErr: h_errno = HOST_NOT_FOUND; return(NULL);
|
|
case noAnsErr: h_errno = TRY_AGAIN; return(NULL);
|
|
case dnrErr: h_errno = NO_RECOVERY; return(NULL);
|
|
case outOfMemory: h_errno = TRY_AGAIN; return(NULL);
|
|
default: h_errno = NO_RECOVERY; return(NULL);
|
|
}
|
|
|
|
/* for some reason there is a dot at the end of the name */
|
|
i = int(strlen(macHost.cname)) - 1;
|
|
if (macHost.cname[i] == '.')
|
|
macHost.cname[i] = 0;
|
|
|
|
/* For some reason, the IP address usually seems to be set to 0 */
|
|
if (!macHost.addr[0])
|
|
macHost.addr[0] = addr;
|
|
|
|
for (i=0; i<NUM_ALT_ADDRS; i++)
|
|
addrPtrs[i] = (ip_addr *) &macHost.addr[i];
|
|
|
|
addrPtrs[NUM_ALT_ADDRS] = NULL;
|
|
|
|
return &unixHost;
|
|
}
|
|
|
|
char * inet_ntoa(struct in_addr inaddr)
|
|
{
|
|
if (INETSockets.Resolver()) {
|
|
h_errno = NO_RECOVERY;
|
|
return NULL;
|
|
}
|
|
|
|
(void) AddrToStr(inaddr.s_addr, macHost.cname);
|
|
|
|
return macHost.cname;
|
|
}
|
|
|
|
struct in_addr inet_addr(char *address)
|
|
{
|
|
if (INETSockets.Resolver()) {
|
|
h_errno = NO_RECOVERY;
|
|
return make_in_addr(0xFFFFFFFF);
|
|
}
|
|
|
|
if (StrToAddr(address,&macHost,NULL,NULL) != noErr)
|
|
return make_in_addr(0xFFFFFFFF);
|
|
|
|
/* was the 'address' really a name? */
|
|
if (macHost.cname[0] != 0)
|
|
return make_in_addr(0xFFFFFFFF);
|
|
|
|
return make_in_addr(macHost.addr[0]);
|
|
}
|
|
|
|
/*
|
|
* gethostid()
|
|
*
|
|
* Get internet address of current host
|
|
*/
|
|
|
|
long gethostid()
|
|
{
|
|
static long sHostID = 0;
|
|
if (sHostID)
|
|
return sHostID;
|
|
|
|
struct GetAddrParamBlock pbr;
|
|
|
|
pbr.ioCRefNum = INETSockets.Driver();
|
|
pbr.csCode = ipctlGetAddr;
|
|
|
|
if (PBControlSync(ParmBlkPtr(&pbr)))
|
|
return 0;
|
|
else
|
|
return sHostID = (long)pbr.ourAddress;
|
|
}
|
|
|
|
/*
|
|
* gethostname()
|
|
*
|
|
* Try to get my host name from DNR. If it fails, just return my
|
|
* IP address as ASCII. This is non-standard, but it's a mac,
|
|
* what do you want me to do?
|
|
*/
|
|
|
|
int gethostname(char *machname, int buflen)
|
|
{
|
|
static char * sHostName = nil;
|
|
|
|
if (!sHostName) {
|
|
in_addr ipaddr;
|
|
struct hostent *hp;
|
|
|
|
ipaddr = make_in_addr(ip_addr(gethostid()));
|
|
|
|
if (!ipaddr.s_addr) // TCP/IP not up at all
|
|
return GUSI_error(ENETDOWN);
|
|
|
|
hp = gethostbyaddr((char *) &ipaddr, sizeof(in_addr), AF_INET);
|
|
|
|
if (!hp) {
|
|
// No good name
|
|
if (buflen < 16) // Not enough space
|
|
return GUSI_error(EINVAL);
|
|
sprintf(machname, "%d.%d.%d.%d",
|
|
ipaddr.s_addr>>24,
|
|
ipaddr.s_addr>>16 & 0xff,
|
|
ipaddr.s_addr>>8 & 0xff,
|
|
ipaddr.s_addr & 0xff);
|
|
return 0;
|
|
} else {
|
|
// We only cache satisfactory replies in sHostName
|
|
sHostName = new char[strlen(hp->h_name)+1];
|
|
strcpy(sHostName, hp->h_name);
|
|
}
|
|
}
|
|
strncpy(machname, sHostName, unsigned(buflen));
|
|
machname[buflen-1] = 0; /* extra safeguard */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* getservbybname()
|
|
*
|
|
*/
|
|
|
|
static char * servlist[] =
|
|
{
|
|
"echo 7/udp",
|
|
"discard 9/udp",
|
|
"time 37/udp",
|
|
"domain 53/udp",
|
|
"sunrpc 111/udp",
|
|
"tftp 69/udp",
|
|
"biff 512/udp",
|
|
"who 513/udp",
|
|
"talk 517/udp",
|
|
"ftp-data 20/tcp",
|
|
"ftp 21/tcp",
|
|
"telnet 23/tcp",
|
|
"smtp 25/tcp",
|
|
"time 37/tcp",
|
|
"whois 43/tcp",
|
|
"domain 53/tcp",
|
|
"hostnames 101/tcp",
|
|
"nntp 119/tcp",
|
|
"finger 79/tcp",
|
|
"ntp 123/tcp",
|
|
"uucp 540/tcp",
|
|
NULL
|
|
};
|
|
|
|
static char servline[128];
|
|
static struct servent serv;
|
|
static FILE * servfil;
|
|
static int servptr;
|
|
static char * servalias[8];
|
|
static int servstay = 0;
|
|
|
|
void setservent(int stayopen)
|
|
{
|
|
if (servfil && servfil != (FILE *) -1) {
|
|
rewind(servfil);
|
|
}
|
|
servptr = 0;
|
|
servstay = servstay || stayopen;
|
|
}
|
|
|
|
void endservent()
|
|
{
|
|
if (servfil && servfil != (FILE *) -1) {
|
|
fclose(servfil);
|
|
servfil = NULL;
|
|
}
|
|
|
|
servstay = 0;
|
|
}
|
|
|
|
struct servent * getservent()
|
|
{
|
|
char * p;
|
|
int aliascount;
|
|
|
|
if (!servfil) {
|
|
TFileSpec serv;
|
|
|
|
if (!FindFolder(
|
|
kOnSystemDisk,
|
|
kPreferencesFolderType,
|
|
kDontCreateFolder,
|
|
&serv.vRefNum,
|
|
&serv.parID)
|
|
) {
|
|
PLstrcpy(serv.name, (StringPtr) "\p/etc/services");
|
|
|
|
if (servfil = fopen(serv.FullPath(), "r"))
|
|
goto retry;
|
|
}
|
|
servfil = (FILE *) -1;
|
|
servptr = 0;
|
|
}
|
|
|
|
retry:
|
|
if (servfil == (FILE *) -1)
|
|
if (!servlist[servptr])
|
|
return (struct servent *) NULL;
|
|
else
|
|
strcpy(servline, servlist[servptr++]);
|
|
else if (!(fgets(servline, 128, servfil)))
|
|
return (struct servent *) NULL;
|
|
|
|
if (p = strpbrk(servline, "#\n\r"))
|
|
*p = 0;
|
|
if (!servline[0])
|
|
goto retry;
|
|
|
|
if (!(serv.s_name = strtok(servline, " \t")))
|
|
goto retry;
|
|
|
|
if (!(p = strtok(NULL, " \t")))
|
|
goto retry;
|
|
|
|
if (!(serv.s_proto = strpbrk(p, "/,")))
|
|
goto retry;
|
|
|
|
*serv.s_proto++ = 0;
|
|
serv.s_port = htons(atoi(p));
|
|
serv.s_aliases = servalias;
|
|
|
|
for (aliascount = 0; aliascount < 7; )
|
|
if (!(servalias[aliascount++] = strtok(NULL, " \t")))
|
|
break;
|
|
|
|
servalias[aliascount] = NULL;
|
|
|
|
return &serv;
|
|
}
|
|
|
|
struct servent * getservbyname(const char * name, const char * proto)
|
|
{
|
|
struct servent * ent;
|
|
char ** al;
|
|
setservent(0);
|
|
|
|
while (ent = getservent()) {
|
|
if (!strcmp(name, ent->s_name))
|
|
goto haveName;
|
|
|
|
for (al = ent->s_aliases; *al; ++al)
|
|
if (!strcmp(name, *al))
|
|
goto haveName;
|
|
|
|
continue;
|
|
haveName:
|
|
if (!proto || !strcmp(proto, ent->s_proto))
|
|
break;
|
|
}
|
|
|
|
if (!servstay)
|
|
endservent();
|
|
|
|
return ent;
|
|
}
|
|
|
|
struct servent * getservbyport(int port, const char * proto)
|
|
{
|
|
struct servent * ent;
|
|
|
|
setservent(0);
|
|
|
|
while (ent = getservent())
|
|
if (port == ent->s_port && (!proto || !strcmp(proto, ent->s_proto)))
|
|
break;
|
|
|
|
if (!servstay)
|
|
endservent();
|
|
|
|
return ent;
|
|
}
|
|
|
|
static char tcp[] = "tcp";
|
|
static char udp[] = "udp";
|
|
#define MAX_PROTOENT 10
|
|
static struct protoent protoents[MAX_PROTOENT];
|
|
static int protoent_count=0;
|
|
|
|
struct protoent * getprotobyname(const char * name)
|
|
{
|
|
struct protoent *pe;
|
|
|
|
pe = &protoents[protoent_count];
|
|
if (strcmp(name, "udp") == 0) {
|
|
pe->p_name = udp;
|
|
pe->p_proto = IPPROTO_UDP;
|
|
} else if (strcmp (name, "tcp") == 0) {
|
|
pe->p_name = tcp;
|
|
pe->p_proto = IPPROTO_TCP;
|
|
} else {
|
|
errno = EPROTONOSUPPORT;
|
|
return NULL;
|
|
}
|
|
pe->p_aliases = aliasPtrs;
|
|
protoent_count = (protoent_count +1) % MAX_PROTOENT;
|
|
return pe;
|
|
}
|
|
|
|
struct protoent * getprotobynumber(int proto)
|
|
{
|
|
struct protoent *pe;
|
|
|
|
pe = &protoents[protoent_count];
|
|
if (proto == IPPROTO_UDP) {
|
|
pe->p_name = udp;
|
|
pe->p_proto = IPPROTO_UDP;
|
|
} else if (proto == IPPROTO_TCP) {
|
|
pe->p_name = tcp;
|
|
pe->p_proto = IPPROTO_TCP;
|
|
} else {
|
|
errno = EPROTONOSUPPORT;
|
|
return NULL;
|
|
}
|
|
pe->p_aliases = aliasPtrs;
|
|
protoent_count = (protoent_count +1) % MAX_PROTOENT;
|
|
return pe;
|
|
}
|
|
|