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 
222  {
223  int_fd released = s;
224  s = -1;
225  return released;
226  }
227 
231  template <typename T>
232  static std::shared_ptr<T> shared(T* t)
233  {
234  std::shared_ptr<T> pointer =
235  std::dynamic_pointer_cast<T>(CHECK_NOTNULL(t)->shared_from_this());
236  CHECK(pointer);
237  return pointer;
238  }
239 
241 };
242 
243 
251 template <typename AddressType>
252 class Socket
253 {
254 public:
255  static_assert(
256  std::is_convertible<AddressType, network::Address>::value,
257  "Requires type convertible to `network::Address`");
258 
269  int_fd s,
271  {
273  if (impl.isError()) {
274  return Error(impl.error());
275  }
276  return Socket(impl.get());
277  }
278 
289  // TODO(josephw): MESOS-5729: Consider making the CLOEXEC option
290  // configurable by the caller of the interface.
292 
307  static Try<Socket> create(
308  Address::Family family,
310 
318  {
319  return impl->kind();
320  }
321 
322  bool operator==(const Socket& that) const
323  {
324  return impl == that.impl;
325  }
326 
327  operator int_fd() const
328  {
329  return impl->get();
330  }
331 
333  {
334  return convert<AddressType>(impl->address());
335  }
336 
338  {
339  return convert<AddressType>(impl->peer());
340  }
341 
342  int_fd get() const
343  {
344  return impl->get();
345  }
346 
347  Try<AddressType> bind(const AddressType& address)
348  {
349  return convert<AddressType>(impl->bind(address));
350  }
351 
352  Try<Nothing> listen(int backlog)
353  {
354  return impl->listen(backlog);
355  }
356 
358  {
359  // NOTE: We save a reference to the listening socket itself
360  // (i.e., 'this') so that we don't close the listening socket
361  // while 'accept' is in flight.
362  std::shared_ptr<SocketImpl> self = impl->shared_from_this();
363 
364  return impl->accept()
365  // TODO(benh): Use && for `accepted` here!
366  .then([self](const std::shared_ptr<SocketImpl>& accepted) {
367  return Socket(accepted);
368  });
369  }
370 
371  // NOTE: Calling this overload when `kind() == SSL` will result
372  // in program termination.
373  Future<Nothing> connect(const AddressType& address)
374  {
375  return impl->connect(address);
376  }
377 
378 #ifdef USE_SSL_SOCKET
379  // NOTE: Calling this overload when `kind() == POLL` will result
380  // in program termination.
382  const AddressType& address,
383  const openssl::TLSClientConfig& config)
384  {
385  return impl->connect(address, config);
386  }
387 #endif
388 
389  Future<size_t> recv(char* data, size_t size) const
390  {
391  return impl->recv(data, size);
392  }
393 
394  Future<size_t> send(const char* data, size_t size) const
395  {
396  return impl->send(data, size);
397  }
398 
399  Future<size_t> sendfile(int_fd fd, off_t offset, size_t size) const
400  {
401  return impl->sendfile(fd, offset, size);
402  }
403 
405  {
406  return impl->recv(size);
407  }
408 
409  Future<Nothing> send(const std::string& data)
410  {
411  return impl->send(data);
412  }
413 
414  enum class Shutdown
415  {
416  READ,
417  WRITE,
418  READ_WRITE
419  };
420 
421  // TODO(benh): Replace the default to Shutdown::READ_WRITE or remove
422  // all together since it's unclear what the default should be.
424  {
425  int how = [&]() {
426  switch (shutdown) {
427  case Shutdown::READ: return SHUT_RD;
428  case Shutdown::WRITE: return SHUT_WR;
429  case Shutdown::READ_WRITE: return SHUT_RDWR;
430  }
431  UNREACHABLE();
432  }();
433 
434  return impl->shutdown(how);
435  }
436 
437  // Support implicit conversion of any `Socket<AddressType>` to a
438  // `Socket<network::Address>`.
439  operator Socket<network::Address>() const
440  {
441  return Socket<network::Address>(impl);
442  }
443 
444 private:
445  // Necessary to support the implicit conversion operator from any
446  // `Socket<AddressType>` to `Socket<network::Address>`.
447  template <typename T>
448  friend class Socket;
449 
450  explicit Socket(std::shared_ptr<SocketImpl>&& that) : impl(std::move(that)) {}
451 
452  explicit Socket(const std::shared_ptr<SocketImpl>& that) : impl(that) {}
453 
454  std::shared_ptr<SocketImpl> impl;
455 };
456 
457 } // namespace internal {
458 
459 
461 
462 namespace inet {
464 } // namespace inet {
465 
466 #ifndef __WINDOWS__
467 namespace unix {
469 } // namespace unix {
470 #endif // __WINDOWS__
471 
472 
473 namespace internal {
474 
475 template <>
477  SocketImpl::Kind kind) = delete;
478 
479 
480 template <>
482  Address::Family family,
483  SocketImpl::Kind kind)
484 {
486  if (impl.isError()) {
487  return Error(impl.error());
488  }
489  return Socket(impl.get());
490 }
491 
492 
493 template <>
495  SocketImpl::Kind kind)
496 {
497  // TODO(benh): Replace this function which defaults to IPv4 in
498  // exchange for explicit IPv4 and IPv6 versions.
501  if (impl.isError()) {
502  return Error(impl.error());
503  }
504  return Socket(impl.get());
505 }
506 
507 
508 template <>
510  Address::Family family,
511  SocketImpl::Kind kind) = delete;
512 
513 
514 #ifndef __WINDOWS__
515 template <>
517  SocketImpl::Kind kind)
518 {
521  if (impl.isError()) {
522  return Error(impl.error());
523  }
524  return Socket(impl.get());
525 }
526 
527 
528 template <>
530  Address::Family family,
531  SocketImpl::Kind kind) = delete;
532 #endif // __WINDOWS__
533 
534 } // namespace internal {
535 } // namespace network {
536 } // namespace process {
537 
538 #endif // __PROCESS_SOCKET_HPP__
network::internal::Socket< network::Address > Socket
Definition: socket.hpp:460
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:399
Future< std::string > recv(const Option< ssize_t > &size=None())
Definition: socket.hpp:404
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:121
int_fd release()
Releases ownership of the file descriptor.
Definition: socket.hpp:221
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:389
Definition: check.hpp:33
int_fd s
Definition: socket.hpp:240
static std::shared_ptr< T > shared(T *t)
Returns a std::shared_ptr<T> from this implementation.
Definition: socket.hpp:232
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:268
virtual Future< size_t > send(const char *data, size_t size)=0
Definition: type_utils.hpp:598
Definition: address.hpp:282
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:352
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:394
ErrnoError SocketError
Definition: error.hpp:33
Try< Nothing, SocketError > shutdown(Shutdown shutdown=Shutdown::READ)
Definition: socket.hpp:423
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:317
Try< AddressType > bind(const AddressType &address)
Definition: socket.hpp:347
Definition: none.hpp:27
Definition: attributes.hpp:24
bool isError() const
Definition: try.hpp:78
bool operator==(const Socket &that) const
Definition: socket.hpp:322
Definition: executor.hpp:48
Future< Nothing > send(const std::string &data)
Definition: socket.hpp:409
constexpr int SHUT_RD
Definition: windows.hpp:191
Future< Socket > accept()
Definition: socket.hpp:357
int int_fd
Definition: int_fd.hpp:35
virtual ~SocketImpl()
Definition: socket.hpp:108
An abstraction around a socket (file descriptor).
Definition: socket.hpp:252
Family
Definition: address.hpp:291
Try< AddressType > address() const
Definition: socket.hpp:332
constexpr int SHUT_WR
Definition: windows.hpp:192
Try< AddressType > peer() const
Definition: socket.hpp:337
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:373
virtual Future< size_t > recv(char *data, size_t size)=0