gdi32: Fix leak in GdiDeleteSpoolFileHandle.
[wine.git] / dlls / netio.sys / netio.c
blob05b5d6d2a69cb198bc4a7bf7d0c41f7dc8ea3610
1 /*
2 * WSK (Winsock Kernel) driver library.
4 * Copyright 2020 Paul Gofman <pgofman@codeweavers.com> for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "windef.h"
26 #include "winioctl.h"
27 #include "winternl.h"
28 #include "ddk/wdm.h"
29 #include "ddk/wsk.h"
30 #include "wine/debug.h"
31 #include "winsock2.h"
32 #include "ws2tcpip.h"
34 #include "wine/heap.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(netio);
38 struct _WSK_CLIENT
40 WSK_REGISTRATION *registration;
41 WSK_CLIENT_NPI *client_npi;
44 struct listen_socket_callback_context
46 SOCKADDR *local_address;
47 SOCKADDR *remote_address;
48 const void *client_dispatch;
49 void *client_context;
50 char addr_buffer[2 * (sizeof(SOCKADDR) + 16)];
51 SOCKET acceptor;
54 #define MAX_PENDING_IO 10
56 struct wsk_pending_io
58 OVERLAPPED ovr;
59 TP_WAIT *tp_wait;
60 void *callback;
61 IRP *irp;
64 struct wsk_socket_internal
66 WSK_SOCKET wsk_socket;
67 SOCKET s;
68 const void *client_dispatch;
69 void *client_context;
70 ULONG flags;
71 ADDRESS_FAMILY address_family;
72 USHORT socket_type;
73 ULONG protocol;
74 BOOL bound;
76 CRITICAL_SECTION cs_socket;
78 struct wsk_pending_io pending_io[MAX_PENDING_IO];
80 union
82 struct listen_socket_callback_context listen_socket_callback_context;
84 callback_context;
87 static LPFN_ACCEPTEX pAcceptEx;
88 static LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockaddrs;
89 static LPFN_CONNECTEX pConnectEx;
91 static const WSK_PROVIDER_CONNECTION_DISPATCH wsk_provider_connection_dispatch;
93 static inline struct wsk_socket_internal *wsk_socket_internal_from_wsk_socket(WSK_SOCKET *wsk_socket)
95 return CONTAINING_RECORD(wsk_socket, struct wsk_socket_internal, wsk_socket);
98 static NTSTATUS sock_error_to_ntstatus(DWORD err)
100 switch (err)
102 case 0: return STATUS_SUCCESS;
103 case WSAEBADF: return STATUS_INVALID_HANDLE;
104 case WSAEACCES: return STATUS_ACCESS_DENIED;
105 case WSAEFAULT: return STATUS_NO_MEMORY;
106 case WSAEINVAL: return STATUS_INVALID_PARAMETER;
107 case WSAEMFILE: return STATUS_TOO_MANY_OPENED_FILES;
108 case WSAEWOULDBLOCK: return STATUS_CANT_WAIT;
109 case WSAEINPROGRESS: return STATUS_PENDING;
110 case WSAEALREADY: return STATUS_NETWORK_BUSY;
111 case WSAENOTSOCK: return STATUS_OBJECT_TYPE_MISMATCH;
112 case WSAEDESTADDRREQ: return STATUS_INVALID_PARAMETER;
113 case WSAEMSGSIZE: return STATUS_BUFFER_OVERFLOW;
114 case WSAEPROTONOSUPPORT:
115 case WSAESOCKTNOSUPPORT:
116 case WSAEPFNOSUPPORT:
117 case WSAEAFNOSUPPORT:
118 case WSAEPROTOTYPE: return STATUS_NOT_SUPPORTED;
119 case WSAENOPROTOOPT: return STATUS_INVALID_PARAMETER;
120 case WSAEOPNOTSUPP: return STATUS_NOT_IMPLEMENTED;
121 case WSAEADDRINUSE: return STATUS_ADDRESS_ALREADY_ASSOCIATED;
122 case WSAEADDRNOTAVAIL: return STATUS_INVALID_PARAMETER;
123 case WSAECONNREFUSED: return STATUS_CONNECTION_REFUSED;
124 case WSAESHUTDOWN: return STATUS_PIPE_DISCONNECTED;
125 case WSAENOTCONN: return STATUS_CONNECTION_DISCONNECTED;
126 case WSAETIMEDOUT: return STATUS_IO_TIMEOUT;
127 case WSAENETUNREACH: return STATUS_NETWORK_UNREACHABLE;
128 case WSAENETDOWN: return STATUS_NETWORK_BUSY;
129 case WSAECONNRESET: return STATUS_CONNECTION_RESET;
130 case WSAECONNABORTED: return STATUS_CONNECTION_ABORTED;
131 case WSAHOST_NOT_FOUND: return STATUS_NOT_FOUND;
132 default:
133 FIXME("Unmapped error %lu.\n", err);
134 return STATUS_UNSUCCESSFUL;
138 static inline void lock_socket(struct wsk_socket_internal *socket)
140 EnterCriticalSection(&socket->cs_socket);
143 static inline void unlock_socket(struct wsk_socket_internal *socket)
145 LeaveCriticalSection(&socket->cs_socket);
148 static void socket_init(struct wsk_socket_internal *socket)
150 InitializeCriticalSection(&socket->cs_socket);
153 static void dispatch_irp(IRP *irp, NTSTATUS status)
155 irp->IoStatus.Status = status;
156 --irp->CurrentLocation;
157 --irp->Tail.Overlay.CurrentStackLocation;
158 IoCompleteRequest(irp, IO_NO_INCREMENT);
161 static struct wsk_pending_io *allocate_pending_io(struct wsk_socket_internal *socket,
162 PTP_WAIT_CALLBACK socket_async_callback, IRP *irp)
164 struct wsk_pending_io *io = socket->pending_io;
165 unsigned int i, io_index;
167 io_index = ~0u;
168 for (i = 0; i < ARRAY_SIZE(socket->pending_io); ++i)
170 if (!io[i].irp)
172 if (io[i].callback == socket_async_callback)
174 io[i].irp = irp;
175 return &io[i];
178 if (io_index == ~0u)
179 io_index = i;
183 if (io_index == ~0u)
185 FIXME("Pending io requests count exceeds limit.\n");
186 return NULL;
189 io[io_index].irp = irp;
191 if (io[io_index].tp_wait)
192 CloseThreadpoolWait(io[io_index].tp_wait);
193 else
194 io[io_index].ovr.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
196 io[io_index].tp_wait = CreateThreadpoolWait(socket_async_callback, socket, NULL);
197 io[io_index].callback = socket_async_callback;
199 return &io[io_index];
202 static struct wsk_pending_io *find_pending_io(struct wsk_socket_internal *socket, TP_WAIT *tp_wait)
204 unsigned int i;
206 for (i = 0; i < ARRAY_SIZE(socket->pending_io); ++i)
208 if (socket->pending_io[i].tp_wait == tp_wait)
209 return &socket->pending_io[i];
212 FIXME("Pending io not found for tp_wait %p.\n", tp_wait);
213 return NULL;
216 static void dispatch_pending_io(struct wsk_pending_io *io, NTSTATUS status, ULONG_PTR information)
218 TRACE("io %p, status %#lx, information %#Ix.\n", io, status, information);
220 io->irp->IoStatus.Information = information;
221 dispatch_irp(io->irp, status);
222 io->irp = NULL;
225 static NTSTATUS WINAPI wsk_control_socket(WSK_SOCKET *socket, WSK_CONTROL_SOCKET_TYPE request_type,
226 ULONG control_code, ULONG level, SIZE_T input_size, void *input_buffer, SIZE_T output_size,
227 void *output_buffer, SIZE_T *output_size_returned, IRP *irp)
229 FIXME("socket %p, request_type %u, control_code %#lx, level %lu, input_size %Iu, input_buffer %p, "
230 "output_size %Iu, output_buffer %p, output_size_returned %p, irp %p stub.\n",
231 socket, request_type, control_code, level, input_size, input_buffer, output_size,
232 output_buffer, output_size_returned, irp);
234 return STATUS_NOT_IMPLEMENTED;
237 static NTSTATUS WINAPI wsk_close_socket(WSK_SOCKET *socket, IRP *irp)
239 struct wsk_socket_internal *s = wsk_socket_internal_from_wsk_socket(socket);
240 NTSTATUS status;
241 unsigned int i;
243 TRACE("socket %p, irp %p.\n", socket, irp);
245 lock_socket(s);
247 for (i = 0; i < ARRAY_SIZE(s->pending_io); ++i)
249 struct wsk_pending_io *io = &s->pending_io[i];
251 if (io->tp_wait)
253 CancelIoEx((HANDLE)s->s, &io->ovr);
254 SetThreadpoolWait(io->tp_wait, NULL, NULL);
255 unlock_socket(s);
256 WaitForThreadpoolWaitCallbacks(io->tp_wait, FALSE);
257 lock_socket(s);
258 CloseThreadpoolWait(io->tp_wait);
259 CloseHandle(io->ovr.hEvent);
262 if (io->irp)
263 dispatch_pending_io(io, STATUS_CANCELLED, 0);
266 if (s->flags & WSK_FLAG_LISTEN_SOCKET && s->callback_context.listen_socket_callback_context.acceptor)
267 closesocket(s->callback_context.listen_socket_callback_context.acceptor);
269 status = closesocket(s->s) ? sock_error_to_ntstatus(WSAGetLastError()) : STATUS_SUCCESS;
271 unlock_socket(s);
272 DeleteCriticalSection(&s->cs_socket);
273 heap_free(socket);
275 irp->IoStatus.Information = 0;
276 dispatch_irp(irp, status);
278 return status ? status : STATUS_PENDING;
281 static NTSTATUS WINAPI wsk_bind(WSK_SOCKET *socket, SOCKADDR *local_address, ULONG flags, IRP *irp)
283 struct wsk_socket_internal *s = wsk_socket_internal_from_wsk_socket(socket);
284 NTSTATUS status;
286 TRACE("socket %p, local_address %p, flags %#lx, irp %p.\n",
287 socket, local_address, flags, irp);
289 if (!irp)
290 return STATUS_INVALID_PARAMETER;
292 if (bind(s->s, local_address, sizeof(*local_address)))
293 status = sock_error_to_ntstatus(WSAGetLastError());
294 else if (s->flags & WSK_FLAG_LISTEN_SOCKET && listen(s->s, SOMAXCONN))
295 status = sock_error_to_ntstatus(WSAGetLastError());
296 else
297 status = STATUS_SUCCESS;
299 if (status == STATUS_SUCCESS)
300 s->bound = TRUE;
302 TRACE("status %#lx.\n", status);
303 irp->IoStatus.Information = 0;
304 dispatch_irp(irp, status);
305 return STATUS_PENDING;
308 static void create_accept_socket(struct wsk_socket_internal *socket, struct wsk_pending_io *io)
310 struct listen_socket_callback_context *context
311 = &socket->callback_context.listen_socket_callback_context;
312 INT local_address_len, remote_address_len;
313 SOCKADDR *local_address, *remote_address;
314 struct wsk_socket_internal *accept_socket;
316 if (!(accept_socket = heap_alloc_zero(sizeof(*accept_socket))))
318 ERR("No memory.\n");
319 dispatch_pending_io(io, STATUS_NO_MEMORY, 0);
321 else
323 TRACE("accept_socket %p.\n", accept_socket);
324 accept_socket->wsk_socket.Dispatch = &wsk_provider_connection_dispatch;
325 accept_socket->s = context->acceptor;
326 accept_socket->client_dispatch = context->client_dispatch;
327 accept_socket->client_context = context->client_context;
328 accept_socket->socket_type = socket->socket_type;
329 accept_socket->address_family = socket->address_family;
330 accept_socket->protocol = socket->protocol;
331 accept_socket->flags = WSK_FLAG_CONNECTION_SOCKET;
332 socket_init(accept_socket);
334 pGetAcceptExSockaddrs(context->addr_buffer, 0, sizeof(SOCKADDR) + 16, sizeof(SOCKADDR) + 16,
335 &local_address, &local_address_len, &remote_address, &remote_address_len);
337 if (context->local_address)
338 memcpy(context->local_address, local_address,
339 min(sizeof(*context->local_address), local_address_len));
341 if (context->remote_address)
342 memcpy(context->remote_address, remote_address,
343 min(sizeof(*context->remote_address), remote_address_len));
345 dispatch_pending_io(io, STATUS_SUCCESS, (ULONG_PTR)&accept_socket->wsk_socket);
349 static void WINAPI accept_callback(TP_CALLBACK_INSTANCE *instance, void *socket_, TP_WAIT *wait,
350 TP_WAIT_RESULT wait_result)
352 struct listen_socket_callback_context *context;
353 struct wsk_socket_internal *socket = socket_;
354 struct wsk_pending_io *io;
355 DWORD size;
357 TRACE("instance %p, socket %p, wait %p, wait_result %#lx.\n", instance, socket, wait, wait_result);
359 lock_socket(socket);
360 context = &socket->callback_context.listen_socket_callback_context;
361 io = find_pending_io(socket, wait);
363 if (GetOverlappedResult((HANDLE)socket->s, &io->ovr, &size, FALSE))
365 create_accept_socket(socket, io);
367 else
369 closesocket(context->acceptor);
370 context->acceptor = 0;
371 dispatch_pending_io(io, io->ovr.Internal, 0);
373 unlock_socket(socket);
376 static BOOL WINAPI init_accept_functions(INIT_ONCE *once, void *param, void **context)
378 GUID get_acceptex_guid = WSAID_GETACCEPTEXSOCKADDRS;
379 GUID acceptex_guid = WSAID_ACCEPTEX;
380 SOCKET s = (SOCKET)param;
381 DWORD size;
383 if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &acceptex_guid, sizeof(acceptex_guid),
384 &pAcceptEx, sizeof(pAcceptEx), &size, NULL, NULL))
386 ERR("Could not get AcceptEx address, error %u.\n", WSAGetLastError());
387 return FALSE;
390 if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &get_acceptex_guid, sizeof(get_acceptex_guid),
391 &pGetAcceptExSockaddrs, sizeof(pGetAcceptExSockaddrs), &size, NULL, NULL))
393 ERR("Could not get AcceptEx address, error %u.\n", WSAGetLastError());
394 return FALSE;
397 return TRUE;
400 static NTSTATUS WINAPI wsk_accept(WSK_SOCKET *listen_socket, ULONG flags, void *accept_socket_context,
401 const WSK_CLIENT_CONNECTION_DISPATCH *accept_socket_dispatch, SOCKADDR *local_address,
402 SOCKADDR *remote_address, IRP *irp)
404 struct wsk_socket_internal *s = wsk_socket_internal_from_wsk_socket(listen_socket);
405 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
406 struct listen_socket_callback_context *context;
407 struct wsk_pending_io *io;
408 SOCKET acceptor;
409 DWORD size;
410 int error;
412 TRACE("listen_socket %p, flags %#lx, accept_socket_context %p, accept_socket_dispatch %p, "
413 "local_address %p, remote_address %p, irp %p.\n",
414 listen_socket, flags, accept_socket_context, accept_socket_dispatch, local_address,
415 remote_address, irp);
417 if (!irp)
418 return STATUS_INVALID_PARAMETER;
420 if (!InitOnceExecuteOnce(&init_once, init_accept_functions, (void *)s->s, NULL))
422 dispatch_irp(irp, STATUS_UNSUCCESSFUL);
423 return STATUS_PENDING;
426 lock_socket(s);
427 if (!(io = allocate_pending_io(s, accept_callback, irp)))
429 irp->IoStatus.Information = 0;
430 dispatch_irp(irp, STATUS_UNSUCCESSFUL);
431 unlock_socket(s);
432 return STATUS_PENDING;
435 context = &s->callback_context.listen_socket_callback_context;
436 if ((acceptor = WSASocketW(s->address_family, s->socket_type, s->protocol, NULL, 0, WSA_FLAG_OVERLAPPED))
437 == INVALID_SOCKET)
439 dispatch_pending_io(io, sock_error_to_ntstatus(WSAGetLastError()), 0);
440 unlock_socket(s);
441 return STATUS_PENDING;
444 context->local_address = local_address;
445 context->remote_address = remote_address;
446 context->client_dispatch = accept_socket_dispatch;
447 context->client_context = accept_socket_context;
448 context->acceptor = acceptor;
450 if (pAcceptEx(s->s, acceptor, context->addr_buffer, 0,
451 sizeof(SOCKADDR) + 16, sizeof(SOCKADDR) + 16, &size, &io->ovr))
453 create_accept_socket(s, io);
455 else if ((error = WSAGetLastError()) == ERROR_IO_PENDING)
457 SetThreadpoolWait(io->tp_wait, io->ovr.hEvent, NULL);
459 else
461 closesocket(acceptor);
462 context->acceptor = 0;
463 dispatch_pending_io(io, sock_error_to_ntstatus(error), 0);
465 unlock_socket(s);
467 return STATUS_PENDING;
470 static NTSTATUS WINAPI wsk_inspect_complete(WSK_SOCKET *listen_socket, WSK_INSPECT_ID *inspect_id,
471 WSK_INSPECT_ACTION action, IRP *irp)
473 FIXME("listen_socket %p, inspect_id %p, action %u, irp %p stub.\n",
474 listen_socket, inspect_id, action, irp);
476 return STATUS_NOT_IMPLEMENTED;
479 static NTSTATUS WINAPI wsk_get_local_address(WSK_SOCKET *socket, SOCKADDR *local_address, IRP *irp)
481 FIXME("socket %p, local_address %p, irp %p stub.\n", socket, local_address, irp);
483 return STATUS_NOT_IMPLEMENTED;
486 static const WSK_PROVIDER_LISTEN_DISPATCH wsk_provider_listen_dispatch =
489 wsk_control_socket,
490 wsk_close_socket,
492 wsk_bind,
493 wsk_accept,
494 wsk_inspect_complete,
495 wsk_get_local_address,
498 static void WINAPI connect_callback(TP_CALLBACK_INSTANCE *instance, void *socket_, TP_WAIT *wait,
499 TP_WAIT_RESULT wait_result)
501 struct wsk_socket_internal *socket = socket_;
502 struct wsk_pending_io *io;
503 DWORD size;
505 TRACE("instance %p, socket %p, wait %p, wait_result %#lx.\n", instance, socket, wait, wait_result);
507 lock_socket(socket);
508 io = find_pending_io(socket, wait);
510 GetOverlappedResult((HANDLE)socket->s, &io->ovr, &size, FALSE);
511 dispatch_pending_io(io, io->ovr.Internal, 0);
512 unlock_socket(socket);
515 static BOOL WINAPI init_connect_functions(INIT_ONCE *once, void *param, void **context)
517 GUID connectex_guid = WSAID_CONNECTEX;
518 SOCKET s = (SOCKET)param;
519 DWORD size;
521 if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &connectex_guid, sizeof(connectex_guid),
522 &pConnectEx, sizeof(pConnectEx), &size, NULL, NULL))
524 ERR("Could not get AcceptEx address, error %u.\n", WSAGetLastError());
525 return FALSE;
527 return TRUE;
530 static NTSTATUS WINAPI wsk_connect(WSK_SOCKET *socket, SOCKADDR *remote_address, ULONG flags, IRP *irp)
532 struct wsk_socket_internal *s = wsk_socket_internal_from_wsk_socket(socket);
533 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
534 struct wsk_pending_io *io;
535 int error;
537 TRACE("socket %p, remote_address %p, flags %#lx, irp %p.\n",
538 socket, remote_address, flags, irp);
540 if (!irp)
541 return STATUS_INVALID_PARAMETER;
543 if (!InitOnceExecuteOnce(&init_once, init_connect_functions, (void *)s->s, NULL))
545 dispatch_irp(irp, STATUS_UNSUCCESSFUL);
546 return STATUS_PENDING;
549 lock_socket(s);
551 if (!(io = allocate_pending_io(s, connect_callback, irp)))
553 irp->IoStatus.Information = 0;
554 dispatch_irp(irp, STATUS_UNSUCCESSFUL);
555 unlock_socket(s);
556 return STATUS_PENDING;
559 if (!s->bound)
561 dispatch_pending_io(io, STATUS_INVALID_DEVICE_STATE, 0);
562 unlock_socket(s);
563 return STATUS_INVALID_DEVICE_STATE;
566 if (pConnectEx(s->s, remote_address, sizeof(*remote_address), NULL, 0, NULL, &io->ovr))
567 dispatch_pending_io(io, STATUS_SUCCESS, 0);
568 else if ((error = WSAGetLastError()) == ERROR_IO_PENDING)
569 SetThreadpoolWait(io->tp_wait, io->ovr.hEvent, NULL);
570 else
571 dispatch_pending_io(io, sock_error_to_ntstatus(error), 0);
573 unlock_socket(s);
575 return STATUS_PENDING;
578 static NTSTATUS WINAPI wsk_get_remote_address(WSK_SOCKET *socket, SOCKADDR *remote_address, IRP *irp)
580 FIXME("socket %p, remote_address %p, irp %p stub.\n", socket, remote_address, irp);
582 return STATUS_NOT_IMPLEMENTED;
585 static void WINAPI send_receive_callback(TP_CALLBACK_INSTANCE *instance, void *socket_, TP_WAIT *wait,
586 TP_WAIT_RESULT wait_result)
588 struct wsk_socket_internal *socket = socket_;
589 struct wsk_pending_io *io;
590 DWORD length, flags;
592 TRACE("instance %p, socket %p, wait %p, wait_result %#lx.\n", instance, socket, wait, wait_result);
594 lock_socket(socket);
595 io = find_pending_io(socket, wait);
597 if (WSAGetOverlappedResult(socket->s, &io->ovr, &length, FALSE, &flags))
598 dispatch_pending_io(io, STATUS_SUCCESS, length);
599 else
600 dispatch_pending_io(io, io->ovr.Internal, 0);
602 unlock_socket(socket);
605 static NTSTATUS do_send_receive(WSK_SOCKET *socket, WSK_BUF *wsk_buf, ULONG flags, IRP *irp, BOOL is_send)
607 struct wsk_socket_internal *s = wsk_socket_internal_from_wsk_socket(socket);
608 struct wsk_pending_io *io;
609 DWORD wsa_flags;
610 WSABUF wsa_buf;
611 DWORD length;
612 int error;
614 TRACE("socket %p, buffer %p, flags %#lx, irp %p, is_send %#x.\n",
615 socket, wsk_buf, flags, irp, is_send);
617 if (!irp)
618 return STATUS_INVALID_PARAMETER;
620 if (!wsk_buf->Mdl && wsk_buf->Length)
621 return STATUS_INVALID_PARAMETER;
623 if (wsk_buf->Mdl && wsk_buf->Mdl->Next)
625 FIXME("Chained MDLs are not supported.\n");
626 irp->IoStatus.Information = 0;
627 dispatch_irp(irp, STATUS_UNSUCCESSFUL);
628 return STATUS_PENDING;
631 if (flags)
632 FIXME("flags %#lx not implemented.\n", flags);
634 lock_socket(s);
635 if (!(io = allocate_pending_io(s, send_receive_callback, irp)))
637 irp->IoStatus.Information = 0;
638 dispatch_irp(irp, STATUS_UNSUCCESSFUL);
639 unlock_socket(s);
640 return STATUS_PENDING;
643 wsa_buf.len = wsk_buf->Length;
644 wsa_buf.buf = wsk_buf->Mdl ? (CHAR *)wsk_buf->Mdl->StartVa
645 + wsk_buf->Mdl->ByteOffset + wsk_buf->Offset : NULL;
647 wsa_flags = 0;
649 if (!(is_send ? WSASend(s->s, &wsa_buf, 1, &length, wsa_flags, &io->ovr, NULL)
650 : WSARecv(s->s, &wsa_buf, 1, &length, &wsa_flags, &io->ovr, NULL)))
652 dispatch_pending_io(io, STATUS_SUCCESS, length);
654 else if ((error = WSAGetLastError()) == WSA_IO_PENDING)
656 SetThreadpoolWait(io->tp_wait, io->ovr.hEvent, NULL);
658 else
660 dispatch_pending_io(io, sock_error_to_ntstatus(error), 0);
662 unlock_socket(s);
664 return STATUS_PENDING;
667 static NTSTATUS WINAPI wsk_send(WSK_SOCKET *socket, WSK_BUF *buffer, ULONG flags, IRP *irp)
669 TRACE("socket %p, buffer %p, flags %#lx, irp %p.\n", socket, buffer, flags, irp);
671 return do_send_receive(socket, buffer, flags, irp, TRUE);
674 static NTSTATUS WINAPI wsk_receive(WSK_SOCKET *socket, WSK_BUF *buffer, ULONG flags, IRP *irp)
676 TRACE("socket %p, buffer %p, flags %#lx, irp %p.\n", socket, buffer, flags, irp);
678 return do_send_receive(socket, buffer, flags, irp, FALSE);
681 static NTSTATUS WINAPI wsk_disconnect(WSK_SOCKET *socket, WSK_BUF *buffer, ULONG flags, IRP *irp)
683 FIXME("socket %p, buffer %p, flags %#lx, irp %p stub.\n", socket, buffer, flags, irp);
685 return STATUS_NOT_IMPLEMENTED;
688 static NTSTATUS WINAPI wsk_release(WSK_SOCKET *socket, WSK_DATA_INDICATION *data_indication)
690 FIXME("socket %p, data_indication %p stub.\n", socket, data_indication);
692 return STATUS_NOT_IMPLEMENTED;
695 static NTSTATUS WINAPI wsk_connext_ex(WSK_SOCKET *socket, SOCKADDR *remote_address, WSK_BUF *buffer,
696 ULONG flags, IRP *irp)
698 FIXME("socket %p, remote_address %p, buffer %p, flags %#lx, irp %p stub.\n",
699 socket, remote_address, buffer, flags, irp);
701 return STATUS_NOT_IMPLEMENTED;
704 static NTSTATUS WINAPI wsk_send_ex(void)
706 FIXME("stub (no prototype, will crash).\n");
708 return STATUS_NOT_IMPLEMENTED;
711 static NTSTATUS WINAPI wsk_receive_ex(void)
713 FIXME("stub (no prototype, will crash).\n");
715 return STATUS_NOT_IMPLEMENTED;
718 static const WSK_PROVIDER_CONNECTION_DISPATCH wsk_provider_connection_dispatch =
721 wsk_control_socket,
722 wsk_close_socket,
724 wsk_bind,
725 wsk_connect,
726 wsk_get_local_address,
727 wsk_get_remote_address,
728 wsk_send,
729 wsk_receive,
730 wsk_disconnect,
731 wsk_release,
732 wsk_connext_ex,
733 wsk_send_ex,
734 wsk_receive_ex,
737 static NTSTATUS WINAPI wsk_socket(WSK_CLIENT *client, ADDRESS_FAMILY address_family, USHORT socket_type,
738 ULONG protocol, ULONG flags, void *socket_context, const void *dispatch, PEPROCESS owning_process,
739 PETHREAD owning_thread, SECURITY_DESCRIPTOR *security_descriptor, IRP *irp)
741 struct wsk_socket_internal *socket;
742 NTSTATUS status;
743 SOCKET s;
745 TRACE("client %p, address_family %#x, socket_type %#x, protocol %#lx, flags %#lx, socket_context %p, dispatch %p, "
746 "owning_process %p, owning_thread %p, security_descriptor %p, irp %p.\n",
747 client, address_family, socket_type, protocol, flags, socket_context, dispatch, owning_process,
748 owning_thread, security_descriptor, irp);
750 if (!irp)
751 return STATUS_INVALID_PARAMETER;
753 if (!client)
754 return STATUS_INVALID_HANDLE;
756 irp->IoStatus.Information = 0;
758 if ((s = WSASocketW(address_family, socket_type, protocol, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
760 status = sock_error_to_ntstatus(WSAGetLastError());
761 goto done;
764 if (!(socket = heap_alloc_zero(sizeof(*socket))))
766 status = STATUS_NO_MEMORY;
767 closesocket(s);
768 goto done;
771 socket->s = s;
772 socket->client_dispatch = dispatch;
773 socket->client_context = socket_context;
774 socket->socket_type = socket_type;
775 socket->flags = flags;
776 socket->address_family = address_family;
777 socket->protocol = protocol;
779 switch (flags)
781 case WSK_FLAG_LISTEN_SOCKET:
782 socket->wsk_socket.Dispatch = &wsk_provider_listen_dispatch;
783 break;
785 case WSK_FLAG_CONNECTION_SOCKET:
786 socket->wsk_socket.Dispatch = &wsk_provider_connection_dispatch;
787 break;
789 default:
790 FIXME("Flags %#lx not implemented.\n", flags);
791 closesocket(s);
792 heap_free(socket);
793 status = STATUS_NOT_IMPLEMENTED;
794 goto done;
797 socket_init(socket);
799 irp->IoStatus.Information = (ULONG_PTR)&socket->wsk_socket;
800 status = STATUS_SUCCESS;
802 done:
803 dispatch_irp(irp, status);
804 return status ? status : STATUS_PENDING;
807 static NTSTATUS WINAPI wsk_socket_connect(WSK_CLIENT *client, USHORT socket_type, ULONG protocol,
808 SOCKADDR *local_address, SOCKADDR *remote_address, ULONG flags, void *socket_context,
809 const WSK_CLIENT_CONNECTION_DISPATCH *dispatch, PEPROCESS owning_process, PETHREAD owning_thread,
810 SECURITY_DESCRIPTOR *security_descriptor, IRP *irp)
812 FIXME("client %p, socket_type %#x, protocol %#lx, local_address %p, remote_address %p, "
813 "flags %#lx, socket_context %p, dispatch %p, owning_process %p, owning_thread %p, "
814 "security_descriptor %p, irp %p stub.\n",
815 client, socket_type, protocol, local_address, remote_address, flags, socket_context,
816 dispatch, owning_process, owning_thread, security_descriptor, irp);
818 return STATUS_NOT_IMPLEMENTED;
821 static NTSTATUS WINAPI wsk_control_client(WSK_CLIENT *client, ULONG control_code, SIZE_T input_size,
822 void *input_buffer, SIZE_T output_size, void *output_buffer, SIZE_T *output_size_returned,
823 IRP *irp
826 FIXME("client %p, control_code %#lx, input_size %Iu, input_buffer %p, output_size %Iu, "
827 "output_buffer %p, output_size_returned %p, irp %p, stub.\n",
828 client, control_code, input_size, input_buffer, output_size, output_buffer,
829 output_size_returned, irp);
831 return STATUS_NOT_IMPLEMENTED;
834 struct wsk_get_address_info_context
836 UNICODE_STRING *node_name;
837 UNICODE_STRING *service_name;
838 ULONG namespace;
839 GUID *provider;
840 ADDRINFOEXW *hints;
841 ADDRINFOEXW **result;
842 IRP *irp;
845 static void WINAPI get_address_info_callback(TP_CALLBACK_INSTANCE *instance, void *context_)
847 struct wsk_get_address_info_context *context = context_;
848 INT ret;
850 TRACE("instance %p, context %p.\n", instance, context);
852 ret = GetAddrInfoExW( context->node_name ? context->node_name->Buffer : NULL,
853 context->service_name ? context->service_name->Buffer : NULL, context->namespace,
854 context->provider, context->hints, context->result, NULL, NULL, NULL, NULL);
856 context->irp->IoStatus.Information = 0;
857 dispatch_irp(context->irp, sock_error_to_ntstatus(ret));
858 heap_free(context);
861 static NTSTATUS WINAPI wsk_get_address_info(WSK_CLIENT *client, UNICODE_STRING *node_name,
862 UNICODE_STRING *service_name, ULONG name_space, GUID *provider, ADDRINFOEXW *hints,
863 ADDRINFOEXW **result, PEPROCESS owning_process, PETHREAD owning_thread, IRP *irp)
865 struct wsk_get_address_info_context *context;
866 NTSTATUS status;
868 TRACE("client %p, node_name %p, service_name %p, name_space %#lx, provider %p, hints %p, "
869 "result %p, owning_process %p, owning_thread %p, irp %p.\n",
870 client, node_name, service_name, name_space, provider, hints, result,
871 owning_process, owning_thread, irp);
873 if (!irp)
874 return STATUS_INVALID_PARAMETER;
876 if (!(context = heap_alloc(sizeof(*context))))
878 ERR("No memory.\n");
879 status = STATUS_NO_MEMORY;
880 dispatch_irp(irp, status);
881 return status;
884 context->node_name = node_name;
885 context->service_name = service_name;
886 context->namespace = name_space;
887 context->provider = provider;
888 context->hints = hints;
889 context->result = result;
890 context->irp = irp;
892 if (!TrySubmitThreadpoolCallback(get_address_info_callback, context, NULL))
894 ERR("Could not submit thread pool callback.\n");
895 status = STATUS_UNSUCCESSFUL;
896 dispatch_irp(irp, status);
897 heap_free(context);
898 return status;
900 TRACE("Submitted threadpool callback, context %p.\n", context);
901 return STATUS_PENDING;
904 static void WINAPI wsk_free_address_info(WSK_CLIENT *client, ADDRINFOEXW *addr_info)
906 TRACE("client %p, addr_info %p.\n", client, addr_info);
908 FreeAddrInfoExW(addr_info);
911 static NTSTATUS WINAPI wsk_get_name_info(WSK_CLIENT *client, SOCKADDR *sock_addr, ULONG sock_addr_length,
912 UNICODE_STRING *node_name, UNICODE_STRING *service_name, ULONG flags, PEPROCESS owning_process,
913 PETHREAD owning_thread, IRP *irp)
915 FIXME("client %p, sock_addr %p, sock_addr_length %lu, node_name %p, service_name %p, "
916 "flags %#lx, owning_process %p, owning_thread %p, irp %p stub.\n",
917 client, sock_addr, sock_addr_length, node_name, service_name, flags,
918 owning_process, owning_thread, irp);
920 return STATUS_NOT_IMPLEMENTED;
923 static const WSK_PROVIDER_DISPATCH wsk_dispatch =
925 MAKE_WSK_VERSION(1, 0), 0,
926 wsk_socket,
927 wsk_socket_connect,
928 wsk_control_client,
929 wsk_get_address_info,
930 wsk_free_address_info,
931 wsk_get_name_info,
934 NTSTATUS WINAPI WskCaptureProviderNPI(WSK_REGISTRATION *wsk_registration, ULONG wait_timeout,
935 WSK_PROVIDER_NPI *wsk_provider_npi)
937 WSK_CLIENT *client = wsk_registration->ReservedRegistrationContext;
939 TRACE("wsk_registration %p, wait_timeout %lu, wsk_provider_npi %p.\n",
940 wsk_registration, wait_timeout, wsk_provider_npi);
942 wsk_provider_npi->Client = client;
943 wsk_provider_npi->Dispatch = &wsk_dispatch;
944 return STATUS_SUCCESS;
947 void WINAPI WskReleaseProviderNPI(WSK_REGISTRATION *wsk_registration)
949 TRACE("wsk_registration %p.\n", wsk_registration);
953 NTSTATUS WINAPI WskRegister(WSK_CLIENT_NPI *wsk_client_npi, WSK_REGISTRATION *wsk_registration)
955 static const WORD version = MAKEWORD( 2, 2 );
956 WSADATA data;
958 WSK_CLIENT *client;
960 TRACE("wsk_client_npi %p, wsk_registration %p.\n", wsk_client_npi, wsk_registration);
962 if (!(client = heap_alloc(sizeof(*client))))
964 ERR("No memory.\n");
965 return STATUS_NO_MEMORY;
968 client->registration = wsk_registration;
969 client->client_npi = wsk_client_npi;
970 wsk_registration->ReservedRegistrationContext = client;
972 if (WSAStartup(version, &data))
973 return STATUS_INTERNAL_ERROR;
975 return STATUS_SUCCESS;
978 void WINAPI WskDeregister(WSK_REGISTRATION *wsk_registration)
980 TRACE("wsk_registration %p.\n", wsk_registration);
982 heap_free(wsk_registration->ReservedRegistrationContext);
985 static void WINAPI driver_unload(DRIVER_OBJECT *driver)
987 TRACE("driver %p.\n", driver);
990 NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *path)
992 TRACE("driver %p, path %s.\n", driver, debugstr_w(path->Buffer));
994 driver->DriverUnload = driver_unload;
995 return STATUS_SUCCESS;