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 */

File diff suppressed because it is too large Load diff

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
@ -260,19 +242,32 @@ 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,9 +425,10 @@ 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 /*
* out port, we use that one rather than creating a new one from # If there already exists a connection for talking to the
* our listening port. * 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, * First we try for a connection from our receive port,
* Then we try any connection to the send port * Then we try any connection to the send 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] {
connectionByOutPort: proxy_connection = [[decoder_connection class]
proxy_connection_out_port]; connectionByOutPort: 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,12 +1342,14 @@ 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
timeout: timeout]; withReceivePort: reply_port
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,28 +1496,30 @@ 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;
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,26 +1602,39 @@ 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
{ {
int c; struct sockaddr_in *addr;
int c;
if (debug_tcp_port > 1) if (debug_tcp_port > 1)
NSLog(@"%s: Write to socket %d\n", object_get_class_name (self), s); NSLog(@"%s: Write to socket %d\n", object_get_class_name (self), s);
/* 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);