I have implemented a XPC server using C APIs. I want to write unit tests for it. I came across the following links that use Swift APIs-
I have tried to write anonymous listener code and the client code in the same file, using C APIs-
#include <unistd.h>
#include <syslog.h>
#include <pthread.h>
#include <stdio.h>
#include <xpc/xpc.h>
#include <xpc/connection.h>
#include <CoreFoundation/CoreFoundation.h>
static void Anon_Client_Connection_Handler(xpc_connection_t connection, xpc_object_t clientMessage)
{
const char *description = xpc_copy_description(clientMessage);
printf("Event received - %s\n", description);
free((void *)description);
xpc_type_t type = xpc_get_type(clientMessage);
if (type == XPC_TYPE_ERROR)
{
if (clientMessage == XPC_ERROR_CONNECTION_INVALID)
printf("Client_Connection_Handler received invalid connection n");
else if (clientMessage == XPC_ERROR_TERMINATION_IMMINENT)
printf("Client_Connection_Handler received termination notice n");
}
else
{
const char *clientMsg = xpc_dictionary_get_string(clientMessage, "message");
printf("Received from client: %s ", clientMsg);
}
}
static void Anon_Listener_Connection_Handler(xpc_connection_t connection)
{
printf("Anon_Listener_Connection_Handler called, setting up event handler \n");
xpc_connection_set_event_handler(connection, ^(xpc_object_t clientMessage) {
printf("Processing the connection! \n");
Anon_Client_Connection_Handler(connection, clientMessage);
});
xpc_connection_resume(connection);
}
int main(int argc, const char *argv[])
{
xpc_connection_t anon_listener = xpc_connection_create(NULL, NULL);
xpc_connection_set_event_handler(anon_listener, ^(xpc_object_t clientConnection) {
printf("Client tried to connect \n");
Anon_Listener_Connection_Handler(clientConnection);
});
xpc_connection_resume(anon_listener);
printf("\nINFO Anonymous connection resumed");
xpc_object_t anon_endpoint = xpc_endpoint_create(anon_listener);
xpc_connection_t clientConnection = xpc_connection_create_from_endpoint(anon_endpoint);
xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(message, "message", "client's message");
xpc_connection_send_message_with_reply(clientConnection, message, dispatch_get_main_queue(), ^(xpc_object_t event) {
printf("\nINFO inside reply");
const char *description = xpc_copy_description(event);
printf("\nINFO %s",description);
free((void *)description);
});
xpc_release(message);
xpc_release(anon_listener);
printf("\nINFO Releasing listener");
xpc_release(anon_endpoint);
printf("\nINFO Releasing endpoint");
// dispatch_main();
return 0;
}
and this is the output I get
INFO Anonymous connection resumed
INFO Releasing listener
INFO Releasing endpoint
I am not able to connect to the client and exchange messages. Where am I going wrong?
Ah, the XPC C API. That’s always fun (-:
The code you posted has a number of problems. I’m gonna start with the highlights. That should get you to the point where the listener receives a connection, which should be sufficient for you to continue making progress by yourself.
So:
-
It’s best to set a target queue on all your connections. It’s not required, but it’ll help keep things straight in your head. I generally use the main queue for these sorts of bring-up tests.
-
You haven’t configured the client connection (
clientConnection
) at all. You need to callxpc_connection_set_event_handler
andxpc_connection_resume
on it. I also recommend you callxpc_connection_set_target_queue
, per the previous point. -
You commented out your call to
dispatch_main
. You’ll need that, otherwise you introduce a race between the main thread returning, which terminates your process, and your XPC messages being handled. -
You release
anon_listener
before you thatdispatch_main
call. I’m not exactly sure what that’ll do, but it doesn’t make sense logically. You want your anonymous listener to be retained while the listener is running. -
Some of your
printf
calls are missing the trailing the\n
. That makes everything confusing, especially when you take line buffering into account. For bringing up stuff like this, usefprintf
and targetstderr
, which is always unbuffered.
With those changes I was able to get it to the point where Anon_Listener_Connection_Handler
runs, and now it’s over to you.
Good luck!
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"