1 /*
2 * BSD-style socket emulation library for the Mac
3 * Original author: Tom Milligan
4 * Current author: Charlie Reiman - creiman@ncsa.uiuc.edu
5 *
6 * This source file is placed in the public domian.
7 * Any resemblance to NCSA Telnet, living or dead, is purely coincidental.
8 *
9 * National Center for Supercomputing Applications
10 * 152 Computing Applications Building
11 * 605 E. Springfield Ave.
12 * Champaign, IL 61820
13 *
14 *
15 * RCS Modification History:
16 * $Log: OTnetdb.c,v $
17 * Revision 1.4 2006/11/27 20:21:26 kans
18 * replaced netdb.h with carbon_netdb.h
19 *
20 * Revision 1.3 2001/11/07 22:45:02 juran
21 * Phil Churchill's 2001-05-07 changes.
22 * Remove debugging.
23 * Use Idle().
24 *
25 * Revision 1.2 ?? juran
26 * Minor edits.
27 *
28 * Revision 1.1 2001/04/03 20:35:27 juran
29 * Phil Churchill's MIT-derived OT sockets library. No changes prior to initial check-in.
30 *
31 * Revision 6.1 2000/03/20 21:50:35 kans
32 * initial checkin - initial work on OpenTransport (Churchill)
33 *
34 * Revision 6.1 1999/11/17 20:52:50 kans
35 * changes to allow compilation under c++
36 *
37 * Revision 6.0 1997/08/25 18:37:31 madden
38 * Revision changed to 6.0
39 *
40 * Revision 4.1 1995/08/01 16:17:20 kans
41 * New gethostbyname and gethostbyaddr contributed by Doug Corarito
42 *
43 * Revision 4.0 1995/07/26 13:56:09 ostell
44 * force revision to 4.0
45 *
46 * Revision 1.3 1995/05/17 17:56:47 epstein
47 * add RCS log revision history
48 *
49 */
50
51 /*
52 * Internet name routines that every good unix program uses...
53 *
54 * gethostbyname
55 * gethostbyaddr
56 * gethostid
57 * gethostname
58 * getdomainname
59 * inet_ntoa
60 * inet_addr
61 */
62
63 #include <stdio.h>
64 #include <stdlib.h> // malloc
65 #include <string.h>
66
67 #include <MacTypes.h>
68 #include <Resources.h>
69 #include <Errors.h>
70 #include <OSUtils.h>
71 #include <OpenTransport.h>
72 #include <OpenTptInternet.h> // for TCP/IP
73
74 #include <carbon_netdb.h>
75 #include <neterrno.h>
76 #include "SocketsInternal.h"
77 #include "a_inet.h"
78
79 /* global variables...
80 */
81 static int h_errno;
82 static short driver = 0;
83 static Boolean gOTInited = false;
84 EndpointRef gDNRep = kOTInvalidEndpointRef;
85 OTNotifyUPP gDNRYieldNotifyUPP = NULL;
86
87
88 /* DNR notifier process
89 *
90 * This function receives any notifications from the OT DNR routines.
91 *
92 * Typically this is used to permit other threads to run while a time
93 * consuming process runs, but it can be used to notify of certain failures.
94 *
95 * You have the ability to handle user abort requests via the Idle() function...
96 */
97
DNRYieldNotifier(void * contextPtr,OTEventCode code,OTResult result,void * cookie)98 static pascal void DNRYieldNotifier( void* contextPtr, OTEventCode code,
99 OTResult result, void* cookie)
100 {
101 #pragma unused(contextPtr)
102 #pragma unused(result)
103 #pragma unused(cookie)
104 OSStatus status;
105
106 switch (code) {
107 case kOTSyncIdleEvent:
108 status = Idle();
109 break;
110 case kOTProviderWillClose: // if the dnr service is going away
111 case kOTProviderIsClosed: // or already gone...
112 (void) OTCloseProvider(gDNRep); // then close our provider
113 gDNRep = kOTInvalidProviderRef; // and note that.
114 break;
115 default:
116 /* do nothing */
117 break;
118 }
119 }
120
121
122 /* ot_OpenDriver
123 *
124 * Performs required initializations needed before OT can be used
125 */
126
ot_OpenDriver(void)127 OSStatus ot_OpenDriver( void)
128 {
129 OSStatus err;
130 int i;
131
132 // if this function has already been performed, then just return
133 if( gOTInited){
134 return( kOTNoError);
135 }
136
137 // Set up the global array of socket pointers and clear it
138 if( gSockets == NULL)
139 gSockets = (SocketPtr *) malloc(kNumSockets * sizeof(SocketPtr));
140
141 if( gSockets == NULL)
142 return(memFullErr);
143
144 for( i = 0; i < kNumSockets; i++)
145 gSockets[i] = NULL;
146
147 #if TARGET_API_MAC_CARBON
148 err = InitOpenTransportInContext(kInitOTForApplicationMask, NULL);
149 #else
150 err = InitOpenTransport();
151 #endif
152
153 gOTInited = (kOTNoError == err);
154
155 return( err);
156 }
157
158
159 /* ot_DNRInit
160 *
161 * Function which initializes the domain name resolver for OpenTransport
162 * for use by gethostbyname, gethostbyaddress, and other utils
163 */
164
ot_DNRInit(void)165 OSStatus ot_DNRInit(void)
166 {
167 OSStatus theError = kOTNoError;
168
169 // First, check to see if we've already initialized. If so, then just return...
170 if( gDNRep != kOTInvalidProviderRef){
171 return (kOTNoError);
172 }
173
174 // Next, check to see if any OT service has been used yet
175 if (!gOTInited){
176 theError = ot_OpenDriver();
177 }
178
179 // Get the internet services reference for DNS
180 if( theError == kOTNoError){
181 #if TARGET_API_MAC_CARBON
182 gDNRep = OTOpenInternetServicesInContext( kDefaultInternetServicesPath, 0, &theError, NULL);
183 #else
184 gDNRep = OTOpenInternetServices( kDefaultInternetServicesPath, 0, &theError);
185 #endif
186 }
187
188 /* We have to choose to be synchronous or async, sync is simpler but
189 * I think that async could be done in the future
190 */
191 if( theError == kOTNoError){
192 theError = OTSetSynchronous( gDNRep);
193 }
194
195 // Give OT a pointer to a notifier function that handles async events
196 if( theError == kOTNoError){
197 gDNRYieldNotifyUPP = NewOTNotifyUPP(DNRYieldNotifier);
198 theError = OTInstallNotifier(gDNRep, gDNRYieldNotifyUPP, nil);
199 }
200
201 /* If we get idle events, then implementing a multi-threaded app shouldn't
202 * be any big deal
203 */
204 if( theError == kOTNoError){
205 theError = OTUseSyncIdleEvents(gDNRep, true);
206 }
207 return( theError);
208 }
209
210
211 /* ot_DNRClose
212 *
213 * If OT ever needs any formal closing/cleanup actions, this is the place
214 * to put it...
215 */
216
ot_DNRClose(InetSvcRef theRef)217 OSStatus ot_DNRClose( InetSvcRef theRef)
218 {
219 OSStatus theErr = kOTNoError;
220
221 return theErr;
222 }
223
224
225 /*
226 * Gethostbyname and gethostbyaddr each return a pointer to an
227 * object with the following structure describing an Internet
228 * host referenced by name or by address, respectively. This
229 * structure contains the information obtained from the OpenTransport
230 * name server.
231 *
232 * struct hostent
233 * {
234 * char *h_name;
235 * char **h_aliases;
236 * int h_addrtype;
237 * int h_length;
238 * char **h_addr_list;
239 * };
240 * #define h_addr h_addr_list[0]
241 *
242 * The members of this structure are:
243 *
244 * h_name Official name of the host.
245 *
246 * h_aliases A zero terminated array of alternate names for the host.
247 *
248 * h_addrtype The type of address being returned; always AF_INET.
249 *
250 * h_length The length, in bytes, of the address.
251 *
252 * h_addr_list A zero terminated array of network addresses for the host.
253 *
254 * Error return status from gethostbyname and gethostbyaddr is
255 * indicated by return of a null pointer. The external integer
256 * h_errno may then be checked to see whether this is a
257 * temporary failure or an invalid or unknown host. The
258 * routine herror can be used to print an error message
259 * describing the failure. If its argument string is non-NULL,
260 * it is printed, followed by a colon and a space. The error
261 * message is printed with a trailing newline.
262 *
263 * h_errno can have the following values:
264 *
265 * HOST_NOT_FOUND No such host is known.
266 *
267 * TRY_AGAIN This is usually a temporary error and
268 * means that the local server did not
269 * receive a response from an authoritative
270 * server. A retry at some later time may
271 * succeed.
272 *
273 * NO_RECOVERY Some unexpected server failure was encountered.
274 * This is a non-recoverable error.
275 *
276 * NO_DATA The requested name is valid but does not
277 * have an IP address; this is not a
278 * temporary error. This means that the name
279 * is known to the name server but there is
280 * no address associated with this name.
281 * Another type of request to the name server
282 * using this domain name will result in an
283 * answer; for example, a mail-forwarder may
284 * be registered for this domain.
285 * (NOT GENERATED BY THIS IMPLEMENTATION)
286 */
287
288 static char cname[255];
289 static struct InetHostInfo hinfo;
290
291 #define MAXALIASES 2
292 static char aliases[MAXALIASES+1][kMaxHostNameLen + 1];
293 static char* aliasPtrs[MAXALIASES+1] = {NULL};
294 static InetHost* addrPtrs[kMaxHostAddrs+1] = {0};
295
296
297 static struct hostent unixHost =
298 {
299 cname,
300 aliasPtrs,
301 AF_INET,
302 sizeof(UInt32),
303 (char **) addrPtrs
304 };
305
306
307 /* Gethostbyname
308 *
309 * UNIX function implemented on top of OpenTransport
310 */
311
312 struct hostent *
gethostbyname(const char * name)313 gethostbyname(const char *name)
314 {
315 extern EndpointRef gDNRep;
316 OSStatus theErr;
317 int i, l;
318
319 // open or get the current resolver reference
320 if( gDNRep == kOTInvalidEndpointRef){
321 theErr = ot_DNRInit();
322 if( theErr != kOTNoError){
323 ncbi_SetOTErrno( theErr);
324 return (NULL);
325 }
326 }
327
328 // Call OT to resolve the address...
329 theErr = OTInetStringToAddress( gDNRep, (char*) name, &hinfo);
330
331 if( theErr != kOTNoError){
332 ncbi_SetOTErrno( theErr);
333 return( NULL);
334 }
335
336 // sometimes the hostname returned has a trailing dot?? (nuke it)
337 l = strlen( hinfo.name);
338 if( hinfo.name[l-1] == '.'){
339 hinfo.name[l-1] = '\0';
340 }
341
342 #if NETDB_DEBUG >= 5
343 printf("gethostbyname: name '%s' returned the following addresses:\n", name);
344 for( i = 0; i < kMaxHostAddrs; i++){
345 if( hinfo.addrs[i] == 0) break;
346 printf("%08x\n", hinfo.addrs[i]);
347 }
348 #endif
349
350 // copy the official hostname to the return struct and first alias
351 strcpy( unixHost.h_name, hinfo.name);
352
353 // copy the name passed in as the first alias
354 strncpy( aliases[0], name, kMaxHostNameLen);
355 aliases[0][kMaxHostNameLen] = '\0';
356
357 // if the answer is different from the query, copy the query as another alias
358 theErr = strcmp( name, hinfo.name);
359 if( theErr != 0){
360 strncpy( aliases[1], hinfo.name, kMaxHostNameLen);
361 aliases[1][kMaxHostNameLen] = '\0';
362 }
363
364 // This block will not need to be changed if we find a way to determine
365 // more aliases than are currently implemented
366 for( i = 0; i <= MAXALIASES; i++){
367 if( aliases[i][0] != '\0'){
368 aliasPtrs[i] = &aliases[i][0];
369 } else{
370 aliasPtrs[i] = NULL;
371 }
372 }
373
374 // copy all of the returned addresses
375 for( i = 0; i < kMaxHostAddrs && hinfo.addrs[i] != 0; i++){
376 addrPtrs[i] = &hinfo.addrs[i];
377 }
378
379 // make the rest NULL
380 for( ; i < kMaxHostAddrs; i++){
381 addrPtrs[i] = NULL;
382 }
383 return( &unixHost);
384 }
385
386
387 /* gethostbyaddr
388 *
389 * Currently only supports IPv4
390 */
391
392 struct hostent *
gethostbyaddr(InetHost * addrP,int len,int type)393 gethostbyaddr( InetHost *addrP, int len, int type)
394 {
395 extern EndpointRef gDNRep;
396 OSStatus theErr = noErr;
397 char addrString[255];
398 int l;
399
400 // Check that the arguments are appropriate
401 if( len != INADDRSZ || (type != AF_INET /* && type != AF_UNSPEC */)){
402 ncbi_SetErrno( EAFNOSUPPORT);
403 return( NULL);
404 }
405
406 // open or get the current resolver reference
407 if( gDNRep == kOTInvalidEndpointRef){
408 theErr = ot_DNRInit();
409 if( theErr != kOTNoError){
410 ncbi_SetErrno( theErr);
411 return (NULL);
412 }
413 }
414
415 #if NETDB_DEBUG >= 5
416 printf("gethostbyaddr: Looking up hostname for address 0x%8x\n", *addrP);
417 #endif
418
419 /* OpenTransport call to get the address as a string */
420 theErr = OTInetAddressToName( gDNRep, *(InetHost*)addrP, addrString);
421 if( theErr == noErr){
422 // for some reason the names have a trailing "."???
423 // Next couple of lines remove it
424 l = strlen( addrString);
425 if( addrString[l-1] == '.'){
426 addrString[l-1] = '\0';
427 }
428 // with the full name, use gethostbyname to fill in all the blanks...
429 return (gethostbyname(addrString) );
430 }
431 else{
432 ncbi_SetErrno( theErr);
433 }
434 return( NULL);
435 }
436
437 /*
438 * gethostid()
439 *
440 * Get Internet address from the primary enet interface.
441 */
442
gethostid(void)443 unsigned long gethostid( void)
444 {
445 OSStatus theErr = kOTNoError;
446 InetInterfaceInfo info;
447 extern EndpointRef gDNRep;
448
449 // open or get the current resolver reference
450 if( gDNRep == kOTInvalidEndpointRef){
451 theErr = ot_DNRInit();
452 if( theErr != kOTNoError){
453 ncbi_SetErrno( theErr);
454 return 0;
455 }
456 }
457 theErr = OTInetGetInterfaceInfo( &info, kDefaultInetInterface);
458 if(theErr != kOTNoError){
459 ncbi_SetErrno( theErr);
460 return 0;
461 }
462 return info.fAddress;
463 }
464
465
466 /*
467 * gethostname()
468 *
469 * Try to get my host name from DNR. If it fails, just return my
470 * IP address as ASCII. This is non-standard, but since Mac's don't require
471 * hostnames to run, we don't have many other options.
472 */
473
gethostname(char * machname,size_t buflen)474 int gethostname( char* machname, size_t buflen)
475 {
476 OSStatus theErr = kOTNoError;
477 InetHost addr;
478 struct hostent *host;
479 char* firstDot;
480
481 if( (machname == NULL) || (buflen < 31)){
482 ncbi_SetErrno( EINVAL);
483 return( -1);
484 }
485
486 addr = gethostid();
487
488 host = gethostbyaddr( &addr, INADDRSZ, AF_INET);
489 if(host == NULL){
490 ncbi_SetErrno( EINVAL);
491 return( -1);
492 }
493
494 firstDot = strchr(host->h_name, '.');
495 if(firstDot != NULL && *firstDot == '.'){
496 *firstDot = '\0';
497 }
498
499 strncpy( machname, host->h_name, buflen);
500 machname[buflen-1] = '\0'; // strncpy doesn't always null terminate
501
502 if(theErr != kOTNoError)
503 return(-1);
504 else
505 return(0);
506 }
507
508 /* inet_ntoa()
509 *
510 * Converts an IP address in 32 bit IPv4 address to a dotted string notation
511 * Function returns a pointer to the resulting string (success), or NULL (failure).
512 */
513
inet_ntoa(struct in_addr addr)514 char *inet_ntoa( struct in_addr addr)
515 {
516 static char addrString[INET_ADDRSTRLEN + 1 /* '\0' */];
517
518 OTInetHostToString( addr.s_addr, addrString);
519
520 return (addrString);
521 }
522
523 /*
524 * inet_aton() - converts an IP address in dotted string notation to a 32 bit IPv4 address
525 * Function returns 1 on success and 0 on failure.
526 */
inet_aton(const char * str,struct in_addr * addr)527 int inet_aton(const char *str, struct in_addr *addr)
528 {
529 InetHost host;
530 OSStatus theError;
531
532 if((str == NULL) || (addr == NULL)){
533 return( INET_FAILURE);
534 }
535
536 theError = OTInetStringToHost((char *) str, &host);
537 if(theError != kOTNoError){
538 ncbi_SetErrno( theError);
539 return( INET_FAILURE);
540 }
541 addr->s_addr = host;
542 return(INET_SUCCESS);
543 }
544
545
546 /* inet_addr
547 *
548 * Does much the same thing as inet_aton, but returns the value rather than
549 * modifying a parameter that's passed in.
550 * Note: failure is reported by returning INADDR_NONE (255.255.255.255)
551 */
552
inet_addr(const char * str)553 InetHost inet_addr(const char *str)
554 {
555 OSStatus theError = kOTNoError;
556 struct in_addr addr;
557
558 theError = inet_aton(str, &addr);
559
560 if(theError != INET_SUCCESS){
561 addr.s_addr = INADDR_NONE;
562 }
563
564 return(addr.s_addr);
565 }
566
567
568 /* One last unix compatibility function that was included
569 * in the ncsa socket lib...
570 */
bzero(char * b,long s)571 void bzero( char *b, long s)
572 {
573 for( ; s ; ++b, --s)
574 *b = 0;
575 }
576
577
578 /* Error reporting strings and functions
579 */
580
581 char* h_errlist[] = {
582 "Error 0",
583 "Unknown host", /* 1 HOST_NOT_FOUND */
584 "Host name lookup failure", /* 2 TRY_AGAIN */
585 "Unknown server error", /* 3 NO_RECOVERY */
586 "No address associated with name", /* 4 NO_ADDRESS */
587 };
588
589 // compute the number of elements in the list (one less place for human error)
590 const int h_nerr = { sizeof(h_errlist)/sizeof(h_errlist[0]) };
591
herror(char * s)592 void herror(char *s)
593 {
594 fprintf(stderr,"%s: ",s);
595 if (h_errno < h_nerr)
596 fprintf(stderr,h_errlist[h_errno]);
597 else
598 fprintf(stderr,"error %d",h_errno);
599 fprintf(stderr,"\n");
600 }
601
herror_str(int theErr)602 char *herror_str(int theErr)
603 {
604 if (theErr > h_nerr )
605 return NULL;
606 else
607 return h_errlist[theErr];
608 }
609
610 // end of file
611