#import "EchoMe.h" #undef NSConnection // redefined as MyConnection in global header file #define LOCAL 0 // use local port #if 0 // my SERVER (i.e. let Client **Connection contact our MYConnection) #define SERVER MYConnection #define OVERRIDE #else #define SERVER NSConnection #endif #if 1 // my CLIENT (i.e. let our MYConnection contact Server **Connection) #define CLIENT MYConnection #define SETCLIENTDELEGATE 1 #else #define CLIENT NSConnection #define SETCLIENTDELEGATE 1 #endif @interface NSConnectionPoser : NSConnection // used to pose as NSConnection but forward to MyConnection @end @implementation NSConnectionPoser + (NSConnection *) lookUpConnectionWithReceivePort:(NSPort *)receivePort sendPort:(NSPort *)sendPort { // look up in the correct domain... NSConnection *c=[MYConnection lookUpConnectionWithReceivePort:receivePort sendPort:sendPort]; if(!c) c=[super lookUpConnectionWithReceivePort:receivePort sendPort:sendPort]; return c; } #ifdef OVERRIDE // Cocoa [client rootProxy] will call -[NSPortCoder dispatch] from the Server's handlePortCoder // which has a hard-coded call to -[[NSConnection alloc] initWithPort...] to create the reverse connection object // And, if our server is MYConnection, then we must init a MYConnection - (id) initWithReceivePort:(NSPort *)receivePort sendPort:(NSPort *)sendPort { static int cnt=-1; if(cnt++ == 0) return [super initWithReceivePort:receivePort sendPort:sendPort]; // first call goes to real NSConnection [self release]; return [[SERVER alloc] initWithReceivePort:receivePort sendPort:sendPort]; // replace } #endif - (void) sendInvocation:(NSInvocation *) i internal:(BOOL) internal; { NSLog(@"sendInvocation:internal: %@ %@", internal?@"YES":@"NO", i); [super sendInvocation:i internal:internal]; } - (void) sendInvocation:(NSInvocation *) i; { NSLog(@"sendInvocation: %@", i); [super sendInvocation:i]; } - (void) dispatchInvocation:(NSInvocation *) i; { NSLog(@"dispatchInvocation: %@", i); NSLog(@"-[%@ %@]", NSStringFromClass([[i target] class]), NSStringFromSelector([i selector])); [super dispatchInvocation:i]; } - (BOOL) _shouldDispatch:(id *) conversation invocation:(id) inv sequence:(unsigned int) seq coder:(NSCoder *) coder; { BOOL r; NSLog(@"_shouldDispatch arg=%@", coder); // NSPortCoder NSLog(@" seq=%u", seq); NSLog(@" conversation=%p", conversation); // a stack address? if(conversation) NSLog(@" *conversation=%@", *conversation); // (null) NSLog(@" invocation=%@", inv); // (null) r=[super _shouldDispatch:conversation invocation:inv sequence:seq coder:coder]; NSLog(@" r=%@", r?@"YES":@"NO"); // YES if ok if(conversation) NSLog(@" *conversation=%@", *conversation); return r; } - (BOOL) _cleanupAndAuthenticate:(NSPortCoder *) arg sequence:(unsigned int) seq conversation:(id *) conversation invocation:(NSInvocation *) inv raise:(BOOL) raise { BOOL r; NSLog(@"_cleanupAndAuthenticate arg=%@", arg); // NSPortCoder NSLog(@" seq=%u", seq); NSLog(@" conversation=%p", conversation); // a stack address? if(conversation) NSLog(@" *conversation=%@", *conversation); // (null) NSLog(@" invocation=%@", inv); // (null) NSLog(@" raise=%@", raise?@"YES":@"NO"); // NO r=[super _cleanupAndAuthenticate:arg sequence:seq conversation:conversation invocation:inv raise:raise]; NSLog(@" r=%@", r?@"YES":@"NO"); // YES if ok if(conversation) NSLog(@" *conversation=%@", *conversation); return r; } - (id) newConversation; { return [super newConversation]; } @end @interface Delegate : NSObject // used as the delegate of NSConnection @end @implementation Delegate #import "Authenticate.h" - (BOOL) connection:(NSConnection *) conn handleRequest:(NSDistantObjectRequest *) doReq { NSLog(@"conn=%@ doReq=%@", conn, doReq); return NO; } - (BOOL) connection:(NSConnection *) parentConnection shouldMakeNewConnection:(NSConnection *) conn; { return YES; } - (id) createConversationForConnection:(NSConnection *) conn; { // !!! this must have a retain count of 1 return [NSObject new]; } - (BOOL) makeNewConnection:(NSConnection *) newConnection sender:(NSConnection *) conn; { return YES; } @end @interface PortDelegate : NSObject // used as the delegate of NSConnection @end @implementation PortDelegate - (void) handlePortMessage:(NSPortMessage *)portMessage { NSLog(@"handle port message %@", portMessage); NSLog(@"msgid %d", [portMessage msgid]); // -> 0 NSLog(@"components %@", [portMessage components]); // -> ( <04edfe1f 0e010101 01010d4e 53496e76 6f636174 696f6e00 00010101 104e5344 69737461 6e744f62 6a656374 00000001 01010102 01010b72 6f6f744f 626a6563 74000101 0440403a 00014001 0000>, <> ) NSLog(@"runloop %@", [NSRunLoop currentRunLoop]); NSLog(@"runloop.currentMode %@", [[NSRunLoop currentRunLoop] currentMode]); // -> "NSConnection Seeking Reply" } @end CLIENT *client; @implementation NSKeyedArchiver (NSConnection) - (NSConnection *) connection { return client; } @end int main(int argc, const char *argv[]) { NSAutoreleasePool *arp=[NSAutoreleasePool new]; NSString *str1, *str2; NSPort *cport; NSDistantObject *proxy; moreinit(); #if LOCAL // local server SERVER *server; // [NSConnectionPoser poseAsClass:[NSConnection class]]; // open connection through Cocoa #if 0 // register simple port { NSPort *port=[NSPort port]; [[NSPortNameServer systemDefaultPortNameServer] registerPort:port name:@"MyService"]; [port scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSConnectionReplyMode]; [port scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [port setDelegate:[PortDelegate new]]; NSLog(@"server.port=%@", port); NSLog(@"server.port.delegate=%@", [port delegate]); } #else server=[SERVER serviceConnectionWithName:@"MyService" rootObject:[[Server alloc] init]]; [server setDelegate:[Delegate new]]; NSLog(@"server=%@", server); NSLog(@"server.recv=%@", [server receivePort]); NSLog(@"server.send=%@", [server sendPort]); NSLog(@"systemDefaultPortNameServer=%@", [NSPortNameServer systemDefaultPortNameServer]); NSLog(@"portForName=%@", [[NSPortNameServer systemDefaultPortNameServer] portForName:@"MyService"]); #endif // connect by our implementation client=[CLIENT connectionWithRegisteredName:@"MyService" host:nil]; #else cport=[[NSSocketPortNameServer sharedInstance] portForName:@"echome" host:@"192.168.2.101"]; NSLog(@"port = %@", cport); if(!cport) exit(1); client=[CLIENT connectionWithReceivePort:nil sendPort:cport]; // NSSocketPort connection #endif // now switch so that our Server implementation is used for responses... [NSConnectionPoser poseAsClass:[NSConnection class]]; NSLog(@"client=%@", client); NSLog(@"client.recv=%@", [client receivePort]); NSLog(@"client.recv.delegate=%@", [[client receivePort] delegate]); NSLog(@"client.send=%@", [client sendPort]); #if SETCLIENTDELEGATE [client setDelegate:[Delegate new]]; #endif NSLog(@"client.send.delegate=%@", [[client sendPort] delegate]); proxy=(NSDistantObject *) [client rootProxy]; NSLog(@"rootProxy=%p", proxy); [proxy myself]; // return the proxy NSLog(@"rootProxy=%@", proxy); // calls [proxy respondsToSelector:@selector(descriptionWithLocale:)] and [proxy description] NSLog(@"rootProxy.class=%@", [proxy class]); [proxy echo:[[NSObject alloc] init]]; // return the same NSDistantObject [proxy echo:[[NSObject alloc] init]]; // return another NSDistantObject [proxy other]; // return a distant object initially only known by proxy [proxy other]; // return another [proxy myself]; // return the proxy again [proxy echo:[[NSObject alloc] init]]; // return another NSDistantObject #if 1 // disable to find more about fetching method signatures from remote side [proxy setProtocolForProxy:@protocol(EchoMeProtocol)]; #endif str2=@"in"; #if 1 { NSString *longstring=[@"" stringByPaddingToLength:257 withString:@"0123456789abcdef" startingAtIndex:0]; #if 1 longstring=(NSString *) [longstring dataUsingEncoding:NSUTF8StringEncoding]; #endif str1=[proxy getMutableCopy:longstring inout:str2]; } #else str1=[proxy getMutableCopy:@"input" inout:str2]; #endif NSLog(@"str1=%p %@", str1, str1); NSLog(@"str2=%p %@", str2, str2); [proxy raiseException]; // find out if exceptions are returned correctly NSApplicationMain(argc, argv); } int moreinit(void) { #if 0 { // learn something about class hierarchy and class versions Class c=[@"string" /*[NSData data]*/ class]; while(YES) { NSLog(@"%@ %d", NSStringFromClass(c), [c version]); if([c superclass] == c) break; c=[c superclass]; } } #endif }