IBR-DTNSuite 0.6

ibrcommon/ibrcommon/net/NetLinkManager.cpp

Go to the documentation of this file.
00001 /*
00002  * NetLinkManager.cpp
00003  *
00004  *  Created on: 21.12.2010
00005  *      Author: morgenro
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                 // create a new socket for the netlink interface
00048                 _sock = new ibrcommon::vsocket();
00049         }
00050 
00051         NetLinkManager::~NetLinkManager()
00052         {
00053                 stop();
00054                 join();
00055 
00056                 // destroy the socket for the netlink interface
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                 _sock->close();
00101 
00102                 return true;
00103         }
00104 
00105         void NetLinkManager::run()
00106         {
00107                 struct nl_handle *handle = nl_handle_alloc();
00108                 nl_connect(handle, NETLINK_ROUTE);
00109 
00110                 // init route messages
00111                 nl_socket_add_membership(handle, RTNLGRP_IPV4_IFADDR);
00112 
00113 //              IPv6 requires further support in the parsing procedures!
00114 //              nl_socket_add_membership(handle, RTNLGRP_IPV6_IFADDR);
00115                 nl_socket_add_membership(handle, RTNLGRP_LINK);
00116 
00117                 // add netlink fd to vsocket
00118                 _sock->add(nl_socket_get_fd(handle));
00119 
00120                 try {
00121                         while (_initialized)
00122                         {
00123                                 std::list<int> fds;
00124                                 _sock->select(fds, NULL);
00125                                 int fd = fds.front();
00126 
00127                                 // create a new event object
00128                                 NetLinkManagerEvent lme(fd);
00129 
00130                                 // get the corresponding interface
00131                                 const vinterface &iface = lme.getInterface();
00132 
00133                                 // ignore if the event is unknown
00134                                 if (lme.getType() == LinkManagerEvent::EVENT_UNKOWN) continue;
00135 
00136                                 // ignore if this is an wireless extension event
00137                                 if (lme.isWirelessExtension()) continue;
00138 
00139                                 // need to refresh the cache
00140                                 {
00141                                         ibrcommon::MutexLock l(_call_mutex);
00142                                         _refresh_cache = true;
00143                                 }
00144 
00145                                 // search for event subscriptions
00146                                 ibrcommon::MutexLock l(_listener_mutex);
00147                                 const std::set<LinkManager::EventCallback* > &ss = _listener[iface];
00148 
00149                                 IBRCOMMON_LOGGER_DEBUG(10) << lme.toString() << IBRCOMMON_LOGGER_ENDL;
00150 
00151                                 for (std::set<LinkManager::EventCallback* >::iterator iter = ss.begin(); iter != ss.end(); iter++)
00152                                 {
00153                                         try {
00154                                                 (*iter)->eventNotify((LinkManagerEvent&)lme);
00155                                         } catch (const std::exception&) { };
00156                                 }
00157                         }
00158                 } catch (const vsocket_exception&) {
00159                         // stopped / interrupted
00160                         IBRCOMMON_LOGGER(error) << "NetLink connection stopped" << IBRCOMMON_LOGGER_ENDL;
00161                 }
00162 
00163                 nl_close(handle);
00164                 nl_handle_destroy(handle);
00165         }
00166 
00167         const std::list<vaddress> NetLinkManager::getAddressList(const vinterface &interface, const vaddress::Family f)
00168         {
00169                 ibrcommon::MutexLock l(_call_mutex);
00170 
00171                 if (_refresh_cache)
00172                 {
00173                         nl_cache_free(_addr_cache);
00174                         nl_cache_free(_link_cache);
00175 
00176                         _link_cache = rtnl_link_alloc_cache(_handle);
00177                         _addr_cache = rtnl_addr_alloc_cache(_handle);
00178                 }
00179 
00180                 std::list<vaddress> addresses;
00181 
00182                 struct rtnl_addr *filter = rtnl_addr_alloc();
00183                 const std::string i = interface.toString();
00184                 rtnl_addr_set_ifindex(filter, rtnl_link_name2i(_link_cache, i.c_str()));
00185 
00186                 if (f == vaddress::VADDRESS_UNSPEC)
00187                 {
00188                         rtnl_addr_set_family(filter, AF_INET6);
00189                         nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
00190                                                                         add_addr_to_list, &addresses);
00191 
00192                         rtnl_addr_set_family(filter, AF_INET);
00193                         nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
00194                                                                         add_addr_to_list, &addresses);
00195                 }
00196                 else
00197                 {
00198                         rtnl_addr_set_family(filter, f);
00199                         nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
00200                                                                         add_addr_to_list, &addresses);
00201                 }
00202 
00203                 rtnl_addr_put(filter);
00204 
00205                 return addresses;
00206         }
00207 
00208         const std::string NetLinkManager::getInterface(const int ifindex) const
00209         {
00210                 char buf[256];
00211                 rtnl_link_i2name(_link_cache, ifindex, (char*)&buf, sizeof buf);
00212                 return std::string((char*)&buf);
00213         }
00214 
00216         NetLinkManagerEvent::NetLinkManagerEvent(int fd)
00217          : _type(EVENT_UNKOWN), _state(0), _wireless(false)
00218         {
00219                 char buf[4096];
00220                 int len = 0;
00221                 struct nlmsghdr *nlh;
00222 
00223                 // cast netlink message
00224                 nlh = (struct nlmsghdr *) buf;
00225 
00226                 // get local reference to the attributes list
00227                 std::map<int, std::string> &attrlist = _attributes;
00228 
00229                 while ((len = recv(fd, nlh, 4096, 0)) > 0)
00230                 {
00231                         while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE))
00232                         {
00233                                 switch (nlh->nlmsg_type)
00234                                 {
00235                                         case RTM_BASE:
00236                                         {
00237                                                 int attrlen, nlmsg_len, rta_len;
00238                                                 struct rtattr * attr;
00239 
00240                                                 struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(nlh);
00241 
00242                                                 nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
00243                                                 attrlen = nlh->nlmsg_len - nlmsg_len;
00244 
00245                                                 if (attrlen < 0) break;
00246 
00247                                                 attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
00248 
00249                                                 rta_len = RTA_ALIGN(sizeof(struct rtattr));
00250                                                 while (RTA_OK(attr, attrlen))
00251                                                 {
00252                                                         size_t rta_length = RTA_PAYLOAD(attr);
00253 
00254                                                         switch (attr->rta_type)
00255                                                         {
00256                                                         case IFLA_IFNAME:
00257                                                                 _interface = ibrcommon::vinterface( std::string((char*)RTA_DATA(attr), rta_length) );
00258                                                                 _type = EVENT_LINK_STATE;
00259                                                                 break;
00260 
00261                                                         case IFLA_OPERSTATE:
00262                                                         {
00263                                                                 char s;
00264                                                                 ::memcpy(&s, (char*)RTA_DATA(attr), 1);
00265                                                                 _state = s;
00266                                                                 break;
00267                                                         }
00268 
00269                                                         case IFLA_WIRELESS:
00270                                                                 _wireless = true;
00271                                                                 break;
00272 
00273                                                         default:
00274                                                                 attrlist[attr->rta_type] = std::string((char*)RTA_DATA(attr), rta_length);
00275                                                                 break;
00276                                                         }
00277 
00278                                                         attr = RTA_NEXT(attr, attrlen);
00279                                                 }
00280                                                 break;
00281                                         }
00282 
00283                                         case RTM_NEWADDR:
00284                                         {
00285                                                 struct ifaddrmsg *ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh);
00286                                                 struct rtattr *rth = IFA_RTA(ifa);
00287                                                 int rtl = IFA_PAYLOAD(nlh);
00288 
00289                                                 while (rtl && RTA_OK(rth, rtl)) {
00290                                                         if (rth->rta_type == IFA_LOCAL) {
00291                                                                 uint32_t ipaddr = htonl(*((uint32_t *)RTA_DATA(rth)));
00292                                                                 char name[IFNAMSIZ];
00293                                                                 if_indextoname(ifa->ifa_index, name);
00294                                                                 _interface = ibrcommon::vinterface(name);
00295 
00296                                                                 char address[256];
00297                                                                 sprintf(address, "%d.%d.%d.%d", (ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff, (ipaddr >> 8) & 0xff, ipaddr & 0xff);
00298 
00299                                                                 _address = ibrcommon::vaddress(ibrcommon::vaddress::VADDRESS_INET, std::string(address));
00300 
00301                                                                 _type = EVENT_ADDRESS_ADDED;
00302                                                         }
00303                                                         rth = RTA_NEXT(rth, rtl);
00304                                                 }
00305                                                 break;
00306                                         }
00307 
00308                                         case RTM_DELADDR:
00309                                         {
00310                                                 struct ifaddrmsg *ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh);
00311                                                 struct rtattr *rth = IFA_RTA(ifa);
00312                                                 int rtl = IFA_PAYLOAD(nlh);
00313 
00314                                                 while (rtl && RTA_OK(rth, rtl)) {
00315                                                         if (rth->rta_type == IFA_LOCAL) {
00316                                                                 uint32_t ipaddr = htonl(*((uint32_t *)RTA_DATA(rth)));
00317                                                                 char name[IFNAMSIZ];
00318                                                                 if_indextoname(ifa->ifa_index, name);
00319                                                                 _interface = ibrcommon::vinterface(name);
00320 
00321                                                                 char address[256];
00322                                                                 sprintf(address, "%d.%d.%d.%d", (ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff, (ipaddr >> 8) & 0xff, ipaddr & 0xff);
00323 
00324                                                                 _address = ibrcommon::vaddress(ibrcommon::vaddress::VADDRESS_INET, std::string(address));
00325 
00326                                                                 _type = EVENT_ADDRESS_REMOVED;
00327                                                         }
00328                                                         rth = RTA_NEXT(rth, rtl);
00329                                                 }
00330                                                 break;
00331                                         }
00332 
00333                                         default:
00334                                                 IBRCOMMON_LOGGER_DEBUG(10) << "unknown netlink type received: " << nlh->nlmsg_type << IBRCOMMON_LOGGER_ENDL;
00335                                                 break;
00336                                 }
00337 
00338                                 nlh = NLMSG_NEXT(nlh, len);
00339                         }
00340 
00341                         return;
00342                 }
00343         }
00344 
00345         NetLinkManagerEvent::~NetLinkManagerEvent()
00346         {
00347         }
00348 
00349         const ibrcommon::vinterface& NetLinkManagerEvent::getInterface() const
00350         {
00351                 return _interface;
00352         }
00353 
00354         const ibrcommon::vaddress& NetLinkManagerEvent::getAddress() const
00355         {
00356                 return _address;
00357         }
00358 
00359         unsigned int NetLinkManagerEvent::getState() const
00360         {
00361                 return _state;
00362         }
00363 
00364         bool NetLinkManagerEvent::isWirelessExtension() const
00365         {
00366                 return _wireless;
00367         }
00368 
00369         LinkManagerEvent::EventType NetLinkManagerEvent::getType() const
00370         {
00371                 return _type;
00372         }
00373 
00374         const std::string NetLinkManagerEvent::toString() const
00375         {
00376                 std::stringstream ss;
00377                 ss << "NetLinkManagerEvent on " << getInterface().toString() << "; Type: " << getType();
00378 
00379                 switch (getType())
00380                 {
00381                 case EVENT_LINK_STATE:
00382                         ss << "; State: " << getState();
00383                         break;
00384 
00385                 case EVENT_ADDRESS_ADDED:
00386                         ss << "; Address added: " << getAddress().toString();
00387                         break;
00388 
00389                 case EVENT_ADDRESS_REMOVED:
00390                         ss << "; Address removed: " << getAddress().toString();
00391                         break;
00392 
00393                 default:
00394                         break;
00395                 };
00396 
00397                 return ss.str();
00398         }
00399 
00400         void NetLinkManagerEvent::debug() const
00401         {
00402 //              for (std::map<int, std::string>::const_iterator iter = attr.begin(); iter != attr.end(); iter++)
00403 //              {
00404 //                      std::stringstream ss;
00405 //                      const std::string &value = (*iter).second;
00406 //
00407 //                      for (std::string::const_iterator si = value.begin(); si != value.end(); si++)
00408 //                      {
00409 //                              const char &c = (*si);
00410 //                              ss << std::hex << "0x" << (int)c << " ";
00411 //                      }
00412 //
00413 //                      IBRCOMMON_LOGGER_DEBUG(10) << (*iter).first << ": " << ss.str() << IBRCOMMON_LOGGER_ENDL;
00414 //              }
00415         }
00416 
00417         void NetLinkManager::registerInterfaceEvent(const vinterface &iface, LinkManager::EventCallback *cb)
00418         {
00419                 if (cb == NULL) return;
00420                 ibrcommon::MutexLock l(_listener_mutex);
00421 
00422                 std::set<LinkManager::EventCallback* > &ss = _listener[iface];
00423                 ss.insert(cb);
00424         }
00425 
00426         void NetLinkManager::unregisterInterfaceEvent(const vinterface &iface, LinkManager::EventCallback *cb)
00427         {
00428                 if (cb == NULL) return;
00429                 ibrcommon::MutexLock l(_listener_mutex);
00430 
00431                 std::set<LinkManager::EventCallback* > &ss = _listener[iface];
00432 
00433                 ss.erase(cb);
00434 
00435                 if (ss.empty())
00436                 {
00437                         _listener.erase(iface);
00438                 }
00439         }
00440 
00441         void NetLinkManager::unregisterAllEvents(LinkManager::EventCallback *cb)
00442         {
00443                 if (cb == NULL) return;
00444 
00445                 try {
00446                         ibrcommon::MutexLock l(_listener_mutex);
00447 
00448                         for (std::map<vinterface, std::set<LinkManager::EventCallback* > >::iterator iter = _listener.begin(); iter != _listener.end(); iter++)
00449                         {
00450                                 std::set<LinkManager::EventCallback* > &ss = iter->second;
00451                                 ss.erase(cb);
00452                         }
00453                 } catch (const ibrcommon::MutexException&) {
00454                         // this happens if this method is called after destroying the object
00455                         // and is normal at shutdown
00456                 }
00457         }
00458 }