+++ /dev/null
-/*
- * Copyright (c) 2003-2004,2006,2011-2012,2014 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#include <list>
-#include <security_utilities/globalizer.h>
-#include <security_utilities/threading.h>
-#include "eventlistener.h"
-#include "SharedMemoryClient.h"
-#include <notify.h>
-#include "sscommon.h"
-#include <sys/syslog.h>
-
-using namespace MachPlusPlus;
-
-
-namespace Security {
-namespace SecurityServer {
-
-typedef RefPointer<EventListener> EventPointer;
-typedef std::list<EventPointer> EventListenerList;
-
-static const char* GetNotificationName ()
-{
- // the name we give the client depends on the value of the environment variable "SECURITYSERVER"
- const char* name = getenv (SECURITYSERVER_BOOTSTRAP_ENV);
- if (name == NULL)
- {
- name = SECURITY_MESSAGES_NAME;
- }
-
- return name;
-}
-
-
-
-class SharedMemoryClientMaker
-{
-private:
- SharedMemoryClient mClient;
-
-public:
- SharedMemoryClientMaker ();
- SharedMemoryClient* Client ();
-};
-
-
-
-SharedMemoryClientMaker::SharedMemoryClientMaker () : mClient (GetNotificationName (), kSharedMemoryPoolSize)
-{
-}
-
-
-
-SharedMemoryClient* SharedMemoryClientMaker::Client ()
-{
- return &mClient;
-}
-
-
-
-ModuleNexus<EventListenerList> gEventListeners;
-ModuleNexus<Mutex> gNotificationLock;
-ModuleNexus<SharedMemoryClientMaker> gMemoryClient;
-
-class NotificationPort : public MachPlusPlus::CFAutoPort
-{
-protected:
- SharedMemoryClient *mClient;
-
- void ReceiveImplementation(u_int8_t* buffer, SegmentOffsetType length, UnavailableReason ur);
- static void HandleRunLoopTimer(CFRunLoopTimerRef timer, void* info);
-
-public:
- NotificationPort (mach_port_t port);
- virtual ~NotificationPort ();
- virtual void receive(const MachPlusPlus::Message &msg);
-};
-
-NotificationPort::NotificationPort (mach_port_t mp) : CFAutoPort (mp)
-{
- mClient = gMemoryClient ().Client ();
-}
-
-
-
-NotificationPort::~NotificationPort ()
-{
-}
-
-
-
-void NotificationPort::ReceiveImplementation(u_int8_t* buffer, SegmentOffsetType length, UnavailableReason ur)
-{
- EventListenerList& eventList = gEventListeners();
-
- // route the message to its destination
- u_int32_t* ptr = (u_int32_t*) buffer;
-
- // we have a message, do the semantics...
- SecurityServer::NotificationDomain domain = (SecurityServer::NotificationDomain) OSSwapBigToHostInt32 (*ptr++);
- SecurityServer::NotificationEvent event = (SecurityServer::NotificationEvent) OSSwapBigToHostInt32 (*ptr++);
- CssmData data ((u_int8_t*) ptr, buffer + length - (u_int8_t*) ptr);
-
- EventListenerList::iterator it = eventList.begin ();
- while (it != eventList.end ())
- {
- try
- {
- EventPointer ep = *it++;
- if (ep->GetDomain () == domain &&
- (ep->GetMask () & (1 << event)) != 0)
- {
- ep->consume (domain, event, data);
- }
- }
- catch (CssmError &e)
- {
- if (e.error != CSSM_ERRCODE_INTERNAL_ERROR)
- {
- throw;
- }
- }
- }
-}
-
-
-
-typedef void (^NotificationBlock)();
-
-
-
-void NotificationPort::HandleRunLoopTimer(CFRunLoopTimerRef timer, void* info)
-{
- // reconstruct our context and call it
- NotificationBlock nb = (NotificationBlock) info;
- nb();
-
- // clean up
- Block_release(nb);
- CFRunLoopTimerInvalidate(timer);
- CFRelease(timer);
-}
-
-
-
-void NotificationPort::receive (const MachPlusPlus::Message &msg)
-{
- /*
- Read each notification received and post a timer for each with an expiration of
- zero. I'd prefer to use a notification here, but I can't because, according to
- the documentation, each application may only have one notification center and
- the main application should have the right to pick the one it needs.
- */
-
- SegmentOffsetType length;
- UnavailableReason ur;
-
- bool result;
-
- while (true)
- {
- u_int8_t *buffer = new u_int8_t[kSharedMemoryPoolSize];
-
- {
- StLock<Mutex> lock (gNotificationLock ());
- result = mClient->ReadMessage(buffer, length, ur);
- if (!result)
- {
- delete [] buffer;
- return;
- }
- }
-
- // make a block that contains our data
- NotificationBlock nb =
- ^{
- ReceiveImplementation(buffer, length, ur);
- delete [] buffer;
- };
-
- // keep it in scope
- nb = Block_copy(nb);
-
- // set up to run the next time the run loop fires
- CFRunLoopTimerContext ctx;
- memset(&ctx, 0, sizeof(ctx));
- ctx.info = nb;
-
- // make a run loop timer
- CFRunLoopTimerRef timerRef =
- CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent(), 0,
- 0, 0, NotificationPort::HandleRunLoopTimer, &ctx);
-
- // install it to be run.
- CFRunLoopAddTimer(CFRunLoopGetCurrent(), timerRef, kCFRunLoopDefaultMode);
- }
-}
-
-
-
-class ThreadNotifier
-{
-protected:
- NotificationPort *mNotificationPort;
- int mNotifyToken;
-
-public:
- ThreadNotifier();
- ~ThreadNotifier();
-};
-
-
-
-ThreadNotifier::ThreadNotifier()
- : mNotificationPort(NULL)
-{
- mach_port_t mp;
- if (notify_register_mach_port (GetNotificationName (), &mp, 0, &mNotifyToken) == NOTIFY_STATUS_OK) {
- mNotificationPort = new NotificationPort (mp);
- mNotificationPort->enable ();
- }
-}
-
-
-
-ThreadNotifier::~ThreadNotifier()
-{
- if (mNotificationPort) {
- notify_cancel (mNotifyToken);
- delete mNotificationPort;
- }
-}
-
-
-
-ModuleNexus<ThreadNexus<ThreadNotifier> > threadInfo;
-
-
-
-static void InitializeNotifications ()
-{
- threadInfo()(); // cause the notifier for this thread to initialize
-}
-
-
-
-EventListener::EventListener (NotificationDomain domain, NotificationMask eventMask)
- : mDomain (domain), mMask (eventMask)
-{
- // make sure that notifications are turned on.
- InitializeNotifications ();
-}
-
-
-//
-// StopNotification() is needed on destruction; everyone else cleans up after themselves.
-//
-EventListener::~EventListener ()
-{
- StLock<Mutex> lock (gNotificationLock ());
-
- // find the listener in the list and remove it
- EventListenerList::iterator it = std::find (gEventListeners ().begin (),
- gEventListeners ().end (),
- this);
- if (it != gEventListeners ().end ())
- {
- gEventListeners ().erase (it);
- }
-}
-
-
-
-// get rid of the pure virtual
-void EventListener::consume(NotificationDomain, NotificationEvent, const Security::CssmData&)
-{
-}
-
-
-
-void EventListener::FinishedInitialization(EventListener *eventListener)
-{
- StLock<Mutex> lock (gNotificationLock ());
- gEventListeners().push_back (eventListener);
-}
-
-
-
-} // end namespace SecurityServer
-} // end namespace Security