diff --git a/ChangeLog b/ChangeLog index 31f0746b9..26c9d699a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +Fri Oct 30 09:00:00 1998 Richard Frith-Macdonald + + * src/include/NSPortNameServer.h: Added ([-removePort:]) method in a + GNUstep catagory so that ports can unregister all their names at one + go. Added maps of names and ports to keep track. + * src/include/Port.h: removed [-invalidate] - inherit from NSPort + * src/Port.m: removed [-invalidate] - inherit from NSPort + * src/NSPort.m: made [-invalidate] method remove all the ports names + from the name server and send the invalidation notification. + * src/NSPortNameServer.m: Keep track of name/port mappings and, the + first time a name is registered for a port, tell gdomap to remove + any pre-existing names for that port (left around from a crashed + server perhaps). + Thu Oct 29 13:30:00 1998 Richard Frith-Macdonald * src/UnixFileHandle.m: Improved handling of error conditions on diff --git a/Headers/gnustep/base/NSPort.h b/Headers/gnustep/base/NSPort.h index f71d16992..4fa645fe2 100644 --- a/Headers/gnustep/base/NSPort.h +++ b/Headers/gnustep/base/NSPort.h @@ -26,6 +26,8 @@ #include +@class NSMutableSet; + extern NSString *NSPortTimeoutException; /* OPENSTEP */ @interface NSPort : NSObject @@ -55,6 +57,7 @@ extern NSString *NSPortTimeoutException; /* OPENSTEP */ + (Class) outPacketClass; - (Class) outPacketClass; + @end extern NSString* NSPortDidBecomeInvalidNotification; diff --git a/Headers/gnustep/base/NSPortNameServer.h b/Headers/gnustep/base/NSPortNameServer.h index 86027a35d..22d64f74e 100644 --- a/Headers/gnustep/base/NSPortNameServer.h +++ b/Headers/gnustep/base/NSPortNameServer.h @@ -33,6 +33,8 @@ NSFileHandle *handle; /* File handle to talk to gdomap. */ NSMutableData *data; /* Where to accumulated incoming data. */ unsigned expecting; /* Length of data we want. */ + NSMapTable *portMap; /* Registered ports information. */ + NSMapTable *nameMap; /* Registered names information. */ } + (id) defaultPortNameServer; - (NSPort*) portForName: (NSString*)name; @@ -43,5 +45,9 @@ - (void) removePortForName: (NSString*)name; @end +@interface NSPortNameServer (GNUstep) +- (void) removePort: (NSPort*)port; /* remove all names for port */ +@end + #endif diff --git a/Headers/gnustep/base/Port.h b/Headers/gnustep/base/Port.h index 2b51fc120..e89f41459 100644 --- a/Headers/gnustep/base/Port.h +++ b/Headers/gnustep/base/Port.h @@ -39,7 +39,6 @@ @interface Port : NSPort { } -- (void) invalidate; - (void) close; + (Class) outPacketClass; diff --git a/Source/NSPort.m b/Source/NSPort.m index a0035a978..cd83444a3 100644 --- a/Source/NSPort.m +++ b/Source/NSPort.m @@ -1,5 +1,5 @@ -/* Implementation of abstract superclass port for use with Connection - Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. +/* Implementation of abstract superclass port for use with NSConnection + Copyright (C) 1997, 1998 Free Software Foundation, Inc. Written by: Richard Frith-Macdonald Created: August 1997 @@ -23,7 +23,9 @@ #include #include +#include #include +#include #include NSString* NSPortDidBecomeInvalidNotification @@ -36,87 +38,96 @@ NSString *NSPortTimeoutException + (NSPort*) port { - return [[[NSPort alloc] init] autorelease]; + return [[[NSPort alloc] init] autorelease]; } + (NSPort*) portWithMachPort: (int)machPort { - return [[[NSPort alloc] initWithMachPort:machPort] autorelease]; + return [[[NSPort alloc] initWithMachPort: machPort] autorelease]; } -- copyWithZone: (NSZone*)aZone +- (id) copyWithZone: (NSZone*)aZone { - return NSCopyObject(self, 0, aZone); + return [self retain]; } -- delegate +- (id) delegate { - return delegate; + return delegate; } - (void) encodeWithCoder: (NSCoder*)aCoder { + [self subclassResponsibility: _cmd]; } -- init +- (id) init { - self = [super init]; - return self; + self = [super init]; + return self; } -- initWithCoder: (NSCoder*)aCoder +- (id) initWithCoder: (NSCoder*)aCoder { - return self; + [self subclassResponsibility: _cmd]; + return nil; } -- initWithMachPort: (int)machPort +- (id) initWithMachPort: (int)machPort { - [self notImplemented: _cmd]; - return nil; + [self notImplemented: _cmd]; + return nil; } +/* + * subclasses should override this method and call [super invalidate] + * in their versions of the method. + */ - (void) invalidate { - [self subclassResponsibility: _cmd]; + [[NSPortNameServer defaultPortNameServer] removePort: self]; + is_valid = NO; + [NSNotificationCenter postNotificationName: NSPortDidBecomeInvalidNotification + object: self]; } - (BOOL) isValid { - return is_valid; + return is_valid; } -- machPort +- (id) machPort { - [self notImplemented: _cmd]; - return nil; + [self notImplemented: _cmd]; + return nil; } - (void) release { - if (is_valid && [self retainCount] == 1) { - NSAutoreleasePool *arp; + if (is_valid && [self retainCount] == 1) + { + NSAutoreleasePool *arp; - /* - * If the port is about to have a final release deallocate it - * we must invalidate it. Use a local autorelease pool when - * invalidating so that we know that anything refering to this - * port during the invalidation process is released immediately. - * Also - bracket with retain/release pair to prevent recursion. - */ - [super retain]; - arp = [[NSAutoreleasePool alloc] init]; - [self invalidate]; - [arp release]; - [super release]; + /* + * If the port is about to have a final release deallocate it + * we must invalidate it. Use a local autorelease pool when + * invalidating so that we know that anything refering to this + * port during the invalidation process is released immediately. + * Also - bracket with retain/release pair to prevent recursion. + */ + [super retain]; + arp = [[NSAutoreleasePool alloc] init]; + [self invalidate]; + [arp release]; + [super release]; } - [super release]; + [super release]; } - (void) setDelegate: anObject { - delegate = anObject; + delegate = anObject; } @end - diff --git a/Source/NSPortNameServer.m b/Source/NSPortNameServer.m index e37f7915a..f1e26a2e1 100644 --- a/Source/NSPortNameServer.m +++ b/Source/NSPortNameServer.m @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -105,6 +107,10 @@ static NSPortNameServer *defaultServer = nil; } s = (NSPortNameServer*)NSAllocateObject(self, 0, NSDefaultMallocZone()); s->data = [NSMutableData new]; + s->portMap = NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks, + NSObjectMapValueCallBacks, 0); + s->nameMap = NSCreateMapTable(NSObjectMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, 0); defaultServer = s; [serverLock unlock]; } @@ -177,7 +183,6 @@ static NSPortNameServer *defaultServer = nil; beforeDate: [NSDate dateWithTimeIntervalSinceNow: writeTimeout]]; if (expecting) { - [self _close]; [NSException raise: NSPortTimeoutException format: @"timed out writing to gdomap"]; } @@ -189,14 +194,12 @@ static NSPortNameServer *defaultServer = nil; beforeDate: [NSDate dateWithTimeIntervalSinceNow: readTimeout]]; if (expecting) { - [self _close]; [NSException raise: NSPortTimeoutException format: @"timed out reading from gdomap"]; } numSvrs = NSSwapBigIntToHost(*(unsigned*)[data bytes]); if (numSvrs == 0) { - [self _close]; [NSException raise: NSInternalInconsistencyException format: @"failed to get list of name servers on net"]; } @@ -237,7 +240,6 @@ static NSPortNameServer *defaultServer = nil; readTimeout]]; if (expecting) { - [self _close]; [NSException raise: NSPortTimeoutException format: @"timed out reading from gdomap"]; } @@ -251,6 +253,7 @@ static NSPortNameServer *defaultServer = nil; /* * If we had a problem - unlock before continueing. */ + [self _close]; [serverLock unlock]; [localException raise]; } @@ -320,6 +323,7 @@ static NSPortNameServer *defaultServer = nil; /* * If we had a problem - unlock before continueing. */ + [self _close]; [serverLock unlock]; [localException raise]; } @@ -391,13 +395,6 @@ static NSPortNameServer *defaultServer = nil; GDO_NAME_MAX_LEN]; } - msg.rtype = GDO_REGISTER; /* Register a port. */ - msg.ptype = GDO_TCP_GDO; /* Port is TCP port for GNU DO */ - msg.nsize = len; - [name getCString: msg.name]; - msg.port = NSSwapHostIntToBig((unsigned)[(TcpInPort*)port portNumber]); - dat = [NSMutableData dataWithBytes: (void*)&msg length: sizeof(msg)]; - /* * Lock out other threads while doing I/O to gdomap */ @@ -405,6 +402,75 @@ static NSPortNameServer *defaultServer = nil; NS_DURING { + NSMutableSet *known = NSMapGet(portMap, port); + + /* + * If there is no set of names for this port - create one. + */ + if (known == nil) + { + known = [NSMutableSet new]; + NSMapInsert(portMap, port, known); + [known release]; + } + + /* + * If this port has never been registered under any name, first + * send an unregister message to gdomap to ensure that any old + * names for the port (perhaps from a server that crashed without + * unregistering its ports) are no longer around. + */ + if ([known count] == 0) + { + msg.rtype = GDO_UNREG; + msg.ptype = GDO_TCP_GDO; + msg.nsize = 0; + msg.port = NSSwapHostIntToBig([(TcpInPort*)port portNumber]); + dat = [NSMutableData dataWithBytes: (void*)&msg length: sizeof(msg)]; + + [self _open: nil]; + + expecting = sizeof(msg); + [handle writeInBackgroundAndNotify: dat + forModes: modes]; + [loop runMode: mode + beforeDate: [NSDate dateWithTimeIntervalSinceNow: writeTimeout]]; + if (expecting) + { + [NSException raise: NSPortTimeoutException + format: @"timed out writing to gdomap"]; + } + + /* + * Queue a read request in our own run mode then run until the + * timeout period or until the read completes. + */ + expecting = sizeof(unsigned); + [data setLength: 0]; + [handle readInBackgroundAndNotifyForModes: modes]; + [loop runMode: mode + beforeDate: [NSDate dateWithTimeIntervalSinceNow: readTimeout]]; + if (expecting) + { + [NSException raise: NSPortTimeoutException + format: @"timed out reading from gdomap"]; + } + + if ([data length] != sizeof(unsigned)) + { + [NSException raise: NSInternalInconsistencyException + format: @"too much data read from gdomap"]; + } + [self _close]; + } + + msg.rtype = GDO_REGISTER; /* Register a port. */ + msg.ptype = GDO_TCP_GDO; /* Port is TCP port for GNU DO */ + msg.nsize = len; + [name getCString: msg.name]; + msg.port = NSSwapHostIntToBig((unsigned)[(TcpInPort*)port portNumber]); + dat = [NSMutableData dataWithBytes: (void*)&msg length: sizeof(msg)]; + [self _open: nil]; /* @@ -418,14 +484,13 @@ static NSPortNameServer *defaultServer = nil; beforeDate: [NSDate dateWithTimeIntervalSinceNow: writeTimeout]]; if (expecting) { - [self _close]; [NSException raise: NSPortTimeoutException format: @"timed out writing to gdomap"]; } /* * Queue a read request in our own run mode then run until the - * timoeut period or until the read completes. + * timeout period or until the read completes. */ expecting = sizeof(unsigned); [data setLength: 0]; @@ -434,16 +499,10 @@ static NSPortNameServer *defaultServer = nil; beforeDate: [NSDate dateWithTimeIntervalSinceNow: readTimeout]]; if (expecting) { - [self _close]; [NSException raise: NSPortTimeoutException format: @"timed out reading from gdomap"]; } - /* - * Finished with server - so close connection. - */ - [self _close]; - if ([data length] != sizeof(unsigned)) { [NSException raise: NSInternalInconsistencyException @@ -457,17 +516,28 @@ static NSPortNameServer *defaultServer = nil; { NSLog(@"NSPortNameServer unable to register '%@'\n", name); } + else + { + /* + * Add this name to the set of names that the port + * is known by and to the name map. + */ + [known addObject: name]; + NSMapInsert(nameMap, name, port); + } } } NS_HANDLER { /* - * If we had a problem - unlock before continueing. + * If we had a problem - close and unlock before continueing. */ + [self _close]; [serverLock unlock]; [localException raise]; } NS_ENDHANDLER + [self _close]; [serverLock unlock]; } @@ -524,7 +594,6 @@ static NSPortNameServer *defaultServer = nil; beforeDate: [NSDate dateWithTimeIntervalSinceNow: writeTimeout]]; if (expecting) { - [self _close]; [NSException raise: NSPortTimeoutException format: @"timed out writing to gdomap"]; } @@ -540,7 +609,6 @@ static NSPortNameServer *defaultServer = nil; beforeDate: [NSDate dateWithTimeIntervalSinceNow: readTimeout]]; if (expecting) { - [self _close]; [NSException raise: NSPortTimeoutException format: @"timed out reading from gdomap"]; } @@ -563,6 +631,31 @@ static NSPortNameServer *defaultServer = nil; { NSLog(@"NSPortNameServer unable to unregister '%@'\n", name); } + else + { + NSPort *port; + + /* + * Find the port that was registered for this name and + * remove the mapping table entries. + */ + port = NSMapGet(nameMap, name); + if (port) + { + NSMutableSet *known; + + NSMapRemove(nameMap, name); + known = NSMapGet(portMap, port); + if (known) + { + [known removeObject: name]; + if ([known count] == 0) + { + NSMapRemove(portMap, port); + } + } + } + } } } NS_HANDLER @@ -570,6 +663,7 @@ static NSPortNameServer *defaultServer = nil; /* * If we had a problem - unlock before continueing. */ + [self _close]; [serverLock unlock]; [localException raise]; } @@ -763,3 +857,31 @@ static NSPortNameServer *defaultServer = nil; @end +@implementation NSPortNameServer (GNUstep) + +/* + * Remove all names for a particular port - used when a port is + * invalidated. + */ +- (void) removePort: (NSPort*)port +{ + [serverLock lock]; + NS_DURING + { + NSMutableSet *known = (NSMutableSet*)NSMapGet(portMap, port); + NSString *name; + + while ((name = [known anyObject]) != nil) + { + [self removePortForName: name]; + } + } + NS_HANDLER + { + [serverLock unlock]; + [localException raise]; + } + NS_ENDHANDLER + [serverLock lock]; +} +@end diff --git a/Source/Port.m b/Source/Port.m index 3df03b8b5..cd3b28684 100644 --- a/Source/Port.m +++ b/Source/Port.m @@ -41,16 +41,6 @@ [self invalidate]; } -- (void) invalidate -{ - assert (is_valid); - - is_valid = NO; - [NotificationDispatcher - postNotificationName: NSPortDidBecomeInvalidNotification - object: self]; -} - + (Class) outPacketClass { [self subclassResponsibility: _cmd];