diff --git a/headers/private/net/net_notifications.h b/headers/private/net/net_notifications.h new file mode 100644 index 0000000000..4c4acfe569 --- /dev/null +++ b/headers/private/net/net_notifications.h @@ -0,0 +1,65 @@ +/* + * Copyright 2008, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef NET_NOTIFICATIONS_H +#define NET_NOTIFICATIONS_H + + +#include + + +#define NET_NOTIFICATIONS_MODULE_NAME "network/notifications/v1" + +namespace BPrivate { + class KMessage; +}; + +struct net_notifications_module_info { + module_info info; + + void (*send_notification)(const BPrivate::KMessage* event); +}; + +// generic syscall interface +#define NET_NOTIFICATIONS_SYSCALLS "network/notifications" + +#define NET_NOTIFICATIONS_START_WATCHING 1 +#define NET_NOTIFICATIONS_STOP_WATCHING 2 + +struct net_notifications_control { + uint32 flags; + port_id port; + uint32 token; +}; + +// TODO: the following part of this header should end up in a public header +// some day! + +#define B_NETWORK_INTERFACE_ADDED 1 +#define B_NETWORK_INTERFACE_REMOVED 2 +#define B_NETWORK_INTERFACE_CHANGED 3 +#define B_NETWORK_DEVICE_LINK_CHANGED 4 +// TODO: add routes, stack unloaded/loaded, ... events + +enum { + B_WATCH_NETWORK_INTERFACE_CHANGES = 0x0001, + B_WATCH_NETWORK_LINK_CHANGES = 0x0002 +}; + +#define B_NETWORK_MONITOR '_NTN' + +#ifndef _KERNEL_MODE +# include + +status_t start_watching_network(uint32 flags, const BMessenger& target); +status_t start_watching_network(uint32 flags, const BHandler* handler, + const BLooper* looper = NULL); + +status_t stop_watching_network(const BMessenger& target); +status_t stop_watching_network(const BHandler* handler, + const BLooper* looper = NULL); + +#endif // _KERNEL_MODE + +#endif // NET_NOTIFICATIONS_H diff --git a/src/add-ons/kernel/network/Jamfile b/src/add-ons/kernel/network/Jamfile index 25e6f30907..66d4448e41 100644 --- a/src/add-ons/kernel/network/Jamfile +++ b/src/add-ons/kernel/network/Jamfile @@ -2,5 +2,6 @@ SubDir HAIKU_TOP src add-ons kernel network ; SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols ; SubInclude HAIKU_TOP src add-ons kernel network devices ; +SubInclude HAIKU_TOP src add-ons kernel network notifications ; SubInclude HAIKU_TOP src add-ons kernel network protocols ; SubInclude HAIKU_TOP src add-ons kernel network stack ; diff --git a/src/add-ons/kernel/network/notifications/Jamfile b/src/add-ons/kernel/network/notifications/Jamfile new file mode 100644 index 0000000000..75870ac48f --- /dev/null +++ b/src/add-ons/kernel/network/notifications/Jamfile @@ -0,0 +1,8 @@ +SubDir HAIKU_TOP src add-ons kernel network notifications ; + +UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ; +UsePrivateHeaders net shared ; + +KernelAddon notifications : + notifications.cpp +; diff --git a/src/add-ons/kernel/network/notifications/notifications.cpp b/src/add-ons/kernel/network/notifications/notifications.cpp new file mode 100644 index 0000000000..c6d5ea3151 --- /dev/null +++ b/src/add-ons/kernel/network/notifications/notifications.cpp @@ -0,0 +1,309 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + +/*! Provides the networking stack notification service. */ + +#include + +//#include +#include +#include + + +// TODO: add generic syscall interface + + +static UserMessagingMessageSender sNotificationSender; + +struct net_listener : public DoublyLinkedListLinkImpl { + ~net_listener(); + + uint32 flags; + NotificationListener* listener; +}; + +typedef DoublyLinkedList ListenerList; + +class UserNetListener : public UserMessagingListener { +public: + UserNetListener(port_id port, int32 token) + : UserMessagingListener(sNotificationSender, port, token) + { + } + + bool operator==(const NotificationListener& _other) const + { + const UserNetListener* other + = dynamic_cast(&_other); + return other != NULL && other->Port() == Port() + && other->Token() == Token(); + } +}; + +class NetNotificationService : public NotificationService { +public: + NetNotificationService(); + virtual ~NetNotificationService(); + + void Notify(const KMessage& event); + + status_t AddListener(const KMessage* eventSpecifier, + NotificationListener& listener); + status_t UpdateListener(const KMessage* eventSpecifier, + NotificationListener& listener); + status_t RemoveListener(const KMessage* eventSpecifier, + NotificationListener& listener); + + status_t RemoveUserListeners(port_id port, uint32 token); + status_t UpdateUserListener(uint32 flags, + port_id port, uint32 token); + + virtual const char* Name() { return "network"; } + +private: + status_t _AddListener(uint32 flags, + NotificationListener& listener); + + recursive_lock fRecursiveLock; + ListenerList fListeners; +}; + +static NetNotificationService sNotificationService; + + +net_listener::~net_listener() +{ + if (dynamic_cast(listener) != NULL) + delete listener; +} + + +// #pragma mark - NetNotificationService + + +NetNotificationService::NetNotificationService() +{ + recursive_lock_init(&fRecursiveLock, "net notifications"); +} + + +NetNotificationService::~NetNotificationService() +{ + recursive_lock_destroy(&fRecursiveLock); +} + + +/*! \brief Notifies all registered listeners. + \param event The message defining the event +*/ +void +NetNotificationService::Notify(const KMessage& event) +{ + uint32 flags = event.GetInt32("flags", 0); + if (flags == 0) + return; + + RecursiveLocker _(fRecursiveLock); + + ListenerList::Iterator iterator = fListeners.GetIterator(); + while (net_listener* listener = iterator.Next()) { + if ((listener->flags & flags) != 0) + listener->listener->EventOccured(*this, &event); + } + + iterator = fListeners.GetIterator(); + while (net_listener* listener = iterator.Next()) { + if ((listener->flags & flags) != 0) + listener->listener->AllListenersNotified(*this); + } +} + + +status_t +NetNotificationService::AddListener(const KMessage* eventSpecifier, + NotificationListener& listener) +{ + if (eventSpecifier == NULL) + return B_BAD_VALUE; + + uint32 flags = eventSpecifier->GetInt32("flags", 0); + + return _AddListener(flags, listener); +} + + +status_t +NetNotificationService::UpdateListener(const KMessage* eventSpecifier, + NotificationListener& notificationListener) +{ + if (eventSpecifier == NULL) + return B_BAD_VALUE; + + uint32 flags = eventSpecifier->GetInt32("flags", 0); + bool addFlags = eventSpecifier->GetBool("add flags", false); + + RecursiveLocker _(fRecursiveLock); + + ListenerList::Iterator iterator = fListeners.GetIterator(); + while (net_listener* listener = iterator.Next()) { + if (*listener->listener == notificationListener) { + if (addFlags) + listener->flags |= flags; + else + listener->flags = flags; + return B_OK; + } + } + + return B_ENTRY_NOT_FOUND; +} + + +status_t +NetNotificationService::RemoveListener(const KMessage* eventSpecifier, + NotificationListener& notificationListener) +{ + RecursiveLocker _(fRecursiveLock); + + ListenerList::Iterator iterator = fListeners.GetIterator(); + while (net_listener* listener = iterator.Next()) { + if (listener->listener == ¬ificationListener) { + iterator.Remove(); + delete listener; + return B_OK; + } + } + + return B_ENTRY_NOT_FOUND; +} + + +inline status_t +NetNotificationService::RemoveUserListeners(port_id port, uint32 token) +{ + UserNetListener userListener(port, token); + + RecursiveLocker _(fRecursiveLock); + + ListenerList::Iterator iterator = fListeners.GetIterator(); + while (net_listener* listener = iterator.Next()) { + if (*listener->listener == userListener) { + iterator.Remove(); + delete listener; + return B_OK; + } + } + + return B_ENTRY_NOT_FOUND; +} + + +status_t +NetNotificationService::UpdateUserListener(uint32 flags, port_id port, + uint32 token) +{ + UserNetListener userListener(port, token); + + RecursiveLocker _(fRecursiveLock); + + ListenerList::Iterator iterator = fListeners.GetIterator(); + while (net_listener* listener = iterator.Next()) { + if (*listener->listener == userListener) { + listener->flags |= flags; + return B_OK; + } + } + + UserNetListener* copiedListener = new(std::nothrow) UserNetListener( + userListener); + if (copiedListener == NULL) + return B_NO_MEMORY; + + status_t status = _AddListener(flags, *copiedListener); + if (status != B_OK) + delete copiedListener; + + return status; +} + + +status_t +NetNotificationService::_AddListener(uint32 flags, + NotificationListener& notificationListener) +{ + net_listener* listener = new(std::nothrow) net_listener; + if (listener == NULL) + return B_NO_MEMORY; + + listener->flags = flags; + listener->listener = ¬ificationListener; + + RecursiveLocker _(fRecursiveLock); + + fListeners.Add(listener); + return B_OK; +} + + +// #pragma mark - User generic syscall + + +status_t +_user_start_watching_network(uint32 flags, port_id port, uint32 token) +{ + return sNotificationService.UpdateUserListener(flags, port, token); +} + + +status_t +_user_stop_watching_network(port_id port, uint32 token) +{ + return sNotificationService.RemoveUserListeners(port, token); +} + + +// #pragma mark - exported module API + + +static void +send_notification(const KMessage* event) +{ + sNotificationService.Notify(*event); +} + + +static status_t +notifications_std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + new(&sNotificationSender) UserMessagingMessageSender(); + new(&sNotificationService) NetNotificationService(); + return B_OK; + case B_MODULE_UNINIT: + sNotificationSender.~UserMessagingMessageSender(); + sNotificationService.~NetNotificationService(); + return B_OK; + + default: + return B_ERROR; + } +} + + +net_notifications_module_info sNotificationsModule = { + { + NET_NOTIFICATIONS_MODULE_NAME, + 0, + notifications_std_ops + }, + + send_notification +}; + +module_info* modules[] = { + (module_info*)&sNotificationsModule, + NULL +}; diff --git a/src/add-ons/kernel/network/stack/Jamfile b/src/add-ons/kernel/network/stack/Jamfile index d11bd6480f..ed7355c0fc 100644 --- a/src/add-ons/kernel/network/stack/Jamfile +++ b/src/add-ons/kernel/network/stack/Jamfile @@ -21,6 +21,7 @@ KernelAddon stack : interfaces.cpp net_buffer.cpp net_socket.cpp + notifications.cpp link.cpp radix.c routes.cpp diff --git a/src/add-ons/kernel/network/stack/notifications.cpp b/src/add-ons/kernel/network/stack/notifications.cpp new file mode 100644 index 0000000000..7b00da7869 --- /dev/null +++ b/src/add-ons/kernel/network/stack/notifications.cpp @@ -0,0 +1,100 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + +/*! Provides the stack internal notification API. + + The actual message sending happens in another module to make the + notification listeners independent from the stack status. +*/ + +#include + +#include + +#include "stack_private.h" + + +static net_notifications_module_info* sNotificationModule; + + +status_t +notify_interface_added(const char* interface) +{ + if (sNotificationModule == NULL) + return B_NOT_SUPPORTED; + + char messageBuffer[512]; + KMessage message; + message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR); + message.AddInt32("opcode", B_NETWORK_INTERFACE_ADDED); + message.AddString("interface", interface); + + return sNotificationModule->send_notification(&message); +} + + +status_t +notify_interface_removed(const char* interface) +{ + if (sNotificationModule == NULL) + return B_NOT_SUPPORTED; + + char messageBuffer[512]; + KMessage message; + message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR); + message.AddInt32("opcode", B_NETWORK_INTERFACE_REMOVED); + message.AddString("interface", interface); + + return sNotificationModule->send_notification(&message); +} + + +status_t +notify_interface_changed(const char* interface) +{ + if (sNotificationModule == NULL) + return B_NOT_SUPPORTED; + + char messageBuffer[512]; + KMessage message; + message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR); + message.AddInt32("opcode", B_NETWORK_INTERFACE_CHANGED); + message.AddString("interface", interface); + + return sNotificationModule->send_notification(&message); +} + + +status_t +notify_link_changed(const char* interface) +{ + if (sNotificationModule == NULL) + return B_NOT_SUPPORTED; + + char messageBuffer[512]; + KMessage message; + message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR); + message.AddInt32("opcode", B_NETWORK_DEVICE_LINK_CHANGED); + message.AddString("interface", interface); + + return sNotificationModule->send_notification(&message); +} + + +status_t +init_notifications() +{ + return get_module(NET_NOTIFICATIONS_MODULE_NAME, + (module_info**)&sNotificationModule); +} + + +void +uninit_notifications() +{ + if (sNotificationModule != NULL) + put_module(NET_NOTIFICATIONS_MODULE_NAME); + +} diff --git a/src/add-ons/kernel/network/stack/stack.cpp b/src/add-ons/kernel/network/stack/stack.cpp index 6f270ee6a2..0d653ced84 100644 --- a/src/add-ons/kernel/network/stack/stack.cpp +++ b/src/add-ons/kernel/network/stack/stack.cpp @@ -753,6 +753,14 @@ init_stack() if (status < B_OK) goto err2; + status = init_notifications(); + if (status < B_OK) { + // If this fails, it just means there won't be any notifications, + // it's not a fatal error. + dprintf("networking stack notifications could not be initialized: %s\n", + strerror(status)); + } + mutex_init(&sChainLock, "net chains"); mutex_init(&sInitializeChainLock, "net intialize chains"); @@ -827,6 +835,7 @@ uninit_stack() uninit_timers(); uninit_interfaces(); uninit_domains(); + uninit_notifications(); mutex_destroy(&sChainLock); mutex_destroy(&sInitializeChainLock); diff --git a/src/add-ons/kernel/network/stack/stack_private.h b/src/add-ons/kernel/network/stack/stack_private.h index f877b3e6d8..7d85bfdb2c 100644 --- a/src/add-ons/kernel/network/stack/stack_private.h +++ b/src/add-ons/kernel/network/stack/stack_private.h @@ -1,5 +1,5 @@ /* - * Copyright 2006-2007, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2008, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -33,6 +33,14 @@ status_t put_domain_protocols(net_socket *socket); status_t get_domain_datalink_protocols(net_interface *interface); status_t put_domain_datalink_protocols(net_interface *interface); +// notifications.cpp +status_t notify_interface_added(const char* interface); +status_t notify_interface_removed(const char* interface); +status_t notify_interface_changed(const char* interface); +status_t notify_link_changed(const char* interface); +status_t init_notifications(); +void uninit_notifications(); + status_t init_stack(); status_t uninit_stack();