xref: /haiku/src/servers/launch/NetworkWatcher.cpp (revision 1deede7388b04dbeec5af85cae7164735ea9e70d)
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 
21 static const bigtime_t kNetworkUpdateInterval = 1000000;
22 	// Update network availability every second
23 
24 static BLocker sLocker("network watcher");
25 static NetworkWatcher* sWatcher;
26 
27 static bool sLastNetworkAvailable;
28 static bigtime_t sLastNetworkUpdate;
29 
30 
31 NetworkListener::~NetworkListener()
32 {
33 }
34 
35 
36 // #pragma mark -
37 
38 
39 NetworkWatcher::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 
54 NetworkWatcher::~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 
65 void
66 NetworkWatcher::AddListener(NetworkListener* listener)
67 {
68 	BAutolock lock(sLocker);
69 	fListeners.AddItem(listener);
70 
71 	if (fListeners.CountItems() == 1)
72 		UpdateAvailability();
73 }
74 
75 
76 void
77 NetworkWatcher::RemoveListener(NetworkListener* listener)
78 {
79 	BAutolock lock(sLocker);
80 	fListeners.RemoveItem(listener);
81 }
82 
83 
84 int32
85 NetworkWatcher::CountListeners() const
86 {
87 	BAutolock lock(sLocker);
88 	return fListeners.CountItems();
89 }
90 
91 
92 void
93 NetworkWatcher::MessageReceived(BMessage* message)
94 {
95 	switch (message->what) {
96 		case B_NETWORK_MONITOR:
97 			UpdateAvailability();
98 			break;
99 	}
100 }
101 
102 
103 /*static*/ void
104 NetworkWatcher::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
115 NetworkWatcher::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
126 NetworkWatcher::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 
153 void
154 NetworkWatcher::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