166 lines
3.0 KiB
C++
166 lines
3.0 KiB
C++
/*
|
|
* Copyright 2015, Axel Dörfler, axeld@pinc-software.de.
|
|
* Distributed under the terms of the MIT License.
|
|
*/
|
|
|
|
|
|
//! The backbone of the NetworkAvailable event, and condition.
|
|
|
|
|
|
#include "NetworkWatcher.h"
|
|
|
|
#include <Application.h>
|
|
#include <Autolock.h>
|
|
#include <NetworkDevice.h>
|
|
#include <NetworkInterface.h>
|
|
#include <NetworkRoster.h>
|
|
|
|
#include "Utility.h"
|
|
|
|
|
|
static const bigtime_t kNetworkUpdateInterval = 1000000;
|
|
// Update network availability every second
|
|
|
|
static BLocker sLocker("network watcher");
|
|
static NetworkWatcher* sWatcher;
|
|
|
|
static bool sLastNetworkAvailable;
|
|
static bigtime_t sLastNetworkUpdate;
|
|
|
|
|
|
NetworkListener::~NetworkListener()
|
|
{
|
|
}
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
NetworkWatcher::NetworkWatcher()
|
|
:
|
|
BHandler("network watcher"),
|
|
fAvailable(false)
|
|
{
|
|
if (be_app->Lock()) {
|
|
be_app->AddHandler(this);
|
|
|
|
start_watching_network(B_WATCH_NETWORK_INTERFACE_CHANGES
|
|
| B_WATCH_NETWORK_LINK_CHANGES, this);
|
|
be_app->Unlock();
|
|
}
|
|
}
|
|
|
|
|
|
NetworkWatcher::~NetworkWatcher()
|
|
{
|
|
if (be_app->Lock()) {
|
|
stop_watching_network(this);
|
|
|
|
be_app->RemoveHandler(this);
|
|
be_app->Unlock();
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
NetworkWatcher::AddListener(NetworkListener* listener)
|
|
{
|
|
BAutolock lock(sLocker);
|
|
fListeners.AddItem(listener);
|
|
|
|
if (fListeners.CountItems() == 1)
|
|
UpdateAvailability();
|
|
}
|
|
|
|
|
|
void
|
|
NetworkWatcher::RemoveListener(NetworkListener* listener)
|
|
{
|
|
BAutolock lock(sLocker);
|
|
fListeners.RemoveItem(listener);
|
|
}
|
|
|
|
|
|
int32
|
|
NetworkWatcher::CountListeners() const
|
|
{
|
|
BAutolock lock(sLocker);
|
|
return fListeners.CountItems();
|
|
}
|
|
|
|
|
|
void
|
|
NetworkWatcher::MessageReceived(BMessage* message)
|
|
{
|
|
switch (message->what) {
|
|
case B_NETWORK_MONITOR:
|
|
UpdateAvailability();
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*static*/ void
|
|
NetworkWatcher::Register(NetworkListener* listener)
|
|
{
|
|
BAutolock lock(sLocker);
|
|
if (sWatcher == NULL)
|
|
sWatcher = new NetworkWatcher();
|
|
|
|
sWatcher->AddListener(listener);
|
|
}
|
|
|
|
|
|
/*static*/ void
|
|
NetworkWatcher::Unregister(NetworkListener* listener)
|
|
{
|
|
BAutolock lock(sLocker);
|
|
sWatcher->RemoveListener(listener);
|
|
|
|
if (sWatcher->CountListeners() == 0)
|
|
delete sWatcher;
|
|
}
|
|
|
|
|
|
/*static*/ bool
|
|
NetworkWatcher::NetworkAvailable(bool immediate)
|
|
{
|
|
if (!immediate
|
|
&& system_time() - sLastNetworkUpdate < kNetworkUpdateInterval) {
|
|
return sLastNetworkAvailable;
|
|
}
|
|
|
|
bool isAvailable = false;
|
|
|
|
BNetworkRoster& roster = BNetworkRoster::Default();
|
|
BNetworkInterface interface;
|
|
uint32 cookie = 0;
|
|
while (roster.GetNextInterface(&cookie, interface) == B_OK) {
|
|
uint32 flags = interface.Flags();
|
|
if ((flags & (IFF_LOOPBACK | IFF_CONFIGURING | IFF_UP | IFF_LINK))
|
|
== (IFF_UP | IFF_LINK)) {
|
|
isAvailable = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
sLastNetworkAvailable = isAvailable;
|
|
sLastNetworkUpdate = system_time();
|
|
return isAvailable;
|
|
}
|
|
|
|
|
|
void
|
|
NetworkWatcher::UpdateAvailability()
|
|
{
|
|
bool isAvailable = NetworkAvailable(true);
|
|
if (isAvailable != fAvailable) {
|
|
fAvailable = isAvailable;
|
|
|
|
BAutolock lock(sLocker);
|
|
for (int32 i = 0; i < fListeners.CountItems(); i++) {
|
|
fListeners.ItemAt(i)->NetworkAvailabilityChanged(fAvailable);
|
|
}
|
|
}
|
|
}
|