90
90
#define CPPHTTPLIB_TCP_NODELAY false
91
91
#endif
92
92
93
+ #ifndef CPPHTTPLIB_IPV6_V6ONLY
94
+ #define CPPHTTPLIB_IPV6_V6ONLY false
95
+ #endif
96
+
93
97
#ifndef CPPHTTPLIB_RECV_BUFSIZ
94
98
#define CPPHTTPLIB_RECV_BUFSIZ size_t (16384u )
95
99
#endif
@@ -900,6 +904,7 @@ class Server {
900
904
901
905
Server &set_address_family (int family);
902
906
Server &set_tcp_nodelay (bool on);
907
+ Server &set_ipv6_v6only (bool on);
903
908
Server &set_socket_options (SocketOptions socket_options);
904
909
905
910
Server &set_default_headers (Headers headers);
@@ -1040,6 +1045,7 @@ class Server {
1040
1045
1041
1046
int address_family_ = AF_UNSPEC;
1042
1047
bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
1048
+ bool ipv6_v6only_ = CPPHTTPLIB_IPV6_V6ONLY;
1043
1049
SocketOptions socket_options_ = default_socket_options;
1044
1050
1045
1051
Headers default_headers_;
@@ -1322,6 +1328,7 @@ class ClientImpl {
1322
1328
1323
1329
void set_address_family (int family);
1324
1330
void set_tcp_nodelay (bool on);
1331
+ void set_ipv6_v6only (bool on);
1325
1332
void set_socket_options (SocketOptions socket_options);
1326
1333
1327
1334
void set_connection_timeout (time_t sec, time_t usec = 0 );
@@ -1459,6 +1466,7 @@ class ClientImpl {
1459
1466
1460
1467
int address_family_ = AF_UNSPEC;
1461
1468
bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
1469
+ bool ipv6_v6only_ = CPPHTTPLIB_IPV6_V6ONLY;
1462
1470
SocketOptions socket_options_ = nullptr ;
1463
1471
1464
1472
bool compress_ = false ;
@@ -1968,19 +1976,19 @@ inline ssize_t Stream::write_format(const char *fmt, const Args &...args) {
1968
1976
}
1969
1977
1970
1978
inline void default_socket_options (socket_t sock) {
1971
- int yes = 1 ;
1979
+ int opt = 1 ;
1972
1980
#ifdef _WIN32
1973
1981
setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
1974
- reinterpret_cast <const char *>(&yes ), sizeof (yes ));
1982
+ reinterpret_cast <const char *>(&opt ), sizeof (opt ));
1975
1983
setsockopt (sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
1976
- reinterpret_cast <const char *>(&yes ), sizeof (yes ));
1984
+ reinterpret_cast <const char *>(&opt ), sizeof (opt ));
1977
1985
#else
1978
1986
#ifdef SO_REUSEPORT
1979
1987
setsockopt (sock, SOL_SOCKET, SO_REUSEPORT,
1980
- reinterpret_cast <const void *>(&yes ), sizeof (yes ));
1988
+ reinterpret_cast <const void *>(&opt ), sizeof (opt ));
1981
1989
#else
1982
1990
setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
1983
- reinterpret_cast <const void *>(&yes ), sizeof (yes ));
1991
+ reinterpret_cast <const void *>(&opt ), sizeof (opt ));
1984
1992
#endif
1985
1993
#endif
1986
1994
}
@@ -2219,12 +2227,15 @@ bool process_client_socket(socket_t sock, time_t read_timeout_sec,
2219
2227
time_t write_timeout_usec,
2220
2228
std::function<bool (Stream &)> callback);
2221
2229
2222
- socket_t create_client_socket (
2223
- const std::string &host, const std::string &ip, int port,
2224
- int address_family, bool tcp_nodelay, SocketOptions socket_options,
2225
- time_t connection_timeout_sec, time_t connection_timeout_usec,
2226
- time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec,
2227
- time_t write_timeout_usec, const std::string &intf, Error &error);
2230
+ socket_t create_client_socket (const std::string &host, const std::string &ip,
2231
+ int port, int address_family, bool tcp_nodelay,
2232
+ bool ipv6_v6only, SocketOptions socket_options,
2233
+ time_t connection_timeout_sec,
2234
+ time_t connection_timeout_usec,
2235
+ time_t read_timeout_sec, time_t read_timeout_usec,
2236
+ time_t write_timeout_sec,
2237
+ time_t write_timeout_usec,
2238
+ const std::string &intf, Error &error);
2228
2239
2229
2240
const char *get_header_value (const Headers &headers, const std::string &key,
2230
2241
const char *def, size_t id);
@@ -3239,7 +3250,7 @@ inline int shutdown_socket(socket_t sock) {
3239
3250
template <typename BindOrConnect>
3240
3251
socket_t create_socket (const std::string &host, const std::string &ip, int port,
3241
3252
int address_family, int socket_flags, bool tcp_nodelay,
3242
- SocketOptions socket_options,
3253
+ bool ipv6_v6only, SocketOptions socket_options,
3243
3254
BindOrConnect bind_or_connect) {
3244
3255
// Get address info
3245
3256
const char *node = nullptr ;
@@ -3350,29 +3361,29 @@ socket_t create_socket(const std::string &host, const std::string &ip, int port,
3350
3361
#endif
3351
3362
3352
3363
if (tcp_nodelay) {
3353
- auto yes = 1 ;
3364
+ auto opt = 1 ;
3354
3365
#ifdef _WIN32
3355
3366
setsockopt (sock, IPPROTO_TCP, TCP_NODELAY,
3356
- reinterpret_cast <const char *>(&yes ), sizeof (yes ));
3367
+ reinterpret_cast <const char *>(&opt ), sizeof (opt ));
3357
3368
#else
3358
3369
setsockopt (sock, IPPROTO_TCP, TCP_NODELAY,
3359
- reinterpret_cast <const void *>(&yes ), sizeof (yes ));
3370
+ reinterpret_cast <const void *>(&opt ), sizeof (opt ));
3360
3371
#endif
3361
3372
}
3362
3373
3363
- if (socket_options) { socket_options (sock); }
3364
-
3365
3374
if (rp->ai_family == AF_INET6) {
3366
- auto no = 0 ;
3375
+ auto opt = ipv6_v6only ? 1 : 0 ;
3367
3376
#ifdef _WIN32
3368
3377
setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY,
3369
- reinterpret_cast <const char *>(&no ), sizeof (no ));
3378
+ reinterpret_cast <const char *>(&opt ), sizeof (opt ));
3370
3379
#else
3371
3380
setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY,
3372
- reinterpret_cast <const void *>(&no ), sizeof (no ));
3381
+ reinterpret_cast <const void *>(&opt ), sizeof (opt ));
3373
3382
#endif
3374
3383
}
3375
3384
3385
+ if (socket_options) { socket_options (sock); }
3386
+
3376
3387
// bind or connect
3377
3388
auto quit = false ;
3378
3389
if (bind_or_connect (sock, *rp, quit)) {
@@ -3477,12 +3488,14 @@ inline std::string if2ip(int address_family, const std::string &ifn) {
3477
3488
3478
3489
inline socket_t create_client_socket (
3479
3490
const std::string &host, const std::string &ip, int port,
3480
- int address_family, bool tcp_nodelay, SocketOptions socket_options,
3481
- time_t connection_timeout_sec, time_t connection_timeout_usec,
3482
- time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec,
3491
+ int address_family, bool tcp_nodelay, bool ipv6_v6only,
3492
+ SocketOptions socket_options, time_t connection_timeout_sec,
3493
+ time_t connection_timeout_usec, time_t read_timeout_sec,
3494
+ time_t read_timeout_usec, time_t write_timeout_sec,
3483
3495
time_t write_timeout_usec, const std::string &intf, Error &error) {
3484
3496
auto sock = create_socket (
3485
- host, ip, port, address_family, 0 , tcp_nodelay, std::move (socket_options),
3497
+ host, ip, port, address_family, 0 , tcp_nodelay, ipv6_v6only,
3498
+ std::move (socket_options),
3486
3499
[&](socket_t sock2, struct addrinfo &ai, bool &quit) -> bool {
3487
3500
if (!intf.empty ()) {
3488
3501
#ifdef USE_IF2IP
@@ -6061,6 +6074,11 @@ inline Server &Server::set_tcp_nodelay(bool on) {
6061
6074
return *this ;
6062
6075
}
6063
6076
6077
+ inline Server &Server::set_ipv6_v6only (bool on) {
6078
+ ipv6_v6only_ = on;
6079
+ return *this ;
6080
+ }
6081
+
6064
6082
inline Server &Server::set_socket_options (SocketOptions socket_options) {
6065
6083
socket_options_ = std::move (socket_options);
6066
6084
return *this ;
@@ -6491,7 +6509,7 @@ Server::create_server_socket(const std::string &host, int port,
6491
6509
SocketOptions socket_options) const {
6492
6510
return detail::create_socket (
6493
6511
host, std::string (), port, address_family_, socket_flags, tcp_nodelay_,
6494
- std::move (socket_options),
6512
+ ipv6_v6only_, std::move (socket_options),
6495
6513
[](socket_t sock, struct addrinfo &ai, bool & /* quit*/ ) -> bool {
6496
6514
if (::bind (sock, ai.ai_addr , static_cast <socklen_t >(ai.ai_addrlen ))) {
6497
6515
return false ;
@@ -7041,6 +7059,7 @@ inline void ClientImpl::copy_settings(const ClientImpl &rhs) {
7041
7059
url_encode_ = rhs.url_encode_ ;
7042
7060
address_family_ = rhs.address_family_ ;
7043
7061
tcp_nodelay_ = rhs.tcp_nodelay_ ;
7062
+ ipv6_v6only_ = rhs.ipv6_v6only_ ;
7044
7063
socket_options_ = rhs.socket_options_ ;
7045
7064
compress_ = rhs.compress_ ;
7046
7065
decompress_ = rhs.decompress_ ;
@@ -7069,9 +7088,9 @@ inline socket_t ClientImpl::create_client_socket(Error &error) const {
7069
7088
if (!proxy_host_.empty () && proxy_port_ != -1 ) {
7070
7089
return detail::create_client_socket (
7071
7090
proxy_host_, std::string (), proxy_port_, address_family_, tcp_nodelay_,
7072
- socket_options_, connection_timeout_sec_, connection_timeout_usec_ ,
7073
- read_timeout_sec_, read_timeout_usec_, write_timeout_sec_ ,
7074
- write_timeout_usec_, interface_, error);
7091
+ ipv6_v6only_, socket_options_, connection_timeout_sec_ ,
7092
+ connection_timeout_usec_, read_timeout_sec_, read_timeout_usec_ ,
7093
+ write_timeout_sec_, write_timeout_usec_, interface_, error);
7075
7094
}
7076
7095
7077
7096
// Check is custom IP specified for host_
@@ -7080,10 +7099,10 @@ inline socket_t ClientImpl::create_client_socket(Error &error) const {
7080
7099
if (it != addr_map_.end ()) { ip = it->second ; }
7081
7100
7082
7101
return detail::create_client_socket (
7083
- host_, ip, port_, address_family_, tcp_nodelay_, socket_options_ ,
7084
- connection_timeout_sec_, connection_timeout_usec_, read_timeout_sec_ ,
7085
- read_timeout_usec_, write_timeout_sec_, write_timeout_usec_, interface_ ,
7086
- error);
7102
+ host_, ip, port_, address_family_, tcp_nodelay_, ipv6_v6only_ ,
7103
+ socket_options_, connection_timeout_sec_, connection_timeout_usec_ ,
7104
+ read_timeout_sec_, read_timeout_usec_, write_timeout_sec_ ,
7105
+ write_timeout_usec_, interface_, error);
7087
7106
}
7088
7107
7089
7108
inline bool ClientImpl::create_and_connect_socket (Socket &socket,
@@ -8487,6 +8506,8 @@ inline void ClientImpl::set_address_family(int family) {
8487
8506
8488
8507
inline void ClientImpl::set_tcp_nodelay (bool on) { tcp_nodelay_ = on; }
8489
8508
8509
+ inline void ClientImpl::set_ipv6_v6only (bool on) { ipv6_v6only_ = on; }
8510
+
8490
8511
inline void ClientImpl::set_socket_options (SocketOptions socket_options) {
8491
8512
socket_options_ = std::move (socket_options);
8492
8513
}
0 commit comments