51 class InterfacesNotifierImp ;
57class GNet::InterfacesNotifierImp :
public InterfacesNotifier
60 static bool active() ;
61 InterfacesNotifierImp( Interfaces * , EventState es ) ;
62 template <
typename T> std::pair<T*,std::size_t> readSocket() ;
70 std::unique_ptr<RawSocket> m_socket ;
77 return InterfacesNotifierImp::active() ;
80void GNet::Interfaces::loadImp( EventState es , std::vector<Item> & list )
83 m_notifier = std::make_unique<InterfacesNotifierImp>(
this , es ) ;
85 ifaddrs * info_p = nullptr ;
86 int rc = getifaddrs( &info_p ) ;
93 using deleter_fn_t = std::function<void(ifaddrs*)> ;
94 using deleter_t = std::unique_ptr<ifaddrs,deleter_fn_t> ;
95 deleter_t deleter( info_p , deleter_fn_t(freeifaddrs) ) ;
97 const std::size_t nmax = AddressStorage().n() ;
98 const bool scope_id_fixup = G::is_bsd() ;
99 for( ; info_p != nullptr ; info_p = info_p->ifa_next )
101 G_ASSERT( info_p->ifa_name && info_p->ifa_name[0] ) ;
102 if( info_p->ifa_name ==
nullptr )
105 if( info_p->ifa_addr ==
nullptr )
112 item.name = std::string( info_p->ifa_name ) ;
113 item.ifindex = index( item.name ) ;
114 item.address_family = info_p->ifa_addr->sa_family ;
115 item.address = Address( info_p->ifa_addr , nmax , scope_id_fixup ) ;
116 item.valid_address = !item.address.isAny() ;
117 item.up = !!( info_p->ifa_flags & IFF_UP ) ;
118 item.loopback = !!( info_p->ifa_flags & IFF_LOOPBACK ) ;
119 item.has_netmask = info_p->ifa_netmask != nullptr ;
121 if( item.has_netmask )
123 if( info_p->ifa_netmask->sa_family == AF_UNSPEC )
124 info_p->ifa_netmask->sa_family = info_p->ifa_addr->sa_family ;
126 Address netmask( info_p->ifa_netmask , nmax ) ;
127 item.netmask_bits = netmask.bits() ;
130 list.push_back( item ) ;
134#if GCONFIG_HAVE_IFINDEX
135#include <sys/ioctl.h>
137int GNet::Interfaces::index(
const std::string & name )
139 struct ifreq req {} ;
141 int fd = socket( AF_INET , SOCK_DGRAM , 0 ) ;
142 if( fd < 0 )
return 0 ;
143 int rc = ioctl( fd , SIOCGIFINDEX , &req ,
sizeof(req) ) ;
145 return rc ? 0 : req.ifr_ifindex ;
148int GNet::Interfaces::index(
const std::string & )
157std::pair<T*,std::size_t> GNet::InterfacesNotifierImp::readSocket()
159 static_assert(
sizeof(T) <= 4096U ,
"" ) ;
160 m_buffer.resize( 4096U ) ;
162 ssize_t rc = m_socket->read( m_buffer.data() , m_buffer.size() ) ;
169 T * p = G::buffer_cast<T*>( m_buffer , std::nothrow ) ;
170 std::size_t n =
static_cast<std::size_t
>( rc >= 0 && p ? rc : 0 ) ;
179#if GCONFIG_HAVE_RTNETLINK
181#include <asm/types.h>
182#include <sys/socket.h>
183#include <linux/netlink.h>
184#include <linux/rtnetlink.h>
186bool GNet::InterfacesNotifierImp::active()
191GNet::InterfacesNotifierImp::InterfacesNotifierImp( Interfaces * outer , EventState es )
195 union netlink_address_union
197 struct sockaddr_nl specific ;
198 struct sockaddr generic ;
200 netlink_address_union address {} ;
201 address.specific.nl_family = AF_NETLINK ;
202 #if GCONFIG_HAVE_IPV6
203 address.specific.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR ;
205 address.specific.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR ;
209 m_socket = std::make_unique<RawSocket>( AF_NETLINK , SOCK_RAW , NETLINK_ROUTE ) ;
210 int rc = ::bind( m_socket->fd() , &address.generic ,
sizeof(address.specific) ) ;
215 m_socket->addReadHandler( *outer , es ) ;
221 auto buffer_pair = readSocket<nlmsghdr>() ;
223 const nlmsghdr * hdr = buffer_pair.first ;
224 std::size_t size = buffer_pair.second ;
225 if( hdr ==
nullptr || size == 0U )
228 const char * sep =
"" ;
229 std::ostringstream ss ;
230 for( ; NLMSG_OK(hdr,size) ; hdr = NLMSG_NEXT(hdr,size) , sep =
", " )
232 if( hdr->nlmsg_type == NLMSG_DONE || hdr->nlmsg_type == NLMSG_ERROR )
235 if( hdr->nlmsg_type == RTM_NEWLINK ||
236 hdr->nlmsg_type == RTM_DELLINK ||
237 hdr->nlmsg_type == RTM_GETLINK )
239 GDEF_UNUSED ifinfomsg * p =
static_cast<ifinfomsg*
>( NLMSG_DATA(hdr) ) ;
240 GDEF_UNUSED
int n = NLMSG_PAYLOAD( hdr , size ) ;
241 ss << sep <<
"link" ;
242 if( hdr->nlmsg_type == RTM_NEWLINK ) ss <<
" new" ;
243 if( hdr->nlmsg_type == RTM_DELLINK ) ss <<
" deleted" ;
245 else if( hdr->nlmsg_type == RTM_NEWADDR ||
246 hdr->nlmsg_type == RTM_DELADDR ||
247 hdr->nlmsg_type == RTM_GETADDR )
249 GDEF_UNUSED ifaddrmsg * p =
static_cast<ifaddrmsg*
>( NLMSG_DATA(hdr) ) ;
250 GDEF_UNUSED
int n = NLMSG_PAYLOAD( hdr , size ) ;
251 ss << sep <<
"address" ;
252 if( hdr->nlmsg_type == RTM_NEWADDR ) ss <<
" new" ;
253 if( hdr->nlmsg_type == RTM_DELADDR ) ss <<
" deleted" ;
261#if GCONFIG_HAVE_NETROUTE
264#include <net/route.h>
266bool GNet::InterfacesNotifierImp::active()
271GNet::InterfacesNotifierImp::InterfacesNotifierImp( Interfaces * outer , EventState es )
277 m_socket = std::make_unique<RawSocket>( PF_ROUTE , SOCK_RAW , AF_UNSPEC ) ;
279 m_socket->addReadHandler( *outer , es ) ;
285 using Header =
struct rt_msghdr ;
287 auto buffer_pair = readSocket<Header>() ;
288 if( buffer_pair.second >= 4U )
290 Header * p = buffer_pair.first ;
291 if( p->rtm_msglen != buffer_pair.second )
292 G_DEBUG(
"GNet::InterfacesNotifierImp::readEvent: invalid message length" ) ;
293 if( p->rtm_type == RTM_NEWADDR )
294 result =
"address new" ;
295 else if( p->rtm_type == RTM_DELADDR )
296 result =
"address deleted" ;
297 else if( p->rtm_type == RTM_IFINFO )
298 result =
"interface change" ;
305bool GNet::InterfacesNotifierImp::active()
310GNet::InterfacesNotifierImp::InterfacesNotifierImp( Interfaces * , EventState )
static bool supports(Family) noexcept
Returns true if the implementation supports the given address family.
static bool exists()
Returns true if an instance exists.
virtual std::string readEvent()=0
Called by GNet::Interfaces to handle a read event.
virtual std::string onFutureEvent()=0
Called by GNet::Interfaces to handle a future event.
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...
static constexpr std::size_t truncate
A special value for the G::Str::strncpy_s() 'count' parameter.
static errno_t strncpy_s(char *dst, std::size_t n_dst, const char *src, std::size_t count) noexcept
Does the same as windows strncpy_s().
A substitute for std::vector<char> that has more useful alignment guarantees and explicitly avoids de...