Commit effd2c41 authored by Erich E. Hoover's avatar Erich E. Hoover Committed by Alexandre Julliard

ws2_32: Add asynchronous support for TransmitFile.

parent b9d8c2b1
......@@ -177,6 +177,8 @@
#define TCP_KEEPIDLE TCP_KEEPALIVE
#endif
#define FILE_USE_FILE_POINTER_POSITION ((LONGLONG)-2)
WINE_DEFAULT_DEBUG_CHANNEL(winsock);
WINE_DECLARE_DEBUG_CHANNEL(winediag);
......@@ -524,6 +526,7 @@ struct ws2_transmitfile_async
DWORD bytes_per_send;
TRANSMIT_FILE_BUFFERS buffers;
DWORD flags;
LARGE_INTEGER offset;
struct ws2_async write;
};
......@@ -2742,9 +2745,10 @@ static BOOL WINAPI WS2_AcceptEx(SOCKET listener, SOCKET acceptor, PVOID dest, DW
*
* Perform an APC-safe ReadFile operation
*/
static NTSTATUS WS2_ReadFile(HANDLE hFile, PIO_STATUS_BLOCK io_status, char* buffer, ULONG length)
static NTSTATUS WS2_ReadFile(HANDLE hFile, PIO_STATUS_BLOCK io_status, char* buffer, ULONG length,
PLARGE_INTEGER offset)
{
int result, unix_handle;
int result = -1, unix_handle;
unsigned int options;
NTSTATUS status;
......@@ -2753,8 +2757,12 @@ static NTSTATUS WS2_ReadFile(HANDLE hFile, PIO_STATUS_BLOCK io_status, char* buf
status = wine_server_handle_to_fd( hFile, FILE_READ_DATA, &unix_handle, &options );
if (status) return status;
while ((result = read( unix_handle, buffer, length )) == -1)
while (result == -1)
{
if (offset->QuadPart != FILE_USE_FILE_POINTER_POSITION)
result = pread( unix_handle, buffer, length, offset->QuadPart );
else
result = read( unix_handle, buffer, length );
if (errno != EINTR)
break;
}
......@@ -2808,10 +2816,13 @@ static NTSTATUS WS2_transmitfile_getbuffer( int fd, struct ws2_transmitfile_asyn
IO_STATUS_BLOCK iosb;
NTSTATUS status;
iosb.Information = 0;
/* when the size of the transfer is limited ensure that we don't go past that limit */
if (wsa->file_bytes != 0)
bytes_per_send = min(bytes_per_send, wsa->file_bytes - wsa->file_read);
status = WS2_ReadFile( wsa->file, &iosb, wsa->buffer, bytes_per_send );
status = WS2_ReadFile( wsa->file, &iosb, wsa->buffer, bytes_per_send, &wsa->offset );
if (wsa->offset.QuadPart != FILE_USE_FILE_POINTER_POSITION)
wsa->offset.QuadPart += iosb.Information;
if (status == STATUS_END_OF_FILE)
wsa->file = NULL; /* continue on to the footer */
else if (status != STATUS_SUCCESS)
......@@ -2860,10 +2871,15 @@ static NTSTATUS WS2_transmitfile_base( int fd, struct ws2_transmitfile_async *ws
status = WS2_transmitfile_getbuffer( fd, wsa );
if (status == STATUS_PENDING)
{
IO_STATUS_BLOCK *iosb = (IO_STATUS_BLOCK *)wsa->write.user_overlapped;
int n;
n = WS2_send( fd, &wsa->write, convert_flags(wsa->write.flags) );
if (n == -1 && errno != EAGAIN)
if (n >= 0)
{
if (iosb) iosb->Information += n;
}
else if (errno != EAGAIN)
return wsaErrStatus();
}
......@@ -2871,6 +2887,33 @@ static NTSTATUS WS2_transmitfile_base( int fd, struct ws2_transmitfile_async *ws
}
/***********************************************************************
* WS2_async_transmitfile (INTERNAL)
*
* Asynchronous callback for overlapped TransmitFile operations.
*/
static NTSTATUS WS2_async_transmitfile( void *user, IO_STATUS_BLOCK *iosb,
NTSTATUS status, void **apc, void **arg )
{
struct ws2_transmitfile_async *wsa = user;
int fd;
if (status == STATUS_ALERTED)
{
if (!(status = wine_server_handle_to_fd( wsa->write.hSocket, FILE_WRITE_DATA, &fd, NULL )))
{
status = WS2_transmitfile_base( fd, wsa );
wine_server_release_fd( wsa->write.hSocket, fd );
}
if (status == STATUS_PENDING)
return status;
}
iosb->u.Status = status;
release_async_io( &wsa->io );
return status;
}
/***********************************************************************
* TransmitFile
*/
static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD file_bytes, DWORD bytes_per_send,
......@@ -2883,14 +2926,6 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD file_bytes, DWORD
NTSTATUS status;
int fd;
if (overlapped)
{
FIXME("(%lx, %p, %d, %d, %p, %p, %d): stub !\n", s, h, file_bytes, bytes_per_send,
overlapped, buffers, flags);
WSASetLastError( WSAEOPNOTSUPP );
return FALSE;
}
TRACE("(%lx, %p, %d, %d, %p, %p, %d)\n", s, h, file_bytes, bytes_per_send, overlapped,
buffers, flags );
......@@ -2937,6 +2972,7 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD file_bytes, DWORD
wsa->file_bytes = file_bytes;
wsa->bytes_per_send = bytes_per_send;
wsa->flags = flags;
wsa->offset.QuadPart = FILE_USE_FILE_POINTER_POSITION;
wsa->write.hSocket = SOCKET2HANDLE(s);
wsa->write.addr = NULL;
wsa->write.addrlen.val = 0;
......@@ -2945,7 +2981,33 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD file_bytes, DWORD
wsa->write.control = NULL;
wsa->write.n_iovecs = 0;
wsa->write.first_iovec = 0;
wsa->write.user_overlapped = NULL;
wsa->write.user_overlapped = overlapped;
if (overlapped)
{
IO_STATUS_BLOCK *iosb = (IO_STATUS_BLOCK *)overlapped;
int status;
wsa->offset.u.LowPart = overlapped->u.s.Offset;
wsa->offset.u.HighPart = overlapped->u.s.OffsetHigh;
iosb->u.Status = STATUS_PENDING;
iosb->Information = 0;
SERVER_START_REQ( register_async )
{
req->type = ASYNC_TYPE_WRITE;
req->async.handle = wine_server_obj_handle( SOCKET2HANDLE(s) );
req->async.event = wine_server_obj_handle( overlapped->hEvent );
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 );
release_sock_fd( s, fd );
WSASetLastError( NtStatusToWSAError(status) );
return FALSE;
}
do
{
......
......@@ -7429,15 +7429,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;
......@@ -7457,6 +7457,7 @@ static void compare_file2(HANDLE handle, SOCKET sock, const char *file, int line
static void test_TransmitFile(void)
{
DWORD num_bytes, err, file_size, total_sent;
GUID transmitFileGuid = WSAID_TRANSMITFILE;
LPFN_TRANSMITFILE pTransmitFile = NULL;
HANDLE file = INVALID_HANDLE_VALUE;
......@@ -7466,11 +7467,13 @@ static void test_TransmitFile(void)
struct sockaddr_in bindAddress;
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);
......@@ -7494,6 +7497,7 @@ static void test_TransmitFile(void)
skip("Unable to open a file to transmit.\n");
goto cleanup;
}
file_size = GetFileSize(file, NULL);
/* Test TransmitFile with an invalid socket */
bret = pTransmitFile(INVALID_SOCKET, file, 0, 0, NULL, NULL, 0);
......@@ -7567,7 +7571,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];
......@@ -7580,7 +7584,81 @@ 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, 2000);
ok(iret == WAIT_OBJECT_0, "Overlapped TransmitFile failed.\n");
WSAGetOverlappedResult(client, &ov, &total_sent, FALSE, NULL);
ok(total_sent == file_size,
"Overlapped TransmitFile sent an unexpected number of bytes (%d != %d).\n",
total_sent, file_size);
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, 2000);
ok(iret == WAIT_OBJECT_0, "Overlapped TransmitFile failed.\n");
WSAGetOverlappedResult(client, &ov, &total_sent, FALSE, NULL);
ok(total_sent == (file_size - ov.Offset),
"Overlapped TransmitFile sent an unexpected number of bytes (%d != %d).\n",
total_sent, file_size - ov.Offset);
compare_file(file, dest, ov.Offset);
/* Test overlapped TransmitFile w/ file and buffer data */
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;
}
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);
ov.Offset = 0;
bret = pTransmitFile(client, file, 0, 0, &ov, &buffers, 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, 2000);
ok(iret == WAIT_OBJECT_0, "Overlapped TransmitFile failed.\n");
WSAGetOverlappedResult(client, &ov, &total_sent, FALSE, NULL);
ok(total_sent == (file_size + buffers.HeadLength + buffers.TailLength),
"Overlapped TransmitFile sent an unexpected number of bytes (%d != %d).\n",
total_sent, file_size + buffers.HeadLength + buffers.TailLength);
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, 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");
......@@ -7595,6 +7673,7 @@ static void test_TransmitFile(void)
cleanup:
CloseHandle(file);
CloseHandle(ov.hEvent);
closesocket(client);
closesocket(server);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment