[launchd-dev] The MachService key

Jerry Krinock jerry at ieee.org
Tue Nov 22 22:07:06 PST 2011


Well, I read all the advice in this thread, all the docs and headers I could find, watched WWDC 2011 Session 206 and came up with the following "Hello World" Mach Service Demo.

Not surprisingly, it doesn't work.  If any of you guys could point out the mistakes I'd appreciate it.  I know there are multiple problems…

• Launchd doesn't even try to launch the Server when Client sends message.   
• Run loops never time out – wrong modes?

Sorry if this is like shooting fish in a bowl, but there's a lot of new stuff in here for me.


*********** Client-main.m ********************************

#import <xpc/xpc.h>

int main(int argc, const char *argv[]) {
    @autoreleasepool {
        NSLog(@"MachServiceDemo Client has launched") ;
        
        // Create the service
        const char* svcName = "com.machservicedemo.client" ;
        xpc_connection_t listener ;
        listener = xpc_connection_create_mach_service(
                                                    svcName,
                                                    NULL,
                                                    0
                                                    ) ;
        // Dispatch queue is NULL per WWDC Session 206 ?!?!
        
        // Set an Event Handler
        xpc_connection_set_event_handler(listener, ^(xpc_object_t event) {
            // This is just a placeholder until we get the server working
        }) ;
        xpc_connection_resume(listener) ;
        
        // Send a "Hello World!" message
        xpc_object_t msgDic ;
        msgDic = xpc_dictionary_create(NULL, NULL, 0) ;
        xpc_dictionary_set_string(msgDic, "Msg", "Hello, World!") ;
        xpc_connection_send_message(listener, msgDic) ;
        xpc_release(msgDic) ;
        
        // Run for a few seconds
        NSTimeInterval doneSeconds = 10 ;        
        NSDate* doneDate = [NSDate dateWithTimeIntervalSinceNow:doneSeconds] ;
        NSLog(@"MachServiceDemo Client will run until %@", doneDate) ;
        
        while ([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                        beforeDate:doneDate]) {
        }
    }
    
    NSLog(@"MachServiceDemo Client is exitting.") ;
    
    return (EXIT_SUCCESS) ;
}


*********** Server-main.m ********************************

#import <xpc/xpc.h>

int main(int argc, const char *argv[]) {
    @autoreleasepool {
        NSLog(@"MachServiceDemo Server has launched") ;
        
        dispatch_queue_t myQ = dispatch_queue_create("myQ", NULL) ;
        
        // Create the service
        const char* svcName = "com.machservicedemo.client" ;
        uint64_t flags = XPC_CONNECTION_MACH_SERVICE_LISTENER ;
        xpc_connection_t listener ;
        listener = xpc_connection_create_mach_service(
                                                      svcName,
                                                      myQ,
                                                      flags
                                                      ) ;    

        // Set an Event Handler
        xpc_connection_set_event_handler(listener, ^(xpc_object_t object) {
            char* desc = xpc_copy_description(object);
            NSLog(@"MachServiceDemo Server got connection: %s", desc) ;
            xpc_connection_set_event_handler(listener, ^(xpc_object_t object) {
                char* desc = xpc_copy_description(object);
                NSLog(@"MachServiceDemo Server got message: %s", desc) ;
                free(desc) ;
            }) ;
        }) ;
        xpc_connection_resume(listener) ;
        
        // Run for a few seconds
        NSTimeInterval doneSeconds = 10 ;        
        NSDate* doneDate = [NSDate dateWithTimeIntervalSinceNow:doneSeconds] ;
        NSLog(@"MachServiceDemo Server will run until %@", doneDate) ;
        while ([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                        beforeDate:doneDate]) {
        }

        dispatch_release(myQ) ;
    }
    
    NSLog(@"MachServiceDemo Server is exitting") ;
    
    return (EXIT_SUCCESS) ;
}


*********** com.machservicedemo.plist *****************

<?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.machservicedemo</string>
    <key>MachServices</key>
    <dict>
        <key>com.machservicedemo.client</key>
        <true/>
    </dict>
    <key>ProgramArguments</key>
    <array>
        <string>/Users/jk/Desktop/MachServiceDemo-Server</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>


*********** Run Script Build Phase *****************

# Copy Server to Desktop
cp $CONFIGURATION_BUILD_DIR/MachServiceDemo-Server $HOME/Desktop/MachServiceDemo-Server

# Copy launchd plist to LaunchAgents
cp $PROJECT_DIR/MachServiceDemo/com.machservicedemo.plist $HOME/Library/LaunchAgents/com.machservicedemo.plist

# (Re)load the launchd job
cd $HOME/Library/LaunchAgents/
launchctl unload com.machservicedemo.plist
sleep 2
launchctl load com.machservicedemo.plist
echo Did reload launchd job


****************************************************


My Xcode project has two targets, Server and Client.
Client target depends on Server target.
Run Script Build Phase is in the Client target.
To test, Build and Run the Client target/scheme.

Thanks again,

Jerry



More information about the launchd-dev mailing list