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  // Helper constructor for converting an `inet::Address`.
370  : Address([](const Try<Address>& address) {
371  // We expect our implementation of the cast operator to be
372  // correct, hence `Address::create` should always succeed.
373  CHECK_SOME(address);
374  return address.get();
375  }(Address::create((sockaddr_storage) address))) {}
376 
377 #ifndef __WINDOWS__
379  : Variant<
380  unix::Address,
381  inet4::Address,
382  inet6::Address>(std::move(address)) {}
383 #endif // __WINDOWS__
384 
386  : Variant<
387 #ifndef __WINDOWS__
388  unix::Address,
389 #endif // __WINDOWS__
390  inet4::Address,
391  inet6::Address>(std::move(address)) {}
392 
394  : Variant<
395 #ifndef __WINDOWS__
396  unix::Address,
397 #endif // __WINDOWS__
398  inet4::Address,
399  inet6::Address>(std::move(address)) {}
400 
401  Family family() const
402  {
403  return visit(
404 #ifndef __WINDOWS__
405  [](const unix::Address& address) {
406  return Address::Family::UNIX;
407  },
408 #endif // __WINDOWS__
409  [](const inet4::Address& address) {
410  return Address::Family::INET4;
411  },
412  [](const inet6::Address& address) {
413  return Address::Family::INET6;
414  });
415  }
416 
417  // Returns the storage size depending on the family of this address.
418  size_t size() const
419  {
420  return visit(
421 #ifndef __WINDOWS__
422  [](const unix::Address& address) {
423  return address.size();
424  },
425 #endif // __WINDOWS__
426  [](const inet4::Address& address) {
427  return sizeof(sockaddr_in);
428  },
429  [](const inet6::Address& address) {
430  return sizeof(sockaddr_in6);
431  });
432  }
433 
434  // Implicit cast for working with C interfaces.
435  operator sockaddr_storage() const
436  {
437  return visit(
438 #ifndef __WINDOWS__
439  [](const unix::Address& address) {
440  return (sockaddr_storage) address;
441  },
442 #endif // __WINDOWS__
443  [](const inet4::Address& address) {
444  return (sockaddr_storage) address;
445  },
446  [](const inet6::Address& address) {
447  return (sockaddr_storage) address;
448  });
449 
450  // TODO(benh): With C++14 generic lambdas:
451  // return visit(
452  // [](const auto& address) {
453  // return (sockaddr_storage) address;
454  // });
455  }
456 };
457 
458 
459 // Helper for converting between Address and other types.
460 template <typename AddressType>
462 
463 
464 // TODO(benh): With C++14 generic lambdas:
465 // template <typename AddressType>
466 // Try<AddressType> convert(Try<Address>&& address)
467 // {
468 // if (address.isError()) {
469 // return Error(address.error());
470 // }
471 
472 // return address->visit(
473 // [](const AddressType& address) -> Try<AddressType> {
474 // return address;
475 // },
476 // [](const auto&) -> Try<AddressType> {
477 // return Error("Unexpected address family");
478 // });
479 // }
480 
481 
482 #ifndef __WINDOWS__
483 template <>
485 {
486  if (address.isError()) {
487  return Error(address.error());
488  }
489 
490  return address->visit(
492  return address;
493  },
494  [](const inet4::Address&) -> Try<unix::Address> {
495  return Error("Unexpected address family");
496  },
497  [](const inet6::Address&) -> Try<unix::Address> {
498  return Error("Unexpected address family");
499  });
500 }
501 #endif // __WINDOWS__
502 
503 
504 template <>
506 {
507  if (address.isError()) {
508  return Error(address.error());
509  }
510 
511  return address->visit(
512 #ifndef __WINDOWS__
513  [](const unix::Address&) -> Try<inet4::Address> {
514  return Error("Unexpected address family");
515  },
516 #endif // __WINDOWS__
518  return address;
519  },
520  [](const inet6::Address&) -> Try<inet4::Address> {
521  return Error("Unexpected address family");
522  });
523 }
524 
525 
526 template <>
528 {
529  if (address.isError()) {
530  return Error(address.error());
531  }
532 
533  return address->visit(
534 #ifndef __WINDOWS__
535  [](const unix::Address&) -> Try<inet6::Address> {
536  return Error("Unexpected address family");
537  },
538 #endif // __WINDOWS__
539  [](const inet4::Address&) -> Try<inet6::Address> {
540  return Error("Unexpected address family");
541  },
543  return address;
544  });
545 }
546 
547 
548 // Explicit instantiation in order to be able to upcast an `inet4::`
549 // or `inet6::Address` to an `inet::Address`.
550 template <>
552 {
553  if (address.isError()) {
554  return Error(address.error());
555  }
556 
557  return address->visit(
558 #ifndef __WINDOWS__
560  return Error("Unexpected address family");
561  },
562 #endif // __WINDOWS__
564  return address;
565  },
567  return address;
568  });
569 
570  // TODO(benh): With C++14 generic lambdas:
571  // return address->visit(
572  // [](const inet4::Address& address) -> Try<inet::Address> {
573  // return address;
574  // },
575  // [](const inet6::Address& address) -> Try<inet::Address> {
576  // return address;
577  // },
578  // [](const auto& t) -> Try<inet::Address> {
579  // return Error("Unexpected address family");
580  // });
581 }
582 
583 
584 template <>
586 {
587  return std::move(address);
588 }
589 
590 } // namespace network {
591 } // namespace process {
592 
593 
594 namespace std {
595 
596 template <>
597 struct hash<process::network::inet::Address>
598 {
599  typedef size_t result_type;
600 
602 
603  result_type operator()(const argument_type& address) const
604  {
605  size_t seed = 0;
606  boost::hash_combine(seed, std::hash<net::IP>()(address.ip));
607  boost::hash_combine(seed, address.port);
608  return seed;
609  }
610 };
611 
612 
613 template <>
614 struct hash<process::network::inet4::Address>
615  : hash<process::network::inet::Address>
616 {};
617 
618 
619 template <>
620 struct hash<process::network::inet6::Address>
621  : hash<process::network::inet::Address>
622 {};
623 
624 } // namespace std {
625 
626 #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:393
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:603
Definition: type_utils.hpp:598
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:418
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:484
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:369
#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:601
Definition: variant.hpp:47
Address(unix::Address address)
Definition: address.hpp:378
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:599
Address(inet4::Address address)
Definition: address.hpp:385
Family family() const
Definition: address.hpp:401
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
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