diff --git a/CMakeLists.txt b/CMakeLists.txt index f7e2f1cdd8b5f20dc399027d0d0018254341fbf7..559659b763452036d1a2e90387637f016defc73f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,9 @@ tdaq_add_library(asyncmsg src/Session.cxx src/NameService.cxx src/UDPSession.cxx + src/Interface.cxx OPTIONS -O3 - LINK_LIBRARIES transport is Boost::system) + LINK_LIBRARIES is Boost::system) tdaq_add_executable(test_namesvc NOINSTALL test/test_namesvc.cxx diff --git a/cmt/requirements b/cmt/requirements deleted file mode 100644 index 3c7e12f4794471375f80ebe31c05ce36064fc906..0000000000000000000000000000000000000000 --- a/cmt/requirements +++ /dev/null @@ -1,46 +0,0 @@ -package asyncmsg - -author Tommaso.Colombo@cern.ch -manager Tommaso.Colombo@cern.ch - -use TDAQPolicy - -use Boost * TDAQCExternal - -use is -use transport - -private - -library asyncmsg "Error.cxx Server.cxx Session.cxx NameService.cxx UDPSession.cxx" -macro asyncmsg_cppflags "-O3" -macro asyncmsg_shlibflags "-lboost_system-${boost_libsuffix} -lis -ltransport" -apply_pattern install_headers src_dir="../asyncmsg/detail" files="*.h" target_dir="detail" -apply_pattern install_libs files="libasyncmsg.so" - -apply_pattern install_data name=isschema files="../schema/MsgInfo_is.schema.xml"\ - target_dir="schema" -macro sw.repository.is-info-file.share/data/asyncmsg/schema/MsgInfo_is.schema.xml:name "MsgInfo IS xml description" - - -# Test programs for name service -# -# This only requires a minimal partition with -# one ipc_server and one IS server called 'DF' -# - -application test_namesvc ../test/test_namesvc.cxx -macro_append test_namesvclinkopts "-lasyncmsg" -macro_append test_namesvc_dependencies "asyncmsg" - -application test_udpsession ../test/test_udpsession.cxx -macro_append test_udpsessionlinkopts "-lasyncmsg" -macro_append test_udpsession_dependencies "asyncmsg" - -# -# This is usually just needed for a special test inside a partition. -# - -# application test_lookup ../test/test_lookup.cxx -# macro_append test_lookuplinkopts "-lasyncmsg -lItemCtrl -lcmdline" -# macro_append test_lookup_dependencies "asyncmsg" diff --git a/src/Interface.cxx b/src/Interface.cxx new file mode 100644 index 0000000000000000000000000000000000000000..edc64b15c7bb3eb55ee2aeda22afcb827ffcc42b --- /dev/null +++ b/src/Interface.cxx @@ -0,0 +1,257 @@ + +#include <string.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <netinet/ether.h> +#include <ifaddrs.h> +#include <netdb.h> +#include "Interface.h" + +#include <iostream> + +namespace daq { + + namespace asyncmsg { + + class Cleanup { + public: + ~Cleanup(); + }; + + // static + std::vector<const Interface *> Interface::s_interfaces; + struct ifaddrs *Interface::s_addresses = 0; + + Cleanup s_cleanup; + + // Interface::Cleanup s_cleanup; + + /** + * Information about a network interface. + * + * This basically encapsulates the information returned + * by various ioctls() in a 'struct ifreq'. + * + * Only the IPv4 address family is supported at + * the moment and only Ethernet HW addresses are known. + */ + + /** The interface name, e.g. eth0 */ + const std::string Interface::name() const + { + return m_addr->ifa_name; + } + + // Return the address family. + int Interface::family() const + { + return m_addr->ifa_addr->sa_family; + } + + /** The internal interface index (usually starting at 1) */ + int Interface::index() const + { + return if_nametoindex(m_addr->ifa_name); + } + + /** The various flags in net/if.h for interfaces */ + int Interface::flags() const + { + return m_addr->ifa_flags; + } + + /** Return true if the corresponding flag from net/if.h is set */ + bool Interface::has_flag(int flag) const + { + return m_addr->ifa_flags & flag; + } + + /** The IP address of this interface or 0 */ + in_addr_t Interface::address() const + { + if(m_addr->ifa_addr->sa_family == AF_INET) { + return ((sockaddr_in *)m_addr->ifa_addr)->sin_addr.s_addr; + } else { + return 0; + } + } + + /** The IP address of this interface or 0 */ + in6_addr Interface::address_v6() const + { + if(m_addr->ifa_addr->sa_family == AF_INET6 ) { + return ((sockaddr_in6 *)m_addr->ifa_addr)->sin6_addr; + } else { + return in6addr_any; + } + } + + /** The IP address of this interface as a string or "" */ + std::string Interface::address_string() const + { + char buf[INET6_ADDRSTRLEN+1]= { 0 }; + getnameinfo(m_addr->ifa_addr, sizeof(sockaddr_storage), buf, sizeof(buf), 0, 0, NI_NUMERICHOST); + return buf; + } + + /** The broadcast IP address of this interface or 0 */ + in_addr_t Interface::broadcast() const + { + if(m_addr->ifa_addr->sa_family == AF_INET) { + return ((sockaddr_in *)m_addr->ifa_broadaddr)->sin_addr.s_addr; + } else { + return 0; + } + } + + /** The broadcast IP address as a string or "" */ + std::string Interface::broadcast_string() const + { + char buf[INET_ADDRSTRLEN] = { 0 }; + if(m_addr->ifa_addr->sa_family == AF_INET && m_addr->ifa_broadaddr) { + getnameinfo(m_addr->ifa_broadaddr, sizeof(sockaddr_in), buf, sizeof(buf), 0, 0, NI_NUMERICHOST); + } + return buf; + } + + + /** The netmask for this interface or 0 */ + in_addr_t Interface::netmask() const + { + return ((sockaddr_in *)m_addr->ifa_netmask)->sin_addr.s_addr; + } + + /** The IP v6 netmask for this interface */ + in6_addr Interface::netmask_v6() const + { + return ((sockaddr_in6 *)m_addr->ifa_netmask)->sin6_addr; + } + + /** The netmask for this interface or 0 */ + std::string Interface::netmask_string() const + { + char buf[INET6_ADDRSTRLEN+1]= { 0 }; + getnameinfo(m_addr->ifa_netmask, sizeof(sockaddr_storage), buf, sizeof(buf), 0, 0, NI_NUMERICHOST); + return buf; + } + + /** Network: address masked with netmask */ + in_addr_t Interface::network() const + { + return ((sockaddr_in *)m_addr->ifa_addr)->sin_addr.s_addr & ((sockaddr_in *)m_addr->ifa_netmask)->sin_addr.s_addr; + } + + /** Network: address masked with netmask, IPV6*/ + in6_addr Interface::network_v6() const + { + in6_addr result = ((sockaddr_in6 *)m_addr->ifa_addr)->sin6_addr; + for(int i = 0; i < 4; i++) { + result.s6_addr32[i] &= ((sockaddr_in6 *)m_addr->ifa_netmask)->sin6_addr.s6_addr32[i]; + } + return result; + } + + +#if 0 + /** The Ethernet hw address of the interface */ + ether_addr Interface::hw_address() const + { + ether_addr addr; + memcpy(&addr, m_addr->ifa_addr->sa_data, sizeof(ether_addr)); + return addr; + } + + std::string Interface::hw_address_string() const + { + char buffer[20]; + return ether_ntoa_r((const ether_addr *)m_addr->ifa_addr->sa_data, buffer); + } +#endif + + /** Find interface by index.*/ + const Interface *Interface::find(int index, int af) + { + const InterfaceList& if_list = interfaces(); + for(InterfaceList::const_iterator it = if_list.begin(); + it != if_list.end(); + ++it) { + if((*it)->index() == index && (*it)->family() == af) return *it; + } + return 0; + } + + /// Find interface by name. + const Interface *Interface::find(const std::string& name, int af) + { + const InterfaceList& if_list = interfaces(); + for(InterfaceList::const_iterator it = if_list.begin(); + it != if_list.end(); + ++it) { + if((*it)->name() == name && (*it)->family() == af) return *it; + } + return 0; + } + + /// Return list of all interfaces. + const Interface::InterfaceList& Interface::interfaces() + { + if(s_interfaces.size() == 0) { + + getifaddrs(&s_addresses); + struct ifaddrs *ptr = s_addresses; + + while(ptr) { + if(ptr->ifa_addr->sa_family == AF_INET || ptr->ifa_addr->sa_family == AF_INET6) { + s_interfaces.push_back(new Interface(ptr)); + } + ptr = ptr->ifa_next; + } + } + + return s_interfaces; + } + + Interface::Interface(ifaddrs *addr) + : m_addr(addr) + { + } + + Interface::~Interface() + { + } + + Cleanup::~Cleanup() + { + for(Interface::InterfaceList::const_iterator it = Interface::s_interfaces.begin(); + it != Interface::s_interfaces.end(); + ++it) { + delete *it; + } + freeifaddrs(Interface::s_addresses); + } + + std::ostream& operator<<(std::ostream& os, const Interface& intf) + { + switch (intf.family()) { + case AF_INET: + case AF_INET6: + os << intf.address_string() << '/' << intf.netmask_string(); + break; + default: + os << intf.name() << ": " << "Unkwown interface type: " << intf.family() ; + break; + } + + return os; + } + + bool operator==(const in6_addr& a, const in6_addr& b) + { + return memcmp(&a,&b, sizeof(in6_addr)) == 0; + } + + } +} + diff --git a/src/Interface.h b/src/Interface.h new file mode 100644 index 0000000000000000000000000000000000000000..4290d75e8125d2c66e0fc371fc30710f18beb0fb --- /dev/null +++ b/src/Interface.h @@ -0,0 +1,118 @@ +// this is -*- c++ -*- +#ifndef TRANSPORT_INTERFACE_H_ +#define TRANSPORT_INTERFACE_H_ + +#include <string> +#include <vector> +#include <iosfwd> + +#include <net/if.h> +#include <netinet/in.h> +#include <net/ethernet.h> + +// fwd declaration +struct ifaddrs; + +namespace daq { + namespace asyncmsg { + + // Internal helper class + class Cleanup; + + /** + * Information about a network interface. + * + * This basically encapsulates the information returned + * by getifaddrs(). + * + * Both IP V4 and V6 are supported. + */ + class Interface { + public: + + /** The interface name, e.g. eth0 */ + const std::string name() const; + + /** The address family for this Interface + * One of AF_INET, AF_INET6, AF_PACKET + */ + int family() const; + + /** The internal interface index (usually starting at 1) */ + int index() const; + + /** The various flags in net/if.h for interfaces */ + int flags() const; + + /** Return true if the corresponding flag from net/if.h is set */ + bool has_flag(int flag) const; + + /** The IP address of this interface or 0 */ + in_addr_t address() const; + + /** The IP V6 address of this interface */ + in6_addr address_v6() const; + + /** The IP address of this interface as a string or "" */ + std::string address_string() const; + + /** The broadcast IP address of this interface or 0 */ + in_addr_t broadcast() const; + + /** The broadcast IP address as a string or "" */ + std::string broadcast_string() const; + + /** The netmask for this interface or 0 */ + in_addr_t netmask() const; + + /** The IP V6 netmask of this interface */ + in6_addr netmask_v6() const; + + /** Network: address masked with netmask */ + in_addr_t network() const; + + /** Network: address masked with netmask, IPV6*/ + in6_addr network_v6() const; + + /** The netmask for this interface or 0 */ + std::string netmask_string() const; + +#if 0 + /** The Ethernet hw address of the interface */ + ether_addr hw_address() const; + + std::string hw_address_string() const; +#endif + public: + /** Find interface by index.*/ + static const Interface *find(int index, int af = AF_INET); + + /// Find interface by name. + static const Interface *find(const std::string& name, int af = AF_INET); + + typedef std::vector<const Interface *> InterfaceList; + + /// Return list of all interfaces. + static const InterfaceList& interfaces(); + + private: + Interface(struct ifaddrs *addr); + ~Interface(); + + // Representation + struct ifaddrs *m_addr; + + friend class Cleanup; + + /// Global list of all interfaces + static InterfaceList s_interfaces; + static struct ifaddrs *s_addresses; + }; + + std::ostream& operator<<(std::ostream& os, const Interface& ); + + bool operator==(const in6_addr& , const in6_addr& ); + } +} + +#endif // TRANSPORT_INTERFACE_H_ diff --git a/src/NameService.cxx b/src/NameService.cxx index 0b9ce4c699cea2a9a346e77918688e7d43d41375..9e67dd3a9435192e46928d588977dca96a5263c4 100644 --- a/src/NameService.cxx +++ b/src/NameService.cxx @@ -1,7 +1,7 @@ #include "asyncmsg/NameService.h" -#include "transport/Interface.h" +#include "Interface.h" #include "MsgInfo.h" #include "MultiCastGroup.h" @@ -73,7 +73,7 @@ namespace daq { info.Hostname = host; info.Port = port; - const daq::transport::Interface::InterfaceList& interfaces = daq::transport::Interface::interfaces(); + const daq::asyncmsg::Interface::InterfaceList& interfaces = daq::asyncmsg::Interface::interfaces(); for(auto intf : interfaces) { @@ -176,7 +176,7 @@ namespace daq { bool NameService::matches(const boost::asio::ip::address& addr, const boost::asio::ip::address& mask) const { - for(const auto intf : daq::transport::Interface::interfaces()) { + for(const auto intf : daq::asyncmsg::Interface::interfaces()) { // ignore these if(!intf->has_flag(IFF_UP) || intf->has_flag(IFF_LOOPBACK) || intf->address() == 0) { @@ -351,7 +351,7 @@ namespace daq { auto addr = boost::asio::ip::address::from_string(local_mask).to_v4(); auto mask = boost::asio::ip::address::from_string(mc_mask).to_v4(); - auto interfaces = daq::transport::Interface::interfaces(); + auto interfaces = daq::asyncmsg::Interface::interfaces(); for(auto intf : interfaces) { if(!intf->has_flag(IFF_UP) || intf->has_flag(IFF_LOOPBACK)) { continue;