diff --git a/patches/09-TransmitFile/0001-ws2_32-Add-stub-for-TransmitFile.patch b/patches/09-TransmitFile/0001-ws2_32-Add-stub-for-TransmitFile.patch new file mode 100644 index 00000000..ca6a6c33 --- /dev/null +++ b/patches/09-TransmitFile/0001-ws2_32-Add-stub-for-TransmitFile.patch @@ -0,0 +1,45 @@ +From 9a7e400269a26545f47dfbd4f40ac2e74713c496 Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +Date: Thu, 16 Jan 2014 17:52:50 -0700 +Subject: ws2_32: Add stub for TransmitFile. + +--- + dlls/ws2_32/socket.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c +index a855285..c7f17c7 100644 +--- a/dlls/ws2_32/socket.c ++++ b/dlls/ws2_32/socket.c +@@ -2473,6 +2473,18 @@ static BOOL WINAPI WS2_AcceptEx(SOCKET listener, SOCKET acceptor, PVOID dest, DW + } + + /*********************************************************************** ++ * TransmitFile ++ */ ++static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWORD bytes_per_send, ++ LPOVERLAPPED overlapped, LPTRANSMIT_FILE_BUFFERS buffers, DWORD flags ) ++{ ++ FIXME("(%lx, %p, %d, %d, %p, %p, %d): stub !\n", s, h, total_bytes, bytes_per_send, overlapped, buffers, ++ flags ); ++ WSASetLastError( WSAEOPNOTSUPP ); ++ return FALSE; ++} ++ ++/*********************************************************************** + * GetAcceptExSockaddrs + */ + static void WINAPI WS2_GetAcceptExSockaddrs(PVOID buffer, DWORD data_size, DWORD local_size, DWORD remote_size, +@@ -3974,7 +3986,8 @@ INT WINAPI WSAIoctl(SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size, LPVOID + } + else if ( IsEqualGUID(&transmitfile_guid, in_buff) ) + { +- FIXME("SIO_GET_EXTENSION_FUNCTION_POINTER: unimplemented TransmitFile\n"); ++ *(LPFN_TRANSMITFILE *)out_buff = WS2_TransmitFile; ++ break; + } + else if ( IsEqualGUID(&transmitpackets_guid, in_buff) ) + { +-- +1.7.9.5 + diff --git a/patches/09-TransmitFile/0002-ws2_32-Check-for-invalid-parameters-in-TransmitFile.patch b/patches/09-TransmitFile/0002-ws2_32-Check-for-invalid-parameters-in-TransmitFile.patch new file mode 100644 index 00000000..5f958ebe --- /dev/null +++ b/patches/09-TransmitFile/0002-ws2_32-Check-for-invalid-parameters-in-TransmitFile.patch @@ -0,0 +1,167 @@ +From 216a9bcfa322c6c7fe73bcb937d864c44ed7e021 Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +Date: Thu, 16 Jan 2014 17:53:31 -0700 +Subject: ws2_32: Check for invalid parameters in TransmitFile. + +--- + dlls/ws2_32/socket.c | 20 +++++++++ + dlls/ws2_32/tests/sock.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 123 insertions(+) + +diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c +index c7f17c7..ae23dd6 100644 +--- a/dlls/ws2_32/socket.c ++++ b/dlls/ws2_32/socket.c +@@ -2478,8 +2478,28 @@ static BOOL WINAPI WS2_AcceptEx(SOCKET listener, SOCKET acceptor, PVOID dest, DW + static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWORD bytes_per_send, + LPOVERLAPPED overlapped, LPTRANSMIT_FILE_BUFFERS buffers, DWORD flags ) + { ++ union generic_unix_sockaddr uaddr; ++ unsigned int uaddrlen = sizeof(uaddr); ++ int fd; ++ + FIXME("(%lx, %p, %d, %d, %p, %p, %d): stub !\n", s, h, total_bytes, bytes_per_send, overlapped, buffers, + flags ); ++ if (s == INVALID_SOCKET) ++ { ++ WSASetLastError( WSAENOTSOCK ); ++ return FALSE; ++ } ++ fd = get_sock_fd( s, 0, NULL ); ++ if (getpeername( fd, &uaddr.addr, &uaddrlen ) != 0) ++ { ++ release_sock_fd( s, fd ); ++ WSASetLastError( WSAENOTCONN ); ++ return FALSE; ++ } ++ release_sock_fd( s, fd ); ++ if (flags) ++ FIXME("Flags are not currently supported (0x%x).\n", flags); ++ + WSASetLastError( WSAEOPNOTSUPP ); + return FALSE; + } +diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c +index 0abf732..30c8bc1 100644 +--- a/dlls/ws2_32/tests/sock.c ++++ b/dlls/ws2_32/tests/sock.c +@@ -6334,6 +6334,108 @@ end: + closesocket(connector2); + } + ++static void test_TransmitFile(void) ++{ ++ GUID transmitFileGuid = WSAID_TRANSMITFILE; ++ LPFN_TRANSMITFILE pTransmitFile = NULL; ++ HANDLE file = INVALID_HANDLE_VALUE; ++ char system_ini_path[MAX_PATH]; ++ struct sockaddr_in bindAddress; ++ SOCKET client, server, dest; ++ DWORD num_bytes, err; ++ int iret, len; ++ BOOL bret; ++ ++ /* Setup sockets for testing TransmitFile */ ++ client = socket(AF_INET, SOCK_STREAM, 0); ++ server = socket(AF_INET, SOCK_STREAM, 0); ++ if (client == INVALID_SOCKET || server == INVALID_SOCKET) ++ { ++ skip("could not create acceptor socket, error %d\n", WSAGetLastError()); ++ goto cleanup; ++ } ++ iret = WSAIoctl(client, SIO_GET_EXTENSION_FUNCTION_POINTER, &transmitFileGuid, sizeof(transmitFileGuid), ++ &pTransmitFile, sizeof(pTransmitFile), &num_bytes, NULL, NULL); ++ if (iret) ++ { ++ skip("WSAIoctl failed to get TransmitFile with ret %d + errno %d\n", iret, WSAGetLastError()); ++ goto cleanup; ++ } ++ GetSystemWindowsDirectoryA(system_ini_path, MAX_PATH ); ++ strcat(system_ini_path, "\\system.ini"); ++ file = CreateFileA(system_ini_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0x0, NULL); ++ if (file == INVALID_HANDLE_VALUE) ++ { ++ skip("Unable to open a file to transmit.\n"); ++ goto cleanup; ++ } ++ ++ /* Test TransmitFile with an invalid socket */ ++ bret = pTransmitFile(INVALID_SOCKET, file, 0, 0, NULL, NULL, 0); ++ err = WSAGetLastError(); ++ ok(!bret, "TransmitFile succeeded unexpectedly.\n"); ++ ok(err == WSAENOTSOCK, "TransmitFile triggered unexpected errno (%d != %d)\n", err, WSAENOTSOCK); ++ ++ /* Test a bogus TransmitFile without a connected socket */ ++ bret = pTransmitFile(client, NULL, 0, 0, NULL, NULL, TF_REUSE_SOCKET); ++ err = WSAGetLastError(); ++ ok(!bret, "TransmitFile succeeded unexpectedly.\n"); ++ ok(err == WSAENOTCONN, "TransmitFile triggered unexpected errno (%d != %d)\n", err, WSAENOTCONN); ++ ++ /* Setup a properly connected socket for transfers */ ++ memset(&bindAddress, 0, sizeof(bindAddress)); ++ bindAddress.sin_family = AF_INET; ++ bindAddress.sin_port = htons(9375); ++ bindAddress.sin_addr.s_addr = inet_addr("127.0.0.1"); ++ iret = bind(server, (struct sockaddr*)&bindAddress, sizeof(bindAddress)); ++ if (iret != 0) ++ { ++ skip("failed to bind(), error %d\n", WSAGetLastError()); ++ goto cleanup; ++ } ++ iret = listen(server, 1); ++ if (iret != 0) ++ { ++ skip("failed to listen(), error %d\n", WSAGetLastError()); ++ goto cleanup; ++ } ++ iret = connect(client, (struct sockaddr*)&bindAddress, sizeof(bindAddress)); ++ if (iret != 0) ++ { ++ skip("failed to connect(), error %d\n", WSAGetLastError()); ++ goto cleanup; ++ } ++ len = sizeof(bindAddress); ++ dest = accept(server, (struct sockaddr*)&bindAddress, &len); ++ if (dest == INVALID_SOCKET) ++ { ++ skip("failed to accept(), error %d\n", WSAGetLastError()); ++ goto cleanup; ++ } ++ if (set_blocking(dest, FALSE)) ++ { ++ skip("couldn't make socket non-blocking, error %d\n", WSAGetLastError()); ++ goto cleanup; ++ } ++ ++ /* Test TransmitFile with no possible buffer */ ++ bret = pTransmitFile(client, NULL, 0, 0, NULL, NULL, 0); ++ todo_wine ok(bret, "TransmitFile failed unexpectedly.\n"); ++ ++ /* 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(); ++ ok(!bret, "TransmitFile succeeded unexpectedly.\n"); ++ ok(err == WSAENOTCONN, "TransmitFile triggered unexpected errno (%d != %d)\n", err, WSAENOTCONN); ++ ++cleanup: ++ CloseHandle(file); ++ closesocket(client); ++ closesocket(server); ++} ++ + static void test_getpeername(void) + { + SOCKET sock; +@@ -7568,6 +7670,7 @@ START_TEST( sock ) + test_getaddrinfo(); + test_AcceptEx(); + test_ConnectEx(); ++ test_TransmitFile(); + + test_sioRoutingInterfaceQuery(); + +-- +1.7.9.5 + diff --git a/patches/09-TransmitFile/0003-ws2_32-Implement-a-basic-synchronous-TransmitFile.patch b/patches/09-TransmitFile/0003-ws2_32-Implement-a-basic-synchronous-TransmitFile.patch new file mode 100644 index 00000000..3e859929 --- /dev/null +++ b/patches/09-TransmitFile/0003-ws2_32-Implement-a-basic-synchronous-TransmitFile.patch @@ -0,0 +1,202 @@ +From e1278ab064bba641f34caa8132c8ddc8e83b9778 Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +Date: Thu, 16 Jan 2014 18:24:27 -0700 +Subject: ws2_32: Implement a basic synchronous TransmitFile. + +--- + dlls/ws2_32/socket.c | 66 ++++++++++++++++++++++++++++++++++++++++-- + dlls/ws2_32/tests/sock.c | 71 +++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 134 insertions(+), 3 deletions(-) + +diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c +index ae23dd6..1faf443 100644 +--- a/dlls/ws2_32/socket.c ++++ b/dlls/ws2_32/socket.c +@@ -2473,6 +2473,64 @@ static BOOL WINAPI WS2_AcceptEx(SOCKET listener, SOCKET acceptor, PVOID dest, DW + } + + /*********************************************************************** ++ * WS2_transmitfile_base (INTERNAL) ++ * ++ * Shared implementation for both synchronous and asynchronous TransmitFile. ++ */ ++static BOOL WS2_transmitfile_base( SOCKET s, HANDLE h, DWORD total_bytes, DWORD bytes_per_send, ++ LPOVERLAPPED overlapped, LPTRANSMIT_FILE_BUFFERS buffers, ++ DWORD flags ) ++{ ++ DWORD bytes_sent = 0; ++ char *buffer = NULL; ++ BOOL ret = FALSE; ++ ++ /* set reasonable defaults when requested */ ++ if (!bytes_per_send) ++ bytes_per_send = 1024; ++ ++ /* send the header (if applicable) */ ++ if (buffers && WS_send( s, buffers->Head, buffers->HeadLength, 0 ) == SOCKET_ERROR) ++ goto cleanup; ++ ++ /* process the main file */ ++ if (h) ++ { ++ buffer = HeapAlloc( GetProcessHeap(), 0, bytes_per_send ); ++ if (!buffer) goto cleanup; ++ ++ /* read and send the data from the file */ ++ do ++ { ++ DWORD n = 0; ++ BOOL ok; ++ ++ /* when the size of the transfer is limited ensure that we don't go past that limit */ ++ if (total_bytes != 0) ++ bytes_per_send = min(bytes_per_send, total_bytes - bytes_sent); ++ ok = ReadFile( h, buffer, bytes_per_send, &n, NULL ); ++ if (ok && n == 0) ++ break; ++ else if(!ok) ++ goto cleanup; ++ if (WS_send( s, buffer, n, 0 ) == SOCKET_ERROR) ++ goto cleanup; ++ bytes_sent += n; ++ } while(total_bytes == 0 || bytes_sent < total_bytes); ++ } ++ ++ /* send the footer (if applicable) */ ++ if (buffers && WS_send( s, buffers->Tail, buffers->TailLength, 0 ) == SOCKET_ERROR) ++ goto cleanup; ++ ++ ret = TRUE; ++ ++cleanup: ++ HeapFree( GetProcessHeap(), 0, buffer ); ++ return ret; ++} ++ ++/*********************************************************************** + * TransmitFile + */ + static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWORD bytes_per_send, +@@ -2482,8 +2540,7 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWOR + unsigned int uaddrlen = sizeof(uaddr); + int fd; + +- FIXME("(%lx, %p, %d, %d, %p, %p, %d): stub !\n", s, h, total_bytes, bytes_per_send, overlapped, buffers, +- flags ); ++ TRACE("(%lx, %p, %d, %d, %p, %p, %d)\n", s, h, total_bytes, bytes_per_send, overlapped, buffers, flags ); + if (s == INVALID_SOCKET) + { + WSASetLastError( WSAENOTSOCK ); +@@ -2500,6 +2557,11 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWOR + if (flags) + FIXME("Flags are not currently supported (0x%x).\n", flags); + ++ if (!overlapped) ++ return WS2_transmitfile_base( s, h, total_bytes, bytes_per_send, overlapped, buffers, flags ); ++ ++ FIXME("(%lx, %p, %d, %d, %p, %p, %d): stub !\n", s, h, total_bytes, bytes_per_send, overlapped, buffers, ++ flags ); + WSASetLastError( WSAEOPNOTSUPP ); + return FALSE; + } +diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c +index 30c8bc1..79052ab 100644 +--- a/dlls/ws2_32/tests/sock.c ++++ b/dlls/ws2_32/tests/sock.c +@@ -6334,15 +6334,45 @@ end: + closesocket(connector2); + } + ++#define compare_file(h,s) compare_file2(h,s,__FILE__,__LINE__) ++ ++static void compare_file2(HANDLE handle, SOCKET sock, const char *file, int line) ++{ ++ char buf1[256], buf2[256]; ++ BOOL success; ++ int i = 0; ++ ++ SetFilePointer(handle, 0, NULL, FILE_BEGIN); ++ while (1) ++ { ++ DWORD n1 = 0, n2 = 0; ++ ++ success = ReadFile(handle, buf1, sizeof(buf1), &n1, NULL); ++ ok_(file,line)(success, "Failed to read from file.\n"); ++ if (success && n1 == 0) ++ break; ++ else if(!success) ++ return; ++ n2 = recv(sock, buf2, n1, 0); ++ ok_(file,line)(n1 == n2, "Block %d size mismatch (%d != %d)\n", i, n1, n2); ++ ok_(file,line)(memcmp(buf1, buf2, n2) == 0, "Block %d failed\n", i); ++ i++; ++ } ++} ++ + static void test_TransmitFile(void) + { + GUID transmitFileGuid = WSAID_TRANSMITFILE; + LPFN_TRANSMITFILE pTransmitFile = NULL; + HANDLE file = INVALID_HANDLE_VALUE; ++ char header_msg[] = "hello world"; ++ char footer_msg[] = "goodbye!!!"; + char system_ini_path[MAX_PATH]; + struct sockaddr_in bindAddress; ++ TRANSMIT_FILE_BUFFERS buffers; + SOCKET client, server, dest; + DWORD num_bytes, err; ++ char buf[256]; + int iret, len; + BOOL bret; + +@@ -6420,7 +6450,46 @@ static void test_TransmitFile(void) + + /* Test TransmitFile with no possible buffer */ + bret = pTransmitFile(client, NULL, 0, 0, NULL, NULL, 0); +- todo_wine ok(bret, "TransmitFile failed unexpectedly.\n"); ++ ok(bret, "TransmitFile failed unexpectedly.\n"); ++ iret = recv(dest, buf, sizeof(buf), 0); ++ ok(iret == -1, "Returned an unexpected buffer from TransmitFile (%d != -1).\n", iret); ++ ++ /* Test TransmitFile with only buffer data */ ++ buffers.Head = &header_msg[0]; ++ buffers.HeadLength = sizeof(header_msg)+1; ++ buffers.Tail = &footer_msg[0]; ++ buffers.TailLength = sizeof(footer_msg)+1; ++ bret = pTransmitFile(client, NULL, 0, 0, NULL, &buffers, 0); ++ ok(bret, "TransmitFile failed unexpectedly.\n"); ++ iret = recv(dest, buf, sizeof(buf), 0); ++ ok(iret == sizeof(header_msg)+sizeof(footer_msg)+2, ++ "Returned an unexpected buffer from TransmitFile (%d != %d).\n", iret, ++ sizeof(header_msg)+sizeof(footer_msg)+2); ++ ok(memcmp(&buf[0], &header_msg[0], sizeof(header_msg)+1) == 0, ++ "TransmitFile header buffer did not match!\n"); ++ ok(memcmp(&buf[sizeof(header_msg)+1], &footer_msg[0], sizeof(footer_msg)+1) == 0, ++ "TransmitFile footer buffer did not match!\n"); ++ ++ /* Test TransmitFile with only file data */ ++ bret = pTransmitFile(client, file, 0, 0, NULL, NULL, 0); ++ ok(bret, "TransmitFile failed unexpectedly.\n"); ++ compare_file(file, dest); ++ ++ /* Test TransmitFile with both file and buffer data */ ++ buffers.Head = &header_msg[0]; ++ buffers.HeadLength = sizeof(header_msg)+1; ++ buffers.Tail = &footer_msg[0]; ++ buffers.TailLength = sizeof(footer_msg)+1; ++ SetFilePointer(file, 0, NULL, FILE_BEGIN); ++ bret = pTransmitFile(client, file, 0, 0, NULL, &buffers, 0); ++ ok(bret, "TransmitFile failed unexpectedly.\n"); ++ iret = recv(dest, buf, sizeof(header_msg)+1, 0); ++ ok(memcmp(buf, &header_msg[0], sizeof(header_msg)+1) == 0, ++ "TransmitFile header buffer did not match!\n"); ++ compare_file(file, dest); ++ iret = recv(dest, buf, sizeof(footer_msg)+1, 0); ++ ok(memcmp(buf, &footer_msg[0], sizeof(footer_msg)+1) == 0, ++ "TransmitFile footer buffer did not match!\n"); + + /* Test TransmitFile with a UDP datagram socket */ + closesocket(client); +-- +1.7.9.5 + diff --git a/patches/09-TransmitFile/0004-ws2_32-Add-asynchronous-support-for-TransmitFile.patch b/patches/09-TransmitFile/0004-ws2_32-Add-asynchronous-support-for-TransmitFile.patch new file mode 100644 index 00000000..bf95fd29 --- /dev/null +++ b/patches/09-TransmitFile/0004-ws2_32-Add-asynchronous-support-for-TransmitFile.patch @@ -0,0 +1,238 @@ +From ecf3a78c92ff49e1322d5e7467c54081606e9e8d Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +Date: Thu, 16 Jan 2014 18:24:53 -0700 +Subject: ws2_32: Add asynchronous support for TransmitFile. + +--- + dlls/ws2_32/socket.c | 86 +++++++++++++++++++++++++++++++++++++++++++--- + dlls/ws2_32/tests/sock.c | 47 ++++++++++++++++++++++--- + 2 files changed, 124 insertions(+), 9 deletions(-) + +diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c +index 1faf443..2323e3d 100644 +--- a/dlls/ws2_32/socket.c ++++ b/dlls/ws2_32/socket.c +@@ -363,6 +363,18 @@ typedef struct ws2_accept_async + struct ws2_async *read; + } ws2_accept_async; + ++typedef struct ws2_transmitfile_async ++{ ++ HANDLE socket; ++ HANDLE file; ++ DWORD total_bytes; ++ DWORD bytes_per_send; ++ LPOVERLAPPED user_overlapped; ++ LPTRANSMIT_FILE_BUFFERS buffers; ++ DWORD flags; ++ ULONG_PTR cvalue; ++} ws2_transmitfile_async; ++ + /****************************************************************/ + + /* ----------------------------------- internal data */ +@@ -2499,6 +2511,16 @@ static BOOL WS2_transmitfile_base( SOCKET s, HANDLE h, DWORD total_bytes, DWORD + buffer = HeapAlloc( GetProcessHeap(), 0, bytes_per_send ); + if (!buffer) goto cleanup; + ++ /* handle the overlapped offset */ ++ if (overlapped) ++ { ++ LARGE_INTEGER offset; ++ ++ offset.u.LowPart = overlapped->u.s.Offset; ++ offset.u.HighPart = overlapped->u.s.OffsetHigh; ++ SetFilePointerEx( h, offset, NULL, FILE_BEGIN ); ++ } ++ + /* read and send the data from the file */ + do + { +@@ -2531,6 +2553,32 @@ cleanup: + } + + /*********************************************************************** ++ * WS2_async_transmitfile (INTERNAL) ++ * ++ * Asynchronous callback for overlapped TransmitFile operations. ++ */ ++static NTSTATUS WS2_async_transmitfile( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved ) ++{ ++ struct ws2_transmitfile_async *wsa = arg; ++ BOOL ret; ++ ++ ret = WS2_transmitfile_base( HANDLE2SOCKET(wsa->socket), wsa->file, wsa->total_bytes, wsa->bytes_per_send, ++ wsa->user_overlapped, wsa->buffers, wsa->flags ); ++ if (!ret) ++ iosb->u.Status = wsaErrStatus(); ++ else ++ iosb->u.Status = STATUS_SUCCESS; ++ iosb->Information = 0; ++ ++ if (wsa->user_overlapped->hEvent) ++ SetEvent(wsa->user_overlapped->hEvent); ++ if (wsa->cvalue) ++ WS_AddCompletion( HANDLE2SOCKET(wsa->socket), wsa->cvalue, iosb->u.Status, iosb->Information ); ++ ++ return iosb->u.Status; ++} ++ ++/*********************************************************************** + * TransmitFile + */ + static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWORD bytes_per_send, +@@ -2538,7 +2586,9 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWOR + { + union generic_unix_sockaddr uaddr; + unsigned int uaddrlen = sizeof(uaddr); +- int fd; ++ IO_STATUS_BLOCK *iosb = (IO_STATUS_BLOCK *)overlapped; ++ struct ws2_transmitfile_async *wsa; ++ int status, fd; + + TRACE("(%lx, %p, %d, %d, %p, %p, %d)\n", s, h, total_bytes, bytes_per_send, overlapped, buffers, flags ); + if (s == INVALID_SOCKET) +@@ -2560,9 +2610,37 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWOR + if (!overlapped) + return WS2_transmitfile_base( s, h, total_bytes, bytes_per_send, overlapped, buffers, flags ); + +- FIXME("(%lx, %p, %d, %d, %p, %p, %d): stub !\n", s, h, total_bytes, bytes_per_send, overlapped, buffers, +- flags ); +- WSASetLastError( WSAEOPNOTSUPP ); ++ iosb->u.Status = STATUS_PENDING; ++ iosb->Information = 0; ++ if (!(wsa = HeapAlloc( GetProcessHeap(), 0, sizeof(*wsa) ))) ++ { ++ SetLastError( WSAEFAULT ); ++ return FALSE; ++ } ++ wsa->socket = SOCKET2HANDLE(s); ++ wsa->file = h; ++ wsa->total_bytes = total_bytes; ++ wsa->bytes_per_send = bytes_per_send; ++ wsa->user_overlapped = overlapped; ++ wsa->buffers = buffers; ++ wsa->flags = flags; ++ wsa->cvalue = (((ULONG_PTR)overlapped->hEvent & 1) == 0) ? (ULONG_PTR)overlapped : 0; ++ ++ SERVER_START_REQ( register_async ) ++ { ++ req->type = ASYNC_TYPE_WRITE; ++ req->async.handle = wine_server_obj_handle( SOCKET2HANDLE(s) ); ++ req->async.callback = wine_server_client_ptr( WS2_async_transmitfile ); ++ req->async.iosb = wine_server_client_ptr( iosb ); ++ req->async.arg = wine_server_client_ptr( wsa ); ++ status = wine_server_call( req ); ++ } ++ SERVER_END_REQ; ++ ++ if(status != STATUS_PENDING) ++ HeapFree( GetProcessHeap(), 0, wsa ); ++ ++ SetLastError( NtStatusToWSAError(status) ); + return FALSE; + } + +diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c +index 79052ab..652f75f 100644 +--- a/dlls/ws2_32/tests/sock.c ++++ b/dlls/ws2_32/tests/sock.c +@@ -6334,15 +6334,15 @@ end: + closesocket(connector2); + } + +-#define compare_file(h,s) compare_file2(h,s,__FILE__,__LINE__) ++#define compare_file(h,s,o) compare_file2(h,s,o,__FILE__,__LINE__) + +-static void compare_file2(HANDLE handle, SOCKET sock, const char *file, int line) ++static void compare_file2(HANDLE handle, SOCKET sock, int offset, const char *file, int line) + { + char buf1[256], buf2[256]; + BOOL success; + int i = 0; + +- SetFilePointer(handle, 0, NULL, FILE_BEGIN); ++ SetFilePointer(handle, offset, NULL, FILE_BEGIN); + while (1) + { + DWORD n1 = 0, n2 = 0; +@@ -6372,10 +6372,13 @@ static void test_TransmitFile(void) + TRANSMIT_FILE_BUFFERS buffers; + SOCKET client, server, dest; + DWORD num_bytes, err; ++ WSAOVERLAPPED ov; + char buf[256]; + int iret, len; + BOOL bret; + ++ memset( &ov, 0, sizeof(ov) ); ++ + /* Setup sockets for testing TransmitFile */ + client = socket(AF_INET, SOCK_STREAM, 0); + server = socket(AF_INET, SOCK_STREAM, 0); +@@ -6473,7 +6476,7 @@ static void test_TransmitFile(void) + /* Test TransmitFile with only file data */ + bret = pTransmitFile(client, file, 0, 0, NULL, NULL, 0); + ok(bret, "TransmitFile failed unexpectedly.\n"); +- compare_file(file, dest); ++ compare_file(file, dest, 0); + + /* Test TransmitFile with both file and buffer data */ + buffers.Head = &header_msg[0]; +@@ -6486,11 +6489,44 @@ static void test_TransmitFile(void) + iret = recv(dest, buf, sizeof(header_msg)+1, 0); + ok(memcmp(buf, &header_msg[0], sizeof(header_msg)+1) == 0, + "TransmitFile header buffer did not match!\n"); +- compare_file(file, dest); ++ compare_file(file, dest, 0); + iret = recv(dest, buf, sizeof(footer_msg)+1, 0); + ok(memcmp(buf, &footer_msg[0], sizeof(footer_msg)+1) == 0, + "TransmitFile footer buffer did not match!\n"); + ++ /* Test overlapped TransmitFile */ ++ ov.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); ++ if (ov.hEvent == INVALID_HANDLE_VALUE) ++ { ++ skip("Could not create event object, some tests will be skipped. errno = %d\n", GetLastError()); ++ goto cleanup; ++ } ++ SetFilePointer(file, 0, NULL, FILE_BEGIN); ++ bret = pTransmitFile(client, file, 0, 0, &ov, NULL, 0); ++ err = WSAGetLastError(); ++ ok(!bret, "TransmitFile succeeded unexpectedly.\n"); ++ ok(err == ERROR_IO_PENDING, "TransmitFile triggered unexpected errno (%d != %d)\n", err, ERROR_IO_PENDING); ++ iret = WaitForSingleObject(ov.hEvent, 100); ++ ok(iret == WAIT_OBJECT_0, "Overlapped TransmitFile failed.\n"); ++ compare_file(file, dest, 0); ++ ++ /* Test overlapped TransmitFile w/ start offset */ ++ ov.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); ++ if (ov.hEvent == INVALID_HANDLE_VALUE) ++ { ++ skip("Could not create event object, some tests will be skipped. errno = %d\n", GetLastError()); ++ goto cleanup; ++ } ++ SetFilePointer(file, 0, NULL, FILE_BEGIN); ++ ov.Offset = 10; ++ bret = pTransmitFile(client, file, 0, 0, &ov, NULL, 0); ++ err = WSAGetLastError(); ++ ok(!bret, "TransmitFile succeeded unexpectedly.\n"); ++ ok(err == ERROR_IO_PENDING, "TransmitFile triggered unexpected errno (%d != %d)\n", err, ERROR_IO_PENDING); ++ iret = WaitForSingleObject(ov.hEvent, 100); ++ ok(iret == WAIT_OBJECT_0, "Overlapped TransmitFile failed.\n"); ++ compare_file(file, dest, 10); ++ + /* Test TransmitFile with a UDP datagram socket */ + closesocket(client); + client = socket(AF_INET, SOCK_DGRAM, 0); +@@ -6501,6 +6537,7 @@ static void test_TransmitFile(void) + + cleanup: + CloseHandle(file); ++ CloseHandle(ov.hEvent); + closesocket(client); + closesocket(server); + } +-- +1.7.9.5 + diff --git a/patches/09-TransmitFile/0005-ws2_32-Add-support-for-TF_DISCONNECT-and-TF_REUSE_SO.patch b/patches/09-TransmitFile/0005-ws2_32-Add-support-for-TF_DISCONNECT-and-TF_REUSE_SO.patch new file mode 100644 index 00000000..4c61dfa6 --- /dev/null +++ b/patches/09-TransmitFile/0005-ws2_32-Add-support-for-TF_DISCONNECT-and-TF_REUSE_SO.patch @@ -0,0 +1,224 @@ +From 986759caf5c16c81f4a479e57b6ff2a96dbb3a2a Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +Date: Thu, 16 Jan 2014 19:08:30 -0700 +Subject: ws2_32: Add support for TF_DISCONNECT and TF_REUSE_SOCKET to + TransmitFile. + +--- + dlls/ws2_32/socket.c | 17 ++++++++++-- + dlls/ws2_32/tests/sock.c | 11 +++++++- + include/winsock.h | 1 + + server/protocol.def | 6 +++++ + server/sock.c | 66 +++++++++++++++++++++++++++++++++++++++------- + 5 files changed, 89 insertions(+), 12 deletions(-) + +diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c +index 2323e3d..500d288 100644 +--- a/dlls/ws2_32/socket.c ++++ b/dlls/ws2_32/socket.c +@@ -2545,6 +2545,18 @@ static BOOL WS2_transmitfile_base( SOCKET s, HANDLE h, DWORD total_bytes, DWORD + if (buffers && WS_send( s, buffers->Tail, buffers->TailLength, 0 ) == SOCKET_ERROR) + goto cleanup; + ++ if (flags & TF_REUSE_SOCKET) ++ { ++ SERVER_START_REQ( reuse_socket ) ++ { ++ req->handle = wine_server_obj_handle( SOCKET2HANDLE(s) ); ++ wine_server_call( req ); ++ } ++ SERVER_END_REQ; ++ } ++ if (flags & TF_DISCONNECT) ++ WS_closesocket( s ); ++ + ret = TRUE; + + cleanup: +@@ -2586,6 +2598,7 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWOR + { + union generic_unix_sockaddr uaddr; + unsigned int uaddrlen = sizeof(uaddr); ++ DWORD unsupported_flags = flags & ~(TF_DISCONNECT|TF_REUSE_SOCKET); + IO_STATUS_BLOCK *iosb = (IO_STATUS_BLOCK *)overlapped; + struct ws2_transmitfile_async *wsa; + int status, fd; +@@ -2604,8 +2617,8 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWOR + return FALSE; + } + release_sock_fd( s, fd ); +- if (flags) +- FIXME("Flags are not currently supported (0x%x).\n", flags); ++ if (unsupported_flags) ++ FIXME("Flags are not currently supported (0x%x).\n", unsupported_flags); + + if (!overlapped) + return WS2_transmitfile_base( s, h, total_bytes, bytes_per_send, overlapped, buffers, flags ); +diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c +index 652f75f..8f96f84 100644 +--- a/dlls/ws2_32/tests/sock.c ++++ b/dlls/ws2_32/tests/sock.c +@@ -6527,8 +6527,17 @@ static void test_TransmitFile(void) + ok(iret == WAIT_OBJECT_0, "Overlapped TransmitFile failed.\n"); + compare_file(file, dest, 10); + +- /* Test TransmitFile with a UDP datagram socket */ ++ /* Test TransmitFile w/ TF_DISCONNECT */ ++ SetFilePointer(file, 0, NULL, FILE_BEGIN); ++ bret = pTransmitFile(client, file, 0, 0, NULL, NULL, TF_DISCONNECT); ++ ok(bret, "TransmitFile failed unexpectedly.\n"); ++ compare_file(file, dest, 0); + closesocket(client); ++ err = WSAGetLastError(); ++ ok(err == ERROR_INVALID_HANDLE, "TransmitFile triggered unexpected errno (%d != %d)\n", err, ++ ERROR_INVALID_HANDLE); ++ ++ /* Test TransmitFile with a UDP datagram socket */ + 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 06e6309..4426557 100644 +--- a/include/winsock.h ++++ b/include/winsock.h +@@ -810,6 +810,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 fec5e75..a1ac327 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -1220,6 +1220,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 5ffb1fe..242327d 100644 +--- a/server/sock.c ++++ b/server/sock.c +@@ -77,6 +77,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 +@@ -121,6 +122,8 @@ static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, + static void sock_reselect_async( struct fd *fd, struct async_queue *queue ); + static void sock_cancel_async( struct fd *fd, struct process *process, struct thread *thread, client_ptr_t iosb ); + ++static int sock_close_handle( struct object *obj, struct process *process, obj_handle_t handle ); ++ + static int sock_get_ntstatus( int err ); + static int sock_get_error( int err ); + static void sock_set_error(void); +@@ -141,7 +144,7 @@ static const struct object_ops sock_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ +- fd_close_handle, /* close_handle */ ++ sock_close_handle, /* close_handle */ + sock_destroy /* destroy */ + }; + +@@ -580,6 +583,47 @@ 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 (debug_level) ++ fprintf(stderr,"socket(%d,%d,%d)=%d\n",family,type,protocol,sockfd); ++ if (sockfd == -1) ++ { ++ sock_set_error(); ++ 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; +@@ -627,15 +671,8 @@ static struct object *create_socket( int family, int type, int protocol, unsigne + struct sock *sock; + int sockfd; + +- sockfd = socket( family, type, protocol ); +- if (debug_level) +- fprintf(stderr,"socket(%d,%d,%d)=%d\n",family,type,protocol,sockfd); +- if (sockfd == -1) +- { +- sock_set_error(); ++ 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 ); +@@ -960,6 +997,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.7.9.5 + diff --git a/patches/09-TransmitFile/5fb1f5c8-7f17-11e3-9b62-0090f5c75ad5.def b/patches/09-TransmitFile/5fb1f5c8-7f17-11e3-9b62-0090f5c75ad5.def new file mode 100644 index 00000000..f829af11 --- /dev/null +++ b/patches/09-TransmitFile/5fb1f5c8-7f17-11e3-9b62-0090f5c75ad5.def @@ -0,0 +1,3 @@ +Revision: 1 +Author: Erich E. Hoover +Title: Implement TransmitFile. diff --git a/patches/patch-list.patch b/patches/patch-list.patch index 67dd6ff5..c3f94960 100644 --- a/patches/patch-list.patch +++ b/patches/patch-list.patch @@ -33,7 +33,7 @@ diff --git a/libs/wine/config.c b/libs/wine/config.c index a273502..5fa0cd5 100644 --- a/libs/wine/config.c +++ b/libs/wine/config.c -@@ -478,6 +478,34 @@ const char *wine_get_version(void) +@@ -478,6 +478,35 @@ const char *wine_get_version(void) return PACKAGE_VERSION; } @@ -51,6 +51,7 @@ index a273502..5fa0cd5 100644 + { "00273da7-72f8-4025-9e96-0c2bc95dacdb:2", "Maarten Lankhorst", "Winepulse patches extracted from https://launchpad.net/~mlankhorst/+archive/ppa/+files/wine1.7_1.7.10-0ubuntu1~saucy1.debian.tar.gz." }, + { "29b2af38-7edd-11e3-a08d-0090f5c75ad5:1", "Erich E. Hoover", "Add support for security access parameters for named pipes." }, + { "17545d49-1dfc-4294-bb30-2df2f29b0d95:1", "Sebastian Lackner", "Implementation of SRWLock functions." }, ++ { "5fb1f5c8-7f17-11e3-9b62-0090f5c75ad5:1", "Erich E. Hoover", "Implement TransmitFile." }, + { "0b21d7ac-0387-4493-aa38-fbafe3e749f5:1", "Michael Müller", "Decrease minimum SetTimer interval from 15 to 5 ms." }, + { "19835498-8d90-4673-867e-2376af4d7c76:1", "Sebastian Lackner", "Allow to set wined3d strictDrawOrdering via environment variable." }, + { "59bd38b7-bbdc-4cfd-9ccd-1c72c4ed84c0:1", "Sebastian Lackner", "Implement X11DRV_FLUSH_GDI_DISPLAY ExtEscape command." },