2 * Copyright (c) 2000-2004,2006,2008 Apple 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@
26 // notifications - handling of securityd-gated notification messages
30 #include "notifications.h"
32 #include "connection.h"
33 #include <securityd_client/ucspNotify.h>
36 Listener::ListenerMap
& Listener::listeners
= *(new Listener::ListenerMap
);
37 Mutex
Listener::setLock(Mutex::recursive
);
43 Listener::Listener(NotificationDomain dom
, NotificationMask evs
, mach_port_t port
)
44 : domain(dom
), events(evs
)
46 assert(events
); // what's the point?
48 // register in listener set
49 StLock
<Mutex
> _(setLock
);
50 listeners
.insert(ListenerMap::value_type(port
, this));
52 secdebug("notify", "%p created for domain 0x%x events 0x%x port %d",
53 this, dom
, evs
, port
);
58 secdebug("notify", "%p destroyed", this);
63 // Send a notification to all registered listeners
65 void Listener::notify(NotificationDomain domain
,
66 NotificationEvent event
, const CssmData
&data
)
68 RefPointer
<Notification
> message
= new Notification(domain
, event
, 0, data
);
69 StLock
<Mutex
> _(setLock
);
70 sendNotification(message
);
73 void Listener::notify(NotificationDomain domain
,
74 NotificationEvent event
, uint32 sequence
, const CssmData
&data
)
76 Connection
¤t
= Server::active().connection();
77 RefPointer
<Notification
> message
= new Notification(domain
, event
, sequence
, data
);
78 if (current
.inSequence(message
)) {
79 StLock
<Mutex
> _(setLock
);
80 sendNotification(message
);
81 while (RefPointer
<Notification
> next
= current
.popNotification())
82 sendNotification(next
);
86 void Listener::sendNotification(Notification
*message
)
88 for (ListenerMap::const_iterator it
= listeners
.begin();
89 it
!= listeners
.end(); it
++) {
90 Listener
*listener
= it
->second
;
91 if (listener
->domain
== kNotificationDomainAll
|| (message
->domain
== listener
->domain
&& listener
->wants(message
->event
)))
92 listener
->notifyMe(message
);
98 // Handle a port death or deallocation by removing all Listeners using that port.
99 // Returns true iff we had one.
101 bool Listener::remove(Port port
)
103 typedef ListenerMap::iterator Iterator
;
104 StLock
<Mutex
> _(setLock
);
105 pair
<Iterator
, Iterator
> range
= listeners
.equal_range(port
);
106 if (range
.first
== range
.second
)
107 return false; // not one of ours
109 assert(range
.first
!= listeners
.end());
110 secdebug("notify", "remove port %d", port
.port());
112 for (Iterator it
= range
.first
; it
!= range
.second
; it
++) {
113 assert(it
->first
== port
);
114 secdebug("notify", "%p listener removed", it
->second
.get());
117 listeners
.erase(range
.first
, range
.second
);
119 return true; // got it
124 // Notification message objects
126 Listener::Notification::Notification(NotificationDomain inDomain
,
127 NotificationEvent inEvent
, uint32 seq
, const CssmData
&inData
)
128 : domain(inDomain
), event(inEvent
), sequence(seq
), data(Allocator::standard(), inData
)
130 secdebug("notify", "%p notification created domain 0x%lx event %ld seq %ld",
131 this, domain
, event
, sequence
);
134 Listener::Notification::~Notification()
136 secdebug("notify", "%p notification done domain 0x%lx event %ld seq %ld",
137 this, domain
, event
, sequence
);
144 bool Listener::JitterBuffer::inSequence(Notification
*message
)
146 if (message
->sequence
== mNotifyLast
+ 1) { // next in sequence
147 mNotifyLast
++; // record next sequence
148 return true; // go ahead
150 secdebug("notify-jit", "%p out of sequence (last %ld got %ld); buffering",
151 message
, mNotifyLast
, message
->sequence
);
152 mBuffer
[message
->sequence
] = message
; // save for later
153 return false; // hold your fire
157 RefPointer
<Listener::Notification
> Listener::JitterBuffer::popNotification()
159 JBuffer::iterator it
= mBuffer
.find(mNotifyLast
+ 1); // have next message?
160 if (it
== mBuffer
.end())
161 return NULL
; // nothing here
163 RefPointer
<Notification
> result
= it
->second
; // save value
164 mBuffer
.erase(it
); // remove from buffer
165 secdebug("notify-jit", "%p retrieved from jitter buffer", result
.get());
166 return result
; // return it
171 * Shared memory listener
175 SharedMemoryListener::SharedMemoryListener(const char* segmentName
, SegmentOffsetType segmentSize
) :
176 Listener (kNotificationDomainAll
, kNotificationAllEvents
),
177 SharedMemoryServer (segmentName
, segmentSize
),
180 if (segmentName
== NULL
)
182 secdebug("notify", "Attempted to start securityd with a NULL segmentName");
187 SharedMemoryListener::~SharedMemoryListener ()
191 const double kServerWait
= 0.005; // time in seconds before clients will be notified that data is available
193 void SharedMemoryListener::notifyMe(Notification
* notification
)
195 const void* data
= notification
->data
.data();
196 UInt32 length
= notification
->data
.length();
197 /* enforce a maximum size of 16k for notifications */
198 if (length
> 16384) return;
200 WriteMessage (notification
->domain
, notification
->event
, data
, length
);
204 Server::active().setTimer (this, Time::Interval(kServerWait
));
209 void SharedMemoryListener::action ()
211 secdebug("notify", "Posted notification to clients.");
212 notify_post (mSegmentName
.c_str ());