Browse Source

Fixed timeout issues

yhirose 4 years ago
parent
commit
21c529229c
2 changed files with 48 additions and 11 deletions
  1. 44 10
      httplib.h
  2. 4 1
      test/test.cc

+ 44 - 10
httplib.h

@@ -2091,8 +2091,9 @@ socket_t create_socket(const char *host, int port, int address_family,
   for (auto rp = result; rp; rp = rp->ai_next) {
     // Create a socket
 #ifdef _WIN32
-    auto sock = WSASocketW(rp->ai_family, rp->ai_socktype, rp->ai_protocol,
-                           nullptr, 0, WSA_FLAG_NO_HANDLE_INHERIT);
+    auto sock =
+        WSASocketW(rp->ai_family, rp->ai_socktype, rp->ai_protocol, nullptr, 0,
+                   WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
     /**
      * Since the WSA_FLAG_NO_HANDLE_INHERIT is only supported on Windows 7 SP1
      * and above the socket creation fails on older Windows Systems.
@@ -2214,11 +2215,12 @@ inline std::string if2ip(const std::string &ifn) {
 }
 #endif
 
-inline socket_t create_client_socket(const char *host, int port,
-                                     int address_family, bool tcp_nodelay,
-                                     SocketOptions socket_options,
-                                     time_t timeout_sec, time_t timeout_usec,
-                                     const std::string &intf, Error &error) {
+inline socket_t create_client_socket(
+    const char *host, int port, int address_family, bool tcp_nodelay,
+    SocketOptions socket_options, time_t connection_timeout_sec,
+    time_t connection_timeout_usec, time_t read_timeout_sec,
+    time_t read_timeout_usec, time_t write_timeout_sec,
+    time_t write_timeout_usec, const std::string &intf, Error &error) {
   auto sock = create_socket(
       host, port, address_family, 0, tcp_nodelay, std::move(socket_options),
       [&](socket_t sock, struct addrinfo &ai) -> bool {
@@ -2240,7 +2242,8 @@ inline socket_t create_client_socket(const char *host, int port,
 
         if (ret < 0) {
           if (is_connection_error() ||
-              !wait_until_socket_is_ready(sock, timeout_sec, timeout_usec)) {
+              !wait_until_socket_is_ready(sock, connection_timeout_sec,
+                                          connection_timeout_usec)) {
             close_socket(sock);
             error = Error::Connection;
             return false;
@@ -2248,6 +2251,21 @@ inline socket_t create_client_socket(const char *host, int port,
         }
 
         set_nonblocking(sock, false);
+
+        {
+          timeval tv;
+          tv.tv_sec = static_cast<long>(read_timeout_sec);
+          tv.tv_usec = static_cast<decltype(tv.tv_usec)>(read_timeout_usec);
+          setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
+        }
+        {
+          timeval tv;
+          tv.tv_sec = static_cast<long>(write_timeout_sec);
+          tv.tv_usec =
+          static_cast<decltype(tv.tv_usec)>(write_timeout_usec);
+          setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv));
+        }
+
         error = Error::Success;
         return true;
       });
@@ -4847,6 +4865,19 @@ inline bool Server::listen_internal() {
         break;
       }
 
+      {
+        timeval tv;
+        tv.tv_sec = static_cast<long>(read_timeout_sec_);
+        tv.tv_usec = static_cast<decltype(tv.tv_usec)>(read_timeout_usec_);
+        setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
+      }
+      {
+        timeval tv;
+        tv.tv_sec = static_cast<long>(write_timeout_sec_);
+        tv.tv_usec = static_cast<decltype(tv.tv_usec)>(write_timeout_usec_);
+        setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv));
+      }
+
 #if __cplusplus > 201703L
       task_queue->enqueue([=, this]() { process_and_close_socket(sock); });
 #else
@@ -5263,11 +5294,14 @@ inline socket_t ClientImpl::create_client_socket(Error &error) const {
     return detail::create_client_socket(
         proxy_host_.c_str(), proxy_port_, address_family_, tcp_nodelay_,
         socket_options_, connection_timeout_sec_, connection_timeout_usec_,
-        interface_, error);
+        read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
+        write_timeout_usec_, interface_, error);
   }
   return detail::create_client_socket(
       host_.c_str(), port_, address_family_, tcp_nodelay_, socket_options_,
-      connection_timeout_sec_, connection_timeout_usec_, interface_, error);
+      connection_timeout_sec_, connection_timeout_usec_, read_timeout_sec_,
+      read_timeout_usec_, write_timeout_sec_, write_timeout_usec_, interface_,
+      error);
 }
 
 inline bool ClientImpl::create_and_connect_socket(Socket &socket,

+ 4 - 1
test/test.cc

@@ -3145,7 +3145,10 @@ static bool send_request(time_t read_timeout_sec, const std::string &req,
 
   auto client_sock =
       detail::create_client_socket(HOST, PORT, AF_UNSPEC, false, nullptr,
-                                   /*timeout_sec=*/5, 0, std::string(), error);
+                                   /*connection_timeout_sec=*/5, 0,
+                                   /*read_timeout_sec=*/5, 0,
+                                   /*write_timeout_sec=*/5, 0,
+                                   std::string(), error);
 
   if (client_sock == INVALID_SOCKET) { return false; }