vfs: check userland buffers before reading them.
[haiku.git] / src / system / kernel / Notifications.cpp
blob0673cbaf84412a3152ec195dd2629d3a6f0014b5
1 /*
2 * Copyright 2007-2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Axel Dörfler, axeld@pinc-software.de
7 * Ingo Weinhold, bonefish@cs.tu-berlin.de
8 */
11 #include <Notifications.h>
13 #include <new>
15 #include <team.h>
18 #ifdef _KERNEL_MODE
20 static const char* kEventMaskString = "event mask";
22 NotificationManager NotificationManager::sManager;
24 #endif
27 // #pragma mark - NotificationListener
30 NotificationListener::~NotificationListener()
35 void
36 NotificationListener::EventOccurred(NotificationService& service,
37 const KMessage* event)
42 void
43 NotificationListener::AllListenersNotified(NotificationService& service)
48 bool
49 NotificationListener::operator==(const NotificationListener& other) const
51 return &other == this;
55 // #pragma mark - UserMessagingMessageSender
58 #ifdef _KERNEL_MODE
61 UserMessagingMessageSender::UserMessagingMessageSender()
63 fMessage(NULL),
64 fTargetCount(0)
69 void
70 UserMessagingMessageSender::SendMessage(const KMessage* message, port_id port,
71 int32 token)
73 if ((message != fMessage && fMessage != NULL)
74 || fTargetCount == MAX_MESSAGING_TARGET_COUNT) {
75 FlushMessage();
78 fMessage = message;
79 fTargets[fTargetCount].port = port;
80 fTargets[fTargetCount].token = token;
81 fTargetCount++;
85 void
86 UserMessagingMessageSender::FlushMessage()
88 if (fMessage != NULL && fTargetCount > 0) {
89 send_message(fMessage->Buffer(), fMessage->ContentSize(),
90 fTargets, fTargetCount);
93 fMessage = NULL;
94 fTargetCount = 0;
98 // #pragma mark - UserMessagingListener
101 UserMessagingListener::UserMessagingListener(UserMessagingMessageSender& sender,
102 port_id port, int32 token)
104 fSender(sender),
105 fPort(port),
106 fToken(token)
111 UserMessagingListener::~UserMessagingListener()
116 void
117 UserMessagingListener::EventOccurred(NotificationService& service,
118 const KMessage* event)
120 fSender.SendMessage(event, fPort, fToken);
124 void
125 UserMessagingListener::AllListenersNotified(NotificationService& service)
127 fSender.FlushMessage();
131 // #pragma mark - NotificationService
134 NotificationService::~NotificationService()
139 // #pragma mark - default_listener
142 default_listener::~default_listener()
144 // Only delete the listener if it's one of ours
145 if (dynamic_cast<UserMessagingListener*>(listener) != NULL) {
146 delete listener;
151 // #pragma mark - DefaultNotificationService
154 DefaultNotificationService::DefaultNotificationService(const char* name)
156 fName(name)
158 recursive_lock_init(&fLock, name);
162 DefaultNotificationService::~DefaultNotificationService()
164 recursive_lock_destroy(&fLock);
168 /*! \brief Notifies all registered listeners.
169 \param event The message defining the event
170 \param eventMask Only listeners with an event mask sharing at least one
171 common bit with this mask will receive the event.
173 void
174 DefaultNotificationService::NotifyLocked(const KMessage& event, uint32 eventMask)
176 // Note: The following iterations support that the listener removes itself
177 // in the hook method. That's a property of the DoublyLinkedList iterator.
179 // notify all listeners about the event
180 DefaultListenerList::Iterator iterator = fListeners.GetIterator();
181 while (default_listener* listener = iterator.Next()) {
182 if ((eventMask & listener->eventMask) != 0)
183 listener->listener->EventOccurred(*this, &event);
186 // notify all listeners that all listeners have been notified
187 iterator = fListeners.GetIterator();
188 while (default_listener* listener = iterator.Next()) {
189 if ((eventMask & listener->eventMask) != 0)
190 listener->listener->AllListenersNotified(*this);
195 status_t
196 DefaultNotificationService::AddListener(const KMessage* eventSpecifier,
197 NotificationListener& notificationListener)
199 if (eventSpecifier == NULL)
200 return B_BAD_VALUE;
202 uint32 eventMask;
203 status_t status = ToEventMask(*eventSpecifier, eventMask);
204 if (status != B_OK)
205 return status;
207 default_listener* listener = new(std::nothrow) default_listener;
208 if (listener == NULL)
209 return B_NO_MEMORY;
211 listener->eventMask = eventMask;
212 listener->team = -1;
213 listener->listener = &notificationListener;
215 RecursiveLocker _(fLock);
216 if (fListeners.IsEmpty())
217 FirstAdded();
218 fListeners.Add(listener);
220 return B_OK;
224 status_t
225 DefaultNotificationService::UpdateListener(const KMessage* eventSpecifier,
226 NotificationListener& notificationListener)
228 return B_NOT_SUPPORTED;
232 status_t
233 DefaultNotificationService::RemoveListener(const KMessage* eventSpecifier,
234 NotificationListener& notificationListener)
236 RecursiveLocker _(fLock);
238 DefaultListenerList::Iterator iterator = fListeners.GetIterator();
239 while (default_listener* listener = iterator.Next()) {
240 if (listener->listener == &notificationListener) {
241 iterator.Remove();
242 delete listener;
244 if (fListeners.IsEmpty())
245 LastRemoved();
246 return B_OK;
250 return B_ENTRY_NOT_FOUND;
254 status_t
255 DefaultNotificationService::Register()
257 return NotificationManager::Manager().RegisterService(*this);
261 void
262 DefaultNotificationService::Unregister()
264 NotificationManager::Manager().UnregisterService(*this);
268 status_t
269 DefaultNotificationService::ToEventMask(const KMessage& eventSpecifier,
270 uint32& eventMask)
272 return eventSpecifier.FindInt32("event mask", (int32*)&eventMask);
276 void
277 DefaultNotificationService::FirstAdded()
282 void
283 DefaultNotificationService::LastRemoved()
288 // #pragma mark - DefaultUserNotificationService
291 DefaultUserNotificationService::DefaultUserNotificationService(const char* name)
292 : DefaultNotificationService(name)
294 NotificationManager::Manager().AddListener("teams", TEAM_REMOVED, *this);
298 DefaultUserNotificationService::~DefaultUserNotificationService()
300 NotificationManager::Manager().RemoveListener("teams", NULL, *this);
304 status_t
305 DefaultUserNotificationService::AddListener(const KMessage* eventSpecifier,
306 NotificationListener& listener)
308 if (eventSpecifier == NULL)
309 return B_BAD_VALUE;
311 uint32 eventMask = eventSpecifier->GetInt32(kEventMaskString, 0);
313 return _AddListener(eventMask, listener);
317 status_t
318 DefaultUserNotificationService::UpdateListener(const KMessage* eventSpecifier,
319 NotificationListener& notificationListener)
321 if (eventSpecifier == NULL)
322 return B_BAD_VALUE;
324 uint32 eventMask = eventSpecifier->GetInt32(kEventMaskString, 0);
325 bool addEvents = eventSpecifier->GetBool("add events", false);
327 RecursiveLocker _(fLock);
329 DefaultListenerList::Iterator iterator = fListeners.GetIterator();
330 while (default_listener* listener = iterator.Next()) {
331 if (*listener->listener == notificationListener) {
332 if (addEvents)
333 listener->eventMask |= eventMask;
334 else
335 listener->eventMask = eventMask;
336 return B_OK;
340 return B_ENTRY_NOT_FOUND;
344 status_t
345 DefaultUserNotificationService::RemoveListener(const KMessage* eventSpecifier,
346 NotificationListener& notificationListener)
348 RecursiveLocker _(fLock);
350 DefaultListenerList::Iterator iterator = fListeners.GetIterator();
351 while (default_listener* listener = iterator.Next()) {
352 if (listener->listener == &notificationListener) {
353 iterator.Remove();
354 delete listener;
355 return B_OK;
359 return B_ENTRY_NOT_FOUND;
363 status_t
364 DefaultUserNotificationService::RemoveUserListeners(port_id port, uint32 token)
366 UserMessagingListener userListener(fSender, port, token);
368 RecursiveLocker _(fLock);
370 DefaultListenerList::Iterator iterator = fListeners.GetIterator();
371 while (default_listener* listener = iterator.Next()) {
372 if (*listener->listener == userListener) {
373 iterator.Remove();
374 delete listener;
376 if (fListeners.IsEmpty())
377 LastRemoved();
378 return B_OK;
382 return B_ENTRY_NOT_FOUND;
386 status_t
387 DefaultUserNotificationService::UpdateUserListener(uint32 eventMask,
388 port_id port, uint32 token)
390 UserMessagingListener userListener(fSender, port, token);
392 RecursiveLocker _(fLock);
394 DefaultListenerList::Iterator iterator = fListeners.GetIterator();
395 while (default_listener* listener = iterator.Next()) {
396 if (*listener->listener == userListener) {
397 listener->eventMask |= eventMask;
398 return B_OK;
402 UserMessagingListener* copiedListener
403 = new(std::nothrow) UserMessagingListener(userListener);
404 if (copiedListener == NULL)
405 return B_NO_MEMORY;
407 status_t status = _AddListener(eventMask, *copiedListener);
408 if (status != B_OK)
409 delete copiedListener;
411 return status;
415 void
416 DefaultUserNotificationService::EventOccurred(NotificationService& service,
417 const KMessage* event)
419 int32 eventCode = event->GetInt32("event", -1);
420 team_id team = event->GetInt32("team", -1);
422 if (eventCode == TEAM_REMOVED && team >= B_OK) {
423 // check if we have any listeners from that team, and remove them
424 RecursiveLocker _(fLock);
426 DefaultListenerList::Iterator iterator = fListeners.GetIterator();
427 while (default_listener* listener = iterator.Next()) {
428 if (listener->team == team) {
429 iterator.Remove();
430 delete listener;
437 void
438 DefaultUserNotificationService::AllListenersNotified(
439 NotificationService& service)
444 status_t
445 DefaultUserNotificationService::_AddListener(uint32 eventMask,
446 NotificationListener& notificationListener)
448 default_listener* listener = new(std::nothrow) default_listener;
449 if (listener == NULL)
450 return B_NO_MEMORY;
452 listener->eventMask = eventMask;
453 listener->team = team_get_current_team_id();
454 listener->listener = &notificationListener;
456 RecursiveLocker _(fLock);
457 if (fListeners.IsEmpty())
458 FirstAdded();
459 fListeners.Add(listener);
461 return B_OK;
465 // #pragma mark - NotificationManager
468 /*static*/ NotificationManager&
469 NotificationManager::Manager()
471 return sManager;
475 /*static*/ status_t
476 NotificationManager::CreateManager()
478 new(&sManager) NotificationManager;
479 return sManager._Init();
483 NotificationManager::NotificationManager()
488 NotificationManager::~NotificationManager()
493 status_t
494 NotificationManager::_Init()
496 mutex_init(&fLock, "notification manager");
498 return fServiceHash.Init();
502 NotificationService*
503 NotificationManager::_ServiceFor(const char* name)
505 return fServiceHash.Lookup(name);
509 status_t
510 NotificationManager::RegisterService(NotificationService& service)
512 MutexLocker _(fLock);
514 if (_ServiceFor(service.Name()))
515 return B_NAME_IN_USE;
517 status_t status = fServiceHash.Insert(&service);
518 if (status == B_OK)
519 service.AcquireReference();
521 return status;
525 void
526 NotificationManager::UnregisterService(NotificationService& service)
528 MutexLocker _(fLock);
529 fServiceHash.Remove(&service);
530 service.ReleaseReference();
534 status_t
535 NotificationManager::AddListener(const char* serviceName,
536 uint32 eventMask, NotificationListener& listener)
538 char buffer[96];
539 KMessage specifier;
540 specifier.SetTo(buffer, sizeof(buffer), 0);
541 specifier.AddInt32(kEventMaskString, eventMask);
543 return AddListener(serviceName, &specifier, listener);
547 status_t
548 NotificationManager::AddListener(const char* serviceName,
549 const KMessage* eventSpecifier, NotificationListener& listener)
551 MutexLocker locker(fLock);
552 NotificationService* service = _ServiceFor(serviceName);
553 if (service == NULL)
554 return B_NAME_NOT_FOUND;
556 BReference<NotificationService> reference(service);
557 locker.Unlock();
559 return service->AddListener(eventSpecifier, listener);
563 status_t
564 NotificationManager::UpdateListener(const char* serviceName,
565 uint32 eventMask, NotificationListener& listener)
567 char buffer[96];
568 KMessage specifier;
569 specifier.SetTo(buffer, sizeof(buffer), 0);
570 specifier.AddInt32(kEventMaskString, eventMask);
572 return UpdateListener(serviceName, &specifier, listener);
576 status_t
577 NotificationManager::UpdateListener(const char* serviceName,
578 const KMessage* eventSpecifier, NotificationListener& listener)
580 MutexLocker locker(fLock);
581 NotificationService* service = _ServiceFor(serviceName);
582 if (service == NULL)
583 return B_NAME_NOT_FOUND;
585 BReference<NotificationService> reference(service);
586 locker.Unlock();
588 return service->UpdateListener(eventSpecifier, listener);
592 status_t
593 NotificationManager::RemoveListener(const char* serviceName,
594 const KMessage* eventSpecifier, NotificationListener& listener)
596 MutexLocker locker(fLock);
597 NotificationService* service = _ServiceFor(serviceName);
598 if (service == NULL)
599 return B_NAME_NOT_FOUND;
601 BReference<NotificationService> reference(service);
602 locker.Unlock();
604 return service->RemoveListener(eventSpecifier, listener);
608 // #pragma mark -
611 extern "C" void
612 notifications_init(void)
614 status_t status = NotificationManager::CreateManager();
615 if (status < B_OK) {
616 panic("Creating the notification manager failed: %s\n",
617 strerror(status));
622 #endif // _KERNEL_MODE