xpc service that support multiple protocols

I'd like to add an additional listener to my XPC service in order to accept method from additional protocol.


@interface ServiceDelegate1 : NSObject <NSXPCListenerDelegate>

@end


@implementation ServiceDelegate1

- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {

...

@end


@interface ServiceDelegate1 : NSObject <NSXPCListenerDelegate>

@end


@implementation ServiceDelegate2

- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {

...

@end


and in main( ) function I use those delegators to create 2 listeners.


ServiceDelegate1 *delegate1 = [ServiceDelegate1 new];

ServiceDelegate2 *delegate2 = [ServiceDelegate2 new];


NSXPCListener *listener1 = [[NSXPCListener alloc] initWithMachServiceName:@"com.xpc.service1"];

listener1.delegate = delegate1;

[listener1 resume];


NSXPCListener *listener2 = [[NSXPCListener alloc] initWithMachServiceName:@"com.xpc.service2"];

listener2.delegate = delegate2;

[listener2 resume];


I also added the additinal service to the xpc service plist invocation file (under /Library/LaunchDaemons):


<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plist version="1.0">

<dict>

<key>Label</key>

<string>com.xpc.service1</string>

<key>RunAtLoad</key>

<true/>

<key>EnablePressuredExit</key>

<false/>

<key>POSIXSpawnType</key>

<string>Adaptive</string>

<key>ProgramArguments</key>

<array>

<string>/Applications/myApp.app/Contents/XPCServices/myservice.xpc/Contents/MacOS/myservice</string>

</array>

<key>MachServices</key>

<dict>

<key>com.xpc.service1</key>

<true/>

<key>com.xpcƒ.service2</key>

<true/>

</dict>

</dict>

</plist>



However, it seems like after i add the second listener, I suddenly stop getting the serviceName in method implmented by the 2 delegators.


Perhaps anybody can tell me if this is the right way to achieve my goal ?


thanks !

Accepted Reply

However, from what I read … about anonymous listeners and endpoints, it's mainly served for communicating between 2 applications that doesn't aware of each-other with launch agent intermediation.

It can be used for that, but that’s not its only use. There are (at least) four common usage patterns for this tech:

  • To communicate between unrelated processes, as you mentioned.

  • To support multiple protocols, as I’m outlining here.

  • To support server-to-client IPC, as I explained on this thread.

  • To support multiple client-to-server connection objects.

Perhaps you can provide some basic code guidance or a minimal example for how to make this 'Broker' service for my scenario ?

Sure. Your main XPC connection would support a protocol like this:

- (void)openServiceNamed:(NSString *)serviceName reply:(void (^)(NSXPCListenerEndpoint * endpoint))reply;

Your client makes that call, passing in an appropriate service name. The server responds by:

  1. Looking up the service name to decide what service to set up.

  2. Creating some sort of state record to record this service.

  3. Creating an anonymous listener (

    +[NSXPCListener anonymousListener]
    ), configuring it with the service’s protocol.
  4. Getting the endpoint from that (

    NSXPCListener.endpoint
    ).
  5. Passing the endpoint from step 2 back to the client by calling the reply block.

Once the client gets the endpoint, it can open a connection to the anonymous listener using

-[NSXPCConnection initWithListenerEndpoint:]
and set up the service’s protocol on that. From here, the connection and the listener act like normal.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

I'd like to add an additional listener to my XPC service in order to accept method from additional protocol.

I would expect this to work for a

launchd
daemon or agent (it’s definitely not going to work for an XPC Service).

Having said that, I probably wouldn’t do it this way. Rather, I’d have a single ‘broker’ service that clients can check in to and then have the server allocate an anonymous listener and pass its endpoint back to the client.

However, it seems like after i add the second listener, I suddenly stop getting the serviceName in method implmented by the 2 delegators.

I don’t understand this. Can you clarify?

Also, I’m presuming that the U+0192 LATIN SMALL LETTER F WITH HOOK:

<key>com.xpcƒ.service2</key>

is a typo in your DevForums post and not in your original launchd property list (-:

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi and thank you for the fast reply.


- Regarding your suggetion, I'm not sure i fully understand your point but it sounds really interesting...


My objective is to use the XPC service for perform priviledge operations for my application.However, from what I read here https://www.objc.io/issues/14-mac/xpc/ about anonymous listeners and endpoints, it's mainly served for communicating between 2 applications that doesn't aware of each-other with launch agent intermediation.


Perhaps you can provide some basic code guidance or a minimal example for how to make this 'Broker' service for my scenario ?


- Regarding my claim about the missing serviceName, it's not that important now that you say it cannot be done in xpc service :-).


- Regarding the suspected typo issue, it's indeed a typo.



thanks !

However, from what I read … about anonymous listeners and endpoints, it's mainly served for communicating between 2 applications that doesn't aware of each-other with launch agent intermediation.

It can be used for that, but that’s not its only use. There are (at least) four common usage patterns for this tech:

  • To communicate between unrelated processes, as you mentioned.

  • To support multiple protocols, as I’m outlining here.

  • To support server-to-client IPC, as I explained on this thread.

  • To support multiple client-to-server connection objects.

Perhaps you can provide some basic code guidance or a minimal example for how to make this 'Broker' service for my scenario ?

Sure. Your main XPC connection would support a protocol like this:

- (void)openServiceNamed:(NSString *)serviceName reply:(void (^)(NSXPCListenerEndpoint * endpoint))reply;

Your client makes that call, passing in an appropriate service name. The server responds by:

  1. Looking up the service name to decide what service to set up.

  2. Creating some sort of state record to record this service.

  3. Creating an anonymous listener (

    +[NSXPCListener anonymousListener]
    ), configuring it with the service’s protocol.
  4. Getting the endpoint from that (

    NSXPCListener.endpoint
    ).
  5. Passing the endpoint from step 2 back to the client by calling the reply block.

Once the client gets the endpoint, it can open a connection to the anonymous listener using

-[NSXPCConnection initWithListenerEndpoint:]
and set up the service’s protocol on that. From here, the connection and the listener act like normal.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"