/* 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 */ #ifdef WIN32 #include #else #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 : [[[[self class] alloc] _initWithHostEntry:entry name:name] autorelease]; } - _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 = [[NSMutableArray array] retain]; addresses = [[NSMutableArray array] retain]; [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 { [names autorelease]; [addresses autorelease]; [super dealloc]; } @end