aboutsummaryrefslogtreecommitdiff
path: root/src/zenhttp/servers/asio_socket_traits.h
blob: 25aeaa24ef0859e5336c8027a71c5078ad0b4a3e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

ZEN_THIRD_PARTY_INCLUDES_START
#include <asio.hpp>
#if ZEN_USE_OPENSSL
#	include <asio/ssl.hpp>
#endif
ZEN_THIRD_PARTY_INCLUDES_END

namespace zen::asio_http {

/**
 * Traits for abstracting socket shutdown/close across plain TCP, Unix domain, and SSL sockets.
 * SSL sockets need lowest_layer() access and have different shutdown semantics.
 */
template<typename SocketType>
struct SocketTraits
{
	/// SSL sockets cannot use zero-copy file send (TransmitFile/sendfile) because
	/// those bypass the encryption layer. This flag lets templated code fall back
	/// to reading-into-memory for SSL connections.
	static constexpr bool IsSslSocket = false;

	static void ShutdownReceive(SocketType& S, std::error_code& Ec) { S.shutdown(asio::socket_base::shutdown_receive, Ec); }

	static void ShutdownBoth(SocketType& S, std::error_code& Ec) { S.shutdown(asio::socket_base::shutdown_both, Ec); }

	static void Close(SocketType& S, std::error_code& Ec) { S.close(Ec); }
};

#if ZEN_USE_OPENSSL
using SslSocket = asio::ssl::stream<asio::ip::tcp::socket>;

template<>
struct SocketTraits<SslSocket>
{
	static constexpr bool IsSslSocket = true;

	static void ShutdownReceive(SslSocket& S, std::error_code& Ec) { S.lowest_layer().shutdown(asio::socket_base::shutdown_receive, Ec); }

	static void ShutdownBoth(SslSocket& S, std::error_code& Ec)
	{
		// Best-effort SSL close_notify, then TCP shutdown
		S.shutdown(Ec);
		S.lowest_layer().shutdown(asio::socket_base::shutdown_both, Ec);
	}

	static void Close(SslSocket& S, std::error_code& Ec) { S.lowest_layer().close(Ec); }
};
#endif

}  // namespace zen::asio_http