32 #include <sys/types.h>
39 const char * port_separators =
":/." ;
40 char port_separator =
'.' ;
43 unsigned short GNet::Address6::family()
48 int GNet::Address6::domain()
53 void GNet::Address6::init()
55 static specific_type zero ;
56 m_inet.specific = zero ;
57 m_inet.specific.sin6_family = family() ;
58 m_inet.specific.sin6_flowinfo = 0 ;
59 m_inet.specific.sin6_port = 0 ;
60 gnet_address6_init( m_inet.specific ) ;
63 GNet::Address6::Address6(
unsigned int port )
66 m_inet.specific.sin6_addr = in6addr_any ;
67 const char * reason = setPort( m_inet , port ) ;
68 if( reason )
throw Address::Error(reason) ;
71 GNet::Address6::Address6(
unsigned int port ,
int )
74 m_inet.specific.sin6_addr = in6addr_loopback ;
75 const char * reason = setPort( m_inet , port ) ;
76 if( reason )
throw Address::Error(reason) ;
79 GNet::Address6::Address6(
const sockaddr * addr , socklen_t len )
83 throw Address::Error() ;
84 if( addr->sa_family != family() || static_cast<size_t>(len) <
sizeof(specific_type) )
85 throw Address::BadFamily() ;
87 m_inet.specific = *(
reinterpret_cast<const specific_type*
>(addr)) ;
90 GNet::Address6::Address6(
const Address6 & other )
92 m_inet.specific = other.m_inet.specific ;
95 GNet::Address6::Address6(
const std::string & host_part ,
unsigned int port )
98 const char * reason = setHostAddress( m_inet , host_part ) ;
100 reason = setPort( m_inet , port ) ;
102 throw Address::BadString( std::string(reason) +
": " + host_part ) ;
105 GNet::Address6::Address6(
const std::string & host_part ,
const std::string & port_part )
108 const char * reason = setHostAddress( m_inet , host_part ) ;
110 reason = setPort( m_inet , port_part ) ;
112 throw Address::BadString( std::string(reason) +
": [" + host_part +
"][" + port_part +
"]" ) ;
115 GNet::Address6::Address6(
const std::string & display_string )
118 const char * reason = setAddress( m_inet , display_string ) ;
120 throw Address::BadString( std::string(reason) +
": " + display_string ) ;
123 const char * GNet::Address6::setAddress( union_type & inet ,
const std::string & display_string )
125 const std::string::size_type pos = display_string.find_last_of( port_separators ) ;
126 if( pos == std::string::npos )
127 return "no port separator" ;
129 std::string host_part =
G::Str::head( display_string , pos ) ;
130 std::string port_part =
G::Str::tail( display_string , pos ) ;
132 const char * reason = setHostAddress( inet , host_part ) ;
134 reason = setPort( inet , port_part ) ;
138 const char * GNet::Address6::setHostAddress( union_type & inet ,
const std::string & host_part )
150 std::string zone =
G::Str::tail( host_part , host_part.find(
'%') , std::string() ) ;
151 std::string host_part_head =
G::Str::head( host_part , host_part.find(
'%') , host_part ) ;
153 int rc = inet_pton( family() , host_part_head.c_str() , &inet.specific.sin6_addr ) ;
155 if( rc == 1 && !zone.empty() )
159 zone_id = if_nametoindex( zone.c_str() ) ;
161 setZone( inet , zone_id ) ;
164 return rc == 1 ?
nullptr :
"invalid network address" ;
167 void GNet::Address6::setPort(
unsigned int port )
169 const char * reason = setPort( m_inet , port ) ;
171 throw Address::Error(
"invalid port number" ) ;
174 const char * GNet::Address6::setPort( union_type & inet ,
const std::string & port_part )
176 if( port_part.length() == 0U )
return "empty port string" ;
181 const char * GNet::Address6::setPort( union_type & inet ,
unsigned int port )
183 if( port > 0xFFFFU )
return "port number too big" ;
184 const g_port_t in_port =
static_cast<g_port_t
>(port) ;
185 inet.specific.sin6_port = htons( in_port ) ;
189 void GNet::Address6::setZone( union_type & inet ,
unsigned int zone_id )
191 inet.specific.sin6_scope_id = zone_id ;
196 std::string GNet::Address6::displayString()
const
198 const bool with_scope_id = false ;
199 std::ostringstream ss ;
200 ss << hostPartString() ;
202 ss <<
"%" << scopeId() ;
203 ss << port_separator << port() ;
207 std::string GNet::Address6::hostPartString()
const
209 char buffer[INET6_ADDRSTRLEN+1U] ;
210 const void * vp = & m_inet.specific.sin6_addr ;
211 const char * p = inet_ntop( family() , const_cast<void*>(vp) , buffer ,
sizeof(buffer) ) ;
213 throw Address::Error(
"inet_ntop() failure" ) ;
214 buffer[
sizeof(buffer)-1U] =
'\0' ;
215 return std::string(buffer) ;
218 bool GNet::Address6::validData(
const sockaddr * addr , socklen_t len )
220 return addr !=
nullptr && addr->sa_family == family() && len ==
sizeof(specific_type) ;
223 bool GNet::Address6::validString(
const std::string & s , std::string * reason_p )
226 const char * reason = setAddress( inet , s ) ;
227 if( reason && reason_p )
228 *reason_p = std::string(reason) ;
229 return reason == nullptr ;
232 bool GNet::Address6::validStrings(
const std::string & host_part ,
const std::string & port_part , std::string * reason_p )
235 const char * reason = setHostAddress( inet , host_part ) ;
237 reason = setPort( inet , port_part ) ;
238 if( reason && reason_p )
239 *reason_p = std::string(reason) ;
240 return reason == nullptr ;
243 bool GNet::Address6::validPort(
unsigned int port )
246 const char * reason = setPort( inet , port ) ;
247 return reason == nullptr ;
250 bool GNet::Address6::same(
const Address6 & other )
const
253 m_inet.specific.sin6_family == family() &&
254 other.m_inet.specific.sin6_family == family() &&
255 sameAddr( m_inet.specific.sin6_addr , other.m_inet.specific.sin6_addr ) &&
256 m_inet.specific.sin6_port == other.m_inet.specific.sin6_port ;
259 bool GNet::Address6::sameHostPart(
const Address6 & other )
const
262 m_inet.specific.sin6_family == family() &&
263 other.m_inet.specific.sin6_family == family() &&
264 sameAddr( m_inet.specific.sin6_addr , other.m_inet.specific.sin6_addr ) ;
267 bool GNet::Address6::sameAddr( const ::in6_addr & a , const ::in6_addr & b )
269 for(
size_t i = 0 ; i < 16U ; i++ )
271 if( a.s6_addr[i] != b.s6_addr[i] )
277 unsigned int GNet::Address6::port()
const
279 return ntohs( m_inet.specific.sin6_port ) ;
282 unsigned long GNet::Address6::scopeId()
const
284 return m_inet.specific.sin6_scope_id ;
287 const sockaddr * GNet::Address6::address()
const
289 return &m_inet.general ;
292 sockaddr * GNet::Address6::address()
294 return &m_inet.general ;
297 socklen_t GNet::Address6::length()
299 return sizeof(specific_type) ;
304 void shiftLeft(
struct in6_addr & mask )
306 bool carry_in = false ;
307 for(
int i = 15 ; i >= 0 ; i-- )
309 const unsigned char top_bit = 128U ;
310 bool carry_out = !!( mask.s6_addr[i] & top_bit ) ;
311 mask.s6_addr[i] <<= 1U ;
312 if( carry_in ) ( mask.s6_addr[i] |= 1U ) ;
313 carry_in = carry_out ;
316 void shiftLeft(
struct in6_addr & mask ,
unsigned int bits )
318 for(
unsigned int i = 0U ; i < bits ; i++ )
321 void reset(
struct in6_addr & addr )
323 for(
unsigned int i = 0 ; i < 16U ; i++ )
324 addr.s6_addr[i] = 0 ;
326 void fill(
struct in6_addr & addr )
328 for(
unsigned int i = 0 ; i < 16U ; i++ )
329 addr.s6_addr[i] = 0xff ;
331 struct in6_addr make( unsigned int lhs_hi , unsigned int lhs_lo , unsigned int rhs )
333 struct in6_addr addr ;
335 addr.s6_addr[15] = rhs ;
336 addr.s6_addr[0] = lhs_hi ;
337 addr.s6_addr[1] = lhs_lo ;
340 void applyMask(
struct in6_addr & addr ,
const struct in6_addr & mask )
342 for(
int i = 0 ; i < 16 ; i++ )
344 addr.s6_addr[i] &= mask.s6_addr[i] ;
347 struct in6_addr mask( unsigned int bits )
349 struct in6_addr addr ;
351 shiftLeft( addr , 128U - bits ) ;
354 struct in6_addr masked( const struct in6_addr & addr_in ,
const struct in6_addr & mask )
356 struct in6_addr result = addr_in ;
357 applyMask( result , mask ) ;
364 Address6 a( *
this ) ;
367 result.reserve( 128U ) ;
368 result.push_back( hostPartString() ) ;
370 struct in6_addr mask ;
373 for(
int bit = 0 ; bit < 128 ; bit++ )
375 std::ostringstream ss ;
376 ss << a.hostPartString() <<
"/" << (128-bit) ;
377 result.push_back( ss.str() ) ;
380 applyMask( a.m_inet.specific.sin6_addr , mask ) ;
385 bool GNet::Address6::isLoopback()
const
388 struct in6_addr _1 = make( 0U , 0U , 1U ) ;
389 return sameAddr( _1 , m_inet.specific.sin6_addr ) ;
392 bool GNet::Address6::isLocal( std::string & reason )
const
394 struct in6_addr addr_128 = masked( m_inet.specific.sin6_addr , mask(128U) ) ;
395 struct in6_addr addr_64 = masked( m_inet.specific.sin6_addr , mask(64U) ) ;
396 struct in6_addr addr_7 = masked( m_inet.specific.sin6_addr , mask(7U) ) ;
398 struct in6_addr _1 = make( 0U , 0U , 1U ) ;
399 struct in6_addr _fe80 = make( 0xfeU , 0x80U , 0U ) ;
400 struct in6_addr _fc00 = make( 0xfcU , 0U , 0U ) ;
403 sameAddr( _1 , addr_128 ) ||
404 sameAddr( _fe80 , addr_64 ) ||
405 sameAddr( _fc00 , addr_7 ) ;
409 std::ostringstream ss ;
410 ss << hostPartString() <<
" is not ::1/128 or in fe80::/64 or fc00::/7" ;
std::vector< std::string > StringArray
A std::vector of std::strings.
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::string::size_type pos, const std::string &default_=std::string())
Returns the last part of the string after the given position.
static unsigned int toUInt(const std::string &s)
Converts string 's' to an unsigned int.
static std::string head(const std::string &in, std::string::size_type pos, const std::string &default_=std::string())
Returns the first part of the string up to just before the given position.
This file is formatted for side-by-side comparison with gaddress4.h.
static bool isUInt(const std::string &s)
Returns true if the string can be converted into an unsigned integer without throwing an exception...