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