00001
00002
00003
00004
00005
00006
00007
00008 #include "ibrcommon/net/NetLinkManager.h"
00009 #include "ibrcommon/thread/MutexLock.h"
00010 #include "ibrcommon/Logger.h"
00011
00012 #include <netlink/cache.h>
00013 #include <netlink/route/addr.h>
00014 #include <netlink/route/link.h>
00015 #include <netlink/route/rtnl.h>
00016 #include <net/if.h>
00017
00018 #include <netdb.h>
00019 #include <sys/socket.h>
00020 #include <sys/types.h>
00021 #include <netinet/tcp.h>
00022 #include <sys/un.h>
00023 #include <errno.h>
00024 #include <string.h>
00025 #include <fcntl.h>
00026 #include <signal.h>
00027 #include <arpa/inet.h>
00028
00029 #include <iostream>
00030 #include <sstream>
00031
00032 namespace ibrcommon
00033 {
00034 NetLinkManager::NetLinkManager()
00035 : _initialized(false), _sock(NULL), _refresh_cache(false)
00036 {
00037 ibrcommon::MutexLock l(_call_mutex);
00038
00039 _handle = nl_handle_alloc();
00040 nl_connect(_handle, NETLINK_ROUTE);
00041
00042 _link_cache = rtnl_link_alloc_cache(_handle);
00043 _addr_cache = rtnl_addr_alloc_cache(_handle);
00044
00045 _initialized = true;
00046
00047
00048 _sock = new ibrcommon::vsocket();
00049 }
00050
00051 NetLinkManager::~NetLinkManager()
00052 {
00053 stop();
00054 join();
00055
00056
00057 _sock = new ibrcommon::vsocket();
00058
00059 nl_close(_handle);
00060 nl_cache_free(_addr_cache);
00061 nl_cache_free(_link_cache);
00062 nl_handle_destroy(_handle);
00063 }
00064
00065 void add_addr_to_list(struct nl_object *obj, void *data)
00066 {
00067 char buf[INET6_ADDRSTRLEN+5];
00068 std::list<vaddress> *list = static_cast<std::list<vaddress>*>(data);
00069
00070 struct nl_addr *naddr = rtnl_addr_get_local((struct rtnl_addr *) obj);
00071 int ifindex = 0;
00072 int scope = rtnl_addr_get_scope((struct rtnl_addr *) obj);
00073
00074 if (scope == rtnl_str2scope("link"))
00075 ifindex = rtnl_addr_get_ifindex((struct rtnl_addr *) obj);
00076
00077 if (naddr)
00078 {
00079 int family = nl_addr_get_family(naddr);
00080 nl_addr2str( naddr, buf, sizeof( buf ) );
00081 vaddress vaddr(vaddress::Family(family), vaddress::strip_netmask(std::string(buf)), ifindex, false);
00082 list->push_back( vaddr );
00083 }
00084
00085 struct nl_addr *baddr = rtnl_addr_get_broadcast((struct rtnl_addr *) obj);
00086
00087 if (baddr)
00088 {
00089 int family = nl_addr_get_family(baddr);
00090 nl_addr2str( baddr, buf, sizeof( buf ) );
00091 vaddress vaddr(vaddress::Family(family), vaddress::strip_netmask(std::string(buf)), ifindex, true);
00092 list->push_back( vaddr );
00093 }
00094 }
00095
00096 bool NetLinkManager::__cancellation()
00097 {
00098 ibrcommon::MutexLock l(_call_mutex);
00099 _initialized = false;
00100 ibrcommon::interrupt(*_sock, *this);
00101
00102 return true;
00103 }
00104
00105 void NetLinkManager::run()
00106 {
00107 Thread::enable_interruption();
00108
00109 struct nl_handle *handle = nl_handle_alloc();
00110 nl_connect(handle, NETLINK_ROUTE);
00111
00112
00113 nl_socket_add_membership(handle, RTNLGRP_IPV4_IFADDR);
00114
00115
00116
00117 nl_socket_add_membership(handle, RTNLGRP_LINK);
00118
00119
00120 _sock->add(nl_socket_get_fd(handle));
00121
00122 try {
00123 while (_initialized)
00124 {
00125 std::list<int> fds;
00126 ibrcommon::select(*_sock, fds, NULL);
00127 int fd = fds.front();
00128
00129
00130 NetLinkManagerEvent lme(fd);
00131
00132
00133 const vinterface &iface = lme.getInterface();
00134
00135
00136 if (lme.getType() == LinkManagerEvent::EVENT_UNKOWN) continue;
00137
00138
00139 if (lme.isWirelessExtension()) continue;
00140
00141
00142 {
00143 ibrcommon::MutexLock l(_call_mutex);
00144 _refresh_cache = true;
00145 }
00146
00147
00148 ibrcommon::MutexLock l(_listener_mutex);
00149 const std::set<LinkManager::EventCallback* > &ss = _listener[iface];
00150
00151 IBRCOMMON_LOGGER_DEBUG(10) << lme.toString() << IBRCOMMON_LOGGER_ENDL;
00152
00153 for (std::set<LinkManager::EventCallback* >::iterator iter = ss.begin(); iter != ss.end(); iter++)
00154 {
00155 try {
00156 (*iter)->eventNotify((LinkManagerEvent&)lme);
00157 } catch (const std::exception&) { };
00158 }
00159 }
00160 } catch (const vsocket_exception&) {
00161
00162 IBRCOMMON_LOGGER(error) << "NetLink connection stopped" << IBRCOMMON_LOGGER_ENDL;
00163 }
00164
00165 nl_close(handle);
00166 nl_handle_destroy(handle);
00167 }
00168
00169 const std::list<vaddress> NetLinkManager::getAddressList(const vinterface &interface, const vaddress::Family f)
00170 {
00171 ibrcommon::MutexLock l(_call_mutex);
00172
00173 if (_refresh_cache)
00174 {
00175 nl_cache_free(_addr_cache);
00176 nl_cache_free(_link_cache);
00177
00178 _link_cache = rtnl_link_alloc_cache(_handle);
00179 _addr_cache = rtnl_addr_alloc_cache(_handle);
00180 }
00181
00182 std::list<vaddress> addresses;
00183
00184 struct rtnl_addr *filter = rtnl_addr_alloc();
00185 const std::string i = interface.toString();
00186 rtnl_addr_set_ifindex(filter, rtnl_link_name2i(_link_cache, i.c_str()));
00187
00188 if (f == vaddress::VADDRESS_UNSPEC)
00189 {
00190 rtnl_addr_set_family(filter, AF_INET6);
00191 nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
00192 add_addr_to_list, &addresses);
00193
00194 rtnl_addr_set_family(filter, AF_INET);
00195 nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
00196 add_addr_to_list, &addresses);
00197 }
00198 else
00199 {
00200 rtnl_addr_set_family(filter, f);
00201 nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
00202 add_addr_to_list, &addresses);
00203 }
00204
00205 rtnl_addr_put(filter);
00206
00207 return addresses;
00208 }
00209
00210 const std::string NetLinkManager::getInterface(const int ifindex) const
00211 {
00212 char buf[256];
00213 rtnl_link_i2name(_link_cache, ifindex, (char*)&buf, sizeof buf);
00214 return std::string((char*)&buf);
00215 }
00216
00218 NetLinkManagerEvent::NetLinkManagerEvent(int fd)
00219 : _type(EVENT_UNKOWN), _state(0), _wireless(false)
00220 {
00221 char buf[4096];
00222 int len = 0;
00223 struct nlmsghdr *nlh;
00224
00225
00226 nlh = (struct nlmsghdr *) buf;
00227
00228
00229 std::map<int, std::string> &attrlist = _attributes;
00230
00231 while ((len = recv(fd, nlh, 4096, 0)) > 0)
00232 {
00233 while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE))
00234 {
00235 switch (nlh->nlmsg_type)
00236 {
00237 case RTM_BASE:
00238 {
00239 int attrlen, nlmsg_len, rta_len;
00240 struct rtattr * attr;
00241
00242 struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(nlh);
00243
00244 nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
00245 attrlen = nlh->nlmsg_len - nlmsg_len;
00246
00247 if (attrlen < 0) break;
00248
00249 attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
00250
00251 rta_len = RTA_ALIGN(sizeof(struct rtattr));
00252 while (RTA_OK(attr, attrlen))
00253 {
00254 size_t rta_length = RTA_PAYLOAD(attr);
00255
00256 switch (attr->rta_type)
00257 {
00258 case IFLA_IFNAME:
00259 _interface = ibrcommon::vinterface( std::string((char*)RTA_DATA(attr), rta_length) );
00260 _type = EVENT_LINK_STATE;
00261 break;
00262
00263 case IFLA_OPERSTATE:
00264 {
00265 char s;
00266 ::memcpy(&s, (char*)RTA_DATA(attr), 1);
00267 _state = s;
00268 break;
00269 }
00270
00271 case IFLA_WIRELESS:
00272 _wireless = true;
00273 break;
00274
00275 default:
00276 attrlist[attr->rta_type] = std::string((char*)RTA_DATA(attr), rta_length);
00277 break;
00278 }
00279
00280 attr = RTA_NEXT(attr, attrlen);
00281 }
00282 break;
00283 }
00284
00285 case RTM_NEWADDR:
00286 {
00287 struct ifaddrmsg *ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh);
00288 struct rtattr *rth = IFA_RTA(ifa);
00289 int rtl = IFA_PAYLOAD(nlh);
00290
00291 while (rtl && RTA_OK(rth, rtl)) {
00292 if (rth->rta_type == IFA_LOCAL) {
00293 uint32_t ipaddr = htonl(*((uint32_t *)RTA_DATA(rth)));
00294 char name[IFNAMSIZ];
00295 if_indextoname(ifa->ifa_index, name);
00296 _interface = ibrcommon::vinterface(name);
00297
00298 char address[256];
00299 sprintf(address, "%d.%d.%d.%d", (ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff, (ipaddr >> 8) & 0xff, ipaddr & 0xff);
00300
00301 _address = ibrcommon::vaddress(ibrcommon::vaddress::VADDRESS_INET, std::string(address));
00302
00303 _type = EVENT_ADDRESS_ADDED;
00304 }
00305 rth = RTA_NEXT(rth, rtl);
00306 }
00307 break;
00308 }
00309
00310 case RTM_DELADDR:
00311 {
00312 struct ifaddrmsg *ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh);
00313 struct rtattr *rth = IFA_RTA(ifa);
00314 int rtl = IFA_PAYLOAD(nlh);
00315
00316 while (rtl && RTA_OK(rth, rtl)) {
00317 if (rth->rta_type == IFA_LOCAL) {
00318 uint32_t ipaddr = htonl(*((uint32_t *)RTA_DATA(rth)));
00319 char name[IFNAMSIZ];
00320 if_indextoname(ifa->ifa_index, name);
00321 _interface = ibrcommon::vinterface(name);
00322
00323 char address[256];
00324 sprintf(address, "%d.%d.%d.%d", (ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff, (ipaddr >> 8) & 0xff, ipaddr & 0xff);
00325
00326 _address = ibrcommon::vaddress(ibrcommon::vaddress::VADDRESS_INET, std::string(address));
00327
00328 _type = EVENT_ADDRESS_REMOVED;
00329 }
00330 rth = RTA_NEXT(rth, rtl);
00331 }
00332 break;
00333 }
00334
00335 default:
00336 IBRCOMMON_LOGGER_DEBUG(10) << "unknown netlink type received: " << nlh->nlmsg_type << IBRCOMMON_LOGGER_ENDL;
00337 break;
00338 }
00339
00340 nlh = NLMSG_NEXT(nlh, len);
00341 }
00342
00343 return;
00344 }
00345 }
00346
00347 NetLinkManagerEvent::~NetLinkManagerEvent()
00348 {
00349 }
00350
00351 const ibrcommon::vinterface& NetLinkManagerEvent::getInterface() const
00352 {
00353 return _interface;
00354 }
00355
00356 const ibrcommon::vaddress& NetLinkManagerEvent::getAddress() const
00357 {
00358 return _address;
00359 }
00360
00361 unsigned int NetLinkManagerEvent::getState() const
00362 {
00363 return _state;
00364 }
00365
00366 bool NetLinkManagerEvent::isWirelessExtension() const
00367 {
00368 return _wireless;
00369 }
00370
00371 LinkManagerEvent::EventType NetLinkManagerEvent::getType() const
00372 {
00373 return _type;
00374 }
00375
00376 const std::string NetLinkManagerEvent::toString() const
00377 {
00378 std::stringstream ss;
00379 ss << "NetLinkManagerEvent on " << getInterface().toString() << "; Type: " << getType();
00380
00381 switch (getType())
00382 {
00383 case EVENT_LINK_STATE:
00384 ss << "; State: " << getState();
00385 break;
00386
00387 case EVENT_ADDRESS_ADDED:
00388 ss << "; Address added: " << getAddress().toString();
00389 break;
00390
00391 case EVENT_ADDRESS_REMOVED:
00392 ss << "; Address removed: " << getAddress().toString();
00393 break;
00394
00395 default:
00396 break;
00397 };
00398
00399 return ss.str();
00400 }
00401
00402 void NetLinkManagerEvent::debug() const
00403 {
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417 }
00418
00419 void NetLinkManager::registerInterfaceEvent(const vinterface &iface, LinkManager::EventCallback *cb)
00420 {
00421 if (cb == NULL) return;
00422 ibrcommon::MutexLock l(_listener_mutex);
00423
00424 std::set<LinkManager::EventCallback* > &ss = _listener[iface];
00425 ss.insert(cb);
00426 }
00427
00428 void NetLinkManager::unregisterInterfaceEvent(const vinterface &iface, LinkManager::EventCallback *cb)
00429 {
00430 if (cb == NULL) return;
00431 ibrcommon::MutexLock l(_listener_mutex);
00432
00433 std::set<LinkManager::EventCallback* > &ss = _listener[iface];
00434
00435 ss.erase(cb);
00436
00437 if (ss.empty())
00438 {
00439 _listener.erase(iface);
00440 }
00441 }
00442
00443 void NetLinkManager::unregisterAllEvents(LinkManager::EventCallback *cb)
00444 {
00445 if (cb == NULL) return;
00446
00447 try {
00448 ibrcommon::MutexLock l(_listener_mutex);
00449
00450 for (std::map<vinterface, std::set<LinkManager::EventCallback* > >::iterator iter = _listener.begin(); iter != _listener.end(); iter++)
00451 {
00452 std::set<LinkManager::EventCallback* > &ss = iter->second;
00453 ss.erase(cb);
00454 }
00455 } catch (const ibrcommon::MutexException&) {
00456
00457
00458 }
00459 }
00460 }