• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

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/socket.h>
00013 #include <netlink/route/rtnl.h>
00014 #include <netlink/route/link.h>
00015 #include <netlink/route/addr.h>
00016 #include <netlink/genl/genl.h>
00017 #include <netlink/genl/ctrl.h>
00018 
00019 #include <netdb.h>
00020 #include <sys/socket.h>
00021 #include <sys/types.h>
00022 #include <netinet/tcp.h>
00023 #include <sys/un.h>
00024 #include <errno.h>
00025 #include <string.h>
00026 #include <fcntl.h>
00027 #include <signal.h>
00028 #include <arpa/inet.h>
00029 
00030 #include <iostream>
00031 #include <sstream>
00032 
00033 namespace ibrcommon
00034 {
00035         NetLinkManager::NetLinkManager()
00036          : _initialized(false), _sock(NULL)
00037         {
00038                 ibrcommon::MutexLock l(_call_mutex);
00039 
00040                 _handle = nl_handle_alloc();
00041                 nl_connect(_handle, NETLINK_ROUTE);
00042 
00043                 _link_cache = rtnl_link_alloc_cache(_handle);
00044                 _addr_cache = rtnl_addr_alloc_cache(_handle);
00045 
00046                 _initialized = true;
00047 
00048                 // create a new socket for the netlink interface
00049                 _sock = new ibrcommon::vsocket();
00050         }
00051 
00052         NetLinkManager::~NetLinkManager()
00053         {
00054                 stop();
00055                 join();
00056 
00057                 // destroy the socket for the netlink interface
00058                 _sock = new ibrcommon::vsocket();
00059 
00060                 nl_close(_handle);
00061                 nl_cache_free(_addr_cache);
00062                 nl_cache_free(_link_cache);
00063                 nl_handle_destroy(_handle);
00064         }
00065 
00066         void add_addr_to_list(struct nl_object *obj, void *data)
00067         {
00068                 char buf[INET6_ADDRSTRLEN+5];
00069                 std::list<vaddress> *list = static_cast<std::list<vaddress>*>(data);
00070 
00071                 struct nl_addr *naddr = rtnl_addr_get_local((struct rtnl_addr *) obj);
00072                 int ifindex = 0;
00073                 int scope = rtnl_addr_get_scope((struct rtnl_addr *) obj);
00074 
00075                 if (scope == rtnl_str2scope("link"))
00076                         ifindex = rtnl_addr_get_ifindex((struct rtnl_addr *) obj);
00077 
00078                 if (naddr)
00079                 {
00080                         int family = nl_addr_get_family(naddr);
00081                         nl_addr2str( naddr, buf, sizeof( buf ) );
00082                         vaddress vaddr(vaddress::Family(family), std::string(buf), ifindex, false);
00083                         list->push_back( vaddr );
00084                 }
00085 
00086                 struct nl_addr *baddr = rtnl_addr_get_broadcast((struct rtnl_addr *) obj);
00087 
00088                 if (baddr)
00089                 {
00090                         int family = nl_addr_get_family(baddr);
00091                         nl_addr2str( baddr, buf, sizeof( buf ) );
00092                         vaddress vaddr(vaddress::Family(family), std::string(buf), ifindex, true);
00093                         list->push_back( vaddr );
00094                 }
00095         }
00096 
00097         bool NetLinkManager::__cancellation()
00098         {
00099                 ibrcommon::MutexLock l(_call_mutex);
00100                 _initialized = false;
00101                 ibrcommon::interrupt(*_sock, *this);
00102 
00103                 return true;
00104         }
00105 
00106         void NetLinkManager::run()
00107         {
00108                 Thread::enable_interruption();
00109 
00110                 struct nl_handle *handle = nl_handle_alloc();
00111                 nl_connect(handle, NETLINK_ROUTE);
00112 
00113                 // init route messages
00114                 nl_socket_add_membership(handle, RTMGRP_IPV6_IFADDR);
00115                 nl_socket_add_membership(handle, RTMGRP_IPV4_IFADDR);
00116                 nl_socket_add_membership(handle, RTMGRP_LINK);
00117 
00118                 // add netlink fd to vsocket
00119                 _sock->add(nl_socket_get_fd(handle));
00120 
00121                 try {
00122                         while (_initialized)
00123                         {
00124                                 std::list<int> fds;
00125                                 ibrcommon::select(*_sock, fds, NULL);
00126                                 int fd = fds.front();
00127 
00128                                 std::map<int, std::string> attr = read_nlmsg(fd);
00129                                 std::string ifname(attr[IFLA_IFNAME]);
00130                                 vinterface iface(ifname.substr(0, ifname.length() - 1));
00131 
00132                                 // search for event subscriptions
00133                                 ibrcommon::MutexLock l(_listener_mutex);
00134                                 const std::set<LinkManager::EventCallback* > &ss = _listener[iface];
00135 
00136                                 for (std::set<LinkManager::EventCallback* >::iterator iter = ss.begin(); iter != ss.end(); iter++)
00137                                 {
00138                                         IBRCOMMON_LOGGER_DEBUG(10) << "one socket has subscribed action on interface: " << iface.toString() << IBRCOMMON_LOGGER_ENDL;
00139                                 }
00140                         }
00141                 } catch (const vsocket_exception&) {
00142                         // stopped / interrupted
00143                 }
00144 
00145                 nl_close(handle);
00146                 nl_handle_destroy(handle);
00147         }
00148 
00149         const std::list<vaddress> NetLinkManager::getAddressList(const vinterface &interface, const vaddress::Family f)
00150         {
00151                 ibrcommon::MutexLock l(_call_mutex);
00152 
00153                 std::list<vaddress> addresses;
00154 
00155                 struct rtnl_addr *filter = rtnl_addr_alloc();
00156                 const std::string i = interface.toString();
00157                 rtnl_addr_set_ifindex(filter, rtnl_link_name2i(_link_cache, i.c_str()));
00158 
00159                 if (f == vaddress::VADDRESS_UNSPEC)
00160                 {
00161                         rtnl_addr_set_family(filter, AF_INET6);
00162                         nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
00163                                                                         add_addr_to_list, &addresses);
00164 
00165                         rtnl_addr_set_family(filter, AF_INET);
00166                         nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
00167                                                                         add_addr_to_list, &addresses);
00168                 }
00169                 else
00170                 {
00171                         rtnl_addr_set_family(filter, f);
00172                         nl_cache_foreach_filter(_addr_cache, (struct nl_object *) filter,
00173                                                                         add_addr_to_list, &addresses);
00174                 }
00175 
00176                 rtnl_addr_put(filter);
00177 
00178                 return addresses;
00179         }
00180 
00181         const std::string NetLinkManager::getInterface(const int ifindex) const
00182         {
00183                 char buf[256];
00184                 rtnl_link_i2name(_link_cache, ifindex, (char*)&buf, sizeof buf);
00185                 return std::string((char*)&buf);
00186         }
00187 
00188         std::map<int, std::string> NetLinkManager::read_nlmsg(int fd)
00189         {
00190                 char buf[1024];
00191                 int left;
00192                 struct sockaddr_nl from;
00193                 socklen_t fromlen;
00194                 struct nlmsghdr *h;
00195 
00196                 fromlen = sizeof(from);
00197 
00198                 // receive the netlink message
00199                 left = recvfrom(fd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr *) &from, &fromlen);
00200 
00201                 if (left < 0 && errno != EINTR && errno != EAGAIN)
00202                 {
00203                         throw parse_exception("recvfrom(netlink) failed");
00204                 }
00205 
00206                 // cast netlink message
00207                 h = (struct nlmsghdr *) buf;
00208 
00209                 std::map<int, std::string> attrlist;
00210 
00211                 while (left >= sizeof(*h))
00212                 {
00213                         int len, plen;
00214 
00215                         len = h->nlmsg_len;
00216 
00217                         plen = len - sizeof(*h);
00218 
00219                         if (len > left || plen < 0)
00220                         {
00221                                 throw parse_exception("Malformed netlink message");
00222                         }
00223 
00224                         if (h->nlmsg_type == RTM_BASE)
00225                         {
00226                                 struct ifinfomsg *ifi;
00227                                 int attrlen, nlmsg_len, rta_len;
00228                                 struct rtattr * attr;
00229 
00230                                 if (len < sizeof(*ifi)) return attrlist;
00231 
00232                                 ifi = (struct ifinfomsg *)NLMSG_DATA(h);
00233 
00234                                 nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
00235 
00236                                 attrlen = h->nlmsg_len - nlmsg_len;
00237                                 if (attrlen < 0) return attrlist;
00238 
00239                                 attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
00240 
00241                                 rta_len = RTA_ALIGN(sizeof(struct rtattr));
00242                                 while (RTA_OK(attr, attrlen))
00243                                 {
00244                                         size_t rta_length = RTA_PAYLOAD(attr);
00245                                         std::string payload((char*)RTA_DATA(attr), rta_length);
00246 
00247                                         attrlist[attr->rta_type] = payload;
00248                                         attr = RTA_NEXT(attr, attrlen);
00249                                 }
00250                         }
00251 
00252                         len = NLMSG_ALIGN(len);
00253                         left -= len;
00254                         h = (struct nlmsghdr *) ((char *) h + len);
00255                 }
00256 
00257                 return attrlist;
00258         }
00259 
00260         void NetLinkManager::registerInterfaceEvent(const vinterface &iface, LinkManager::EventCallback *cb)
00261         {
00262                 if (cb == NULL) return;
00263                 ibrcommon::MutexLock l(_listener_mutex);
00264 
00265                 std::set<LinkManager::EventCallback* > &ss = _listener[iface];
00266                 ss.insert(cb);
00267         }
00268 
00269         void NetLinkManager::unregisterInterfaceEvent(const vinterface &iface, LinkManager::EventCallback *cb)
00270         {
00271                 if (cb == NULL) return;
00272                 ibrcommon::MutexLock l(_listener_mutex);
00273 
00274                 std::set<LinkManager::EventCallback* > &ss = _listener[iface];
00275 
00276                 ss.erase(cb);
00277 
00278                 if (ss.empty())
00279                 {
00280                         _listener.erase(iface);
00281                 }
00282         }
00283 
00284         void NetLinkManager::unregisterAllEvents(LinkManager::EventCallback *cb)
00285         {
00286                 if (cb == NULL) return;
00287 
00288                 try {
00289                         ibrcommon::MutexLock l(_listener_mutex);
00290 
00291                         for (std::map<vinterface, std::set<LinkManager::EventCallback* > >::iterator iter = _listener.begin(); iter != _listener.end(); iter++)
00292                         {
00293                                 std::set<LinkManager::EventCallback* > &ss = iter->second;
00294                                 ss.erase(cb);
00295                         }
00296                 } catch (const ibrcommon::MutexException&) {
00297                         // this happens if this method is called after destroying the object
00298                         // and is normal at shutdown
00299                 }
00300         }
00301 }

Generated on Thu Mar 10 2011 15:44:03 for IBR-DTNSuite by  doxygen 1.7.1