libBsdSockets
C++ Wrapper classes to the BSD Socket API
InetAddress.cpp
Go to the documentation of this file.
1 /*
2 
3 Copyright (c) 2013, Komodo Does Inc
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
7 
8 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
9 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
10 Neither the name of the Komodo Does Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12 
13 */
14 
15 #include <sys/socket.h>
16 #include <arpa/inet.h>
17 #include <netdb.h>
18 #include <string.h>
19 #include <memory>
20 
21 #include <stdexcept>
22 #include <system_error>
23 #include <string>
24 #include <vector>
25 
26 #include "AddressInfoConversions.h"
27 #include "InetAddress.h"
28 
29 #include "LowLevelAddress.h"
30 
31 namespace {
32  /** Return actual address string from sockaddr info
33  *
34  * @param int family to use to decode
35  * @param result struct addrinfo to calculate address string of
36  *
37  * @return string representation of address in result
38  */
39  std::string parseAddress(const int family, const struct sockaddr_in* const sin) {
40  const size_t bufferLen = std::max(INET_ADDRSTRLEN, INET6_ADDRSTRLEN);
41  char buffer[bufferLen];
42  buffer[0] = '\0';
43 
44  const char* actualAddressString = inet_ntop(family, &(sin->sin_addr.s_addr), buffer, bufferLen);
45  if(nullptr == actualAddressString) {
46  throw std::invalid_argument("Address not valid");
47  }
48 
49  return actualAddressString;
50  }
51 
52  /** Return actual address string from addrinfo
53  *
54  * @param result struct addrinfo to calculate address string of
55  *
56  * @return string representation of address in result
57  */
58  std::string parseAddress(const struct addrinfo& result) {
59  const struct sockaddr_in* const sin = (sockaddr_in*) result.ai_addr;
60  return parseAddress(result.ai_family, sin);
61  }
62 }
63 
64 namespace BsdSockets {
66 
67  /** \brief The private implementation of InetAddress.
68  *
69  * This provides both the LowLevelAddress and the computed details of the Address
70  * such as port number and actual address matched.
71  *
72  * The actual address may differ from the actual address due to hostname
73  * resolution, etc.
74  */
76  public:
77  typedef std::shared_ptr<InetAddressPimpl> Ptr;
78 
79  /** Create with parameters
80  * @param theLowLevelAddress to save a copy of for later use in getSockAddr()
81  * @param theActualAddress the already formatted string version of the
82  * address in theLowLevelAddress
83  */
84  InetAddressPimpl(const sockaddr_in& theLowLevelAddress, const std::string& theActualAddress)
85  : InetLowLevelAddress(theLowLevelAddress), actualAddress(theActualAddress)
86  {
87  }
88 
89  private:
90  InetAddressPimpl() = delete;
91  InetAddressPimpl(const InetAddressPimpl& rhs) = delete;
92  InetAddressPimpl(InetAddressPimpl&& rhs) = delete;
93  InetAddressPimpl& operator=(const InetAddressPimpl& rhs) = delete;
94  InetAddressPimpl& operator=(InetAddressPimpl&& rhs) = delete;
95 
96  public:
97  /** @return the actual address matched */
98  const std::string& getActualAddress() const {
99  return actualAddress;
100  }
101 
102  /** @return the port or 0 for none */
103  const unsigned int getPort() const {
104  return ntohs(lowLevelAddress.sin_port);
105  }
106 
107  private:
108  /** The actual address matched */
109  const std::string actualAddress;
110  };
111 
112  /*
113  * InetAddress implementation
114  */
115 
117  SocketType socketType, const std::string& serviceName, const std::string& address,
118  std::vector<InetAddress::Ptr>& created, unsigned int max
119  ) {
120  // Setup hints to resolve address
121  struct addrinfo hints;
122  memset(&hints, 0, sizeof(hints));
123  hints.ai_family = PF_UNSPEC;
124  hints.ai_socktype = socketTypeToLowLevel(socketType);
125 
126  // Resolve address and throw and handle errors including failing to match
127  struct addrinfo *results = nullptr;
128  const int error = getaddrinfo(address.c_str(), serviceName.c_str(), &hints, &results);
129  if (error) {
130  // TODO: this might not be appropriate to pass the error code here
131  throw std::system_error(error, std::system_category(), gai_strerror(error));
132  }
133 
134  if(nullptr == results) {
135  // Did not match
136  throw std::invalid_argument("Invalid address and/or service");
137  }
138 
139  // Loop over all results and push into created
140  // Note, if max > 0, we stop after creating max InetAddresses
141  unsigned int count = 0;
142  for(struct addrinfo* result = results; nullptr != result && (max <= 0 || count < max); result = result->ai_next, ++count) {
143  // Parse the socket domain and actual address
144  const SocketDomain socketDomain = lowLevelToSocketDomain(result->ai_family);
145  if(SocketDomain::INET4 != socketDomain && SocketDomain::INET6 != socketDomain) {
146  throw std::invalid_argument("Invalid address family for address");
147  }
148  const std::string actualAddress = parseAddress(*result);
149 
150  // Create the pimpl and InetAddress
152  *reinterpret_cast<const struct sockaddr_in* const>(result->ai_addr), actualAddress));
153  created.push_back(InetAddress::Ptr(new InetAddress(socketDomain, socketType, result->ai_protocol, serviceName, address, pimpl)));
154  }
155 
156  // Free results
157  freeaddrinfo(results);
158 
159  return count;
160  }
161 
162  InetAddress::Ptr InetAddress::create(SocketType socketType, const std::string& serviceName, const std::string& address) {
163  // find at most 1... if none are found exceptions will be thrown, so found.at(0) should be safe
164  std::vector<InetAddress::Ptr> found;
165  create(socketType, serviceName, address, found, 1);
166  return found.at(0);
167  }
168 
170  }
171 
172  InetAddress::InetAddress(SocketDomain theSocketDomain, SocketType theSocketType, int theProtocol,
173  const std::string& theServiceName, const std::string& theRequestedAddress,
174  std::shared_ptr<InetAddressPimpl> pimpl
175  )
176  : Address(theSocketDomain, theSocketType, theProtocol),
177  serviceName(theServiceName),
178  requestedAddress(theRequestedAddress),
179  pimpl(pimpl)
180  {
181  if(nullptr == pimpl) {
182  throw new std::invalid_argument("Invalid address");
183  }
184  }
185 
186  const std::string& InetAddress::getRequestedAddress() const {
187  return requestedAddress;
188  }
189 
190  const std::string& InetAddress::getActualAddress() const {
191  return pimpl->getActualAddress();
192  }
193 
194  const std::string& InetAddress::getServiceName() const {
195  return serviceName;
196  }
197 
198  const unsigned int InetAddress::getPort() const {
199  return pimpl->getPort();
200  }
201 
204  }
205 
206  Address::Ptr InetAddress::create(std::shared_ptr<LowLevelAddress> fromLowLevelAddress) const {
207  const int fromLowLevelAddressFamily = fromLowLevelAddress->getSockAddr().sa_family;
208 
209  if(AF_INET != fromLowLevelAddressFamily && AF_INET6 != fromLowLevelAddressFamily) {
210  throw std::invalid_argument("LowLevelAddress is of wrong type for InetAddress to create");
211  }
212 
213  const struct sockaddr_in* const sin =
214  reinterpret_cast<const struct sockaddr_in* const>(&fromLowLevelAddress->getSockAddr());
215 
216  const std::string theActualAddress = parseAddress(fromLowLevelAddressFamily, sin);
217  InetAddressPimpl::Ptr pimpl(new InetAddressPimpl(*sin, theActualAddress));
218  return InetAddress::Ptr(new InetAddress(getSocketDomain(), getSocketType(), getProtocol(), serviceName, "", pimpl));
219  }
220 
222  return *pimpl;
223  }
224 
225 } // namespace BsdSockets
Base class for all addresses.
Definition: Address.h:36
int getProtocol() const
Definition: Address.cpp:43
std::shared_ptr< Address > Ptr
Definition: Address.h:38
SocketDomain getSocketDomain() const
Definition: Address.cpp:35
SocketType getSocketType() const
Definition: Address.cpp:39
Internet Address Class supporting IPv4 and IPv6 and creatable from hostnames and service names.
Definition: InetAddress.h:41
const unsigned int getPort() const
const std::string & getActualAddress() const
const std::string & getServiceName() const
const std::string & getRequestedAddress() const
std::shared_ptr< InetAddress > Ptr
Definition: InetAddress.h:43
virtual std::shared_ptr< LowLevelAddress > makeTempLowLevelAddress() const
static int create(SocketType socketType, const std::string &serviceName, const std::string &address, std::vector< InetAddress::Ptr > &created, unsigned int max=0)
virtual LowLevelAddress & getLowLevelAddress() const
The private implementation of InetAddress.
Definition: InetAddress.cpp:75
InetAddressPimpl(const sockaddr_in &theLowLevelAddress, const std::string &theActualAddress)
Definition: InetAddress.cpp:84
const unsigned int getPort() const
std::shared_ptr< InetAddressPimpl > Ptr
Definition: InetAddress.cpp:77
const std::string & getActualAddress() const
Definition: InetAddress.cpp:98
Interface for the low-level address implementation.
std::shared_ptr< LowLevelAddress > Ptr
LowLevelAddress template for the various cast-to-sockaddr implementaitons.
Namespace of the BsdSockets library.
Definition: Address.cpp:20
LowLevelAddressType< struct sockaddr_in > InetLowLevelAddress
Definition: InetAddress.cpp:65
int socketTypeToLowLevel(SocketType type)
SocketDomain lowLevelToSocketDomain(int lowLevel)