1/* 2 * Copyright 2015, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7//! The backbone of the NetworkAvailable event, and condition. 8 9 10#include "NetworkWatcher.h" 11 12#include <Application.h> 13#include <Autolock.h> 14#include <NetworkDevice.h> 15#include <NetworkInterface.h> 16#include <NetworkRoster.h> 17 18#include "Utility.h" 19 20 21static const bigtime_t kNetworkUpdateInterval = 1000000; 22 // Update network availability every second 23 24static BLocker sLocker("network watcher"); 25static NetworkWatcher* sWatcher; 26 27static bool sLastNetworkAvailable; 28static bigtime_t sLastNetworkUpdate; 29 30 31NetworkListener::~NetworkListener() 32{ 33} 34 35 36// #pragma mark - 37 38 39NetworkWatcher::NetworkWatcher() 40 : 41 BHandler("network watcher"), 42 fAvailable(false) 43{ 44 if (be_app->Lock()) { 45 be_app->AddHandler(this); 46 47 start_watching_network(B_WATCH_NETWORK_INTERFACE_CHANGES 48 | B_WATCH_NETWORK_LINK_CHANGES, this); 49 be_app->Unlock(); 50 } 51} 52 53 54NetworkWatcher::~NetworkWatcher() 55{ 56 if (be_app->Lock()) { 57 stop_watching_network(this); 58 59 be_app->RemoveHandler(this); 60 be_app->Unlock(); 61 } 62} 63 64 65void 66NetworkWatcher::AddListener(NetworkListener* listener) 67{ 68 BAutolock lock(sLocker); 69 fListeners.AddItem(listener); 70 71 if (fListeners.CountItems() == 1) 72 UpdateAvailability(); 73} 74 75 76void 77NetworkWatcher::RemoveListener(NetworkListener* listener) 78{ 79 BAutolock lock(sLocker); 80 fListeners.RemoveItem(listener); 81} 82 83 84int32 85NetworkWatcher::CountListeners() const 86{ 87 BAutolock lock(sLocker); 88 return fListeners.CountItems(); 89} 90 91 92void 93NetworkWatcher::MessageReceived(BMessage* message) 94{ 95 switch (message->what) { 96 case B_NETWORK_MONITOR: 97 UpdateAvailability(); 98 break; 99 } 100} 101 102 103/*static*/ void 104NetworkWatcher::Register(NetworkListener* listener) 105{ 106 BAutolock lock(sLocker); 107 if (sWatcher == NULL) 108 sWatcher = new NetworkWatcher(); 109 110 sWatcher->AddListener(listener); 111} 112 113 114/*static*/ void 115NetworkWatcher::Unregister(NetworkListener* listener) 116{ 117 BAutolock lock(sLocker); 118 sWatcher->RemoveListener(listener); 119 120 if (sWatcher->CountListeners() == 0) 121 delete sWatcher; 122} 123 124 125/*static*/ bool 126NetworkWatcher::NetworkAvailable(bool immediate) 127{ 128 if (!immediate 129 && system_time() - sLastNetworkUpdate < kNetworkUpdateInterval) { 130 return sLastNetworkAvailable; 131 } 132 133 bool isAvailable = false; 134 135 BNetworkRoster& roster = BNetworkRoster::Default(); 136 BNetworkInterface interface; 137 uint32 cookie = 0; 138 while (roster.GetNextInterface(&cookie, interface) == B_OK) { 139 uint32 flags = interface.Flags(); 140 if ((flags & (IFF_LOOPBACK | IFF_CONFIGURING | IFF_UP | IFF_LINK)) 141 == (IFF_UP | IFF_LINK)) { 142 isAvailable = true; 143 break; 144 } 145 } 146 147 sLastNetworkAvailable = isAvailable; 148 sLastNetworkUpdate = system_time(); 149 return isAvailable; 150} 151 152 153void 154NetworkWatcher::UpdateAvailability() 155{ 156 bool isAvailable = NetworkAvailable(true); 157 if (isAvailable != fAvailable) { 158 fAvailable = isAvailable; 159 160 BAutolock lock(sLocker); 161 for (int32 i = 0; i < fListeners.CountItems(); i++) { 162 fListeners.ItemAt(i)->NetworkAvailabilityChanged(fAvailable); 163 } 164 } 165} 166