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
23 #define NONAMELESSUNION
24 #define NONAMELESSSTRUCT
27 #define WIN32_NO_STATUS
33 #include "wine/debug.h"
37 #include "wine/heap.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(netio
);
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
;
53 char addr_buffer
[2 * (sizeof(SOCKADDR
) + 16)];
57 #define MAX_PENDING_IO 10
67 struct wsk_socket_internal
69 WSK_SOCKET wsk_socket
;
71 const void *client_dispatch
;
74 ADDRESS_FAMILY address_family
;
79 CRITICAL_SECTION cs_socket
;
81 struct wsk_pending_io pending_io
[MAX_PENDING_IO
];
85 struct listen_socket_callback_context listen_socket_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
)
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
;
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
;
171 for (i
= 0; i
< ARRAY_SIZE(socket
->pending_io
); ++i
)
175 if (io
[i
].callback
== socket_async_callback
)
188 FIXME("Pending io requests count exceeds limit.\n");
192 io
[io_index
].irp
= irp
;
194 if (io
[io_index
].tp_wait
)
195 CloseThreadpoolWait(io
[io_index
].tp_wait
);
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
)
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
);
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
);
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
);
246 TRACE("socket %p, irp %p.\n", socket
, irp
);
250 for (i
= 0; i
< ARRAY_SIZE(s
->pending_io
); ++i
)
252 struct wsk_pending_io
*io
= &s
->pending_io
[i
];
256 CancelIoEx((HANDLE
)s
->s
, &io
->ovr
);
257 SetThreadpoolWait(io
->tp_wait
, NULL
, NULL
);
259 WaitForThreadpoolWaitCallbacks(io
->tp_wait
, FALSE
);
261 CloseThreadpoolWait(io
->tp_wait
);
262 CloseHandle(io
->ovr
.hEvent
);
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
;
275 DeleteCriticalSection(&s
->cs_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
);
289 TRACE("socket %p, local_address %p, flags %#x, irp %p.\n",
290 socket
, local_address
, flags
, 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());
300 status
= STATUS_SUCCESS
;
302 if (status
== STATUS_SUCCESS
)
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
))))
322 dispatch_pending_io(io
, STATUS_NO_MEMORY
, 0);
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
;
360 TRACE("instance %p, socket %p, wait %p, wait_result %#x.\n", instance
, socket
, wait
, wait_result
);
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
);
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
;
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());
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());
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
;
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
);
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
;
430 if (!(io
= allocate_pending_io(s
, accept_callback
, irp
)))
432 irp
->IoStatus
.Information
= 0;
433 dispatch_irp(irp
, STATUS_UNSUCCESSFUL
);
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
))
442 dispatch_pending_io(io
, sock_error_to_ntstatus(WSAGetLastError()), 0);
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
);
464 closesocket(acceptor
);
465 context
->acceptor
= 0;
466 dispatch_pending_io(io
, sock_error_to_ntstatus(error
), 0);
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
=
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
;
508 TRACE("instance %p, socket %p, wait %p, wait_result %#x.\n", instance
, socket
, wait
, wait_result
);
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
;
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());
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
;
540 TRACE("socket %p, remote_address %p, flags %#x, irp %p.\n",
541 socket
, remote_address
, flags
, 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
;
554 if (!(io
= allocate_pending_io(s
, connect_callback
, irp
)))
556 irp
->IoStatus
.Information
= 0;
557 dispatch_irp(irp
, STATUS_UNSUCCESSFUL
);
559 return STATUS_PENDING
;
564 dispatch_pending_io(io
, STATUS_INVALID_DEVICE_STATE
, 0);
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
);
574 dispatch_pending_io(io
, sock_error_to_ntstatus(error
), 0);
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
;
595 TRACE("instance %p, socket %p, wait %p, wait_result %#x.\n", instance
, socket
, wait
, wait_result
);
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
);
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
;
617 TRACE("socket %p, buffer %p, flags %#x, irp %p, is_send %#x.\n",
618 socket
, wsk_buf
, flags
, irp
, is_send
);
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
;
635 FIXME("flags %#x not implemented.\n", flags
);
638 if (!(io
= allocate_pending_io(s
, send_receive_callback
, irp
)))
640 irp
->IoStatus
.Information
= 0;
641 dispatch_irp(irp
, STATUS_UNSUCCESSFUL
);
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
;
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
);
663 dispatch_pending_io(io
, sock_error_to_ntstatus(error
), 0);
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
=
729 wsk_get_local_address
,
730 wsk_get_remote_address
,
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
;
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
);
754 return STATUS_INVALID_PARAMETER
;
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());
767 if (!(socket
= heap_alloc_zero(sizeof(*socket
))))
769 status
= STATUS_NO_MEMORY
;
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
;
784 case WSK_FLAG_LISTEN_SOCKET
:
785 socket
->wsk_socket
.Dispatch
= &wsk_provider_listen_dispatch
;
788 case WSK_FLAG_CONNECTION_SOCKET
:
789 socket
->wsk_socket
.Dispatch
= &wsk_provider_connection_dispatch
;
793 FIXME("Flags %#x not implemented.\n", flags
);
796 status
= STATUS_NOT_IMPLEMENTED
;
802 irp
->IoStatus
.Information
= (ULONG_PTR
)&socket
->wsk_socket
;
803 status
= STATUS_SUCCESS
;
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
,
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
;
844 ADDRINFOEXW
**result
;
848 static void WINAPI
get_address_info_callback(TP_CALLBACK_INSTANCE
*instance
, void *context_
)
850 struct wsk_get_address_info_context
*context
= context_
;
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
));
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
;
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
);
877 return STATUS_INVALID_PARAMETER
;
879 if (!(context
= heap_alloc(sizeof(*context
))))
882 status
= STATUS_NO_MEMORY
;
883 dispatch_irp(irp
, 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
;
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
);
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,
932 wsk_get_address_info
,
933 wsk_free_address_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 );
963 TRACE("wsk_client_npi %p, wsk_registration %p.\n", wsk_client_npi
, wsk_registration
);
965 if (!(client
= heap_alloc(sizeof(*client
))))
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
;