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 <stddef.h>
17 #include <stdint.h>
18 #ifndef __WINDOWS__
19 #include <unistd.h>
20 #endif // __WINDOWS__
21 
22 #ifndef __WINDOWS__
23 #include <arpa/inet.h>
24 #endif // __WINDOWS__
25 
26 #include <glog/logging.h>
27 
28 #ifndef __WINDOWS__
29 #include <sys/un.h>
30 #endif // __WINDOWS__
31 
32 #include <ostream>
33 #include <utility>
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 
65  // TODO(jmlvanre): Consider making this return a Future in order to
66  // deal with slow name resolution.
67  //
68  // TODO(bevers): A given IP can have multiple associated PTR records,
69  // (e.g. a shared web server hosting multiple domains), so the return
70  // value should probably be a list of strings.
72  {
74  ? net::hostname()
76 
77  if (hostname.isError()) {
78  return Error(hostname.error());
79  }
80 
81  return hostname.get();
82  }
83 
84  operator sockaddr_storage() const
85  {
86  union {
87  sockaddr_storage storage;
88  sockaddr_in in;
89  sockaddr_in6 in6;
90  } sockaddr;
91  memset(&sockaddr.storage, 0, sizeof(sockaddr_storage));
92  switch (ip.family()) {
93  case AF_INET:
94  sockaddr.in.sin_family = AF_INET;
95  sockaddr.in.sin_addr = ip.in().get();
96  sockaddr.in.sin_port = htons(port);
97  break;
98  case AF_INET6:
99  sockaddr.in6.sin6_family = AF_INET6;
100  sockaddr.in6.sin6_addr = ip.in6().get();
101  sockaddr.in6.sin6_port = htons(port);
102  break;
103  default:
104  ABORT("Unexpected family: " + stringify(ip.family()));
105  }
106  return sockaddr.storage;
107  }
108 
109  bool operator<(const Address& that) const
110  {
111  if (ip == that.ip) {
112  return port < that.port;
113  } else {
114  return ip < that.ip;
115  }
116  }
117 
118  bool operator>(const Address& that) const
119  {
120  if (ip == that.ip) {
121  return port > that.port;
122  } else {
123  return ip > that.ip;
124  }
125  }
126 
127  bool operator==(const Address& that) const
128  {
129  return (ip == that.ip && port == that.port);
130  }
131 
132  bool operator!=(const Address& that) const
133  {
134  return !(*this == that);
135  }
136 
137  // TODO(benh): Consider using `sockaddr_storage` here like we do for
138  // `unix::Address`. This will require changing all places that
139  // either the `ip` or `port` field are currently used.
141  uint16_t port;
142 };
143 
144 
145 inline std::ostream& operator<<(std::ostream& stream, const Address& address)
146 {
147  stream << address.ip << ":" << address.port;
148  return stream;
149 }
150 
151 } // namespace inet {
152 
153 
154 namespace inet4 {
155 
156 class Address : public inet::Address
157 {
158 public:
160  {
161  return Address(net::IPv4::LOOPBACK(), 0);
162  }
163 
164  static Address ANY_ANY()
165  {
166  return Address(net::IPv4::ANY(), 0);
167  }
168 
169  Address(const net::IPv4& ip, uint16_t port)
170  : inet::Address(ip, port) {}
171 
172  Address(const sockaddr_in& in)
173  : inet::Address(net::IPv4(in.sin_addr), ntohs(in.sin_port)) {}
174 };
175 
176 } // namespace inet4 {
177 
178 
179 namespace inet6 {
180 
181 class Address : public inet::Address
182 {
183 public:
185  {
186  return Address(net::IPv6::LOOPBACK(), 0);
187  }
188 
189  static Address ANY_ANY()
190  {
191  return Address(net::IPv6::ANY(), 0);
192  }
193 
194  Address(const net::IPv6& ip, uint16_t port)
195  : inet::Address(ip, port) {}
196 
197  Address(const sockaddr_in6& in6)
198  : inet::Address(net::IPv6(in6.sin6_addr), ntohs(in6.sin6_port)) {}
199 };
200 
201 } // namespace inet6 {
202 
203 
204 #ifndef __WINDOWS__
205 namespace unix {
206 
207 class Address
208 {
209 public:
210  static Try<Address> create(const std::string& path)
211  {
212  sockaddr_un un;
213 
214  const size_t PATH_LENGTH = sizeof(un.sun_path);
215 
216  if (path.length() >= PATH_LENGTH) {
217  return Error("Path too long, must be less than " +
218  stringify(PATH_LENGTH) + " bytes");
219  }
220 
221  un.sun_family = AF_UNIX;
222  memcpy(un.sun_path, path.c_str(), path.length() + 1);
223 
224  return Address(
225  un, path.length() + offsetof(struct sockaddr_un, sun_path) + 1);
226  }
227 
228  // For pathname sockets, `length` can be omitted to signal that it should be
229  // determined automatically from the string length of the null-terminated
230  // string inside `sun_path`. For abstract and unnamed domain sockets, the
231  // correct length must be passed manually. See `man(7) unix` on the details
232  // how to compute the correct length. For functions that return a socket
233  // address (`recvfrom()`, `getpeername()`, etc.) the returned length will be
234  // set to the correct value during the call.
235  Address(const sockaddr_un& un, Option<socklen_t> _length = None())
236  : sockaddr() // Zero initialize.
237  {
238  sockaddr.un = un;
239 
240  if (_length.isNone()) {
241  CHECK(un.sun_path[0] != 0)
242  << "Cannot automatically determine size of abstract socket address";
243 
244  length = ::strlen(un.sun_path) + offsetof(sockaddr_un, sun_path) + 1;
245  } else {
246  CHECK(_length.get() <= sizeof(struct sockaddr_un));
247  length = _length.get();
248  }
249  }
250 
251  size_t size() const
252  {
253  return length;
254  }
255 
256  std::string path() const
257  {
258  return std::string(sockaddr.un.sun_path, path_length());
259  }
260 
261  operator sockaddr_storage() const
262  {
263  return sockaddr.storage;
264  }
265 
266  bool operator==(const Address& that) const
267  {
268  return length == that.length &&
269  !memcmp(sockaddr.un.sun_path, that.sockaddr.un.sun_path, path_length());
270  }
271 
272 private:
273  friend std::ostream& operator<<(
274  std::ostream& stream,
275  const Address& address);
276 
277  // Size of the address data inside `sun_path`, in bytes.
278  // The length computations here are defined in `man(7) unix`.
279  size_t path_length() const
280  {
281  if (length == sizeof(sa_family_t)) {
282  // Unnamed socket.
283  return 0;
284  } else if (sockaddr.un.sun_path[0] == '\0') {
285  // Abstract domain socket.
286  return length - sizeof(sa_family_t);
287  } else {
288  // Pathname socket.
289  return length - offsetof(struct sockaddr_un, sun_path) - 1;
290  }
291  }
292 
293  union {
294  sockaddr_storage storage;
295  sockaddr_un un;
296  } sockaddr;
297 
298  // Size of this socket. Unlike TCP/IP sockets, this is not just a
299  // compile time constant, but depends on the type of the socket
300  // address and the path it contains.
301  socklen_t length;
302 };
303 
304 
305 inline std::ostream& operator<<(
306  std::ostream& stream,
307  const Address& address)
308 {
309  std::string path = address.path();
310  if (!path.empty() && path[0] == '\0') {
311  path[0] = '@';
312  }
313  return stream << path;
314 }
315 
316 } // namespace unix {
317 #endif // __WINDOWS__
318 
319 
320 // Represents a network "address", subsuming the `struct addrinfo` and
321 // `struct sockaddr` that typically is used to encapsulate an address.
322 //
323 // TODO(jieyu): Move this class to stout.
324 class Address :
325  public Variant<
326 #ifndef __WINDOWS__
327  unix::Address,
328 #endif // __WINDOWS__
329  inet4::Address,
330  inet6::Address>
331 {
332 public:
333  enum class Family {
334 #ifndef __WINDOWS__
335  UNIX,
336 #endif // __WINDOWS__
337  INET4,
338  INET6
339  };
340 
341  // The `length` is the size of this `struct sockaddr`. For `AF_INET`
342  // and `AF_INET6` this parameters is ignored, since there is only
343  // one possible value anyways.
345  const sockaddr_storage& storage,
346  Option<socklen_t> length = None())
347  {
348  switch (storage.ss_family) {
349 #ifndef __WINDOWS__
350  case AF_UNIX:
351  // We need to know the length in addition to the address, to
352  // distinguish between e.g. an unnamed socket and an abstract
353  // socket whose name is a single null byte.
354  if (length.isNone()) {
355  return Error("Need length to create unix address from sockaddr");
356  }
357  return unix::Address((const sockaddr_un&) storage, *length);
358 #endif // __WINDOWS__
359  case AF_INET:
360  return inet4::Address((const sockaddr_in&) storage);
361  case AF_INET6:
362  return inet6::Address((const sockaddr_in6&) storage);
363  default:
364  return Error("Unsupported family: " + stringify(storage.ss_family));
365  }
366  }
367 
368  // The `length` is the size of the data pointed to by `struct sockaddr`.
370  const sockaddr* address,
371  size_t length)
372  {
373  switch (address->sa_family) {
374 #ifndef __WINDOWS__
375  case AF_UNIX:
376  // We need to know the length in addition to the address, to
377  // distinguish between e.g. an unnamed socket and an abstract
378  // socket whose name is a single null byte.
379  if (length > sizeof(struct sockaddr_un)) {
380  return Error("Invalid size for AF_UNIX sockaddr: " +
381  stringify(length) + " actual vs " +
382  stringify(sizeof(struct sockaddr_un)) + " expected");
383  }
384  return unix::Address(*((const sockaddr_un*)address), length);
385 #endif // __WINDOWS__
386  case AF_INET:
387  if (length < sizeof(struct sockaddr_in)) {
388  return Error("Invalid size for AF_INET sockaddr: " +
389  stringify(length) + " actual vs " +
390  stringify(sizeof(struct sockaddr_in)) + " expected");
391  }
392  return inet4::Address(*((const sockaddr_in*)address));
393  case AF_INET6:
394  if (length < sizeof(struct sockaddr_in6)) {
395  return Error("Invalid size for AF_INET6 sockaddr: " +
396  stringify(length) + " actual vs " +
397  stringify(sizeof(struct sockaddr_in6)) + " expected");
398  }
399  return inet6::Address(*((const sockaddr_in6*)address));
400  default:
401  return Error("Unsupported family: " + stringify(address->sa_family));
402  }
403  }
404 
405  // Helper constructor for converting an `inet::Address`.
407  : Address([](const Try<Address>& address) {
408  // We expect our implementation of the cast operator to be
409  // correct, hence `Address::create` should always succeed.
410  CHECK_SOME(address);
411  return address.get();
412  }(Address::create((sockaddr_storage) address))) {}
413 
414 #ifndef __WINDOWS__
416  : Variant<
417  unix::Address,
418  inet4::Address,
419  inet6::Address>(std::move(address)) {}
420 #endif // __WINDOWS__
421 
423  : Variant<
424 #ifndef __WINDOWS__
425  unix::Address,
426 #endif // __WINDOWS__
427  inet4::Address,
428  inet6::Address>(std::move(address)) {}
429 
431  : Variant<
432 #ifndef __WINDOWS__
433  unix::Address,
434 #endif // __WINDOWS__
435  inet4::Address,
436  inet6::Address>(std::move(address)) {}
437 
438  Family family() const
439  {
440  return visit(
441 #ifndef __WINDOWS__
442  [](const unix::Address& address) {
443  return Address::Family::UNIX;
444  },
445 #endif // __WINDOWS__
446  [](const inet4::Address& address) {
447  return Address::Family::INET4;
448  },
449  [](const inet6::Address& address) {
450  return Address::Family::INET6;
451  });
452  }
453 
454  // Returns the storage size depending on the family of this address.
455  size_t size() const
456  {
457  return visit(
458 #ifndef __WINDOWS__
459  [](const unix::Address& address) {
460  return address.size();
461  },
462 #endif // __WINDOWS__
463  [](const inet4::Address& address) {
464  return sizeof(sockaddr_in);
465  },
466  [](const inet6::Address& address) {
467  return sizeof(sockaddr_in6);
468  });
469  }
470 
471  // Implicit cast for working with C interfaces.
472  operator sockaddr_storage() const
473  {
474  return visit(
475 #ifndef __WINDOWS__
476  [](const unix::Address& address) {
477  return (sockaddr_storage) address;
478  },
479 #endif // __WINDOWS__
480  [](const inet4::Address& address) {
481  return (sockaddr_storage) address;
482  },
483  [](const inet6::Address& address) {
484  return (sockaddr_storage) address;
485  });
486 
487  // TODO(benh): With C++14 generic lambdas:
488  // return visit(
489  // [](const auto& address) {
490  // return (sockaddr_storage) address;
491  // });
492  }
493 };
494 
495 
496 // Helper for converting between Address and other types.
497 template <typename AddressType>
499 
500 
501 // TODO(benh): With C++14 generic lambdas:
502 // template <typename AddressType>
503 // Try<AddressType> convert(Try<Address>&& address)
504 // {
505 // if (address.isError()) {
506 // return Error(address.error());
507 // }
508 
509 // return address->visit(
510 // [](const AddressType& address) -> Try<AddressType> {
511 // return address;
512 // },
513 // [](const auto&) -> Try<AddressType> {
514 // return Error("Unexpected address family");
515 // });
516 // }
517 
518 
519 #ifndef __WINDOWS__
520 template <>
522 {
523  if (address.isError()) {
524  return Error(address.error());
525  }
526 
527  return address->visit(
529  return address;
530  },
531  [](const inet4::Address&) -> Try<unix::Address> {
532  return Error("Unexpected address family");
533  },
534  [](const inet6::Address&) -> Try<unix::Address> {
535  return Error("Unexpected address family");
536  });
537 }
538 #endif // __WINDOWS__
539 
540 
541 template <>
543 {
544  if (address.isError()) {
545  return Error(address.error());
546  }
547 
548  return address->visit(
549 #ifndef __WINDOWS__
550  [](const unix::Address&) -> Try<inet4::Address> {
551  return Error("Unexpected address family");
552  },
553 #endif // __WINDOWS__
555  return address;
556  },
557  [](const inet6::Address&) -> Try<inet4::Address> {
558  return Error("Unexpected address family");
559  });
560 }
561 
562 
563 template <>
565 {
566  if (address.isError()) {
567  return Error(address.error());
568  }
569 
570  return address->visit(
571 #ifndef __WINDOWS__
572  [](const unix::Address&) -> Try<inet6::Address> {
573  return Error("Unexpected address family");
574  },
575 #endif // __WINDOWS__
576  [](const inet4::Address&) -> Try<inet6::Address> {
577  return Error("Unexpected address family");
578  },
580  return address;
581  });
582 }
583 
584 
585 // Explicit instantiation in order to be able to upcast an `inet4::`
586 // or `inet6::Address` to an `inet::Address`.
587 template <>
589 {
590  if (address.isError()) {
591  return Error(address.error());
592  }
593 
594  return address->visit(
595 #ifndef __WINDOWS__
597  return Error("Unexpected address family");
598  },
599 #endif // __WINDOWS__
601  return address;
602  },
604  return address;
605  });
606 
607  // TODO(benh): With C++14 generic lambdas:
608  // return address->visit(
609  // [](const inet4::Address& address) -> Try<inet::Address> {
610  // return address;
611  // },
612  // [](const inet6::Address& address) -> Try<inet::Address> {
613  // return address;
614  // },
615  // [](const auto& t) -> Try<inet::Address> {
616  // return Error("Unexpected address family");
617  // });
618 }
619 
620 
621 template <>
623 {
624  return std::move(address);
625 }
626 
627 } // namespace network {
628 } // namespace process {
629 
630 
631 namespace std {
632 
633 template <>
634 struct hash<process::network::inet::Address>
635 {
636  typedef size_t result_type;
637 
639 
640  result_type operator()(const argument_type& address) const
641  {
642  size_t seed = 0;
643  boost::hash_combine(seed, std::hash<net::IP>()(address.ip));
644  boost::hash_combine(seed, address.port);
645  return seed;
646  }
647 };
648 
649 
650 template <>
651 struct hash<process::network::inet4::Address>
652  : hash<process::network::inet::Address>
653 {};
654 
655 
656 template <>
657 struct hash<process::network::inet6::Address>
658  : hash<process::network::inet::Address>
659 {};
660 
661 } // namespace std {
662 
663 #endif // __PROCESS_ADDRESS_HPP__
static Address ANY_ANY()
Definition: address.hpp:164
Definition: path.hpp:29
sockaddr_storage storage
Definition: address.hpp:294
static IPv6 ANY()
Definition: ip.hpp:386
std::string path() const
Definition: address.hpp:256
Definition: errorbase.hpp:36
Definition: ip.hpp:334
Address(const sockaddr_in6 &in6)
Definition: address.hpp:197
Definition: option.hpp:29
#define ABORT(...)
Definition: abort.hpp:40
Address(const sockaddr_in &in)
Definition: address.hpp:172
T & get()&
Definition: try.hpp:80
Address(inet6::Address address)
Definition: address.hpp:430
Try< struct in_addr > in() const
Definition: ip.hpp:124
Address(const sockaddr_un &un, Option< socklen_t > _length=None())
Definition: address.hpp:235
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:109
Definition: ip.hpp:682
bool operator!=(const Address &that) const
Definition: address.hpp:132
bool isAny() const
Definition: ip.hpp:157
result_type operator()(const argument_type &address) const
Definition: address.hpp:640
Definition: type_utils.hpp:619
Definition: address.hpp:324
static Address LOOPBACK_ANY()
Definition: address.hpp:159
Address(const net::IP &_ip, uint16_t _port)
Definition: address.hpp:55
size_t size() const
Definition: address.hpp:455
bool operator>(const Address &that) const
Definition: address.hpp:118
Try< std::string > getHostname(const IP &ip)
Definition: net.hpp:45
static Try< Address > create(const sockaddr_storage &storage, Option< socklen_t > length=None())
Definition: address.hpp:344
bool operator==(const Address &that) const
Definition: address.hpp:266
Try< AddressType > convert(Try< Address > &&address)
Definition: address.hpp:521
static Try< Address > create(const std::string &path)
Definition: address.hpp:210
Definition: ip.hpp:73
static Address LOOPBACK_ANY()
Definition: address.hpp:184
Address(const inet::Address &address)
Definition: address.hpp:406
#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:194
bool operator==(const Address &that) const
Definition: address.hpp:127
uint16_t port
Definition: address.hpp:141
process::network::inet::Address argument_type
Definition: address.hpp:638
Definition: variant.hpp:47
Address(unix::Address address)
Definition: address.hpp:415
Try< std::string > hostname()
Definition: net.hpp:154
static Address ANY_ANY()
Definition: address.hpp:189
static Try error(const E &e)
Definition: try.hpp:43
Definition: address.hpp:207
size_t size() const
Definition: address.hpp:251
static IPv6 LOOPBACK()
Definition: ip.hpp:381
Definition: ip.hpp:378
Definition: address.hpp:52
size_t result_type
Definition: address.hpp:636
Address(inet4::Address address)
Definition: address.hpp:422
Family family() const
Definition: address.hpp:438
Definition: none.hpp:27
bool isError() const
Definition: try.hpp:78
Try< struct in6_addr > in6() const
Definition: ip.hpp:134
Definition: executor.hpp:48
Address(const net::IPv4 &ip, uint16_t port)
Definition: address.hpp:169
int family() const
Definition: ip.hpp:118
static Try< Address > create(const sockaddr *address, size_t length)
Definition: address.hpp:369
sockaddr_un un
Definition: address.hpp:295
Try< std::string > lookup_hostname() const
Returns the hostname of this address&#39;s IP, using a reverse DNS lookup for remote addresses or the loc...
Definition: address.hpp:71
Definition: address.hpp:156
std::ostream & operator<<(std::ostream &stream, const Address &address)
Definition: address.hpp:145
std::string stringify(int flags)
net::IP ip
Definition: address.hpp:140
Definition: address.hpp:181
Family
Definition: address.hpp:333