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