E-MailRelay

gaddress.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gaddress.cpp
19///
20
21#include "gdef.h"
22#include "gaddress4.h"
23#include "gaddress6.h"
24#include "gaddresslocal.h"
25#include "gaddress.h"
26#include "gstr.h"
27#include "gassert.h"
28#include <algorithm> // std::swap()
29#include <utility> // std::swap()
30#include <sstream>
31#include <cstring>
32
33 bool GNet::Address::supports( Family f ) noexcept
34{
35 if( f == Address::Family::ipv4 && Address4::af() == 0 )
36 return false ; // fwiw
37 else if( f == Address::Family::ipv6 && Address6::af() == 0 )
38 return false ; // fwiw
39 else if( f == Address::Family::local && AddressLocal::af() == 0 )
40 return false ;
41 else
42 return true ;
43}
44
45 bool GNet::Address::supports( int af , int ) noexcept
46{
47 return af == Address4::af() || af == Address6::af() || af == AddressLocal::af() ;
48}
49
50 bool GNet::Address::supports( const Address::Domain & , int domain ) noexcept
51{
52 return domain == Address4::domain() || domain == Address6::domain() || domain == AddressLocal::domain() ;
53}
54
55 GNet::Address::Address( Family f , unsigned int port )
56{
57 if( Address4::af() && f == Address::Family::ipv4 )
58 m_ipv4 = std::make_unique<Address4>( port ) ;
59 else if( Address6::af() && f == Address::Family::ipv6 )
60 m_ipv6 = std::make_unique<Address6>( port ) ;
61 else if( AddressLocal::af() && f == Address::Family::local )
62 m_local = std::make_unique<AddressLocal>( port ) ;
63 else
64 throw Address::BadFamily() ;
65}
66
67 GNet::Address::Address( const sockaddr * addr , socklen_t len , bool ipv6_scope_id_fixup )
68{
69 if( addr == nullptr || len < static_cast<socklen_t>(sizeof(sockaddr::sa_family)) )
70 throw Address::Error() ;
71 else if( addr->sa_family == 0 )
72 throw Address::BadFamily() ;
73 else if( Address4::af() && addr->sa_family == Address4::af() )
74 m_ipv4 = std::make_unique<Address4>( addr , len ) ;
75 else if( Address6::af() && addr->sa_family == Address6::af() )
76 m_ipv6 = std::make_unique<Address6>( addr , len , ipv6_scope_id_fixup ) ;
77 else if( AddressLocal::af() && addr->sa_family == AddressLocal::af() )
78 m_local = std::make_unique<AddressLocal>( addr , len ) ;
79 else
80 throw Address::BadFamily() ;
81}
82
83 GNet::Address::Address( const sockaddr * addr , socklen_t len ) :
84 Address(addr,len,false)
85{
86}
87
88 GNet::Address::Address( const AddressStorage & storage ) :
89 Address(storage.p(),storage.n(),false)
90{
91}
92
93 GNet::Address::Address( std::string_view s , bool with_local )
94{
95 if( s.empty() )
96 throw Address::Error( "empty string" ) ;
97
98 std::string r1 ;
99 std::string r2 ;
100 if( with_local && AddressLocal::af() && isFamilyLocal(s) )
101 m_local = std::make_unique<AddressLocal>( s ) ;
102 else if( Address4::af() && Address4::validString(s,&r1) )
103 m_ipv4 = std::make_unique<Address4>( s ) ;
104 else if( Address6::af() && Address6::validString(s,&r2) )
105 m_ipv6 = std::make_unique<Address6>( s ) ;
106 else
107 throw Address::Error( r1 , r1==r2?std::string():r2 , G::Str::printable(s) ) ;
108}
109
110 GNet::Address::Address( std::string_view host_part , std::string_view port_part )
111{
112 if( host_part.empty() )
113 throw Address::Error( "empty string" ) ;
114
115 std::string r1 ;
116 std::string r2 ;
117 if( AddressLocal::af() && isFamilyLocal( host_part ) )
118 m_local = std::make_unique<AddressLocal>( host_part ) ;
119 else if( Address4::af() && Address4::validStrings(host_part,port_part,&r1) )
120 m_ipv4 = std::make_unique<Address4>( host_part , port_part ) ;
121 else if( Address6::af() && Address6::validStrings(host_part,port_part,&r2) )
122 m_ipv6 = std::make_unique<Address6>( host_part , port_part ) ;
123 else
124 throw Address::Error( r1 , r1==r2?std::string():r2 , G::Str::printable(host_part) , G::Str::printable(port_part) ) ;
125}
126
127 GNet::Address::Address( std::string_view host_part , unsigned int port ) :
128 Address(host_part,G::Str::fromUInt(port))
129{
130}
131
132 GNet::Address::Address( Family f , unsigned int port , int loopback_overload )
133{
134 if( Address4::af() && f == Address::Family::ipv4 )
135 m_ipv4 = std::make_unique<Address4>( port , loopback_overload ) ;
136 else if( Address6::af() && f == Address::Family::ipv6 )
137 m_ipv6 = std::make_unique<Address6>( port , loopback_overload ) ;
138 else if( AddressLocal::af() && f == Address::Family::local )
139 m_local = std::make_unique<AddressLocal>( port , loopback_overload ) ;
140 else
141 throw Address::BadFamily() ;
142}
143
144 GNet::Address::Address( const Address & other )
145{
146 G_ASSERT( other.m_ipv4 || other.m_ipv6 || other.m_local ) ;
147 if( other.m_ipv4 )
148 m_ipv4 = std::make_unique<Address4>( *other.m_ipv4 ) ;
149 if( other.m_ipv6 )
150 m_ipv6 = std::make_unique<Address6>( *other.m_ipv6 ) ;
151 if( other.m_local )
152 m_local = std::make_unique<AddressLocal>( *other.m_local ) ;
153}
154
155 GNet::Address::Address( Address && other ) noexcept
156= default ;
157
158 GNet::Address::~Address()
159= default;
160
161 void GNet::Address::swap( Address & other ) noexcept
162{
163 using std::swap ;
164 swap( m_ipv4 , other.m_ipv4 ) ;
165 swap( m_ipv6 , other.m_ipv6 ) ;
166 swap( m_local , other.m_local ) ;
167}
168
169 GNet::Address & GNet::Address::operator=( const Address & other )
170{
171 Address(other).swap( *this ) ;
172 return *this ;
173}
174
175 GNet::Address & GNet::Address::operator=( Address && other ) noexcept
176= default ;
177
178 GNet::Address GNet::Address::parse( std::string_view s )
179{
180 return { s , true } ;
181}
182
183 GNet::Address GNet::Address::parse( std::string_view s , Address::NotLocal )
184{
185 return { s , false } ;
186}
187
188 GNet::Address GNet::Address::parse( std::string_view host_part , unsigned int port )
189{
190 return { host_part , port } ;
191}
192
193 GNet::Address GNet::Address::parse( std::string_view host_part , std::string_view port_part )
194{
195 return { host_part , port_part } ;
196}
197
198 bool GNet::Address::isFamilyLocal( std::string_view s ) noexcept
199{
200 return supports( Family::local ) && !s.empty() && s[0] == '/' ;
201}
202
203 GNet::Address GNet::Address::defaultAddress()
204{
205 return { Family::ipv4 , 0U } ;
206}
207
208 GNet::Address GNet::Address::loopback( Family f , unsigned int port )
209{
210 return { f , port , 1 } ;
211}
212
213GNet::Address::operator G::BasicAddress() const
214{
215 return G::BasicAddress( displayString() ) ;
216}
217
218 GNet::Address & GNet::Address::setPort( unsigned int port )
219{
220 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
221 if( m_ipv4 ) m_ipv4->setPort( port ) ;
222 if( m_ipv6 ) m_ipv6->setPort( port ) ;
223 if( m_local ) m_local->setPort( port ) ;
224 return *this ;
225}
226
227#ifndef G_LIB_SMALL
228 bool GNet::Address::setZone( const std::string & ipv6_zone )
229{
230 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
231 if( m_ipv4 ) m_ipv4->setZone( ipv6_zone ) ;
232 if( m_ipv6 ) m_ipv6->setZone( ipv6_zone ) ;
233 if( m_local ) m_local->setZone( ipv6_zone ) ;
234 return true ;
235}
236#endif
237
238 GNet::Address & GNet::Address::setScopeId( unsigned long ipv6_scope_id )
239{
240 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
241 if( m_ipv4 ) m_ipv4->setScopeId( ipv6_scope_id ) ;
242 if( m_ipv6 ) m_ipv6->setScopeId( ipv6_scope_id ) ;
243 if( m_local ) m_local->setScopeId( ipv6_scope_id ) ;
244 return *this ;
245}
246
247 unsigned int GNet::Address::bits() const
248{
249 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
250 if( m_ipv4 ) return m_ipv4->bits() ;
251 if( m_ipv6 ) return m_ipv6->bits() ;
252 if( m_local ) return m_local->bits() ;
253 return 0U ;
254}
255
256 bool GNet::Address::isLoopback() const
257{
258 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
259 return
260 ( m_ipv4 && m_ipv4->isLoopback() ) ||
261 ( m_ipv6 && m_ipv6->isLoopback() ) ||
262 ( m_local && m_local->isLoopback() ) ;
263}
264
265 bool GNet::Address::isLocal( std::string & reason ) const
266{
267 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
268 return
269 ( m_ipv4 && m_ipv4->isLocal(reason) ) ||
270 ( m_ipv6 && m_ipv6->isLocal(reason) ) ||
271 ( m_local && m_local->isLocal(reason) ) ;
272}
273
274 bool GNet::Address::isLinkLocal() const
275{
276 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
277 return
278 ( m_ipv4 && m_ipv4->isLinkLocal() ) ||
279 ( m_ipv6 && m_ipv6->isLinkLocal() ) ||
280 ( m_local && m_local->isLinkLocal() ) ;
281}
282
283#ifndef G_LIB_SMALL
284 bool GNet::Address::isMulticast() const
285{
286 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
287 return
288 ( m_ipv4 && m_ipv4->isMulticast() ) ||
289 ( m_ipv6 && m_ipv6->isMulticast() ) ||
290 ( m_local && m_local->isMulticast() ) ;
291}
292#endif
293
294 bool GNet::Address::isUniqueLocal() const
295{
296 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
297 return
298 ( m_ipv4 && m_ipv4->isUniqueLocal() ) ||
299 ( m_ipv6 && m_ipv6->isUniqueLocal() ) ||
300 ( m_local && m_local->isUniqueLocal() ) ;
301}
302
303 bool GNet::Address::isAny() const
304{
305 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
306 return
307 ( m_ipv4 && m_ipv4->isAny() ) ||
308 ( m_ipv6 && m_ipv6->isAny() ) ||
309 ( m_local && m_local->isAny() ) ;
310}
311
312 bool GNet::Address::is4() const noexcept
313{
314 return !!m_ipv4 ;
315}
316
317 bool GNet::Address::is6() const noexcept
318{
319 return !!m_ipv6 ;
320}
321
322 bool GNet::Address::same( const Address & other , bool ipv6_compare_with_scope ) const
323{
324 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
325 return
326 ( m_ipv4 && other.m_ipv4 && m_ipv4->same(*other.m_ipv4,ipv6_compare_with_scope) ) ||
327 ( m_ipv6 && other.m_ipv6 && m_ipv6->same(*other.m_ipv6,ipv6_compare_with_scope) ) ||
328 ( m_local && other.m_local && m_local->same(*other.m_local,ipv6_compare_with_scope) ) ;
329}
330
331 bool GNet::Address::operator==( const Address & other ) const
332{
333 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
334 return
335 ( m_ipv4 && other.m_ipv4 && m_ipv4->same(*other.m_ipv4) ) ||
336 ( m_ipv6 && other.m_ipv6 && m_ipv6->same(*other.m_ipv6) ) ||
337 ( m_local && other.m_local && m_local->same(*other.m_local) ) ;
338}
339
340 bool GNet::Address::operator!=( const Address & other ) const
341{
342 return !( *this == other ) ;
343}
344
345#ifndef G_LIB_SMALL
346 bool GNet::Address::sameHostPart( const Address & other ) const
347{
348 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
349 return
350 ( m_ipv4 && other.m_ipv4 && m_ipv4->sameHostPart(*other.m_ipv4) ) ||
351 ( m_ipv6 && other.m_ipv6 && m_ipv6->sameHostPart(*other.m_ipv6) ) ||
352 ( m_local && other.m_local && m_local->sameHostPart(*other.m_local) ) ;
353}
354#endif
355
356std::string GNet::Address::displayString( bool ipv6_with_scope_id ) const
357{
358 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
359 if( m_ipv4 ) return m_ipv4->displayString( ipv6_with_scope_id ) ;
360 if( m_ipv6 ) return m_ipv6->displayString( ipv6_with_scope_id ) ;
361 if( m_local ) return m_local->displayString( ipv6_with_scope_id ) ;
362 return {} ;
363}
364
365std::string GNet::Address::hostPartString() const
366{
367 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
368 if( m_ipv4 ) return m_ipv4->hostPartString() ;
369 if( m_ipv6 ) return m_ipv6->hostPartString() ;
370 if( m_local ) return m_local->hostPartString() ;
371 return {} ;
372}
373
374std::string GNet::Address::queryString() const
375{
376 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
377 if( m_ipv4 ) return m_ipv4->queryString() ;
378 if( m_ipv6 ) return m_ipv6->queryString() ;
379 if( m_local ) return m_local->queryString() ;
380 return {} ;
381}
382
383 bool GNet::Address::validString( std::string_view s , std::string * reason_p )
384{
385 return
386 Address4::validString( s , reason_p ) ||
387 Address6::validString( s , reason_p ) ||
388 AddressLocal::validString( s , reason_p ) ;
389}
390
391 bool GNet::Address::validString( std::string_view s , NotLocal , std::string * reason_p )
392{
393 return
394 Address4::validString( s , reason_p ) ||
395 Address6::validString( s , reason_p ) ;
396}
397
398 bool GNet::Address::validStrings( std::string_view s1 , std::string_view s2 , std::string * reason_p )
399{
400 return
401 Address4::validStrings( s1 , s2 , reason_p ) ||
402 Address6::validStrings( s1 , s2 , reason_p ) ||
403 AddressLocal::validStrings( s1 , s2 , reason_p ) ;
404}
405
406#ifndef G_LIB_SMALL
407sockaddr * GNet::Address::address()
408{
409 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
410 if( m_ipv4 ) return m_ipv4->address() ;
411 if( m_ipv6 ) return m_ipv6->address() ;
412 if( m_local ) return m_local->address() ;
413 return nullptr ;
414}
415#endif
416
417 const sockaddr * GNet::Address::address() const
418{
419 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
420 if( m_ipv4 ) return m_ipv4->address() ;
421 if( m_ipv6 ) return m_ipv6->address() ;
422 if( m_local ) return m_local->address() ;
423 return nullptr ;
424}
425
426socklen_t GNet::Address::length() const
427{
428 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
429 if( m_ipv4 ) return Address4::length() ;
430 if( m_ipv6 ) return Address6::length() ;
431 if( m_local ) return m_local->length() ;
432 return 0 ;
433}
434
435 unsigned int GNet::Address::port() const
436{
437 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
438 if( m_ipv4 ) return m_ipv4->port() ;
439 if( m_ipv6 ) return m_ipv6->port() ;
440 if( m_local ) return m_local->port() ;
441 return 0 ;
442}
443
444 unsigned long GNet::Address::scopeId( unsigned long default_ ) const
445{
446 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
447 if( m_ipv4 ) return m_ipv4->scopeId( default_ ) ;
448 if( m_ipv6 ) return m_ipv6->scopeId( default_ ) ;
449 if( m_local ) return m_local->scopeId( default_ ) ;
450 return default_ ;
451}
452
453 bool GNet::Address::validPort( unsigned int port )
454{
455 return Address4::validPort( port ) ;
456}
457
458 bool GNet::Address::validData( const sockaddr * addr , socklen_t len )
459{
460 return
461 Address4::validData( addr , len ) ||
462 Address6::validData( addr , len ) ||
463 AddressLocal::validData( addr , len ) ;
464}
465
466 int GNet::Address::domain( Family family ) noexcept
467{
468 if( family == Family::ipv4 ) return Address4::domain() ;
469 if( family == Family::ipv6 ) return Address6::domain() ;
470 if( family == Family::local ) return AddressLocal::domain() ;
471 return 0 ;
472}
473
474GNet::Address::Family GNet::Address::family() const noexcept
475{
476 if( m_ipv4 ) return Family::ipv4 ;
477 if( m_ipv6 ) return Family::ipv6 ;
478 if( m_local ) return Family::local ;
479 return Family::ipv4 ;
480}
481
482 int GNet::Address::af() const noexcept
483{
484 if( m_ipv4 ) return Address4::af() ;
485 if( m_ipv6 ) return Address6::af() ;
486 if( m_local ) return AddressLocal::af() ;
487 return 0 ;
488}
489
490 G::StringArray GNet::Address::wildcards() const
491{
492 G_ASSERT( m_ipv4 || m_ipv6 || m_local ) ;
493 if( m_ipv4 ) return m_ipv4->wildcards() ;
494 if( m_ipv6 ) return m_ipv6->wildcards() ;
495 if( m_local ) return m_local->wildcards() ;
496 return {} ;
497}
498
499// ===
500
501//| \class GNet::AddressStorageImp
502/// A pimple-pattern implementation class used by GNet::AddressStorage.
503///
504 class GNet::AddressStorageImp
505{
506 public:
507 sockaddr_storage u ;
508 socklen_t n ;
509} ;
510
511// ==
512
513 GNet::AddressStorage::AddressStorage() :
514 m_imp(std::make_unique<AddressStorageImp>())
515{
516 static_assert( sizeof(Address4::sockaddr_type) <= sizeof(sockaddr_storage) , "" ) ;
517 static_assert( sizeof(Address6::sockaddr_type) <= sizeof(sockaddr_storage) , "" ) ;
518 static_assert( sizeof(AddressLocal::sockaddr_type) <= sizeof(sockaddr_storage) , "" ) ;
519
520 static_assert( alignof(Address4::sockaddr_type) <= alignof(sockaddr_storage) , "" ) ;
521 static_assert( alignof(Address6::sockaddr_type) <= alignof(sockaddr_storage) , "" ) ;
522 static_assert( alignof(AddressLocal::sockaddr_type) <= alignof(sockaddr_storage) , "" ) ;
523
524 m_imp->n = sizeof( sockaddr_storage ) ;
525}
526
527 GNet::AddressStorage::~AddressStorage()
528= default ;
529
530sockaddr * GNet::AddressStorage::p1()
531{
532 return reinterpret_cast<sockaddr*>(&(m_imp->u)) ;
533}
534
535socklen_t * GNet::AddressStorage::p2()
536{
537 return &m_imp->n ;
538}
539
540 const sockaddr * GNet::AddressStorage::p() const
541{
542 return reinterpret_cast<const sockaddr*>(&(m_imp->u)) ;
543}
544
545socklen_t GNet::AddressStorage::n() const
546{
547 return m_imp->n ;
548}
549
550// ==
551
552#if ! GCONFIG_HAVE_INET_PTON
553// fallback implementation for inet_pton() using getaddrinfo() -- see gdef.h
554#ifndef G_LIB_SMALL
555 int GNet::inet_pton_imp( int f , const char * p , void * result )
556{
557 if( p == nullptr || result == nullptr ) return 0 ; // just in case
558 struct addrinfo ai_hint ;
559 std::memset( &ai_hint , 0 , sizeof(ai_hint) ) ;
560 ai_hint.ai_family = f ;
561 ai_hint.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV ;
562 struct addrinfo * ai_p = nullptr ;
563 int rc = getaddrinfo( p , nullptr , &ai_hint , &ai_p ) ;
564 bool ok = rc == 0 && ai_p != nullptr ;
565 if( ok && ai_p->ai_addr == nullptr ) { freeaddrinfo(ai_p) ; return 1 ; } // just in case
566 if( ok )
567 {
568 struct sockaddr * sa_p = ai_p->ai_addr ;
569 if( ai_p->ai_family == AF_INET )
570 {
571 struct sockaddr_in sa ;
572 std::memcpy( &sa , sa_p , sizeof(sa) ) ;
573 std::memcpy( result , &sa.sin_addr , sizeof(sa.sin_addr) ) ;
574 }
575 else if( ai_p->ai_family == AF_INET6 )
576 {
577 struct sockaddr_in6 sa ;
578 std::memcpy( &sa , sa_p , sizeof(sa) ) ;
579 std::memcpy( result , &sa.sin6_addr , sizeof(sa.sin6_addr) ) ;
580 }
581 else
582 {
583 ok = false ;
584 }
585 freeaddrinfo( ai_p ) ;
586 }
587 return ok ? 1 : 0 ;
588}
589#endif
590#endif
591
592#if ! GCONFIG_HAVE_INET_NTOP
593// fallback implementation for inet_ntop() using inet_ntoa() for ipv4 and by hand for ipv6 -- see gdef.h
594#ifndef G_LIB_SMALL
595 const char * GNet::inet_ntop_imp( int f , void * ap , char * buffer , std::size_t n )
596{
597 std::string s ;
598 if( f == AF_INET )
599 {
600 std::ostringstream ss ;
601 struct in_addr a ;
602 std::memcpy( &a , ap , sizeof(a) ) ;
603 ss << inet_ntoa( a ) ; // ignore warnings - this code is not used if inet_ntop is available
604 s = ss.str() ;
605 }
606 else if( f == AF_INET6 )
607 {
608 struct in6_addr a ;
609 std::memcpy( &a , ap , sizeof(a) ) ;
610 std::ostringstream ss ;
611 const char * sep = ":" ;
612 const char * hexmap = "0123456789abcdef" ;
613 for( int i = 0 ; i < 16 ; i++ , sep = *sep ? "" : ":" ) // sep alternates
614 {
615 unsigned int nn = static_cast<unsigned int>(a.s6_addr[i]) % 256U ;
616 ss << sep << hexmap[(nn>>4U)%16U] << hexmap[(nn&15U)%16U] ;
617 }
618 ss << ":" ;
619 // eg. ":0001:0002:0000:0000:0005:0006:dead:beef:"
620 s = ss.str() ;
621 for( std::string::size_type pos = s.find(":0") ; pos != std::string::npos ; pos = s.find(":0",pos) )
622 {
623 pos += 1U ;
624 while( s.at(pos) == '0' && s.at(pos+1U) != ':' )
625 s.erase( pos , 1U ) ;
626 }
627 // eg. ":1:2:0:0:5:6:dead:beef:"
628 std::string run = ":0:0:0:0:0:0:0:0:" ;
629 while( run.length() >= 5U ) // (single zero fields are not elided)
630 {
631 std::string::size_type pos = s.find( run ) ;
632 if( pos != std::string::npos )
633 {
634 std::string::size_type r = 2U ; // ":1:0:0:2:" -> ":1::2:"
635 if( pos == 0U ) r++ ; // ":0:0:1:2:" -> ":::1:2:"
636 if( (pos + run.length()) == s.length() ) r++ ; // ":1:0:0:" -> ":1:::", ":0:0:0:" -> "::::"
637 s.replace( pos , run.length() , std::string("::::").substr(0U,r) ) ;
638 break ;
639 }
640 run.erase( 0U , 2U ) ;
641 }
642 // eg. ":1:2::5:6:dead:beef:"
643 G_ASSERT( s.length() > 2U ) ;
644 s.erase( 0U , 1U ) ;
645 s.erase( s.length()-1U , 1U ) ;
646 // eg. "1:2::5:6:dead:beef"
647 }
648 else
649 {
650 return nullptr ;
651 }
652 if( n <= s.length() ) return nullptr ;
653 std::strncpy( buffer , s.c_str() , n ) ;
654 return buffer ;
655}
656#endif
657#endif
658
GNet::AddressStorage
A helper class for calling accept(), getsockname() and getpeername() and hiding the definition of soc...
Definition: gaddress.h:310
GNet::AddressStorage::p1
sockaddr * p1()
Returns the sockaddr pointer for accept()/getsockname()/getpeername() to write into.
Definition: gaddress.cpp:530
GNet::AddressStorage::p
const sockaddr * p() const
Returns the pointer, typically set via p1().
Definition: gaddress.cpp:540
GNet::AddressStorage::p2
socklen_t * p2()
Returns the length pointer for accept()/getsockname()/getpeername() to write into.
Definition: gaddress.cpp:535
GNet::AddressStorage::AddressStorage
AddressStorage()
Default constructor, with n() reflecting the size of the largest supported address type.
Definition: gaddress.cpp:513
GNet::AddressStorage::~AddressStorage
~AddressStorage()
Destructor.
GNet::AddressStorage::n
socklen_t n() const
Returns the length, typically modified via p2().
Definition: gaddress.cpp:545
GNet::Address
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:63
GNet::Address::setZone
bool setZone(const std::string &)
Sets the zone.
Definition: gaddress.cpp:228
GNet::Address::setScopeId
Address & setScopeId(unsigned long)
Sets the scope-id.
Definition: gaddress.cpp:238
GNet::Address::Address
Address(const Address &)
Copy constructor.
Definition: gaddress.cpp:144
GNet::Address::is6
bool is6() const noexcept
Returns true if family() is ipv6.
Definition: gaddress.cpp:317
GNet::Address::operator!=
bool operator!=(const Address &) const
Comparison operator.
Definition: gaddress.cpp:340
GNet::Address::isLinkLocal
bool isLinkLocal() const
Returns true if this is a link-local address.
Definition: gaddress.cpp:274
GNet::Address::operator==
bool operator==(const Address &) const
Comparison operator.
Definition: gaddress.cpp:331
GNet::Address::af
int af() const noexcept
Returns the address family number such as AF_INET or AFINET6.
Definition: gaddress.cpp:482
GNet::Address::queryString
std::string queryString() const
Returns a string that can be used as a prefix for rDNS or DNSBL queries.
Definition: gaddress.cpp:374
GNet::Address::wildcards
G::StringArray wildcards() const
Returns an ordered list of wildcard strings that match this address.
Definition: gaddress.cpp:490
GNet::Address::validData
static bool validData(const sockaddr *, socklen_t len)
Returns true if the sockaddr data is valid.
Definition: gaddress.cpp:458
GNet::Address::domain
static int domain(Family) noexcept
Returns the address 'domain' for the given family, eg.
Definition: gaddress.cpp:466
GNet::Address::validString
static bool validString(std::string_view display_string, std::string *reason=nullptr)
Returns true if the transport-address display string is valid.
Definition: gaddress.cpp:383
GNet::Address::validStrings
static bool validStrings(std::string_view ip, std::string_view port_string, std::string *reason=nullptr)
Returns true if the combined network-address string and port string is valid.
Definition: gaddress.cpp:398
GNet::Address::loopback
static Address loopback(Family, unsigned int port=0U)
Returns a loopback address.
Definition: gaddress.cpp:208
GNet::Address::is4
bool is4() const noexcept
Returns true if family() is ipv4.
Definition: gaddress.cpp:312
GNet::Address::validPort
static bool validPort(unsigned int n)
Returns true if the port number is within the valid range.
Definition: gaddress.cpp:453
GNet::Address::isUniqueLocal
bool isUniqueLocal() const
Returns true if this is a locally administered address.
Definition: gaddress.cpp:294
GNet::Address::swap
void swap(Address &other) noexcept
Swaps this with other.
Definition: gaddress.cpp:161
GNet::Address::length
socklen_t length() const
Returns the size of the sockaddr address. See address().
Definition: gaddress.cpp:426
GNet::Address::isLocal
bool isLocal(std::string &reason) const
Returns true if this seems to be a 'local' address, ie.
Definition: gaddress.cpp:265
GNet::Address::defaultAddress
static Address defaultAddress()
Returns a default address, being the IPv4 wildcard address with a zero port number.
Definition: gaddress.cpp:203
GNet::Address::operator=
Address & operator=(const Address &)
Assignment operator.
Definition: gaddress.cpp:169
GNet::Address::isAny
bool isAny() const
Returns true if this is the address family's 'any' address.
Definition: gaddress.cpp:303
GNet::Address::isFamilyLocal
static bool isFamilyLocal(std::string_view display_string) noexcept
Returns true if the given address display string looks will parse to Family::local and Family::local ...
Definition: gaddress.cpp:198
GNet::Address::~Address
~Address()
Destructor.
GNet::Address::parse
static Address parse(std::string_view display_string)
Factory function for any address family.
Definition: gaddress.cpp:178
GNet::Address::supports
static bool supports(Family) noexcept
Returns true if the implementation supports the given address family.
Definition: gaddress.cpp:33
GNet::Address::sameHostPart
bool sameHostPart(const Address &other) const
Returns true if the two addresses have the same host part (ie.
Definition: gaddress.cpp:346
GNet::Address::bits
unsigned int bits() const
Returns the number of leading bits set, relevant only to netmask addresses.
Definition: gaddress.cpp:247
GNet::Address::displayString
std::string displayString(bool with_scope_id=false) const
Returns a printable string that represents the transport address.
Definition: gaddress.cpp:356
GNet::Address::port
unsigned int port() const
Returns port part of the address.
Definition: gaddress.cpp:435
GNet::Address::hostPartString
std::string hostPartString() const
Returns a printable string that represents the network address.
Definition: gaddress.cpp:365
GNet::Address::isMulticast
bool isMulticast() const
Returns true if this is a multicast address.
Definition: gaddress.cpp:284
GNet::Address::isLoopback
bool isLoopback() const
Returns true if this is a loopback address.
Definition: gaddress.cpp:256
GNet::Address::address
const sockaddr * address() const
Returns the sockaddr address.
Definition: gaddress.cpp:417
GNet::Address::scopeId
unsigned long scopeId(unsigned long default_=0UL) const
Returns the scope-id.
Definition: gaddress.cpp:444
GNet::Address::setPort
Address & setPort(unsigned int port)
Sets the port number.
Definition: gaddress.cpp:218
GNet::Address::family
Family family() const noexcept
Returns the address family enumeration.
Definition: gaddress.cpp:474
GNet::Address::same
bool same(const Address &, bool ipv6_compare_with_scope) const
Comparison function.
Definition: gaddress.cpp:322
G::BasicAddress
A structure that holds a network address as a string with no dependency on any low-level network libr...
Definition: gbasicaddress.h:37
G::Str::printable
static std::string printable(const std::string &in, char escape='\\')
Returns a printable representation of the given input string, using chacter code ranges 0x20 to 0x7e ...
Definition: gstr.cpp:913
gaddress4.h
gaddress6.h
gaddress.h
gaddresslocal.h
gassert.h
gstr.h
G
Low-level classes.
Definition: garg.h:36
G::StringArray
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstringarray.h:30
std
STL namespace.
GNet::Address::Domain
Overload discriminator for Address::supports()
Definition: gaddress.h:72
GNet::Address::NotLocal
Overload discriminator for Address::parse()
Definition: gaddress.h:126