Bugfixes in name serve stuff - should be much more robust.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@3147 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
richard 1998-10-30 08:40:03 +00:00
parent 531cbe66df
commit 04b7295d82
7 changed files with 216 additions and 71 deletions

View file

@ -1,3 +1,17 @@
Fri Oct 30 09:00:00 1998 Richard Frith-Macdonald <richard@brainstorm.co.uk>
* 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 <richard@brainstorm.co.uk> Thu Oct 29 13:30:00 1998 Richard Frith-Macdonald <richard@brainstorm.co.uk>
* src/UnixFileHandle.m: Improved handling of error conditions on * src/UnixFileHandle.m: Improved handling of error conditions on

View file

@ -26,6 +26,8 @@
#include <Foundation/NSObject.h> #include <Foundation/NSObject.h>
@class NSMutableSet;
extern NSString *NSPortTimeoutException; /* OPENSTEP */ extern NSString *NSPortTimeoutException; /* OPENSTEP */
@interface NSPort : NSObject <NSCoding, NSCopying> @interface NSPort : NSObject <NSCoding, NSCopying>
@ -55,6 +57,7 @@ extern NSString *NSPortTimeoutException; /* OPENSTEP */
+ (Class) outPacketClass; + (Class) outPacketClass;
- (Class) outPacketClass; - (Class) outPacketClass;
@end @end
extern NSString* NSPortDidBecomeInvalidNotification; extern NSString* NSPortDidBecomeInvalidNotification;

View file

@ -33,6 +33,8 @@
NSFileHandle *handle; /* File handle to talk to gdomap. */ NSFileHandle *handle; /* File handle to talk to gdomap. */
NSMutableData *data; /* Where to accumulated incoming data. */ NSMutableData *data; /* Where to accumulated incoming data. */
unsigned expecting; /* Length of data we want. */ unsigned expecting; /* Length of data we want. */
NSMapTable *portMap; /* Registered ports information. */
NSMapTable *nameMap; /* Registered names information. */
} }
+ (id) defaultPortNameServer; + (id) defaultPortNameServer;
- (NSPort*) portForName: (NSString*)name; - (NSPort*) portForName: (NSString*)name;
@ -43,5 +45,9 @@
- (void) removePortForName: (NSString*)name; - (void) removePortForName: (NSString*)name;
@end @end
@interface NSPortNameServer (GNUstep)
- (void) removePort: (NSPort*)port; /* remove all names for port */
@end
#endif #endif

View file

@ -39,7 +39,6 @@
@interface Port : NSPort @interface Port : NSPort
{ {
} }
- (void) invalidate;
- (void) close; - (void) close;
+ (Class) outPacketClass; + (Class) outPacketClass;

View file

@ -1,5 +1,5 @@
/* Implementation of abstract superclass port for use with Connection /* Implementation of abstract superclass port for use with NSConnection
Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. Copyright (C) 1997, 1998 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk> Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
Created: August 1997 Created: August 1997
@ -23,7 +23,9 @@
#include <config.h> #include <config.h>
#include <Foundation/NSString.h> #include <Foundation/NSString.h>
#include <Foundation/NSNotificationQueue.h>
#include <Foundation/NSPort.h> #include <Foundation/NSPort.h>
#include <Foundation/NSPortNameServer.h>
#include <Foundation/NSAutoreleasePool.h> #include <Foundation/NSAutoreleasePool.h>
NSString* NSPortDidBecomeInvalidNotification NSString* NSPortDidBecomeInvalidNotification
@ -36,87 +38,96 @@ NSString *NSPortTimeoutException
+ (NSPort*) port + (NSPort*) port
{ {
return [[[NSPort alloc] init] autorelease]; return [[[NSPort alloc] init] autorelease];
} }
+ (NSPort*) portWithMachPort: (int)machPort + (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 - (void) encodeWithCoder: (NSCoder*)aCoder
{ {
[self subclassResponsibility: _cmd];
} }
- init - (id) init
{ {
self = [super init]; self = [super init];
return self; 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]; [self notImplemented: _cmd];
return nil; return nil;
} }
/*
* subclasses should override this method and call [super invalidate]
* in their versions of the method.
*/
- (void) invalidate - (void) invalidate
{ {
[self subclassResponsibility: _cmd]; [[NSPortNameServer defaultPortNameServer] removePort: self];
is_valid = NO;
[NSNotificationCenter postNotificationName: NSPortDidBecomeInvalidNotification
object: self];
} }
- (BOOL) isValid - (BOOL) isValid
{ {
return is_valid; return is_valid;
} }
- machPort - (id) machPort
{ {
[self notImplemented: _cmd]; [self notImplemented: _cmd];
return nil; return nil;
} }
- (void) release - (void) release
{ {
if (is_valid && [self retainCount] == 1) { if (is_valid && [self retainCount] == 1)
NSAutoreleasePool *arp; {
NSAutoreleasePool *arp;
/* /*
* If the port is about to have a final release deallocate it * If the port is about to have a final release deallocate it
* we must invalidate it. Use a local autorelease pool when * we must invalidate it. Use a local autorelease pool when
* invalidating so that we know that anything refering to this * invalidating so that we know that anything refering to this
* port during the invalidation process is released immediately. * port during the invalidation process is released immediately.
* Also - bracket with retain/release pair to prevent recursion. * Also - bracket with retain/release pair to prevent recursion.
*/ */
[super retain]; [super retain];
arp = [[NSAutoreleasePool alloc] init]; arp = [[NSAutoreleasePool alloc] init];
[self invalidate]; [self invalidate];
[arp release]; [arp release];
[super release]; [super release];
} }
[super release]; [super release];
} }
- (void) setDelegate: anObject - (void) setDelegate: anObject
{ {
delegate = anObject; delegate = anObject;
} }
@end @end

View file

@ -31,6 +31,8 @@
#include <Foundation/NSRunLoop.h> #include <Foundation/NSRunLoop.h>
#include <Foundation/NSNotificationQueue.h> #include <Foundation/NSNotificationQueue.h>
#include <Foundation/NSPort.h> #include <Foundation/NSPort.h>
#include <Foundation/NSMapTable.h>
#include <Foundation/NSSet.h>
#include <Foundation/NSPortNameServer.h> #include <Foundation/NSPortNameServer.h>
#include <gnustep/base/TcpPort.h> #include <gnustep/base/TcpPort.h>
@ -105,6 +107,10 @@ static NSPortNameServer *defaultServer = nil;
} }
s = (NSPortNameServer*)NSAllocateObject(self, 0, NSDefaultMallocZone()); s = (NSPortNameServer*)NSAllocateObject(self, 0, NSDefaultMallocZone());
s->data = [NSMutableData new]; s->data = [NSMutableData new];
s->portMap = NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks,
NSObjectMapValueCallBacks, 0);
s->nameMap = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSNonOwnedPointerMapValueCallBacks, 0);
defaultServer = s; defaultServer = s;
[serverLock unlock]; [serverLock unlock];
} }
@ -177,7 +183,6 @@ static NSPortNameServer *defaultServer = nil;
beforeDate: [NSDate dateWithTimeIntervalSinceNow: writeTimeout]]; beforeDate: [NSDate dateWithTimeIntervalSinceNow: writeTimeout]];
if (expecting) if (expecting)
{ {
[self _close];
[NSException raise: NSPortTimeoutException [NSException raise: NSPortTimeoutException
format: @"timed out writing to gdomap"]; format: @"timed out writing to gdomap"];
} }
@ -189,14 +194,12 @@ static NSPortNameServer *defaultServer = nil;
beforeDate: [NSDate dateWithTimeIntervalSinceNow: readTimeout]]; beforeDate: [NSDate dateWithTimeIntervalSinceNow: readTimeout]];
if (expecting) if (expecting)
{ {
[self _close];
[NSException raise: NSPortTimeoutException [NSException raise: NSPortTimeoutException
format: @"timed out reading from gdomap"]; format: @"timed out reading from gdomap"];
} }
numSvrs = NSSwapBigIntToHost(*(unsigned*)[data bytes]); numSvrs = NSSwapBigIntToHost(*(unsigned*)[data bytes]);
if (numSvrs == 0) if (numSvrs == 0)
{ {
[self _close];
[NSException raise: NSInternalInconsistencyException [NSException raise: NSInternalInconsistencyException
format: @"failed to get list of name servers on net"]; format: @"failed to get list of name servers on net"];
} }
@ -237,7 +240,6 @@ static NSPortNameServer *defaultServer = nil;
readTimeout]]; readTimeout]];
if (expecting) if (expecting)
{ {
[self _close];
[NSException raise: NSPortTimeoutException [NSException raise: NSPortTimeoutException
format: @"timed out reading from gdomap"]; format: @"timed out reading from gdomap"];
} }
@ -251,6 +253,7 @@ static NSPortNameServer *defaultServer = nil;
/* /*
* If we had a problem - unlock before continueing. * If we had a problem - unlock before continueing.
*/ */
[self _close];
[serverLock unlock]; [serverLock unlock];
[localException raise]; [localException raise];
} }
@ -320,6 +323,7 @@ static NSPortNameServer *defaultServer = nil;
/* /*
* If we had a problem - unlock before continueing. * If we had a problem - unlock before continueing.
*/ */
[self _close];
[serverLock unlock]; [serverLock unlock];
[localException raise]; [localException raise];
} }
@ -391,13 +395,6 @@ static NSPortNameServer *defaultServer = nil;
GDO_NAME_MAX_LEN]; 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 * Lock out other threads while doing I/O to gdomap
*/ */
@ -405,6 +402,75 @@ static NSPortNameServer *defaultServer = nil;
NS_DURING 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]; [self _open: nil];
/* /*
@ -418,14 +484,13 @@ static NSPortNameServer *defaultServer = nil;
beforeDate: [NSDate dateWithTimeIntervalSinceNow: writeTimeout]]; beforeDate: [NSDate dateWithTimeIntervalSinceNow: writeTimeout]];
if (expecting) if (expecting)
{ {
[self _close];
[NSException raise: NSPortTimeoutException [NSException raise: NSPortTimeoutException
format: @"timed out writing to gdomap"]; format: @"timed out writing to gdomap"];
} }
/* /*
* Queue a read request in our own run mode then run until the * 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); expecting = sizeof(unsigned);
[data setLength: 0]; [data setLength: 0];
@ -434,16 +499,10 @@ static NSPortNameServer *defaultServer = nil;
beforeDate: [NSDate dateWithTimeIntervalSinceNow: readTimeout]]; beforeDate: [NSDate dateWithTimeIntervalSinceNow: readTimeout]];
if (expecting) if (expecting)
{ {
[self _close];
[NSException raise: NSPortTimeoutException [NSException raise: NSPortTimeoutException
format: @"timed out reading from gdomap"]; format: @"timed out reading from gdomap"];
} }
/*
* Finished with server - so close connection.
*/
[self _close];
if ([data length] != sizeof(unsigned)) if ([data length] != sizeof(unsigned))
{ {
[NSException raise: NSInternalInconsistencyException [NSException raise: NSInternalInconsistencyException
@ -457,17 +516,28 @@ static NSPortNameServer *defaultServer = nil;
{ {
NSLog(@"NSPortNameServer unable to register '%@'\n", name); 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 NS_HANDLER
{ {
/* /*
* If we had a problem - unlock before continueing. * If we had a problem - close and unlock before continueing.
*/ */
[self _close];
[serverLock unlock]; [serverLock unlock];
[localException raise]; [localException raise];
} }
NS_ENDHANDLER NS_ENDHANDLER
[self _close];
[serverLock unlock]; [serverLock unlock];
} }
@ -524,7 +594,6 @@ static NSPortNameServer *defaultServer = nil;
beforeDate: [NSDate dateWithTimeIntervalSinceNow: writeTimeout]]; beforeDate: [NSDate dateWithTimeIntervalSinceNow: writeTimeout]];
if (expecting) if (expecting)
{ {
[self _close];
[NSException raise: NSPortTimeoutException [NSException raise: NSPortTimeoutException
format: @"timed out writing to gdomap"]; format: @"timed out writing to gdomap"];
} }
@ -540,7 +609,6 @@ static NSPortNameServer *defaultServer = nil;
beforeDate: [NSDate dateWithTimeIntervalSinceNow: readTimeout]]; beforeDate: [NSDate dateWithTimeIntervalSinceNow: readTimeout]];
if (expecting) if (expecting)
{ {
[self _close];
[NSException raise: NSPortTimeoutException [NSException raise: NSPortTimeoutException
format: @"timed out reading from gdomap"]; format: @"timed out reading from gdomap"];
} }
@ -563,6 +631,31 @@ static NSPortNameServer *defaultServer = nil;
{ {
NSLog(@"NSPortNameServer unable to unregister '%@'\n", name); 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 NS_HANDLER
@ -570,6 +663,7 @@ static NSPortNameServer *defaultServer = nil;
/* /*
* If we had a problem - unlock before continueing. * If we had a problem - unlock before continueing.
*/ */
[self _close];
[serverLock unlock]; [serverLock unlock];
[localException raise]; [localException raise];
} }
@ -763,3 +857,31 @@ static NSPortNameServer *defaultServer = nil;
@end @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

View file

@ -41,16 +41,6 @@
[self invalidate]; [self invalidate];
} }
- (void) invalidate
{
assert (is_valid);
is_valid = NO;
[NotificationDispatcher
postNotificationName: NSPortDidBecomeInvalidNotification
object: self];
}
+ (Class) outPacketClass + (Class) outPacketClass
{ {
[self subclassResponsibility: _cmd]; [self subclassResponsibility: _cmd];