/* Implementation of host class Copyright (C) 1996, 1997 Free Software Foundation, Inc. Written by: Luke Howard Date: 1996 This file is part of the GNUstep Base Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include /* #include */ #if defined(__WIN32__) && !defined(__CYGWIN__) #include #else #include #include #include #include #include #endif /* __WIN32__ */ static NSLock *_hostCacheLock = nil; static BOOL _hostCacheEnabled = NO; static NSMutableDictionary *_hostCache = nil; @interface NSHost (Private) + (NSHost *)_hostWithHostEntry: (struct hostent *)entry; + (NSHost *)_hostWithHostEntry: (struct hostent *)entry name: name; - _initWithHostEntry: (struct hostent *)entry name: name; @end @implementation NSHost (Private) + (NSHost *)_hostWithHostEntry: (struct hostent *)entry { if (!entry) return nil; return [[self class] _hostWithHostEntry: entry name: [NSString stringWithCString: entry->h_name]]; } + (NSHost *)_hostWithHostEntry: (struct hostent *)entry name: name { NSHost *res = nil; [_hostCacheLock lock]; if (_hostCacheEnabled == YES) { res = [_hostCache objectForKey: name]; } [_hostCacheLock unlock]; return (res != nil) ? res : AUTORELEASE([[[self class] alloc] _initWithHostEntry: entry name: name]); } - _initWithHostEntry: (struct hostent *)entry name: name { int i; char *ptr; struct in_addr in; NSString *h_name; [super init]; if (entry == (struct hostent *)NULL) { return nil; } names = RETAIN([NSMutableArray array]); addresses = RETAIN([NSMutableArray array]); [names addObject: name]; h_name = [NSString stringWithCString: entry->h_name]; if (![h_name isEqual: name]) { [names addObject: h_name]; } for (i = 0, ptr = entry->h_aliases[0]; ptr != NULL; i++, ptr = entry->h_aliases[i]) { [names addObject: [NSString stringWithCString: ptr]]; } for (i = 0, ptr = entry->h_addr_list[0]; ptr != NULL; i++, ptr = entry->h_addr_list[i]) { memcpy((void *)&in.s_addr, (const void *)ptr, entry->h_length); [addresses addObject: [NSString stringWithCString: (char*)inet_ntoa(in)]]; } [_hostCacheLock lock]; if (_hostCacheEnabled == YES) { [_hostCache setObject: self forKey: name]; } [_hostCacheLock unlock]; return self; } @end @implementation NSHost - init { return nil; } + (void)initialize { _hostCacheLock = [[NSConditionLock alloc] init]; _hostCache = [NSMutableDictionary new]; } + (NSHost *)currentHost { char name[MAXHOSTNAMELEN]; int res; struct hostent *h; res = gethostname(name, sizeof(name)); if (res < 0) { return nil; } h = gethostbyname(name); if (h == NULL) { NSLog(@"Unable to determine current host"); return nil; } return [self _hostWithHostEntry: h name: [NSString stringWithCString: name]]; } + (NSHost *)hostWithName: (NSString *)name { struct hostent *h; if (name == nil) { NSLog(@"Nil host name sent to +[NSHost hostWithName]"); return nil; } h = gethostbyname((char *)[name cString]); return [self _hostWithHostEntry: h name: name]; } + (NSHost *)hostWithAddress: (NSString *)address { struct hostent *h; struct in_addr hostaddr; if (address == nil) { NSLog(@"Nil address sent to +[NSHost hostWithAddress]"); return nil; } hostaddr.s_addr = inet_addr((char *)[address cString]); if (hostaddr.s_addr == -1) { return nil; } h = gethostbyaddr((char *)&hostaddr, sizeof(hostaddr), AF_INET); return [self _hostWithHostEntry: h]; } + (void)setHostCacheEnabled: (BOOL)flag { [_hostCacheLock lock]; _hostCacheEnabled = flag; [_hostCacheLock unlock]; } + (BOOL)isHostCacheEnabled; { BOOL res; [_hostCacheLock lock]; res = _hostCacheEnabled; [_hostCacheLock unlock]; return res; } + (void)flushHostCache { [_hostCacheLock lock]; [_hostCache removeAllObjects]; [_hostCacheLock unlock]; } /* Methods for encoding/decoding */ - (Class) classForPortCoder { return [self class]; } - replacementObjectForPortCoder: (NSPortCoder*)aCoder { return self; } - (void) encodeWithCoder: (NSCoder*)aCoder { [super encodeWithCoder: aCoder]; [aCoder encodeObject: [self address]]; } #if 1 /* GNUstep specific method for more efficient decoding. */ + (id) newWithCoder: (NSCoder*)aCoder { NSString *address = [aCoder decodeObject]; return [NSHost hostWithAddress: address]; } #else /* OpenStep methods for decoding (not used) */ - (id) awakeAfterUsingCoder: (NSCoder*)aCoder { return [NSHost hostWithAddress: [addresses objectAtIndex: 0]]; } - (id) initWithCoder: (NSCoder*)aCoder { NSString *address; [super initWithCoder: aCoder]; address = [aCoder decodeObject]; addresses = [NSArray arrayWithObject: address]; return self; } #endif /* * The OpenStep spec says that [-hash] must be the same for any two * objects that [-isEqual: ] returns YES for. We have a problem in * that [-isEqualToHost: ] is specified to return YES if any name or * address part of two hosts is the same. That means we can't * reasonably calculate a hash since two hosts with radically * different ivar contents may be 'equal'. The best I can think of * is for all hosts to hash to the same value - which makes it very * inefficient to store them in a set, dictionary, map or hash table. */ - (unsigned) hash { return 1; } - (BOOL) isEqual: (id)other { if (other == self) return YES; if ([other isKindOfClass: [NSHost class]]) return [self isEqualToHost: (NSHost*)other]; return NO; } - (BOOL)isEqualToHost: (NSHost *)aHost { NSArray* a; int i; if (aHost == self) return YES; a = [aHost addresses]; for (i = 0; i < [a count]; i++) if ([addresses containsObject: [a objectAtIndex: i]]) return YES; a = [aHost names]; for (i = 0; i < [a count]; i++) if ([addresses containsObject: [a objectAtIndex: i]]) return YES; return NO; } - (NSString *)name { return [names objectAtIndex: 0]; } - (NSArray *)names { return names; } - (NSString *)address { return [addresses objectAtIndex: 0]; } - (NSArray *)addresses { return addresses; } - (NSString *)description { return [NSString stringWithFormat: @"Host %@ (%@ %@)", [self name], [[self names] description], [[self addresses] description]]; } - (void) dealloc { RELEASE(names); RELEASE(addresses); [super dealloc]; } @end