diff --git a/src/servers/registrar/Jamfile b/src/servers/registrar/Jamfile index 2008cfdfe1..21c6c7105b 100644 --- a/src/servers/registrar/Jamfile +++ b/src/servers/registrar/Jamfile @@ -20,6 +20,7 @@ Server obos_registrar : MessageEvent.cpp MessageRunnerManager.cpp MIMEManager.cpp + NodeMonitoring.cpp RDiskDevice.cpp RDiskDeviceList.cpp RecentApps.cpp @@ -29,6 +30,7 @@ Server obos_registrar : RosterSettingsCharStream.cpp RPartition.cpp RSession.cpp + RVolumeList.cpp TRoster.cpp Watcher.cpp WatchingService.cpp @@ -42,3 +44,10 @@ LinkSharedOSLibs obos_registrar : stdc++.r4 be ; + +# Helper needed for node watching +# +BinCommand NodeMonitor : NodeMonitor.cpp : be ; + +Depends obos_registrar : NodeMonitor ; + diff --git a/src/servers/registrar/NodeMonitor.cpp b/src/servers/registrar/NodeMonitor.cpp new file mode 100644 index 0000000000..833417097b --- /dev/null +++ b/src/servers/registrar/NodeMonitor.cpp @@ -0,0 +1,145 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- + +#include +#include +#include +#include +#include + +// Monitor +class Monitor : public BHandler { +public: + Monitor(BMessenger target); + virtual ~Monitor(); + + virtual void MessageReceived(BMessage *message); + + BMessenger Target() const { return fTarget; } + +private: + BMessenger fTarget; +}; + +// NodeMonitorApp +class NodeMonitorApp : public BApplication { +public: + NodeMonitorApp(); + virtual ~NodeMonitorApp(); + + virtual void MessageReceived(BMessage *message); + +private: + BObjectList fMonitors; +}; + + +// Monitor + +// constructor +Monitor::Monitor(BMessenger target) + : BHandler(), + fTarget(target) +{ +} + +// destructor +Monitor::~Monitor() +{ +} + +// MessageReceived +void +Monitor::MessageReceived(BMessage *message) +{ + switch (message->what) { + case B_NODE_MONITOR: + fTarget.SendMessage(message); + break; + } +} + + +// NodeMonitorApp + +// constructor +NodeMonitorApp::NodeMonitorApp() + : BApplication("application/x-vnd.obos-NodeMonitor"), + fMonitors(10, true) +{ +} + +// destructor +NodeMonitorApp::~NodeMonitorApp() +{ + Lock(); + for (int32 i = 0; Monitor *monitor = fMonitors.ItemAt(i); i++) + RemoveHandler(monitor); + Unlock(); +} + +// MessageReceived +void +NodeMonitorApp::MessageReceived(BMessage *message) +{ + switch (message->what) { + case 'wtch': + { + status_t error = B_BAD_VALUE; + node_ref ref; + BMessenger target; + uint32 flags; + if (message->FindInt32("device", &ref.device) == B_OK + && message->FindInt64("node", &ref.node) == B_OK + && message->FindMessenger("target", &target) == B_OK + && message->FindInt32("flags", (int32*)&flags) == B_OK) { + Monitor *monitor = new Monitor(target); + fMonitors.AddItem(monitor); + AddHandler(monitor); + error = watch_node(&ref, flags, monitor); + if (error != B_OK) { + RemoveHandler(monitor); + fMonitors.RemoveItem(monitor); + } + } + BMessage reply(B_SIMPLE_DATA); + reply.AddInt32("result", error); + message->SendReply(&reply); + break; + } + case 'hctw': + { + status_t error = B_BAD_VALUE; + BMessenger target; + if (message->FindMessenger("target", &target) == B_OK) { + error = B_OK; + for (int32 i = fMonitors.CountItems(); + Monitor *monitor = fMonitors.ItemAt(i); + i--) { + if (monitor->Target() == target) { + error = stop_watching(monitor->Target()); + RemoveHandler(monitor); + delete fMonitors.RemoveItemAt(i); + } + } + } + BMessage reply(B_SIMPLE_DATA); + reply.AddInt32("result", error); + message->SendReply(&reply); + break; + } + } +} + + +// main +int +main() +{ + NodeMonitorApp app; + app.Run(); + return 0; +} + diff --git a/src/servers/registrar/NodeMonitoring.cpp b/src/servers/registrar/NodeMonitoring.cpp new file mode 100644 index 0000000000..4725dd5434 --- /dev/null +++ b/src/servers/registrar/NodeMonitoring.cpp @@ -0,0 +1,226 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +//--------------------------------------------------------------------- + +// A fake implementation of the node monitoring functions. +// They start a remote application that functions as an adapter for the +// functions in libbe.so. +// Note: We can't use the node monitoring provided by libbe directly, since +// it makes sure, that the target is local using BMessenger::Target(), which +// can't work. + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "Debug.h" + +// NodeMonitor +class NodeMonitor { +public: + NodeMonitor(); + ~NodeMonitor(); + + status_t GetMessenger(BMessenger &monitor); + status_t WatchingRequest(const node_ref *node, uint32 flags, + BMessenger target, bool start); + +private: + bool fInitialized; + status_t fStatus; + thread_id fThread; + team_id fTeam; + BMessenger fMessenger; + BLocker fLock; +}; + +static NodeMonitor gNodeMonitor; + +// constructor +NodeMonitor::NodeMonitor() + : fInitialized(false), + fStatus(B_ERROR), + fThread(-1), + fTeam(-1), + fMessenger(), + fLock() +{ +} + +// destructor +NodeMonitor::~NodeMonitor() +{ + fLock.Lock(); + if (fInitialized) { + if (fMessenger.IsValid()) + fMessenger.SendMessage(B_QUIT_REQUESTED); + else if (fThread >= 0) + kill_thread(fThread); + } + fLock.Unlock(); +} + +// GetMessenger +status_t +NodeMonitor::GetMessenger(BMessenger &monitor) +{ + fLock.Lock(); + if (!fInitialized) { + fInitialized = true; + // get NodeMonitor path + char path[B_PATH_NAME_LENGTH]; + fStatus = BPrivate::get_app_path(path); + if (fStatus == B_OK) { + if (char *leaf = strstr(path, "obos_registrar")) { + strcpy(leaf, "../../bin/NodeMonitor"); + } else + fStatus = B_ERROR; + } + // start the NodeMonitor + if (fStatus == B_OK) { + const char *argv[] = { path, NULL }; + fThread = load_image(1, argv, + const_cast(environ)); + if (fThread >= 0) { + resume_thread(fThread); + thread_info info; + fStatus = get_thread_info(fThread, &info); + if (fStatus == B_OK) + fTeam = info.team; + } else + fStatus = fThread; + } + // find the app looper port + port_id port = -1; + if (fStatus == B_OK) { + snooze(200000); + port_info info; + int32 cookie = 0; + fStatus = B_ERROR; + while (get_next_port_info(fTeam, &cookie, &info) == B_OK) { + if (!strcmp(info.name, "AppLooperPort")) { + fStatus = B_OK; + port = info.port; + break; + } + } + } + // get a messenger + if (fStatus == B_OK) { + struct { + port_id fPort; + int32 fHandlerToken; + team_id fTeam; + int32 extra0; + int32 extra1; + bool fPreferredTarget; + bool extra2; + bool extra3; + bool extra4; + } fakeMessenger; + fakeMessenger.fPort = port; + fakeMessenger.fHandlerToken = -1; + fakeMessenger.fTeam = fTeam; + fakeMessenger.fPreferredTarget = true; + fMessenger = *(BMessenger*)&fakeMessenger; + if (!fMessenger.IsValid()) + fStatus = B_ERROR; + } + } + // set result + if (fStatus == B_OK) + monitor = fMessenger; + fLock.Unlock(); + return fStatus; +} + +// WatchingRequest +status_t +NodeMonitor::WatchingRequest(const node_ref *node, uint32 flags, + BMessenger target, bool start) +{ + BMessenger monitor; + status_t error = GetMessenger(monitor); + // prepare request message + BMessage request; + if (error == B_OK) { + if (start) { + request.what = 'wtch'; + request.AddInt32("device", node->device); + request.AddInt64("node", node->node); + request.AddInt32("flags", (int32)flags); + } else { + request.what = 'hctw'; + } + request.AddMessenger("target", target); + } + // send request + BMessage reply; + if (error == B_OK) + error = monitor.SendMessage(&request, &reply); + // analyze reply + if (error == B_OK) { + status_t result; + error = reply.FindInt32("result", &result); + if (error == B_OK) + error = result; + } + return error; +} + +// watch_node +status_t +watch_node(const node_ref *node, uint32 flags, BMessenger target) +{ + status_t error = B_OK; + if (flags == B_STOP_WATCHING) + error = stop_watching(target); + else { + node_ref fakeNode; + if (!node) + node = &fakeNode; + error = gNodeMonitor.WatchingRequest(node, flags, target, true); + } + return error; +} + +// watch_node +status_t +watch_node(const node_ref *node, uint32 flags, const BHandler *handler, + const BLooper *looper) +{ + status_t error = (handler || looper ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + BMessenger target(handler, looper); + error = watch_node(node, flags, target); + } + return error; +} + +// stop_watching +status_t +stop_watching(BMessenger target) +{ + return gNodeMonitor.WatchingRequest(NULL, 0, target, false); +} + +// stop_watching +status_t +stop_watching(const BHandler *handler, const BLooper *looper) +{ + status_t error = (handler || looper ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + BMessenger target(handler, looper); + error = stop_watching(target); + } + return error; +} +