Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have a launch daemon which I want to ask for status information from a user app. I implemented a client-server model (with the daemon as server) using unix sockets as described here: OS X - Communication between launch daemon and launch agent

In fact it works well, when I run the daemon as a user process (for debugging), but it will fail when it is actually launched as root.

I have read the TN on Daemons and Agents and the Daemon & Services Programming Guide. However, I could not find decent information how the socket must be used in a launch daemon.

I am confused by several things:

  • Must I specify the socket in the launch daemon plist file? And how?

  • If the socket is specified in the plist, does that change the way I need to create the socket in code?

  • What path would be good for the unix socket? The Technical Note recommends /var/run but I guess a user process may not write there, or can it?

  • Is there maybe a easier way to do IPC between daemon and client?

  • What is the best way to log the daemon output. I tried NSLog but it seems not work...


I am also unsure if my socket code is correct. Maybe someone more experienced can tell me if I'm on the right track here. I have the following code in the daemon to initialize the unix socket:

#define SOCKETNAME  "/var/run/com.company.myApp.socket"

- (void) startServer {
    //remove any prev socket
    unlink(SOCKETNAME);
    CFSocketContext CTX = { 0, (__bridge void *)(self), NULL, NULL, NULL };

    CFSocketRef unixSocket = CFSocketCreate(NULL, PF_UNIX, SOCK_STREAM, 0,
                               kCFSocketAcceptCallBack, (CFSocketCallBack)AcceptCallBack, &CTX);
    if (unixSocket == NULL) {/*log and return*/} 

    struct sockaddr_un addr;
    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path, SOCKETNAME);
    addr.sun_len = strlen(addr.sun_path) + sizeof (addr.sun_family);

    NSData *address = [ NSData dataWithBytes: &addr length: sizeof(addr) ];
    if (CFSocketSetAddress(unixSocket, (__bridge CFDataRef) address) != kCFSocketSuccess) {
        NSLog(@"CFSocketSetAddress() failed\n");
        CFRelease(unixSocket);
    }

    CFRunLoopSourceRef sourceRef = CFSocketCreateRunLoopSource(kCFAllocatorDefault, unixSocket, 0);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), sourceRef, kCFRunLoopCommonModes);
    CFRelease(sourceRef);    
    CFRunLoopRun();
}


void AcceptCallBack(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) {
    CTServerController* selfServerController = (__bridge CTServerController*) info;
    //NSLog(@"acceptCallBack");   
    //...
}
share|improve this question

Know someone who can answer? Share a link to this question via email, Google+, Twitter, or Facebook.

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.