Apache Mesos
socket.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_SOCKET_HPP__
14 #define __PROCESS_SOCKET_HPP__
15 
16 #ifndef __WINDOWS__
17 #include <sys/socket.h>
18 #include <sys/wait.h>
19 #endif // __WINDOWS__
20 
21 #include <memory>
22 
23 #include <process/address.hpp>
24 #include <process/future.hpp>
25 
27 
28 #include <stout/abort.hpp>
29 #include <stout/error.hpp>
30 #include <stout/nothing.hpp>
31 #include <stout/try.hpp>
32 #include <stout/unreachable.hpp>
33 #ifdef __WINDOWS__
34 #include <stout/windows.hpp>
35 #endif // __WINDOWS__
36 
37 #include <stout/os/int_fd.hpp>
38 
39 
40 namespace process {
41 namespace network {
42 namespace internal {
43 
58 class SocketImpl : public std::enable_shared_from_this<SocketImpl>
59 {
60 public:
67  enum class Kind
68  {
69  POLL,
70 #ifdef USE_SSL_SOCKET
71  SSL
72 #endif
73  };
74 
78  static Kind DEFAULT_KIND();
79 
90  int_fd s,
91  Kind kind = DEFAULT_KIND());
92 
102  // TODO(josephw): MESOS-5729: Consider making the CLOEXEC option
103  // configurable by the caller of the interface.
105  Address::Family family,
106  Kind kind = DEFAULT_KIND());
107 
108  virtual ~SocketImpl()
109  {
110  // Don't close if the socket was released.
111  if (s >= 0) {
112  CHECK_SOME(os::close(s)) << "Failed to close socket";
113  }
114  }
115 
119  int_fd get() const
120  {
121  return s;
122  }
123 
127  Try<Address> address() const;
128 
132  Try<Address> peer() const;
133 
140  Try<Address> bind(const Address& address);
141 
142  virtual Try<Nothing> listen(int backlog) = 0;
143 
153 
154  virtual Future<Nothing> connect(
155  const Address& address) = 0;
156 
157 #ifdef USE_SSL_SOCKET
158  virtual Future<Nothing> connect(
159  const Address& address,
160  const openssl::TLSClientConfig& config) = 0;
161 #endif
162 
163  virtual Future<size_t> recv(char* data, size_t size) = 0;
164  virtual Future<size_t> send(const char* data, size_t size) = 0;
165  virtual Future<size_t> sendfile(int_fd fd, off_t offset, size_t size) = 0;
166 
181  // TODO(benh): Consider returning Owned<std::string> or
182  // Shared<std::string>, the latter enabling reuse of a pool of
183  // preallocated strings/buffers.
184  virtual Future<std::string> recv(const Option<ssize_t>& size = None());
185 
193  // TODO(benh): Consider taking Shared<std::string>, the latter
194  // enabling reuse of a pool of preallocated strings/buffers.
195  virtual Future<Nothing> send(const std::string& data);
196 
202  {
203  if (::shutdown(s, how) < 0) {
204  return SocketError();
205  }
206 
207  return Nothing();
208  }
209 
210  virtual Kind kind() const = 0;
211 
212 protected:
213  explicit SocketImpl(int_fd _s) : s(_s) { CHECK(s >= 0); }
214 
215 #if defined(USE_SSL_SOCKET) && !defined(USE_LIBEVENT)
216  // Allows this class access to `release()` other types of sockets,
217  // like the `PollSocketImpl`.
218  friend class OpenSSLSocketImpl;
219 #endif // USE_SSL_SOCKET && !USE_LIBEVENT
220 
228  {
229  int_fd released = s;
230  s = -1;
231  return released;
232  }
233 
237  template <typename T>
238  static std::shared_ptr<T> shared(T* t)
239  {
240  std::shared_ptr<T> pointer =
241  std::dynamic_pointer_cast<T>(CHECK_NOTNULL(t)->shared_from_this());
242  CHECK(pointer);
243  return pointer;
244  }
245 
247 };
248 
249 
257 template <typename AddressType>
258 class Socket
259 {
260 public:
261  static_assert(
262  std::is_convertible<AddressType, network::Address>::value,
263  "Requires type convertible to `network::Address`");
264 
275  int_fd s,
277  {
279  if (impl.isError()) {
280  return Error(impl.error());
281  }
282  return Socket(impl.get());
283  }
284 
295  // TODO(josephw): MESOS-5729: Consider making the CLOEXEC option
296  // configurable by the caller of the interface.
298 
313  static Try<Socket> create(
314  Address::Family family,
316 
324  {
325  return impl->kind();
326  }
327 
328  bool operator==(const Socket& that) const
329  {
330  return impl == that.impl;
331  }
332 
333  operator int_fd() const
334  {
335  return impl->get();
336  }
337 
339  {
340  return convert<AddressType>(impl->address());
341  }
342 
344  {
345  return convert<AddressType>(impl->peer());
346  }
347 
348  int_fd get() const
349  {
350  return impl->get();
351  }
352 
353  Try<AddressType> bind(const AddressType& address)
354  {
355  return convert<AddressType>(impl->bind(address));
356  }
357 
358  Try<Nothing> listen(int backlog)
359  {
360  return impl->listen(backlog);
361  }
362 
364  {
365  // NOTE: We save a reference to the listening socket itself
366  // (i.e., 'this') so that we don't close the listening socket
367  // while 'accept' is in flight.
368  std::shared_ptr<SocketImpl> self = impl->shared_from_this();
369 
370  return impl->accept()
371  // TODO(benh): Use && for `accepted` here!
372  .then([self](const std::shared_ptr<SocketImpl>& accepted) {
373  return Socket(accepted);
374  });
375  }
376 
377  // NOTE: Calling this overload when `kind() == SSL` will result
378  // in program termination.
379  Future<Nothing> connect(const AddressType& address)
380  {
381  return impl->connect(address);
382  }
383 
384 #ifdef USE_SSL_SOCKET
385  // NOTE: Calling this overload when `kind() == POLL` will result
386  // in program termination.
388  const AddressType& address,
389  const openssl::TLSClientConfig& config)
390  {
391  return impl->connect(address, config);
392  }
393 #endif
394 
395  Future<size_t> recv(char* data, size_t size) const
396  {
397  return impl->recv(data, size);
398  }
399 
400  Future<size_t> send(const char* data, size_t size) const
401  {
402  return impl->send(data, size);
403  }
404 
405  Future<size_t> sendfile(int_fd fd, off_t offset, size_t size) const
406  {
407  return impl->sendfile(fd, offset, size);
408  }
409 
411  {
412  return impl->recv(size);
413  }
414 
415  Future<Nothing> send(const std::string& data)
416  {
417  return impl->send(data);
418  }
419 
420  enum class Shutdown
421  {
422  READ,
423  WRITE,
424  READ_WRITE
425  };
426 
427  // TODO(benh): Replace the default to Shutdown::READ_WRITE or remove
428  // all together since it's unclear what the default should be.
430  {
431  int how = [&]() {
432  switch (shutdown) {
433  case Shutdown::READ: return SHUT_RD;
434  case Shutdown::WRITE: return SHUT_WR;
435  case Shutdown::READ_WRITE: return SHUT_RDWR;
436  }
437  UNREACHABLE();
438  }();
439 
440  return impl->shutdown(how);
441  }
442 
443  // Support implicit conversion of any `Socket<AddressType>` to a
444  // `Socket<network::Address>`.
445  operator Socket<network::Address>() const
446  {
447  return Socket<network::Address>(impl);
448  }
449 
450 private:
451  // Necessary to support the implicit conversion operator from any
452  // `Socket<AddressType>` to `Socket<network::Address>`.
453  template <typename T>
454  friend class Socket;
455 
456  explicit Socket(std::shared_ptr<SocketImpl>&& that) : impl(std::move(that)) {}
457 
458  explicit Socket(const std::shared_ptr<SocketImpl>& that) : impl(that) {}
459 
460  std::shared_ptr<SocketImpl> impl;
461 };
462 
463 } // namespace internal {
464 
465 
467 
468 namespace inet {
470 } // namespace inet {
471 
472 #ifndef __WINDOWS__
473 namespace unix {
475 } // namespace unix {
476 #endif // __WINDOWS__
477 
478 
479 namespace internal {
480 
481 template <>
483  SocketImpl::Kind kind) = delete;
484 
485 
486 template <>
488  Address::Family family,
489  SocketImpl::Kind kind)
490 {
492  if (impl.isError()) {
493  return Error(impl.error());
494  }
495  return Socket(impl.get());
496 }
497 
498 
499 template <>
501  SocketImpl::Kind kind)
502 {
503  // TODO(benh): Replace this function which defaults to IPv4 in
504  // exchange for explicit IPv4 and IPv6 versions.
507  if (impl.isError()) {
508  return Error(impl.error());
509  }
510  return Socket(impl.get());
511 }
512 
513 
514 template <>
516  Address::Family family,
517  SocketImpl::Kind kind) = delete;
518 
519 
520 #ifndef __WINDOWS__
521 template <>
523  SocketImpl::Kind kind)
524 {
527  if (impl.isError()) {
528  return Error(impl.error());
529  }
530  return Socket(impl.get());
531 }
532 
533 
534 template <>
536  Address::Family family,
537  SocketImpl::Kind kind) = delete;
538 #endif // __WINDOWS__
539 
540 } // namespace internal {
541 } // namespace network {
542 } // namespace process {
543 
544 #endif // __PROCESS_SOCKET_HPP__
network::internal::Socket< network::Address > Socket
Definition: socket.hpp:466
const short READ
A possible event while polling.
Definition: io.hpp:35
Future< size_t > sendfile(int_fd fd, off_t offset, size_t size) const
Definition: socket.hpp:405
Future< std::string > recv(const Option< ssize_t > &size=None())
Definition: socket.hpp:410
Definition: openssl_socket.hpp:27
Definition: nothing.hpp:16
virtual Future< std::shared_ptr< SocketImpl > > accept()=0
Returns an implementation corresponding to the next pending connection for the listening socket...
Definition: errorbase.hpp:36
Definition: option.hpp:29
Try< Bytes > size(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:130
int_fd release()
Releases ownership of the file descriptor.
Definition: socket.hpp:227
T & get()&
Definition: try.hpp:80
virtual Future< size_t > sendfile(int_fd fd, off_t offset, size_t size)=0
Try< Address > peer() const
Returns the peer&#39;s Address for the accepted or connected socket.
Future< size_t > recv(char *data, size_t size) const
Definition: socket.hpp:395
Definition: check.hpp:33
int_fd s
Definition: socket.hpp:246
static std::shared_ptr< T > shared(T *t)
Returns a std::shared_ptr<T> from this implementation.
Definition: socket.hpp:238
Kind
Available kinds of implementations.
Definition: socket.hpp:67
static Try< Socket > create(int_fd s, SocketImpl::Kind kind=SocketImpl::DEFAULT_KIND())
Returns an instance of a Socket using the specified kind of implementation.
Definition: socket.hpp:274
virtual Future< size_t > send(const char *data, size_t size)=0
Definition: type_utils.hpp:598
Definition: address.hpp:324
static Kind DEFAULT_KIND()
Returns the default Kind of implementation.
constexpr int SHUT_RDWR
Definition: windows.hpp:193
virtual Try< Nothing, SocketError > shutdown(int how)
Shuts down the socket.
Definition: socket.hpp:201
Try< Nothing > listen(int backlog)
Definition: socket.hpp:358
Try< Address > bind(const Address &address)
Assigns the specified address to the socket.
virtual Future< Nothing > connect(const Address &address)=0
Future< size_t > send(const char *data, size_t size) const
Definition: socket.hpp:400
ErrnoError SocketError
Definition: error.hpp:33
Try< Nothing, SocketError > shutdown(Shutdown shutdown=Shutdown::READ)
Definition: socket.hpp:429
virtual Try< Nothing > listen(int backlog)=0
Try< Address > address() const
Returns the Address with the assigned ip and assigned port.
#define CHECK_SOME(expression)
Definition: check.hpp:50
SocketImpl(int_fd _s)
Definition: socket.hpp:213
Try< Nothing > close(int fd)
Definition: close.hpp:24
const short WRITE
A possible event while polling.
Definition: io.hpp:40
Implementation interface for a Socket.
Definition: socket.hpp:58
static Try error(const E &e)
Definition: try.hpp:43
#define UNREACHABLE()
Definition: unreachable.hpp:22
SocketImpl::Kind kind() const
Returns the kind representing the underlying implementation of the Socket instance.
Definition: socket.hpp:323
Try< AddressType > bind(const AddressType &address)
Definition: socket.hpp:353
Definition: none.hpp:27
Definition: attributes.hpp:24
bool isError() const
Definition: try.hpp:78
bool operator==(const Socket &that) const
Definition: socket.hpp:328
Definition: executor.hpp:48
Future< Nothing > send(const std::string &data)
Definition: socket.hpp:415
constexpr int SHUT_RD
Definition: windows.hpp:191
Future< Socket > accept()
Definition: socket.hpp:363
int int_fd
Definition: int_fd.hpp:35
virtual ~SocketImpl()
Definition: socket.hpp:108
An abstraction around a socket (file descriptor).
Definition: socket.hpp:258
Family
Definition: address.hpp:333
Try< AddressType > address() const
Definition: socket.hpp:338
constexpr int SHUT_WR
Definition: windows.hpp:192
Try< AddressType > peer() const
Definition: socket.hpp:343
static Try< std::shared_ptr< SocketImpl > > create(int_fd s, Kind kind=DEFAULT_KIND())
Returns an instance of a SocketImpl using the specified kind of implementation.
Definition: future.hpp:58
Future< Nothing > connect(const AddressType &address)
Definition: socket.hpp:379
virtual Future< size_t > recv(char *data, size_t size)=0