41 constexpr std::string_view port_separators {
":.",2U} ;
42 constexpr char port_separator =
'.' ;
46unsigned short GNet::Address6::af() noexcept
51int GNet::Address6::domain() noexcept
56GNet::Address6::Address6( std::nullptr_t ) :
59 m_inet.sin6_family = af() ;
60 m_inet.sin6_port = 0 ;
61 m_inet.sin6_flowinfo = 0 ;
62 gdef_address6_init( m_inet ) ;
65GNet::Address6::Address6(
unsigned int port ) :
68 m_inet.sin6_addr = in6addr_any ;
69 const char * reason = setPort( m_inet , port ) ;
70 if( reason )
throw Address::Error(reason) ;
73GNet::Address6::Address6(
unsigned int port ,
int ) :
76 m_inet.sin6_addr = in6addr_loopback ;
77 const char * reason = setPort( m_inet , port ) ;
78 if( reason )
throw Address::Error(reason) ;
81GNet::Address6::Address6(
const sockaddr * addr , socklen_t len ,
bool ipv6_scope_id_fixup ) :
85 throw Address::Error() ;
86 if( addr->sa_family != af() ||
static_cast<std::size_t
>(len) <
sizeof(sockaddr_type) )
87 throw Address::BadFamily() ;
89 std::memcpy( &m_inet , addr ,
sizeof(m_inet) ) ;
91 if( ipv6_scope_id_fixup )
93 auto hi =
static_cast<unsigned int>( m_inet.sin6_addr.s6_addr[2] ) ;
94 auto lo =
static_cast<unsigned int>( m_inet.sin6_addr.s6_addr[3] ) ;
95 m_inet.sin6_addr.s6_addr[2] = 0 ;
96 m_inet.sin6_addr.s6_addr[3] = 0 ;
97 m_inet.sin6_scope_id = ( hi << 8U | lo ) ;
101GNet::Address6::Address6( std::string_view host_part , std::string_view port_part ) :
104 const char * reason = setHostAddress( m_inet , host_part ) ;
106 reason = setPort( m_inet , port_part ) ;
108 throw Address::BadString( std::string(reason).append(
": [").append(host_part.data(),host_part.size()).append(
"][").append(port_part.data(),port_part.size()).append(1U,
']') ) ;
111GNet::Address6::Address6( std::string_view display_string ) :
114 const char * reason = setAddress( m_inet , display_string ) ;
116 throw Address::BadString( std::string(reason).append(
": ").append(display_string.data(),display_string.size()) ) ;
119const char * GNet::Address6::setAddress( sockaddr_type & inet , std::string_view display_string )
121 const std::string::size_type pos = display_string.find_last_of( Address6Imp::port_separators ) ;
122 if( pos == std::string::npos )
123 return "no port separator" ;
128 const char * reason = setHostAddress( inet , host_part ) ;
130 reason = setPort( inet , port_part ) ;
134const char * GNet::Address6::setHostAddress( sockaddr_type & inet , std::string_view host_part )
146 std::string_view zone =
G::Str::tailView( host_part , host_part.find(
'%') ) ;
147 std::string_view host_part_head =
G::Str::headView( host_part , host_part.find(
'%') , host_part ) ;
149 int rc = inet_pton( af() , G::sv_to_string(host_part_head).c_str() , &inet.sin6_addr ) ;
151 if( rc == 1 && !zone.empty() )
153 if( !setZone( inet , zone ) )
154 return "invalid address zone/scope" ;
157 return rc == 1 ? nullptr :
"invalid network address" ;
160void GNet::Address6::setPort(
unsigned int port )
162 const char * reason = setPort( m_inet , port ) ;
164 throw Address::Error(
"invalid port number" ) ;
167const char * GNet::Address6::setPort( sockaddr_type & inet , std::string_view port_part )
169 if( port_part.empty() )
return "empty port string" ;
174const char * GNet::Address6::setPort( sockaddr_type & inet ,
unsigned int port )
176 if( port > 0xFFFFU )
return "port number too big" ;
177 const g_port_t in_port =
static_cast<g_port_t
>(port) ;
178 inet.sin6_port = htons( in_port ) ;
182bool GNet::Address6::setZone( std::string_view zone )
184 return setZone( m_inet , zone ) ;
187bool GNet::Address6::setZone( sockaddr_type & inet , std::string_view zone )
189 unsigned long scope_id = 0UL ;
196 scope_id = gdef_if_nametoindex( G::sv_to_string(zone).c_str() ) ;
200 inet.sin6_scope_id = scope_id ;
201 const bool no_overflow = scope_id == inet.sin6_scope_id ;
205void GNet::Address6::setScopeId(
unsigned long ipv6_scope_id )
207 m_inet.sin6_scope_id = ipv6_scope_id ;
210std::string GNet::Address6::displayString(
bool ipv6_with_scope_id )
const
212 std::ostringstream ss ;
213 ss << hostPartString() ;
214 if( ipv6_with_scope_id && scopeId() != 0U )
215 ss <<
"%" << scopeId() ;
216 ss << Address6Imp::port_separator << port() ;
220std::string GNet::Address6::hostPartString()
const
222 std::array<char,INET6_ADDRSTRLEN+1U> buffer {} ;
223 const void * vp = & m_inet.sin6_addr ;
224 const char * p = inet_ntop( af() ,
const_cast<void*
>(vp) , buffer.data() , buffer.size() ) ;
226 throw Address::Error(
"inet_ntop() failure" ) ;
227 buffer[buffer.size()-1U] =
'\0' ;
228 return { buffer.data() } ;
231std::string GNet::Address6::queryString()
const
233 std::ostringstream ss ;
234 const char * hexmap =
"0123456789abcdef" ;
235 for( std::size_t i = 0U ; i < 16U ; i++ )
237 unsigned int n =
static_cast<unsigned int>(m_inet.sin6_addr.s6_addr[15U-i]) % 256U ;
238 ss << (i==0U?
"":
".") << hexmap[(n&15U)%16U] <<
"." << hexmap[(n>>4U)%16U] ;
243bool GNet::Address6::validData(
const sockaddr * addr , socklen_t len )
245 return addr !=
nullptr && addr->sa_family == af() && len ==
sizeof(sockaddr_type) ;
248bool GNet::Address6::validString( std::string_view s , std::string * reason_p )
250 sockaddr_type inet {} ;
251 const char * reason = setAddress( inet , s ) ;
252 if( reason && reason_p )
253 *reason_p = std::string(reason) ;
254 return reason == nullptr ;
257bool GNet::Address6::validStrings( std::string_view host_part , std::string_view port_part ,
258 std::string * reason_p )
260 sockaddr_type inet {} ;
261 const char * reason = setHostAddress( inet , host_part ) ;
263 reason = setPort( inet , port_part ) ;
264 if( reason && reason_p )
265 *reason_p = std::string(reason) ;
266 return reason == nullptr ;
270bool GNet::Address6::validPort(
unsigned int port )
272 sockaddr_type inet {} ;
273 const char * reason = setPort( inet , port ) ;
274 return reason == nullptr ;
278bool GNet::Address6::same(
const Address6 & other ,
bool with_scope )
const
281 m_inet.sin6_family == af() &&
282 other.m_inet.sin6_family == af() &&
283 sameAddr( m_inet.sin6_addr , other.m_inet.sin6_addr ) &&
284 ( !with_scope || m_inet.sin6_scope_id == other.m_inet.sin6_scope_id ) &&
285 m_inet.sin6_port == other.m_inet.sin6_port ;
288bool GNet::Address6::sameHostPart(
const Address6 & other ,
bool with_scope )
const
291 m_inet.sin6_family == af() &&
292 other.m_inet.sin6_family == af() &&
293 sameAddr( m_inet.sin6_addr , other.m_inet.sin6_addr ) &&
294 ( !with_scope || m_inet.sin6_scope_id == other.m_inet.sin6_scope_id ) ;
297bool GNet::Address6::sameAddr( const ::in6_addr & a , const ::in6_addr & b )
299 for( std::size_t i = 0 ; i < 16U ; i++ )
301 if( a.s6_addr[i] != b.s6_addr[i] )
307unsigned int GNet::Address6::port()
const
309 return ntohs( m_inet.sin6_port ) ;
312unsigned long GNet::Address6::scopeId(
unsigned long )
const
314 return m_inet.sin6_scope_id ;
318const sockaddr * GNet::Address6::address()
const
322 return reinterpret_cast<const sockaddr*
>( &m_inet ) ;
326sockaddr * GNet::Address6::address()
328 return reinterpret_cast<sockaddr*
>( &m_inet ) ;
331socklen_t GNet::Address6::length() noexcept
333 return sizeof(sockaddr_type) ;
338 namespace Address6Imp
340 bool shiftLeft(
struct in6_addr & mask )
342 bool carry_out = false ;
343 bool carry_in = false ;
344 for(
int i = 15 ; i >= 0 ; i-- )
346 const unsigned char top_bit = 128U ;
347 carry_out = !!( mask.s6_addr[i] & top_bit ) ;
348 mask.s6_addr[i] <<= 1U ;
349 if( carry_in ) ( mask.s6_addr[i] |= 1U ) ;
350 carry_in = carry_out ;
354 void shiftLeft(
struct in6_addr & mask ,
unsigned int bits )
356 for(
unsigned int i = 0U ; i < bits ; i++ )
359 void reset(
struct in6_addr & addr )
361 for(
unsigned int i = 0 ; i < 16U ; i++ )
362 addr.s6_addr[i] = 0 ;
364 void fill(
struct in6_addr & addr )
366 for(
unsigned int i = 0 ; i < 16U ; i++ )
367 addr.s6_addr[i] = 0xff ;
369 struct in6_addr make( unsigned int lhs_hi , unsigned int lhs_lo , unsigned int rhs )
371 struct in6_addr addr {} ;
373 using lhs_type = std::remove_reference<
decltype(addr.s6_addr[0])>::type ;
374 addr.s6_addr[15] =
static_cast<lhs_type
>(rhs) ;
375 addr.s6_addr[0] =
static_cast<lhs_type
>(lhs_hi) ;
376 addr.s6_addr[1] =
static_cast<lhs_type
>(lhs_lo) ;
379 void applyMask(
struct in6_addr & addr ,
const struct in6_addr & mask )
381 for(
int i = 0 ; i < 16 ; i++ )
383 addr.s6_addr[i] &= mask.s6_addr[i] ;
386 struct in6_addr mask( unsigned int bits )
388 struct in6_addr addr {} ;
390 shiftLeft( addr , 128U - bits ) ;
393 struct in6_addr masked( const struct in6_addr & addr_in ,
const struct in6_addr & mask )
395 struct in6_addr result = addr_in ;
396 applyMask( result , mask ) ;
404 namespace imp = Address6Imp ;
405 Address6 a( *
this ) ;
408 result.reserve( 128U ) ;
409 result.push_back( hostPartString() ) ;
411 struct in6_addr mask {} ;
414 for(
int bit = 0 ; bit <= 128 ; bit++ )
416 std::ostringstream ss ;
417 ss << a.hostPartString() <<
"/" << (128-bit) ;
418 result.push_back( ss.str() ) ;
420 imp::shiftLeft( mask ) ;
421 imp::applyMask( a.m_inet.sin6_addr , mask ) ;
426unsigned int GNet::Address6::bits()
const
428 namespace imp = Address6Imp ;
429 struct in6_addr a = m_inet.sin6_addr ;
430 unsigned int count = 0U ;
431 while( imp::shiftLeft(a) )
436bool GNet::Address6::isLocal( std::string & reason )
const
438 if( isLoopback() || isLinkLocal() || isUniqueLocal() )
444 std::ostringstream ss ;
445 ss << hostPartString() <<
" is not in ::1/128 or fe80::/64 or fc00::/7" ;
454 namespace imp = Address6Imp ;
455 struct in6_addr _1 = imp::make( 0U , 0U , 1U ) ;
456 return sameAddr( _1 , m_inet.sin6_addr ) ;
459bool GNet::Address6::isLinkLocal()
const
462 namespace imp = Address6Imp ;
463 struct in6_addr addr_64 = imp::masked( m_inet.sin6_addr , imp::mask(64U) ) ;
464 struct in6_addr _fe80 = imp::make( 0xfeU , 0x80U , 0U ) ;
465 return sameAddr( _fe80 , addr_64 ) ;
468bool GNet::Address6::isMulticast()
const
473bool GNet::Address6::isUniqueLocal()
const
476 namespace imp = Address6Imp ;
477 struct in6_addr addr_7 = imp::masked( m_inet.sin6_addr , imp::mask(7U) ) ;
478 struct in6_addr _fc00 = imp::make( 0xfcU , 0U , 0U ) ;
479 return sameAddr( _fc00 , addr_7 ) ;
482bool GNet::Address6::isAny()
const
484 for(
int i = 0 ; i < 16 ; i++ )
486 if( m_inet.sin6_addr.s6_addr[i] != in6addr_any.s6_addr[i] )
static bool isUInt(std::string_view s) noexcept
Returns true if the string can be converted into an unsigned integer without throwing an exception.
static bool isNumeric(std::string_view s, bool allow_minus_sign=false) noexcept
Returns true if every character is a decimal digit.
static bool isULong(std::string_view s) noexcept
Returns true if the string can be converted into an unsigned long without throwing an exception.
static std::string_view tailView(std::string_view in, std::size_t pos, std::string_view default_={}) noexcept
Like tail() but returning a view into the input string.
static unsigned int toUInt(std::string_view s)
Converts string 's' to an unsigned int.
static unsigned long toULong(std::string_view s, Limited)
Converts string 's' to an unsigned long.
static std::string_view headView(std::string_view in, std::size_t pos, std::string_view default_={}) noexcept
Like head() but returning a view into the input string.
std::vector< std::string > StringArray
A std::vector of std::strings.