~ubuntu-branches/ubuntu/karmic/gnustep-base/karmic

« back to all changes in this revision

Viewing changes to Source/NSConnection.m

  • Committer: Bazaar Package Importer
  • Author(s): Eric Heintzmann
  • Date: 2005-04-17 00:14:38 UTC
  • mfrom: (1.2.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050417001438-enf0y07c9tku85z1
Tags: 1.10.3-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
26
26
 
27
27
   <title>NSConnection class reference</title>
28
 
   $Date: 2002/02/13 18:49:32 $ $Revision: 1.93 $
 
28
   $Date: 2005/02/22 11:22:43 $ $Revision: 1.134 $
29
29
   */
30
30
 
31
 
#include <config.h>
32
 
#include <base/preface.h>
33
 
#ifdef  HAVE_FLOAT_H
34
 
#include <float.h>
35
 
#endif
 
31
#include "config.h"
 
32
#include "GNUstepBase/preface.h"
 
33
#include "GNUstepBase/GSLock.h"
36
34
 
37
35
/*
38
36
 *      Setup for inline operation of pointer map tables.
45
43
#define GSI_MAP_EQUAL(M, X,Y)   ((X).ptr == (Y).ptr)
46
44
#define GSI_MAP_NOCLEAN 1
47
45
 
48
 
#include <base/GSIMap.h>
 
46
#include "GNUstepBase/GSIMap.h"
49
47
 
50
48
#define _IN_CONNECTION_M
51
 
#include <Foundation/NSConnection.h>
 
49
#include "Foundation/NSConnection.h"
52
50
#undef  _IN_CONNECTION_M
53
51
 
54
52
#include <mframe.h>
58
56
#include "callframe.h"
59
57
#endif
60
58
 
61
 
#include <Foundation/NSPortCoder.h>
62
 
#include <base/DistributedObjects.h>
63
 
 
64
 
#include <Foundation/NSHashTable.h>
65
 
#include <Foundation/NSMapTable.h>
66
 
#include <Foundation/NSData.h>
67
 
#include <Foundation/NSRunLoop.h>
68
 
#include <Foundation/NSArray.h>
69
 
#include <Foundation/NSDictionary.h>
70
 
#include <Foundation/NSValue.h>
71
 
#include <Foundation/NSString.h>
72
 
#include <Foundation/NSDate.h>
73
 
#include <Foundation/NSException.h>
74
 
#include <Foundation/NSLock.h>
75
 
#include <Foundation/NSThread.h>
76
 
#include <Foundation/NSPort.h>
77
 
#include <Foundation/NSPortMessage.h>
78
 
#include <Foundation/NSPortNameServer.h>
79
 
#include <Foundation/NSNotification.h>
80
 
#include <Foundation/NSDebug.h>
81
 
#include <base/GSInvocation.h>
 
59
#include "Foundation/NSPortCoder.h"
 
60
#include "GNUstepBase/DistributedObjects.h"
 
61
 
 
62
#include "Foundation/NSHashTable.h"
 
63
#include "Foundation/NSMapTable.h"
 
64
#include "Foundation/NSData.h"
 
65
#include "Foundation/NSRunLoop.h"
 
66
#include "Foundation/NSArray.h"
 
67
#include "Foundation/NSDictionary.h"
 
68
#include "Foundation/NSValue.h"
 
69
#include "Foundation/NSString.h"
 
70
#include "Foundation/NSDate.h"
 
71
#include "Foundation/NSException.h"
 
72
#include "Foundation/NSLock.h"
 
73
#include "Foundation/NSThread.h"
 
74
#include "Foundation/NSPort.h"
 
75
#include "Foundation/NSPortMessage.h"
 
76
#include "Foundation/NSPortNameServer.h"
 
77
#include "Foundation/NSNotification.h"
 
78
#include "Foundation/NSDebug.h"
 
79
#include "GSInvocation.h"
 
80
 
 
81
#ifdef HAVE_MALLOC_H
 
82
#include <malloc.h>
 
83
#endif
 
84
 
 
85
extern NSRunLoop        *GSRunLoopForThread(NSThread*);
82
86
 
83
87
#define F_LOCK(X) {NSDebugFLLog(@"GSConnection",@"Lock %@",X);[X lock];}
84
88
#define F_UNLOCK(X) {NSDebugFLLog(@"GSConnection",@"Unlock %@",X);[X unlock];}
85
89
#define M_LOCK(X) {NSDebugMLLog(@"GSConnection",@"Lock %@",X);[X lock];}
86
90
#define M_UNLOCK(X) {NSDebugMLLog(@"GSConnection",@"Unlock %@",X);[X unlock];}
87
91
 
 
92
NSString * const NSFailedAuthenticationException =
 
93
  @"NSFailedAuthenticationExceptions";
 
94
NSString * const NSObjectInaccessibleException =
 
95
  @"NSObjectInaccessibleException";
 
96
 
88
97
/*
89
98
 * Set up a type to permit us to have direct access into an NSDistantObject
90
99
 */
99
108
static Class    connectionClass;
100
109
static Class    dateClass;
101
110
static Class    distantObjectClass;
102
 
static Class    localCounterClass;
103
111
static Class    sendCoderClass;
104
112
static Class    recvCoderClass;
105
113
static Class    runLoopClass;
134
142
    }
135
143
}
136
144
 
137
 
/*
138
 
 *      GSLocalCounter is a trivial class to keep track of how
139
 
 *      many different connections a particular local object is vended
140
 
 *      over.  This is required so that we know when to remove an object
141
 
 *      from the global list when it is removed from the list of objects
142
 
 *      vended on a particular connection.
143
 
 */
144
 
@interface      GSLocalCounter : NSObject
145
 
{
146
 
@public
147
 
  unsigned      ref;
148
 
  unsigned      target;
149
 
  id            object;
150
 
}
151
 
+ (id) newWithObject: (id)ob;
152
 
@end
153
 
 
154
 
@implementation GSLocalCounter
155
 
 
156
 
static unsigned local_object_counter = 0;
157
 
 
158
 
+ (id) newWithObject: (id)obj
159
 
{
160
 
  GSLocalCounter        *counter;
161
 
 
162
 
  counter = (GSLocalCounter*)NSAllocateObject(self, 0, NSDefaultMallocZone());
163
 
  counter->ref = 1;
164
 
  counter->object = RETAIN(obj);
165
 
  counter->target = ++local_object_counter;
166
 
  return counter;
167
 
}
168
 
- (void) dealloc
169
 
{
170
 
  RELEASE(object);
171
 
  NSDeallocateObject(self);
172
 
}
173
 
@end
174
 
 
175
145
 
176
146
 
177
147
/*
178
 
 *      CachedLocalObject is a trivial class to keep track of how
179
 
 *      many different connections a particular local object is vended
180
 
 *      over.  This is required so that we know when to remove an object
181
 
 *      from the global list when it is removed from the list of objects
182
 
 *      vended on a particular connection.
 
148
 * CachedLocalObject is a trivial class to keep track of local
 
149
 * proxies which have been removed from their connections and
 
150
 * need to persist a while in case another process needs them.
183
151
 */
184
152
@interface      CachedLocalObject : NSObject
185
153
{
186
 
  id    obj;
187
 
  int   time;
 
154
  NSDistantObject       *obj;
 
155
  int                   time;
188
156
}
189
157
- (BOOL) countdown;
190
 
- (id) obj;
191
 
+ (id) newWithObject: (id)o time: (int)t;
 
158
- (NSDistantObject*) obj;
 
159
+ (id) newWithObject: (NSDistantObject*)o time: (int)t;
192
160
@end
193
161
 
194
162
@implementation CachedLocalObject
195
163
 
196
 
+ (id) newWithObject: (id)o time: (int)t
 
164
+ (id) newWithObject: (NSDistantObject*)o time: (int)t
197
165
{
198
166
  CachedLocalObject     *item;
199
167
 
216
184
  return NO;
217
185
}
218
186
 
219
 
- (id) obj
 
187
- (NSDistantObject*) obj
220
188
{
221
189
  return obj;
222
190
}
231
199
+ (void) setDebug: (int)val;
232
200
 
233
201
- (void) addLocalObject: (NSDistantObject*)anObj;
234
 
- (NSDistantObject*) localForObject: (id)object;
235
 
- (void) removeLocalObject: (id)anObj;
 
202
- (void) removeLocalObject: (NSDistantObject*)anObj;
236
203
 
237
204
- (void) _doneInReply: (NSPortCoder*)c;
238
205
- (void) _doneInRmc: (NSPortCoder*)c;
241
208
- (NSPortCoder*) _getReplyRmc: (int)sn;
242
209
- (NSPortCoder*) _makeInRmc: (NSMutableArray*)components;
243
210
- (NSPortCoder*) _makeOutRmc: (int)sequence generate: (int*)sno reply: (BOOL)f;
 
211
- (void) _portIsInvalid: (NSNotification*)notification;
244
212
- (void) _sendOutRmc: (NSPortCoder*)c type: (int)msgid;
245
213
 
246
214
- (void) _service_forwardForProxy: (NSPortCoder*)rmc;
249
217
- (void) _service_rootObject: (NSPortCoder*)rmc;
250
218
- (void) _service_shutdown: (NSPortCoder*)rmc;
251
219
- (void) _service_typeForSelector: (NSPortCoder*)rmc;
 
220
+ (void) _threadWillExit: (NSNotification*)notification;
252
221
@end
253
222
 
254
223
#define _proxiesGate _refGate
256
225
 
257
226
 
258
227
/* class defaults */
259
 
static NSTimer          *timer;
 
228
static NSTimer          *timer = nil;
260
229
 
261
230
static BOOL cacheCoders = NO;
262
231
static int debug_connection = 0;
289
258
          break;
290
259
        }
291
260
    }
 
261
  NSEndHashTableEnumeration(&enumerator);
292
262
  F_UNLOCK(connection_table_gate);
293
263
  return c;
294
264
}
330
300
  F_UNLOCK(root_object_map_gate);
331
301
}
332
302
 
333
 
static NSMapTable *objectToCounter = NULL;
334
 
static NSMapTable *targetToCounter = NULL;
335
303
static NSMapTable *targetToCached = NULL;
336
 
static NSLock   *global_proxies_gate = nil;
 
304
static NSLock   *cached_proxies_gate = nil;
337
305
 
338
 
static BOOL     multi_threaded = NO;
339
306
 
340
307
 
341
308
 
 
309
/**
 
310
 * NSConnection objects are used to manage communications between
 
311
 * objects in different processes, in different machines, or in
 
312
 * different threads.
 
313
 */
342
314
@implementation NSConnection
343
315
 
344
 
/*
345
 
 *      When the system becomes multithreaded, we set a flag to say so and
346
 
 *      make sure that connection locking is enabled.
 
316
/**
 
317
 * Returns an array containing all the NSConnection objects known to
 
318
 * the system. These connections will be valid at the time that the
 
319
 * array was created, but may be invalidated by other threads
 
320
 * before you get to examine the array.
347
321
 */
348
 
+ (void) _becomeThreaded: (NSNotification*)notification
349
 
{
350
 
  if (multi_threaded == NO)
351
 
    {
352
 
      NSHashEnumerator  enumerator;
353
 
      NSConnection              *c;
354
 
 
355
 
      multi_threaded = YES;
356
 
      if (connection_table_gate == nil)
357
 
        {
358
 
          connection_table_gate = [NSLock new];
359
 
        }
360
 
      if (global_proxies_gate == nil)
361
 
        {
362
 
          global_proxies_gate = [NSLock new];
363
 
        }
364
 
      if (root_object_map_gate == nil)
365
 
        {
366
 
          root_object_map_gate = [NSLock new];
367
 
        }
368
 
      enumerator = NSEnumerateHashTable(connection_table);
369
 
      while ((c = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil)
370
 
        {
371
 
          if (c->_refGate == nil)
372
 
            {
373
 
              c->_refGate = [NSRecursiveLock new];
374
 
            }
375
 
        }
376
 
    }
377
 
  [[NSNotificationCenter defaultCenter]
378
 
    removeObserver: self
379
 
              name: NSWillBecomeMultiThreadedNotification
380
 
            object: nil];
381
 
}
382
 
 
383
322
+ (NSArray*) allConnections
384
323
{
385
324
  NSArray       *a;
390
329
  return a;
391
330
}
392
331
 
 
332
/**
 
333
 * Returns a connection initialised using -initWithReceivePort:sendPort:
 
334
 */
393
335
+ (NSConnection*) connectionWithReceivePort: (NSPort*)r
394
336
                                   sendPort: (NSPort*)s
395
337
{
404
346
  return c;
405
347
}
406
348
 
 
349
/**
 
350
 * <p>Returns an NSConnection object whose send port is that of the
 
351
 * NSConnection registered under the name n on the host h
 
352
 * </p>
 
353
 * <p>This method calls +connectionWithRegisteredName:host:usingNameServer:
 
354
 * using the default system name server.
 
355
 * </p>
 
356
 */
407
357
+ (NSConnection*) connectionWithRegisteredName: (NSString*)n
408
358
                                          host: (NSString*)h
409
359
{
415
365
                            usingNameServer: s];
416
366
}
417
367
 
418
 
/*
419
 
 * Create a connection to a remote server.
 
368
/**
 
369
 * <p>
 
370
 *   Returns an NSConnection object whose send port is that of the
 
371
 *   NSConnection registered under <em>name</em> on <em>host</em>.
 
372
 * </p>
 
373
 * <p>
 
374
 *   The nameserver <em>server</em> is used to look up the send
 
375
 *   port to be used for the connection.
 
376
 * </p>
 
377
 * <p>
 
378
 *   If <em>host</em> is <code>nil</code> or an empty string,
 
379
 *   the host is taken to be the local machine.
 
380
 *   If it is an asterisk ('*') then the nameserver checks all
 
381
 *   hosts on the local subnet (unless the nameserver is one
 
382
 *   that only manages local ports).
 
383
 *   In the GNUstep implementation, the local host is searched before
 
384
 *   any other hosts.
 
385
 * </p>
 
386
 * <p>
 
387
 *   If no NSConnection can be found for <em>name</em> and
 
388
 *   <em>host</em>host, the method returns <code>nil</code>.
 
389
 * </p>
 
390
 * <p>
 
391
 *   The returned object has the default NSConnection of the
 
392
 *   current thread as its parent (it has the same receive port
 
393
 *   as the default connection).
 
394
 * </p>
420
395
 */
421
396
+ (NSConnection*) connectionWithRegisteredName: (NSString*)n
422
397
                                          host: (NSString*)h
442
417
               */
443
418
              recvPort = [NSPort port];
444
419
            }
 
420
          else if (![recvPort isMemberOfClass: [sendPort class]])
 
421
            {
 
422
              /*
 
423
              We can only use the port of the default connection for
 
424
              connections using the same port class. For other port classes,
 
425
              we must use a receiving port of the same class as the sending
 
426
              port, so we allocate one here.
 
427
              */
 
428
              recvPort = [[sendPort class] port];
 
429
            }
 
430
 
445
431
          con = existingConnection(recvPort, sendPort);
446
432
          if (con == nil)
447
433
            {
453
439
  return con;
454
440
}
455
441
 
 
442
/**
 
443
 * Return the current conversation ... not implemented in GNUstep
 
444
 */
456
445
+ (id) currentConversation
457
446
{
458
 
  [self notImplemented: _cmd];
459
 
  return self;
 
447
  return nil;
460
448
}
461
449
 
462
 
/*
463
 
 *      Get the default connection for a thread.
464
 
 *      Possible problem - if the connection is invalidated, it won't be
465
 
 *      cleaned up until this thread calls this method again.  The connection
466
 
 *      and it's ports could hang around for a very long time.
 
450
/**
 
451
 * Returns the default connection for a thread.<br />
 
452
 * Creates a new instance if necessary.<br />
 
453
 * The default connection has a single NSPort object used for
 
454
 * both sending and receiving - this it can't be used to
 
455
 * connect to a remote process, but can be used to vend objects.<br />
 
456
 * Possible problem - if the connection is invalidated, it won't be
 
457
 * cleaned up until this thread calls this method again.  The connection
 
458
 * and it's ports could hang around for a very long time.
467
459
 */
468
460
+ (NSConnection*) defaultConnection
469
461
{
502
494
{
503
495
  if (self == [NSConnection class])
504
496
    {
 
497
      NSNotificationCenter      *nc;
 
498
 
505
499
      connectionClass = self;
506
500
      dateClass = [NSDate class];
507
501
      distantObjectClass = [NSDistantObject class];
508
 
      localCounterClass = [GSLocalCounter class];
509
502
      sendCoderClass = [NSPortCoder class];
510
503
      recvCoderClass = [NSPortCoder class];
511
504
      runLoopClass = [NSRunLoop class];
512
505
 
513
506
      dummyObject = [NSObject new];
514
507
 
515
 
      connection_table = 
 
508
      connection_table =
516
509
        NSCreateHashTable(NSNonRetainedObjectHashCallBacks, 0);
517
510
 
518
 
      objectToCounter =
519
 
        NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
520
 
                          NSObjectMapValueCallBacks, 0);
521
 
      targetToCounter =
522
 
        NSCreateMapTable(NSIntMapKeyCallBacks,
523
 
                          NSNonOwnedPointerMapValueCallBacks, 0);
524
511
      targetToCached =
525
512
        NSCreateMapTable(NSIntMapKeyCallBacks,
526
513
                          NSObjectMapValueCallBacks, 0);
528
515
      root_object_map =
529
516
        NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
530
517
                          NSObjectMapValueCallBacks, 0);
531
 
      if ([NSThread isMultiThreaded])
532
 
        {
533
 
          [self _becomeThreaded: nil];
534
 
        }
535
 
      else
536
 
        {
537
 
          [[NSNotificationCenter defaultCenter]
538
 
            addObserver: self
539
 
               selector: @selector(_becomeThreaded:)
540
 
                   name: NSWillBecomeMultiThreadedNotification
541
 
                 object: nil];
542
 
        }
 
518
 
 
519
      if (connection_table_gate == nil)
 
520
        {
 
521
          connection_table_gate = [GSLazyLock new];
 
522
        }
 
523
      if (cached_proxies_gate == nil)
 
524
        {
 
525
          cached_proxies_gate = [GSLazyLock new];
 
526
        }
 
527
      if (root_object_map_gate == nil)
 
528
        {
 
529
          root_object_map_gate = [GSLazyLock new];
 
530
        }
 
531
 
 
532
      /*
 
533
       * When any thread exits, we must check to see if we are using its
 
534
       * runloop, and remove ourselves from it if necessary.
 
535
       */
 
536
      nc = [NSNotificationCenter defaultCenter];
 
537
      [nc addObserver: self
 
538
             selector: @selector(_threadWillExit:)
 
539
                 name: NSThreadWillExitNotification
 
540
               object: nil];
543
541
    }
544
542
}
545
543
 
 
544
/**
 
545
 * Undocumented feature for compatibility with OPENSTEP/MacOS-X
 
546
 * +new returns the default connection.
 
547
 */
546
548
+ (id) new
547
549
{
548
 
  /*
549
 
   * Undocumented feature of OPENSTEP/MacOS-X
550
 
   * +new returns the default connection.
551
 
   */
552
550
  return RETAIN([self defaultConnection]);
553
551
}
554
552
 
 
553
/**
 
554
 * This method calls
 
555
 * +rootProxyForConnectionWithRegisteredName:host:usingNameServer:
 
556
 * to return a proxy for a root object on the remote connection with
 
557
 * the send port registered under name n on host h.
 
558
 */
555
559
+ (NSDistantObject*) rootProxyForConnectionWithRegisteredName: (NSString*)n
556
560
                                                         host: (NSString*)h
557
561
{
563
567
    {
564
568
      proxy = [connection rootProxy];
565
569
    }
566
 
  
 
570
 
567
571
  return proxy;
568
572
}
569
573
 
 
574
/**
 
575
 * This method calls
 
576
 * +connectionWithRegisteredName:host:usingNameServer:
 
577
 * to get a connection, then sends it a -rootProxy message to get
 
578
 * a proxy for the root object being vended by the remote connection.
 
579
 * Returns the proxy or nil if it couldn't find a connection or if
 
580
 * the root object for the connection has not been set.
 
581
 */
570
582
+ (NSDistantObject*) rootProxyForConnectionWithRegisteredName: (NSString*)n
571
583
  host: (NSString*)h usingNameServer: (NSPortNameServer*)s
572
584
{
580
592
    {
581
593
      proxy = [connection rootProxy];
582
594
    }
583
 
  
 
595
 
584
596
  return proxy;
585
597
}
586
598
 
589
601
  NSArray       *cached_locals;
590
602
  int   i;
591
603
 
 
604
  M_LOCK(cached_proxies_gate);
592
605
  cached_locals = NSAllMapTableValues(targetToCached);
593
606
  for (i = [cached_locals count]; i > 0; i--)
594
607
    {
596
609
 
597
610
      if ([item countdown] == NO)
598
611
        {
599
 
          GSLocalCounter        *counter = [item obj];
600
 
          NSMapRemove(targetToCached, (void*)counter->target);
 
612
          NSDistantObject       *obj = [item obj];
 
613
          NSMapRemove(targetToCached, (void*)((ProxyStruct*)obj)->_handle);
601
614
        }
602
615
    }
603
616
  if ([cached_locals count] == 0)
605
618
      [t invalidate];
606
619
      timer = nil;
607
620
    }
 
621
  M_UNLOCK(cached_proxies_gate);
608
622
}
609
623
 
 
624
/**
 
625
 * Adds mode to the run loop modes that the NSConnection
 
626
 * will listen to for incoming messages.
 
627
 */
610
628
- (void) addRequestMode: (NSString*)mode
611
629
{
612
630
  M_LOCK(_refGate);
628
646
  M_UNLOCK(_refGate);
629
647
}
630
648
 
 
649
/**
 
650
 * Adds loop to the set of run loops that the NSConnection
 
651
 * will listen to for incoming messages.
 
652
 */
631
653
- (void) addRunLoop: (NSRunLoop*)loop
632
654
{
633
655
  M_LOCK(_refGate);
635
657
    {
636
658
      if ([_runLoops indexOfObjectIdenticalTo: loop] == NSNotFound)
637
659
        {
638
 
          unsigned      c = [_requestModes count];
 
660
          unsigned              c = [_requestModes count];
639
661
 
640
662
          while (c-- > 0)
641
663
            {
656
678
  [super dealloc];
657
679
}
658
680
 
 
681
/**
 
682
 * Returns the delegate of the NSConnection.
 
683
 */
659
684
- (id) delegate
660
685
{
661
686
  return GS_GC_UNHIDE(_delegate);
662
687
}
663
688
 
 
689
/**
 
690
 * Sets the NSConnection configuration so that multiple threads may
 
691
 * use the connection to send requests to the remote connection.<br />
 
692
 * This option is inherited by child connections.<br />
 
693
 * NB. A connection with multiple threads enabled will run slower than
 
694
 * a normal connection.
 
695
 */
664
696
- (void) enableMultipleThreads
665
697
{
666
698
  _multipleThreads = YES;
667
699
}
668
700
 
 
701
/**
 
702
 * Returns YES if the NSConnection is configured to
 
703
 * handle remote messages atomically, NO otherwise.<br />
 
704
 * This option is inherited by child connections.
 
705
 */
669
706
- (BOOL) independentConversationQueueing
670
707
{
671
708
  return _independentQueueing;
672
709
}
673
710
 
 
711
/**
 
712
 * Return a connection able to act as a server receive incoming requests.
 
713
 */
674
714
- (id) init
675
715
{
676
 
  /*
677
 
   * Undocumented feature of OPENSTEP/MacOS-X
678
 
   * -init returns the default connection.
679
 
   */
680
 
  RELEASE(self);
681
 
  return RETAIN([connectionClass defaultConnection]);
 
716
  NSPort        *port = [NSPort port];
 
717
 
 
718
  self = [self initWithReceivePort: port sendPort: nil];
 
719
  return self;
682
720
}
683
721
 
684
 
/* This is the designated initializer for NSConnection */
 
722
/** <init />
 
723
 * Initialises an NSConnection with the receive port r and the
 
724
 * send port s.<br />
 
725
 * Behavior varies with the port values as follows -
 
726
 * <deflist>
 
727
 *   <term>r is <code>nil</code></term>
 
728
 *   <desc>
 
729
 *     The NSConnection is released and the method returns
 
730
 *     <code>nil</code>.
 
731
 *   </desc>
 
732
 *   <term>s is <code>nil</code></term>
 
733
 *   <desc>
 
734
 *     The NSConnection uses r as the send port as
 
735
 *     well as the receive port.
 
736
 *   </desc>
 
737
 *   <term>s is the same as r</term>
 
738
 *   <desc>
 
739
 *     The NSConnection is usable only for vending objects.
 
740
 *   </desc>
 
741
 *   <term>A connection with the same ports exists</term>
 
742
 *   <desc>
 
743
 *     The new connection is released and the old connection
 
744
 *     is retained and returned.
 
745
 *   </desc>
 
746
 *   <term>A connection with the same ports (swapped) exists</term>
 
747
 *   <desc>
 
748
 *     The new connection is initialised as normal, and will
 
749
 *     communicate with the old connection.
 
750
 *   </desc>
 
751
 * </deflist>
 
752
 * <p>
 
753
 *   If a connection exists whose send and receive ports are
 
754
 *   both the same as the new connections receive port, that
 
755
 *   existing connection is deemed to be the parent of the
 
756
 *   new connection.  The new connection inherits configuration
 
757
 *   information from the parent, and the delegate of the
 
758
 *   parent has a chance to adjust ythe configuration of the
 
759
 *   new connection or veto its creation.
 
760
 *   <br/>
 
761
 *   NSConnectionDidInitializeNotification is posted once a new
 
762
 *   connection is initialised.
 
763
 * </p>
 
764
 */
685
765
- (id) initWithReceivePort: (NSPort*)r
686
766
                  sendPort: (NSPort*)s
687
767
{
799
879
 
800
880
  _requestDepth = 0;
801
881
  _delegate = nil;
802
 
  if (multi_threaded == YES)
803
 
    {
804
 
      _refGate = [NSRecursiveLock new];
805
 
    }
 
882
  _refGate = [GSLazyRecursiveLock new];
806
883
 
807
884
  /*
808
885
   * Some attributes are inherited from the parent if possible.
827
904
    {
828
905
      _multipleThreads = NO;
829
906
      _independentQueueing = NO;
830
 
#ifndef DBL_MAX
831
 
#define DBL_MAX 100000000.0
832
 
#endif
833
 
      _replyTimeout = DBL_MAX;
834
 
      _requestTimeout = DBL_MAX;
 
907
      _replyTimeout = 300.0;    // Five minute default.
 
908
      _requestTimeout = 300.0;  // Five minute default.
835
909
      /*
836
910
       * Set up request modes array and make sure the receiving port
837
911
       * is added to the run loop to get data.
838
912
       */
839
 
      loop = [runLoopClass currentRunLoop];
 
913
      loop = GSRunLoopForThread(nil);
840
914
      _runLoops = [[NSMutableArray alloc] initWithObjects: &loop count: 1];
841
915
      _requestModes = [[NSMutableArray alloc] initWithCapacity: 2];
842
 
      [self addRequestMode: NSDefaultRunLoopMode]; 
843
 
      [self addRequestMode: NSConnectionReplyMode]; 
 
916
      [self addRequestMode: NSDefaultRunLoopMode];
 
917
      [self addRequestMode: NSConnectionReplyMode];
844
918
 
845
919
      /*
846
920
       * If we have no parent, we must handle incoming packets on our
876
950
     a substitute.  Note: The delegate is responsible for freeing
877
951
     newConn if it returns something different. */
878
952
  if ([del respondsToSelector: @selector(connection:didConnect:)])
879
 
    self = [del connection: parent didConnect: self];
 
953
    {
 
954
      self = [del connection: parent didConnect: self];
 
955
    }
880
956
 
881
 
  /* Register ourselves for invalidation notification when the
882
 
     ports become invalid. */
883
957
  nCenter = [NSNotificationCenter defaultCenter];
 
958
  /*
 
959
   * Register ourselves for invalidation notification when the
 
960
   * ports become invalid.
 
961
   */
884
962
  [nCenter addObserver: self
885
 
              selector: @selector(portIsInvalid:)
 
963
              selector: @selector(_portIsInvalid:)
886
964
                  name: NSPortDidBecomeInvalidNotification
887
965
                object: r];
888
966
  if (s != nil)
889
 
    [nCenter addObserver: self
890
 
                selector: @selector(portIsInvalid:)
891
 
                    name: NSPortDidBecomeInvalidNotification
892
 
                  object: s];
 
967
    {
 
968
      [nCenter addObserver: self
 
969
                  selector: @selector(_portIsInvalid:)
 
970
                      name: NSPortDidBecomeInvalidNotification
 
971
                    object: s];
 
972
    }
893
973
 
894
974
  /* In order that connections may be deallocated - there is an
895
975
     implementation of [-release] to automatically remove the connection
897
977
  NSHashInsert(connection_table, (void*)self);
898
978
  M_UNLOCK(connection_table_gate);
899
979
 
900
 
  [[NSNotificationCenter defaultCenter]
901
 
    postNotificationName: NSConnectionDidInitializeNotification
902
 
                  object: self];
 
980
  [nCenter postNotificationName: NSConnectionDidInitializeNotification
 
981
                         object: self];
903
982
 
904
983
  return self;
905
984
}
906
985
 
 
986
/**
 
987
 * Marks the receiving NSConnection as invalid.
 
988
 * <br />
 
989
 * Removes the NSConnections ports from any run loops.
 
990
 * <br />
 
991
 * Posts an NSConnectionDidDieNotification.
 
992
 * <br />
 
993
 * Invalidates all remote objects and local proxies.
 
994
 */
907
995
- (void) invalidate
908
996
{
909
997
  M_LOCK(_refGate);
915
1003
  _isValid = NO;
916
1004
  M_LOCK(connection_table_gate);
917
1005
  NSHashRemove(connection_table, self);
918
 
  [timer invalidate];
919
 
  timer = nil;
920
1006
  M_UNLOCK(connection_table_gate);
921
1007
 
922
1008
  M_UNLOCK(_refGate);
923
1009
 
924
1010
  /*
925
 
   *    Don't need notifications any more - so remove self as observer.
 
1011
   * Don't need notifications any more - so remove self as observer.
926
1012
   */
927
1013
  [[NSNotificationCenter defaultCenter] removeObserver: self];
928
1014
 
944
1030
        (gsaddr)self, _receivePort, _sendPort);
945
1031
    }
946
1032
  /*
947
 
   *    We need to notify any watchers of our death - but if we are already
948
 
   *    in the deallocation process, we can't have a notification retaining
949
 
   *    and autoreleasing us later once we are deallocated - so we do the
950
 
   *    notification with a local autorelease pool to ensure that any release
951
 
   *    is done before the deallocation completes.
 
1033
   * We need to notify any watchers of our death - but if we are already
 
1034
   * in the deallocation process, we can't have a notification retaining
 
1035
   * and autoreleasing us later once we are deallocated - so we do the
 
1036
   * notification with a local autorelease pool to ensure that any release
 
1037
   * is done before the deallocation completes.
952
1038
   */
953
1039
  {
954
1040
    CREATE_AUTORELEASE_POOL(arp);
968
1054
  M_LOCK(_proxiesGate);
969
1055
  if (_localTargets != 0)
970
1056
    {
971
 
      NSMutableArray    *targets;
972
 
      unsigned          i = _localTargets->nodeCount;
 
1057
      NSMutableArray            *targets;
 
1058
      unsigned                  i = _localTargets->nodeCount;
973
1059
      GSIMapEnumerator_t        enumerator;
974
1060
      GSIMapNode                node;
975
1061
 
983
1069
        }
984
1070
      while (i-- > 0)
985
1071
        {
986
 
          id    t = ((ProxyStruct*)[targets objectAtIndex: i])->_object;
987
 
 
988
 
          [self removeLocalObject: t];
 
1072
          [self removeLocalObject: [targets objectAtIndex: i]];
989
1073
        }
990
1074
      RELEASE(targets);
991
1075
      GSIMapEmptyMap(_localTargets);
1017
1101
    }
1018
1102
  M_UNLOCK(_proxiesGate);
1019
1103
 
 
1104
  /*
 
1105
   * If we are invalidated, we shouldn't be receiving any event and
 
1106
   * should not need to be in any run loops.
 
1107
   */
 
1108
  while ([_runLoops count] > 0)
 
1109
    {
 
1110
      [self removeRunLoop: [_runLoops lastObject]];
 
1111
    }
 
1112
 
 
1113
  /*
 
1114
   * Invalidate the current conversation so we don't leak.
 
1115
   */
 
1116
  if ([_sendPort isValid] == YES)
 
1117
    {
 
1118
      [[_sendPort conversation: _receivePort] invalidate];
 
1119
    }
 
1120
 
1020
1121
  RELEASE(self);
1021
1122
}
1022
1123
 
 
1124
/**
 
1125
 * Returns YES if the connection is valid, NO otherwise.
 
1126
 * A connection is valid until it has been sent an -invalidate message.
 
1127
 */
1023
1128
- (BOOL) isValid
1024
1129
{
1025
1130
  return _isValid;
1026
1131
}
1027
1132
 
 
1133
/**
 
1134
 * Returns an array of all the local objects that have proxies at the
 
1135
 * remote end of the connection because they have been sent over the
 
1136
 * connection and not yet released by the far end.
 
1137
 */
1028
1138
- (NSArray*) localObjects
1029
1139
{
1030
1140
  NSMutableArray        *c;
1054
1164
  return c;
1055
1165
}
1056
1166
 
 
1167
/**
 
1168
 * Returns YES if the connection permits multiple threads to use it to
 
1169
 * send requests, NO otherwise.<br />
 
1170
 * See the -enableMultipleThreads method.
 
1171
 */
1057
1172
- (BOOL) multipleThreadsEnabled
1058
1173
{
1059
1174
  return _multipleThreads;
1060
1175
}
1061
1176
 
 
1177
/**
 
1178
 * Returns the NSPort object on which incoming messages are recieved.
 
1179
 */
1062
1180
- (NSPort*) receivePort
1063
1181
{
1064
1182
  return _receivePort;
1065
1183
}
1066
1184
 
 
1185
/**
 
1186
 * Simply invokes -registerName:withNameServer:
 
1187
 * passing it the default system nameserver.
 
1188
 */
1067
1189
- (BOOL) registerName: (NSString*)name
1068
1190
{
1069
1191
  NSPortNameServer      *svr = [NSPortNameServer systemDefaultPortNameServer];
1071
1193
  return [self registerName: name withNameServer: svr];
1072
1194
}
1073
1195
 
 
1196
/**
 
1197
 * Registers the recieve port of the NSConnection as name and
 
1198
 * unregisters the previous value (if any).<br />
 
1199
 * Returns YES on success, NO on failure.<br />
 
1200
 * On failure, the connection remains registered under the
 
1201
 * previous name.<br />
 
1202
 * Supply nil as name to unregister the NSConnection.
 
1203
 */
1074
1204
- (BOOL) registerName: (NSString*)name withNameServer: (NSPortNameServer*)svr
1075
1205
{
1076
1206
  BOOL                  result = YES;
1108
1238
  [super release];
1109
1239
}
1110
1240
 
 
1241
/**
 
1242
 * Returns an array of proxies to all the remote objects known to
 
1243
 * the NSConnection.
 
1244
 */
1111
1245
- (NSArray *) remoteObjects
1112
1246
{
1113
1247
  NSMutableArray        *c;
1137
1271
  return c;
1138
1272
}
1139
1273
 
 
1274
/**
 
1275
 * Removes mode from the run loop modes used to receive incoming messages.
 
1276
 */
1140
1277
- (void) removeRequestMode: (NSString*)mode
1141
1278
{
1142
1279
  M_LOCK(_refGate);
1155
1292
  M_UNLOCK(_refGate);
1156
1293
}
1157
1294
 
 
1295
/**
 
1296
 * Removes loop from the run loops used to recieve incoming messages.
 
1297
 */
1158
1298
- (void) removeRunLoop: (NSRunLoop*)loop
1159
1299
{
1160
1300
  M_LOCK(_refGate);
1178
1318
  M_UNLOCK(_refGate);
1179
1319
}
1180
1320
 
 
1321
/**
 
1322
 * Returns the timeout interval used when waiting for a reply to
 
1323
 * a request sent on the NSConnection.  This value is inherited
 
1324
 * from the parent connection or may be set using the -setReplyTimeout:
 
1325
 * method.<br />
 
1326
 * Under MacOS-X the default value is documented as the maximum delay
 
1327
 * (effectively infinite), but under GNUstep it is set to a more
 
1328
 * useful 300 seconds.
 
1329
 */
1181
1330
- (NSTimeInterval) replyTimeout
1182
1331
{
1183
1332
  return _replyTimeout;
1184
1333
}
1185
1334
 
 
1335
/**
 
1336
 * Returns an array of all the run loop modes that the NSConnection
 
1337
 * uses when waiting for an incoming request.
 
1338
 */
1186
1339
- (NSArray*) requestModes
1187
1340
{
1188
1341
  NSArray       *c;
1193
1346
  return c;
1194
1347
}
1195
1348
 
 
1349
/**
 
1350
 * Returns the timeout interval used when trying to send a request
 
1351
 * on the NSConnection.  This value is inherited from the parent
 
1352
 * connection or may be set using the -setRequestTimeout: method.<br />
 
1353
 * Under MacOS-X the default value is documented as the maximum delay
 
1354
 * (effectively infinite), but under GNUstep it is set to a more
 
1355
 * useful 300 seconds.
 
1356
 */
1196
1357
- (NSTimeInterval) requestTimeout
1197
1358
{
1198
1359
  return _requestTimeout;
1199
1360
}
1200
1361
 
 
1362
/**
 
1363
 * Returns the object that is made available by this connection
 
1364
 * or by its parent (the object is associated with the receive port).<br />
 
1365
 * Returns nil if no root object has been set.
 
1366
 */
1201
1367
- (id) rootObject
1202
1368
{
1203
1369
  return rootObjectForInPort(_receivePort);
1204
1370
}
1205
1371
 
 
1372
/**
 
1373
 * Returns the proxy for the root object of the remote NSConnection.<br />
 
1374
 * Generally you will wish to call [NSDistantObject-setProtocolForProxy:]
 
1375
 * immediately after obtaining such a root proxy.
 
1376
 */
1206
1377
- (NSDistantObject*) rootProxy
1207
1378
{
1208
1379
  NSPortCoder           *op;
1230
1401
  return AUTORELEASE(newProxy);
1231
1402
}
1232
1403
 
 
1404
/**
 
1405
 * Removes the NSConnection from the current threads default
 
1406
 * run loop, then creates a new thread and runs the NSConnection in it.
 
1407
 */
1233
1408
- (void) runInNewThread
1234
1409
{
1235
 
  [self removeRunLoop: [runLoopClass currentRunLoop]];
 
1410
  [self removeRunLoop: GSRunLoopForThread(nil)];
1236
1411
  [NSThread detachNewThreadSelector: @selector(_runInNewThread)
1237
1412
                           toTarget: self
1238
1413
                         withObject: nil];
1239
1414
}
1240
1415
 
 
1416
/**
 
1417
 * Returns the port on which the NSConnection sends messages.
 
1418
 */
1241
1419
- (NSPort*) sendPort
1242
1420
{
1243
1421
  return _sendPort;
1244
1422
}
1245
1423
 
 
1424
/**
 
1425
 * Sets the NSConnection's delegate (without retaining it).<br />
 
1426
 * The delegate is able to control some of the NSConnection's
 
1427
 * behavior by implementing methods in an informal protocol.
 
1428
 */
1246
1429
- (void) setDelegate: (id)anObj
1247
1430
{
1248
1431
  _delegate = GS_GC_HIDE(anObj);
1252
1435
    [anObj respondsToSelector: @selector(authenticationDataForComponents:)];
1253
1436
}
1254
1437
 
 
1438
/**
 
1439
 * Sets whether or not the NSConnection should handle requests
 
1440
 * arriving from the remote NSConnection atomically.<br />
 
1441
 * By default, this is set to NO ... if set to YES then any messages
 
1442
 * arriving while one message is being dealt with, will be queued.<br />
 
1443
 * NB. careful - use of this option can cause deadlocks.
 
1444
 */
1255
1445
- (void) setIndependentConversationQueueing: (BOOL)flag
1256
1446
{
1257
1447
  _independentQueueing = flag;
1258
1448
}
1259
1449
 
 
1450
/**
 
1451
 * Sets the time interval that the NSConnection will wait for a
 
1452
 * reply for one of its requests before raising an
 
1453
 * NSPortTimeoutException.<br />
 
1454
 * NB. In GNUstep you may also get such an exception if the connection
 
1455
 * becomes invalidated while waiting for a reply to a request.
 
1456
 */
1260
1457
- (void) setReplyTimeout: (NSTimeInterval)to
1261
1458
{
1262
1459
  _replyTimeout = to;
1263
1460
}
1264
1461
 
 
1462
/**
 
1463
 * Sets the runloop mode in which requests will be sent to the remote
 
1464
 * end of the connection.  Normally this is NSDefaultRunloopMode
 
1465
 */
1265
1466
- (void) setRequestMode: (NSString*)mode
1266
1467
{
1267
1468
  M_LOCK(_refGate);
1284
1485
  M_UNLOCK(_refGate);
1285
1486
}
1286
1487
 
 
1488
/**
 
1489
 * Sets the time interval that the NSConnection will wait to send
 
1490
 * one of its requests before raising an NSPortTimeoutException.
 
1491
 */
1287
1492
- (void) setRequestTimeout: (NSTimeInterval)to
1288
1493
{
1289
1494
  _requestTimeout = to;
1290
1495
}
1291
1496
 
 
1497
/**
 
1498
 * Sets the root object that is vended by the connection.
 
1499
 */
1292
1500
- (void) setRootObject: (id)anObj
1293
1501
{
1294
1502
  setRootObjectForInPort(anObj, _receivePort);
1295
1503
}
1296
1504
 
 
1505
/**
 
1506
 * Returns an object containing various statistics for the
 
1507
 * NSConnection.
 
1508
 * <br />
 
1509
 * On GNUstep the dictionary contains -
 
1510
 * <deflist>
 
1511
 *   <term>NSConnectionRepliesReceived</term>
 
1512
 *   <desc>
 
1513
 *     The number of messages replied to by the remote NSConnection.
 
1514
 *   </desc>
 
1515
 *   <term>NSConnectionRepliesSent</term>
 
1516
 *   <desc>
 
1517
 *     The number of replies sent to the remote NSConnection.
 
1518
 *   </desc>
 
1519
 *   <term>NSConnectionRequestsReceived</term>
 
1520
 *   <desc>
 
1521
 *     The number of messages recieved from the remote NSConnection.
 
1522
 *   </desc>
 
1523
 *   <term>NSConnectionRequestsSent</term>
 
1524
 *   <desc>
 
1525
 *     The number of messages sent to the remote NSConnection.
 
1526
 *   </desc>
 
1527
 *   <term>NSConnectionLocalCount</term>
 
1528
 *   <desc>
 
1529
 *     The number of local objects currently vended.
 
1530
 *   </desc>
 
1531
 *   <term>NSConnectionProxyCount</term>
 
1532
 *   <desc>
 
1533
 *     The number of remote objects currently in use.
 
1534
 *   </desc>
 
1535
 * </deflist>
 
1536
 */
1297
1537
- (NSDictionary*) statistics
1298
1538
{
1299
1539
  NSMutableDictionary   *d;
1405
1645
 
1406
1646
      while (node != 0)
1407
1647
        {
1408
 
          if (node->key.obj != dummyObject)
 
1648
          if (node->value.obj != dummyObject)
1409
1649
            {
1410
 
              RELEASE(node->key.obj);
 
1650
              RELEASE(node->value.obj);
1411
1651
            }
1412
1652
          node = GSIMapEnumeratorNextNode(&enumerator);
1413
1653
        }
1476
1716
  else
1477
1717
    {
1478
1718
      [coder decodeValueOfObjCType: type at: ctxt->datum];
1479
 
      if ((*type == _C_CHARPTR || *type == _C_PTR) && *(void**)ctxt->datum != 0)
1480
 
        {
1481
 
          [NSData dataWithBytesNoCopy: *(void**)ctxt->datum length: 1];
1482
 
        }
1483
1719
    }
1484
1720
}
1485
1721
 
1487
1723
{
1488
1724
  switch (*ctxt->type)
1489
1725
    {
1490
 
    case _C_ID: 
 
1726
    case _C_ID:
1491
1727
      if (ctxt->flags & _F_BYCOPY)
1492
1728
        {
1493
1729
          [ctxt->encoder encodeBycopyObject: *(id*)ctxt->datum];
1503
1739
          [ctxt->encoder encodeObject: *(id*)ctxt->datum];
1504
1740
        }
1505
1741
      break;
1506
 
    default: 
 
1742
    default:
1507
1743
      [ctxt->encoder encodeValueOfObjCType: ctxt->type at: ctxt->datum];
1508
1744
    }
1509
1745
}
1510
1746
 
1511
1747
/*
1512
 
 * NSDistantObject's -forward: : method calls this to send the message
 
1748
 * NSDistantObject's -forward:: method calls this to send the message
1513
1749
 * over the wire.
1514
1750
 */
1515
1751
- (retval_t) forwardForProxy: (NSDistantObject*)object
1521
1757
  const char    *type;
1522
1758
  retval_t      retframe;
1523
1759
  DOContext     ctxt;
 
1760
  NSThread      *thread = GSCurrentThread();
 
1761
  NSRunLoop     *runLoop = GSRunLoopForThread(thread);
1524
1762
 
1525
1763
  memset(&ctxt, 0, sizeof(ctxt));
1526
1764
  ctxt.connection = self;
1527
 
  
 
1765
 
1528
1766
  /* Encode the method on an RMC, and send it. */
1529
1767
 
1530
1768
  NSParameterAssert (_isValid);
1531
1769
 
 
1770
  if ([_runLoops indexOfObjectIdenticalTo: runLoop] == NSNotFound)
 
1771
    {
 
1772
      if (_multipleThreads == NO)
 
1773
        {
 
1774
          [NSException raise: NSObjectInaccessibleException
 
1775
                      format: @"Forwarding message in wrong thread"];
 
1776
        }
 
1777
      else
 
1778
        {
 
1779
          [self addRunLoop: runLoop];
 
1780
        }
 
1781
    }
 
1782
 
1532
1783
  /* get the method types from the selector */
1533
1784
#if NeXT_RUNTIME
1534
1785
  [NSException
1542
1793
      type = [[object methodSignatureForSelector: sel] methodType];
1543
1794
      if (type)
1544
1795
        {
1545
 
          sel_register_typed_name(sel_get_name(sel), type);
 
1796
          sel_register_typed_name(GSNameFromSelector(sel), type);
1546
1797
        }
1547
1798
    }
1548
1799
#endif
1594
1845
 
1595
1846
  [self _sendOutRmc: ctxt.encoder type: METHOD_REQUEST];
1596
1847
  ctxt.encoder = nil;
1597
 
  NSDebugMLLog(@"NSConnection", @"Sent message to 0x%x", (gsaddr)self);
 
1848
  NSDebugMLLog(@"NSConnection", @"Sent message (%s) to 0x%x",
 
1849
    GSNameFromSelector(sel), (gsaddr)self);
1598
1850
 
1599
1851
  if (needsResponse == NO)
1600
1852
    {
1641
1893
 * NSDistantObject's -forwardInvocation: method calls this to send the message
1642
1894
 * over the wire.
1643
1895
 */
1644
 
- (void) forwardInvocation: (NSInvocation *)inv 
1645
 
                  forProxy: (NSDistantObject*)object 
 
1896
- (void) forwardInvocation: (NSInvocation*)inv
 
1897
                  forProxy: (NSDistantObject*)object
1646
1898
{
1647
1899
  NSPortCoder   *op;
1648
1900
  BOOL          outParams;
1649
1901
  BOOL          needsResponse;
1650
1902
  const char    *type;
1651
1903
  DOContext     ctxt;
 
1904
  NSThread      *thread = GSCurrentThread();
 
1905
  NSRunLoop     *runLoop = GSRunLoopForThread(thread);
 
1906
 
 
1907
  if ([_runLoops indexOfObjectIdenticalTo: runLoop] == NSNotFound)
 
1908
    {
 
1909
      if (_multipleThreads == NO)
 
1910
        {
 
1911
          [NSException raise: NSObjectInaccessibleException
 
1912
                      format: @"Forwarding message in wrong thread"];
 
1913
        }
 
1914
      else
 
1915
        {
 
1916
          [self addRunLoop: runLoop];
 
1917
        }
 
1918
    }
1652
1919
 
1653
1920
  /* Encode the method on an RMC, and send it. */
1654
1921
 
1661
1928
      type = [[object methodSignatureForSelector: [inv selector]] methodType];
1662
1929
      if (type)
1663
1930
        {
1664
 
          sel_register_typed_name(sel_get_name([inv selector]), type);
 
1931
          sel_register_typed_name(GSNameFromSelector([inv selector]), type);
1665
1932
        }
1666
1933
    }
1667
1934
  NSParameterAssert(type);
1675
1942
  if (debug_connection > 4)
1676
1943
    NSLog(@"building packet seq %d", ctxt.seq);
1677
1944
 
 
1945
  [inv setTarget: object];
1678
1946
  outParams = [inv encodeWithDistantCoder: op passPointers: NO];
1679
1947
 
1680
1948
  if (outParams == YES)
1734
2002
    }
1735
2003
  else
1736
2004
    {
1737
 
#ifdef USE_FFCALL
 
2005
#ifdef USE_LIBFFI
 
2006
      cifframe_build_return (inv, type, outParams, retDecoder, &ctxt);
 
2007
#elif defined(USE_FFCALL)
1738
2008
      callframe_build_return (inv, type, outParams, retDecoder, &ctxt);
1739
2009
#endif
1740
2010
      /* Make sure we processed all arguments, and dismissed the IP.
1751
2021
  id op, ip;
1752
2022
  char  *type = 0;
1753
2023
  int   seq_num;
 
2024
  NSData *data;
1754
2025
 
1755
2026
  NSParameterAssert(_receivePort);
1756
2027
  NSParameterAssert (_isValid);
1760
2031
  [self _sendOutRmc: op type: METHODTYPE_REQUEST];
1761
2032
  ip = [self _getReplyRmc: seq_num];
1762
2033
  [ip decodeValueOfObjCType: @encode(char*) at: &type];
 
2034
  data = type ? [NSData dataWithBytes: type length: strlen(type)+1] : nil;
1763
2035
  [self _doneInRmc: ip];
1764
 
  return type;
 
2036
  return (const char*)[data bytes];
1765
2037
}
1766
2038
 
1767
2039
 
1792
2064
          count++;
1793
2065
        }
1794
2066
    }
 
2067
  NSEndHashTableEnumeration(&enumerator);
1795
2068
  M_UNLOCK(connection_table_gate);
1796
2069
 
1797
2070
  return count;
1863
2136
 
1864
2137
  switch (type)
1865
2138
    {
1866
 
      case ROOTPROXY_REQUEST: 
 
2139
      case ROOTPROXY_REQUEST:
1867
2140
        /* It won't take much time to handle this, so go ahead and service
1868
2141
           it, even if we are waiting for a reply. */
1869
2142
        [conn _service_rootObject: rmc];
1870
2143
        break;
1871
2144
 
1872
 
      case METHODTYPE_REQUEST: 
 
2145
      case METHODTYPE_REQUEST:
1873
2146
        /* It won't take much time to handle this, so go ahead and service
1874
2147
           it, even if we are waiting for a reply. */
1875
2148
        [conn _service_typeForSelector: rmc];
1876
2149
        break;
1877
2150
 
1878
 
      case METHOD_REQUEST: 
 
2151
      case METHOD_REQUEST:
1879
2152
        /*
1880
2153
         * We just got a new request; we need to decide whether to queue
1881
2154
         * it or service it now.
1889
2162
          {
1890
2163
            conn->_requestDepth++;
1891
2164
            M_UNLOCK(conn->_queueGate);
1892
 
            [conn _service_forwardForProxy: rmc];
 
2165
            [conn _service_forwardForProxy: rmc];       // Catches exceptions
1893
2166
            M_LOCK(conn->_queueGate);
1894
2167
            conn->_requestDepth--;
1895
2168
          }
1906
2179
            rmc = [conn->_requestQueue objectAtIndex: 0];
1907
2180
            [conn->_requestQueue removeObjectAtIndex: 0];
1908
2181
            M_UNLOCK(conn->_queueGate);
1909
 
            [conn _service_forwardForProxy: rmc];
 
2182
            [conn _service_forwardForProxy: rmc];       // Catches exceptions
1910
2183
            M_LOCK(conn->_queueGate);
1911
2184
          }
1912
2185
        M_UNLOCK(conn->_queueGate);
1917
2190
       * store it in a map using thee sequence number as the key.  That way
1918
2191
       * it's easy for the connection to find replies by their numbers.
1919
2192
       */
1920
 
      case ROOTPROXY_REPLY: 
1921
 
      case METHOD_REPLY: 
1922
 
      case METHODTYPE_REPLY: 
1923
 
      case RETAIN_REPLY: 
 
2193
      case ROOTPROXY_REPLY:
 
2194
      case METHOD_REPLY:
 
2195
      case METHODTYPE_REPLY:
 
2196
      case RETAIN_REPLY:
1924
2197
        {
1925
2198
          int           sequence;
1926
2199
          GSIMapNode    node;
1951
2224
        }
1952
2225
        break;
1953
2226
 
1954
 
      case CONNECTION_SHUTDOWN: 
 
2227
      case CONNECTION_SHUTDOWN:
1955
2228
        {
1956
2229
          [conn _service_shutdown: rmc];
1957
2230
          break;
1958
2231
        }
1959
 
      case PROXY_RELEASE: 
 
2232
      case PROXY_RELEASE:
1960
2233
        {
1961
2234
          [conn _service_release: rmc];
1962
2235
          break;
1963
2236
        }
1964
 
      case PROXY_RETAIN: 
 
2237
      case PROXY_RETAIN:
1965
2238
        {
1966
2239
          [conn _service_retain: rmc];
1967
2240
          break;
1968
2241
        }
1969
 
      default: 
 
2242
      default:
1970
2243
        [NSException raise: NSGenericException
1971
2244
                    format: @"unrecognized NSPortCoder identifier"];
1972
2245
    }
1974
2247
 
1975
2248
- (void) _runInNewThread
1976
2249
{
1977
 
  NSRunLoop     *loop = [runLoopClass currentRunLoop];
 
2250
  NSRunLoop     *loop = GSRunLoopForThread(nil);
1978
2251
 
1979
2252
  [self addRunLoop: loop];
1980
2253
  [loop run];
2015
2288
    }
2016
2289
  else
2017
2290
    {
2018
 
      void      *datum = ctxt->datum;
2019
 
 
2020
 
      [ctxt->decoder decodeValueOfObjCType: type at: datum];
2021
 
      /*
2022
 
       * -decodeValueOfObjCType:at: malloc's new memory
2023
 
       * for pointers.  We need to make sure it gets freed eventually
2024
 
       * so we don't have a memory leak.  Request here that it be
2025
 
       * autorelease'ed.
2026
 
       */
2027
 
      if ((*type == _C_CHARPTR || *type == _C_PTR) && *(void**)datum != 0)
2028
 
        {
2029
 
          [NSData dataWithBytesNoCopy: *(void**)datum length: 1];
2030
 
        }
 
2291
      [ctxt->decoder decodeValueOfObjCType: type at: ctxt->datum];
2031
2292
    }
2032
2293
}
2033
2294
 
2104
2365
   */
2105
2366
  NS_DURING
2106
2367
    {
 
2368
      NSThread  *thread = GSCurrentThread();
 
2369
      NSRunLoop *runLoop = GSRunLoopForThread(thread);
 
2370
 
2107
2371
      NSParameterAssert (_isValid);
 
2372
      if ([_runLoops indexOfObjectIdenticalTo: runLoop] == NSNotFound)
 
2373
        {
 
2374
          if (_multipleThreads == YES)
 
2375
            {
 
2376
              [self addRunLoop: runLoop];
 
2377
            }
 
2378
          else
 
2379
            {
 
2380
              [NSException raise: NSObjectInaccessibleException
 
2381
                          format: @"Message received in wrong thread"];
 
2382
            }
 
2383
        }
2108
2384
 
2109
2385
      /* Save this for later */
2110
2386
      [aRmc decodeValueOfObjCType: @encode(int) at: &ctxt.seq];
2139
2415
    }
2140
2416
  NS_HANDLER
2141
2417
    {
 
2418
      if (debug_connection > 3)
 
2419
        NSLog(@"forwarding exception for (0x%x) - %@",
 
2420
          (gsaddr)self, localException);
 
2421
 
2142
2422
      /* Send the exception back to the client. */
2143
2423
      if (_isValid == YES)
2144
2424
        {
2181
2461
        }
2182
2462
    }
2183
2463
  NS_ENDHANDLER;
2184
 
  if (forward_type != 0)
2185
 
    {
2186
 
      NSZoneFree(NSDefaultMallocZone(), forward_type);
2187
 
    }
2188
2464
}
2189
2465
 
2190
2466
- (void) _service_rootObject: (NSPortCoder*)rmc
2226
2502
      if (prox != nil)
2227
2503
        {
2228
2504
          if (debug_connection > 3)
2229
 
            NSLog(@"releasing object with target (0x%x) on (0x%x)",
2230
 
                target, (gsaddr)self);
2231
 
          [self removeLocalObject: ((ProxyStruct*)prox)->_object];
 
2505
            NSLog(@"releasing object with target (0x%x) on (0x%x) counter %d",
 
2506
                target, (gsaddr)self, ((ProxyStruct*)prox)->_counter);
 
2507
#if 1
 
2508
          // FIXME thread safety
 
2509
          if (--(((ProxyStruct*)prox)->_counter) == 0)
 
2510
            {
 
2511
              [self removeLocalObject: prox];
 
2512
            }
 
2513
#else
 
2514
          [self removeLocalObject: prox];
 
2515
#endif
2232
2516
        }
2233
2517
      else if (debug_connection > 3)
2234
2518
        NSLog(@"releasing object with target (0x%x) on (0x%x) - nothing to do",
2239
2523
 
2240
2524
- (void) _service_retain: (NSPortCoder*)rmc
2241
2525
{
2242
 
  unsigned      target;
2243
 
  NSPortCoder   *op;
2244
 
  int           sequence;
 
2526
  unsigned              target;
 
2527
  NSPortCoder           *op;
 
2528
  int                   sequence;
 
2529
  NSDistantObject       *local;
 
2530
  NSString              *response = nil;
2245
2531
 
2246
2532
  NSParameterAssert (_isValid);
2247
2533
 
2255
2541
    NSLog(@"looking to retain local object with target (0x%x) on (0x%x)",
2256
2542
                target, (gsaddr)self);
2257
2543
 
2258
 
  if ([self includesLocalTarget: target] == nil)
2259
 
    {
2260
 
      GSLocalCounter    *counter;
2261
 
 
2262
 
      M_LOCK(global_proxies_gate);
2263
 
      counter = NSMapGet (targetToCounter, (void*)target);
2264
 
      if (counter == nil)
2265
 
        {
2266
 
          /*
2267
 
           *    If the target doesn't exist for any connection, but still
2268
 
           *    persists in the cache (ie it was recently released) then
2269
 
           *    we move it back from the cache to the main maps so we can
2270
 
           *    retain it on this connection.
2271
 
           */
2272
 
          counter = NSMapGet (targetToCached, (void*)target);
2273
 
          if (counter)
2274
 
            {
2275
 
              unsigned  t = counter->target;
2276
 
              id        o = counter->object;
2277
 
 
2278
 
              NSMapInsert(objectToCounter, (void*)o, counter);
2279
 
              NSMapInsert(targetToCounter, (void*)t, counter);
2280
 
              NSMapRemove(targetToCached, (void*)t);
2281
 
              if (debug_connection > 3)
2282
 
                NSLog(@"target (0x%x) moved from cache", target);
2283
 
            }
2284
 
        }
2285
 
      M_UNLOCK(global_proxies_gate);
2286
 
      if (counter == nil)
2287
 
        {
2288
 
          [op encodeObject: @"target not found anywhere"];
2289
 
          if (debug_connection > 3)
2290
 
            NSLog(@"target (0x%x) not found anywhere for retain", target);
2291
 
        }
2292
 
      else
2293
 
        {
2294
 
          [distantObjectClass proxyWithLocal: counter->object
2295
 
                                  connection: self];
2296
 
          [op encodeObject: nil];
2297
 
          if (debug_connection > 3)
2298
 
            NSLog(@"retained object (0x%x) target (0x%x) on connection(0x%x)",
2299
 
                        counter->object, counter->target, self);
2300
 
        }
2301
 
    }
2302
 
  else 
2303
 
    {
2304
 
      [op encodeObject: nil];
2305
 
      if (debug_connection > 3)
2306
 
        NSLog(@"target (0x%x) already retained on connection (0x%x)",
2307
 
                target, self);
2308
 
    }
2309
 
 
 
2544
  M_LOCK(_proxiesGate);
 
2545
  local = [self locateLocalTarget: target];
 
2546
  if (local == nil)
 
2547
    {
 
2548
      response = @"target not found anywhere";
 
2549
    }
 
2550
  else
 
2551
    {
 
2552
      ((ProxyStruct*)local)->_counter++;        // Vended on connection.
 
2553
    }
 
2554
  M_UNLOCK(_proxiesGate);
 
2555
 
 
2556
  [op encodeObject: response];
2310
2557
  [self _sendOutRmc: op type: RETAIN_REPLY];
2311
2558
}
2312
2559
 
2336
2583
  unsigned      target;
2337
2584
  NSDistantObject *p;
2338
2585
  int           sequence;
2339
 
  id o;
2340
 
  SEL sel;
2341
 
  const char *type;
 
2586
  id            o;
 
2587
  SEL           sel;
 
2588
  const char    *type;
2342
2589
  struct objc_method* m;
2343
2590
 
2344
2591
  NSParameterAssert(_receivePort);
2351
2598
  [rmc decodeValueOfObjCType: @encode(unsigned) at: &target];
2352
2599
  [self _doneInRmc: rmc];
2353
2600
  p = [self includesLocalTarget: target];
2354
 
  o = ((ProxyStruct*)p)->_object;
 
2601
  o = (p != nil) ? ((ProxyStruct*)p)->_object : nil;
2355
2602
 
2356
2603
  /* xxx We should make sure that TARGET is a valid object. */
2357
2604
  /* Not actually a Proxy, but we avoid the warnings "id" would have made. */
2358
 
  m = class_get_instance_method(((NSDistantObject*)o)->isa, sel);
 
2605
  m = GSGetMethod(((NSDistantObject*)o)->isa, sel, YES, YES);
2359
2606
  /* Perhaps I need to be more careful in the line above to get the
2360
2607
     version of the method types that has the type qualifiers in it.
2361
2608
     Search the protocols list. */
2377
2624
- _getReplyRmc: (int)sn
2378
2625
{
2379
2626
  NSPortCoder           *rmc;
2380
 
  GSIMapNode            node;
 
2627
  GSIMapNode            node = 0;
2381
2628
  NSDate                *timeout_date = nil;
2382
2629
  NSTimeInterval        last_interval = 0.0001;
2383
2630
  NSTimeInterval        delay_interval = last_interval;
2384
2631
  NSDate                *delay_date = nil;
2385
 
  NSRunLoop             *runLoop = [runLoopClass currentRunLoop];
 
2632
  NSThread              *thread = GSCurrentThread();
 
2633
  NSRunLoop             *runLoop = GSRunLoopForThread(thread);
 
2634
  BOOL                  isLocked = NO;
2386
2635
 
2387
 
  if (debug_connection > 5)
2388
 
    NSLog(@"Waiting for reply sequence %d on %x:%x",
2389
 
      sn, self, [NSThread currentThread]);
2390
 
  M_LOCK(_queueGate);
2391
 
  while ((node = GSIMapNodeForKey(_replyMap, (GSIMapKey)sn)) != 0
2392
 
    && node->value.obj == dummyObject)
 
2636
  /*
 
2637
   * If we have sent out a request on a run loop that we don't already
 
2638
   * know about, it must be on a new thread - so if we have multipleThreads
 
2639
   * enabled, we must add the run loop of the new thread so that we can
 
2640
   * get the reply in this thread.
 
2641
   */
 
2642
  if ([_runLoops indexOfObjectIdenticalTo: runLoop] == NSNotFound)
2393
2643
    {
2394
 
      M_UNLOCK(_queueGate);
2395
 
      if (timeout_date == nil)
2396
 
        {
2397
 
          timeout_date = [dateClass allocWithZone: NSDefaultMallocZone()];
2398
 
          timeout_date
2399
 
            = [timeout_date initWithTimeIntervalSinceNow: _replyTimeout];
2400
 
        }
2401
2644
      if (_multipleThreads == YES)
2402
2645
        {
2403
 
          NSDate                *limit_date;
2404
 
          NSTimeInterval        next_interval;
 
2646
          [self addRunLoop: runLoop];
 
2647
        }
 
2648
      else
 
2649
        {
 
2650
          [NSException raise: NSObjectInaccessibleException
 
2651
                      format: @"Waiting for reply in wrong thread"];
 
2652
        }
 
2653
    }
2405
2654
 
2406
 
          /*
2407
 
           * If multiple threads are using this connections, another
2408
 
           * thread may read the reply we are waiting for - so we must
2409
 
           * break out of the runloop frequently to check.  We do this
2410
 
           * by setting a small delay and increasing it each time round
2411
 
           * so that this semi-busy wait doesn't consume too much
2412
 
           * processor time (I hope).
2413
 
           * We set an upper limit on the delay to avoid responsiveness
2414
 
           * problems.
2415
 
           */
2416
 
          RELEASE(delay_date);
2417
 
          delay_date = [dateClass allocWithZone: NSDefaultMallocZone()];
2418
 
          if (delay_interval < 1.0)
 
2655
  NS_DURING
 
2656
    {
 
2657
      if (debug_connection > 5)
 
2658
        NSLog(@"Waiting for reply sequence %d on %x:%x",
 
2659
          sn, self, [NSThread currentThread]);
 
2660
      M_LOCK(_queueGate); isLocked = YES;
 
2661
      while (_isValid == YES
 
2662
        && (node = GSIMapNodeForKey(_replyMap, (GSIMapKey)sn)) != 0
 
2663
        && node->value.obj == dummyObject)
 
2664
        {
 
2665
          M_UNLOCK(_queueGate); isLocked = NO;
 
2666
          if (timeout_date == nil)
2419
2667
            {
2420
 
              next_interval = last_interval + delay_interval;
2421
 
              last_interval = delay_interval;
2422
 
              delay_interval = next_interval;
 
2668
              timeout_date = [dateClass allocWithZone: NSDefaultMallocZone()];
 
2669
              timeout_date
 
2670
                = [timeout_date initWithTimeIntervalSinceNow: _replyTimeout];
2423
2671
            }
2424
 
          delay_date
2425
 
            = [delay_date initWithTimeIntervalSinceNow: delay_interval];
2426
 
 
2427
 
          /*
2428
 
           * We must not set a delay date that is further in the future
2429
 
           * than the timeout date for the response to be returned.
2430
 
           */
2431
 
          if ([timeout_date earlierDate: delay_date] == timeout_date)
 
2672
          if (_multipleThreads == YES)
2432
2673
            {
2433
 
              limit_date = timeout_date;
 
2674
              NSDate            *limit_date;
 
2675
              NSTimeInterval    next_interval;
 
2676
 
 
2677
              /*
 
2678
               * If multiple threads are using this connections, another
 
2679
               * thread may read the reply we are waiting for - so we must
 
2680
               * break out of the runloop frequently to check.  We do this
 
2681
               * by setting a small delay and increasing it each time round
 
2682
               * so that this semi-busy wait doesn't consume too much
 
2683
               * processor time (I hope).
 
2684
               * We set an upper limit on the delay to avoid responsiveness
 
2685
               * problems.
 
2686
               */
 
2687
              RELEASE(delay_date);
 
2688
              delay_date = [dateClass allocWithZone: NSDefaultMallocZone()];
 
2689
              if (delay_interval < 1.0)
 
2690
                {
 
2691
                  next_interval = last_interval + delay_interval;
 
2692
                  last_interval = delay_interval;
 
2693
                  delay_interval = next_interval;
 
2694
                }
 
2695
              delay_date
 
2696
                = [delay_date initWithTimeIntervalSinceNow: delay_interval];
 
2697
 
 
2698
              /*
 
2699
               * We must not set a delay date that is further in the future
 
2700
               * than the timeout date for the response to be returned.
 
2701
               */
 
2702
              if ([timeout_date earlierDate: delay_date] == timeout_date)
 
2703
                {
 
2704
                  limit_date = timeout_date;
 
2705
                }
 
2706
              else
 
2707
                {
 
2708
                  limit_date = delay_date;
 
2709
                }
 
2710
 
 
2711
              /*
 
2712
               * If the runloop returns without having done anything, AND we
 
2713
               * were waiting for the final timeout, then we must break out
 
2714
               * of the loop.
 
2715
               */
 
2716
              if ([runLoop runMode: NSConnectionReplyMode
 
2717
                        beforeDate: limit_date] == NO
 
2718
                || [timeout_date timeIntervalSinceNow] <= 0.0)
 
2719
                {
 
2720
                  if (limit_date == timeout_date)
 
2721
                    {
 
2722
                      M_LOCK(_queueGate); isLocked = YES;
 
2723
                      node = GSIMapNodeForKey(_replyMap, (GSIMapKey)sn);
 
2724
                      break;
 
2725
                    }
 
2726
                }
2434
2727
            }
2435
2728
          else
2436
2729
            {
2437
 
              limit_date = delay_date;
2438
 
            }
2439
 
 
2440
 
          /*
2441
 
           * If the runloop returns without having done anything, AND we
2442
 
           * were waiting for the final timeout, then we must break out
2443
 
           * of the loop.
2444
 
           */
2445
 
          if ([runLoop runMode: NSConnectionReplyMode
2446
 
                    beforeDate: limit_date] == NO)
2447
 
            {
2448
 
              if (limit_date == timeout_date)
 
2730
              /*
 
2731
               * Normal operation - wait for data or for a timeout.
 
2732
               */
 
2733
              if ([runLoop runMode: NSConnectionReplyMode
 
2734
                        beforeDate: timeout_date] == NO
 
2735
                || [timeout_date timeIntervalSinceNow] <= 0.0)
2449
2736
                {
2450
 
                  M_LOCK(_queueGate);
 
2737
                  M_LOCK(_queueGate); isLocked = YES;
2451
2738
                  node = GSIMapNodeForKey(_replyMap, (GSIMapKey)sn);
2452
2739
                  break;
2453
2740
                }
2454
2741
            }
 
2742
          M_LOCK(_queueGate); isLocked = YES;
 
2743
        }
 
2744
      if (node == 0)
 
2745
        {
 
2746
          rmc = nil;
2455
2747
        }
2456
2748
      else
2457
2749
        {
2458
 
          /*
2459
 
           * Normal operation - wait for data to be recieved or for a timeout.
2460
 
           */
2461
 
          if ([runLoop runMode: NSConnectionReplyMode
2462
 
                    beforeDate: timeout_date] == NO)
2463
 
            {
2464
 
              M_LOCK(_queueGate);
2465
 
              node = GSIMapNodeForKey(_replyMap, (GSIMapKey)sn);
2466
 
              break;
2467
 
            }
2468
 
        }
2469
 
      M_LOCK(_queueGate);
2470
 
    }
2471
 
  if (node == 0)
2472
 
    {
2473
 
      rmc = nil;
2474
 
    }
2475
 
  else
2476
 
    {
2477
 
      rmc = node->value.obj;
2478
 
      GSIMapRemoveKey(_replyMap, (GSIMapKey)sn);
2479
 
    }
2480
 
  M_UNLOCK(_queueGate);
2481
 
  TEST_RELEASE(delay_date);
2482
 
  TEST_RELEASE(timeout_date);
2483
 
  if (rmc == nil)
2484
 
    {
2485
 
      [NSException raise: NSInternalInconsistencyException
2486
 
                  format: @"no reply message available"];
2487
 
    }
2488
 
  if (rmc == dummyObject)
2489
 
    {
2490
 
      [NSException raise: NSPortTimeoutException
2491
 
                  format: @"timed out waiting for reply"];
2492
 
    }
 
2750
          rmc = node->value.obj;
 
2751
          GSIMapRemoveKey(_replyMap, (GSIMapKey)sn);
 
2752
        }
 
2753
      M_UNLOCK(_queueGate); isLocked = NO;
 
2754
      TEST_RELEASE(delay_date);
 
2755
      TEST_RELEASE(timeout_date);
 
2756
      if (rmc == nil)
 
2757
        {
 
2758
          [NSException raise: NSInternalInconsistencyException
 
2759
                      format: @"no reply message available"];
 
2760
        }
 
2761
      if (rmc == dummyObject)
 
2762
        {
 
2763
          if (_isValid == YES)
 
2764
            {
 
2765
              [NSException raise: NSPortTimeoutException
 
2766
                          format: @"timed out waiting for reply"];
 
2767
            }
 
2768
          else
 
2769
            {
 
2770
              [NSException raise: NSPortTimeoutException
 
2771
                          format: @"invalidated while awaiting reply"];
 
2772
            }
 
2773
        }
 
2774
    }
 
2775
  NS_HANDLER
 
2776
    {
 
2777
      if (isLocked == YES)
 
2778
        {
 
2779
          M_UNLOCK(_queueGate);
 
2780
        }
 
2781
      [localException raise];
 
2782
    }
 
2783
  NS_ENDHANDLER
 
2784
 
2493
2785
  NSDebugMLLog(@"NSConnection", @"Consuming reply RMC %d on %x", sn, self);
2494
2786
  return rmc;
2495
2787
}
2692
2984
                          reserved: [_sendPort reservedSpaceLength]];
2693
2985
 
2694
2986
  M_LOCK(_refGate);
2695
 
  /*
2696
 
   * If we have sent out a request on a run loop that we don't already
2697
 
   * know about, it must be on a new thread - so if we have multipleThreads
2698
 
   * enabled, we must add the run loop of the new thread so that we can
2699
 
   * get the reply in this thread.
2700
 
   */
2701
 
  if (_multipleThreads == YES && needsReply == YES)
2702
 
    {
2703
 
      NSRunLoop *loop = [runLoopClass currentRunLoop];
2704
 
 
2705
 
      if ([_runLoops indexOfObjectIdenticalTo: loop] == NSNotFound)
2706
 
        {
2707
 
          [self addRunLoop: loop];
2708
 
        }
2709
 
    }
2710
 
 
2711
 
  /*
2712
 
   * We replace the code we have just used in the cache, and tell it not to
 
2987
 
 
2988
  /*
 
2989
   * We replace the coder we have just used in the cache, and tell it not to
2713
2990
   * retain this connection any more.
2714
2991
   */
2715
2992
  if (cacheCoders == YES && _cachedEncoders != nil)
2758
3035
/* Managing objects and proxies. */
2759
3036
- (void) addLocalObject: (NSDistantObject*)anObj
2760
3037
{
 
3038
  static unsigned       local_object_counter = 0;
2761
3039
  id                    object;
2762
3040
  unsigned              target;
2763
 
  GSLocalCounter        *counter;
2764
3041
  GSIMapNode            node;
2765
3042
 
2766
3043
  M_LOCK(_proxiesGate);
2767
 
  M_LOCK(global_proxies_gate);
2768
3044
  NSParameterAssert (_isValid);
2769
3045
 
 
3046
  object = ((ProxyStruct*)anObj)->_object;
 
3047
  target = ((ProxyStruct*)anObj)->_handle;
 
3048
 
 
3049
  /*
 
3050
   * If there is no target allocated to the proxy, we add one.
 
3051
   */
 
3052
  if (target == 0)
 
3053
    {
 
3054
      ((ProxyStruct*)anObj)->_handle = target = ++local_object_counter;
 
3055
    }
 
3056
 
2770
3057
  /*
2771
3058
   * Record the value in the _localObjects map, retaining it.
2772
3059
   */
2773
 
  object = ((ProxyStruct*)anObj)->_object;
2774
3060
  node = GSIMapNodeForKey(_localObjects, (GSIMapKey)object);
2775
 
  IF_NO_GC(RETAIN(anObj));
2776
 
  if (node == 0)
2777
 
    {
2778
 
      GSIMapAddPair(_localObjects, (GSIMapKey)object, (GSIMapVal)anObj);
2779
 
    }
2780
 
  else
2781
 
    {
2782
 
      RELEASE(node->value.obj);
2783
 
      node->value.obj = anObj;
2784
 
    }
 
3061
  NSAssert(node == 0, NSInternalInconsistencyException);
 
3062
  node = GSIMapNodeForKey(_localTargets, (GSIMapKey)target);
 
3063
  NSAssert(node == 0, NSInternalInconsistencyException);
2785
3064
 
2786
 
  /*
2787
 
   *    Keep track of local objects accross all connections.
2788
 
   */
2789
 
  counter = NSMapGet(objectToCounter, (void*)object);
2790
 
  if (counter)
2791
 
    {
2792
 
      counter->ref++;
2793
 
      target = counter->target;
2794
 
    }
2795
 
  else
2796
 
    {
2797
 
      counter = [localCounterClass newWithObject: object];
2798
 
      target = counter->target;
2799
 
      NSMapInsert(objectToCounter, (void*)object, counter);
2800
 
      NSMapInsert(targetToCounter, (void*)target, counter);
2801
 
      RELEASE(counter);
2802
 
    }
2803
 
  ((ProxyStruct*)anObj)->_handle = target;
 
3065
  RETAIN(anObj);
 
3066
  GSIMapAddPair(_localObjects, (GSIMapKey)object, (GSIMapVal)anObj);
2804
3067
  GSIMapAddPair(_localTargets, (GSIMapKey)target, (GSIMapVal)anObj);
 
3068
 
2805
3069
  if (debug_connection > 2)
2806
3070
    NSLog(@"add local object (0x%x) target (0x%x) "
2807
 
          @"to connection (0x%x) (ref %d)",
2808
 
                (gsaddr)object, target, (gsaddr) self, counter->ref);
2809
 
  M_UNLOCK(global_proxies_gate);
 
3071
          @"to connection (0x%x)", (gsaddr)object, target, (gsaddr) self);
 
3072
 
2810
3073
  M_UNLOCK(_proxiesGate);
2811
3074
}
2812
3075
 
2813
 
- (NSDistantObject*) localForObject: (id)object
 
3076
- (NSDistantObject*) retainOrAddLocal: (NSDistantObject*)proxy
 
3077
                            forObject: (id)object
2814
3078
{
2815
3079
  GSIMapNode            node;
2816
3080
  NSDistantObject       *p;
2825
3089
  else
2826
3090
    {
2827
3091
      p = node->value.obj;
 
3092
      RETAIN(p);
 
3093
      DESTROY(proxy);
 
3094
    }
 
3095
  if (p == nil && proxy != nil)
 
3096
    {
 
3097
      p = proxy;
 
3098
      [self addLocalObject: p];
2828
3099
    }
2829
3100
  M_UNLOCK(_proxiesGate);
2830
 
  NSParameterAssert(p == nil || [p connectionForProxy] == self);
2831
3101
  return p;
2832
3102
}
2833
3103
 
2834
 
- (void) removeLocalObject: (id)anObj
 
3104
- (void) removeLocalObject: (NSDistantObject*)prox
2835
3105
{
2836
 
  NSDistantObject       *prox;
2837
 
  unsigned              target;
2838
 
  GSLocalCounter        *counter;
2839
 
  unsigned              val = 0;
2840
 
  GSIMapNode            node;
 
3106
  id            anObj;
 
3107
  unsigned      target;
 
3108
  unsigned      val = 0;
 
3109
  GSIMapNode    node;
2841
3110
 
2842
 
  M_LOCK(global_proxies_gate);
2843
3111
  M_LOCK(_proxiesGate);
2844
 
 
 
3112
  anObj = ((ProxyStruct*)prox)->_object;
2845
3113
  node = GSIMapNodeForKey(_localObjects, (GSIMapKey)anObj);
2846
 
  if (node == 0)
2847
 
    {
2848
 
      prox = nil;
2849
 
    }
2850
 
  else
2851
 
    {
2852
 
      prox = node->value.obj;
2853
 
    }
2854
 
  target = ((ProxyStruct*)prox)->_handle;
2855
3114
 
2856
3115
  /*
2857
 
   *    If all references to a local proxy have gone - remove the
2858
 
   *    global reference as well.
 
3116
   * The NSDistantObject concerned may not belong to this connection,
 
3117
   * so we need to check that any matching proxy is identical to the
 
3118
   * argument we were given.
2859
3119
   */
2860
 
  counter = NSMapGet(objectToCounter, (void*)anObj);
2861
 
  if (counter)
 
3120
  if (node != 0 && node->value.obj == prox)
2862
3121
    {
2863
 
      counter->ref--;
2864
 
      if ((val = counter->ref) == 0)
 
3122
      target = ((ProxyStruct*)prox)->_handle;
 
3123
 
 
3124
      /*
 
3125
       * If this proxy has been vended onwards to another process
 
3126
       * which has not myet released it, we need to keep a reference
 
3127
       * to the local object around for a while in case that other
 
3128
       * process needs it.
 
3129
       */
 
3130
      if ((((ProxyStruct*)prox)->_counter) != 0)
2865
3131
        {
2866
 
          /*
2867
 
           *    If this proxy has been vended onwards by another process, we
2868
 
           *    need to keep a reference to the local object around for a
2869
 
           *    while in case that other process needs it.
2870
 
           */
2871
 
          if (0)
 
3132
          CachedLocalObject     *item;
 
3133
 
 
3134
          (((ProxyStruct*)prox)->_counter) = 0;
 
3135
          M_LOCK(cached_proxies_gate);
 
3136
          if (timer == nil)
2872
3137
            {
2873
 
              id        item;
2874
 
              if (timer == nil)
2875
 
                {
2876
 
                  timer = [NSTimer scheduledTimerWithTimeInterval: 1.0
2877
 
                                         target: connectionClass
2878
 
                                         selector: @selector(_timeout:)
2879
 
                                         userInfo: nil
2880
 
                                          repeats: YES];
2881
 
                }
2882
 
              item = [CachedLocalObject newWithObject: counter time: 30];
2883
 
              NSMapInsert(targetToCached, (void*)target, item);
2884
 
              RELEASE(item);
2885
 
              if (debug_connection > 3)
2886
 
                NSLog(@"placed local object (0x%x) target (0x%x) in cache",
2887
 
                            (gsaddr)anObj, target);
 
3138
              timer = [NSTimer scheduledTimerWithTimeInterval: 1.0
 
3139
                target: connectionClass
 
3140
                selector: @selector(_timeout:)
 
3141
                userInfo: nil
 
3142
                repeats: YES];
2888
3143
            }
2889
 
          NSMapRemove(objectToCounter, (void*)anObj);
2890
 
          NSMapRemove(targetToCounter, (void*)target);
 
3144
          item = [CachedLocalObject newWithObject: prox time: 5];
 
3145
          NSMapInsert(targetToCached, (void*)target, item);
 
3146
          M_UNLOCK(cached_proxies_gate);
 
3147
          RELEASE(item);
 
3148
          if (debug_connection > 3)
 
3149
            NSLog(@"placed local object (0x%x) target (0x%x) in cache",
 
3150
                        (gsaddr)anObj, target);
2891
3151
        }
 
3152
 
 
3153
      /*
 
3154
       * Remove the proxy from _localObjects and release it.
 
3155
       */
 
3156
      GSIMapRemoveKey(_localObjects, (GSIMapKey)anObj);
 
3157
      RELEASE(prox);
 
3158
 
 
3159
      /*
 
3160
       * Remove the target info too - no release required.
 
3161
       */
 
3162
      GSIMapRemoveKey(_localTargets, (GSIMapKey)target);
 
3163
 
 
3164
      if (debug_connection > 2)
 
3165
        NSLog(@"removed local object (0x%x) target (0x%x) "
 
3166
            @"from connection (0x%x) (ref %d)",
 
3167
                    (gsaddr)anObj, target, (gsaddr)self, val);
2892
3168
    }
2893
 
 
2894
 
  /*
2895
 
   * Remove the proxy from _localObjects and release it.
2896
 
   */
2897
 
  GSIMapRemoveKey(_localObjects, (GSIMapKey)anObj);
2898
 
  RELEASE(prox);
2899
 
 
2900
 
  /*
2901
 
   * Remove the target info too - no release required.
2902
 
   */
2903
 
  GSIMapRemoveKey(_localTargets, (GSIMapKey)target);
2904
 
 
2905
 
  if (debug_connection > 2)
2906
 
    NSLog(@"remove local object (0x%x) target (0x%x) "
2907
 
        @"from connection (0x%x) (ref %d)",
2908
 
                (gsaddr)anObj, target, (gsaddr)self, val);
2909
 
 
2910
3169
  M_UNLOCK(_proxiesGate);
2911
 
  M_UNLOCK(global_proxies_gate);
2912
3170
}
2913
3171
 
2914
 
- (void) _release_targets: (unsigned*)list count: (unsigned)number
 
3172
- (void) _release_target: (unsigned)target count: (unsigned)number
2915
3173
{
2916
3174
  NS_DURING
2917
3175
    {
2932
3190
 
2933
3191
          for (i = 0; i < number; i++)
2934
3192
            {
2935
 
              [op encodeValueOfObjCType: @encode(unsigned) at: &list[i]];
 
3193
              [op encodeValueOfObjCType: @encode(unsigned) at: &target];
2936
3194
              if (debug_connection > 3)
2937
3195
                NSLog(@"sending release for target (0x%x) on (0x%x)",
2938
 
                      list[i], (gsaddr)self);
 
3196
                      target, (gsaddr)self);
2939
3197
            }
2940
3198
 
2941
3199
          [self _sendOutRmc: op type: PROXY_RELEASE];
2949
3207
  NS_ENDHANDLER
2950
3208
}
2951
3209
 
2952
 
- (void) retainTarget: (unsigned)target
2953
 
{
2954
 
  NS_DURING
2955
 
    {
2956
 
      /*
2957
 
       *        Tell the remote app that it must retain the local object
2958
 
       *        for the target on this connection.
2959
 
       */
2960
 
      if (_receivePort && _isValid)
2961
 
        {
2962
 
          NSPortCoder   *op;
2963
 
          id    ip;
2964
 
          id    result;
2965
 
          int   seq_num;
2966
 
 
2967
 
          op = [self _makeOutRmc: 0 generate: &seq_num reply: YES];
2968
 
          [op encodeValueOfObjCType: @encode(typeof(target)) at: &target];
2969
 
          [self _sendOutRmc: op type: PROXY_RETAIN];
2970
 
 
2971
 
          ip = [self _getReplyRmc: seq_num];
2972
 
          [ip decodeValueOfObjCType: @encode(id) at: &result];
2973
 
          [self _doneInRmc: ip];
2974
 
          if (result != nil)
2975
 
            NSLog(@"failed to retain target - %@", result);
2976
 
        }
2977
 
    }
2978
 
  NS_HANDLER
2979
 
    {
2980
 
      NSLog(@"failed to retain target - %@", localException);
2981
 
    }
2982
 
  NS_ENDHANDLER
 
3210
- (NSDistantObject*) locateLocalTarget: (unsigned)target
 
3211
{
 
3212
  NSDistantObject       *proxy = nil;
 
3213
  GSIMapNode            node;
 
3214
 
 
3215
  M_LOCK(_proxiesGate);
 
3216
 
 
3217
  /*
 
3218
   * Try a quick lookup to see if the target references a local object
 
3219
   * belonging to the receiver ... usually it should.
 
3220
   */
 
3221
  node = GSIMapNodeForKey(_localTargets, (GSIMapKey)target);
 
3222
  if (node != 0)
 
3223
    {
 
3224
      proxy = node->value.obj;
 
3225
    }
 
3226
 
 
3227
  /*
 
3228
   * If the target doesn't exist in the receiver, but still
 
3229
   * persists in the cache (ie it was recently released) then
 
3230
   * we move it back from the cache to the receiver.
 
3231
   */
 
3232
  if (proxy == nil)
 
3233
    {
 
3234
      CachedLocalObject *cached;
 
3235
 
 
3236
      M_LOCK(cached_proxies_gate);
 
3237
      cached = NSMapGet (targetToCached, (void*)target);
 
3238
      if (cached != nil)
 
3239
        {
 
3240
          proxy = [cached obj];
 
3241
          /*
 
3242
           * Found in cache ... add to this connection as the object
 
3243
           * is no longer in use by any connection.
 
3244
           */
 
3245
          ASSIGN(((ProxyStruct*)proxy)->_connection, self);
 
3246
          [self addLocalObject: proxy];
 
3247
          NSMapRemove(targetToCached, (void*)target);
 
3248
          if (debug_connection > 3)
 
3249
            NSLog(@"target (0x%x) moved from cache", target);
 
3250
        }
 
3251
      M_UNLOCK(cached_proxies_gate);
 
3252
    }
 
3253
 
 
3254
  /*
 
3255
   * If not found in the current connection or the cache of local references
 
3256
   * of recently invalidated connections, try all other existing connections.
 
3257
   */
 
3258
  if (proxy == nil)
 
3259
    {
 
3260
      NSHashEnumerator  enumerator;
 
3261
      NSConnection      *c;
 
3262
 
 
3263
      M_LOCK(connection_table_gate);
 
3264
      enumerator = NSEnumerateHashTable(connection_table);
 
3265
      while (proxy == nil
 
3266
        && (c = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil)
 
3267
        {
 
3268
          if (c != self && [c isValid] == YES)
 
3269
            {
 
3270
              M_LOCK(c->_proxiesGate);
 
3271
              node = GSIMapNodeForKey(c->_localTargets, (GSIMapKey)target);
 
3272
              if (node != 0)
 
3273
                {
 
3274
                  id            local;
 
3275
                  unsigned      nTarget;
 
3276
 
 
3277
                  /*
 
3278
                   * We found the local object in use in another connection
 
3279
                   * so we create a new reference to the same object and
 
3280
                   * add it to our connection, adjusting the target of the
 
3281
                   * new reference to be the value we need.
 
3282
                   *
 
3283
                   * We don't want to just share the NSDistantObject with
 
3284
                   * the other connection, since we might want to keep
 
3285
                   * track of information on a per-connection basis in
 
3286
                   * order to handle connection shutdown cleanly.
 
3287
                   */
 
3288
                  proxy = node->value.obj;
 
3289
                  local = RETAIN(((ProxyStruct*)proxy)->_object);
 
3290
                  proxy = [NSDistantObject proxyWithLocal: local
 
3291
                                               connection: self];
 
3292
                  nTarget = ((ProxyStruct*)proxy)->_handle;
 
3293
                  GSIMapRemoveKey(_localTargets, (GSIMapKey)nTarget);
 
3294
                  ((ProxyStruct*)proxy)->_handle = target;
 
3295
                  GSIMapAddPair(_localTargets, (GSIMapKey)target,
 
3296
                    (GSIMapVal)proxy);
 
3297
                }
 
3298
              M_UNLOCK(c->_proxiesGate);
 
3299
            }
 
3300
        }
 
3301
      NSEndHashTableEnumeration(&enumerator);
 
3302
      M_UNLOCK(connection_table_gate);
 
3303
    }
 
3304
 
 
3305
  M_UNLOCK(_proxiesGate);
 
3306
 
 
3307
  if (proxy == nil)
 
3308
    {
 
3309
      if (debug_connection > 3)
 
3310
        NSLog(@"target (0x%x) not found anywhere", target);
 
3311
    }
 
3312
  return proxy;
 
3313
}
 
3314
 
 
3315
- (void) vendLocal: (NSDistantObject*)aProxy
 
3316
{
 
3317
  M_LOCK(_proxiesGate);
 
3318
  ((ProxyStruct*)aProxy)->_counter++;
 
3319
  M_UNLOCK(_proxiesGate);
 
3320
}
 
3321
 
 
3322
- (void) aquireProxyForTarget: (unsigned)target
 
3323
{
 
3324
  NSDistantObject       *found;
 
3325
  GSIMapNode            node;
 
3326
 
 
3327
  /* Don't assert (_isValid); */
 
3328
  M_LOCK(_proxiesGate);
 
3329
  node = GSIMapNodeForKey(_remoteProxies, (GSIMapKey)target);
 
3330
  if (node == 0)
 
3331
    {
 
3332
      found = nil;
 
3333
    }
 
3334
  else
 
3335
    {
 
3336
      found = node->value.obj;
 
3337
    }
 
3338
  M_UNLOCK(_proxiesGate);
 
3339
  if (found == nil)
 
3340
    {
 
3341
      NS_DURING
 
3342
        {
 
3343
          /*
 
3344
           * Tell the remote app that it must retain the local object
 
3345
           * for the target on this connection.
 
3346
           */
 
3347
          if (_receivePort && _isValid)
 
3348
            {
 
3349
              NSPortCoder       *op;
 
3350
              id        ip;
 
3351
              id        result;
 
3352
              int       seq_num;
 
3353
 
 
3354
              op = [self _makeOutRmc: 0 generate: &seq_num reply: YES];
 
3355
              [op encodeValueOfObjCType: @encode(typeof(target)) at: &target];
 
3356
              [self _sendOutRmc: op type: PROXY_RETAIN];
 
3357
 
 
3358
              ip = [self _getReplyRmc: seq_num];
 
3359
              [ip decodeValueOfObjCType: @encode(id) at: &result];
 
3360
              [self _doneInRmc: ip];
 
3361
              if (result != nil)
 
3362
                NSLog(@"failed to retain target - %@", result);
 
3363
              else if (debug_connection > 3)
 
3364
                NSLog(@"sending retain for target - %u", target);
 
3365
            }
 
3366
        }
 
3367
      NS_HANDLER
 
3368
        {
 
3369
          NSLog(@"failed to retain target - %@", localException);
 
3370
        }
 
3371
      NS_ENDHANDLER
 
3372
    }
 
3373
}
 
3374
 
 
3375
- (id) retain
 
3376
{
 
3377
  return [super retain];
2983
3378
}
2984
3379
 
2985
3380
- (void) removeProxy: (NSDistantObject*)aProxy
2988
3383
  if (_isValid == YES)
2989
3384
    {
2990
3385
      unsigned          target;
 
3386
      unsigned          count = 1;
2991
3387
      GSIMapNode        node;
2992
3388
 
2993
3389
      target = ((ProxyStruct*)aProxy)->_handle;
2994
3390
      node = GSIMapNodeForKey(_remoteProxies, (GSIMapKey)target);
2995
 
      if (node != 0)
 
3391
 
 
3392
      /*
 
3393
       * Only remove if the proxy for the target is the same as the
 
3394
       * supplied argument.
 
3395
       */
 
3396
      if (node != 0 && node->value.obj == aProxy)
2996
3397
        {
2997
 
          RELEASE(node->value.obj);
 
3398
          count = ((ProxyStruct*)aProxy)->_counter;
2998
3399
          GSIMapRemoveKey(_remoteProxies, (GSIMapKey)target);
 
3400
          /*
 
3401
           * Tell the remote application that we have removed our proxy and
 
3402
           * it can release it's local object.
 
3403
           */
 
3404
          [self _release_target: target count: count];
2999
3405
        }
3000
 
      /*
3001
 
       * Tell the remote application that we have removed our proxy and
3002
 
       * it can release it's local object.
3003
 
       */
3004
 
      [self _release_targets: &target count: 1];
3005
3406
    }
3006
3407
  M_UNLOCK(_proxiesGate);
3007
3408
}
3008
3409
 
3009
 
- (NSDistantObject*) proxyForTarget: (unsigned)target
 
3410
 
 
3411
/**
 
3412
 * Private method used only when a remote process/thread has sent us a
 
3413
 * target which we are decoding into a proxy in this process/thread.
 
3414
 * <p>The argument aProxy may be nil, in which case an existing proxy
 
3415
 * matching aTarget is retrieved retained, and returned (this is done
 
3416
 * when a proxy target is sent to us by a remote process).
 
3417
 * </p>
 
3418
 * <p>If aProxy is not nil, but a proxy with the same target already
 
3419
 * exists, then aProxy is released and the existing proxy is returned
 
3420
 * as in the case where aProxy was nil.
 
3421
 * </p>
 
3422
 * <p>If aProxy is not nil and there was no prior proxy with the same
 
3423
 * target, aProxy is added to the receiver and returned.
 
3424
 * </p>
 
3425
 */
 
3426
- (NSDistantObject*) retainOrAddProxy: (NSDistantObject*)aProxy
 
3427
                            forTarget: (unsigned)aTarget
3010
3428
{
3011
3429
  NSDistantObject       *p;
3012
3430
  GSIMapNode            node;
3013
3431
 
3014
3432
  /* Don't assert (_isValid); */
 
3433
  NSParameterAssert(aTarget > 0);
 
3434
  NSParameterAssert(aProxy==nil || aProxy->isa == distantObjectClass);
 
3435
  NSParameterAssert(aProxy==nil || [aProxy connectionForProxy] == self);
 
3436
  NSParameterAssert(aProxy==nil || aTarget == ((ProxyStruct*)aProxy)->_handle);
 
3437
 
3015
3438
  M_LOCK(_proxiesGate);
3016
 
  node = GSIMapNodeForKey(_remoteProxies, (GSIMapKey)target);
 
3439
  node = GSIMapNodeForKey(_remoteProxies, (GSIMapKey)aTarget);
3017
3440
  if (node == 0)
3018
3441
    {
3019
3442
      p = nil;
3021
3444
  else
3022
3445
    {
3023
3446
      p = node->value.obj;
 
3447
      RETAIN(p);
 
3448
      DESTROY(aProxy);
 
3449
    }
 
3450
  if (p == nil && aProxy != nil)
 
3451
    {
 
3452
      p = aProxy;
 
3453
      GSIMapAddPair(_remoteProxies, (GSIMapKey)aTarget, (GSIMapVal)p);
 
3454
    }
 
3455
  /*
 
3456
   * Whether this is a new proxy or an existing proxy, this method is
 
3457
   * only called for an object being vended by a remote process/thread.
 
3458
   * We therefore need to increment the count of the number of times
 
3459
   * the proxy has been vended.
 
3460
   */
 
3461
  if (p != nil)
 
3462
    {
 
3463
      ((ProxyStruct*)p)->_counter++;
3024
3464
    }
3025
3465
  M_UNLOCK(_proxiesGate);
3026
3466
  return p;
3027
3467
}
3028
3468
 
3029
 
- (void) addProxy: (NSDistantObject*) aProxy
3030
 
{
3031
 
  unsigned      target;
3032
 
  GSIMapNode    node;
3033
 
 
3034
 
  M_LOCK(_proxiesGate);
3035
 
  NSParameterAssert(_isValid);
3036
 
  NSParameterAssert(aProxy->isa == distantObjectClass);
3037
 
  NSParameterAssert([aProxy connectionForProxy] == self);
3038
 
  target = ((ProxyStruct*)aProxy)->_handle;
3039
 
  node = GSIMapNodeForKey(_remoteProxies, (GSIMapKey)target);
3040
 
  if (node != 0)
3041
 
    {
3042
 
      M_UNLOCK(_proxiesGate);
3043
 
      [NSException raise: NSGenericException
3044
 
                  format: @"Trying to add the same proxy twice"];
3045
 
    }
3046
 
  GSIMapAddPair(_remoteProxies, (GSIMapKey)target, (GSIMapVal)aProxy);
3047
 
  M_UNLOCK(_proxiesGate);
3048
 
}
3049
 
 
3050
 
- (id) includesProxyForTarget: (unsigned)target
3051
 
{
3052
 
  NSDistantObject       *ret;
3053
 
  GSIMapNode            node;
3054
 
 
3055
 
  /* Don't assert (_isValid); */
3056
 
  M_LOCK(_proxiesGate);
3057
 
  node = GSIMapNodeForKey(_remoteProxies, (GSIMapKey)target);
3058
 
  if (node == 0)
3059
 
    {
3060
 
      ret = nil;
3061
 
    }
3062
 
  else
3063
 
    {
3064
 
      ret = node->value.obj;
3065
 
    }
3066
 
  M_UNLOCK(_proxiesGate);
3067
 
  return ret;
3068
 
}
3069
 
 
3070
3469
- (id) includesLocalObject: (id)anObj
3071
3470
{
3072
3471
  NSDistantObject       *ret;
3087
3486
  return ret;
3088
3487
}
3089
3488
 
3090
 
- (id) includesLocalTarget: (unsigned)target
 
3489
- (NSDistantObject*) includesLocalTarget: (unsigned)target
3091
3490
{
3092
3491
  NSDistantObject       *ret;
3093
3492
  GSIMapNode            node;
3107
3506
  return ret;
3108
3507
}
3109
3508
 
3110
 
/* Check all connections.
3111
 
   Proxy needs to use this when decoding a local object in order to
3112
 
   make sure the target address is a valid object.  It is not enough
3113
 
   for the Proxy to check the Proxy's connection only (using
3114
 
   -includesLocalTarget), because the proxy may have come from a
3115
 
   triangle connection. */
3116
 
+ (id) includesLocalTarget: (unsigned)target
3117
 
{
3118
 
  id ret;
3119
 
 
3120
 
  /* Don't assert (_isValid); */
3121
 
  M_LOCK(global_proxies_gate);
3122
 
  ret = NSMapGet(targetToCounter, (void*)target);
3123
 
  M_UNLOCK(global_proxies_gate);
3124
 
  return ret;
3125
 
}
3126
 
 
3127
 
 
3128
 
/* Accessing ivars */
3129
 
 
3130
 
 
3131
3509
/* Prevent trying to encode the connection itself */
3132
3510
 
3133
3511
- (void) encodeWithCoder: (NSCoder*)anEncoder
3134
3512
{
3135
3513
  [self shouldNotImplement: _cmd];
3136
3514
}
3137
 
 
3138
3515
- (id) initWithCoder: (NSCoder*)aDecoder;
3139
3516
{
3140
3517
  [self shouldNotImplement: _cmd];
3141
3518
  return self;
3142
3519
}
3143
3520
 
3144
 
 
3145
 
/* Shutting down and deallocating. */
3146
 
 
3147
3521
/*
3148
3522
 *      We register this method for a notification when a port dies.
3149
3523
 *      NB. It is possible that the death of a port could be notified
3150
3524
 *      to us after we are invalidated - in which case we must ignore it.
3151
3525
 */
3152
 
- (void) portIsInvalid: (NSNotification*)notification
 
3526
- (void) _portIsInvalid: (NSNotification*)notification
3153
3527
{
3154
3528
  if (_isValid)
3155
3529
    {
3171
3545
    }
3172
3546
}
3173
3547
 
 
3548
/**
 
3549
 * On thread exit, we need all connections to be removed from the runloop
 
3550
 * of the thread or they will retain that and cause a memory leak.
 
3551
 */
 
3552
+ (void) _threadWillExit: (NSNotification*)notification
 
3553
{
 
3554
  NSRunLoop             *runLoop = GSRunLoopForThread([notification object]);
 
3555
 
 
3556
  if (runLoop != nil)
 
3557
    {
 
3558
      NSHashEnumerator  enumerator;
 
3559
      NSConnection      *c;
 
3560
 
 
3561
      M_LOCK(connection_table_gate);
 
3562
      enumerator = NSEnumerateHashTable(connection_table);
 
3563
      while ((c = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil)
 
3564
        {
 
3565
          [c removeRunLoop: runLoop];
 
3566
        }
 
3567
      NSEndHashTableEnumeration(&enumerator);
 
3568
      M_UNLOCK(connection_table_gate);
 
3569
    }
 
3570
}
 
3571
 
 
3572
@end
 
3573
 
 
3574
 
 
3575
 
 
3576
/**
 
3577
 * This category represents an informal protocol to which NSConnection
 
3578
 * delegates may conform ...  implementing these methods has the effect
 
3579
 * documented.
 
3580
 */
 
3581
@implementation Object (NSConnectionDelegate)
 
3582
/**
 
3583
 * <p>
 
3584
 *   This is not an NSConnection method, but is a method that may
 
3585
 *   be implemented by the delegate of an NSConnection object.
 
3586
 * </p>
 
3587
 * <p>
 
3588
 *   If the delegate implements this method, the NSConnection will
 
3589
 *   invoke the method for every message request or reply it receives
 
3590
 *   from the remote NSConnection.  The delegate should use the
 
3591
 *   authentication data to check all the NSData objects
 
3592
 *   in the components array (ignoring NSPort objects),
 
3593
 *   and return YES if they are valid, NO otherwise.
 
3594
 * </p>
 
3595
 * <p>
 
3596
 *   If the method returns NO then an
 
3597
 *   NSFailedAuthentication exception will be raised.
 
3598
 * </p>
 
3599
 * <p>
 
3600
 *   In GNUstep the components array is mutable, allowing
 
3601
 *   you to replace the NSData objects with your own version.
 
3602
 * </p>
 
3603
 */
 
3604
- (BOOL) authenticateComponents: (NSMutableArray*)components
 
3605
                       withData: (NSData*)authenticationData
 
3606
{
 
3607
  return NO;
 
3608
}
 
3609
 
 
3610
/**
 
3611
 * <p>
 
3612
 *   This is not an NSConnection method, but is a method that may
 
3613
 *   be implemented by the delegate of an NSConnection object.
 
3614
 * </p>
 
3615
 * <p>
 
3616
 *   If the delegate implements this method, the NSConnection will
 
3617
 *   invoke the method for every message request ro reply it sends
 
3618
 *   to the remote NSConnection.  The delegate should generate
 
3619
 *   authentication data by examining all the NSData objects
 
3620
 *   in the components array (ignoring NSPort objects),
 
3621
 *   and return the authentication data that can be used by the
 
3622
 *   remote NSConnection.
 
3623
 * </p>
 
3624
 * <p>
 
3625
 *   If the method returns nil then an
 
3626
 *   NSGenericException exception will be raised.
 
3627
 * </p>
 
3628
 * <p>
 
3629
 *   In GNUstep the components array is mutable, allowing
 
3630
 *   you to replace the NSData objects with your own version.
 
3631
 * </p>
 
3632
 */
 
3633
- (NSData*) authenticationDataForComponents: (NSMutableArray*)components
 
3634
{
 
3635
  return nil;
 
3636
}
 
3637
 
 
3638
/**
 
3639
 * <p>
 
3640
 *   This is not an NSConnection method, but is a method that may
 
3641
 *   be implemented by the delegate of an NSConnection object.
 
3642
 * </p>
 
3643
 * <p>
 
3644
 *   If the delegate implements this method, it will be called
 
3645
 *   whenever a new NSConnection is created that has this
 
3646
 *   NSConnection as its parent.  The delegate may take this
 
3647
 *   opportunity to adjust the configuration of the new
 
3648
 *   connection and may return a boolean value to tell the
 
3649
 *   parent whether the creation of the new connection is to
 
3650
 *   be permitted or not.
 
3651
 * </p>
 
3652
 */
 
3653
 - (BOOL) connection: (NSConnection*)parent
 
3654
  shouldMakeNewConnection: (NSConnection*)newConnection
 
3655
{
 
3656
  return NO;
 
3657
}
 
3658
 
 
3659
- (NSConnection*) connection: (NSConnection*)ancestorConn
 
3660
                  didConnect: (NSConnection*)newConn
 
3661
{
 
3662
  return nil;
 
3663
}
 
3664
 
 
3665
/**
 
3666
 * An old fashioned synonym for -connection:shouldMakeNewConnection: -
 
3667
 * don't use this.
 
3668
 */
 
3669
- (BOOL) makeNewConnection: (NSConnection*)newConnection
 
3670
                    sender: (NSConnection*)parent
 
3671
{
 
3672
  return NO;
 
3673
}
3174
3674
@end
3175
3675