diff --git a/ChangeLog b/ChangeLog index 581108c20..6571f50d8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2009-12-02 Richard Frith-Macdonald + + * Source/NSMessagePortNameServer.m: + * Source/NSMessagePort.m: + On initialisation, remove any old ports/names for the current process + idntifier. Also remove ports/names for processes which don't exist. + Avoids any possibility of nameserver confusion between two processes + with the same ID. + 2009-12-01 Richard Frith-Macdonald * Source/NSMessagePortNameServer.m: Tolerate '*' host name. diff --git a/Source/NSMessagePort.m b/Source/NSMessagePort.m index 1bbda2dd0..62e8faff7 100644 --- a/Source/NSMessagePort.m +++ b/Source/NSMessagePort.m @@ -91,6 +91,10 @@ #include #endif +@interface NSProcessInfo (private) ++ (BOOL) _exists: (int)pid; +@end + /* * Largest chunk of data possible in DO */ @@ -1120,12 +1124,56 @@ typedef struct { { if (self == [NSMessagePort class]) { + NSFileManager *mgr; + NSString *path; + NSString *pref; + NSString *file; + NSEnumerator *files; + messagePortClass = self; messagePortMap = NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks, NSNonOwnedPointerMapValueCallBacks, 0); messagePortLock = [GSLazyRecursiveLock new]; atexit(clean_up_sockets); + + /* It's possible that an old process, with the same process ID as + * this one, got forcibly killed or crashed so that clean_up_sockets + * was never called. + * To deal with that unlikely situation, we need to remove all such + * ports which have been left over. + */ + path = NSTemporaryDirectory(); + path = [path stringByAppendingPathComponent: @"NSMessagePort"]; + path = [path stringByAppendingPathComponent: @"ports"]; + pref = [NSString stringWithFormat: @"%i.", + [[NSProcessInfo processInfo] processIdentifier]]; + mgr = [NSFileManager defaultManager]; + files = [[mgr directoryContentsAtPath: path] objectEnumerator]; + while ((file = [files nextObject]) != nil) + { + NSString *old = [path stringByAppendingPathComponent: file]; + + if (YES == [file hasPrefix: pref]) + { + NSDebugMLLog(@"NSMessagePort", @"Removing old port %@", old); + [mgr removeFileAtPath: old handler: nil]; + } + else + { + int pid = [file intValue]; + + if (pid > 0) + { + if (NO == [NSProcessInfo _exists: pid]) + { + NSDebugMLLog(@"NSMessagePort", + @"Removing old port %@ for process %d", old, pid); + [mgr removeFileAtPath: old handler: nil]; + } + } + } + } } } diff --git a/Source/NSMessagePortNameServer.m b/Source/NSMessagePortNameServer.m index e06a6aa8c..255ac5ba4 100644 --- a/Source/NSMessagePortNameServer.m +++ b/Source/NSMessagePortNameServer.m @@ -57,6 +57,9 @@ (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) #endif +@interface NSProcessInfo (private) ++ (BOOL) _exists: (int)pid; +@end static NSRecursiveLock *serverLock = nil; static NSMessagePortNameServer *defaultServer = nil; @@ -116,10 +119,55 @@ static void clean_up_names(void) { if (self == [NSMessagePortNameServer class]) { + NSFileManager *mgr; + NSString *path; + NSString *pref; + NSString *file; + NSEnumerator *files; + serverLock = [NSRecursiveLock new]; portToNamesMap = NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks, NSObjectMapValueCallBacks, 0); atexit(clean_up_names); + + /* It's possible that an old process, with the same process ID as + * this one, got forcibly killed or crashed so that clean_up_names + * was never called. + * To deal with that unlikely situation, we need to remove all such + * names which have been left over. + */ + path = NSTemporaryDirectory(); + path = [path stringByAppendingPathComponent: @"NSMessagePort"]; + path = [path stringByAppendingPathComponent: @"names"]; + pref = [NSString stringWithFormat: @"%i.", + [[NSProcessInfo processInfo] processIdentifier]]; + mgr = [NSFileManager defaultManager]; + files = [[mgr directoryContentsAtPath: path] objectEnumerator]; + while ((file = [files nextObject]) != nil) + { + NSString *old = [path stringByAppendingPathComponent: file]; + NSString *port = [NSString stringWithContentsOfFile: old]; + + if (YES == [port hasPrefix: pref]) + { + NSDebugMLLog(@"NSMessagePort", @"Removing old name %@", old); + [mgr removeFileAtPath: old handler: nil]; + } + else + { + int pid = [port intValue]; + + if (pid > 0) + { + if (NO == [NSProcessInfo _exists: pid]) + { + NSDebugMLLog(@"NSMessagePort", + @"Removing old name %@ for process %d", old, pid); + [mgr removeFileAtPath: old handler: nil]; + } + } + } + } } }