50 class InterfacesNotifierImp ;
59 static bool active() ;
63 template <
typename T> std::pair<T*,std::size_t> readSocket() ;
67 std::unique_ptr<RawSocket> m_socket ;
74 return InterfacesNotifierImp::active() ;
77void GNet::Interfaces::loadImp(
ExceptionSink es , std::vector<Item> & list )
80 m_notifier = std::make_unique<InterfacesNotifierImp>(
this , es ) ;
82 ifaddrs * info_p = nullptr ;
83 int rc = getifaddrs( &info_p ) ;
90 using deleter_fn_t = std::function<void(ifaddrs*)> ;
91 using deleter_t = std::unique_ptr<ifaddrs,deleter_fn_t> ;
92 deleter_t deleter( info_p , deleter_fn_t(freeifaddrs) ) ;
94 const std::size_t nmax = AddressStorage().n() ;
95 const bool scope_id_fixup = G::is_bsd() ;
96 for( ; info_p != nullptr ; info_p = info_p->ifa_next )
98 G_ASSERT( info_p->ifa_name && info_p->ifa_name[0] ) ;
99 if( info_p->ifa_name ==
nullptr )
102 G_ASSERT( info_p->ifa_addr ) ;
103 if( info_p->ifa_addr ==
nullptr )
110 item.name = std::string( info_p->ifa_name ) ;
111 item.address_family = info_p->ifa_addr->sa_family ;
112 item.address = Address( info_p->ifa_addr , nmax , scope_id_fixup ) ;
113 item.valid_address = !item.address.isAny() ;
114 item.up = !!( info_p->ifa_flags & IFF_UP ) ;
115 item.loopback = !!( info_p->ifa_flags & IFF_LOOPBACK ) ;
116 item.has_netmask = info_p->ifa_netmask != nullptr ;
118 if( item.has_netmask )
120 if( info_p->ifa_netmask->sa_family == AF_UNSPEC )
121 info_p->ifa_netmask->sa_family = info_p->ifa_addr->sa_family ;
123 Address netmask( info_p->ifa_netmask , nmax ) ;
124 item.netmask_bits = netmask.bits() ;
127 list.push_back( item ) ;
134std::pair<T*,std::size_t> GNet::InterfacesNotifierImp::readSocket()
136 static_assert(
sizeof(T) <= 4096U ,
"" ) ;
137 m_buffer.resize( 4096U ) ;
139 ssize_t rc = m_socket->read( &m_buffer[0] , m_buffer.size() ) ;
146 T * p = G::buffer_cast<T*>( m_buffer , std::nothrow ) ;
147 std::size_t n =
static_cast<std::size_t
>( rc >= 0 && p ? rc : 0 ) ;
153 return std::string() ;
156#if GCONFIG_HAVE_RTNETLINK
158#include <asm/types.h>
159#include <sys/socket.h>
160#include <linux/netlink.h>
161#include <linux/rtnetlink.h>
163bool GNet::InterfacesNotifierImp::active()
168GNet::InterfacesNotifierImp::InterfacesNotifierImp( Interfaces * outer , ExceptionSink es )
172 union netlink_address_union
174 struct sockaddr_nl specific ;
175 struct sockaddr generic ;
177 netlink_address_union address {} ;
178 address.specific.nl_family = AF_NETLINK ;
179 #if GCONFIG_HAVE_IPV6
180 address.specific.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR ;
182 address.specific.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR ;
186 m_socket = std::make_unique<RawSocket>( AF_NETLINK , SOCK_RAW , NETLINK_ROUTE ) ;
187 int rc = ::bind( m_socket->fd() , &address.generic ,
sizeof(address.specific) ) ;
192 m_socket->addReadHandler( *outer , es ) ;
198 auto buffer_pair = readSocket<nlmsghdr>() ;
200 const nlmsghdr * hdr = buffer_pair.first ;
201 std::size_t size = buffer_pair.second ;
202 if( hdr ==
nullptr || size == 0U )
203 return std::string() ;
205 const char * sep =
"" ;
206 std::ostringstream ss ;
207 for( ; NLMSG_OK(hdr,size) ; hdr = NLMSG_NEXT(hdr,size) , sep =
", " )
209 if( hdr->nlmsg_type == NLMSG_DONE || hdr->nlmsg_type == NLMSG_ERROR )
212 if( hdr->nlmsg_type == RTM_NEWLINK ||
213 hdr->nlmsg_type == RTM_DELLINK ||
214 hdr->nlmsg_type == RTM_GETLINK )
216 GDEF_UNUSED ifinfomsg * p =
static_cast<ifinfomsg*
>( NLMSG_DATA(hdr) ) ;
217 GDEF_UNUSED
int n = NLMSG_PAYLOAD( hdr , size ) ;
218 ss << sep <<
"link" ;
219 if( hdr->nlmsg_type == RTM_NEWLINK ) ss <<
" new" ;
220 if( hdr->nlmsg_type == RTM_DELLINK ) ss <<
" deleted" ;
222 else if( hdr->nlmsg_type == RTM_NEWADDR ||
223 hdr->nlmsg_type == RTM_DELADDR ||
224 hdr->nlmsg_type == RTM_GETADDR )
226 GDEF_UNUSED ifaddrmsg * p =
static_cast<ifaddrmsg*
>( NLMSG_DATA(hdr) ) ;
227 GDEF_UNUSED
int n = NLMSG_PAYLOAD( hdr , size ) ;
228 ss << sep <<
"address" ;
229 if( hdr->nlmsg_type == RTM_NEWADDR ) ss <<
" new" ;
230 if( hdr->nlmsg_type == RTM_DELADDR ) ss <<
" deleted" ;
238#if GCONFIG_HAVE_NETROUTE
241#include <net/route.h>
243bool GNet::InterfacesNotifierImp::active()
248GNet::InterfacesNotifierImp::InterfacesNotifierImp( Interfaces * outer , ExceptionSink es )
254 m_socket = std::make_unique<RawSocket>( PF_ROUTE , SOCK_RAW , AF_UNSPEC ) ;
256 m_socket->addReadHandler( *outer , es ) ;
262 using Header =
struct rt_msghdr ;
264 auto buffer_pair = readSocket<Header>() ;
265 if( buffer_pair.second >= 4U )
267 Header * p = buffer_pair.first ;
268 if( p->rtm_msglen != buffer_pair.second )
269 G_DEBUG(
"GNet::InterfacesNotifierImp::readEvent: invalid message length" ) ;
270 if( p->rtm_type == RTM_NEWADDR )
271 result =
"address new" ;
272 else if( p->rtm_type == RTM_DELADDR )
273 result =
"address deleted" ;
274 else if( p->rtm_type == RTM_IFINFO )
275 result =
"interface change" ;
282bool GNet::InterfacesNotifierImp::active()
287GNet::InterfacesNotifierImp::InterfacesNotifierImp( Interfaces * , ExceptionSink )
293 return std::string() ;
static bool supports(Family)
Returns true if the implementation supports the given address family.
static bool exists()
Returns true if an instance exists.
A tuple containing an ExceptionHandler interface pointer and a bound 'exception source' pointer.
Handles read events on a routing netlink socket.
std::string readEvent() override
Called by GNet::Interfaces to handle a read event.
std::string onFutureEvent() override
Called by GNet::Interfaces to handle a future event.
A pimple base-class used by GNet::Interfaces.
A class for getting a list of network interfaces and their addresses.
static bool active()
Returns true if the implementation can raise InterfacesHandler events.
A general-purpose exception class derived from std::exception and containing an error message.
static std::string strerror(int errno_)
Translates an 'errno' value into a meaningful diagnostic string.
static int errno_(const SignalSafe &=G::SignalSafe()) noexcept
Returns the process's current 'errno' value.
A class which acquires the process's special privileges on construction and releases them on destruct...