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