X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/bac41a7b9a0a9254fa30f8bb6e6038ab71a483e2..ce0ac947b4708d0bc1c7e6789b3e1f3bfc80d6e9:/cdsa/cdsa_utilities/machserver.cpp?ds=sidebyside diff --git a/cdsa/cdsa_utilities/machserver.cpp b/cdsa/cdsa_utilities/machserver.cpp index 408ac91b..80db1fd5 100644 --- a/cdsa/cdsa_utilities/machserver.cpp +++ b/cdsa/cdsa_utilities/machserver.cpp @@ -58,7 +58,7 @@ MachServer::MachServer(const char *name, const Bootstrap &boot) void MachServer::setup(const char *name) { - debug("machsrv", "%p preparing service for \"%s\"", this, name); + secdebug("machsrv", "%p preparing service for \"%s\"", this, name); workerTimeout = 60 * 2; // 2 minutes default timeout maxWorkerCount = 100; // sanity check limit @@ -69,26 +69,55 @@ MachServer::~MachServer() { // The ReceivePort members will clean themselves up. // The bootstrap server will clear us from its map when our receive port dies. - debug("machsrv", "%p destroyed", this); + secdebug("machsrv", "%p destroyed", this); } // -// Utility access +// Add and remove extra listening ports. +// Messages directed to those ports are dispatched through the main handler. +// To get automatic call-out to another handler, use the Handler class. // -void MachServer::notifyIfDead(Port port) const +void MachServer::add(Port receiver) { - port.requestNotify(mServerPort, MACH_NOTIFY_DEAD_NAME, true); + secdebug("machsrv", "adding port %d to primary dispatch", receiver.port()); + mPortSet += receiver; +} + +void MachServer::remove(Port receiver) +{ + secdebug("machsrv", "removing port %d from primary dispatch", receiver.port()); + mPortSet -= receiver; +} + + +// +// Register for mach port notifications +// +void MachServer::notifyIfDead(Port port, bool doNotify) const +{ + if (doNotify) + port.requestNotify(mServerPort, MACH_NOTIFY_DEAD_NAME, true); + else + port.cancelNotify(MACH_NOTIFY_DEAD_NAME); +} + +void MachServer::notifyIfUnused(Port port, bool doNotify) const +{ + if (doNotify) + port.requestNotify(port, MACH_NOTIFY_NO_SENDERS, true); + else + port.cancelNotify(MACH_NOTIFY_NO_SENDERS); } // // Initiate service. // This call will take control of the current thread and use it to service -// incoming requests. The thread will not be released until an error happens. +// incoming requests. The thread will not be released until an error happens, which +// will cause an exception to be thrown. In other words, this never returns normally. // We may also be creating additional threads to service concurrent requests // as appropriate. -// @@@ Additional threads are not being reaped at this point. // @@@ Msg-errors in additional threads are not acted upon. // void MachServer::run(size_t maxSize, mach_msg_options_t options) @@ -114,7 +143,8 @@ void MachServer::run(size_t maxSize, mach_msg_options_t options) // // This is the core of a server thread at work. It takes over the thread until -// something makes it exit normally. Then it returns. Errors cause exceptions. +// (a) an error occurs, throwing an exception +// (b) low-load timeout happens, causing a normal return (doTimeout only) // This code is loosely based on mach_msg_server.c, but is drifting away for // various reasons of flexibility and resilience. // @@ -126,10 +156,10 @@ void MachServer::runServerThread(bool doTimeout) Message bufRequest(mMaxSize); Message bufReply(mMaxSize); - // all exits from runServerThread are through exceptions or "goto exit" + // all exits from runServerThread are through exceptions try { // register as a worker thread - debug("machsrv", "%p starting service on port %d", this, int(mServerPort)); + secdebug("machsrv", "%p starting service on port %d", this, int(mServerPort)); perThread().server = this; for (;;) { @@ -145,13 +175,13 @@ void MachServer::runServerThread(bool doTimeout) // perform self-timeout processing if (doTimeout) { if (workerCount > maxWorkerCount) { - debug("machsrv", "%p too many threads; reaping immediately", this); + secdebug("machsrv", "%p too many threads; reaping immediately", this); break; } Time::Absolute rightNow = Time::now(); if (rightNow >= nextCheckTime) { // reaping period complete; process uint32 idlers = leastIdleWorkers; - debug("machsrv", "%p end of reaping period: %ld (min) idle of %ld total", + secdebug("machsrv", "%p end of reaping period: %ld (min) idle of %ld total", this, idlers, workerCount); nextCheckTime = rightNow + workerTimeout; leastIdleWorkers = INT_MAX; @@ -182,13 +212,13 @@ void MachServer::runServerThread(bool doTimeout) // receive next IPC request (or wait for timeout) switch (mach_msg_return_t mr = indefinite ? - mach_msg_overwrite_trap(bufRequest, + mach_msg_overwrite(bufRequest, MACH_RCV_MSG | mMsgOptions, 0, mMaxSize, mPortSet, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, (mach_msg_header_t *) 0, 0) : - mach_msg_overwrite_trap(bufRequest, + mach_msg_overwrite(bufRequest, MACH_RCV_MSG | MACH_RCV_TIMEOUT | mMsgOptions, 0, mMaxSize, mPortSet, mach_msg_timeout_t(timeout.mSeconds()), MACH_PORT_NULL, @@ -218,18 +248,24 @@ void MachServer::runServerThread(bool doTimeout) } else { // normal request message { StLock _(managerLock); idleCount--; } - debug("machsrvreq", + secdebug("machsrvreq", "servicing port %d request id=%d", bufRequest.localPort().port(), bufRequest.msgId()); - if (bufRequest.localPort() == mServerPort) { // primary + + // try subsidiary handlers first + bool handled = false; + for (HandlerSet::const_iterator it = mHandlers.begin(); + it != mHandlers.end(); it++) + if (bufRequest.localPort() == (*it)->port()) { + (*it)->handle(bufRequest, bufReply); + handled = true; + } + if (!handled) { + // unclaimed, send to main handler handle(bufRequest, bufReply); - } else { - for (HandlerSet::const_iterator it = mHandlers.begin(); - it != mHandlers.end(); it++) - if (bufRequest.localPort() == (*it)->port()) - (*it)->handle(bufRequest, bufReply); } - debug("machsrvreq", "request complete"); + + secdebug("machsrvreq", "request complete"); { StLock _(managerLock); idleCount++; } } @@ -259,7 +295,7 @@ void MachServer::runServerThread(bool doTimeout) * To avoid falling off the kernel's fast RPC path unnecessarily, * we only supply MACH_SEND_TIMEOUT when absolutely necessary. */ - switch (mach_msg_return_t mr = mach_msg_overwrite_trap(bufReply, + switch (mach_msg_return_t mr = mach_msg_overwrite(bufReply, (MACH_MSGH_BITS_REMOTE(bufReply.bits()) == MACH_MSG_TYPE_MOVE_SEND_ONCE) ? MACH_SEND_MSG | mMsgOptions : @@ -278,11 +314,11 @@ void MachServer::runServerThread(bool doTimeout) } } perThread().server = NULL; - debug("machsrv", "%p ending service on port %d", this, int(mServerPort)); + secdebug("machsrv", "%p ending service on port %d", this, int(mServerPort)); } catch (...) { perThread().server = NULL; - debug("machsrv", "%p aborted by exception (port %d)", this, int(mServerPort)); + secdebug("machsrv", "%p aborted by exception (port %d)", this, int(mServerPort)); throw; } } @@ -331,7 +367,7 @@ void MachServer::releaseWhenDone(CssmAllocator &alloc, void *memory) if (memory) { set &releaseSet = perThread().deferredAllocations; assert(releaseSet.find(Allocation(memory, alloc)) == releaseSet.end()); - debug("machsrvmem", "%p register %p for release with %p", + secdebug("machsrvmem", "%p register %p for release with %p", this, memory, &alloc); releaseSet.insert(Allocation(memory, alloc)); } @@ -349,7 +385,7 @@ void MachServer::releaseDeferredAllocations() { set &releaseSet = perThread().deferredAllocations; for (set::iterator it = releaseSet.begin(); it != releaseSet.end(); it++) { - debug("machsrvmem", "%p release %p with %p", this, it->addr, it->allocator); + secdebug("machsrvmem", "%p release %p with %p", this, it->addr, it->allocator); it->allocator->free(it->addr); } releaseSet.erase(releaseSet.begin(), releaseSet.end()); @@ -389,7 +425,7 @@ void MachServer::addThread(Thread *thread) StLock _(managerLock); workerCount++; idleCount++; - debug("machsrv", "%p adding worker thread (%ld workers, %ld idle)", + secdebug("machsrv", "%p adding worker thread (%ld workers, %ld idle)", this, workerCount, idleCount); workers.insert(thread); } @@ -399,7 +435,7 @@ void MachServer::removeThread(Thread *thread) StLock _(managerLock); workerCount--; idleCount--; - debug("machsrv", "%p removing worker thread (%ld workers, %ld idle)", + secdebug("machsrv", "%p removing worker thread (%ld workers, %ld idle)", this, workerCount, idleCount); workers.erase(thread); } @@ -415,13 +451,13 @@ bool MachServer::processTimer() if (!(top = static_cast(timers.pop(Time::now())))) return false; // nothing (more) to be done now } // drop lock; work has been retrieved - debug("machsrvtime", "%p timer %p executing at %.3f", + secdebug("machsrvtime", "%p timer %p executing at %.3f", this, top, Time::now().internalForm()); try { top->action(); - debug("machsrvtime", "%p timer %p done", this, top); + secdebug("machsrvtime", "%p timer %p done", this, top); } catch (...) { - debug("machsrvtime", "%p server timer %p failed with exception", this, top); + secdebug("machsrvtime", "%p server timer %p failed with exception", this, top); } return true; } @@ -458,13 +494,15 @@ void cdsa_mach_notify_port_destroyed(mach_port_t, mach_port_name_t port) void MachServer::notifyPortDestroyed(Port) { } -void cdsa_mach_notify_send_once(mach_port_t) -{ MachServer::active().notifySendOnce(); } +void cdsa_mach_notify_send_once(mach_port_t port) +{ MachServer::active().notifySendOnce(port); } + +void MachServer::notifySendOnce(Port) { } -void MachServer::notifySendOnce() { } +void cdsa_mach_notify_no_senders(mach_port_t port, mach_port_mscount_t count) +{ MachServer::active().notifyNoSenders(port, count); } -void cdsa_mach_notify_no_senders(mach_port_t) -{ /* legacy handler - not used by system */ } +void MachServer::notifyNoSenders(Port, mach_port_mscount_t) { } } // end namespace MachPlusPlus