2 * Copyright (c) 2003-2004,2006 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <security_utilities/globalizer.h>
26 #include <security_utilities/threading.h>
27 #include "eventlistener.h"
28 #include "SharedMemoryClient.h"
31 #include <sys/syslog.h>
33 using namespace MachPlusPlus
;
37 namespace SecurityServer
{
39 typedef RefPointer
<EventListener
> EventPointer
;
40 typedef std::list
<EventPointer
> EventListenerList
;
42 static const char* GetNotificationName ()
44 // the name we give the client depends on the value of the environment variable "SECURITYSERVER"
45 const char* name
= getenv (SECURITYSERVER_BOOTSTRAP_ENV
);
48 name
= SECURITY_MESSAGES_NAME
;
56 class SharedMemoryClientMaker
59 SharedMemoryClient mClient
;
62 SharedMemoryClientMaker ();
63 SharedMemoryClient
* Client ();
68 SharedMemoryClientMaker::SharedMemoryClientMaker () : mClient (GetNotificationName (), kSharedMemoryPoolSize
)
74 SharedMemoryClient
* SharedMemoryClientMaker::Client ()
81 ModuleNexus
<EventListenerList
> gEventListeners
;
82 ModuleNexus
<Mutex
> gNotificationLock
;
83 ModuleNexus
<SharedMemoryClientMaker
> gMemoryClient
;
85 class NotificationPort
: public MachPlusPlus::CFAutoPort
88 SharedMemoryClient
*mClient
;
90 void ReceiveImplementation(u_int8_t
* buffer
, SegmentOffsetType length
, UnavailableReason ur
);
91 static void HandleRunLoopTimer(CFRunLoopTimerRef timer
, void* info
);
94 NotificationPort (mach_port_t port
);
95 virtual ~NotificationPort ();
96 virtual void receive(const MachPlusPlus::Message
&msg
);
99 NotificationPort::NotificationPort (mach_port_t mp
) : CFAutoPort (mp
)
101 mClient
= gMemoryClient ().Client ();
106 NotificationPort::~NotificationPort ()
112 void NotificationPort::ReceiveImplementation(u_int8_t
* buffer
, SegmentOffsetType length
, UnavailableReason ur
)
114 EventListenerList
& eventList
= gEventListeners();
116 // route the message to its destination
117 u_int32_t
* ptr
= (u_int32_t
*) buffer
;
119 // we have a message, do the semantics...
120 SecurityServer::NotificationDomain domain
= (SecurityServer::NotificationDomain
) OSSwapBigToHostInt32 (*ptr
++);
121 SecurityServer::NotificationEvent event
= (SecurityServer::NotificationEvent
) OSSwapBigToHostInt32 (*ptr
++);
122 CssmData
data ((u_int8_t
*) ptr
, buffer
+ length
- (u_int8_t
*) ptr
);
124 EventListenerList::iterator it
= eventList
.begin ();
125 while (it
!= eventList
.end ())
129 EventPointer ep
= *it
++;
130 if (ep
->GetDomain () == domain
&&
131 (ep
->GetMask () & (1 << event
)) != 0)
133 ep
->consume (domain
, event
, data
);
138 if (e
.error
!= CSSM_ERRCODE_INTERNAL_ERROR
)
148 typedef void (^NotificationBlock
)();
152 void NotificationPort::HandleRunLoopTimer(CFRunLoopTimerRef timer
, void* info
)
154 // reconstruct our context and call it
155 NotificationBlock nb
= (NotificationBlock
) info
;
160 CFRunLoopTimerInvalidate(timer
);
166 void NotificationPort::receive (const MachPlusPlus::Message
&msg
)
169 Read each notification received and post a timer for each with an expiration of
170 zero. I'd prefer to use a notification here, but I can't because, according to
171 the documentation, each application may only have one notification center and
172 the main application should have the right to pick the one it needs.
175 SegmentOffsetType length
;
176 UnavailableReason ur
;
182 u_int8_t
*buffer
= new u_int8_t
[kSharedMemoryPoolSize
];
185 StLock
<Mutex
> lock (gNotificationLock ());
186 result
= mClient
->ReadMessage(buffer
, length
, ur
);
194 // make a block that contains our data
195 NotificationBlock nb
=
197 ReceiveImplementation(buffer
, length
, ur
);
204 // set up to run the next time the run loop fires
205 CFRunLoopTimerContext ctx
;
206 memset(&ctx
, 0, sizeof(ctx
));
209 // make a run loop timer
210 CFRunLoopTimerRef timerRef
=
211 CFRunLoopTimerCreate(NULL
, CFAbsoluteTimeGetCurrent(), 0,
212 0, 0, NotificationPort::HandleRunLoopTimer
, &ctx
);
214 // install it to be run.
215 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timerRef
, kCFRunLoopDefaultMode
);
224 NotificationPort
*mNotificationPort
;
234 ThreadNotifier::ThreadNotifier()
235 : mNotificationPort(NULL
)
238 if (notify_register_mach_port (GetNotificationName (), &mp
, 0, &mNotifyToken
) == NOTIFY_STATUS_OK
) {
239 mNotificationPort
= new NotificationPort (mp
);
240 mNotificationPort
->enable ();
246 ThreadNotifier::~ThreadNotifier()
248 if (mNotificationPort
) {
249 notify_cancel (mNotifyToken
);
250 delete mNotificationPort
;
256 ModuleNexus
<ThreadNexus
<ThreadNotifier
> > threadInfo
;
260 static void InitializeNotifications ()
262 threadInfo()(); // cause the notifier for this thread to initialize
267 EventListener::EventListener (NotificationDomain domain
, NotificationMask eventMask
)
268 : mDomain (domain
), mMask (eventMask
)
270 // make sure that notifications are turned on.
271 InitializeNotifications ();
276 // StopNotification() is needed on destruction; everyone else cleans up after themselves.
278 EventListener::~EventListener ()
280 StLock
<Mutex
> lock (gNotificationLock ());
282 // find the listener in the list and remove it
283 EventListenerList::iterator it
= std::find (gEventListeners ().begin (),
284 gEventListeners ().end (),
286 if (it
!= gEventListeners ().end ())
288 gEventListeners ().erase (it
);
294 // get rid of the pure virtual
295 void EventListener::consume(NotificationDomain
, NotificationEvent
, const Security::CssmData
&)
301 void EventListener::FinishedInitialization(EventListener
*eventListener
)
303 StLock
<Mutex
> lock (gNotificationLock ());
304 gEventListeners().push_back (eventListener
);
309 } // end namespace SecurityServer
310 } // end namespace Security