]> git.saurik.com Git - apple/security.git/blob - securityd/src/notifications.cpp
Security-57740.1.18.tar.gz
[apple/security.git] / securityd / src / notifications.cpp
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 #include <security_utilities/casts.h>
35
36
37 Listener::ListenerMap& Listener::listeners = *(new Listener::ListenerMap);
38 Mutex Listener::setLock(Mutex::recursive);
39
40
41 //
42 // Listener basics
43 //
44 Listener::Listener(NotificationDomain dom, NotificationMask evs, mach_port_t port)
45 : domain(dom), events(evs)
46 {
47 assert(events); // what's the point?
48
49 // register in listener set
50 StLock<Mutex> _(setLock);
51 listeners.insert(ListenerMap::value_type(port, this));
52
53 secinfo("notify", "%p created for domain 0x%x events 0x%x port %d",
54 this, dom, evs, port);
55 }
56
57 Listener::~Listener()
58 {
59 secinfo("notify", "%p destroyed", this);
60 }
61
62
63 //
64 // Send a notification to all registered listeners
65 //
66 void Listener::notify(NotificationDomain domain,
67 NotificationEvent event, const CssmData &data)
68 {
69 RefPointer<Notification> message = new Notification(domain, event, 0, data);
70 StLock<Mutex> _(setLock);
71 sendNotification(message);
72 }
73
74 void Listener::notify(NotificationDomain domain,
75 NotificationEvent event, uint32 sequence, const CssmData &data)
76 {
77 Connection &current = Server::active().connection();
78 RefPointer<Notification> message = new Notification(domain, event, sequence, data);
79 if (current.inSequence(message)) {
80 StLock<Mutex> _(setLock);
81 sendNotification(message);
82 while (RefPointer<Notification> next = current.popNotification())
83 sendNotification(next);
84 }
85 }
86
87 void Listener::sendNotification(Notification *message)
88 {
89 for (ListenerMap::const_iterator it = listeners.begin();
90 it != listeners.end(); it++) {
91 Listener *listener = it->second;
92 if (listener->domain == kNotificationDomainAll || (message->domain == listener->domain && listener->wants(message->event)))
93 listener->notifyMe(message);
94 }
95 }
96
97
98 //
99 // Handle a port death or deallocation by removing all Listeners using that port.
100 // Returns true iff we had one.
101 //
102 bool Listener::remove(Port port)
103 {
104 typedef ListenerMap::iterator Iterator;
105 StLock<Mutex> _(setLock);
106 pair<Iterator, Iterator> range = listeners.equal_range(port);
107 if (range.first == range.second)
108 return false; // not one of ours
109
110 assert(range.first != listeners.end());
111 secinfo("notify", "remove port %d", port.port());
112 #if !defined(NDEBUG)
113 for (Iterator it = range.first; it != range.second; it++) {
114 assert(it->first == port);
115 secinfo("notify", "%p listener removed", it->second.get());
116 }
117 #endif //NDEBUG
118 listeners.erase(range.first, range.second);
119 port.destroy();
120 return true; // got it
121 }
122
123
124 //
125 // Notification message objects
126 //
127 Listener::Notification::Notification(NotificationDomain inDomain,
128 NotificationEvent inEvent, uint32 seq, const CssmData &inData)
129 : domain(inDomain), event(inEvent), sequence(seq), data(Allocator::standard(), inData)
130 {
131 secinfo("notify", "%p notification created domain 0x%x event %d seq %d",
132 this, domain, event, sequence);
133 }
134
135 Listener::Notification::~Notification()
136 {
137 secinfo("notify", "%p notification done domain 0x%x event %d seq %d",
138 this, domain, event, sequence);
139 }
140
141
142 //
143 // Jitter buffering
144 //
145 bool Listener::JitterBuffer::inSequence(Notification *message)
146 {
147 if (message->sequence == mNotifyLast + 1) { // next in sequence
148 mNotifyLast++; // record next sequence
149 return true; // go ahead
150 } else {
151 secinfo("notify-jit", "%p out of sequence (last %d got %d); buffering",
152 message, mNotifyLast, message->sequence);
153 mBuffer[message->sequence] = message; // save for later
154 return false; // hold your fire
155 }
156 }
157
158 RefPointer<Listener::Notification> Listener::JitterBuffer::popNotification()
159 {
160 JBuffer::iterator it = mBuffer.find(mNotifyLast + 1); // have next message?
161 if (it == mBuffer.end())
162 return NULL; // nothing here
163 else {
164 RefPointer<Notification> result = it->second; // save value
165 mBuffer.erase(it); // remove from buffer
166 secinfo("notify-jit", "%p retrieved from jitter buffer", result.get());
167 return result; // return it
168 }
169 }
170
171 /*
172 * Shared memory listener
173 */
174
175
176 SharedMemoryListener::SharedMemoryListener(const char* segmentName, SegmentOffsetType segmentSize) :
177 Listener (kNotificationDomainAll, kNotificationAllEvents),
178 SharedMemoryServer (segmentName, segmentSize),
179 mActive (false)
180 {
181 if (segmentName == NULL)
182 {
183 secerror("Attempted to start securityd with a NULL segmentName");
184 abort();
185 }
186 }
187
188 SharedMemoryListener::~SharedMemoryListener ()
189 {
190 }
191
192 const double kServerWait = 0.005; // time in seconds before clients will be notified that data is available
193
194 void SharedMemoryListener::notifyMe(Notification* notification)
195 {
196 const void* data = notification->data.data();
197 size_t length = notification->data.length();
198 /* enforce a maximum size of 16k for notifications */
199 if (length > 16384) return;
200
201 WriteMessage (notification->domain, notification->event, data, int_cast<size_t, UInt32>(length));
202
203 if (!mActive)
204 {
205 Server::active().setTimer (this, Time::Interval(kServerWait));
206 mActive = true;
207 }
208 }
209
210 void SharedMemoryListener::action ()
211 {
212 secinfo("notify", "Posted notification to clients.");
213 notify_post (mSegmentName.c_str ());
214 mActive = false;
215 }