1717
1818#include < boost/system/error_code.hpp>
1919#include < boost/asio/ip/address.hpp>
20+ #include < boost/asio/error.hpp>
21+
22+ #include < boost/system/error_code.hpp>
23+ #include < boost/system/result.hpp>
24+ #include < boost/config.hpp>
25+
26+ #if defined(__linux__) || defined(__APPLE__)
27+ # include < sys/socket.h>
28+ #elif defined(BOOST_WINDOWS)
29+ # include < mstcpip.h>
30+ #endif
2031
2132namespace proxy {
2233
2334 namespace net = boost::asio;
2435
36+
37+ inline void make_error_code (boost::system::error_code& ec, bool err) noexcept
38+ {
39+ if (!err)
40+ {
41+ ec = {};
42+ }
43+ else
44+ {
45+ #if defined(BOOST_WINDOWS)
46+ ec = boost::system::error_code (WSAGetLastError (), net::error::get_system_category ());
47+ #else
48+ ec = boost::system::error_code (errno, net::error::get_system_category ());
49+ #endif
50+ }
51+ }
52+
2553 // 检测 host 是否是域名或主机名, 如果是域名则返回 true, 否则返回 false.
2654 inline bool is_hostname (std::string_view host) noexcept
2755 {
@@ -38,6 +66,70 @@ namespace proxy {
3866 static std::random_device rd;
3967 return rd;
4068 }
69+
70+ #if defined(BOOST_WINDOWS)
71+ // 启用 TCP Keep-Alive 选项.
72+ inline boost::system::result<bool > set_tcp_keepalive (SOCKET fd) noexcept
73+ {
74+ boost::system::error_code ec;
75+ int ret = 0 ;
76+
77+ struct tcp_keepalive alive;
78+ alive.onoff = 1 ;
79+ alive.keepalivetime = 30000 ; // 30 seconds
80+ alive.keepaliveinterval = 15000 ; // 15 seconds
81+ ret = ::WSAIoctl (fd, SIO_KEEPALIVE_VALS , &alive, sizeof (alive), NULL , 0 , NULL , NULL , NULL );
82+ make_error_code (ec, ret != 0 );
83+ if (ret != 0 )
84+ return ec;
85+ return true ;
86+ }
87+ #else
88+ // 启用 TCP Keep-Alive 选项.
89+ inline boost::system::result<bool > set_tcp_keepalive (int fd) noexcept
90+ {
91+ boost::system::error_code ec;
92+ int ret = 0 ;
93+ int keepalive = 1 ;
94+
95+ ret = ::setsockopt (fd, SOL_SOCKET , SO_KEEPALIVE , &keepalive, sizeof (keepalive));
96+ make_error_code (ec, ret != 0 );
97+ if (ret != 0 )
98+ return ec;
99+
100+ int idle_time = 30 ; // 30 seconds
101+ ret = ::setsockopt (fd, IPPROTO_TCP , TCP_KEEPIDLE , &idle_time, sizeof (idle_time));
102+ make_error_code (ec, ret != 0 );
103+ if (ret != 0 )
104+ return ec;
105+
106+ int interval = 15 ; // 15 seconds
107+ ret = ::setsockopt (fd, IPPROTO_TCP , TCP_KEEPINTVL , &interval, sizeof (interval));
108+ make_error_code (ec, ret != 0 );
109+ if (ret != 0 )
110+ return ec;
111+
112+ int maxpkt = 3 ; // 3 probes
113+ ret = ::setsockopt (fd, IPPROTO_TCP , TCP_KEEPCNT , &maxpkt, sizeof (maxpkt));
114+ make_error_code (ec, ret != 0 );
115+ if (ret != 0 )
116+ return ec;
117+
118+ return true ;
119+ }
120+ #endif
121+
122+ inline boost::system::result<bool > set_socket_mark (int fd, uint32_t mark) noexcept
123+ {
124+ boost::system::error_code ec;
125+ #if defined(__linux__)
126+ int ret = ::setsockopt (fd, SOL_SOCKET , SO_MARK , &mark, sizeof (uint32_t ));
127+ make_error_code (ec, ret != 0 );
128+ if (ret != 0 )
129+ return ec;
130+ #endif
131+ return true ;
132+ }
41133}
42134
43135#endif // INCLUDE__2026_06_08__PROXY_UTIL_HPP
0 commit comments