Apache Mesos
libevent_ssl_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 __LIBEVENT_SSL_SOCKET_HPP__
14 #define __LIBEVENT_SSL_SOCKET_HPP__
15 
16 #include <event2/buffer.h>
17 #include <event2/bufferevent_ssl.h>
18 #include <event2/event.h>
19 #include <event2/listener.h>
20 #include <event2/util.h>
21 
22 #include <atomic>
23 #include <memory>
24 
25 #include <process/queue.hpp>
26 #include <process/socket.hpp>
27 
28 namespace process {
29 namespace network {
30 namespace internal {
31 
33 {
34 public:
35  // See 'Socket::create()'.
37 
39 
40  ~LibeventSSLSocketImpl() override;
41 
42  // Implement 'SocketImpl' interface.
43  Future<Nothing> connect(const Address& address) override;
45  const Address& address,
46  const openssl::TLSClientConfig& config) override;
47 
48  Future<size_t> recv(char* data, size_t size) override;
49  // Send does not currently support discard. See implementation.
50  Future<size_t> send(const char* data, size_t size) override;
51  Future<size_t> sendfile(int_fd fd, off_t offset, size_t size) override;
52  Try<Nothing> listen(int backlog) override;
54  SocketImpl::Kind kind() const override { return SocketImpl::Kind::SSL; }
55 
56  // Shuts down the socket.
57  //
58  // NOTE: Although this method accepts an integer which specifies the
59  // shutdown mode, this parameter is ignored because SSL connections
60  // do not have a concept of read/write-only shutdown. If either end
61  // of the socket is closed, then the futures of any outstanding read
62  // requests will be completed (possibly as failures).
63  Try<Nothing, SocketError> shutdown(int how) override;
64 
65  // We need a post-initializer because 'shared_from_this()' is not
66  // valid until the constructor has finished.
67  void initialize();
68 
69 private:
70  // A set of helper functions that transitions an accepted socket to
71  // an SSL connected socket. With the libevent-openssl library, once
72  // we return from the 'accept_callback()' which is scheduled by
73  // 'listen' then we still need to wait for the 'BEV_EVENT_CONNECTED'
74  // state before we know the SSL connection has been established.
75  struct AcceptRequest
76  {
77  AcceptRequest(
78  int_fd _socket,
79  evconnlistener* _listener,
80  const Option<net::IP>& _ip)
81  : peek_event(nullptr),
82  listener(_listener),
83  socket(_socket),
84  ip(_ip) {}
85  event* peek_event;
87  evconnlistener* listener;
88  int_fd socket;
89  Option<net::IP> ip;
90  };
91 
92  struct RecvRequest
93  {
94  RecvRequest(char* _data, size_t _size)
95  : data(_data), size(_size) {}
97  char* data;
98  size_t size;
99  };
100 
101  struct SendRequest
102  {
103  SendRequest(size_t _size)
104  : size(_size) {}
106  size_t size;
107  };
108 
109  struct ConnectRequest
110  {
112  };
113 
114  // This is a private constructor used by the accept helper
115  // functions.
117  int_fd _s,
118  bufferevent* bev);
119 
120  // This is called when the equivalent of 'accept' returns. The role
121  // of this function is to set up the SSL object and bev. If we
122  // support both SSL and non-SSL traffic simultaneously then we first
123  // wait for data to be ready and test the hello handshake to
124  // disambiguate between the kinds of traffic.
125  void accept_callback(AcceptRequest* request);
126 
127  // This is the continuation of 'accept_callback' that handles an SSL
128  // connection.
129  static void accept_SSL_callback(AcceptRequest* request);
130 
131  // This function peeks at the data on an accepted socket to see if
132  // there is an SSL handshake or not. It then dispatches to the
133  // SSL handling function or creates a non-SSL socket.
134  static void peek_callback(evutil_socket_t fd, short what, void* arg);
135 
136  // The following are function pairs of static functions to member
137  // functions. The static functions test and hold the weak pointer to
138  // the socket before calling the member functions. This protects
139  // against the socket being destroyed before the event loop calls
140  // the callbacks.
141  static void recv_callback(bufferevent* bev, void* arg);
142  void recv_callback();
143 
144  static void send_callback(bufferevent* bev, void* arg);
145  void send_callback();
146 
147  static void event_callback(bufferevent* bev, short events, void* arg);
148  void event_callback(short events);
149 
150  bufferevent* bev;
151 
152  evconnlistener* listener;
153 
154  // Protects the following instance variables.
155  std::atomic_flag lock = ATOMIC_FLAG_INIT;
156  Owned<RecvRequest> recv_request;
157  Owned<SendRequest> send_request;
158  Owned<ConnectRequest> connect_request;
159 
160  // Indicates whether or not an EOF has been received on this socket.
161  // Our accesses to this member are not synchronized because they all
162  // occur within the event loop, which runs on a single thread.
163  bool received_eof = false;
164 
165  // This is a weak pointer to 'this', i.e., ourselves, this class
166  // instance. We need this for our event loop callbacks because it's
167  // possible that we'll actually want to cleanup this socket impl
168  // before the event loop callback gets executed ... and we'll check
169  // in each event loop callback whether or not this weak_ptr is valid
170  // by attempting to upgrade it to shared_ptr. It is the
171  // responsibility of the event loop through the deferred lambda in
172  // the destructor to clean up this pointer.
173  // 1) It is a 'weak_ptr' as opposed to a 'shared_ptr' because we
174  // want to test whether the object is still around from within the
175  // event loop. If it was a 'shared_ptr' then we would be
176  // contributing to the lifetime of the object and would no longer be
177  // able to test the lifetime correctly.
178  // 2) This is a pointer to a 'weak_ptr' so that we can pass this
179  // through to the event loop through the C-interface. We need access
180  // to the 'weak_ptr' from outside the object (in the event loop) to
181  // test if the object is still alive. By maintaining this 'weak_ptr'
182  // on the heap we can be sure it is safe to access from the
183  // event loop until it is destroyed.
184  std::weak_ptr<LibeventSSLSocketImpl>* event_loop_handle;
185 
186  // This queue stores accepted sockets that are considered connected
187  // (either the SSL handshake has completed or the socket has been
188  // downgraded). The 'accept()' call returns sockets from this queue.
189  // We wrap the socket in a 'Future' so that we can pass failures or
190  // discards through.
192 
193  Option<net::IP> peer_ip;
194  Option<openssl::TLSClientConfig> client_config;
195 };
196 
197 } // namespace internal {
198 } // namespace network {
199 } // namespace process {
200 
201 #endif // __LIBEVENT_SSL_SOCKET_HPP__
Try< Bytes > size(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:130
Future< Response > request(const Request &request, bool streamedResponse=false)
Asynchronously sends an HTTP request to the process and returns the HTTP response once the entire res...
Definition: check.hpp:33
int_fd s
Definition: socket.hpp:246
Kind
Available kinds of implementations.
Definition: socket.hpp:67
Future< std::shared_ptr< SocketImpl > > accept() override
Returns an implementation corresponding to the next pending connection for the listening socket...
Future< Nothing > connect(const Address &address) override
static Try< std::shared_ptr< SocketImpl > > create(int_fd s)
Definition: address.hpp:324
Try< Nothing > listen(int backlog) override
Try< Address > address() const
Returns the Address with the assigned ip and assigned port.
SocketImpl::Kind kind() const override
Definition: libevent_ssl_socket.hpp:54
Implementation interface for a Socket.
Definition: socket.hpp:58
Definition: future.hpp:74
Protocol< PromiseRequest, PromiseResponse > promise
Definition: attributes.hpp:24
Definition: queue.hpp:29
Definition: executor.hpp:48
Definition: libevent_ssl_socket.hpp:32
Future< size_t > sendfile(int_fd fd, off_t offset, size_t size) override
Try< Netlink< struct nl_sock > > socket(int protocol=NETLINK_ROUTE)
Definition: internal.hpp:91
int int_fd
Definition: int_fd.hpp:35
Future< size_t > send(const char *data, size_t size) override
Try< Nothing, SocketError > shutdown(int how) override
Shuts down the socket.
Future< size_t > recv(char *data, size_t size) override