42 const char * port_separators =
":." ;
43 char port_separator =
'.' ;
47unsigned short GNet::Address6::af() noexcept
52int GNet::Address6::domain() noexcept
57GNet::Address6::Address6( std::nullptr_t ) :
60 m_inet.sin6_family = af() ;
61 m_inet.sin6_port = 0 ;
62 m_inet.sin6_flowinfo = 0 ;
63 gdef_address6_init( m_inet ) ;
66GNet::Address6::Address6(
unsigned int port ) :
69 m_inet.sin6_addr = in6addr_any ;
70 const char * reason = setPort( m_inet , port ) ;
71 if( reason )
throw Address::Error(reason) ;
74GNet::Address6::Address6(
unsigned int port ,
int ) :
77 m_inet.sin6_addr = in6addr_loopback ;
78 const char * reason = setPort( m_inet , port ) ;
79 if( reason )
throw Address::Error(reason) ;
82GNet::Address6::Address6(
const sockaddr * addr , socklen_t len ,
bool ipv6_scope_id_fixup ) :
86 throw Address::Error() ;
87 if( addr->sa_family != af() ||
static_cast<std::size_t
>(len) <
sizeof(sockaddr_type) )
88 throw Address::BadFamily() ;
90 std::memcpy( &m_inet , addr ,
sizeof(m_inet) ) ;
92 if( ipv6_scope_id_fixup )
94 auto hi =
static_cast<unsigned int>( m_inet.sin6_addr.s6_addr[2] ) ;
95 auto lo =
static_cast<unsigned int>( m_inet.sin6_addr.s6_addr[3] ) ;
96 m_inet.sin6_addr.s6_addr[2] = 0 ;
97 m_inet.sin6_addr.s6_addr[3] = 0 ;
98 m_inet.sin6_scope_id = ( hi << 8U | lo ) ;
102GNet::Address6::Address6(
const std::string & host_part ,
const std::string & port_part ) :
105 const char * reason = setHostAddress( m_inet , host_part ) ;
107 reason = setPort( m_inet , port_part ) ;
109 throw Address::BadString( std::string(reason) +
": [" + host_part +
"][" + port_part +
"]" ) ;
112GNet::Address6::Address6(
const std::string & display_string ) :
115 const char * reason = setAddress( m_inet , display_string ) ;
117 throw Address::BadString( std::string(reason) +
": " + display_string ) ;
120const char * GNet::Address6::setAddress( sockaddr_type & inet ,
const std::string & display_string )
122 const std::string::size_type pos = display_string.find_last_of( Address6Imp::port_separators ) ;
123 if( pos == std::string::npos )
124 return "no port separator" ;
126 std::string host_part =
G::Str::head( display_string , pos ) ;
127 std::string port_part =
G::Str::tail( display_string , pos ) ;
129 const char * reason = setHostAddress( inet , host_part ) ;
131 reason = setPort( inet , port_part ) ;
135const char * GNet::Address6::setHostAddress( sockaddr_type & inet ,
const std::string & host_part )
147 std::string zone =
G::Str::tail( host_part , host_part.find(
'%') , std::string() ) ;
148 std::string host_part_head =
G::Str::head( host_part , host_part.find(
'%') , host_part ) ;
150 int rc = inet_pton( af() , host_part_head.c_str() , &inet.sin6_addr ) ;
152 if( rc == 1 && !zone.empty() )
154 if( !setZone( inet , zone ) )
155 return "invalid address zone/scope" ;
158 return rc == 1 ? nullptr :
"invalid network address" ;
161void GNet::Address6::setPort(
unsigned int port )
163 const char * reason = setPort( m_inet , port ) ;
165 throw Address::Error(
"invalid port number" ) ;
168const char * GNet::Address6::setPort( sockaddr_type & inet ,
const std::string & port_part )
170 if( port_part.length() == 0U )
return "empty port string" ;
175const char * GNet::Address6::setPort( sockaddr_type & inet ,
unsigned int port )
177 if( port > 0xFFFFU )
return "port number too big" ;
178 const g_port_t in_port =
static_cast<g_port_t
>(port) ;
179 inet.sin6_port = htons( in_port ) ;
183bool GNet::Address6::setZone(
const std::string & zone )
185 return setZone( m_inet , zone ) ;
188bool GNet::Address6::setZone( sockaddr_type & inet ,
const std::string & zone )
190 unsigned long scope_id = 0UL ;
197 scope_id = gdef_if_nametoindex( zone.c_str() ) ;
201 inet.sin6_scope_id = scope_id ;
202 const bool no_overflow = scope_id == inet.sin6_scope_id ;
206void GNet::Address6::setScopeId(
unsigned long ipv6_scope_id )
208 m_inet.sin6_scope_id = ipv6_scope_id ;
211std::string GNet::Address6::displayString(
bool ipv6_with_scope_id )
const
213 std::ostringstream ss ;
214 ss << hostPartString() ;
215 if( ipv6_with_scope_id && scopeId() != 0U )
216 ss <<
"%" << scopeId() ;
217 ss << Address6Imp::port_separator << port() ;
221std::string GNet::Address6::hostPartString()
const
223 std::array<char,INET6_ADDRSTRLEN+1U> buffer {} ;
224 const void * vp = & m_inet.sin6_addr ;
225 const char * p = inet_ntop( af() ,
const_cast<void*
>(vp) , &buffer[0] , buffer.size() ) ;
227 throw Address::Error(
"inet_ntop() failure" ) ;
228 buffer[buffer.size()-1U] =
'\0' ;
229 return { &buffer[0] } ;
232std::string GNet::Address6::queryString()
const
234 std::ostringstream ss ;
235 const char * hexmap =
"0123456789abcdef" ;
236 for( std::size_t i = 0U ; i < 16U ; i++ )
238 unsigned int n =
static_cast<unsigned int>(m_inet.sin6_addr.s6_addr[15U-i]) % 256U ;
239 ss << (i==0U?
"":
".") << hexmap[(n&15U)%16U] <<
"." << hexmap[(n>>4U)%16U] ;
244bool GNet::Address6::validData(
const sockaddr * addr , socklen_t len )
246 return addr !=
nullptr && addr->sa_family == af() && len ==
sizeof(sockaddr_type) ;
249bool GNet::Address6::validString(
const std::string & s , std::string * reason_p )
251 sockaddr_type inet {} ;
252 const char * reason = setAddress( inet , s ) ;
253 if( reason && reason_p )
254 *reason_p = std::string(reason) ;
255 return reason == nullptr ;
258bool GNet::Address6::validStrings(
const std::string & host_part ,
const std::string & port_part ,
259 std::string * reason_p )
261 sockaddr_type inet {} ;
262 const char * reason = setHostAddress( inet , host_part ) ;
264 reason = setPort( inet , port_part ) ;
265 if( reason && reason_p )
266 *reason_p = std::string(reason) ;
267 return reason == nullptr ;
271bool GNet::Address6::validPort(
unsigned int port )
273 sockaddr_type inet {} ;
274 const char * reason = setPort( inet , port ) ;
275 return reason == nullptr ;
279bool GNet::Address6::same(
const Address6 & other ,
bool with_scope )
const
282 m_inet.sin6_family == af() &&
283 other.m_inet.sin6_family == af() &&
284 sameAddr( m_inet.sin6_addr , other.m_inet.sin6_addr ) &&
285 ( !with_scope || m_inet.sin6_scope_id == other.m_inet.sin6_scope_id ) &&
286 m_inet.sin6_port == other.m_inet.sin6_port ;
289bool GNet::Address6::sameHostPart(
const Address6 & other ,
bool with_scope )
const
292 m_inet.sin6_family == af() &&
293 other.m_inet.sin6_family == af() &&
294 sameAddr( m_inet.sin6_addr , other.m_inet.sin6_addr ) &&
295 ( !with_scope || m_inet.sin6_scope_id == other.m_inet.sin6_scope_id ) ;
298bool GNet::Address6::sameAddr( const ::in6_addr & a , const ::in6_addr & b )
300 for( std::size_t i = 0 ; i < 16U ; i++ )
302 if( a.s6_addr[i] != b.s6_addr[i] )
308unsigned int GNet::Address6::port()
const
310 return ntohs( m_inet.sin6_port ) ;
313unsigned long GNet::Address6::scopeId(
unsigned long )
const
315 return m_inet.sin6_scope_id ;
319const sockaddr * GNet::Address6::address()
const
323 return reinterpret_cast<const sockaddr*
>( &m_inet ) ;
327sockaddr * GNet::Address6::address()
329 return reinterpret_cast<sockaddr*
>( &m_inet ) ;
332socklen_t GNet::Address6::length() noexcept
334 return sizeof(sockaddr_type) ;
339 namespace Address6Imp
341 bool shiftLeft(
struct in6_addr & mask )
343 bool carry_out = false ;
344 bool carry_in = false ;
345 for(
int i = 15 ; i >= 0 ; i-- )
347 const unsigned char top_bit = 128U ;
348 carry_out = !!( mask.s6_addr[i] & top_bit ) ;
349 mask.s6_addr[i] <<= 1U ;
350 if( carry_in ) ( mask.s6_addr[i] |= 1U ) ;
351 carry_in = carry_out ;
355 void shiftLeft(
struct in6_addr & mask ,
unsigned int bits )
357 for(
unsigned int i = 0U ; i < bits ; i++ )
360 void reset(
struct in6_addr & addr )
362 for(
unsigned int i = 0 ; i < 16U ; i++ )
363 addr.s6_addr[i] = 0 ;
365 void fill(
struct in6_addr & addr )
367 for(
unsigned int i = 0 ; i < 16U ; i++ )
368 addr.s6_addr[i] = 0xff ;
370 struct in6_addr make( unsigned int lhs_hi , unsigned int lhs_lo , unsigned int rhs )
372 struct in6_addr addr {} ;
374 using lhs_type = std::remove_reference<
decltype(addr.s6_addr[0])>::type ;
375 addr.s6_addr[15] =
static_cast<lhs_type
>(rhs) ;
376 addr.s6_addr[0] =
static_cast<lhs_type
>(lhs_hi) ;
377 addr.s6_addr[1] =
static_cast<lhs_type
>(lhs_lo) ;
380 void applyMask(
struct in6_addr & addr ,
const struct in6_addr & mask )
382 for(
int i = 0 ; i < 16 ; i++ )
384 addr.s6_addr[i] &= mask.s6_addr[i] ;
387 struct in6_addr mask( unsigned int bits )
389 struct in6_addr addr {} ;
391 shiftLeft( addr , 128U - bits ) ;
394 struct in6_addr masked( const struct in6_addr & addr_in ,
const struct in6_addr & mask )
396 struct in6_addr result = addr_in ;
397 applyMask( result , mask ) ;
405 namespace imp = Address6Imp ;
406 Address6 a( *
this ) ;
409 result.reserve( 128U ) ;
410 result.push_back( hostPartString() ) ;
412 struct in6_addr mask {} ;
415 for(
int bit = 0 ; bit <= 128 ; bit++ )
417 std::ostringstream ss ;
418 ss << a.hostPartString() <<
"/" << (128-bit) ;
419 result.push_back( ss.str() ) ;
421 imp::shiftLeft( mask ) ;
422 imp::applyMask( a.m_inet.sin6_addr , mask ) ;
427unsigned int GNet::Address6::bits()
const
429 namespace imp = Address6Imp ;
430 struct in6_addr a = m_inet.sin6_addr ;
431 unsigned int count = 0U ;
432 while( imp::shiftLeft(a) )
437bool GNet::Address6::isLocal( std::string & reason )
const
439 if( isLoopback() || isLinkLocal() || isUniqueLocal() )
445 std::ostringstream ss ;
446 ss << hostPartString() <<
" is not in ::1/128 or fe80::/64 or fc00::/7" ;
455 namespace imp = Address6Imp ;
456 struct in6_addr _1 = imp::make( 0U , 0U , 1U ) ;
457 return sameAddr( _1 , m_inet.sin6_addr ) ;
460bool GNet::Address6::isLinkLocal()
const
463 namespace imp = Address6Imp ;
464 struct in6_addr addr_64 = imp::masked( m_inet.sin6_addr , imp::mask(64U) ) ;
465 struct in6_addr _fe80 = imp::make( 0xfeU , 0x80U , 0U ) ;
466 return sameAddr( _fe80 , addr_64 ) ;
469bool GNet::Address6::isMulticast()
const
474bool GNet::Address6::isUniqueLocal()
const
477 namespace imp = Address6Imp ;
478 struct in6_addr addr_7 = imp::masked( m_inet.sin6_addr , imp::mask(7U) ) ;
479 struct in6_addr _fc00 = imp::make( 0xfcU , 0U , 0U ) ;
480 return sameAddr( _fc00 , addr_7 ) ;
483bool GNet::Address6::isAny()
const
485 for(
int i = 0 ; i < 16 ; i++ )
487 if( m_inet.sin6_addr.s6_addr[i] != in6addr_any.s6_addr[i] )
static unsigned int toUInt(string_view s)
Converts string 's' to an unsigned int.
static bool isNumeric(string_view s, bool allow_minus_sign=false) noexcept
Returns true if every character is a decimal digit.
static bool isULong(string_view s) noexcept
Returns true if the string can be converted into an unsigned long without throwing an exception.
static bool isUInt(string_view s) noexcept
Returns true if the string can be converted into an unsigned integer without throwing an exception.
static unsigned long toULong(string_view s, Limited)
Converts string 's' to an unsigned long.
static std::string tail(string_view in, std::size_t pos, string_view default_={})
Returns the last part of the string after the given position.
static std::string head(string_view in, std::size_t pos, string_view default_={})
Returns the first part of the string up to just before the given position.
std::vector< std::string > StringArray
A std::vector of std::strings.