Branch data Line data Source code
1 : : /*
2 : : * Copyright 2025 Jinwoo Sung
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at
7 : : *
8 : : * http://www.apache.org/licenses/LICENSE-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : :
17 : : #include "wirestead/transport/tcp_server/ssl_tcp_socket.hpp"
18 : :
19 : : #ifdef WIRESTEAD_TLS_ENABLED
20 : :
21 : : #include <openssl/ssl.h>
22 : :
23 : : #include <utility>
24 : :
25 : : namespace wirestead {
26 : : namespace transport {
27 : :
28 : 32 : SslTcpSocket::SslTcpSocket(tcp::socket sock, std::shared_ptr<ssl::context> context)
29 : 32 : : context_(std::move(context)), stream_(std::move(sock), *context_) {}
30 : :
31 : 4 : void SslTcpSocket::async_read_some(const net::mutable_buffer& buffer,
32 : : std::function<void(const boost::system::error_code&, std::size_t)> handler) {
33 : 4 : stream_.async_read_some(buffer, std::move(handler));
34 : 4 : }
35 : :
36 : 0 : void SslTcpSocket::async_write(const net::const_buffer& buffer,
37 : : std::function<void(const boost::system::error_code&, std::size_t)> handler) {
38 : 0 : net::async_write(stream_, buffer, std::move(handler));
39 : 0 : }
40 : :
41 : 2 : void SslTcpSocket::async_write(const std::vector<net::const_buffer>& buffers,
42 : : std::function<void(const boost::system::error_code&, std::size_t)> handler) {
43 : 2 : net::async_write(stream_, buffers, std::move(handler));
44 : 2 : }
45 : :
46 : 32 : void SslTcpSocket::async_handshake(std::function<void(const boost::system::error_code&)> handler) {
47 : 32 : stream_.async_handshake(ssl::stream_base::server,
48 : 64 : [handler = std::move(handler)](const boost::system::error_code& ec) {
49 [ + - ]: 32 : if (handler) handler(ec);
50 : 32 : });
51 : 32 : }
52 : :
53 : : // Sends close_notify without waiting for the peer's.
54 : : //
55 : : // ssl::stream::shutdown() is the obvious call here and is wrong: it runs the
56 : : // full bidirectional exchange and blocks until the peer answers. Measured
57 : : // against two peers that completed the handshake and then stopped reading,
58 : : // stop() went from 0 ms to 8035 ms - an io thread parked on a peer under no
59 : : // obligation to reply, for as long as it feels like not replying.
60 : : //
61 : : // SSL_shutdown's first call writes our close_notify and returns 0 rather than
62 : : // waiting for the reply; only a second call would block for it. One call is
63 : : // exactly the half we want. The peer sees a clean end of stream instead of a
64 : : // truncation, and a peer that never answers costs us nothing.
65 : 32 : void SslTcpSocket::shutdown(tcp::socket::shutdown_type what, boost::system::error_code& ec) {
66 : 32 : ::SSL_shutdown(stream_.native_handle());
67 : 32 : stream_.lowest_layer().shutdown(what, ec);
68 : 32 : }
69 : :
70 : 32 : void SslTcpSocket::close(boost::system::error_code& ec) { stream_.lowest_layer().close(ec); }
71 : :
72 : 0 : tcp::endpoint SslTcpSocket::remote_endpoint(boost::system::error_code& ec) const {
73 : 0 : return stream_.lowest_layer().remote_endpoint(ec);
74 : : }
75 : :
76 : : } // namespace transport
77 : : } // namespace wirestead
78 : :
79 : : #endif // WIRESTEAD_TLS_ENABLED
|