[PATCH 2/2 v2] ws2_32: Add tests for exclusive flag for IOCTL_AFD_POLL.
Guillaume Charifi
guillaume.charifi at sfr.fr
Thu Sep 2 16:52:14 CDT 2021
v2: Extensive tests.
Signed-off-by: Guillaume Charifi <guillaume.charifi at sfr.fr>
---
dlls/ws2_32/tests/afd.c | 431 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 431 insertions(+)
diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c
index eb7c8ee50de..f4821e55843 100644
--- a/dlls/ws2_32/tests/afd.c
+++ b/dlls/ws2_32/tests/afd.c
@@ -212,6 +212,7 @@ static void test_poll(void)
in_params->timeout = 0;
in_params->count = 1;
+ in_params->exclusive = FALSE;
in_params->sockets[0].socket = listener;
in_params->sockets[0].flags = ~0;
in_params->sockets[0].status = 0xdeadbeef;
@@ -746,6 +747,435 @@ static void test_poll(void)
free(large_buffer);
}
+struct poll_exclusive_thread_cb_ctx
+{
+ SOCKET ctl_sock;
+ HANDLE event;
+ IO_STATUS_BLOCK *io;
+ ULONG params_size;
+ struct afd_poll_params *in_params;
+ struct afd_poll_params *out_params;
+};
+
+static DWORD WINAPI poll_exclusive_thread_cb(void *param)
+{
+ struct poll_exclusive_thread_cb_ctx *ctx = param;
+ int ret;
+
+ ret = NtDeviceIoControlFile((HANDLE)ctx->ctl_sock, ctx->event, NULL, NULL, ctx->io,
+ IOCTL_AFD_POLL, ctx->in_params, ctx->params_size, ctx->out_params, ctx->params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(ctx->event, 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ return 0;
+}
+
+#define POLL_SOCK_CNT 2
+#define POLL_CNT 4
+
+static void test_poll_exclusive(void)
+{
+ char in_buffer[offsetof(struct afd_poll_params, sockets[POLL_SOCK_CNT + 1])];
+ char out_buffers[POLL_CNT][offsetof(struct afd_poll_params, sockets[POLL_SOCK_CNT + 1])];
+ struct afd_poll_params *in_params = (struct afd_poll_params *)in_buffer;
+ struct afd_poll_params *out_params[POLL_CNT] = {
+ (struct afd_poll_params *)out_buffers[0],
+ (struct afd_poll_params *)out_buffers[1],
+ (struct afd_poll_params *)out_buffers[2],
+ (struct afd_poll_params *)out_buffers[3]
+ };
+ SOCKET ctl_sock;
+ SOCKET socks[POLL_CNT];
+ IO_STATUS_BLOCK io[POLL_CNT];
+ HANDLE events[POLL_CNT];
+ ULONG params_size;
+ struct poll_exclusive_thread_cb_ctx cb_ctx;
+ HANDLE thrd;
+ int ret;
+
+ ctl_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ for (size_t i = 0; i < POLL_CNT; i++)
+ {
+ socks[i] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ events[i] = CreateEventW(NULL, TRUE, FALSE, NULL);
+ }
+
+ params_size = offsetof(struct afd_poll_params, sockets[1]);
+
+ in_params->timeout = 0x7fffffffffffffff; /* TIMEOUT_INFINITE */
+ in_params->count = 1;
+ in_params->exclusive = FALSE;
+ in_params->sockets[0].socket = socks[0];
+ in_params->sockets[0].flags = ~0;
+ in_params->sockets[0].status = 0;
+
+ /***** Exclusive explicitely terminated *****/
+
+ /*
+ * (0) Exclusive | [A] Cancel (0)
+ * Terminated by [A] |
+ */
+
+ in_params->exclusive = TRUE;
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[0], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ CancelIo((HANDLE)ctl_sock);
+
+ ret = WaitForSingleObject(events[0], 100);
+ ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
+
+ /***** Same socket tests *****/
+
+ /*
+ * (0) Non-exclusive | (1) Non-exclusive
+ * Not terminated | Not terminated
+ */
+
+ in_params->exclusive = FALSE;
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[0], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[1], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ CancelIo((HANDLE)ctl_sock);
+
+ /***** Same socket tests *****/
+
+ /*
+ * (0) Exclusive | (1) Exclusive
+ * Terminated by (1) | Not terminated
+ */
+
+ in_params->exclusive = TRUE;
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[0], 100);
+ ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[1], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ CancelIo((HANDLE)ctl_sock);
+
+ /*
+ * (0) Non-exclusive | (1) Exclusive | (2) Exclusive
+ * Not terminated | Not terminated | Not terminated
+ */
+
+ in_params->exclusive = FALSE;
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ in_params->exclusive = TRUE;
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[2], NULL, NULL, &io[2],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[2], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[0], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[1], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[2], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ CancelIo((HANDLE)ctl_sock);
+
+ /*
+ * (0) Non-exclusive | [A] Cancel (0) | (1) Exclusive | (2) Exclusive
+ * Terminated by [A] | | Terminated by (2) | Not terminated
+ */
+
+ in_params->exclusive = FALSE;
+
+ ret = NtDeviceIoControlFile((HANDLE)socks[0], events[0], NULL, NULL, &io[0],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ CancelIo((HANDLE)socks[0]);
+
+ ret = WaitForSingleObject(events[0], 100);
+ ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
+
+ in_params->exclusive = TRUE;
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[2], NULL, NULL, &io[2],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[2], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[1], 100);
+ ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[2], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ CancelIo((HANDLE)ctl_sock);
+
+ /*
+ * (0) Non-exclusive | (1) Exclusive | [A] Cancel (0) | (2) Exclusive
+ * Terminated by [A] | Not terminated | | Not terminated
+ */
+
+ in_params->exclusive = FALSE;
+
+ ret = NtDeviceIoControlFile((HANDLE)socks[0], events[0], NULL, NULL, &io[0],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ in_params->exclusive = TRUE;
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ CancelIo((HANDLE)socks[0]);
+
+ ret = WaitForSingleObject(events[0], 100);
+ ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[2], NULL, NULL, &io[2],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[2], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[1], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[2], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ CancelIo((HANDLE)ctl_sock);
+
+ /*
+ * (0) Non-exclusive | (1) Exclusive | [A] Cancel (0) | (2) Exclusive | (3) Exclusive
+ * Terminated by [A] | Not terminated | | Terminated by (3) | Not terminated
+ */
+
+ in_params->exclusive = FALSE;
+
+ ret = NtDeviceIoControlFile((HANDLE)socks[0], events[0], NULL, NULL, &io[0],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ in_params->exclusive = TRUE;
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ CancelIo((HANDLE)socks[0]);
+
+ ret = WaitForSingleObject(events[0], 100);
+ ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[2], NULL, NULL, &io[2],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[2], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[3], NULL, NULL, &io[3],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[3], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[1], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[2], 100);
+ ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[3], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ CancelIo((HANDLE)ctl_sock);
+
+ /*
+ * (0) Exclusive | (1) Non-exclusive | (2) Exclusive | (3) Exclusive
+ * Terminated by (2) | Not terminated | Terminated by (3) | Not terminated
+ */
+
+ in_params->exclusive = TRUE;
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ in_params->exclusive = FALSE;
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[0], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ in_params->exclusive = TRUE;
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[2], NULL, NULL, &io[2],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[2], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[0], 100);
+ ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[2], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[3], NULL, NULL, &io[3],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[3], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[2], 100);
+ ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[1], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[3], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ CancelIo((HANDLE)ctl_sock);
+
+ /***** Exclusive poll on different sockets *****/
+
+ /*
+ * (0) Exclusive 0 | (1) Exclusive 1
+ * Not terminated | Not terminated
+ */
+
+ in_params->exclusive = TRUE;
+ in_params->sockets[0].socket = socks[0];
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ in_params->sockets[0].socket = socks[1];
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[0], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[1], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ CancelIo((HANDLE)ctl_sock);
+
+ /***** Exclusive poll from other thread *****/
+
+ /*
+ * (0) Exclusive | (1) Exclusive
+ * Terminated by (1) | Not terminated
+ */
+
+ in_params->exclusive = TRUE;
+ in_params->sockets[0].socket = ctl_sock;
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ cb_ctx.ctl_sock = ctl_sock;
+ cb_ctx.event = events[1];
+ cb_ctx.io = &io[1];
+ cb_ctx.params_size = params_size;
+ cb_ctx.in_params = in_params;
+ cb_ctx.out_params = out_params[1];
+
+ thrd = CreateThread(NULL, 0, poll_exclusive_thread_cb, &cb_ctx, 0, NULL);
+ WaitForSingleObject(thrd, INFINITE);
+ CloseHandle(thrd);
+
+ ret = WaitForSingleObject(events[0], 100);
+ ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
+
+ CancelIo((HANDLE)ctl_sock);
+
+ /***** Exclusive poll on multiple overlapping socket sets *****/
+
+ /*
+ * (0) Exclusive c,0 | (1) Exclusive c,1
+ * Terminated by (1) | Not terminated
+ */
+
+ params_size = offsetof(struct afd_poll_params, sockets[2]);
+
+ in_params->exclusive = TRUE;
+ in_params->count = 2;
+ in_params->sockets[0].socket = ctl_sock;
+ in_params->sockets[1].socket = socks[0];
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[0], NULL, NULL, &io[0],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[0], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ in_params->sockets[0].socket = ctl_sock;
+ in_params->sockets[1].socket = socks[1];
+
+ ret = NtDeviceIoControlFile((HANDLE)ctl_sock, events[1], NULL, NULL, &io[1],
+ IOCTL_AFD_POLL, in_params, params_size, out_params[1], params_size);
+ ok(ret == STATUS_PENDING, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[0], 100);
+ ok(ret == STATUS_SUCCESS, "got %#x\n", ret);
+
+ ret = WaitForSingleObject(events[1], 100);
+ ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
+
+ CancelIo((HANDLE)ctl_sock);
+
+ /* Cleanup */
+
+ closesocket(ctl_sock);
+
+ for (size_t i = 0; i < POLL_CNT; i++)
+ {
+ closesocket(socks[i]);
+ CloseHandle(events[i]);
+ }
+}
+
+#undef POLL_SOCK_CNT
+#undef POLL_CNT
+
static void test_poll_completion_port(void)
{
struct afd_poll_params params = {0};
@@ -1751,6 +2181,7 @@ START_TEST(afd)
test_open_device();
test_poll();
+ test_poll_exclusive();
test_poll_completion_port();
test_recv();
test_event_select();
--
2.33.0
More information about the wine-devel
mailing list