VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gaddress_ipv6.cpp
1 //
2 // Copyright (C) 2017 Graeme Walker
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 // gaddress_ipv6.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gnet.h"
23 #include "gaddress.h"
24 #include "gaddress4.h"
25 #include "gaddress6.h"
26 #include <cstring>
27 
28 namespace
29 {
30  static bool is4( const sockaddr * p )
31  {
32  return p && p->sa_family == GNet::Address4::family() ;
33  }
34  static bool is4( const std::string & s )
35  {
36  std::string r ;
37  return GNet::Address4::validString(s,&r) ;
38  }
39  static bool is4( const std::string & s , unsigned int )
40  {
41  std::string r ;
42  return GNet::Address4::validStrings(s,"0",&r) ;
43  }
44 }
45 
46 bool GNet::Address::supports( Family )
47 {
48  return true ;
49 }
50 
52 {
53  return Address( Family::ipv4() , 0U ) ;
54 }
55 
56 GNet::Address::Address( Family f , unsigned int port ) :
57  m_4imp( f==Family::ipv4() ? new Address4(port) : nullptr ) ,
58  m_6imp( f!=Family::ipv4() ? new Address6(port) : nullptr )
59 {
60 }
61 
62 GNet::Address::Address( const AddressStorage & storage ) :
63  m_4imp( is4(storage.p()) ? new Address4(storage.p(),storage.n()) : nullptr ) ,
64  m_6imp( !is4(storage.p()) ? new Address6(storage.p(),storage.n()) : nullptr )
65 {
66 }
67 
68 GNet::Address::Address( const sockaddr * addr , socklen_t len ) :
69  m_4imp( is4(addr) ? new Address4(addr,len) : nullptr ) ,
70  m_6imp( !is4(addr) ? new Address6(addr,len) : nullptr )
71 {
72 }
73 
74 GNet::Address::Address( const std::string & s ) :
75  m_4imp( is4(s) ? new Address4(s) : nullptr ) ,
76  m_6imp( !is4(s) ? new Address6(s) : nullptr )
77 {
78 }
79 
80 GNet::Address::Address( const std::string & s , unsigned int port ) :
81  m_4imp( is4(s,port) ? new Address4(s,port) : nullptr ) ,
82  m_6imp( !is4(s,port) ? new Address6(s,port) : nullptr )
83 {
84 }
85 
86 GNet::Address::Address( const Address & other ) :
87  m_4imp( other.m_4imp ? new Address4(*other.m_4imp) : nullptr ) ,
88  m_6imp( other.m_6imp ? new Address6(*other.m_6imp) : nullptr )
89 {
90 }
91 
92 GNet::Address::Address( Family f , unsigned int port , int loopback_overload ) :
93  m_4imp( f==Family::ipv4() ? new Address4(port,loopback_overload) : nullptr ) ,
94  m_6imp( f!=Family::ipv4() ? new Address6(port,loopback_overload) : nullptr )
95 {
96 }
97 
98 GNet::Address GNet::Address::loopback( Family f , unsigned int port )
99 {
100  return Address( f , port , 1 ) ;
101 }
102 
103 void GNet::Address::operator=( const Address & addr )
104 {
105  Address temp( addr ) ;
106  std::swap( m_4imp , temp.m_4imp ) ;
107  std::swap( m_6imp , temp.m_6imp ) ;
108 }
109 
111 {
112  delete m_4imp ;
113  delete m_6imp ;
114 }
115 
116 void GNet::Address::setPort( unsigned int port )
117 {
118  m_4imp ? m_4imp->setPort(port) : m_6imp->setPort(port) ;
119 }
120 
121 bool GNet::Address::isLoopback() const
122 {
123  return
124  ( m_4imp && m_4imp->isLoopback() ) ||
125  ( m_6imp && m_6imp->isLoopback() ) ;
126 }
127 
128 bool GNet::Address::isLocal( std::string & reason ) const
129 {
130  return
131  ( m_4imp && m_4imp->isLocal(reason) ) ||
132  ( m_6imp && m_6imp->isLocal(reason) ) ;
133 }
134 
135 bool GNet::Address::operator==( const Address & other ) const
136 {
137  return
138  ( m_4imp && other.m_4imp && m_4imp->same(*other.m_4imp) ) ||
139  ( m_6imp && other.m_6imp && m_6imp->same(*other.m_6imp) ) ;
140 }
141 
142 bool GNet::Address::operator!=( const Address & other ) const
143 {
144  return !( *this == other ) ;
145 }
146 
147 bool GNet::Address::sameHostPart( const Address & other ) const
148 {
149  return
150  ( m_4imp && other.m_4imp && m_4imp->sameHostPart(*other.m_4imp) ) ||
151  ( m_6imp && other.m_6imp && m_6imp->sameHostPart(*other.m_6imp) ) ;
152 }
153 
154 std::string GNet::Address::displayString() const
155 {
156  return m_4imp ? m_4imp->displayString() : m_6imp->displayString() ;
157 }
158 
159 std::string GNet::Address::hostPartString() const
160 {
161  return m_4imp ? m_4imp->hostPartString() : m_6imp->hostPartString() ;
162 }
163 
164 bool GNet::Address::validString( const std::string & s , std::string * reason_p )
165 {
166  return Address4::validString( s , reason_p ) || Address6::validString( s , reason_p ) ;
167 }
168 
169 bool GNet::Address::validStrings( const std::string & s1 , const std::string & s2 , std::string * reason_p )
170 {
171  return Address4::validStrings( s1 , s2 , reason_p ) || Address6::validStrings( s1 , s2 , reason_p ) ;
172 }
173 
174 sockaddr * GNet::Address::address()
175 {
176  return m_4imp ? m_4imp->address() : m_6imp->address() ;
177 }
178 
179 const sockaddr * GNet::Address::address() const
180 {
181  return m_4imp ? m_4imp->address() : m_6imp->address() ;
182 }
183 
184 socklen_t GNet::Address::length() const
185 {
186  return m_4imp ? Address4::length() : Address6::length() ;
187 }
188 
189 unsigned int GNet::Address::port() const
190 {
191  return m_4imp ? m_4imp->port() : m_6imp->port() ;
192 }
193 
194 unsigned long GNet::Address::scopeId( unsigned long default_ ) const
195 {
196  return m_4imp ? default_ : m_6imp->scopeId() ;
197 }
198 
199 bool GNet::Address::validPort( unsigned int port )
200 {
201  return Address4::validPort( port ) ;
202 }
203 
204 bool GNet::Address::validData( const sockaddr * addr , socklen_t len )
205 {
206  return Address4::validData( addr , len ) || Address6::validData( addr , len ) ;
207 }
208 
209 int GNet::Address::domain() const
210 {
211  return m_4imp ? Address4::domain() : Address6::domain() ;
212 }
213 
215 {
216  return m_4imp ? Family::ipv4() : Family::ipv6() ;
217 }
218 
220 {
221  return m_4imp ? m_4imp->wildcards() : m_6imp->wildcards() ;
222 }
223 
224 // ===
225 
226 /// \class GNet::AddressStorageImp
227 /// A pimple-pattern implementation class used by GNet::AddressStorage.
228 ///
230 {
231 public:
232  Address6::union_type u ;
233  socklen_t n ;
234 } ;
235 
236 // ==
237 
239  m_imp(new AddressStorageImp)
240 {
241  m_imp->n = sizeof(Address6::union_type) ;
242 }
243 
245 {
246  delete m_imp ;
247 }
248 
249 sockaddr * GNet::AddressStorage::p1()
250 {
251  return &(m_imp->u.general) ;
252 }
253 
254 socklen_t * GNet::AddressStorage::p2()
255 {
256  return &m_imp->n ;
257 }
258 
259 const sockaddr * GNet::AddressStorage::p() const
260 {
261  return &m_imp->u.general ;
262 }
263 
264 socklen_t GNet::AddressStorage::n() const
265 {
266  return m_imp->n ;
267 }
268 
269 // ==
270 
271 // fallback implementation for inet_pton() -- see GCONFIG_HAVE_INET_PTON in gdef.h
272 //
273 int GNet::inet_pton_imp( int f , const char * p , void * result )
274 {
275  if( p == nullptr || result == nullptr ) return 0 ; // just in case
276  struct addrinfo ai_hint ;
277  std::memset( &ai_hint , 0 , sizeof(ai_hint) ) ;
278  ai_hint.ai_family = f ;
279  ai_hint.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV ;
280  struct addrinfo * ai_p = nullptr ;
281  int rc = getaddrinfo( p , nullptr , &ai_hint , &ai_p ) ;
282  bool ok = rc == 0 && ai_p != nullptr ;
283  if( ok && ai_p->ai_addr == nullptr ) { freeaddrinfo(ai_p) ; return 1 ; } // just in case
284  if( ok )
285  {
286  struct sockaddr * sa_p = ai_p->ai_addr ;
287  if( ai_p->ai_family == AF_INET )
288  {
289  struct sockaddr_in sa = *reinterpret_cast<struct sockaddr_in*>(sa_p) ;
290  *reinterpret_cast<struct in_addr*>(result) = sa.sin_addr ;
291  }
292  else if( ai_p->ai_family == AF_INET6 )
293  {
294  struct sockaddr_in6 sa = *reinterpret_cast<struct sockaddr_in6*>(sa_p) ;
295  *reinterpret_cast<struct in6_addr*>(result) = sa.sin6_addr ;
296  }
297  else
298  ok = false ;
299  freeaddrinfo( ai_p ) ;
300  }
301  return ok ? 1 : 0 ;
302 }
303 
304 #if ! GCONFIG_HAVE_INET_NTOP
305 // fallback implementation for inet_ntop() -- see GCONFIG_HAVE_INET_NTOP in gdef.h
306 const char * GNet::inet_ntop_imp( int f , void * ap , char * buffer , size_t n )
307 {
308  std::string s ;
309  if( f == AF_INET )
310  {
311  std::ostringstream ss ;
312  struct in_addr a = *reinterpret_cast<struct in_addr*>(ap) ;
313  ss << inet_ntoa( a ) ; // ignore warnings - this is not used if inet_ntop is available
314  s = ss.str() ;
315  }
316  else if( f == AF_INET6 )
317  {
318  struct in6_addr a = *reinterpret_cast<struct in6_addr*>(ap) ;
319  std::ostringstream ss ;
320  const char * sep = ":" ;
321  const char * hexmap = "0123456789abcdef" ;
322  for( int i = 0 ; i < 16 ; i++ , sep = *sep ? "" : ":" )
323  {
324  unsigned int n = static_cast<unsigned int>(a.s6_addr[i]) % 256U ;
325  ss << sep << hexmap[(n>>4U)%16U] << hexmap[(n&15U)%16U] ;
326  }
327  ss << ":" ;
328  s = ss.str() ;
329  for( std::string::size_type pos = s.find(":0") ; pos != std::string::npos ; pos = s.find(":0",pos) )
330  {
331  if( s.find(":0:",pos) == std::string::npos )
332  s.erase( pos+1U , 1U ) ;
333  else
334  pos++ ;
335  }
336  std::string run = ":0:0:0:0:0:0:0:0:" ;
337  while( run.length() >= 3U )
338  {
339  std::string::size_type pos = s.find( run ) ;
340  if( pos != std::string::npos )
341  {
342  std::string::size_type r = 2U ;
343  if( pos == 0U ) r++ ;
344  if( (pos + run.length()) == s.length() ) r++ ;
345  s.replace( pos , run.length() , std::string("::::").substr(0U,r) ) ;
346  break ;
347  }
348  run.erase( 0U , 2U ) ;
349  }
350  s.erase( 0U , 1U ) ;
351  s.erase( s.length()-1U , 1U ) ;
352  }
353  else
354  {
355  return nullptr ;
356  }
357  if( n <= s.length() ) return nullptr ;
358  std::strncpy( buffer , s.c_str() , n ) ;
359  return buffer ;
360 }
361 #endif
362 
static Address loopback(Family, unsigned int port=0U)
Returns a loopback address.
Family family() const
Returns the address family.
static bool validData(const sockaddr *, socklen_t len)
Returns true if the sockaddr data is valid.
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:55
bool isLoopback() const
Returns true if this is a loopback address.
static bool validStrings(const std::string &ip, const std::string &port_string, std::string *reason=nullptr)
Returns true if the combined ip address string and port string is valid.
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstrings.h:33
socklen_t * p2()
Returns the length pointer for accept()/getsockname()/getpeername() to write into.
sockaddr * p1()
Returns the sockaddr pointer for accept()/getsockname()/getpeername() to write into.
A pimple-pattern implementation class used by GNet::AddressStorage.
const sockaddr * address() const
Returns the sockaddr address.
bool sameHostPart(const Address &other) const
Returns true if the two addresses have the same host part (ie.
unsigned int port() const
Returns port part of the address.
bool operator==(const Address &) const
Comparison operator.
const sockaddr * p() const
Returns the pointer.
AddressStorage()
Default constructor.
static Address defaultAddress()
Returns a default address, being the IPv4 wildcard address with a zero port number.
G::StringArray wildcards() const
Returns an ordered list of wildcard strings that match this address.
socklen_t length() const
Returns the size of the sockaddr address. See address().
std::string hostPartString() const
Returns a string which represents the network address for debugging and diagnostics purposes...
unsigned long scopeId(unsigned long default_=0UL) const
Returns the scope-id.
static bool validString(const std::string &display_string, std::string *reason=nullptr)
Returns true if the display string is valid.
int domain() const
Returns the address 'domain', eg. PF_INET.
~Address()
Destructor.
~AddressStorage()
Destructor.
static bool validPort(unsigned int n)
Returns true if the port number is within the valid range.
A type-safe enumerator for IP address family.
Definition: gaddress.h:58
This file is formatted for side-by-side comparison with gaddress4.h.
bool isLocal(std::string &reason) const
Returns true if this seems to be a local address.
void operator=(const Address &addr)
Assignment operator.
Address(const Address &)
Copy constructor.
This file is formatted for side-by-side comparison with gaddress6.h.
void setPort(unsigned int port)
Sets the port number.
socklen_t n() const
Returns the length.
static bool supports(Family)
Returns true if the implementation supports the given address family.
bool operator!=(const Address &) const
Comparison operator.
std::string displayString() const
Returns a string which represents the transport address for debugging and diagnostics purposes...