maju
OP
Created
Dec ’19
Replies
10
Boosts
0
Views
4k
Participants
5
Long polling
Reverse connection
Thanks eskimo! Let me try and get back to you on this solution.
If you’re using NSXPCConnection you can send an NSXPCListenerEndpoint object over the connection by simply including it as a parameter in one of the calls defined in your protocol.To send something to the service/daemon, Client/Agent side needs to
already have established a connection?
Yes.is the new connection-from-endpoint created on the service side unique
Yes.Can I have more than one?
Agent (maintains anonymous listener) connects to Daemon (mach-service-named), calls the Daemon and registers its anonymous-listener's endpoint.
Daemon in turn creates the reverse-connection, and later uses it to convey information to the Agent using specific protocol and methods.
Code Block - (id)synchronousRemoteObjectProxyWithErrorHandler:(void (^)(NSError *error))handler API_AVAILABLE(macos(10.11), ios(9.0), watchos(2.0), tvos(9.0));
That is surprising. I would have expected that to happen.If my Agent goes away (killed, quits etc.) Daemon's connection for
some reason doesn't know about it (neither interruption handler nor
invalidation handler on the reverse-connection are being called).
The resulting proxy will run requests synchronously, that is, when you make a call on the proxy the calling thread will block until the remote process has responded to that request.I do not understand what's "synchronous" here --- this is just an
accessor providing me a proxy.
An even better option is scheduleSendBarrierBlock(_:). There’s no documentation for this (r. 75253743) but <Foundation/NSXPCConnection.h> has a great comment explaining how it works.For this reason it’s important that the service not send unbounded
requests to the client. A good way to handle this is to use a
request/response pair, and wait for the response before sending any
more requests.
XPC is bidirectional. Just use setExportedInterface and setExportedObject in your client. Then in the server when you call a method on the remoteObjectProxy you will receive the method call in the exported object in the client.
FYI this is how apps that use CoreLocation receive location updates from the locationd daemon. Use Hopper on the CoreLocation framework and take a look at _CLLocationManagerRoutineProxy createConnection for more detail.
`/* @class _CLLocationManagerRoutineProxy */
-(void)createConnection {
rbx = self;
rdi = self->_connection;
if (rdi != 0x0) {
[rdi release];
*(rbx + 0x18) = 0x0;
}
rax = [NSXPCConnection alloc];
rax = [rax initWithMachServiceName:@"com.apple.locationd.routine" options:0x1000];
*(rbx + 0x18) = rax;
if (rax != 0x0) {
[*(rbx + 0x18) setExportedInterface:[NSXPCInterface interfaceWithProtocol:@protocol(CLLocationManagerRoutineClientInterface)]];
[*(rbx + 0x18) setExportedObject:rbx];
r14 = [*(rbx + 0x18) exportedInterface];
r13 = objc_opt_class(@class(NSArray));
objc_opt_class(@class(CLLocation));
[r14 setClasses:[NSSet setWithObjects:r13] forSelector:@selector(didUpdateLocations:) argumentIndex:0x0 ofReply:0x0];
rdx = [NSXPCInterface interfaceWithProtocol:@protocol(CLLocationManagerRoutineServerInterface)];
[*(rbx + 0x18) setRemoteObjectInterface:rdx];
r14 = [*(rbx + 0x18) serviceName];
rdi = *(rbx + 0x18);
var_78 = *__NSConcreteStackBlock;
*(&var_78 + 0x8) = 0xffffffffc2000000;
*(&var_78 + 0x10) = sub_911b;
*(&var_78 + 0x18) = 0x71d40;
*(&var_78 + 0x20) = r14;
[rdi setInterruptionHandler:rdx];
rdi = *(rbx + 0x18);
var_50 = *__NSConcreteStackBlock;
*(&var_50 + 0x8) = 0xffffffffc2000000;
*(&var_50 + 0x10) = sub_9133;
*(&var_50 + 0x18) = 0x71d40;
*(&var_50 + 0x20) = r14;
[rdi setInvalidationHandler:&var_50];
[*(rbx + 0x18) resume];
}
if ([rbx updating] != 0x0) {
[[[rbx connection] remoteObjectProxy] startUpdatingLocation];
}
return;
}
`
There is info on how to do this in the docs here: https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingXPCServices.html#//apple_ref/doc/uid/10000172i-SW6-SW15
See the note that says:
Note: If you want to allow the helper process to call methods on an object in your application, you must set the exportedInterface and exportedObject properties before calling resume. These properties are described further in the next section.