views:

131

answers:

2

Hi,

This is really doing my head in, I hope someone can solve my issue.

I'm trying to learn distributed object, bonjour, etc with Cocoa.

I can get things up and running but there's just one case that's annoying me, i don't understand why it's happening.

I'm trying to setup a DO server that advertise itself with Bonjour.

Here's the relevant server code:

- (void) startServer
{
 NSSocketPort *socket = [[NSSocketPort alloc] init];

 pubService = [[NSNetService alloc] initWithDomain:@"local." type:@"_myservice._tcp" name:@"my_server" port:[socket socket]];
 [pubService publish];

 theConnection = [[NSConnection alloc] initWithReceivePort:socket sendPort:nil];

 [theConnection setRootObject:self];

 [[NSSocketPortNameServer sharedInstance] registerPort:socket name:@"my_server"];

 [theConnection setDelegate:self];

 [theConnection retain];

}

For the client, i'll skip some code sample, I use a NSNetServiceBrowser and search for the appropriate services. It finds the service (NSNetService) OK. I call resolveWithTimeout on the service, and that works well too.

When the service is resolved I try to connect to it.

if I connect like this:

- (void) connect:(NSNetService *) service;
{

 NSLog(@"Remote is %@ [%@] [%d]",[service hostName],[service name],[service port]);

 NSSocketPort *port = (NSSocketPort *) [[NSSocketPortNameServer sharedInstance] portForName:[service name] host:[service hostName]];

 connection = [[NSConnection connectionWithReceivePort:nil sendPort:port] retain];

 @try
 {
  clientObject = (NSDistantObject<DOProtocol>*) connection.rootProxy;
 }
 @catch (id exception) {
  NSLog(@"Caught exception %@",exception);
 }

}

then everything works well, clientObject get initialised and we're all happy.

But if I do this - "manually" creating a remote TCPPort instead of using NSSocketPortNameServer:

- (void) connect:(NSNetService *) service;
{

 NSLog(@"Remote is %@ [%@] [%d]",[service hostName],[service name],[service port]);

 NSSocketPort *port = [[NSSocketPort alloc] initRemoteWithTCPPort:[service port] host:[service hostName]];

 connection = [[NSConnection connectionWithReceivePort:nil sendPort:port] retain];

 @try
 {
  clientObject = (NSDistantObject<DOProtocol>*) connection.rootProxy;
 }
 @catch (id exception) {
  NSLog(@"Caught exception %@",exception);
 }
}

Then the call to connection.rootProxy always throws the exception: "[NSPortCoder sendBeforeTime:sendReplyPort:] timed out"

Why is that?

All the logging that I can do on the two different port object show no differences between them, yet one work, one doesn't.

I hope somebody can shed some light. All the search I did on this show people with some similar but I can't find an answer that solve my case, or tells me why it's happening.

Thanks!

EDIT: just to clarify... the reason i'm trying this is I'm just curious if it can be done without using the NSSocketPortNameServer.

A: 

Quoting apple.com, did you read that last line:

initRemoteWithTCPPort:host:
Initializes the receiver as a TCP/IP socket of type SOCK_STREAM that can connect to a remote host on a specified port.
...
A connection is not opened to the remote host until data is sent.

Don't know much (i.e. nothing) about NSSocket api, but it may be that you never send one byte, and are thus waiting for nothing to happen, and timeout.

mvds
That doesn't really help. It's a chicken and the egg scenario if that's the case
Ben
but if the client should set up the connection, shouldn't it at least.. connect? just throw a single byte that way?
mvds
could you tcpdump to see what goes on?
mvds
[connection isValid] is YES. The connection seems fine. How would I 'throw a single byte' anyway?
Ben
dunno, using `[[connection sendPort] sendBeforeDate:components:from:reserved:]`, but that may interfere with the normal way things work. I just saw your timeout error and read that single line in the docs, which sounded like a match, but appearantly this `NSConnection` thing is way more than the low level socket programming I'm used to. Too bad! Good luck anyway ;-)
mvds
Thanks for trying :) sendBeforeDate didn't help. That wouldn't sound like the Cocoa way of doing things anyway. It's gotta be something simple(r).
Ben
mvds
Good suggestion, i'll try that
Ben
Okay, tried the sort/diff thing.. there's definitely some differences but i'm none the wiser as to why it's happening..
Ben
oh, and giving you the bounty for trying to help me out (even though i didn't get a complete answer)
Ben
Thanks! Is the list of differences short enough to share here?
mvds
@mvds, just posted it as a reply
Ben
A: 

mvds, here's the diff result of the two msgSends outputs..

diff msgSends-NOTWORKING msgSends-WORKING

9a10
> + AppController NSObject instanceMethodSignatureForSelector:
573a575
> + NSData NSData dataWithBytesNoCopy:length:freeWhenDone:
640a643
> + NSDistantObject NSDistantObject newDistantObjectWithCoder:
770,777d772
< + NSException NSException exceptionWithName:reason:userInfo:
< + NSException NSException raise:format:
< + NSException NSException raise:format:arguments:
< + NSException NSObject alloc
< + NSException NSObject allocWithZone:
< + NSException NSObject initialize
< + NSException NSObject resolveInstanceMethod:
< + NSException NSObject self
1076a1072,1073
> + NSMachPort NSObject class
> + NSMachPort NSObject initialize
1143a1141
> + NSMessageBuilder NSMessageBuilder initialize
1273d1270
< + NSNumber NSNumber numberWithInt:
1287a1285
> + NSObject NSObject instanceMethodSignatureForSelector:
1435a1434,1435
> + NSPortMessage NSObject allocWithZone:
> + NSPortMessage NSObject initialize
1749d1748
< + NSTextInputContext NSTextInputContext _applicationDeactivated:
1808,1809d1806
< + NSThread NSThread callStackReturnAddresses
< + NSThread NSThread callStackSymbols
2010,2014d2006
< + _NSCallStackArray NSArray allocWithZone:
< + _NSCallStackArray NSObject alloc
< + _NSCallStackArray NSObject initialize
< + _NSCallStackArray NSObject new
< + _NSCallStackArray _NSCallStackArray arrayWithFrames:count:symbols:
2374d2365
< - AppController NSObject isEqual:
2607d2597
< - NSApplication NSApplication _setMouseActivationInProgress:
3245d3234
< - NSCFNumber NSCFNumber intValue
3812,3813d3800
< - NSComboBox NSView _drawRectIfEmpty
< - NSComboBox NSView _drawRectIfEmptyWhenSubviewsCoverDirtyRect:
4094d4080
< - NSComboBoxWindow NSWindow _deactivateTrackingRectsForApplicationDeactivation
4687a4674,4675
> - NSConcreteData NSData isEqual:
> - NSConcreteData NSData isEqualToData:
4755a4744
> - NSConcreteMutableData NSData isNSData__
4794a4784,4785
> - NSConcretePortCoder NSCoder allowsKeyedCoding
> - NSConcretePortCoder NSCoder decodeObject
4796a4788,4792
> - NSConcretePortCoder NSConcretePortCoder decodeBytesWithReturnedLength:
> - NSConcretePortCoder NSConcretePortCoder decodeRetainedObject
> - NSConcretePortCoder NSConcretePortCoder decodeReturnValue:
> - NSConcretePortCoder NSConcretePortCoder decodeValueOfObjCType:at:
> - NSConcretePortCoder NSConcretePortCoder dispatch
4800a4797
> - NSConcretePortCoder NSConcretePortCoder importObject:
4803a4801
> - NSConcretePortCoder NSConcretePortCoder versionForClassName:
4805a4804,4805
> - NSConcretePortCoder NSObject retain
> - NSConcretePortCoder NSObject zone
4830d4829
< - NSConcreteTextStorage NSObject autorelease
4849a4849
> - NSConnection NSConnection addClassNamed:version:
4850a4851
> - NSConnection NSConnection decodeReleasedProxies:
4851a4853,4854
> - NSConnection NSConnection handlePortCoder:
> - NSConnection NSConnection handleReleasedProxies:length:
4861a4865
> - NSConnection NSConnection sendReleasedProxies
4863a4868
> - NSConnection NSConnection versionForClassNamed:
4898a4904,4905
> - NSCountedSet NSCountedSet addObject:
> - NSCountedSet NSCountedSet countForObject:
4900a4908,4909
> - NSCountedSet NSCountedSet member:
> - NSCountedSet NSCountedSet removeObject:
4930a4940
> - NSDOStreamData NSDOStreamData bytes
4932a4943,4944
> - NSDOStreamData NSDOStreamData length
> - NSDOStreamData NSData isNSData__
4933a4946
> - NSDOStreamData NSObject retain
4949a4963
> - NSDistantObject NSDistantObject description
4953a4968,4969
> - NSDistantObject NSDistantObject retain
> - NSDistantObject NSDistantObject retainWireCount
4955a4972
> - NSDistantObject NSProxy respondsToSelector:
5098d5114
< - NSEvent NSEvent data2
5106a5123
> - NSEvent NSEvent trackingNumber
5116,5123d5132
< - NSException NSException dealloc
< - NSException NSException description
< - NSException NSException initWithName:reason:userInfo:
< - NSException NSObject autorelease
< - NSException NSObject class
< - NSException NSObject isKindOfClass:
< - NSException NSObject release
< - NSException NSObject respondsToSelector:
5251d5259
< - NSHelpManager NSHelpManager _orderOutHelpWindow
5338a5347
> - NSInvocation NSInvocation _addAttachedObject:
5340a5350
> - NSInvocation NSInvocation getReturnValue:
5342a5353,5355
> - NSInvocation NSInvocation setArgument:atIndex:
> - NSInvocation NSInvocation setSelector:
> - NSInvocation NSInvocation setTarget:
5346a5360
> - NSInvocation NSObject retain
5532d5545
< - NSLayoutManager NSLayoutManager _hasSeenRightToLeft
5559d5571
< - NSLayoutManager NSLayoutManager characterIndexForPoint:inTextContainer:fractionOfDistanceBetweenInsertionPoints:
5570d5581
< - NSLayoutManager NSLayoutManager fractionOfDistanceThroughGlyphForPoint:inTextContainer:
5575,5576d5585
< - NSLayoutManager NSLayoutManager glyphIndexForPoint:inTextContainer:
< - NSLayoutManager NSLayoutManager glyphIndexForPoint:inTextContainer:fractionOfDistanceThroughGlyph:
5578d5586
< - NSLayoutManager NSLayoutManager glyphRangeForBoundingRectWithoutAdditionalLayout:inTextContainer:
5744a5753
> - NSLevelIndicatorCell NSObject isEqual:
5939a5949
> - NSMethodSignature NSMethodSignature methodReturnType
6268a6279
> - NSObjectController NSObject isEqual:
6365d6375
< - NSPlaceholderNumber NSPlaceholderNumber initWithInt:
6379a6390,6391
> - NSPort NSObject dealloc
> - NSPort NSPort addConnection:toRunLoop:forMode:
6380a6393,6399
> - NSPortMessage NSObject release
> - NSPortMessage NSPortMessage components
> - NSPortMessage NSPortMessage dealloc
> - NSPortMessage NSPortMessage initWithSendPort:receivePort:components:
> - NSPortMessage NSPortMessage receivePort
> - NSPortMessage NSPortMessage sendPort
> - NSPortMessage NSPortMessage setMsgid:
6447a6467,6471
> - NSRunLoop NSRunLoop _addPort:forMode:
> - NSRunLoop NSRunLoop _containsPort:forMode:
> - NSRunLoop NSRunLoop _enumerateInfoPairsWithBlock:
> - NSRunLoop NSRunLoop _removePort:forMode:
> - NSRunLoop NSRunLoop addPort:forMode:
6448a6473
> - NSRunLoop NSRunLoop containsPort:forMode:
6450a6476
> - NSRunLoop NSRunLoop removePort:forMode:
6823a6850
> - NSSocketPort NSObject hash
6824a6852
> - NSSocketPort NSPort removeConnection:fromRunLoop:forMode:
6825a6854,6855
> - NSSocketPort NSSocketPort _handleMessage:from:socket:
> - NSSocketPort NSSocketPort _incrementUseCount
6828a6859
> - NSSocketPort NSSocketPort addConnection:toRunLoop:forMode:
6830a6862
> - NSSocketPort NSSocketPort handlePortMessage:
6836a6869
> - NSSocketPort NSSocketPort removeFromRunLoop:forMode:
6837a6871
> - NSSocketPort NSSocketPort scheduleInRunLoop:forMode:
6838a6873
> - NSSocketPort NSSocketPort setDelegate:
7035a7071
> - NSTempAttributeDictionary NSAttributeDictionary count
7334d7369
< - NSTextInputContext NSTextInputContext deactivate
7361,7362d7395
< - NSTextView NSTextView _cellForPoint:characterIndex:level:row:column:range:
< - NSTextView NSTextView _characterRangeBetweenIndexes:
7378,7379d7410
< - NSTextView NSTextView _getGlyphIndex:characterIndex:forWindowPoint:pinnedPoint:anchorPoint:useAnchorPoint:preferredTextView:partialFraction:
< - NSTextView NSTextView _getGlyphIndex:characterIndex:forWindowPoint:pinnedPoint:preferredTextView:partialFraction:
7388d7418
< - NSTextView NSTextView _selectedRanges
7391d7420
< - NSTextView NSTextView _setScrollingToEnd:
7405,7406d7433
< - NSTextView NSTextView becomeKeyWindow
< - NSTextView NSTextView becomeMainWindow
7441d7467
< - NSTextView NSTextView mouseDown:
7446d7471
< - NSTextView NSTextView resignKeyWindow
7450,7451d7474
< - NSTextView NSTextView selectionAffinity
< - NSTextView NSTextView selectionRangeForProposedRange:granularity:
7474d7496
< - NSTextView NSTextView setSelectionGranularity:
7523d7544
< - NSTextView NSView _disableTrackingArea:
7528d7548
< - NSTextView NSView _enableTrackingArea:
7552d7571
< - NSTextView NSView _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:
7554d7572
< - NSTextView NSView _recursiveSetTrackingAreasDirty:
7573d7590
< - NSTextView NSView _windowChangedKeyState
7662d7678
< - NSThemeFrame NSObject isEqual:
7808,7809d7823
< - NSThemeFrame NSView _drawRectIfEmpty
< - NSThemeFrame NSView _drawRectIfEmptyWhenSubviewsCoverDirtyRect:
8042d8055
< - NSView NSResponder acceptsFirstResponder
8068,8069d8080
< - NSView NSView _drawRectIfEmpty
< - NSView NSView _drawRectIfEmptyWhenSubviewsCoverDirtyRect:
8130d8140
< - NSView NSView acceptsFirstMouse:
8159d8168
< - NSView NSView needsPanelToBecomeKey
8181d8189
< - NSView NSView shouldDelayWindowOrderingForEvent:
8259d8266
< - NSWindow NSWindow _deactivateTrackingRectsForApplicationDeactivation
8266d8272
< - NSWindow NSWindow _disableTrackingArea:
8280d8285
< - NSWindow NSWindow _enableTrackingArea:
8283d8287
< - NSWindow NSWindow _getPositionFromServer
8342d8345
< - NSWindow NSWindow _removeMouseMovedListener:
8398d8400
< - NSWindow NSWindow _updateMouseMovedState
8481d8482
< - NSWindow NSWindow nextEventMatchingMask:
8492,8493d8492
< - NSWindow NSWindow resignKeyWindow
< - NSWindow NSWindow resignMainWindow
8602,8606d8600
< - _NSCallStackArray NSObject autorelease
< - _NSCallStackArray NSObject init
< - _NSCallStackArray NSObject release
< - _NSCallStackArray NSObject retain
< - _NSCallStackArray _NSCallStackArray dealloc
8816d8809
< - _NSKeyboardFocusClipView NSView _enableOrDisableTrackingAreas
8843d8835
< - _NSKeyboardFocusClipView NSView _recursiveDisplayRectIfNeededIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:topView:
8867d8858
< - _NSKeyboardFocusClipView NSView _windowChangedKeyState
8882d8872
< - _NSKeyboardFocusClipView NSView hitTest:
Ben
I think in your version the port is not added to the runloop. see `> - NSPort NSPort addConnection:toRunLoop:forMode:`. Also there is a lot of `NSPortMessage` stuff missing one one side of the diff. Since I see exception stuff, you probably didn't do a blunt `exit()` before the `try` part. It would make things clearer, although I think you can already find the difference in the full trace easily. Just look at the first thing looking like `NSRunLoop` or `NSPortMessage` after `initRemoteWithTCPPort` (which can be found contained in both traces)
mvds
btw: `egrep '^>[^_]+$'` to get the list of interesting things.
mvds
Thanks for the help again. The app runs in a cocoa app, so there might be some additional "noise" from that in the diff.calling addConnection:toRunLoop:forMode: didn't change anything. According to the doc, the NSConnection calls this method internally anyway.hmmmm...
Ben
Regarding debugging methods: The cocoa noise should be in both traces and therefore not in the diff. You make one change and keep all else equal, so the diff results should all relate to that one change. If you `exit()` before the `try` part you will not get the exception calls. Does adding `addConnection:...` show all those missing calls in the trace? Should you call `NSSocketPort scheduleInRunLoop:forMode:` as well / instead?
mvds
I see what you mean. makes sense. I'll try running it again and see if the diff is any better. I tried scheduleInRunLoop but it didn't seem to change anything..
Ben