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