2005-11-08 16:44:46 +00:00
|
|
|
/** Implementation of network port object based on windows mailboxes
|
|
|
|
Copyright (C) 2005 Free Software Foundation, Inc.
|
2005-11-05 05:58:43 +00:00
|
|
|
|
|
|
|
Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
|
|
|
|
|
|
|
This file is part of the GNUstep Base Library.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
|
|
License along with this library; if not, write to the Free
|
|
|
|
Software Foundation, Inc.,
|
|
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "GNUstepBase/preface.h"
|
|
|
|
#include "GNUstepBase/GSLock.h"
|
|
|
|
#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"
|
|
|
|
#include "Foundation/NSValue.h"
|
|
|
|
#include "Foundation/NSFileManager.h"
|
|
|
|
#include "Foundation/NSProcessInfo.h"
|
|
|
|
|
|
|
|
#include "GSPortPrivate.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2005-11-08 16:44:46 +00:00
|
|
|
extern int errno;
|
|
|
|
|
2005-11-05 16:20:19 +00:00
|
|
|
#define UNISTR(X) \
|
|
|
|
((const unichar*)[(X) cStringUsingEncoding: NSUnicodeStringEncoding])
|
|
|
|
|
2005-11-05 05:58:43 +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
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 {
|
2005-11-08 16:44:46 +00:00
|
|
|
GSP_ITEM, /* Expecting a port item header. */
|
2005-11-05 05:58:43 +00:00
|
|
|
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 {
|
|
|
|
gsu32 type; /* A GSPortItemType as a 4-byte number. */
|
|
|
|
gsu32 length; /* The length of the item (excluding header). */
|
|
|
|
} 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 {
|
|
|
|
gsu32 mId; /* The ID for the message starting with this. */
|
|
|
|
gsu32 nItems; /* Number of items (including this one). */
|
2005-11-08 16:44:46 +00:00
|
|
|
unsigned char version;
|
|
|
|
unsigned char port[24];
|
2005-11-05 05:58:43 +00:00
|
|
|
} GSPortMsgHeader;
|
|
|
|
|
|
|
|
typedef struct {
|
2005-11-08 16:44:46 +00:00
|
|
|
NSString *name;
|
|
|
|
NSRecursiveLock *lock;
|
|
|
|
HANDLE handle;
|
|
|
|
HANDLE event;
|
|
|
|
OVERLAPPED ov;
|
|
|
|
DWORD size;
|
|
|
|
BOOL listener;
|
|
|
|
|
|
|
|
NSMutableData *wData; /* Data object being written. */
|
2005-11-09 16:30:57 +00:00
|
|
|
DWORD wLength; /* Amount written so far. */
|
2005-11-08 16:44:46 +00:00
|
|
|
NSMutableArray *wMsgs; /* Message in progress. */
|
|
|
|
NSMutableData *rData; /* Buffer for incoming data */
|
2005-11-09 16:30:57 +00:00
|
|
|
DWORD rLength; /* Amount read so far. */
|
|
|
|
DWORD rWant; /* Amount desired. */
|
2005-11-08 16:44:46 +00:00
|
|
|
NSMessagePort *rPort; /* Port of message being read. */
|
|
|
|
NSMutableArray *rItems; /* Message in progress. */
|
|
|
|
gsu32 rId; /* Id of incoming message. */
|
|
|
|
unsigned nItems; /* Number of items to be read. */
|
|
|
|
} internal;
|
|
|
|
#define PORT(X) ((internal*)((NSMessagePort*)X)->_internal)
|
2005-11-05 17:41:01 +00:00
|
|
|
|
2005-11-05 05:58:43 +00:00
|
|
|
@implementation NSMessagePort
|
|
|
|
|
|
|
|
static NSRecursiveLock *messagePortLock = nil;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Maps port name to NSMessagePort objects.
|
|
|
|
*/
|
2005-11-08 16:44:46 +00:00
|
|
|
static NSMapTable *recvPorts = 0;
|
|
|
|
static NSMapTable *sendPorts = 0;
|
2005-11-05 05:58:43 +00:00
|
|
|
static Class messagePortClass;
|
|
|
|
|
|
|
|
#define HDR (sizeof(GSPortItemHeader) + sizeof(GSPortMsgHeader))
|
|
|
|
|
|
|
|
#if NEED_WORD_ALIGNMENT
|
|
|
|
static unsigned wordAlign;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
{
|
|
|
|
if (self == [NSMessagePort class])
|
|
|
|
{
|
|
|
|
#if NEED_WORD_ALIGNMENT
|
|
|
|
wordAlign = objc_alignof_type(@encode(gsu32));
|
|
|
|
#endif
|
|
|
|
messagePortClass = self;
|
2005-11-08 16:44:46 +00:00
|
|
|
recvPorts = NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks,
|
|
|
|
NSNonOwnedPointerMapValueCallBacks, 0);
|
|
|
|
sendPorts = NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks,
|
2005-11-05 05:58:43 +00:00
|
|
|
NSNonOwnedPointerMapValueCallBacks, 0);
|
|
|
|
|
|
|
|
messagePortLock = [GSLazyRecursiveLock new];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-08 16:44:46 +00:00
|
|
|
+ (NSMessagePort*) recvPort: (NSString*)name
|
2005-11-05 05:58:43 +00:00
|
|
|
{
|
2005-11-08 16:44:46 +00:00
|
|
|
NSMessagePort *p;
|
2005-11-05 05:58:43 +00:00
|
|
|
|
2005-11-08 16:44:46 +00:00
|
|
|
if (name == nil)
|
|
|
|
{
|
|
|
|
p = AUTORELEASE([[self alloc] init]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
M_LOCK(messagePortLock);
|
|
|
|
p = AUTORELEASE(RETAIN((NSMessagePort*)NSMapGet(recvPorts, (void*)name)));
|
|
|
|
M_UNLOCK(messagePortLock);
|
|
|
|
}
|
|
|
|
return p;
|
2005-11-05 05:58:43 +00:00
|
|
|
}
|
|
|
|
|
2005-11-08 16:44:46 +00:00
|
|
|
+ (NSMessagePort*) sendPort: (NSString*)name
|
2005-11-05 05:58:43 +00:00
|
|
|
{
|
2005-11-08 16:44:46 +00:00
|
|
|
NSMessagePort *p;
|
2005-11-05 05:58:43 +00:00
|
|
|
|
2005-11-08 16:44:46 +00:00
|
|
|
NSAssert(p != nil, @"sendPort: called with nil name");
|
2005-11-05 05:58:43 +00:00
|
|
|
M_LOCK(messagePortLock);
|
2005-11-08 16:44:46 +00:00
|
|
|
p = AUTORELEASE(RETAIN((NSMessagePort*)NSMapGet(sendPorts, (void*)name)));
|
|
|
|
if (p == nil)
|
2005-11-05 05:58:43 +00:00
|
|
|
{
|
2005-11-08 16:44:46 +00:00
|
|
|
p = AUTORELEASE([[self alloc] initWithName: name]);
|
2005-11-05 05:58:43 +00:00
|
|
|
}
|
|
|
|
M_UNLOCK(messagePortLock);
|
2005-11-08 16:44:46 +00:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) addConnection: (NSConnection*)aConnection
|
|
|
|
toRunLoop: (NSRunLoop*)aLoop
|
|
|
|
forMode: (NSString*)aMode
|
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
NSDebugMLLog(@"NSMessagePort", @"%@ add to 0x%x in mode %@",
|
|
|
|
self, aLoop, aMode);
|
|
|
|
[aLoop addEvent: (void*)(gsaddr)PORT(self)->event
|
2005-11-08 16:44:46 +00:00
|
|
|
type: ET_HANDLE
|
|
|
|
watcher: (id<RunLoopEvents>)self
|
|
|
|
forMode: aMode];
|
2005-11-05 05:58:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id) copyWithZone: (NSZone*)zone
|
|
|
|
{
|
|
|
|
return RETAIN(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
[self gcFinalize];
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString*) description
|
|
|
|
{
|
|
|
|
NSString *desc;
|
|
|
|
|
|
|
|
desc = [NSString stringWithFormat: @"<NSMessagePort %p with name %@>",
|
2005-11-08 16:44:46 +00:00
|
|
|
self, PORT(self)->name];
|
2005-11-05 05:58:43 +00:00
|
|
|
return desc;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) gcFinalize
|
|
|
|
{
|
2005-11-08 16:44:46 +00:00
|
|
|
internal *this;
|
|
|
|
|
2005-11-05 05:58:43 +00:00
|
|
|
NSDebugMLLog(@"NSMessagePort", @"NSMessagePort 0x%x finalized", self);
|
|
|
|
[self invalidate];
|
2005-11-08 16:44:46 +00:00
|
|
|
this = PORT(self);
|
|
|
|
if (this != 0)
|
|
|
|
{
|
|
|
|
DESTROY(this->name);
|
|
|
|
DESTROY(this->rData);
|
|
|
|
DESTROY(this->rItems);
|
|
|
|
DESTROY(this->wMsgs);
|
|
|
|
DESTROY(this->lock);
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), _internal);
|
|
|
|
_internal = 0;
|
|
|
|
}
|
2005-11-05 05:58:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id) conversation: (NSPort*)recvPort
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) handlePortMessage: (NSPortMessage*)m
|
|
|
|
{
|
|
|
|
id d = [self delegate];
|
|
|
|
|
|
|
|
if (d == nil)
|
|
|
|
{
|
|
|
|
NSDebugMLLog(@"NSMessagePort",
|
|
|
|
@"No delegate to handle incoming message", 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ([d respondsToSelector: @selector(handlePortMessage:)] == NO)
|
|
|
|
{
|
|
|
|
NSDebugMLLog(@"NSMessagePort", @"delegate doesn't handle messages", 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
[d handlePortMessage: m];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (unsigned) hash
|
|
|
|
{
|
2005-11-08 16:44:46 +00:00
|
|
|
return [PORT(self)->name hash];
|
2005-11-05 05:58:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id) init
|
|
|
|
{
|
2005-11-08 16:44:46 +00:00
|
|
|
static unsigned sequence = 0;
|
|
|
|
static int ident;
|
|
|
|
internal *this;
|
2005-11-09 09:39:25 +00:00
|
|
|
NSString *path;
|
2005-11-08 16:44:46 +00:00
|
|
|
|
|
|
|
if (sequence == 0)
|
|
|
|
{
|
|
|
|
ident = [[NSProcessInfo processInfo] processIdentifier];
|
|
|
|
}
|
|
|
|
M_LOCK(messagePortLock);
|
|
|
|
_internal = NSZoneMalloc(NSDefaultMallocZone(), sizeof(internal));
|
|
|
|
memset(_internal, '\0', sizeof(internal));
|
|
|
|
this = PORT(self);
|
|
|
|
self->_is_valid = YES;
|
|
|
|
#if (GS_SIZEOF_INT > 4)
|
|
|
|
this->name = [[NSString alloc] initWithFormat: @"%08x%08x%08x",
|
|
|
|
(((unsigned)ident) >> 32), (((unsigned)ident) & 0xffffffff), sequence++];
|
|
|
|
#else
|
|
|
|
this->name = [[NSString alloc] initWithFormat: @"00000000%08x%08x",
|
|
|
|
((unsigned)ident), sequence++];
|
|
|
|
#endif
|
|
|
|
|
|
|
|
this->listener = YES;
|
|
|
|
this->event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
this->ov.hEvent = this->event;
|
|
|
|
this->lock = [GSLazyRecursiveLock new];
|
|
|
|
this->rData = [NSMutableData new];
|
|
|
|
|
2005-11-09 09:39:25 +00:00
|
|
|
path = [NSString stringWithFormat:
|
|
|
|
@"\\\\.\\mailslot\\GNUstep\\NSMessagePort\\%@", this->name];
|
|
|
|
|
2005-11-08 16:44:46 +00:00
|
|
|
this->handle = CreateMailslotW(
|
2005-11-09 09:39:25 +00:00
|
|
|
UNISTR(path),
|
2005-11-08 16:44:46 +00:00
|
|
|
0, /* No max message size. */
|
|
|
|
MAILSLOT_WAIT_FOREVER, /* No read/write timeout. */
|
|
|
|
(LPSECURITY_ATTRIBUTES)0);
|
|
|
|
|
|
|
|
if (this->handle == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
NSLog(@"unable to create mailslot '%@' - %s",
|
|
|
|
this->name, GSLastErrorStr(errno));
|
|
|
|
DESTROY(self);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSMapInsert(recvPorts, (void*)this->name, (void*)self);
|
|
|
|
NSDebugMLLog(@"NSMessagePort", @"Created listening port: %@", self);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Simulate a read event to kick off the I/O for this handle.
|
|
|
|
* If we can't start reading, we will be invalidated, and must
|
|
|
|
* then destroy self.
|
|
|
|
*/
|
|
|
|
[self receivedEventRead];
|
|
|
|
if ([self isValid] == NO)
|
|
|
|
{
|
|
|
|
DESTROY(self);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
M_UNLOCK(messagePortLock);
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) initWithName: (NSString*)name
|
|
|
|
{
|
|
|
|
NSMessagePort *p;
|
|
|
|
|
|
|
|
M_LOCK(messagePortLock);
|
2005-11-09 16:30:57 +00:00
|
|
|
p = RETAIN((NSMessagePort*)NSMapGet(sendPorts, (void*)name));
|
2005-11-08 16:44:46 +00:00
|
|
|
if (p == nil)
|
|
|
|
{
|
|
|
|
internal *this;
|
2005-11-09 09:39:25 +00:00
|
|
|
NSString *path;
|
2005-11-08 16:44:46 +00:00
|
|
|
|
|
|
|
_internal = NSZoneMalloc(NSDefaultMallocZone(), sizeof(internal));
|
|
|
|
memset(_internal, '\0', sizeof(internal));
|
|
|
|
this = PORT(self);
|
|
|
|
self->_is_valid = YES;
|
|
|
|
this->name = [name copy];
|
|
|
|
|
|
|
|
this->listener = NO;
|
|
|
|
this->event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
this->ov.hEvent = this->event;
|
|
|
|
this->lock = [GSLazyRecursiveLock new];
|
|
|
|
this->wMsgs = [NSMutableArray new];
|
2005-11-09 09:39:25 +00:00
|
|
|
path = [NSString stringWithFormat:
|
|
|
|
@"\\\\.\\mailslot\\GNUstep\\NSMessagePort\\%@", this->name];
|
2005-11-08 16:44:46 +00:00
|
|
|
|
|
|
|
this->handle = CreateFileW(
|
2005-11-09 09:39:25 +00:00
|
|
|
UNISTR(path),
|
2005-11-08 16:44:46 +00:00
|
|
|
GENERIC_WRITE,
|
2005-11-09 16:30:57 +00:00
|
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
2005-11-08 16:44:46 +00:00
|
|
|
(LPSECURITY_ATTRIBUTES)0,
|
|
|
|
OPEN_EXISTING,
|
2005-11-09 16:30:57 +00:00
|
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
2005-11-08 16:44:46 +00:00
|
|
|
(HANDLE)0);
|
|
|
|
if (this->handle == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
NSLog(@"unable to access mailslot '%@' - %s",
|
|
|
|
this->name, GSLastErrorStr(errno));
|
|
|
|
DESTROY(self);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSMapInsert(sendPorts, (void*)this->name, (void*)self);
|
|
|
|
NSDebugMLLog(@"NSMessagePort", @"Created speaking port: %@", self);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RELEASE(self);
|
|
|
|
self = p;
|
|
|
|
}
|
|
|
|
M_UNLOCK(messagePortLock);
|
2005-11-05 05:58:43 +00:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) invalidate
|
|
|
|
{
|
2005-11-08 16:44:46 +00:00
|
|
|
RETAIN(self);
|
2005-11-05 05:58:43 +00:00
|
|
|
if ([self isValid] == YES)
|
|
|
|
{
|
2005-11-08 16:44:46 +00:00
|
|
|
internal *this;
|
|
|
|
|
|
|
|
this = PORT(self);
|
|
|
|
M_LOCK(this->lock);
|
2005-11-05 05:58:43 +00:00
|
|
|
if ([self isValid] == YES)
|
|
|
|
{
|
|
|
|
M_LOCK(messagePortLock);
|
2005-11-08 16:44:46 +00:00
|
|
|
if (this->handle != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
(void) CancelIo(this->handle);
|
|
|
|
}
|
|
|
|
if (this->event != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
(void) CloseHandle(this->event);
|
|
|
|
this->event = INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
if (this->handle != INVALID_HANDLE_VALUE)
|
2005-11-05 05:58:43 +00:00
|
|
|
{
|
2005-11-08 16:44:46 +00:00
|
|
|
(void) CloseHandle(this->handle);
|
|
|
|
this->handle = INVALID_HANDLE_VALUE;
|
2005-11-05 05:58:43 +00:00
|
|
|
}
|
2005-11-08 16:44:46 +00:00
|
|
|
if (this->listener == YES)
|
2005-11-05 05:58:43 +00:00
|
|
|
{
|
2005-11-08 16:44:46 +00:00
|
|
|
NSMapRemove(recvPorts, (void*)this->name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSMapRemove(sendPorts, (void*)this->name);
|
2005-11-05 05:58:43 +00:00
|
|
|
}
|
|
|
|
M_UNLOCK(messagePortLock);
|
|
|
|
|
2005-11-08 20:42:45 +00:00
|
|
|
[[NSMessagePortNameServer sharedInstance] removePort: self];
|
2005-11-05 05:58:43 +00:00
|
|
|
[super invalidate];
|
|
|
|
}
|
2005-11-08 16:44:46 +00:00
|
|
|
M_UNLOCK(this->lock);
|
2005-11-05 05:58:43 +00:00
|
|
|
}
|
2005-11-08 16:44:46 +00:00
|
|
|
RELEASE(self);
|
2005-11-05 05:58:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) isEqual: (id)anObject
|
|
|
|
{
|
|
|
|
if (anObject == self)
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
if ([anObject class] == [self class])
|
|
|
|
{
|
|
|
|
NSMessagePort *o = (NSMessagePort*)anObject;
|
|
|
|
|
2005-11-08 16:44:46 +00:00
|
|
|
return [PORT(o)->name isEqual: PORT(self)->name];
|
2005-11-05 05:58:43 +00:00
|
|
|
}
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2005-11-08 16:44:46 +00:00
|
|
|
- (NSString*) name
|
|
|
|
{
|
|
|
|
return PORT(self)->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Called when an event occurs on a listener port
|
|
|
|
* ALSO called when the port is created, to start reading.
|
|
|
|
*/
|
|
|
|
- (void) receivedEventRead
|
|
|
|
{
|
|
|
|
internal *this = PORT(self);
|
|
|
|
BOOL shouldDispatch = NO;
|
|
|
|
|
|
|
|
M_LOCK(this->lock);
|
|
|
|
|
2005-11-09 09:39:25 +00:00
|
|
|
if (this->rWant > 0)
|
2005-11-08 16:44:46 +00:00
|
|
|
{
|
2005-11-09 09:39:25 +00:00
|
|
|
/*
|
|
|
|
* Have we read something?
|
|
|
|
*/
|
|
|
|
if (GetOverlappedResult(
|
|
|
|
this->handle,
|
|
|
|
&this->ov,
|
|
|
|
&this->size,
|
|
|
|
TRUE) == 0)
|
2005-11-08 16:44:46 +00:00
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
errno = GetLastError();
|
|
|
|
/*
|
|
|
|
* Our overlapped read attempt should fail ... because mailslots
|
|
|
|
* insist we read an entire message in one go, and we asked it
|
|
|
|
* to read zero bytes. The error we are expecting is
|
|
|
|
* ERROR_INSUFFICIENT_BUFFER ... indicating that there is a
|
|
|
|
* message to be read ... so we can ask for its size and read it
|
|
|
|
* synchronously.
|
|
|
|
*/
|
|
|
|
if (errno == ERROR_INSUFFICIENT_BUFFER)
|
|
|
|
{
|
|
|
|
if (GetMailslotInfo(
|
|
|
|
this->handle,
|
|
|
|
0,
|
|
|
|
&this->rWant,
|
|
|
|
0,
|
|
|
|
0) == 0)
|
|
|
|
{
|
|
|
|
NSLog(@"unable to get info from mailslot '%@' - %s",
|
|
|
|
this->name, GSLastErrorStr(errno));
|
|
|
|
[self invalidate];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[this->rData setLength: this->rWant];
|
|
|
|
if (ReadFile(this->handle,
|
|
|
|
[this->rData mutableBytes], // Store results here
|
|
|
|
this->rWant,
|
|
|
|
&this->size,
|
|
|
|
NULL) == 0)
|
|
|
|
{
|
|
|
|
NSLog(@"unable to read from mailslot '%@' - %s",
|
|
|
|
this->name, GSLastErrorStr(errno));
|
|
|
|
[self invalidate];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (this->size != this->rWant)
|
|
|
|
{
|
|
|
|
NSLog(@"only read %d of %d bytes from mailslot '%@' - %s",
|
|
|
|
this->size, this->rWant, this->name,
|
|
|
|
GSLastErrorStr(errno));
|
|
|
|
[self invalidate];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this->rLength += this->size;
|
|
|
|
this->size = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSLog(@"GetOverlappedResult failed ...%s", GSLastErrorStr(errno));
|
|
|
|
this->rLength = 0;
|
|
|
|
this->rWant = 1;
|
|
|
|
}
|
2005-11-09 09:39:25 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this->rLength += this->size;
|
|
|
|
this->size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do next part only if we have completed a read.
|
|
|
|
*/
|
|
|
|
if (this->rLength == this->rWant)
|
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
unsigned char *buf = [this->rData mutableBytes];
|
|
|
|
GSPortItemType rType;
|
|
|
|
GSPortItemHeader *pih;
|
|
|
|
unsigned off = 0;
|
|
|
|
unsigned l;
|
|
|
|
|
|
|
|
while (off + sizeof(GSPortItemHeader) < this->rLength)
|
2005-11-08 16:44:46 +00:00
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
pih = (GSPortItemHeader*)(buf + off);
|
|
|
|
off += sizeof(GSPortItemHeader);
|
|
|
|
rType = GSSwapBigI32ToHost(pih->type);
|
|
|
|
l = GSSwapBigI32ToHost(pih->length);
|
|
|
|
if (l + off > this->rLength)
|
2005-11-08 16:44:46 +00:00
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
NSLog(@"%@ - unreasonable length (%u) for data", self, l);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (rType != GSP_HEAD && [this->rItems count] == 0)
|
|
|
|
{
|
|
|
|
NSLog(@"%@ - initial part of message had bad type");
|
|
|
|
break;
|
2005-11-08 16:44:46 +00:00
|
|
|
}
|
2005-11-09 09:39:25 +00:00
|
|
|
|
2005-11-09 16:30:57 +00:00
|
|
|
if (rType == GSP_HEAD)
|
2005-11-08 16:44:46 +00:00
|
|
|
{
|
2005-11-09 09:39:25 +00:00
|
|
|
GSPortMsgHeader *pmh;
|
|
|
|
NSString *n;
|
2005-11-09 16:30:57 +00:00
|
|
|
NSMessagePort *p;
|
|
|
|
NSMutableData *d;
|
2005-11-09 09:39:25 +00:00
|
|
|
|
2005-11-09 16:30:57 +00:00
|
|
|
if (l < sizeof(GSPortMsgHeader))
|
|
|
|
{
|
|
|
|
NSLog(@"%@ - bad length for header", self);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pmh = (GSPortMsgHeader*)(buf + off);
|
|
|
|
off += sizeof(GSPortMsgHeader);
|
|
|
|
l -= sizeof(GSPortMsgHeader);
|
2005-11-09 09:39:25 +00:00
|
|
|
this->rId = GSSwapBigI32ToHost(pmh->mId);
|
|
|
|
this->nItems = GSSwapBigI32ToHost(pmh->nItems);
|
|
|
|
if (this->nItems == 0)
|
2005-11-08 16:44:46 +00:00
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
NSLog(@"%@ - unable to decode item count", self);
|
2005-11-08 16:44:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2005-11-09 09:39:25 +00:00
|
|
|
n = [[NSString alloc] initWithBytes: pmh->port
|
|
|
|
length: 24
|
|
|
|
encoding: NSASCIIStringEncoding];
|
|
|
|
NSDebugFLLog(@"NSMessagePort", @"Decoded port as '%@'", n);
|
|
|
|
p = [NSMessagePort sendPort: n];
|
|
|
|
RELEASE(n);
|
|
|
|
if (p == nil)
|
2005-11-08 16:44:46 +00:00
|
|
|
{
|
2005-11-09 09:39:25 +00:00
|
|
|
NSLog(@"%@ - unable to decode remote port", self);
|
|
|
|
break;
|
2005-11-08 16:44:46 +00:00
|
|
|
}
|
2005-11-09 09:39:25 +00:00
|
|
|
ASSIGN(this->rPort, p);
|
|
|
|
this->rItems
|
|
|
|
= [NSMutableArray allocWithZone: NSDefaultMallocZone()];
|
|
|
|
this->rItems = [this->rItems initWithCapacity: this->nItems];
|
2005-11-09 16:30:57 +00:00
|
|
|
d = [[NSMutableData alloc] initWithBytes: buf + off
|
|
|
|
length: l];
|
2005-11-09 09:39:25 +00:00
|
|
|
[this->rItems addObject: d];
|
|
|
|
RELEASE(d);
|
|
|
|
if (this->nItems == [this->rItems count])
|
2005-11-08 16:44:46 +00:00
|
|
|
{
|
2005-11-09 09:39:25 +00:00
|
|
|
shouldDispatch = YES;
|
2005-11-09 16:30:57 +00:00
|
|
|
break;
|
2005-11-08 16:44:46 +00:00
|
|
|
}
|
2005-11-09 16:30:57 +00:00
|
|
|
off += l;
|
2005-11-08 16:44:46 +00:00
|
|
|
}
|
2005-11-09 16:30:57 +00:00
|
|
|
else if (rType == GSP_DATA)
|
2005-11-08 16:44:46 +00:00
|
|
|
{
|
2005-11-09 09:39:25 +00:00
|
|
|
NSMutableData *d;
|
2005-11-08 16:44:46 +00:00
|
|
|
|
2005-11-09 16:30:57 +00:00
|
|
|
d = [[NSMutableData alloc] initWithBytes: buf + off
|
|
|
|
length: l];
|
2005-11-09 09:39:25 +00:00
|
|
|
[this->rItems addObject: d];
|
|
|
|
RELEASE(d);
|
|
|
|
if (this->nItems == [this->rItems count])
|
|
|
|
{
|
|
|
|
shouldDispatch = YES;
|
2005-11-09 16:30:57 +00:00
|
|
|
break;
|
2005-11-09 09:39:25 +00:00
|
|
|
}
|
2005-11-09 16:30:57 +00:00
|
|
|
off += l;
|
2005-11-08 16:44:46 +00:00
|
|
|
}
|
2005-11-09 16:30:57 +00:00
|
|
|
else if (rType == GSP_PORT)
|
2005-11-08 16:44:46 +00:00
|
|
|
{
|
2005-11-09 09:39:25 +00:00
|
|
|
NSMessagePort *p;
|
2005-11-09 16:30:57 +00:00
|
|
|
NSString *n;
|
2005-11-09 09:39:25 +00:00
|
|
|
|
2005-11-09 16:30:57 +00:00
|
|
|
if (l != 24)
|
|
|
|
{
|
|
|
|
NSLog(@"%@ - bad length for port item", self);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
n = [[NSString alloc] initWithBytes: buf + off
|
2005-11-09 09:39:25 +00:00
|
|
|
length: 24
|
|
|
|
encoding: NSASCIIStringEncoding];
|
|
|
|
NSDebugFLLog(@"NSMessagePort", @"Decoded port as '%@'", n);
|
|
|
|
p = [NSMessagePort sendPort: n];
|
|
|
|
RELEASE(n);
|
|
|
|
if (p == nil)
|
|
|
|
{
|
|
|
|
NSLog(@"%@ - unable to decode remote port", self);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
[this->rItems addObject: p];
|
|
|
|
if (this->nItems == [this->rItems count])
|
|
|
|
{
|
|
|
|
shouldDispatch = YES;
|
2005-11-09 16:30:57 +00:00
|
|
|
break;
|
2005-11-09 09:39:25 +00:00
|
|
|
}
|
2005-11-08 16:44:46 +00:00
|
|
|
}
|
2005-11-09 16:30:57 +00:00
|
|
|
off += l;
|
2005-11-08 16:44:46 +00:00
|
|
|
}
|
2005-11-09 16:30:57 +00:00
|
|
|
this->rWant = 1; // Queue a read
|
|
|
|
this->rLength = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSLog(@"Unexpected STATE");
|
2005-11-08 16:44:46 +00:00
|
|
|
}
|
|
|
|
}
|
2005-11-09 16:30:57 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
this->rWant = 1; // Queue a read
|
|
|
|
this->rLength = 0;
|
|
|
|
}
|
|
|
|
|
2005-11-08 16:44:46 +00:00
|
|
|
|
|
|
|
if (shouldDispatch == YES)
|
|
|
|
{
|
|
|
|
NSPortMessage *pm;
|
|
|
|
|
|
|
|
pm = [NSPortMessage allocWithZone: NSDefaultMallocZone()];
|
2005-11-09 16:30:57 +00:00
|
|
|
pm = [pm initWithSendPort: self
|
|
|
|
receivePort: this->rPort
|
2005-11-08 16:44:46 +00:00
|
|
|
components: this->rItems];
|
|
|
|
[pm setMsgid: this->rId];
|
|
|
|
this->rId = 0;
|
|
|
|
DESTROY(this->rPort);
|
|
|
|
DESTROY(this->rItems);
|
2005-11-09 16:30:57 +00:00
|
|
|
NSDebugMLLog(@"NSMessagePort", @"got message %@ on 0x%x", pm, self);
|
2005-11-08 16:44:46 +00:00
|
|
|
M_UNLOCK(this->lock);
|
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
[self handlePortMessage: pm];
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
M_LOCK(this->lock);
|
|
|
|
RELEASE(pm);
|
|
|
|
[localException raise];
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
|
|
|
M_LOCK(this->lock);
|
|
|
|
RELEASE(pm);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Got something ... is it all we want? If not, ask to read more.
|
|
|
|
*/
|
|
|
|
if ([self isValid] == YES && this->rLength < this->rWant)
|
|
|
|
{
|
2005-11-09 09:39:25 +00:00
|
|
|
int rc;
|
|
|
|
|
2005-11-08 16:44:46 +00:00
|
|
|
this->ov.Offset = 0;
|
|
|
|
this->ov.OffsetHigh = 0;
|
|
|
|
this->ov.hEvent = this->event;
|
2005-11-09 16:30:57 +00:00
|
|
|
if ([this->rData length] < (this->rWant - this->rLength))
|
|
|
|
{
|
|
|
|
[this->rData setLength: this->rWant - this->rLength];
|
|
|
|
}
|
2005-11-09 09:39:25 +00:00
|
|
|
rc = ReadFile(this->handle,
|
2005-11-08 16:44:46 +00:00
|
|
|
[this->rData mutableBytes], // Store results here
|
|
|
|
this->rWant - this->rLength,
|
|
|
|
&this->size,
|
2005-11-09 09:39:25 +00:00
|
|
|
&this->ov);
|
|
|
|
|
|
|
|
if (rc > 0)
|
|
|
|
{
|
|
|
|
[self receivedEventRead]; // Read completed synchronously
|
|
|
|
}
|
2005-11-09 16:30:57 +00:00
|
|
|
else if ((errno = GetLastError()) == ERROR_IO_PENDING)
|
|
|
|
{
|
|
|
|
; // OK ...
|
|
|
|
}
|
|
|
|
else if (errno == ERROR_INSUFFICIENT_BUFFER)
|
|
|
|
{
|
|
|
|
[self receivedEventRead]; // Need to determine message size
|
|
|
|
}
|
|
|
|
else
|
2005-11-08 16:44:46 +00:00
|
|
|
{
|
|
|
|
NSLog(@"unable to read from mailslot '%@' - %s",
|
|
|
|
this->name, GSLastErrorStr(errno));
|
|
|
|
[self invalidate];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
M_UNLOCK(this->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Called when an event occurs on a speaker port
|
|
|
|
* ALSO called when we start trying to write a new message and there
|
|
|
|
* wasn't one in progress.
|
|
|
|
*/
|
|
|
|
- (void) receivedEventWrite
|
|
|
|
{
|
|
|
|
internal *this = PORT(self);
|
|
|
|
|
|
|
|
M_LOCK(this->lock);
|
|
|
|
|
2005-11-09 16:30:57 +00:00
|
|
|
if (this->wData != nil)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Have we read something?
|
|
|
|
*/
|
|
|
|
if (GetOverlappedResult(
|
|
|
|
this->handle,
|
|
|
|
&this->ov,
|
|
|
|
&this->size,
|
|
|
|
TRUE) == 0)
|
|
|
|
{
|
|
|
|
NSLog(@"GetOverlappedResult failed ...%s", GSLastErrorStr(errno));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this->wLength += this->size;
|
|
|
|
this->size = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-08 16:44:46 +00:00
|
|
|
/*
|
2005-11-09 16:30:57 +00:00
|
|
|
* Handle start of next data item if we have completed one,
|
2005-11-08 16:44:46 +00:00
|
|
|
* or if we are called without a write in progress.
|
|
|
|
*/
|
|
|
|
if (this->wData == nil || this->wLength == [this->wData length])
|
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
if (this->wData != nil)
|
2005-11-08 16:44:46 +00:00
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
unsigned idx;
|
|
|
|
|
|
|
|
NSDebugMLLog(@"NSMessagePort",
|
2005-11-08 16:44:46 +00:00
|
|
|
@"completed 0x%x on 0x%x", this->wData, self);
|
|
|
|
idx = [this->wMsgs indexOfObjectIdenticalTo: this->wData];
|
2005-11-09 16:30:57 +00:00
|
|
|
if (idx != NSNotFound)
|
|
|
|
{
|
|
|
|
[this->wMsgs removeObjectAtIndex: idx];
|
|
|
|
}
|
2005-11-08 16:44:46 +00:00
|
|
|
}
|
|
|
|
if ([this->wMsgs count] > 0)
|
|
|
|
{
|
|
|
|
this->wData = [this->wMsgs objectAtIndex: 0];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this->wData = nil; // Nothing to write.
|
|
|
|
}
|
|
|
|
this->wLength = 0; // Nothing written yet.
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this->wData != nil)
|
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
int rc;
|
|
|
|
|
2005-11-08 16:44:46 +00:00
|
|
|
this->ov.Offset = 0;
|
|
|
|
this->ov.OffsetHigh = 0;
|
|
|
|
this->ov.hEvent = this->event;
|
2005-11-09 16:30:57 +00:00
|
|
|
rc = WriteFile(this->handle,
|
2005-11-08 16:44:46 +00:00
|
|
|
[this->wData bytes], // Output from here
|
|
|
|
[this->wData length] - this->wLength,
|
|
|
|
&this->size, // Store number of bytes written
|
2005-11-09 16:30:57 +00:00
|
|
|
&this->ov);
|
|
|
|
if (rc > 0)
|
|
|
|
{
|
|
|
|
NSDebugMLLog(@"NSMessagePort", @"Write of %d performs %d",
|
|
|
|
[this->wData length] - this->wLength, this->size);
|
|
|
|
[self receivedEventWrite]; // Completed synchronously
|
|
|
|
}
|
|
|
|
else if ((errno = GetLastError()) != ERROR_IO_PENDING)
|
2005-11-08 16:44:46 +00:00
|
|
|
{
|
|
|
|
NSLog(@"unable to write to mailslot '%@' - %s",
|
|
|
|
this->name, GSLastErrorStr(errno));
|
|
|
|
[self invalidate];
|
|
|
|
}
|
2005-11-09 16:30:57 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
NSDebugMLLog(@"NSMessagePort", @"Write of %d queued",
|
|
|
|
[this->wData length] - this->wLength);
|
|
|
|
}
|
2005-11-08 16:44:46 +00:00
|
|
|
}
|
|
|
|
M_UNLOCK(this->lock);
|
|
|
|
}
|
|
|
|
|
2005-11-05 05:58:43 +00:00
|
|
|
- (void) receivedEvent: (void*)data
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
extra: (void*)extra
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
{
|
2005-11-08 16:44:46 +00:00
|
|
|
RETAIN(self);
|
|
|
|
if ([self isValid] == YES)
|
|
|
|
{
|
|
|
|
internal *this = PORT(self);
|
2005-11-05 05:58:43 +00:00
|
|
|
|
2005-11-08 16:44:46 +00:00
|
|
|
if (this->listener == YES)
|
|
|
|
{
|
|
|
|
[self receivedEventRead];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[self receivedEventWrite];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Event on invalid port ... remove port from run loop
|
|
|
|
[[NSRunLoop currentRunLoop] removeEvent: data
|
|
|
|
type: type
|
|
|
|
forMode: mode
|
|
|
|
all: YES];
|
|
|
|
}
|
|
|
|
RELEASE(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void) removeConnection: (NSConnection*)aConnection
|
|
|
|
fromRunLoop: (NSRunLoop*)aLoop
|
|
|
|
forMode: (NSString*)aMode
|
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
NSDebugMLLog(@"NSMessagePort", @"%@ remove from 0x%x in mode %@",
|
|
|
|
self, aLoop, aMode);
|
|
|
|
[aLoop removeEvent: (void*)(gsaddr)PORT(self)->event
|
2005-11-08 16:44:46 +00:00
|
|
|
type: ET_HANDLE
|
|
|
|
forMode: aMode
|
|
|
|
all: NO];
|
2005-11-05 05:58:43 +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
|
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
return sizeof(GSPortItemHeader) + sizeof(GSPortMsgHeader);
|
2005-11-05 05:58:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL) sendBeforeDate: (NSDate*)when
|
|
|
|
msgid: (int)msgId
|
|
|
|
components: (NSMutableArray*)components
|
|
|
|
from: (NSPort*)receivingPort
|
|
|
|
reserved: (unsigned)length
|
|
|
|
{
|
2005-11-08 16:44:46 +00:00
|
|
|
NSMutableData *h;
|
|
|
|
NSRunLoop *loop;
|
2005-11-05 05:58:43 +00:00
|
|
|
BOOL sent = NO;
|
|
|
|
unsigned rl;
|
2005-11-08 16:44:46 +00:00
|
|
|
unsigned l = 0;
|
|
|
|
unsigned c;
|
|
|
|
unsigned i;
|
|
|
|
internal *this;
|
2005-11-05 05:58:43 +00:00
|
|
|
|
|
|
|
if ([self isValid] == NO)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
2005-11-08 16:44:46 +00:00
|
|
|
this = PORT(self);
|
|
|
|
|
|
|
|
NSAssert(PORT(self)->listener == NO, @"Attempt to send through recv port");
|
|
|
|
c = [components count];
|
|
|
|
if (c == 0)
|
2005-11-05 05:58:43 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2005-11-08 16:44:46 +00:00
|
|
|
NSAssert([receivingPort isKindOfClass: messagePortClass] == YES,
|
|
|
|
@"Receiving port is not the correct type");
|
|
|
|
NSAssert([receivingPort isValid] == YES,
|
|
|
|
@"Receiving port is not valid");
|
|
|
|
NSAssert(PORT(receivingPort)->listener == YES,
|
|
|
|
@"Attempt to send to send port");
|
|
|
|
|
|
|
|
if (c == 1 && length == rl)
|
2005-11-05 05:58:43 +00:00
|
|
|
{
|
2005-11-08 16:44:46 +00:00
|
|
|
GSPortItemHeader *pih;
|
|
|
|
GSPortMsgHeader *pmh;
|
|
|
|
|
|
|
|
h = [components objectAtIndex: 0];
|
|
|
|
pih = (GSPortItemHeader*)[h mutableBytes];
|
|
|
|
pih->type = GSSwapHostI32ToBig(GSP_HEAD);
|
2005-11-09 16:30:57 +00:00
|
|
|
l = [h length] - sizeof(GSPortItemHeader);
|
2005-11-08 16:44:46 +00:00
|
|
|
pih->length = GSSwapHostI32ToBig(l);
|
|
|
|
pmh = (GSPortMsgHeader*)&pih[1];
|
|
|
|
pmh->mId = GSSwapHostI32ToBig(msgId);
|
|
|
|
pmh->nItems = GSSwapHostI32ToBig(c);
|
|
|
|
pmh->version = 0;
|
|
|
|
memcpy(pmh->port, [[(NSMessagePort*)receivingPort name] UTF8String], 24);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < c; i++)
|
|
|
|
{
|
|
|
|
id o = [components objectAtIndex: i];
|
|
|
|
|
|
|
|
if ([o isKindOfClass: [NSData class]] == YES)
|
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
l += sizeof(GSPortItemHeader) + [o length];
|
2005-11-08 16:44:46 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
l += sizeof(GSPortItemHeader) + 24; // A port
|
|
|
|
}
|
|
|
|
}
|
|
|
|
h = [[NSMutableData alloc] initWithCapacity: sizeof(GSPortMsgHeader) + l];
|
|
|
|
|
|
|
|
for (i = 0; i < c; i++)
|
|
|
|
{
|
|
|
|
id o = [components objectAtIndex: i];
|
|
|
|
GSPortItemHeader pih;
|
|
|
|
|
|
|
|
if (i == 0)
|
|
|
|
{
|
|
|
|
GSPortMsgHeader pmh;
|
|
|
|
|
|
|
|
// First item must be an NSData
|
|
|
|
pih.type = GSSwapHostI32ToBig(GSP_HEAD);
|
|
|
|
l = sizeof(GSPortMsgHeader) + [o length];
|
|
|
|
pih.length = GSSwapHostI32ToBig(l);
|
|
|
|
[h appendBytes: &pih length: sizeof(pih)];
|
|
|
|
pmh.mId = GSSwapHostI32ToBig(msgId);
|
|
|
|
pmh.nItems = GSSwapHostI32ToBig(c);
|
|
|
|
pmh.version = 0;
|
|
|
|
memcpy(pmh.port,
|
|
|
|
[[(NSMessagePort*)receivingPort name] UTF8String], 24);
|
|
|
|
[h appendBytes: &pmh length: sizeof(pmh)];
|
|
|
|
[h appendData: o];
|
|
|
|
}
|
|
|
|
else if ([o isKindOfClass: [NSData class]] == YES)
|
|
|
|
{
|
|
|
|
pih.type = GSSwapHostI32ToBig(GSP_DATA);
|
|
|
|
l = [o length];
|
|
|
|
pih.length = GSSwapHostI32ToBig(l);
|
|
|
|
[h appendBytes: &pih length: sizeof(pih)];
|
|
|
|
[h appendData: o];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pih.type = GSSwapHostI32ToBig(GSP_PORT);
|
|
|
|
l = 24;
|
|
|
|
pih.length = GSSwapHostI32ToBig(l);
|
|
|
|
[h appendBytes: &pih length: sizeof(pih)];
|
|
|
|
[h appendBytes: [o UTF8String] length: 24];
|
|
|
|
}
|
|
|
|
}
|
2005-11-05 05:58:43 +00:00
|
|
|
}
|
2005-11-08 16:44:46 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now send the message.
|
|
|
|
*/
|
|
|
|
M_LOCK(this->lock);
|
|
|
|
[this->wMsgs addObject: h];
|
|
|
|
if (this->wData == nil)
|
|
|
|
{
|
|
|
|
[self receivedEventWrite]; // Start async write.
|
|
|
|
}
|
|
|
|
|
|
|
|
loop = [NSRunLoop currentRunLoop];
|
|
|
|
|
|
|
|
RETAIN(self);
|
2005-11-09 16:30:57 +00:00
|
|
|
AUTORELEASE(RETAIN(components));
|
2005-11-08 16:44:46 +00:00
|
|
|
|
2005-11-09 16:30:57 +00:00
|
|
|
[loop addEvent: (void*)(gsaddr)this->event
|
2005-11-08 16:44:46 +00:00
|
|
|
type: ET_HANDLE
|
|
|
|
watcher: (id<RunLoopEvents>)self
|
|
|
|
forMode: NSConnectionReplyMode];
|
2005-11-09 16:30:57 +00:00
|
|
|
[loop addEvent: (void*)(gsaddr)this->event
|
2005-11-08 16:44:46 +00:00
|
|
|
type: ET_HANDLE
|
|
|
|
watcher: (id<RunLoopEvents>)self
|
|
|
|
forMode: NSDefaultRunLoopMode];
|
|
|
|
|
|
|
|
while ([self isValid] == YES
|
|
|
|
&& [this->wMsgs indexOfObjectIdenticalTo: h] != NSNotFound
|
|
|
|
&& [when timeIntervalSinceNow] > 0)
|
|
|
|
{
|
|
|
|
M_UNLOCK(this->lock);
|
|
|
|
[loop runMode: NSConnectionReplyMode beforeDate: when];
|
|
|
|
M_LOCK(this->lock);
|
|
|
|
}
|
|
|
|
|
2005-11-09 16:30:57 +00:00
|
|
|
[loop removeEvent: (void*)(gsaddr)this->event
|
2005-11-08 16:44:46 +00:00
|
|
|
type: ET_HANDLE
|
|
|
|
forMode: NSConnectionReplyMode
|
|
|
|
all: NO];
|
2005-11-09 16:30:57 +00:00
|
|
|
[loop removeEvent: (void*)(gsaddr)this->event
|
2005-11-08 16:44:46 +00:00
|
|
|
type: ET_HANDLE
|
|
|
|
forMode: NSDefaultRunLoopMode
|
|
|
|
all: NO];
|
|
|
|
|
|
|
|
if ([this->wMsgs indexOfObjectIdenticalTo: h] == NSNotFound)
|
|
|
|
{
|
|
|
|
sent = YES;
|
|
|
|
}
|
|
|
|
RELEASE(h);
|
|
|
|
M_UNLOCK(this->lock);
|
|
|
|
RELEASE(self);
|
2005-11-05 05:58:43 +00:00
|
|
|
|
|
|
|
return sent;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSDate*) timedOutEvent: (void*)data
|
|
|
|
type: (RunLoopEventType)type
|
|
|
|
forMode: (NSString*)mode
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|