2003-07-15 05:21:34 +00:00
|
|
|
|
/** Implementation of network port object based on unix domain sockets
|
|
|
|
|
Copyright (C) 2000 Free Software Foundation, Inc.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2003-07-15 05:21:34 +00:00
|
|
|
|
Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
|
|
|
|
Based on code by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2003-07-15 05:21:34 +00:00
|
|
|
|
This file is part of the GNUstep Base Library.
|
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
2007-09-14 11:36:11 +00:00
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
2003-07-15 05:21:34 +00:00
|
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-08 10:38:33 +00:00
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2003-07-15 05:21:34 +00:00
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
Library General Public License for more details.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2007-09-14 11:36:11 +00:00
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
2003-07-15 05:21:34 +00:00
|
|
|
|
License along with this library; if not, write to the Free
|
2006-10-20 10:56:27 +00:00
|
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
|
Boston, MA 02111 USA.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
*/
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
|
|
|
|
#include "config.h"
|
2003-07-31 23:49:32 +00:00
|
|
|
|
#include "GNUstepBase/preface.h"
|
2004-02-08 09:42:38 +00:00
|
|
|
|
#include "GNUstepBase/GSLock.h"
|
2003-07-15 05:21:34 +00:00
|
|
|
|
#include "Foundation/NSArray.h"
|
|
|
|
|
#include "Foundation/NSNotification.h"
|
|
|
|
|
#include "Foundation/NSException.h"
|
|
|
|
|
#include "Foundation/NSRunLoop.h"
|
|
|
|
|
#include "Foundation/NSByteOrder.h"
|
|
|
|
|
#include "Foundation/NSData.h"
|
|
|
|
|
#include "Foundation/NSDate.h"
|
|
|
|
|
#include "Foundation/NSMapTable.h"
|
|
|
|
|
#include "Foundation/NSPortMessage.h"
|
|
|
|
|
#include "Foundation/NSPortNameServer.h"
|
|
|
|
|
#include "Foundation/NSLock.h"
|
|
|
|
|
#include "Foundation/NSThread.h"
|
|
|
|
|
#include "Foundation/NSConnection.h"
|
|
|
|
|
#include "Foundation/NSDebug.h"
|
|
|
|
|
#include "Foundation/NSPathUtilities.h"
|
2004-03-28 05:31:16 +00:00
|
|
|
|
#include "Foundation/NSValue.h"
|
|
|
|
|
#include "Foundation/NSFileManager.h"
|
|
|
|
|
#include "Foundation/NSProcessInfo.h"
|
2005-11-01 20:37:34 +00:00
|
|
|
|
|
2006-10-09 14:00:01 +00:00
|
|
|
|
#include "GSPrivate.h"
|
2005-11-01 20:37:34 +00:00
|
|
|
|
#include "GSPortPrivate.h"
|
|
|
|
|
|
2003-07-15 05:21:34 +00:00
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
2005-11-04 17:58:27 +00:00
|
|
|
|
|
2003-07-15 05:21:34 +00:00
|
|
|
|
#ifdef HAVE_UNISTD_H
|
2008-02-20 09:22:43 +00:00
|
|
|
|
#include <unistd.h>
|
2003-07-15 05:21:34 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <sys/param.h> /* for MAXHOSTNAMELEN */
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/un.h>
|
|
|
|
|
#include <arpa/inet.h> /* for inet_ntoa() */
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <string.h> /* for strchr() */
|
|
|
|
|
#include <ctype.h> /* for strchr() */
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#include <sys/resource.h>
|
|
|
|
|
#include <netdb.h>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <sys/file.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
/*
|
|
|
|
|
* Stuff for setting the sockets into non-blocking mode.
|
|
|
|
|
*/
|
|
|
|
|
#ifdef __POSIX_SOURCE
|
|
|
|
|
#define NBLK_OPT O_NONBLOCK
|
|
|
|
|
#else
|
|
|
|
|
#define NBLK_OPT FNDELAY
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
#include <net/if.h>
|
|
|
|
|
#if !defined(SIOCGIFCONF) || defined(__CYGWIN__)
|
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
|
#ifndef SIOCGIFCONF
|
|
|
|
|
#include <sys/sockio.h>
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if defined(__svr4__)
|
|
|
|
|
#include <sys/stropts.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Largest chunk of data possible in DO
|
|
|
|
|
*/
|
2006-01-11 08:37:16 +00:00
|
|
|
|
static uint32_t maxDataLength = 32 * 1024 * 1024;
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
#define M_LOCK(X) {NSDebugMLLog(@"NSMessagePort",@"lock %@",X); [X lock];}
|
|
|
|
|
#define M_UNLOCK(X) {NSDebugMLLog(@"NSMessagePort",@"unlock %@",X); [X unlock];}
|
|
|
|
|
#else
|
|
|
|
|
#define M_LOCK(X) {[X lock];}
|
|
|
|
|
#define M_UNLOCK(X) {[X unlock];}
|
|
|
|
|
#endif
|
|
|
|
|
|
2005-11-01 20:37:34 +00:00
|
|
|
|
|
2003-07-15 05:21:34 +00:00
|
|
|
|
/*
|
|
|
|
|
* The GSPortItemType constant is used to identify the type of data in
|
|
|
|
|
* each packet read. All data transmitted is in a packet, each packet
|
|
|
|
|
* has an initial packet type and packet length.
|
|
|
|
|
*/
|
|
|
|
|
typedef enum {
|
|
|
|
|
GSP_NONE,
|
|
|
|
|
GSP_PORT, /* Simple port item. */
|
|
|
|
|
GSP_DATA, /* Simple data item. */
|
|
|
|
|
GSP_HEAD /* Port message header + initial data. */
|
|
|
|
|
} GSPortItemType;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The GSPortItemHeader structure defines the header for each item transmitted.
|
|
|
|
|
* Its contents are transmitted in network byte order.
|
|
|
|
|
*/
|
|
|
|
|
typedef struct {
|
2006-01-11 08:37:16 +00:00
|
|
|
|
uint32_t type; /* A GSPortItemType as a 4-byte number. */
|
|
|
|
|
uint32_t length; /* The length of the item (excluding header). */
|
2003-07-15 05:21:34 +00:00
|
|
|
|
} GSPortItemHeader;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The GSPortMsgHeader structure is at the start of any item of type GSP_HEAD.
|
|
|
|
|
* Its contents are transmitted in network byte order.
|
|
|
|
|
* Any additional data in the item is an NSData object.
|
|
|
|
|
* NB. additional data counts as part of the same item.
|
|
|
|
|
*/
|
|
|
|
|
typedef struct {
|
2006-01-11 08:37:16 +00:00
|
|
|
|
uint32_t mId; /* The ID for the message starting with this. */
|
|
|
|
|
uint32_t nItems; /* Number of items (including this one). */
|
2003-07-15 05:21:34 +00:00
|
|
|
|
} GSPortMsgHeader;
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
2005-07-08 11:48:37 +00:00
|
|
|
|
unsigned char version;
|
2005-11-04 17:58:27 +00:00
|
|
|
|
unsigned char addr[0]; /* name of the port on the local host */
|
2003-07-15 05:21:34 +00:00
|
|
|
|
} GSPortInfo;
|
|
|
|
|
|
2005-11-04 17:58:27 +00:00
|
|
|
|
/*
|
|
|
|
|
* Utility functions for encoding and decoding ports.
|
|
|
|
|
*/
|
|
|
|
|
static NSMessagePort*
|
|
|
|
|
decodePort(NSData *data)
|
|
|
|
|
{
|
|
|
|
|
GSPortItemHeader *pih;
|
|
|
|
|
GSPortInfo *pi;
|
|
|
|
|
|
|
|
|
|
pih = (GSPortItemHeader*)[data bytes];
|
|
|
|
|
NSCAssert(GSSwapBigI32ToHost(pih->type) == GSP_PORT,
|
|
|
|
|
NSInternalInconsistencyException);
|
|
|
|
|
pi = (GSPortInfo*)&pih[1];
|
|
|
|
|
if (pi->version != 0)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"Remote version of GNUstep is more recent than this one (%i)",
|
|
|
|
|
pi->version);
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSDebugFLLog(@"NSMessagePort", @"Decoded port as '%s'", pi->addr);
|
|
|
|
|
|
|
|
|
|
return [NSMessagePort _portWithName: pi->addr
|
|
|
|
|
listener: NO];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NSData*
|
|
|
|
|
newDataWithEncodedPort(NSMessagePort *port)
|
|
|
|
|
{
|
|
|
|
|
GSPortItemHeader *pih;
|
|
|
|
|
GSPortInfo *pi;
|
|
|
|
|
NSMutableData *data;
|
|
|
|
|
unsigned plen;
|
|
|
|
|
const unsigned char *name = [port _name];
|
|
|
|
|
|
|
|
|
|
plen = 2 + strlen((char*)name);
|
|
|
|
|
|
|
|
|
|
data = [[NSMutableData alloc] initWithLength: sizeof(GSPortItemHeader)+plen];
|
|
|
|
|
pih = (GSPortItemHeader*)[data mutableBytes];
|
|
|
|
|
pih->type = GSSwapHostI32ToBig(GSP_PORT);
|
|
|
|
|
pih->length = GSSwapHostI32ToBig(plen);
|
|
|
|
|
pi = (GSPortInfo*)&pih[1];
|
|
|
|
|
strcpy((char*)pi->addr, (char*)name);
|
|
|
|
|
|
|
|
|
|
NSDebugFLLog(@"NSMessagePort", @"Encoded port as '%s'", pi->addr);
|
|
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Older systems (Solaris) compatibility */
|
|
|
|
|
#ifndef AF_LOCAL
|
|
|
|
|
#define AF_LOCAL AF_UNIX
|
|
|
|
|
#define PF_LOCAL PF_UNIX
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef SUN_LEN
|
|
|
|
|
#define SUN_LEN(su) \
|
|
|
|
|
(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define GS_CONNECTION_MSG 0
|
|
|
|
|
#define NETBLOCK 8192
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Theory of operation
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Private interfaces */
|
|
|
|
|
|
2003-07-15 05:21:34 +00:00
|
|
|
|
/*
|
|
|
|
|
* Here is how data is transmitted over a socket -
|
|
|
|
|
* Initially the process making the connection sends an item of type
|
|
|
|
|
* GSP_PORT to tell the remote end what port is connecting to it.
|
|
|
|
|
* Therafter, all communication is via port messages. Each port message
|
|
|
|
|
* consists of an item of type GSP_HEAD followed by zero or more items
|
|
|
|
|
* of type GSP_PORT or GSP_DATA. The number of items in a port message
|
|
|
|
|
* is encoded in the 'nItems' field of the header.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
|
GS_H_UNCON = 0, // Currently idle and unconnected.
|
|
|
|
|
GS_H_TRYCON, // Trying connection (outgoing).
|
|
|
|
|
GS_H_ACCEPT, // Making initial connection (incoming).
|
|
|
|
|
GS_H_CONNECTED // Currently connected.
|
|
|
|
|
} GSHandleState;
|
|
|
|
|
|
2009-01-12 18:36:37 +00:00
|
|
|
|
@interface GSMessageHandle : NSObject <RunLoopEvents>
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
int desc; /* File descriptor for I/O. */
|
|
|
|
|
unsigned wItem; /* Index of item being written. */
|
|
|
|
|
NSMutableData *wData; /* Data object being written. */
|
|
|
|
|
unsigned wLength; /* Ammount written so far. */
|
|
|
|
|
NSMutableArray *wMsgs; /* Message in progress. */
|
|
|
|
|
NSMutableData *rData; /* Buffer for incoming data */
|
2006-01-11 08:37:16 +00:00
|
|
|
|
uint32_t rLength; /* Amount read so far. */
|
|
|
|
|
uint32_t rWant; /* Amount desired. */
|
2003-07-15 05:21:34 +00:00
|
|
|
|
NSMutableArray *rItems; /* Message in progress. */
|
|
|
|
|
GSPortItemType rType; /* Type of data being read. */
|
2006-01-11 08:37:16 +00:00
|
|
|
|
uint32_t rId; /* Id of incoming message. */
|
2003-07-15 05:21:34 +00:00
|
|
|
|
unsigned nItems; /* Number of items to be read. */
|
|
|
|
|
GSHandleState state; /* State of the handle. */
|
|
|
|
|
unsigned int addrNum; /* Address number within host. */
|
|
|
|
|
@public
|
|
|
|
|
NSRecursiveLock *myLock; /* Lock for this handle. */
|
|
|
|
|
BOOL caller; /* Did we connect to other end? */
|
|
|
|
|
BOOL valid;
|
|
|
|
|
NSMessagePort *recvPort;
|
|
|
|
|
NSMessagePort *sendPort;
|
|
|
|
|
struct sockaddr_un sockAddr; /* Far end of connection. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (GSMessageHandle*) handleWithDescriptor: (int)d;
|
|
|
|
|
- (BOOL) connectToPort: (NSMessagePort*)aPort beforeDate: (NSDate*)when;
|
|
|
|
|
- (int) descriptor;
|
|
|
|
|
- (void) invalidate;
|
|
|
|
|
- (BOOL) isValid;
|
|
|
|
|
- (void) receivedEvent: (void*)data
|
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
|
extra: (void*)extra
|
|
|
|
|
forMode: (NSString*)mode;
|
|
|
|
|
- (NSMessagePort*) recvPort;
|
|
|
|
|
- (BOOL) sendMessage: (NSArray*)components beforeDate: (NSDate*)when;
|
|
|
|
|
- (NSMessagePort*) sendPort;
|
|
|
|
|
- (void) setState: (GSHandleState)s;
|
|
|
|
|
- (GSHandleState) state;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation GSMessageHandle
|
|
|
|
|
|
|
|
|
|
static Class mutableArrayClass;
|
|
|
|
|
static Class mutableDataClass;
|
|
|
|
|
static Class portMessageClass;
|
|
|
|
|
static Class runLoopClass;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+ (id) allocWithZone: (NSZone*)zone
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
|
format: @"attempt to alloc a GSMessageHandle!"];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (GSMessageHandle*) handleWithDescriptor: (int)d
|
|
|
|
|
{
|
|
|
|
|
GSMessageHandle *handle;
|
|
|
|
|
int e;
|
|
|
|
|
|
|
|
|
|
if (d < 0)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"illegal descriptor (%d) for message handle", d);
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
if ((e = fcntl(d, F_GETFL, 0)) >= 0)
|
|
|
|
|
{
|
|
|
|
|
e |= NBLK_OPT;
|
|
|
|
|
if (fcntl(d, F_SETFL, e) < 0)
|
|
|
|
|
{
|
2006-10-09 14:00:01 +00:00
|
|
|
|
NSLog(@"unable to set non-blocking mode on %d - %@",
|
2006-10-20 10:56:27 +00:00
|
|
|
|
d, [NSError _last]);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2006-10-09 14:00:01 +00:00
|
|
|
|
NSLog(@"unable to get non-blocking mode on %d - %@",
|
2006-10-20 10:56:27 +00:00
|
|
|
|
d, [NSError _last]);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
handle = (GSMessageHandle*)NSAllocateObject(self, 0, NSDefaultMallocZone());
|
|
|
|
|
handle->desc = d;
|
|
|
|
|
handle->wMsgs = [NSMutableArray new];
|
2004-02-08 09:42:38 +00:00
|
|
|
|
handle->myLock = [GSLazyRecursiveLock new];
|
2003-07-15 05:21:34 +00:00
|
|
|
|
handle->valid = YES;
|
|
|
|
|
return AUTORELEASE(handle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [GSMessageHandle class])
|
|
|
|
|
{
|
|
|
|
|
mutableArrayClass = [NSMutableArray class];
|
|
|
|
|
mutableDataClass = [NSMutableData class];
|
|
|
|
|
portMessageClass = [NSPortMessage class];
|
|
|
|
|
runLoopClass = [NSRunLoop class];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) connectToPort: (NSMessagePort*)aPort beforeDate: (NSDate*)when
|
|
|
|
|
{
|
|
|
|
|
NSRunLoop *l;
|
|
|
|
|
const unsigned char *name;
|
|
|
|
|
|
|
|
|
|
M_LOCK(myLock);
|
2005-02-22 14:17:22 +00:00
|
|
|
|
NSDebugMLLog(@"NSMessagePort", @"Connecting on 0x%x before %@", self, when);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
if (state != GS_H_UNCON)
|
|
|
|
|
{
|
|
|
|
|
BOOL result;
|
|
|
|
|
|
|
|
|
|
if (state == GS_H_CONNECTED) /* Already connected. */
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"attempting connect on connected handle");
|
|
|
|
|
result = YES;
|
|
|
|
|
}
|
|
|
|
|
else if (state == GS_H_ACCEPT) /* Impossible. */
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"attempting connect with accepting handle");
|
|
|
|
|
result = NO;
|
|
|
|
|
}
|
|
|
|
|
else /* Already connecting. */
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"attempting connect while connecting");
|
|
|
|
|
result = NO;
|
|
|
|
|
}
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (recvPort == nil || aPort == nil)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"attempting connect with port(s) unset");
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
return NO; /* impossible. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
name = [aPort _name];
|
|
|
|
|
memset(&sockAddr, '\0', sizeof(sockAddr));
|
|
|
|
|
sockAddr.sun_family = AF_LOCAL;
|
2005-07-08 11:48:37 +00:00
|
|
|
|
strncpy(sockAddr.sun_path, (char*)name, sizeof(sockAddr.sun_path));
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
|
|
|
|
if (connect(desc, (struct sockaddr*)&sockAddr, SUN_LEN(&sockAddr)) < 0)
|
|
|
|
|
{
|
|
|
|
|
if (errno != EINPROGRESS)
|
|
|
|
|
{
|
2006-10-09 14:00:01 +00:00
|
|
|
|
NSLog(@"unable to make connection to %s - %@",
|
2006-10-20 10:56:27 +00:00
|
|
|
|
sockAddr.sun_path, [NSError _last]);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
state = GS_H_TRYCON;
|
|
|
|
|
l = [NSRunLoop currentRunLoop];
|
2006-01-11 09:32:13 +00:00
|
|
|
|
[l addEvent: (void*)(uintptr_t)desc
|
2003-07-15 05:21:34 +00:00
|
|
|
|
type: ET_WDESC
|
|
|
|
|
watcher: self
|
|
|
|
|
forMode: NSConnectionReplyMode];
|
2006-01-11 09:32:13 +00:00
|
|
|
|
[l addEvent: (void*)(uintptr_t)desc
|
2005-11-01 20:37:34 +00:00
|
|
|
|
type: ET_WDESC
|
|
|
|
|
watcher: self
|
|
|
|
|
forMode: NSDefaultRunLoopMode];
|
2004-01-23 18:12:37 +00:00
|
|
|
|
|
2003-07-15 05:21:34 +00:00
|
|
|
|
while (valid == YES && state == GS_H_TRYCON
|
|
|
|
|
&& [when timeIntervalSinceNow] > 0)
|
|
|
|
|
{
|
|
|
|
|
[l runMode: NSConnectionReplyMode beforeDate: when];
|
|
|
|
|
}
|
2004-01-23 18:12:37 +00:00
|
|
|
|
|
2006-01-11 09:32:13 +00:00
|
|
|
|
[l removeEvent: (void*)(uintptr_t)desc
|
2003-07-15 05:21:34 +00:00
|
|
|
|
type: ET_WDESC
|
|
|
|
|
forMode: NSConnectionReplyMode
|
|
|
|
|
all: NO];
|
2006-01-11 09:32:13 +00:00
|
|
|
|
[l removeEvent: (void*)(uintptr_t)desc
|
2005-11-01 20:37:34 +00:00
|
|
|
|
type: ET_WDESC
|
|
|
|
|
forMode: NSDefaultRunLoopMode
|
|
|
|
|
all: NO];
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
|
|
|
|
if (state == GS_H_TRYCON)
|
|
|
|
|
{
|
|
|
|
|
state = GS_H_UNCON;
|
|
|
|
|
addrNum = 0;
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
return NO; /* Timed out */
|
|
|
|
|
}
|
|
|
|
|
else if (state == GS_H_UNCON)
|
|
|
|
|
{
|
|
|
|
|
addrNum = 0;
|
|
|
|
|
state = GS_H_UNCON;
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2005-06-15 03:56:13 +00:00
|
|
|
|
int status = 1;
|
|
|
|
|
|
|
|
|
|
setsockopt(desc, SOL_SOCKET, SO_KEEPALIVE, (char*)&status,
|
|
|
|
|
sizeof(status));
|
2003-07-15 05:21:34 +00:00
|
|
|
|
addrNum = 0;
|
|
|
|
|
caller = YES;
|
|
|
|
|
[aPort addHandle: self forSend: YES];
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
2009-01-12 18:36:37 +00:00
|
|
|
|
[self finalize];
|
2003-07-15 05:21:34 +00:00
|
|
|
|
DESTROY(rData);
|
|
|
|
|
DESTROY(rItems);
|
|
|
|
|
DESTROY(wMsgs);
|
|
|
|
|
DESTROY(myLock);
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) description
|
|
|
|
|
{
|
|
|
|
|
return [NSString stringWithFormat: @"<GSMessageHandle %p (%d) to %s>",
|
|
|
|
|
self, desc, sockAddr.sun_path];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (int) descriptor
|
|
|
|
|
{
|
|
|
|
|
return desc;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-12 18:36:37 +00:00
|
|
|
|
- (void) finalize
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
[self invalidate];
|
|
|
|
|
(void)close(desc);
|
|
|
|
|
desc = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) invalidate
|
|
|
|
|
{
|
|
|
|
|
if (valid == YES)
|
|
|
|
|
{
|
|
|
|
|
M_LOCK(myLock);
|
|
|
|
|
if (valid == YES)
|
2005-02-22 11:22:44 +00:00
|
|
|
|
{
|
2003-07-15 05:21:34 +00:00
|
|
|
|
NSRunLoop *l;
|
|
|
|
|
|
|
|
|
|
valid = NO;
|
|
|
|
|
l = [runLoopClass currentRunLoop];
|
2006-01-11 09:32:13 +00:00
|
|
|
|
[l removeEvent: (void*)(uintptr_t)desc
|
2003-07-15 05:21:34 +00:00
|
|
|
|
type: ET_RDESC
|
|
|
|
|
forMode: nil
|
|
|
|
|
all: YES];
|
2006-01-11 09:32:13 +00:00
|
|
|
|
[l removeEvent: (void*)(uintptr_t)desc
|
2003-07-15 05:21:34 +00:00
|
|
|
|
type: ET_WDESC
|
|
|
|
|
forMode: nil
|
|
|
|
|
all: YES];
|
2005-02-22 14:17:22 +00:00
|
|
|
|
NSDebugMLLog(@"NSMessagePort", @"invalidated 0x%x", self);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
[[self recvPort] removeHandle: self];
|
|
|
|
|
[[self sendPort] removeHandle: self];
|
|
|
|
|
}
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) isValid
|
|
|
|
|
{
|
|
|
|
|
return valid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSMessagePort*) recvPort
|
|
|
|
|
{
|
|
|
|
|
if (recvPort == nil)
|
|
|
|
|
return nil;
|
|
|
|
|
else
|
|
|
|
|
return GS_GC_UNHIDE(recvPort);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) receivedEvent: (void*)data
|
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
|
extra: (void*)extra
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
2004-08-24 08:08:14 +00:00
|
|
|
|
NSDebugMLLog(@"NSMessagePort_details",
|
2005-02-22 14:17:22 +00:00
|
|
|
|
@"received %s event on 0x%x",
|
2009-03-21 09:04:02 +00:00
|
|
|
|
type != ET_WDESC ? "read" : "write", self);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
/*
|
|
|
|
|
* If we have been invalidated (desc < 0) then we should ignore this
|
|
|
|
|
* event and remove ourself from the runloop.
|
|
|
|
|
*/
|
|
|
|
|
if (desc < 0)
|
|
|
|
|
{
|
|
|
|
|
NSRunLoop *l = [runLoopClass currentRunLoop];
|
|
|
|
|
|
|
|
|
|
[l removeEvent: data
|
|
|
|
|
type: ET_WDESC
|
|
|
|
|
forMode: mode
|
|
|
|
|
all: YES];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
M_LOCK(myLock);
|
|
|
|
|
|
2009-03-21 09:04:02 +00:00
|
|
|
|
if (type != ET_WDESC)
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned want;
|
|
|
|
|
void *bytes;
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Make sure we have a buffer big enough to hold all the data we are
|
|
|
|
|
* expecting, or NETBLOCK bytes, whichever is greater.
|
|
|
|
|
*/
|
|
|
|
|
if (rData == nil)
|
|
|
|
|
{
|
|
|
|
|
rData = [[mutableDataClass alloc] initWithLength: NETBLOCK];
|
|
|
|
|
rWant = sizeof(GSPortItemHeader);
|
|
|
|
|
rLength = 0;
|
|
|
|
|
want = NETBLOCK;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
want = [rData length];
|
|
|
|
|
if (want < rWant)
|
|
|
|
|
{
|
|
|
|
|
want = rWant;
|
|
|
|
|
[rData setLength: want];
|
|
|
|
|
}
|
|
|
|
|
if (want < NETBLOCK)
|
|
|
|
|
{
|
|
|
|
|
want = NETBLOCK;
|
|
|
|
|
[rData setLength: want];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now try to fill the buffer with data.
|
|
|
|
|
*/
|
|
|
|
|
bytes = [rData mutableBytes];
|
|
|
|
|
res = read(desc, bytes + rLength, want - rLength);
|
|
|
|
|
if (res <= 0)
|
|
|
|
|
{
|
|
|
|
|
if (res == 0)
|
|
|
|
|
{
|
2005-02-22 14:17:22 +00:00
|
|
|
|
NSDebugMLLog(@"NSMessagePort", @"read eof on 0x%x", self);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
[self invalidate];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (errno != EINTR && errno != EAGAIN)
|
|
|
|
|
{
|
|
|
|
|
NSDebugMLLog(@"NSMessagePort",
|
2006-10-20 10:56:27 +00:00
|
|
|
|
@"read failed - %@ on 0x%p", [NSError _last], self);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
[self invalidate];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
res = 0; /* Interrupted - continue */
|
|
|
|
|
}
|
2004-08-24 08:08:14 +00:00
|
|
|
|
NSDebugMLLog(@"NSMessagePort_details",
|
2005-02-22 14:17:22 +00:00
|
|
|
|
@"read %d bytes on 0x%x", res, self);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
rLength += res;
|
|
|
|
|
|
|
|
|
|
while (valid == YES && rLength >= rWant)
|
|
|
|
|
{
|
|
|
|
|
BOOL shouldDispatch = NO;
|
|
|
|
|
|
|
|
|
|
switch (rType)
|
|
|
|
|
{
|
|
|
|
|
case GSP_NONE:
|
|
|
|
|
{
|
|
|
|
|
GSPortItemHeader *h;
|
|
|
|
|
unsigned l;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We have read an item header - set up to read the
|
|
|
|
|
* remainder of the item.
|
|
|
|
|
*/
|
|
|
|
|
h = (GSPortItemHeader*)bytes;
|
|
|
|
|
rType = GSSwapBigI32ToHost(h->type);
|
|
|
|
|
l = GSSwapBigI32ToHost(h->length);
|
|
|
|
|
if (rType == GSP_PORT)
|
|
|
|
|
{
|
|
|
|
|
if (l > 512)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"%@ - unreasonable length (%u) for port",
|
|
|
|
|
self, l);
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
[self invalidate];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* For a port, we leave the item header in the data
|
|
|
|
|
* so that our decode function can check length info.
|
|
|
|
|
*/
|
|
|
|
|
rWant += l;
|
|
|
|
|
}
|
|
|
|
|
else if (rType == GSP_DATA)
|
|
|
|
|
{
|
|
|
|
|
if (l == 0)
|
|
|
|
|
{
|
|
|
|
|
NSData *d;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* For a zero-length data chunk, we create an empty
|
|
|
|
|
* data object and add it to the current message.
|
|
|
|
|
*/
|
|
|
|
|
rType = GSP_NONE; /* ready for a new item */
|
|
|
|
|
rLength -= rWant;
|
|
|
|
|
if (rLength > 0)
|
|
|
|
|
{
|
2004-07-13 14:11:27 +00:00
|
|
|
|
memmove(bytes, bytes + rWant, rLength);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
rWant = sizeof(GSPortItemHeader);
|
|
|
|
|
d = [mutableDataClass new];
|
|
|
|
|
[rItems addObject: d];
|
|
|
|
|
RELEASE(d);
|
|
|
|
|
if (nItems == [rItems count])
|
|
|
|
|
{
|
|
|
|
|
shouldDispatch = YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (l > maxDataLength)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"%@ - unreasonable length (%u) for data",
|
|
|
|
|
self, l);
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
[self invalidate];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* If not a port or zero length data,
|
|
|
|
|
* we discard the data read so far and fill the
|
|
|
|
|
* data object with the data item from the msg.
|
|
|
|
|
*/
|
|
|
|
|
rLength -= rWant;
|
|
|
|
|
if (rLength > 0)
|
|
|
|
|
{
|
2004-07-13 14:11:27 +00:00
|
|
|
|
memmove(bytes, bytes + rWant, rLength);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
rWant = l;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (rType == GSP_HEAD)
|
|
|
|
|
{
|
|
|
|
|
if (l > maxDataLength)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"%@ - unreasonable length (%u) for data",
|
|
|
|
|
self, l);
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
[self invalidate];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* If not a port or zero length data,
|
|
|
|
|
* we discard the data read so far and fill the
|
|
|
|
|
* data object with the data item from the msg.
|
|
|
|
|
*/
|
|
|
|
|
rLength -= rWant;
|
|
|
|
|
if (rLength > 0)
|
|
|
|
|
{
|
2004-07-13 14:11:27 +00:00
|
|
|
|
memmove(bytes, bytes + rWant, rLength);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
rWant = l;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2004-08-24 08:08:14 +00:00
|
|
|
|
NSLog(@"%@ - bad data received on port handle, rType=%i",
|
|
|
|
|
self, rType);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
[self invalidate];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GSP_HEAD:
|
|
|
|
|
{
|
|
|
|
|
GSPortMsgHeader *h;
|
|
|
|
|
|
|
|
|
|
rType = GSP_NONE; /* ready for a new item */
|
|
|
|
|
/*
|
|
|
|
|
* We have read a message header - set up to read the
|
|
|
|
|
* remainder of the message.
|
|
|
|
|
*/
|
|
|
|
|
h = (GSPortMsgHeader*)bytes;
|
|
|
|
|
rId = GSSwapBigI32ToHost(h->mId);
|
|
|
|
|
nItems = GSSwapBigI32ToHost(h->nItems);
|
|
|
|
|
NSAssert(nItems >0, NSInternalInconsistencyException);
|
|
|
|
|
rItems
|
|
|
|
|
= [mutableArrayClass allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
rItems = [rItems initWithCapacity: nItems];
|
|
|
|
|
if (rWant > sizeof(GSPortMsgHeader))
|
|
|
|
|
{
|
|
|
|
|
NSData *d;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The first data item of the message was included in
|
|
|
|
|
* the header - so add it to the rItems array.
|
|
|
|
|
*/
|
|
|
|
|
rWant -= sizeof(GSPortMsgHeader);
|
|
|
|
|
d = [mutableDataClass alloc];
|
|
|
|
|
d = [d initWithBytes: bytes + sizeof(GSPortMsgHeader)
|
|
|
|
|
length: rWant];
|
|
|
|
|
[rItems addObject: d];
|
|
|
|
|
RELEASE(d);
|
|
|
|
|
rWant += sizeof(GSPortMsgHeader);
|
|
|
|
|
rLength -= rWant;
|
|
|
|
|
if (rLength > 0)
|
|
|
|
|
{
|
2004-07-13 14:11:27 +00:00
|
|
|
|
memmove(bytes, bytes + rWant, rLength);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
rWant = sizeof(GSPortItemHeader);
|
|
|
|
|
if (nItems == 1)
|
|
|
|
|
{
|
|
|
|
|
shouldDispatch = YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* want to read another item
|
|
|
|
|
*/
|
|
|
|
|
rLength -= rWant;
|
|
|
|
|
if (rLength > 0)
|
|
|
|
|
{
|
2004-07-13 14:11:27 +00:00
|
|
|
|
memmove(bytes, bytes + rWant, rLength);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
rWant = sizeof(GSPortItemHeader);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GSP_DATA:
|
|
|
|
|
{
|
|
|
|
|
NSData *d;
|
|
|
|
|
|
|
|
|
|
rType = GSP_NONE; /* ready for a new item */
|
|
|
|
|
d = [mutableDataClass allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
d = [d initWithBytes: bytes length: rWant];
|
|
|
|
|
[rItems addObject: d];
|
|
|
|
|
RELEASE(d);
|
|
|
|
|
rLength -= rWant;
|
|
|
|
|
if (rLength > 0)
|
|
|
|
|
{
|
2004-07-13 14:11:27 +00:00
|
|
|
|
memmove(bytes, bytes + rWant, rLength);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
rWant = sizeof(GSPortItemHeader);
|
|
|
|
|
if (nItems == [rItems count])
|
|
|
|
|
{
|
|
|
|
|
shouldDispatch = YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case GSP_PORT:
|
|
|
|
|
{
|
|
|
|
|
NSMessagePort *p;
|
|
|
|
|
|
|
|
|
|
rType = GSP_NONE; /* ready for a new item */
|
|
|
|
|
p = decodePort(rData);
|
|
|
|
|
if (p == nil)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"%@ - unable to decode remote port", self);
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
[self invalidate];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Set up to read another item header.
|
|
|
|
|
*/
|
|
|
|
|
rLength -= rWant;
|
|
|
|
|
if (rLength > 0)
|
|
|
|
|
{
|
2004-07-13 14:11:27 +00:00
|
|
|
|
memmove(bytes, bytes + rWant, rLength);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
rWant = sizeof(GSPortItemHeader);
|
|
|
|
|
|
|
|
|
|
if (state == GS_H_ACCEPT)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* This is the initial port information on a new
|
|
|
|
|
* connection - set up port relationships.
|
|
|
|
|
*/
|
|
|
|
|
state = GS_H_CONNECTED;
|
|
|
|
|
[p addHandle: self forSend: YES];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* This is a port within a port message - add
|
|
|
|
|
* it to the message components.
|
|
|
|
|
*/
|
|
|
|
|
[rItems addObject: p];
|
|
|
|
|
if (nItems == [rItems count])
|
|
|
|
|
{
|
|
|
|
|
shouldDispatch = YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (shouldDispatch == YES)
|
|
|
|
|
{
|
|
|
|
|
NSPortMessage *pm;
|
|
|
|
|
NSMessagePort *rp = [self recvPort];
|
|
|
|
|
|
|
|
|
|
pm = [portMessageClass allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
pm = [pm initWithSendPort: [self sendPort]
|
|
|
|
|
receivePort: rp
|
|
|
|
|
components: rItems];
|
|
|
|
|
[pm setMsgid: rId];
|
|
|
|
|
rId = 0;
|
|
|
|
|
DESTROY(rItems);
|
|
|
|
|
NSDebugMLLog(@"NSMessagePort_details",
|
2005-02-22 14:17:22 +00:00
|
|
|
|
@"got message %@ on 0x%x", pm, self);
|
2009-01-12 12:48:46 +00:00
|
|
|
|
IF_NO_GC([rp retain];)
|
2003-07-15 05:21:34 +00:00
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
[rp handlePortMessage: pm];
|
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
M_LOCK(myLock);
|
|
|
|
|
RELEASE(pm);
|
|
|
|
|
RELEASE(rp);
|
|
|
|
|
[localException raise];
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER
|
|
|
|
|
M_LOCK(myLock);
|
|
|
|
|
RELEASE(pm);
|
|
|
|
|
RELEASE(rp);
|
|
|
|
|
bytes = [rData mutableBytes];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (state == GS_H_TRYCON) /* Connection attempt. */
|
|
|
|
|
{
|
2005-07-08 11:48:37 +00:00
|
|
|
|
int res = 0;
|
|
|
|
|
unsigned len = sizeof(res);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
2006-11-30 09:00:44 +00:00
|
|
|
|
if (getsockopt(desc, SOL_SOCKET, SO_ERROR, (char*)&res, &len) != 0)
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
state = GS_H_UNCON;
|
2006-10-20 10:56:27 +00:00
|
|
|
|
NSLog(@"connect attempt failed - %@", [NSError _last]);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
2006-11-30 09:00:44 +00:00
|
|
|
|
else if (res != 0)
|
|
|
|
|
{
|
|
|
|
|
state = GS_H_UNCON;
|
|
|
|
|
NSLog(@"connect attempt failed - %@",
|
|
|
|
|
[NSError _systemError: res]);
|
|
|
|
|
}
|
2003-07-15 05:21:34 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSData *d = newDataWithEncodedPort([self recvPort]);
|
|
|
|
|
|
|
|
|
|
len = write(desc, [d bytes], [d length]);
|
|
|
|
|
if (len == (int)[d length])
|
|
|
|
|
{
|
|
|
|
|
NSDebugMLLog(@"NSMessagePort_details",
|
2005-02-22 14:17:22 +00:00
|
|
|
|
@"wrote %d bytes on 0x%x", len, self);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
state = GS_H_CONNECTED;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
state = GS_H_UNCON;
|
2006-10-09 14:00:01 +00:00
|
|
|
|
NSLog(@"connect write attempt failed - %@",
|
2006-10-20 10:56:27 +00:00
|
|
|
|
[NSError _last]);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
RELEASE(d);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int res;
|
|
|
|
|
unsigned l;
|
|
|
|
|
const void *b;
|
|
|
|
|
|
|
|
|
|
if (wData == nil)
|
|
|
|
|
{
|
|
|
|
|
if ([wMsgs count] > 0)
|
|
|
|
|
{
|
|
|
|
|
NSArray *components = [wMsgs objectAtIndex: 0];
|
|
|
|
|
|
|
|
|
|
wData = [components objectAtIndex: wItem++];
|
|
|
|
|
wLength = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// NSLog(@"No messages to write on 0x%x.", self);
|
2004-01-23 18:12:37 +00:00
|
|
|
|
M_UNLOCK(myLock);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
b = [wData bytes];
|
|
|
|
|
l = [wData length];
|
|
|
|
|
res = write(desc, b + wLength, l - wLength);
|
|
|
|
|
if (res < 0)
|
|
|
|
|
{
|
|
|
|
|
if (errno != EINTR && errno != EAGAIN)
|
|
|
|
|
{
|
2006-10-20 10:56:27 +00:00
|
|
|
|
NSLog(@"write attempt failed - %@", [NSError _last]);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
[self invalidate];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSDebugMLLog(@"NSMessagePort_details",
|
2005-02-22 14:17:22 +00:00
|
|
|
|
@"wrote %d bytes on 0x%x", res, self);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
wLength += res;
|
|
|
|
|
if (wLength == l)
|
|
|
|
|
{
|
|
|
|
|
NSArray *components;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We have completed a data item so see what is
|
|
|
|
|
* left of the message components.
|
|
|
|
|
*/
|
|
|
|
|
components = [wMsgs objectAtIndex: 0];
|
|
|
|
|
wLength = 0;
|
|
|
|
|
if ([components count] > wItem)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* More to write - get next item.
|
|
|
|
|
*/
|
|
|
|
|
wData = [components objectAtIndex: wItem++];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* message completed - remove from list.
|
|
|
|
|
*/
|
|
|
|
|
NSDebugMLLog(@"NSMessagePort_details",
|
2005-02-22 14:17:22 +00:00
|
|
|
|
@"completed 0x%x on 0x%x", components, self);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
wData = nil;
|
|
|
|
|
wItem = 0;
|
|
|
|
|
[wMsgs removeObjectAtIndex: 0];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) sendMessage: (NSArray*)components beforeDate: (NSDate*)when
|
|
|
|
|
{
|
|
|
|
|
NSRunLoop *l;
|
|
|
|
|
BOOL sent = NO;
|
|
|
|
|
|
|
|
|
|
NSAssert([components count] > 0, NSInternalInconsistencyException);
|
|
|
|
|
NSDebugMLLog(@"NSMessagePort_details",
|
2005-02-22 14:17:22 +00:00
|
|
|
|
@"Sending message 0x%x %@ on 0x%x(%d) before %@",
|
|
|
|
|
components, components, self, desc, when);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
M_LOCK(myLock);
|
|
|
|
|
[wMsgs addObject: components];
|
|
|
|
|
|
|
|
|
|
l = [runLoopClass currentRunLoop];
|
|
|
|
|
|
2009-01-12 12:48:46 +00:00
|
|
|
|
IF_NO_GC([self retain];)
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
2006-01-11 09:32:13 +00:00
|
|
|
|
[l addEvent: (void*)(uintptr_t)desc
|
2003-07-15 05:21:34 +00:00
|
|
|
|
type: ET_WDESC
|
|
|
|
|
watcher: self
|
|
|
|
|
forMode: NSConnectionReplyMode];
|
2006-01-11 09:32:13 +00:00
|
|
|
|
[l addEvent: (void*)(uintptr_t)desc
|
2005-11-01 20:37:34 +00:00
|
|
|
|
type: ET_WDESC
|
|
|
|
|
watcher: self
|
|
|
|
|
forMode: NSDefaultRunLoopMode];
|
2004-01-23 18:12:37 +00:00
|
|
|
|
|
2003-07-15 05:21:34 +00:00
|
|
|
|
while (valid == YES
|
|
|
|
|
&& [wMsgs indexOfObjectIdenticalTo: components] != NSNotFound
|
|
|
|
|
&& [when timeIntervalSinceNow] > 0)
|
|
|
|
|
{
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
[l runMode: NSConnectionReplyMode beforeDate: when];
|
|
|
|
|
M_LOCK(myLock);
|
|
|
|
|
}
|
2004-01-23 18:12:37 +00:00
|
|
|
|
|
2006-01-11 09:32:13 +00:00
|
|
|
|
[l removeEvent: (void*)(uintptr_t)desc
|
2004-01-23 18:12:37 +00:00
|
|
|
|
type: ET_WDESC
|
|
|
|
|
forMode: NSConnectionReplyMode
|
|
|
|
|
all: NO];
|
2006-01-11 09:32:13 +00:00
|
|
|
|
[l removeEvent: (void*)(uintptr_t)desc
|
2005-11-01 20:37:34 +00:00
|
|
|
|
type: ET_WDESC
|
|
|
|
|
forMode: NSDefaultRunLoopMode
|
|
|
|
|
all: NO];
|
2004-01-23 18:12:37 +00:00
|
|
|
|
|
2003-07-15 05:21:34 +00:00
|
|
|
|
if ([wMsgs indexOfObjectIdenticalTo: components] == NSNotFound)
|
|
|
|
|
{
|
|
|
|
|
sent = YES;
|
|
|
|
|
}
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
RELEASE(self);
|
|
|
|
|
NSDebugMLLog(@"NSMessagePort_details",
|
2005-02-22 14:17:22 +00:00
|
|
|
|
@"Message send 0x%x on 0x%x status %d", components, self, sent);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
return sent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSMessagePort*) sendPort
|
|
|
|
|
{
|
|
|
|
|
if (sendPort == nil)
|
|
|
|
|
return nil;
|
|
|
|
|
else if (caller == YES)
|
|
|
|
|
return GS_GC_UNHIDE(sendPort); // We called, so port is not retained.
|
|
|
|
|
else
|
|
|
|
|
return sendPort; // Retained port.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setState: (GSHandleState)s
|
|
|
|
|
{
|
|
|
|
|
state = s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (GSHandleState) state
|
|
|
|
|
{
|
|
|
|
|
return state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@interface NSMessagePort (RunLoop) <RunLoopEvents>
|
|
|
|
|
- (void) receivedEvent: (void*)data
|
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
|
extra: (void*)extra
|
|
|
|
|
forMode: (NSString*)mode;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation NSMessagePort
|
|
|
|
|
|
|
|
|
|
static NSRecursiveLock *messagePortLock = nil;
|
|
|
|
|
|
|
|
|
|
/*
|
2005-11-04 17:58:27 +00:00
|
|
|
|
* Maps port name to NSMessagePort objects.
|
|
|
|
|
*/
|
2003-07-15 05:21:34 +00:00
|
|
|
|
static NSMapTable *messagePortMap = 0;
|
|
|
|
|
static Class messagePortClass;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void clean_up_sockets(void)
|
|
|
|
|
{
|
|
|
|
|
NSMessagePort *port;
|
2005-11-04 17:58:27 +00:00
|
|
|
|
NSData *name;
|
2003-07-15 05:21:34 +00:00
|
|
|
|
NSMapEnumerator mEnum;
|
2004-05-17 13:22:52 +00:00
|
|
|
|
BOOL unknownThread = GSRegisterCurrentThread();
|
|
|
|
|
CREATE_AUTORELEASE_POOL(arp);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
|
|
|
|
mEnum = NSEnumerateMapTable(messagePortMap);
|
2005-11-04 17:58:27 +00:00
|
|
|
|
while (NSNextMapEnumeratorPair(&mEnum, (void *)&name, (void *)&port))
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
if ([port _listener] != -1)
|
2005-11-04 17:58:27 +00:00
|
|
|
|
unlink([name bytes]);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
NSEndMapTableEnumeration(&mEnum);
|
2009-01-12 12:48:46 +00:00
|
|
|
|
IF_NO_GC(DESTROY(arp);)
|
2004-05-17 13:22:52 +00:00
|
|
|
|
if (unknownThread == YES)
|
|
|
|
|
{
|
|
|
|
|
GSUnregisterCurrentThread();
|
|
|
|
|
}
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-11-04 17:58:27 +00:00
|
|
|
|
typedef struct {
|
|
|
|
|
NSData *_name;
|
|
|
|
|
NSRecursiveLock *_myLock;
|
|
|
|
|
NSMapTable *_handles; /* Handles indexed by socket. */
|
|
|
|
|
int _listener; /* Descriptor to listen on. */
|
|
|
|
|
} internal;
|
|
|
|
|
#define name ((internal*)_internal)->_name
|
|
|
|
|
#define myLock ((internal*)_internal)->_myLock
|
|
|
|
|
#define handles ((internal*)_internal)->_handles
|
|
|
|
|
#define lDesc ((internal*)_internal)->_listener
|
|
|
|
|
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [NSMessagePort class])
|
|
|
|
|
{
|
|
|
|
|
messagePortClass = self;
|
|
|
|
|
messagePortMap = NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks,
|
|
|
|
|
NSNonOwnedPointerMapValueCallBacks, 0);
|
|
|
|
|
|
2004-02-08 09:42:38 +00:00
|
|
|
|
messagePortLock = [GSLazyRecursiveLock new];
|
2003-07-15 05:21:34 +00:00
|
|
|
|
atexit(clean_up_sockets);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (id) new
|
|
|
|
|
{
|
2005-11-01 20:37:34 +00:00
|
|
|
|
static int unique_index = 0;
|
2004-03-28 05:31:16 +00:00
|
|
|
|
NSString *path;
|
|
|
|
|
NSNumber *p = [NSNumber numberWithInt: 0700];
|
|
|
|
|
NSDictionary *attr;
|
|
|
|
|
|
|
|
|
|
attr = [NSDictionary dictionaryWithObject: p
|
|
|
|
|
forKey: NSFilePosixPermissions];
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
|
|
|
|
path = NSTemporaryDirectory();
|
|
|
|
|
|
|
|
|
|
path = [path stringByAppendingPathComponent: @"NSMessagePort"];
|
2004-03-28 05:31:16 +00:00
|
|
|
|
[[NSFileManager defaultManager] createDirectoryAtPath: path
|
|
|
|
|
attributes: attr];
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
|
|
|
|
path = [path stringByAppendingPathComponent: @"ports"];
|
2004-03-28 05:31:16 +00:00
|
|
|
|
[[NSFileManager defaultManager] createDirectoryAtPath: path
|
|
|
|
|
attributes: attr];
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
|
|
|
|
M_LOCK(messagePortLock);
|
|
|
|
|
path = [path stringByAppendingPathComponent:
|
2004-03-28 05:31:16 +00:00
|
|
|
|
[NSString stringWithFormat: @"%i.%i",
|
|
|
|
|
[[NSProcessInfo processInfo] processIdentifier], unique_index++]];
|
2003-07-15 05:21:34 +00:00
|
|
|
|
M_UNLOCK(messagePortLock);
|
|
|
|
|
|
2005-07-08 11:48:37 +00:00
|
|
|
|
return RETAIN([self _portWithName:
|
|
|
|
|
(unsigned char*)[path fileSystemRepresentation] listener: YES]);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This is the preferred initialisation method for NSMessagePort
|
|
|
|
|
*
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* 'socketName' is the name of the socket in the port directory
|
2003-07-15 05:21:34 +00:00
|
|
|
|
*/
|
|
|
|
|
+ (NSMessagePort*) _portWithName: (const unsigned char *)socketName
|
2005-11-01 07:21:08 +00:00
|
|
|
|
listener: (BOOL)shouldListen
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
NSMessagePort *port = nil;
|
2004-08-24 08:08:14 +00:00
|
|
|
|
NSData *theName;
|
|
|
|
|
|
|
|
|
|
theName = [[NSData alloc] initWithBytes: socketName
|
2005-07-08 11:48:37 +00:00
|
|
|
|
length: strlen((char*)socketName)+1];
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
|
|
|
|
M_LOCK(messagePortLock);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* First try to find a pre-existing port.
|
|
|
|
|
*/
|
|
|
|
|
port = (NSMessagePort*)NSMapGet(messagePortMap, theName);
|
|
|
|
|
|
|
|
|
|
if (port == nil)
|
|
|
|
|
{
|
|
|
|
|
port = (NSMessagePort*)NSAllocateObject(self, 0, NSDefaultMallocZone());
|
2005-11-01 20:37:34 +00:00
|
|
|
|
port->_internal = (internal*)NSZoneMalloc(NSDefaultMallocZone(),
|
|
|
|
|
sizeof(internal));
|
|
|
|
|
((internal*)(port->_internal))->_name = theName;
|
|
|
|
|
((internal*)(port->_internal))->_listener = -1;
|
|
|
|
|
((internal*)(port->_internal))->_handles
|
|
|
|
|
= NSCreateMapTable(NSIntMapKeyCallBacks,
|
2003-07-15 05:21:34 +00:00
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
2005-11-01 20:37:34 +00:00
|
|
|
|
((internal*)(port->_internal))->_myLock = [GSLazyRecursiveLock new];
|
2003-07-15 05:21:34 +00:00
|
|
|
|
port->_is_valid = YES;
|
|
|
|
|
|
|
|
|
|
if (shouldListen == YES)
|
|
|
|
|
{
|
|
|
|
|
int desc;
|
2005-11-01 07:21:08 +00:00
|
|
|
|
struct sockaddr_un sockAddr;
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
|
|
|
|
/*
|
2005-11-01 07:21:08 +00:00
|
|
|
|
* Need size of buffer for getsockbyname() later.
|
2003-07-15 05:21:34 +00:00
|
|
|
|
*/
|
2005-11-01 07:21:08 +00:00
|
|
|
|
i = sizeof(sockAddr);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
|
|
|
|
/*
|
2005-11-01 07:21:08 +00:00
|
|
|
|
* Creating a new port on the local host - so we must create a
|
|
|
|
|
* listener socket to accept incoming connections.
|
2003-07-15 05:21:34 +00:00
|
|
|
|
*/
|
2005-11-01 07:21:08 +00:00
|
|
|
|
memset(&sockAddr, '\0', sizeof(sockAddr));
|
|
|
|
|
sockAddr.sun_family = AF_LOCAL;
|
|
|
|
|
strncpy(sockAddr.sun_path, (char*)socketName,
|
|
|
|
|
sizeof(sockAddr.sun_path));
|
2003-07-15 05:21:34 +00:00
|
|
|
|
if ((desc = socket(PF_LOCAL, SOCK_STREAM, PF_UNSPEC)) < 0)
|
|
|
|
|
{
|
2006-10-20 10:56:27 +00:00
|
|
|
|
NSLog(@"unable to create socket - %@", [NSError _last]);
|
2005-11-01 07:21:08 +00:00
|
|
|
|
desc = -1;
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
2005-11-01 07:21:08 +00:00
|
|
|
|
else if (bind(desc, (struct sockaddr *)&sockAddr,
|
|
|
|
|
SUN_LEN(&sockAddr)) < 0)
|
|
|
|
|
{
|
|
|
|
|
if (connect(desc, (struct sockaddr*)&sockAddr,
|
|
|
|
|
SUN_LEN(&sockAddr)) < 0)
|
|
|
|
|
{
|
|
|
|
|
NSDebugLLog(@"NSMessagePort", @"not live, reseting");
|
|
|
|
|
unlink((const char*)socketName);
|
|
|
|
|
close(desc);
|
|
|
|
|
if ((desc = socket(PF_LOCAL, SOCK_STREAM, PF_UNSPEC)) < 0)
|
|
|
|
|
{
|
2006-10-09 14:00:01 +00:00
|
|
|
|
NSLog(@"unable to create socket - %@",
|
2006-10-20 10:56:27 +00:00
|
|
|
|
[NSError _last]);
|
2005-11-01 07:21:08 +00:00
|
|
|
|
desc = -1;
|
|
|
|
|
}
|
|
|
|
|
else if (bind(desc, (struct sockaddr *)&sockAddr,
|
|
|
|
|
SUN_LEN(&sockAddr)) < 0)
|
|
|
|
|
{
|
2006-10-09 14:00:01 +00:00
|
|
|
|
NSLog(@"unable to bind to %s - %@",
|
2006-10-20 10:56:27 +00:00
|
|
|
|
sockAddr.sun_path, [NSError _last]);
|
2005-11-01 07:21:08 +00:00
|
|
|
|
(void) close(desc);
|
|
|
|
|
desc = -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2006-10-09 14:00:01 +00:00
|
|
|
|
NSLog(@"unable to bind to %s - %@",
|
2006-10-20 10:56:27 +00:00
|
|
|
|
sockAddr.sun_path, [NSError _last]);
|
2005-11-01 07:21:08 +00:00
|
|
|
|
(void) close(desc);
|
|
|
|
|
desc = -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (desc == -1)
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
DESTROY(port);
|
|
|
|
|
}
|
2005-10-31 20:50:25 +00:00
|
|
|
|
else if (listen(desc, 128) < 0)
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
2006-10-20 10:56:27 +00:00
|
|
|
|
NSLog(@"unable to listen on port - %@", [NSError _last]);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
(void) close(desc);
|
|
|
|
|
DESTROY(port);
|
|
|
|
|
}
|
2005-11-01 07:21:08 +00:00
|
|
|
|
else if (getsockname(desc, (struct sockaddr*)&sockAddr, &i) < 0)
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
2006-10-20 10:56:27 +00:00
|
|
|
|
NSLog(@"unable to get socket name - %@", [NSError _last]);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
(void) close(desc);
|
|
|
|
|
DESTROY(port);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Set up the listening descriptor and the actual message port
|
|
|
|
|
* number (which will have been set to a real port number when
|
|
|
|
|
* we did the 'bind' call.
|
|
|
|
|
*/
|
2005-11-01 20:37:34 +00:00
|
|
|
|
((internal*)port->_internal)->_listener = desc;
|
2003-07-15 05:21:34 +00:00
|
|
|
|
/*
|
|
|
|
|
* Make sure we have the map table for this port.
|
|
|
|
|
*/
|
|
|
|
|
NSMapInsert(messagePortMap, (void*)theName, (void*)port);
|
2004-08-24 08:08:14 +00:00
|
|
|
|
NSDebugMLLog(@"NSMessagePort", @"Created listening port: %@",
|
|
|
|
|
port);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Make sure we have the map table for this port.
|
|
|
|
|
*/
|
|
|
|
|
NSMapInsert(messagePortMap, (void*)theName, (void*)port);
|
|
|
|
|
NSDebugMLLog(@"NSMessagePort", @"Created speaking port: %@", port);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
RELEASE(theName);
|
2009-01-12 12:48:46 +00:00
|
|
|
|
IF_NO_GC([port retain];)
|
2003-07-15 05:21:34 +00:00
|
|
|
|
NSDebugMLLog(@"NSMessagePort", @"Using pre-existing port: %@", port);
|
|
|
|
|
}
|
|
|
|
|
IF_NO_GC(AUTORELEASE(port));
|
|
|
|
|
|
|
|
|
|
M_UNLOCK(messagePortLock);
|
|
|
|
|
return port;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) addHandle: (GSMessageHandle*)handle forSend: (BOOL)send
|
|
|
|
|
{
|
|
|
|
|
M_LOCK(myLock);
|
|
|
|
|
if (send == YES)
|
|
|
|
|
{
|
|
|
|
|
if (handle->caller == YES)
|
|
|
|
|
handle->sendPort = GS_GC_HIDE(self);
|
|
|
|
|
else
|
|
|
|
|
ASSIGN(handle->sendPort, self);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
handle->recvPort = GS_GC_HIDE(self);
|
|
|
|
|
}
|
2006-01-11 09:32:13 +00:00
|
|
|
|
NSMapInsert(handles, (void*)(uintptr_t)[handle descriptor], (void*)handle);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) copyWithZone: (NSZone*)zone
|
|
|
|
|
{
|
|
|
|
|
return RETAIN(self);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
2009-01-12 18:36:37 +00:00
|
|
|
|
[self finalize];
|
2003-07-15 05:21:34 +00:00
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) description
|
|
|
|
|
{
|
|
|
|
|
NSString *desc;
|
|
|
|
|
|
|
|
|
|
desc = [NSString stringWithFormat: @"<NSMessagePort %p with name %s>",
|
|
|
|
|
self, [name bytes]];
|
|
|
|
|
return desc;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-12 18:36:37 +00:00
|
|
|
|
- (void) finalize
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
NSDebugMLLog(@"NSMessagePort", @"NSMessagePort 0x%x finalized", self);
|
|
|
|
|
[self invalidate];
|
2008-11-15 07:15:39 +00:00
|
|
|
|
if (_internal != 0)
|
|
|
|
|
{
|
|
|
|
|
DESTROY(name);
|
|
|
|
|
NSFreeMapTable(handles);
|
|
|
|
|
RELEASE(myLock);
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), _internal);
|
|
|
|
|
}
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This is a callback method used by the NSRunLoop class to determine which
|
|
|
|
|
* descriptors to watch for the port.
|
|
|
|
|
*/
|
|
|
|
|
- (void) getFds: (int*)fds count: (int*)count
|
|
|
|
|
{
|
|
|
|
|
NSMapEnumerator me;
|
2005-10-04 11:54:03 +00:00
|
|
|
|
void *sock;
|
|
|
|
|
GSMessageHandle *handle;
|
2003-07-15 05:21:34 +00:00
|
|
|
|
id recvSelf;
|
|
|
|
|
|
|
|
|
|
M_LOCK(myLock);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Make sure there is enough room in the provided array.
|
|
|
|
|
*/
|
|
|
|
|
NSAssert(*count > (int)NSCountMapTable(handles),
|
|
|
|
|
NSInternalInconsistencyException);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Put in our listening socket.
|
|
|
|
|
*/
|
|
|
|
|
*count = 0;
|
2005-11-01 20:37:34 +00:00
|
|
|
|
if (lDesc >= 0)
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
2005-11-01 20:37:34 +00:00
|
|
|
|
fds[(*count)++] = lDesc;
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Enumerate all our socket handles, and put them in as long as they
|
|
|
|
|
* are to be used for receiving.
|
|
|
|
|
*/
|
|
|
|
|
recvSelf = GS_GC_HIDE(self);
|
|
|
|
|
me = NSEnumerateMapTable(handles);
|
2005-10-04 11:54:03 +00:00
|
|
|
|
while (NSNextMapEnumeratorPair(&me, &sock, (void**)&handle))
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
if (handle->recvPort == recvSelf)
|
|
|
|
|
{
|
2006-01-10 10:29:11 +00:00
|
|
|
|
fds[(*count)++] = (int)(intptr_t)sock;
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
NSEndMapTableEnumeration(&me);
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
}
|
|
|
|
|
|
2004-08-24 08:08:14 +00:00
|
|
|
|
- (id) conversation: (NSPort*)recvPort
|
|
|
|
|
{
|
|
|
|
|
NSMapEnumerator me;
|
2005-10-04 11:54:03 +00:00
|
|
|
|
void *dummy;
|
2004-08-24 08:08:14 +00:00
|
|
|
|
GSMessageHandle *handle = nil;
|
|
|
|
|
|
|
|
|
|
M_LOCK(myLock);
|
|
|
|
|
/*
|
|
|
|
|
* Enumerate all our socket handles, and look for one with port.
|
|
|
|
|
*/
|
|
|
|
|
me = NSEnumerateMapTable(handles);
|
2005-10-04 11:54:03 +00:00
|
|
|
|
while (NSNextMapEnumeratorPair(&me, &dummy, (void**)&handle))
|
2004-08-24 08:08:14 +00:00
|
|
|
|
{
|
2008-11-17 13:45:32 +00:00
|
|
|
|
if ((NSPort*) [handle recvPort] == recvPort)
|
2004-08-24 08:08:14 +00:00
|
|
|
|
{
|
2009-01-12 12:48:46 +00:00
|
|
|
|
IF_NO_GC([handle retain];)
|
2004-08-24 08:08:14 +00:00
|
|
|
|
NSEndMapTableEnumeration(&me);
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
return AUTORELEASE(handle);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
NSEndMapTableEnumeration(&me);
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (GSMessageHandle*) handleForPort: (NSMessagePort*)recvPort
|
|
|
|
|
beforeDate: (NSDate*)when
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
NSMapEnumerator me;
|
|
|
|
|
int sock;
|
2005-10-04 11:54:03 +00:00
|
|
|
|
void *dummy;
|
2004-11-22 11:48:50 +00:00
|
|
|
|
#ifndef BROKEN_SO_REUSEADDR
|
2003-07-15 05:21:34 +00:00
|
|
|
|
int opt = 1;
|
2004-11-22 11:48:50 +00:00
|
|
|
|
#endif
|
2004-08-24 08:08:14 +00:00
|
|
|
|
GSMessageHandle *handle = nil;
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
|
|
|
|
M_LOCK(myLock);
|
|
|
|
|
/*
|
|
|
|
|
* Enumerate all our socket handles, and look for one with port.
|
|
|
|
|
*/
|
|
|
|
|
me = NSEnumerateMapTable(handles);
|
2005-10-04 11:54:03 +00:00
|
|
|
|
while (NSNextMapEnumeratorPair(&me, &dummy, (void**)&handle))
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
if ([handle recvPort] == recvPort)
|
|
|
|
|
{
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
NSEndMapTableEnumeration(&me);
|
|
|
|
|
return handle;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
NSEndMapTableEnumeration(&me);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Not found ... create a new handle.
|
|
|
|
|
*/
|
|
|
|
|
handle = nil;
|
2005-10-04 11:54:03 +00:00
|
|
|
|
sock = socket(PF_LOCAL, SOCK_STREAM, PF_UNSPEC);
|
|
|
|
|
if (sock < 0)
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
2006-10-20 10:56:27 +00:00
|
|
|
|
NSLog(@"unable to create socket - %@", [NSError _last]);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
#ifndef BROKEN_SO_REUSEADDR
|
|
|
|
|
/*
|
|
|
|
|
* Under decent systems, SO_REUSEADDR means that the port can be reused
|
|
|
|
|
* immediately that this process exits. Under some it means
|
|
|
|
|
* that multiple processes can serve the same port simultaneously.
|
|
|
|
|
* We don't want that broken behavior!
|
|
|
|
|
*/
|
|
|
|
|
else if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&opt,
|
|
|
|
|
sizeof(opt)) < 0)
|
|
|
|
|
{
|
|
|
|
|
(void)close(sock);
|
2006-10-20 10:56:27 +00:00
|
|
|
|
NSLog(@"unable to set reuse on socket - %@", [NSError _last]);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
else if ((handle = [GSMessageHandle handleWithDescriptor: sock]) == nil)
|
|
|
|
|
{
|
|
|
|
|
(void)close(sock);
|
2006-10-20 10:56:27 +00:00
|
|
|
|
NSLog(@"unable to create GSMessageHandle - %@", [NSError _last]);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[recvPort addHandle: handle forSend: NO];
|
|
|
|
|
}
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
/*
|
|
|
|
|
* If we succeeded in creating a new handle - connect to remote host.
|
|
|
|
|
*/
|
|
|
|
|
if (handle != nil)
|
|
|
|
|
{
|
|
|
|
|
if ([handle connectToPort: self beforeDate: when] == NO)
|
|
|
|
|
{
|
|
|
|
|
[handle invalidate];
|
|
|
|
|
handle = nil;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return handle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) handlePortMessage: (NSPortMessage*)m
|
|
|
|
|
{
|
|
|
|
|
id d = [self delegate];
|
|
|
|
|
|
|
|
|
|
if (d == nil)
|
|
|
|
|
{
|
2004-08-24 08:08:14 +00:00
|
|
|
|
NSDebugMLLog(@"NSMessagePort",
|
|
|
|
|
@"No delegate to handle incoming message", 0);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ([d respondsToSelector: @selector(handlePortMessage:)] == NO)
|
|
|
|
|
{
|
|
|
|
|
NSDebugMLLog(@"NSMessagePort", @"delegate doesn't handle messages", 0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
[d handlePortMessage: m];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (unsigned) hash
|
|
|
|
|
{
|
|
|
|
|
return [name hash];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) init
|
|
|
|
|
{
|
|
|
|
|
RELEASE(self);
|
|
|
|
|
self = [messagePortClass new];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) invalidate
|
|
|
|
|
{
|
|
|
|
|
if ([self isValid] == YES)
|
|
|
|
|
{
|
2009-01-12 12:48:46 +00:00
|
|
|
|
IF_NO_GC([self retain];)
|
2008-11-15 07:15:39 +00:00
|
|
|
|
M_LOCK(myLock);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
|
|
|
|
if ([self isValid] == YES)
|
|
|
|
|
{
|
|
|
|
|
NSArray *handleArray;
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
M_LOCK(messagePortLock);
|
2006-09-10 10:47:50 +00:00
|
|
|
|
NSMapRemove(messagePortMap, (void*)name);
|
|
|
|
|
M_UNLOCK(messagePortLock);
|
2005-11-01 20:37:34 +00:00
|
|
|
|
if (lDesc >= 0)
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
2005-11-01 20:37:34 +00:00
|
|
|
|
(void) close(lDesc);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
unlink([name bytes]);
|
2005-11-01 20:37:34 +00:00
|
|
|
|
lDesc = -1;
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-11-15 07:15:39 +00:00
|
|
|
|
handleArray = NSAllMapTableValues(handles);
|
|
|
|
|
i = [handleArray count];
|
|
|
|
|
while (i-- > 0)
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
2008-11-15 07:15:39 +00:00
|
|
|
|
GSMessageHandle *handle;
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
2008-11-15 07:15:39 +00:00
|
|
|
|
handle = [handleArray objectAtIndex: i];
|
|
|
|
|
[handle invalidate];
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
2008-11-15 07:15:39 +00:00
|
|
|
|
|
2003-07-15 05:21:34 +00:00
|
|
|
|
[[NSMessagePortNameServer sharedInstance] removePort: self];
|
|
|
|
|
[super invalidate];
|
|
|
|
|
}
|
2008-11-15 07:15:39 +00:00
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
RELEASE(self);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) isEqual: (id)anObject
|
|
|
|
|
{
|
|
|
|
|
if (anObject == self)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
2008-11-15 07:15:39 +00:00
|
|
|
|
if ([anObject class] == [self class] && [self isValid] && [anObject isValid])
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
NSMessagePort *o = (NSMessagePort*)anObject;
|
|
|
|
|
|
2005-11-01 20:37:34 +00:00
|
|
|
|
return [((internal*)o->_internal)->_name isEqual: name];
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) receivedEvent: (void*)data
|
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
|
extra: (void*)extra
|
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
|
{
|
2006-01-11 09:32:13 +00:00
|
|
|
|
int desc = (int)(uintptr_t)extra;
|
2003-07-15 05:21:34 +00:00
|
|
|
|
GSMessageHandle *handle;
|
|
|
|
|
|
2005-11-01 20:37:34 +00:00
|
|
|
|
if (desc == lDesc)
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
struct sockaddr_un sockAddr;
|
2005-07-08 11:48:37 +00:00
|
|
|
|
unsigned size = sizeof(sockAddr);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
2005-11-01 20:37:34 +00:00
|
|
|
|
desc = accept(lDesc, (struct sockaddr*)&sockAddr, &size);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
if (desc < 0)
|
|
|
|
|
{
|
2004-08-24 08:08:14 +00:00
|
|
|
|
NSDebugMLLog(@"NSMessagePort",
|
|
|
|
|
@"accept failed - handled in other thread?");
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2005-06-15 03:56:13 +00:00
|
|
|
|
int status = 1;
|
|
|
|
|
|
|
|
|
|
setsockopt(desc, SOL_SOCKET, SO_KEEPALIVE, (char*)&status,
|
|
|
|
|
sizeof(status));
|
2003-07-15 05:21:34 +00:00
|
|
|
|
/*
|
|
|
|
|
* Create a handle for the socket and set it up so we are its
|
|
|
|
|
* receiving port, and it's waiting to get the port name from
|
|
|
|
|
* the other end.
|
|
|
|
|
*/
|
|
|
|
|
handle = [GSMessageHandle handleWithDescriptor: desc];
|
|
|
|
|
memcpy(&handle->sockAddr, &sockAddr, sizeof(sockAddr));
|
|
|
|
|
|
|
|
|
|
[handle setState: GS_H_ACCEPT];
|
|
|
|
|
[self addHandle: handle forSend: NO];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
M_LOCK(myLock);
|
2006-01-11 09:32:13 +00:00
|
|
|
|
handle = (GSMessageHandle*)NSMapGet(handles, (void*)(uintptr_t)desc);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
IF_NO_GC(AUTORELEASE(RETAIN(handle)));
|
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
if (handle == nil)
|
|
|
|
|
{
|
|
|
|
|
const char *t;
|
|
|
|
|
|
|
|
|
|
if (type == ET_RDESC) t = "rdesc";
|
|
|
|
|
else if (type == ET_WDESC) t = "wdesc";
|
|
|
|
|
else if (type == ET_RPORT) t = "rport";
|
|
|
|
|
else t = "unknown";
|
|
|
|
|
NSLog(@"No handle for event %s on descriptor %d", t, desc);
|
|
|
|
|
[[runLoopClass currentRunLoop] removeEvent: extra
|
|
|
|
|
type: type
|
|
|
|
|
forMode: mode
|
|
|
|
|
all: YES];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[handle receivedEvent: data type: type extra: extra forMode: mode];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-09-10 10:47:50 +00:00
|
|
|
|
- (void) release
|
|
|
|
|
{
|
|
|
|
|
M_LOCK(messagePortLock);
|
|
|
|
|
if (NSDecrementExtraRefCountWasZero(self))
|
|
|
|
|
{
|
2007-02-04 09:57:20 +00:00
|
|
|
|
if (_internal != 0)
|
|
|
|
|
{
|
|
|
|
|
NSMapRemove(messagePortMap, (void*)name);
|
|
|
|
|
}
|
2006-09-10 10:47:50 +00:00
|
|
|
|
M_UNLOCK(messagePortLock);
|
|
|
|
|
[self dealloc];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
M_UNLOCK(messagePortLock);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-15 05:21:34 +00:00
|
|
|
|
- (void) removeHandle: (GSMessageHandle*)handle
|
|
|
|
|
{
|
2009-01-12 12:48:46 +00:00
|
|
|
|
IF_NO_GC([self retain];)
|
2008-11-15 07:15:39 +00:00
|
|
|
|
M_LOCK(myLock);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
if ([handle sendPort] == self)
|
|
|
|
|
{
|
|
|
|
|
if (handle->caller != YES)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* This is a handle for a send port, and the handle was not formed
|
|
|
|
|
* by calling the remote process, so this port object must have
|
|
|
|
|
* been created to deal with an incoming connection and will have
|
|
|
|
|
* been retained - we must therefore release this port since the
|
|
|
|
|
* handle no longer uses it.
|
|
|
|
|
*/
|
2009-01-12 12:48:46 +00:00
|
|
|
|
IF_NO_GC([self autorelease];)
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
handle->sendPort = nil;
|
|
|
|
|
}
|
|
|
|
|
if ([handle recvPort] == self)
|
|
|
|
|
{
|
|
|
|
|
handle->recvPort = nil;
|
|
|
|
|
}
|
2006-01-11 09:32:13 +00:00
|
|
|
|
NSMapRemove(handles, (void*)(uintptr_t)[handle descriptor]);
|
2005-11-01 20:37:34 +00:00
|
|
|
|
if (lDesc < 0 && NSCountMapTable(handles) == 0)
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
[self invalidate];
|
|
|
|
|
}
|
2008-11-15 07:15:39 +00:00
|
|
|
|
M_UNLOCK(myLock);
|
|
|
|
|
RELEASE(self);
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This returns the amount of space that a port coder should reserve at the
|
|
|
|
|
* start of its encoded data so that the NSMessagePort can insert header info
|
|
|
|
|
* into the data.
|
|
|
|
|
* The idea is that a message consisting of a single data item with space at
|
|
|
|
|
* the start can be written directly without having to copy data to another
|
|
|
|
|
* buffer etc.
|
|
|
|
|
*/
|
|
|
|
|
- (unsigned int) reservedSpaceLength
|
|
|
|
|
{
|
|
|
|
|
return sizeof(GSPortItemHeader) + sizeof(GSPortMsgHeader);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) sendBeforeDate: (NSDate*)when
|
|
|
|
|
msgid: (int)msgId
|
|
|
|
|
components: (NSMutableArray*)components
|
|
|
|
|
from: (NSPort*)receivingPort
|
|
|
|
|
reserved: (unsigned)length
|
|
|
|
|
{
|
|
|
|
|
BOOL sent = NO;
|
|
|
|
|
GSMessageHandle *h;
|
|
|
|
|
unsigned rl;
|
|
|
|
|
|
|
|
|
|
if ([self isValid] == NO)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
if ([components count] == 0)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"empty components sent");
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* If the reserved length in the first data object is wrong - we have to
|
|
|
|
|
* fail, unless it's zero, in which case we can insert a data object for
|
|
|
|
|
* the header.
|
|
|
|
|
*/
|
|
|
|
|
rl = [self reservedSpaceLength];
|
|
|
|
|
if (length != 0 && length != rl)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"bad reserved length - %u", length);
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
if ([receivingPort isKindOfClass: messagePortClass] == NO)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"woah there - receiving port is not the correct type");
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
h = [self handleForPort: (NSMessagePort*)receivingPort beforeDate: when];
|
|
|
|
|
if (h != nil)
|
|
|
|
|
{
|
|
|
|
|
NSMutableData *header;
|
|
|
|
|
unsigned hLength;
|
|
|
|
|
unsigned l;
|
|
|
|
|
GSPortItemHeader *pih;
|
|
|
|
|
GSPortMsgHeader *pmh;
|
|
|
|
|
unsigned c = [components count];
|
|
|
|
|
unsigned i;
|
|
|
|
|
BOOL pack = YES;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Ok - ensure we have space to insert header info.
|
|
|
|
|
*/
|
|
|
|
|
if (length == 0 && rl != 0)
|
|
|
|
|
{
|
|
|
|
|
header = [[mutableDataClass alloc] initWithCapacity: NETBLOCK];
|
|
|
|
|
|
|
|
|
|
[header setLength: rl];
|
|
|
|
|
[components insertObject: header atIndex: 0];
|
|
|
|
|
RELEASE(header);
|
2005-02-22 11:22:44 +00:00
|
|
|
|
}
|
2003-07-15 05:21:34 +00:00
|
|
|
|
|
|
|
|
|
header = [components objectAtIndex: 0];
|
|
|
|
|
/*
|
|
|
|
|
* The Item header contains the item type and the length of the
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* data in the item (excluding the item header itself).
|
2003-07-15 05:21:34 +00:00
|
|
|
|
*/
|
|
|
|
|
hLength = [header length];
|
|
|
|
|
l = hLength - sizeof(GSPortItemHeader);
|
|
|
|
|
pih = (GSPortItemHeader*)[header mutableBytes];
|
|
|
|
|
pih->type = GSSwapHostI32ToBig(GSP_HEAD);
|
|
|
|
|
pih->length = GSSwapHostI32ToBig(l);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The message header contains the message Id and the original count
|
|
|
|
|
* of components in the message (excluding any extra component added
|
|
|
|
|
* simply to hold the header).
|
|
|
|
|
*/
|
|
|
|
|
pmh = (GSPortMsgHeader*)&pih[1];
|
|
|
|
|
pmh->mId = GSSwapHostI32ToBig(msgId);
|
|
|
|
|
pmh->nItems = GSSwapHostI32ToBig(c);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now insert item header information as required.
|
|
|
|
|
* Pack as many items into the initial data object as possible, up to
|
|
|
|
|
* a maximum of NETBLOCK bytes. This is to try to get a single,
|
|
|
|
|
* efficient write operation if possible.
|
|
|
|
|
*/
|
2007-12-31 20:38:50 +00:00
|
|
|
|
c = [components count];
|
2003-07-15 05:21:34 +00:00
|
|
|
|
for (i = 1; i < c; i++)
|
|
|
|
|
{
|
|
|
|
|
id o = [components objectAtIndex: i];
|
|
|
|
|
|
|
|
|
|
if ([o isKindOfClass: [NSData class]])
|
|
|
|
|
{
|
|
|
|
|
GSPortItemHeader *pih;
|
|
|
|
|
unsigned h = sizeof(GSPortItemHeader);
|
|
|
|
|
unsigned l = [o length];
|
|
|
|
|
void *b;
|
|
|
|
|
|
|
|
|
|
if (pack == YES && hLength + l + h <= NETBLOCK)
|
|
|
|
|
{
|
|
|
|
|
[header setLength: hLength + l + h];
|
|
|
|
|
b = [header mutableBytes];
|
|
|
|
|
b += hLength;
|
|
|
|
|
#if NEED_WORD_ALIGNMENT
|
|
|
|
|
/*
|
|
|
|
|
* When packing data, an item may not be aligned on a
|
|
|
|
|
* word boundary, so we work with an aligned buffer
|
|
|
|
|
* and use memcmpy()
|
|
|
|
|
*/
|
2006-01-11 08:37:16 +00:00
|
|
|
|
if ((hLength % __alignof__(uint32_t)) != 0)
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
GSPortItemHeader itemHeader;
|
|
|
|
|
|
|
|
|
|
pih = (GSPortItemHeader*)&itemHeader;
|
|
|
|
|
pih->type = GSSwapHostI32ToBig(GSP_DATA);
|
|
|
|
|
pih->length = GSSwapHostI32ToBig(l);
|
|
|
|
|
memcpy(b, (void*)pih, h);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pih = (GSPortItemHeader*)b;
|
|
|
|
|
pih->type = GSSwapHostI32ToBig(GSP_DATA);
|
|
|
|
|
pih->length = GSSwapHostI32ToBig(l);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
pih = (GSPortItemHeader*)b;
|
|
|
|
|
pih->type = GSSwapHostI32ToBig(GSP_DATA);
|
|
|
|
|
pih->length = GSSwapHostI32ToBig(l);
|
|
|
|
|
#endif
|
|
|
|
|
memcpy(b+h, [o bytes], l);
|
|
|
|
|
[components removeObjectAtIndex: i--];
|
|
|
|
|
c--;
|
|
|
|
|
hLength += l + h;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSMutableData *d;
|
|
|
|
|
|
|
|
|
|
pack = NO;
|
|
|
|
|
d = [[NSMutableData alloc] initWithLength: l + h];
|
|
|
|
|
b = [d mutableBytes];
|
|
|
|
|
pih = (GSPortItemHeader*)b;
|
|
|
|
|
memcpy(b+h, [o bytes], l);
|
|
|
|
|
pih->type = GSSwapHostI32ToBig(GSP_DATA);
|
|
|
|
|
pih->length = GSSwapHostI32ToBig(l);
|
|
|
|
|
[components replaceObjectAtIndex: i
|
|
|
|
|
withObject: d];
|
|
|
|
|
RELEASE(d);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if ([o isKindOfClass: messagePortClass])
|
|
|
|
|
{
|
|
|
|
|
NSData *d = newDataWithEncodedPort(o);
|
|
|
|
|
unsigned dLength = [d length];
|
|
|
|
|
|
|
|
|
|
if (pack == YES && hLength + dLength <= NETBLOCK)
|
|
|
|
|
{
|
|
|
|
|
void *b;
|
|
|
|
|
|
|
|
|
|
[header setLength: hLength + dLength];
|
|
|
|
|
b = [header mutableBytes];
|
|
|
|
|
b += hLength;
|
|
|
|
|
hLength += dLength;
|
|
|
|
|
memcpy(b, [d bytes], dLength);
|
|
|
|
|
[components removeObjectAtIndex: i--];
|
|
|
|
|
c--;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pack = NO;
|
|
|
|
|
[components replaceObjectAtIndex: i withObject: d];
|
|
|
|
|
}
|
|
|
|
|
RELEASE(d);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now send the message.
|
|
|
|
|
*/
|
|
|
|
|
sent = [h sendMessage: components beforeDate: when];
|
|
|
|
|
}
|
|
|
|
|
return sent;
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-01 20:37:34 +00:00
|
|
|
|
- (const unsigned char *) _name
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
|
|
|
|
return [name bytes];
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-01 20:37:34 +00:00
|
|
|
|
- (int) _listener
|
2003-07-15 05:21:34 +00:00
|
|
|
|
{
|
2005-11-01 20:37:34 +00:00
|
|
|
|
return lDesc;
|
2003-07-15 05:21:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|