1 /*********************************************************************
2 Project : GUSI - Grand Unified Socket Interface
3 File : GUSINetDB.cp - Convert internet names to adresses
4 Author : Matthias Neeracher
6 This file was derived from the socket library by
8 Charlie Reiman <creiman@ncsa.uiuc.edu> and
9 Tom Milligan <milligan@madhaus.utcs.utoronto.ca>
14 Revision 1.1 2000/09/12 20:24:49 jack
17 Revision 1.1 1998/08/18 14:52:38 jack
18 Putting Python-specific GUSI modifications under CVS.
20 Revision 1.3 1994/08/10 00:07:30 neeri
21 Sanitized for universal headers.
23 Revision 1.2 1994/05/01 23:43:31 neeri
24 getservbyname() without /etc/services would fail.
26 Revision 1.1 1994/02/25 02:29:36 neeri
29 Revision 0.5 1993/10/31 00:00:00 neeri
30 Deferred opening of resolver
32 Revision 0.4 1993/07/29 00:00:00 neeri
33 Real getservent code (adapted from Sak Wathanasin)
35 Revision 0.3 1993/01/19 00:00:00 neeri
36 Can't set aliases to NULL.
38 Revision 0.2 1992/11/21 00:00:00 neeri
41 Revision 0.1 1992/09/14 00:00:00 neeri
42 Maybe it works, maybe it doesn't
44 *********************************************************************/
46 #include "GUSIINET_P.h"
48 #include "TFileSpec.h"
50 #include "PLStringFuncs.h"
54 // I disapprove of the way dnr.c is written
55 // This disapproval gets stronger with every version
58 #pragma require_prototypes reset
59 #pragma cplusplus reset
63 #pragma segment GUSIINET
66 static pascal void DNRDone(struct hostInfo *, Boolean * done)
72 RoutineDescriptor uDNRDone =
73 BUILD_ROUTINE_DESCRIPTOR(uppResultProcInfo, DNRDone);
75 #define uDNRDone DNRDone
81 * Gethostbyname and gethostbyaddr each return a pointer to an
82 * object with the following structure describing an Internet
83 * host referenced by name or by address, respectively. This
84 * structure contains the information obtained from the MacTCP
95 * #define h_addr h_addr_list[0]
97 * The members of this structure are:
99 * h_name Official name of the host.
101 * h_aliases A zero terminated array of alternate names for the host.
103 * h_addrtype The type of address being returned; always AF_INET.
105 * h_length The length, in bytes, of the address.
107 * h_addr_list A zero terminated array of network addresses for the host.
109 * Error return status from gethostbyname and gethostbyaddr is
110 * indicated by return of a null pointer. The external integer
111 * h_errno may then be checked to see whether this is a
112 * temporary failure or an invalid or unknown host. The
113 * routine herror can be used to print an error message
114 * describing the failure. If its argument string is non-NULL,
115 * it is printed, followed by a colon and a space. The error
116 * message is printed with a trailing newline.
118 * h_errno can have the following values:
120 * HOST_NOT_FOUND No such host is known.
122 * TRY_AGAIN This is usually a temporary error and
123 * means that the local server did not
124 * receive a response from an authoritative
125 * server. A retry at some later time may
128 * NO_RECOVERY Some unexpected server failure was encountered.
129 * This is a non-recoverable error.
131 * NO_DATA The requested name is valid but does not
132 * have an IP address; this is not a
133 * temporary error. This means that the name
134 * is known to the name server but there is
135 * no address associated with this name.
136 * Another type of request to the name server
137 * using this domain name will result in an
138 * answer; for example, a mail-forwarder may
139 * be registered for this domain.
140 * (NOT GENERATED BY THIS IMPLEMENTATION)
143 static struct hostInfo macHost;
146 static char *aliasPtrs[MAXALIASES+1] = {NULL};
147 static ip_addr *addrPtrs[NUM_ALT_ADDRS+1];
149 static struct hostent unixHost =
158 inline struct in_addr make_in_addr(ip_addr addr)
167 struct hostent * gethostbyname(char *name)
172 if (!strcmp(name, "localhost")) {
175 ipaddr = make_in_addr(ip_addr(gethostid()));
178 return gethostbyaddr((char *) &ipaddr, sizeof(in_addr), AF_INET);
180 h_errno = HOST_NOT_FOUND;
185 if (INETSockets.Resolver()) {
186 h_errno = NO_RECOVERY;
190 for (i=0; i<NUM_ALT_ADDRS; i++)
195 if (StrToAddr(name, &macHost, ResultUPP(&uDNRDone), (char *) &done) == cacheFault)
196 SPINP(!done,SP_NAME,0L);
198 switch (macHost.rtnCode) {
201 case nameSyntaxErr: h_errno = HOST_NOT_FOUND; return(NULL);
202 case cacheFault: h_errno = NO_RECOVERY; return(NULL);
203 case noResultProc: h_errno = NO_RECOVERY; return(NULL);
204 case noNameServer: h_errno = HOST_NOT_FOUND; return(NULL);
205 case authNameErr: h_errno = HOST_NOT_FOUND; return(NULL);
206 case noAnsErr: h_errno = TRY_AGAIN; return(NULL);
207 case dnrErr: h_errno = NO_RECOVERY; return(NULL);
208 case outOfMemory: h_errno = TRY_AGAIN; return(NULL);
209 default: h_errno = NO_RECOVERY; return(NULL);
212 /* was the 'name' an IP address? */
213 if (macHost.cname[0] == 0) {
214 h_errno = HOST_NOT_FOUND;
218 /* for some reason there is a dot at the end of the name */
219 i = int(strlen(macHost.cname)) - 1;
220 if (macHost.cname[i] == '.')
221 macHost.cname[i] = 0;
223 for (i=0; i<NUM_ALT_ADDRS && macHost.addr[i]!=0; i++)
224 addrPtrs[i] = (ip_addr *) &macHost.addr[i];
231 struct hostent * gethostbyaddr(const char *addrP, int, int)
236 if (INETSockets.Resolver()) {
237 h_errno = NO_RECOVERY;
241 for (i=0; i<NUM_ALT_ADDRS; i++)
246 ip_addr addr = FIX_LOOPBACK(*(ip_addr *)addrP);
248 if (AddrToName(addr, &macHost, ResultUPP(&uDNRDone), (char *) &done) == cacheFault)
249 SPINP(!done,SP_ADDR,0L);
251 switch (macHost.rtnCode) {
254 case cacheFault: h_errno = NO_RECOVERY; return(NULL);
255 case noNameServer: h_errno = HOST_NOT_FOUND; return(NULL);
256 case authNameErr: h_errno = HOST_NOT_FOUND; return(NULL);
257 case noAnsErr: h_errno = TRY_AGAIN; return(NULL);
258 case dnrErr: h_errno = NO_RECOVERY; return(NULL);
259 case outOfMemory: h_errno = TRY_AGAIN; return(NULL);
260 default: h_errno = NO_RECOVERY; return(NULL);
263 /* for some reason there is a dot at the end of the name */
264 i = int(strlen(macHost.cname)) - 1;
265 if (macHost.cname[i] == '.')
266 macHost.cname[i] = 0;
268 /* For some reason, the IP address usually seems to be set to 0 */
269 if (!macHost.addr[0])
270 macHost.addr[0] = addr;
272 for (i=0; i<NUM_ALT_ADDRS; i++)
273 addrPtrs[i] = (ip_addr *) &macHost.addr[i];
275 addrPtrs[NUM_ALT_ADDRS] = NULL;
280 char * inet_ntoa(struct in_addr inaddr)
282 if (INETSockets.Resolver()) {
283 h_errno = NO_RECOVERY;
287 (void) AddrToStr(inaddr.s_addr, macHost.cname);
289 return macHost.cname;
292 struct in_addr inet_addr(char *address)
294 if (INETSockets.Resolver()) {
295 h_errno = NO_RECOVERY;
296 return make_in_addr(0xFFFFFFFF);
299 if (StrToAddr(address,&macHost,NULL,NULL) != noErr)
300 return make_in_addr(0xFFFFFFFF);
302 /* was the 'address' really a name? */
303 if (macHost.cname[0] != 0)
304 return make_in_addr(0xFFFFFFFF);
306 return make_in_addr(macHost.addr[0]);
312 * Get internet address of current host
317 static long sHostID = 0;
321 struct GetAddrParamBlock pbr;
323 pbr.ioCRefNum = INETSockets.Driver();
324 pbr.csCode = ipctlGetAddr;
326 if (PBControlSync(ParmBlkPtr(&pbr)))
329 return sHostID = (long)pbr.ourAddress;
335 * Try to get my host name from DNR. If it fails, just return my
336 * IP address as ASCII. This is non-standard, but it's a mac,
337 * what do you want me to do?
340 int gethostname(char *machname, int buflen)
342 static char * sHostName = nil;
348 ipaddr = make_in_addr(ip_addr(gethostid()));
350 if (!ipaddr.s_addr) // TCP/IP not up at all
351 return GUSI_error(ENETDOWN);
353 hp = gethostbyaddr((char *) &ipaddr, sizeof(in_addr), AF_INET);
357 if (buflen < 16) // Not enough space
358 return GUSI_error(EINVAL);
359 sprintf(machname, "%d.%d.%d.%d",
361 ipaddr.s_addr>>16 & 0xff,
362 ipaddr.s_addr>>8 & 0xff,
363 ipaddr.s_addr & 0xff);
366 // We only cache satisfactory replies in sHostName
367 sHostName = new char[strlen(hp->h_name)+1];
368 strcpy(sHostName, hp->h_name);
371 strncpy(machname, sHostName, unsigned(buflen));
372 machname[buflen-1] = 0; /* extra safeguard */
383 static char * servlist[] =
409 static char servline[128];
410 static struct servent serv;
411 static FILE * servfil;
413 static char * servalias[8];
414 static int servstay = 0;
416 void setservent(int stayopen)
418 if (servfil && servfil != (FILE *) -1) {
422 servstay = servstay || stayopen;
427 if (servfil && servfil != (FILE *) -1) {
435 struct servent * getservent()
445 kPreferencesFolderType,
450 PLstrcpy(serv.name, (StringPtr) "\p/etc/services");
452 if (servfil = fopen(serv.FullPath(), "r"))
455 servfil = (FILE *) -1;
460 if (servfil == (FILE *) -1)
461 if (!servlist[servptr])
462 return (struct servent *) NULL;
464 strcpy(servline, servlist[servptr++]);
465 else if (!(fgets(servline, 128, servfil)))
466 return (struct servent *) NULL;
468 if (p = strpbrk(servline, "#\n\r"))
473 if (!(serv.s_name = strtok(servline, " \t")))
476 if (!(p = strtok(NULL, " \t")))
479 if (!(serv.s_proto = strpbrk(p, "/,")))
483 serv.s_port = htons(atoi(p));
484 serv.s_aliases = servalias;
486 for (aliascount = 0; aliascount < 7; )
487 if (!(servalias[aliascount++] = strtok(NULL, " \t")))
490 servalias[aliascount] = NULL;
495 struct servent * getservbyname(const char * name, const char * proto)
497 struct servent * ent;
501 while (ent = getservent()) {
502 if (!strcmp(name, ent->s_name))
505 for (al = ent->s_aliases; *al; ++al)
506 if (!strcmp(name, *al))
511 if (!proto || !strcmp(proto, ent->s_proto))
521 struct servent * getservbyport(int port, const char * proto)
523 struct servent * ent;
527 while (ent = getservent())
528 if (port == ent->s_port && (!proto || !strcmp(proto, ent->s_proto)))
537 static char tcp[] = "tcp";
538 static char udp[] = "udp";
539 #define MAX_PROTOENT 10
540 static struct protoent protoents[MAX_PROTOENT];
541 static int protoent_count=0;
543 struct protoent * getprotobyname(const char * name)
547 pe = &protoents[protoent_count];
548 if (strcmp(name, "udp") == 0) {
550 pe->p_proto = IPPROTO_UDP;
551 } else if (strcmp (name, "tcp") == 0) {
553 pe->p_proto = IPPROTO_TCP;
555 errno = EPROTONOSUPPORT;
558 pe->p_aliases = aliasPtrs;
559 protoent_count = (protoent_count +1) % MAX_PROTOENT;
563 struct protoent * getprotobynumber(int proto)
567 pe = &protoents[protoent_count];
568 if (proto == IPPROTO_UDP) {
570 pe->p_proto = IPPROTO_UDP;
571 } else if (proto == IPPROTO_TCP) {
573 pe->p_proto = IPPROTO_TCP;
575 errno = EPROTONOSUPPORT;
578 pe->p_aliases = aliasPtrs;
579 protoent_count = (protoent_count +1) % MAX_PROTOENT;