| /********************************************************************* |
| 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 2000/09/12 20:24:49 jack |
| Moved to Unsupported. |
| |
| 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; |
| } |
| |