Skip to content

Commit f048510

Browse files
authored
fix(nvhttp): wrap TLS socket to ensure graceful closure (#3077)
1 parent e15fd55 commit f048510

File tree

1 file changed

+39
-20
lines changed

1 file changed

+39
-20
lines changed

src/nvhttp.cpp

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,38 @@ namespace nvhttp {
4444

4545
crypto::cert_chain_t cert_chain;
4646

47-
class SunshineHttpsServer: public SimpleWeb::Server<SimpleWeb::HTTPS> {
47+
class SunshineHTTPS: public SimpleWeb::HTTPS {
4848
public:
49-
SunshineHttpsServer(const std::string &certification_file, const std::string &private_key_file):
50-
SimpleWeb::Server<SimpleWeb::HTTPS>::Server(certification_file, private_key_file) {}
49+
SunshineHTTPS(boost::asio::io_service &io_service, boost::asio::ssl::context &ctx):
50+
SimpleWeb::HTTPS(io_service, ctx) {}
51+
52+
virtual ~SunshineHTTPS() {
53+
// Gracefully shutdown the TLS connection
54+
SimpleWeb::error_code ec;
55+
shutdown(ec);
56+
}
57+
};
58+
59+
class SunshineHTTPSServer: public SimpleWeb::ServerBase<SunshineHTTPS> {
60+
public:
61+
SunshineHTTPSServer(const std::string &certification_file, const std::string &private_key_file):
62+
ServerBase<SunshineHTTPS>::ServerBase(443),
63+
context(boost::asio::ssl::context::tls_server) {
64+
// Disabling TLS 1.0 and 1.1 (see RFC 8996)
65+
context.set_options(boost::asio::ssl::context::no_tlsv1);
66+
context.set_options(boost::asio::ssl::context::no_tlsv1_1);
67+
context.use_certificate_chain_file(certification_file);
68+
context.use_private_key_file(private_key_file, boost::asio::ssl::context::pem);
69+
}
5170

5271
std::function<int(SSL *)> verify;
5372
std::function<void(std::shared_ptr<Response>, std::shared_ptr<Request>)> on_verify_failed;
5473

5574
protected:
75+
boost::asio::ssl::context context;
76+
5677
void
5778
after_bind() override {
58-
SimpleWeb::Server<SimpleWeb::HTTPS>::after_bind();
59-
6079
if (verify) {
6180
context.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert | boost::asio::ssl::verify_client_once);
6281
context.set_verify_callback([](int verified, boost::asio::ssl::verify_context &ctx) {
@@ -108,7 +127,7 @@ namespace nvhttp {
108127
}
109128
};
110129

111-
using https_server_t = SunshineHttpsServer;
130+
using https_server_t = SunshineHTTPSServer;
112131
using http_server_t = SimpleWeb::Server<SimpleWeb::HTTP>;
113132

114133
struct conf_intern_t {
@@ -142,7 +161,7 @@ namespace nvhttp {
142161
struct {
143162
util::Either<
144163
std::shared_ptr<typename SimpleWeb::ServerBase<SimpleWeb::HTTP>::Response>,
145-
std::shared_ptr<typename SimpleWeb::ServerBase<SimpleWeb::HTTPS>::Response>>
164+
std::shared_ptr<typename SimpleWeb::ServerBase<SunshineHTTPS>::Response>>
146165
response;
147166
std::string salt;
148167
} async_insert_pin;
@@ -154,8 +173,8 @@ namespace nvhttp {
154173
std::atomic<uint32_t> session_id_counter;
155174

156175
using args_t = SimpleWeb::CaseInsensitiveMultimap;
157-
using resp_https_t = std::shared_ptr<typename SimpleWeb::ServerBase<SimpleWeb::HTTPS>::Response>;
158-
using req_https_t = std::shared_ptr<typename SimpleWeb::ServerBase<SimpleWeb::HTTPS>::Request>;
176+
using resp_https_t = std::shared_ptr<typename SimpleWeb::ServerBase<SunshineHTTPS>::Response>;
177+
using req_https_t = std::shared_ptr<typename SimpleWeb::ServerBase<SunshineHTTPS>::Request>;
159178
using resp_http_t = std::shared_ptr<typename SimpleWeb::ServerBase<SimpleWeb::HTTP>::Response>;
160179
using req_http_t = std::shared_ptr<typename SimpleWeb::ServerBase<SimpleWeb::HTTP>::Request>;
161180

@@ -483,7 +502,7 @@ namespace nvhttp {
483502
struct tunnel;
484503

485504
template <>
486-
struct tunnel<SimpleWeb::HTTPS> {
505+
struct tunnel<SunshineHTTPS> {
487506
static auto constexpr to_string = "HTTPS"sv;
488507
};
489508

@@ -671,7 +690,7 @@ namespace nvhttp {
671690
print_req<T>(request);
672691

673692
int pair_status = 0;
674-
if constexpr (std::is_same_v<SimpleWeb::HTTPS, T>) {
693+
if constexpr (std::is_same_v<SunshineHTTPS, T>) {
675694
auto args = request->parse_query_string();
676695
auto clientID = args.find("uniqueid"s);
677696

@@ -696,7 +715,7 @@ namespace nvhttp {
696715

697716
// Only include the MAC address for requests sent from paired clients over HTTPS.
698717
// For HTTP requests, use a placeholder MAC address that Moonlight knows to ignore.
699-
if constexpr (std::is_same_v<SimpleWeb::HTTPS, T>) {
718+
if constexpr (std::is_same_v<SunshineHTTPS, T>) {
700719
tree.put("root.mac", platf::get_mac_address(net::addr_to_normalized_string(local_endpoint.address())));
701720
}
702721
else {
@@ -777,7 +796,7 @@ namespace nvhttp {
777796

778797
void
779798
applist(resp_https_t response, req_https_t request) {
780-
print_req<SimpleWeb::HTTPS>(request);
799+
print_req<SunshineHTTPS>(request);
781800

782801
pt::ptree tree;
783802

@@ -806,7 +825,7 @@ namespace nvhttp {
806825

807826
void
808827
launch(bool &host_audio, resp_https_t response, req_https_t request) {
809-
print_req<SimpleWeb::HTTPS>(request);
828+
print_req<SunshineHTTPS>(request);
810829

811830
pt::ptree tree;
812831
auto g = util::fail_guard([&]() {
@@ -899,7 +918,7 @@ namespace nvhttp {
899918

900919
void
901920
resume(bool &host_audio, resp_https_t response, req_https_t request) {
902-
print_req<SimpleWeb::HTTPS>(request);
921+
print_req<SunshineHTTPS>(request);
903922

904923
pt::ptree tree;
905924
auto g = util::fail_guard([&]() {
@@ -985,7 +1004,7 @@ namespace nvhttp {
9851004

9861005
void
9871006
cancel(resp_https_t response, req_https_t request) {
988-
print_req<SimpleWeb::HTTPS>(request);
1007+
print_req<SunshineHTTPS>(request);
9891008

9901009
pt::ptree tree;
9911010
auto g = util::fail_guard([&]() {
@@ -1016,7 +1035,7 @@ namespace nvhttp {
10161035

10171036
void
10181037
appasset(resp_https_t response, req_https_t request) {
1019-
print_req<SimpleWeb::HTTPS>(request);
1038+
print_req<SunshineHTTPS>(request);
10201039

10211040
auto args = request->parse_query_string();
10221041
auto app_image = proc::proc.get_app_image(util::from_view(get_arg(args, "appid")));
@@ -1109,9 +1128,9 @@ namespace nvhttp {
11091128
tree.put("root.<xmlattr>.status_message"s, "The client is not authorized. Certificate verification failed."s);
11101129
};
11111130

1112-
https_server.default_resource["GET"] = not_found<SimpleWeb::HTTPS>;
1113-
https_server.resource["^/serverinfo$"]["GET"] = serverinfo<SimpleWeb::HTTPS>;
1114-
https_server.resource["^/pair$"]["GET"] = [&add_cert](auto resp, auto req) { pair<SimpleWeb::HTTPS>(add_cert, resp, req); };
1131+
https_server.default_resource["GET"] = not_found<SunshineHTTPS>;
1132+
https_server.resource["^/serverinfo$"]["GET"] = serverinfo<SunshineHTTPS>;
1133+
https_server.resource["^/pair$"]["GET"] = [&add_cert](auto resp, auto req) { pair<SunshineHTTPS>(add_cert, resp, req); };
11151134
https_server.resource["^/applist$"]["GET"] = applist;
11161135
https_server.resource["^/appasset$"]["GET"] = appasset;
11171136
https_server.resource["^/launch$"]["GET"] = [&host_audio](auto resp, auto req) { launch(host_audio, resp, req); };

0 commit comments

Comments
 (0)