dodo  0.0.1
A C++ library to create containerized Linux services
address.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the dodo library (https://github.com/jmspit/dodo).
3  * Copyright (c) 2019 Jan-Marten Spit.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * 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 /**
19  * @file address.cpp
20  * Implements the dodo::network::Address class.
21  */
22 
23 #include <cstring>
24 #include <fcntl.h>
25 #include <iostream>
26 #include <iostream>
27 #include <netdb.h>
28 #include <sstream>
29 #include <unistd.h>
30 
31 #include "network/address.hpp"
32 
33 namespace dodo::network {
34 
35  Address::Address( const std::string &address ) {
36  init();
37  *this = address;
38  }
39 
40  Address::Address( const std::string &ip, uint16_t port ) {
41  init();
42  *this = ip;
43  setPort( port );
44  }
45 
46  Address::Address( const sockaddr_storage& address ) {
47  addr_.ss_family = AF_UNSPEC;
48  memcpy( &addr_, &address, sizeof(addr_) );
49  }
50 
51  Address::Address( const sockaddr *address, socklen_t len ) {
52  addr_.ss_family = AF_UNSPEC;
53  memcpy( &addr_, address, len );
54  }
55 
56  Address::Address( const Address &address ) {
57  addr_.ss_family = AF_UNSPEC;
58  memcpy( &addr_, &(address.addr_), sizeof(addr_) );
59  }
60 
61  void Address::init() {
62  memset( &addr_, 0, sizeof(addr_) );
63  addr_.ss_family = AF_UNSPEC;
64  }
65 
66  Address& Address::operator=( const std::string& address ) {
67  auto rc = inet_pton( AF_INET, address.c_str(), &asIPv4Address()->sin_addr );
68  if ( rc != 1 ) {
69  rc = inet_pton( AF_INET6, address.c_str(), &asIPv6Address()->sin6_addr );
70  if ( rc != 1 ) {
71  memset( &addr_, 0, sizeof(addr_) );
72  addr_.ss_family = AF_UNSPEC;
73  } else {
74  addr_.ss_family = AF_INET6;
75  }
76  } else {
77  addr_.ss_family = AF_INET;
78  }
79  return *this;
80  }
81 
82  Address& Address::operator=( const Address& address ) {
83  memcpy( &addr_, &(address.addr_), sizeof(addr_) );
84  return *this;
85  }
86 
87  Address& Address::operator=( const sockaddr_storage& address ) {
88  memcpy( &addr_, &address, sizeof(addr_) );
89  return *this;
90  }
91 
92  bool Address::operator==( const Address& address ) const {
93  if ( addr_.ss_family == address.addr_.ss_family ) {
94  if ( addr_.ss_family == AF_INET ) {
95  sockaddr_in* local = asIPv4Address();
96  sockaddr_in* other = address.asIPv4Address();
97  return memcmp( local, other, sizeof(sockaddr_in) ) == 0;
98  } else if ( addr_.ss_family == AF_INET6 ) {
99  sockaddr_in6* local = asIPv6Address();
100  sockaddr_in6* other = address.asIPv6Address();
101  return memcmp( local, other, sizeof(sockaddr_in6) ) == 0;
102  } else return false;
103  } else return false;
104  }
105 
106 
107  std::string Address::asString( bool withport ) const {
108  char ip_[INET6_ADDRSTRLEN];
109  std::stringstream ss;
110  if ( addr_.ss_family == AF_INET ) {
111  if ( !inet_ntop( AF_INET, &asIPv4Address()->sin_addr, ip_, sizeof(ip_) ) )
112  throw_SystemExceptionObject( "inet_ntop failed", errno, this );
113  } else if ( addr_.ss_family == AF_INET6 ) {
114  if ( !inet_ntop( AF_INET6, &asIPv6Address()->sin6_addr, ip_, sizeof(ip_) ) )
115  throw_SystemExceptionObject( "inet_ntop failed", errno, this );
116  } else if ( addr_.ss_family == AF_UNSPEC ) {
117  return "invalid address";
118  } else {
119  return "unhandled address family";
120  }
121  ss << ip_;
122  if ( withport )
123  if ( getPort() ) ss << ":" << getPort();
124  return ss.str();
125  }
126 
127  uint16_t Address::getPort() const {
128  if ( addr_.ss_family == AF_INET ) {
129  return ntohs( asIPv4Address()->sin_port );
130  } else if ( addr_.ss_family == AF_INET6 ) {
131  return ntohs( asIPv6Address()->sin6_port );
132  }
133  return 0;
134  }
135 
136  void Address::setPort( uint16_t port ) {
137  if ( addr_.ss_family == AF_INET ) {
138  asIPv4Address()->sin_port = htons( port );
139  } else if ( addr_.ss_family == AF_INET6 ) {
140  asIPv6Address()->sin6_port = htons( port );
141  }
142  }
143 
144  common::SystemError Address::getHostAddrInfo( const std::string &hostname, AddrInfo& info ) {
145  struct addrinfo *ainfo = 0;
146  struct addrinfo ahints;
147  memset( &ahints, 0, sizeof(ahints) );
148  ahints.ai_family = AF_UNSPEC;
149  ahints.ai_flags = AI_CANONNAME | AI_CANONIDN | AI_ADDRCONFIG;
150  common::SystemError rc = getaddrinfo( hostname.c_str(),
151  0,
152  &ahints,
153  &ainfo );
154  if ( rc == common::SystemError::ecOK ) {
155  struct addrinfo *rp = 0;
156  for ( rp = ainfo; rp != NULL; rp = rp->ai_next ) {
157  AddrInfoItem item;
158  item.address = Address( rp->ai_addr, rp->ai_addrlen );
159  item.params.setAddressFamily( SocketParams::AddressFamily( rp->ai_family ) );
160  item.params.setSocketType( SocketParams::SocketType( rp->ai_socktype ) );
161  item.params.setProtocol( SocketParams::ProtocolNumber(rp->ai_protocol) );
162  if ( rp->ai_canonname ) info.canonicalname = rp->ai_canonname;
163  info.items.push_back( item );
164  }
165  if ( ainfo ) freeaddrinfo( ainfo );
166  } else if ( rc == common::SystemError::ecEAI_ADDRFAMILY ||
169  if ( ainfo ) freeaddrinfo( ainfo );
170  } else {
171  freeaddrinfo( ainfo );
172  throw_SystemException( "Address::getHostAddrInfo failed", rc );
173  }
174  return rc;
175  }
176 
177  common::SystemError Address::getHostAddrInfo( const std::string &hostname, SocketParams &params, Address &address, std::string &canonicalname ) {
178  address = Address();
179  canonicalname = "";
180  AddrInfo info;
181  common::SystemError error = getHostAddrInfo( hostname, info );
182  if ( error == common::SystemError::ecOK ) {
183  if ( info.items.size() < 1 ) return common::SystemError::ecEAI_NODATA;
184  for ( auto item : info.items ) {
185  if ( item.params.getAddressFamily() == params.getAddressFamily() || params.getAddressFamily() == SocketParams::afUNSPEC ) {
186  if ( item.params.getSocketType() == params.getSocketType() ) {
187  if ( item.params.getProtocol() == params.getProtocol() ) {
188  canonicalname = info.canonicalname;
189  address = item.address;
190  params.setAddressFamily( address.getAddressFamily() );
192  }
193  }
194  }
195  }
197  } else return error;
198  }
199 
200  common::SystemError Address::getNameInfo( std::string &hostname ) const {
201  char hbuf[NI_MAXHOST];
202  auto error = getnameinfo( (const sockaddr*) &addr_,
203  sizeof(addr_),
204  hbuf,
205  sizeof(hbuf),
206  NULL,
207  0,
208  NI_NAMEREQD );
209  if ( error == common::SystemError::ecEAI_SYSTEM ) error = errno;
210  if ( !error ) hostname = hbuf; else hostname = "";
211  return error;
212  }
213 
214  common::SystemError Address::getNameInfo( std::string &hostname, std::string &service ) const {
215  char hbuf[NI_MAXHOST];
216  char sbuf[NI_MAXSERV];
217  auto error = getnameinfo( (const sockaddr*) &addr_,
218  sizeof(addr_),
219  hbuf,
220  sizeof(hbuf),
221  sbuf,
222  sizeof(sbuf),
223  NI_NAMEREQD );
224  if ( error == common::SystemError::ecEAI_SYSTEM ) error = errno;
225  if ( !error ) hostname = hbuf; else hostname = "";
226  return error;
227  }
228 
229  common::SystemError Address::getNameInfo( std::string &hostname, uint16_t &port ) const {
230  char hbuf[NI_MAXHOST];
231  char sbuf[NI_MAXSERV];
232  auto error = getnameinfo( (const sockaddr*) &addr_,
233  sizeof(addr_),
234  hbuf,
235  sizeof(hbuf),
236  sbuf,
237  sizeof(sbuf),
238  NI_NAMEREQD | NI_NUMERICSERV );
239  if ( error == common::SystemError::ecEAI_SYSTEM ) error = errno;
240  if ( !error ) {
241  hostname = hbuf;
242  errno = 0;
243  int p = atoi( sbuf );
244  if ( errno ) throw_SystemException( "atoi faiure reading numeric port", errno );
245  port = static_cast<uint16_t>( p );
246  } else {
247  hostname = "";
248  port = 0;
249  }
250  return error;
251  }
252 
253 }
dodo::network::Address::getPort
uint16_t getPort() const
Return the port number.
Definition: address.cpp:127
dodo::network::Address::operator=
Address & operator=(const std::string &address)
Assign from "ip" string.
Definition: address.cpp:66
dodo::network::SocketParams::getAddressFamily
AddressFamily getAddressFamily() const
Get the AddressFamily.
Definition: socketparams.hpp:148
dodo::network::Address::getNameInfo
common::SystemError getNameInfo(std::string &hostname) const
Do a reverse DNS lookup on this Address and return in hostname.
Definition: address.cpp:200
dodo::network::SocketParams::setAddressFamily
void setAddressFamily(AddressFamily family)
Set the AddressFamily.
Definition: socketparams.hpp:166
dodo::network::Address::asString
std::string asString(bool withport=false) const
Return a string representation of this Address.
Definition: address.cpp:107
dodo::network::AddrInfo::canonicalname
std::string canonicalname
The canonical name for a host.
Definition: address.hpp:345
dodo::network::Address::getAddressFamily
SocketParams::AddressFamily getAddressFamily() const
Get this Address family.
Definition: address.hpp:159
dodo::network::SocketParams::AddressFamily
AddressFamily
Addres family type.
Definition: socketparams.hpp:41
dodo::network::Address
Generic network Address, supporting ipv4 and ipv6 transparently.
Definition: address.hpp:90
dodo::common::SystemError::ecEAI_ADDRFAMILY
@ ecEAI_ADDRFAMILY
-9 Address family for NAME not supported.
Definition: systemerror.hpp:204
dodo::network::Address::getHostAddrInfo
static common::SystemError getHostAddrInfo(const std::string &hostname, AddrInfo &info)
Get Address information on a host in a AddrInfo struct.
Definition: address.cpp:144
dodo::network::AddrInfo::items
std::list< AddrInfoItem > items
AddrInfoItem list for the host.
Definition: address.hpp:355
dodo::network::Address::Address
Address()
Construct an invalid (unspecified) address.
Definition: address.hpp:96
dodo::network::Address::setPort
void setPort(uint16_t port)
Set the port number.
Definition: address.cpp:136
dodo::network::Address::init
void init()
Initialize the internals.
Definition: address.cpp:61
dodo::network::SocketParams
Socket parameters - the family (domain), socket type and protocol triplet.
Definition: socketparams.hpp:35
dodo::network::Address::asIPv6Address
struct sockaddr_in6 * asIPv6Address() const
Explicit cast of addr_ as sockaddr_in6*.
Definition: address.hpp:284
dodo::network::Address::asIPv4Address
struct sockaddr_in * asIPv4Address() const
Explicit cast of addr_ as sockaddr_in*.
Definition: address.hpp:278
address.hpp
throw_SystemException
#define throw_SystemException(what, errno)
Throws an Exception with errno, passes FILE and LINE to constructor.
Definition: exception.hpp:188
throw_SystemExceptionObject
#define throw_SystemExceptionObject(what, errno, thing)
Throws an Exception with errno, passes FILE and LINE to constructor.
Definition: exception.hpp:196
dodo::common::SystemError::ecOK
@ ecOK
0 Not an error, success
Definition: systemerror.hpp:60
dodo::network::SocketParams::setSocketType
void setSocketType(SocketType sockettype)
Set the SocketType.
Definition: socketparams.hpp:172
dodo::network::SocketParams::setProtocol
void setProtocol(ProtocolNumber protocol)
Set the ProtocolNumber.
Definition: socketparams.hpp:178
dodo::network
Interface for network communication.
Definition: address.hpp:37
dodo::network::Address::operator==
bool operator==(const Address &address) const
Test for equality.
Definition: address.cpp:92
dodo::network::AddrInfoItem::address
Address address
The Address of this item.
Definition: address.hpp:314
dodo::common::SystemError::ecEAI_SYSTEM
@ ecEAI_SYSTEM
-11 System error returned in ‘errno’.
Definition: systemerror.hpp:206
dodo::network::SocketParams::getSocketType
SocketType getSocketType() const
Get the SocketType.
Definition: socketparams.hpp:154
dodo::common::SystemError
Linux system error primitive to provide a consistent interface to Linux error codes.
Definition: systemerror.hpp:53
dodo::network::Address::addr_
struct sockaddr_storage addr_
The address storage (for either ipv4 or ipv6).
Definition: address.hpp:289
dodo::network::AddrInfoItem::params
SocketParams params
The SocketParams for this item.
Definition: address.hpp:319
dodo::network::SocketParams::ProtocolNumber
ProtocolNumber
IANA Protocol number.
Definition: socketparams.hpp:73
dodo::network::SocketParams::SocketType
SocketType
Socket Type type.
Definition: socketparams.hpp:59
dodo::network::AddrInfo
Address info, comprising the canonical name of a host, and list of address info items for the host.
Definition: address.hpp:337
dodo::common::SystemError::ecEAI_NONAME
@ ecEAI_NONAME
-2 NAME or SERVICE is unknown.
Definition: systemerror.hpp:197
dodo::network::SocketParams::getProtocol
ProtocolNumber getProtocol() const
Get the ProtocolNumber.
Definition: socketparams.hpp:160
dodo::common::SystemError::ecEAI_NODATA
@ ecEAI_NODATA
-5 No address associated with NAME.
Definition: systemerror.hpp:200
dodo::network::AddrInfoItem
Address info item as used in AddrInfo.
Definition: address.hpp:309