Re: Why is Leopard annoying my users?
Re: Why is Leopard annoying my users?
- Subject: Re: Why is Leopard annoying my users?
- From: James Bucanek <email@hidden>
- Date: Tue, 20 Nov 2007 08:52:01 -0700
Alastair Houghton <mailto:email@hidden> wrote
(Tuesday, November 20, 2007 6:48 AM -0000):
Well regardless of whether or not you think your application isn't
creating any TCP sockets, it clearly is; protocol 6 is TCP and the
reason you're being pestered is that your programs are binding ports
for listening on any address.
Exactly. Since I spend days trying to figure out how to create
an interprocess Distributed Objects communications pipe that did
*not* use TCP I'm feeling cheated.
Perhaps it's your DO set-up that needs altering here? Maybe posting
the code will help someone spot why it's trying to bind TCP sockets?
... and ...
Nir Soffer <mailto:email@hidden> wrote (Tuesday, November
20, 2007 6:51 AM +0200):
Seems that your socket listen to to any interface on port 49287 and
49288, while you really want to listen only to localhost. I guess that
you need to configure the socket when you create the NSConnection.
But there's the rub: I spent a lot of work and time explicitly
NOT creating a TCP socket.
OK, here's the meat of the code that I use to create the
server's distributed objects communications port using named sockets:
NSPort* pipe = [[[NSSocketPort alloc] initWithProtocolFamily:AF_UNIX
socketType:SOCK_STREAM
protocol:0
address:[self socketAddressData]]
NSConnection* connection = [NSConnection
connectionWithReceivePort:port sendPort:nil];
And before anyone suggests using Mach ports, Mach ports won't
work. These sockets are created so that client processes can
communicate with a launchd daemon. Leopard Mach kernel namespace
changes have made this impossible to do this using Mach ports.
The recommended solution, according to technote 2083
<http://developer.apple.com/technotes/tn2005/tn2083.html> is to
use UNIX Domain Sockets. I do not want to use TCP sockets for a
variety of security and performance reasons.
And for anyone who has other questions about the code, here's
the whole class:
//
// QRUserBSDSocketPath.m
// Quantum Recall
//
// Created by James Bucanek on 10/18/07.
// Copyright 2007 Dawn to Dusk Software. All rights reserved.
//
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#import "QRUserBSDSocketPath.h"
#import "QuantumDefs.h"
#import "QRPosixPath.h"
#if !defined(NO_LOGGER) // Compile only if the
Logger class is available
#import "FileManagerErrorLogger.h"
#import "QRException.h" // just for a property
name, not for QRException
#import "Logger.h"
#endif
@implementation QRUserBSDSocketPath
+ (QRUserBSDSocketPath*)schedulerSocketPath
{
return ([[[QRUserBSDSocketPath alloc]
initWithName:kSchedulerConnectionName] autorelease]);
}
+ (QRUserBSDSocketPath*)helperSocketPath
{
// Create a unique helper process socket name
QRUserBSDSocketPath* path;
do {
NSString* name = [NSString
stringWithFormat:kHelperConnectionName @".%x",random()&0x3fffffff];
path = [[[QRUserBSDSocketPath alloc] initWithName:name] autorelease];
} while ([path socketExists]);
return (path);
}
- (id)initWithName:(NSString*)name
{
NSString* perUserFolder = [NSString stringWithFormat:@"QRecall.%d",getuid()];
NSDictionary* createAttributes = [NSDictionary
dictionaryWithObject:[NSNumber numberWithUnsignedLong:0700] // rwx------
forKey:NSFilePosixPermissions];
if ( (self=[super initWithName:perUserFolder
inPath:[QRPosixPath varTmpPath]
withAttributes:createAttributes])!=nil )
{
socketName = [name retain];
[self create]; // the
socket's parent directory must always exist
}
return self;
}
- (void)dealloc
{
[socketName release];
[super dealloc];
}
#pragma mark Properties
- (NSString*)name
{
return (socketName);
}
- (NSString*)socketPath
{
return ([[self path] stringByAppendingPathComponent:socketName]);
}
- (NSData*)socketAddressData
{
// Create an BSD address structure that specifies the named
socket in the file system
struct sockaddr_un socketAddress;
bzero(&socketAddress,sizeof(socketAddress));
socketAddress.sun_len = sizeof(socketAddress);
socketAddress.sun_family = AF_UNIX;
strcpy(socketAddress.sun_path,[[self socketPath] cStringUsingEncoding:NSASCIIStringEncoding]);
// socketAddress.sun_len = SUN_LEN(&socketAddress);
NSData* socketAddressData = [NSData dataWithBytes:&socketAddress
length:/*SUN_LEN(&socketAddress)*/sizeof(socketAddress)];
return (socketAddressData);
}
#pragma mark Socket Utilities
- (BOOL)socketExists
{
return ([[NSFileManager defaultManager]
fileExistsAtPath:[self socketPath]]);
}
- (void)deleteSocket
{
#ifdef NO_LOGGER
[[NSFileManager defaultManager] removeFileAtPath:[self
socketPath] handler:nil];
#else
if (![[NSFileManager defaultManager] removeFileAtPath:[self
socketPath] handler:[FileManagerErrorLogger errorLogger]])
{
LogLineIdentifier* lID = [Logger log:kLogError
message:@"Unable to delete communications pipe"];
[Logger log:kLogDetails inLine:lID key:kDetailsPath
value:[self socketPath]];
}
else
{
[Logger log:kLogDebug format:@"%s %@",__func__,[self socketPath]];
}
#endif
}
#pragma mark Notifications
- (void)portDidBecomeInvalidNotification:(NSNotification*)notification
{
#pragma unused(notification)
#if !defined(NO_LOGGER)
[Logger log:kLogDebug format:@"%s",__func__];
#endif
// The port that uses this BSD socket is no longer valid.
// Delete the underlying pipe file.
[self deleteSocket];
[self autorelease]; // balance retain in
-[QRUserBSDSocketPath createPort]
}
#pragma mark Communication ports
- (NSConnection*)serverConnection
{
NSConnection* connection = nil;
NSPort* port = [self createPort];
if (port!=nil)
connection = [NSConnection
connectionWithReceivePort:port sendPort:nil];
return (connection);
}
- (NSConnection*)clientConnection
{
NSConnection* connection = nil;
NSPort* port = nil;
if ([self socketExists])
port = [self connectPort];
if (port!=nil)
connection = [NSConnection
connectionWithReceivePort:nil sendPort:port];
return (connection);
}
- (NSPort*)createPort
{
// This method creates the pipe file, binds to it, and
returns it as an NSPort object.
// It fails if the pipe file already exists.
NSPort* pipe = [[[NSSocketPort alloc] initWithProtocolFamily:AF_UNIX
socketType:SOCK_STREAM
protocol:0
address:[self socketAddressData]] autorelease];
if (pipe!=nil)
{
// Creating this NSSocketPort will bind() the address,
which creates a pipe file.
// Listen for the NSPortDidBecomeInvalidNotification
notification and delete the pipe file
// when it's no longer being used.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(portDidBecomeInvalidNotification:)
name:NSPortDidBecomeInvalidNotification
object:pipe];
[self retain]; // retain until the
notification is received
#if !defined(NO_LOGGER)
[Logger log:kLogDebug format:@"%s %@",__func__,[self socketPath]];
}
else
{
[Logger log:kLogDebug format:@"%s failed to create
%@",__func__,[self socketPath]];
#endif
}
return (pipe);
}
- (NSPort*)connectPort
{
// This method connects with an already existing socket in
the file system.
// It fails (returns nil) if the socket does not exist.
NSPort* pipe = nil;
if ([self socketExists])
pipe = [[[NSSocketPort alloc] initRemoteWithProtocolFamily:AF_UNIX
socketType:SOCK_STREAM
protocol:0
address:[self socketAddressData]] autorelease];
#if !defined(NO_LOGGER)
if (pipe!=nil)
[Logger log:kLogDebug format:@"%s %@",__func__,[self socketPath]];
else
[Logger log:kLogDebug format:@"%s failed to connect
%@",__func__,[self socketPath]];
#endif
return (pipe);
}
@end
--
James Bucanek
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden