38 constexpr const char * port_separators =
":" ;
39 constexpr char port_separator =
':' ;
43unsigned short GNet::Address4::af() noexcept
48int GNet::Address4::domain() noexcept
53GNet::Address4::Address4( std::nullptr_t ) :
56 m_inet.sin_family = af() ;
60GNet::Address4::Address4(
unsigned int port ) :
63 m_inet.sin_addr.s_addr = htonl(INADDR_ANY);
64 const char * reason = setPort( m_inet , port ) ;
65 if( reason )
throw Address::Error(reason) ;
68GNet::Address4::Address4(
unsigned int port ,
int ) :
71 m_inet.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
72 const char * reason = setPort( m_inet , port ) ;
73 if( reason )
throw Address::Error(reason) ;
76GNet::Address4::Address4(
const sockaddr * addr , socklen_t len ,
bool ) :
80 throw Address::Error() ;
81 if( addr->sa_family != af() ||
static_cast<std::size_t
>(len) <
sizeof(sockaddr_type) )
82 throw Address::BadFamily() ;
84 m_inet = *(
reinterpret_cast<const sockaddr_type*
>(addr)) ;
87GNet::Address4::Address4(
const std::string & host_part ,
unsigned int port ) :
90 const char * reason = setHostAddress( m_inet , host_part ) ;
92 reason = setPort( m_inet , port ) ;
94 throw Address::BadString( std::string(reason) +
": " + host_part ) ;
97GNet::Address4::Address4(
const std::string & host_part ,
const std::string & port_part ) :
100 const char * reason = setHostAddress( m_inet , host_part ) ;
102 reason = setPort( m_inet , port_part ) ;
104 throw Address::BadString( std::string(reason) +
": [" + host_part +
"][" + port_part +
"]" ) ;
107GNet::Address4::Address4(
const std::string & display_string ) :
110 const char * reason = setAddress( m_inet , display_string ) ;
112 throw Address::BadString( std::string(reason) +
": " + display_string ) ;
115const char * GNet::Address4::setAddress( sockaddr_type & inet ,
const std::string & display_string )
117 const std::string::size_type pos = display_string.find_last_of( Address4Imp::port_separators ) ;
118 if( pos == std::string::npos )
119 return "no port separator" ;
121 std::string host_part =
G::Str::head( display_string , pos ) ;
122 std::string port_part =
G::Str::tail( display_string , pos ) ;
124 const char * reason = setHostAddress( inet , host_part ) ;
126 reason = setPort( inet , port_part ) ;
130const char * GNet::Address4::setHostAddress( sockaddr_type & inet ,
const std::string & host_part )
133 if( !Address4::format(host_part) )
134 return "invalid network address" ;
136 int rc = inet_pton( af() , host_part.c_str() , &inet.sin_addr ) ;
137 return rc == 1 ? nullptr :
"invalid network address" ;
140void GNet::Address4::setPort(
unsigned int port )
142 const char * reason = setPort( m_inet , port ) ;
144 throw Address::Error(
"invalid port number" ) ;
147const char * GNet::Address4::setPort( sockaddr_type & inet ,
const std::string & port_part )
149 if( port_part.length() == 0U )
return "empty port string" ;
154const char * GNet::Address4::setPort( sockaddr_type & inet ,
unsigned int port )
156 if( port > 0xFFFFU )
return "port number too big" ;
157 const g_port_t in_port =
static_cast<g_port_t
>(port) ;
158 inet.sin_port = htons( in_port ) ;
162bool GNet::Address4::setZone(
const std::string & )
167void GNet::Address4::setScopeId(
unsigned long )
171std::string GNet::Address4::displayString(
bool )
const
173 std::ostringstream ss ;
174 ss << hostPartString() ;
175 ss << Address4Imp::port_separator << port() ;
179std::string GNet::Address4::hostPartString(
bool )
const
181 std::array<char,INET_ADDRSTRLEN+1U> buffer {} ;
182 const void * vp = & m_inet.sin_addr ;
183 const char * p = inet_ntop( af() ,
const_cast<void*
>(vp) , &buffer[0] , buffer.size() ) ;
185 throw Address::Error(
"inet_ntop() failure" ) ;
186 buffer[buffer.size()-1U] =
'\0' ;
187 return { &buffer[0] } ;
190std::string GNet::Address4::queryString()
const
193 std::reverse( parts.begin() , parts.end() ) ;
197bool GNet::Address4::validData(
const sockaddr * addr , socklen_t len )
199 return addr !=
nullptr && addr->sa_family == af() && len ==
sizeof(sockaddr_type) ;
202bool GNet::Address4::validString(
const std::string & s , std::string * reason_p )
204 sockaddr_type inet {} ;
205 const char * reason = setAddress( inet , s ) ;
206 if( reason && reason_p )
207 *reason_p = std::string(reason) ;
208 return reason == nullptr ;
211bool GNet::Address4::validStrings(
const std::string & host_part ,
const std::string & port_part ,
212 std::string * reason_p )
214 sockaddr_type inet {} ;
215 const char * reason = setHostAddress( inet , host_part ) ;
217 reason = setPort( inet , port_part ) ;
218 if( reason && reason_p )
219 *reason_p = std::string(reason) ;
220 return reason == nullptr ;
223bool GNet::Address4::validPort(
unsigned int port )
225 sockaddr_type inet {} ;
226 const char * reason = setPort( inet , port ) ;
227 return reason == nullptr ;
230bool GNet::Address4::same(
const Address4 & other ,
bool )
const
233 m_inet.sin_family == af() &&
234 other.m_inet.sin_family == af() &&
235 sameAddr( m_inet.sin_addr , other.m_inet.sin_addr ) &&
236 m_inet.sin_port == other.m_inet.sin_port ;
239bool GNet::Address4::sameHostPart(
const Address4 & other )
const
242 m_inet.sin_family == af() &&
243 other.m_inet.sin_family == af() &&
244 sameAddr( m_inet.sin_addr , other.m_inet.sin_addr ) ;
247bool GNet::Address4::sameAddr( const ::in_addr & a , const ::in_addr & b )
249 return a.s_addr == b.s_addr ;
252unsigned int GNet::Address4::port()
const
254 return ntohs( m_inet.sin_port ) ;
257unsigned long GNet::Address4::scopeId(
unsigned long default_ )
const
262const sockaddr * GNet::Address4::address()
const
264 return reinterpret_cast<const sockaddr*
>(&m_inet) ;
267sockaddr * GNet::Address4::address()
269 return reinterpret_cast<sockaddr*
>(&m_inet) ;
272socklen_t GNet::Address4::length() noexcept
274 return sizeof(sockaddr_type) ;
279 std::string ip_string = hostPartString() ;
282 result.reserve( 38U ) ;
283 result.push_back( ip_string ) ;
289 G_ASSERT( part.size() == 4U ) ;
290 if( part.size() != 4U )
306 std::string part_0_1_2 = part[0] ;
307 part_0_1_2.append( 1U ,
'.' ) ;
308 part_0_1_2.append( part[1] ) ;
309 part_0_1_2.append( 1U ,
'.' ) ;
310 part_0_1_2.append( part[2] ) ;
311 part_0_1_2.append( 1U ,
'.' ) ;
313 std::string part_0_1 = part[0] ;
314 part_0_1.append( 1U ,
'.' ) ;
315 part_0_1.append( part[1] ) ;
316 part_0_1.append( 1U ,
'.' ) ;
318 std::string part_0 = part[0] ;
319 part_0.append( 1U ,
'.' ) ;
321 const std::string empty ;
323 add( result , part_0_1_2 , n3 & 0xffU ,
"/32" ) ;
324 add( result , part_0_1_2 , n3 & 0xfeU ,
"/31" ) ;
325 add( result , part_0_1_2 , n3 & 0xfcU ,
"/30" ) ;
326 add( result , part_0_1_2 , n3 & 0xf8U ,
"/29" ) ;
327 add( result , part_0_1_2 , n3 & 0xf0U ,
"/28" ) ;
328 add( result , part_0_1_2 , n3 & 0xe0U ,
"/27" ) ;
329 add( result , part_0_1_2 , n3 & 0xc0U ,
"/26" ) ;
330 add( result , part_0_1_2 , n3 & 0x80U ,
"/25" ) ;
331 add( result , part_0_1_2 , 0 ,
"/24" ) ;
332 add( result , part_0_1_2 ,
"*" ) ;
333 add( result , part_0_1 , n2 & 0xfeU ,
".0/23" ) ;
334 add( result , part_0_1 , n2 & 0xfcU ,
".0/22" ) ;
335 add( result , part_0_1 , n2 & 0xfcU ,
".0/21" ) ;
336 add( result , part_0_1 , n2 & 0xf8U ,
".0/20" ) ;
337 add( result , part_0_1 , n2 & 0xf0U ,
".0/19" ) ;
338 add( result , part_0_1 , n2 & 0xe0U ,
".0/18" ) ;
339 add( result , part_0_1 , n2 & 0xc0U ,
".0/17" ) ;
340 add( result , part_0_1 , 0 ,
".0/16" ) ;
341 add( result , part_0_1 ,
"*.*" ) ;
342 add( result , part_0 , n1 & 0xfeU ,
".0.0/15" ) ;
343 add( result , part_0 , n1 & 0xfcU ,
".0.0/14" ) ;
344 add( result , part_0 , n1 & 0xf8U ,
".0.0/13" ) ;
345 add( result , part_0 , n1 & 0xf0U ,
".0.0/12" ) ;
346 add( result , part_0 , n1 & 0xe0U ,
".0.0/11" ) ;
347 add( result , part_0 , n1 & 0xc0U ,
".0.0/10" ) ;
348 add( result , part_0 , n1 & 0x80U ,
".0.0/9" ) ;
349 add( result , part_0 , 0 ,
".0.0/8" ) ;
350 add( result , part_0 ,
"*.*.*" ) ;
351 add( result , empty , n0 & 0xfeU ,
".0.0.0/7" ) ;
352 add( result , empty , n0 & 0xfcU ,
".0.0.0/6" ) ;
353 add( result , empty , n0 & 0xf8U ,
".0.0.0/5" ) ;
354 add( result , empty , n0 & 0xf0U ,
".0.0.0/4" ) ;
355 add( result , empty , n0 & 0xe0U ,
".0.0.0/3" ) ;
356 add( result , empty , n0 & 0xc0U ,
".0.0.0/2" ) ;
357 add( result , empty , n0 & 0x80U ,
".0.0.0/1" ) ;
358 add( result , empty , 0 ,
".0.0.0/0" ) ;
359 add( result , empty ,
"*.*.*.*" ) ;
364void GNet::Address4::add(
G::StringArray & result ,
const std::string & head ,
unsigned int n ,
const char * tail )
366 std::string s = head ;
369 result.push_back( s ) ;
372void GNet::Address4::add(
G::StringArray & result ,
const std::string & head ,
const char * tail )
374 result.push_back( head + tail ) ;
377bool GNet::Address4::format( std::string s )
381 if( s.empty() || s.find_first_not_of(
"0123456789.") != std::string::npos ||
382 std::count(s.begin(),s.end(),
'.') != 3U || s.at(0U) ==
'.' ||
383 s.at(s.length()-1U) ==
'.' || s.find(
"..") != std::string::npos )
386 unsigned int n = 0U ;
387 unsigned int z =
static_cast<unsigned char>(
'0') ;
390 unsigned int uc =
static_cast<unsigned char>(c) ;
391 n = c ==
'.' ? 0U : ( ( n * 10U ) + (uc-z) ) ;
398unsigned int GNet::Address4::bits()
const
400 const unsigned long a = ntohl( m_inet.sin_addr.s_addr ) ;
401 unsigned int count = 0U ;
402 for(
unsigned long mask = 0x80000000U ; mask && ( a & mask ) ; mask >>= 1U )
407bool GNet::Address4::isLocal( std::string & reason )
const
410 if( isLoopback() || isLinkLocal() || isUniqueLocal() )
416 std::ostringstream ss ;
417 ss << hostPartString() <<
" is not in "
418 "127.0.0.0/8, 169.254.0.0/16, 10.0.0.0/8, 172.16.0.0/12, or 192.168.0.0/16" ;
424bool GNet::Address4::isLoopback()
const
427 return ( ntohl(m_inet.sin_addr.s_addr) >> 24U ) == 127U ;
430bool GNet::Address4::isLinkLocal()
const
433 return ( ntohl(m_inet.sin_addr.s_addr) >> 16U ) == 0xA9FEU ;
436bool GNet::Address4::isUniqueLocal()
const
440 ( ntohl(m_inet.sin_addr.s_addr) >> 24U ) == 0x0AU ||
441 ( ntohl(m_inet.sin_addr.s_addr) >> 20U ) == 0xAC1U ||
442 ( ntohl(m_inet.sin_addr.s_addr) >> 16U ) == 0xC0A8U ;
445bool GNet::Address4::isAny()
const
447 return m_inet.sin_addr.s_addr == htonl(INADDR_ANY) ;
static std::string join(const std::string &sep, const StringArray &strings)
Concatenates an array of strings with separators.
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 void splitIntoFields(const std::string &in, StringArray &out, string_view ws, char escape='\0', bool remove_escapes=true)
Splits the string into fields.
static std::string fromUInt(unsigned int ui)
Converts unsigned int 'ui' to a string.
static unsigned int toUInt(const std::string &s)
Converts string 's' to an unsigned int.
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.