Re: Launchd daemon
Re: Launchd daemon
- Subject: Re: Launchd daemon
- From: Sidney San Martín <email@hidden>
- Date: Sun, 24 Mar 2013 00:26:21 -0400
I just joined and saw this thread, might be able to fill in a couple of gaps (though as a result I don't have your email — hope you see this response).
> - Communication will most probably be done with UNIX Domain Sockets.
> - I will need to configure the plist, which is very well explained (in an other documentation).
>
> I have also taken a look at SampleD.
> - It gets their socket from launch_data_dict_lookup(sockets_dict, "MyListenerSocket");
> Do I need to obtain a control socket from launchd or can I register it myself using ctl_register()?
UNIX domain sockets work great. You can even have launchd create the server end of it for you and grab it at checkin time.
Here's some code from a project of mine that might help with this. Does it cover what you meant by "obtaining a control socket from launchd"? It also grabs a timeout — my daemon exits if it's been idle for a while, yours may not need to. (Replace log() with calls to asl_log() or your own helpful logging function):
int launchdSocketFd = 0;
int launchdTimeout = 0;
launch_data_t checkin_request;
launch_data_t checkin_response;
// Check in with launchd. Even if we weren't launched by launchd these first two calls should succeed
if ((checkin_request = launch_data_new_string(LAUNCH_KEY_CHECKIN)) == NULL) {
log(ASL_LEVEL_ERR, @"launch_data_new_string(\"" LAUNCH_KEY_CHECKIN "\") Unable to create string.");
exit(EXIT_FAILURE);
}
if ((checkin_response = launch_msg(checkin_request)) == NULL) {
log(ASL_LEVEL_ERR, @"launch_msg(\"" LAUNCH_KEY_CHECKIN "\") IPC failure: %s", strerror(errno));
exit(EXIT_FAILURE);
}
// If we were started by launchd, get the file descriptor of the socket launchd opened for us
if (LAUNCH_DATA_DICTIONARY == launch_data_get_type(checkin_response)) {
launch_data_t sockets_dict = launch_data_dict_lookup(checkin_response, LAUNCH_JOBKEY_SOCKETS);
size_t socketCount;
if (sockets_dict && (socketCount = launch_data_dict_get_count(sockets_dict))) {
if(socketCount > 1){
log(ASL_LEVEL_WARNING, @"Launchd gave us extra sockets, ignoring them");
}
launch_data_t listening_fd_array = launch_data_dict_lookup(sockets_dict, "sockserverSocket");
if (listening_fd_array && launch_data_array_get_count(listening_fd_array)) {
launchdSocketFd = launch_data_get_fd(launch_data_array_get_index(listening_fd_array, 0));
}
}
launch_data_t timeout = launch_data_dict_lookup(checkin_response, LAUNCH_JOBKEY_TIMEOUT);
if(timeout){
launchdTimeout = launch_data_get_integer(timeout);
}
if(!launchdSocketFd){
log(ASL_LEVEL_ERR, @"Missing a socket to answer requests!");
exit(EXIT_FAILURE);
}
} else {
errno = launch_data_get_errno(checkin_response);
log(ASL_LEVEL_ERR, @"Couldn't check in with launchd: %m");
}
launch_data_free(checkin_request);
launch_data_free(checkin_response);
> - How to set up my project to use Objective-C for my daemon.
> - What does my Objective-C entry point look like (int main(…) ?)
> - How do I handle SIGKILL
> - If I can't use a for/while/etc. loop, how do I prevent my daemon from exiting once the main function returns?
> - Do I need to obtain a control socket from launchd or can I register it myself using ctl_register()?
>
>> Daemos are by definition command line.
> Do you know how to select objective-C as developing language?
Just create a Foundation command line tool! A launchd daemon can be *any* executable (though it shouldn't use AppKit), it isn't special. Your main()'ll probably look like this:
int main () {
[MyBigFancyController new];
[[NSRunLoop currentRunLoop] run];
return 0;
}
Do whatever initialization you want from main() — it can be inline, a call to a C function, or a call to one or more ObjC methods, as above. It can start listening to the domain socket you got from launchd — you're welcome to wrap it in an NSFileHandle and -acceptConnectionInBackgroundAndNotify — or open files, connect to other programs, whatever.
The NSRunLoop is your infinite loop, the same one used by Cocoa apps, and the call to -run won't return while the it has input sources. Any evented ObjC call (NSTimer, -performSelector:afterDelay:, notification center, NSURLConnection, -acceptConnectionInBackgroundAndNotify, etc.) that can call you back at a later time registers itself with the run loop and counts as an input source, so don't worry about it.
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden