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