#include <sysexits.h>
#include <unistd.h>
#include <sys/types.h>
#include <servers/bootstrap.h>
#include "configd.h"
#include "configd_server.h"
#include "notify_server.h"
#include "session.h"
extern struct mig_subsystem _config_subsystem;
extern boolean_t config_server(mach_msg_header_t *, mach_msg_header_t *);
#include "shared_dns_info_types.h"
#include "dnsinfo_server.h"
extern struct mig_subsystem _shared_dns_info_subsystem;
extern boolean_t shared_dns_info_server(mach_msg_header_t *, mach_msg_header_t *);
static CFMachPortRef configd_port = NULL;
__private_extern__
boolean_t
config_demux(mach_msg_header_t *request, mach_msg_header_t *reply)
{
Boolean processed = FALSE;
processed = config_server(request, reply);
if (processed) {
return TRUE;
}
processed = shared_dns_info_server(request, reply);
if (processed) {
return TRUE;
}
processed = notify_server(request, reply);
if (processed) {
return TRUE;
}
SCLog(TRUE, LOG_ERR, CFSTR("config_demux(): unknown message ID (%d) received"), request->msgh_id);
reply->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(request->msgh_bits), 0);
reply->msgh_remote_port = request->msgh_remote_port;
reply->msgh_size = sizeof(mig_reply_error_t);
reply->msgh_local_port = MACH_PORT_NULL;
reply->msgh_id = request->msgh_id + 100;
((mig_reply_error_t *)reply)->NDR = NDR_record;
((mig_reply_error_t *)reply)->RetCode = MIG_BAD_ID;
return FALSE;
}
#define MACH_MSG_BUFFER_SIZE 128
__private_extern__
void
configdCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
{
mig_reply_error_t * bufRequest = msg;
uint32_t bufReply_q[MACH_MSG_BUFFER_SIZE/sizeof(uint32_t)];
mig_reply_error_t * bufReply = (mig_reply_error_t *)bufReply_q;
static CFIndex bufSize = 0;
mach_msg_return_t mr;
int options;
if (bufSize == 0) {
bufSize = _config_subsystem.maxsize;
if (_shared_dns_info_subsystem.maxsize > bufSize) {
bufSize = _shared_dns_info_subsystem.maxsize;
}
if (bufSize > sizeof(bufReply_q)) {
SCLog(TRUE, LOG_NOTICE,
CFSTR("configdCallback(): buffer size should be increased > %d"),
_config_subsystem.maxsize);
}
}
if (bufSize > sizeof(bufReply_q)) {
bufReply = CFAllocatorAllocate(NULL, _config_subsystem.maxsize, 0);
}
bufReply->RetCode = 0;
(void) config_demux(&bufRequest->Head, &bufReply->Head);
if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
if (bufReply->RetCode == MIG_NO_REPLY) {
bufReply->Head.msgh_remote_port = MACH_PORT_NULL;
} else if ((bufReply->RetCode != KERN_SUCCESS) &&
(bufRequest->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
mach_msg_destroy(&bufRequest->Head);
}
}
if (bufReply->Head.msgh_remote_port != MACH_PORT_NULL) {
options = MACH_SEND_MSG;
if (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) != MACH_MSG_TYPE_MOVE_SEND_ONCE) {
options |= MACH_SEND_TIMEOUT;
}
mr = mach_msg(&bufReply->Head,
options,
bufReply->Head.msgh_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
switch (mr) {
case MACH_SEND_INVALID_DEST:
case MACH_SEND_TIMED_OUT:
break;
default :
goto done;
}
}
if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
mach_msg_destroy(&bufReply->Head);
}
done :
if (bufReply != (mig_reply_error_t *)bufReply_q)
CFAllocatorDeallocate(NULL, bufReply);
return;
}
static CFStringRef
serverMPCopyDescription(const void *info)
{
return CFStringCreateWithFormat(NULL, NULL, CFSTR("<main DynamicStore MP>"));
}
__private_extern__
void
server_init()
{
serverSessionRef mySession;
CFRunLoopSourceRef rls;
char *service_name;
mach_port_t service_port = MACH_PORT_NULL;
kern_return_t status;
service_name = getenv("SCD_SERVER");
if (!service_name) {
service_name = SCD_SERVER;
}
status = bootstrap_check_in(bootstrap_port, service_name, &service_port);
switch (status) {
case BOOTSTRAP_SUCCESS :
break;
case BOOTSTRAP_NOT_PRIVILEGED :
SCLog(TRUE, LOG_ERR, CFSTR("'%s' server already starting"), service_name);
exit (EX_UNAVAILABLE);
case BOOTSTRAP_SERVICE_ACTIVE :
SCLog(TRUE, LOG_ERR, CFSTR("'%s' server already active"), service_name);
exit (EX_UNAVAILABLE);
default :
SCLog(TRUE, LOG_ERR,
CFSTR("server_init bootstrap_check_in() failed: %s"),
bootstrap_strerror(status));
exit (EX_UNAVAILABLE);
}
mySession = addSession(service_port, serverMPCopyDescription);
configd_port = mySession->serverPort;
rls = CFMachPortCreateRunLoopSource(NULL, configd_port, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, CFSTR("locked"));
CFRelease(rls);
return;
}
__private_extern__
int
server_shutdown()
{
if (configd_port != NULL) {
mach_port_t service_port = CFMachPortGetPort(configd_port);
CFMachPortSetInvalidationCallBack(configd_port, NULL);
CFMachPortInvalidate(configd_port);
CFRelease(configd_port);
configd_port = NULL;
if (service_port != MACH_PORT_NULL) {
(void) mach_port_mod_refs(mach_task_self(),
service_port,
MACH_PORT_RIGHT_RECEIVE,
-1);
}
}
return EX_OK;
}
__private_extern__
void
server_loop()
{
CFStringRef rlMode;
pthread_setname_np("SCDynamicStore");
while (TRUE) {
rlMode = (storeLocked > 0) ? CFSTR("locked") : kCFRunLoopDefaultMode;
CFRunLoopRunInMode(rlMode, 1.0e10, TRUE);
pushNotifications(_configd_trace);
}
}