dodo  0.0.1
A C++ library to create containerized Linux services
address.hpp
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.hpp
20  * Defines the dodo::network::Address class.
21  */
22 
23 #ifndef network_address_hpp
24 #define network_address_hpp
25 
26 #include <arpa/inet.h>
27 #include <iostream>
28 #include <list>
29 #include <map>
30 #include <stdint.h>
31 #include <string>
32 #include <sys/socket.h>
33 
34 #include "common/exception.hpp"
35 #include "network/socketparams.hpp"
36 
37 namespace dodo::network {
38 
39  struct AddrInfo;
40 
41  /**
42  * Generic network Address, supporting ipv4 and ipv6 transparently.
43  *
44  * Typical client use is to first resolve a host name. We specify SocketParams::afUNSPEC
45  * for the address family, allowing for both ipv4 and ipv6 and specify the TCP protocol (stSTRAM + pnTCP ).
46  *
47  * @code
48  * using namespace dodo::common;
49  * using namespace dodo::network;
50  *
51  * Address address;
52  * SocketParams sock_params = SocketParams( SocketParams::afUNSPEC,
53  * SocketParams::stSTREAM,
54  * SocketParams::pnTCP );
55  * std::string canonicalname;
56  * SystemError error = Address::getHostAddrInfo( "httpbin.org", sock_params, address, canonicalname );
57  *
58  * @endcode
59  *
60  * The canonical name is set and may differ from the host name passed to getHostAddrInfo.
61  *
62  * After the getHostAddrInfo (if error == SystemError::ecOK ) the sock_params will have its address family set to
63  * either network::SocketParams::afINET or network::SocketParams::afINET6, depending on what the server
64  * (httpbin.org) supports. But we can continue to connect without any reference to the actual address family being
65  * used:
66  *
67  * @code
68  * if ( error == SystemError::ecOK ) {
69  * address.setPort( 443 );
70  * Socket socket( true, sock_params );
71  * error = socket.connect( address );
72  * if ( error == SystemError::ecOK ) {
73  * // connected
74  * }
75  * }
76  * @endcode
77  *
78  * There are two prototypes for getHostAddrInfo, one returns the preferred Address (as above), the other a list of
79  * addresses (an AddrInfo structure), the preferred address the first in the list. Subsequent calls do not necessarily
80  * (under DNS round robin for example) return the same address as preferred address.
81  *
82  * As the getHostAddrInfo calls are quite expensive, prefer reuse of obtained Address objects where possible.
83  *
84  * | Special addresses | ipv4 | ipv6 |
85  * |---------|------|------|
86  * | INADDR_ANY | 0.0.0.0 | ::0 |
87  * | localhost | 127.0.0.1 | ::1 |
88  *
89  */
90  class Address : public common::DebugObject {
91  public:
92 
93  /**
94  * Construct an invalid (unspecified) address.
95  */
96  Address() { addr_.ss_family = AF_UNSPEC; };
97 
98  /**
99  * Construct from "ip", port
100  * @param ip The string representation of the ip, either ipv4 or ipv6.
101  * @param port The port number (only specified for listen addresses).
102  */
103  Address( const std::string &ip, uint16_t port );
104 
105  /**
106  * Construct from ip, do not set port (only a listening socket needs a port preset).
107  * @param ip The string representation of the ip, either ipv4 or ipv6.
108  */
109  Address( const std::string &ip );
110 
111  /**
112  * Construct from sockaddr_storage.
113  * @param address A sockaddr_storage structure.
114  */
115  Address( const sockaddr_storage& address );
116 
117  /**
118  * Construct from sockaddr *.
119  * @param address A const sockaddr*
120  * @param len And its length.
121  */
122  Address( const sockaddr *address, socklen_t len );
123 
124  /**
125  * Copy from Address
126  * @param address Source address to copy from.
127  */
128  Address( const Address &address );
129 
130  /**
131  * True if this Address is valid.
132  * @return true when this Address is valid.
133  */
134  bool isValid() const { return addr_.ss_family != AF_UNSPEC; };
135 
136  /**
137  * Return a string representation of this Address.
138  * @param withport If true, append ':' + port number.
139  * @return string representation of this Address.
140  */
141  std::string asString( bool withport = false ) const;
142 
143  /**
144  * Return the port number.
145  * @return The port number.
146  */
147  uint16_t getPort() const;
148 
149  /**
150  * Set the port number.
151  * @param port The new port number.
152  */
153  void setPort( uint16_t port );
154 
155  /**
156  * Get this Address family.
157  * @return The address family of this Address.
158  */
160 
161  /**
162  * Get to the underlying sockaddr_storage.
163  * @return A pointer to the underlying socket storage.
164  */
165  const sockaddr_storage* getAddress() const { return &addr_; };
166 
167  /**
168  * Assign from "ip" string.
169  * @param address The address to assign in string form.
170  * @return This Address.
171  */
172  Address& operator=( const std::string& address );
173 
174  /**
175  * Assign (copy) from Address.
176  * @param address The Address to assign.
177  * @return This Address.
178  */
179  Address& operator=( const Address& address );
180 
181  /**
182  * Assign from sockaddr_storage.
183  * @param address The address to assign in sockaddr_storage form.
184  * @return This Address.
185  */
186  Address& operator=( const sockaddr_storage& address );
187 
188  /**
189  * Test for equality. The comparison is a byte compare on the internal sockaddr_in / sockaddr_in6
190  * structures, which guarantees that Address objects assigned "::1" and "0:0:0:0:0:0:0:1" are considered equal.
191  * @param address The address to compare to.
192  * @return True if the addresses are equal.
193  */
194  bool operator==( const Address& address ) const;
195 
196  /**
197  * Get Address information on a host in a AddrInfo struct.
198  *
199  * Could return the following SystemError
200  * - SystemError::ecOK
201  * - SystemError::ecEAI_ADDRFAMILY (The hosts exists but has not address in the requested address family)
202  * - SystemError::ecEAI_NODATA (The hosts exists in DNS but has no addresses)
203  * - SystemError::ecEAI_NONAME (The hosts does not exist in DNS)
204  *
205  * @param hostname The host name to lookup.
206  * @param info The AddrInfo structure to fill.
207  * @return SystemError::ecOK if the lookup resulted in at least one address.
208  */
209  static common::SystemError getHostAddrInfo( const std::string &hostname, AddrInfo& info );
210 
211  /**
212  * Return the first hit on SocketParams in address and canonicalname.
213  *
214  * Could return the following SystemError
215  * - SystemError::ecOK
216  * - SystemError::ecEAI_ADDRFAMILY (The hosts exists but has not address in the requested address family)
217  * - SystemError::ecEAI_NODATA (The hosts exists in DNS but has no addresses)
218  * - SystemError::ecEAI_NONAME (The hosts does not exist in DNS)
219  *
220  * @param hostname The host name to lookup.
221  * @param params The SocketParams the entry must match to.
222  * @param address The result address (set to invalid when this call returns an error).
223  * @param canonicalname The canonicalname of hostname (set to "" when this call returns an error).
224  * @return SystemError::ecOK if the lookup resulted in an address.
225  */
226  static common::SystemError getHostAddrInfo( const std::string &hostname,
227  SocketParams &params,
228  Address &address,
229  std::string &canonicalname );
230 
231  /**
232  * Do a reverse DNS lookup on this Address and return in hostname.
233  *
234  * Could return the following SystemError
235  * - SystemError::ecOK
236  * - SystemError::ecEAI_AGAIN
237  * - SystemError::ecEAI_BADFLAGS
238  * - SystemError::ecEAI_FAIL
239  * - SystemError::ecEAI_FAMILY
240  * - SystemError::ecEAI_MEMORY
241  * - SystemError::ecEAI_NONAME
242  * - SystemError::ecEAI_OVERFLOW
243  * - SystemError::ecEAI_SYSTEM is silently replaced by errno
244  * @param hostname The string to receive the hostname.
245  * @return The error or SystemError::ecOK on success.
246  */
247  common::SystemError getNameInfo( std::string &hostname ) const;
248 
249  /**
250  * Do a reverse DNS lookup on this Address and its port, and return in hostname and service.
251  * @param hostname The string variable to receive the hostname.
252  * @param service The string variable to receive the service name.
253  * @return The error or SystemError::ecOK on success.
254  * @see getNameInfo() for a full list of possible errors returned.
255  */
256  common::SystemError getNameInfo( std::string &hostname, std::string &service ) const;
257 
258  /**
259  * Do a reverse DNS lookup on this Address and its port, and return in hostname and port.
260  * @param hostname The string variable to receive the hostname.
261  * @param port The uint16_t variable to receive the port number.
262  * @return The error or SystemError::ecOK on success.
263  * @see getNameInfo() for a full list of possible errors returned.
264  */
265  common::SystemError getNameInfo( std::string &hostname, uint16_t &port ) const;
266 
267  private:
268 
269  /**
270  * Initialize the internals.
271  */
272  void init();
273 
274  /**
275  * Explicit cast of addr_ as sockaddr_in*.
276  * @return The pointer.
277  */
278  struct sockaddr_in* asIPv4Address() const { return (struct sockaddr_in *)&addr_; };
279 
280  /**
281  * Explicit cast of addr_ as sockaddr_in6*.
282  * @return The pointer.
283  */
284  struct sockaddr_in6* asIPv6Address() const { return (struct sockaddr_in6 *)&addr_; };
285 
286  /**
287  * The address storage (for either ipv4 or ipv6).
288  */
289  struct sockaddr_storage addr_;
290 
291  /**
292  * Socket may access this class directly.
293  */
294  friend class Socket;
295  /**
296  * BaseSocket may access this class directly.
297  */
298  friend class BaseSocket;
299 
300  };
301 
302 
303  /**
304  * Address info item as used in AddrInfo
305  * @see AddrInfo
306  * @see Address::getHostAddrInfogetHostAddrInfo( const std::string &hostname, AddrInfo& info )
307  * @see Address::getHostAddrInfo( const std::string &hostname, const SocketParams &params, Address &address, string &canonicalname )
308  */
309  struct AddrInfoItem {
310 
311  /**
312  * The Address of this item.
313  */
315 
316  /**
317  * The SocketParams for this item.
318  */
320 
321  /**
322  * String representation.
323  * @return The string.
324  */
325  std::string asString() {
326  std::stringstream ss;
327  ss << address.asString() << " " << params.asString();
328  return ss.str();
329  };
330  };
331 
332  /**
333  * Address info, comprising the canonical name of a host, and list of address info items for the host.
334  * @see AddrInfoItem
335  * @see Address::getHostAddrInfo()
336  */
337  struct AddrInfo {
338 
339  /**
340  * Initialize
341  */
343  items.clear();
344  canonicalname = "";
345  };
346 
347  /**
348  * The canonical name for a host.
349  */
350  std::string canonicalname;
351 
352  /**
353  * AddrInfoItem list for the host.
354  */
355  std::list<AddrInfoItem> items;
356  };
357 
358 };
359 
360 #endif
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
socketparams.hpp
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::AddrInfo::AddrInfo
AddrInfo()
Initialize.
Definition: address.hpp:342
dodo::network::Address::isValid
bool isValid() const
True if this Address is valid.
Definition: address.hpp:134
dodo::common::DebugObject
Interface to objects that support dumping their state to a string.
Definition: exception.hpp:39
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::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
dodo::network::SocketParams::asString
std::string asString() const
Return the parameters as a string.
Definition: socketparams.hpp:184
dodo::network
Interface for network communication.
Definition: address.hpp:37
dodo::network::Socket
A Linux socket.
Definition: socket.hpp:50
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
exception.hpp
dodo::network::Address::getAddress
const sockaddr_storage * getAddress() const
Get to the underlying sockaddr_storage.
Definition: address.hpp:165
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::AddrInfo
Address info, comprising the canonical name of a host, and list of address info items for the host.
Definition: address.hpp:337
dodo::network::AddrInfoItem
Address info item as used in AddrInfo.
Definition: address.hpp:309
dodo::network::BaseSocket
Interface to and common implementation of concrete sockets (Socket, TLSSocket).
Definition: basesocket.hpp:36
dodo::network::AddrInfoItem::asString
std::string asString()
String representation.
Definition: address.hpp:325