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

« back to all changes in this revision

Viewing changes to Source/NSDistantObject.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:
22
22
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
23
23
 
24
24
   <title>NSDistantObject class reference</title>
25
 
   $Date: 2002/02/03 17:21:20 $ $Revision: 1.41 $
 
25
   $Date: 2005/02/22 11:22:44 $ $Revision: 1.65 $
26
26
   */
27
27
 
28
 
#include <config.h>
29
 
#include <base/preface.h>
30
 
#include <base/DistributedObjects.h>
31
 
#include <Foundation/NSLock.h>
32
 
#include <Foundation/NSPort.h>
33
 
#include <Foundation/NSMethodSignature.h>
34
 
#include <Foundation/NSException.h>
35
 
#include <Foundation/NSObjCRuntime.h>
36
 
#include <Foundation/NSInvocation.h>
 
28
#include "config.h"
 
29
#include "GNUstepBase/preface.h"
 
30
#include "GNUstepBase/DistributedObjects.h"
 
31
#include "Foundation/NSDebug.h"
 
32
#include "Foundation/NSLock.h"
 
33
#include "Foundation/NSPort.h"
 
34
#include "Foundation/NSMethodSignature.h"
 
35
#include "Foundation/NSException.h"
 
36
#include "Foundation/NSObjCRuntime.h"
 
37
#include "Foundation/NSInvocation.h"
37
38
 
38
 
#define DO_FORWARD_INVOCATION(_SELX, _ARG1)                     \
 
39
#define DO_FORWARD_INVOCATION(_SELX, _ARG1) ({                  \
39
40
  sig = [self methodSignatureForSelector: @selector(_SELX)];    \
40
 
  inv = [NSInvocation invocationWithMethodSignature: sig];      \
41
 
  [inv setSelector: @selector(_SELX)];                          \
42
 
  [inv setTarget: self];                                        \
43
 
  [inv setArgument: (void*)&_ARG1 atIndex: 2];                  \
44
 
  [self forwardInvocation: inv];                                \
45
 
  [inv getReturnValue: &m]
 
41
  if (sig != nil)                                               \
 
42
  {                                                             \
 
43
    inv = [NSInvocation invocationWithMethodSignature: sig];    \
 
44
    [inv setSelector: @selector(_SELX)];                        \
 
45
    [inv setTarget: self];                                      \
 
46
    [inv setArgument: (void*)&_ARG1 atIndex: 2];                \
 
47
    [self forwardInvocation: inv];                              \
 
48
    [inv getReturnValue: &m];                                   \
 
49
  }                                                             \
 
50
  else                                                          \
 
51
  {                                                             \
 
52
    NSWarnLog(@"DO_FORWARD_INVOCATION failed, got nil signature for '%@'.", \
 
53
      NSStringFromSelector(@selector(_SELX)));                  \
 
54
  }})
46
55
 
47
56
 
48
57
static int      debug_proxy = 0;
53
62
  @defs(NSDistantObject)
54
63
} NSDO;
55
64
 
 
65
@interface Object (NSConformsToProtocolNamed)
 
66
- (BOOL) _conformsToProtocolNamed: (char*)aName;
 
67
@end
 
68
@interface NSObject (NSConformsToProtocolNamed)
 
69
- (BOOL) _conformsToProtocolNamed: (char*)aName;
 
70
@end
 
71
/*
 
72
 * Evil hack ... if a remote system wants to know if we conform
 
73
 * to a protocol we pretend we have a local protocol with the same name.
 
74
 */
 
75
typedef struct {
 
76
    @defs(Protocol)
 
77
} Proto;
 
78
@implementation Object (NSConformsToProtocolNamed)
 
79
- (BOOL) _conformsToProtocolNamed: (char*)aName
 
80
{
 
81
  Proto p;
 
82
  p.protocol_name = (char*)aName;
 
83
  return [self conformsTo: (Protocol*)&p];
 
84
}
 
85
@end
 
86
@implementation NSObject (NSConformsToProtocolNamed)
 
87
- (BOOL) _conformsToProtocolNamed: (char*)aName
 
88
{
 
89
  Proto p;
 
90
  p.protocol_name = (char*)aName;
 
91
  return [self conformsToProtocol: (Protocol*)&p];
 
92
}
 
93
@end
 
94
 
56
95
@interface NSConnection (DistantObjectHacks)
57
 
- (BOOL) includesProxyForTarget: (unsigned)target;
58
 
- (void) addLocalObject: (id)obj;
59
 
- (void) addProxy: (id)obj;
 
96
- (void) aquireProxyForTarget: (unsigned)target;
 
97
- (NSDistantObject*) retainOrAddLocal: (NSDistantObject*)aProxy
 
98
                            forObject: (id)anObject;
 
99
- (NSDistantObject*) retainOrAddProxy: (NSDistantObject*)aProxy
 
100
                            forTarget: (unsigned)aTarget;
60
101
- (void) removeProxy: (id)obj;
 
102
- (void) vendLocal: (NSDistantObject*)aProxy;
61
103
@end
62
104
 
63
105
/* This is the proxy tag; it indicates where the local object is,
64
106
   and determines whether the reply port to the Connection-where-the-
65
107
   proxy-is-local needs to encoded/decoded or not. */
66
 
enum
 
108
enum proxyLocation
67
109
{
68
110
  PROXY_LOCAL_FOR_RECEIVER = 0,
69
111
  PROXY_LOCAL_FOR_SENDER,
70
112
  PROXY_REMOTE_FOR_BOTH
71
 
} proxyLocation;
 
113
};
72
114
 
73
115
 
74
116
 
114
156
 
115
157
+ (BOOL) respondsToSelector: (SEL)sel
116
158
{
117
 
  return (IMP)class_get_instance_method(self, sel) != (IMP)0;
 
159
  return GSGetMethod(self, sel, NO, YES) != (GSMethod)0;
118
160
}
119
161
 
120
162
+ (id) initWithCoder: (NSCoder*)aCoder
122
164
  gsu8                  proxy_tag;
123
165
  unsigned              target;
124
166
  id                    decoder_connection;
 
167
  NSDistantObject       *o;
125
168
 
126
169
/*
127
170
  if ([aCoder isKindOfClass: [NSPortCoder class]] == NO)
155
198
          NSLog(@"Receiving a proxy for local object 0x%x "
156
199
                @"connection 0x%x\n", target, (gsaddr)decoder_connection);
157
200
 
158
 
        if (![[decoder_connection class] includesLocalTarget: target])
 
201
        o = [decoder_connection locateLocalTarget: target];
 
202
        if (o == nil)
159
203
          {
160
204
            [NSException raise: @"ProxyDecodedBadTarget"
161
205
                        format: @"No local object with given target (0x%x)",
163
207
          }
164
208
        else
165
209
          {
166
 
            NSDistantObject     *o;
167
 
 
168
 
            o = [decoder_connection includesLocalTarget: target];
169
210
            if (debug_proxy)
170
211
              {
171
212
                NSLog(@"Local object is 0x%x (0x%x)\n",
172
213
                  (gsaddr)o, (gsaddr)o ? ((NSDO*)o)->_object : 0);
173
214
              }
174
 
            return o ? RETAIN(((NSDO*)o)->_object) : nil;
 
215
            return RETAIN(((NSDO*)o)->_object);
175
216
          }
176
217
 
177
218
      case PROXY_LOCAL_FOR_SENDER:
187
228
        if (debug_proxy)
188
229
          NSLog(@"Receiving a proxy, was local 0x%x connection 0x%x\n",
189
230
                  target, (gsaddr)decoder_connection);
190
 
        return [self initWithTarget: target
191
 
                         connection: decoder_connection];
 
231
        o = [self initWithTarget: target
 
232
                      connection: decoder_connection];
 
233
        return o;
192
234
 
193
235
      case PROXY_REMOTE_FOR_BOTH:
194
236
        /*
238
280
          /*
239
281
           #    If there already exists a connection for talking to the
240
282
           *    out port, we use that one rather than creating a new one from
241
 
           *    our listening port. 
 
283
           *    our listening port.
242
284
           *
243
285
           *    First we try for a connection from our receive port,
244
286
           *    Then we try any connection to the send port
260
302
            NSInternalInconsistencyException);
261
303
 
262
304
          /*
263
 
           *    If we don't already have a proxy for the object on the
264
 
           *    remote system, we must tell the other end to retain its
265
 
           *    local object for our use.
 
305
           * We may not already have a proxy for the object on the
 
306
           * remote system, we must tell the connection to make sure
 
307
           * the other end knows we are creating one.
266
308
           */
267
 
          if ([proxy_connection includesProxyForTarget: target] == NO)
268
 
            [proxy_connection retainTarget: target];
 
309
          [proxy_connection aquireProxyForTarget: target];
269
310
 
270
311
          /*
271
312
           *    Finally - we get a proxy via a direct connection to the
274
315
           *    and will therefore go away when the current autorelease
275
316
           *    pool is destroyed.
276
317
           */
277
 
          return [self initWithTarget: target
278
 
                           connection: proxy_connection];
 
318
          o = [self initWithTarget: target
 
319
                        connection: proxy_connection];
 
320
          return o;
279
321
        }
280
322
 
281
323
    default:
297
339
   *    If there already is a local proxy for this target/connection
298
340
   *    combination, don't create a new one, just return the old one.
299
341
   */
300
 
  if ((proxy = [aConnection localForObject: anObject]))
 
342
  proxy = [aConnection retainOrAddLocal: nil forObject: anObject];
 
343
  if (proxy == nil)
301
344
    {
302
 
      return RETAIN(proxy);
 
345
      proxy = (NSDistantObject*)NSAllocateObject(distantObjectClass,
 
346
        0, NSDefaultMallocZone());
 
347
      proxy = [proxy initWithLocal: anObject connection: aConnection];
303
348
    }
304
 
 
305
 
  proxy = (NSDistantObject*)NSAllocateObject(distantObjectClass,
306
 
        0, NSDefaultMallocZone());
307
 
  return [proxy initWithLocal: anObject connection: aConnection];
 
349
  return proxy;
308
350
}
309
351
 
310
352
+ (id) initWithTarget: (unsigned)target connection: (NSConnection*)aConnection
314
356
  NSAssert([aConnection isValid], NSInternalInconsistencyException);
315
357
 
316
358
  /*
317
 
   *    If there already is a local proxy for this target/connection
318
 
   *    combination, don't create a new one, just return the old one.
 
359
   * If there already is a local proxy for this target/connection
 
360
   * combination, don't create a new one, just return the old one.
319
361
   */
320
 
  if ((proxy = [aConnection proxyForTarget: target]))
 
362
  proxy = [aConnection retainOrAddProxy: nil forTarget: target];
 
363
  if (proxy == nil)
321
364
    {
322
 
      return RETAIN(proxy);
 
365
      proxy = (NSDistantObject*)NSAllocateObject(distantObjectClass,
 
366
        0, NSDefaultMallocZone());
 
367
      proxy = [proxy initWithTarget: target connection: aConnection];
323
368
    }
324
 
 
325
 
  proxy = (NSDistantObject*)NSAllocateObject(distantObjectClass,
326
 
        0, NSDefaultMallocZone());
327
 
  return [proxy initWithTarget: target connection: aConnection];
 
369
  return proxy;
328
370
}
329
371
@end
330
372
 
339
381
}
340
382
@end
341
383
 
 
384
/**
 
385
 * Instances of this class act as proxies to remote objects using
 
386
 * the Distributed Objects system.  They also hold references to
 
387
 * local objects which are vended to remote processes.
 
388
 */
342
389
@implementation NSDistantObject
343
390
 
344
391
+ (void) initialize
354
401
  return placeHolder;
355
402
}
356
403
 
 
404
/**
 
405
 * Creates and returns a proxy associated with aConnection
 
406
 * which will hold a reference to the local object anObject.
 
407
 */
357
408
+ (NSDistantObject*) proxyWithLocal: (id)anObject
358
409
                         connection: (NSConnection*)aConnection
359
410
{
361
412
                                     connection: aConnection]);
362
413
}
363
414
 
 
415
/**
 
416
 * Creates and returns a proxy associated with aConnection
 
417
 * which will provide a link to a remote object whose reference
 
418
 * locally is anObject.
 
419
 */
364
420
+ (NSDistantObject*) proxyWithTarget: (unsigned)anObject
365
421
                          connection: (NSConnection*)aConnection
366
422
{
368
424
                                      connection: aConnection]);
369
425
}
370
426
 
 
427
/**
 
428
 * Returns the [NSConnection] instance with which the receiver is
 
429
 * associated.
 
430
 */
371
431
- (NSConnection*) connectionForProxy
372
432
{
373
433
  return _connection;
423
483
 
424
484
          [aRmc encodeValueOfObjCType: @encode(typeof(proxy_target))
425
485
                                   at: &proxy_target];
 
486
          /*
 
487
           * Tell connection this object is being vended.
 
488
           */
 
489
          [_connection vendLocal: self];
426
490
        }
427
491
      else
428
492
        {
460
524
      proxy_tag = PROXY_REMOTE_FOR_BOTH;
461
525
 
462
526
      /*
463
 
       *        Get a proxy to refer to self - we send this to the other
464
 
       *        side so we will be retained until the other side has
465
 
       *        obtained a proxy to the original object via a connection
466
 
       *        to the original vendor.
 
527
       * Get a proxy to refer to self - we send this to the other
 
528
       * side so we will be retained until the other side has
 
529
       * obtained a proxy to the original object via a connection
 
530
       * to the original vendor.
467
531
       */
468
532
      localProxy = [NSDistantObject proxyWithLocal: self
469
533
                                        connection: encoder_connection];
475
539
                proxy_target, (gsaddr)_connection);
476
540
 
477
541
      /*
478
 
       *        It's remote here, so we need to tell other side where to form
479
 
       *        triangle connection to
 
542
       * It's remote here, so we need to tell other side where to form
 
543
       * triangle connection to
480
544
       */
481
545
      [aRmc encodeValueOfObjCType: @encode(typeof(proxy_tag))
482
546
                               at: &proxy_tag];
488
552
                               at: &proxy_target];
489
553
 
490
554
      [aRmc encodeBycopyObject: proxy_connection_out_port];
 
555
 
 
556
      /*
 
557
       * Tell connection that localProxy is being vended.
 
558
       */
 
559
      [encoder_connection vendLocal: localProxy];
491
560
    }
492
561
}
493
562
 
511
580
 
512
581
- (id) initWithCoder: (NSCoder*)aCoder
513
582
{
514
 
  gsu8          proxy_tag;
515
 
  unsigned      target;
516
 
  id            decoder_connection;
517
 
 
518
 
/*
519
 
  if ([aCoder isKindOfClass: [NSPortCoder class]] == NO)
520
 
    {
521
 
      RELEASE(self);
522
 
      [NSException raise: NSGenericException
523
 
                  format: @"NSDistantObject objects only decode with "
524
 
                          @"NSPortCoder class"];
525
 
    }
526
 
*/
527
 
 
528
 
  decoder_connection = [(NSPortCoder*)aCoder connection];
529
 
  NSAssert(decoder_connection, NSInternalInconsistencyException);
530
 
 
531
 
  /* First get the tag, so we know what values need to be decoded. */
532
 
  [aCoder decodeValueOfObjCType: @encode(typeof(proxy_tag))
533
 
                             at: &proxy_tag];
534
 
 
535
 
  switch (proxy_tag)
536
 
    {
537
 
      case PROXY_LOCAL_FOR_RECEIVER:
538
 
        /*
539
 
         *      This was a proxy on the other side of the connection, but
540
 
         *      here it's local.
541
 
         *      Lookup the target handle to ensure that it exists here.
542
 
         *      Return a retained copy of the local target object.
543
 
         */
544
 
        [aCoder decodeValueOfObjCType: @encode(typeof(target))
545
 
                                   at: &target];
546
 
 
547
 
        if (debug_proxy)
548
 
          NSLog(@"Receiving a proxy for local object 0x%x "
549
 
                @"connection 0x%x\n", target, (gsaddr)decoder_connection);
550
 
 
551
 
        if (![[decoder_connection class] includesLocalTarget: target])
552
 
          {
553
 
            RELEASE(self);
554
 
            [NSException raise: @"ProxyDecodedBadTarget"
555
 
                        format: @"No local object with given target (0x%x)",
556
 
                                target];
557
 
          }
558
 
        else
559
 
          {
560
 
            NSDistantObject     *o;
561
 
 
562
 
            o = [decoder_connection includesLocalTarget: target];
563
 
            if (debug_proxy)
564
 
              {
565
 
                NSLog(@"Local object is 0x%x (0x%x)\n",
566
 
                  (gsaddr)o, (gsaddr)o ? o->_object : 0);
567
 
              }
568
 
            RELEASE(self);
569
 
            return o ? RETAIN(o->_object) : nil;
570
 
          }
571
 
 
572
 
      case PROXY_LOCAL_FOR_SENDER:
573
 
        /*
574
 
         *      This was a local object on the other side of the connection,
575
 
         *      but here it's a proxy object.  Get the target address, and
576
 
         *      send [NSDistantObject +proxyWithTarget:connection:]; this will
577
 
         *      return the proxy object we already created for this target, or
578
 
         *      create a new proxy object if necessary.
579
 
         */
580
 
        [aCoder decodeValueOfObjCType: @encode(typeof(target))
581
 
                                   at: &target];
582
 
        if (debug_proxy)
583
 
          NSLog(@"Receiving a proxy, was local 0x%x connection 0x%x\n",
584
 
                  target, (gsaddr)decoder_connection);
585
 
        RELEASE(self);
586
 
        return RETAIN([NSDistantObject proxyWithTarget: target
587
 
                                            connection: decoder_connection]);
588
 
 
589
 
      case PROXY_REMOTE_FOR_BOTH:
590
 
        /*
591
 
         *      This was a proxy on the other side of the connection, and it
592
 
         *      will be a proxy on this side too; that is, the local version
593
 
         *      of this object is not on this host, not on the host the
594
 
         *      NSPortCoder is connected to, but on a *third* host.
595
 
         *      This is why I call this a "triangle connection".  In addition
596
 
         *      to decoding the target, we decode the OutPort object that we
597
 
         *      will use to talk directly to this third host.  We send
598
 
         *      [NSConnection +newForInPort:outPort:ancestorConnection:]; this
599
 
         *      will either return the connection already created for this
600
 
         *      inPort/outPort pair, or create a new connection if necessary.
601
 
         */
602
 
        {
603
 
          NSDistantObject       *result;
604
 
          NSConnection          *proxy_connection;
605
 
          NSPort                *proxy_connection_out_port = nil;
606
 
          unsigned              intermediary;
607
 
 
608
 
          /*
609
 
           *    There is an object on the intermediary host that is keeping
610
 
           *    that hosts proxy for the original object retained, thus
611
 
           *    ensuring that the original is not released.  We create a
612
 
           *    proxy for that intermediate proxy.  When we release this
613
 
           *    proxy, the intermediary will be free to release it's proxy
614
 
           *    and the original can then be released.  Of course, by that
615
 
           *    time we will have obtained our own proxy for the original
616
 
           *    object ...
617
 
           */
618
 
          [aCoder decodeValueOfObjCType: @encode(typeof(intermediary))
619
 
                                     at: &intermediary];
620
 
          [NSDistantObject proxyWithTarget: intermediary
621
 
                                connection: decoder_connection];
622
 
 
623
 
          /*
624
 
           *    Now we get the target number and port for the orignal object
625
 
           *    and (if necessary) get the originating process to retain the
626
 
           *    object for us.
627
 
           */
628
 
          [aCoder decodeValueOfObjCType: @encode(typeof(target))
629
 
                                     at: &target];
630
 
 
631
 
          [aCoder decodeValueOfObjCType: @encode(id)
632
 
                                     at: &proxy_connection_out_port];
633
 
 
634
 
          NSAssert(proxy_connection_out_port, NSInternalInconsistencyException);
635
 
          /*
636
 
           #    If there already exists a connection for talking to the
637
 
           *    out port, we use that one rather than creating a new one from
638
 
           *    our listening port. 
639
 
           *
640
 
           *    First we try for a connection from our receive port,
641
 
           *    Then we try any connection to the send port
642
 
           *    Finally we resort to creating a new connection - we don't
643
 
           *    release the newly created connection - it will get released
644
 
           *    automatically when no proxies are left on it.
645
 
           */
646
 
          proxy_connection = [[decoder_connection class]
647
 
            connectionWithReceivePort: [decoder_connection receivePort]
648
 
                             sendPort: proxy_connection_out_port];
649
 
 
650
 
          if (debug_proxy)
651
 
            NSLog(@"Receiving a triangle-connection proxy 0x%x "
652
 
                  @"connection 0x%x\n", target, (gsaddr)proxy_connection);
653
 
 
654
 
          NSAssert(proxy_connection != decoder_connection,
655
 
            NSInternalInconsistencyException);
656
 
          NSAssert([proxy_connection isValid],
657
 
            NSInternalInconsistencyException);
658
 
 
659
 
          /*
660
 
           *    If we don't already have a proxy for the object on the
661
 
           *    remote system, we must tell the other end to retain its
662
 
           *    local object for our use.
663
 
           */
664
 
          if ([proxy_connection includesProxyForTarget: target] == NO)
665
 
            [proxy_connection retainTarget: target];
666
 
 
667
 
          result = RETAIN([NSDistantObject proxyWithTarget: target
668
 
                                                connection: proxy_connection]);
669
 
          RELEASE(self);
670
 
 
671
 
          /*
672
 
           *    Finally - we have a proxy via a direct connection to the
673
 
           *    originating server.  We have also created a proxy to an
674
 
           *    intermediate object - but this proxy has not been retained
675
 
           *    and will therefore go away when the current autorelease
676
 
           *    pool is destroyed.
677
 
           */
678
 
          return result;
679
 
        }
680
 
 
681
 
    default:
682
 
      /* xxx This should be something different than NSGenericException. */
683
 
      RELEASE(self);
684
 
      [NSException raise: NSGenericException
685
 
                  format: @"Bad proxy tag"];
686
 
    }
687
 
  /* Not reached. */
 
583
  DESTROY(self);
 
584
  [NSException raise: NSGenericException
 
585
              format: @"NSDistantObject decodes from placeholder"];
688
586
  return nil;
689
587
}
690
588
 
 
589
/**
 
590
 * Initialises and returns a proxy associated with aConnection
 
591
 * which will hold a reference to the local object anObject.
 
592
 */
691
593
- (id) initWithLocal: (id)anObject connection: (NSConnection*)aConnection
692
594
{
693
 
  NSDistantObject       *new_proxy;
694
 
 
695
595
  NSAssert([aConnection isValid], NSInternalInconsistencyException);
696
596
 
697
 
  /*
698
 
   *    If there already is a local proxy for this target/connection
699
 
   *    combination, don't create a new one, just return the old one.
700
 
   */
701
 
  if ((new_proxy = [aConnection localForObject: anObject]))
702
 
    {
703
 
      RETAIN(new_proxy);
704
 
      RELEASE(self);
705
 
      return new_proxy;
706
 
    }
707
 
 
708
 
  /*
709
 
   *    We don't need to retain the oibject here - the connection
710
 
   *    will retain the proxies local object if necessary (and release it
711
 
   *    when all proxies referring to it have been released).
712
 
   */
713
 
  _object = anObject;
714
 
 
715
 
  /*
716
 
   *    We register this proxy with the connection using it.
717
 
   */
 
597
  _object = RETAIN(anObject);
 
598
  _handle = 0;
718
599
  _connection = RETAIN(aConnection);
719
 
  [_connection addLocalObject: self];
 
600
  self = [_connection retainOrAddLocal: self forObject: anObject];
720
601
 
721
602
  if (debug_proxy)
722
603
    NSLog(@"Created new local=0x%x object 0x%x target 0x%x connection 0x%x\n",
725
606
  return self;
726
607
}
727
608
 
 
609
/**
 
610
 * Initialises and returns a proxy associated with aConnection
 
611
 * which will provide a link to a remote object whose reference
 
612
 * locally is target.
 
613
 */
728
614
- (id) initWithTarget: (unsigned)target connection: (NSConnection*)aConnection
729
615
{
730
 
  NSDistantObject       *new_proxy;
731
 
 
732
616
  NSAssert([aConnection isValid], NSInternalInconsistencyException);
733
617
 
734
 
  /*
735
 
   *    If there already is a proxy for this target/connection combination,
736
 
   *    don't create a new one, just return the old one.
737
 
   */
738
 
  if ((new_proxy = [aConnection proxyForTarget: target]))
739
 
    {
740
 
      RETAIN(new_proxy);
741
 
      RELEASE(self);
742
 
      return new_proxy;
743
 
    }
744
 
 
745
618
  _object = nil;
746
619
  _handle = target;
747
 
 
748
 
  /*
749
 
   *    We retain our connection so it can't disappear while the app
750
 
   *    may want to use it.
751
 
   */
752
620
  _connection = RETAIN(aConnection);
753
621
 
754
622
  /*
755
 
   *    We register this object with the connection using it.
 
623
   * We register this object with the connection using it.
 
624
   * Conceivably this could result in self being changed.
756
625
   */
757
 
  [_connection addProxy: self];
 
626
  self = [_connection retainOrAddProxy: self forTarget: target];
758
627
 
759
628
  if (debug_proxy)
760
629
      NSLog(@"Created new proxy=0x%x target 0x%x connection 0x%x\n",
763
632
  return self;
764
633
}
765
634
 
766
 
- (IMP) methodForSelector: (SEL)aSelector
767
 
{
768
 
  return get_imp(GSObjCClass((id)self), aSelector);
769
 
}
770
 
 
 
635
/**
 
636
 * <p>Returns the method signature describing the arguments and return
 
637
 * types of the method in the object referred to by the receiver
 
638
 * which implements the aSelecto message.
 
639
 * </p>
 
640
 * <p>This method may need to refer to another process (causing relatively
 
641
 * slow network communication) and apprximately double the time taken for
 
642
 * sending a distributed objects message, so you are advised to use the
 
643
 * -setProtocolForProxy: method to avoid this occurring.
 
644
 * </p>
 
645
 */
771
646
- (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector
772
647
{
773
648
  if (_object != nil)
793
668
            }
794
669
          return sig;
795
670
        }
 
671
      /*
 
672
       * Simlarly, when we fetch a method signature from the remote end,
 
673
       * we get a proxy, and when we build a local signature we need to
 
674
       * ask the proxy for its types ... and must avoid recursion again.
 
675
       */
 
676
      if (sel_eq(aSelector, @selector(methodType)))
 
677
        {
 
678
          static        NSMethodSignature       *sig = nil;
 
679
 
 
680
          if (sig == nil)
 
681
            {
 
682
              sig = [NSMethodSignature signatureWithObjCTypes: "r*@:"];
 
683
              RETAIN(sig);
 
684
            }
 
685
          return sig;
 
686
        }
796
687
 
797
688
      if (_protocol != nil)
798
689
        {
800
691
 
801
692
          struct objc_method_description* mth;
802
693
 
803
 
          mth = [_protocol descriptionForInstanceMethod: aSelector];
 
694
          /* Older gcc versions may not initialise Protocol objects properly
 
695
           * so we have an evil hack which checks for a known bad value of
 
696
           * the class pointer, and uses an internal function
 
697
           * (implemented in NSObject.m) to examine the protocol contents
 
698
           * without sending any ObjectiveC message to it.
 
699
           */
 
700
          if ((int)GSObjCClass(_protocol) == 0x2)
 
701
            {
 
702
              extern struct objc_method_description*
 
703
                GSDescriptionForInstanceMethod();
 
704
              mth = GSDescriptionForInstanceMethod(_protocol, aSelector);
 
705
            }
 
706
          else
 
707
            {
 
708
              mth = [_protocol descriptionForInstanceMethod: aSelector];
 
709
            }
804
710
          if (mth == 0)
805
711
            {
806
 
              mth = [_protocol descriptionForClassMethod: aSelector];
 
712
              if ((int)GSObjCClass(_protocol) == 0x2)
 
713
                {
 
714
                  extern struct objc_method_description*
 
715
                    GSDescriptionForClassMethod();
 
716
                  mth = GSDescriptionForClassMethod(_protocol, aSelector);
 
717
                }
 
718
              else
 
719
                {
 
720
                  mth = [_protocol descriptionForClassMethod: aSelector];
 
721
                }
807
722
            }
808
723
          if (mth != 0)
809
724
            {
810
725
              types = mth->types;
811
726
            }
812
 
          if (types == 0)
813
 
            {
814
 
              return nil;
815
 
            }
816
 
          return [NSMethodSignature signatureWithObjCTypes: types];
 
727
          if (types)
 
728
            return [NSMethodSignature signatureWithObjCTypes: types];
817
729
        }
818
 
      else
 
730
 
819
731
        {
820
 
          id            m;
821
 
          const char    *types;
822
 
#ifdef USE_FFCALL
 
732
          id            m = nil;
 
733
#if     defined(USE_FFCALL) || defined(USE_LIBFFI)
823
734
          id            inv;
824
735
          id            sig;
825
736
 
840
751
          retframe = [self forward: _cmd : args];
841
752
          m = retframe_id(retframe);
842
753
#endif
843
 
          types = [m methodType];
844
 
          return [NSMethodSignature signatureWithObjCTypes: types];
 
754
          if ([m isProxy] == YES)
 
755
            {
 
756
              const char        *types = [m methodType];
 
757
 
 
758
              m = [NSMethodSignature signatureWithObjCTypes: types];
 
759
            }
 
760
          return m;
845
761
        }
846
762
    }
847
763
}
848
764
 
 
765
/**
 
766
 * <p>A key method for Distributed Objects performance.  This sets the
 
767
 * a protocol that the distant object referred to by the proxy should
 
768
 * conform to.  When messages in that protocol are sent to the proxy,
 
769
 * the proxy knows that it does not need to ask the remote object for
 
770
 * the method siagnature in order to send the message to it, but can
 
771
 * send the message straight away based on the local method signature
 
772
 * information obtained from the protocol.
 
773
 * </p>
 
774
 * <example>
 
775
 *   if ([anObj isProxy] == YES)
 
776
 *     {
 
777
 *       [anObj setProtocolForProxy: @protocol(MyProtocol)];
 
778
 *     }
 
779
 * </example>
 
780
 * <p>It is <em>highly recommended</em> that you make use of this facility,
 
781
 * but you must beware that versions of the compiler prior to 3.3 suffer a
 
782
 * serious bug with respect to the @protocol directive.  If the protocol
 
783
 * referred to is not declared and implemented in the file where @protocol
 
784
 * is used to refer to the protocol by name, a runtime error will occur
 
785
 * when you try to use it.
 
786
 * </p>
 
787
 * <p>Beware, if you don't use this method to set the protocol, the system
 
788
 * might well ask the remote process for method signature information, and
 
789
 * the remote process might get it <em>wrong</em>.  This is because the
 
790
 * class of the remote object needs to have been declared to conform to the
 
791
 * protocol in order for it to know about any protocol qualifiers (the
 
792
 * keywords <code>bycopy, byref, in, out, inout,</code> and
 
793
 * <code>oneway</code>).  If the author of the server process forgot to do
 
794
 * this, the type information returned from that process may not be what
 
795
 * you are expecting.
 
796
 * </p>
 
797
 * The class of the server object should be declared like this ...
 
798
 * <example>
 
799
 * @interface MyServerClass : NSObject &lt;MyProtocol&gt;
 
800
 * ...
 
801
 * @end
 
802
 * </example>
 
803
 */
849
804
- (void) setProtocolForProxy: (Protocol*)aProtocol
850
805
{
851
806
  _protocol = aProtocol;
853
808
 
854
809
@end
855
810
 
 
811
/**
 
812
 *  Adds some backwards-compatibility and other methods.
 
813
 */
856
814
@implementation NSDistantObject(GNUstepExtensions)
857
815
 
 
816
/**
 
817
 * Used by the garbage collection system to tidy up when a proxy is destroyed.
 
818
 */
858
819
- (void) gcFinalize
859
820
{
860
821
  if (_connection)
863
824
        NSLog(@"retain count for connection (0x%x) is now %u\n",
864
825
                (gsaddr)_connection, [_connection retainCount]);
865
826
      /*
866
 
       * A proxy for local object does not retain it's target - the
867
 
       * NSConnection class does that for us - so we need not release it.
 
827
       * A proxy for local object retains its target - so we release it.
868
828
       * For a local object the connection also retains this proxy, so we
869
829
       * can't be deallocated unless we are already removed from the
870
 
       * connection.
 
830
       * connection, and there is no need to remove self from connection.
871
831
       *
872
 
       * A proxy retains it's connection so that the connection will
873
 
       * continue to exist as long as there is a something to use it.
 
832
       * A proxy has a nil local object, and retains it's connection so
 
833
       * that the connection will continue to exist as long as there is
 
834
       * a something to use it.
874
835
       * So we release our reference to the connection here just as soon
875
836
       * as we have removed ourself from the connection.
876
837
       */
877
838
      if (_object == nil)
878
839
        [_connection removeProxy: self];
 
840
      else
 
841
        DESTROY(_object);
879
842
      RELEASE(_connection);
880
843
    }
881
844
}
882
845
 
883
 
- (id) awakeAfterUsingCoder: (NSCoder*)aDecoder
884
 
{
885
 
  return self;
886
 
}
887
 
 
888
846
static inline BOOL class_is_kind_of (Class self, Class aClassObject)
889
847
{
890
848
  Class class;
891
849
 
892
 
  for (class = self; class!=Nil; class = class_get_super_class(class))
 
850
  for (class = self; class!=Nil; class = GSObjCSuper(class))
893
851
    if (class==aClassObject)
894
852
      return YES;
895
853
  return NO;
897
855
 
898
856
 
899
857
 
 
858
/**
 
859
 * For backward compatibility ... do not use this method.<br />
 
860
 * Returns the type information ... the modern way of doing this is
 
861
 * with the -methodSignatureForSelector: method.
 
862
 */
900
863
- (const char *) selectorTypeForProxy: (SEL)selector
901
864
{
902
865
#if NeXT_RUNTIME
910
873
#endif
911
874
}
912
875
 
 
876
/**
 
877
 * For backward compatibility ... do not use this method.<br />
 
878
 * Handle old fashioned forwarding to the proxy.
 
879
 */
913
880
- (id) forward: (SEL)aSel :(arglist_t)frame
914
881
{
915
882
  if (debug_proxy)
916
 
    NSLog(@"NSDistantObject forwarding %s\n", sel_get_name(aSel));
 
883
    NSLog(@"NSDistantObject forwarding %s\n", GSNameFromSelector(aSel));
917
884
 
918
885
  if (![_connection isValid])
919
886
    [NSException
932
899
  return object_get_class (self);
933
900
}
934
901
 
 
902
/**
 
903
 * Returns the class of the receiver.
 
904
 */
935
905
- (Class) classForPortCoder
936
906
{
937
907
  return object_get_class (self);
938
908
}
939
909
 
 
910
/**
 
911
 * If a protocol has been set for the receiver, this method tests to
 
912
 * see that the set protocol conforms to aProtocol. Otherwise, the
 
913
 * remote object is checked to see whether it conforms to aProtocol.
 
914
 */
940
915
- (BOOL) conformsToProtocol: (Protocol*)aProtocol
941
916
{
942
 
#ifdef USE_FFCALL
943
 
  BOOL m;
944
 
  id inv, sig;
945
 
  DO_FORWARD_INVOCATION(conformsToProtocol:, aProtocol);
946
 
  return m;
947
 
#else
948
 
  arglist_t     args;
949
 
  void          *retframe;
950
 
 
951
 
  BOOL retframe_bool (void *rframe)
952
 
    {
953
 
      __builtin_return (rframe);
954
 
    }
955
 
 
956
 
  /*
957
 
   *    Try forwarding the message.
958
 
   */
959
 
  args = __builtin_apply_args();
960
 
  retframe = [self forward: _cmd : args];
961
 
  return retframe_bool(retframe);
962
 
#endif
 
917
  if (_protocol != nil)
 
918
    {
 
919
      return [_protocol conformsTo: aProtocol];
 
920
    }
 
921
  else
 
922
    {
 
923
      return [(id)self _conformsToProtocolNamed: (char*)[aProtocol name]];
 
924
    }
963
925
}
964
926
 
965
927
- (BOOL) respondsToSelector: (SEL)aSelector
966
928
{
967
 
#ifdef USE_FFCALL
968
 
  BOOL m;
 
929
#if     defined(USE_FFCALL) || defined(USE_LIBFFI)
 
930
  BOOL m = NO;
969
931
  id inv, sig;
970
932
  DO_FORWARD_INVOCATION(respondsToSelector:, aSelector);
971
933
  return m;
1004
966
{
1005
967
#if NeXT_runtime
1006
968
  {
1007
 
    Method m = class_get_instance_method(isa, selector);
 
969
    Method m = GSGetInstanceMethod(isa, selector);
1008
970
    if (m)
1009
971
      return m->method_types;
1010
972
    else