From 5cce90db6d3f5cc4dd4db2125bf4d2f3d2ec5b63 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Thu, 20 Nov 2014 13:27:24 +0100
Subject: ws2_32: Implement returning the proper time with SO_CONNECT_TIME.

Based on a patch by Erich Hoover.

To avoid calculations on the client-side, the server sends the connect time as relative (negative) value.
Needs tools/make_requests.
---
 dlls/ws2_32/socket.c     | 21 ++++++++++++++++-----
 dlls/ws2_32/tests/sock.c | 19 +++++++++++++++++++
 server/protocol.def      |  1 +
 server/sock.c            |  1 +
 4 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index b3db306..ac6d831 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -881,6 +881,21 @@ static NTSTATUS _is_blocking(SOCKET s, BOOL *ret)
     return status;
 }
 
+static DWORD _get_connect_time(SOCKET s)
+{
+    NTSTATUS status;
+    DWORD connect_time = ~0u;
+    SERVER_START_REQ( get_socket_info )
+    {
+        req->handle  = wine_server_obj_handle( SOCKET2HANDLE(s) );
+        status = wine_server_call( req );
+        if (!status)
+            connect_time = reply->connect_time / -10000000;
+    }
+    SERVER_END_REQ;
+    return connect_time;
+}
+
 static unsigned int _get_sock_mask(SOCKET s)
 {
     unsigned int ret;
@@ -3125,7 +3140,6 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level,
 
         case WS_SO_CONNECT_TIME:
         {
-            static int pretendtime = 0;
             struct WS_sockaddr addr;
             int len = sizeof(addr);
 
@@ -3137,10 +3151,7 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level,
             if (WS_getpeername(s, &addr, &len) == SOCKET_ERROR)
                 *(DWORD *)optval = ~0u;
             else
-            {
-                if (!pretendtime) FIXME("WS_SO_CONNECT_TIME - faking results\n");
-                *(DWORD *)optval = pretendtime++;
-            }
+                *(DWORD *)optval = _get_connect_time(s);
             *optlen = sizeof(DWORD);
             return ret;
         }
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index acc2783..422174f 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -4254,6 +4254,8 @@ static void test_send(void)
     OVERLAPPED ov;
     BOOL bret;
     DWORD id, bytes_sent, dwRet;
+    DWORD expected_time, connect_time;
+    socklen_t optlen;
 
     memset(&ov, 0, sizeof(ov));
 
@@ -4262,6 +4264,7 @@ static void test_send(void)
         ok(0, "creating socket pair failed, skipping test\n");
         return;
     }
+    expected_time = GetTickCount();
 
     set_blocking(dst, FALSE);
     /* force disable buffering so we can get a pending overlapped request */
@@ -4348,6 +4351,22 @@ static void test_send(void)
     ok(ret == SOCKET_ERROR && WSAGetLastError() == ERROR_IO_PENDING,
        "Failed to start overlapped send %d - %d\n", ret, WSAGetLastError());
 
+    expected_time = (GetTickCount() - expected_time) / 1000;
+
+    connect_time = 0xdeadbeef;
+    optlen = sizeof(connect_time);
+    ret = getsockopt(dst, SOL_SOCKET, SO_CONNECT_TIME, (char *)&connect_time, &optlen);
+    ok(!ret, "getsockopt failed %d\n", WSAGetLastError());
+    ok(connect_time >= expected_time && connect_time <= expected_time + 1,
+       "unexpected connect time %u, expected %u\n", connect_time, expected_time);
+
+    connect_time = 0xdeadbeef;
+    optlen = sizeof(connect_time);
+    ret = getsockopt(src, SOL_SOCKET, SO_CONNECT_TIME, (char *)&connect_time, &optlen);
+    ok(!ret, "getsockopt failed %d\n", WSAGetLastError());
+    ok(connect_time >= expected_time && connect_time <= expected_time + 1,
+       "unexpected connect time %u, expected %u\n", connect_time, expected_time);
+
 end:
     if (src != INVALID_SOCKET)
         closesocket(src);
diff --git a/server/protocol.def b/server/protocol.def
index fc6bec5..840ba0d 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1238,6 +1238,7 @@ enum server_fd_type
     int family;                 /* family, see socket manpage */
     int type;                   /* type, see socket manpage */
     int protocol;               /* protocol, see socket manpage */
+    timeout_t connect_time;     /* time the socket was connected (relative) */
 @END
 
 
diff --git a/server/sock.c b/server/sock.c
index 7c0212e..7416eec 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -1093,6 +1093,7 @@ DECL_HANDLER(get_socket_info)
     reply->family   = sock->family;
     reply->type     = sock->type;
     reply->protocol = sock->proto;
+    reply->connect_time = -(current_time - sock->connect_time);
 
     release_object( &sock->obj );
 }
-- 
2.1.3

