39 constexpr const char * port_separators =
":" ;
40 constexpr char port_separator =
':' ;
44unsigned short GNet::Address4::af() noexcept
49int GNet::Address4::domain() noexcept
54GNet::Address4::Address4( std::nullptr_t ) :
57 m_inet.sin_family = af() ;
61GNet::Address4::Address4(
unsigned int port ) :
64 m_inet.sin_addr.s_addr = htonl(INADDR_ANY);
65 const char * reason = setPort( m_inet , port ) ;
66 if( reason )
throw Address::Error(reason) ;
69GNet::Address4::Address4(
unsigned int port ,
int ) :
72 m_inet.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
73 const char * reason = setPort( m_inet , port ) ;
74 if( reason )
throw Address::Error(reason) ;
77GNet::Address4::Address4(
const sockaddr * addr , socklen_t len ) :
81 throw Address::Error() ;
82 if( addr->sa_family != af() ||
static_cast<std::size_t
>(len) <
sizeof(sockaddr_type) )
83 throw Address::BadFamily() ;
85 m_inet = *(
reinterpret_cast<const sockaddr_type*
>(addr)) ;
88GNet::Address4::Address4(
const std::string & host_part ,
const std::string & port_part ) :
91 const char * reason = setHostAddress( m_inet , host_part ) ;
93 reason = setPort( m_inet , port_part ) ;
95 throw Address::BadString( std::string(reason).append(
": [").append(host_part).append(
"][").append(port_part).append(1U,
']') ) ;
98GNet::Address4::Address4(
const std::string & display_string ) :
101 const char * reason = setAddress( m_inet , display_string ) ;
103 throw Address::BadString( std::string(reason).append(
": ").append(display_string) ) ;
106const char * GNet::Address4::setAddress( sockaddr_type & inet ,
G::string_view display_string )
108 const std::string::size_type pos = display_string.find_last_of( Address4Imp::port_separators ) ;
109 if( pos == std::string::npos )
110 return "no port separator" ;
115 const char * reason = setHostAddress( inet , host_part ) ;
117 reason = setPort( inet , port_part ) ;
121const char * GNet::Address4::setHostAddress( sockaddr_type & inet ,
G::string_view host_part )
124 if( !Address4::format(host_part) )
125 return "invalid network address" ;
127 int rc = inet_pton( af() , G::sv_to_string(host_part).c_str() , &inet.sin_addr ) ;
128 return rc == 1 ? nullptr :
"invalid network address" ;
131void GNet::Address4::setPort(
unsigned int port )
133 const char * reason = setPort( m_inet , port ) ;
135 throw Address::Error(
"invalid port number" ) ;
138const char * GNet::Address4::setPort( sockaddr_type & inet ,
G::string_view port_part )
140 if( port_part.empty() )
return "empty port string" ;
145const char * GNet::Address4::setPort( sockaddr_type & inet ,
unsigned int port )
147 if( port > 0xFFFFU )
return "port number too big" ;
148 const g_port_t in_port =
static_cast<g_port_t
>(port) ;
149 inet.sin_port = htons( in_port ) ;
153bool GNet::Address4::setZone(
const std::string & )
158void GNet::Address4::setScopeId(
unsigned long )
162std::string GNet::Address4::displayString(
bool )
const
164 std::ostringstream ss ;
165 ss << hostPartString() ;
166 ss << Address4Imp::port_separator << port() ;
170std::string GNet::Address4::hostPartString()
const
172 std::array<char,INET_ADDRSTRLEN+1U> buffer {} ;
173 const void * vp = & m_inet.sin_addr ;
174 const char * p = inet_ntop( af() ,
const_cast<void*
>(vp) , &buffer[0] , buffer.size() ) ;
176 throw Address::Error(
"inet_ntop() failure" ) ;
177 buffer[buffer.size()-1U] =
'\0' ;
178 return { &buffer[0] } ;
181std::string GNet::Address4::queryString()
const
184 std::reverse( parts.begin() , parts.end() ) ;
188bool GNet::Address4::validData(
const sockaddr * addr , socklen_t len )
190 return addr !=
nullptr && addr->sa_family == af() && len ==
sizeof(sockaddr_type) ;
193bool GNet::Address4::validString(
const std::string & s , std::string * reason_p )
195 sockaddr_type inet {} ;
196 const char * reason = setAddress( inet , s ) ;
197 if( reason && reason_p )
198 *reason_p = std::string(reason) ;
199 return reason == nullptr ;
202bool GNet::Address4::validStrings(
const std::string & host_part ,
const std::string & port_part ,
203 std::string * reason_p )
205 sockaddr_type inet {} ;
206 const char * reason = setHostAddress( inet , host_part ) ;
208 reason = setPort( inet , port_part ) ;
209 if( reason && reason_p )
210 *reason_p = std::string(reason) ;
211 return reason == nullptr ;
214bool GNet::Address4::validPort(
unsigned int port )
216 sockaddr_type inet {} ;
217 const char * reason = setPort( inet , port ) ;
218 return reason == nullptr ;
221bool GNet::Address4::same(
const Address4 & other ,
bool )
const
224 m_inet.sin_family == af() &&
225 other.m_inet.sin_family == af() &&
226 sameAddr( m_inet.sin_addr , other.m_inet.sin_addr ) &&
227 m_inet.sin_port == other.m_inet.sin_port ;
230bool GNet::Address4::sameHostPart(
const Address4 & other )
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 ) ;
238bool GNet::Address4::sameAddr( const ::in_addr & a , const ::in_addr & b )
240 return a.s_addr == b.s_addr ;
243unsigned int GNet::Address4::port()
const
245 return ntohs( m_inet.sin_port ) ;
248unsigned long GNet::Address4::scopeId(
unsigned long default_ )
const
254const sockaddr * GNet::Address4::address()
const
256 return reinterpret_cast<const sockaddr*
>(&m_inet) ;
260sockaddr * GNet::Address4::address()
262 return reinterpret_cast<sockaddr*
>(&m_inet) ;
265socklen_t GNet::Address4::length() noexcept
267 return sizeof(sockaddr_type) ;
272 std::string ip_str = hostPartString() ;
275 result.reserve( 38U ) ;
276 result.push_back( ip_str ) ;
285 G_ASSERT( part.valid() ) ;
289 G_ASSERT( !(++part).valid() ) ;
304 std::string part_0_1_2 = std::string(part0.data(),part0.size()).append(1U,
'.')
305 .append(part1.data(),part1.size()).append(1U,
'.')
306 .append(part2.data(),part2.size()).append(1U,
'.') ;
307 std::string part_0_1 = std::string(part0.data(),part0.size()).append(1U,
'.')
308 .append(part1.data(),part1.size()).append(1U,
'.') ;
309 std::string part_0 = std::string(part0.data(),part0.size()).append(1U,
'.') ;
311 add( result , part_0_1_2 , n3 & 0xffU ,
"/32" ) ;
312 add( result , part_0_1_2 , n3 & 0xfeU ,
"/31" ) ;
313 add( result , part_0_1_2 , n3 & 0xfcU ,
"/30" ) ;
314 add( result , part_0_1_2 , n3 & 0xf8U ,
"/29" ) ;
315 add( result , part_0_1_2 , n3 & 0xf0U ,
"/28" ) ;
316 add( result , part_0_1_2 , n3 & 0xe0U ,
"/27" ) ;
317 add( result , part_0_1_2 , n3 & 0xc0U ,
"/26" ) ;
318 add( result , part_0_1_2 , n3 & 0x80U ,
"/25" ) ;
319 add( result , part_0_1_2 , 0 ,
"/24" ) ;
320 add( result , part_0_1_2 ,
"*" ) ;
321 add( result , part_0_1 , n2 & 0xfeU ,
".0/23" ) ;
322 add( result , part_0_1 , n2 & 0xfcU ,
".0/22" ) ;
323 add( result , part_0_1 , n2 & 0xfcU ,
".0/21" ) ;
324 add( result , part_0_1 , n2 & 0xf8U ,
".0/20" ) ;
325 add( result , part_0_1 , n2 & 0xf0U ,
".0/19" ) ;
326 add( result , part_0_1 , n2 & 0xe0U ,
".0/18" ) ;
327 add( result , part_0_1 , n2 & 0xc0U ,
".0/17" ) ;
328 add( result , part_0_1 , 0 ,
".0/16" ) ;
329 add( result , part_0_1 ,
"*.*" ) ;
330 add( result , part_0 , n1 & 0xfeU ,
".0.0/15" ) ;
331 add( result , part_0 , n1 & 0xfcU ,
".0.0/14" ) ;
332 add( result , part_0 , n1 & 0xf8U ,
".0.0/13" ) ;
333 add( result , part_0 , n1 & 0xf0U ,
".0.0/12" ) ;
334 add( result , part_0 , n1 & 0xe0U ,
".0.0/11" ) ;
335 add( result , part_0 , n1 & 0xc0U ,
".0.0/10" ) ;
336 add( result , part_0 , n1 & 0x80U ,
".0.0/9" ) ;
337 add( result , part_0 , 0 ,
".0.0/8" ) ;
338 add( result , part_0 ,
"*.*.*" ) ;
339 add( result , n0 & 0xfeU ,
".0.0.0/7" ) ;
340 add( result , n0 & 0xfcU ,
".0.0.0/6" ) ;
341 add( result , n0 & 0xf8U ,
".0.0.0/5" ) ;
342 add( result , n0 & 0xf0U ,
".0.0.0/4" ) ;
343 add( result , n0 & 0xe0U ,
".0.0.0/3" ) ;
344 add( result , n0 & 0xc0U ,
".0.0.0/2" ) ;
345 add( result , n0 & 0x80U ,
".0.0.0/1" ) ;
346 add( result , 0 ,
".0.0.0/0" ) ;
347 add( result ,
"*.*.*.*" ) ;
354 result.push_back( G::sv_to_string(head).append(
G::Str::fromUInt(n)).append(tail) ) ;
357void GNet::Address4::add(
G::StringArray & result ,
unsigned int n ,
const char * tail )
364 result.push_back( G::sv_to_string(head).append(tail) ) ;
367void GNet::Address4::add(
G::StringArray & result ,
const char * tail )
369 result.push_back( std::string(tail) ) ;
376 if( s.empty() || s.find_first_not_of(
"0123456789.") != std::string::npos ||
377 std::count(s.begin(),s.end(),
'.') != 3U || s.at(0U) ==
'.' ||
378 s.at(s.size()-1U) ==
'.' || s.find(
"..") != std::string::npos )
381 unsigned int n = 0U ;
382 unsigned int z =
static_cast<unsigned char>(
'0') ;
385 unsigned int uc =
static_cast<unsigned char>(c) ;
386 n = c ==
'.' ? 0U : ( ( n * 10U ) + (uc-z) ) ;
393unsigned int GNet::Address4::bits()
const
395 const unsigned long a = ntohl( m_inet.sin_addr.s_addr ) ;
396 unsigned int count = 0U ;
397 for(
unsigned long mask = 0x80000000U ; mask && ( a & mask ) ; mask >>= 1U )
402bool GNet::Address4::isLocal( std::string & reason )
const
404 if( isLoopback() || isLinkLocal() || isUniqueLocal() )
410 reason = hostPartString().append(
" is not in "
411 "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" ) ;
416bool GNet::Address4::isLoopback()
const
419 return ( ntohl(m_inet.sin_addr.s_addr) >> 24U ) == 127U ;
422bool GNet::Address4::isLinkLocal()
const
425 return ( ntohl(m_inet.sin_addr.s_addr) >> 16U ) == 0xA9FEU ;
428bool GNet::Address4::isUniqueLocal()
const
432 ( ntohl(m_inet.sin_addr.s_addr) >> 24U ) == 0x0AU ||
433 ( ntohl(m_inet.sin_addr.s_addr) >> 20U ) == 0xAC1U ||
434 ( ntohl(m_inet.sin_addr.s_addr) >> 16U ) == 0xC0A8U ;
437bool GNet::Address4::isMulticast()
const
440 return ( ntohl(m_inet.sin_addr.s_addr) >> 28U ) == 0x0EU ;
443bool GNet::Address4::isAny()
const
445 return m_inet.sin_addr.s_addr == htonl(INADDR_ANY) ;
static string_view headView(string_view in, std::size_t pos, string_view default_={}) noexcept
Like head() but returning a view into the input string.
static string_view tailView(string_view in, std::size_t pos, string_view default_={}) noexcept
Like tail() but returning a view into the input string.
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 std::string join(string_view sep, const StringArray &strings)
Concatenates an array of strings with separators.
static bool isUInt(string_view s) noexcept
Returns true if the string can be converted into an unsigned integer without throwing an exception.
static std::string fromUInt(unsigned int ui)
Converts unsigned int 'ui' to a string.
static void splitIntoFields(string_view in, StringArray &out, char sep, char escape='\0', bool remove_escapes=true)
Splits the string into fields.
A zero-copy string field iterator where the field separators are short fixed strings.
A class like c++17's std::string_view.
std::vector< std::string > StringArray
A std::vector of std::strings.