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