Thrill  0.1
socket_address.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * thrill/net/tcp/socket_address.cpp
3  *
4  * Implements lookups and conversions to low-level socket address structs.
5  *
6  * Part of Project Thrill - http://project-thrill.org
7  *
8  * Copyright (C) 2015 Timo Bingmann <[email protected]>
9  *
10  * All rights reserved. Published under the BSD-2 license in the LICENSE file.
11  ******************************************************************************/
12 
13 #include <thrill/common/logger.hpp>
15 
16 #include <arpa/inet.h>
17 #include <netdb.h>
18 
19 #include <algorithm>
20 #include <cerrno>
21 #include <string>
22 #include <vector>
23 
24 namespace thrill {
25 namespace net {
26 namespace tcp {
27 
28 /******************************************************************************/
29 
30 SocketAddress::SocketAddress(struct sockaddr* sa, socklen_t salen)
31  : resolve_error_(0) {
32  memcpy(&sockaddr_, sa, std::min<socklen_t>(salen, sizeof(sockaddr_)));
33 }
34 
36  std::string host = hostport;
37  size_t colonpos = host.rfind(':');
38  if (colonpos == std::string::npos)
39  {
40  Resolve(hostport.c_str());
41  }
42  else
43  {
44  std::string port = host.substr(colonpos + 1);
45  host.erase(colonpos);
46  Resolve(host.c_str(), port.c_str());
47  }
48 }
49 
50 SocketAddress::SocketAddress(const char* hostname, const char* servicename) {
51  Resolve(hostname, servicename);
52 }
53 
55  char str[64];
56  if (sockaddr()->sa_family == AF_INET)
57  {
58  if (inet_ntop(AF_INET,
59  &sockaddr_in()->sin_addr, str, sizeof(str)) == nullptr)
60  {
61  sLOG << "Error in inet_ntop: " << strerror(errno);
62  return "<error>";
63  }
64  return str;
65  }
66  else if (sockaddr()->sa_family == AF_INET6)
67  {
68  if (inet_ntop(AF_INET6,
69  &sockaddr_in6()->sin6_addr, str, sizeof(str)) == nullptr)
70  {
71  sLOG << "Error in inet_ntop: " << strerror(errno);
72  return "<error>";
73  }
74  return str;
75  }
76  else
77  return "<invalid>";
78 }
79 
81  return ToStringHost() + ":" + std::to_string(GetPort());
82 }
83 
84 std::ostream& operator << (std::ostream& os, const SocketAddress& sa) {
85  return os << sa.ToStringHostPort();
86 }
87 
88 bool SocketAddress::Resolve(const char* hostname, const char* servicename) {
89  struct addrinfo* result;
90  struct addrinfo hints;
91 
92  memset(&hints, 0, sizeof(struct addrinfo));
93  hints.ai_family = AF_INET; /* Allow IPv4 or IPv6 */
94  hints.ai_socktype = SOCK_STREAM;
95  hints.ai_flags = 0;
96  hints.ai_protocol = 0;
97 
98  int gai = getaddrinfo(hostname, servicename, &hints, &result);
99  if (gai != 0)
100  {
101  memset(&sockaddr_, 0, sizeof(sockaddr_));
102  resolve_error_ = gai;
103  return false;
104  }
105  else
106  {
107  *this = SocketAddress(result->ai_addr, result->ai_addrlen);
108  freeaddrinfo(result);
109  return IsValid();
110  }
111 }
112 
113 const char* SocketAddress::GetResolveError() const {
114  return gai_strerror(resolve_error_);
115 }
116 
118 SocketAddress::ResolveOne(const char* hostname, const char* servicename) {
119  struct addrinfo* result;
120  struct addrinfo hints;
121 
122  memset(&hints, 0, sizeof(struct addrinfo));
123  hints.ai_family = AF_INET; /* Allow IPv4 or IPv6 */
124  hints.ai_socktype = SOCK_STREAM;
125  hints.ai_flags = 0;
126  hints.ai_protocol = 0;
127 
128  int s = getaddrinfo(hostname, servicename, &hints, &result);
129  if (s != 0) {
130  return SocketAddress();
131  }
132 
133  SocketAddress sa(result->ai_addr, result->ai_addrlen);
134 
135  freeaddrinfo(result);
136 
137  return sa;
138 }
139 
141 SocketAddress::ResolveWithPort(const char* hostname,
142  const char* defaultservice) {
143  std::string host = hostname;
144 
145  std::string::size_type colonpos = host.rfind(':');
146  if (colonpos == std::string::npos)
147  return ResolveOne(hostname, defaultservice);
148 
149  std::string servicename(host, colonpos + 1);
150  host.erase(colonpos);
151 
152  return ResolveOne(host.c_str(), servicename.c_str());
153 }
154 
155 std::vector<SocketAddress>
156 SocketAddress::ResolveAll(const char* hostname, const char* servicename) {
157  std::vector<SocketAddress> salist;
158 
159  struct addrinfo* result;
160  struct addrinfo hints;
161 
162  memset(&hints, 0, sizeof(struct addrinfo));
163  hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
164  hints.ai_socktype = SOCK_STREAM;
165  hints.ai_flags = 0;
166  hints.ai_protocol = 0;
167 
168  int s = getaddrinfo(hostname, servicename, &hints, &result);
169  if (s != 0) {
170  return salist;
171  }
172 
173  for (struct addrinfo* ap = result; ap != nullptr; ap = ap->ai_next)
174  {
175  salist.push_back(SocketAddress(ap->ai_addr, ap->ai_addrlen));
176  }
177 
178  freeaddrinfo(result);
179 
180  return salist;
181 }
182 
183 /******************************************************************************/
184 
185 IPv4Address::IPv4Address(const char* ipstring, uint16_t port)
186  : SocketAddress() {
187  struct sockaddr_in* sin = sockaddr_in();
188  sin->sin_family = AF_INET;
189  if (inet_pton(AF_INET, ipstring, &sin->sin_addr) <= 0) {
190  sin->sin_family = 0;
191  return;
192  }
193  sin->sin_port = htons(port);
194 }
195 
196 /******************************************************************************/
197 
198 IPv6Address::IPv6Address(const char* ipstring, uint16_t port)
199  : SocketAddress() {
200  struct sockaddr_in6* sin6 = sockaddr_in6();
201  sin6->sin6_family = AF_INET6;
202  if (inet_pton(AF_INET6, ipstring, &sin6->sin6_addr) <= 0) {
203  sin6->sin6_family = 0;
204  return;
205  }
206  sin6->sin6_port = htons(port);
207 }
208 
209 } // namespace tcp
210 } // namespace net
211 } // namespace thrill
212 
213 /******************************************************************************/
static SocketAddress ResolveOne(const char *hostname, const char *servicename=nullptr)
static SocketAddress ResolveWithPort(const char *hostname, const char *defaultservice)
#define sLOG
Default logging method: output if the local debug variable is true.
Definition: logger.hpp:34
bool Resolve(const char *hostname, const char *servicename=nullptr)
SocketAddress is a super class used to unify the two different IPv4 and IPv6 socket address represent...
SocketAddress()
Create empty invalid address object by clearing all bytes.
IPv6Address()
Create uninitialized IPv6 address.
union thrill::net::tcp::SocketAddress::SockAddrUnion sockaddr_
static std::vector< SocketAddress > ResolveAll(const char *hostname, const char *servicename=nullptr)
friend std::ostream & operator<<(std::ostream &os, const SocketAddress &sa)
Make the socket address ostream-able: outputs address:port.
uint16_t GetPort() const
Return the currently set port address in host byte-order.
static by_string to_string(int val)
convert to string
const char * GetResolveError() const
struct sockaddr_in * sockaddr_in()
Cast the enclosed sockaddr into the sockaddr_in IPv4 structure.
std::string ToStringHost() const
Return the enclosed socket address as a string without the port number.
std::basic_string< char, std::char_traits< char >, Allocator< char > > string
string with Manager tracking
Definition: allocator.hpp:220
IPv4Address()
Create uninitialized IPv4 address.
struct sockaddr * sockaddr()
Return pointer to enclosed address as a generic sockattr struct.
std::string ToStringHostPort() const
Return the enclosed socket address as a string with the port number.
struct sockaddr_in6 * sockaddr_in6()
Cast the enclosed sockaddr into the sockaddr_in6 IPv6 structure.