2001-12-17 14:31:42 +00:00
|
|
|
|
/** Implementation of connection object for remote object messaging
|
2000-07-04 11:05:46 +00:00
|
|
|
|
Copyright (C) 1994, 1995, 1996, 1997, 2000 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
|
|
Created by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
|
|
|
|
Date: July 1994
|
|
|
|
|
Minor rewrite for OPENSTEP by: Richard Frith-Macdonald <rfm@gnu.org>
|
|
|
|
|
Date: August 1997
|
|
|
|
|
Major rewrite for MACOSX by: Richard Frith-Macdonald <rfm@gnu.org>
|
|
|
|
|
Date: 2000
|
|
|
|
|
|
|
|
|
|
This file is part of the GNUstep Base Library.
|
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
2007-09-14 11:36:11 +00:00
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
2000-07-04 11:05:46 +00:00
|
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-08 10:38:33 +00:00
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
2007-09-14 11:36:11 +00:00
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
2000-07-04 11:05:46 +00:00
|
|
|
|
License along with this library; if not, write to the Free
|
2006-06-04 06:42:10 +00:00
|
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
|
Boston, MA 02111 USA.
|
2001-12-18 16:54:15 +00:00
|
|
|
|
|
|
|
|
|
<title>NSConnection class reference</title>
|
|
|
|
|
$Date$ $Revision$
|
2000-07-04 11:05:46 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2007-11-29 20:53:26 +00:00
|
|
|
|
#import "config.h"
|
2009-10-05 16:00:28 +00:00
|
|
|
|
|
2007-12-21 13:46:50 +00:00
|
|
|
|
#ifdef HAVE_ALLOCA_H
|
|
|
|
|
#include <alloca.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2007-11-29 20:53:26 +00:00
|
|
|
|
#import "Foundation/NSEnumerator.h"
|
|
|
|
|
#import "GNUstepBase/preface.h"
|
|
|
|
|
#import "GNUstepBase/GSLock.h"
|
2009-08-15 21:44:21 +00:00
|
|
|
|
#import "Foundation/NSDebug.h"
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2000-07-05 12:23:00 +00:00
|
|
|
|
/*
|
|
|
|
|
* Setup for inline operation of pointer map tables.
|
|
|
|
|
*/
|
2009-10-02 15:14:42 +00:00
|
|
|
|
#define GSI_MAP_KTYPES GSUNION_PTR | GSUNION_OBJ | GSUNION_INT
|
|
|
|
|
#define GSI_MAP_VTYPES GSUNION_PTR | GSUNION_OBJ
|
2002-01-24 17:03:04 +00:00
|
|
|
|
#define GSI_MAP_RETAIN_KEY(M, X)
|
|
|
|
|
#define GSI_MAP_RELEASE_KEY(M, X)
|
|
|
|
|
#define GSI_MAP_RETAIN_VAL(M, X)
|
|
|
|
|
#define GSI_MAP_RELEASE_VAL(M, X)
|
|
|
|
|
#define GSI_MAP_HASH(M, X) ((X).uint ^ ((X).uint >> 3))
|
|
|
|
|
#define GSI_MAP_EQUAL(M, X,Y) ((X).ptr == (Y).ptr)
|
2002-02-13 18:49:32 +00:00
|
|
|
|
#define GSI_MAP_NOCLEAN 1
|
2009-03-09 15:11:51 +00:00
|
|
|
|
#if GS_WITH_GC
|
|
|
|
|
// FIXME ...
|
|
|
|
|
#include <gc_typed.h>
|
|
|
|
|
static GC_descr nodeDesc; // Type descriptor for map node.
|
|
|
|
|
#define GSI_MAP_NODES(M, X) \
|
|
|
|
|
(GSIMapNode)GC_calloc_explicitly_typed(X, sizeof(GSIMapNode_t), nodeDesc)
|
|
|
|
|
#endif
|
|
|
|
|
|
2000-07-05 12:23:00 +00:00
|
|
|
|
|
2003-07-31 23:49:32 +00:00
|
|
|
|
#include "GNUstepBase/GSIMap.h"
|
2000-07-05 12:23:00 +00:00
|
|
|
|
|
|
|
|
|
#define _IN_CONNECTION_M
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "Foundation/NSConnection.h"
|
2000-07-05 12:23:00 +00:00
|
|
|
|
#undef _IN_CONNECTION_M
|
|
|
|
|
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "Foundation/NSPortCoder.h"
|
2003-07-31 23:49:32 +00:00
|
|
|
|
#include "GNUstepBase/DistributedObjects.h"
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "Foundation/NSHashTable.h"
|
|
|
|
|
#include "Foundation/NSMapTable.h"
|
|
|
|
|
#include "Foundation/NSData.h"
|
|
|
|
|
#include "Foundation/NSRunLoop.h"
|
|
|
|
|
#include "Foundation/NSArray.h"
|
|
|
|
|
#include "Foundation/NSDictionary.h"
|
|
|
|
|
#include "Foundation/NSValue.h"
|
|
|
|
|
#include "Foundation/NSString.h"
|
|
|
|
|
#include "Foundation/NSDate.h"
|
|
|
|
|
#include "Foundation/NSException.h"
|
|
|
|
|
#include "Foundation/NSLock.h"
|
|
|
|
|
#include "Foundation/NSThread.h"
|
|
|
|
|
#include "Foundation/NSPort.h"
|
|
|
|
|
#include "Foundation/NSPortMessage.h"
|
|
|
|
|
#include "Foundation/NSPortNameServer.h"
|
|
|
|
|
#include "Foundation/NSNotification.h"
|
|
|
|
|
#include "Foundation/NSDebug.h"
|
2003-07-31 23:49:32 +00:00
|
|
|
|
#include "GSInvocation.h"
|
2006-03-08 11:28:59 +00:00
|
|
|
|
#include "GSPortPrivate.h"
|
2008-03-17 15:23:11 +00:00
|
|
|
|
#include "GSPrivate.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline NSRunLoop *
|
|
|
|
|
GSRunLoopForThread(NSThread *aThread)
|
|
|
|
|
{
|
|
|
|
|
GSRunLoopThreadInfo *info = GSRunLoopInfoForThread(aThread);
|
2008-06-18 13:11:11 +00:00
|
|
|
|
|
2008-03-17 15:23:11 +00:00
|
|
|
|
if (info == nil || info->loop == nil)
|
|
|
|
|
{
|
2008-06-18 13:11:11 +00:00
|
|
|
|
if (aThread == nil || aThread == GSCurrentThread())
|
2008-03-17 15:23:11 +00:00
|
|
|
|
{
|
|
|
|
|
return [NSRunLoop currentRunLoop];
|
|
|
|
|
}
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
return info->loop;
|
|
|
|
|
}
|
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2006-03-08 11:28:59 +00:00
|
|
|
|
@interface NSPortCoder (Private)
|
|
|
|
|
- (NSMutableArray*) _components;
|
|
|
|
|
@end
|
|
|
|
|
@interface NSPortMessage (Private)
|
|
|
|
|
- (NSMutableArray*) _components;
|
|
|
|
|
@end
|
|
|
|
|
|
2009-01-12 18:36:37 +00:00
|
|
|
|
@interface NSConnection (GNUstepExtensions)
|
|
|
|
|
- (void) finalize;
|
2006-03-08 11:28:59 +00:00
|
|
|
|
- (retval_t) forwardForProxy: (NSDistantObject*)object
|
|
|
|
|
selector: (SEL)sel
|
|
|
|
|
argFrame: (arglist_t)argframe;
|
|
|
|
|
- (void) forwardInvocation: (NSInvocation *)inv
|
|
|
|
|
forProxy: (NSDistantObject*)object;
|
|
|
|
|
- (const char *) typeForSelector: (SEL)sel remoteTarget: (unsigned)target;
|
|
|
|
|
@end
|
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
#define F_LOCK(X) {NSDebugFLLog(@"GSConnection",@"Lock %@",X);[X lock];}
|
|
|
|
|
#define F_UNLOCK(X) {NSDebugFLLog(@"GSConnection",@"Unlock %@",X);[X unlock];}
|
|
|
|
|
#define M_LOCK(X) {NSDebugMLLog(@"GSConnection",@"Lock %@",X);[X lock];}
|
|
|
|
|
#define M_UNLOCK(X) {NSDebugMLLog(@"GSConnection",@"Unlock %@",X);[X unlock];}
|
|
|
|
|
|
2008-03-17 05:45:55 +00:00
|
|
|
|
NSString * const NSDestinationInvalidException =
|
|
|
|
|
@"NSDestinationInvalidException";
|
2002-05-08 05:43:15 +00:00
|
|
|
|
NSString * const NSFailedAuthenticationException =
|
|
|
|
|
@"NSFailedAuthenticationExceptions";
|
2003-09-15 13:54:06 +00:00
|
|
|
|
NSString * const NSObjectInaccessibleException =
|
|
|
|
|
@"NSObjectInaccessibleException";
|
2008-03-16 22:43:43 +00:00
|
|
|
|
NSString * const NSObjectNotAvailableException =
|
|
|
|
|
@"NSObjectNotAvailableException";
|
2002-05-08 05:43:15 +00:00
|
|
|
|
|
2000-07-05 16:56:06 +00:00
|
|
|
|
/*
|
|
|
|
|
* Set up a type to permit us to have direct access into an NSDistantObject
|
|
|
|
|
*/
|
|
|
|
|
typedef struct {
|
|
|
|
|
@defs(NSDistantObject)
|
|
|
|
|
} ProxyStruct;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Cache various class pointers.
|
|
|
|
|
*/
|
2000-07-05 12:23:00 +00:00
|
|
|
|
static id dummyObject;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
static Class connectionClass;
|
|
|
|
|
static Class dateClass;
|
|
|
|
|
static Class distantObjectClass;
|
2001-04-11 12:30:32 +00:00
|
|
|
|
static Class sendCoderClass;
|
|
|
|
|
static Class recvCoderClass;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
static Class runLoopClass;
|
|
|
|
|
|
|
|
|
|
static NSString*
|
|
|
|
|
stringFromMsgType(int type)
|
|
|
|
|
{
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case METHOD_REQUEST:
|
|
|
|
|
return @"method request";
|
|
|
|
|
case METHOD_REPLY:
|
|
|
|
|
return @"method reply";
|
|
|
|
|
case ROOTPROXY_REQUEST:
|
|
|
|
|
return @"root proxy request";
|
|
|
|
|
case ROOTPROXY_REPLY:
|
|
|
|
|
return @"root proxy reply";
|
|
|
|
|
case CONNECTION_SHUTDOWN:
|
|
|
|
|
return @"connection shutdown";
|
|
|
|
|
case METHODTYPE_REQUEST:
|
|
|
|
|
return @"methodtype request";
|
|
|
|
|
case METHODTYPE_REPLY:
|
|
|
|
|
return @"methodtype reply";
|
|
|
|
|
case PROXY_RELEASE:
|
|
|
|
|
return @"proxy release";
|
|
|
|
|
case PROXY_RETAIN:
|
|
|
|
|
return @"proxy retain";
|
|
|
|
|
case RETAIN_REPLY:
|
|
|
|
|
return @"retain replay";
|
|
|
|
|
default:
|
|
|
|
|
return @"unknown operation type!";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2003-10-21 17:05:36 +00:00
|
|
|
|
* CachedLocalObject is a trivial class to keep track of local
|
|
|
|
|
* proxies which have been removed from their connections and
|
|
|
|
|
* need to persist a while in case another process needs them.
|
2000-07-04 11:05:46 +00:00
|
|
|
|
*/
|
|
|
|
|
@interface CachedLocalObject : NSObject
|
|
|
|
|
{
|
2003-10-21 17:05:36 +00:00
|
|
|
|
NSDistantObject *obj;
|
|
|
|
|
int time;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2000-07-05 12:23:00 +00:00
|
|
|
|
- (BOOL) countdown;
|
2003-10-21 17:05:36 +00:00
|
|
|
|
- (NSDistantObject*) obj;
|
|
|
|
|
+ (id) newWithObject: (NSDistantObject*)o time: (int)t;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation CachedLocalObject
|
|
|
|
|
|
2003-10-21 17:05:36 +00:00
|
|
|
|
+ (id) newWithObject: (NSDistantObject*)o time: (int)t
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
|
|
|
|
CachedLocalObject *item;
|
|
|
|
|
|
|
|
|
|
item = (CachedLocalObject*)NSAllocateObject(self, 0, NSDefaultMallocZone());
|
|
|
|
|
item->obj = RETAIN(o);
|
|
|
|
|
item->time = t;
|
|
|
|
|
return item;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
RELEASE(obj);
|
2009-10-10 08:16:17 +00:00
|
|
|
|
[super dealloc];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) countdown
|
|
|
|
|
{
|
|
|
|
|
if (time-- > 0)
|
|
|
|
|
return YES;
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
2003-10-21 17:05:36 +00:00
|
|
|
|
- (NSDistantObject*) obj
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-11-23 09:42:18 +00:00
|
|
|
|
/** <ignore> */
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
#define GSInternal NSConnectionInternal
|
|
|
|
|
#include "GSInternal.h"
|
|
|
|
|
GS_BEGIN_INTERNAL(NSConnection)
|
|
|
|
|
BOOL _isValid;
|
|
|
|
|
BOOL _independentQueueing;
|
|
|
|
|
BOOL _authenticateIn;
|
|
|
|
|
BOOL _authenticateOut;
|
|
|
|
|
BOOL _multipleThreads;
|
|
|
|
|
BOOL _shuttingDown;
|
|
|
|
|
BOOL _useKeepalive;
|
|
|
|
|
BOOL _keepaliveWait;
|
|
|
|
|
NSPort *_receivePort;
|
|
|
|
|
NSPort *_sendPort;
|
|
|
|
|
unsigned _requestDepth;
|
|
|
|
|
unsigned _messageCount;
|
|
|
|
|
unsigned _reqOutCount;
|
|
|
|
|
unsigned _reqInCount;
|
|
|
|
|
unsigned _repOutCount;
|
|
|
|
|
unsigned _repInCount;
|
|
|
|
|
GSIMapTable _localObjects;
|
|
|
|
|
GSIMapTable _localTargets;
|
|
|
|
|
GSIMapTable _remoteProxies;
|
|
|
|
|
GSIMapTable _replyMap;
|
|
|
|
|
NSTimeInterval _replyTimeout;
|
|
|
|
|
NSTimeInterval _requestTimeout;
|
|
|
|
|
NSMutableArray *_requestModes;
|
|
|
|
|
NSMutableArray *_runLoops;
|
|
|
|
|
NSMutableArray *_requestQueue;
|
|
|
|
|
id _delegate;
|
|
|
|
|
NSRecursiveLock *_refGate;
|
|
|
|
|
NSMutableArray *_cachedDecoders;
|
|
|
|
|
NSMutableArray *_cachedEncoders;
|
|
|
|
|
NSString *_remoteName;
|
|
|
|
|
NSString *_registeredName;
|
|
|
|
|
NSPortNameServer *_nameServer;
|
|
|
|
|
int _lastKeepalive;
|
|
|
|
|
GS_END_INTERNAL(NSConnection)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define IisValid (internal->_isValid)
|
|
|
|
|
#define IindependentQueueing (internal->_independentQueueing)
|
|
|
|
|
#define IauthenticateIn (internal->_authenticateIn)
|
|
|
|
|
#define IauthenticateOut (internal->_authenticateOut)
|
|
|
|
|
#define ImultipleThreads (internal->_multipleThreads)
|
|
|
|
|
#define IshuttingDown (internal->_shuttingDown)
|
|
|
|
|
#define IuseKeepalive (internal->_useKeepalive)
|
|
|
|
|
#define IkeepaliveWait (internal->_keepaliveWait)
|
|
|
|
|
#define IreceivePort (internal->_receivePort)
|
|
|
|
|
#define IsendPort (internal->_sendPort)
|
|
|
|
|
#define IrequestDepth (internal->_requestDepth)
|
|
|
|
|
#define ImessageCount (internal->_messageCount)
|
|
|
|
|
#define IreqOutCount (internal->_reqOutCount)
|
|
|
|
|
#define IreqInCount (internal->_reqInCount)
|
|
|
|
|
#define IrepOutCount (internal->_repOutCount)
|
|
|
|
|
#define IrepInCount (internal->_repInCount)
|
|
|
|
|
#define IlocalObjects (internal->_localObjects)
|
|
|
|
|
#define IlocalTargets (internal->_localTargets)
|
|
|
|
|
#define IremoteProxies (internal->_remoteProxies)
|
|
|
|
|
#define IreplyMap (internal->_replyMap)
|
|
|
|
|
#define IreplyTimeout (internal->_replyTimeout)
|
|
|
|
|
#define IrequestTimeout (internal->_requestTimeout)
|
|
|
|
|
#define IrequestModes (internal->_requestModes)
|
|
|
|
|
#define IrunLoops (internal->_runLoops)
|
|
|
|
|
#define IrequestQueue (internal->_requestQueue)
|
|
|
|
|
#define Idelegate (internal->_delegate)
|
|
|
|
|
#define IrefGate (internal->_refGate)
|
|
|
|
|
#define IcachedDecoders (internal->_cachedDecoders)
|
|
|
|
|
#define IcachedEncoders (internal->_cachedEncoders)
|
|
|
|
|
#define IremoteName (internal->_remoteName)
|
|
|
|
|
#define IregisteredName (internal->_registeredName)
|
|
|
|
|
#define InameServer (internal->_nameServer)
|
|
|
|
|
#define IlastKeepalive (internal->_lastKeepalive)
|
|
|
|
|
|
2009-11-23 09:42:18 +00:00
|
|
|
|
/** </ignore> */
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
@interface NSConnection(Private)
|
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (void) handlePortMessage: (NSPortMessage*)msg;
|
|
|
|
|
- (void) _runInNewThread;
|
|
|
|
|
+ (void) setDebug: (int)val;
|
2008-11-21 08:02:41 +00:00
|
|
|
|
- (void) _enableKeepalive;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2000-07-05 16:56:06 +00:00
|
|
|
|
- (void) addLocalObject: (NSDistantObject*)anObj;
|
2003-10-27 13:41:01 +00:00
|
|
|
|
- (void) removeLocalObject: (NSDistantObject*)anObj;
|
2000-07-05 16:56:06 +00:00
|
|
|
|
|
2001-09-19 21:31:18 +00:00
|
|
|
|
- (void) _doneInReply: (NSPortCoder*)c;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (void) _doneInRmc: (NSPortCoder*)c;
|
2001-04-11 12:30:32 +00:00
|
|
|
|
- (void) _failInRmc: (NSPortCoder*)c;
|
|
|
|
|
- (void) _failOutRmc: (NSPortCoder*)c;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (NSPortCoder*) _getReplyRmc: (int)sn;
|
|
|
|
|
- (NSPortCoder*) _makeInRmc: (NSMutableArray*)components;
|
2000-07-05 12:23:00 +00:00
|
|
|
|
- (NSPortCoder*) _makeOutRmc: (int)sequence generate: (int*)sno reply: (BOOL)f;
|
2003-09-15 13:54:06 +00:00
|
|
|
|
- (void) _portIsInvalid: (NSNotification*)notification;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (void) _sendOutRmc: (NSPortCoder*)c type: (int)msgid;
|
|
|
|
|
|
|
|
|
|
- (void) _service_forwardForProxy: (NSPortCoder*)rmc;
|
|
|
|
|
- (void) _service_release: (NSPortCoder*)rmc;
|
|
|
|
|
- (void) _service_retain: (NSPortCoder*)rmc;
|
|
|
|
|
- (void) _service_rootObject: (NSPortCoder*)rmc;
|
|
|
|
|
- (void) _service_shutdown: (NSPortCoder*)rmc;
|
|
|
|
|
- (void) _service_typeForSelector: (NSPortCoder*)rmc;
|
2005-11-21 13:15:39 +00:00
|
|
|
|
- (void) _shutdown;
|
2004-11-25 17:00:45 +00:00
|
|
|
|
+ (void) _threadWillExit: (NSNotification*)notification;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* class defaults */
|
2002-06-15 10:07:06 +00:00
|
|
|
|
static NSTimer *timer = nil;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2001-06-08 14:04:20 +00:00
|
|
|
|
static BOOL cacheCoders = NO;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
static int debug_connection = 0;
|
|
|
|
|
|
|
|
|
|
static NSHashTable *connection_table;
|
2000-08-07 22:00:31 +00:00
|
|
|
|
static NSLock *connection_table_gate = nil;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Locate an existing connection with the specified send and receive ports.
|
|
|
|
|
* nil ports act as wildcards and return the first match.
|
|
|
|
|
*/
|
|
|
|
|
static NSConnection*
|
|
|
|
|
existingConnection(NSPort *receivePort, NSPort *sendPort)
|
|
|
|
|
{
|
|
|
|
|
NSHashEnumerator enumerator;
|
|
|
|
|
NSConnection *c;
|
|
|
|
|
|
|
|
|
|
F_LOCK(connection_table_gate);
|
|
|
|
|
enumerator = NSEnumerateHashTable(connection_table);
|
|
|
|
|
while ((c = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil)
|
|
|
|
|
{
|
|
|
|
|
if ((sendPort == nil || [sendPort isEqual: [c sendPort]])
|
|
|
|
|
&& (receivePort == nil || [receivePort isEqual: [c receivePort]]))
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* We don't want this connection to be destroyed by another thread
|
|
|
|
|
* between now and when it's returned from this function and used!
|
|
|
|
|
*/
|
2009-01-12 12:48:46 +00:00
|
|
|
|
IF_NO_GC([[c retain] autorelease];)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-05-28 05:23:36 +00:00
|
|
|
|
NSEndHashTableEnumeration(&enumerator);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
F_UNLOCK(connection_table_gate);
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NSMapTable *root_object_map;
|
2000-08-07 22:00:31 +00:00
|
|
|
|
static NSLock *root_object_map_gate = nil;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
static id
|
|
|
|
|
rootObjectForInPort(NSPort *aPort)
|
|
|
|
|
{
|
|
|
|
|
id rootObject;
|
|
|
|
|
|
|
|
|
|
F_LOCK(root_object_map_gate);
|
2006-01-11 09:32:13 +00:00
|
|
|
|
rootObject = (id)NSMapGet(root_object_map, (void*)(uintptr_t)aPort);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
F_UNLOCK(root_object_map_gate);
|
|
|
|
|
return rootObject;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Pass nil to remove any reference keyed by aPort. */
|
|
|
|
|
static void
|
|
|
|
|
setRootObjectForInPort(id anObj, NSPort *aPort)
|
|
|
|
|
{
|
|
|
|
|
id oldRootObject;
|
|
|
|
|
|
|
|
|
|
F_LOCK(root_object_map_gate);
|
2006-01-11 09:32:13 +00:00
|
|
|
|
oldRootObject = (id)NSMapGet(root_object_map, (void*)(uintptr_t)aPort);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
if (oldRootObject != anObj)
|
|
|
|
|
{
|
|
|
|
|
if (anObj != nil)
|
|
|
|
|
{
|
2006-01-11 09:32:13 +00:00
|
|
|
|
NSMapInsert(root_object_map, (void*)(uintptr_t)aPort,
|
|
|
|
|
(void*)(uintptr_t)anObj);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
else /* anObj == nil && oldRootObject != nil */
|
|
|
|
|
{
|
2006-01-11 09:32:13 +00:00
|
|
|
|
NSMapRemove(root_object_map, (void*)(uintptr_t)aPort);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
F_UNLOCK(root_object_map_gate);
|
|
|
|
|
}
|
|
|
|
|
|
2000-07-05 16:56:06 +00:00
|
|
|
|
static NSMapTable *targetToCached = NULL;
|
2003-10-21 17:05:36 +00:00
|
|
|
|
static NSLock *cached_proxies_gate = nil;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* NSConnection objects are used to manage communications between
|
|
|
|
|
* objects in different processes, in different machines, or in
|
|
|
|
|
* different threads.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
@implementation NSConnection
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns an array containing all the NSConnection objects known to
|
|
|
|
|
* the system. These connections will be valid at the time that the
|
|
|
|
|
* array was created, but may be invalidated by other threads
|
|
|
|
|
* before you get to examine the array.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
+ (NSArray*) allConnections
|
|
|
|
|
{
|
2000-07-04 19:53:39 +00:00
|
|
|
|
NSArray *a;
|
|
|
|
|
|
|
|
|
|
M_LOCK(connection_table_gate);
|
|
|
|
|
a = NSAllHashTableObjects(connection_table);
|
|
|
|
|
M_UNLOCK(connection_table_gate);
|
|
|
|
|
return a;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
2005-11-21 09:59:42 +00:00
|
|
|
|
* Returns a connection initialised using -initWithReceivePort:sendPort:<br />
|
|
|
|
|
* Both ports must be of the same type.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
+ (NSConnection*) connectionWithReceivePort: (NSPort*)r
|
|
|
|
|
sendPort: (NSPort*)s
|
|
|
|
|
{
|
|
|
|
|
NSConnection *c = existingConnection(r, s);
|
|
|
|
|
|
|
|
|
|
if (c == nil)
|
|
|
|
|
{
|
|
|
|
|
c = [self allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
c = [c initWithReceivePort: r sendPort: s];
|
2009-01-12 12:48:46 +00:00
|
|
|
|
IF_NO_GC([c autorelease];)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>Returns an NSConnection object whose send port is that of the
|
|
|
|
|
* NSConnection registered under the name n on the host h
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>This method calls +connectionWithRegisteredName:host:usingNameServer:
|
|
|
|
|
* using the default system name server.
|
|
|
|
|
* </p>
|
2005-11-21 09:59:42 +00:00
|
|
|
|
* <p>Use [NSSocketPortNameServer] for connections to remote hosts.
|
|
|
|
|
* </p>
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
+ (NSConnection*) connectionWithRegisteredName: (NSString*)n
|
|
|
|
|
host: (NSString*)h
|
|
|
|
|
{
|
|
|
|
|
NSPortNameServer *s;
|
|
|
|
|
|
|
|
|
|
s = [NSPortNameServer systemDefaultPortNameServer];
|
|
|
|
|
return [self connectionWithRegisteredName: n
|
|
|
|
|
host: h
|
|
|
|
|
usingNameServer: s];
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>
|
|
|
|
|
* Returns an NSConnection object whose send port is that of the
|
|
|
|
|
* NSConnection registered under <em>name</em> on <em>host</em>.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>
|
|
|
|
|
* The nameserver <em>server</em> is used to look up the send
|
2005-11-21 09:59:42 +00:00
|
|
|
|
* port to be used for the connection.<br />
|
|
|
|
|
* Use [NSSocketPortNameServer+sharedInstance]
|
|
|
|
|
* for connections to remote hosts.
|
|
|
|
|
* </p>
|
2002-03-21 17:03:17 +00:00
|
|
|
|
* <p>
|
|
|
|
|
* If <em>host</em> is <code>nil</code> or an empty string,
|
2009-12-01 07:47:29 +00:00
|
|
|
|
* the host is taken to be the local machine.<br />
|
2002-03-21 17:03:17 +00:00
|
|
|
|
* If it is an asterisk ('*') then the nameserver checks all
|
|
|
|
|
* hosts on the local subnet (unless the nameserver is one
|
2009-12-01 07:47:29 +00:00
|
|
|
|
* that only manages local ports).<br />
|
2002-03-21 17:03:17 +00:00
|
|
|
|
* In the GNUstep implementation, the local host is searched before
|
2009-12-01 07:49:38 +00:00
|
|
|
|
* any other hosts.<br />
|
|
|
|
|
* NB. if the nameserver does not support connections to remote hosts
|
|
|
|
|
* (the default situation) the host argeument should be omitted.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
* </p>
|
|
|
|
|
* <p>
|
|
|
|
|
* If no NSConnection can be found for <em>name</em> and
|
|
|
|
|
* <em>host</em>host, the method returns <code>nil</code>.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>
|
|
|
|
|
* The returned object has the default NSConnection of the
|
|
|
|
|
* current thread as its parent (it has the same receive port
|
|
|
|
|
* as the default connection).
|
|
|
|
|
* </p>
|
2000-09-12 05:16:01 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
+ (NSConnection*) connectionWithRegisteredName: (NSString*)n
|
|
|
|
|
host: (NSString*)h
|
|
|
|
|
usingNameServer: (NSPortNameServer*)s
|
|
|
|
|
{
|
|
|
|
|
NSConnection *con = nil;
|
|
|
|
|
|
|
|
|
|
if (s != nil)
|
|
|
|
|
{
|
|
|
|
|
NSPort *sendPort = [s portForName: n onHost: h];
|
|
|
|
|
|
|
|
|
|
if (sendPort != nil)
|
|
|
|
|
{
|
2000-07-04 19:53:39 +00:00
|
|
|
|
NSPort *recvPort;
|
|
|
|
|
|
|
|
|
|
recvPort = [[self defaultConnection] receivePort];
|
2000-09-12 05:16:01 +00:00
|
|
|
|
if (recvPort == sendPort)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* If the receive and send port are the same, the server
|
|
|
|
|
* must be in this process - so we need to create a new
|
|
|
|
|
* connection to talk to it.
|
|
|
|
|
*/
|
|
|
|
|
recvPort = [NSPort port];
|
|
|
|
|
}
|
2003-07-15 04:47:06 +00:00
|
|
|
|
else if (![recvPort isMemberOfClass: [sendPort class]])
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
We can only use the port of the default connection for
|
|
|
|
|
connections using the same port class. For other port classes,
|
|
|
|
|
we must use a receiving port of the same class as the sending
|
|
|
|
|
port, so we allocate one here.
|
|
|
|
|
*/
|
|
|
|
|
recvPort = [[sendPort class] port];
|
|
|
|
|
}
|
|
|
|
|
|
2000-07-04 19:53:39 +00:00
|
|
|
|
con = existingConnection(recvPort, sendPort);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
if (con == nil)
|
|
|
|
|
{
|
|
|
|
|
con = [self connectionWithReceivePort: recvPort
|
|
|
|
|
sendPort: sendPort];
|
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
ASSIGNCOPY(GSIVar(con, _remoteName), n);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return con;
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
2004-08-24 08:08:14 +00:00
|
|
|
|
* Return the current conversation ... not implemented in GNUstep
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
+ (id) currentConversation
|
|
|
|
|
{
|
2004-08-24 08:08:14 +00:00
|
|
|
|
return nil;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the default connection for a thread.<br />
|
|
|
|
|
* Creates a new instance if necessary.<br />
|
|
|
|
|
* The default connection has a single NSPort object used for
|
|
|
|
|
* both sending and receiving - this it can't be used to
|
|
|
|
|
* connect to a remote process, but can be used to vend objects.<br />
|
|
|
|
|
* Possible problem - if the connection is invalidated, it won't be
|
|
|
|
|
* cleaned up until this thread calls this method again. The connection
|
|
|
|
|
* and it's ports could hang around for a very long time.
|
2000-07-04 11:05:46 +00:00
|
|
|
|
*/
|
|
|
|
|
+ (NSConnection*) defaultConnection
|
|
|
|
|
{
|
|
|
|
|
static NSString *tkey = @"NSConnectionThreadKey";
|
|
|
|
|
NSConnection *c;
|
|
|
|
|
NSMutableDictionary *d;
|
|
|
|
|
|
|
|
|
|
d = GSCurrentThreadDictionary();
|
|
|
|
|
c = (NSConnection*)[d objectForKey: tkey];
|
|
|
|
|
if (c != nil && [c isValid] == NO)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* If the default connection for this thread has been invalidated -
|
|
|
|
|
* release it and create a new one.
|
|
|
|
|
*/
|
|
|
|
|
[d removeObjectForKey: tkey];
|
|
|
|
|
c = nil;
|
|
|
|
|
}
|
|
|
|
|
if (c == nil)
|
|
|
|
|
{
|
|
|
|
|
NSPort *port;
|
|
|
|
|
|
|
|
|
|
c = [self alloc];
|
|
|
|
|
port = [NSPort port];
|
|
|
|
|
c = [c initWithReceivePort: port sendPort: nil];
|
2000-07-08 07:14:08 +00:00
|
|
|
|
if (c != nil)
|
|
|
|
|
{
|
|
|
|
|
[d setObject: c forKey: tkey];
|
|
|
|
|
RELEASE(c);
|
|
|
|
|
}
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
2008-10-17 09:51:23 +00:00
|
|
|
|
if (connectionClass == nil)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2004-11-25 17:00:45 +00:00
|
|
|
|
NSNotificationCenter *nc;
|
|
|
|
|
|
2009-03-08 14:34:16 +00:00
|
|
|
|
GSMakeWeakPointer(self, "delegate");
|
2009-03-09 15:11:51 +00:00
|
|
|
|
|
|
|
|
|
#if GS_WITH_GC
|
|
|
|
|
/* We create a typed memory descriptor for map nodes.
|
|
|
|
|
* FIXME
|
|
|
|
|
*/
|
|
|
|
|
GC_word w[GC_BITMAP_SIZE(GSIMapNode_t)] = {0};
|
|
|
|
|
GC_set_bit(w, GC_WORD_OFFSET(GSIMapNode_t, key));
|
|
|
|
|
GC_set_bit(w, GC_WORD_OFFSET(GSIMapNode_t, value));
|
|
|
|
|
nodeDesc = GC_make_descriptor(w, GC_WORD_LEN(GSIMapNode_t));
|
|
|
|
|
#endif
|
2000-07-04 11:05:46 +00:00
|
|
|
|
connectionClass = self;
|
|
|
|
|
dateClass = [NSDate class];
|
|
|
|
|
distantObjectClass = [NSDistantObject class];
|
2001-04-11 12:30:32 +00:00
|
|
|
|
sendCoderClass = [NSPortCoder class];
|
|
|
|
|
recvCoderClass = [NSPortCoder class];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
runLoopClass = [NSRunLoop class];
|
|
|
|
|
|
2000-07-05 12:23:00 +00:00
|
|
|
|
dummyObject = [NSObject new];
|
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
|
connection_table =
|
2000-07-04 11:05:46 +00:00
|
|
|
|
NSCreateHashTable(NSNonRetainedObjectHashCallBacks, 0);
|
2000-07-05 16:56:06 +00:00
|
|
|
|
|
|
|
|
|
targetToCached =
|
2000-07-04 11:05:46 +00:00
|
|
|
|
NSCreateMapTable(NSIntMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
2000-08-07 22:00:31 +00:00
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
root_object_map =
|
|
|
|
|
NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
2004-02-08 09:23:09 +00:00
|
|
|
|
|
|
|
|
|
if (connection_table_gate == nil)
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
2006-09-06 21:06:38 +00:00
|
|
|
|
connection_table_gate = [GSLazyRecursiveLock new];
|
2000-08-07 22:00:31 +00:00
|
|
|
|
}
|
2004-02-08 09:23:09 +00:00
|
|
|
|
if (cached_proxies_gate == nil)
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
2004-02-08 09:23:09 +00:00
|
|
|
|
cached_proxies_gate = [GSLazyLock new];
|
|
|
|
|
}
|
|
|
|
|
if (root_object_map_gate == nil)
|
|
|
|
|
{
|
|
|
|
|
root_object_map_gate = [GSLazyLock new];
|
2000-08-07 22:00:31 +00:00
|
|
|
|
}
|
2004-11-25 17:00:45 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* When any thread exits, we must check to see if we are using its
|
|
|
|
|
* runloop, and remove ourselves from it if necessary.
|
|
|
|
|
*/
|
|
|
|
|
nc = [NSNotificationCenter defaultCenter];
|
|
|
|
|
[nc addObserver: self
|
|
|
|
|
selector: @selector(_threadWillExit:)
|
|
|
|
|
name: NSThreadWillExitNotification
|
|
|
|
|
object: nil];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Undocumented feature for compatibility with OPENSTEP/MacOS-X
|
|
|
|
|
* +new returns the default connection.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
+ (id) new
|
|
|
|
|
{
|
|
|
|
|
return RETAIN([self defaultConnection]);
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* This method calls
|
|
|
|
|
* +rootProxyForConnectionWithRegisteredName:host:usingNameServer:
|
|
|
|
|
* to return a proxy for a root object on the remote connection with
|
|
|
|
|
* the send port registered under name n on host h.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
+ (NSDistantObject*) rootProxyForConnectionWithRegisteredName: (NSString*)n
|
|
|
|
|
host: (NSString*)h
|
|
|
|
|
{
|
2008-02-18 07:23:47 +00:00
|
|
|
|
CREATE_AUTORELEASE_POOL(arp);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
NSConnection *connection;
|
|
|
|
|
NSDistantObject *proxy = nil;
|
|
|
|
|
|
|
|
|
|
connection = [self connectionWithRegisteredName: n host: h];
|
|
|
|
|
if (connection != nil)
|
|
|
|
|
{
|
2008-02-18 07:23:47 +00:00
|
|
|
|
proxy = RETAIN([connection rootProxy]);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2008-02-18 07:23:47 +00:00
|
|
|
|
RELEASE(arp);
|
|
|
|
|
return AUTORELEASE(proxy);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* This method calls
|
|
|
|
|
* +connectionWithRegisteredName:host:usingNameServer:
|
|
|
|
|
* to get a connection, then sends it a -rootProxy message to get
|
|
|
|
|
* a proxy for the root object being vended by the remote connection.
|
|
|
|
|
* Returns the proxy or nil if it couldn't find a connection or if
|
2005-11-21 09:59:42 +00:00
|
|
|
|
* the root object for the connection has not been set.<br />
|
|
|
|
|
* Use [NSSocketPortNameServer+sharedInstance]
|
|
|
|
|
* for connections to remote hosts.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
+ (NSDistantObject*) rootProxyForConnectionWithRegisteredName: (NSString*)n
|
|
|
|
|
host: (NSString*)h usingNameServer: (NSPortNameServer*)s
|
|
|
|
|
{
|
2008-02-18 07:23:47 +00:00
|
|
|
|
CREATE_AUTORELEASE_POOL(arp);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
NSConnection *connection;
|
|
|
|
|
NSDistantObject *proxy = nil;
|
|
|
|
|
|
|
|
|
|
connection = [self connectionWithRegisteredName: n
|
|
|
|
|
host: h
|
|
|
|
|
usingNameServer: s];
|
|
|
|
|
if (connection != nil)
|
|
|
|
|
{
|
2008-02-18 07:23:47 +00:00
|
|
|
|
proxy = RETAIN([connection rootProxy]);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2008-02-18 07:23:47 +00:00
|
|
|
|
RELEASE(arp);
|
|
|
|
|
return AUTORELEASE(proxy);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-06-06 13:57:06 +00:00
|
|
|
|
+ (id) serviceConnectionWithName: (NSString *)name
|
|
|
|
|
rootObject: (id)root
|
|
|
|
|
{
|
|
|
|
|
return [self serviceConnectionWithName: name
|
|
|
|
|
rootObject: root
|
|
|
|
|
usingNameServer: [NSPortNameServer systemDefaultPortNameServer]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (id) serviceConnectionWithName: (NSString *)name
|
|
|
|
|
rootObject: (id)root
|
|
|
|
|
usingNameServer: (NSPortNameServer *)server
|
|
|
|
|
{
|
|
|
|
|
NSConnection *c;
|
|
|
|
|
NSPort *p;
|
|
|
|
|
|
|
|
|
|
if ([server isKindOfClass: [NSMessagePortNameServer class]] == YES)
|
|
|
|
|
{
|
|
|
|
|
p = [NSMessagePort port];
|
|
|
|
|
}
|
|
|
|
|
else if ([server isKindOfClass: [NSSocketPortNameServer class]] == YES)
|
|
|
|
|
{
|
|
|
|
|
p = [NSSocketPort port];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
p = nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c = [[NSConnection alloc] initWithReceivePort: p sendPort: nil];
|
2009-09-14 20:33:12 +00:00
|
|
|
|
[c setRootObject: root];
|
2008-06-06 13:57:06 +00:00
|
|
|
|
if ([c registerName: name withNameServer: server] == NO)
|
|
|
|
|
{
|
|
|
|
|
DESTROY(c);
|
|
|
|
|
}
|
|
|
|
|
return AUTORELEASE(c);
|
|
|
|
|
}
|
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
+ (void) _timeout: (NSTimer*)t
|
|
|
|
|
{
|
|
|
|
|
NSArray *cached_locals;
|
|
|
|
|
int i;
|
|
|
|
|
|
2003-10-21 17:05:36 +00:00
|
|
|
|
M_LOCK(cached_proxies_gate);
|
2000-07-05 16:56:06 +00:00
|
|
|
|
cached_locals = NSAllMapTableValues(targetToCached);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
for (i = [cached_locals count]; i > 0; i--)
|
|
|
|
|
{
|
|
|
|
|
CachedLocalObject *item = [cached_locals objectAtIndex: i-1];
|
|
|
|
|
|
|
|
|
|
if ([item countdown] == NO)
|
|
|
|
|
{
|
2003-10-21 17:05:36 +00:00
|
|
|
|
NSDistantObject *obj = [item obj];
|
2006-01-10 10:29:11 +00:00
|
|
|
|
|
|
|
|
|
NSMapRemove(targetToCached,
|
|
|
|
|
(void*)(uintptr_t)((ProxyStruct*)obj)->_handle);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ([cached_locals count] == 0)
|
|
|
|
|
{
|
|
|
|
|
[t invalidate];
|
|
|
|
|
timer = nil;
|
|
|
|
|
}
|
2003-10-21 17:05:36 +00:00
|
|
|
|
M_UNLOCK(cached_proxies_gate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Adds mode to the run loop modes that the NSConnection
|
|
|
|
|
* will listen to for incoming messages.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (void) addRequestMode: (NSString*)mode
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
if ([self isValid] == YES)
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if ([IrequestModes containsObject: mode] == NO)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
unsigned c = [IrunLoops count];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
while (c-- > 0)
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSRunLoop *loop = [IrunLoops objectAtIndex: c];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[IreceivePort addConnection: self toRunLoop: loop forMode: mode];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[IrequestModes addObject: mode];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Adds loop to the set of run loops that the NSConnection
|
|
|
|
|
* will listen to for incoming messages.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (void) addRunLoop: (NSRunLoop*)loop
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
if ([self isValid] == YES)
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if ([IrunLoops indexOfObjectIdenticalTo: loop] == NSNotFound)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
unsigned c = [IrequestModes count];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
while (c-- > 0)
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSString *mode = [IrequestModes objectAtIndex: c];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[IreceivePort addConnection: self toRunLoop: loop forMode: mode];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[IrunLoops addObject: loop];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
if (debug_connection)
|
2005-11-09 16:30:57 +00:00
|
|
|
|
NSLog(@"deallocating %@", self);
|
2009-01-12 18:36:37 +00:00
|
|
|
|
[self finalize];
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (internal != nil)
|
|
|
|
|
{
|
|
|
|
|
GS_DESTROY_INTERNAL(NSConnection);
|
|
|
|
|
}
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the delegate of the NSConnection.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (id) delegate
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
return GS_GC_UNHIDE(Idelegate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-11-09 16:30:57 +00:00
|
|
|
|
- (NSString*) description
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
return [NSString stringWithFormat: @"%@ local: '%@',%@ remote '%@',%@",
|
|
|
|
|
[super description],
|
|
|
|
|
IregisteredName ? (id)IregisteredName : (id)@"", [self receivePort],
|
|
|
|
|
IremoteName ? (id)IremoteName : (id)@"", [self sendPort]];
|
2005-11-09 16:30:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Sets the NSConnection configuration so that multiple threads may
|
|
|
|
|
* use the connection to send requests to the remote connection.<br />
|
|
|
|
|
* This option is inherited by child connections.<br />
|
|
|
|
|
* NB. A connection with multiple threads enabled will run slower than
|
|
|
|
|
* a normal connection.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (void) enableMultipleThreads
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
ImultipleThreads = YES;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns YES if the NSConnection is configured to
|
|
|
|
|
* handle remote messages atomically, NO otherwise.<br />
|
|
|
|
|
* This option is inherited by child connections.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (BOOL) independentConversationQueueing
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
return IindependentQueueing;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
2003-02-05 12:55:02 +00:00
|
|
|
|
* Return a connection able to act as a server receive incoming requests.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (id) init
|
|
|
|
|
{
|
2003-02-05 12:55:02 +00:00
|
|
|
|
NSPort *port = [NSPort port];
|
|
|
|
|
|
|
|
|
|
self = [self initWithReceivePort: port sendPort: nil];
|
|
|
|
|
return self;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/** <init />
|
2005-02-22 11:22:44 +00:00
|
|
|
|
* Initialises an NSConnection with the receive port r and the
|
2002-03-21 17:03:17 +00:00
|
|
|
|
* send port s.<br />
|
2003-07-06 06:34:34 +00:00
|
|
|
|
* Behavior varies with the port values as follows -
|
|
|
|
|
* <deflist>
|
|
|
|
|
* <term>r is <code>nil</code></term>
|
|
|
|
|
* <desc>
|
|
|
|
|
* The NSConnection is released and the method returns
|
|
|
|
|
* <code>nil</code>.
|
|
|
|
|
* </desc>
|
|
|
|
|
* <term>s is <code>nil</code></term>
|
|
|
|
|
* <desc>
|
|
|
|
|
* The NSConnection uses r as the send port as
|
|
|
|
|
* well as the receive port.
|
|
|
|
|
* </desc>
|
|
|
|
|
* <term>s is the same as r</term>
|
|
|
|
|
* <desc>
|
|
|
|
|
* The NSConnection is usable only for vending objects.
|
|
|
|
|
* </desc>
|
|
|
|
|
* <term>A connection with the same ports exists</term>
|
|
|
|
|
* <desc>
|
|
|
|
|
* The new connection is released and the old connection
|
|
|
|
|
* is retained and returned.
|
|
|
|
|
* </desc>
|
|
|
|
|
* <term>A connection with the same ports (swapped) exists</term>
|
|
|
|
|
* <desc>
|
|
|
|
|
* The new connection is initialised as normal, and will
|
|
|
|
|
* communicate with the old connection.
|
|
|
|
|
* </desc>
|
|
|
|
|
* </deflist>
|
|
|
|
|
* <p>
|
|
|
|
|
* If a connection exists whose send and receive ports are
|
|
|
|
|
* both the same as the new connections receive port, that
|
|
|
|
|
* existing connection is deemed to be the parent of the
|
|
|
|
|
* new connection. The new connection inherits configuration
|
|
|
|
|
* information from the parent, and the delegate of the
|
2005-11-06 13:53:40 +00:00
|
|
|
|
* parent has a chance to adjust the configuration of the
|
2003-07-06 06:34:34 +00:00
|
|
|
|
* new connection or veto its creation.
|
|
|
|
|
* <br/>
|
|
|
|
|
* NSConnectionDidInitializeNotification is posted once a new
|
|
|
|
|
* connection is initialised.
|
|
|
|
|
* </p>
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (id) initWithReceivePort: (NSPort*)r
|
|
|
|
|
sendPort: (NSPort*)s
|
|
|
|
|
{
|
|
|
|
|
NSNotificationCenter *nCenter;
|
|
|
|
|
NSConnection *parent;
|
|
|
|
|
NSConnection *conn;
|
|
|
|
|
NSRunLoop *loop;
|
|
|
|
|
id del;
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSZone *z;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
z = NSDefaultMallocZone();
|
2000-07-04 11:05:46 +00:00
|
|
|
|
/*
|
|
|
|
|
* If the receive port is nil, deallocate connection and return nil.
|
|
|
|
|
*/
|
|
|
|
|
if (r == nil)
|
|
|
|
|
{
|
|
|
|
|
if (debug_connection > 2)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"Asked to create connection with nil receive port");
|
|
|
|
|
}
|
|
|
|
|
DESTROY(self);
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the send port is nil, set it to the same as the receive port
|
|
|
|
|
* This connection will then only be useful to act as a server.
|
|
|
|
|
*/
|
|
|
|
|
if (s == nil)
|
|
|
|
|
{
|
|
|
|
|
s = r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
conn = existingConnection(r, s);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the send and receive ports match an existing connection
|
|
|
|
|
* deallocate the new one and retain and return the old one.
|
|
|
|
|
*/
|
|
|
|
|
if (conn != nil)
|
|
|
|
|
{
|
|
|
|
|
RELEASE(self);
|
|
|
|
|
self = RETAIN(conn);
|
|
|
|
|
if (debug_connection > 2)
|
|
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
|
NSLog(@"Found existing connection (%@) for \n\t%@\n\t%@",
|
|
|
|
|
conn, r, s);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
/* Create our private data structure.
|
|
|
|
|
*/
|
|
|
|
|
GS_CREATE_INTERNAL(NSConnection);
|
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
/*
|
|
|
|
|
* The parent connection is the one whose send and receive ports are
|
|
|
|
|
* both the same as our receive port.
|
|
|
|
|
*/
|
|
|
|
|
parent = existingConnection(r, r);
|
|
|
|
|
|
|
|
|
|
if (debug_connection)
|
|
|
|
|
{
|
2005-11-10 13:37:01 +00:00
|
|
|
|
NSLog(@"Initialising new connection with parent %@, %@\n "
|
|
|
|
|
@"Send: %@\n Recv: %@", parent, self, s, r);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
M_LOCK(connection_table_gate);
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IisValid = YES;
|
|
|
|
|
IreceivePort = RETAIN(r);
|
|
|
|
|
IsendPort = RETAIN(s);
|
|
|
|
|
ImessageCount = 0;
|
|
|
|
|
IrepOutCount = 0;
|
|
|
|
|
IreqOutCount = 0;
|
|
|
|
|
IrepInCount = 0;
|
|
|
|
|
IreqInCount = 0;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* These arrays cache NSPortCoder objects
|
|
|
|
|
*/
|
2001-06-08 14:04:20 +00:00
|
|
|
|
if (cacheCoders == YES)
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IcachedDecoders = [NSMutableArray new];
|
|
|
|
|
IcachedEncoders = [NSMutableArray new];
|
2001-06-08 14:04:20 +00:00
|
|
|
|
}
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This is used to queue up incoming NSPortMessages representing requests
|
|
|
|
|
* that can't immediately be dealt with.
|
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IrequestQueue = [NSMutableArray new];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This maps request sequence numbers to the NSPortCoder objects representing
|
|
|
|
|
* replies arriving from the remote connection.
|
|
|
|
|
*/
|
2009-03-09 15:11:51 +00:00
|
|
|
|
#if GS_WITH_GC
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IreplyMap
|
|
|
|
|
= (GSIMapTable)NSAllocateCollectable(sizeof(GSIMapTable_t),
|
2009-03-09 15:11:51 +00:00
|
|
|
|
NSScannedOption);
|
|
|
|
|
#else
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IreplyMap = (GSIMapTable)NSZoneMalloc(z, sizeof(GSIMapTable_t));
|
2009-03-09 15:11:51 +00:00
|
|
|
|
#endif
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIMapInitWithZoneAndCapacity(IreplyMap, z, 4);
|
2000-07-04 11:05:46 +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.
|
|
|
|
|
*/
|
2009-03-09 15:11:51 +00:00
|
|
|
|
#if GS_WITH_GC
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IlocalObjects
|
|
|
|
|
= (GSIMapTable)NSAllocateCollectable(sizeof(GSIMapTable_t),
|
2009-03-09 15:11:51 +00:00
|
|
|
|
NSScannedOption);
|
|
|
|
|
#else
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IlocalObjects
|
|
|
|
|
= (GSIMapTable)NSZoneMalloc(z, sizeof(GSIMapTable_t));
|
2009-03-09 15:11:51 +00:00
|
|
|
|
#endif
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIMapInitWithZoneAndCapacity(IlocalObjects, z, 4);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This maps handles for local objects to their local proxies.
|
|
|
|
|
*/
|
2009-03-09 15:11:51 +00:00
|
|
|
|
#if GS_WITH_GC
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IlocalTargets
|
|
|
|
|
= (GSIMapTable)NSAllocateCollectable(sizeof(GSIMapTable_t),
|
2009-03-09 15:11:51 +00:00
|
|
|
|
NSScannedOption);
|
|
|
|
|
#else
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IlocalTargets
|
|
|
|
|
= (GSIMapTable)NSZoneMalloc(z, sizeof(GSIMapTable_t));
|
2009-03-09 15:11:51 +00:00
|
|
|
|
#endif
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIMapInitWithZoneAndCapacity(IlocalTargets, z, 4);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
/*
|
2000-07-05 16:56:06 +00:00
|
|
|
|
* This maps targets to remote proxies.
|
2000-07-04 11:05:46 +00:00
|
|
|
|
*/
|
2009-03-09 15:11:51 +00:00
|
|
|
|
#if GS_WITH_GC
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IremoteProxies
|
|
|
|
|
= (GSIMapTable)NSAllocateCollectable(sizeof(GSIMapTable_t),
|
2009-03-09 15:11:51 +00:00
|
|
|
|
NSScannedOption);
|
|
|
|
|
#else
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IremoteProxies
|
|
|
|
|
= (GSIMapTable)NSZoneMalloc(z, sizeof(GSIMapTable_t));
|
2009-03-09 15:11:51 +00:00
|
|
|
|
#endif
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIMapInitWithZoneAndCapacity(IremoteProxies, z, 4);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IrequestDepth = 0;
|
|
|
|
|
Idelegate = nil;
|
|
|
|
|
IrefGate = [GSLazyRecursiveLock new];
|
2000-07-04 19:53:39 +00:00
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
/*
|
|
|
|
|
* Some attributes are inherited from the parent if possible.
|
|
|
|
|
*/
|
|
|
|
|
if (parent != nil)
|
|
|
|
|
{
|
2000-07-04 19:53:39 +00:00
|
|
|
|
unsigned count;
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
ImultipleThreads = GSIVar(parent, _multipleThreads);
|
|
|
|
|
IindependentQueueing = GSIVar(parent, _independentQueueing);
|
|
|
|
|
IreplyTimeout = GSIVar(parent, _replyTimeout);
|
|
|
|
|
IrequestTimeout = GSIVar(parent, _requestTimeout);
|
|
|
|
|
IrunLoops = [GSIVar(parent, _runLoops) mutableCopy];
|
|
|
|
|
count = [GSIVar(parent, _requestModes) count];
|
|
|
|
|
IrequestModes
|
|
|
|
|
= [[NSMutableArray alloc] initWithCapacity: count];
|
2000-07-04 19:53:39 +00:00
|
|
|
|
while (count-- > 0)
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[self addRequestMode:
|
|
|
|
|
[GSIVar(parent, _requestModes) objectAtIndex: count]];
|
2000-07-04 19:53:39 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (GSIVar(parent, _useKeepalive) == YES)
|
2008-11-21 10:41:43 +00:00
|
|
|
|
{
|
|
|
|
|
[self _enableKeepalive];
|
|
|
|
|
}
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
ImultipleThreads = NO;
|
|
|
|
|
IindependentQueueing = NO;
|
|
|
|
|
IreplyTimeout = 1.0E12;
|
|
|
|
|
IrequestTimeout = 1.0E12;
|
2000-07-04 19:53:39 +00:00
|
|
|
|
/*
|
|
|
|
|
* Set up request modes array and make sure the receiving port
|
|
|
|
|
* is added to the run loop to get data.
|
|
|
|
|
*/
|
2004-11-25 17:00:45 +00:00
|
|
|
|
loop = GSRunLoopForThread(nil);
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IrunLoops = [[NSMutableArray alloc] initWithObjects: &loop count: 1];
|
|
|
|
|
IrequestModes = [[NSMutableArray alloc] initWithCapacity: 2];
|
2005-02-22 11:22:44 +00:00
|
|
|
|
[self addRequestMode: NSDefaultRunLoopMode];
|
|
|
|
|
[self addRequestMode: NSConnectionReplyMode];
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IuseKeepalive = NO;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2000-07-04 19:53:39 +00:00
|
|
|
|
/*
|
|
|
|
|
* If we have no parent, we must handle incoming packets on our
|
|
|
|
|
* receive port ourself - so we set ourself up as the port delegate.
|
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[IreceivePort setDelegate: self];
|
2000-07-04 19:53:39 +00:00
|
|
|
|
}
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
/* Ask the delegate for permission, (OpenStep-style and GNUstep-style). */
|
|
|
|
|
|
|
|
|
|
/* Preferred MacOS-X version, which just allows the returning of BOOL */
|
|
|
|
|
del = [parent delegate];
|
2001-05-10 10:15:38 +00:00
|
|
|
|
if ([del respondsToSelector: @selector(connection:shouldMakeNewConnection:)])
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
|
|
|
|
if ([del connection: parent shouldMakeNewConnection: self] == NO)
|
|
|
|
|
{
|
|
|
|
|
M_UNLOCK(connection_table_gate);
|
|
|
|
|
RELEASE(self);
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Deprecated OpenStep version, which just allows the returning of BOOL */
|
2001-05-10 10:15:38 +00:00
|
|
|
|
if ([del respondsToSelector: @selector(makeNewConnection:sender:)])
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
|
|
|
|
if (![del makeNewConnection: self sender: parent])
|
|
|
|
|
{
|
|
|
|
|
M_UNLOCK(connection_table_gate);
|
|
|
|
|
RELEASE(self);
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Here is the GNUstep version, which allows the delegate to specify
|
|
|
|
|
a substitute. Note: The delegate is responsible for freeing
|
|
|
|
|
newConn if it returns something different. */
|
2001-05-10 10:15:38 +00:00
|
|
|
|
if ([del respondsToSelector: @selector(connection:didConnect:)])
|
2003-09-15 13:54:06 +00:00
|
|
|
|
{
|
|
|
|
|
self = [del connection: parent didConnect: self];
|
|
|
|
|
}
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
nCenter = [NSNotificationCenter defaultCenter];
|
2003-09-15 13:54:06 +00:00
|
|
|
|
/*
|
|
|
|
|
* Register ourselves for invalidation notification when the
|
|
|
|
|
* ports become invalid.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[nCenter addObserver: self
|
2003-09-15 13:54:06 +00:00
|
|
|
|
selector: @selector(_portIsInvalid:)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
name: NSPortDidBecomeInvalidNotification
|
|
|
|
|
object: r];
|
|
|
|
|
if (s != nil)
|
2003-09-15 13:54:06 +00:00
|
|
|
|
{
|
|
|
|
|
[nCenter addObserver: self
|
|
|
|
|
selector: @selector(_portIsInvalid:)
|
|
|
|
|
name: NSPortDidBecomeInvalidNotification
|
|
|
|
|
object: s];
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
/* In order that connections may be deallocated - there is an
|
|
|
|
|
implementation of [-release] to automatically remove the connection
|
|
|
|
|
from this array when it is the only thing retaining it. */
|
|
|
|
|
NSHashInsert(connection_table, (void*)self);
|
|
|
|
|
M_UNLOCK(connection_table_gate);
|
|
|
|
|
|
2003-09-15 13:54:06 +00:00
|
|
|
|
[nCenter postNotificationName: NSConnectionDidInitializeNotification
|
2004-11-25 17:00:45 +00:00
|
|
|
|
object: self];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Marks the receiving NSConnection as invalid.
|
|
|
|
|
* <br />
|
|
|
|
|
* Removes the NSConnections ports from any run loops.
|
|
|
|
|
* <br />
|
|
|
|
|
* Posts an NSConnectionDidDieNotification.
|
|
|
|
|
* <br />
|
|
|
|
|
* Invalidates all remote objects and local proxies.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (void) invalidate
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
if (IisValid == NO)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (IshuttingDown == NO)
|
2005-11-21 13:15:39 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IshuttingDown = YES;
|
2005-11-21 13:15:39 +00:00
|
|
|
|
/*
|
|
|
|
|
* Not invalidated as a result of a shutdown from the other end,
|
|
|
|
|
* so tell the other end it must shut down.
|
|
|
|
|
*/
|
|
|
|
|
//[self _shutdown];
|
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IisValid = NO;
|
2000-07-04 19:53:39 +00:00
|
|
|
|
M_LOCK(connection_table_gate);
|
|
|
|
|
NSHashRemove(connection_table, self);
|
|
|
|
|
M_UNLOCK(connection_table_gate);
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 19:53:39 +00:00
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
/*
|
2003-09-15 13:54:06 +00:00
|
|
|
|
* Don't need notifications any more - so remove self as observer.
|
2000-07-04 11:05:46 +00:00
|
|
|
|
*/
|
|
|
|
|
[[NSNotificationCenter defaultCenter] removeObserver: self];
|
|
|
|
|
|
2000-07-04 19:53:39 +00:00
|
|
|
|
/*
|
|
|
|
|
* Make sure we are not registered.
|
|
|
|
|
*/
|
2009-09-11 19:19:05 +00:00
|
|
|
|
#if !defined(__MINGW32__)
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if ([IreceivePort isKindOfClass: [NSMessagePort class]])
|
2005-04-12 18:30:51 +00:00
|
|
|
|
{
|
|
|
|
|
[self registerName: nil
|
|
|
|
|
withNameServer: [NSMessagePortNameServer sharedInstance]];
|
|
|
|
|
}
|
2005-04-20 07:37:01 +00:00
|
|
|
|
else
|
|
|
|
|
#endif
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if ([IreceivePort isKindOfClass: [NSSocketPort class]])
|
2005-04-12 18:30:51 +00:00
|
|
|
|
{
|
|
|
|
|
[self registerName: nil
|
|
|
|
|
withNameServer: [NSSocketPortNameServer sharedInstance]];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[self registerName: nil];
|
|
|
|
|
}
|
2000-07-04 19:53:39 +00:00
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
/*
|
|
|
|
|
* Withdraw from run loops.
|
|
|
|
|
*/
|
|
|
|
|
[self setRequestMode: nil];
|
|
|
|
|
|
2009-01-12 12:48:46 +00:00
|
|
|
|
IF_NO_GC([self retain];)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
if (debug_connection)
|
|
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
|
NSLog(@"Invalidating connection %@", self);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
/*
|
2003-09-15 13:54:06 +00:00
|
|
|
|
* We need to notify any watchers of our death - but if we are already
|
|
|
|
|
* in the deallocation process, we can't have a notification retaining
|
|
|
|
|
* and autoreleasing us later once we are deallocated - so we do the
|
|
|
|
|
* notification with a local autorelease pool to ensure that any release
|
|
|
|
|
* is done before the deallocation completes.
|
2000-07-04 11:05:46 +00:00
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
CREATE_AUTORELEASE_POOL(arp);
|
|
|
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
|
postNotificationName: NSConnectionDidDieNotification
|
|
|
|
|
object: self];
|
|
|
|
|
RELEASE(arp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we have been invalidated, we don't need to retain proxies
|
|
|
|
|
* for local objects any more. In fact, we want to get rid of
|
|
|
|
|
* these proxies in case they are keeping us retained when we
|
|
|
|
|
* might otherwise de deallocated.
|
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
if (IlocalTargets != 0)
|
2000-07-04 19:53:39 +00:00
|
|
|
|
{
|
2003-09-15 13:54:06 +00:00
|
|
|
|
NSMutableArray *targets;
|
2009-09-07 16:25:04 +00:00
|
|
|
|
unsigned i = IlocalTargets->nodeCount;
|
2000-12-21 10:31:33 +00:00
|
|
|
|
GSIMapEnumerator_t enumerator;
|
|
|
|
|
GSIMapNode node;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2000-07-05 12:23:00 +00:00
|
|
|
|
targets = [[NSMutableArray alloc] initWithCapacity: i];
|
2009-09-07 16:25:04 +00:00
|
|
|
|
enumerator = GSIMapEnumeratorForMap(IlocalTargets);
|
2000-12-21 10:31:33 +00:00
|
|
|
|
node = GSIMapEnumeratorNextNode(&enumerator);
|
2000-07-05 12:23:00 +00:00
|
|
|
|
while (node != 0)
|
|
|
|
|
{
|
|
|
|
|
[targets addObject: node->value.obj];
|
2000-12-21 10:31:33 +00:00
|
|
|
|
node = GSIMapEnumeratorNextNode(&enumerator);
|
2000-07-05 12:23:00 +00:00
|
|
|
|
}
|
2000-07-04 19:53:39 +00:00
|
|
|
|
while (i-- > 0)
|
|
|
|
|
{
|
2003-10-27 13:41:01 +00:00
|
|
|
|
[self removeLocalObject: [targets objectAtIndex: i]];
|
2000-07-04 19:53:39 +00:00
|
|
|
|
}
|
|
|
|
|
RELEASE(targets);
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIMapEmptyMap(IlocalTargets);
|
|
|
|
|
NSZoneFree(IlocalTargets->zone, (void*)IlocalTargets);
|
|
|
|
|
IlocalTargets = 0;
|
2000-07-04 19:53:39 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (IremoteProxies != 0)
|
2000-07-04 20:25:50 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIMapEmptyMap(IremoteProxies);
|
|
|
|
|
NSZoneFree(IremoteProxies->zone, (void*)IremoteProxies);
|
|
|
|
|
IremoteProxies = 0;
|
2000-07-04 20:25:50 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (IlocalObjects != 0)
|
2000-07-04 20:25:50 +00:00
|
|
|
|
{
|
2000-12-21 10:31:33 +00:00
|
|
|
|
GSIMapEnumerator_t enumerator;
|
|
|
|
|
GSIMapNode node;
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
enumerator = GSIMapEnumeratorForMap(IlocalObjects);
|
2000-12-21 10:31:33 +00:00
|
|
|
|
node = GSIMapEnumeratorNextNode(&enumerator);
|
2000-07-05 12:23:00 +00:00
|
|
|
|
|
|
|
|
|
while (node != 0)
|
|
|
|
|
{
|
|
|
|
|
RELEASE(node->key.obj);
|
2000-12-21 10:31:33 +00:00
|
|
|
|
node = GSIMapEnumeratorNextNode(&enumerator);
|
2000-07-05 12:23:00 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIMapEmptyMap(IlocalObjects);
|
|
|
|
|
NSZoneFree(IlocalObjects->zone, (void*)IlocalObjects);
|
|
|
|
|
IlocalObjects = 0;
|
2000-07-04 20:25:50 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2003-09-15 13:54:06 +00:00
|
|
|
|
/*
|
|
|
|
|
* If we are invalidated, we shouldn't be receiving any event and
|
|
|
|
|
* should not need to be in any run loops.
|
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
while ([IrunLoops count] > 0)
|
2003-09-15 13:54:06 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[self removeRunLoop: [IrunLoops lastObject]];
|
2003-09-15 13:54:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-08-24 08:08:14 +00:00
|
|
|
|
/*
|
|
|
|
|
* Invalidate the current conversation so we don't leak.
|
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if ([IsendPort isValid] == YES)
|
2004-08-24 08:08:14 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[[IsendPort conversation: IreceivePort] invalidate];
|
2004-08-24 08:08:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
RELEASE(self);
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
2002-10-05 17:47:54 +00:00
|
|
|
|
* Returns YES if the connection is valid, NO otherwise.
|
|
|
|
|
* A connection is valid until it has been sent an -invalidate message.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (BOOL) isValid
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
return IisValid;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
2003-10-21 17:05:36 +00:00
|
|
|
|
* Returns an array of all the local objects that have proxies at the
|
|
|
|
|
* remote end of the connection because they have been sent over the
|
|
|
|
|
* connection and not yet released by the far end.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (NSArray*) localObjects
|
|
|
|
|
{
|
2000-07-05 12:23:00 +00:00
|
|
|
|
NSMutableArray *c;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
/* Don't assert (IisValid); */
|
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
if (IlocalObjects != 0)
|
2000-07-05 12:23:00 +00:00
|
|
|
|
{
|
2000-12-21 10:31:33 +00:00
|
|
|
|
GSIMapEnumerator_t enumerator;
|
|
|
|
|
GSIMapNode node;
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
enumerator = GSIMapEnumeratorForMap(IlocalObjects);
|
2000-12-21 10:31:33 +00:00
|
|
|
|
node = GSIMapEnumeratorNextNode(&enumerator);
|
2000-07-06 20:26:49 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
c = [NSMutableArray arrayWithCapacity: IlocalObjects->nodeCount];
|
2000-07-06 20:26:49 +00:00
|
|
|
|
while (node != 0)
|
|
|
|
|
{
|
|
|
|
|
[c addObject: node->key.obj];
|
2000-12-21 10:31:33 +00:00
|
|
|
|
node = GSIMapEnumeratorNextNode(&enumerator);
|
2000-07-06 20:26:49 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
c = [NSArray array];
|
2000-07-05 12:23:00 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns YES if the connection permits multiple threads to use it to
|
2002-10-05 17:47:54 +00:00
|
|
|
|
* send requests, NO otherwise.<br />
|
|
|
|
|
* See the -enableMultipleThreads method.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (BOOL) multipleThreadsEnabled
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
return ImultipleThreads;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
2005-11-06 13:53:40 +00:00
|
|
|
|
* Returns the NSPort object on which incoming messages are received.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (NSPort*) receivePort
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
return IreceivePort;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
2002-11-04 15:39:43 +00:00
|
|
|
|
* Simply invokes -registerName:withNameServer:
|
|
|
|
|
* passing it the default system nameserver.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (BOOL) registerName: (NSString*)name
|
|
|
|
|
{
|
|
|
|
|
NSPortNameServer *svr = [NSPortNameServer systemDefaultPortNameServer];
|
|
|
|
|
|
|
|
|
|
return [self registerName: name withNameServer: svr];
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
2005-11-06 13:53:40 +00:00
|
|
|
|
* Registers the receive port of the NSConnection as name and
|
2002-03-21 17:03:17 +00:00
|
|
|
|
* unregisters the previous value (if any).<br />
|
|
|
|
|
* Returns YES on success, NO on failure.<br />
|
|
|
|
|
* On failure, the connection remains registered under the
|
|
|
|
|
* previous name.<br />
|
|
|
|
|
* Supply nil as name to unregister the NSConnection.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (BOOL) registerName: (NSString*)name withNameServer: (NSPortNameServer*)svr
|
|
|
|
|
{
|
|
|
|
|
BOOL result = YES;
|
|
|
|
|
|
|
|
|
|
if (name != nil)
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
result = [svr registerPort: IreceivePort forName: name];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2000-07-04 19:53:39 +00:00
|
|
|
|
if (result == YES)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (IregisteredName != nil)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[InameServer removePort: IreceivePort forName: IregisteredName];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
ASSIGN(IregisteredName, name);
|
|
|
|
|
ASSIGN(InameServer, svr);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) release
|
|
|
|
|
{
|
2006-09-07 11:47:45 +00:00
|
|
|
|
/* We lock the connection table while checking, to prevent
|
|
|
|
|
* another thread from grabbing this connection while we are
|
|
|
|
|
* checking it.
|
|
|
|
|
* If we are going to deallocate the object, we first remove
|
|
|
|
|
* it from the table so that no other thread will find it
|
|
|
|
|
* and try to use it while it is being deallocated.
|
2000-07-04 11:05:46 +00:00
|
|
|
|
*/
|
2006-09-06 15:12:03 +00:00
|
|
|
|
M_LOCK(connection_table_gate);
|
2006-09-07 11:47:45 +00:00
|
|
|
|
if (NSDecrementExtraRefCountWasZero(self))
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2006-09-07 11:47:45 +00:00
|
|
|
|
NSHashRemove(connection_table, self);
|
|
|
|
|
M_UNLOCK(connection_table_gate);
|
|
|
|
|
[self dealloc];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
M_UNLOCK(connection_table_gate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
2003-10-21 17:05:36 +00:00
|
|
|
|
* Returns an array of proxies to all the remote objects known to
|
2002-03-21 17:03:17 +00:00
|
|
|
|
* the NSConnection.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (NSArray *) remoteObjects
|
|
|
|
|
{
|
2000-07-05 12:23:00 +00:00
|
|
|
|
NSMutableArray *c;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
/* Don't assert (IisValid); */
|
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
if (IremoteProxies != 0)
|
2000-07-06 20:26:49 +00:00
|
|
|
|
{
|
2000-12-21 10:31:33 +00:00
|
|
|
|
GSIMapEnumerator_t enumerator;
|
|
|
|
|
GSIMapNode node;
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
enumerator = GSIMapEnumeratorForMap(IremoteProxies);
|
2000-12-21 10:31:33 +00:00
|
|
|
|
node = GSIMapEnumeratorNextNode(&enumerator);
|
2000-07-06 20:26:49 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
c = [NSMutableArray arrayWithCapacity: IremoteProxies->nodeCount];
|
2000-07-06 20:26:49 +00:00
|
|
|
|
while (node != 0)
|
|
|
|
|
{
|
|
|
|
|
[c addObject: node->key.obj];
|
2000-12-21 10:31:33 +00:00
|
|
|
|
node = GSIMapEnumeratorNextNode(&enumerator);
|
2000-07-06 20:26:49 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2000-07-05 12:23:00 +00:00
|
|
|
|
{
|
2000-07-06 20:26:49 +00:00
|
|
|
|
c = [NSMutableArray array];
|
2000-07-05 12:23:00 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
2004-08-24 08:08:14 +00:00
|
|
|
|
* Removes mode from the run loop modes used to receive incoming messages.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (void) removeRequestMode: (NSString*)mode
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
if (IrequestModes != nil && [IrequestModes containsObject: mode])
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
unsigned c = [IrunLoops count];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
while (c-- > 0)
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSRunLoop *loop = [IrunLoops objectAtIndex: c];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[IreceivePort removeConnection: self
|
2005-11-04 17:58:27 +00:00
|
|
|
|
fromRunLoop: loop
|
|
|
|
|
forMode: mode];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[IrequestModes removeObject: mode];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
2005-11-06 13:53:40 +00:00
|
|
|
|
* Removes loop from the run loops used to receive incoming messages.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (void) removeRunLoop: (NSRunLoop*)loop
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
if (IrunLoops != nil)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
unsigned pos = [IrunLoops indexOfObjectIdenticalTo: loop];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2000-07-06 20:26:49 +00:00
|
|
|
|
if (pos != NSNotFound)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
unsigned c = [IrequestModes count];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2000-07-06 20:26:49 +00:00
|
|
|
|
while (c-- > 0)
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSString *mode = [IrequestModes objectAtIndex: c];
|
2000-07-06 20:26:49 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[IreceivePort removeConnection: self
|
|
|
|
|
fromRunLoop: [IrunLoops objectAtIndex: pos]
|
2005-11-04 17:58:27 +00:00
|
|
|
|
forMode: mode];
|
2000-07-06 20:26:49 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[IrunLoops removeObjectAtIndex: pos];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the timeout interval used when waiting for a reply to
|
|
|
|
|
* a request sent on the NSConnection. This value is inherited
|
|
|
|
|
* from the parent connection or may be set using the -setReplyTimeout:
|
|
|
|
|
* method.<br />
|
2005-02-27 12:25:10 +00:00
|
|
|
|
* The default value is the maximum delay (effectively infinite).
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (NSTimeInterval) replyTimeout
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
return IreplyTimeout;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns an array of all the run loop modes that the NSConnection
|
|
|
|
|
* uses when waiting for an incoming request.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (NSArray*) requestModes
|
|
|
|
|
{
|
2000-07-06 20:26:49 +00:00
|
|
|
|
NSArray *c;
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
c = AUTORELEASE([IrequestModes copy]);
|
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-06 20:26:49 +00:00
|
|
|
|
return c;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the timeout interval used when trying to send a request
|
|
|
|
|
* on the NSConnection. This value is inherited from the parent
|
|
|
|
|
* connection or may be set using the -setRequestTimeout: method.<br />
|
2005-02-27 12:25:10 +00:00
|
|
|
|
* The default value is the maximum delay (effectively infinite).
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (NSTimeInterval) requestTimeout
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
return IrequestTimeout;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the object that is made available by this connection
|
|
|
|
|
* or by its parent (the object is associated with the receive port).<br />
|
|
|
|
|
* Returns nil if no root object has been set.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (id) rootObject
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
return rootObjectForInPort(IreceivePort);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
2003-07-05 10:40:20 +00:00
|
|
|
|
* Returns the proxy for the root object of the remote NSConnection.<br />
|
|
|
|
|
* Generally you will wish to call [NSDistantObject-setProtocolForProxy:]
|
|
|
|
|
* immediately after obtaining such a root proxy.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (NSDistantObject*) rootProxy
|
|
|
|
|
{
|
|
|
|
|
NSPortCoder *op;
|
|
|
|
|
NSPortCoder *ip;
|
|
|
|
|
NSDistantObject *newProxy = nil;
|
|
|
|
|
int seq_num;
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSParameterAssert(IreceivePort);
|
|
|
|
|
NSParameterAssert(IisValid);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2000-09-12 05:16:01 +00:00
|
|
|
|
/*
|
|
|
|
|
* If this is a server connection without a remote end, its root proxy
|
|
|
|
|
* is the same as its root object.
|
|
|
|
|
*/
|
2009-10-03 15:35:40 +00:00
|
|
|
|
if (IreceivePort == IsendPort)
|
2000-09-12 05:16:01 +00:00
|
|
|
|
{
|
|
|
|
|
return [self rootObject];
|
|
|
|
|
}
|
2000-07-05 12:23:00 +00:00
|
|
|
|
op = [self _makeOutRmc: 0 generate: &seq_num reply: YES];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[self _sendOutRmc: op type: ROOTPROXY_REQUEST];
|
|
|
|
|
|
|
|
|
|
ip = [self _getReplyRmc: seq_num];
|
|
|
|
|
[ip decodeValueOfObjCType: @encode(id) at: &newProxy];
|
2001-04-11 12:30:32 +00:00
|
|
|
|
[self _doneInRmc: ip];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
return AUTORELEASE(newProxy);
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Removes the NSConnection from the current threads default
|
|
|
|
|
* run loop, then creates a new thread and runs the NSConnection in it.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (void) runInNewThread
|
|
|
|
|
{
|
2004-11-25 17:00:45 +00:00
|
|
|
|
[self removeRunLoop: GSRunLoopForThread(nil)];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[NSThread detachNewThreadSelector: @selector(_runInNewThread)
|
|
|
|
|
toTarget: self
|
|
|
|
|
withObject: nil];
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the port on which the NSConnection sends messages.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (NSPort*) sendPort
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
return IsendPort;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Sets the NSConnection's delegate (without retaining it).<br />
|
|
|
|
|
* The delegate is able to control some of the NSConnection's
|
|
|
|
|
* behavior by implementing methods in an informal protocol.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (void) setDelegate: (id)anObj
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
Idelegate = GS_GC_HIDE(anObj);
|
|
|
|
|
IauthenticateIn =
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[anObj respondsToSelector: @selector(authenticateComponents:withData:)];
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IauthenticateOut =
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[anObj respondsToSelector: @selector(authenticationDataForComponents:)];
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Sets whether or not the NSConnection should handle requests
|
|
|
|
|
* arriving from the remote NSConnection atomically.<br />
|
|
|
|
|
* By default, this is set to NO ... if set to YES then any messages
|
|
|
|
|
* arriving while one message is being dealt with, will be queued.<br />
|
|
|
|
|
* NB. careful - use of this option can cause deadlocks.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (void) setIndependentConversationQueueing: (BOOL)flag
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IindependentQueueing = flag;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Sets the time interval that the NSConnection will wait for a
|
2002-10-05 17:47:54 +00:00
|
|
|
|
* reply for one of its requests before raising an
|
|
|
|
|
* NSPortTimeoutException.<br />
|
|
|
|
|
* NB. In GNUstep you may also get such an exception if the connection
|
|
|
|
|
* becomes invalidated while waiting for a reply to a request.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (void) setReplyTimeout: (NSTimeInterval)to
|
|
|
|
|
{
|
2005-02-27 12:25:10 +00:00
|
|
|
|
if (to <= 0.0 || to > 1.0E12) to = 1.0E12;
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IreplyTimeout = to;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Sets the runloop mode in which requests will be sent to the remote
|
2003-07-05 10:40:20 +00:00
|
|
|
|
* end of the connection. Normally this is NSDefaultRunloopMode
|
2002-03-21 17:03:17 +00:00
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (void) setRequestMode: (NSString*)mode
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
if (IrequestModes != nil)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
while ([IrequestModes count] > 0
|
|
|
|
|
&& [IrequestModes objectAtIndex: 0] != mode)
|
2000-07-06 20:26:49 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[self removeRequestMode: [IrequestModes objectAtIndex: 0]];
|
2000-07-06 20:26:49 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
while ([IrequestModes count] > 1)
|
2000-07-06 20:26:49 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[self removeRequestMode: [IrequestModes objectAtIndex: 1]];
|
2000-07-06 20:26:49 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (mode != nil && [IrequestModes count] == 0)
|
2000-07-06 20:26:49 +00:00
|
|
|
|
{
|
|
|
|
|
[self addRequestMode: mode];
|
|
|
|
|
}
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Sets the time interval that the NSConnection will wait to send
|
|
|
|
|
* one of its requests before raising an NSPortTimeoutException.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (void) setRequestTimeout: (NSTimeInterval)to
|
|
|
|
|
{
|
2005-02-27 12:25:10 +00:00
|
|
|
|
if (to <= 0.0 || to > 1.0E12) to = 1.0E12;
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IrequestTimeout = to;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Sets the root object that is vended by the connection.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (void) setRootObject: (id)anObj
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
setRootObjectForInPort(anObj, IreceivePort);
|
2009-09-11 19:19:05 +00:00
|
|
|
|
#if defined(__MINGW32__)
|
2008-12-17 08:49:50 +00:00
|
|
|
|
/* On ms-windows, the operating system does not inform us when the remote
|
|
|
|
|
* client of a message port goes away ... so we need to enable keepalive
|
|
|
|
|
* to detect that condition.
|
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if ([IreceivePort isKindOfClass: [NSMessagePort class]])
|
2008-12-17 08:49:50 +00:00
|
|
|
|
{
|
|
|
|
|
[self _enableKeepalive];
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-21 17:03:17 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns an object containing various statistics for the
|
|
|
|
|
* NSConnection.
|
|
|
|
|
* <br />
|
|
|
|
|
* On GNUstep the dictionary contains -
|
|
|
|
|
* <deflist>
|
|
|
|
|
* <term>NSConnectionRepliesReceived</term>
|
|
|
|
|
* <desc>
|
2004-07-29 15:30:47 +00:00
|
|
|
|
* The number of messages replied to by the remote NSConnection.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
* </desc>
|
|
|
|
|
* <term>NSConnectionRepliesSent</term>
|
|
|
|
|
* <desc>
|
2004-07-29 15:30:47 +00:00
|
|
|
|
* The number of replies sent to the remote NSConnection.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
* </desc>
|
|
|
|
|
* <term>NSConnectionRequestsReceived</term>
|
|
|
|
|
* <desc>
|
2005-11-06 13:53:40 +00:00
|
|
|
|
* The number of messages received from the remote NSConnection.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
* </desc>
|
|
|
|
|
* <term>NSConnectionRequestsSent</term>
|
|
|
|
|
* <desc>
|
2004-07-29 15:30:47 +00:00
|
|
|
|
* The number of messages sent to the remote NSConnection.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
* </desc>
|
|
|
|
|
* <term>NSConnectionLocalCount</term>
|
|
|
|
|
* <desc>
|
2004-07-29 15:30:47 +00:00
|
|
|
|
* The number of local objects currently vended.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
* </desc>
|
|
|
|
|
* <term>NSConnectionProxyCount</term>
|
|
|
|
|
* <desc>
|
2004-07-29 15:30:47 +00:00
|
|
|
|
* The number of remote objects currently in use.
|
2002-03-21 17:03:17 +00:00
|
|
|
|
* </desc>
|
|
|
|
|
* </deflist>
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (NSDictionary*) statistics
|
|
|
|
|
{
|
|
|
|
|
NSMutableDictionary *d;
|
|
|
|
|
id o;
|
|
|
|
|
|
|
|
|
|
d = [NSMutableDictionary dictionaryWithCapacity: 8];
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* These are in OPENSTEP 4.2
|
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
o = [NSNumber numberWithUnsignedInt: IrepInCount];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[d setObject: o forKey: NSConnectionRepliesReceived];
|
2009-09-07 16:25:04 +00:00
|
|
|
|
o = [NSNumber numberWithUnsignedInt: IrepOutCount];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[d setObject: o forKey: NSConnectionRepliesSent];
|
2009-09-07 16:25:04 +00:00
|
|
|
|
o = [NSNumber numberWithUnsignedInt: IreqInCount];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[d setObject: o forKey: NSConnectionRequestsReceived];
|
2009-09-07 16:25:04 +00:00
|
|
|
|
o = [NSNumber numberWithUnsignedInt: IreqOutCount];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[d setObject: o forKey: NSConnectionRequestsSent];
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* These are GNUstep extras
|
|
|
|
|
*/
|
2000-07-06 20:26:49 +00:00
|
|
|
|
o = [NSNumber numberWithUnsignedInt:
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IlocalTargets ? IlocalTargets->nodeCount : 0];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[d setObject: o forKey: NSConnectionLocalCount];
|
2000-07-06 20:26:49 +00:00
|
|
|
|
o = [NSNumber numberWithUnsignedInt:
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IremoteProxies ? IremoteProxies->nodeCount : 0];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[d setObject: o forKey: NSConnectionProxyCount];
|
2000-07-06 20:26:49 +00:00
|
|
|
|
o = [NSNumber numberWithUnsignedInt:
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IreplyMap ? IreplyMap->nodeCount : 0];
|
2000-07-05 12:23:00 +00:00
|
|
|
|
[d setObject: o forKey: @"NSConnectionReplyQueue"];
|
2009-09-07 16:25:04 +00:00
|
|
|
|
o = [NSNumber numberWithUnsignedInt: [IrequestQueue count]];
|
2000-07-05 12:23:00 +00:00
|
|
|
|
[d setObject: o forKey: @"NSConnectionRequestQueue"];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
return d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation NSConnection (GNUstepExtensions)
|
|
|
|
|
|
|
|
|
|
+ (NSConnection*) newRegisteringAtName: (NSString*)name
|
|
|
|
|
withRootObject: (id)anObject
|
|
|
|
|
{
|
|
|
|
|
NSConnection *conn;
|
|
|
|
|
|
2006-03-08 11:28:59 +00:00
|
|
|
|
GSOnceMLog(@"This method is deprecated, use standard initialisation");
|
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
conn = [[self alloc] initWithReceivePort: [NSPort port]
|
|
|
|
|
sendPort: nil];
|
|
|
|
|
[conn setRootObject: anObject];
|
|
|
|
|
if ([conn registerName: name] == NO)
|
|
|
|
|
{
|
|
|
|
|
DESTROY(conn);
|
|
|
|
|
}
|
|
|
|
|
return conn;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-12 18:36:37 +00:00
|
|
|
|
- (void) finalize
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
|
|
|
|
CREATE_AUTORELEASE_POOL(arp);
|
|
|
|
|
|
|
|
|
|
if (debug_connection)
|
2005-11-09 16:30:57 +00:00
|
|
|
|
NSLog(@"finalising %@", self);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
[self invalidate];
|
|
|
|
|
|
|
|
|
|
/* Remove rootObject from root_object_map if this is last connection */
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (IreceivePort != nil && existingConnection(IreceivePort, nil) == nil)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
setRootObjectForInPort(nil, IreceivePort);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Remove receive port from run loop. */
|
|
|
|
|
[self setRequestMode: nil];
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
DESTROY(IrequestModes);
|
|
|
|
|
DESTROY(IrunLoops);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Finished with ports - releasing them may generate a notification
|
|
|
|
|
* If we are the receive port delagate, try to shift responsibility.
|
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if ([IreceivePort delegate] == self)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSConnection *root = existingConnection(IreceivePort, IreceivePort);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
if (root == nil)
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
root = existingConnection(IreceivePort, nil);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[IreceivePort setDelegate: root];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
DESTROY(IreceivePort);
|
|
|
|
|
DESTROY(IsendPort);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
DESTROY(IrequestQueue);
|
|
|
|
|
if (IreplyMap != 0)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2000-12-21 10:31:33 +00:00
|
|
|
|
GSIMapEnumerator_t enumerator;
|
|
|
|
|
GSIMapNode node;
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
enumerator = GSIMapEnumeratorForMap(IreplyMap);
|
2000-12-21 10:31:33 +00:00
|
|
|
|
node = GSIMapEnumeratorNextNode(&enumerator);
|
2000-07-05 12:23:00 +00:00
|
|
|
|
|
|
|
|
|
while (node != 0)
|
|
|
|
|
{
|
2003-09-25 12:15:51 +00:00
|
|
|
|
if (node->value.obj != dummyObject)
|
2000-12-21 10:31:33 +00:00
|
|
|
|
{
|
2003-09-25 12:15:51 +00:00
|
|
|
|
RELEASE(node->value.obj);
|
2000-12-21 10:31:33 +00:00
|
|
|
|
}
|
|
|
|
|
node = GSIMapEnumeratorNextNode(&enumerator);
|
2000-07-05 12:23:00 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIMapEmptyMap(IreplyMap);
|
|
|
|
|
NSZoneFree(IreplyMap->zone, (void*)IreplyMap);
|
|
|
|
|
IreplyMap = 0;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
DESTROY(IcachedDecoders);
|
|
|
|
|
DESTROY(IcachedEncoders);
|
|
|
|
|
|
|
|
|
|
DESTROY(IremoteName);
|
|
|
|
|
|
|
|
|
|
DESTROY(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
RELEASE(arp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2002-07-09 07:35:28 +00:00
|
|
|
|
* NSDistantObject's -forward:: method calls this to send the message
|
2000-07-04 11:05:46 +00:00
|
|
|
|
* over the wire.
|
|
|
|
|
*/
|
|
|
|
|
- (retval_t) forwardForProxy: (NSDistantObject*)object
|
|
|
|
|
selector: (SEL)sel
|
|
|
|
|
argFrame: (arglist_t)argframe
|
|
|
|
|
{
|
2009-10-04 09:53:19 +00:00
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Obsolete method called"];
|
|
|
|
|
return 0;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-12-08 19:06:00 +00:00
|
|
|
|
/*
|
|
|
|
|
* NSDistantObject's -forwardInvocation: method calls this to send the message
|
|
|
|
|
* over the wire.
|
|
|
|
|
*/
|
2005-02-22 11:22:44 +00:00
|
|
|
|
- (void) forwardInvocation: (NSInvocation*)inv
|
|
|
|
|
forProxy: (NSDistantObject*)object
|
2000-12-08 19:06:00 +00:00
|
|
|
|
{
|
|
|
|
|
NSPortCoder *op;
|
|
|
|
|
BOOL outParams;
|
|
|
|
|
BOOL needsResponse;
|
|
|
|
|
const char *type;
|
2009-10-04 15:26:07 +00:00
|
|
|
|
unsigned seq;
|
2008-06-18 13:11:11 +00:00
|
|
|
|
NSRunLoop *runLoop = GSRunLoopForThread(nil);
|
2000-12-08 19:06:00 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if ([IrunLoops indexOfObjectIdenticalTo: runLoop] == NSNotFound)
|
2003-09-15 13:54:06 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (ImultipleThreads == NO)
|
2003-09-15 13:54:06 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSObjectInaccessibleException
|
|
|
|
|
format: @"Forwarding message in wrong thread"];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[self addRunLoop: runLoop];
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2000-12-08 19:06:00 +00:00
|
|
|
|
/* Encode the method on an RMC, and send it. */
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSParameterAssert (IisValid);
|
2000-12-08 19:06:00 +00:00
|
|
|
|
|
|
|
|
|
/* get the method types from the selector */
|
|
|
|
|
type = [[inv methodSignature] methodType];
|
|
|
|
|
if (type == 0 || *type == '\0')
|
|
|
|
|
{
|
|
|
|
|
type = [[object methodSignatureForSelector: [inv selector]] methodType];
|
|
|
|
|
if (type)
|
|
|
|
|
{
|
2003-08-24 23:07:41 +00:00
|
|
|
|
sel_register_typed_name(GSNameFromSelector([inv selector]), type);
|
2000-12-08 19:06:00 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
NSParameterAssert(type);
|
|
|
|
|
NSParameterAssert(*type);
|
|
|
|
|
|
2009-10-04 15:26:07 +00:00
|
|
|
|
op = [self _makeOutRmc: 0 generate: (int*)&seq reply: YES];
|
2000-12-08 19:06:00 +00:00
|
|
|
|
|
|
|
|
|
if (debug_connection > 4)
|
2009-10-04 15:26:07 +00:00
|
|
|
|
NSLog(@"building packet seq %d", seq);
|
2000-12-08 19:06:00 +00:00
|
|
|
|
|
2003-04-04 14:15:30 +00:00
|
|
|
|
[inv setTarget: object];
|
2001-09-19 21:31:18 +00:00
|
|
|
|
outParams = [inv encodeWithDistantCoder: op passPointers: NO];
|
2000-12-08 19:06:00 +00:00
|
|
|
|
|
|
|
|
|
if (outParams == YES)
|
|
|
|
|
{
|
|
|
|
|
needsResponse = YES;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int flags;
|
|
|
|
|
|
|
|
|
|
needsResponse = NO;
|
|
|
|
|
flags = objc_get_type_qualifiers(type);
|
|
|
|
|
if ((flags & _F_ONEWAY) == 0)
|
|
|
|
|
{
|
|
|
|
|
needsResponse = YES;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const char *tmptype = objc_skip_type_qualifiers(type);
|
|
|
|
|
|
|
|
|
|
if (*tmptype != _C_VOID)
|
|
|
|
|
{
|
|
|
|
|
needsResponse = YES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[self _sendOutRmc: op type: METHOD_REQUEST];
|
2008-11-21 09:35:41 +00:00
|
|
|
|
NSDebugMLLog(@"NSConnection", @"Sent message %s RMC %d to 0x%x",
|
2009-10-04 15:26:07 +00:00
|
|
|
|
GSNameFromSelector([inv selector]), seq, (uintptr_t)self);
|
2000-12-08 19:06:00 +00:00
|
|
|
|
|
|
|
|
|
if (needsResponse == NO)
|
|
|
|
|
{
|
2001-04-11 12:30:32 +00:00
|
|
|
|
GSIMapNode node;
|
|
|
|
|
|
2000-12-08 19:06:00 +00:00
|
|
|
|
/*
|
|
|
|
|
* Since we don't need a response, we can remove the placeholder from
|
2009-09-07 16:25:04 +00:00
|
|
|
|
* the IreplyMap. However, in case the other end has already sent us
|
2001-04-11 12:30:32 +00:00
|
|
|
|
* a response, we must check for it and scrap it if necessary.
|
2000-12-08 19:06:00 +00:00
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
2009-10-04 15:26:07 +00:00
|
|
|
|
node = GSIMapNodeForKey(IreplyMap, (GSIMapKey)seq);
|
2001-04-11 12:30:32 +00:00
|
|
|
|
if (node != 0 && node->value.obj != dummyObject)
|
|
|
|
|
{
|
|
|
|
|
BOOL is_exception = NO;
|
|
|
|
|
SEL sel = [inv selector];
|
|
|
|
|
|
|
|
|
|
[node->value.obj decodeValueOfObjCType: @encode(BOOL)
|
|
|
|
|
at: &is_exception];
|
|
|
|
|
if (is_exception == YES)
|
|
|
|
|
NSLog(@"Got exception with %@", NSStringFromSelector(sel));
|
|
|
|
|
else
|
|
|
|
|
NSLog(@"Got response with %@", NSStringFromSelector(sel));
|
|
|
|
|
[self _doneInRmc: node->value.obj];
|
|
|
|
|
}
|
2009-10-04 15:26:07 +00:00
|
|
|
|
GSIMapRemoveKey(IreplyMap, (GSIMapKey)seq);
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-12-08 19:06:00 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-10-04 09:53:19 +00:00
|
|
|
|
int argnum;
|
|
|
|
|
int flags;
|
|
|
|
|
const char *tmptype;
|
|
|
|
|
void *datum;
|
2009-10-04 08:43:56 +00:00
|
|
|
|
NSPortCoder *aRmc;
|
2009-10-04 09:53:19 +00:00
|
|
|
|
BOOL is_exception;
|
2009-10-04 08:43:56 +00:00
|
|
|
|
|
|
|
|
|
if ([self isValid] == NO)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
|
format: @"connection waiting for request was shut down"];
|
|
|
|
|
}
|
2009-10-04 15:26:07 +00:00
|
|
|
|
aRmc = [self _getReplyRmc: seq];
|
2009-10-04 08:43:56 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Find out if the server is returning an exception instead
|
|
|
|
|
* of the return values.
|
|
|
|
|
*/
|
|
|
|
|
[aRmc decodeValueOfObjCType: @encode(BOOL) at: &is_exception];
|
|
|
|
|
if (is_exception == YES)
|
|
|
|
|
{
|
|
|
|
|
/* Decode the exception object, and raise it. */
|
|
|
|
|
id exc = [aRmc decodeObject];
|
|
|
|
|
|
|
|
|
|
[self _doneInReply: aRmc];
|
|
|
|
|
[exc raise];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the return type qualifier flags, and the return type. */
|
|
|
|
|
flags = objc_get_type_qualifiers(type);
|
|
|
|
|
tmptype = objc_skip_type_qualifiers(type);
|
|
|
|
|
|
|
|
|
|
/* Decode the return value and pass-by-reference values, if there
|
|
|
|
|
are any. OUT_PARAMETERS should be the value returned by
|
|
|
|
|
cifframe_dissect_call(). */
|
|
|
|
|
if (outParams || *tmptype != _C_VOID || (flags & _F_ONEWAY) == 0)
|
|
|
|
|
/* xxx What happens with method declared "- (oneway) foo: (out int*)ip;" */
|
|
|
|
|
/* xxx What happens with method declared "- (in char *) bar;" */
|
|
|
|
|
/* xxx Is this right? Do we also have to check _F_ONEWAY? */
|
|
|
|
|
{
|
|
|
|
|
/* If there is a return value, decode it, and put it in datum. */
|
|
|
|
|
if (*tmptype != _C_VOID || (flags & _F_ONEWAY) == 0)
|
|
|
|
|
{
|
|
|
|
|
switch (*tmptype)
|
|
|
|
|
{
|
|
|
|
|
case _C_PTR:
|
|
|
|
|
/* We are returning a pointer to something. */
|
|
|
|
|
tmptype++;
|
|
|
|
|
datum = alloca (objc_sizeof_type (tmptype));
|
|
|
|
|
[aRmc decodeValueOfObjCType: tmptype at: datum];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_VOID:
|
|
|
|
|
datum = alloca (sizeof (int));
|
|
|
|
|
[aRmc decodeValueOfObjCType: @encode(int) at: datum];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
datum = alloca (objc_sizeof_type (tmptype));
|
|
|
|
|
[aRmc decodeValueOfObjCType: tmptype at: datum];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[inv setReturnValue: datum];
|
|
|
|
|
|
|
|
|
|
/* Decode the values returned by reference. Note: this logic
|
|
|
|
|
must match exactly the code in _service_forwardForProxy:
|
|
|
|
|
*/
|
|
|
|
|
if (outParams)
|
|
|
|
|
{
|
|
|
|
|
/* Step through all the arguments, finding the ones that were
|
|
|
|
|
passed by reference. */
|
|
|
|
|
for (tmptype = objc_skip_argspec (tmptype), argnum = 0;
|
|
|
|
|
*tmptype != '\0';
|
|
|
|
|
tmptype = objc_skip_argspec (tmptype), argnum++)
|
|
|
|
|
{
|
|
|
|
|
/* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */
|
|
|
|
|
flags = objc_get_type_qualifiers(tmptype);
|
|
|
|
|
/* Skip over the type qualifiers, so now TYPE is
|
|
|
|
|
pointing directly at the char corresponding to the
|
|
|
|
|
argument's type, as defined in <objc/objc-api.h> */
|
|
|
|
|
tmptype = objc_skip_type_qualifiers(tmptype);
|
|
|
|
|
|
|
|
|
|
if (*tmptype == _C_PTR
|
|
|
|
|
&& ((flags & _F_OUT) || !(flags & _F_IN)))
|
|
|
|
|
{
|
2009-10-04 09:53:19 +00:00
|
|
|
|
/* If the arg was myref, we obtain its address
|
|
|
|
|
* and decode the data directly to it.
|
|
|
|
|
*/
|
2009-10-04 08:43:56 +00:00
|
|
|
|
tmptype++;
|
2009-10-04 09:53:19 +00:00
|
|
|
|
[inv getArgument: &datum atIndex: argnum];
|
2009-10-04 08:43:56 +00:00
|
|
|
|
[aRmc decodeValueOfObjCType: tmptype at: datum];
|
|
|
|
|
}
|
|
|
|
|
else if (*tmptype == _C_CHARPTR
|
|
|
|
|
&& ((flags & _F_OUT) || !(flags & _F_IN)))
|
|
|
|
|
{
|
|
|
|
|
[aRmc decodeValueOfObjCType: tmptype at: &datum];
|
2009-10-04 09:53:19 +00:00
|
|
|
|
[inv setArgument: datum atIndex: argnum];
|
2009-10-04 08:43:56 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[self _doneInReply: aRmc];
|
2000-12-08 19:06:00 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (const char *) typeForSelector: (SEL)sel remoteTarget: (unsigned)target
|
|
|
|
|
{
|
|
|
|
|
id op, ip;
|
|
|
|
|
char *type = 0;
|
|
|
|
|
int seq_num;
|
2003-04-11 15:43:45 +00:00
|
|
|
|
NSData *data;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSParameterAssert(IreceivePort);
|
|
|
|
|
NSParameterAssert (IisValid);
|
2000-07-05 12:23:00 +00:00
|
|
|
|
op = [self _makeOutRmc: 0 generate: &seq_num reply: YES];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[op encodeValueOfObjCType: ":" at: &sel];
|
|
|
|
|
[op encodeValueOfObjCType: @encode(unsigned) at: &target];
|
|
|
|
|
[self _sendOutRmc: op type: METHODTYPE_REQUEST];
|
|
|
|
|
ip = [self _getReplyRmc: seq_num];
|
|
|
|
|
[ip decodeValueOfObjCType: @encode(char*) at: &type];
|
2003-04-11 15:43:45 +00:00
|
|
|
|
data = type ? [NSData dataWithBytes: type length: strlen(type)+1] : nil;
|
2001-04-11 12:30:32 +00:00
|
|
|
|
[self _doneInRmc: ip];
|
2003-04-11 15:43:45 +00:00
|
|
|
|
return (const char*)[data bytes];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Class-wide stats and collections. */
|
|
|
|
|
|
|
|
|
|
+ (unsigned) connectionsCount
|
|
|
|
|
{
|
|
|
|
|
unsigned result;
|
|
|
|
|
|
|
|
|
|
M_LOCK(connection_table_gate);
|
|
|
|
|
result = NSCountHashTable(connection_table);
|
|
|
|
|
M_UNLOCK(connection_table_gate);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (unsigned) connectionsCountWithInPort: (NSPort*)aPort
|
|
|
|
|
{
|
|
|
|
|
unsigned count = 0;
|
|
|
|
|
NSHashEnumerator enumerator;
|
|
|
|
|
NSConnection *o;
|
|
|
|
|
|
|
|
|
|
M_LOCK(connection_table_gate);
|
|
|
|
|
enumerator = NSEnumerateHashTable(connection_table);
|
|
|
|
|
while ((o = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil)
|
|
|
|
|
{
|
|
|
|
|
if ([aPort isEqual: [o receivePort]])
|
|
|
|
|
{
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-05-28 05:23:36 +00:00
|
|
|
|
NSEndHashTableEnumeration(&enumerator);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
M_UNLOCK(connection_table_gate);
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation NSConnection (Private)
|
|
|
|
|
|
|
|
|
|
- (void) handlePortMessage: (NSPortMessage*)msg
|
|
|
|
|
{
|
|
|
|
|
NSPortCoder *rmc;
|
|
|
|
|
int type = [msg msgid];
|
|
|
|
|
NSMutableArray *components = [msg _components];
|
|
|
|
|
NSPort *rp = [msg receivePort];
|
|
|
|
|
NSPort *sp = [msg sendPort];
|
|
|
|
|
NSConnection *conn;
|
|
|
|
|
|
|
|
|
|
if (debug_connection > 4)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"handling packet of type %d (%@)", type, stringFromMsgType(type));
|
|
|
|
|
}
|
|
|
|
|
conn = [connectionClass connectionWithReceivePort: rp sendPort: sp];
|
|
|
|
|
if (conn == nil)
|
|
|
|
|
{
|
2008-10-17 09:51:23 +00:00
|
|
|
|
NSLog(@"Received port message for unknown connection - %@", msg);
|
|
|
|
|
NSLog(@"All connections: %@", [NSConnection allConnections]);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if ([conn isValid] == NO)
|
|
|
|
|
{
|
|
|
|
|
if (debug_connection)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"received port message for invalid connection - %@", msg);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2000-09-12 05:16:01 +00:00
|
|
|
|
if (debug_connection > 4)
|
|
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
|
NSLog(@" connection is %@", conn);
|
2000-09-12 05:16:01 +00:00
|
|
|
|
}
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (GSIVar(conn, _authenticateIn) == YES
|
2000-07-04 14:37:18 +00:00
|
|
|
|
&& (type == METHOD_REQUEST || type == METHOD_REPLY))
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
|
|
|
|
NSData *d;
|
|
|
|
|
unsigned count = [components count];
|
|
|
|
|
|
2000-07-04 14:37:18 +00:00
|
|
|
|
d = RETAIN([components objectAtIndex: --count]);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[components removeObjectAtIndex: count];
|
2000-07-04 14:37:18 +00:00
|
|
|
|
if ([[conn delegate] authenticateComponents: components
|
2000-07-04 11:05:46 +00:00
|
|
|
|
withData: d] == NO)
|
|
|
|
|
{
|
2000-07-04 14:37:18 +00:00
|
|
|
|
RELEASE(d);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[NSException raise: NSFailedAuthenticationException
|
|
|
|
|
format: @"message not authenticated by delegate"];
|
|
|
|
|
}
|
2000-07-04 14:37:18 +00:00
|
|
|
|
RELEASE(d);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rmc = [conn _makeInRmc: components];
|
2001-04-11 12:30:32 +00:00
|
|
|
|
if (debug_connection > 5)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"made rmc 0x%x for %d", rmc, type);
|
|
|
|
|
}
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
2005-02-22 11:22:44 +00:00
|
|
|
|
case ROOTPROXY_REQUEST:
|
2000-07-04 11:05:46 +00:00
|
|
|
|
/* It won't take much time to handle this, so go ahead and service
|
|
|
|
|
it, even if we are waiting for a reply. */
|
|
|
|
|
[conn _service_rootObject: rmc];
|
|
|
|
|
break;
|
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
|
case METHODTYPE_REQUEST:
|
2000-07-04 11:05:46 +00:00
|
|
|
|
/* It won't take much time to handle this, so go ahead and service
|
|
|
|
|
it, even if we are waiting for a reply. */
|
|
|
|
|
[conn _service_typeForSelector: rmc];
|
|
|
|
|
break;
|
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
|
case METHOD_REQUEST:
|
2000-07-04 11:05:46 +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 independent_queuing is NO.
|
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(GSIVar(conn, _refGate));
|
|
|
|
|
if (GSIVar(conn, _requestDepth) == 0
|
|
|
|
|
|| GSIVar(conn, _independentQueueing) == NO)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIVar(conn, _requestDepth)++;
|
|
|
|
|
M_UNLOCK(GSIVar(conn, _refGate));
|
2003-05-02 11:54:54 +00:00
|
|
|
|
[conn _service_forwardForProxy: rmc]; // Catches exceptions
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(GSIVar(conn, _refGate));
|
|
|
|
|
GSIVar(conn, _requestDepth)--;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[GSIVar(conn, _requestQueue) addObject: rmc];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Service any requests that were queued while we
|
|
|
|
|
* were waiting for replies.
|
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
while (GSIVar(conn, _requestDepth) == 0
|
|
|
|
|
&& [GSIVar(conn, _requestQueue) count] > 0)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
rmc = [GSIVar(conn, _requestQueue) objectAtIndex: 0];
|
|
|
|
|
[GSIVar(conn, _requestQueue) removeObjectAtIndex: 0];
|
|
|
|
|
M_UNLOCK(GSIVar(conn, _refGate));
|
2003-05-02 11:54:54 +00:00
|
|
|
|
[conn _service_forwardForProxy: rmc]; // Catches exceptions
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(GSIVar(conn, _refGate));
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(GSIVar(conn, _refGate));
|
2000-07-04 11:05:46 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* For replies, we read the sequence number from the reply object and
|
|
|
|
|
* store it in a map using thee sequence number as the key. That way
|
|
|
|
|
* it's easy for the connection to find replies by their numbers.
|
|
|
|
|
*/
|
2005-02-22 11:22:44 +00:00
|
|
|
|
case ROOTPROXY_REPLY:
|
|
|
|
|
case METHOD_REPLY:
|
|
|
|
|
case METHODTYPE_REPLY:
|
|
|
|
|
case RETAIN_REPLY:
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2000-07-05 12:23:00 +00:00
|
|
|
|
int sequence;
|
|
|
|
|
GSIMapNode node;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
[rmc decodeValueOfObjCType: @encode(int) at: &sequence];
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (type == ROOTPROXY_REPLY && GSIVar(conn, _keepaliveWait) == YES
|
|
|
|
|
&& sequence == GSIVar(conn, _lastKeepalive))
|
2008-11-21 08:02:41 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIVar(conn, _keepaliveWait) = NO;
|
2008-11-21 08:02:41 +00:00
|
|
|
|
NSDebugMLLog(@"NSConnection", @"Handled keepalive %d on %@",
|
|
|
|
|
sequence, conn);
|
|
|
|
|
[self _doneInRmc: rmc];
|
2008-12-07 16:03:29 +00:00
|
|
|
|
break;
|
2008-11-21 08:02:41 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(GSIVar(conn, _refGate));
|
|
|
|
|
node = GSIMapNodeForKey(GSIVar(conn, _replyMap), (GSIMapKey)sequence);
|
2000-07-05 12:23:00 +00:00
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
|
NSDebugMLLog(@"NSConnection", @"Ignoring reply RMC %d on %@",
|
2000-09-12 05:16:01 +00:00
|
|
|
|
sequence, conn);
|
2001-04-11 12:30:32 +00:00
|
|
|
|
[self _doneInRmc: rmc];
|
2000-07-05 12:23:00 +00:00
|
|
|
|
}
|
|
|
|
|
else if (node->value.obj == dummyObject)
|
|
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
|
NSDebugMLLog(@"NSConnection", @"Saving reply RMC %d on %@",
|
2001-04-11 12:30:32 +00:00
|
|
|
|
sequence, conn);
|
2000-07-05 12:23:00 +00:00
|
|
|
|
node->value.obj = rmc;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2005-11-09 16:30:57 +00:00
|
|
|
|
NSDebugMLLog(@"NSConnection", @"Replace reply RMC %d on %@",
|
2000-09-12 05:16:01 +00:00
|
|
|
|
sequence, conn);
|
2001-04-11 12:30:32 +00:00
|
|
|
|
[self _doneInRmc: node->value.obj];
|
2000-07-05 12:23:00 +00:00
|
|
|
|
node->value.obj = rmc;
|
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(GSIVar(conn, _refGate));
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
|
case CONNECTION_SHUTDOWN:
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
|
|
|
|
[conn _service_shutdown: rmc];
|
|
|
|
|
break;
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
case PROXY_RELEASE:
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
|
|
|
|
[conn _service_release: rmc];
|
|
|
|
|
break;
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
case PROXY_RETAIN:
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
|
|
|
|
[conn _service_retain: rmc];
|
|
|
|
|
break;
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
default:
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
|
format: @"unrecognized NSPortCoder identifier"];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _runInNewThread
|
|
|
|
|
{
|
2004-11-25 17:00:45 +00:00
|
|
|
|
NSRunLoop *loop = GSRunLoopForThread(nil);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
[self addRunLoop: loop];
|
|
|
|
|
[loop run];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) setDebug: (int)val
|
|
|
|
|
{
|
|
|
|
|
debug_connection = val;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-21 08:02:41 +00:00
|
|
|
|
- (void) _keepalive: (NSNotification*)n
|
|
|
|
|
{
|
|
|
|
|
if ([self isValid])
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (IkeepaliveWait == NO)
|
2008-11-21 08:02:41 +00:00
|
|
|
|
{
|
|
|
|
|
NSPortCoder *op;
|
|
|
|
|
|
|
|
|
|
/* Send out a root proxy request to ping the other end.
|
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
op = [self _makeOutRmc: 0 generate: &IlastKeepalive reply: NO];
|
|
|
|
|
IkeepaliveWait = YES;
|
2008-11-21 08:02:41 +00:00
|
|
|
|
[self _sendOutRmc: op type: ROOTPROXY_REQUEST];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* keepalive timeout outstanding still.
|
|
|
|
|
*/
|
|
|
|
|
[self invalidate];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-21 10:41:43 +00:00
|
|
|
|
/**
|
|
|
|
|
*/
|
2008-11-21 08:02:41 +00:00
|
|
|
|
- (void) _enableKeepalive
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IuseKeepalive = YES; /* Set so that child connections will inherit. */
|
|
|
|
|
IkeepaliveWait = NO;
|
|
|
|
|
if (IreceivePort !=IsendPort)
|
2008-11-21 08:02:41 +00:00
|
|
|
|
{
|
2008-11-21 10:41:43 +00:00
|
|
|
|
/* If this is not a listening connection, we actually enable the
|
|
|
|
|
* keepalive timing (usng the regular housekeeping notifications)
|
|
|
|
|
* and must also enable multiple thread support as the keepalive
|
|
|
|
|
* notification may arrive in a different thread from the one we
|
|
|
|
|
* are running in.
|
|
|
|
|
*/
|
|
|
|
|
[self enableMultipleThreads];
|
|
|
|
|
[[NSNotificationCenter defaultCenter] addObserver: self
|
|
|
|
|
selector: @selector(_keepalive:)
|
|
|
|
|
name: @"GSHousekeeping" object: nil];
|
2008-11-21 08:02:41 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-19 21:31:18 +00:00
|
|
|
|
|
|
|
|
|
/* NSConnection calls this to service the incoming method request. */
|
|
|
|
|
- (void) _service_forwardForProxy: (NSPortCoder*)aRmc
|
|
|
|
|
{
|
|
|
|
|
char *forward_type = 0;
|
2009-10-04 15:26:07 +00:00
|
|
|
|
NSPortCoder *decoder = nil;
|
|
|
|
|
NSPortCoder *encoder = nil;
|
|
|
|
|
NSInvocation *inv = nil;
|
|
|
|
|
unsigned seq;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2001-09-19 21:31:18 +00:00
|
|
|
|
/*
|
|
|
|
|
* Make sure don't let exceptions caused by servicing the client's
|
|
|
|
|
* request cause us to crash.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
2009-10-04 15:26:07 +00:00
|
|
|
|
NSRunLoop *runLoop = GSRunLoopForThread(nil);
|
|
|
|
|
const char *type;
|
|
|
|
|
const char *tmptype;
|
|
|
|
|
const char *etmptype;
|
|
|
|
|
id tmp;
|
|
|
|
|
id object;
|
|
|
|
|
SEL selector;
|
|
|
|
|
GSMethod meth = 0;
|
|
|
|
|
BOOL is_exception = NO;
|
|
|
|
|
unsigned flags;
|
|
|
|
|
int argnum;
|
|
|
|
|
BOOL out_parameters = NO;
|
|
|
|
|
NSMethodSignature *sig;
|
|
|
|
|
const char *encoded_types = forward_type;
|
2003-09-15 13:54:06 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSParameterAssert (IisValid);
|
|
|
|
|
if ([IrunLoops indexOfObjectIdenticalTo: runLoop] == NSNotFound)
|
2003-09-15 13:54:06 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (ImultipleThreads == YES)
|
2003-09-15 13:54:06 +00:00
|
|
|
|
{
|
|
|
|
|
[self addRunLoop: runLoop];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSObjectInaccessibleException
|
|
|
|
|
format: @"Message received in wrong thread"];
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
/* Save this for later */
|
2009-10-04 15:26:07 +00:00
|
|
|
|
[aRmc decodeValueOfObjCType: @encode(int) at: &seq];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2001-09-19 21:31:18 +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.
|
|
|
|
|
*/
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[aRmc decodeValueOfObjCType: @encode(char*) at: &forward_type];
|
|
|
|
|
|
|
|
|
|
if (debug_connection > 1)
|
2008-11-21 09:35:41 +00:00
|
|
|
|
NSLog(
|
|
|
|
|
@"Handling message (sig %s) RMC %d from %@",
|
2009-10-04 15:26:07 +00:00
|
|
|
|
forward_type, seq, (uintptr_t)self);
|
2008-11-21 09:35:41 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IreqInCount++; /* Handling an incoming request. */
|
2001-09-19 21:31:18 +00:00
|
|
|
|
|
2009-10-04 15:26:07 +00:00
|
|
|
|
encoded_types = forward_type;
|
2009-10-04 09:53:19 +00:00
|
|
|
|
etmptype = encoded_types;
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
2009-10-04 15:26:07 +00:00
|
|
|
|
decoder = aRmc;
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
/* Decode the object, (which is always the first argument to a method). */
|
2009-10-04 15:26:07 +00:00
|
|
|
|
[decoder decodeValueOfObjCType: @encode(id) at: &object];
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
2009-10-04 15:26:07 +00:00
|
|
|
|
/* Decode the selector, (which is the second argument to a method). */
|
2009-10-04 09:53:19 +00:00
|
|
|
|
/* xxx @encode(SEL) produces "^v" in gcc 2.5.8. It should be ":" */
|
2009-10-04 15:26:07 +00:00
|
|
|
|
[decoder decodeValueOfObjCType: @encode(SEL) at: &selector];
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
/* Get the "selector type" for this method. The "selector type" is
|
|
|
|
|
a string that lists the return and argument types, and also
|
|
|
|
|
indicates in which registers and where on the stack the arguments
|
|
|
|
|
should be placed before the method call. The selector type
|
|
|
|
|
string we get here should have the same argument and return types
|
|
|
|
|
as the ENCODED_TYPES string, but it will have different register
|
|
|
|
|
and stack locations if the ENCODED_TYPES came from a machine of a
|
|
|
|
|
different architecture. */
|
|
|
|
|
if (GSObjCIsClass(object))
|
|
|
|
|
{
|
|
|
|
|
meth = GSGetMethod(object, selector, NO, YES);
|
|
|
|
|
}
|
|
|
|
|
else if (GSObjCIsInstance(object))
|
|
|
|
|
{
|
|
|
|
|
meth = GSGetMethod(GSObjCClass(object), selector, YES, YES);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"decoded object %p is invalid", object];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (meth != 0)
|
|
|
|
|
{
|
|
|
|
|
type = meth->method_types;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSDebugLog(@"Local object <%p %s> doesn't implement: %s directly. "
|
|
|
|
|
@"Will search for arbitrary signature.",
|
|
|
|
|
object,
|
|
|
|
|
GSNameFromClass(GSObjCIsClass(object)
|
|
|
|
|
? object : (id)GSObjCClass(object)),
|
|
|
|
|
GSNameFromSelector(selector));
|
|
|
|
|
type = GSTypesFromSelector(selector);
|
|
|
|
|
}
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
/* Make sure we successfully got the method type, and that its
|
|
|
|
|
types match the ENCODED_TYPES. */
|
|
|
|
|
NSCParameterAssert (type);
|
|
|
|
|
if (GSSelectorTypesMatch(encoded_types, type) == NO)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"NSConection types (%s / %s) missmatch for %s",
|
|
|
|
|
encoded_types, type, GSNameFromSelector(selector)];
|
|
|
|
|
}
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
sig = [NSMethodSignature signatureWithObjCTypes: type];
|
|
|
|
|
inv = [[NSInvocation alloc] initWithMethodSignature: sig];
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
tmptype = objc_skip_argspec (type);
|
|
|
|
|
etmptype = objc_skip_argspec (etmptype);
|
|
|
|
|
[inv setTarget: object];
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
tmptype = objc_skip_argspec (tmptype);
|
|
|
|
|
etmptype = objc_skip_argspec (etmptype);
|
|
|
|
|
[inv setSelector: selector];
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
/* Step TMPTYPE and ETMPTYPE in lock-step through their
|
|
|
|
|
method type strings. */
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
for (tmptype = objc_skip_argspec (tmptype),
|
|
|
|
|
etmptype = objc_skip_argspec (etmptype), argnum = 2;
|
|
|
|
|
*tmptype != '\0';
|
|
|
|
|
tmptype = objc_skip_argspec (tmptype),
|
|
|
|
|
etmptype = objc_skip_argspec (etmptype), argnum++)
|
|
|
|
|
{
|
|
|
|
|
void *datum;
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
/* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */
|
|
|
|
|
flags = objc_get_type_qualifiers (etmptype);
|
|
|
|
|
/* Skip over the type qualifiers, so now TYPE is pointing directly
|
|
|
|
|
at the char corresponding to the argument's type, as defined
|
|
|
|
|
in <objc/objc-api.h> */
|
|
|
|
|
tmptype = objc_skip_type_qualifiers(tmptype);
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
/* Decide how, (or whether or not), to decode the argument
|
|
|
|
|
depending on its FLAGS and TMPTYPE. Only the first two cases
|
|
|
|
|
involve parameters that may potentially be passed by
|
|
|
|
|
reference, and thus only the first two may change the value
|
|
|
|
|
of OUT_PARAMETERS. *** Note: This logic must match exactly
|
|
|
|
|
the code in cifframe_dissect_call(); that function should
|
|
|
|
|
encode exactly what we decode here. *** */
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
switch (*tmptype)
|
|
|
|
|
{
|
|
|
|
|
case _C_CHARPTR:
|
|
|
|
|
/* Handle a (char*) argument. */
|
|
|
|
|
/* If the char* is qualified as an OUT parameter, or if it
|
|
|
|
|
not explicitly qualified as an IN parameter, then we will
|
|
|
|
|
have to get this char* again after the method is run,
|
|
|
|
|
because the method may have changed it. Set
|
|
|
|
|
OUT_PARAMETERS accordingly. */
|
|
|
|
|
if ((flags & _F_OUT) || !(flags & _F_IN))
|
|
|
|
|
out_parameters = YES;
|
|
|
|
|
/* If the char* is qualified as an IN parameter, or not
|
|
|
|
|
explicity qualified as an OUT parameter, then decode it.
|
|
|
|
|
Note: the decoder allocates memory for holding the
|
|
|
|
|
string, and it is also responsible for making sure that
|
|
|
|
|
the memory gets freed eventually, (usually through the
|
|
|
|
|
autorelease of NSData object). */
|
|
|
|
|
if ((flags & _F_IN) || !(flags & _F_OUT))
|
|
|
|
|
{
|
|
|
|
|
datum = alloca (sizeof(char*));
|
2009-10-04 15:26:07 +00:00
|
|
|
|
[decoder decodeValueOfObjCType: tmptype at: datum];
|
2009-10-04 09:53:19 +00:00
|
|
|
|
[inv setArgument: datum atIndex: argnum];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _C_PTR:
|
|
|
|
|
/* If the pointer's value is qualified as an OUT parameter,
|
|
|
|
|
or if it not explicitly qualified as an IN parameter,
|
|
|
|
|
then we will have to get the value pointed to again after
|
|
|
|
|
the method is run, because the method may have changed
|
|
|
|
|
it. Set OUT_PARAMETERS accordingly. */
|
|
|
|
|
if ((flags & _F_OUT) || !(flags & _F_IN))
|
|
|
|
|
out_parameters = YES;
|
|
|
|
|
|
|
|
|
|
/* Handle an argument that is a pointer to a non-char. But
|
|
|
|
|
(void*) and (anything**) is not allowed. */
|
|
|
|
|
/* The argument is a pointer to something; increment TYPE
|
|
|
|
|
so we can see what it is a pointer to. */
|
|
|
|
|
tmptype++;
|
|
|
|
|
/* If the pointer's value is qualified as an IN parameter,
|
|
|
|
|
or not explicity qualified as an OUT parameter, then
|
|
|
|
|
decode it. */
|
|
|
|
|
if ((flags & _F_IN) || !(flags & _F_OUT))
|
|
|
|
|
{
|
|
|
|
|
datum = alloca (objc_sizeof_type (tmptype));
|
2009-10-04 15:26:07 +00:00
|
|
|
|
[decoder decodeValueOfObjCType: tmptype at: datum];
|
2009-10-04 09:53:19 +00:00
|
|
|
|
[inv setArgument: &datum atIndex: argnum];
|
|
|
|
|
}
|
|
|
|
|
break;
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
default:
|
|
|
|
|
datum = alloca (objc_sizeof_type (tmptype));
|
|
|
|
|
if (*tmptype == _C_ID)
|
|
|
|
|
{
|
2009-10-04 15:26:07 +00:00
|
|
|
|
*(id*)datum = [decoder decodeObject];
|
2009-10-04 09:53:19 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-10-04 15:26:07 +00:00
|
|
|
|
[decoder decodeValueOfObjCType: tmptype at: datum];
|
2009-10-04 09:53:19 +00:00
|
|
|
|
}
|
|
|
|
|
[inv setArgument: datum atIndex: argnum];
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
/* Stop using the decoder.
|
|
|
|
|
*/
|
2009-10-04 15:26:07 +00:00
|
|
|
|
tmp = decoder;
|
|
|
|
|
decoder = nil;
|
|
|
|
|
[self _doneInRmc: tmp];
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
/* Invoke the method! */
|
|
|
|
|
[inv invoke];
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
/* It is possible that our connection died while the method was
|
|
|
|
|
* being called - in this case we mustn't try to send the result
|
|
|
|
|
* back to the remote application!
|
|
|
|
|
*/
|
|
|
|
|
if ([self isValid] == NO)
|
|
|
|
|
{
|
2009-10-04 15:26:07 +00:00
|
|
|
|
tmp = inv;
|
|
|
|
|
inv = nil;
|
|
|
|
|
[tmp release];
|
2009-11-27 13:05:26 +00:00
|
|
|
|
NS_VOIDRETURN;
|
2009-10-04 07:46:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
/* Encode the return value and pass-by-reference values, if there
|
|
|
|
|
are any. This logic must match exactly that in
|
|
|
|
|
cifframe_build_return(). */
|
|
|
|
|
/* OUT_PARAMETERS should be true here in exactly the same
|
|
|
|
|
situations as it was true in cifframe_dissect_call(). */
|
|
|
|
|
|
|
|
|
|
/* Get the qualifier type of the return value. */
|
|
|
|
|
flags = objc_get_type_qualifiers (encoded_types);
|
|
|
|
|
/* Get the return type; store it our two temporary char*'s. */
|
|
|
|
|
etmptype = objc_skip_type_qualifiers (encoded_types);
|
|
|
|
|
tmptype = objc_skip_type_qualifiers (type);
|
|
|
|
|
|
2009-11-27 13:05:26 +00:00
|
|
|
|
/* If this is a oneway void with no out parameters, we don't need to
|
|
|
|
|
* send back any response.
|
|
|
|
|
*/
|
|
|
|
|
if (*tmptype == _C_VOID && (flags & _F_ONEWAY) && !out_parameters)
|
|
|
|
|
{
|
|
|
|
|
tmp = inv;
|
|
|
|
|
inv = nil;
|
|
|
|
|
[tmp release];
|
|
|
|
|
NS_VOIDRETURN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We create a new coder object and encode a flag to
|
|
|
|
|
* say that this is not an exception.
|
|
|
|
|
*/
|
|
|
|
|
encoder = [self _makeOutRmc: seq generate: 0 reply: NO];
|
|
|
|
|
[encoder encodeValueOfObjCType: @encode(BOOL) at: &is_exception];
|
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
/* Only encode return values if there is a non-void return value,
|
|
|
|
|
a non-oneway void return value, or if there are values that were
|
|
|
|
|
passed by reference. */
|
|
|
|
|
|
|
|
|
|
if (*tmptype == _C_VOID)
|
2009-10-04 07:46:01 +00:00
|
|
|
|
{
|
2009-10-04 09:53:19 +00:00
|
|
|
|
if ((flags & _F_ONEWAY) == 0)
|
|
|
|
|
{
|
|
|
|
|
int dummy = 0;
|
|
|
|
|
|
2009-10-04 15:26:07 +00:00
|
|
|
|
[encoder encodeValueOfObjCType: @encode(int) at: (void*)&dummy];
|
2009-10-04 09:53:19 +00:00
|
|
|
|
}
|
|
|
|
|
/* No return value to encode; do nothing. */
|
2009-10-04 07:46:01 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-10-04 09:53:19 +00:00
|
|
|
|
void *datum;
|
|
|
|
|
|
|
|
|
|
if (*tmptype == _C_PTR)
|
|
|
|
|
{
|
|
|
|
|
/* The argument is a pointer to something; increment TYPE
|
|
|
|
|
so we can see what it is a pointer to. */
|
|
|
|
|
tmptype++;
|
|
|
|
|
datum = alloca (objc_sizeof_type (tmptype));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
datum = alloca (objc_sizeof_type (tmptype));
|
|
|
|
|
}
|
|
|
|
|
[inv getReturnValue: datum];
|
2009-10-04 15:26:07 +00:00
|
|
|
|
[encoder encodeValueOfObjCType: tmptype at: datum];
|
2009-10-04 07:46:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
/* Encode the values returned by reference. Note: this logic
|
|
|
|
|
must match exactly the code in cifframe_build_return(); that
|
|
|
|
|
function should decode exactly what we encode here. */
|
2009-10-04 07:46:01 +00:00
|
|
|
|
|
2009-10-04 09:53:19 +00:00
|
|
|
|
if (out_parameters)
|
2009-10-04 07:46:01 +00:00
|
|
|
|
{
|
2009-10-04 09:53:19 +00:00
|
|
|
|
/* Step through all the arguments, finding the ones that were
|
|
|
|
|
passed by reference. */
|
|
|
|
|
for (tmptype = objc_skip_argspec (tmptype),
|
|
|
|
|
argnum = 0,
|
|
|
|
|
etmptype = objc_skip_argspec (etmptype);
|
|
|
|
|
*tmptype != '\0';
|
|
|
|
|
tmptype = objc_skip_argspec (tmptype),
|
|
|
|
|
argnum++,
|
|
|
|
|
etmptype = objc_skip_argspec (etmptype))
|
2009-10-04 07:46:01 +00:00
|
|
|
|
{
|
2009-10-04 09:53:19 +00:00
|
|
|
|
/* Get the type qualifiers, like IN, OUT, INOUT, ONEWAY. */
|
|
|
|
|
flags = objc_get_type_qualifiers(etmptype);
|
|
|
|
|
/* Skip over the type qualifiers, so now TYPE is pointing directly
|
|
|
|
|
at the char corresponding to the argument's type, as defined
|
|
|
|
|
in <objc/objc-api.h> */
|
|
|
|
|
tmptype = objc_skip_type_qualifiers (tmptype);
|
|
|
|
|
|
|
|
|
|
/* Decide how, (or whether or not), to encode the argument
|
|
|
|
|
depending on its FLAGS and TMPTYPE. */
|
|
|
|
|
if (((flags & _F_OUT) || !(flags & _F_IN))
|
|
|
|
|
&& (*tmptype == _C_PTR || *tmptype == _C_CHARPTR))
|
2009-10-04 07:46:01 +00:00
|
|
|
|
{
|
2009-10-04 09:53:19 +00:00
|
|
|
|
void *datum;
|
|
|
|
|
|
|
|
|
|
if (*tmptype == _C_PTR)
|
|
|
|
|
{
|
|
|
|
|
/* The argument is a pointer (to a non-char), and the
|
|
|
|
|
pointer's value is qualified as an OUT parameter, or
|
|
|
|
|
it not explicitly qualified as an IN parameter, then
|
|
|
|
|
it is a pass-by-reference argument.*/
|
|
|
|
|
++tmptype;
|
|
|
|
|
[inv getArgument: &datum atIndex: argnum];
|
2009-10-04 15:26:07 +00:00
|
|
|
|
[encoder encodeValueOfObjCType: tmptype at: datum];
|
2009-10-04 09:53:19 +00:00
|
|
|
|
}
|
|
|
|
|
else if (*tmptype == _C_CHARPTR)
|
|
|
|
|
{
|
|
|
|
|
datum = alloca (sizeof (char*));
|
|
|
|
|
[inv getArgument: datum atIndex: argnum];
|
2009-10-04 15:26:07 +00:00
|
|
|
|
[encoder encodeValueOfObjCType: tmptype at: datum];
|
2009-10-04 09:53:19 +00:00
|
|
|
|
}
|
2009-10-04 07:46:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-10-04 15:26:07 +00:00
|
|
|
|
tmp = inv;
|
|
|
|
|
inv = nil;
|
|
|
|
|
[tmp release];
|
|
|
|
|
tmp = encoder;
|
|
|
|
|
encoder = nil;
|
|
|
|
|
[self _sendOutRmc: tmp type: METHOD_REPLY];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
2003-10-21 17:05:36 +00:00
|
|
|
|
if (debug_connection > 3)
|
2005-11-09 16:30:57 +00:00
|
|
|
|
NSLog(@"forwarding exception for (%@) - %@", self, localException);
|
2003-10-21 17:05:36 +00:00
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
/* Send the exception back to the client. */
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (IisValid == YES)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2001-09-19 21:31:18 +00:00
|
|
|
|
BOOL is_exception = YES;
|
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
2001-09-19 21:31:18 +00:00
|
|
|
|
NSPortCoder *op;
|
|
|
|
|
|
2009-10-04 15:26:07 +00:00
|
|
|
|
if (inv != nil)
|
2001-09-21 15:14:57 +00:00
|
|
|
|
{
|
2009-10-04 15:26:07 +00:00
|
|
|
|
[inv release];
|
2001-09-21 15:14:57 +00:00
|
|
|
|
}
|
2009-10-04 15:26:07 +00:00
|
|
|
|
if (decoder != nil)
|
2001-09-19 21:31:18 +00:00
|
|
|
|
{
|
2009-10-04 15:26:07 +00:00
|
|
|
|
[self _failInRmc: decoder];
|
2001-09-19 21:31:18 +00:00
|
|
|
|
}
|
2009-10-04 15:26:07 +00:00
|
|
|
|
if (encoder != nil)
|
2001-04-11 12:30:32 +00:00
|
|
|
|
{
|
2009-10-04 15:26:07 +00:00
|
|
|
|
[self _failOutRmc: encoder];
|
2001-04-11 12:30:32 +00:00
|
|
|
|
}
|
2009-10-04 15:26:07 +00:00
|
|
|
|
op = [self _makeOutRmc: seq generate: 0 reply: NO];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[op encodeValueOfObjCType: @encode(BOOL)
|
|
|
|
|
at: &is_exception];
|
|
|
|
|
[op encodeBycopyObject: localException];
|
|
|
|
|
[self _sendOutRmc: op type: METHOD_REPLY];
|
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"Exception when sending exception back to client - %@",
|
|
|
|
|
localException);
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _service_rootObject: (NSPortCoder*)rmc
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
id rootObject = rootObjectForInPort(IreceivePort);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
int sequence;
|
|
|
|
|
NSPortCoder *op;
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSParameterAssert(IreceivePort);
|
|
|
|
|
NSParameterAssert(IisValid);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
NSParameterAssert([rmc connection] == self);
|
|
|
|
|
|
|
|
|
|
[rmc decodeValueOfObjCType: @encode(int) at: &sequence];
|
|
|
|
|
[self _doneInRmc: rmc];
|
2000-07-05 12:23:00 +00:00
|
|
|
|
op = [self _makeOutRmc: sequence generate: 0 reply: NO];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[op encodeObject: rootObject];
|
|
|
|
|
[self _sendOutRmc: op type: ROOTPROXY_REPLY];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _service_release: (NSPortCoder*)rmc
|
|
|
|
|
{
|
|
|
|
|
unsigned int count;
|
|
|
|
|
unsigned int pos;
|
|
|
|
|
int sequence;
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSParameterAssert (IisValid);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
[rmc decodeValueOfObjCType: @encode(int) at: &sequence];
|
|
|
|
|
[rmc decodeValueOfObjCType: @encode(typeof(count)) at: &count];
|
|
|
|
|
|
|
|
|
|
for (pos = 0; pos < count; pos++)
|
|
|
|
|
{
|
|
|
|
|
unsigned target;
|
2009-10-03 15:35:40 +00:00
|
|
|
|
ProxyStruct *prox;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
[rmc decodeValueOfObjCType: @encode(typeof(target)) at: &target];
|
|
|
|
|
|
2009-10-03 15:35:40 +00:00
|
|
|
|
prox = (ProxyStruct*)[self includesLocalTarget: target];
|
|
|
|
|
if (prox != 0)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
|
|
|
|
if (debug_connection > 3)
|
2005-11-09 16:30:57 +00:00
|
|
|
|
NSLog(@"releasing object with target (0x%x) on (%@) counter %d",
|
2009-10-03 15:35:40 +00:00
|
|
|
|
target, self, prox->_counter);
|
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
NS_DURING
|
2003-10-27 13:41:01 +00:00
|
|
|
|
{
|
2009-10-03 15:35:40 +00:00
|
|
|
|
if (--(prox->_counter) == 0)
|
|
|
|
|
{
|
|
|
|
|
id rootObject = rootObjectForInPort(IreceivePort);
|
|
|
|
|
|
|
|
|
|
if (rootObject == prox->_object)
|
|
|
|
|
{
|
|
|
|
|
/* Don't deallocate root object ...
|
|
|
|
|
*/
|
|
|
|
|
prox->_counter = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[self removeLocalObject: (id)prox];
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-10-27 13:41:01 +00:00
|
|
|
|
}
|
2009-10-03 15:35:40 +00:00
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
M_UNLOCK(IrefGate);
|
|
|
|
|
[localException raise];
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER
|
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
else if (debug_connection > 3)
|
2005-11-09 16:30:57 +00:00
|
|
|
|
NSLog(@"releasing object with target (0x%x) on (%@) - nothing to do",
|
|
|
|
|
target, self);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
[self _doneInRmc: rmc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _service_retain: (NSPortCoder*)rmc
|
|
|
|
|
{
|
2003-10-27 13:41:01 +00:00
|
|
|
|
unsigned target;
|
|
|
|
|
NSPortCoder *op;
|
|
|
|
|
int sequence;
|
|
|
|
|
NSDistantObject *local;
|
|
|
|
|
NSString *response = nil;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSParameterAssert (IisValid);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
[rmc decodeValueOfObjCType: @encode(int) at: &sequence];
|
2000-07-05 12:23:00 +00:00
|
|
|
|
op = [self _makeOutRmc: sequence generate: 0 reply: NO];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
[rmc decodeValueOfObjCType: @encode(typeof(target)) at: &target];
|
|
|
|
|
[self _doneInRmc: rmc];
|
|
|
|
|
|
|
|
|
|
if (debug_connection > 3)
|
2005-11-09 16:30:57 +00:00
|
|
|
|
NSLog(@"looking to retain local object with target (0x%x) on (%@)",
|
|
|
|
|
target, self);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
local = [self locateLocalTarget: target];
|
|
|
|
|
if (local == nil)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2003-10-27 13:41:01 +00:00
|
|
|
|
response = @"target not found anywhere";
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2003-10-27 13:41:01 +00:00
|
|
|
|
else
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2003-10-27 13:41:01 +00:00
|
|
|
|
((ProxyStruct*)local)->_counter++; // Vended on connection.
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2003-10-27 13:41:01 +00:00
|
|
|
|
[op encodeObject: response];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[self _sendOutRmc: op type: RETAIN_REPLY];
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-21 13:15:39 +00:00
|
|
|
|
- (void) _shutdown
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSParameterAssert(IreceivePort);
|
|
|
|
|
NSParameterAssert (IisValid);
|
2005-11-21 13:15:39 +00:00
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
NSPortCoder *op;
|
|
|
|
|
int sno;
|
|
|
|
|
|
|
|
|
|
op = [self _makeOutRmc: 0 generate: &sno reply: NO];
|
|
|
|
|
[self _sendOutRmc: op type: CONNECTION_SHUTDOWN];
|
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
NS_ENDHANDLER
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _service_shutdown: (NSPortCoder*)rmc
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSParameterAssert (IisValid);
|
|
|
|
|
IshuttingDown = YES; // Prevent shutdown being sent back to other end
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[self _doneInRmc: rmc];
|
|
|
|
|
[self invalidate];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _service_typeForSelector: (NSPortCoder*)rmc
|
|
|
|
|
{
|
|
|
|
|
NSPortCoder *op;
|
|
|
|
|
unsigned target;
|
|
|
|
|
NSDistantObject *p;
|
|
|
|
|
int sequence;
|
2002-12-10 11:30:56 +00:00
|
|
|
|
id o;
|
|
|
|
|
SEL sel;
|
|
|
|
|
const char *type;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
struct objc_method* m;
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSParameterAssert(IreceivePort);
|
|
|
|
|
NSParameterAssert (IisValid);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
[rmc decodeValueOfObjCType: @encode(int) at: &sequence];
|
2000-07-05 12:23:00 +00:00
|
|
|
|
op = [self _makeOutRmc: sequence generate: 0 reply: NO];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
[rmc decodeValueOfObjCType: ":" at: &sel];
|
|
|
|
|
[rmc decodeValueOfObjCType: @encode(unsigned) at: &target];
|
|
|
|
|
[self _doneInRmc: rmc];
|
|
|
|
|
p = [self includesLocalTarget: target];
|
2003-10-21 17:05:36 +00:00
|
|
|
|
o = (p != nil) ? ((ProxyStruct*)p)->_object : nil;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
/* xxx We should make sure that TARGET is a valid object. */
|
|
|
|
|
/* Not actually a Proxy, but we avoid the warnings "id" would have made. */
|
2004-08-20 17:53:16 +00:00
|
|
|
|
m = GSGetMethod(((NSDistantObject*)o)->isa, sel, YES, YES);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
/* 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 = "";
|
|
|
|
|
[op encodeValueOfObjCType: @encode(char*) at: &type];
|
|
|
|
|
[self _sendOutRmc: op type: METHODTYPE_REPLY];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check the queue, then try to get it from the network by waiting
|
|
|
|
|
* while we run the NSRunLoop. Raise exception if we don't get anything
|
|
|
|
|
* before timing out.
|
|
|
|
|
*/
|
2005-07-08 11:48:37 +00:00
|
|
|
|
- (NSPortCoder*) _getReplyRmc: (int)sn
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2008-11-17 13:45:32 +00:00
|
|
|
|
NSPortCoder *rmc = nil;
|
2002-09-19 16:24:20 +00:00
|
|
|
|
GSIMapNode node = 0;
|
2000-11-15 17:28:44 +00:00
|
|
|
|
NSDate *timeout_date = nil;
|
2009-09-07 11:29:50 +00:00
|
|
|
|
NSTimeInterval delay_interval = 0.0;
|
|
|
|
|
NSTimeInterval last_interval;
|
|
|
|
|
NSTimeInterval maximum_interval;
|
2000-11-15 17:28:44 +00:00
|
|
|
|
NSDate *delay_date = nil;
|
2009-09-07 11:29:50 +00:00
|
|
|
|
NSDate *start_date = nil;
|
2009-07-28 19:04:40 +00:00
|
|
|
|
NSRunLoop *runLoop;
|
2003-07-25 09:27:44 +00:00
|
|
|
|
BOOL isLocked = NO;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (IisValid == NO)
|
2009-07-28 19:04:40 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSObjectInaccessibleException
|
|
|
|
|
format: @"Connection has been invalidated"];
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-25 09:27:44 +00:00
|
|
|
|
/*
|
|
|
|
|
* If we have sent out a request on a run loop that we don't already
|
|
|
|
|
* know about, it must be on a new thread - so if we have multipleThreads
|
|
|
|
|
* enabled, we must add the run loop of the new thread so that we can
|
|
|
|
|
* get the reply in this thread.
|
|
|
|
|
*/
|
2009-07-28 19:04:40 +00:00
|
|
|
|
runLoop = GSRunLoopForThread(nil);
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if ([IrunLoops indexOfObjectIdenticalTo: runLoop] == NSNotFound)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (ImultipleThreads == YES)
|
2003-09-15 13:54:06 +00:00
|
|
|
|
{
|
|
|
|
|
[self addRunLoop: runLoop];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSObjectInaccessibleException
|
|
|
|
|
format: @"Waiting for reply in wrong thread"];
|
|
|
|
|
}
|
2003-07-25 09:27:44 +00:00
|
|
|
|
}
|
2000-11-15 17:28:44 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (ImultipleThreads == YES)
|
2009-09-07 11:29:50 +00:00
|
|
|
|
{
|
|
|
|
|
/* Since multiple threads are using this connection, another
|
|
|
|
|
* thread may read the reply we are waiting for - so we must
|
|
|
|
|
* break out of the runloop frequently to check. We do this
|
|
|
|
|
* by setting a small delay and increasing it each time round
|
|
|
|
|
* so that this semi-busy wait doesn't consume too much
|
|
|
|
|
* processor time (I hope).
|
|
|
|
|
* We set an upper limit on the delay to avoid responsiveness
|
|
|
|
|
* problems.
|
|
|
|
|
*/
|
|
|
|
|
last_interval = 0.0001;
|
|
|
|
|
maximum_interval = 1.0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* As the connection is single threaded, we can wait indefinitely
|
|
|
|
|
* for a response ... but we recheck every five minutes anyway.
|
|
|
|
|
*/
|
|
|
|
|
last_interval = maximum_interval = 300.0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-25 09:27:44 +00:00
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
2009-09-07 13:49:48 +00:00
|
|
|
|
BOOL warned = NO;
|
|
|
|
|
|
2003-07-25 09:27:44 +00:00
|
|
|
|
if (debug_connection > 5)
|
2005-11-09 16:30:57 +00:00
|
|
|
|
NSLog(@"Waiting for reply sequence %d on %@",
|
|
|
|
|
sn, self);
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate); isLocked = YES;
|
|
|
|
|
while (IisValid == YES
|
|
|
|
|
&& (node = GSIMapNodeForKey(IreplyMap, (GSIMapKey)sn)) != 0
|
2003-07-25 09:27:44 +00:00
|
|
|
|
&& node->value.obj == dummyObject)
|
|
|
|
|
{
|
2009-09-07 11:29:50 +00:00
|
|
|
|
NSDate *limit_date;
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate); isLocked = NO;
|
2009-09-07 11:29:50 +00:00
|
|
|
|
if (start_date == nil)
|
2001-11-27 15:51:59 +00:00
|
|
|
|
{
|
2009-09-07 11:29:50 +00:00
|
|
|
|
start_date = [dateClass allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
start_date = [start_date init];
|
2003-07-25 09:27:44 +00:00
|
|
|
|
timeout_date = [dateClass allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
timeout_date
|
2009-09-07 16:25:04 +00:00
|
|
|
|
= [timeout_date initWithTimeIntervalSinceNow: IreplyTimeout];
|
2001-11-27 15:51:59 +00:00
|
|
|
|
}
|
2009-09-07 11:29:50 +00:00
|
|
|
|
RELEASE(delay_date);
|
|
|
|
|
delay_date = [dateClass allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
if (delay_interval < maximum_interval)
|
2000-11-15 17:28:44 +00:00
|
|
|
|
{
|
2009-09-07 11:29:50 +00:00
|
|
|
|
NSTimeInterval next_interval = last_interval + delay_interval;
|
2003-07-25 09:27:44 +00:00
|
|
|
|
|
2009-09-07 11:29:50 +00:00
|
|
|
|
last_interval = delay_interval;
|
|
|
|
|
delay_interval = next_interval;
|
|
|
|
|
}
|
|
|
|
|
delay_date
|
|
|
|
|
= [delay_date initWithTimeIntervalSinceNow: delay_interval];
|
2003-07-25 09:27:44 +00:00
|
|
|
|
|
2009-09-07 11:29:50 +00:00
|
|
|
|
/*
|
|
|
|
|
* We must not set a delay date that is further in the future
|
|
|
|
|
* than the timeout date for the response to be returned.
|
|
|
|
|
*/
|
|
|
|
|
if ([timeout_date earlierDate: delay_date] == timeout_date)
|
|
|
|
|
{
|
|
|
|
|
limit_date = timeout_date;
|
2000-11-15 17:28:44 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-09-07 11:29:50 +00:00
|
|
|
|
limit_date = delay_date;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the runloop returns without having done anything, AND we
|
|
|
|
|
* were waiting for the final timeout, then we must break out
|
|
|
|
|
* of the loop.
|
|
|
|
|
*/
|
2009-09-07 13:49:48 +00:00
|
|
|
|
if (([runLoop runMode: NSConnectionReplyMode
|
2009-09-07 11:29:50 +00:00
|
|
|
|
beforeDate: limit_date] == NO
|
2009-09-07 13:49:48 +00:00
|
|
|
|
&& (limit_date == timeout_date))
|
2009-09-07 11:29:50 +00:00
|
|
|
|
|| [timeout_date timeIntervalSinceNow] <= 0.0)
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate); isLocked = YES;
|
|
|
|
|
node = GSIMapNodeForKey(IreplyMap, (GSIMapKey)sn);
|
2009-09-07 13:49:48 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else if (warned == NO && [start_date timeIntervalSinceNow] <= -300.0)
|
|
|
|
|
{
|
|
|
|
|
warned = YES;
|
|
|
|
|
NSLog(@"WARNING ... waiting for reply %u since %@ on %@",
|
|
|
|
|
sn, start_date, self);
|
2000-11-15 17:28:44 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate); isLocked = YES;
|
2003-07-25 09:27:44 +00:00
|
|
|
|
}
|
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
|
|
|
|
rmc = nil;
|
2000-11-15 17:28:44 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2003-07-25 09:27:44 +00:00
|
|
|
|
rmc = node->value.obj;
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIMapRemoveKey(IreplyMap, (GSIMapKey)sn);
|
2003-07-25 09:27:44 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate); isLocked = NO;
|
2009-09-07 11:29:50 +00:00
|
|
|
|
TEST_RELEASE(start_date);
|
2003-07-25 09:27:44 +00:00
|
|
|
|
TEST_RELEASE(delay_date);
|
|
|
|
|
TEST_RELEASE(timeout_date);
|
|
|
|
|
if (rmc == nil)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"no reply message available"];
|
|
|
|
|
}
|
|
|
|
|
if (rmc == dummyObject)
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (IisValid == YES)
|
2000-11-15 17:28:44 +00:00
|
|
|
|
{
|
2003-07-25 09:27:44 +00:00
|
|
|
|
[NSException raise: NSPortTimeoutException
|
|
|
|
|
format: @"timed out waiting for reply"];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2008-03-17 05:50:50 +00:00
|
|
|
|
[NSException raise: NSInvalidReceivePortException
|
2003-07-25 09:27:44 +00:00
|
|
|
|
format: @"invalidated while awaiting reply"];
|
2000-11-15 17:28:44 +00:00
|
|
|
|
}
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2000-07-05 12:23:00 +00:00
|
|
|
|
}
|
2003-07-25 09:27:44 +00:00
|
|
|
|
NS_HANDLER
|
2000-07-05 12:23:00 +00:00
|
|
|
|
{
|
2003-07-25 09:27:44 +00:00
|
|
|
|
if (isLocked == YES)
|
2002-09-19 16:24:20 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2002-09-19 16:24:20 +00:00
|
|
|
|
}
|
2003-07-25 09:27:44 +00:00
|
|
|
|
[localException raise];
|
2000-07-05 12:23:00 +00:00
|
|
|
|
}
|
2003-07-25 09:27:44 +00:00
|
|
|
|
NS_ENDHANDLER
|
|
|
|
|
|
2001-04-11 12:30:32 +00:00
|
|
|
|
NSDebugMLLog(@"NSConnection", @"Consuming reply RMC %d on %x", sn, self);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
return rmc;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-19 21:31:18 +00:00
|
|
|
|
- (void) _doneInReply: (NSPortCoder*)c
|
|
|
|
|
{
|
|
|
|
|
[self _doneInRmc: c];
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IrepInCount++;
|
2001-09-19 21:31:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (void) _doneInRmc: (NSPortCoder*)c
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
2001-04-11 12:30:32 +00:00
|
|
|
|
if (debug_connection > 5)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"done rmc 0x%x", c);
|
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (cacheCoders == YES && IcachedDecoders != nil)
|
2001-06-08 14:04:20 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[IcachedDecoders addObject: c];
|
2001-06-08 14:04:20 +00:00
|
|
|
|
}
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[c dispatch]; /* Tell NSPortCoder to release the connection. */
|
|
|
|
|
RELEASE(c);
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-04-11 12:30:32 +00:00
|
|
|
|
/*
|
|
|
|
|
* This method called if an exception occurred, and we don't know
|
|
|
|
|
* whether we have already tidied the NSPortCoder object up or not.
|
|
|
|
|
*/
|
|
|
|
|
- (void) _failInRmc: (NSPortCoder*)c
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
if (cacheCoders == YES && IcachedDecoders != nil
|
|
|
|
|
&& [IcachedDecoders indexOfObjectIdenticalTo: c] == NSNotFound)
|
2001-04-11 12:30:32 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[IcachedDecoders addObject: c];
|
2001-04-11 12:30:32 +00:00
|
|
|
|
}
|
2001-06-08 14:04:20 +00:00
|
|
|
|
if (debug_connection > 5)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"fail rmc 0x%x", c);
|
|
|
|
|
}
|
|
|
|
|
[c dispatch]; /* Tell NSPortCoder to release the connection. */
|
|
|
|
|
RELEASE(c);
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2001-04-11 12:30:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This method called if an exception occurred, and we don't know
|
|
|
|
|
* whether we have already tidied the NSPortCoder object up or not.
|
|
|
|
|
*/
|
|
|
|
|
- (void) _failOutRmc: (NSPortCoder*)c
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
if (cacheCoders == YES && IcachedEncoders != nil
|
|
|
|
|
&& [IcachedEncoders indexOfObjectIdenticalTo: c] == NSNotFound)
|
2001-04-11 12:30:32 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[IcachedEncoders addObject: c];
|
2001-04-11 12:30:32 +00:00
|
|
|
|
}
|
2001-06-08 14:04:20 +00:00
|
|
|
|
[c dispatch]; /* Tell NSPortCoder to release the connection. */
|
|
|
|
|
RELEASE(c);
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2001-04-11 12:30:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
- (NSPortCoder*) _makeInRmc: (NSMutableArray*)components
|
|
|
|
|
{
|
|
|
|
|
NSPortCoder *coder;
|
|
|
|
|
unsigned count;
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSParameterAssert(IisValid);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
if (cacheCoders == YES && IcachedDecoders != nil
|
|
|
|
|
&& (count = [IcachedDecoders count]) > 0)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
coder = RETAIN([IcachedDecoders objectAtIndex: --count]);
|
|
|
|
|
[IcachedDecoders removeObjectAtIndex: count];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2001-04-11 12:30:32 +00:00
|
|
|
|
coder = [recvCoderClass allocWithZone: NSDefaultMallocZone()];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
coder = [coder initWithReceivePort: IreceivePort
|
|
|
|
|
sendPort:IsendPort
|
2000-07-04 11:05:46 +00:00
|
|
|
|
components: components];
|
|
|
|
|
return coder;
|
|
|
|
|
}
|
|
|
|
|
|
2000-07-05 12:23:00 +00:00
|
|
|
|
/*
|
|
|
|
|
* Create an NSPortCoder object for encoding an outgoing message or reply.
|
|
|
|
|
*
|
|
|
|
|
* sno Is the seqence number to encode into the coder.
|
|
|
|
|
* ret If non-null, generate a new sequence number and return it
|
|
|
|
|
* here. Ignore the sequence number passed in sno.
|
2009-09-07 16:25:04 +00:00
|
|
|
|
* rep If this flag is YES, add a placeholder to the IreplyMap
|
2000-07-05 12:23:00 +00:00
|
|
|
|
* so we handle an incoming reply for this sequence number.
|
|
|
|
|
*/
|
|
|
|
|
- (NSPortCoder*) _makeOutRmc: (int)sno generate: (int*)ret reply: (BOOL)rep
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
|
|
|
|
NSPortCoder *coder;
|
|
|
|
|
unsigned count;
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSParameterAssert(IisValid);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
2000-07-05 12:23:00 +00:00
|
|
|
|
/*
|
|
|
|
|
* Generate a new sequence number if required.
|
|
|
|
|
*/
|
|
|
|
|
if (ret != 0)
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
sno = ImessageCount++;
|
2000-07-05 12:23:00 +00:00
|
|
|
|
*ret = sno;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Add a placeholder to the reply map if we expect a reply.
|
|
|
|
|
*/
|
|
|
|
|
if (rep == YES)
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIMapAddPair(IreplyMap, (GSIMapKey)sno, (GSIMapVal)dummyObject);
|
2000-07-05 12:23:00 +00:00
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Locate or create an rmc
|
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (cacheCoders == YES && IcachedEncoders != nil
|
|
|
|
|
&& (count = [IcachedEncoders count]) > 0)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
coder = RETAIN([IcachedEncoders objectAtIndex: --count]);
|
|
|
|
|
[IcachedEncoders removeObjectAtIndex: count];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2001-04-11 12:30:32 +00:00
|
|
|
|
coder = [sendCoderClass allocWithZone: NSDefaultMallocZone()];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
coder = [coder initWithReceivePort: IreceivePort
|
|
|
|
|
sendPort:IsendPort
|
2000-07-04 11:05:46 +00:00
|
|
|
|
components: nil];
|
2000-07-05 12:23:00 +00:00
|
|
|
|
[coder encodeValueOfObjCType: @encode(int) at: &sno];
|
2008-12-07 16:03:29 +00:00
|
|
|
|
NSDebugMLLog(@"NSConnection",
|
|
|
|
|
@"Make out RMC %u on %@", sno, self);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
return coder;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _sendOutRmc: (NSPortCoder*)c type: (int)msgid
|
|
|
|
|
{
|
|
|
|
|
NSDate *limit;
|
|
|
|
|
BOOL sent = NO;
|
|
|
|
|
BOOL raiseException = NO;
|
|
|
|
|
NSMutableArray *components = [c _components];
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (IauthenticateOut == YES
|
2000-07-04 14:37:18 +00:00
|
|
|
|
&& (msgid == METHOD_REQUEST || msgid == METHOD_REPLY))
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
|
|
|
|
NSData *d;
|
|
|
|
|
|
|
|
|
|
d = [[self delegate] authenticationDataForComponents: components];
|
|
|
|
|
if (d == nil)
|
|
|
|
|
{
|
|
|
|
|
RELEASE(c);
|
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
|
format: @"Bad authentication data provided by delegate"];
|
|
|
|
|
}
|
|
|
|
|
[components addObject: d];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (msgid)
|
|
|
|
|
{
|
|
|
|
|
case PROXY_RETAIN:
|
|
|
|
|
case CONNECTION_SHUTDOWN:
|
|
|
|
|
case METHOD_REPLY:
|
|
|
|
|
case ROOTPROXY_REPLY:
|
|
|
|
|
case METHODTYPE_REPLY:
|
|
|
|
|
case PROXY_RELEASE:
|
|
|
|
|
case RETAIN_REPLY:
|
|
|
|
|
raiseException = NO;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case METHOD_REQUEST:
|
|
|
|
|
case ROOTPROXY_REQUEST:
|
|
|
|
|
case METHODTYPE_REQUEST:
|
|
|
|
|
default:
|
|
|
|
|
raiseException = YES;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-07 16:03:29 +00:00
|
|
|
|
NSDebugMLLog(@"NSConnection",
|
|
|
|
|
@"Sending %@ on %@", stringFromMsgType(msgid), self);
|
2000-09-12 05:16:01 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
limit = [dateClass dateWithTimeIntervalSinceNow: IrequestTimeout];
|
|
|
|
|
sent = [IsendPort sendBeforeDate: limit
|
2000-07-04 11:05:46 +00:00
|
|
|
|
msgid: msgid
|
|
|
|
|
components: components
|
2009-09-07 16:25:04 +00:00
|
|
|
|
from: IreceivePort
|
|
|
|
|
reserved: [IsendPort reservedSpaceLength]];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
/*
|
2003-10-27 13:41:01 +00:00
|
|
|
|
* We replace the coder we have just used in the cache, and tell it not to
|
2000-07-04 11:05:46 +00:00
|
|
|
|
* retain this connection any more.
|
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (cacheCoders == YES && IcachedEncoders != nil)
|
2001-06-08 14:04:20 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
[IcachedEncoders addObject: c];
|
2001-06-08 14:04:20 +00:00
|
|
|
|
}
|
2000-07-04 11:05:46 +00:00
|
|
|
|
[c dispatch]; /* Tell NSPortCoder to release the connection. */
|
|
|
|
|
RELEASE(c);
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
if (sent == NO)
|
|
|
|
|
{
|
|
|
|
|
NSString *text = stringFromMsgType(msgid);
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if ([IsendPort isValid] == NO)
|
2000-07-07 10:19:31 +00:00
|
|
|
|
{
|
|
|
|
|
text = [text stringByAppendingFormat: @" - port was invalidated"];
|
|
|
|
|
}
|
2000-07-04 11:05:46 +00:00
|
|
|
|
if (raiseException == YES)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSPortTimeoutException format: text];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"Port operation timed out - %@", text);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch (msgid)
|
|
|
|
|
{
|
|
|
|
|
case METHOD_REQUEST:
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IreqOutCount++; /* Sent a request. */
|
2000-07-04 11:05:46 +00:00
|
|
|
|
break;
|
|
|
|
|
case METHOD_REPLY:
|
2009-09-07 16:25:04 +00:00
|
|
|
|
IrepOutCount++; /* Sent back a reply. */
|
2000-07-04 11:05:46 +00:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Managing objects and proxies. */
|
2000-07-05 16:56:06 +00:00
|
|
|
|
- (void) addLocalObject: (NSDistantObject*)anObj
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2003-10-21 17:05:36 +00:00
|
|
|
|
static unsigned local_object_counter = 0;
|
2000-07-05 16:56:06 +00:00
|
|
|
|
id object;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
unsigned target;
|
2000-07-05 12:23:00 +00:00
|
|
|
|
GSIMapNode node;
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
NSParameterAssert (IisValid);
|
2000-07-05 12:23:00 +00:00
|
|
|
|
|
2003-10-21 17:05:36 +00:00
|
|
|
|
object = ((ProxyStruct*)anObj)->_object;
|
|
|
|
|
target = ((ProxyStruct*)anObj)->_handle;
|
|
|
|
|
|
2000-07-05 12:23:00 +00:00
|
|
|
|
/*
|
2003-10-21 17:05:36 +00:00
|
|
|
|
* If there is no target allocated to the proxy, we add one.
|
2000-07-05 12:23:00 +00:00
|
|
|
|
*/
|
2003-10-21 17:05:36 +00:00
|
|
|
|
if (target == 0)
|
2000-07-05 12:23:00 +00:00
|
|
|
|
{
|
2003-10-21 17:05:36 +00:00
|
|
|
|
((ProxyStruct*)anObj)->_handle = target = ++local_object_counter;
|
2000-07-05 12:23:00 +00:00
|
|
|
|
}
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
/*
|
2009-09-07 16:25:04 +00:00
|
|
|
|
* Record the value in the IlocalObjects map, retaining it.
|
2000-07-04 11:05:46 +00:00
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
node = GSIMapNodeForKey(IlocalObjects, (GSIMapKey)object);
|
2003-10-21 17:05:36 +00:00
|
|
|
|
NSAssert(node == 0, NSInternalInconsistencyException);
|
2009-09-07 16:25:04 +00:00
|
|
|
|
node = GSIMapNodeForKey(IlocalTargets, (GSIMapKey)target);
|
2003-10-21 17:05:36 +00:00
|
|
|
|
NSAssert(node == 0, NSInternalInconsistencyException);
|
|
|
|
|
|
2009-01-12 12:48:46 +00:00
|
|
|
|
IF_NO_GC([anObj retain];)
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIMapAddPair(IlocalObjects, (GSIMapKey)object, (GSIMapVal)((id)anObj));
|
|
|
|
|
GSIMapAddPair(IlocalTargets, (GSIMapKey)target, (GSIMapVal)((id)anObj));
|
2003-10-21 17:05:36 +00:00
|
|
|
|
|
2000-07-04 11:05:46 +00:00
|
|
|
|
if (debug_connection > 2)
|
|
|
|
|
NSLog(@"add local object (0x%x) target (0x%x) "
|
2006-01-11 09:32:13 +00:00
|
|
|
|
@"to connection (%@)", (uintptr_t)object, target, self);
|
2003-10-21 17:05:36 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-10-27 13:41:01 +00:00
|
|
|
|
- (NSDistantObject*) retainOrAddLocal: (NSDistantObject*)proxy
|
|
|
|
|
forObject: (id)object
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2000-07-05 12:23:00 +00:00
|
|
|
|
GSIMapNode node;
|
|
|
|
|
NSDistantObject *p;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
/* Don't assert (IisValid); */
|
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
node = GSIMapNodeForKey(IlocalObjects, (GSIMapKey)object);
|
2000-07-05 12:23:00 +00:00
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
|
|
|
|
p = nil;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-01-12 12:48:46 +00:00
|
|
|
|
p = RETAIN(node->value.obj);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
DESTROY(proxy);
|
|
|
|
|
}
|
|
|
|
|
if (p == nil && proxy != nil)
|
|
|
|
|
{
|
|
|
|
|
p = proxy;
|
|
|
|
|
[self addLocalObject: p];
|
2000-07-05 12:23:00 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
2003-10-27 13:41:01 +00:00
|
|
|
|
- (void) removeLocalObject: (NSDistantObject*)prox
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2003-10-27 13:41:01 +00:00
|
|
|
|
id anObj;
|
|
|
|
|
unsigned target;
|
|
|
|
|
unsigned val = 0;
|
|
|
|
|
GSIMapNode node;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
anObj = ((ProxyStruct*)prox)->_object;
|
2009-09-07 16:25:04 +00:00
|
|
|
|
node = GSIMapNodeForKey(IlocalObjects, (GSIMapKey)anObj);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2003-10-27 13:41:01 +00:00
|
|
|
|
/*
|
|
|
|
|
* The NSDistantObject concerned may not belong to this connection,
|
|
|
|
|
* so we need to check that any matching proxy is identical to the
|
|
|
|
|
* argument we were given.
|
|
|
|
|
*/
|
|
|
|
|
if (node != 0 && node->value.obj == prox)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2003-10-27 13:41:01 +00:00
|
|
|
|
target = ((ProxyStruct*)prox)->_handle;
|
2003-10-21 17:05:36 +00:00
|
|
|
|
|
|
|
|
|
/*
|
2003-10-27 13:41:01 +00:00
|
|
|
|
* If this proxy has been vended onwards to another process
|
|
|
|
|
* which has not myet released it, we need to keep a reference
|
|
|
|
|
* to the local object around for a while in case that other
|
|
|
|
|
* process needs it.
|
2003-10-21 17:05:36 +00:00
|
|
|
|
*/
|
2003-10-27 13:41:01 +00:00
|
|
|
|
if ((((ProxyStruct*)prox)->_counter) != 0)
|
2003-10-21 17:05:36 +00:00
|
|
|
|
{
|
2003-10-27 13:41:01 +00:00
|
|
|
|
CachedLocalObject *item;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2003-10-27 13:41:01 +00:00
|
|
|
|
(((ProxyStruct*)prox)->_counter) = 0;
|
|
|
|
|
M_LOCK(cached_proxies_gate);
|
|
|
|
|
if (timer == nil)
|
|
|
|
|
{
|
|
|
|
|
timer = [NSTimer scheduledTimerWithTimeInterval: 1.0
|
|
|
|
|
target: connectionClass
|
|
|
|
|
selector: @selector(_timeout:)
|
|
|
|
|
userInfo: nil
|
|
|
|
|
repeats: YES];
|
|
|
|
|
}
|
|
|
|
|
item = [CachedLocalObject newWithObject: prox time: 5];
|
2006-01-10 10:29:11 +00:00
|
|
|
|
NSMapInsert(targetToCached, (void*)(uintptr_t)target, item);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
M_UNLOCK(cached_proxies_gate);
|
|
|
|
|
RELEASE(item);
|
|
|
|
|
if (debug_connection > 3)
|
|
|
|
|
NSLog(@"placed local object (0x%x) target (0x%x) in cache",
|
2006-01-11 09:32:13 +00:00
|
|
|
|
(uintptr_t)anObj, target);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
}
|
2000-07-05 12:23:00 +00:00
|
|
|
|
|
2003-10-27 13:41:01 +00:00
|
|
|
|
/*
|
2009-09-07 16:25:04 +00:00
|
|
|
|
* Remove the proxy from IlocalObjects and release it.
|
2003-10-27 13:41:01 +00:00
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIMapRemoveKey(IlocalObjects, (GSIMapKey)anObj);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
RELEASE(prox);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2003-10-27 13:41:01 +00:00
|
|
|
|
/*
|
|
|
|
|
* Remove the target info too - no release required.
|
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIMapRemoveKey(IlocalTargets, (GSIMapKey)target);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2003-10-27 13:41:01 +00:00
|
|
|
|
if (debug_connection > 2)
|
|
|
|
|
NSLog(@"removed local object (0x%x) target (0x%x) "
|
2006-01-11 09:32:13 +00:00
|
|
|
|
@"from connection (%@) (ref %d)", (uintptr_t)anObj, target, self, val);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-10-27 13:41:01 +00:00
|
|
|
|
- (void) _release_target: (unsigned)target count: (unsigned)number
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Tell the remote app that it can release its local objects
|
|
|
|
|
* for the targets in the specified list since we don't have
|
|
|
|
|
* proxies for them any more.
|
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (IreceivePort != nil && IisValid == YES && number > 0)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
|
|
|
|
id op;
|
|
|
|
|
unsigned i;
|
2000-07-05 12:23:00 +00:00
|
|
|
|
int sequence;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2000-07-05 12:23:00 +00:00
|
|
|
|
op = [self _makeOutRmc: 0 generate: &sequence reply: NO];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
[op encodeValueOfObjCType: @encode(unsigned) at: &number];
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < number; i++)
|
|
|
|
|
{
|
2003-10-27 13:41:01 +00:00
|
|
|
|
[op encodeValueOfObjCType: @encode(unsigned) at: &target];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
if (debug_connection > 3)
|
2005-11-09 16:30:57 +00:00
|
|
|
|
NSLog(@"sending release for target (0x%x) on (%@)",
|
|
|
|
|
target, self);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[self _sendOutRmc: op type: PROXY_RELEASE];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
if (debug_connection)
|
|
|
|
|
NSLog(@"failed to release targets - %@", localException);
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER
|
|
|
|
|
}
|
|
|
|
|
|
2002-12-10 11:30:56 +00:00
|
|
|
|
- (NSDistantObject*) locateLocalTarget: (unsigned)target
|
|
|
|
|
{
|
|
|
|
|
NSDistantObject *proxy = nil;
|
|
|
|
|
GSIMapNode node;
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Try a quick lookup to see if the target references a local object
|
|
|
|
|
* belonging to the receiver ... usually it should.
|
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
node = GSIMapNodeForKey(IlocalTargets, (GSIMapKey)target);
|
2002-12-10 11:30:56 +00:00
|
|
|
|
if (node != 0)
|
|
|
|
|
{
|
|
|
|
|
proxy = node->value.obj;
|
|
|
|
|
}
|
2003-10-21 17:05:36 +00:00
|
|
|
|
|
|
|
|
|
/*
|
2003-10-27 13:41:01 +00:00
|
|
|
|
* If the target doesn't exist in the receiver, but still
|
|
|
|
|
* persists in the cache (ie it was recently released) then
|
|
|
|
|
* we move it back from the cache to the receiver.
|
|
|
|
|
*/
|
|
|
|
|
if (proxy == nil)
|
|
|
|
|
{
|
|
|
|
|
CachedLocalObject *cached;
|
|
|
|
|
|
|
|
|
|
M_LOCK(cached_proxies_gate);
|
2006-01-10 10:29:11 +00:00
|
|
|
|
cached = NSMapGet (targetToCached, (void*)(uintptr_t)target);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
if (cached != nil)
|
|
|
|
|
{
|
|
|
|
|
proxy = [cached obj];
|
|
|
|
|
/*
|
|
|
|
|
* Found in cache ... add to this connection as the object
|
|
|
|
|
* is no longer in use by any connection.
|
|
|
|
|
*/
|
|
|
|
|
ASSIGN(((ProxyStruct*)proxy)->_connection, self);
|
|
|
|
|
[self addLocalObject: proxy];
|
2006-01-10 10:29:11 +00:00
|
|
|
|
NSMapRemove(targetToCached, (void*)(uintptr_t)target);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
if (debug_connection > 3)
|
|
|
|
|
NSLog(@"target (0x%x) moved from cache", target);
|
|
|
|
|
}
|
|
|
|
|
M_UNLOCK(cached_proxies_gate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If not found in the current connection or the cache of local references
|
|
|
|
|
* of recently invalidated connections, try all other existing connections.
|
2003-10-21 17:05:36 +00:00
|
|
|
|
*/
|
|
|
|
|
if (proxy == nil)
|
2002-12-10 11:30:56 +00:00
|
|
|
|
{
|
2003-10-21 17:05:36 +00:00
|
|
|
|
NSHashEnumerator enumerator;
|
|
|
|
|
NSConnection *c;
|
2002-12-10 11:30:56 +00:00
|
|
|
|
|
2003-10-21 17:05:36 +00:00
|
|
|
|
M_LOCK(connection_table_gate);
|
|
|
|
|
enumerator = NSEnumerateHashTable(connection_table);
|
|
|
|
|
while (proxy == nil
|
|
|
|
|
&& (c = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil)
|
2002-12-10 11:30:56 +00:00
|
|
|
|
{
|
2003-10-21 17:05:36 +00:00
|
|
|
|
if (c != self && [c isValid] == YES)
|
2002-12-10 11:30:56 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(GSIVar(c, _refGate));
|
|
|
|
|
node = GSIMapNodeForKey(GSIVar(c, _localTargets),
|
|
|
|
|
(GSIMapKey)target);
|
2003-10-21 17:05:36 +00:00
|
|
|
|
if (node != 0)
|
|
|
|
|
{
|
2003-10-27 13:41:01 +00:00
|
|
|
|
id local;
|
|
|
|
|
unsigned nTarget;
|
|
|
|
|
|
2003-10-21 17:05:36 +00:00
|
|
|
|
/*
|
2003-10-27 13:41:01 +00:00
|
|
|
|
* We found the local object in use in another connection
|
|
|
|
|
* so we create a new reference to the same object and
|
|
|
|
|
* add it to our connection, adjusting the target of the
|
|
|
|
|
* new reference to be the value we need.
|
|
|
|
|
*
|
|
|
|
|
* We don't want to just share the NSDistantObject with
|
|
|
|
|
* the other connection, since we might want to keep
|
|
|
|
|
* track of information on a per-connection basis in
|
|
|
|
|
* order to handle connection shutdown cleanly.
|
2003-10-21 17:05:36 +00:00
|
|
|
|
*/
|
2003-10-27 13:41:01 +00:00
|
|
|
|
proxy = node->value.obj;
|
|
|
|
|
local = RETAIN(((ProxyStruct*)proxy)->_object);
|
|
|
|
|
proxy = [NSDistantObject proxyWithLocal: local
|
|
|
|
|
connection: self];
|
|
|
|
|
nTarget = ((ProxyStruct*)proxy)->_handle;
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIMapRemoveKey(IlocalTargets, (GSIMapKey)nTarget);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
((ProxyStruct*)proxy)->_handle = target;
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIMapAddPair(IlocalTargets, (GSIMapKey)target,
|
2005-10-07 09:57:51 +00:00
|
|
|
|
(GSIMapVal)((id)proxy));
|
2003-10-21 17:05:36 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(GSIVar(c, _refGate));
|
2002-12-10 11:30:56 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2003-10-21 17:05:36 +00:00
|
|
|
|
NSEndHashTableEnumeration(&enumerator);
|
|
|
|
|
M_UNLOCK(connection_table_gate);
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2003-10-21 17:05:36 +00:00
|
|
|
|
|
|
|
|
|
if (proxy == nil)
|
|
|
|
|
{
|
|
|
|
|
if (debug_connection > 3)
|
|
|
|
|
NSLog(@"target (0x%x) not found anywhere", target);
|
2002-12-10 11:30:56 +00:00
|
|
|
|
}
|
|
|
|
|
return proxy;
|
|
|
|
|
}
|
|
|
|
|
|
2003-10-27 13:41:01 +00:00
|
|
|
|
- (void) vendLocal: (NSDistantObject*)aProxy
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
((ProxyStruct*)aProxy)->_counter++;
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
}
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2005-11-06 13:53:40 +00:00
|
|
|
|
- (void) acquireProxyForTarget: (unsigned)target
|
2003-10-27 13:41:01 +00:00
|
|
|
|
{
|
|
|
|
|
NSDistantObject *found;
|
|
|
|
|
GSIMapNode node;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
/* Don't assert (IisValid); */
|
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
node = GSIMapNodeForKey(IremoteProxies, (GSIMapKey)target);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
|
|
|
|
found = nil;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2003-10-27 13:41:01 +00:00
|
|
|
|
else
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2003-10-27 13:41:01 +00:00
|
|
|
|
found = node->value.obj;
|
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
if (found == nil)
|
|
|
|
|
{
|
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Tell the remote app that it must retain the local object
|
|
|
|
|
* for the target on this connection.
|
|
|
|
|
*/
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (IreceivePort && IisValid)
|
2003-10-27 13:41:01 +00:00
|
|
|
|
{
|
|
|
|
|
NSPortCoder *op;
|
|
|
|
|
id ip;
|
|
|
|
|
id result;
|
|
|
|
|
int seq_num;
|
|
|
|
|
|
|
|
|
|
op = [self _makeOutRmc: 0 generate: &seq_num reply: YES];
|
|
|
|
|
[op encodeValueOfObjCType: @encode(typeof(target)) at: &target];
|
|
|
|
|
[self _sendOutRmc: op type: PROXY_RETAIN];
|
|
|
|
|
|
|
|
|
|
ip = [self _getReplyRmc: seq_num];
|
|
|
|
|
[ip decodeValueOfObjCType: @encode(id) at: &result];
|
|
|
|
|
[self _doneInRmc: ip];
|
|
|
|
|
if (result != nil)
|
|
|
|
|
NSLog(@"failed to retain target - %@", result);
|
|
|
|
|
else if (debug_connection > 3)
|
|
|
|
|
NSLog(@"sending retain for target - %u", target);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"failed to retain target - %@", localException);
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
2003-10-27 13:41:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) retain
|
|
|
|
|
{
|
|
|
|
|
return [super retain];
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) removeProxy: (NSDistantObject*)aProxy
|
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
if (IisValid == YES)
|
2000-07-06 20:26:49 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned target;
|
2003-10-27 13:41:01 +00:00
|
|
|
|
unsigned count = 1;
|
2000-07-06 20:26:49 +00:00
|
|
|
|
GSIMapNode node;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2000-07-06 20:26:49 +00:00
|
|
|
|
target = ((ProxyStruct*)aProxy)->_handle;
|
2009-09-07 16:25:04 +00:00
|
|
|
|
node = GSIMapNodeForKey(IremoteProxies, (GSIMapKey)target);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Only remove if the proxy for the target is the same as the
|
|
|
|
|
* supplied argument.
|
|
|
|
|
*/
|
|
|
|
|
if (node != 0 && node->value.obj == aProxy)
|
2000-07-06 20:26:49 +00:00
|
|
|
|
{
|
2003-10-27 13:41:01 +00:00
|
|
|
|
count = ((ProxyStruct*)aProxy)->_counter;
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIMapRemoveKey(IremoteProxies, (GSIMapKey)target);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
/*
|
|
|
|
|
* Tell the remote application that we have removed our proxy and
|
|
|
|
|
* it can release it's local object.
|
|
|
|
|
*/
|
|
|
|
|
[self _release_target: target count: count];
|
2000-07-06 20:26:49 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-10-27 13:41:01 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Private method used only when a remote process/thread has sent us a
|
|
|
|
|
* target which we are decoding into a proxy in this process/thread.
|
|
|
|
|
* <p>The argument aProxy may be nil, in which case an existing proxy
|
|
|
|
|
* matching aTarget is retrieved retained, and returned (this is done
|
|
|
|
|
* when a proxy target is sent to us by a remote process).
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>If aProxy is not nil, but a proxy with the same target already
|
|
|
|
|
* exists, then aProxy is released and the existing proxy is returned
|
|
|
|
|
* as in the case where aProxy was nil.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>If aProxy is not nil and there was no prior proxy with the same
|
|
|
|
|
* target, aProxy is added to the receiver and returned.
|
|
|
|
|
* </p>
|
|
|
|
|
*/
|
|
|
|
|
- (NSDistantObject*) retainOrAddProxy: (NSDistantObject*)aProxy
|
|
|
|
|
forTarget: (unsigned)aTarget
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2000-07-05 12:23:00 +00:00
|
|
|
|
NSDistantObject *p;
|
|
|
|
|
GSIMapNode node;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
/* Don't assert (IisValid); */
|
2003-10-27 13:41:01 +00:00
|
|
|
|
NSParameterAssert(aTarget > 0);
|
|
|
|
|
NSParameterAssert(aProxy==nil || aProxy->isa == distantObjectClass);
|
|
|
|
|
NSParameterAssert(aProxy==nil || [aProxy connectionForProxy] == self);
|
|
|
|
|
NSParameterAssert(aProxy==nil || aTarget == ((ProxyStruct*)aProxy)->_handle);
|
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
node = GSIMapNodeForKey(IremoteProxies, (GSIMapKey)aTarget);
|
2000-07-05 12:23:00 +00:00
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
|
|
|
|
p = nil;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-01-12 12:48:46 +00:00
|
|
|
|
p = RETAIN(node->value.obj);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
DESTROY(aProxy);
|
2000-07-05 12:23:00 +00:00
|
|
|
|
}
|
2003-10-27 13:41:01 +00:00
|
|
|
|
if (p == nil && aProxy != nil)
|
2000-07-05 12:23:00 +00:00
|
|
|
|
{
|
2003-10-27 13:41:01 +00:00
|
|
|
|
p = aProxy;
|
2009-09-07 16:25:04 +00:00
|
|
|
|
GSIMapAddPair(IremoteProxies, (GSIMapKey)aTarget, (GSIMapVal)((id)p));
|
2000-07-05 12:23:00 +00:00
|
|
|
|
}
|
2003-10-27 13:41:01 +00:00
|
|
|
|
/*
|
|
|
|
|
* Whether this is a new proxy or an existing proxy, this method is
|
|
|
|
|
* only called for an object being vended by a remote process/thread.
|
|
|
|
|
* We therefore need to increment the count of the number of times
|
|
|
|
|
* the proxy has been vended.
|
|
|
|
|
*/
|
|
|
|
|
if (p != nil)
|
2000-07-05 12:23:00 +00:00
|
|
|
|
{
|
2003-10-27 13:41:01 +00:00
|
|
|
|
((ProxyStruct*)p)->_counter++;
|
2000-07-05 12:23:00 +00:00
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2003-10-27 13:41:01 +00:00
|
|
|
|
return p;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) includesLocalObject: (id)anObj
|
|
|
|
|
{
|
|
|
|
|
NSDistantObject *ret;
|
2000-07-05 12:23:00 +00:00
|
|
|
|
GSIMapNode node;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
/* Don't assert (IisValid); */
|
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
node = GSIMapNodeForKey(IlocalObjects, (GSIMapKey)anObj);
|
2000-07-05 12:23:00 +00:00
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
|
|
|
|
ret = nil;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret = node->value.obj;
|
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2002-12-10 11:30:56 +00:00
|
|
|
|
- (NSDistantObject*) includesLocalTarget: (unsigned)target
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
|
|
|
|
NSDistantObject *ret;
|
2000-07-05 12:23:00 +00:00
|
|
|
|
GSIMapNode node;
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
2009-09-07 16:25:04 +00:00
|
|
|
|
/* Don't assert (IisValid); */
|
|
|
|
|
M_LOCK(IrefGate);
|
|
|
|
|
node = GSIMapNodeForKey(IlocalTargets, (GSIMapKey)target);
|
2000-07-05 12:23:00 +00:00
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
|
|
|
|
ret = nil;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret = node->value.obj;
|
|
|
|
|
}
|
2009-09-07 16:25:04 +00:00
|
|
|
|
M_UNLOCK(IrefGate);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Prevent trying to encode the connection itself */
|
|
|
|
|
|
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)anEncoder
|
|
|
|
|
{
|
|
|
|
|
[self shouldNotImplement: _cmd];
|
|
|
|
|
}
|
|
|
|
|
- (id) initWithCoder: (NSCoder*)aDecoder;
|
|
|
|
|
{
|
|
|
|
|
[self shouldNotImplement: _cmd];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We register this method for a notification when a port dies.
|
|
|
|
|
* NB. It is possible that the death of a port could be notified
|
|
|
|
|
* to us after we are invalidated - in which case we must ignore it.
|
|
|
|
|
*/
|
2003-09-15 13:54:06 +00:00
|
|
|
|
- (void) _portIsInvalid: (NSNotification*)notification
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
2009-09-07 16:25:04 +00:00
|
|
|
|
if (IisValid)
|
2000-07-04 11:05:46 +00:00
|
|
|
|
{
|
|
|
|
|
id port = [notification object];
|
|
|
|
|
|
|
|
|
|
if (debug_connection)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"Received port invalidation notification for "
|
2005-11-09 16:30:57 +00:00
|
|
|
|
@"connection %@\n\t%@", self, port);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We shouldn't be getting any port invalidation notifications,
|
|
|
|
|
except from our own ports; this is how we registered ourselves
|
|
|
|
|
with the NSNotificationCenter in
|
|
|
|
|
+newForInPort: outPort: ancestorConnection. */
|
2009-09-07 16:25:04 +00:00
|
|
|
|
NSParameterAssert (port == IreceivePort || port == IsendPort);
|
2000-07-04 11:05:46 +00:00
|
|
|
|
|
|
|
|
|
[self invalidate];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-15 13:54:06 +00:00
|
|
|
|
/**
|
2004-11-25 17:00:45 +00:00
|
|
|
|
* On thread exit, we need all connections to be removed from the runloop
|
|
|
|
|
* of the thread or they will retain that and cause a memory leak.
|
2003-09-15 13:54:06 +00:00
|
|
|
|
*/
|
2004-11-25 17:00:45 +00:00
|
|
|
|
+ (void) _threadWillExit: (NSNotification*)notification
|
2003-09-15 13:54:06 +00:00
|
|
|
|
{
|
2006-08-25 15:49:01 +00:00
|
|
|
|
NSRunLoop *runLoop = GSRunLoopForThread ([notification object]);
|
2003-09-15 13:54:06 +00:00
|
|
|
|
|
2004-11-25 17:00:45 +00:00
|
|
|
|
if (runLoop != nil)
|
2003-09-15 13:54:06 +00:00
|
|
|
|
{
|
2006-08-25 15:49:01 +00:00
|
|
|
|
NSEnumerator *enumerator;
|
2004-11-25 17:00:45 +00:00
|
|
|
|
NSConnection *c;
|
|
|
|
|
|
2006-08-25 15:49:01 +00:00
|
|
|
|
M_LOCK (connection_table_gate);
|
|
|
|
|
enumerator = [NSAllHashTableObjects(connection_table) objectEnumerator];
|
|
|
|
|
M_UNLOCK (connection_table_gate);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We enumerate an array copy of the contents of the hash table
|
|
|
|
|
* as we know we can do that safely outside the locked region.
|
|
|
|
|
* The temporary array and the enumerator are autoreleased and
|
|
|
|
|
* will be deallocated with the threads autorelease pool.
|
|
|
|
|
*/
|
|
|
|
|
while ((c = [enumerator nextObject]) != nil)
|
2004-11-25 17:00:45 +00:00
|
|
|
|
{
|
|
|
|
|
[c removeRunLoop: runLoop];
|
|
|
|
|
}
|
2003-09-15 13:54:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2000-07-04 11:05:46 +00:00
|
|
|
|
@end
|
|
|
|
|
|