Fix for processes interfering with eath others changes to names and ports.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/branches/stable@26090 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2008-02-18 18:37:51 +00:00
parent cc93ad9017
commit e6a6d04987
2 changed files with 120 additions and 27 deletions

View file

@ -1,3 +1,8 @@
2008-02-18 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSMessagePortNameServer.m: Use locks to prevent two
processes from interfering with each other.
2008-02-14 Richard Frith-Macdonald <rfm@gnu.org>
* Source/GSHTTPURLHandle.m: Remove self as observer of socket

View file

@ -29,6 +29,7 @@
#include "Foundation/NSDebug.h"
#include "Foundation/NSException.h"
#include "Foundation/NSLock.h"
#include "Foundation/NSDistributedLock.h"
#include "Foundation/NSMapTable.h"
#include "Foundation/NSPathUtilities.h"
#include "Foundation/NSPort.h"
@ -77,7 +78,8 @@ static NSMapTable portToNamesMap;
@interface NSMessagePortNameServer (private)
+(NSString *) _pathForName: (NSString *)name;
+ (NSDistributedLock*) _fileLock;
+ (NSString *) _pathForName: (NSString *)name;
@end
@ -139,21 +141,77 @@ static void clean_up_names(void)
return defaultServer;
}
+ (NSDistributedLock*) _fileLock
{
NSDistributedLock *dl;
dl = [NSDistributedLock lockWithPath: [self _pathForName: nil]];
if ([dl tryLock] == NO)
{
NSDate *limit = [NSDate dateWithTimeIntervalSinceNow: 2.0];
while (dl != nil && [dl tryLock] == NO)
{
CREATE_AUTORELEASE_POOL(pool);
if ([limit timeIntervalSinceNow] > 0.0)
{
[NSThread sleepUntilDate:
[NSDate dateWithTimeIntervalSinceNow: 0.1]];
}
else
{
if ([[dl lockDate] timeIntervalSinceNow] < -15.0)
{
NS_DURING
{
[dl breakLock];
}
NS_HANDLER
{
NSLog(@"Failed to break lock on names for "
@"NSMessagePortNameServer: %@", localException);
dl = nil;
}
NS_ENDHANDLER
}
else
{
NSLog(@"Failed to lock names for NSMessagePortNameServer");
dl = nil;
}
}
RELEASE(pool);
}
}
return dl;
}
/* Return the full path for the supplied port name or, if it's nil,
* the path for the distributed lock protecting all names.
*/
+ (NSString *) _pathForName: (NSString *)name
{
static NSString *base_path = nil;
NSString *path;
NSData *data;
if (name == nil)
{
name = @"lock";
}
else
{
/*
* Make sure name is representable as a filename ... assume base64 encoded
* strings are valid on all filesystems.
*/
data = [name dataUsingEncoding: NSUTF8StringEncoding];
data = [GSMimeDocument encodeBase64: data];
name = [[NSString alloc] initWithData: data encoding: NSASCIIStringEncoding];
name = [[NSString alloc] initWithData: data
encoding: NSASCIIStringEncoding];
AUTORELEASE(name);
}
[serverLock lock];
if (!base_path)
{
@ -260,6 +318,7 @@ static void clean_up_names(void)
- (NSPort*) portForName: (NSString *)name
onHost: (NSString *)host
{
NSDistributedLock *dl;
NSString *path;
FILE *f;
char socket_path[512];
@ -278,8 +337,14 @@ static void clean_up_names(void)
}
path = [[self class] _pathForName: name];
if ((dl = [[self class] _fileLock]) == nil)
{
[NSException raise: NSGenericException
format: @"Failed to lock names for NSMessagePortNameServer"];
}
if (![[self class] _livePort: path])
{
[dl unlock];
NSDebugLLog(@"NSMessagePort", @"not a live port");
return nil;
}
@ -287,6 +352,7 @@ static void clean_up_names(void)
f = fopen([path fileSystemRepresentation], "rt");
if (!f)
{
[dl unlock];
NSDebugLLog(@"NSMessagePort", @"can't open file (%m)");
return nil;
}
@ -296,6 +362,7 @@ static void clean_up_names(void)
fclose(f);
NSDebugLLog(@"NSMessagePort", @"got %s", socket_path);
[dl unlock];
return [NSMessagePort _portWithName: (unsigned char*)socket_path
listener: NO];
@ -306,6 +373,7 @@ static void clean_up_names(void)
{
int fd;
unsigned char buf[32];
NSDistributedLock *dl;
NSString *path;
const unsigned char *socket_name;
NSMutableArray *a;
@ -316,13 +384,17 @@ static void clean_up_names(void)
[NSException raise: NSInvalidArgumentException
format: @"Attempted to register a non-NSMessagePort (%@)",
port];
return NO;
}
path = [[self class] _pathForName: name];
if ((dl = [[self class] _fileLock]) == nil)
{
[NSException raise: NSGenericException
format: @"Failed to lock names for NSMessagePortNameServer"];
}
if ([[self class] _livePort: path])
{
[dl unlock];
NSDebugLLog(@"NSMessagePort", @"fail, is a live port (%@)", name);
return NO;
}
@ -330,6 +402,7 @@ static void clean_up_names(void)
fd = open([path fileSystemRepresentation], O_CREAT|O_EXCL|O_WRONLY, 0600);
if (fd < 0)
{
[dl unlock];
NSDebugLLog(@"NSMessagePort", @"fail, can't open file (%@) for %@",
path, name);
return NO;
@ -355,17 +428,25 @@ static void clean_up_names(void)
[a addObject: [name copy]];
[serverLock unlock];
[dl unlock];
return YES;
}
- (BOOL) removePortForName: (NSString *)name
{
NSDistributedLock *dl;
NSString *path;
NSDebugLLog(@"NSMessagePort", @"removePortForName: %@", name);
path = [[self class] _pathForName: name];
if ((dl = [[self class] _fileLock]) == nil)
{
[NSException raise: NSGenericException
format: @"Failed to lock names for NSMessagePortNameServer"];
}
unlink([path fileSystemRepresentation]);
[dl unlock];
return YES;
}
@ -405,29 +486,36 @@ static void clean_up_names(void)
{
FILE *f;
char socket_path[512];
NSDistributedLock *dl;
NSString *path;
const unsigned char *port_path;
NSDebugLLog(@"NSMessagePort", @"removePort: %@ forName: %@", port, name);
path = [[self class] _pathForName: name];
if ((dl = [[self class] _fileLock]) == nil)
{
[NSException raise: NSGenericException
format: @"Failed to lock names for NSMessagePortNameServer"];
}
f = fopen([path fileSystemRepresentation], "rt");
if (!f)
{
[dl unlock];
return YES;
}
fgets(socket_path, sizeof(socket_path), f);
if (strlen(socket_path) > 0) socket_path[strlen(socket_path) - 1] = 0;
if (strlen(socket_path) > 0)
{
socket_path[strlen(socket_path) - 1] = 0;
}
fclose(f);
port_path = [(NSMessagePort *)port _name];
if (!strcmp((char*)socket_path, (char*)port_path))
{
unlink([path fileSystemRepresentation]);
}
[dl unlock];
return YES;
}