#include <unistd.h>
#include "configd.h"
#include "configd_server.h"
#include "session.h"
void
pushNotifications()
{
void **sessionsToNotify;
CFIndex notifyCnt;
int server;
serverSessionRef theSession;
SCDSessionPrivateRef sessionPrivate;
if (needsNotification == NULL)
return;
notifyCnt = CFSetGetCount(needsNotification);
sessionsToNotify = malloc(notifyCnt * sizeof(CFNumberRef));
CFSetGetValues(needsNotification, sessionsToNotify);
while (--notifyCnt >= 0) {
(void) CFNumberGetValue(sessionsToNotify[notifyCnt],
kCFNumberIntType,
&server);
theSession = getSession(server);
sessionPrivate = (SCDSessionPrivateRef)theSession->session;
if (sessionPrivate->callbackFunction != NULL) {
SCDLog(LOG_DEBUG, CFSTR("executing notifiction callback function (server=%d)."),
sessionPrivate->server);
(void) (*sessionPrivate->callbackFunction)(theSession->session,
sessionPrivate->callbackArgument);
}
if (sessionPrivate->notifyPort != MACH_PORT_NULL) {
mach_msg_empty_send_t msg;
mach_msg_option_t options;
kern_return_t status;
SCDLog(LOG_DEBUG, CFSTR("sending mach message notification."));
SCDLog(LOG_DEBUG, CFSTR(" port = %d"), sessionPrivate->notifyPort);
SCDLog(LOG_DEBUG, CFSTR(" msgid = %d"), sessionPrivate->notifyPortIdentifier);
msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
msg.header.msgh_size = sizeof(msg);
msg.header.msgh_remote_port = sessionPrivate->notifyPort;
msg.header.msgh_local_port = MACH_PORT_NULL;
msg.header.msgh_id = sessionPrivate->notifyPortIdentifier;
options = MACH_SEND_TIMEOUT;
status = mach_msg(&msg.header,
MACH_SEND_MSG|options,
msg.header.msgh_size,
0,
MACH_PORT_NULL,
0,
MACH_PORT_NULL);
}
if (sessionPrivate->notifyFile >= 0) {
ssize_t written;
SCDLog(LOG_DEBUG, CFSTR("sending (UNIX domain) socket notification"));
SCDLog(LOG_DEBUG, CFSTR(" fd = %d"), sessionPrivate->notifyFile);
SCDLog(LOG_DEBUG, CFSTR(" msgid = %d"), sessionPrivate->notifyFileIdentifier);
written = write(sessionPrivate->notifyFile,
&sessionPrivate->notifyFileIdentifier,
sizeof(sessionPrivate->notifyFileIdentifier));
if (written == -1) {
if (errno == EWOULDBLOCK) {
SCDLog(LOG_DEBUG,
CFSTR("sorry, only one outstanding notification per session."));
} else {
SCDLog(LOG_DEBUG,
CFSTR("could not send notification, write() failed: %s"),
strerror(errno));
sessionPrivate->notifyFile = -1;
}
} else if (written != sizeof(sessionPrivate->notifyFileIdentifier)) {
SCDLog(LOG_DEBUG,
CFSTR("could not send notification, incomplete write()"));
sessionPrivate->notifyFile = -1;
}
}
if (sessionPrivate->notifySignal > 0) {
kern_return_t status;
pid_t pid;
status = pid_for_task(sessionPrivate->notifySignalTask, &pid);
if (status == KERN_SUCCESS) {
SCDLog(LOG_DEBUG, CFSTR("sending signal notification"));
SCDLog(LOG_DEBUG, CFSTR(" pid = %d"), pid);
SCDLog(LOG_DEBUG, CFSTR(" signal = %d"), sessionPrivate->notifySignal);
if (kill(pid, sessionPrivate->notifySignal) != 0) {
SCDLog(LOG_DEBUG, CFSTR("could not send signal: %s"), strerror(errno));
status = KERN_FAILURE;
}
} else {
mach_port_type_t pt;
if ((mach_port_type(mach_task_self(), sessionPrivate->notifySignalTask, &pt) == KERN_SUCCESS) &&
(pt & MACH_PORT_TYPE_DEAD_NAME)) {
SCDLog(LOG_DEBUG, CFSTR("could not send signal, process died"));
} else {
SCDLog(LOG_DEBUG, CFSTR("could not send signal: %s"), mach_error_string(status));
}
}
if (status != KERN_SUCCESS) {
(void) mach_port_destroy(mach_task_self(), sessionPrivate->notifySignalTask);
sessionPrivate->notifySignal = 0;
sessionPrivate->notifySignalTask = TASK_NULL;
}
}
}
free(sessionsToNotify);
CFRelease(needsNotification);
needsNotification = NULL;
return;
}