]> git.saurik.com Git - apple/security.git/blame - securityd/src/notifications.cpp
Security-57336.10.29.tar.gz
[apple/security.git] / securityd / src / notifications.cpp
CommitLineData
d8f41ccd
A
1/*
2 * Copyright (c) 2000-2004,2006,2008 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25//
26// notifications - handling of securityd-gated notification messages
27//
28#include <notify.h>
29
30#include "notifications.h"
31#include "server.h"
32#include "connection.h"
33#include <securityd_client/ucspNotify.h>
34
35
36Listener::ListenerMap& Listener::listeners = *(new Listener::ListenerMap);
37Mutex Listener::setLock(Mutex::recursive);
38
39
40//
41// Listener basics
42//
43Listener::Listener(NotificationDomain dom, NotificationMask evs, mach_port_t port)
44 : domain(dom), events(evs)
45{
46 assert(events); // what's the point?
47
48 // register in listener set
49 StLock<Mutex> _(setLock);
50 listeners.insert(ListenerMap::value_type(port, this));
51
52 secdebug("notify", "%p created for domain 0x%x events 0x%x port %d",
53 this, dom, evs, port);
54}
55
56Listener::~Listener()
57{
58 secdebug("notify", "%p destroyed", this);
59}
60
61
62//
63// Send a notification to all registered listeners
64//
65void Listener::notify(NotificationDomain domain,
66 NotificationEvent event, const CssmData &data)
67{
68 RefPointer<Notification> message = new Notification(domain, event, 0, data);
69 StLock<Mutex> _(setLock);
70 sendNotification(message);
71}
72
73void Listener::notify(NotificationDomain domain,
74 NotificationEvent event, uint32 sequence, const CssmData &data)
75{
76 Connection &current = 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);
83 }
84}
85
86void Listener::sendNotification(Notification *message)
87{
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);
93 }
94}
95
96
97//
98// Handle a port death or deallocation by removing all Listeners using that port.
99// Returns true iff we had one.
100//
101bool Listener::remove(Port port)
102{
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
108
109 assert(range.first != listeners.end());
110 secdebug("notify", "remove port %d", port.port());
111#if !defined(NDEBUG)
112 for (Iterator it = range.first; it != range.second; it++) {
113 assert(it->first == port);
114 secdebug("notify", "%p listener removed", it->second.get());
115 }
116#endif //NDEBUG
117 listeners.erase(range.first, range.second);
118 port.destroy();
119 return true; // got it
120}
121
122
123//
124// Notification message objects
125//
126Listener::Notification::Notification(NotificationDomain inDomain,
127 NotificationEvent inEvent, uint32 seq, const CssmData &inData)
128 : domain(inDomain), event(inEvent), sequence(seq), data(Allocator::standard(), inData)
129{
130 secdebug("notify", "%p notification created domain 0x%lx event %ld seq %ld",
131 this, domain, event, sequence);
132}
133
134Listener::Notification::~Notification()
135{
136 secdebug("notify", "%p notification done domain 0x%lx event %ld seq %ld",
137 this, domain, event, sequence);
138}
139
140
141//
142// Jitter buffering
143//
144bool Listener::JitterBuffer::inSequence(Notification *message)
145{
146 if (message->sequence == mNotifyLast + 1) { // next in sequence
147 mNotifyLast++; // record next sequence
148 return true; // go ahead
149 } else {
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
154 }
155}
156
157RefPointer<Listener::Notification> Listener::JitterBuffer::popNotification()
158{
159 JBuffer::iterator it = mBuffer.find(mNotifyLast + 1); // have next message?
160 if (it == mBuffer.end())
161 return NULL; // nothing here
162 else {
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
167 }
168}
169
170/*
171 * Shared memory listener
172 */
173
174
175SharedMemoryListener::SharedMemoryListener(const char* segmentName, SegmentOffsetType segmentSize) :
176 Listener (kNotificationDomainAll, kNotificationAllEvents),
177 SharedMemoryServer (segmentName, segmentSize),
178 mActive (false)
179{
180 if (segmentName == NULL)
181 {
182 secdebug("notify", "Attempted to start securityd with a NULL segmentName");
183 exit(1);
184 }
185}
186
187SharedMemoryListener::~SharedMemoryListener ()
188{
189}
190
191const double kServerWait = 0.005; // time in seconds before clients will be notified that data is available
192
193void SharedMemoryListener::notifyMe(Notification* notification)
194{
195 const void* data = notification->data.data();
196 UInt32 length = notification->data.length();
197 WriteMessage (notification->domain, notification->event, data, length);
198
199 if (!mActive)
200 {
201 Server::active().setTimer (this, Time::Interval(kServerWait));
202 mActive = true;
203 }
204}
205
206void SharedMemoryListener::action ()
207{
208 secdebug("notify", "Posted notification to clients.");
209 notify_post (mSegmentName.c_str ());
210 mActive = false;
211}