Apache Mesos
address.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License
12 
13 #ifndef __PROCESS_ADDRESS_HPP__
14 #define __PROCESS_ADDRESS_HPP__
15 
16 #include <stdint.h>
17 #ifndef __WINDOWS__
18 #include <unistd.h>
19 #endif // __WINDOWS__
20 
21 #ifndef __WINDOWS__
22 #include <arpa/inet.h>
23 #endif // __WINDOWS__
24 
25 #include <glog/logging.h>
26 
27 #ifndef __WINDOWS__
28 #include <sys/un.h>
29 #endif // __WINDOWS__
30 
31 #include <ostream>
32 
33 #include <boost/functional/hash.hpp>
34 
35 #include <stout/abort.hpp>
36 #include <stout/check.hpp>
37 #include <stout/ip.hpp>
38 #include <stout/variant.hpp>
39 #include <stout/net.hpp>
40 #include <stout/stringify.hpp>
41 #include <stout/unreachable.hpp>
42 
43 namespace process {
44 namespace network {
45 
46 class Address;
47 
48 namespace inet {
49 
50 class Address
51 {
52 public:
53  Address(const net::IP& _ip, uint16_t _port)
54  : ip(_ip), port(_port) {}
55 
61  // TODO(jmlvanre): Consider making this return a Future in order to
62  // deal with slow name resolution.
64  {
66  ? net::hostname()
68 
69  if (hostname.isError()) {
70  return Error(hostname.error());
71  }
72 
73  return hostname.get();
74  }
75 
76  operator sockaddr_storage() const
77  {
78  union {
79  sockaddr_storage storage;
80  sockaddr_in in;
81  sockaddr_in6 in6;
82  } sockaddr;
83  memset(&sockaddr.storage, 0, sizeof(sockaddr_storage));
84  switch (ip.family()) {
85  case AF_INET:
86  sockaddr.in.sin_family = AF_INET;
87  sockaddr.in.sin_addr = ip.in().get();
88  sockaddr.in.sin_port = htons(port);
89  break;
90  case AF_INET6:
91  sockaddr.in6.sin6_family = AF_INET6;
92  sockaddr.in6.sin6_addr = ip.in6().get();
93  sockaddr.in6.sin6_port = htons(port);
94  break;
95  default:
96  ABORT("Unexpected family: " + stringify(ip.family()));
97  }
98  return sockaddr.storage;
99  }
100 
101  bool operator<(const Address& that) const
102  {
103  if (ip == that.ip) {
104  return port < that.port;
105  } else {
106  return ip < that.ip;
107  }
108  }
109 
110  bool operator>(const Address& that) const
111  {
112  if (ip == that.ip) {
113  return port > that.port;
114  } else {
115  return ip > that.ip;
116  }
117  }
118 
119  bool operator==(const Address& that) const
120  {
121  return (ip == that.ip && port == that.port);
122  }
123 
124  bool operator!=(const Address& that) const
125  {
126  return !(*this == that);
127  }
128 
129  // TODO(benh): Consider using `sockaddr_storage` here like we do for
130  // `unix::Address`. This will require changing all places that
131  // either the `ip` or `port` field are currently used.
133  uint16_t port;
134 };
135 
136 
137 inline std::ostream& operator<<(std::ostream& stream, const Address& address)
138 {
139  stream << address.ip << ":" << address.port;
140  return stream;
141 }
142 
143 } // namespace inet {
144 
145 
146 namespace inet4 {
147 
148 class Address : public inet::Address
149 {
150 public:
152  {
153  return Address(net::IPv4::LOOPBACK(), 0);
154  }
155 
156  static Address ANY_ANY()
157  {
158  return Address(net::IPv4::ANY(), 0);
159  }
160 
161  Address(const net::IPv4& ip, uint16_t port)
162  : inet::Address(ip, port) {}
163 
164  Address(const sockaddr_in& in)
165  : inet::Address(net::IPv4(in.sin_addr), ntohs(in.sin_port)) {}
166 };
167 
168 } // namespace inet4 {
169 
170 
171 namespace inet6 {
172 
173 class Address : public inet::Address
174 {
175 public:
177  {
178  return Address(net::IPv6::LOOPBACK(), 0);
179  }
180 
181  static Address ANY_ANY()
182  {
183  return Address(net::IPv6::ANY(), 0);
184  }
185 
186  Address(const net::IPv6& ip, uint16_t port)
187  : inet::Address(ip, port) {}
188 
189  Address(const sockaddr_in6& in6)
190  : inet::Address(net::IPv6(in6.sin6_addr), ntohs(in6.sin6_port)) {}
191 };
192 
193 } // namespace inet6 {
194 
195 
196 #ifndef __WINDOWS__
197 namespace unix {
198 
199 class Address
200 {
201 public:
202  static Try<Address> create(const std::string& path)
203  {
204  sockaddr_un un;
205 
206  const size_t PATH_LENGTH = sizeof(un.sun_path);
207 
208  if (path.length() >= PATH_LENGTH) {
209  return Error("Path too long, must be less than " +
210  stringify(PATH_LENGTH) + " bytes");
211  }
212 
213  un.sun_family = AF_UNIX;
214  memcpy(un.sun_path, path.c_str(), path.length() + 1);
215 
216  return Address(un);
217  }
218 
219  Address(const sockaddr_un& un)
220  : sockaddr() // Zero initialize.
221  {
222  sockaddr.un = un;
223  }
224 
225  std::string path() const
226  {
227  if (sockaddr.un.sun_path[0] == '\0') {
228  return '\0' + std::string(sockaddr.un.sun_path + 1);
229  }
230 
231  return std::string(sockaddr.un.sun_path);
232  }
233 
234  operator sockaddr_storage() const
235  {
236  return sockaddr.storage;
237  }
238 
239  bool operator==(const Address& that) const
240  {
241  return path() == that.path();
242  }
243 
244 private:
245  friend std::ostream& operator<<(
246  std::ostream& stream,
247  const Address& address);
248 
249  union {
250  sockaddr_storage storage;
251  sockaddr_un un;
252  } sockaddr;
253 };
254 
255 
256 inline std::ostream& operator<<(
257  std::ostream& stream,
258  const Address& address)
259 {
260  std::string path = address.path();
261  if (!path.empty() && path[0] == '\0') {
262  path[0] = '@';
263  }
264  return stream << path;
265 }
266 
267 } // namespace unix {
268 #endif // __WINDOWS__
269 
270 
271 // Represents a network "address", subsuming the `struct addrinfo` and
272 // `struct sockaddr` that typically is used to encapsulate an address.
273 //
274 // TODO(jieyu): Move this class to stout.
275 class Address :
276  public Variant<
277 #ifndef __WINDOWS__
278  unix::Address,
279 #endif // __WINDOWS__
280  inet4::Address,
281  inet6::Address>
282 {
283 public:
284  enum class Family {
285 #ifndef __WINDOWS__
286  UNIX,
287 #endif // __WINDOWS__
288  INET4,
289  INET6
290  };
291 
292  static Try<Address> create(const sockaddr_storage& storage)
293  {
294  switch (storage.ss_family) {
295 #ifndef __WINDOWS__
296  case AF_UNIX:
297  return unix::Address((const sockaddr_un&) storage);
298 #endif // __WINDOWS__
299  case AF_INET:
300  return inet4::Address((const sockaddr_in&) storage);
301  case AF_INET6:
302  return inet6::Address((const sockaddr_in6&) storage);
303  default:
304  return Error("Unsupported family: " + stringify(storage.ss_family));
305  }
306  }
307 
308  // Helper constructor for converting an `inet::Address`.
310  : Address([](const Try<Address>& address) {
311  // We expect our implementation of the cast operator to be
312  // correct, hence `Address::create` should always succeed.
313  CHECK_SOME(address);
314  return address.get();
315  }(Address::create((sockaddr_storage) address))) {}
316 
317 #ifndef __WINDOWS__
319  : Variant<
320  unix::Address,
321  inet4::Address,
322  inet6::Address>(std::move(address)) {}
323 #endif // __WINDOWS__
324 
326  : Variant<
327 #ifndef __WINDOWS__
328  unix::Address,
329 #endif // __WINDOWS__
330  inet4::Address,
331  inet6::Address>(std::move(address)) {}
332 
334  : Variant<
335 #ifndef __WINDOWS__
336  unix::Address,
337 #endif // __WINDOWS__
338  inet4::Address,
339  inet6::Address>(std::move(address)) {}
340 
341  Family family() const
342  {
343  return visit(
344 #ifndef __WINDOWS__
345  [](const unix::Address& address) {
346  return Address::Family::UNIX;
347  },
348 #endif // __WINDOWS__
349  [](const inet4::Address& address) {
350  return Address::Family::INET4;
351  },
352  [](const inet6::Address& address) {
353  return Address::Family::INET6;
354  });
355  }
356 
357  // Returns the storage size depending on the family of this address.
358  size_t size() const
359  {
360  return visit(
361 #ifndef __WINDOWS__
362  [](const unix::Address& address) {
363  return sizeof(sockaddr_un);
364  },
365 #endif // __WINDOWS__
366  [](const inet4::Address& address) {
367  return sizeof(sockaddr_in);
368  },
369  [](const inet6::Address& address) {
370  return sizeof(sockaddr_in6);
371  });
372  }
373 
374  // Implicit cast for working with C interfaces.
375  operator sockaddr_storage() const
376  {
377  return visit(
378 #ifndef __WINDOWS__
379  [](const unix::Address& address) {
380  return (sockaddr_storage) address;
381  },
382 #endif // __WINDOWS__
383  [](const inet4::Address& address) {
384  return (sockaddr_storage) address;
385  },
386  [](const inet6::Address& address) {
387  return (sockaddr_storage) address;
388  });
389 
390  // TODO(benh): With C++14 generic lambdas:
391  // return visit(
392  // [](const auto& address) {
393  // return (sockaddr_storage) address;
394  // });
395  }
396 };
397 
398 
399 // Helper for converting between Address and other types.
400 template <typename AddressType>
402 
403 
404 // TODO(benh): With C++14 generic lambdas:
405 // template <typename AddressType>
406 // Try<AddressType> convert(Try<Address>&& address)
407 // {
408 // if (address.isError()) {
409 // return Error(address.error());
410 // }
411 
412 // return address->visit(
413 // [](const AddressType& address) -> Try<AddressType> {
414 // return address;
415 // },
416 // [](const auto&) -> Try<AddressType> {
417 // return Error("Unexpected address family");
418 // });
419 // }
420 
421 
422 #ifndef __WINDOWS__
423 template <>
425 {
426  if (address.isError()) {
427  return Error(address.error());
428  }
429 
430  return address->visit(
432  return address;
433  },
434  [](const inet4::Address&) -> Try<unix::Address> {
435  return Error("Unexpected address family");
436  },
437  [](const inet6::Address&) -> Try<unix::Address> {
438  return Error("Unexpected address family");
439  });
440 }
441 #endif // __WINDOWS__
442 
443 
444 template <>
446 {
447  if (address.isError()) {
448  return Error(address.error());
449  }
450 
451  return address->visit(
452 #ifndef __WINDOWS__
453  [](const unix::Address&) -> Try<inet4::Address> {
454  return Error("Unexpected address family");
455  },
456 #endif // __WINDOWS__
458  return address;
459  },
460  [](const inet6::Address&) -> Try<inet4::Address> {
461  return Error("Unexpected address family");
462  });
463 }
464 
465 
466 template <>
468 {
469  if (address.isError()) {
470  return Error(address.error());
471  }
472 
473  return address->visit(
474 #ifndef __WINDOWS__
475  [](const unix::Address&) -> Try<inet6::Address> {
476  return Error("Unexpected address family");
477  },
478 #endif // __WINDOWS__
479  [](const inet4::Address&) -> Try<inet6::Address> {
480  return Error("Unexpected address family");
481  },
483  return address;
484  });
485 }
486 
487 
488 // Explicit instantiation in order to be able to upcast an `inet4::`
489 // or `inet6::Address` to an `inet::Address`.
490 template <>
492 {
493  if (address.isError()) {
494  return Error(address.error());
495  }
496 
497  return address->visit(
498 #ifndef __WINDOWS__
500  return Error("Unexpected address family");
501  },
502 #endif // __WINDOWS__
504  return address;
505  },
507  return address;
508  });
509 
510  // TODO(benh): With C++14 generic lambdas:
511  // return address->visit(
512  // [](const inet4::Address& address) -> Try<inet::Address> {
513  // return address;
514  // },
515  // [](const inet6::Address& address) -> Try<inet::Address> {
516  // return address;
517  // },
518  // [](const auto& t) -> Try<inet::Address> {
519  // return Error("Unexpected address family");
520  // });
521 }
522 
523 
524 template <>
526 {
527  return address;
528 }
529 
530 } // namespace network {
531 } // namespace process {
532 
533 
534 namespace std {
535 
536 template <>
537 struct hash<process::network::inet::Address>
538 {
539  typedef size_t result_type;
540 
542 
543  result_type operator()(const argument_type& address) const
544  {
545  size_t seed = 0;
546  boost::hash_combine(seed, std::hash<net::IP>()(address.ip));
547  boost::hash_combine(seed, address.port);
548  return seed;
549  }
550 };
551 
552 
553 template <>
554 struct hash<process::network::inet4::Address>
555  : hash<process::network::inet::Address>
556 {};
557 
558 
559 template <>
560 struct hash<process::network::inet6::Address>
561  : hash<process::network::inet::Address>
562 {};
563 
564 } // namespace std {
565 
566 #endif // __PROCESS_ADDRESS_HPP__
static Address ANY_ANY()
Definition: address.hpp:156
Definition: path.hpp:26
sockaddr_storage storage
Definition: address.hpp:250
static IPv6 ANY()
Definition: ip.hpp:386
static Try< Address > create(const sockaddr_storage &storage)
Definition: address.hpp:292
std::string path() const
Definition: address.hpp:225
Definition: errorbase.hpp:35
Definition: ip.hpp:334
Address(const sockaddr_in6 &in6)
Definition: address.hpp:189
#define ABORT(...)
Definition: abort.hpp:40
Address(const sockaddr_in &in)
Definition: address.hpp:164
T & get()&
Definition: try.hpp:73
Address(inet6::Address address)
Definition: address.hpp:333
Try< struct in_addr > in() const
Definition: ip.hpp:124
Definition: check.hpp:33
Try< Address > address(int_fd s)
Returns the Address with the assigned ip and assigned port.
Definition: network.hpp:79
static IPv4 ANY()
Definition: ip.hpp:342
bool operator<(const Address &that) const
Definition: address.hpp:101
Definition: ip.hpp:682
bool operator!=(const Address &that) const
Definition: address.hpp:124
bool isAny() const
Definition: ip.hpp:157
result_type operator()(const argument_type &address) const
Definition: address.hpp:543
Definition: type_utils.hpp:510
Definition: address.hpp:275
static Address LOOPBACK_ANY()
Definition: address.hpp:151
Address(const net::IP &_ip, uint16_t _port)
Definition: address.hpp:53
size_t size() const
Definition: address.hpp:358
bool operator>(const Address &that) const
Definition: address.hpp:110
Try< std::string > getHostname(const IP &ip)
Definition: net.hpp:45
bool operator==(const Address &that) const
Definition: address.hpp:239
Try< AddressType > convert(Try< Address > &&address)
Definition: address.hpp:424
static Try< Address > create(const std::string &path)
Definition: address.hpp:202
Definition: ip.hpp:73
static Address LOOPBACK_ANY()
Definition: address.hpp:176
Address(const inet::Address &address)
Definition: address.hpp:309
Try< std::string > hostname() const
Returns the hostname of this address&#39;s IP.
Definition: address.hpp:63
#define CHECK_SOME(expression)
Definition: check.hpp:50
static IPv4 LOOPBACK()
Definition: ip.hpp:337
Definition: ip.hpp:70
Address(const net::IPv6 &ip, uint16_t port)
Definition: address.hpp:186
bool operator==(const Address &that) const
Definition: address.hpp:119
uint16_t port
Definition: address.hpp:133
process::network::inet::Address argument_type
Definition: address.hpp:541
Definition: variant.hpp:47
Address(unix::Address address)
Definition: address.hpp:318
Try< std::string > hostname()
Definition: net.hpp:154
static Address ANY_ANY()
Definition: address.hpp:181
static Try error(const E &e)
Definition: try.hpp:42
Definition: address.hpp:199
static IPv6 LOOPBACK()
Definition: ip.hpp:381
Definition: ip.hpp:378
Definition: address.hpp:50
size_t result_type
Definition: address.hpp:539
Address(inet4::Address address)
Definition: address.hpp:325
Address(const sockaddr_un &un)
Definition: address.hpp:219
Family family() const
Definition: address.hpp:341
bool isError() const
Definition: try.hpp:71
Try< struct in6_addr > in6() const
Definition: ip.hpp:134
Definition: executor.hpp:47
Address(const net::IPv4 &ip, uint16_t port)
Definition: address.hpp:161
int family() const
Definition: ip.hpp:118
sockaddr_un un
Definition: address.hpp:251
Definition: address.hpp:148
std::ostream & operator<<(std::ostream &stream, const Address &address)
Definition: address.hpp:137
std::string stringify(int flags)
net::IP ip
Definition: address.hpp:132
Definition: address.hpp:173
Family
Definition: address.hpp:284