* 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:
parent
311635a1ab
commit
e6dd439f7c
65
headers/private/net/net_notifications.h
Normal file
65
headers/private/net/net_notifications.h
Normal 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
|
@ -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 ;
|
||||
|
8
src/add-ons/kernel/network/notifications/Jamfile
Normal file
8
src/add-ons/kernel/network/notifications/Jamfile
Normal 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
|
||||
;
|
309
src/add-ons/kernel/network/notifications/notifications.cpp
Normal file
309
src/add-ons/kernel/network/notifications/notifications.cpp
Normal 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 == ¬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
|
||||
};
|
@ -21,6 +21,7 @@ KernelAddon stack :
|
||||
interfaces.cpp
|
||||
net_buffer.cpp
|
||||
net_socket.cpp
|
||||
notifications.cpp
|
||||
link.cpp
|
||||
radix.c
|
||||
routes.cpp
|
||||
|
100
src/add-ons/kernel/network/stack/notifications.cpp
Normal file
100
src/add-ons/kernel/network/stack/notifications.cpp
Normal 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);
|
||||
|
||||
}
|
@ -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);
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user