From 9565c624d9d70dc5433a89be22ea14ae58e52d28 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 16 Jan 2014 19:08:30 -0700
Subject: [PATCH] ws2_32: Add support for TF_REUSE_SOCKET to TransmitFile.

---
 dlls/ws2_32/socket.c     | 13 +++++++++-
 dlls/ws2_32/tests/sock.c |  1 -
 include/winsock.h        |  1 +
 server/protocol.def      |  6 +++++
 server/sock.c            | 63 ++++++++++++++++++++++++++++++++++++++++++------
 5 files changed, 74 insertions(+), 10 deletions(-)

diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 6be4324..3cdd76b 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -3103,6 +3103,17 @@ static NTSTATUS WS2_transmitfile_base( int fd, struct ws2_transmitfile_async *ws
     if (status != STATUS_SUCCESS)
         return status;
 
+    if (wsa->flags & TF_REUSE_SOCKET)
+    {
+        SERVER_START_REQ( reuse_socket )
+        {
+            req->handle = wine_server_obj_handle( wsa->write.hSocket );
+            status = wine_server_call( req );
+        }
+        SERVER_END_REQ;
+        if (status != STATUS_SUCCESS)
+            return status;
+    }
     if (wsa->flags & TF_DISCONNECT)
     {
         /* we can't use WS_closesocket because it modifies the last error */
@@ -3145,7 +3156,7 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD file_bytes, DWORD
                                      LPOVERLAPPED overlapped, LPTRANSMIT_FILE_BUFFERS buffers,
                                      DWORD flags )
 {
-    DWORD unsupported_flags = flags & ~(TF_DISCONNECT);
+    DWORD unsupported_flags = flags & ~(TF_DISCONNECT|TF_REUSE_SOCKET);
     union generic_unix_sockaddr uaddr;
     socklen_t uaddrlen = sizeof(uaddr);
     struct ws2_transmitfile_async *wsa;
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index dbcb2b2..c14f5f9 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -9095,7 +9095,6 @@ static void test_TransmitFile(void)
                  err, WSAENOTSOCK);
 
     /* Test TransmitFile with a UDP datagram socket */
-    closesocket(client);
     client = socket(AF_INET, SOCK_DGRAM, 0);
     bret = pTransmitFile(client, NULL, 0, 0, NULL, NULL, 0);
     err = WSAGetLastError();
diff --git a/include/winsock.h b/include/winsock.h
index 789e1da..86ce4ff 100644
--- a/include/winsock.h
+++ b/include/winsock.h
@@ -829,6 +829,7 @@ typedef struct WS(WSAData)
 
 /* internal per-socket flags */
 #ifdef __WINESRC__
+#define FD_WINE_REUSE              0x08000000
 #define FD_WINE_LISTENING          0x10000000
 #define FD_WINE_NONBLOCKING        0x20000000
 #define FD_WINE_CONNECTED          0x40000000
diff --git a/server/protocol.def b/server/protocol.def
index 8795c67..94c1535 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1382,6 +1382,12 @@ enum server_fd_type
 @END
 
 
+/* Mark a socket to be reused after "closed" */
+@REQ(reuse_socket)
+    obj_handle_t handle;       /* handle to the socket */
+@END
+
+
 /* Set socket event parameters */
 @REQ(set_socket_event)
     obj_handle_t  handle;        /* handle to the socket */
diff --git a/server/sock.c b/server/sock.c
index 77c3db8..8b85e59 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -86,6 +86,7 @@
 #define FD_CLOSE                   0x00000020
 
 /* internal per-socket flags */
+#define FD_WINE_REUSE              0x08000000
 #define FD_WINE_LISTENING          0x10000000
 #define FD_WINE_NONBLOCKING        0x20000000
 #define FD_WINE_CONNECTED          0x40000000
@@ -132,6 +133,7 @@ static enum server_fd_type sock_get_fd_type( struct fd *fd );
 static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async );
 static void sock_queue_async( struct fd *fd, struct async *async, int type, int count );
 static void sock_reselect_async( struct fd *fd, struct async_queue *queue );
+static int sock_close_handle( struct object *obj, struct process *process, obj_handle_t handle );
 
 static int sock_get_ntstatus( int err );
 static unsigned int sock_get_error( int err );
@@ -157,7 +159,7 @@ static const struct object_ops sock_ops =
     no_open_file,                 /* open_file */
     no_kernel_obj_list,           /* get_kernel_obj_list */
     no_alloc_handle,              /* alloc_handle */
-    fd_close_handle,              /* close_handle */
+    sock_close_handle,            /* close_handle */
     sock_destroy                  /* destroy */
 };
 
@@ -609,6 +611,46 @@ static struct fd *sock_get_fd( struct object *obj )
     return (struct fd *)grab_object( sock->fd );
 }
 
+static int init_sockfd( int family, int type, int protocol )
+{
+    int sockfd;
+
+    sockfd = socket( family, type, protocol );
+    if (sockfd == -1)
+    {
+        if (errno == EINVAL) set_win32_error( WSAESOCKTNOSUPPORT );
+        else set_win32_error( sock_get_error( errno ));
+        return sockfd;
+    }
+    fcntl(sockfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */
+    return sockfd;
+}
+
+static int sock_close_handle( struct object *obj, struct process *process, obj_handle_t handle )
+{
+    struct sock *sock = (struct sock *)obj;
+
+    assert( obj->ops == &sock_ops );
+    if (!fd_close_handle( obj, process, handle ))
+        return FALSE;
+
+    if (sock->state & FD_WINE_REUSE)
+    {
+        struct fd *fd;
+        int sockfd;
+
+        if ((sockfd = init_sockfd( sock->family, sock->type, sock->proto )) == -1)
+            return TRUE;
+        if (!(fd = create_anonymous_fd( &sock_fd_ops, sockfd, &sock->obj, get_fd_options(sock->fd) )))
+            return TRUE;
+        shutdown( get_unix_fd(sock->fd), SHUT_RDWR );
+        release_object( sock->fd );
+        sock->fd = fd;
+        return FALSE;
+    }
+    return TRUE;
+}
+
 static void sock_destroy( struct object *obj )
 {
     struct sock *sock = (struct sock *)obj;
@@ -662,14 +704,8 @@ static struct object *create_socket( int family, int type, int protocol, unsigne
     struct sock *sock;
     int sockfd;
 
-    sockfd = socket( family, type, protocol );
-    if (sockfd == -1)
-    {
-        if (errno == EINVAL) set_win32_error( WSAESOCKTNOSUPPORT );
-        else set_win32_error( sock_get_error( errno ));
+    if ((sockfd = init_sockfd( family, type, protocol )) == -1)
         return NULL;
-    }
-    fcntl(sockfd, F_SETFL, O_NONBLOCK); /* make socket nonblocking */
     if (!(sock = alloc_object( &sock_ops )))
     {
         close( sockfd );
@@ -1222,6 +1258,17 @@ DECL_HANDLER(accept_into_socket)
     release_object( sock );
 }
 
+/* mark a socket to be recreated on close */
+DECL_HANDLER(reuse_socket)
+{
+    struct sock *sock;
+
+    if (!(sock = (struct sock *)get_handle_obj( current->process, req->handle,
+                                                FILE_WRITE_ATTRIBUTES, &sock_ops))) return;
+    sock->state |= FD_WINE_REUSE;
+    release_object( &sock->obj );
+}
+
 /* set socket event parameters */
 DECL_HANDLER(set_socket_event)
 {
-- 
1.9.1

