source: source/ariba/communication/networkinfo/NetworkChangeDetection.cpp@ 10576

Last change on this file since 10576 was 8569, checked in by Christoph Mayer, 14 years ago
File size: 9.6 KB
Line 
1// [License]
2// The Ariba-Underlay Copyright
3//
4// Copyright (c) 2008-2009, Institute of Telematics, UniversitÀt Karlsruhe (TH)
5//
6// Institute of Telematics
7// UniversitÀt Karlsruhe (TH)
8// Zirkel 2, 76128 Karlsruhe
9// Germany
10//
11// Redistribution and use in source and binary forms, with or without
12// modification, are permitted provided that the following conditions are
13// met:
14//
15// 1. Redistributions of source code must retain the above copyright
16// notice, this list of conditions and the following disclaimer.
17// 2. Redistributions in binary form must reproduce the above copyright
18// notice, this list of conditions and the following disclaimer in the
19// documentation and/or other materials provided with the distribution.
20//
21// THIS SOFTWARE IS PROVIDED BY THE INSTITUTE OF TELEMATICS ``AS IS'' AND
22// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ARIBA PROJECT OR
25// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32//
33// The views and conclusions contained in the software and documentation
34// are those of the authors and should not be interpreted as representing
35// official policies, either expressed or implied, of the Institute of
36// Telematics.
37// [License]
38
39#include "NetworkChangeDetection.h"
40
41namespace ariba {
42namespace communication {
43
44use_logging_cpp(NetworkChangeDetection);
45SystemEventType NetworkChangeDetectionEventType("NetworkChangeDetectionEventType");
46
47NetworkChangeDetection::NetworkChangeDetection()
48 : running( false ), monitoringThread( NULL ), routingSocket( -1 ){
49 startMonitoring();
50}
51
52NetworkChangeDetection::~NetworkChangeDetection(){
53 stopMonitoring();
54}
55
56void NetworkChangeDetection::registerNotification(NetworkChangeInterface* callback){
57
58 RegistrationList::iterator i = find(
59 registrations.begin(), registrations.end(), callback );
60
61 if( i == registrations.end() )
62 registrations.push_back( callback );
63}
64
65void NetworkChangeDetection::unregisterNotification(NetworkChangeInterface* callback){
66
67 RegistrationList::iterator i = find(
68 registrations.begin(), registrations.end(), callback );
69
70 if( i != registrations.end() )
71 registrations.erase( i );
72}
73
74void NetworkChangeDetection::startMonitoring(){
75
76 logging_debug( "starting network change monitoring ..." );
77
78 running = true;
79 monitoringThread = new boost::thread(
80 boost::bind(&NetworkChangeDetection::monitoringThreadFunc, this) );
81}
82
83void NetworkChangeDetection::stopMonitoring(){
84
85 logging_debug( "stopping network change monitoring ..." );
86
87 // trigger the blocking read to end
88 running = false;
89
90 shutdown( routingSocket, SHUT_RDWR );
91 close( routingSocket );
92
93 // end the monitoring thread
94 monitoringThread->join();
95
96 delete monitoringThread;
97 monitoringThread = NULL;
98}
99
100void NetworkChangeDetection::monitoringThreadFunc(NetworkChangeDetection* obj){
101
102 //
103 // Most information about this routing socket interface is available
104 // when searching for NETLINK_ROUTE and in http://www.faqs.org/rfcs/rfc3549.html
105 // A small program that uses this stuff is ifplugd, nice reference for
106 // getting network interface notifications using routing sockets
107 // (e.g. http://ifplugd.sourcearchive.com/documentation/0.26/ifmonitor_8c-source.html)
108 // And the best resource is the linux code ... http://www.srcdoc.com/linux_2.2.26/rtnetlink_8h-source.html
109 // More:
110 // http://m.linuxjournal.com/article/8498
111 // http://lkml.indiana.edu/hypermail/linux/net/0508.2/0016.html
112 // http://infrahip.hiit.fi/hipl/release/1.0.1/hipl.1.0.1/hipd/netdev.c
113 // http://www.google.de/codesearch?hl=de&q=rtmsg_ifinfo+show:Ndy7Mq7IdCw:aylASy5mtF0:ClfaxlLp-PU&source=universal&cs_p=ftp://ftp.kernel.org/pub/linux/kernel/v2.4/linux-2.4.18.tar.gz&cs_f=linux/net/core/rtnetlink.c#l490
114 // http://www.google.com/codesearch?hl=en&q=RTM_NEWADDR+NETLINK_ROUTE+show:eUekvGbF94M:iCwmLwtnVbU:38qoeYp--0A&sa=N&cd=1&ct=rc&cs_p=ftp://ftp.stacken.kth.se/pub/arla/arla-0.42.tar.gz&cs_f=arla-0.42/lib/roken/getifaddrs.c
115 // http://www.google.com/codesearch?hl=en&q=RTMGRP_LINK+rtm_newaddr+nl_groups+show:sUV8mV--Lb4:gk0jx_xv0Yg:ZB9MN7Fgkgg&sa=N&cd=1&ct=rc&cs_p=http://freshmeat.net/redir/strongswan/60428/url_bz2/strongswan-4.1.2.tar.bz2&cs_f=strongswan-4.1.4/src/charon/kernel/kernel_interface.c#l689
116 //
117
118 //
119 // open the netlink routing socket, don't need raw sockets here!
120 //
121
122 obj->routingSocket = socket( PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE );
123 if( obj->routingSocket < 0 ){
124 logging_error("could not connect to routing socket: " +
125 string(strerror(errno)));
126 return;
127 }
128
129 //
130 // set a socket read timeout. this is actually bad, but closing
131 // the blocking socket using shutdown, close, or writing EOF to
132 // the socket did not work. this seems to be a bug related to
133 // routing sockets that will not close when in blocking mode
134 //
135
136 struct timeval tv;
137 tv.tv_sec = 1;
138 tv.tv_usec = 0;
139
140 setsockopt( obj->routingSocket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv) );
141
142 //
143 // bind the netlink routing socket to our local address
144 // for the nl_groups, see http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/include/linux/rtnetlink.h#L520
145 // we listen on ipv4/6 new/delete address and link up/down notifications
146 //
147
148 struct sockaddr_nl addr;
149 memset( &addr, 0, sizeof(addr) );
150 addr.nl_family = AF_NETLINK;
151 addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_LINK;
152 addr.nl_pid = getpid();
153
154 int ret = bind( obj->routingSocket, (struct sockaddr*)&addr, sizeof(addr) );
155 if( ret < 0 ){
156 close( obj->routingSocket );
157 logging_error( "could not bind routing socket: " + string(strerror(errno)) );
158 return;
159 }
160
161 //
162 // read from the netlink routing socket
163 //
164
165 logging_debug( "network change monitoring started" );
166
167 while( obj->running ){
168
169 char buffer[1024];
170 struct nlmsghdr* header = (struct nlmsghdr*)buffer;
171
172 int bytesRead = recv( obj->routingSocket, &buffer, sizeof(buffer), 0 );
173
174 if( bytesRead < 0 ){
175
176 // socket timeout, just continue
177 if( errno == EWOULDBLOCK ) continue;
178
179 // triggered by shutdown() function in stopMonitoring
180 if( errno == EBADF ) return;
181
182 // gracefull exit by signals
183 if( errno == EAGAIN || errno == EINTR ) return;
184
185 // all others are some kind of error
186 logging_error( "could not read from routing socket: " +
187 string(strerror(errno)) );
188 break;
189 }
190
191 for( ; bytesRead > 0; header = NLMSG_NEXT(header, bytesRead)) {
192 if (!NLMSG_OK(header, (size_t)bytesRead) ||
193 (size_t) bytesRead < sizeof(struct nlmsghdr) ||
194 (size_t) bytesRead < (size_t)header->nlmsg_len) {
195 continue;
196 }
197
198 // somehow all notifications with pid=0 are
199 // invalid and occur much too often
200 if(header->nlmsg_pid == 0) continue;
201
202 //
203 // here we evaluate the routing netlink message. for, the following
204 // messages are of interest:
205 // RTM_NEWADDR, RTM_DELADDR -> new address on iface, address deleted from iface
206 //
207
208 NetworkChangeInterface::NetworkChangeInfo changeInfo;
209
210 switch( header->nlmsg_type ){
211
212 //
213 // handle network address configuration changes
214 // --> network layer notifications
215 //
216
217 case RTM_NEWADDR:
218 case RTM_DELADDR:
219
220 changeInfo = obj->extractAddressEvent( header );
221 break;
222
223 //
224 // other RTM message are ignored in case
225 // we did subscribe using nl_groups (see above)
226 //
227
228 default: break;
229
230 } // switch( header->nlmsg_type )
231
232 logging_info( "network change detected: [" << changeInfo << "]" );
233
234 // put noficiation event into the system queue for main
235 // thread synchronization. will be handled in NetworkChangeDetection::handleSystemEvent()
236 // that will run synchronized with the main thread
237
238 SystemQueue::instance().scheduleEvent(
239 SystemEvent( obj, NetworkChangeDetectionEventType,
240 new NetworkChangeInterface::NetworkChangeInfo(changeInfo)));
241
242 } // for( ; bytesRead > 0; header = NLMSG_NEXT(header, bytesRead))
243 } // while( running )
244
245 logging_debug( "network change monitoring stopped" );
246}
247
248NetworkChangeInterface::NetworkChangeInfo NetworkChangeDetection::extractAddressEvent(struct nlmsghdr* header){
249 NetworkChangeInterface::NetworkChangeInfo changeInfo;
250
251 //
252 // handle network address configuration changes
253 // addresses are added/removed from an interface
254 //
255
256 if( header->nlmsg_type == RTM_NEWADDR ){
257 logging_debug("network change message RTM_NEWADDR");
258 changeInfo.type = NetworkChangeInterface::EventTypeInterfaceUp;
259 }else if( header->nlmsg_type == RTM_DELADDR ){
260 logging_debug("network change message RTM_DELADDR");
261 changeInfo.type = NetworkChangeInterface::EventTypeInterfaceDown;
262 }
263
264 struct ifaddrmsg* detailAddr = (struct ifaddrmsg*)NLMSG_DATA(header);
265 changeInfo.interface = networkInformation.getInterface( detailAddr->ifa_index );
266
267 return changeInfo;
268}
269
270void NetworkChangeDetection::handleSystemEvent(const SystemEvent& event){
271
272 NetworkChangeInterface::NetworkChangeInfo* changeInfo = event.getData<NetworkChangeInterface::NetworkChangeInfo>();
273 const NetworkChangeDetection* obj = (const NetworkChangeDetection*)event.getListener();
274
275 RegistrationList::const_iterator i = obj->registrations.begin();
276 RegistrationList::const_iterator iend = obj->registrations.end();
277
278 for( ; i != iend; i++ )
279 (*i)->onNetworkChange(*changeInfo);
280
281 delete changeInfo;
282}
283
284}} // namespace ariba, communication
Note: See TracBrowser for help on using the repository browser.