* Work-in-progress of a network notification implementation.

* Compiles, but doesn't work at all yet. For those who wonder: the networking
  notifications are put into a separate module, so that the network stack can
  be unloaded without losing connection, IOW user applications will continue
  to retrieve notifications when the stack is loaded again.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28790 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2008-12-09 23:16:10 +00:00
parent 311635a1ab
commit e6dd439f7c
8 changed files with 502 additions and 1 deletions

View File

@ -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 <module.h>
#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 <Messenger.h>
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

View File

@ -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 ;

View File

@ -0,0 +1,8 @@
SubDir HAIKU_TOP src add-ons kernel network notifications ;
UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ;
UsePrivateHeaders net shared ;
KernelAddon <net>notifications :
notifications.cpp
;

View File

@ -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 <net_notifications.h>
//#include <messaging.h>
#include <Notifications.h>
#include <util/KMessage.h>
// TODO: add generic syscall interface
static UserMessagingMessageSender sNotificationSender;
struct net_listener : public DoublyLinkedListLinkImpl<net_listener> {
~net_listener();
uint32 flags;
NotificationListener* listener;
};
typedef DoublyLinkedList<net_listener> 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<const UserNetListener*>(&_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<UserNetListener*>(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 == &notificationListener) {
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 = &notificationListener;
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
};

View File

@ -21,6 +21,7 @@ KernelAddon stack :
interfaces.cpp
net_buffer.cpp
net_socket.cpp
notifications.cpp
link.cpp
radix.c
routes.cpp

View File

@ -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 <net_notifications.h>
#include <util/KMessage.h>
#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);
}

View File

@ -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);

View File

@ -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();