50 class InterfacesNotifierImp ;
56class GNet::InterfacesNotifierImp :
public InterfacesNotifier
59 static bool active() ;
60 InterfacesNotifierImp( Interfaces * , ExceptionSink es ) ;
61 template <
typename T> std::pair<T*,std::size_t> readSocket() ;
69 std::unique_ptr<RawSocket> m_socket ;
76 return InterfacesNotifierImp::active() ;
79void GNet::Interfaces::loadImp( ExceptionSink es , std::vector<Item> & list )
82 m_notifier = std::make_unique<InterfacesNotifierImp>(
this , es ) ;
84 ifaddrs * info_p = nullptr ;
85 int rc = getifaddrs( &info_p ) ;
92 using deleter_fn_t = std::function<void(ifaddrs*)> ;
93 using deleter_t = std::unique_ptr<ifaddrs,deleter_fn_t> ;
94 deleter_t deleter( info_p , deleter_fn_t(freeifaddrs) ) ;
96 const std::size_t nmax = AddressStorage().n() ;
97 const bool scope_id_fixup = G::is_bsd() ;
98 for( ; info_p != nullptr ; info_p = info_p->ifa_next )
100 G_ASSERT( info_p->ifa_name && info_p->ifa_name[0] ) ;
101 if( info_p->ifa_name ==
nullptr )
104 if( info_p->ifa_addr ==
nullptr )
111 item.name = std::string( info_p->ifa_name ) ;
112 item.ifindex = index( item.name ) ;
113 item.address_family = info_p->ifa_addr->sa_family ;
114 item.address = Address( info_p->ifa_addr , nmax , scope_id_fixup ) ;
115 item.valid_address = !item.address.isAny() ;
116 item.up = !!( info_p->ifa_flags & IFF_UP ) ;
117 item.loopback = !!( info_p->ifa_flags & IFF_LOOPBACK ) ;
118 item.has_netmask = info_p->ifa_netmask != nullptr ;
120 if( item.has_netmask )
122 if( info_p->ifa_netmask->sa_family == AF_UNSPEC )
123 info_p->ifa_netmask->sa_family = info_p->ifa_addr->sa_family ;
125 Address netmask( info_p->ifa_netmask , nmax ) ;
126 item.netmask_bits = netmask.bits() ;
129 list.push_back( item ) ;
133#if GCONFIG_HAVE_IFINDEX
134#include <sys/ioctl.h>
136int GNet::Interfaces::index(
const std::string & name )
138 struct ifreq req {} ;
140 int fd = socket( AF_INET , SOCK_DGRAM , 0 ) ;
141 if( fd < 0 )
return 0 ;
142 int rc = ioctl( fd , SIOCGIFINDEX , &req ,
sizeof(req) ) ;
144 return rc ? 0 : req.ifr_ifindex ;
147int GNet::Interfaces::index(
const std::string & )
156std::pair<T*,std::size_t> GNet::InterfacesNotifierImp::readSocket()
158 static_assert(
sizeof(T) <= 4096U ,
"" ) ;
159 m_buffer.resize( 4096U ) ;
161 ssize_t rc = m_socket->read( &m_buffer[0] , m_buffer.size() ) ;
168 T * p = G::buffer_cast<T*>( m_buffer , std::nothrow ) ;
169 std::size_t n =
static_cast<std::size_t
>( rc >= 0 && p ? rc : 0 ) ;
175 return std::string() ;
178#if GCONFIG_HAVE_RTNETLINK
180#include <asm/types.h>
181#include <sys/socket.h>
182#include <linux/netlink.h>
183#include <linux/rtnetlink.h>
185bool GNet::InterfacesNotifierImp::active()
190GNet::InterfacesNotifierImp::InterfacesNotifierImp( Interfaces * outer , ExceptionSink es )
194 union netlink_address_union
196 struct sockaddr_nl specific ;
197 struct sockaddr generic ;
199 netlink_address_union address {} ;
200 address.specific.nl_family = AF_NETLINK ;
201 #if GCONFIG_HAVE_IPV6
202 address.specific.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR ;
204 address.specific.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR ;
208 m_socket = std::make_unique<RawSocket>( AF_NETLINK , SOCK_RAW , NETLINK_ROUTE ) ;
209 int rc = ::bind( m_socket->fd() , &address.generic ,
sizeof(address.specific) ) ;
214 m_socket->addReadHandler( *outer , es ) ;
220 auto buffer_pair = readSocket<nlmsghdr>() ;
222 const nlmsghdr * hdr = buffer_pair.first ;
223 std::size_t size = buffer_pair.second ;
224 if( hdr ==
nullptr || size == 0U )
225 return std::string() ;
227 const char * sep =
"" ;
228 std::ostringstream ss ;
229 for( ; NLMSG_OK(hdr,size) ; hdr = NLMSG_NEXT(hdr,size) , sep =
", " )
231 if( hdr->nlmsg_type == NLMSG_DONE || hdr->nlmsg_type == NLMSG_ERROR )
234 if( hdr->nlmsg_type == RTM_NEWLINK ||
235 hdr->nlmsg_type == RTM_DELLINK ||
236 hdr->nlmsg_type == RTM_GETLINK )
238 GDEF_UNUSED ifinfomsg * p =
static_cast<ifinfomsg*
>( NLMSG_DATA(hdr) ) ;
239 GDEF_UNUSED
int n = NLMSG_PAYLOAD( hdr , size ) ;
240 ss << sep <<
"link" ;
241 if( hdr->nlmsg_type == RTM_NEWLINK ) ss <<
" new" ;
242 if( hdr->nlmsg_type == RTM_DELLINK ) ss <<
" deleted" ;
244 else if( hdr->nlmsg_type == RTM_NEWADDR ||
245 hdr->nlmsg_type == RTM_DELADDR ||
246 hdr->nlmsg_type == RTM_GETADDR )
248 GDEF_UNUSED ifaddrmsg * p =
static_cast<ifaddrmsg*
>( NLMSG_DATA(hdr) ) ;
249 GDEF_UNUSED
int n = NLMSG_PAYLOAD( hdr , size ) ;
250 ss << sep <<
"address" ;
251 if( hdr->nlmsg_type == RTM_NEWADDR ) ss <<
" new" ;
252 if( hdr->nlmsg_type == RTM_DELADDR ) ss <<
" deleted" ;
260#if GCONFIG_HAVE_NETROUTE
263#include <net/route.h>
265bool GNet::InterfacesNotifierImp::active()
270GNet::InterfacesNotifierImp::InterfacesNotifierImp( Interfaces * outer , ExceptionSink es )
276 m_socket = std::make_unique<RawSocket>( PF_ROUTE , SOCK_RAW , AF_UNSPEC ) ;
278 m_socket->addReadHandler( *outer , es ) ;
284 using Header =
struct rt_msghdr ;
286 auto buffer_pair = readSocket<Header>() ;
287 if( buffer_pair.second >= 4U )
289 Header * p = buffer_pair.first ;
290 if( p->rtm_msglen != buffer_pair.second )
291 G_DEBUG(
"GNet::InterfacesNotifierImp::readEvent: invalid message length" ) ;
292 if( p->rtm_type == RTM_NEWADDR )
293 result =
"address new" ;
294 else if( p->rtm_type == RTM_DELADDR )
295 result =
"address deleted" ;
296 else if( p->rtm_type == RTM_IFINFO )
297 result =
"interface change" ;
304bool GNet::InterfacesNotifierImp::active()
309GNet::InterfacesNotifierImp::InterfacesNotifierImp( Interfaces * , ExceptionSink )
315 return std::string() ;
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...