dwrite: Check for allocation failures of glyph buffers.
[wine.git] / dlls / netio.sys / netio.c
blobfe73b06b9782e0fc8ff38ca77dfa3bb0f9b0c672
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 #define NONAMELESSUNION
24 #define NONAMELESSSTRUCT
26 #include "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #include "windef.h"
29 #include "winioctl.h"
30 #include "winternl.h"
31 #include "ddk/wdm.h"
32 #include "ddk/wsk.h"
33 #include "wine/debug.h"
34 #include "winsock2.h"
35 #include "ws2tcpip.h"
37 #include "wine/heap.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(netio);
41 struct _WSK_CLIENT
43 WSK_REGISTRATION *registration;
44 WSK_CLIENT_NPI *client_npi;
47 struct listen_socket_callback_context
49 SOCKADDR *local_address;
50 SOCKADDR *remote_address;
51 const void *client_dispatch;
52 void *client_context;
53 char addr_buffer[2 * (sizeof(SOCKADDR) + 16)];
54 SOCKET acceptor;
57 #define MAX_PENDING_IO 10
59 struct wsk_pending_io
61 OVERLAPPED ovr;
62 TP_WAIT *tp_wait;
63 void *callback;
64 IRP *irp;
67 struct wsk_socket_internal
69 WSK_SOCKET wsk_socket;
70 SOCKET s;
71 const void *client_dispatch;
72 void *client_context;
73 ULONG flags;
74 ADDRESS_FAMILY address_family;
75 USHORT socket_type;
76 ULONG protocol;
77 BOOL bound;
79 CRITICAL_SECTION cs_socket;
81 struct wsk_pending_io pending_io[MAX_PENDING_IO];
83 union
85 struct listen_socket_callback_context listen_socket_callback_context;
87 callback_context;
90 static LPFN_ACCEPTEX pAcceptEx;
91 static LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockaddrs;
92 static LPFN_CONNECTEX pConnectEx;
94 static const WSK_PROVIDER_CONNECTION_DISPATCH wsk_provider_connection_dispatch;
96 static inline struct wsk_socket_internal *wsk_socket_internal_from_wsk_socket(WSK_SOCKET *wsk_socket)
98 return CONTAINING_RECORD(wsk_socket, struct wsk_socket_internal, wsk_socket);
101 static NTSTATUS sock_error_to_ntstatus(DWORD err)
103 switch (err)
105 case 0: return STATUS_SUCCESS;
106 case WSAEBADF: return STATUS_INVALID_HANDLE;
107 case WSAEACCES: return STATUS_ACCESS_DENIED;
108 case WSAEFAULT: return STATUS_NO_MEMORY;
109 case WSAEINVAL: return STATUS_INVALID_PARAMETER;
110 case WSAEMFILE: return STATUS_TOO_MANY_OPENED_FILES;
111 case WSAEWOULDBLOCK: return STATUS_CANT_WAIT;
112 case WSAEINPROGRESS: return STATUS_PENDING;
113 case WSAEALREADY: return STATUS_NETWORK_BUSY;
114 case WSAENOTSOCK: return STATUS_OBJECT_TYPE_MISMATCH;
115 case WSAEDESTADDRREQ: return STATUS_INVALID_PARAMETER;
116 case WSAEMSGSIZE: return STATUS_BUFFER_OVERFLOW;
117 case WSAEPROTONOSUPPORT:
118 case WSAESOCKTNOSUPPORT:
119 case WSAEPFNOSUPPORT:
120 case WSAEAFNOSUPPORT:
121 case WSAEPROTOTYPE: return STATUS_NOT_SUPPORTED;
122 case WSAENOPROTOOPT: return STATUS_INVALID_PARAMETER;
123 case WSAEOPNOTSUPP: return STATUS_NOT_IMPLEMENTED;
124 case WSAEADDRINUSE: return STATUS_ADDRESS_ALREADY_ASSOCIATED;
125 case WSAEADDRNOTAVAIL: return STATUS_INVALID_PARAMETER;
126 case WSAECONNREFUSED: return STATUS_CONNECTION_REFUSED;
127 case WSAESHUTDOWN: return STATUS_PIPE_DISCONNECTED;
128 case WSAENOTCONN: return STATUS_CONNECTION_DISCONNECTED;
129 case WSAETIMEDOUT: return STATUS_IO_TIMEOUT;
130 case WSAENETUNREACH: return STATUS_NETWORK_UNREACHABLE;
131 case WSAENETDOWN: return STATUS_NETWORK_BUSY;
132 case WSAECONNRESET: return STATUS_CONNECTION_RESET;
133 case WSAECONNABORTED: return STATUS_CONNECTION_ABORTED;
134 case WSAHOST_NOT_FOUND: return STATUS_NOT_FOUND;
135 default:
136 FIXME("Unmapped error %u.\n", err);
137 return STATUS_UNSUCCESSFUL;
141 static inline void lock_socket(struct wsk_socket_internal *socket)
143 EnterCriticalSection(&socket->cs_socket);
146 static inline void unlock_socket(struct wsk_socket_internal *socket)
148 LeaveCriticalSection(&socket->cs_socket);
151 static void socket_init(struct wsk_socket_internal *socket)
153 InitializeCriticalSection(&socket->cs_socket);
156 static void dispatch_irp(IRP *irp, NTSTATUS status)
158 irp->IoStatus.u.Status = status;
159 --irp->CurrentLocation;
160 --irp->Tail.Overlay.s.u2.CurrentStackLocation;
161 IoCompleteRequest(irp, IO_NO_INCREMENT);
164 static struct wsk_pending_io *allocate_pending_io(struct wsk_socket_internal *socket,
165 PTP_WAIT_CALLBACK socket_async_callback, IRP *irp)
167 struct wsk_pending_io *io = socket->pending_io;
168 unsigned int i, io_index;
170 io_index = ~0u;
171 for (i = 0; i < ARRAY_SIZE(socket->pending_io); ++i)
173 if (!io[i].irp)
175 if (io[i].callback == socket_async_callback)
177 io[i].irp = irp;
178 return &io[i];
181 if (io_index == ~0u)
182 io_index = i;
186 if (io_index == ~0u)
188 FIXME("Pending io requests count exceeds limit.\n");
189 return NULL;
192 io[io_index].irp = irp;
194 if (io[io_index].tp_wait)
195 CloseThreadpoolWait(io[io_index].tp_wait);
196 else
197 io[io_index].ovr.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
199 io[io_index].tp_wait = CreateThreadpoolWait(socket_async_callback, socket, NULL);
200 io[io_index].callback = socket_async_callback;
202 return &io[io_index];
205 static struct wsk_pending_io *find_pending_io(struct wsk_socket_internal *socket, TP_WAIT *tp_wait)
207 unsigned int i;
209 for (i = 0; i < ARRAY_SIZE(socket->pending_io); ++i)
211 if (socket->pending_io[i].tp_wait == tp_wait)
212 return &socket->pending_io[i];
215 FIXME("Pending io not found for tp_wait %p.\n", tp_wait);
216 return NULL;
219 static void dispatch_pending_io(struct wsk_pending_io *io, NTSTATUS status, ULONG_PTR information)
221 TRACE("io %p, status %#x, information %#lx.\n", io, status, information);
223 io->irp->IoStatus.Information = information;
224 dispatch_irp(io->irp, status);
225 io->irp = NULL;
228 static NTSTATUS WINAPI wsk_control_socket(WSK_SOCKET *socket, WSK_CONTROL_SOCKET_TYPE request_type,
229 ULONG control_code, ULONG level, SIZE_T input_size, void *input_buffer, SIZE_T output_size,
230 void *output_buffer, SIZE_T *output_size_returned, IRP *irp)
232 FIXME("socket %p, request_type %u, control_code %#x, level %u, input_size %lu, input_buffer %p, "
233 "output_size %lu, output_buffer %p, output_size_returned %p, irp %p stub.\n",
234 socket, request_type, control_code, level, input_size, input_buffer, output_size,
235 output_buffer, output_size_returned, irp);
237 return STATUS_NOT_IMPLEMENTED;
240 static NTSTATUS WINAPI wsk_close_socket(WSK_SOCKET *socket, IRP *irp)
242 struct wsk_socket_internal *s = wsk_socket_internal_from_wsk_socket(socket);
243 NTSTATUS status;
244 unsigned int i;
246 TRACE("socket %p, irp %p.\n", socket, irp);
248 lock_socket(s);
250 for (i = 0; i < ARRAY_SIZE(s->pending_io); ++i)
252 struct wsk_pending_io *io = &s->pending_io[i];
254 if (io->tp_wait)
256 CancelIoEx((HANDLE)s->s, &io->ovr);
257 SetThreadpoolWait(io->tp_wait, NULL, NULL);
258 unlock_socket(s);
259 WaitForThreadpoolWaitCallbacks(io->tp_wait, FALSE);
260 lock_socket(s);
261 CloseThreadpoolWait(io->tp_wait);
262 CloseHandle(io->ovr.hEvent);
265 if (io->irp)
266 dispatch_pending_io(io, STATUS_CANCELLED, 0);
269 if (s->flags & WSK_FLAG_LISTEN_SOCKET && s->callback_context.listen_socket_callback_context.acceptor)
270 closesocket(s->callback_context.listen_socket_callback_context.acceptor);
272 status = closesocket(s->s) ? sock_error_to_ntstatus(WSAGetLastError()) : STATUS_SUCCESS;
274 unlock_socket(s);
275 DeleteCriticalSection(&s->cs_socket);
276 heap_free(socket);
278 irp->IoStatus.Information = 0;
279 dispatch_irp(irp, status);
281 return status ? status : STATUS_PENDING;
284 static NTSTATUS WINAPI wsk_bind(WSK_SOCKET *socket, SOCKADDR *local_address, ULONG flags, IRP *irp)
286 struct wsk_socket_internal *s = wsk_socket_internal_from_wsk_socket(socket);
287 NTSTATUS status;
289 TRACE("socket %p, local_address %p, flags %#x, irp %p.\n",
290 socket, local_address, flags, irp);
292 if (!irp)
293 return STATUS_INVALID_PARAMETER;
295 if (bind(s->s, local_address, sizeof(*local_address)))
296 status = sock_error_to_ntstatus(WSAGetLastError());
297 else if (s->flags & WSK_FLAG_LISTEN_SOCKET && listen(s->s, SOMAXCONN))
298 status = sock_error_to_ntstatus(WSAGetLastError());
299 else
300 status = STATUS_SUCCESS;
302 if (status == STATUS_SUCCESS)
303 s->bound = TRUE;
305 TRACE("status %#x.\n", status);
306 irp->IoStatus.Information = 0;
307 dispatch_irp(irp, status);
308 return STATUS_PENDING;
311 static void create_accept_socket(struct wsk_socket_internal *socket, struct wsk_pending_io *io)
313 struct listen_socket_callback_context *context
314 = &socket->callback_context.listen_socket_callback_context;
315 INT local_address_len, remote_address_len;
316 SOCKADDR *local_address, *remote_address;
317 struct wsk_socket_internal *accept_socket;
319 if (!(accept_socket = heap_alloc_zero(sizeof(*accept_socket))))
321 ERR("No memory.\n");
322 dispatch_pending_io(io, STATUS_NO_MEMORY, 0);
324 else
326 TRACE("accept_socket %p.\n", accept_socket);
327 accept_socket->wsk_socket.Dispatch = &wsk_provider_connection_dispatch;
328 accept_socket->s = context->acceptor;
329 accept_socket->client_dispatch = context->client_dispatch;
330 accept_socket->client_context = context->client_context;
331 accept_socket->socket_type = socket->socket_type;
332 accept_socket->address_family = socket->address_family;
333 accept_socket->protocol = socket->protocol;
334 accept_socket->flags = WSK_FLAG_CONNECTION_SOCKET;
335 socket_init(accept_socket);
337 pGetAcceptExSockaddrs(context->addr_buffer, 0, sizeof(SOCKADDR) + 16, sizeof(SOCKADDR) + 16,
338 &local_address, &local_address_len, &remote_address, &remote_address_len);
340 if (context->local_address)
341 memcpy(context->local_address, local_address,
342 min(sizeof(*context->local_address), local_address_len));
344 if (context->remote_address)
345 memcpy(context->remote_address, remote_address,
346 min(sizeof(*context->remote_address), remote_address_len));
348 dispatch_pending_io(io, STATUS_SUCCESS, (ULONG_PTR)&accept_socket->wsk_socket);
352 static void WINAPI accept_callback(TP_CALLBACK_INSTANCE *instance, void *socket_, TP_WAIT *wait,
353 TP_WAIT_RESULT wait_result)
355 struct listen_socket_callback_context *context;
356 struct wsk_socket_internal *socket = socket_;
357 struct wsk_pending_io *io;
358 DWORD size;
360 TRACE("instance %p, socket %p, wait %p, wait_result %#x.\n", instance, socket, wait, wait_result);
362 lock_socket(socket);
363 context = &socket->callback_context.listen_socket_callback_context;
364 io = find_pending_io(socket, wait);
366 if (GetOverlappedResult((HANDLE)socket->s, &io->ovr, &size, FALSE))
368 create_accept_socket(socket, io);
370 else
372 closesocket(context->acceptor);
373 context->acceptor = 0;
374 dispatch_pending_io(io, io->ovr.Internal, 0);
376 unlock_socket(socket);
379 static BOOL WINAPI init_accept_functions(INIT_ONCE *once, void *param, void **context)
381 GUID get_acceptex_guid = WSAID_GETACCEPTEXSOCKADDRS;
382 GUID acceptex_guid = WSAID_ACCEPTEX;
383 SOCKET s = (SOCKET)param;
384 DWORD size;
386 if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &acceptex_guid, sizeof(acceptex_guid),
387 &pAcceptEx, sizeof(pAcceptEx), &size, NULL, NULL))
389 ERR("Could not get AcceptEx address, error %u.\n", WSAGetLastError());
390 return FALSE;
393 if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &get_acceptex_guid, sizeof(get_acceptex_guid),
394 &pGetAcceptExSockaddrs, sizeof(pGetAcceptExSockaddrs), &size, NULL, NULL))
396 ERR("Could not get AcceptEx address, error %u.\n", WSAGetLastError());
397 return FALSE;
400 return TRUE;
403 static NTSTATUS WINAPI wsk_accept(WSK_SOCKET *listen_socket, ULONG flags, void *accept_socket_context,
404 const WSK_CLIENT_CONNECTION_DISPATCH *accept_socket_dispatch, SOCKADDR *local_address,
405 SOCKADDR *remote_address, IRP *irp)
407 struct wsk_socket_internal *s = wsk_socket_internal_from_wsk_socket(listen_socket);
408 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
409 struct listen_socket_callback_context *context;
410 struct wsk_pending_io *io;
411 SOCKET acceptor;
412 DWORD size;
413 int error;
415 TRACE("listen_socket %p, flags %#x, accept_socket_context %p, accept_socket_dispatch %p, "
416 "local_address %p, remote_address %p, irp %p.\n",
417 listen_socket, flags, accept_socket_context, accept_socket_dispatch, local_address,
418 remote_address, irp);
420 if (!irp)
421 return STATUS_INVALID_PARAMETER;
423 if (!InitOnceExecuteOnce(&init_once, init_accept_functions, (void *)s->s, NULL))
425 dispatch_irp(irp, STATUS_UNSUCCESSFUL);
426 return STATUS_PENDING;
429 lock_socket(s);
430 if (!(io = allocate_pending_io(s, accept_callback, irp)))
432 irp->IoStatus.Information = 0;
433 dispatch_irp(irp, STATUS_UNSUCCESSFUL);
434 unlock_socket(s);
435 return STATUS_PENDING;
438 context = &s->callback_context.listen_socket_callback_context;
439 if ((acceptor = WSASocketW(s->address_family, s->socket_type, s->protocol, NULL, 0, WSA_FLAG_OVERLAPPED))
440 == INVALID_SOCKET)
442 dispatch_pending_io(io, sock_error_to_ntstatus(WSAGetLastError()), 0);
443 unlock_socket(s);
444 return STATUS_PENDING;
447 context->local_address = local_address;
448 context->remote_address = remote_address;
449 context->client_dispatch = accept_socket_dispatch;
450 context->client_context = accept_socket_context;
451 context->acceptor = acceptor;
453 if (pAcceptEx(s->s, acceptor, context->addr_buffer, 0,
454 sizeof(SOCKADDR) + 16, sizeof(SOCKADDR) + 16, &size, &io->ovr))
456 create_accept_socket(s, io);
458 else if ((error = WSAGetLastError()) == ERROR_IO_PENDING)
460 SetThreadpoolWait(io->tp_wait, io->ovr.hEvent, NULL);
462 else
464 closesocket(acceptor);
465 context->acceptor = 0;
466 dispatch_pending_io(io, sock_error_to_ntstatus(error), 0);
468 unlock_socket(s);
470 return STATUS_PENDING;
473 static NTSTATUS WINAPI wsk_inspect_complete(WSK_SOCKET *listen_socket, WSK_INSPECT_ID *inspect_id,
474 WSK_INSPECT_ACTION action, IRP *irp)
476 FIXME("listen_socket %p, inspect_id %p, action %u, irp %p stub.\n",
477 listen_socket, inspect_id, action, irp);
479 return STATUS_NOT_IMPLEMENTED;
482 static NTSTATUS WINAPI wsk_get_local_address(WSK_SOCKET *socket, SOCKADDR *local_address, IRP *irp)
484 FIXME("socket %p, local_address %p, irp %p stub.\n", socket, local_address, irp);
486 return STATUS_NOT_IMPLEMENTED;
489 static const WSK_PROVIDER_LISTEN_DISPATCH wsk_provider_listen_dispatch =
492 wsk_control_socket,
493 wsk_close_socket,
495 wsk_bind,
496 wsk_accept,
497 wsk_inspect_complete,
498 wsk_get_local_address,
501 static void WINAPI connect_callback(TP_CALLBACK_INSTANCE *instance, void *socket_, TP_WAIT *wait,
502 TP_WAIT_RESULT wait_result)
504 struct wsk_socket_internal *socket = socket_;
505 struct wsk_pending_io *io;
506 DWORD size;
508 TRACE("instance %p, socket %p, wait %p, wait_result %#x.\n", instance, socket, wait, wait_result);
510 lock_socket(socket);
511 io = find_pending_io(socket, wait);
513 GetOverlappedResult((HANDLE)socket->s, &io->ovr, &size, FALSE);
514 dispatch_pending_io(io, io->ovr.Internal, 0);
515 unlock_socket(socket);
518 static BOOL WINAPI init_connect_functions(INIT_ONCE *once, void *param, void **context)
520 GUID connectex_guid = WSAID_CONNECTEX;
521 SOCKET s = (SOCKET)param;
522 DWORD size;
524 if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &connectex_guid, sizeof(connectex_guid),
525 &pConnectEx, sizeof(pConnectEx), &size, NULL, NULL))
527 ERR("Could not get AcceptEx address, error %u.\n", WSAGetLastError());
528 return FALSE;
530 return TRUE;
533 static NTSTATUS WINAPI wsk_connect(WSK_SOCKET *socket, SOCKADDR *remote_address, ULONG flags, IRP *irp)
535 struct wsk_socket_internal *s = wsk_socket_internal_from_wsk_socket(socket);
536 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
537 struct wsk_pending_io *io;
538 int error;
540 TRACE("socket %p, remote_address %p, flags %#x, irp %p.\n",
541 socket, remote_address, flags, irp);
543 if (!irp)
544 return STATUS_INVALID_PARAMETER;
546 if (!InitOnceExecuteOnce(&init_once, init_connect_functions, (void *)s->s, NULL))
548 dispatch_irp(irp, STATUS_UNSUCCESSFUL);
549 return STATUS_PENDING;
552 lock_socket(s);
554 if (!(io = allocate_pending_io(s, connect_callback, irp)))
556 irp->IoStatus.Information = 0;
557 dispatch_irp(irp, STATUS_UNSUCCESSFUL);
558 unlock_socket(s);
559 return STATUS_PENDING;
562 if (!s->bound)
564 dispatch_pending_io(io, STATUS_INVALID_DEVICE_STATE, 0);
565 unlock_socket(s);
566 return STATUS_INVALID_DEVICE_STATE;
569 if (pConnectEx(s->s, remote_address, sizeof(*remote_address), NULL, 0, NULL, &io->ovr))
570 dispatch_pending_io(io, STATUS_SUCCESS, 0);
571 else if ((error = WSAGetLastError()) == ERROR_IO_PENDING)
572 SetThreadpoolWait(io->tp_wait, io->ovr.hEvent, NULL);
573 else
574 dispatch_pending_io(io, sock_error_to_ntstatus(error), 0);
576 unlock_socket(s);
578 return STATUS_PENDING;
581 static NTSTATUS WINAPI wsk_get_remote_address(WSK_SOCKET *socket, SOCKADDR *remote_address, IRP *irp)
583 FIXME("socket %p, remote_address %p, irp %p stub.\n", socket, remote_address, irp);
585 return STATUS_NOT_IMPLEMENTED;
588 static void WINAPI send_receive_callback(TP_CALLBACK_INSTANCE *instance, void *socket_, TP_WAIT *wait,
589 TP_WAIT_RESULT wait_result)
591 struct wsk_socket_internal *socket = socket_;
592 struct wsk_pending_io *io;
593 DWORD length, flags;
595 TRACE("instance %p, socket %p, wait %p, wait_result %#x.\n", instance, socket, wait, wait_result);
597 lock_socket(socket);
598 io = find_pending_io(socket, wait);
600 if (WSAGetOverlappedResult(socket->s, &io->ovr, &length, FALSE, &flags))
601 dispatch_pending_io(io, STATUS_SUCCESS, length);
602 else
603 dispatch_pending_io(io, io->ovr.Internal, 0);
605 unlock_socket(socket);
608 static NTSTATUS do_send_receive(WSK_SOCKET *socket, WSK_BUF *wsk_buf, ULONG flags, IRP *irp, BOOL is_send)
610 struct wsk_socket_internal *s = wsk_socket_internal_from_wsk_socket(socket);
611 struct wsk_pending_io *io;
612 DWORD wsa_flags;
613 WSABUF wsa_buf;
614 DWORD length;
615 int error;
617 TRACE("socket %p, buffer %p, flags %#x, irp %p, is_send %#x.\n",
618 socket, wsk_buf, flags, irp, is_send);
620 if (!irp)
621 return STATUS_INVALID_PARAMETER;
623 if (!wsk_buf->Mdl && wsk_buf->Length)
624 return STATUS_INVALID_PARAMETER;
626 if (wsk_buf->Mdl && wsk_buf->Mdl->Next)
628 FIXME("Chained MDLs are not supported.\n");
629 irp->IoStatus.Information = 0;
630 dispatch_irp(irp, STATUS_UNSUCCESSFUL);
631 return STATUS_PENDING;
634 if (flags)
635 FIXME("flags %#x not implemented.\n", flags);
637 lock_socket(s);
638 if (!(io = allocate_pending_io(s, send_receive_callback, irp)))
640 irp->IoStatus.Information = 0;
641 dispatch_irp(irp, STATUS_UNSUCCESSFUL);
642 unlock_socket(s);
643 return STATUS_PENDING;
646 wsa_buf.len = wsk_buf->Length;
647 wsa_buf.buf = wsk_buf->Mdl ? (CHAR *)wsk_buf->Mdl->StartVa
648 + wsk_buf->Mdl->ByteOffset + wsk_buf->Offset : NULL;
650 wsa_flags = 0;
652 if (!(is_send ? WSASend(s->s, &wsa_buf, 1, &length, wsa_flags, &io->ovr, NULL)
653 : WSARecv(s->s, &wsa_buf, 1, &length, &wsa_flags, &io->ovr, NULL)))
655 dispatch_pending_io(io, STATUS_SUCCESS, length);
657 else if ((error = WSAGetLastError()) == WSA_IO_PENDING)
659 SetThreadpoolWait(io->tp_wait, io->ovr.hEvent, NULL);
661 else
663 dispatch_pending_io(io, sock_error_to_ntstatus(error), 0);
665 unlock_socket(s);
667 return STATUS_PENDING;
670 static NTSTATUS WINAPI wsk_send(WSK_SOCKET *socket, WSK_BUF *buffer, ULONG flags, IRP *irp)
672 TRACE("socket %p, buffer %p, flags %#x, irp %p.\n", socket, buffer, flags, irp);
674 return do_send_receive(socket, buffer, flags, irp, TRUE);
677 static NTSTATUS WINAPI wsk_receive(WSK_SOCKET *socket, WSK_BUF *buffer, ULONG flags, IRP *irp)
679 TRACE("socket %p, buffer %p, flags %#x, irp %p.\n", socket, buffer, flags, irp);
681 return do_send_receive(socket, buffer, flags, irp, FALSE);
684 static NTSTATUS WINAPI wsk_disconnect(WSK_SOCKET *socket, WSK_BUF *buffer, ULONG flags, IRP *irp)
686 FIXME("socket %p, buffer %p, flags %#x, irp %p stub.\n", socket, buffer, flags, irp);
688 return STATUS_NOT_IMPLEMENTED;
691 static NTSTATUS WINAPI wsk_release(WSK_SOCKET *socket, WSK_DATA_INDICATION *data_indication)
693 FIXME("socket %p, data_indication %p stub.\n", socket, data_indication);
695 return STATUS_NOT_IMPLEMENTED;
698 static NTSTATUS WINAPI wsk_connext_ex(WSK_SOCKET *socket, SOCKADDR *remote_address, WSK_BUF *buffer,
699 ULONG flags, IRP *irp)
701 FIXME("socket %p, remote_address %p, buffer %p, flags %#x, irp %p stub.\n",
702 socket, remote_address, buffer, flags, irp);
704 return STATUS_NOT_IMPLEMENTED;
707 static NTSTATUS WINAPI wsk_send_ex(void)
709 FIXME("stub (no prototype, will crash).\n");
711 return STATUS_NOT_IMPLEMENTED;
714 static NTSTATUS WINAPI wsk_receive_ex(void)
716 FIXME("stub (no prototype, will crash).\n");
718 return STATUS_NOT_IMPLEMENTED;
721 static const WSK_PROVIDER_CONNECTION_DISPATCH wsk_provider_connection_dispatch =
724 wsk_control_socket,
725 wsk_close_socket,
727 wsk_bind,
728 wsk_connect,
729 wsk_get_local_address,
730 wsk_get_remote_address,
731 wsk_send,
732 wsk_receive,
733 wsk_disconnect,
734 wsk_release,
735 wsk_connext_ex,
736 wsk_send_ex,
737 wsk_receive_ex,
740 static NTSTATUS WINAPI wsk_socket(WSK_CLIENT *client, ADDRESS_FAMILY address_family, USHORT socket_type,
741 ULONG protocol, ULONG flags, void *socket_context, const void *dispatch, PEPROCESS owning_process,
742 PETHREAD owning_thread, SECURITY_DESCRIPTOR *security_descriptor, IRP *irp)
744 struct wsk_socket_internal *socket;
745 NTSTATUS status;
746 SOCKET s;
748 TRACE("client %p, address_family %#x, socket_type %#x, protocol %#x, flags %#x, socket_context %p, dispatch %p, "
749 "owning_process %p, owning_thread %p, security_descriptor %p, irp %p.\n",
750 client, address_family, socket_type, protocol, flags, socket_context, dispatch, owning_process,
751 owning_thread, security_descriptor, irp);
753 if (!irp)
754 return STATUS_INVALID_PARAMETER;
756 if (!client)
757 return STATUS_INVALID_HANDLE;
759 irp->IoStatus.Information = 0;
761 if ((s = WSASocketW(address_family, socket_type, protocol, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
763 status = sock_error_to_ntstatus(WSAGetLastError());
764 goto done;
767 if (!(socket = heap_alloc_zero(sizeof(*socket))))
769 status = STATUS_NO_MEMORY;
770 closesocket(s);
771 goto done;
774 socket->s = s;
775 socket->client_dispatch = dispatch;
776 socket->client_context = socket_context;
777 socket->socket_type = socket_type;
778 socket->flags = flags;
779 socket->address_family = address_family;
780 socket->protocol = protocol;
782 switch (flags)
784 case WSK_FLAG_LISTEN_SOCKET:
785 socket->wsk_socket.Dispatch = &wsk_provider_listen_dispatch;
786 break;
788 case WSK_FLAG_CONNECTION_SOCKET:
789 socket->wsk_socket.Dispatch = &wsk_provider_connection_dispatch;
790 break;
792 default:
793 FIXME("Flags %#x not implemented.\n", flags);
794 closesocket(s);
795 heap_free(socket);
796 status = STATUS_NOT_IMPLEMENTED;
797 goto done;
800 socket_init(socket);
802 irp->IoStatus.Information = (ULONG_PTR)&socket->wsk_socket;
803 status = STATUS_SUCCESS;
805 done:
806 dispatch_irp(irp, status);
807 return status ? status : STATUS_PENDING;
810 static NTSTATUS WINAPI wsk_socket_connect(WSK_CLIENT *client, USHORT socket_type, ULONG protocol,
811 SOCKADDR *local_address, SOCKADDR *remote_address, ULONG flags, void *socket_context,
812 const WSK_CLIENT_CONNECTION_DISPATCH *dispatch, PEPROCESS owning_process, PETHREAD owning_thread,
813 SECURITY_DESCRIPTOR *security_descriptor, IRP *irp)
815 FIXME("client %p, socket_type %#x, protocol %#x, local_address %p, remote_address %p, "
816 "flags %#x, socket_context %p, dispatch %p, owning_process %p, owning_thread %p, "
817 "security_descriptor %p, irp %p stub.\n",
818 client, socket_type, protocol, local_address, remote_address, flags, socket_context,
819 dispatch, owning_process, owning_thread, security_descriptor, irp);
821 return STATUS_NOT_IMPLEMENTED;
824 static NTSTATUS WINAPI wsk_control_client(WSK_CLIENT *client, ULONG control_code, SIZE_T input_size,
825 void *input_buffer, SIZE_T output_size, void *output_buffer, SIZE_T *output_size_returned,
826 IRP *irp
829 FIXME("client %p, control_code %#x, input_size %lu, input_buffer %p, output_size %lu, "
830 "output_buffer %p, output_size_returned %p, irp %p, stub.\n",
831 client, control_code, input_size, input_buffer, output_size, output_buffer,
832 output_size_returned, irp);
834 return STATUS_NOT_IMPLEMENTED;
837 struct wsk_get_address_info_context
839 UNICODE_STRING *node_name;
840 UNICODE_STRING *service_name;
841 ULONG namespace;
842 GUID *provider;
843 ADDRINFOEXW *hints;
844 ADDRINFOEXW **result;
845 IRP *irp;
848 static void WINAPI get_address_info_callback(TP_CALLBACK_INSTANCE *instance, void *context_)
850 struct wsk_get_address_info_context *context = context_;
851 INT ret;
853 TRACE("instance %p, context %p.\n", instance, context);
855 ret = GetAddrInfoExW( context->node_name ? context->node_name->Buffer : NULL,
856 context->service_name ? context->service_name->Buffer : NULL, context->namespace,
857 context->provider, context->hints, context->result, NULL, NULL, NULL, NULL);
859 context->irp->IoStatus.Information = 0;
860 dispatch_irp(context->irp, sock_error_to_ntstatus(ret));
861 heap_free(context);
864 static NTSTATUS WINAPI wsk_get_address_info(WSK_CLIENT *client, UNICODE_STRING *node_name,
865 UNICODE_STRING *service_name, ULONG name_space, GUID *provider, ADDRINFOEXW *hints,
866 ADDRINFOEXW **result, PEPROCESS owning_process, PETHREAD owning_thread, IRP *irp)
868 struct wsk_get_address_info_context *context;
869 NTSTATUS status;
871 TRACE("client %p, node_name %p, service_name %p, name_space %#x, provider %p, hints %p, "
872 "result %p, owning_process %p, owning_thread %p, irp %p.\n",
873 client, node_name, service_name, name_space, provider, hints, result,
874 owning_process, owning_thread, irp);
876 if (!irp)
877 return STATUS_INVALID_PARAMETER;
879 if (!(context = heap_alloc(sizeof(*context))))
881 ERR("No memory.\n");
882 status = STATUS_NO_MEMORY;
883 dispatch_irp(irp, status);
884 return status;
887 context->node_name = node_name;
888 context->service_name = service_name;
889 context->namespace = name_space;
890 context->provider = provider;
891 context->hints = hints;
892 context->result = result;
893 context->irp = irp;
895 if (!TrySubmitThreadpoolCallback(get_address_info_callback, context, NULL))
897 ERR("Could not submit thread pool callback.\n");
898 status = STATUS_UNSUCCESSFUL;
899 dispatch_irp(irp, status);
900 heap_free(context);
901 return status;
903 TRACE("Submitted threadpool callback, context %p.\n", context);
904 return STATUS_PENDING;
907 static void WINAPI wsk_free_address_info(WSK_CLIENT *client, ADDRINFOEXW *addr_info)
909 TRACE("client %p, addr_info %p.\n", client, addr_info);
911 FreeAddrInfoExW(addr_info);
914 static NTSTATUS WINAPI wsk_get_name_info(WSK_CLIENT *client, SOCKADDR *sock_addr, ULONG sock_addr_length,
915 UNICODE_STRING *node_name, UNICODE_STRING *service_name, ULONG flags, PEPROCESS owning_process,
916 PETHREAD owning_thread, IRP *irp)
918 FIXME("client %p, sock_addr %p, sock_addr_length %u, node_name %p, service_name %p, "
919 "flags %#x, owning_process %p, owning_thread %p, irp %p stub.\n",
920 client, sock_addr, sock_addr_length, node_name, service_name, flags,
921 owning_process, owning_thread, irp);
923 return STATUS_NOT_IMPLEMENTED;
926 static const WSK_PROVIDER_DISPATCH wsk_dispatch =
928 MAKE_WSK_VERSION(1, 0), 0,
929 wsk_socket,
930 wsk_socket_connect,
931 wsk_control_client,
932 wsk_get_address_info,
933 wsk_free_address_info,
934 wsk_get_name_info,
937 NTSTATUS WINAPI WskCaptureProviderNPI(WSK_REGISTRATION *wsk_registration, ULONG wait_timeout,
938 WSK_PROVIDER_NPI *wsk_provider_npi)
940 WSK_CLIENT *client = wsk_registration->ReservedRegistrationContext;
942 TRACE("wsk_registration %p, wait_timeout %u, wsk_provider_npi %p.\n",
943 wsk_registration, wait_timeout, wsk_provider_npi);
945 wsk_provider_npi->Client = client;
946 wsk_provider_npi->Dispatch = &wsk_dispatch;
947 return STATUS_SUCCESS;
950 void WINAPI WskReleaseProviderNPI(WSK_REGISTRATION *wsk_registration)
952 TRACE("wsk_registration %p.\n", wsk_registration);
956 NTSTATUS WINAPI WskRegister(WSK_CLIENT_NPI *wsk_client_npi, WSK_REGISTRATION *wsk_registration)
958 static const WORD version = MAKEWORD( 2, 2 );
959 WSADATA data;
961 WSK_CLIENT *client;
963 TRACE("wsk_client_npi %p, wsk_registration %p.\n", wsk_client_npi, wsk_registration);
965 if (!(client = heap_alloc(sizeof(*client))))
967 ERR("No memory.\n");
968 return STATUS_NO_MEMORY;
971 client->registration = wsk_registration;
972 client->client_npi = wsk_client_npi;
973 wsk_registration->ReservedRegistrationContext = client;
975 if (WSAStartup(version, &data))
976 return STATUS_INTERNAL_ERROR;
978 return STATUS_SUCCESS;
981 void WINAPI WskDeregister(WSK_REGISTRATION *wsk_registration)
983 TRACE("wsk_registration %p.\n", wsk_registration);
985 heap_free(wsk_registration->ReservedRegistrationContext);
988 static void WINAPI driver_unload(DRIVER_OBJECT *driver)
990 TRACE("driver %p.\n", driver);
993 NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *path)
995 TRACE("driver %p, path %s.\n", driver, debugstr_w(path->Buffer));
997 driver->DriverUnload = driver_unload;
998 return STATUS_SUCCESS;