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_handlerandxpc_connection_resumeon 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_listenerbefore you thatdispatch_maincall. 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
printfcalls are missing the trailing the\n. That makes everything confusing, especially when you take line buffering into account. For bringing up stuff like this, usefprintfand 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"