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