mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-25 09:41:15 +00:00
for name arguments to encoding methods. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@796 72102866-910b-0410-8b05-ffd578937521
378 lines
8.4 KiB
Objective-C
378 lines
8.4 KiB
Objective-C
/* Implementation of GNU Objective-C Proxy for remote object messaging
|
|
Copyright (C) 1994, 1995 Free Software Foundation, Inc.
|
|
|
|
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
|
|
Date: July 1994
|
|
|
|
This file is part of the GNU Objective C Class Library.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with this library; if not, write to the Free
|
|
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <objects/stdobjects.h>
|
|
#include <objects/Proxy.h>
|
|
#include <objects/Connection.h>
|
|
#include <objects/ConnectedCoder.h>
|
|
#include <objects/eltfuncs.h>
|
|
#include <assert.h>
|
|
|
|
static BOOL debugProxies = NO;
|
|
|
|
#if NeXT_runtime
|
|
static id tmp_kludge_protocol = nil;
|
|
#endif
|
|
|
|
@implementation Proxy
|
|
|
|
/* Required by NeXT runtime */
|
|
+ initialize
|
|
{
|
|
return self;
|
|
}
|
|
|
|
#if NeXT_runtime
|
|
+ setProtocolForProxies: (Protocol*)p
|
|
{
|
|
tmp_kludge_protocol = p;
|
|
return self;
|
|
}
|
|
#endif
|
|
|
|
+ newForRemote: (unsigned)aTarget connection: (Connection*)c
|
|
{
|
|
Proxy *newProxy;
|
|
|
|
if ((newProxy = [c proxyForTarget:aTarget]))
|
|
return newProxy;
|
|
|
|
newProxy = class_create_instance([Proxy class]);
|
|
newProxy->target = aTarget;
|
|
newProxy->connection = c;
|
|
newProxy->retain_count = 0;
|
|
#if NeXT_runtime
|
|
newProxy->_method_types = coll_hash_new(32,
|
|
elt_hash_void_ptr,
|
|
elt_compare_void_ptrs);
|
|
newProxy->protocol = nil;
|
|
#endif
|
|
|
|
if (debugProxies)
|
|
printf("%s: proxy=0x%x name %u\n",
|
|
sel_get_name(_cmd), (unsigned)newProxy, newProxy->target);
|
|
|
|
[c addProxy:newProxy];
|
|
return newProxy;
|
|
}
|
|
|
|
- notImplemented: (SEL)aSel
|
|
{
|
|
[Object error:"Proxy notImplemented %s", sel_get_name(aSel)];
|
|
return self;
|
|
}
|
|
|
|
- self
|
|
{
|
|
return self;
|
|
}
|
|
|
|
#if NeXT_runtime
|
|
+ class
|
|
{
|
|
return self;
|
|
}
|
|
#else
|
|
+ (Class) class
|
|
{
|
|
return (Class)self;
|
|
}
|
|
#endif
|
|
|
|
- invalidateProxy
|
|
{
|
|
/* What should go here? */
|
|
[connection removeProxy:self];
|
|
return self;
|
|
}
|
|
|
|
- (BOOL) isProxy
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
- (void) encodeWithCoder: aRmc
|
|
{
|
|
[[self classForConnectedCoder:aRmc]
|
|
encodeObject:self
|
|
withConnectedCoder:aRmc];
|
|
}
|
|
|
|
- classForConnectedCoder: aRmc;
|
|
{
|
|
return object_get_class(self);
|
|
}
|
|
|
|
static inline BOOL class_is_kind_of(Class self, Class aClassObject)
|
|
{
|
|
Class class;
|
|
|
|
for (class = self; class!=Nil; class = class_get_super_class(class))
|
|
if (class==aClassObject)
|
|
return YES;
|
|
return NO;
|
|
}
|
|
|
|
+ (void) encodeObject: anObject withConnectedCoder: aRmc
|
|
{
|
|
unsigned aTarget;
|
|
BOOL willBeLocal;
|
|
assert([aRmc connection]);
|
|
if (class_is_kind_of(object_get_class(anObject), [Proxy class]))
|
|
{
|
|
/* anObject is a Proxy, or a Proxy subclass */
|
|
aTarget = [anObject targetForProxy];
|
|
if ([aRmc connection] == [anObject connectionForProxy])
|
|
{
|
|
/* This proxy is local on the other side */
|
|
willBeLocal = YES;
|
|
[aRmc encodeObjectBycopy:nil
|
|
withName:@"Proxy is local on other side"];
|
|
[aRmc encodeValueOfObjCType:@encode(unsigned)
|
|
at:&aTarget
|
|
withName:@"Object Proxy target"];
|
|
[aRmc encodeValueOfObjCType:@encode(BOOL)
|
|
at:&willBeLocal
|
|
withName:@"Proxy willBeLocal"];
|
|
}
|
|
else
|
|
{
|
|
/* This proxy will still be remote on the other side */
|
|
id op = [[anObject connectionForProxy] outPort];
|
|
willBeLocal = NO;
|
|
if (debugProxies)
|
|
fprintf(stderr, "Sending a triangle-connection proxy\n");
|
|
/* It's remote here, so we need to tell other side where to form
|
|
triangle connection to */
|
|
[aRmc encodeObjectBycopy:op
|
|
withName:@"Proxy outPort"];
|
|
[aRmc encodeValueOfObjCType:@encode(unsigned)
|
|
at:&aTarget
|
|
withName:@"Object Proxy target"];
|
|
[aRmc encodeValueOfObjCType:@encode(BOOL)
|
|
at:&willBeLocal
|
|
withName:@"Proxy willBeLocal"];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* anObject is a non-Proxy object, e.g. Object */
|
|
aTarget = PTR2LONG(anObject);
|
|
willBeLocal = NO;
|
|
/* Let the connection know that we're going, this also retains anObj */
|
|
[[aRmc connection] addLocalObject:anObject];
|
|
/* if nil port, other connection will use ConnectedCoder remotePort */
|
|
[aRmc encodeObjectBycopy:nil
|
|
withName:@"Proxy outPort == remotePort"];
|
|
[aRmc encodeValueOfObjCType:@encode(unsigned)
|
|
at:&aTarget
|
|
withName:@"Object Proxy target"];
|
|
[aRmc encodeValueOfObjCType:@encode(BOOL)
|
|
at:&willBeLocal
|
|
withName:@"Proxy willBeLocal"];
|
|
}
|
|
}
|
|
|
|
+ newWithCoder: aRmc
|
|
{
|
|
unsigned new_target;
|
|
id newConnectionOutPort;
|
|
id c;
|
|
BOOL willBeLocal;
|
|
|
|
if ([aRmc class] != [ConnectedCoder class])
|
|
[self error:"Proxy objects only code with ConnectedCoder class"];
|
|
assert([aRmc connection]);
|
|
[aRmc decodeObjectAt:&newConnectionOutPort withName:NULL];
|
|
[aRmc decodeValueOfObjCType:@encode(unsigned)
|
|
at:&new_target
|
|
withName:NULL];
|
|
[aRmc decodeValueOfObjCType:@encode(BOOL)
|
|
at:&willBeLocal
|
|
withName:NULL];
|
|
if (newConnectionOutPort)
|
|
{
|
|
c = [Connection newForInPort:[[aRmc connection] inPort]
|
|
outPort:newConnectionOutPort
|
|
ancestorConnection:[aRmc connection]];
|
|
}
|
|
else
|
|
{
|
|
c = [aRmc connection];
|
|
}
|
|
|
|
if (!willBeLocal)
|
|
{
|
|
if (debugProxies)
|
|
printf("returning remote Proxy, target=0x%x\n", new_target);
|
|
return [self newForRemote:new_target connection:c];
|
|
}
|
|
else
|
|
{
|
|
assert(new_target);
|
|
if (debugProxies)
|
|
printf("returning local Object, target=0x%x\n", new_target);
|
|
/* xxx I should add something that makes sure this number is a
|
|
valid object address... offer a little protection against bad
|
|
clients. */
|
|
return (id)new_target;
|
|
}
|
|
}
|
|
|
|
- (unsigned) targetForProxy
|
|
{
|
|
return target;
|
|
}
|
|
|
|
- connectionForProxy
|
|
{
|
|
return connection;
|
|
}
|
|
|
|
- (const char *) selectorTypeForProxy: (SEL)selector
|
|
{
|
|
#if NeXT_runtime
|
|
#if 0
|
|
{
|
|
/* This is bogosity. You are required to include all methods sent
|
|
by any proxies in the protocol you pass to
|
|
+setProtocolForProxy: */
|
|
struct objc_method_description *md;
|
|
md = [tmp_kludge_protocol descriptionForInstanceMethod:selector];
|
|
if (md)
|
|
return md->types;
|
|
else
|
|
return NULL;
|
|
}
|
|
#elif 0
|
|
{
|
|
/* This is disgusting bogosity. This only works if some other
|
|
class in the executable responds to this method. */
|
|
/* xxx Look in the class hash table at all classes... */
|
|
}
|
|
#else
|
|
{
|
|
elt e;
|
|
const char *t;
|
|
e = coll_hash_value_for_key(_method_types, selector);
|
|
t = e.char_ptr_u;
|
|
if (!t)
|
|
{
|
|
/* This isn't what we want, unless the remote machine has
|
|
the same architecture as us. */
|
|
t = [connection _typeForSelector:selector remoteTarget:target];
|
|
coll_hash_add(&_method_types, (void*)selector, t);
|
|
}
|
|
return t;
|
|
}
|
|
#endif /* 1 */
|
|
#else
|
|
return sel_get_type(selector);
|
|
#endif
|
|
}
|
|
|
|
/* xxx Clean up all this junk below */
|
|
|
|
- (oneway void) release
|
|
{
|
|
if (!retain_count--)
|
|
{
|
|
[self invalidateProxy];
|
|
[self dealloc];
|
|
}
|
|
}
|
|
|
|
- retain
|
|
{
|
|
retain_count++;
|
|
return self;
|
|
}
|
|
|
|
- (void) dealloc
|
|
{
|
|
#if NeXT_runtime
|
|
coll_hash_delete(_method_types);
|
|
object_dispose((Object*)self);
|
|
#else
|
|
NSDeallocateObject((id)self);
|
|
#endif
|
|
}
|
|
|
|
- forward: (SEL)aSel :(arglist_t)frame
|
|
{
|
|
if (debugProxies)
|
|
printf("Proxy forwarding %s\n", sel_get_name(aSel));
|
|
return [connection connectionForward:self :aSel :frame];
|
|
}
|
|
|
|
/* We need to make an effort to pass errors back from the server
|
|
to the client */
|
|
|
|
- (unsigned) retainCount
|
|
{
|
|
return retain_count;
|
|
}
|
|
|
|
- autorelease
|
|
{
|
|
/* xxx Problems here if the Connection goes away? */
|
|
[[NSObject autoreleaseClass] addObject:self];
|
|
return self;
|
|
}
|
|
|
|
- (NSZone*) zone
|
|
{
|
|
return NULL; /* xxx Fix this. */
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation NSObject (ForProxy)
|
|
- (const char *) selectorTypeForProxy: (SEL)selector
|
|
{
|
|
#if NeXT_runtime
|
|
{
|
|
Method m = class_get_instance_method(isa, selector);
|
|
if (m)
|
|
return m->method_types;
|
|
else
|
|
return NULL;
|
|
}
|
|
#else
|
|
return sel_get_type(selector);
|
|
#endif
|
|
}
|
|
@end
|
|
|
|
@implementation Protocol (RemoteSelfCoding)
|
|
|
|
/* Perhaps Protocol's should be sent bycopy? */
|
|
|
|
- classForConnectedCoder: aRmc;
|
|
{
|
|
return [Proxy class];
|
|
}
|
|
|
|
@end
|