Distributed objects tidyup with a few minor bugfixes

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@3687 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
richard 1999-02-11 08:10:24 +00:00
parent 51bab6f104
commit 39a39a1ab9
7 changed files with 625 additions and 626 deletions

View file

@ -1,3 +1,13 @@
Thu Feb 11 7:27:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Source/NSConnection.m: Tidy up with bugfixes and better distributed
retain/release for triangle connections.
* Source/NSDistantObject.m: ditto
* Source/TcpPort.m: ditto
* Source/include/DistributedObjects.h: ditto
* Source/include/NSConnection.h: ditto
* Source/include/NSDistantObject.h: ditto
1999-02-09 Adam Fedor <fedor@gnu.org> 1999-02-09 Adam Fedor <fedor@gnu.org>
* Source/HashTable.m: Moved to extensions. * Source/HashTable.m: Moved to extensions.

View file

@ -58,10 +58,11 @@ enum {
ROOTPROXY_REQUEST, ROOTPROXY_REQUEST,
ROOTPROXY_REPLY, ROOTPROXY_REPLY,
CONNECTION_SHUTDOWN, CONNECTION_SHUTDOWN,
METHODTYPE_REQUEST, /* these two only needed with NeXT runtime */ METHODTYPE_REQUEST,
METHODTYPE_REPLY, /* these two only needed with NeXT runtime */ METHODTYPE_REPLY,
PROXY_RELEASE, PROXY_RELEASE,
PROXY_RETAIN, PROXY_RETAIN,
RETAIN_REPLY
}; };

View file

@ -25,11 +25,8 @@
#ifndef __NSConnection_h_GNUSTEP_BASE_INCLUDE #ifndef __NSConnection_h_GNUSTEP_BASE_INCLUDE
#define __NSConnection_h_GNUSTEP_BASE_INCLUDE #define __NSConnection_h_GNUSTEP_BASE_INCLUDE
#include <base/preface.h> #include <Foundation/NSObject.h>
#include <stdlib.h> #include <Foundation/NSDictionary.h>
#include <stdarg.h>
#include <base/Collecting.h>
#include <base/Dictionary.h>
#include <Foundation/NSString.h> #include <Foundation/NSString.h>
#include <Foundation/NSTimer.h> #include <Foundation/NSTimer.h>
#include <Foundation/NSRunLoop.h> #include <Foundation/NSRunLoop.h>
@ -100,7 +97,6 @@ extern NSString *NSConnectionProxyCount; /* Objects received */
- (BOOL) independantConversationQueueing; - (BOOL) independantConversationQueueing;
- (void) invalidate; - (void) invalidate;
- (BOOL) isValid; - (BOOL) isValid;
- (BOOL) registerName: (NSString*)name;
- (NSArray *) remoteObjects; - (NSArray *) remoteObjects;
- (void) removeRequestMode: (NSString*)mode; - (void) removeRequestMode: (NSString*)mode;
- (void) removeRunLoop: (NSRunLoop *)runloop; - (void) removeRunLoop: (NSRunLoop *)runloop;
@ -139,7 +135,9 @@ extern NSString *NSConnectionProxyCount; /* Objects received */
* This catagory contains legacy methods from the original GNU 'Connection' * This catagory contains legacy methods from the original GNU 'Connection'
* class, and useful extensions to NSConnection. * class, and useful extensions to NSConnection.
*/ */
@interface NSConnection (GNUstepExtensions) @interface NSConnection (GNUstepExtensions) <GCFinalization>
- (void) gcFinalize;
/* Setting and getting class configuration */ /* Setting and getting class configuration */
+ (Class) defaultReceivePortClass; + (Class) defaultReceivePortClass;

View file

@ -35,7 +35,6 @@
NSConnection *_connection; NSConnection *_connection;
id _object; id _object;
unsigned _handle; unsigned _handle;
BOOL _isVended;
Protocol *_protocol; Protocol *_protocol;
} }
@ -56,12 +55,13 @@
@end @end
@interface NSDistantObject(GNUstepExtensions) @interface NSDistantObject(GNUstepExtensions) <GCFinalization>
- awakeAfterUsingCoder: aDecoder; - (id) awakeAfterUsingCoder: (NSCoder*)aDecoder;
- classForPortCoder; - (Class) classForPortCoder;
- (const char *) selectorTypeForProxy: (SEL)selector; - (const char *) selectorTypeForProxy: (SEL)selector;
- forward: (SEL)aSel :(arglist_t)frame; - (id) forward: (SEL)aSel :(arglist_t)frame;
- (void) gcFinalize;
@end @end
#endif /* __NSDistantObject_h_GNUSTEP_BASE_INCLUDE */ #endif /* __NSDistantObject_h_GNUSTEP_BASE_INCLUDE */

View file

@ -35,7 +35,8 @@
#include <Foundation/DistributedObjects.h> #include <Foundation/DistributedObjects.h>
#include <base/TcpPort.h> #include <base/TcpPort.h>
#include <mframe.h> #include <mframe.h>
#include <base/NotificationDispatcher.h> #include <Foundation/NSHashTable.h>
#include <Foundation/NSMapTable.h>
#include <Foundation/NSData.h> #include <Foundation/NSData.h>
#include <Foundation/NSRunLoop.h> #include <Foundation/NSRunLoop.h>
#include <Foundation/NSArray.h> #include <Foundation/NSArray.h>
@ -63,18 +64,12 @@ NSString *NSConnectionLocalCount = @"NSConnectionLocalCount";
NSString *NSConnectionProxyCount = @"NSConnectionProxyCount"; NSString *NSConnectionProxyCount = @"NSConnectionProxyCount";
@interface NSDistantObject (NSConnection) @interface NSDistantObject (NSConnection)
- (BOOL) isVended;
- (id) localForProxy; - (id) localForProxy;
- (void) setProxyTarget: (unsigned)target; - (void) setProxyTarget: (unsigned)target;
- (void) setVended;
- (unsigned) targetForProxy; - (unsigned) targetForProxy;
@end @end
@implementation NSDistantObject (NSConnection) @implementation NSDistantObject (NSConnection)
- (BOOL) isVended
{
return _isVended;
}
- (id) localForProxy - (id) localForProxy
{ {
return _object; return _object;
@ -83,10 +78,6 @@ NSString *NSConnectionProxyCount = @"NSConnectionProxyCount";
{ {
_handle = target; _handle = target;
} }
- (void) setVended
{
_isVended = YES;
}
- (unsigned) targetForProxy - (unsigned) targetForProxy
{ {
return _handle; return _handle;
@ -120,10 +111,15 @@ static unsigned local_object_counter = 0;
counter = (GSLocalCounter*)NSAllocateObject(self, 0, NSDefaultMallocZone()); counter = (GSLocalCounter*)NSAllocateObject(self, 0, NSDefaultMallocZone());
counter->ref = 1; counter->ref = 1;
counter->object = obj; counter->object = [obj retain];
counter->target = ++local_object_counter; counter->target = ++local_object_counter;
return counter; return counter;
} }
- (void) dealloc
{
[object release];
[super dealloc];
}
@end @end
@ -244,15 +240,8 @@ static NSTimer *timer;
static int debug_connection = 0; static int debug_connection = 0;
/* Perhaps this should be a hashtable, keyed by remote port. static NSHashTable *connection_table;
But we may also need to include the local port---even though static NSLock *connection_table_gate;
when receiving the local port is fixed, there may be more than
one registered connection (with different in ports) in the
application. */
/* We could write -hash and -isEqual implementations for NSConnection */
static NSMutableArray *connection_array;
static NSMutableArray *not_owned;
static NSLock *connection_array_gate;
static NSMutableDictionary *root_object_dictionary; static NSMutableDictionary *root_object_dictionary;
static NSLock *root_object_dictionary_gate; static NSLock *root_object_dictionary_gate;
@ -278,11 +267,7 @@ static int messages_received_count;
+ (NSArray*) allConnections + (NSArray*) allConnections
{ {
int count = [connection_array count]; return NSAllHashTableObjects(connection_table);
id cons[count];
[connection_array getObjects: cons];
return [NSArray arrayWithObjects: cons count: count];
} }
+ (NSConnection*) connectionWithRegisteredName: (NSString*)n + (NSConnection*) connectionWithRegisteredName: (NSString*)n
@ -329,9 +314,9 @@ static int messages_received_count;
+ (void) initialize + (void) initialize
{ {
not_owned = [[NSMutableArray alloc] initWithCapacity:8]; connection_table =
connection_array = [[NSMutableArray alloc] initWithCapacity:8]; NSCreateHashTable (NSNonRetainedObjectHashCallBacks, 0);
connection_array_gate = [NSLock new]; connection_table_gate = [NSLock new];
/* xxx When NSHashTable's are working, change this. */ /* xxx When NSHashTable's are working, change this. */
all_connections_local_objects = all_connections_local_objects =
NSCreateMapTable (NSNonOwnedPointerMapKeyCallBacks, NSCreateMapTable (NSNonOwnedPointerMapKeyCallBacks,
@ -414,39 +399,10 @@ static int messages_received_count;
} }
} }
/* This needs locks */
- (void) dealloc - (void) dealloc
{ {
if (debug_connection) if (debug_connection)
NSLog(@"deallocating 0x%x\n", (unsigned)self); NSLog(@"deallocating 0x%x\n", (gsaddr)self);
[self invalidate];
/* Remove rootObject from root_object_dictionary
if this is last connection */
if (![NSConnection connectionsCountWithInPort:receive_port])
[NSConnection setRootObject:nil forInPort:receive_port];
/* Remove receive port from run loop. */
[self setRequestMode: nil];
[[NSRunLoop currentRunLoop] removePort: receive_port
forMode: NSConnectionReplyMode];
[request_modes release];
/* Finished with ports - releasing them may generate a notification */
[receive_port release];
[send_port release];
/* Don't need notifications any more - so remove self as observer. */
[NotificationDispatcher removeObserver: self];
[proxiesHashGate lock];
NSFreeMapTable (remote_proxies);
NSFreeMapTable (local_objects);
NSFreeMapTable (local_targets);
NSFreeMapTable (incoming_xref_2_const_ptr);
NSFreeMapTable (outgoing_const_ptr_2_xref);
[proxiesHashGate unlock];
[super dealloc]; [super dealloc];
} }
@ -482,18 +438,6 @@ static int messages_received_count;
return newConn; return newConn;
} }
/* xxx This method is an anomaly, just until we get a proper name
server for port objects. Richard Frith-MacDonald is working on a
name server. */
- (BOOL) registerName: (NSString*)name
{
id old_receive_port = receive_port;
receive_port = [default_receive_port_class newForReceivingFromRegisteredName: name];
[old_receive_port release];
return YES;
}
/* /*
* Keep track of connections created by DO system but not necessarily * Keep track of connections created by DO system but not necessarily
* ever retained by users code. These must be retained now for later * ever retained by users code. These must be retained now for later
@ -501,17 +445,20 @@ static int messages_received_count;
*/ */
- (void) setNotOwned - (void) setNotOwned
{ {
if (![not_owned containsObject:self]) {
[not_owned addObject:self];
}
} }
/* xxx This needs locks */ /* xxx This needs locks */
- (void) invalidate - (void) invalidate
{ {
if (is_valid) if (is_valid == NO)
{ return;
is_valid = 0;
is_valid = NO;
/*
* Don't need notifications any more - so remove self as observer.
*/
[NSNotificationCenter removeObserver: self];
/* /*
* We can't be the ancestor of anything if we are invalid. * We can't be the ancestor of anything if we are invalid.
@ -540,23 +487,24 @@ static int messages_received_count;
[targets release]; [targets release];
[proxiesHashGate unlock]; [proxiesHashGate unlock];
} }
/* xxx Note: this is causing us to send a shutdown message
to the connection that shut *us* down. Don't do that.
Well, perhaps it's a good idea just in case other side didn't really
send us the shutdown; this way we let them know we're going away */
#if 0
[self shutdown];
#endif
if (debug_connection) if (debug_connection)
NSLog(@"Invalidating connection 0x%x\n\t%@\n\t%@\n", (unsigned)self, NSLog(@"Invalidating connection 0x%x\n\t%@\n\t%@\n", (gsaddr)self,
[receive_port description], [send_port description]); [receive_port description], [send_port description]);
[NotificationDispatcher /*
postNotificationName: NSConnectionDidDieNotification * We need to notify any watchers of our death - but if we are already
object: self]; * in the deallocation process, we can't have a notification retaining
* and autoreleasing us later once we are deallocated - so we do the
* notification with a local autorelease pool to ensure that any release
* is done before the deallocation completes.
*/
{
NSAutoreleasePool *arp = [NSAutoreleasePool new];
[not_owned removeObjectIdenticalTo:self]; [NSNotificationCenter postNotificationName: NSConnectionDidDieNotification
object: self];
[arp release];
} }
} }
@ -568,21 +516,15 @@ static int messages_received_count;
- (void) release - (void) release
{ {
/* /*
* In order that connections may be deallocated - we check to see if * If this would cause the connection to be deallocated then we
* the only thing still retaining us is the connection_array. * must perform all necessary work (done in [-gcFinalize]).
* if so (we assume a retain count of 2 means this) we remove self * We bracket the code with a retain and release so that any
* from the connection array. * retain/release pairs in the code won't cause recursion.
* NB. bracket this operation with retain and release so that we don't
* suffer problems with recursion.
*/ */
if ([self retainCount] == 2) { if ([self retainCount] == 1)
{
[super retain]; [super retain];
[connection_array_gate lock]; [self gcFinalize];
[connection_array removeObject: self];
[timer invalidate];
timer = nil;
NSResetMapTable(all_connections_local_cached);
[connection_array_gate unlock];
[super release]; [super release];
} }
[super release]; [super release];
@ -596,7 +538,8 @@ static int messages_received_count;
- (void) removeRequestMode: (NSString*)mode - (void) removeRequestMode: (NSString*)mode
{ {
if ([request_modes containsObject:mode]) { if ([request_modes containsObject:mode])
{
[request_modes removeObject:mode]; [request_modes removeObject:mode];
[[NSRunLoop currentRunLoop] removePort: receive_port forMode: mode]; [[NSRunLoop currentRunLoop] removePort: receive_port forMode: mode];
} }
@ -614,7 +557,7 @@ static int messages_received_count;
- (NSArray*) requestModes - (NSArray*) requestModes
{ {
return [request_modes copy]; return [[request_modes copy] autorelease];
} }
- (NSTimeInterval) requestTimeout - (NSTimeInterval) requestTimeout
@ -622,11 +565,6 @@ static int messages_received_count;
return request_timeout; return request_timeout;
} }
- (id) retain
{
return [super retain];
}
- (id) rootObject - (id) rootObject
{ {
return [[self class] rootObjectForInPort: receive_port]; return [[self class] rootObjectForInPort: receive_port];
@ -669,13 +607,16 @@ static int messages_received_count;
- (void) setRequestMode: (NSString*)mode - (void) setRequestMode: (NSString*)mode
{ {
while ([request_modes count]>0 && [request_modes objectAtIndex:0]!=mode) { while ([request_modes count] > 0 && [request_modes objectAtIndex: 0] != mode)
{
[self removeRequestMode: [request_modes objectAtIndex: 0]]; [self removeRequestMode: [request_modes objectAtIndex: 0]];
} }
while ([request_modes count]>1) { while ([request_modes count] > 1)
{
[self removeRequestMode: [request_modes objectAtIndex: 1]]; [self removeRequestMode: [request_modes objectAtIndex: 1]];
} }
if (mode != nil && [request_modes count] == 0) { if (mode != nil && [request_modes count] == 0)
{
[self addRequestMode: mode]; [self addRequestMode: mode];
} }
} }
@ -716,6 +657,10 @@ static int messages_received_count;
[d setObject: o forKey: NSConnectionLocalCount]; [d setObject: o forKey: NSConnectionLocalCount];
o = [NSNumber numberWithUnsignedInt: NSCountMapTable(remote_proxies)]; o = [NSNumber numberWithUnsignedInt: NSCountMapTable(remote_proxies)];
[d setObject: o forKey: NSConnectionProxyCount]; [d setObject: o forKey: NSConnectionProxyCount];
[received_request_rmc_queue_gate lock];
o = [NSNumber numberWithUnsignedInt: [received_request_rmc_queue count]];
[received_request_rmc_queue_gate unlock];
[d setObject: o forKey: @"Pending packets"];
return d; return d;
} }
@ -726,6 +671,46 @@ static int messages_received_count;
@implementation NSConnection (GNUstepExtensions) @implementation NSConnection (GNUstepExtensions)
- (void) gcFinalize
{
NSAutoreleasePool *arp = [NSAutoreleasePool new];
if (debug_connection)
NSLog(@"finalising 0x%x\n", (gsaddr)self);
[self invalidate];
[connection_table_gate lock];
NSHashRemove(connection_table, self);
[timer invalidate];
timer = nil;
[connection_table_gate unlock];
/* Remove rootObject from root_object_dictionary
if this is last connection */
if (![NSConnection connectionsCountWithInPort:receive_port])
[NSConnection setRootObject:nil forInPort:receive_port];
/* Remove receive port from run loop. */
[self setRequestMode: nil];
[[NSRunLoop currentRunLoop] removePort: receive_port
forMode: NSConnectionReplyMode];
[request_modes release];
/* Finished with ports - releasing them may generate a notification */
[receive_port release];
[send_port release];
[proxiesHashGate lock];
NSFreeMapTable (remote_proxies);
NSFreeMapTable (local_objects);
NSFreeMapTable (local_targets);
NSFreeMapTable (incoming_xref_2_const_ptr);
NSFreeMapTable (outgoing_const_ptr_2_xref);
[proxiesHashGate unlock];
[arp release];
}
/* Getting and setting class variables */ /* Getting and setting class variables */
+ (Class) default_decoding_class + (Class) default_decoding_class
@ -797,24 +782,25 @@ static int messages_received_count;
+ (unsigned) connectionsCount + (unsigned) connectionsCount
{ {
return [connection_array count]; return NSCountHashTable(connection_table);
} }
+ (unsigned) connectionsCountWithInPort: (NSPort*)aPort + (unsigned) connectionsCountWithInPort: (NSPort*)aPort
{ {
unsigned count = 0; unsigned count = 0;
unsigned pos; NSHashEnumerator enumerator;
NSConnection *o;
[connection_array_gate lock]; [connection_table_gate lock];
count = [connection_array count]; enumerator = NSEnumerateHashTable(connection_table);
for (pos = 0; pos < [connection_array count]; pos++) { while ((o = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil)
id o = [connection_array objectAtIndex:pos]; {
if ([aPort isEqual: [o receivePort]])
if ([aPort isEqual: [o receivePort]]) { {
count++; count++;
} }
} }
[connection_array_gate unlock]; [connection_table_gate unlock];
return count; return count;
} }
@ -904,25 +890,30 @@ static int messages_received_count;
/* This is the designated initializer for NSConnection */ /* This is the designated initializer for NSConnection */
+ (NSConnection*) newForInPort: (NSPort*)ip outPort: (NSPort*)op + (NSConnection*) newForInPort: (NSPort*)ip
ancestorConnection: ancestor outPort: (NSPort*)op
ancestorConnection: (NSConnection*)ancestor
{ {
NSConnection *newConn; NSConnection *newConn;
NSParameterAssert (ip); NSParameterAssert (ip);
/* Find previously existing connection if there */ /* Find previously existing connection if there */
newConn = [[self connectionByInPort: ip outPort: op] retain]; newConn = [self connectionByInPort: ip outPort: op];
if (newConn) if (newConn)
return newConn; {
if (debug_connection > 2)
[connection_array_gate lock]; NSLog(@"Found existing connection (0x%x) for \n\t%@\n\t%@\n",
(gsaddr)newConn, [ip description], [op description]);
return [newConn retain];
}
[connection_table_gate lock];
newConn = [[NSConnection alloc] _superInit]; newConn = [[NSConnection alloc] _superInit];
if (debug_connection) if (debug_connection)
NSLog(@"Created new connection 0x%x\n\t%@\n\t%@\n", NSLog(@"Created new connection 0x%x\n\t%@\n\t%@\n",
(unsigned)newConn, [ip description], [op description]); (gsaddr)newConn, [ip description], [op description]);
newConn->is_valid = 1; newConn->is_valid = YES;
newConn->receive_port = ip; newConn->receive_port = ip;
[ip retain]; [ip retain];
newConn->send_port = op; newConn->send_port = op;
@ -948,7 +939,7 @@ static int messages_received_count;
/* This maps [proxy targetForProxy] to proxy. The proxy's are retained. */ /* This maps [proxy targetForProxy] to proxy. The proxy's are retained. */
newConn->remote_proxies = newConn->remote_proxies =
NSCreateMapTable (NSIntMapKeyCallBacks, NSCreateMapTable (NSIntMapKeyCallBacks,
NSObjectMapValueCallBacks, 0); NSNonOwnedPointerMapValueCallBacks, 0);
newConn->incoming_xref_2_const_ptr = newConn->incoming_xref_2_const_ptr =
NSCreateMapTable (NSIntMapKeyCallBacks, NSCreateMapTable (NSIntMapKeyCallBacks,
@ -1009,7 +1000,7 @@ static int messages_received_count;
if (![[ancestor delegate] connection: ancestor if (![[ancestor delegate] connection: ancestor
shouldMakeNewConnection: (NSConnection*)newConn]) shouldMakeNewConnection: (NSConnection*)newConn])
{ {
[connection_array_gate unlock]; [connection_table_gate unlock];
[newConn release]; [newConn release];
return nil; return nil;
} }
@ -1020,7 +1011,7 @@ static int messages_received_count;
if (![[ancestor delegate] makeNewConnection: (NSConnection*)newConn if (![[ancestor delegate] makeNewConnection: (NSConnection*)newConn
sender: ancestor]) sender: ancestor])
{ {
[connection_array_gate unlock]; [connection_table_gate unlock];
[newConn release]; [newConn release];
return nil; return nil;
} }
@ -1034,12 +1025,12 @@ static int messages_received_count;
/* Register ourselves for invalidation notification when the /* Register ourselves for invalidation notification when the
ports become invalid. */ ports become invalid. */
[NotificationDispatcher addObserver: newConn [NSNotificationCenter addObserver: newConn
selector: @selector(portIsInvalid:) selector: @selector(portIsInvalid:)
name: NSPortDidBecomeInvalidNotification name: NSPortDidBecomeInvalidNotification
object: ip]; object: ip];
if (op) if (op)
[NotificationDispatcher addObserver: newConn [NSNotificationCenter addObserver: newConn
selector: @selector(portIsInvalid:) selector: @selector(portIsInvalid:)
name: NSPortDidBecomeInvalidNotification name: NSPortDidBecomeInvalidNotification
object: op]; object: op];
@ -1051,10 +1042,10 @@ static int messages_received_count;
/* In order that connections may be deallocated - there is an /* In order that connections may be deallocated - there is an
implementation of [-release] to automatically remove the connection implementation of [-release] to automatically remove the connection
from this array when it is the only thing retaining it. */ from this array when it is the only thing retaining it. */
[connection_array addObject: newConn]; NSHashInsert(connection_table, (void*)newConn);
[connection_array_gate unlock]; [connection_table_gate unlock];
[NotificationDispatcher [NSNotificationCenter
postNotificationName: NSConnectionDidInitializeNotification postNotificationName: NSConnectionDidInitializeNotification
object: newConn]; object: newConn];
@ -1064,56 +1055,54 @@ static int messages_received_count;
+ (NSConnection*) connectionByInPort: (NSPort*)ip + (NSConnection*) connectionByInPort: (NSPort*)ip
outPort: (NSPort*)op outPort: (NSPort*)op
{ {
int count; NSHashEnumerator enumerator;
int i; NSConnection *o;
NSParameterAssert (ip); NSParameterAssert (ip);
[connection_array_gate lock]; [connection_table_gate lock];
count = [connection_array count];
for (i = 0; i < count; i++) enumerator = NSEnumerateHashTable(connection_table);
while ((o = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil)
{ {
id newConnInPort; id newConnInPort;
id newConnOutPort; id newConnOutPort;
NSConnection *newConn;
newConn = [connection_array objectAtIndex: i]; newConnInPort = [o receivePort];
newConnInPort = [newConn receivePort]; newConnOutPort = [o sendPort];
newConnOutPort = [newConn sendPort];
if ([newConnInPort isEqual: ip] if ([newConnInPort isEqual: ip]
&& [newConnOutPort isEqual: op]) && [newConnOutPort isEqual: op])
{ {
[connection_array_gate unlock]; [connection_table_gate unlock];
return newConn; return o;
} }
} }
[connection_array_gate unlock]; [connection_table_gate unlock];
return nil; return nil;
} }
+ (NSConnection*) connectionByOutPort: (NSPort*)op + (NSConnection*) connectionByOutPort: (NSPort*)op
{ {
int i, count; NSHashEnumerator enumerator;
NSConnection *o;
NSParameterAssert (op); NSParameterAssert (op);
[connection_array_gate lock]; [connection_table_gate lock];
count = [connection_array count]; enumerator = NSEnumerateHashTable(connection_table);
for (i = 0; i < count; i++) while ((o = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil)
{ {
id newConnOutPort; id newConnOutPort;
NSConnection *newConn;
newConn = [connection_array objectAtIndex: i]; newConnOutPort = [o sendPort];
newConnOutPort = [newConn sendPort];
if ([newConnOutPort isEqual: op]) if ([newConnOutPort isEqual: op])
{ {
[connection_array_gate unlock]; [connection_table_gate unlock];
return newConn; return o;
} }
} }
[connection_array_gate unlock]; [connection_table_gate unlock];
return nil; return nil;
} }
@ -1192,7 +1181,6 @@ static int messages_received_count;
int seq_num; int seq_num;
NSParameterAssert (is_valid); NSParameterAssert (is_valid);
[[self retain] autorelease];
/* get the method types from the selector */ /* get the method types from the selector */
#if NeXT_runtime #if NeXT_runtime
@ -1214,6 +1202,8 @@ static int messages_received_count;
op = [self newSendingRequestRmc]; op = [self newSendingRequestRmc];
seq_num = [op sequenceNumber]; seq_num = [op sequenceNumber];
if (debug_connection > 4)
NSLog(@"building packet seq %d\n", seq_num);
/* Send the types that we're using, so that the performer knows /* Send the types that we're using, so that the performer knows
exactly what qualifiers we're using. exactly what qualifiers we're using.
@ -1232,7 +1222,7 @@ static int messages_received_count;
/* Send the rmc */ /* Send the rmc */
[op dismiss]; [op dismiss];
if (debug_connection > 1) if (debug_connection > 1)
NSLog(@"Sent message to 0x%x\n", (unsigned)self); NSLog(@"Sent message to 0x%x\n", (gsaddr)self);
req_out_count++; /* Sent a request. */ req_out_count++; /* Sent a request. */
/* Get the reply rmc, and decode it. */ /* Get the reply rmc, and decode it. */
@ -1387,7 +1377,7 @@ static int messages_received_count;
withName:NULL]; withName:NULL];
if (debug_connection > 1) if (debug_connection > 1)
NSLog(@"Handling message from 0x%x\n", (unsigned)self); NSLog(@"Handling message from 0x%x\n", (gsaddr)self);
req_in_count++; /* Handling an incoming request. */ req_in_count++; /* Handling an incoming request. */
mframe_do_call (forward_type, decoder, encoder); mframe_do_call (forward_type, decoder, encoder);
[op dismiss]; [op dismiss];
@ -1445,6 +1435,7 @@ static int messages_received_count;
if ([rmc connection] != self) if ([rmc connection] != self)
{ {
[rmc dismiss];
[NSException raise: @"ProxyDecodedBadTarget" [NSException raise: @"ProxyDecodedBadTarget"
format: @"request to release object on bad connection"]; format: @"request to release object on bad connection"];
} }
@ -1456,26 +1447,23 @@ static int messages_received_count;
for (pos = 0; pos < count; pos++) for (pos = 0; pos < count; pos++)
{ {
unsigned target; unsigned target;
char vended;
NSDistantObject *prox; NSDistantObject *prox;
[rmc decodeValueOfCType: @encode(typeof(target)) [rmc decodeValueOfCType: @encode(typeof(target))
at: &target at: &target
withName: NULL]; withName: NULL];
[rmc decodeValueOfCType: @encode(typeof(char))
at: &vended
withName: NULL];
prox = (NSDistantObject*)[self includesLocalTarget: target]; prox = (NSDistantObject*)[self includesLocalTarget: target];
if (prox != nil) if (prox != nil)
{ {
if (vended) if (debug_connection > 3)
{ NSLog(@"releasing object with target (0x%x) on (0x%x)",
[prox setVended]; target, (gsaddr)self);
}
[self removeLocalObject: [prox localForProxy]]; [self removeLocalObject: [prox localForProxy]];
} }
else if (debug_connection > 3)
NSLog(@"releasing object with target (0x%x) on (0x%x) - nothing to do",
target, (gsaddr)self);
} }
[rmc dismiss]; [rmc dismiss];
@ -1484,28 +1472,83 @@ static int messages_received_count;
- (void) _service_retain: rmc forConnection: receiving_connection - (void) _service_retain: rmc forConnection: receiving_connection
{ {
unsigned target; unsigned target;
NSPortCoder *op;
NSParameterAssert (is_valid); NSParameterAssert (is_valid);
if ([rmc connection] != self) if ([rmc connection] != self)
{ {
[rmc dismiss];
[NSException raise: @"ProxyDecodedBadTarget" [NSException raise: @"ProxyDecodedBadTarget"
format: @"request to retain object on bad connection"]; format: @"request to retain object on bad connection"];
} }
op = [[self encodingClass] newForWritingWithConnection: [rmc connection]
sequenceNumber: [rmc sequenceNumber]
identifier: RETAIN_REPLY];
[rmc decodeValueOfCType: @encode(typeof(target)) [rmc decodeValueOfCType: @encode(typeof(target))
at: &target at: &target
withName: NULL]; withName: NULL];
if (debug_connection > 3)
NSLog(@"looking to retain local object with target (0x%x) on (0x%x)",
target, (gsaddr)self);
if ([self includesLocalTarget: target] == nil) if ([self includesLocalTarget: target] == nil)
{ {
GSLocalCounter *counter; GSLocalCounter *counter;
counter = (GSLocalCounter*)[[self class] includesLocalTarget: target]; [proxiesHashGate lock];
if (counter != nil) counter = NSMapGet (all_connections_local_targets, (void*)target);
[NSDistantObject proxyWithLocal: counter->object connection: self]; if (counter == nil)
{
/*
* If the target doesn't exist for any connection, but still
* persists in the cache (ie it was recently released) then
* we move it back from the cache to the main maps so we can
* retain it on this connection.
*/
counter = NSMapGet (all_connections_local_cached, (void*)target);
if (counter)
{
unsigned t = counter->target;
id o = counter->object;
NSMapInsert(all_connections_local_objects, (void*)o, counter);
NSMapInsert(all_connections_local_targets, (void*)t, counter);
NSMapRemove(all_connections_local_cached, (void*)t);
if (debug_connection > 3)
NSLog(@"target (0x%x) moved from cache", target);
}
}
[proxiesHashGate unlock];
if (counter == nil)
{
[op encodeObject: @"target not found anywhere"
withName: @"retain failed"];
if (debug_connection > 3)
NSLog(@"target (0x%x) not found anywhere for retain", target);
}
else
{
[NSDistantObject proxyWithLocal: counter->object
connection: self];
[op encodeObject: nil withName: @"retain ok"];
if (debug_connection > 3)
NSLog(@"retained object (0x%x) target (0x%x) on connection(0x%x)",
counter->object, counter->target, self);
}
}
else
{
[op encodeObject: nil withName: @"already retained"];
if (debug_connection > 3)
NSLog(@"target (0x%x) already retained on connection (0x%x)",
target, self);
} }
[op dismiss];
[rmc dismiss]; [rmc dismiss];
} }
@ -1619,9 +1662,13 @@ static int messages_received_count;
- (void) _handleRmc: rmc - (void) _handleRmc: rmc
{ {
NSConnection* conn = [[rmc connection] retain]; NSConnection *conn = [rmc connection];
int ident = [rmc identifier];
switch ([rmc identifier]) if (debug_connection > 4)
NSLog(@"handling packet of type %d seq %d\n", ident, [rmc sequenceNumber]);
switch (ident)
{ {
case ROOTPROXY_REQUEST: case ROOTPROXY_REQUEST:
/* It won't take much time to handle this, so go ahead and service /* It won't take much time to handle this, so go ahead and service
@ -1642,14 +1689,12 @@ static int messages_received_count;
if independant_queuing is NO. */ if independant_queuing is NO. */
if (reply_depth == 0 || independant_queueing == NO) if (reply_depth == 0 || independant_queueing == NO)
{ {
[self retain];
[conn _service_forwardForProxy: rmc]; [conn _service_forwardForProxy: rmc];
/* Service any requests that were queued while we /* Service any requests that were queued while we
were waiting for replies. were waiting for replies.
xxx Is this the right place for this check? */ xxx Is this the right place for this check? */
if (reply_depth == 0) if (reply_depth == 0)
[self _handleQueuedRmcRequests]; [self _handleQueuedRmcRequests];
[self release];
} }
else else
{ {
@ -1661,6 +1706,7 @@ static int messages_received_count;
case ROOTPROXY_REPLY: case ROOTPROXY_REPLY:
case METHOD_REPLY: case METHOD_REPLY:
case METHODTYPE_REPLY: case METHODTYPE_REPLY:
case RETAIN_REPLY:
/* Remember multi-threaded callbacks will have to be handled specially */ /* Remember multi-threaded callbacks will have to be handled specially */
[received_reply_rmc_queue_gate lock]; [received_reply_rmc_queue_gate lock];
[received_reply_rmc_queue addObject: rmc]; [received_reply_rmc_queue addObject: rmc];
@ -1682,11 +1728,10 @@ static int messages_received_count;
break; break;
} }
default: default:
[conn release]; [rmc dismiss];
[NSException raise: NSGenericException [NSException raise: NSGenericException
format: @"unrecognized NSPortCoder identifier"]; format: @"unrecognized NSPortCoder identifier"];
} }
[conn release];
} }
- (void) _handleQueuedRmcRequests - (void) _handleQueuedRmcRequests
@ -1694,6 +1739,7 @@ static int messages_received_count;
id rmc; id rmc;
[received_request_rmc_queue_gate lock]; [received_request_rmc_queue_gate lock];
[self retain];
while (is_valid && ([received_request_rmc_queue count] > 0)) while (is_valid && ([received_request_rmc_queue count] > 0))
{ {
rmc = [received_request_rmc_queue objectAtIndex: 0]; rmc = [received_request_rmc_queue objectAtIndex: 0];
@ -1702,6 +1748,7 @@ static int messages_received_count;
[self _handleRmc: rmc]; [self _handleRmc: rmc];
[received_request_rmc_queue_gate lock]; [received_request_rmc_queue_gate lock];
} }
[self release];
[received_request_rmc_queue_gate unlock]; [received_request_rmc_queue_gate unlock];
} }
@ -1770,12 +1817,24 @@ static int messages_received_count;
This method is called by InPort when it receives a new packet. */ This method is called by InPort when it receives a new packet. */
+ (void) invokeWithObject: packet + (void) invokeWithObject: packet
{ {
id rmc = [NSPortCoder id rmc;
newDecodingWithPacket: packet NSConnection *connection;
connection: NSMapGet (receive_port_2_ancestor,
[packet receivingInPort])]; if (debug_connection > 3)
NSLog(@"packet arrived on %@", [[packet receivingInPort] description]);
connection = NSMapGet(receive_port_2_ancestor, [packet receivingInPort]);
if (connection && [connection isValid])
{
rmc = [NSPortCoder newDecodingWithPacket: packet
connection: connection];
[[rmc connection] _handleRmc: rmc]; [[rmc connection] _handleRmc: rmc];
} }
else
{
[packet release]; /* Discard data on invalid connection. */
}
}
- (int) _newMsgNumber - (int) _newMsgNumber
{ {
@ -1800,13 +1859,13 @@ static int messages_received_count;
NSParameterAssert (is_valid); NSParameterAssert (is_valid);
[proxiesHashGate lock]; [proxiesHashGate lock];
/* xxx Do we need to check to make sure it's not already there? */ /* xxx Do we need to check to make sure it's not already there? */
/* This retains anObj. */ /* This retains object. */
NSMapInsert(local_objects, (void*)object, anObj); NSMapInsert(local_objects, (void*)object, anObj);
/* /*
* Keep track of local objects accross all connections. * Keep track of local objects accross all connections.
*/ */
counter = NSMapGet(all_connections_local_targets, (void*)target); counter = NSMapGet(all_connections_local_objects, (void*)object);
if (counter) if (counter)
{ {
counter->ref++; counter->ref++;
@ -1823,8 +1882,9 @@ static int messages_received_count;
[anObj setProxyTarget: target]; [anObj setProxyTarget: target];
NSMapInsert(local_targets, (void*)target, anObj); NSMapInsert(local_targets, (void*)target, anObj);
if (debug_connection > 2) if (debug_connection > 2)
NSLog(@"add local object (0x%x) to connection (0x%x) (ref %d)\n", NSLog(@"add local object (0x%x) target (0x%x) "
(unsigned)object, (unsigned) self, counter->ref); @"to connection (0x%x) (ref %d)\n",
(gsaddr)object, target, (gsaddr) self, counter->ref);
[proxiesHashGate unlock]; [proxiesHashGate unlock];
} }
@ -1843,15 +1903,13 @@ static int messages_received_count;
/* This should get called whenever an object free's itself */ /* This should get called whenever an object free's itself */
+ (void) removeLocalObject: (id)anObj + (void) removeLocalObject: (id)anObj
{ {
id c; NSHashEnumerator enumerator;
int i, count = [connection_array count]; NSConnection *o;
/* Don't assert (is_valid); */ enumerator = NSEnumerateHashTable(connection_table);
for (i = 0; i < count; i++) while ((o = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil)
{ {
c = [connection_array objectAtIndex:i]; [o removeLocalObject: anObj];
[c removeLocalObject: anObj];
// [c removeProxy: anObj];
} }
} }
@ -1877,14 +1935,12 @@ static int messages_received_count;
counter->ref--; counter->ref--;
if ((val = counter->ref) == 0) if ((val = counter->ref) == 0)
{ {
NSMapRemove(all_connections_local_objects, (void*)anObj);
NSMapRemove(all_connections_local_targets, (void*)target);
/* /*
* If this proxy has been vended onwards by another process, we * If this proxy has been vended onwards by another process, we
* need to keep a reference to the local object around for a * need to keep a reference to the local object around for a
* while in case that other process needs it. * while in case that other process needs it.
*/ */
if ([prox isVended]) if (0)
{ {
id item; id item;
if (timer == nil) if (timer == nil)
@ -1897,7 +1953,12 @@ static int messages_received_count;
} }
item = [CachedLocalObject itemWithObject: counter time: 30]; item = [CachedLocalObject itemWithObject: counter time: 30];
NSMapInsert(all_connections_local_cached, (void*)target, item); NSMapInsert(all_connections_local_cached, (void*)target, item);
if (debug_connection > 3)
NSLog(@"placed local object (0x%x) target (0x%x) in cache",
(gsaddr)anObj, target);
} }
NSMapRemove(all_connections_local_objects, (void*)anObj);
NSMapRemove(all_connections_local_targets, (void*)target);
} }
} }
@ -1905,13 +1966,14 @@ static int messages_received_count;
NSMapRemove(local_targets, (void*)target); NSMapRemove(local_targets, (void*)target);
if (debug_connection > 2) if (debug_connection > 2)
NSLog(@"remove local object (0x%x) to connection (0x%x) (ref %d)\n", NSLog(@"remove local object (0x%x) target (0x%x) "
(unsigned)anObj, (unsigned) self, val); @"from connection (0x%x) (ref %d)\n",
(gsaddr)anObj, target, (gsaddr)self, val);
[proxiesHashGate unlock]; [proxiesHashGate unlock];
} }
- (void) _release_targets: (NSDistantObject**)list count:(unsigned int)number - (void) _release_targets: (unsigned*)list count: (unsigned)number
{ {
NS_DURING NS_DURING
{ {
@ -1922,27 +1984,25 @@ static int messages_received_count;
*/ */
if (receive_port && is_valid && number > 0) { if (receive_port && is_valid && number > 0) {
id op; id op;
unsigned int i; unsigned i;
op = [[self encodingClass] op = [[self encodingClass]
newForWritingWithConnection: self newForWritingWithConnection: self
sequenceNumber: [self _newMsgNumber] sequenceNumber: [self _newMsgNumber]
identifier: PROXY_RELEASE]; identifier: PROXY_RELEASE];
[op encodeValueOfCType: @encode(typeof(number)) [op encodeValueOfCType: @encode(unsigned)
at: &number at: &number
withName: NULL]; withName: NULL];
for (i = 0; i < number; i++) { for (i = 0; i < number; i++)
unsigned target = [list[i] targetForProxy]; {
char vended = [list[i] isVended]; [op encodeValueOfCType: @encode(unsigned)
at: &list[i]
[op encodeValueOfCType: @encode(typeof(target))
at: &target
withName: NULL];
[op encodeValueOfCType: @encode(char)
at: &vended
withName: NULL]; withName: NULL];
if (debug_connection > 3)
NSLog(@"sending release for target (0x%x) on (0x%x)",
list[i], (gsaddr)self);
} }
[op dismiss]; [op dismiss];
@ -1967,7 +2027,9 @@ static int messages_received_count;
if (receive_port && is_valid) if (receive_port && is_valid)
{ {
id op; id op;
id ip;
unsigned int i; unsigned int i;
id result;
int seq_num = [self _newMsgNumber]; int seq_num = [self _newMsgNumber];
op = [[self encodingClass] op = [[self encodingClass]
@ -1980,11 +2042,15 @@ static int messages_received_count;
withName: NULL]; withName: NULL];
[op dismiss]; [op dismiss];
ip = [self _getReceivedReplyRmcWithSequenceNumber: seq_num];
[ip decodeObjectAt: &result withName: NULL];
if (result != nil)
NSLog(@"failed to retain target - %@\n", result);
[ip dismiss];
} }
} }
NS_HANDLER NS_HANDLER
{ {
if (debug_connection)
NSLog(@"failed to retain target - %@\n", [localException name]); NSLog(@"failed to retain target - %@\n", [localException name]);
} }
NS_ENDHANDLER NS_ENDHANDLER
@ -1992,7 +2058,7 @@ static int messages_received_count;
- (void) removeProxy: (NSDistantObject*)aProxy - (void) removeProxy: (NSDistantObject*)aProxy
{ {
unsigned target = (unsigned)[aProxy targetForProxy]; unsigned target = [aProxy targetForProxy];
/* Don't assert (is_valid); */ /* Don't assert (is_valid); */
[proxiesHashGate lock]; [proxiesHashGate lock];
@ -2004,7 +2070,7 @@ static int messages_received_count;
* Tell the remote application that we have removed our proxy and * Tell the remote application that we have removed our proxy and
* it can release it's local object. * it can release it's local object.
*/ */
[self _release_targets:&aProxy count:1]; [self _release_targets: &target count: 1];
} }
- (NSArray *) localObjects - (NSArray *) localObjects
@ -2050,8 +2116,11 @@ static int messages_received_count;
NSParameterAssert([aProxy connectionForProxy] == self); NSParameterAssert([aProxy connectionForProxy] == self);
[proxiesHashGate lock]; [proxiesHashGate lock];
if (NSMapGet (remote_proxies, (void*)target)) if (NSMapGet (remote_proxies, (void*)target))
{
[proxiesHashGate unlock];
[NSException raise: NSGenericException [NSException raise: NSGenericException
format: @"Trying to add the same proxy twice"]; format: @"Trying to add the same proxy twice"];
}
NSMapInsert (remote_proxies, (void*)target, aProxy); NSMapInsert (remote_proxies, (void*)target, aProxy);
[proxiesHashGate unlock]; [proxiesHashGate unlock];
} }
@ -2103,9 +2172,6 @@ static int messages_received_count;
NSParameterAssert (all_connections_local_targets); NSParameterAssert (all_connections_local_targets);
[proxiesHashGate lock]; [proxiesHashGate lock];
ret = NSMapGet (all_connections_local_targets, (void*)target); ret = NSMapGet (all_connections_local_targets, (void*)target);
if (ret == nil) {
ret = NSMapGet (all_connections_local_cached, (void*)target);
}
[proxiesHashGate unlock]; [proxiesHashGate unlock];
return ret; return ret;
} }
@ -2253,12 +2319,12 @@ static int messages_received_count;
if (debug_connection) if (debug_connection)
NSLog(@"Received port invalidation notification for " NSLog(@"Received port invalidation notification for "
@"connection 0x%x\n\t%@\n", (unsigned)self, @"connection 0x%x\n\t%@\n", (gsaddr)self,
[port description]); [port description]);
/* We shouldn't be getting any port invalidation notifications, /* We shouldn't be getting any port invalidation notifications,
except from our own ports; this is how we registered ourselves except from our own ports; this is how we registered ourselves
with the NotificationDispatcher in with the NSNotificationCenter in
+newForInPort:outPort:ancestorConnection. */ +newForInPort:outPort:ancestorConnection. */
NSParameterAssert (port == receive_port || port == send_port); NSParameterAssert (port == receive_port || port == send_port);

View file

@ -170,24 +170,7 @@ enum
- (void) dealloc - (void) dealloc
{ {
if (_object) [self gcFinalize];
{
/*
* A proxy for local object retains it's target so that it
* will continue to exist as long as there is a remote
* application using it - so we release the object here.
*/
[_object release];
}
else
{
/*
* A proxy retains it's connection so that the connection will
* continue to exist as long as there is a somethig to use it.
* So we release our reference to the connection here.
*/
[_connection release];
}
[super dealloc]; [super dealloc];
} }
@ -199,7 +182,8 @@ enum
if ([aRmc class] != [PortEncoder class]) if ([aRmc class] != [PortEncoder class])
[NSException raise: NSGenericException [NSException raise: NSGenericException
format: @"NSDistantObject objects only encode with PortEncoder class"]; format: @"NSDistantObject objects only "
@"encode with PortEncoder class"];
encoder_connection = [(NSPortCoder*)aRmc connection]; encoder_connection = [(NSPortCoder*)aRmc connection];
NSAssert(encoder_connection, NSInternalInconsistencyException); NSAssert(encoder_connection, NSInternalInconsistencyException);
@ -223,8 +207,7 @@ format: @"NSDistantObject objects only encode with PortEncoder class"];
if (debug_proxy) if (debug_proxy)
NSLog(@"Sending a proxy, will be remote 0x%x connection 0x%x\n", NSLog(@"Sending a proxy, will be remote 0x%x connection 0x%x\n",
(unsigned)proxy_target, proxy_target, (gsaddr)_connection);
(unsigned)_connection);
[aRmc encodeValueOfCType: @encode(typeof(proxy_tag)) [aRmc encodeValueOfCType: @encode(typeof(proxy_tag))
at: &proxy_tag at: &proxy_tag
@ -243,8 +226,7 @@ format: @"NSDistantObject objects only encode with PortEncoder class"];
if (debug_proxy) if (debug_proxy)
NSLog(@"Sending a proxy, will be local 0x%x connection 0x%x\n", NSLog(@"Sending a proxy, will be local 0x%x connection 0x%x\n",
(unsigned)proxy_target, proxy_target, (gsaddr)_connection);
(unsigned)_connection);
[aRmc encodeValueOfCType: @encode(typeof(proxy_tag)) [aRmc encodeValueOfCType: @encode(typeof(proxy_tag))
at: &proxy_tag at: &proxy_tag
@ -261,18 +243,31 @@ format: @"NSDistantObject objects only encode with PortEncoder class"];
* This proxy will still be remote on the other side * This proxy will still be remote on the other side
*/ */
NSPort *proxy_connection_out_port = [_connection sendPort]; NSPort *proxy_connection_out_port = [_connection sendPort];
NSDistantObject *localProxy;
NSAssert(proxy_connection_out_port, NSInternalInconsistencyException); NSAssert(proxy_connection_out_port,
NSAssert([proxy_connection_out_port isValid], NSInternalInconsistencyException); NSInternalInconsistencyException);
NSAssert(proxy_connection_out_port != [encoder_connection sendPort], NSInternalInconsistencyException); NSAssert([proxy_connection_out_port isValid],
NSInternalInconsistencyException);
NSAssert(proxy_connection_out_port != [encoder_connection sendPort],
NSInternalInconsistencyException);
proxy_tag = PROXY_REMOTE_FOR_BOTH; proxy_tag = PROXY_REMOTE_FOR_BOTH;
/*
* Get a proxy to refer to self - we send this to the other
* side so we will be retained until the other side has
* obtained a proxy to the original object via a connection
* to the original vendor.
*/
localProxy = [NSDistantObject proxyWithLocal: self
connection: encoder_connection];
if (debug_proxy) if (debug_proxy)
NSLog(@"Sending triangle-connection proxy 0x%x " NSLog(@"Sending triangle-connection proxy 0x%x "
@"proxy-conn 0x%x to-conn 0x%x\n", @"proxy-conn 0x%x to-proxy 0x%x to-conn 0x%x\n",
(unsigned)_object, localProxy->_handle, (gsaddr)localProxy->_connection,
(unsigned)_connection, (unsigned)encoder_connection); proxy_target, (gsaddr)_connection);
/* /*
* It's remote here, so we need to tell other side where to form * It's remote here, so we need to tell other side where to form
@ -282,16 +277,16 @@ format: @"NSDistantObject objects only encode with PortEncoder class"];
at: &proxy_tag at: &proxy_tag
withName: @"Proxy remote for both sender and receiver"]; withName: @"Proxy remote for both sender and receiver"];
[aRmc encodeValueOfCType: @encode(typeof(localProxy->_handle))
at: &localProxy->_handle
withName: @"Intermediary target"];
[aRmc encodeValueOfCType: @encode(typeof(proxy_target)) [aRmc encodeValueOfCType: @encode(typeof(proxy_target))
at: &proxy_target at: &proxy_target
withName: @"Proxy target"]; withName: @"Original target"];
[aRmc encodeBycopyObject: proxy_connection_out_port [aRmc encodeBycopyObject: proxy_connection_out_port
withName: @"Proxy outPort"]; withName: @"Original port"];
/*
* Make a note that we have passed this on to another process.
*/
_isVended = YES;
} }
} }
@ -341,13 +336,14 @@ format: @"NSDistantObject objects only encode with PortEncoder class"];
if (debug_proxy) if (debug_proxy)
NSLog(@"Receiving a proxy for local object 0x%x " NSLog(@"Receiving a proxy for local object 0x%x "
@"connection 0x%x\n", target, (unsigned)decoder_connection); @"connection 0x%x\n", target, (gsaddr)decoder_connection);
if (![[decoder_connection class] includesLocalTarget: target]) if (![[decoder_connection class] includesLocalTarget: target])
{ {
[self release]; [self release];
[NSException raise: @"ProxyDecodedBadTarget" [NSException raise: @"ProxyDecodedBadTarget"
format: @"No local object with given address"]; format: @"No local object with given target (0x%x)",
target];
} }
else else
{ {
@ -357,7 +353,7 @@ format: @"NSDistantObject objects only encode with PortEncoder class"];
if (debug_proxy) if (debug_proxy)
{ {
NSLog(@"Local object is 0x%x (0x%x)\n", NSLog(@"Local object is 0x%x (0x%x)\n",
(unsigned)o, (unsigned)o ? o->_object : 0); (gsaddr)o, (gsaddr)o ? o->_object : 0);
} }
[self release]; [self release];
return o ? [o->_object retain] : nil; return o ? [o->_object retain] : nil;
@ -376,7 +372,7 @@ format: @"NSDistantObject objects only encode with PortEncoder class"];
withName: NULL]; withName: NULL];
if (debug_proxy) if (debug_proxy)
NSLog(@"Receiving a proxy, was local 0x%x connection 0x%x\n", NSLog(@"Receiving a proxy, was local 0x%x connection 0x%x\n",
(unsigned)target, (unsigned)decoder_connection); target, (gsaddr)decoder_connection);
[self release]; [self release];
return [[NSDistantObject proxyWithTarget: target return [[NSDistantObject proxyWithTarget: target
connection: decoder_connection] retain]; connection: decoder_connection] retain];
@ -398,7 +394,29 @@ format: @"NSDistantObject objects only encode with PortEncoder class"];
NSDistantObject *result; NSDistantObject *result;
NSConnection *proxy_connection; NSConnection *proxy_connection;
NSPort *proxy_connection_out_port = nil; NSPort *proxy_connection_out_port = nil;
unsigned intermediary;
/*
* There is an object on the intermediary host that is keeping
* that hosts proxy for the original object retained, thus
* ensuring that the original is not released. We create a
* proxy for that intermediate proxy. When we release this
* proxy, the intermediary will be free to release it's proxy
* and the original can then be released. Of course, by that
* time we will have obtained our own proxy for the original
* object ...
*/
[aCoder decodeValueOfCType: @encode(typeof(intermediary))
at: &intermediary
withName: NULL];
[NSDistantObject proxyWithTarget: intermediary
connection: decoder_connection];
/*
* Now we get the target number and port for the orignal object
* and (if necessary) get the originating process to retain the
* object for us.
*/
[aCoder decodeValueOfCType: @encode(typeof(target)) [aCoder decodeValueOfCType: @encode(typeof(target))
at: &target at: &target
withName: NULL]; withName: NULL];
@ -407,7 +425,8 @@ format: @"NSDistantObject objects only encode with PortEncoder class"];
withName: NULL]; withName: NULL];
NSAssert(proxy_connection_out_port, NSInternalInconsistencyException); NSAssert(proxy_connection_out_port, NSInternalInconsistencyException);
/* xxx - if there already exists a connection for talking to the /*
# If there already exists a connection for talking to the
* out port, we use that one rather than creating a new one from * out port, we use that one rather than creating a new one from
* our listening port. * our listening port.
* *
@ -423,21 +442,28 @@ format: @"NSDistantObject objects only encode with PortEncoder class"];
outPort: outPort:
proxy_connection_out_port]; proxy_connection_out_port];
if (proxy_connection == nil) if (proxy_connection == nil)
{
proxy_connection = [[decoder_connection class] proxy_connection = [[decoder_connection class]
connectionByOutPort: connectionByOutPort: proxy_connection_out_port];
proxy_connection_out_port]; }
if (proxy_connection == nil) if (proxy_connection == nil)
{
proxy_connection = [[decoder_connection class] proxy_connection = [[decoder_connection class]
newForInPort: [decoder_connection receivePort] newForInPort: [decoder_connection receivePort]
outPort: proxy_connection_out_port outPort: proxy_connection_out_port
ancestorConnection: decoder_connection]; ancestorConnection: decoder_connection];
[proxy_connection setNotOwned];
[proxy_connection autorelease];
}
if (debug_proxy) if (debug_proxy)
NSLog(@"Receiving a triangle-connection proxy 0x%x " NSLog(@"Receiving a triangle-connection proxy 0x%x "
@"connection 0x%x\n", target, (unsigned)proxy_connection); @"connection 0x%x\n", target, (gsaddr)proxy_connection);
NSAssert(proxy_connection != decoder_connection, NSInternalInconsistencyException); NSAssert(proxy_connection != decoder_connection,
NSAssert([proxy_connection isValid], NSInternalInconsistencyException); NSInternalInconsistencyException);
NSAssert([proxy_connection isValid],
NSInternalInconsistencyException);
/* /*
* If we don't already have a proxy for the object on the * If we don't already have a proxy for the object on the
@ -447,9 +473,17 @@ format: @"NSDistantObject objects only encode with PortEncoder class"];
if ([proxy_connection includesProxyForTarget: target] == NO) if ([proxy_connection includesProxyForTarget: target] == NO)
[proxy_connection retainTarget: target]; [proxy_connection retainTarget: target];
[self release];
result = [[NSDistantObject proxyWithTarget: target result = [[NSDistantObject proxyWithTarget: target
connection: proxy_connection] retain]; connection: proxy_connection] retain];
[self release];
/*
* Finally - we have a proxy via a direct connection to the
* originating server. We have also created a proxy to an
* intermediate object - but this proxy has not been retained
* and will therefore go away when the current autorelease
* pool is destroyed.
*/
return result; return result;
} }
@ -475,26 +509,26 @@ format: @"NSDistantObject objects only encode with PortEncoder class"];
*/ */
if ((new_proxy = [aConnection localForObject: anObject])) if ((new_proxy = [aConnection localForObject: anObject]))
{ {
[self dealloc]; [self release];
return [new_proxy retain]; return [new_proxy retain];
} }
_connection = aConnection; /*
* We don't need to retain the oibject here - the connection
* will retain the proxies local object if necessary (and release it
* when all proxies referring to it have been released).
*/
_object = anObject;
/* /*
* We retain our target object so it can't disappear while a remote * We register this proxy with the connection using it.
* application wants to use it.
*/
_object = [anObject retain];
/*
* We register this object with the connection using it.
*/ */
_connection = [aConnection retain];
[_connection addLocalObject: self]; [_connection addLocalObject: self];
if (debug_proxy) if (debug_proxy)
NSLog(@"Created new local=0x%x object 0x%x connection 0x%x\n", NSLog(@"Created new local=0x%x object 0x%x target 0x%x connection 0x%x\n",
(unsigned)self, (unsigned)_object, (unsigned)_connection); (gsaddr)self, (gsaddr)_object, _handle, (gsaddr)_connection);
return self; return self;
} }
@ -511,7 +545,7 @@ format: @"NSDistantObject objects only encode with PortEncoder class"];
*/ */
if ((new_proxy = [aConnection proxyForTarget: target])) if ((new_proxy = [aConnection proxyForTarget: target]))
{ {
[self dealloc]; [self release];
return [new_proxy retain]; return [new_proxy retain];
} }
@ -530,8 +564,8 @@ format: @"NSDistantObject objects only encode with PortEncoder class"];
[_connection addProxy: self]; [_connection addProxy: self];
if (debug_proxy) if (debug_proxy)
NSLog(@"Created new proxy=0x%x object 0x%x connection 0x%x\n", NSLog(@"Created new proxy=0x%x target 0x%x connection 0x%x\n",
(unsigned)self, (unsigned)_object, (unsigned)_connection); (gsaddr)self, _handle, (gsaddr)_connection);
return self; return self;
} }
@ -583,36 +617,36 @@ format: @"NSDistantObject objects only encode with PortEncoder class"];
_protocol = aProtocol; _protocol = aProtocol;
} }
- (void) release
{
if ([self retainCount] == 2)
{
if (_object == nil)
{
/*
* If the only thing retaining us after this release is our
* connection we must be removed from the connection.
* Bracket that removal with a retain and release to ensure
* that we don't have problems when the connection releases us.
*/
[super retain];
[_connection removeProxy: self];
[super release];
}
}
[super release];
}
@end @end
@implementation NSDistantObject(GNUstepExtensions) @implementation NSDistantObject(GNUstepExtensions)
+ newForRemoteTarget: (unsigned)target connection: (NSConnection*)conn - (void) gcFinalize
{ {
return [[NSDistantObject alloc] initWithTarget: target connection: conn]; if (_connection)
{
if (debug_proxy > 3)
NSLog(@"retain count for connection (0x%x) is now %u\n",
(gsaddr)_connection, [_connection retainCount]);
/*
* A proxy for local object does not retain it's target - the
* NSConnection class does that for us - so we need not release it.
* For a local object the connection also retains this proxy, so we
* can't be deallocated unless we are already removed from the
* connection.
*
* A proxy retains it's connection so that the connection will
* continue to exist as long as there is a something to use it.
* So we release our reference to the connection here just as soon
* as we have removed ourself from the connection.
*/
if (_object == nil)
[_connection removeProxy: self];
[_connection release];
}
} }
- awakeAfterUsingCoder: aDecoder - (id) awakeAfterUsingCoder: (NSCoder*)aDecoder
{ {
return self; return self;
} }
@ -629,157 +663,6 @@ static inline BOOL class_is_kind_of (Class self, Class aClassObject)
#if 0
+ newWithCoder: aRmc
{
gsu8 proxy_tag;
unsigned target;
id decoder_connection;
if ([aRmc class] != [PortDecoder class])
[NSException raise: NSGenericException
format: @"NSDistantObject objects only decode with PortDecoder class"];
decoder_connection = [aRmc connection];
NSAssert(decoder_connection, NSInternalInconsistencyException);
/* First get the tag, so we know what values need to be decoded. */
[aRmc decodeValueOfCType: @encode(typeof(proxy_tag))
at: &proxy_tag
withName: NULL];
switch (proxy_tag)
{
case PROXY_LOCAL_FOR_RECEIVER:
/*
* This was a proxy on the other side of the connection, but
* here it's local.
* Lookup the target handle to ensure that it exists here.
* Return a retained copy of the local target object.
*/
[aRmc decodeValueOfCType: @encode(typeof(target))
at: &target
withName: NULL];
if (debug_proxy)
NSLog(@"Receiving a proxy for local object 0x%x "
@"connection 0x%x\n", target, (unsigned)decoder_connection);
if (![[decoder_connection class] includesLocalTarget: target])
[NSException raise: @"ProxyDecodedBadTarget"
format: @"No local object with given address"];
else
{
NSDistantObject *o;
o = [decoder_connection includesLocalTarget: target];
if (debug_proxy)
{
NSLog(@"Local object is 0x%x (0x%x)\n",
(unsigned)o, (unsigned)o->_object);
}
[self release];
return [o->_object retain];
}
case PROXY_LOCAL_FOR_SENDER:
/*
* This was a local object on the other side of the connection,
* but here it's a proxy object. Get the target address, and
* send [NSDistantObject +proxyWithTarget:connection:]; this will
* return the proxy object we already created for this target, or
* create a new proxy object if necessary.
*/
[aRmc decodeValueOfCType: @encode(typeof(target))
at: &target
withName: NULL];
if (debug_proxy)
NSLog(@"Receiving a proxy, was local 0x%x connection 0x%x\n",
(unsigned)target, (unsigned)decoder_connection);
return [[NSDistantObject proxyWithTarget: target
connection: decoder_connection] retain];
case PROXY_REMOTE_FOR_BOTH:
/*
* This was a proxy on the other side of the connection, and it
* will be a proxy on this side too; that is, the local version
* of this object is not on this host, not on the host the
* NSPortCoder is connected to, but on a *third* host.
* This is why I call this a "triangle connection". In addition
* to decoding the target, we decode the OutPort object that we
* will use to talk directly to this third host. We send
* [NSConnection +newForInPort:outPort:ancestorConnection:]; this
* will either return the connection already created for this
* inPort/outPort pair, or create a new connection if necessary.
*/
{
NSDistantObject *result;
NSConnection *proxy_connection;
NSPort* proxy_connection_out_port = nil;
[aRmc decodeValueOfCType: @encode(typeof(target))
at: &target
withName: NULL];
[aRmc decodeObjectAt: &proxy_connection_out_port
withName: NULL];
NSAssert(proxy_connection_out_port, NSInternalInconsistencyException);
/* xxx - if there already exists a connection for talking to the
* out port, we use that one rather than creating a new one from
* our listening port.
*
* First we try for a connection from our receive port,
* Then we try any connection to the send port
* Finally we resort to creating a new connection - we don't
* release the newly created connection - it will get released
* automatically when no proxies are left on it.
*/
proxy_connection = [[decoder_connection class]
connectionByInPort:
[decoder_connection receivePort]
outPort:
proxy_connection_out_port];
if (proxy_connection == nil)
proxy_connection = [[decoder_connection class]
connectionByOutPort:
proxy_connection_out_port];
if (proxy_connection == nil)
proxy_connection = [[decoder_connection class]
newForInPort: [decoder_connection receivePort]
outPort: proxy_connection_out_port
ancestorConnection: decoder_connection];
if (debug_proxy)
NSLog(@"Receiving a triangle-connection proxy 0x%x "
@"connection 0x%x\n", target, (unsigned)proxy_connection);
NSAssert(proxy_connection != decoder_connection, NSInternalInconsistencyException);
NSAssert([proxy_connection isValid], NSInternalInconsistencyException);
/*
* If we don't already have a proxy for the object on the
* remote system, we must tell the other end to retain its
* local object for our use.
*/
if ([proxy_connection includesProxyForTarget: target] == NO)
[proxy_connection retainTarget: target];
result = [[NSDistantObject proxyWithTarget: target
connection: proxy_connection] retain];
return result;
}
default:
/* xxx This should be something different than NSGenericException. */
[NSException raise: NSGenericException
format: @"Bad proxy tag"];
}
/* Not reached. */
return nil;
}
#endif
- (const char *) selectorTypeForProxy: (SEL)selector - (const char *) selectorTypeForProxy: (SEL)selector
{ {
#if NeXT_runtime #if NeXT_runtime
@ -802,7 +685,7 @@ format: @"NSDistantObject objects only decode with PortDecoder class"];
#endif #endif
} }
- forward: (SEL)aSel :(arglist_t)frame - (id) forward: (SEL)aSel :(arglist_t)frame
{ {
if (debug_proxy) if (debug_proxy)
NSLog(@"NSDistantObject forwarding %s\n", sel_get_name(aSel)); NSLog(@"NSDistantObject forwarding %s\n", sel_get_name(aSel));
@ -819,22 +702,22 @@ format: @"NSDistantObject objects only decode with PortDecoder class"];
argFrame: frame]; argFrame: frame];
} }
- classForCoder - (Class) classForCoder
{ {
return object_get_class (self); return object_get_class (self);
} }
- classForPortCoder - (Class) classForPortCoder
{ {
return object_get_class (self); return object_get_class (self);
} }
- replacementObjectForCoder:(NSCoder*)aCoder - (id) replacementObjectForCoder: (NSCoder*)aCoder
{ {
return self; return self;
} }
- replacementObjectForPortCoder:(NSPortCoder*)aCoder - (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder
{ {
return self; return self;
} }

View file

@ -40,6 +40,7 @@
#include <base/NotificationDispatcher.h> #include <base/NotificationDispatcher.h>
#include <base/NSException.h> #include <base/NSException.h>
#include <Foundation/NSRunLoop.h> #include <Foundation/NSRunLoop.h>
#include <Foundation/NSByteOrder.h>
#include <base/Invocation.h> #include <base/Invocation.h>
#include <Foundation/NSData.h> #include <Foundation/NSData.h>
#include <Foundation/NSDate.h> #include <Foundation/NSDate.h>
@ -129,14 +130,15 @@ static int debug_tcp_port = 0;
@interface TcpInPacket (Private) @interface TcpInPacket (Private)
- (int) _fillFromSocket: (int)s; - (int) _fillFromSocket: (int)s;
+ (void) _getPacketSize: (int*)size + (void) _getPacketSize: (int*)size
andReplyPort: (id*)rp andSendPort: (id*)sp
fromSocket: (int)s andReceivePort: (id*)rp
inPort: ip; fromSocket: (int)s;
@end @end
@interface TcpOutPacket (Private) @interface TcpOutPacket (Private)
- (void) _writeToSocket: (int)s - (void) _writeToSocket: (int)s
withReplySockaddr: (struct sockaddr_in*)addr withSendPort: (id)sp
withReceivePort: (id)rp
timeout: (NSTimeInterval)t; timeout: (NSTimeInterval)t;
@end @end
@ -428,9 +430,9 @@ static NSMapTable* port_number_2_port;
will accept connection on any of the machine network addresses; will accept connection on any of the machine network addresses;
most machine will have both an Internet address, and the most machine will have both an Internet address, and the
"localhost" address (i.e. 127.0.0.1) */ "localhost" address (i.e. 127.0.0.1) */
p->_listening_address.sin_addr.s_addr = htonl (INADDR_ANY); p->_listening_address.sin_addr.s_addr = GSSwapHostI32ToBig (INADDR_ANY);
p->_listening_address.sin_family = AF_INET; p->_listening_address.sin_family = AF_INET;
p->_listening_address.sin_port = htons (n); p->_listening_address.sin_port = GSSwapHostI16ToBig (n);
/* N may be zero, in which case bind() will choose a port number /* N may be zero, in which case bind() will choose a port number
for us. */ for us. */
if (bind (p->_port_socket, if (bind (p->_port_socket,
@ -448,7 +450,7 @@ static NSMapTable* port_number_2_port;
for (count = 0; count < 10; count++) { for (count = 0; count < 10; count++) {
memset(&p->_listening_address, 0, sizeof(p->_listening_address)); memset(&p->_listening_address, 0, sizeof(p->_listening_address));
p->_listening_address.sin_addr.s_addr = htonl (INADDR_ANY); p->_listening_address.sin_addr.s_addr = GSSwapHostI32ToBig (INADDR_ANY);
p->_listening_address.sin_family = AF_INET; p->_listening_address.sin_family = AF_INET;
if (bind (p->_port_socket, if (bind (p->_port_socket,
(struct sockaddr*) &(p->_listening_address), (struct sockaddr*) &(p->_listening_address),
@ -484,7 +486,7 @@ static NSMapTable* port_number_2_port;
} }
NSAssert(p->_listening_address.sin_port, NSInternalInconsistencyException); NSAssert(p->_listening_address.sin_port, NSInternalInconsistencyException);
n = ntohs(p->_listening_address.sin_port); n = GSSwapBigI16ToHost(p->_listening_address.sin_port);
} }
/* Now change _LISTENING_ADDRESS to the specific network address of this /* Now change _LISTENING_ADDRESS to the specific network address of this
@ -692,11 +694,12 @@ static NSMapTable* port_number_2_port;
/* First, get the packet size and reply port, (which is /* First, get the packet size and reply port, (which is
encoded in the first few bytes of the stream). */ encoded in the first few bytes of the stream). */
int packet_size; int packet_size;
id reply_port; id send_port;
id receive_port;
[TcpInPacket _getPacketSize: &packet_size [TcpInPacket _getPacketSize: &packet_size
andReplyPort: &reply_port andSendPort: &send_port
fromSocket: fd_index andReceivePort: &receive_port
inPort: self]; fromSocket: fd_index];
/* If we got an EOF when trying to read the packet prefix, /* If we got an EOF when trying to read the packet prefix,
invalidate the port, and keep on waiting for incoming invalidate the port, and keep on waiting for incoming
data on other sockets. */ data on other sockets. */
@ -710,8 +713,8 @@ static NSMapTable* port_number_2_port;
{ {
packet = [[TcpInPacket alloc] packet = [[TcpInPacket alloc]
initForReceivingWithCapacity: packet_size initForReceivingWithCapacity: packet_size
receivingInPort: self receivingInPort: send_port
replyOutPort: reply_port]; replyOutPort: receive_port];
if (packet == nil) if (packet == nil)
[NSException raise: NSInternalInconsistencyException [NSException raise: NSInternalInconsistencyException
format: @"[TcpInPort _tryToGetPacketFromReadableFD:" format: @"[TcpInPort _tryToGetPacketFromReadableFD:"
@ -864,7 +867,7 @@ static NSMapTable* port_number_2_port;
- (int) portNumber - (int) portNumber
{ {
return (int) ntohs (_listening_address.sin_port); return (int) GSSwapBigI16ToHost (_listening_address.sin_port);
} }
- (void) invalidate - (void) invalidate
@ -882,7 +885,7 @@ static NSMapTable* port_number_2_port;
+newForReceivingFromPortNumber: from returning invalid sockets. */ +newForReceivingFromPortNumber: from returning invalid sockets. */
NSMapRemove (socket_2_port, (void*)_port_socket); NSMapRemove (socket_2_port, (void*)_port_socket);
NSMapRemove (port_number_2_port, NSMapRemove (port_number_2_port,
(void*)(int) ntohs(_listening_address.sin_port)); (void*)(int)GSSwapBigI16ToHost(_listening_address.sin_port));
for (i = 0; for (i = 0;
NSNextMapEnumeratorPair (&me, (void*)&sock, (void*)&out_port); NSNextMapEnumeratorPair (&me, (void*)&sock, (void*)&out_port);
@ -943,7 +946,7 @@ static NSMapTable* port_number_2_port;
object_get_class_name (self), object_get_class_name (self),
is_valid ? ' ' : '-', is_valid ? ' ' : '-',
(unsigned)self, (unsigned)self,
ntohs (_listening_address.sin_port), GSSwapBigI16ToHost(_listening_address.sin_port),
_port_socket]; _port_socket];
} }
@ -1259,7 +1262,7 @@ static NSMapTable *out_port_bag = NULL;
/* Get the sockaddr_in address. */ /* Get the sockaddr_in address. */
memcpy (&addr.sin_addr, hp->h_addr, hp->h_length); memcpy (&addr.sin_addr, hp->h_addr, hp->h_length);
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_port = htons (n); addr.sin_port = GSSwapHostI16ToBig (n);
return [self newForSendingToSockaddr: &addr return [self newForSendingToSockaddr: &addr
withAcceptedSocket: 0 withAcceptedSocket: 0
@ -1293,7 +1296,7 @@ static NSMapTable *out_port_bag = NULL;
} }
NSAssert(size == sizeof (struct sockaddr_in), NSInternalInconsistencyException); NSAssert(size == sizeof (struct sockaddr_in), NSInternalInconsistencyException);
/* xxx Perhaps I have to get peer name here!! */ /* xxx Perhaps I have to get peer name here!! */
NSAssert(ntohs (addr.sin_port) != [p portNumber], NSInternalInconsistencyException); NSAssert(GSSwapBigI16ToHost(addr.sin_port) != [p portNumber], NSInternalInconsistencyException);
#elif 0 #elif 0
struct sockaddr_in in_port_address; struct sockaddr_in in_port_address;
c = read (s, &in_port_address, sizeof(struct sockaddr_in)); c = read (s, &in_port_address, sizeof(struct sockaddr_in));
@ -1339,11 +1342,13 @@ static NSMapTable *out_port_bag = NULL;
/* Ask the packet to write it's bytes to the socket. /* Ask the packet to write it's bytes to the socket.
The TcpPacket will also write a prefix, indicating the packet size The TcpPacket will also write a prefix, indicating the packet size
and the reply port address. If REPLY_PORT is nil, the second argument and the port addresses. If REPLY_PORT is nil, the third argument
to this call with be NULL, and __writeToSocket:withReplySockaddr:timeout: to this call with be NULL, and
__writeToSocket:withSendPort:withReceivePort:timeout:
will know that there is no reply port. */ will know that there is no reply port. */
[packet _writeToSocket: _port_socket [packet _writeToSocket: _port_socket
withReplySockaddr: [reply_port _listeningSockaddr] withSendPort: self
withReceivePort: reply_port
timeout: timeout]; timeout: timeout];
return YES; return YES;
} }
@ -1355,7 +1360,7 @@ static NSMapTable *out_port_bag = NULL;
- (int) portNumber - (int) portNumber
{ {
return (int) ntohs (_remote_in_port_address.sin_port); return (int) GSSwapBigI16ToHost (_remote_in_port_address.sin_port);
} }
- (void) close - (void) close
@ -1442,7 +1447,7 @@ static NSMapTable *out_port_bag = NULL;
is_valid ? ' ' : '-', is_valid ? ' ' : '-',
(unsigned)self, (unsigned)self,
inet_ntoa (_remote_in_port_address.sin_addr), inet_ntoa (_remote_in_port_address.sin_addr),
ntohs (_remote_in_port_address.sin_port), GSSwapBigI16ToHost(_remote_in_port_address.sin_port),
_port_socket]; _port_socket];
} }
@ -1450,7 +1455,7 @@ static NSMapTable *out_port_bag = NULL;
{ {
NSAssert(is_valid, NSInternalInconsistencyException); NSAssert(is_valid, NSInternalInconsistencyException);
NSAssert(!_polling_in_port NSAssert(!_polling_in_port
|| (ntohs (_remote_in_port_address.sin_port) || (GSSwapBigI16ToHost(_remote_in_port_address.sin_port)
!= [_polling_in_port portNumber]), NSInternalInconsistencyException); != [_polling_in_port portNumber]), NSInternalInconsistencyException);
/* Encode these at bytes, not as C-variables, because they are /* Encode these at bytes, not as C-variables, because they are
already in "network byte-order". */ already in "network byte-order". */
@ -1462,7 +1467,7 @@ static NSMapTable *out_port_bag = NULL;
withName: @"inet address"]; withName: @"inet address"];
if (debug_tcp_port) if (debug_tcp_port)
NSLog(@"TcpOutPort encoded port %hd host %s\n", NSLog(@"TcpOutPort encoded port %hd host %s\n",
ntohs (_remote_in_port_address.sin_port), GSSwapBigI16ToHost(_remote_in_port_address.sin_port),
inet_ntoa (_remote_in_port_address.sin_addr)); inet_ntoa (_remote_in_port_address.sin_addr));
} }
@ -1479,7 +1484,7 @@ static NSMapTable *out_port_bag = NULL;
withName: NULL]; withName: NULL];
if (debug_tcp_port) if (debug_tcp_port)
NSLog(@"TcpOutPort decoded port %hd host %s\n", NSLog(@"TcpOutPort decoded port %hd host %s\n",
ntohs (addr.sin_port), GSSwapBigI16ToHost(addr.sin_port),
inet_ntoa (addr.sin_addr)); inet_ntoa (addr.sin_addr));
return [TcpOutPort newForSendingToSockaddr: &addr return [TcpOutPort newForSendingToSockaddr: &addr
withAcceptedSocket: 0 withAcceptedSocket: 0
@ -1491,20 +1496,20 @@ static NSMapTable *out_port_bag = NULL;
/* In and Out Packet classes. */ /* In and Out Packet classes. */
/* If you change this "unsigned long", you must change the use #define PREFIX_LENGTH_TYPE gsu32
of ntohl() and htonl() below. */
#define PREFIX_LENGTH_TYPE unsigned long
#define PREFIX_LENGTH_SIZE sizeof (PREFIX_LENGTH_TYPE) #define PREFIX_LENGTH_SIZE sizeof (PREFIX_LENGTH_TYPE)
#define PREFIX_ADDRESS_TYPE struct sockaddr_in #define PREFIX_ADDRESS_TYPE struct sockaddr_in
#define PREFIX_ADDRESS_SIZE sizeof (PREFIX_ADDRESS_TYPE) #define PREFIX_ADDRESS_SIZE sizeof (PREFIX_ADDRESS_TYPE)
#define PREFIX_SIZE (PREFIX_LENGTH_SIZE + PREFIX_ADDRESS_SIZE) #define PREFIX_SP_OFF PREFIX_LENGTH_SIZE
#define PREFIX_RP_OFF (PREFIX_LENGTH_SIZE + PREFIX_ADDRESS_SIZE)
#define PREFIX_SIZE (PREFIX_LENGTH_SIZE + 2*PREFIX_ADDRESS_SIZE)
@implementation TcpInPacket @implementation TcpInPacket
+ (void) _getPacketSize: (int*)packet_size + (void) _getPacketSize: (int*)packet_size
andReplyPort: (id*)rp andSendPort: (id*)sp
andReceivePort: (id*)rp
fromSocket: (int)s fromSocket: (int)s
inPort: ip
{ {
char prefix_buffer[PREFIX_SIZE]; char prefix_buffer[PREFIX_SIZE];
int c; int c;
@ -1512,7 +1517,9 @@ static NSMapTable *out_port_bag = NULL;
c = tryRead (s, 3, prefix_buffer, PREFIX_SIZE); c = tryRead (s, 3, prefix_buffer, PREFIX_SIZE);
if (c <= 0) if (c <= 0)
{ {
*packet_size = EOF; *rp = nil; *packet_size = EOF;
*sp = nil;
*rp = nil;
return; return;
} }
if (c != PREFIX_SIZE) if (c != PREFIX_SIZE)
@ -1522,27 +1529,48 @@ static NSMapTable *out_port_bag = NULL;
we should treat it differently. */ we should treat it differently. */
fprintf (stderr, "[%s %s]: Got %d chars instead of full prefix\n", fprintf (stderr, "[%s %s]: Got %d chars instead of full prefix\n",
class_get_class_name (self), sel_get_name (_cmd), c); class_get_class_name (self), sel_get_name (_cmd), c);
*packet_size = EOF; *rp = nil; *packet_size = EOF;
*sp = nil;
*rp = nil;
return; return;
} }
/* *size is the number of bytes in the packet, not including /* *size is the number of bytes in the packet, not including
the PREFIX_SIZE-byte header. */ the PREFIX_SIZE-byte header. */
*packet_size = ntohl (*(PREFIX_LENGTH_TYPE*) prefix_buffer); *packet_size = GSSwapBigI32ToHost (*(PREFIX_LENGTH_TYPE*) prefix_buffer);
NSAssert(packet_size, NSInternalInconsistencyException); NSAssert(packet_size, NSInternalInconsistencyException);
/* If the reply address is non-zero, and the TcpOutPort for this socket /* If the reply address is non-zero, and the TcpOutPort for this socket
doesn't already have its _address ivar set, then set it now. */ doesn't already have its _address ivar set, then set it now. */
{ {
struct sockaddr_in addr; struct sockaddr_in addr;
/* Do this memcpy instead of simply casting the pointer because
/* Use memcpy instead of simply casting the pointer because
some systems fail to do the cast correctly (due to alignment issues?) */ some systems fail to do the cast correctly (due to alignment issues?) */
memcpy (&addr, prefix_buffer + PREFIX_LENGTH_SIZE, sizeof (typeof (addr)));
/*
* Get the senders send port (our receive port)
*/
memcpy (&addr, prefix_buffer + PREFIX_SP_OFF, sizeof (typeof (addr)));
if (addr.sin_family)
{
gsu16 pnum = GSSwapBigI16ToHost(addr.sin_port);
*sp = [TcpInPort newForReceivingFromPortNumber: pnum];
[(*sp) autorelease];
}
else
*sp = nil;
/*
* Now get the senders receive port (our send port)
*/
memcpy (&addr, prefix_buffer + PREFIX_RP_OFF, sizeof (typeof (addr)));
if (addr.sin_family) if (addr.sin_family)
{ {
*rp = [TcpOutPort newForSendingToSockaddr: &addr *rp = [TcpOutPort newForSendingToSockaddr: &addr
withAcceptedSocket: s withAcceptedSocket: s
pollingInPort: ip]; pollingInPort: *sp];
[(*rp) autorelease]; [(*rp) autorelease];
} }
else else
@ -1574,9 +1602,11 @@ static NSMapTable *out_port_bag = NULL;
} }
- (void) _writeToSocket: (int)s - (void) _writeToSocket: (int)s
withReplySockaddr: (struct sockaddr_in*)addr withSendPort: (id)sp
withReceivePort: (id)rp
timeout: (NSTimeInterval)timeout timeout: (NSTimeInterval)timeout
{ {
struct sockaddr_in *addr;
int c; int c;
if (debug_tcp_port > 1) if (debug_tcp_port > 1)
@ -1584,16 +1614,27 @@ static NSMapTable *out_port_bag = NULL;
/* Put the packet size in the first four bytes of the packet. */ /* Put the packet size in the first four bytes of the packet. */
NSAssert(prefix == PREFIX_SIZE, NSInternalInconsistencyException); NSAssert(prefix == PREFIX_SIZE, NSInternalInconsistencyException);
*(PREFIX_LENGTH_TYPE*)[data mutableBytes] = htonl (eof_position); *(PREFIX_LENGTH_TYPE*)[data mutableBytes] = GSSwapHostI32ToBig(eof_position);
addr = [sp _remoteInPortSockaddr];
/* Put the sockaddr_in for replies in the next bytes of the prefix /* Put the sockaddr_in for replies in the next bytes of the prefix
region. If there is no reply address specified, fill it with zeros. */ region. If there is no reply address specified, fill it with zeros. */
if (addr) if (addr)
/* Do this memcpy instead of simply casting the pointer because /* Do this memcpy instead of simply casting the pointer because
some systems fail to do the cast correctly (due to alignment issues?) */ some systems fail to do the cast correctly (due to alignment issues?) */
memcpy ([data mutableBytes]+PREFIX_LENGTH_SIZE, addr, PREFIX_ADDRESS_SIZE); memcpy ([data mutableBytes]+PREFIX_SP_OFF, addr, PREFIX_ADDRESS_SIZE);
else else
memset ([data mutableBytes]+PREFIX_LENGTH_SIZE, 0, PREFIX_ADDRESS_SIZE); memset ([data mutableBytes]+PREFIX_SP_OFF, 0, PREFIX_ADDRESS_SIZE);
addr = [rp _listeningSockaddr];
/* Put the sockaddr_in for the destination in the next bytes of the prefix
region. If there is no destination address specified, fill with zeros. */
if (addr)
/* Do this memcpy instead of simply casting the pointer because
some systems fail to do the cast correctly (due to alignment issues?) */
memcpy ([data mutableBytes]+PREFIX_RP_OFF, addr, PREFIX_ADDRESS_SIZE);
else
memset ([data mutableBytes]+PREFIX_RP_OFF, 0, PREFIX_ADDRESS_SIZE);
/* Write the packet on the socket. */ /* Write the packet on the socket. */
c = tryWrite (s, (int)timeout, (unsigned char*)[data bytes], prefix + eof_position); c = tryWrite (s, (int)timeout, (unsigned char*)[data bytes], prefix + eof_position);