41 const char * port_separators =
":." ;
42 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(
const std::string & host_part ,
unsigned int port ) :
104 const char * reason = setHostAddress( m_inet , host_part ) ;
106 reason = setPort( m_inet , port ) ;
108 throw Address::BadString( std::string(reason) +
": " + host_part ) ;
111GNet::Address6::Address6(
const std::string & host_part ,
const std::string & port_part ) :
114 const char * reason = setHostAddress( m_inet , host_part ) ;
116 reason = setPort( m_inet , port_part ) ;
118 throw Address::BadString( std::string(reason) +
": [" + host_part +
"][" + port_part +
"]" ) ;
121GNet::Address6::Address6(
const std::string & display_string ) :
124 const char * reason = setAddress( m_inet , display_string ) ;
126 throw Address::BadString( std::string(reason) +
": " + display_string ) ;
129const char * GNet::Address6::setAddress( sockaddr_type & inet ,
const std::string & display_string )
131 const std::string::size_type pos = display_string.find_last_of( Address6Imp::port_separators ) ;
132 if( pos == std::string::npos )
133 return "no port separator" ;
135 std::string host_part =
G::Str::head( display_string , pos ) ;
136 std::string port_part =
G::Str::tail( display_string , pos ) ;
138 const char * reason = setHostAddress( inet , host_part ) ;
140 reason = setPort( inet , port_part ) ;
144const char * GNet::Address6::setHostAddress( sockaddr_type & inet ,
const std::string & host_part )
156 std::string zone =
G::Str::tail( host_part , host_part.find(
'%') , std::string() ) ;
157 std::string host_part_head =
G::Str::head( host_part , host_part.find(
'%') , host_part ) ;
159 int rc = inet_pton( af() , host_part_head.c_str() , &inet.sin6_addr ) ;
161 if( rc == 1 && !zone.empty() )
163 if( !setZone( inet , zone ) )
164 return "invalid address zone/scope" ;
167 return rc == 1 ? nullptr :
"invalid network address" ;
170void GNet::Address6::setPort(
unsigned int port )
172 const char * reason = setPort( m_inet , port ) ;
174 throw Address::Error(
"invalid port number" ) ;
177const char * GNet::Address6::setPort( sockaddr_type & inet ,
const std::string & port_part )
179 if( port_part.length() == 0U )
return "empty port string" ;
184const char * GNet::Address6::setPort( sockaddr_type & inet ,
unsigned int port )
186 if( port > 0xFFFFU )
return "port number too big" ;
187 const g_port_t in_port =
static_cast<g_port_t
>(port) ;
188 inet.sin6_port = htons( in_port ) ;
192bool GNet::Address6::setZone(
const std::string & zone )
194 return setZone( m_inet , zone ) ;
197bool GNet::Address6::setZone( sockaddr_type & inet ,
const std::string & zone )
199 unsigned long scope_id = 0UL ;
206 scope_id = gdef_if_nametoindex( zone.c_str() ) ;
210 inet.sin6_scope_id = scope_id ;
211 const bool no_overflow = scope_id == inet.sin6_scope_id ;
215void GNet::Address6::setScopeId(
unsigned long ipv6_scope_id )
217 m_inet.sin6_scope_id = ipv6_scope_id ;
220std::string GNet::Address6::displayString(
bool ipv6_with_scope_id )
const
222 std::ostringstream ss ;
223 ss << hostPartString() ;
224 if( ipv6_with_scope_id && scopeId() != 0U )
225 ss <<
"%" << scopeId() ;
226 ss << Address6Imp::port_separator << port() ;
230std::string GNet::Address6::hostPartString(
bool )
const
232 std::array<char,INET6_ADDRSTRLEN+1U> buffer {} ;
233 const void * vp = & m_inet.sin6_addr ;
234 const char * p = inet_ntop( af() ,
const_cast<void*
>(vp) , &buffer[0] , buffer.size() ) ;
236 throw Address::Error(
"inet_ntop() failure" ) ;
237 buffer[buffer.size()-1U] =
'\0' ;
238 return { &buffer[0] } ;
241std::string GNet::Address6::queryString()
const
243 std::ostringstream ss ;
244 const char * hexmap =
"0123456789abcdef" ;
245 for( std::size_t i = 0U ; i < 16U ; i++ )
247 unsigned int n =
static_cast<unsigned int>(m_inet.sin6_addr.s6_addr[15U-i]) % 256U ;
248 ss << (i==0U?
"":
".") << hexmap[(n&15U)%16U] <<
"." << hexmap[(n>>4U)%16U] ;
253bool GNet::Address6::validData(
const sockaddr * addr , socklen_t len )
255 return addr !=
nullptr && addr->sa_family == af() && len ==
sizeof(sockaddr_type) ;
258bool GNet::Address6::validString(
const std::string & s , std::string * reason_p )
260 sockaddr_type inet {} ;
261 const char * reason = setAddress( inet , s ) ;
262 if( reason && reason_p )
263 *reason_p = std::string(reason) ;
264 return reason == nullptr ;
267bool GNet::Address6::validStrings(
const std::string & host_part ,
const std::string & port_part ,
268 std::string * reason_p )
270 sockaddr_type inet {} ;
271 const char * reason = setHostAddress( inet , host_part ) ;
273 reason = setPort( inet , port_part ) ;
274 if( reason && reason_p )
275 *reason_p = std::string(reason) ;
276 return reason == nullptr ;
279bool GNet::Address6::validPort(
unsigned int port )
281 sockaddr_type inet {} ;
282 const char * reason = setPort( inet , port ) ;
283 return reason == nullptr ;
286bool GNet::Address6::same(
const Address6 & other ,
bool with_scope )
const
289 m_inet.sin6_family == af() &&
290 other.m_inet.sin6_family == af() &&
291 sameAddr( m_inet.sin6_addr , other.m_inet.sin6_addr ) &&
292 ( !with_scope || m_inet.sin6_scope_id == other.m_inet.sin6_scope_id ) &&
293 m_inet.sin6_port == other.m_inet.sin6_port ;
296bool GNet::Address6::sameHostPart(
const Address6 & other ,
bool with_scope )
const
299 m_inet.sin6_family == af() &&
300 other.m_inet.sin6_family == af() &&
301 sameAddr( m_inet.sin6_addr , other.m_inet.sin6_addr ) &&
302 ( !with_scope || m_inet.sin6_scope_id == other.m_inet.sin6_scope_id ) ;
305bool GNet::Address6::sameAddr( const ::in6_addr & a , const ::in6_addr & b )
307 for( std::size_t i = 0 ; i < 16U ; i++ )
309 if( a.s6_addr[i] != b.s6_addr[i] )
315unsigned int GNet::Address6::port()
const
317 return ntohs( m_inet.sin6_port ) ;
320unsigned long GNet::Address6::scopeId(
unsigned long )
const
322 return m_inet.sin6_scope_id ;
325const sockaddr * GNet::Address6::address()
const
329 return reinterpret_cast<const sockaddr*
>( &m_inet ) ;
332sockaddr * GNet::Address6::address()
334 return reinterpret_cast<sockaddr*
>( &m_inet ) ;
337socklen_t GNet::Address6::length() noexcept
339 return sizeof(sockaddr_type) ;
344 namespace Address6Imp
346 bool shiftLeft(
struct in6_addr & mask )
348 bool carry_out = false ;
349 bool carry_in = false ;
350 for(
int i = 15 ; i >= 0 ; i-- )
352 const unsigned char top_bit = 128U ;
353 carry_out = !!( mask.s6_addr[i] & top_bit ) ;
354 mask.s6_addr[i] <<= 1U ;
355 if( carry_in ) ( mask.s6_addr[i] |= 1U ) ;
356 carry_in = carry_out ;
360 void shiftLeft(
struct in6_addr & mask ,
unsigned int bits )
362 for(
unsigned int i = 0U ; i < bits ; i++ )
365 void reset(
struct in6_addr & addr )
367 for(
unsigned int i = 0 ; i < 16U ; i++ )
368 addr.s6_addr[i] = 0 ;
370 void fill(
struct in6_addr & addr )
372 for(
unsigned int i = 0 ; i < 16U ; i++ )
373 addr.s6_addr[i] = 0xff ;
375 struct in6_addr make( unsigned int lhs_hi , unsigned int lhs_lo , unsigned int rhs )
377 struct in6_addr addr {} ;
379 addr.s6_addr[15] = rhs ;
380 addr.s6_addr[0] = lhs_hi ;
381 addr.s6_addr[1] = lhs_lo ;
384 void applyMask(
struct in6_addr & addr ,
const struct in6_addr & mask )
386 for(
int i = 0 ; i < 16 ; i++ )
388 addr.s6_addr[i] &= mask.s6_addr[i] ;
391 struct in6_addr mask( unsigned int bits )
393 struct in6_addr addr {} ;
395 shiftLeft( addr , 128U - bits ) ;
398 struct in6_addr masked( const struct in6_addr & addr_in ,
const struct in6_addr & mask )
400 struct in6_addr result = addr_in ;
401 applyMask( result , mask ) ;
409 namespace imp = Address6Imp ;
410 Address6 a( *
this ) ;
413 result.reserve( 128U ) ;
414 result.push_back( hostPartString() ) ;
416 struct in6_addr mask {} ;
419 for(
int bit = 0 ; bit < 128 ; bit++ )
421 std::ostringstream ss ;
422 ss << a.hostPartString() <<
"/" << (128-bit) ;
423 result.push_back( ss.str() ) ;
425 imp::shiftLeft( mask ) ;
426 imp::applyMask( a.m_inet.sin6_addr , mask ) ;
431unsigned int GNet::Address6::bits()
const
433 namespace imp = Address6Imp ;
434 struct in6_addr a = m_inet.sin6_addr ;
435 unsigned int count = 0U ;
436 while( imp::shiftLeft(a) )
441bool GNet::Address6::isLocal( std::string & reason )
const
443 if( isLoopback() || isLinkLocal() || isUniqueLocal() )
449 std::ostringstream ss ;
450 ss << hostPartString() <<
" is not in ::1/128 or fe80::/64 or fc00::/7" ;
459 namespace imp = Address6Imp ;
460 struct in6_addr _1 = imp::make( 0U , 0U , 1U ) ;
461 return sameAddr( _1 , m_inet.sin6_addr ) ;
464bool GNet::Address6::isLinkLocal()
const
467 namespace imp = Address6Imp ;
468 struct in6_addr addr_64 = imp::masked( m_inet.sin6_addr , imp::mask(64U) ) ;
469 struct in6_addr _fe80 = imp::make( 0xfeU , 0x80U , 0U ) ;
470 return sameAddr( _fe80 , addr_64 ) ;
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 isNumeric(const std::string &s, bool allow_minus_sign=false)
Returns true if every character is a decimal digit.
static std::string tail(const std::string &in, std::size_t pos, const std::string &default_=std::string())
Returns the last part of the string after the given position.
static bool isULong(const std::string &s)
Returns true if the string can be converted into an unsigned long without throwing an exception.
static unsigned int toUInt(const std::string &s)
Converts string 's' to an unsigned int.
static unsigned long toULong(const std::string &s, Limited)
Converts string 's' to an unsigned long.
static bool isUInt(const std::string &s)
Returns true if the string can be converted into an unsigned integer without throwing an exception.
static std::string head(const std::string &in, std::size_t pos, const std::string &default_=std::string())
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.