9090#define CPPHTTPLIB_TCP_NODELAY false
9191#endif
9292
93+ #ifndef CPPHTTPLIB_IPV6_V6ONLY
94+ #define CPPHTTPLIB_IPV6_V6ONLY false
95+ #endif
96+
9397#ifndef CPPHTTPLIB_RECV_BUFSIZ
9498#define CPPHTTPLIB_RECV_BUFSIZ size_t (16384u )
9599#endif
@@ -900,6 +904,7 @@ class Server {
900904
901905 Server &set_address_family (int family);
902906 Server &set_tcp_nodelay (bool on);
907+ Server &set_ipv6_v6only (bool on);
903908 Server &set_socket_options (SocketOptions socket_options);
904909
905910 Server &set_default_headers (Headers headers);
@@ -1040,6 +1045,7 @@ class Server {
10401045
10411046 int address_family_ = AF_UNSPEC;
10421047 bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
1048+ bool ipv6_v6only_ = CPPHTTPLIB_IPV6_V6ONLY;
10431049 SocketOptions socket_options_ = default_socket_options;
10441050
10451051 Headers default_headers_;
@@ -1322,6 +1328,7 @@ class ClientImpl {
13221328
13231329 void set_address_family (int family);
13241330 void set_tcp_nodelay (bool on);
1331+ void set_ipv6_v6only (bool on);
13251332 void set_socket_options (SocketOptions socket_options);
13261333
13271334 void set_connection_timeout (time_t sec, time_t usec = 0 );
@@ -1459,6 +1466,7 @@ class ClientImpl {
14591466
14601467 int address_family_ = AF_UNSPEC;
14611468 bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
1469+ bool ipv6_v6only_ = CPPHTTPLIB_IPV6_V6ONLY;
14621470 SocketOptions socket_options_ = nullptr ;
14631471
14641472 bool compress_ = false ;
@@ -1968,19 +1976,19 @@ inline ssize_t Stream::write_format(const char *fmt, const Args &...args) {
19681976}
19691977
19701978inline void default_socket_options (socket_t sock) {
1971- int yes = 1 ;
1979+ int opt = 1 ;
19721980#ifdef _WIN32
19731981 setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
1974- reinterpret_cast <const char *>(&yes ), sizeof (yes ));
1982+ reinterpret_cast <const char *>(&opt ), sizeof (opt ));
19751983 setsockopt (sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
1976- reinterpret_cast <const char *>(&yes ), sizeof (yes ));
1984+ reinterpret_cast <const char *>(&opt ), sizeof (opt ));
19771985#else
19781986#ifdef SO_REUSEPORT
19791987 setsockopt (sock, SOL_SOCKET, SO_REUSEPORT,
1980- reinterpret_cast <const void *>(&yes ), sizeof (yes ));
1988+ reinterpret_cast <const void *>(&opt ), sizeof (opt ));
19811989#else
19821990 setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
1983- reinterpret_cast <const void *>(&yes ), sizeof (yes ));
1991+ reinterpret_cast <const void *>(&opt ), sizeof (opt ));
19841992#endif
19851993#endif
19861994}
@@ -2219,12 +2227,15 @@ bool process_client_socket(socket_t sock, time_t read_timeout_sec,
22192227 time_t write_timeout_usec,
22202228 std::function<bool (Stream &)> callback);
22212229
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);
22282239
22292240const char *get_header_value (const Headers &headers, const std::string &key,
22302241 const char *def, size_t id);
@@ -3239,7 +3250,7 @@ inline int shutdown_socket(socket_t sock) {
32393250template <typename BindOrConnect>
32403251socket_t create_socket (const std::string &host, const std::string &ip, int port,
32413252 int address_family, int socket_flags, bool tcp_nodelay,
3242- SocketOptions socket_options,
3253+ bool ipv6_v6only, SocketOptions socket_options,
32433254 BindOrConnect bind_or_connect) {
32443255 // Get address info
32453256 const char *node = nullptr ;
@@ -3350,29 +3361,29 @@ socket_t create_socket(const std::string &host, const std::string &ip, int port,
33503361#endif
33513362
33523363 if (tcp_nodelay) {
3353- auto yes = 1 ;
3364+ auto opt = 1 ;
33543365#ifdef _WIN32
33553366 setsockopt (sock, IPPROTO_TCP, TCP_NODELAY,
3356- reinterpret_cast <const char *>(&yes ), sizeof (yes ));
3367+ reinterpret_cast <const char *>(&opt ), sizeof (opt ));
33573368#else
33583369 setsockopt (sock, IPPROTO_TCP, TCP_NODELAY,
3359- reinterpret_cast <const void *>(&yes ), sizeof (yes ));
3370+ reinterpret_cast <const void *>(&opt ), sizeof (opt ));
33603371#endif
33613372 }
33623373
3363- if (socket_options) { socket_options (sock); }
3364-
33653374 if (rp->ai_family == AF_INET6) {
3366- auto no = 0 ;
3375+ auto opt = ipv6_v6only ? 1 : 0 ;
33673376#ifdef _WIN32
33683377 setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY,
3369- reinterpret_cast <const char *>(&no ), sizeof (no ));
3378+ reinterpret_cast <const char *>(&opt ), sizeof (opt ));
33703379#else
33713380 setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY,
3372- reinterpret_cast <const void *>(&no ), sizeof (no ));
3381+ reinterpret_cast <const void *>(&opt ), sizeof (opt ));
33733382#endif
33743383 }
33753384
3385+ if (socket_options) { socket_options (sock); }
3386+
33763387 // bind or connect
33773388 auto quit = false ;
33783389 if (bind_or_connect (sock, *rp, quit)) {
@@ -3477,12 +3488,14 @@ inline std::string if2ip(int address_family, const std::string &ifn) {
34773488
34783489inline socket_t create_client_socket (
34793490 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,
34833495 time_t write_timeout_usec, const std::string &intf, Error &error) {
34843496 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),
34863499 [&](socket_t sock2, struct addrinfo &ai, bool &quit) -> bool {
34873500 if (!intf.empty ()) {
34883501#ifdef USE_IF2IP
@@ -6061,6 +6074,11 @@ inline Server &Server::set_tcp_nodelay(bool on) {
60616074 return *this ;
60626075}
60636076
6077+ inline Server &Server::set_ipv6_v6only (bool on) {
6078+ ipv6_v6only_ = on;
6079+ return *this ;
6080+ }
6081+
60646082inline Server &Server::set_socket_options (SocketOptions socket_options) {
60656083 socket_options_ = std::move (socket_options);
60666084 return *this ;
@@ -6491,7 +6509,7 @@ Server::create_server_socket(const std::string &host, int port,
64916509 SocketOptions socket_options) const {
64926510 return detail::create_socket (
64936511 host, std::string (), port, address_family_, socket_flags, tcp_nodelay_,
6494- std::move (socket_options),
6512+ ipv6_v6only_, std::move (socket_options),
64956513 [](socket_t sock, struct addrinfo &ai, bool & /* quit*/ ) -> bool {
64966514 if (::bind (sock, ai.ai_addr , static_cast <socklen_t >(ai.ai_addrlen ))) {
64976515 return false ;
@@ -7041,6 +7059,7 @@ inline void ClientImpl::copy_settings(const ClientImpl &rhs) {
70417059 url_encode_ = rhs.url_encode_ ;
70427060 address_family_ = rhs.address_family_ ;
70437061 tcp_nodelay_ = rhs.tcp_nodelay_ ;
7062+ ipv6_v6only_ = rhs.ipv6_v6only_ ;
70447063 socket_options_ = rhs.socket_options_ ;
70457064 compress_ = rhs.compress_ ;
70467065 decompress_ = rhs.decompress_ ;
@@ -7069,9 +7088,9 @@ inline socket_t ClientImpl::create_client_socket(Error &error) const {
70697088 if (!proxy_host_.empty () && proxy_port_ != -1 ) {
70707089 return detail::create_client_socket (
70717090 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);
70757094 }
70767095
70777096 // Check is custom IP specified for host_
@@ -7080,10 +7099,10 @@ inline socket_t ClientImpl::create_client_socket(Error &error) const {
70807099 if (it != addr_map_.end ()) { ip = it->second ; }
70817100
70827101 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);
70877106}
70887107
70897108inline bool ClientImpl::create_and_connect_socket (Socket &socket,
@@ -8487,6 +8506,8 @@ inline void ClientImpl::set_address_family(int family) {
84878506
84888507inline void ClientImpl::set_tcp_nodelay (bool on) { tcp_nodelay_ = on; }
84898508
8509+ inline void ClientImpl::set_ipv6_v6only (bool on) { ipv6_v6only_ = on; }
8510+
84908511inline void ClientImpl::set_socket_options (SocketOptions socket_options) {
84918512 socket_options_ = std::move (socket_options);
84928513}
0 commit comments