machrunloopserver.cpp [plain text]
#include "machrunloopserver.h"
#include <Security/cfutilities.h>
#include <mach/mach_error.h>
#include <Security/debugging.h>
namespace Security {
namespace MachPlusPlus {
MachRunLoopServer::MachRunLoopServer(const char *name) : MachServer(name)
{
}
MachRunLoopServer::MachRunLoopServer(const char *name, const Bootstrap &boot)
: MachServer(name, boot)
{
}
void MachRunLoopServer::run(size_t bufferSize, mach_msg_options_t options)
{
replyBuffer = CssmAllocator::standard().malloc<mach_msg_header_t>(bufferSize);
runLoop = CFRunLoopGetCurrent();
CFRef<CFMachPortRef> cfPort = CFMachPortCreateWithPort(NULL, mServerPort, cfCallback,
NULL, NULL);
runLoopSource =
CFMachPortCreateRunLoopSource(NULL, cfPort, 10); if (!runLoop || !runLoopSource || !cfPort)
CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); CFRunLoopAddSource(runLoop, runLoopSource, kCFRunLoopDefaultMode);
perThread().server = this;
}
MachRunLoopServer::~MachRunLoopServer()
{
CFRunLoopRemoveSource(runLoop, runLoopSource, kCFRunLoopDefaultMode);
CFRelease(runLoopSource);
CssmAllocator::standard().free(replyBuffer);
perThread().server = NULL;
}
void MachRunLoopServer::blockNewRequests(bool block)
{
if (block) {
CFRunLoopRemoveSource(runLoop, runLoopSource, kCFRunLoopDefaultMode);
debug("machsrv", "disabled request reception");
} else {
CFRunLoopAddSource(runLoop, runLoopSource, kCFRunLoopDefaultMode);
debug("machsrv", "enabled request reception");
}
}
void MachRunLoopServer::alsoListenOn(Port port)
{
CFRef<CFMachPortRef> cfPort = CFMachPortCreateWithPort(NULL, port, cfCallback,
NULL, NULL);
CFRef<CFRunLoopSourceRef> source =
CFMachPortCreateRunLoopSource(NULL, cfPort, 10); CFRunLoopAddSource(runLoop, source, kCFRunLoopDefaultMode);
debug("machsrv", "also receiving from port %d", port.port());
}
void MachRunLoopServer::stopListenOn(Port port)
{
CFRef<CFMachPortRef> cfPort = CFMachPortCreateWithPort(NULL, port, cfCallback,
NULL, NULL);
CFRef<CFRunLoopSourceRef> source =
CFMachPortCreateRunLoopSource(NULL, cfPort, 10); CFRunLoopRemoveSource(runLoop, source, kCFRunLoopDefaultMode);
debug("machsrv", "no longer receiving from port %d", port.port());
}
void MachRunLoopServer::notifyIfDead(Port port) const
{
CFMachPortRef cfPort = CFMachPortCreateWithPort(NULL, port, NULL, NULL, NULL);
CFMachPortSetInvalidationCallBack(cfPort, cfInvalidateCallback);
}
void MachRunLoopServer::cfInvalidateCallback(CFMachPortRef cfPort, void *)
{
active().notifyDeadName(CFMachPortGetPort(cfPort));
}
void MachRunLoopServer::cfCallback(CFMachPortRef port, void *msg, CFIndex, void *)
{
active().oneRequest(reinterpret_cast<mach_msg_header_t *>(msg));
}
void MachRunLoopServer::oneRequest(mach_msg_header_t *request)
{
if (!handle(request, replyBuffer)) {
debug("machrls", "MachRunLoopServer dispatch failed");
return;
}
if (kern_return_t err = mach_msg_overwrite(replyBuffer,
(MACH_MSGH_BITS_REMOTE(replyBuffer->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE) ?
MACH_SEND_MSG : MACH_SEND_MSG|MACH_SEND_TIMEOUT,
replyBuffer->msgh_size, 0, MACH_PORT_NULL,
0, MACH_PORT_NULL, (mach_msg_header_t *) 0, 0)) {
debug("machsrv", "RunloopServer cannot post reply: %s", mach_error_string(err));
active().releaseDeferredAllocations();
return;
}
active().releaseDeferredAllocations();
return;
}
} }