1994-11-04 16:29:24 +00:00
|
|
|
|
/* Implementation of connection object for remote object messaging
|
1996-01-24 14:11:20 +00:00
|
|
|
|
Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-04-17 20:17:45 +00:00
|
|
|
|
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
1994-11-04 16:29:24 +00:00
|
|
|
|
Date: July 1994
|
|
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
|
This file is part of the GNUstep Base Library.
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
|
|
|
License along with this library; if not, write to the Free
|
|
|
|
|
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
*/
|
|
|
|
|
|
1996-03-12 14:43:30 +00:00
|
|
|
|
/* To do:
|
|
|
|
|
Integrate with NSRunLoop
|
|
|
|
|
Pass exceptions back to client.
|
|
|
|
|
Find bug with proxies of invalidated connections.
|
|
|
|
|
Make it thread-safe.
|
|
|
|
|
Support @"*" hostname.
|
|
|
|
|
*/
|
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
/* RMC == Remote Method Coder, or Remote Method Call.
|
1996-03-01 15:54:57 +00:00
|
|
|
|
It's an instance of ConnectedEncoder or ConnectedDecoder. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-04-17 15:34:35 +00:00
|
|
|
|
#include <gnustep/base/preface.h>
|
1996-04-17 15:23:00 +00:00
|
|
|
|
#include <gnustep/base/Connection.h>
|
|
|
|
|
#include <gnustep/base/Proxy.h>
|
|
|
|
|
#include <gnustep/base/ConnectedCoder.h>
|
|
|
|
|
#include <gnustep/base/TcpPort.h>
|
|
|
|
|
#include <gnustep/base/Array.h>
|
|
|
|
|
#include <gnustep/base/Dictionary.h>
|
|
|
|
|
#include <gnustep/base/Queue.h>
|
|
|
|
|
#include <gnustep/base/mframe.h>
|
|
|
|
|
#include <gnustep/base/Notification.h>
|
|
|
|
|
#include <gnustep/base/RunLoop.h>
|
|
|
|
|
#include <gnustep/base/MallocAddress.h>
|
1995-04-17 21:13:20 +00:00
|
|
|
|
#include <Foundation/NSString.h>
|
1996-03-12 19:40:16 +00:00
|
|
|
|
#include <Foundation/NSDate.h>
|
1996-03-26 20:59:42 +00:00
|
|
|
|
#include <Foundation/NSException.h>
|
1994-11-04 16:29:24 +00:00
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
|
|
@interface Connection (GettingCoderInterface)
|
1996-03-12 19:40:16 +00:00
|
|
|
|
- (void) _handleRmc: rmc;
|
|
|
|
|
- (void) _handleQueuedRmcRequests;
|
|
|
|
|
- _getReceivedReplyRmcWithSequenceNumber: (int)n;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
- newSendingRequestRmc;
|
|
|
|
|
- newSendingReplyRmcWithSequenceNumber: (int)n;
|
|
|
|
|
- (int) _newMsgNumber;
|
|
|
|
|
@end
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
@interface Connection (Private)
|
|
|
|
|
- _superInit;
|
|
|
|
|
@end
|
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
#define proxiesHashGate refGate
|
|
|
|
|
#define sequenceNumberGate refGate
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
/* xxx Fix this! */
|
|
|
|
|
#define refGate nil
|
|
|
|
|
|
|
|
|
|
static inline BOOL
|
|
|
|
|
class_is_kind_of (Class self, Class aClassObject)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1995-03-08 23:04:52 +00:00
|
|
|
|
Class class;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
|
|
|
|
for (class = self; class!=Nil; class = class_get_super_class(class))
|
|
|
|
|
if (class==aClassObject)
|
|
|
|
|
return YES;
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline unsigned int
|
|
|
|
|
hash_int (cache_ptr cache, const void *key)
|
|
|
|
|
{
|
|
|
|
|
return (unsigned)key & cache->mask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
|
compare_ints (const void *k1, const void *k2)
|
|
|
|
|
{
|
|
|
|
|
return !(k1 - k2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
type_get_number_of_arguments (const char *type)
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
while (*type)
|
|
|
|
|
{
|
|
|
|
|
type = objc_skip_argspec (type);
|
|
|
|
|
i += 1;
|
|
|
|
|
}
|
|
|
|
|
return i - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* class defaults */
|
1996-03-06 14:05:36 +00:00
|
|
|
|
static id default_in_port_class;
|
|
|
|
|
static id default_out_port_class;
|
1996-03-01 15:54:57 +00:00
|
|
|
|
static id default_proxy_class;
|
|
|
|
|
static id default_encoding_class;
|
|
|
|
|
static id default_decoding_class;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
static int default_in_timeout;
|
|
|
|
|
static int default_out_timeout;
|
|
|
|
|
|
1996-04-16 23:27:53 +00:00
|
|
|
|
static int debug_connection = 0;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
|
|
|
|
/* Perhaps this should be a hashtable, keyed by remote port.
|
|
|
|
|
But we may also need to include the local port---even though
|
|
|
|
|
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 Connection */
|
1996-03-01 15:54:57 +00:00
|
|
|
|
static Array *connection_array;
|
|
|
|
|
static Lock *connection_array_gate;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
static Dictionary *root_object_dictionary;
|
|
|
|
|
static Lock *root_object_dictionary_gate;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-13 02:32:46 +00:00
|
|
|
|
static NSMapTable *in_port_2_ancestor;
|
|
|
|
|
|
1996-03-06 14:05:36 +00:00
|
|
|
|
static NSMapTable *all_connections_local_targets = NULL;
|
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
/* rmc handling */
|
1996-03-01 15:54:57 +00:00
|
|
|
|
static Queue *received_request_rmc_queue;
|
|
|
|
|
static Lock *received_request_rmc_queue_gate;
|
|
|
|
|
static Queue *received_reply_rmc_queue;
|
|
|
|
|
static Lock *received_reply_rmc_queue_gate;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
static int messages_received_count;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
|
|
|
|
@implementation Connection
|
|
|
|
|
|
1995-03-12 22:23:25 +00:00
|
|
|
|
+ (void) initialize
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
connection_array = [[Array alloc] init];
|
|
|
|
|
connection_array_gate = [Lock new];
|
1996-03-06 16:40:00 +00:00
|
|
|
|
/* xxx When NSHashTable's are working, change this. */
|
|
|
|
|
all_connections_local_targets =
|
|
|
|
|
NSCreateMapTable (NSNonOwnedPointerMapKeyCallBacks,
|
|
|
|
|
NSNonOwnedPointerMapValueCallBacks, 0);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
received_request_rmc_queue = [[Queue alloc] init];
|
|
|
|
|
received_request_rmc_queue_gate = [Lock new];
|
|
|
|
|
received_reply_rmc_queue = [[Queue alloc] init];
|
|
|
|
|
received_reply_rmc_queue_gate = [Lock new];
|
|
|
|
|
root_object_dictionary = [[Dictionary alloc] init];
|
|
|
|
|
root_object_dictionary_gate = [Lock new];
|
1996-03-13 02:32:46 +00:00
|
|
|
|
in_port_2_ancestor =
|
|
|
|
|
NSCreateMapTable (NSNonOwnedPointerMapKeyCallBacks,
|
|
|
|
|
NSNonOwnedPointerMapValueCallBacks, 0);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
messages_received_count = 0;
|
1996-03-06 14:05:36 +00:00
|
|
|
|
default_in_port_class = [TcpInPort class];
|
|
|
|
|
default_out_port_class = [TcpOutPort class];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
default_proxy_class = [Proxy class];
|
|
|
|
|
default_encoding_class = [ConnectedEncoder class];
|
|
|
|
|
default_decoding_class = [ConnectedDecoder class];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
default_in_timeout = CONNECTION_DEFAULT_TIMEOUT;
|
|
|
|
|
default_out_timeout = CONNECTION_DEFAULT_TIMEOUT;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
|
|
|
|
/* Getting and setting class variables */
|
|
|
|
|
|
1996-03-06 14:05:36 +00:00
|
|
|
|
+ (void) setDefaultInPortClass: (Class)aClass
|
|
|
|
|
{
|
|
|
|
|
default_in_port_class = aClass;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (Class) defaultInPortClass
|
|
|
|
|
{
|
|
|
|
|
return default_in_port_class;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) setDefaultOutPortClass: (Class)aClass
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-06 14:05:36 +00:00
|
|
|
|
default_out_port_class = aClass;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-06 14:05:36 +00:00
|
|
|
|
+ (Class) defaultOutPortClass
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-06 14:05:36 +00:00
|
|
|
|
return default_out_port_class;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
+ (void) setDefaultProxyClass: (Class)aClass
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
default_proxy_class = aClass;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
+ (Class) defaultProxyClass
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return default_proxy_class;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
+ (void) setDefaultDecodingClass: (Class) aClass
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
default_decoding_class = aClass;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (Class) default_decoding_class
|
|
|
|
|
{
|
|
|
|
|
return default_decoding_class;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (int) defaultOutTimeout
|
|
|
|
|
{
|
|
|
|
|
return default_out_timeout;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
+ (void) setDefaultOutTimeout: (int)to
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
default_out_timeout = to;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (int) defaultInTimeout
|
|
|
|
|
{
|
|
|
|
|
return default_in_timeout;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
+ (void) setDefaultInTimeout: (int)to
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
default_in_timeout = to;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
|
|
|
|
/* Class-wide stats and collections. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
+ (int) messagesReceived
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return messages_received_count;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (id <Collecting>) allConnections
|
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return [connection_array copy];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (unsigned) connectionsCount
|
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return [connection_array count];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-12 19:40:16 +00:00
|
|
|
|
+ (unsigned) connectionsCountWithInPort: (InPort*)aPort
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned count = 0;
|
1996-03-01 15:54:57 +00:00
|
|
|
|
id o;
|
|
|
|
|
[connection_array_gate lock];
|
|
|
|
|
FOR_ARRAY (connection_array, o)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
if ([aPort isEqual: [o inPort]])
|
1994-11-04 16:29:24 +00:00
|
|
|
|
count++;
|
|
|
|
|
}
|
1996-03-03 00:45:04 +00:00
|
|
|
|
END_FOR_ARRAY (connection_array);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[connection_array_gate unlock];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
|
|
|
|
/* Creating and initializing connections. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
|
|
|
|
- init
|
|
|
|
|
{
|
1996-03-06 14:05:36 +00:00
|
|
|
|
id newPort = [default_in_port_class newForReceiving];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
id newConn =
|
|
|
|
|
[Connection newForInPort:newPort outPort:nil ancestorConnection:nil];
|
1995-03-12 19:58:48 +00:00
|
|
|
|
[self release];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
return newConn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ new
|
|
|
|
|
{
|
1996-03-06 14:05:36 +00:00
|
|
|
|
id newPort = [default_in_port_class newForReceiving];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
id newConn =
|
|
|
|
|
[Connection newForInPort:newPort outPort:nil ancestorConnection:nil];
|
|
|
|
|
return newConn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (Connection*) newWithRootObject: anObj;
|
|
|
|
|
{
|
|
|
|
|
id newPort;
|
|
|
|
|
id newConn;
|
|
|
|
|
|
1996-03-06 14:05:36 +00:00
|
|
|
|
newPort = [default_in_port_class newForReceiving];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
newConn = [self newForInPort:newPort outPort:nil
|
|
|
|
|
ancestorConnection:nil];
|
|
|
|
|
[self setRootObject:anObj forInPort:newPort];
|
|
|
|
|
return newConn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* I want this method name to clearly indicate that we're not connecting
|
|
|
|
|
to a pre-existing registration name, we're registering a new name,
|
|
|
|
|
and this method will fail if that name has already been registered.
|
|
|
|
|
This is why I don't like "newWithRegisteredName:" --- it's unclear
|
|
|
|
|
if we're connecting to another Connection that already registered
|
|
|
|
|
with that name. */
|
|
|
|
|
|
1995-04-03 03:23:45 +00:00
|
|
|
|
+ (Connection*) newRegisteringAtName: (id <String>)n withRootObject: anObj
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
id newPort;
|
|
|
|
|
id newConn;
|
|
|
|
|
|
1996-03-06 14:05:36 +00:00
|
|
|
|
newPort = [default_in_port_class newForReceivingFromRegisteredName: n];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
newConn = [self newForInPort:newPort outPort:nil
|
|
|
|
|
ancestorConnection:nil];
|
|
|
|
|
[self setRootObject:anObj forInPort:newPort];
|
|
|
|
|
return newConn;
|
|
|
|
|
}
|
|
|
|
|
|
1995-04-03 03:23:45 +00:00
|
|
|
|
+ (Proxy*) rootProxyAtName: (id <String>)n
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return [self rootProxyAtName: n onHost: @""];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-04-03 03:23:45 +00:00
|
|
|
|
+ (Proxy*) rootProxyAtName: (id <String>)n onHost: (id <String>)h
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-06 14:05:36 +00:00
|
|
|
|
id p = [default_out_port_class newForSendingToRegisteredName: n onHost: h];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return [self rootProxyAtPort: p];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-12 19:40:16 +00:00
|
|
|
|
+ (Proxy*) rootProxyAtPort: (OutPort*)anOutPort
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-06 14:05:36 +00:00
|
|
|
|
id newInPort = [default_in_port_class newForReceiving];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return [self rootProxyAtPort: anOutPort withInPort: newInPort];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-12 19:40:16 +00:00
|
|
|
|
+ (Proxy*) rootProxyAtPort: (OutPort*)anOutPort withInPort: (InPort*)anInPort
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
Connection *newConn = [self newForInPort:anInPort
|
|
|
|
|
outPort:anOutPort
|
|
|
|
|
ancestorConnection:nil];
|
|
|
|
|
Proxy *newRemote;
|
|
|
|
|
|
|
|
|
|
newRemote = [newConn rootProxy];
|
|
|
|
|
return newRemote;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
/* This is the designated initializer for Connection */
|
|
|
|
|
|
1996-03-12 19:40:16 +00:00
|
|
|
|
+ (Connection*) newForInPort: (InPort*)ip outPort: (OutPort*)op
|
1996-03-13 02:32:46 +00:00
|
|
|
|
ancestorConnection: ancestor
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
Connection *newConn;
|
|
|
|
|
int i, count;
|
|
|
|
|
id newConnInPort, newConnOutPort;
|
1996-03-06 14:05:36 +00:00
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert (ip);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[connection_array_gate lock];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
|
|
|
|
/* Find previously existing connection if there */
|
|
|
|
|
/* xxx Clean this up */
|
1996-03-01 15:54:57 +00:00
|
|
|
|
count = [connection_array count];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
newConn = [connection_array objectAtIndex: i];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
newConnInPort = [newConn inPort];
|
|
|
|
|
newConnOutPort = [newConn outPort];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
if ([newConnInPort isEqual: ip]
|
|
|
|
|
&& [newConnOutPort isEqual: op])
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[connection_array_gate unlock];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
return newConn;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newConn = [[Connection alloc] _superInit];
|
|
|
|
|
if (debug_connection)
|
1996-03-06 14:05:36 +00:00
|
|
|
|
fprintf(stderr, "Created new connection 0x%x\n\t%s\n\t%s\n",
|
|
|
|
|
(unsigned)newConn,
|
|
|
|
|
[[ip description] cStringNoCopy],
|
|
|
|
|
[[op description] cStringNoCopy]);
|
1996-03-13 02:32:46 +00:00
|
|
|
|
newConn->is_valid = 1;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
newConn->in_port = ip;
|
|
|
|
|
[ip retain];
|
|
|
|
|
newConn->out_port = op;
|
|
|
|
|
[op retain];
|
|
|
|
|
newConn->message_count = 0;
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
/* This maps (void*)obj to (id)obj. The obj's are retained.
|
|
|
|
|
We use this instead of an NSHashTable because we only care about
|
|
|
|
|
the object's address, and don't want to send the -hash message to it. */
|
|
|
|
|
newConn->local_targets =
|
|
|
|
|
NSCreateMapTable (NSNonOwnedPointerMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
|
|
|
|
|
|
|
|
|
/* This maps [proxy targetForProxy] to proxy. The proxy's are retained. */
|
|
|
|
|
newConn->remote_proxies =
|
|
|
|
|
NSCreateMapTable (NSIntMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
|
|
|
|
|
|
|
|
|
newConn->incoming_xref_2_const_ptr =
|
|
|
|
|
NSCreateMapTable (NSIntMapKeyCallBacks,
|
|
|
|
|
NSNonOwnedPointerMapValueCallBacks, 0);
|
|
|
|
|
newConn->outgoing_const_ptr_2_xref =
|
|
|
|
|
NSCreateMapTable (NSIntMapKeyCallBacks,
|
|
|
|
|
NSNonOwnedPointerMapValueCallBacks, 0);
|
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
newConn->in_timeout = [self defaultInTimeout];
|
|
|
|
|
newConn->out_timeout = [self defaultOutTimeout];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
newConn->encoding_class = default_encoding_class;
|
1996-03-13 02:32:46 +00:00
|
|
|
|
|
|
|
|
|
/* xxx ANCESTOR argument is currently ignored; in the future it
|
|
|
|
|
will be removed. */
|
|
|
|
|
/* xxx It this the correct behavior? */
|
|
|
|
|
if (!(ancestor = NSMapGet (in_port_2_ancestor, ip)))
|
|
|
|
|
{
|
|
|
|
|
NSMapInsert (in_port_2_ancestor, ip, newConn);
|
1996-03-18 20:08:53 +00:00
|
|
|
|
[[RunLoop currentInstance] addPort: ip
|
|
|
|
|
forMode: RunLoopDefaultMode];
|
|
|
|
|
[[RunLoop currentInstance] addPort: ip
|
|
|
|
|
forMode: RunLoopConnectionReplyMode];
|
1996-03-13 02:32:46 +00:00
|
|
|
|
/* This will cause the connection with the registered name
|
|
|
|
|
to receive the -invokeWithObject: from the IN_PORT.
|
|
|
|
|
This ends up being the ancestor of future new Connections
|
|
|
|
|
on this in port. */
|
|
|
|
|
/* xxx Could it happen that this connection was invalidated, but
|
|
|
|
|
the others would still be OK? That would cause problems.
|
|
|
|
|
No. I don't think that can happen. */
|
|
|
|
|
[ip setReceivedPacketInvocation: (id)[self class]];
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
if (ancestor)
|
1996-03-06 14:05:36 +00:00
|
|
|
|
{
|
|
|
|
|
newConn->in_port_class = [ancestor inPortClass];
|
|
|
|
|
newConn->out_port_class = [ancestor outPortClass];
|
|
|
|
|
}
|
1996-03-01 15:54:57 +00:00
|
|
|
|
else
|
1996-03-06 14:05:36 +00:00
|
|
|
|
{
|
|
|
|
|
newConn->in_port_class = default_in_port_class;
|
|
|
|
|
newConn->out_port_class = default_out_port_class;
|
|
|
|
|
}
|
1996-03-01 15:54:57 +00:00
|
|
|
|
newConn->delay_dialog_interruptions = YES;
|
1996-03-12 19:40:16 +00:00
|
|
|
|
newConn->reply_depth = 0;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
newConn->delegate = nil;
|
|
|
|
|
|
|
|
|
|
/* Here ask the delegate for permission. */
|
|
|
|
|
/* delegate is responsible for freeing newConn if it returns something
|
|
|
|
|
different. */
|
|
|
|
|
if ([[ancestor delegate] respondsTo:@selector(connection:didConnect:)])
|
|
|
|
|
newConn = [[ancestor delegate] connection:ancestor
|
|
|
|
|
didConnect:newConn];
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
/* Register outselves for invalidation notification when the
|
|
|
|
|
ports become invalid. */
|
1996-03-06 14:05:36 +00:00
|
|
|
|
[NotificationDispatcher addObserver: newConn
|
|
|
|
|
selector: @selector(portIsInvalid:)
|
|
|
|
|
name: PortBecameInvalidNotification
|
|
|
|
|
object: ip];
|
1996-03-07 18:08:24 +00:00
|
|
|
|
if (op)
|
|
|
|
|
[NotificationDispatcher addObserver: newConn
|
|
|
|
|
selector: @selector(portIsInvalid:)
|
|
|
|
|
name: PortBecameInvalidNotification
|
|
|
|
|
object: op];
|
|
|
|
|
/* if OP is nil, making this notification request would have
|
|
|
|
|
registered us to receive all PortBecameInvalidNotification
|
|
|
|
|
requests, independent of which port posted them. This isn't
|
|
|
|
|
what we want. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1995-06-29 00:53:34 +00:00
|
|
|
|
/* xxx This is weird, though. When will newConn ever get dealloc'ed?
|
|
|
|
|
connectionArray will retain it, but connectionArray will never get
|
|
|
|
|
deallocated. This sort of retain/release cirularity must be common
|
|
|
|
|
enough. Think about this and fix it. */
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[connection_array addObject: newConn];
|
1995-06-29 00:53:34 +00:00
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[connection_array_gate unlock];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-06 14:05:36 +00:00
|
|
|
|
[NotificationDispatcher
|
|
|
|
|
postNotificationName: ConnectionWasCreatedNotification
|
|
|
|
|
object: newConn];
|
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
return newConn;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- _superInit
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[super init];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Creating new rmc's for encoding requests and replies */
|
|
|
|
|
|
|
|
|
|
/* Create a new, empty rmc, which will be filled with a request. */
|
|
|
|
|
- newSendingRequestRmc
|
|
|
|
|
{
|
|
|
|
|
id rmc;
|
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert(in_port);
|
|
|
|
|
NSParameterAssert (is_valid);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
rmc = [[self encodingClass] newForWritingWithConnection: self
|
1996-03-06 14:05:36 +00:00
|
|
|
|
sequenceNumber: [self _newMsgNumber]
|
|
|
|
|
identifier: METHOD_REQUEST];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return rmc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Create a new, empty rmc, which will be filled with a reply to msg #n. */
|
|
|
|
|
- newSendingReplyRmcWithSequenceNumber: (int)n
|
|
|
|
|
{
|
|
|
|
|
id rmc = [[self encodingClass] newForWritingWithConnection: self
|
1996-03-06 14:05:36 +00:00
|
|
|
|
sequenceNumber: n
|
|
|
|
|
identifier: METHOD_REPLY];
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert (is_valid);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return rmc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Methods for handling client and server, requests and replies */
|
|
|
|
|
|
|
|
|
|
/* Proxy's -forward:: method calls this to the the message over the wire. */
|
|
|
|
|
- (retval_t) forwardForProxy: (Proxy*)object
|
|
|
|
|
selector: (SEL)sel
|
|
|
|
|
argFrame: (arglist_t)argframe
|
|
|
|
|
{
|
|
|
|
|
ConnectedEncoder *op;
|
|
|
|
|
|
|
|
|
|
/* The callback for encoding the args of the method call. */
|
|
|
|
|
void encoder (int argnum, void *datum, const char *type, int flags)
|
|
|
|
|
{
|
|
|
|
|
#define ENCODED_ARGNAME @"argument value"
|
|
|
|
|
switch (*type)
|
|
|
|
|
{
|
|
|
|
|
case _C_ID:
|
|
|
|
|
if (flags & _F_BYCOPY)
|
|
|
|
|
[op encodeBycopyObject: *(id*)datum withName: ENCODED_ARGNAME];
|
|
|
|
|
else
|
|
|
|
|
[op encodeObject: *(id*)datum withName: ENCODED_ARGNAME];
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
[op encodeValueOfObjCType: type at: datum withName: ENCODED_ARGNAME];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Encode the method on an RMC, and send it. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
BOOL out_parameters;
|
|
|
|
|
const char *type;
|
|
|
|
|
retval_t retframe;
|
|
|
|
|
int seq_num;
|
1996-03-26 22:34:40 +00:00
|
|
|
|
|
|
|
|
|
NSParameterAssert (is_valid);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
op = [self newSendingRequestRmc];
|
|
|
|
|
seq_num = [op sequenceNumber];
|
|
|
|
|
|
|
|
|
|
/* get the method types from the selector */
|
|
|
|
|
#if NeXT_runtime
|
1996-03-26 20:52:26 +00:00
|
|
|
|
[NSException
|
|
|
|
|
raise: NSGenericException
|
|
|
|
|
format: @"Sorry, distributed objects does not work with NeXT runtime"];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
/* type = [object selectorTypeForProxy:sel]; */
|
|
|
|
|
#else
|
|
|
|
|
type = sel_get_type(sel);
|
1995-04-07 21:23:24 +00:00
|
|
|
|
#endif
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert(type);
|
|
|
|
|
NSParameterAssert(*type);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
|
|
|
|
/* Send the types that we're using, so that the performer knows
|
|
|
|
|
exactly what qualifiers we're using.
|
|
|
|
|
If all selectors included qualifiers, and if I could make
|
|
|
|
|
sel_types_match() work the way I wanted, we wouldn't need to do
|
|
|
|
|
this. */
|
|
|
|
|
[op encodeValueOfCType: @encode(char*)
|
|
|
|
|
at: &type
|
|
|
|
|
withName: @"selector type"];
|
|
|
|
|
|
|
|
|
|
/* xxx This doesn't work with proxies and the NeXT runtime because
|
|
|
|
|
type may be a method_type from a remote machine with a
|
|
|
|
|
different architecture, and its argframe layout specifiers
|
|
|
|
|
won't be right for this machine! */
|
1996-03-29 17:55:15 +00:00
|
|
|
|
out_parameters = mframe_dissect_call (argframe, type, encoder);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
/* Send the rmc */
|
|
|
|
|
[op dismiss];
|
|
|
|
|
|
|
|
|
|
/* Get the reply rmc, and decode it. */
|
|
|
|
|
{
|
|
|
|
|
ConnectedDecoder *ip = nil;
|
|
|
|
|
int last_argnum;
|
1996-03-26 22:34:40 +00:00
|
|
|
|
BOOL is_exception;
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
|
|
|
|
void decoder(int argnum, void *datum, const char *type, int flags)
|
|
|
|
|
{
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert(ip != (id)-1);
|
|
|
|
|
/* If we didn't get the reply packet yet, get it now. */
|
1996-03-01 15:54:57 +00:00
|
|
|
|
if (!ip)
|
1996-03-26 22:34:40 +00:00
|
|
|
|
{
|
|
|
|
|
/* xxx Why do we get the reply packet in here, and not
|
|
|
|
|
just before calling dissect_method_return() below? */
|
|
|
|
|
ip = [self _getReceivedReplyRmcWithSequenceNumber:seq_num];
|
|
|
|
|
/* Find out if the server is returning an exception instead
|
|
|
|
|
of the return values. */
|
|
|
|
|
[ip decodeValueOfCType: @encode(BOOL)
|
|
|
|
|
at: &is_exception
|
|
|
|
|
withName: NULL];
|
|
|
|
|
if (is_exception)
|
|
|
|
|
{
|
|
|
|
|
/* Decode the exception object, and raise it. */
|
|
|
|
|
id exc;
|
|
|
|
|
[ip decodeObjectAt: &exc
|
|
|
|
|
withName: NULL];
|
|
|
|
|
[ip dismiss];
|
|
|
|
|
/* xxx Is there anything else to clean up in
|
|
|
|
|
dissect_method_return()? */
|
|
|
|
|
[exc raise];
|
|
|
|
|
}
|
|
|
|
|
}
|
1996-03-29 17:55:15 +00:00
|
|
|
|
[ip decodeValueOfObjCType: type at: datum withName: NULL];
|
|
|
|
|
/* -decodeValueOfCType:at:withName: malloc's new memory
|
|
|
|
|
for char*'s. We need to make sure it gets freed eventually
|
|
|
|
|
so we don't have a memory leak. Request here that it be
|
|
|
|
|
autorelease'ed. */
|
|
|
|
|
if (*type == _C_CHARPTR)
|
|
|
|
|
[MallocAddress autoreleaseMallocAddress: *(char**)datum];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
if (argnum == last_argnum)
|
|
|
|
|
{
|
|
|
|
|
/* this must be here to avoid trashing alloca'ed retframe */
|
|
|
|
|
[ip dismiss];
|
|
|
|
|
ip = (id)-1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
last_argnum = type_get_number_of_arguments(type) - 1;
|
1996-03-29 17:55:15 +00:00
|
|
|
|
retframe = mframe_build_return (argframe, type, out_parameters,
|
|
|
|
|
decoder);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return retframe;
|
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
/* Connection calls this to service the incoming method request. */
|
|
|
|
|
- (void) _service_forwardForProxy: aRmc
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
char *forward_type;
|
|
|
|
|
id op = nil;
|
|
|
|
|
int reply_sequence_number;
|
|
|
|
|
int numargs;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
void decoder (int argnum, void *datum, const char *type)
|
|
|
|
|
{
|
|
|
|
|
[aRmc decodeValueOfObjCType:type
|
|
|
|
|
at:datum
|
|
|
|
|
withName:NULL];
|
1996-03-29 17:55:15 +00:00
|
|
|
|
/* -decodeValueOfCType:at:withName: malloc's new memory
|
|
|
|
|
for char*'s. We need to make sure it gets freed eventually
|
|
|
|
|
so we don't have a memory leak. Request here that it be
|
|
|
|
|
autorelease'ed. */
|
|
|
|
|
if (*type == _C_CHARPTR)
|
|
|
|
|
[MallocAddress autoreleaseMallocAddress: *(char**)datum];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
/* We need this "dismiss" to happen here and not later so that Coder
|
|
|
|
|
"-awake..." methods will get sent before the __builtin_apply! */
|
|
|
|
|
if (argnum == numargs-1)
|
|
|
|
|
[aRmc dismiss];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void encoder (int argnum, void *datum, const char *type, int flags)
|
|
|
|
|
{
|
|
|
|
|
#define ENCODED_RETNAME @"return value"
|
|
|
|
|
if (op == nil)
|
1996-03-26 22:34:40 +00:00
|
|
|
|
{
|
|
|
|
|
BOOL is_exception = NO;
|
|
|
|
|
op = [self newSendingReplyRmcWithSequenceNumber:
|
|
|
|
|
reply_sequence_number];
|
|
|
|
|
[op encodeValueOfCType: @encode(BOOL)
|
|
|
|
|
at: &is_exception
|
|
|
|
|
withName: @"Exceptional reply flag"];
|
|
|
|
|
}
|
1996-03-01 15:54:57 +00:00
|
|
|
|
switch (*type)
|
|
|
|
|
{
|
|
|
|
|
case _C_ID:
|
|
|
|
|
if (flags & _F_BYCOPY)
|
|
|
|
|
[op encodeBycopyObject:*(id*)datum withName:ENCODED_RETNAME];
|
|
|
|
|
else
|
|
|
|
|
[op encodeObject:*(id*)datum withName:ENCODED_RETNAME];
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
[op encodeValueOfObjCType:type at:datum withName:ENCODED_RETNAME];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
/* Make sure don't let exceptions caused by servicing the client's
|
|
|
|
|
request cause us to crash. */
|
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
NSParameterAssert (is_valid);
|
1996-03-07 18:08:24 +00:00
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
/* Save this for later */
|
|
|
|
|
reply_sequence_number = [aRmc sequenceNumber];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
/* Get the types that we're using, so that we know
|
|
|
|
|
exactly what qualifiers the forwarder used.
|
|
|
|
|
If all selectors included qualifiers and I could make
|
|
|
|
|
sel_types_match() work the way I wanted, we wouldn't need
|
|
|
|
|
to do this. */
|
|
|
|
|
[aRmc decodeValueOfCType:@encode(char*)
|
|
|
|
|
at:&forward_type
|
|
|
|
|
withName:NULL];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
numargs = type_get_number_of_arguments(forward_type);
|
|
|
|
|
|
1996-03-29 17:55:15 +00:00
|
|
|
|
mframe_do_call (forward_type, decoder, encoder);
|
1996-03-26 22:34:40 +00:00
|
|
|
|
[op dismiss];
|
|
|
|
|
}
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
/* Make sure we pass all exceptions back to the requestor. */
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
BOOL is_exception = YES;
|
|
|
|
|
/* Try to clean up a little. */
|
|
|
|
|
if (op)
|
|
|
|
|
[op release];
|
|
|
|
|
|
|
|
|
|
/* Send the exception back to the client. */
|
|
|
|
|
op = [self newSendingReplyRmcWithSequenceNumber: reply_sequence_number];
|
|
|
|
|
[op encodeValueOfCType: @encode(BOOL)
|
|
|
|
|
at: &is_exception
|
|
|
|
|
withName: @"Exceptional reply flag"];
|
|
|
|
|
[op encodeBycopyObject: exception
|
|
|
|
|
withName: @"Exception object"];
|
|
|
|
|
[op dismiss];
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER;
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
if (forward_type)
|
|
|
|
|
(*objc_free) (forward_type);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (Proxy*) rootProxy
|
|
|
|
|
{
|
|
|
|
|
id op, ip;
|
|
|
|
|
Proxy *newProxy;
|
|
|
|
|
int seq_num = [self _newMsgNumber];
|
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert(in_port);
|
|
|
|
|
NSParameterAssert (is_valid);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
op = [[self encodingClass]
|
|
|
|
|
newForWritingWithConnection: self
|
|
|
|
|
sequenceNumber: seq_num
|
|
|
|
|
identifier: ROOTPROXY_REQUEST];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[op dismiss];
|
1996-03-12 19:40:16 +00:00
|
|
|
|
ip = [self _getReceivedReplyRmcWithSequenceNumber: seq_num];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[ip decodeObjectAt: &newProxy withName: NULL];
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert (class_is_kind_of (newProxy->isa, objc_get_class ("Proxy")));
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[ip dismiss];
|
|
|
|
|
return newProxy;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- (void) _service_rootObject: rmc
|
|
|
|
|
{
|
|
|
|
|
id rootObject = [Connection rootObjectForInPort:in_port];
|
|
|
|
|
ConnectedEncoder* op = [[self encodingClass]
|
|
|
|
|
newForWritingWithConnection: [rmc connection]
|
|
|
|
|
sequenceNumber: [rmc sequenceNumber]
|
|
|
|
|
identifier: ROOTPROXY_REPLY];
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert (in_port);
|
|
|
|
|
NSParameterAssert (is_valid);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
/* Perhaps we should turn this into a class method. */
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert([rmc connection] == self);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[op encodeObject: rootObject withName: @"root object"];
|
|
|
|
|
[op dismiss];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) shutdown
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
id op;
|
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert(in_port);
|
|
|
|
|
NSParameterAssert (is_valid);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
op = [[self encodingClass]
|
|
|
|
|
newForWritingWithConnection: self
|
|
|
|
|
sequenceNumber: [self _newMsgNumber]
|
|
|
|
|
identifier: CONNECTION_SHUTDOWN];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[op dismiss];
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- (void) _service_shutdown: rmc forConnection: receiving_connection
|
|
|
|
|
{
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert (is_valid);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[self invalidate];
|
|
|
|
|
if (receiving_connection == self)
|
1996-03-26 20:52:26 +00:00
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
|
format: @"connection waiting for request was shut down"];
|
1996-03-07 18:08:24 +00:00
|
|
|
|
[self dealloc]; // xxx release instead? YES!!
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[rmc dismiss];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (const char *) typeForSelector: (SEL)sel remoteTarget: (unsigned)target
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
id op, ip;
|
|
|
|
|
char *type;
|
|
|
|
|
int seq_num;
|
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert(in_port);
|
|
|
|
|
NSParameterAssert (is_valid);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
seq_num = [self _newMsgNumber];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
op = [[self encodingClass]
|
|
|
|
|
newForWritingWithConnection: self
|
|
|
|
|
sequenceNumber: seq_num
|
|
|
|
|
identifier: METHODTYPE_REQUEST];
|
1996-01-23 23:57:17 +00:00
|
|
|
|
[op encodeValueOfObjCType:":"
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&sel
|
|
|
|
|
withName:NULL];
|
1996-01-23 23:57:17 +00:00
|
|
|
|
[op encodeValueOfCType:@encode(unsigned)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&target
|
|
|
|
|
withName:NULL];
|
|
|
|
|
[op dismiss];
|
1996-03-12 19:40:16 +00:00
|
|
|
|
ip = [self _getReceivedReplyRmcWithSequenceNumber:seq_num];
|
1996-01-23 23:57:17 +00:00
|
|
|
|
[ip decodeValueOfCType:@encode(char*)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&type
|
|
|
|
|
withName:NULL];
|
|
|
|
|
[ip dismiss];
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- (void) _service_typeForSelector: rmc
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
ConnectedEncoder* op;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
unsigned target;
|
|
|
|
|
SEL sel;
|
|
|
|
|
const char *type;
|
|
|
|
|
struct objc_method* m;
|
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert(in_port);
|
|
|
|
|
NSParameterAssert (is_valid);
|
|
|
|
|
NSParameterAssert([rmc connection] == self);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
op = [[self encodingClass]
|
|
|
|
|
newForWritingWithConnection: [rmc connection]
|
|
|
|
|
sequenceNumber: [rmc sequenceNumber]
|
|
|
|
|
identifier: METHODTYPE_REPLY];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-01-23 23:57:17 +00:00
|
|
|
|
[rmc decodeValueOfObjCType:":"
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&sel
|
|
|
|
|
withName:NULL];
|
1996-01-23 23:57:17 +00:00
|
|
|
|
[rmc decodeValueOfCType:@encode(unsigned)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&target
|
|
|
|
|
withName:NULL];
|
|
|
|
|
/* xxx We should make sure that TARGET is a valid object. */
|
|
|
|
|
/* Not actually a Proxy, but we avoid the warnings "id" would have made. */
|
|
|
|
|
m = class_get_instance_method(((Proxy*)target)->isa, sel);
|
|
|
|
|
/* Perhaps I need to be more careful in the line above to get the
|
|
|
|
|
version of the method types that has the type qualifiers in it.
|
|
|
|
|
Search the protocols list. */
|
|
|
|
|
if (m)
|
|
|
|
|
type = m->method_types;
|
|
|
|
|
else
|
|
|
|
|
type = "";
|
1996-01-23 23:57:17 +00:00
|
|
|
|
[op encodeValueOfCType:@encode(char*)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&type
|
1996-01-24 03:33:21 +00:00
|
|
|
|
withName:@"Requested Method Type for Target"];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[op dismiss];
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
|
|
|
|
/* Running the connection, getting/sending requests/replies. */
|
|
|
|
|
|
1996-03-12 19:40:16 +00:00
|
|
|
|
- (void) runConnectionUntilDate: date
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-12 19:40:16 +00:00
|
|
|
|
[RunLoop runUntilDate: date];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-12 19:40:16 +00:00
|
|
|
|
- (void) runConnection
|
1996-03-01 15:54:57 +00:00
|
|
|
|
{
|
1996-03-12 19:40:16 +00:00
|
|
|
|
[self runConnectionUntilDate: [NSDate distantFuture]];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-12 19:40:16 +00:00
|
|
|
|
- (void) _handleRmc: rmc
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-12 19:40:16 +00:00
|
|
|
|
switch ([rmc identifier])
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-12 19:40:16 +00:00
|
|
|
|
case ROOTPROXY_REQUEST:
|
|
|
|
|
/* It won't take much time to handle this, so go ahead and service
|
|
|
|
|
it, even if we are waiting for a reply. */
|
|
|
|
|
[[rmc connection] _service_rootObject: rmc];
|
|
|
|
|
[rmc dismiss];
|
|
|
|
|
break;
|
|
|
|
|
case METHODTYPE_REQUEST:
|
|
|
|
|
/* It won't take much time to handle this, so go ahead and service
|
|
|
|
|
it, even if we are waiting for a reply. */
|
|
|
|
|
[[rmc connection] _service_typeForSelector: rmc];
|
|
|
|
|
[rmc dismiss];
|
|
|
|
|
break;
|
|
|
|
|
case METHOD_REQUEST:
|
1996-03-19 00:58:38 +00:00
|
|
|
|
/* We just got a new request; we need to decide whether to queue
|
|
|
|
|
it or service it now.
|
|
|
|
|
If the REPLY_DEPTH is 0, then we aren't in the middle of waiting
|
|
|
|
|
for a reply, we are waiting for requests---so service it now.
|
|
|
|
|
If REPLY_DEPTH is non-zero, we may still want to service it now
|
|
|
|
|
if it is a request made as a callback from our peer---the request
|
|
|
|
|
is part of the remote code necessary to finish calculating our
|
|
|
|
|
reply; we know it's a callback from our peer if the [RMC CONNECTION]
|
|
|
|
|
is self.
|
|
|
|
|
If REPLY_DEPTH is non-zero, and the [RMC CONNECTION] is not self,
|
|
|
|
|
then we may still want to service it now if DELAY_DIALOG_INTERRUPTIONS
|
|
|
|
|
is false. */
|
|
|
|
|
if (reply_depth == 0
|
|
|
|
|
|| [rmc connection] == self
|
|
|
|
|
|| !delay_dialog_interruptions)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-12 19:40:16 +00:00
|
|
|
|
[[rmc connection] _service_forwardForProxy: rmc];
|
|
|
|
|
/* Service any requests that were queued while we
|
|
|
|
|
were waiting for replies.
|
|
|
|
|
xxx Is this the right place for this check? */
|
|
|
|
|
if (reply_depth == 0)
|
|
|
|
|
[self _handleQueuedRmcRequests];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1996-03-12 19:40:16 +00:00
|
|
|
|
[received_request_rmc_queue_gate lock];
|
|
|
|
|
[received_request_rmc_queue enqueueObject: rmc];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[received_request_rmc_queue_gate unlock];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
1996-03-12 19:40:16 +00:00
|
|
|
|
break;
|
|
|
|
|
case ROOTPROXY_REPLY:
|
|
|
|
|
case METHOD_REPLY:
|
|
|
|
|
case METHODTYPE_REPLY:
|
|
|
|
|
/* Remember multi-threaded callbacks will have to be handled specially */
|
|
|
|
|
[received_reply_rmc_queue_gate lock];
|
|
|
|
|
[received_reply_rmc_queue enqueueObject: rmc];
|
|
|
|
|
[received_reply_rmc_queue_gate unlock];
|
|
|
|
|
break;
|
|
|
|
|
case CONNECTION_SHUTDOWN:
|
|
|
|
|
{
|
|
|
|
|
[[rmc connection] _service_shutdown: rmc forConnection: self];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
1996-03-26 20:52:26 +00:00
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
|
format: @"unrecognized ConnectedDecoder identifier"];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-12 19:40:16 +00:00
|
|
|
|
- (void) _handleQueuedRmcRequests
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-12 19:40:16 +00:00
|
|
|
|
id rmc;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-12 19:40:16 +00:00
|
|
|
|
[received_request_rmc_queue_gate lock];
|
|
|
|
|
while ((rmc = [received_request_rmc_queue dequeueObject]))
|
|
|
|
|
{
|
|
|
|
|
[received_request_rmc_queue_gate unlock];
|
|
|
|
|
[self _handleRmc: rmc];
|
|
|
|
|
[received_request_rmc_queue_gate lock];
|
|
|
|
|
}
|
|
|
|
|
[received_request_rmc_queue_gate unlock];
|
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-12 19:40:16 +00:00
|
|
|
|
/* Deal with an RMC, either by queuing it for later service, or
|
|
|
|
|
by servicing it right away. This method is called by the
|
|
|
|
|
in_port's received-packet-invocation. */
|
|
|
|
|
|
|
|
|
|
/* Look for it on the queue, if it is not there, return nil. */
|
|
|
|
|
- _getReceivedReplyRmcFromQueueWithSequenceNumber: (int)sn
|
|
|
|
|
{
|
|
|
|
|
id the_rmc = nil;
|
|
|
|
|
unsigned count, i;
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[received_reply_rmc_queue_gate lock];
|
1996-03-12 19:40:16 +00:00
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
count = [received_reply_rmc_queue count];
|
|
|
|
|
/* xxx There should be a per-thread queue of rmcs so we can do
|
1994-11-04 16:29:24 +00:00
|
|
|
|
callbacks when multi-threaded. */
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
1996-03-12 19:40:16 +00:00
|
|
|
|
id a_rmc = [received_reply_rmc_queue objectAtIndex: i];
|
|
|
|
|
if ([a_rmc connection] == self
|
|
|
|
|
&& [a_rmc sequenceNumber] == sn)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
if (debug_connection)
|
|
|
|
|
printf("Getting received reply from queue\n");
|
1996-03-12 19:40:16 +00:00
|
|
|
|
[received_reply_rmc_queue removeObjectAtIndex: i];
|
|
|
|
|
the_rmc = a_rmc;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
1996-03-12 19:40:16 +00:00
|
|
|
|
/* xxx Make sure that there isn't a higher sequenceNumber, meaning
|
|
|
|
|
that we somehow dropped a packet. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[received_reply_rmc_queue_gate unlock];
|
1996-03-12 19:40:16 +00:00
|
|
|
|
return the_rmc;
|
|
|
|
|
}
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
1996-03-12 19:40:16 +00:00
|
|
|
|
/* Check the queue, then try to get it from the network by waiting
|
|
|
|
|
while we run the RunLoop. Return nil if we don't get anything
|
|
|
|
|
before timing out. */
|
|
|
|
|
- _getReceivedReplyRmcWithSequenceNumber: (int)sn
|
|
|
|
|
{
|
|
|
|
|
id rmc;
|
|
|
|
|
id timeout_date = nil;
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
1996-03-12 19:40:16 +00:00
|
|
|
|
reply_depth++;
|
|
|
|
|
while (!(rmc = [self _getReceivedReplyRmcFromQueueWithSequenceNumber: sn]))
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-12 19:40:16 +00:00
|
|
|
|
if (!timeout_date)
|
|
|
|
|
timeout_date = [[NSDate alloc]
|
|
|
|
|
initWithTimeIntervalSinceNow: in_timeout];
|
1996-03-18 20:08:53 +00:00
|
|
|
|
[RunLoop runOnceBeforeDate: timeout_date
|
1996-03-18 20:27:30 +00:00
|
|
|
|
forMode: RunLoopConnectionReplyMode];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
1996-03-12 19:40:16 +00:00
|
|
|
|
reply_depth--;
|
|
|
|
|
return rmc;
|
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-12 19:40:16 +00:00
|
|
|
|
/* Sneaky, sneaky. See "sneaky" comment in TcpPort.m.
|
1996-03-13 02:32:46 +00:00
|
|
|
|
This method is called by InPort when it receives a new packet. */
|
|
|
|
|
+ (void) invokeWithObject: packet
|
1996-03-12 19:40:16 +00:00
|
|
|
|
{
|
1996-03-13 02:32:46 +00:00
|
|
|
|
id rmc = [ConnectedDecoder
|
|
|
|
|
newDecodingWithPacket: packet
|
|
|
|
|
connection: NSMapGet (in_port_2_ancestor,
|
|
|
|
|
[packet receivingInPort])];
|
|
|
|
|
[[rmc connection] _handleRmc: rmc];
|
1996-03-12 19:40:16 +00:00
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-12 19:40:16 +00:00
|
|
|
|
- (int) _newMsgNumber
|
|
|
|
|
{
|
|
|
|
|
int n;
|
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert (is_valid);
|
1996-03-12 19:40:16 +00:00
|
|
|
|
[sequenceNumberGate lock];
|
|
|
|
|
n = message_count++;
|
|
|
|
|
[sequenceNumberGate unlock];
|
|
|
|
|
return n;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-12 19:40:16 +00:00
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
|
|
|
|
/* Managing objects and proxies. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-06 16:40:00 +00:00
|
|
|
|
- (void) addLocalObject: anObj
|
|
|
|
|
{
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert (is_valid);
|
1996-03-06 16:40:00 +00:00
|
|
|
|
[proxiesHashGate lock];
|
|
|
|
|
/* xxx Do we need to check to make sure it's not already there? */
|
|
|
|
|
/* This retains anObj. */
|
|
|
|
|
NSMapInsert (local_targets, (void*)anObj, anObj);
|
|
|
|
|
/* This does not retain anObj. */
|
|
|
|
|
NSMapInsert (all_connections_local_targets, (void*)anObj, anObj);
|
|
|
|
|
[proxiesHashGate unlock];
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
/* This should get called whenever an object free's itself */
|
|
|
|
|
+ (void) removeLocalObject: anObj
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
id c;
|
|
|
|
|
int i, count = [connection_array count];
|
1996-03-07 18:08:24 +00:00
|
|
|
|
|
|
|
|
|
/* Don't assert (is_valid); */
|
1996-03-01 15:54:57 +00:00
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
c = [connection_array objectAtIndex:i];
|
|
|
|
|
[c removeLocalObject: anObj];
|
|
|
|
|
[c removeProxy: anObj];
|
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- (void) removeLocalObject: anObj
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-07 18:08:24 +00:00
|
|
|
|
/* Don't assert (is_valid); */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[proxiesHashGate lock];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
/* This also releases anObj */
|
|
|
|
|
NSMapRemove (local_targets, (void*)anObj);
|
1996-03-06 16:40:00 +00:00
|
|
|
|
NSMapRemove (all_connections_local_targets, (void*)anObj);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[proxiesHashGate unlock];
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- (void) removeProxy: (Proxy*)aProxy
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned target = [aProxy targetForProxy];
|
1996-03-07 18:08:24 +00:00
|
|
|
|
|
|
|
|
|
/* Don't assert (is_valid); */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[proxiesHashGate lock];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
/* This also releases aProxy */
|
|
|
|
|
NSMapRemove (remote_proxies, (void*)target);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[proxiesHashGate unlock];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id <Collecting>) localObjects
|
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
id c;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-07 18:08:24 +00:00
|
|
|
|
/* Don't assert (is_valid); */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[proxiesHashGate lock];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
c = NSAllMapTableValues (local_targets);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[proxiesHashGate unlock];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return c;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id <Collecting>) proxies
|
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
id c;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-07 18:08:24 +00:00
|
|
|
|
/* Don't assert (is_valid); */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[proxiesHashGate lock];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
c = NSAllMapTableValues (remote_proxies);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[proxiesHashGate unlock];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return c;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (Proxy*) proxyForTarget: (unsigned)target
|
|
|
|
|
{
|
|
|
|
|
Proxy *p;
|
1996-03-07 18:08:24 +00:00
|
|
|
|
|
|
|
|
|
/* Don't assert (is_valid); */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[proxiesHashGate lock];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
p = NSMapGet (remote_proxies, (void*)target);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[proxiesHashGate unlock];
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert(!p || [p connectionForProxy] == self);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- (void) addProxy: (Proxy*) aProxy
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned target = [aProxy targetForProxy];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert (is_valid);
|
|
|
|
|
NSParameterAssert(aProxy->isa == [Proxy class]);
|
|
|
|
|
NSParameterAssert([aProxy connectionForProxy] == self);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[proxiesHashGate lock];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
if (NSMapGet (remote_proxies, (void*)target))
|
1996-03-26 20:52:26 +00:00
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
|
format: @"Trying to add the same proxy twice"];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
NSMapInsert (remote_proxies, (void*)target, aProxy);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[proxiesHashGate unlock];
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- (BOOL) includesProxyForTarget: (unsigned)target
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
BOOL ret;
|
1996-03-07 18:08:24 +00:00
|
|
|
|
|
|
|
|
|
/* Don't assert (is_valid); */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[proxiesHashGate lock];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
ret = NSMapGet (remote_proxies, (void*)target) ? YES : NO;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[proxiesHashGate unlock];
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- (BOOL) includesLocalObject: anObj
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
BOOL ret;
|
1996-03-07 18:08:24 +00:00
|
|
|
|
|
|
|
|
|
/* Don't assert (is_valid); */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[proxiesHashGate lock];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
ret = NSMapGet (local_targets, (void*)anObj) ? YES : NO;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[proxiesHashGate unlock];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return ret;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-06 14:05:36 +00:00
|
|
|
|
/* Check all connections.
|
|
|
|
|
Proxy needs to use this when decoding a local object in order to
|
|
|
|
|
make sure the target address is a valid object. It is not enough
|
|
|
|
|
for the Proxy to check the Proxy's connection only (using
|
|
|
|
|
-includesLocalObject), because the proxy may have come from a
|
|
|
|
|
triangle connection. */
|
|
|
|
|
+ (BOOL) includesLocalObject: anObj
|
|
|
|
|
{
|
|
|
|
|
BOOL ret;
|
1996-03-07 18:08:24 +00:00
|
|
|
|
|
|
|
|
|
/* Don't assert (is_valid); */
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert (all_connections_local_targets);
|
1996-03-06 14:05:36 +00:00
|
|
|
|
[proxiesHashGate lock];
|
|
|
|
|
ret = NSMapGet (all_connections_local_targets, (void*)anObj) ? YES : NO;
|
|
|
|
|
[proxiesHashGate unlock];
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
/* Pass nil to remove any reference keyed by aPort. */
|
1996-03-12 19:40:16 +00:00
|
|
|
|
+ (void) setRootObject: anObj forInPort: (InPort*)aPort
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
id oldRootObject = [self rootObjectForInPort: aPort];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert ([aPort isValid]);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
/* xxx This retains aPort? How will aPort ever get dealloc'ed? */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
if (oldRootObject != anObj)
|
|
|
|
|
{
|
|
|
|
|
if (anObj)
|
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[root_object_dictionary_gate lock];
|
|
|
|
|
[root_object_dictionary putObject: anObj atKey: aPort];
|
|
|
|
|
[root_object_dictionary_gate unlock];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
else /* anObj == nil && oldRootObject != nil */
|
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[root_object_dictionary_gate lock];
|
|
|
|
|
[root_object_dictionary removeObjectAtKey: aPort];
|
|
|
|
|
[root_object_dictionary_gate unlock];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-12 19:40:16 +00:00
|
|
|
|
+ rootObjectForInPort: (InPort*)aPort
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
id ro;
|
1996-03-07 18:08:24 +00:00
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[root_object_dictionary_gate lock];
|
|
|
|
|
ro = [root_object_dictionary objectAtKey:aPort];
|
|
|
|
|
[root_object_dictionary_gate unlock];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
return ro;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- setRootObject: anObj
|
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[[self class] setRootObject: anObj forInPort: in_port];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- rootObject
|
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return [[self class] rootObjectForInPort: in_port];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
|
|
|
|
/* Accessing ivars */
|
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
- (int) outTimeout
|
|
|
|
|
{
|
|
|
|
|
return out_timeout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (int) inTimeout
|
|
|
|
|
{
|
|
|
|
|
return in_timeout;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- (void) setOutTimeout: (int)to
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
out_timeout = to;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- (void) setInTimeout: (int)to
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
in_timeout = to;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-06 14:05:36 +00:00
|
|
|
|
- (Class) inPortClass
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-06 14:05:36 +00:00
|
|
|
|
return in_port_class;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-06 14:05:36 +00:00
|
|
|
|
- (Class) outPortClass
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-06 14:05:36 +00:00
|
|
|
|
return out_port_class;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setInPortClass: (Class) aPortClass
|
|
|
|
|
{
|
|
|
|
|
in_port_class = aPortClass;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setOutPortClass: (Class) aPortClass
|
|
|
|
|
{
|
|
|
|
|
out_port_class = aPortClass;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- (Class) proxyClass
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
/* we might replace this with a per-Connection proxy class. */
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return default_proxy_class;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- (Class) encodingClass
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return encoding_class;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- (Class) decodingClass
|
|
|
|
|
{
|
|
|
|
|
/* we might replace this with a per-Connection class. */
|
|
|
|
|
return default_decoding_class;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- outPort
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
return out_port;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- inPort
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
return in_port;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- delegate
|
|
|
|
|
{
|
|
|
|
|
return delegate;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- (void) setDelegate: anObj
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
delegate = anObj;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
|
|
|
|
/* Support for cross-connection const-ptr cache. */
|
|
|
|
|
|
|
|
|
|
- (unsigned) _encoderCreateReferenceForConstPtr: (const void*)ptr
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
unsigned xref;
|
1996-03-07 18:08:24 +00:00
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert (is_valid);
|
1996-03-06 14:05:36 +00:00
|
|
|
|
/* This must match the assignment of xref in _decoderCreateRef... */
|
1996-03-01 15:54:57 +00:00
|
|
|
|
xref = NSCountMapTable (outgoing_const_ptr_2_xref) + 1;
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert (! NSMapGet (outgoing_const_ptr_2_xref, (void*)xref));
|
1996-03-01 15:54:57 +00:00
|
|
|
|
NSMapInsert (outgoing_const_ptr_2_xref, ptr, (void*)xref);
|
1996-03-12 19:40:16 +00:00
|
|
|
|
return xref;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- (unsigned) _encoderReferenceForConstPtr: (const void*)ptr
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert (is_valid);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return (unsigned) NSMapGet (outgoing_const_ptr_2_xref, ptr);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- (unsigned) _decoderCreateReferenceForConstPtr: (const void*)ptr
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
unsigned xref;
|
1996-03-07 18:08:24 +00:00
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert (is_valid);
|
1996-03-06 14:05:36 +00:00
|
|
|
|
/* This must match the assignment of xref in _encoderCreateRef... */
|
|
|
|
|
xref = NSCountMapTable (incoming_xref_2_const_ptr) + 1;
|
1996-03-01 15:54:57 +00:00
|
|
|
|
NSMapInsert (incoming_xref_2_const_ptr, (void*)xref, ptr);
|
|
|
|
|
return xref;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
- (const void*) _decoderConstPtrAtReference: (unsigned)xref
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert (is_valid);
|
1996-03-01 15:54:57 +00:00
|
|
|
|
return NSMapGet (incoming_xref_2_const_ptr, (void*)xref);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Prevent trying to encode the connection itself */
|
|
|
|
|
|
1995-04-09 01:53:53 +00:00
|
|
|
|
- (void) encodeWithCoder: anEncoder
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
[self shouldNotImplement:_cmd];
|
|
|
|
|
}
|
|
|
|
|
|
1995-04-09 01:53:53 +00:00
|
|
|
|
+ newWithCoder: aDecoder;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
[self shouldNotImplement:_cmd];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
|
|
|
|
|
/* Shutting down and deallocating. */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-06 14:05:36 +00:00
|
|
|
|
/* We register this method with NotificationDispatcher for when a port dies. */
|
1996-03-07 18:08:24 +00:00
|
|
|
|
- (void) portIsInvalid: notification
|
1996-03-01 15:54:57 +00:00
|
|
|
|
{
|
1996-03-07 18:08:24 +00:00
|
|
|
|
id port = [notification object];
|
|
|
|
|
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert (is_valid);
|
1996-03-07 18:08:24 +00:00
|
|
|
|
if (debug_connection)
|
|
|
|
|
fprintf (stderr, "Received port invalidation notification for "
|
|
|
|
|
"connection 0x%x\n\t%s\n", (unsigned)self,
|
|
|
|
|
[[port description] cStringNoCopy]);
|
|
|
|
|
/* We shouldn't be getting any port invalidation notifications,
|
|
|
|
|
except from our own ports; this is how we registered ourselves
|
|
|
|
|
with the NotificationDispatcher in
|
|
|
|
|
+newForInPort:outPort:ancestorConnection. */
|
1996-03-26 22:34:40 +00:00
|
|
|
|
NSParameterAssert (port == in_port || port == out_port);
|
1996-03-13 02:32:46 +00:00
|
|
|
|
|
|
|
|
|
/* xxx This also needs to be done properly in cases where the
|
|
|
|
|
Connection invalidates itself. */
|
|
|
|
|
/* Remove ourselves from the in_port_2_ancestor, if necessary. */
|
|
|
|
|
{
|
|
|
|
|
id ancestor;
|
|
|
|
|
if ([port isKindOfClass: [InPort class]]
|
|
|
|
|
&& (self == (ancestor = NSMapGet (in_port_2_ancestor, port))))
|
|
|
|
|
NSMapRemove (in_port_2_ancestor, port);
|
|
|
|
|
}
|
1996-03-07 18:08:24 +00:00
|
|
|
|
[self invalidate];
|
|
|
|
|
/* xxx Anything else? */
|
1996-03-01 15:54:57 +00:00
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
/* xxx This needs locks */
|
|
|
|
|
- (void) invalidate
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-07 18:08:24 +00:00
|
|
|
|
if (is_valid)
|
|
|
|
|
{
|
|
|
|
|
is_valid = 0;
|
|
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
fprintf(stderr, "Invalidating connection 0x%x\n\t%s\n\t%s\n",
|
|
|
|
|
(unsigned)self,
|
|
|
|
|
[[in_port description] cStringNoCopy],
|
|
|
|
|
[[out_port description] cStringNoCopy]);
|
1996-03-13 02:32:46 +00:00
|
|
|
|
|
1996-03-07 18:08:24 +00:00
|
|
|
|
[NotificationDispatcher
|
|
|
|
|
postNotificationName: ConnectionBecameInvalidNotification
|
|
|
|
|
object: self];
|
|
|
|
|
/* xxx Anything else? */
|
|
|
|
|
/* xxx Yes, somehow Proxies of connections with invalid ports
|
|
|
|
|
are being asked to encode themselves. */
|
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-03-12 14:43:30 +00:00
|
|
|
|
- (BOOL) isValid
|
|
|
|
|
{
|
|
|
|
|
return is_valid;
|
|
|
|
|
}
|
|
|
|
|
|
1996-03-01 15:54:57 +00:00
|
|
|
|
/* This needs locks */
|
|
|
|
|
- (void) dealloc
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-03-01 15:54:57 +00:00
|
|
|
|
if (debug_connection)
|
|
|
|
|
printf("deallocating 0x%x\n", (unsigned)self);
|
|
|
|
|
[self invalidate];
|
|
|
|
|
[connection_array removeObject: self];
|
|
|
|
|
/* Remove rootObject from root_object_dictionary
|
|
|
|
|
if this is last connection */
|
|
|
|
|
if (![Connection connectionsCountWithInPort:in_port])
|
|
|
|
|
[Connection setRootObject:nil forInPort:in_port];
|
1996-03-06 14:05:36 +00:00
|
|
|
|
[NotificationDispatcher removeObserver: self];
|
1996-03-01 15:54:57 +00:00
|
|
|
|
[in_port release];
|
|
|
|
|
[out_port release];
|
|
|
|
|
|
|
|
|
|
[proxiesHashGate lock];
|
|
|
|
|
NSFreeMapTable (remote_proxies);
|
|
|
|
|
NSFreeMapTable (local_targets);
|
|
|
|
|
NSFreeMapTable (incoming_xref_2_const_ptr);
|
|
|
|
|
NSFreeMapTable (outgoing_const_ptr_2_xref);
|
|
|
|
|
[proxiesHashGate unlock];
|
|
|
|
|
|
|
|
|
|
[super dealloc];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
1996-03-03 00:45:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Notification Strings. */
|
|
|
|
|
|
|
|
|
|
NSString *ConnectionBecameInvalidNotification
|
|
|
|
|
= @"ConnectionBecameInvalidNotification";
|
1996-03-06 14:05:36 +00:00
|
|
|
|
|
|
|
|
|
NSString *ConnectionWasCreatedNotification
|
|
|
|
|
= @"ConnectionWasCreatedNotification";
|
1996-03-18 20:08:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* RunLoop modes */
|
|
|
|
|
NSString *RunLoopConnectionReplyMode
|
|
|
|
|
= @"RunLoopConnectionReplyMode";
|