40 constexpr std::string_view port_separators {
":",1U} ;
41 constexpr char port_separator =
':' ;
45unsigned short GNet::Address4::af() noexcept
50int GNet::Address4::domain() noexcept
55GNet::Address4::Address4( std::nullptr_t ) :
58 m_inet.sin_family = af() ;
62GNet::Address4::Address4(
unsigned int port ) :
65 m_inet.sin_addr.s_addr = htonl(INADDR_ANY);
66 const char * reason = setPort( m_inet , port ) ;
67 if( reason )
throw Address::Error(reason) ;
70GNet::Address4::Address4(
unsigned int port ,
int ) :
73 m_inet.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
74 const char * reason = setPort( m_inet , port ) ;
75 if( reason )
throw Address::Error(reason) ;
78GNet::Address4::Address4(
const sockaddr * addr , socklen_t len ) :
82 throw Address::Error() ;
83 if( addr->sa_family != af() ||
static_cast<std::size_t
>(len) <
sizeof(sockaddr_type) )
84 throw Address::BadFamily() ;
86 m_inet = *(
reinterpret_cast<const sockaddr_type*
>(addr)) ;
89GNet::Address4::Address4( std::string_view host_part , std::string_view port_part ) :
92 const char * reason = setHostAddress( m_inet , host_part ) ;
94 reason = setPort( m_inet , port_part ) ;
96 throw Address::BadString( std::string(reason).append(
": [").append(host_part.data(),host_part.size()).append(
"][").append(port_part.data(),port_part.size()).append(1U,
']') ) ;
99GNet::Address4::Address4( std::string_view display_string ) :
102 const char * reason = setAddress( m_inet , display_string ) ;
104 throw Address::BadString( std::string(reason).append(
": ").append(display_string.data(),display_string.size()) ) ;
107const char * GNet::Address4::setAddress( sockaddr_type & inet , std::string_view display_string )
109 const std::string::size_type pos = display_string.find_last_of( Address4Imp::port_separators ) ;
110 if( pos == std::string::npos )
111 return "no port separator" ;
116 const char * reason = setHostAddress( inet , host_part ) ;
118 reason = setPort( inet , port_part ) ;
122const char * GNet::Address4::setHostAddress( sockaddr_type & inet , std::string_view host_part )
125 if( !Address4::format(host_part) )
126 return "invalid network address" ;
128 int rc = inet_pton( af() , G::sv_to_string(host_part).c_str() , &inet.sin_addr ) ;
129 return rc == 1 ? nullptr :
"invalid network address" ;
132void GNet::Address4::setPort(
unsigned int port )
134 const char * reason = setPort( m_inet , port ) ;
136 throw Address::Error(
"invalid port number" ) ;
139const char * GNet::Address4::setPort( sockaddr_type & inet , std::string_view port_part )
141 if( port_part.empty() )
return "empty port string" ;
146const char * GNet::Address4::setPort( sockaddr_type & inet ,
unsigned int port )
148 if( port > 0xFFFFU )
return "port number too big" ;
149 const g_port_t in_port =
static_cast<g_port_t
>(port) ;
150 inet.sin_port = htons( in_port ) ;
154bool GNet::Address4::setZone( std::string_view )
159void GNet::Address4::setScopeId(
unsigned long )
163std::string GNet::Address4::displayString(
bool )
const
165 std::ostringstream ss ;
166 ss << hostPartString() ;
167 ss << Address4Imp::port_separator << port() ;
171std::string GNet::Address4::hostPartString()
const
173 std::array<char,INET_ADDRSTRLEN+1U> buffer {} ;
174 const void * vp = & m_inet.sin_addr ;
175 const char * p = inet_ntop( af() ,
const_cast<void*
>(vp) , buffer.data() , buffer.size() ) ;
177 throw Address::Error(
"inet_ntop() failure" ) ;
178 buffer[buffer.size()-1U] =
'\0' ;
179 return { buffer.data() } ;
182std::string GNet::Address4::queryString()
const
185 std::reverse( parts.begin() , parts.end() ) ;
189bool GNet::Address4::validData(
const sockaddr * addr , socklen_t len )
191 return addr !=
nullptr && addr->sa_family == af() && len ==
sizeof(sockaddr_type) ;
194bool GNet::Address4::validString( std::string_view s , std::string * reason_p )
196 sockaddr_type inet {} ;
197 const char * reason = setAddress( inet , s ) ;
198 if( reason && reason_p )
199 *reason_p = std::string(reason) ;
200 return reason == nullptr ;
203bool GNet::Address4::validStrings( std::string_view host_part , std::string_view port_part ,
204 std::string * reason_p )
206 sockaddr_type inet {} ;
207 const char * reason = setHostAddress( inet , host_part ) ;
209 reason = setPort( inet , port_part ) ;
210 if( reason && reason_p )
211 *reason_p = std::string(reason) ;
212 return reason == nullptr ;
215bool GNet::Address4::validPort(
unsigned int port )
217 sockaddr_type inet {} ;
218 const char * reason = setPort( inet , port ) ;
219 return reason == nullptr ;
222bool GNet::Address4::same(
const Address4 & other ,
bool )
const
225 m_inet.sin_family == af() &&
226 other.m_inet.sin_family == af() &&
227 sameAddr( m_inet.sin_addr , other.m_inet.sin_addr ) &&
228 m_inet.sin_port == other.m_inet.sin_port ;
231bool GNet::Address4::sameHostPart(
const Address4 & other )
const
234 m_inet.sin_family == af() &&
235 other.m_inet.sin_family == af() &&
236 sameAddr( m_inet.sin_addr , other.m_inet.sin_addr ) ;
239bool GNet::Address4::sameAddr( const ::in_addr & a , const ::in_addr & b )
241 return a.s_addr == b.s_addr ;
244unsigned int GNet::Address4::port()
const
246 return ntohs( m_inet.sin_port ) ;
249unsigned long GNet::Address4::scopeId(
unsigned long default_ )
const
255const sockaddr * GNet::Address4::address()
const
257 return reinterpret_cast<const sockaddr*
>(&m_inet) ;
261sockaddr * GNet::Address4::address()
263 return reinterpret_cast<sockaddr*
>(&m_inet) ;
266socklen_t GNet::Address4::length() noexcept
268 return sizeof(sockaddr_type) ;
273 std::string ip_str = hostPartString() ;
276 result.reserve( 38U ) ;
277 result.push_back( ip_str ) ;
279 std::string_view ip_sv( ip_str.data() , ip_str.size() ) ;
281 std::string_view part0 = part() ;
282 std::string_view part1 = (++part)() ;
283 std::string_view part2 = (++part)() ;
284 std::string_view part3 = (++part)() ;
286 G_ASSERT( part.valid() ) ;
290 G_ASSERT( !(++part).valid() ) ;
305 std::string part_0_1_2 = std::string(part0.data(),part0.size()).append(1U,
'.')
306 .append(part1.data(),part1.size()).append(1U,
'.')
307 .append(part2.data(),part2.size()).append(1U,
'.') ;
308 std::string part_0_1 = std::string(part0.data(),part0.size()).append(1U,
'.')
309 .append(part1.data(),part1.size()).append(1U,
'.') ;
310 std::string part_0 = std::string(part0.data(),part0.size()).append(1U,
'.') ;
312 add( result , part_0_1_2 , n3 & 0xffU ,
"/32" ) ;
313 add( result , part_0_1_2 , n3 & 0xfeU ,
"/31" ) ;
314 add( result , part_0_1_2 , n3 & 0xfcU ,
"/30" ) ;
315 add( result , part_0_1_2 , n3 & 0xf8U ,
"/29" ) ;
316 add( result , part_0_1_2 , n3 & 0xf0U ,
"/28" ) ;
317 add( result , part_0_1_2 , n3 & 0xe0U ,
"/27" ) ;
318 add( result , part_0_1_2 , n3 & 0xc0U ,
"/26" ) ;
319 add( result , part_0_1_2 , n3 & 0x80U ,
"/25" ) ;
320 add( result , part_0_1_2 , 0 ,
"/24" ) ;
321 add( result , part_0_1_2 ,
"*" ) ;
322 add( result , part_0_1 , n2 & 0xfeU ,
".0/23" ) ;
323 add( result , part_0_1 , n2 & 0xfcU ,
".0/22" ) ;
324 add( result , part_0_1 , n2 & 0xfcU ,
".0/21" ) ;
325 add( result , part_0_1 , n2 & 0xf8U ,
".0/20" ) ;
326 add( result , part_0_1 , n2 & 0xf0U ,
".0/19" ) ;
327 add( result , part_0_1 , n2 & 0xe0U ,
".0/18" ) ;
328 add( result , part_0_1 , n2 & 0xc0U ,
".0/17" ) ;
329 add( result , part_0_1 , 0 ,
".0/16" ) ;
330 add( result , part_0_1 ,
"*.*" ) ;
331 add( result , part_0 , n1 & 0xfeU ,
".0.0/15" ) ;
332 add( result , part_0 , n1 & 0xfcU ,
".0.0/14" ) ;
333 add( result , part_0 , n1 & 0xf8U ,
".0.0/13" ) ;
334 add( result , part_0 , n1 & 0xf0U ,
".0.0/12" ) ;
335 add( result , part_0 , n1 & 0xe0U ,
".0.0/11" ) ;
336 add( result , part_0 , n1 & 0xc0U ,
".0.0/10" ) ;
337 add( result , part_0 , n1 & 0x80U ,
".0.0/9" ) ;
338 add( result , part_0 , 0 ,
".0.0/8" ) ;
339 add( result , part_0 ,
"*.*.*" ) ;
340 add( result , n0 & 0xfeU ,
".0.0.0/7" ) ;
341 add( result , n0 & 0xfcU ,
".0.0.0/6" ) ;
342 add( result , n0 & 0xf8U ,
".0.0.0/5" ) ;
343 add( result , n0 & 0xf0U ,
".0.0.0/4" ) ;
344 add( result , n0 & 0xe0U ,
".0.0.0/3" ) ;
345 add( result , n0 & 0xc0U ,
".0.0.0/2" ) ;
346 add( result , n0 & 0x80U ,
".0.0.0/1" ) ;
347 add( result , 0 ,
".0.0.0/0" ) ;
348 add( result ,
"*.*.*.*" ) ;
353void GNet::Address4::add(
G::StringArray & result , std::string_view head ,
unsigned int n ,
const char * tail )
355 result.push_back( G::sv_to_string(head).append(
G::Str::fromUInt(n)).append(tail) ) ;
358void GNet::Address4::add(
G::StringArray & result ,
unsigned int n ,
const char * tail )
363void GNet::Address4::add(
G::StringArray & result , std::string_view head ,
const char * tail )
365 result.push_back( G::sv_to_string(head).append(tail) ) ;
368void GNet::Address4::add(
G::StringArray & result ,
const char * tail )
370 result.emplace_back( tail ) ;
373bool GNet::Address4::format( std::string_view s )
377 if( s.empty() || s.find_first_not_of(
"0123456789.") != std::string::npos ||
378 std::count(s.begin(),s.end(),
'.') != 3U || s.at(0U) ==
'.' ||
379 s.at(s.size()-1U) ==
'.' || s.find(
"..") != std::string::npos )
382 unsigned int n = 0U ;
383 unsigned int z =
static_cast<unsigned char>(
'0') ;
386 unsigned int uc =
static_cast<unsigned char>(c) ;
387 n = c ==
'.' ? 0U : ( ( n * 10U ) + (uc-z) ) ;
394unsigned int GNet::Address4::bits()
const
396 const unsigned long a = ntohl( m_inet.sin_addr.s_addr ) ;
397 unsigned int count = 0U ;
398 for(
unsigned long mask = 0x80000000U ; mask && ( a & mask ) ; mask >>= 1U )
403bool GNet::Address4::isLocal( std::string & reason )
const
405 if( isLoopback() || isLinkLocal() || isUniqueLocal() )
411 reason = hostPartString().append(
" is not in "
412 "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" ) ;
417bool GNet::Address4::isLoopback()
const
420 return ( ntohl(m_inet.sin_addr.s_addr) >> 24U ) == 127U ;
423bool GNet::Address4::isLinkLocal()
const
426 return ( ntohl(m_inet.sin_addr.s_addr) >> 16U ) == 0xA9FEU ;
429bool GNet::Address4::isUniqueLocal()
const
433 ( ntohl(m_inet.sin_addr.s_addr) >> 24U ) == 0x0AU ||
434 ( ntohl(m_inet.sin_addr.s_addr) >> 20U ) == 0xAC1U ||
435 ( ntohl(m_inet.sin_addr.s_addr) >> 16U ) == 0xC0A8U ;
438bool GNet::Address4::isMulticast()
const
441 return ( ntohl(m_inet.sin_addr.s_addr) >> 28U ) == 0x0EU ;
444bool GNet::Address4::isAny()
const
446 return m_inet.sin_addr.s_addr == htonl(INADDR_ANY) ;
static bool isUInt(std::string_view s) noexcept
Returns true if the string can be converted into an unsigned integer without throwing an exception.
static std::string join(std::string_view sep, const StringArray &strings)
Concatenates an array of strings with separators.
static void splitIntoFields(std::string_view in, StringArray &out, char sep, char escape='\0', bool remove_escapes=true)
Splits the string into fields.
static bool isNumeric(std::string_view s, bool allow_minus_sign=false) noexcept
Returns true if every character is a decimal digit.
static std::string fromUInt(unsigned int ui)
Converts unsigned int 'ui' to a string.
static std::string_view tailView(std::string_view in, std::size_t pos, std::string_view default_={}) noexcept
Like tail() but returning a view into the input string.
static unsigned int toUInt(std::string_view s)
Converts string 's' to an unsigned int.
static std::string_view headView(std::string_view in, std::size_t pos, std::string_view default_={}) noexcept
Like head() but returning a view into the input string.
A zero-copy string field iterator where the field separators are short fixed strings.
std::vector< std::string > StringArray
A std::vector of std::strings.