aboutsummaryrefslogtreecommitdiff
path: root/ksocket
diff options
context:
space:
mode:
Diffstat (limited to 'ksocket')
-rw-r--r--ksocket/berkeley.c580
-rw-r--r--ksocket/berkeley.h41
-rw-r--r--ksocket/helper.hpp157
-rw-r--r--ksocket/ksocket.c713
-rw-r--r--ksocket/ksocket.h99
-rw-r--r--ksocket/wsk.h460
6 files changed, 2050 insertions, 0 deletions
diff --git a/ksocket/berkeley.c b/ksocket/berkeley.c
new file mode 100644
index 0000000..e72f92e
--- /dev/null
+++ b/ksocket/berkeley.c
@@ -0,0 +1,580 @@
+#include "berkeley.h"
+#include "ksocket.h"
+
+//////////////////////////////////////////////////////////////////////////
+// Definitions.
+//////////////////////////////////////////////////////////////////////////
+
+#define MEMORY_TAG ((ULONG)0x2e2e4242)
+#define SOCKETFD_MAX 128
+#define TO_SOCKETFD(index) ((index % SOCKETFD_MAX) + 0)
+#define FROM_SOCKETFD(sockfd) ((sockfd)-0)
+
+//////////////////////////////////////////////////////////////////////////
+// Function prototypes.
+//////////////////////////////////////////////////////////////////////////
+
+NTSTATUS
+NTAPI
+KspUtilAddrInfoToAddrInfoEx(_In_ PADDRINFOA AddrInfo,
+ _Out_ PADDRINFOEXW *AddrInfoEx);
+
+NTSTATUS
+NTAPI
+KspUtilAddrInfoExToAddrInfo(_In_ PADDRINFOEXW AddrInfoEx,
+ _Out_ PADDRINFOA *AddrInfo);
+
+VOID NTAPI KspUtilFreeAddrInfo(_In_ PADDRINFOA AddrInfo);
+
+VOID NTAPI KspUtilFreeAddrInfoEx(_In_ PADDRINFOEXW AddrInfo);
+
+//////////////////////////////////////////////////////////////////////////
+// Variables.
+//////////////////////////////////////////////////////////////////////////
+
+//
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+//
+// This is complete bollocks and ideally it should be replaced with
+// something like RTL_AVL_TABLE.
+//
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+//
+
+PKSOCKET KsArray[SOCKETFD_MAX] = {0};
+ULONG KsIndex = 0;
+
+//////////////////////////////////////////////////////////////////////////
+// Private functions.
+//////////////////////////////////////////////////////////////////////////
+
+NTSTATUS
+NTAPI
+KspUtilAddrInfoToAddrInfoEx(_In_ PADDRINFOA AddrInfo,
+ _Out_ PADDRINFOEXW *AddrInfoEx) {
+ NTSTATUS Status;
+
+ //
+ // Convert NULL input into NULL output.
+ //
+
+ if (AddrInfo == NULL) {
+ *AddrInfoEx = NULL;
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Allocate memory for the output structure.
+ //
+
+ PADDRINFOEXW Result =
+ ExAllocatePoolWithTag(PagedPool, sizeof(ADDRINFOEXW), MEMORY_TAG);
+
+ if (Result == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Error1;
+ }
+
+ //
+ // Copy numeric values.
+ //
+
+ RtlZeroMemory(Result, sizeof(ADDRINFOEXW));
+ Result->ai_flags = AddrInfo->ai_flags;
+ Result->ai_family = AddrInfo->ai_family;
+ Result->ai_socktype = AddrInfo->ai_socktype;
+ Result->ai_protocol = AddrInfo->ai_protocol;
+ Result->ai_addrlen = AddrInfo->ai_addrlen;
+
+ //
+ // Copy canonical name.
+ //
+
+ ANSI_STRING CanonicalNameAnsi;
+ UNICODE_STRING CanonicalNameUnicode;
+
+ if (AddrInfo->ai_canonname) {
+ RtlInitAnsiString(&CanonicalNameAnsi, AddrInfo->ai_canonname);
+
+ Status = RtlAnsiStringToUnicodeString(&CanonicalNameUnicode,
+ &CanonicalNameAnsi, TRUE);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error2;
+ }
+
+ Result->ai_canonname = CanonicalNameUnicode.Buffer;
+ }
+
+ //
+ // Copy address.
+ //
+
+ Result->ai_addr = AddrInfo->ai_addr;
+
+ //
+ // Copy the next structure (recursively).
+ //
+
+ PADDRINFOEXW NextAddrInfo;
+ Status = KspUtilAddrInfoToAddrInfoEx(AddrInfo->ai_next, &NextAddrInfo);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error3;
+ }
+
+ Result->ai_next = NextAddrInfo;
+
+ //
+ // All done!
+ //
+
+ *AddrInfoEx = Result;
+
+ return Status;
+
+Error3:
+ RtlFreeAnsiString(&CanonicalNameAnsi);
+
+Error2:
+ ExFreePoolWithTag(Result, MEMORY_TAG);
+
+Error1:
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+KspUtilAddrInfoExToAddrInfo(_In_ PADDRINFOEXW AddrInfoEx,
+ _Out_ PADDRINFOA *AddrInfo) {
+ NTSTATUS Status;
+
+ //
+ // Convert NULL input into NULL output.
+ //
+
+ if (AddrInfoEx == NULL) {
+ *AddrInfo = NULL;
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Allocate memory for the output structure.
+ //
+
+ PADDRINFOA Result =
+ ExAllocatePoolWithTag(PagedPool, sizeof(ADDRINFOA), MEMORY_TAG);
+
+ if (Result == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Error1;
+ }
+
+ //
+ // Copy numeric values.
+ //
+
+ RtlZeroMemory(Result, sizeof(ADDRINFOA));
+ Result->ai_flags = AddrInfoEx->ai_flags;
+ Result->ai_family = AddrInfoEx->ai_family;
+ Result->ai_socktype = AddrInfoEx->ai_socktype;
+ Result->ai_protocol = AddrInfoEx->ai_protocol;
+ Result->ai_addrlen = AddrInfoEx->ai_addrlen;
+
+ //
+ // Copy canonical name.
+ //
+
+ UNICODE_STRING CanonicalNameUnicode;
+ ANSI_STRING CanonicalNameAnsi;
+
+ if (AddrInfoEx->ai_canonname) {
+ RtlInitUnicodeString(&CanonicalNameUnicode, AddrInfoEx->ai_canonname);
+ Status = RtlUnicodeStringToAnsiString(&CanonicalNameAnsi,
+ &CanonicalNameUnicode, TRUE);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error2;
+ }
+
+ Result->ai_canonname = CanonicalNameAnsi.Buffer;
+ }
+
+ //
+ // Copy address.
+ //
+
+ Result->ai_addr = AddrInfoEx->ai_addr;
+
+ //
+ // Copy the next structure (recursively).
+ //
+
+ PADDRINFOA NextAddrInfo;
+ Status = KspUtilAddrInfoExToAddrInfo(AddrInfoEx->ai_next, &NextAddrInfo);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error3;
+ }
+
+ Result->ai_next = NextAddrInfo;
+
+ //
+ // All done!
+ //
+
+ *AddrInfo = Result;
+
+ return Status;
+
+Error3:
+ RtlFreeAnsiString(&CanonicalNameAnsi);
+
+Error2:
+ ExFreePoolWithTag(Result, MEMORY_TAG);
+
+Error1:
+ return Status;
+}
+
+VOID NTAPI KspUtilFreeAddrInfo(_In_ PADDRINFOA AddrInfo) {
+ //
+ // Free all structures recursively.
+ //
+
+ if (AddrInfo->ai_next) {
+ KspUtilFreeAddrInfo(AddrInfo->ai_next);
+ }
+
+ //
+ // Free the canonical name buffer.
+ //
+
+ if (AddrInfo->ai_canonname) {
+ ANSI_STRING CanonicalName;
+ RtlInitAnsiString(&CanonicalName, AddrInfo->ai_canonname);
+ RtlFreeAnsiString(&CanonicalName);
+ }
+
+ //
+ // Finally, free the structure itself.
+ //
+
+ ExFreePoolWithTag(AddrInfo, MEMORY_TAG);
+}
+
+VOID NTAPI KspUtilFreeAddrInfoEx(_In_ PADDRINFOEXW AddrInfo) {
+ //
+ // Free all structures recursively.
+ //
+
+ if (AddrInfo->ai_next) {
+ KspUtilFreeAddrInfoEx(AddrInfo->ai_next);
+ }
+
+ //
+ // Free the canonical name buffer.
+ //
+
+ if (AddrInfo->ai_canonname) {
+ UNICODE_STRING CanonicalName;
+ RtlInitUnicodeString(&CanonicalName, AddrInfo->ai_canonname);
+ RtlFreeUnicodeString(&CanonicalName);
+ }
+
+ //
+ // Finally, free the structure itself.
+ //
+
+ ExFreePoolWithTag(AddrInfo, MEMORY_TAG);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Public functions.
+//////////////////////////////////////////////////////////////////////////
+
+uint32_t htonl(uint32_t hostlong) { return __builtin_bswap32(hostlong); }
+
+uint16_t htons(uint16_t hostshort) { return __builtin_bswap16(hostshort); }
+
+uint32_t ntohl(uint32_t netlong) { return __builtin_bswap32(netlong); }
+
+uint16_t ntohs(uint16_t netshort) { return __builtin_bswap16(netshort); }
+
+int getaddrinfo(const char *node, const char *service,
+ const struct addrinfo *hints, struct addrinfo **res) {
+ NTSTATUS Status;
+
+ //
+ // Convert node name to the UNICODE_STRING (if present).
+ //
+
+ ANSI_STRING NodeNameAnsi;
+ UNICODE_STRING NodeNameUnicode;
+ PUNICODE_STRING NodeName = NULL;
+
+ if (node) {
+ RtlInitAnsiString(&NodeNameAnsi, node);
+ Status =
+ RtlAnsiStringToUnicodeString(&NodeNameUnicode, &NodeNameAnsi, TRUE);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error1;
+ }
+
+ NodeName = &NodeNameUnicode;
+ }
+
+ //
+ // Convert service name to the UNICODE_STRING (if present).
+ //
+
+ ANSI_STRING ServiceNameAnsi;
+ UNICODE_STRING ServiceNameUnicode;
+ PUNICODE_STRING ServiceName = NULL;
+
+ if (service) {
+ RtlInitAnsiString(&ServiceNameAnsi, service);
+ Status = RtlAnsiStringToUnicodeString(&ServiceNameUnicode, &ServiceNameAnsi,
+ TRUE);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error2;
+ }
+
+ ServiceName = &ServiceNameUnicode;
+ }
+
+ //
+ // Convert "struct addrinfo" to the "ADDRINFOEXW".
+ //
+
+ PADDRINFOEXW Hints;
+ Status = KspUtilAddrInfoToAddrInfoEx((PADDRINFOA)hints, &Hints);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error3;
+ }
+
+ //
+ // All data is prepared, call the underlying API.
+ //
+
+ PADDRINFOEXW Result;
+ Status = KsGetAddrInfo(NodeName, ServiceName, Hints, &Result);
+
+ //
+ // Free the memory of the converted "Hints".
+ //
+
+ KspUtilFreeAddrInfoEx(Hints);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error3;
+ }
+
+ //
+ // Convert the result "ADDRINFOEXW" to the "struct addrinfo".
+ //
+
+ Status = KspUtilAddrInfoExToAddrInfo(Result, res);
+
+ //
+ // Free the original result.
+ //
+
+ KsFreeAddrInfo(Result);
+
+ if (!NT_SUCCESS(Status)) {
+ goto Error3;
+ }
+
+ return STATUS_SUCCESS;
+
+Error3:
+ RtlFreeUnicodeString(&ServiceNameUnicode);
+
+Error2:
+ RtlFreeUnicodeString(&NodeNameUnicode);
+
+Error1:
+ return Status;
+}
+
+void freeaddrinfo(struct addrinfo *res) {
+ //
+ // Call our implementation.
+ //
+
+ KspUtilFreeAddrInfo(res);
+}
+
+int socket_connection(int domain, int type, int protocol) {
+ NTSTATUS Status;
+ PKSOCKET Socket;
+
+ Status = KsCreateConnectionSocket(&Socket, (ADDRESS_FAMILY)domain,
+ (USHORT)type, (ULONG)protocol);
+
+ if (NT_SUCCESS(Status)) {
+ int sockfd = TO_SOCKETFD(KsIndex++);
+
+ KsArray[FROM_SOCKETFD(sockfd)] = Socket;
+
+ return sockfd;
+ }
+
+ return -1;
+}
+
+int socket_listen(int domain, int type, int protocol) {
+ NTSTATUS Status;
+ PKSOCKET Socket;
+
+ //
+ // WskSocket() returns STATUS_PROTOCOL_UNREACHABLE (0xC000023E)
+ // when Protocol == 0, so coerce this value to IPPROTO_TCP here.
+ //
+
+ Status = KsCreateListenSocket(&Socket, (ADDRESS_FAMILY)domain, (USHORT)type,
+ protocol ? (ULONG)protocol : IPPROTO_TCP);
+
+ if (NT_SUCCESS(Status)) {
+ int sockfd = TO_SOCKETFD(KsIndex++);
+
+ KsArray[FROM_SOCKETFD(sockfd)] = Socket;
+
+ return sockfd;
+ }
+
+ return -1;
+}
+
+int socket_datagram(int domain, int type, int protocol) {
+ NTSTATUS Status;
+ PKSOCKET Socket;
+
+ Status = KsCreateDatagramSocket(&Socket, (ADDRESS_FAMILY)domain, (USHORT)type,
+ (ULONG)protocol);
+
+ if (NT_SUCCESS(Status)) {
+ int sockfd = TO_SOCKETFD(KsIndex++);
+
+ KsArray[FROM_SOCKETFD(sockfd)] = Socket;
+
+ return sockfd;
+ }
+
+ return -1;
+}
+
+int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
+ UNREFERENCED_PARAMETER(addrlen);
+
+ NTSTATUS Status;
+ PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)];
+
+ Status = KsConnect(Socket, (PSOCKADDR)addr);
+
+ return NT_SUCCESS(Status) ? 0 : -1;
+}
+
+int listen(int sockfd, int backlog) {
+ UNREFERENCED_PARAMETER(sockfd);
+ UNREFERENCED_PARAMETER(backlog);
+ return 0;
+}
+
+int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
+ UNREFERENCED_PARAMETER(addrlen);
+
+ NTSTATUS Status;
+ PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)];
+
+ Status = KsBind(Socket, (PSOCKADDR)addr);
+
+ return NT_SUCCESS(Status) ? 0 : -1;
+}
+
+int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
+ NTSTATUS Status;
+ PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)];
+
+ PKSOCKET NewSocket;
+ Status = KsAccept(Socket, &NewSocket, NULL, (PSOCKADDR)addr);
+ *addrlen = sizeof(SOCKADDR);
+
+ if (NT_SUCCESS(Status)) {
+ int newsockfd = TO_SOCKETFD(KsIndex++);
+
+ KsArray[FROM_SOCKETFD(newsockfd)] = NewSocket;
+
+ return newsockfd;
+ }
+
+ return -1;
+}
+
+int send(int sockfd, const void *buf, size_t len, int flags) {
+ NTSTATUS Status;
+ PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)];
+
+ ULONG Length = (ULONG)len;
+ Status = KsSend(Socket, (PVOID)buf, &Length, (ULONG)flags);
+
+ return NT_SUCCESS(Status) ? (int)Length : -1;
+}
+
+int sendto(int sockfd, const void *buf, size_t len, int flags,
+ const struct sockaddr *dest_addr, socklen_t addrlen) {
+ UNREFERENCED_PARAMETER(addrlen);
+
+ NTSTATUS Status;
+ PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)];
+
+ ULONG Length = (ULONG)len;
+ Status =
+ KsSendTo(Socket, (PVOID)buf, &Length, (ULONG)flags, (PSOCKADDR)dest_addr);
+
+ return NT_SUCCESS(Status) ? (int)Length : -1;
+}
+
+int recv(int sockfd, void *buf, size_t len, int flags) {
+ NTSTATUS Status;
+ PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)];
+
+ ULONG Length = (ULONG)len;
+ Status = KsRecv(Socket, (PVOID)buf, &Length, (ULONG)flags);
+
+ return NT_SUCCESS(Status) ? (int)Length : -1;
+}
+
+int recvfrom(int sockfd, void *buf, size_t len, int flags,
+ struct sockaddr *src_addr, socklen_t *addrlen) {
+ UNREFERENCED_PARAMETER(addrlen);
+
+ NTSTATUS Status;
+ PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)];
+
+ ULONG Length = (ULONG)len;
+ Status =
+ KsSendTo(Socket, (PVOID)buf, &Length, (ULONG)flags, (PSOCKADDR)src_addr);
+ *addrlen = sizeof(SOCKADDR);
+
+ return NT_SUCCESS(Status) ? (int)Length : -1;
+}
+
+int closesocket(int sockfd) {
+ NTSTATUS Status;
+ PKSOCKET Socket = KsArray[FROM_SOCKETFD(sockfd)];
+
+ Status = KsCloseSocket(Socket);
+
+ KsArray[FROM_SOCKETFD(sockfd)] = NULL;
+
+ return NT_SUCCESS(Status) ? 0 : -1;
+}
diff --git a/ksocket/berkeley.h b/ksocket/berkeley.h
new file mode 100644
index 0000000..b879d3c
--- /dev/null
+++ b/ksocket/berkeley.h
@@ -0,0 +1,41 @@
+#pragma once
+#include <ntddk.h>
+#include <stdint.h>
+#include <ksocket/wsk.h>
+
+#define socket socket_connection
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int socklen_t;
+typedef intptr_t ssize_t;
+
+uint32_t htonl(uint32_t hostlong);
+uint16_t htons(uint16_t hostshort);
+uint32_t ntohl(uint32_t netlong);
+uint16_t ntohs(uint16_t netshort);
+
+int getaddrinfo(const char *node, const char *service,
+ const struct addrinfo *hints, struct addrinfo **res);
+void freeaddrinfo(struct addrinfo *res);
+
+int socket_connection(int domain, int type, int protocol);
+int socket_listen(int domain, int type, int protocol);
+int socket_datagram(int domain, int type, int protocol);
+int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+int listen(int sockfd, int backlog);
+int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+int send(int sockfd, const void *buf, size_t len, int flags);
+int sendto(int sockfd, const void *buf, size_t len, int flags,
+ const struct sockaddr *dest_addr, socklen_t addrlen);
+int recv(int sockfd, void *buf, size_t len, int flags);
+int recvfrom(int sockfd, void *buf, size_t len, int flags,
+ struct sockaddr *src_addr, socklen_t *addrlen);
+int closesocket(int sockfd);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/ksocket/helper.hpp b/ksocket/helper.hpp
new file mode 100644
index 0000000..153e549
--- /dev/null
+++ b/ksocket/helper.hpp
@@ -0,0 +1,157 @@
+#ifndef HELPER_HPP
+#define HELPER_HPP 1
+
+#include <protobuf-c/protobuf-c.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <EASTL/algorithm.h>
+#include <EASTL/array.h>
+#include <EASTL/initializer_list.h>
+#include <EASTL/string.h>
+#include <EASTL/vector.h>
+
+#ifndef SOCKET_ERROR
+#define SOCKET_ERROR -1
+#endif
+
+#define SEND_ALL(sock, socket_buffer, retval) \
+ if (socket_buffer.GetRemainingSendSize() > 0) { \
+ do { \
+ retval = send(sock, socket_buffer.GetStartS(), \
+ socket_buffer.GetRemainingSendSize(), 0); \
+ if (retval == SOCKET_ERROR || retval == 0) \
+ break; \
+ if (!socket_buffer.Consume(iResult)) \
+ break; \
+ } while (!socket_buffer.AllConsumed()); \
+ socket_buffer.Sweep(); \
+ }
+#define RECV_PDU_BEGIN(sock, socket_buffer, retval, pdu_type, pdu_len) \
+ do { \
+ if (socket_buffer.GetRemainingRecvSize() == 0) \
+ break; \
+ uint16_t pdu_type; \
+ uint32_t pdu_len; \
+ do { \
+ retval = recv(sock, socket_buffer.GetStartS(), \
+ socket_buffer.GetRemainingRecvSize(), 0); \
+ if (retval == SOCKET_ERROR || retval == 0) \
+ break; \
+ } while (!socket_buffer.GetPdu(retval, pdu_type, pdu_len));
+#define RECV_PDU_END(socket_buffer, pdu_len) \
+ socket_buffer.Consume(pdu_len); \
+ socket_buffer.Sweep(); \
+ } \
+ while (0)
+
+class BaseSerializer {
+public:
+ virtual uint16_t GetPduType(void) = 0;
+ virtual size_t GetSerializedSize(void) = 0;
+ virtual size_t Serialize(uint8_t *buf) = 0;
+};
+
+class BaseDeserializer {
+public:
+ virtual bool Deserialize(size_t pdu_len, uint8_t *buf) = 0;
+ virtual void DeserializeFree(void) = 0;
+};
+
+template <size_t SIZE> class SocketBuffer {
+public:
+ SocketBuffer(void) {}
+ ~SocketBuffer(void) {}
+ size_t GetRemainingSendSize(void) { return GetUsed(); }
+ size_t GetRemainingRecvSize(void) { return GetSize() - GetUsed(); }
+ uint8_t *GetStart(void) { return buffer + consumed; }
+ char *GetStartS(void) { return (char *)buffer + consumed; }
+ bool SizeCheck(size_t required_size) { return used + required_size < SIZE; };
+ template <typename T> bool GetPrimitve(size_t offset, T &out) {
+ if (offset + sizeof(out) > used)
+ return false;
+ out = *(T *)(GetStart() + offset);
+ return true;
+ }
+ template <typename T> bool AddPrimitve(T value) {
+ if (!SizeCheck(sizeof(value)))
+ return false;
+ *(T *)(GetEnd()) = value;
+ used += sizeof(value);
+ return true;
+ }
+ bool GetPdu(size_t received_size, uint16_t &pdu_type, uint32_t &pdu_len) {
+ if (received_size > SIZE - used)
+ return false; // You did something wrong!
+ used += received_size;
+ if (used < sizeof(pdu_type) + sizeof(pdu_len))
+ return false;
+ if (GetPrimitve<uint32_t>(0, pdu_len) == false)
+ return false;
+ if (GetPrimitve<uint16_t>(4, pdu_type) == false)
+ return false;
+
+ pdu_len = ntohl(pdu_len);
+ pdu_type = ntohs(pdu_type);
+
+ if (used < sizeof(pdu_type) + sizeof(pdu_len) + pdu_len)
+ return false;
+
+ consumed += sizeof(pdu_type) + sizeof(pdu_len);
+
+ return true;
+ }
+ bool AddPdu(BaseSerializer &bs) {
+ uint16_t pdu_type = bs.GetPduType();
+ uint32_t pdu_len = bs.GetSerializedSize();
+
+ if (!SizeCheck(sizeof(pdu_type) + sizeof(pdu_len) + pdu_len))
+ return false;
+
+ if (!AddPrimitve<uint32_t>(htonl(pdu_len)))
+ return false;
+ if (!AddPrimitve<uint16_t>(htons(pdu_type)))
+ return false;
+ if (bs.Serialize(GetEnd()) != pdu_len)
+ return false;
+ used += pdu_len;
+
+ return true;
+ }
+ bool AllConsumed(void) { return used == consumed; }
+ bool Consume(size_t consuming_size) {
+ if (consuming_size + consumed > used)
+ return false;
+ consumed += consuming_size;
+ return true;
+ }
+ void Sweep() {
+ if (consumed == 0)
+ return;
+ if (used != consumed)
+ memmove(buffer, buffer + consumed, used - consumed);
+ used -= consumed;
+ consumed = 0;
+ }
+
+private:
+ uint8_t buffer[SIZE];
+ size_t used = 0;
+ size_t consumed = 0;
+
+ size_t GetSize(void) { return SIZE; }
+ size_t GetUsed(void) { return used - consumed; }
+ uint8_t *GetEnd() { return buffer + used; }
+};
+
+class ProtobufCBinaryDataClass : public ProtobufCBinaryData {
+public:
+ ProtobufCBinaryDataClass(std::initializer_list<uint8_t> bytes) {
+ len = bytes.size();
+ data = new uint8_t[len];
+ eastl::copy(bytes.begin(), bytes.end(), data);
+ }
+ ~ProtobufCBinaryDataClass(void) { delete data; }
+};
+
+#endif
diff --git a/ksocket/ksocket.c b/ksocket/ksocket.c
new file mode 100644
index 0000000..3b6ba4d
--- /dev/null
+++ b/ksocket/ksocket.c
@@ -0,0 +1,713 @@
+#include "ksocket.h"
+
+//////////////////////////////////////////////////////////////////////////
+// Definitions.
+//////////////////////////////////////////////////////////////////////////
+
+#define MEMORY_TAG ((ULONG)0x2e2e4142)
+
+//////////////////////////////////////////////////////////////////////////
+// Structures.
+//////////////////////////////////////////////////////////////////////////
+
+typedef struct _KSOCKET_ASYNC_CONTEXT {
+ KEVENT CompletionEvent;
+ PIRP Irp;
+} KSOCKET_ASYNC_CONTEXT, *PKSOCKET_ASYNC_CONTEXT;
+
+typedef struct _KSOCKET {
+ PWSK_SOCKET WskSocket;
+
+ union {
+ PVOID WskDispatch;
+
+ PWSK_PROVIDER_CONNECTION_DISPATCH WskConnectionDispatch;
+ PWSK_PROVIDER_LISTEN_DISPATCH WskListenDispatch;
+ PWSK_PROVIDER_DATAGRAM_DISPATCH WskDatagramDispatch;
+#if (NTDDI_VERSION >= NTDDI_WIN10_RS2)
+ PWSK_PROVIDER_STREAM_DISPATCH WskStreamDispatch;
+#endif
+ };
+
+ KSOCKET_ASYNC_CONTEXT AsyncContext;
+} KSOCKET, *PKSOCKET;
+
+//////////////////////////////////////////////////////////////////////////
+// Variables.
+//////////////////////////////////////////////////////////////////////////
+
+WSK_REGISTRATION WskRegistration;
+WSK_PROVIDER_NPI WskProvider;
+WSK_CLIENT_DISPATCH WskDispatch = {MAKE_WSK_VERSION(1, 0), 0, NULL};
+
+//////////////////////////////////////////////////////////////////////////
+// Function prototypes.
+//////////////////////////////////////////////////////////////////////////
+
+NTSTATUS
+NTAPI
+KspAsyncContextAllocate(_Out_ PKSOCKET_ASYNC_CONTEXT AsyncContext);
+
+VOID NTAPI KspAsyncContextFree(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext);
+
+VOID NTAPI KspAsyncContextReset(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext);
+
+static NTSTATUS
+KspAsyncContextCompletionRoutine(_In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp, _In_ PVOID CompletionEvent);
+
+NTSTATUS
+NTAPI
+KspAsyncContextWaitForCompletion(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext,
+ _Inout_ PNTSTATUS Status);
+
+//////////////////////////////////////////////////////////////////////////
+// Private functions.
+//////////////////////////////////////////////////////////////////////////
+
+NTSTATUS
+NTAPI
+KspAsyncContextAllocate(_Out_ PKSOCKET_ASYNC_CONTEXT AsyncContext) {
+ //
+ // Initialize the completion event.
+ //
+
+ KeInitializeEvent(&AsyncContext->CompletionEvent, SynchronizationEvent,
+ FALSE);
+
+ //
+ // Initialize the IRP.
+ //
+
+ AsyncContext->Irp = IoAllocateIrp(1, FALSE);
+
+ if (AsyncContext->Irp == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // KspAsyncContextCompletionRoutine will set
+ // the CompletionEvent.
+ //
+
+ IoSetCompletionRoutine(AsyncContext->Irp, &KspAsyncContextCompletionRoutine,
+ &AsyncContext->CompletionEvent, TRUE, TRUE, TRUE);
+
+ return STATUS_SUCCESS;
+}
+
+VOID NTAPI KspAsyncContextFree(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext) {
+ //
+ // Free the IRP.
+ //
+
+ IoFreeIrp(AsyncContext->Irp);
+}
+
+VOID NTAPI KspAsyncContextReset(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext) {
+ //
+ // If the WSK application allocated the IRP, or is reusing an IRP
+ // that it previously allocated, then it must set an IoCompletion
+ // routine for the IRP before calling a WSK function. In this
+ // situation, the WSK application must specify TRUE for the
+ // InvokeOnSuccess, InvokeOnError, and InvokeOnCancel parameters that
+ // are passed to the IoSetCompletionRoutine function to ensure that
+ // the IoCompletion routine is always called. Furthermore, the IoCompletion
+ // routine that is set for the IRP must always return
+ // STATUS_MORE_PROCESSING_REQUIRED to terminate the completion processing
+ // of the IRP. If the WSK application is done using the IRP after the
+ // IoCompletion routine has been called, then it should call the IoFreeIrp
+ // function to free the IRP before returning from the IoCompletion routine.
+ // If the WSK application does not free the IRP then it can reuse the IRP
+ // for a call to another WSK function.
+ //
+ // (ref:
+ // https://docs.microsoft.com/en-us/windows-hardware/drivers/network/using-irps-with-winsock-kernel-functions)
+ //
+
+ //
+ // Reset the completion event.
+ //
+
+ KeResetEvent(&AsyncContext->CompletionEvent);
+
+ //
+ // Reuse the IRP.
+ //
+
+ IoReuseIrp(AsyncContext->Irp, STATUS_UNSUCCESSFUL);
+
+ IoSetCompletionRoutine(AsyncContext->Irp, &KspAsyncContextCompletionRoutine,
+ &AsyncContext->CompletionEvent, TRUE, TRUE, TRUE);
+}
+
+static NTSTATUS
+KspAsyncContextCompletionRoutine(_In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp, _In_ PVOID CompletionEvent) {
+ UNREFERENCED_PARAMETER(DeviceObject);
+ UNREFERENCED_PARAMETER(Irp);
+
+ KeSetEvent((PKEVENT)CompletionEvent, IO_NO_INCREMENT, FALSE);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+NTAPI
+KspAsyncContextWaitForCompletion(_In_ PKSOCKET_ASYNC_CONTEXT AsyncContext,
+ _Inout_ PNTSTATUS Status) {
+ if (*Status == STATUS_PENDING) {
+ KeWaitForSingleObject(&AsyncContext->CompletionEvent, Executive, KernelMode,
+ FALSE, NULL);
+
+ *Status = AsyncContext->Irp->IoStatus.Status;
+ }
+
+ return *Status;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Public functions.
+//////////////////////////////////////////////////////////////////////////
+
+NTSTATUS
+NTAPI
+KsInitialize(VOID) {
+ OSVERSIONINFOEXW OsVersionInfo;
+ NTSTATUS Status;
+
+ OsVersionInfo.dwOSVersionInfoSize = sizeof(OsVersionInfo);
+ Status = RtlGetVersion((POSVERSIONINFOW)&OsVersionInfo);
+
+ if (!NT_SUCCESS(Status)) {
+ return Status;
+ }
+
+ if (OsVersionInfo.wProductType != VER_NT_WORKSTATION ||
+ OsVersionInfo.dwMajorVersion != 10 || OsVersionInfo.dwMinorVersion != 0) {
+ return STATUS_UNSUPPORTED_WINDOWS_VERSION;
+ }
+
+ //
+ // Register as a WSK client.
+ //
+
+ WSK_CLIENT_NPI WskClient;
+ WskClient.ClientContext = NULL;
+ WskClient.Dispatch = &WskDispatch;
+
+ Status = WskRegister(&WskClient, &WskRegistration);
+
+ if (!NT_SUCCESS(Status)) {
+ return Status;
+ }
+
+ //
+ // Capture the provider NPI.
+ //
+
+ return WskCaptureProviderNPI(&WskRegistration, WSK_INFINITE_WAIT,
+ &WskProvider);
+}
+
+VOID NTAPI KsDestroy(VOID) {
+ //
+ // Release the provider NPI instance.
+ //
+
+ WskReleaseProviderNPI(&WskRegistration);
+
+ //
+ // Deregister as a WSK client.
+ //
+
+ WskDeregister(&WskRegistration);
+}
+
+NTSTATUS
+NTAPI
+KsGetAddrInfo(_In_ PUNICODE_STRING NodeName, _In_ PUNICODE_STRING ServiceName,
+ _In_ PADDRINFOEXW Hints, _Out_ PADDRINFOEXW *Result) {
+ NTSTATUS Status;
+
+ //
+ // Allocate async context.
+ //
+
+ KSOCKET_ASYNC_CONTEXT AsyncContext;
+ Status = KspAsyncContextAllocate(&AsyncContext);
+
+ if (!NT_SUCCESS(Status)) {
+ return Status;
+ }
+
+ //
+ // Call the WSK API.
+ //
+
+ Status = WskProvider.Dispatch->WskGetAddressInfo(WskProvider.Client, // Client
+ NodeName, // NodeName
+ ServiceName, // ServiceName
+ 0, // NameSpace
+ NULL, // Provider
+ Hints, // Hints
+ Result, // Result
+ NULL, // OwningProcess
+ NULL, // OwningThread
+ AsyncContext.Irp // Irp
+ );
+
+ KspAsyncContextWaitForCompletion(&AsyncContext, &Status);
+
+ //
+ // Free the async context.
+ //
+
+ KspAsyncContextFree(&AsyncContext);
+
+ return Status;
+}
+
+VOID NTAPI KsFreeAddrInfo(_In_ PADDRINFOEXW AddrInfo) {
+ WskProvider.Dispatch->WskFreeAddressInfo(WskProvider.Client, // Client
+ AddrInfo // AddrInfo
+ );
+}
+
+NTSTATUS
+NTAPI
+KsCreateSocket(_Out_ PKSOCKET *Socket, _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType, _In_ ULONG Protocol, _In_ ULONG Flags) {
+ NTSTATUS Status;
+
+ //
+ // Allocate memory for the socket structure.
+ //
+
+ PKSOCKET NewSocket =
+ (PKSOCKET)ExAllocatePoolWithTag(PagedPool, sizeof(KSOCKET), MEMORY_TAG);
+
+ if (!NewSocket) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Allocate async context for the socket.
+ //
+
+ Status = KspAsyncContextAllocate(&NewSocket->AsyncContext);
+
+ if (!NT_SUCCESS(Status)) {
+ return Status;
+ }
+
+ //
+ // Create the WSK socket.
+ //
+
+ Status = WskProvider.Dispatch->WskSocket(WskProvider.Client, // Client
+ AddressFamily, // AddressFamily
+ SocketType, // SocketType
+ Protocol, // Protocol
+ Flags, // Flags
+ NULL, // SocketContext
+ NULL, // Dispatch
+ NULL, // OwningProcess
+ NULL, // OwningThread
+ NULL, // SecurityDescriptor
+ NewSocket->AsyncContext.Irp // Irp
+ );
+
+ KspAsyncContextWaitForCompletion(&NewSocket->AsyncContext, &Status);
+
+ //
+ // Save the socket instance and the socket dispatch table.
+ //
+
+ if (NT_SUCCESS(Status)) {
+ NewSocket->WskSocket =
+ (PWSK_SOCKET)NewSocket->AsyncContext.Irp->IoStatus.Information;
+ NewSocket->WskDispatch = (PVOID)NewSocket->WskSocket->Dispatch;
+
+ *Socket = NewSocket;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+KsCreateConnectionSocket(_Out_ PKSOCKET *Socket,
+ _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType, _In_ ULONG Protocol) {
+ return KsCreateSocket(Socket, AddressFamily, SocketType, Protocol,
+ WSK_FLAG_CONNECTION_SOCKET);
+}
+
+NTSTATUS
+NTAPI
+KsCreateListenSocket(_Out_ PKSOCKET *Socket, _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType, _In_ ULONG Protocol) {
+ return KsCreateSocket(Socket, AddressFamily, SocketType, Protocol,
+ WSK_FLAG_LISTEN_SOCKET);
+}
+
+NTSTATUS
+NTAPI
+KsCreateDatagramSocket(_Out_ PKSOCKET *Socket,
+ _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType, _In_ ULONG Protocol) {
+ return KsCreateSocket(Socket, AddressFamily, SocketType, Protocol,
+ WSK_FLAG_DATAGRAM_SOCKET);
+}
+
+NTSTATUS
+NTAPI
+KsCloseSocket(_In_ PKSOCKET Socket) {
+ NTSTATUS Status;
+
+ //
+ // Reset the async context.
+ //
+
+ KspAsyncContextReset(&Socket->AsyncContext);
+
+ //
+ // Close the WSK socket.
+ //
+
+ Status = Socket->WskConnectionDispatch->WskCloseSocket(
+ Socket->WskSocket, Socket->AsyncContext.Irp);
+
+ KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status);
+
+ //
+ // Free the async context.
+ //
+
+ KspAsyncContextFree(&Socket->AsyncContext);
+
+ //
+ // Free memory for the socket structure.
+ //
+
+ ExFreePoolWithTag(Socket, MEMORY_TAG);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+KsBind(_In_ PKSOCKET Socket, _In_ PSOCKADDR LocalAddress) {
+ NTSTATUS Status;
+
+ //
+ // Reset the async context.
+ //
+
+ KspAsyncContextReset(&Socket->AsyncContext);
+
+ //
+ // Bind the socket.
+ //
+
+ Status = Socket->WskListenDispatch->WskBind(Socket->WskSocket, // Socket
+ LocalAddress, // LocalAddress
+ 0, // Flags (reserved)
+ Socket->AsyncContext.Irp // Irp
+ );
+
+ KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+KsAccept(_In_ PKSOCKET Socket, _Out_ PKSOCKET *NewSocket,
+ _Out_opt_ PSOCKADDR LocalAddress, _Out_opt_ PSOCKADDR RemoteAddress) {
+ NTSTATUS Status;
+
+ //
+ // Reset the async context.
+ //
+
+ KspAsyncContextReset(&Socket->AsyncContext);
+
+ //
+ // Accept the connection.
+ //
+
+ Status =
+ Socket->WskListenDispatch->WskAccept(Socket->WskSocket, // ListenSocket
+ 0, // Flags
+ NULL, // AcceptSocketContext
+ NULL, // AcceptSocketDispatch
+ LocalAddress, // LocalAddress
+ RemoteAddress, // RemoteAddress
+ Socket->AsyncContext.Irp // Irp
+ );
+
+ KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status);
+
+ //
+ // Save the socket instance and the socket dispatch table.
+ //
+
+ if (NT_SUCCESS(Status)) {
+ PKSOCKET KNewSocket =
+ ExAllocatePoolWithTag(PagedPool, sizeof(KSOCKET), MEMORY_TAG);
+
+ if (!KNewSocket) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ KNewSocket->WskSocket =
+ (PWSK_SOCKET)Socket->AsyncContext.Irp->IoStatus.Information;
+ KNewSocket->WskDispatch = (PVOID)KNewSocket->WskSocket->Dispatch;
+ KspAsyncContextAllocate(&KNewSocket->AsyncContext);
+
+ *NewSocket = KNewSocket;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+KsConnect(_In_ PKSOCKET Socket, _In_ PSOCKADDR RemoteAddress) {
+ NTSTATUS Status;
+
+ //
+ // Reset the async context.
+ //
+
+ KspAsyncContextReset(&Socket->AsyncContext);
+
+ //
+ // Bind the socket to the local address.
+ //
+
+ SOCKADDR_IN LocalAddress;
+ LocalAddress.sin_family = AF_INET;
+ LocalAddress.sin_addr.s_addr = INADDR_ANY;
+ LocalAddress.sin_port = 0;
+
+ Status = Socket->WskConnectionDispatch->WskBind(
+ Socket->WskSocket, // Socket
+ (PSOCKADDR)&LocalAddress, // LocalAddress
+ 0, // Flags (reserved)
+ Socket->AsyncContext.Irp // Irp
+ );
+
+ KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status);
+
+ if (!NT_SUCCESS(Status)) {
+ return Status;
+ }
+
+ //
+ // Reset the async context (again).
+ //
+
+ KspAsyncContextReset(&Socket->AsyncContext);
+
+ //
+ // Connect to the remote host.
+ //
+ // N.B.: Instead of calling WskSocket(), WskBind() and WskConnect(),
+ // it is possible to just call WskSocketConnect().
+ //
+
+ Status =
+ Socket->WskConnectionDispatch->WskConnect(Socket->WskSocket, // Socket
+ RemoteAddress, // RemoteAddress
+ 0, // Flags (reserved)
+ Socket->AsyncContext.Irp // Irp
+ );
+
+ KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+KsSendRecv(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags, _In_ BOOLEAN Send) {
+ NTSTATUS Status;
+
+ //
+ // Wrap the buffer into the "WSK buffer".
+ //
+
+ WSK_BUF WskBuffer;
+ WskBuffer.Offset = 0;
+ WskBuffer.Length = *Length;
+ WskBuffer.Mdl =
+ IoAllocateMdl(Buffer, (ULONG)WskBuffer.Length, FALSE, FALSE, NULL);
+
+ //__try
+ { MmProbeAndLockPages(WskBuffer.Mdl, KernelMode, IoWriteAccess); }
+#if 0
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = STATUS_ACCESS_VIOLATION;
+ goto Error;
+ }
+#endif
+
+ //
+ // Reset the async context.
+ //
+
+ KspAsyncContextReset(&Socket->AsyncContext);
+
+ //
+ // Send / receive the data.
+ //
+
+ if (Send) {
+ Status =
+ Socket->WskConnectionDispatch->WskSend(Socket->WskSocket, // Socket
+ &WskBuffer, // Buffer
+ Flags, // Flags
+ Socket->AsyncContext.Irp // Irp
+ );
+ } else {
+ Status = Socket->WskConnectionDispatch->WskReceive(
+ Socket->WskSocket, // Socket
+ &WskBuffer, // Buffer
+ Flags, // Flags
+ Socket->AsyncContext.Irp // Irp
+ );
+ }
+
+ KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status);
+
+ //
+ // Set the number of bytes sent / received.
+ //
+
+ if (NT_SUCCESS(Status)) {
+ *Length = (ULONG)Socket->AsyncContext.Irp->IoStatus.Information;
+ }
+
+ //
+ // Free the MDL.
+ //
+
+ MmUnlockPages(WskBuffer.Mdl);
+
+ // Error:
+ IoFreeMdl(WskBuffer.Mdl);
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+KsSendRecvUdp(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags, _In_ PSOCKADDR RemoteAddress,
+ _In_ BOOLEAN Send) {
+ NTSTATUS Status;
+
+ //
+ // Wrap the buffer into the "WSK buffer".
+ //
+
+ WSK_BUF WskBuffer;
+ WskBuffer.Offset = 0;
+ WskBuffer.Length = *Length;
+ WskBuffer.Mdl =
+ IoAllocateMdl(Buffer, (ULONG)WskBuffer.Length, FALSE, FALSE, NULL);
+
+ //__try
+ { MmProbeAndLockPages(WskBuffer.Mdl, KernelMode, IoWriteAccess); }
+#if 0
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = STATUS_ACCESS_VIOLATION;
+ goto Error;
+ }
+#endif
+
+ //
+ // Reset the async context.
+ //
+
+ KspAsyncContextReset(&Socket->AsyncContext);
+
+ //
+ // Send / receive the data.
+ //
+
+ if (Send) {
+ Status =
+ Socket->WskDatagramDispatch->WskSendTo(Socket->WskSocket, // Socket
+ &WskBuffer, // Buffer
+ Flags, // Flags (reserved)
+ RemoteAddress, // RemoteAddress
+ 0, // ControlInfoLength
+ NULL, // ControlInfo
+ Socket->AsyncContext.Irp // Irp
+ );
+ } else {
+ Status = Socket->WskDatagramDispatch->WskReceiveFrom(
+ Socket->WskSocket, // Socket
+ &WskBuffer, // Buffer
+ Flags, // Flags (reserved)
+ RemoteAddress, // RemoteAddress
+ NULL, // ControlInfoLength
+ NULL, // ControlInfo
+ NULL, // ControlFlags
+ Socket->AsyncContext.Irp // Irp
+ );
+ }
+
+ KspAsyncContextWaitForCompletion(&Socket->AsyncContext, &Status);
+
+ //
+ // Set the number of bytes sent / received.
+ //
+
+ if (NT_SUCCESS(Status)) {
+ *Length = (ULONG)Socket->AsyncContext.Irp->IoStatus.Information;
+ }
+
+ //
+ // Free the MDL.
+ //
+
+ MmUnlockPages(WskBuffer.Mdl);
+
+ // Error:
+ IoFreeMdl(WskBuffer.Mdl);
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+KsSend(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags) {
+ return KsSendRecv(Socket, Buffer, Length, Flags, TRUE);
+}
+
+NTSTATUS
+NTAPI
+KsRecv(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags) {
+ return KsSendRecv(Socket, Buffer, Length, Flags, FALSE);
+}
+
+NTSTATUS
+NTAPI
+KsSendTo(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags, _In_ PSOCKADDR RemoteAddress) {
+ return KsSendRecvUdp(Socket, Buffer, Length, Flags, RemoteAddress, TRUE);
+}
+
+NTSTATUS
+NTAPI
+KsRecvFrom(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags, _In_ PSOCKADDR RemoteAddress) {
+ return KsSendRecvUdp(Socket, Buffer, Length, Flags, RemoteAddress, FALSE);
+}
diff --git a/ksocket/ksocket.h b/ksocket/ksocket.h
new file mode 100644
index 0000000..0a6717e
--- /dev/null
+++ b/ksocket/ksocket.h
@@ -0,0 +1,99 @@
+#pragma once
+#include "wsk.h"
+#include <ntddk.h>
+
+#define STATUS_UNSUPPORTED_WINDOWS_VERSION \
+ (STATUS_SEVERITY_ERROR | (1 << 29) | (1 << 16) | 1)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _KSOCKET KSOCKET, *PKSOCKET;
+
+NTSTATUS
+NTAPI
+KsInitialize(VOID);
+
+VOID NTAPI KsDestroy(VOID);
+
+NTSTATUS
+NTAPI
+KsGetAddrInfo(_In_ PUNICODE_STRING NodeName, _In_ PUNICODE_STRING ServiceName,
+ _In_ PADDRINFOEXW Hints, _Out_ PADDRINFOEXW *Result);
+
+VOID NTAPI KsFreeAddrInfo(_In_ PADDRINFOEXW AddrInfo);
+
+NTSTATUS
+NTAPI
+KsCreateSocket(_Out_ PKSOCKET *Socket, _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType, _In_ ULONG Protocol, _In_ ULONG Flags);
+
+NTSTATUS
+NTAPI
+KsCreateConnectionSocket(_Out_ PKSOCKET *Socket,
+ _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType, _In_ ULONG Protocol);
+
+NTSTATUS
+NTAPI
+KsCreateListenSocket(_Out_ PKSOCKET *Socket, _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType, _In_ ULONG Protocol);
+
+NTSTATUS
+NTAPI
+KsCreateDatagramSocket(_Out_ PKSOCKET *Socket,
+ _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType, _In_ ULONG Protocol);
+
+NTSTATUS
+NTAPI
+KsCloseSocket(_In_ PKSOCKET Socket);
+
+NTSTATUS
+NTAPI
+KsBind(_In_ PKSOCKET Socket, _In_ PSOCKADDR LocalAddress);
+
+NTSTATUS
+NTAPI
+KsAccept(_In_ PKSOCKET Socket, _Out_ PKSOCKET *NewSocket,
+ _Out_opt_ PSOCKADDR LocalAddress, _Out_opt_ PSOCKADDR RemoteAddress);
+
+NTSTATUS
+NTAPI
+KsConnect(_In_ PKSOCKET Socket, _In_ PSOCKADDR RemoteAddress);
+
+NTSTATUS
+NTAPI
+KsSendRecv(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags, _In_ BOOLEAN Send);
+
+NTSTATUS
+NTAPI
+KsSendRecvUdp(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags, _In_ PSOCKADDR RemoteAddress,
+ _In_ BOOLEAN Send);
+
+NTSTATUS
+NTAPI
+KsSend(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags);
+
+NTSTATUS
+NTAPI
+KsRecv(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags);
+
+NTSTATUS
+NTAPI
+KsSendTo(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags, _In_ PSOCKADDR RemoteAddress);
+
+NTSTATUS
+NTAPI
+KsRecvFrom(_In_ PKSOCKET Socket, _In_ PVOID Buffer, _Inout_ PULONG Length,
+ _In_ ULONG Flags, _In_ PSOCKADDR RemoteAddress);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/ksocket/wsk.h b/ksocket/wsk.h
new file mode 100644
index 0000000..ccea103
--- /dev/null
+++ b/ksocket/wsk.h
@@ -0,0 +1,460 @@
+#ifndef WSK_H
+#define WSK_H 1
+
+#include <ntddk.h>
+
+#if !defined(__MINGW64__)
+#error \
+ "This was designed to work **only** with Mingw-w64! For MSVC, please check https://github.com/wbenny/KSOCKET out"
+#endif
+
+#if (NTDDI_VERSION < NTDDI_WIN10)
+#error \
+ "Your mingw-w64 toolchain is too old. Please use the one provided by https://github.com/utoni/mingw-w64-ddk-template"
+#endif
+
+#if !defined(__BYTE_ORDER__) || __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
+#error \
+ "This project requires a little endian system. Does Windows support any other?"
+#endif
+
+// ---------------------------------------------------------------
+// defines
+// ---------------------------------------------------------------
+
+#define WSKAPI NTAPI
+#define MAKE_WSK_VERSION(Mj, Mn) ((USHORT)((Mj) << 8) | (USHORT)((Mn)&0xff))
+#define WSK_NO_WAIT 0
+#define WSK_INFINITE_WAIT 0xffffffff
+
+#define WSK_FLAG_BASIC_SOCKET 0x00000000
+#define WSK_FLAG_LISTEN_SOCKET 0x00000001
+#define WSK_FLAG_CONNECTION_SOCKET 0x00000002
+#define WSK_FLAG_DATAGRAM_SOCKET 0x00000004
+#define WSK_FLAG_STREAM_SOCKET 0x00000008
+
+#define INADDR_ANY ((ULONG)0x00000000)
+
+// ---------------------------------------------------------------
+// forward decls / opaque structs
+// ---------------------------------------------------------------
+
+struct _WSK_CLIENT_CONNECTION_DISPATCH;
+typedef struct _WSK_CLIENT_CONNECTION_DISPATCH WSK_CLIENT_CONNECTION_DISPATCH;
+typedef WSK_CLIENT_CONNECTION_DISPATCH *PWSK_CLIENT_CONNECTION_DISPATCH;
+struct _WSK_CLIENT_NPI;
+typedef struct _WSK_CLIENT_NPI WSK_CLIENT_NPI;
+typedef struct _WSK_CLIENT_NPI *PWSK_CLIENT_NPI;
+struct _WSK_PROVIDER_NPI;
+typedef struct _WSK_PROVIDER_NPI WSK_PROVIDER_NPI;
+typedef struct _WSK_PROVIDER_NPI *PWSK_PROVIDER_NPI;
+
+typedef PVOID PWSK_CLIENT;
+
+// ---------------------------------------------------------------
+// enums
+// ---------------------------------------------------------------
+
+typedef enum {
+ WskSetOption, // set socket option
+ WskGetOption, // get socket option
+ WskIoctl, // socket IOCTL
+ WskControlMax
+} WSK_CONTROL_SOCKET_TYPE,
+ *PWSK_CONTROL_SOCKET_TYPE;
+
+enum {
+ AI_PASSIVE = 0x01,
+ AI_CANONNAME = 0x02,
+ AI_NUMERICHOST = 0x04,
+ AI_ALL = 0x0100,
+ AI_ADDRCONFIG = 0x0400,
+ AI_V4MAPPED = 0x0800,
+ AI_NON_AUTHORITATIVE = 0x4000,
+ AI_SECURE = 0x08000,
+ AI_RETURN_PREFERRED_NAMES = 0x10000,
+ AI_FQDN = 0x00020000,
+ AI_FILESERVER = 0x00040000
+};
+
+typedef enum ADDRESS_FAMILY {
+ AF_UNSPEC = 0,
+ AF_INET = 2,
+ AF_INET6 = 23
+} ADDRESS_FAMILY;
+
+enum {
+ IPPROTO_ICMP = 1,
+ IPPROTO_IGMP = 2,
+ BTHPROTO_RFCOMM = 3,
+ IPPROTO_TCP = 6,
+ IPPROTO_UDP = 17,
+ IPPROTO_ICMPV6 = 58,
+ IPPROTO_RM = 113
+};
+
+enum {
+ SOCK_STREAM = 1,
+ SOCK_DGRAM = 2,
+ SOCK_RAW = 3,
+ SOCK_RDM = 4,
+ SOCK_SEQPACKET = 5,
+};
+
+typedef enum {
+ WskInspectReject, // reject the connection request
+ WskInspectAccept, // proceed with accept
+ WskInspectPend, // delay the decision (use WskInspectComplete later)
+ WskInspectMax
+} WSK_INSPECT_ACTION,
+ *PWSK_INSPECT_ACTION;
+
+// ---------------------------------------------------------------
+// general structs
+// ---------------------------------------------------------------
+
+typedef struct addrinfo {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ char *ai_canonname;
+ struct sockaddr *ai_addr;
+ struct addrinfo *ai_next;
+} ADDRINFOA, *PADDRINFOA;
+
+typedef struct addrinfoexA {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ char *ai_canonname;
+ struct sockaddr *ai_addr;
+ void *ai_blob;
+ size_t ai_bloblen;
+ LPGUID ai_provider;
+ struct addrinfoexA *ai_next;
+} ADDRINFOEXA, *PADDRINFOEXA, *LPADDRINFOEXA;
+
+typedef struct addrinfoW {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ PWSTR ai_canonname;
+ struct sockaddr *ai_addr;
+ struct addrinfoW *ai_next;
+} ADDRINFOW, *PADDRINFOW;
+
+typedef struct addrinfoexW {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ PWSTR ai_canonname;
+ struct sockaddr *ai_addr;
+ void *ai_blob;
+ size_t ai_bloblen;
+ LPGUID ai_provider;
+ struct addrinfoexW *ai_next;
+} ADDRINFOEXW, *PADDRINFOEXW, *LPADDRINFOEXW;
+
+typedef struct sockaddr {
+ ADDRESS_FAMILY sa_family;
+ CHAR sa_data[14];
+} SOCKADDR, *PSOCKADDR, *LPSOCKADDR;
+
+struct in_addr {
+ union {
+ struct {
+ UCHAR s_b1;
+ UCHAR s_b2;
+ UCHAR s_b3;
+ UCHAR s_b4;
+ } s_un_b;
+ struct {
+ USHORT s_w1;
+ USHORT s_w2;
+ } s_un_w;
+ ULONG s_addr;
+ };
+};
+
+typedef struct sockaddr_in {
+ short sin_family;
+ USHORT sin_port;
+ struct in_addr sin_addr;
+ char sin_zero[8];
+} SOCKADDR_IN, *PSOCKADDR_IN, *LPSOCKADDR_IN;
+
+typedef struct _WSK_SOCKET {
+ const VOID *Dispatch;
+} WSK_SOCKET, *PWSK_SOCKET;
+
+typedef struct _WSK_BUF {
+ PMDL Mdl; // Locked MDL chain
+ ULONG Offset; // Offset into the "first" Mdl in the chain
+ SIZE_T Length; // Length of data starting from Offset
+} WSK_BUF, *PWSK_BUF;
+
+typedef struct _WSK_BUF_LIST {
+ struct _WSK_BUF_LIST *Next;
+ WSK_BUF Buffer;
+} WSK_BUF_LIST, *PWSK_BUF_LIST;
+
+typedef struct _WSK_DATA_INDICATION {
+ struct _WSK_DATA_INDICATION *Next;
+ WSK_BUF Buffer;
+} WSK_DATA_INDICATION, *PWSK_DATA_INDICATION;
+
+typedef struct _WSK_INSPECT_ID {
+ ULONG_PTR Key;
+ ULONG SerialNumber;
+} WSK_INSPECT_ID, *PWSK_INSPECT_ID;
+
+typedef struct _WSACMSGHDR {
+ SIZE_T cmsg_len;
+ INT cmsg_level;
+ INT cmsg_type;
+} WSACMSGHDR, *PWSACMSGHDR, *LPWSACMSGHDR, CMSGHDR, *PCMSGHDR;
+
+typedef struct _WSK_DATAGRAM_INDICATION {
+ struct _WSK_DATAGRAM_INDICATION *Next;
+ WSK_BUF Buffer;
+ _Field_size_bytes_(ControlInfoLength) PCMSGHDR ControlInfo;
+ ULONG ControlInfoLength;
+ PSOCKADDR RemoteAddress;
+} WSK_DATAGRAM_INDICATION, *PWSK_DATAGRAM_INDICATION;
+
+typedef struct _WSK_REGISTRATION {
+ ULONGLONG ReservedRegistrationState;
+ PVOID ReservedRegistrationContext;
+ KSPIN_LOCK ReservedRegistrationLock;
+} WSK_REGISTRATION, *PWSK_REGISTRATION;
+
+// ---------------------------------------------------------------
+// callback functions
+// ---------------------------------------------------------------
+
+typedef NTSTATUS(WSKAPI *PFN_WSK_CONTROL_SOCKET)(
+ _In_ PWSK_SOCKET Socket, _In_ WSK_CONTROL_SOCKET_TYPE RequestType,
+ _In_ ULONG ControlCode, _In_ ULONG Level, _In_ SIZE_T InputSize,
+ _In_opt_ PVOID InputBuffer, _In_ SIZE_T OutputSize,
+ _Out_opt_ PVOID OutputBuffer, _Out_opt_ SIZE_T *OutputSizeReturned,
+ _In_ _Out_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_CLOSE_SOCKET)(_In_ PWSK_SOCKET Socket,
+ _Inout_ PIRP Irp);
+
+typedef NTSTATUS(WSKAPI *PFN_WSK_CONNECT)(_In_ PWSK_SOCKET Socket,
+ _In_ PSOCKADDR RemoteAddress,
+ ULONG Flags, _In_ _Out_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_BIND)(_In_ PWSK_SOCKET Socket,
+ _In_ PSOCKADDR LocalAddress,
+ _Reserved_ ULONG Flags,
+ _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_GET_LOCAL_ADDRESS)(
+ _In_ PWSK_SOCKET Socket, _Out_ PSOCKADDR LocalAddress, _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_GET_REMOTE_ADDRESS)(
+ _In_ PWSK_SOCKET Socket, _Out_ PSOCKADDR RemoteAddress, _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_SEND)(_In_ PWSK_SOCKET Socket,
+ _In_ PWSK_BUF Buffer, _In_ ULONG Flags,
+ _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_RECEIVE)(_In_ PWSK_SOCKET Socket,
+ _In_ PWSK_BUF Buffer,
+ _In_ ULONG Flags, _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_DISCONNECT)(_In_ PWSK_SOCKET Socket,
+ _In_opt_ PWSK_BUF Buffer,
+ _In_ ULONG Flags,
+ _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_RELEASE_DATA_INDICATION_LIST)(
+ _In_ PWSK_SOCKET Socket, _In_ PWSK_DATA_INDICATION DataIndication);
+typedef NTSTATUS(WSKAPI *PFN_WSK_CONNECT_EX)(_In_ PWSK_SOCKET Socket,
+ _In_ PSOCKADDR RemoteAddress,
+ _In_opt_ PWSK_BUF Buffer,
+ _Reserved_ ULONG Flags,
+ _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_CONNECT_EX)(_In_ PWSK_SOCKET Socket,
+ _In_ PSOCKADDR RemoteAddress,
+ _In_opt_ PWSK_BUF Buffer,
+ _Reserved_ ULONG Flags,
+ _Inout_ PIRP Irp);
+typedef void *PFN_WSK_SEND_EX; // reserved for system use
+typedef void *PFN_WSK_RECEIVE_EX; // reserved for system use
+typedef _At_(Irp->IoStatus.Information, __drv_allocatesMem(Mem))
+ NTSTATUS(WSKAPI *PFN_WSK_ACCEPT)(
+ _In_ PWSK_SOCKET ListenSocket, _Reserved_ ULONG Flags,
+ _In_opt_ PVOID AcceptSocketContext,
+ _In_opt_ CONST WSK_CLIENT_CONNECTION_DISPATCH *AcceptSocketDispatch,
+ _Out_opt_ PSOCKADDR LocalAddress, _Out_opt_ PSOCKADDR RemoteAddress,
+ _Inout_ PIRP Irp);
+typedef _Must_inspect_result_ NTSTATUS(WSKAPI *PFN_WSK_RECEIVE_EVENT)(
+ _In_opt_ PVOID SocketContext, _In_ ULONG Flags,
+ _In_opt_ PWSK_DATA_INDICATION DataIndication, _In_ SIZE_T BytesIndicated,
+ _Inout_ SIZE_T *BytesAccepted);
+typedef NTSTATUS(WSKAPI *PFN_WSK_DISCONNECT_EVENT)(_In_opt_ PVOID SocketContext,
+ _In_ ULONG Flags);
+typedef NTSTATUS(WSKAPI *PFN_WSK_SEND_BACKLOG_EVENT)(
+ _In_opt_ PVOID SocketContext, _In_ SIZE_T IdealBacklogSize);
+typedef NTSTATUS(WSKAPI *PFN_WSK_INSPECT_COMPLETE)(
+ _In_ PWSK_SOCKET ListenSocket, _In_ PWSK_INSPECT_ID InspectID,
+ _In_ WSK_INSPECT_ACTION Action, _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_SEND_TO)(
+ _In_ PWSK_SOCKET Socket, _In_ PWSK_BUF Buffer, _Reserved_ ULONG Flags,
+ _In_opt_ PSOCKADDR RemoteAddress, _In_ ULONG ControlInfoLength,
+ _In_reads_bytes_opt_(ControlInfoLength) PCMSGHDR ControlInfo,
+ _Inout_ PIRP Irp);
+typedef _Must_inspect_result_ NTSTATUS(WSKAPI *PFN_WSK_RECEIVE_FROM_EVENT)(
+ _In_opt_ PVOID SocketContext, _In_ ULONG Flags,
+ _In_opt_ PWSK_DATAGRAM_INDICATION DataIndication);
+typedef NTSTATUS(WSKAPI *PFN_WSK_RECEIVE_FROM)(
+ _In_ PWSK_SOCKET Socket, _In_ PWSK_BUF Buffer, _Reserved_ ULONG Flags,
+ _Out_opt_ PSOCKADDR RemoteAddress, _Inout_ PULONG ControlLength,
+ _Out_writes_bytes_opt_(*ControlLength) PCMSGHDR ControlInfo,
+ _Out_opt_ PULONG ControlFlags, _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_RELEASE_DATAGRAM_INDICATION_LIST)(
+ _In_ PWSK_SOCKET Socket, _In_ PWSK_DATAGRAM_INDICATION DatagramIndication);
+typedef NTSTATUS(WSKAPI *PFN_WSK_SEND_MESSAGES)(
+ _In_ PWSK_SOCKET Socket, _In_ PWSK_BUF_LIST BufferList,
+ _Reserved_ ULONG Flags, _In_opt_ PSOCKADDR RemoteAddress,
+ _In_ ULONG ControlInfoLength,
+ _In_reads_bytes_opt_(ControlInfoLength) PCMSGHDR ControlInfo,
+ _Inout_ PIRP Irp);
+typedef _At_((void *)Irp->IoStatus.Information, __drv_allocatesMem(Mem))
+ NTSTATUS(WSKAPI *PFN_WSK_SOCKET)(
+ _In_ PWSK_CLIENT Client, _In_ ADDRESS_FAMILY AddressFamily,
+ _In_ USHORT SocketType, _In_ ULONG Protocol, _In_ ULONG Flags,
+ _In_opt_ PVOID SocketContext, _In_opt_ CONST VOID *Dispatch,
+ _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread,
+ _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor, _Inout_ PIRP Irp);
+typedef _At_(Irp->IoStatus.Information, __drv_allocatesMem(Mem))
+ NTSTATUS(WSKAPI *PFN_WSK_SOCKET_CONNECT)(
+ _In_ PWSK_CLIENT Client, _In_ USHORT SocketType, _In_ ULONG Protocol,
+ _In_ PSOCKADDR LocalAddress, _In_ PSOCKADDR RemoteAddress,
+ _Reserved_ ULONG Flags, _In_opt_ PVOID SocketContext,
+ _In_opt_ CONST WSK_CLIENT_CONNECTION_DISPATCH *Dispatch,
+ _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread,
+ _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor, _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_CONTROL_CLIENT)(
+ _In_ PWSK_CLIENT Client, _In_ ULONG ControlCode, _In_ SIZE_T InputSize,
+ _In_reads_bytes_opt_(InputSize) PVOID InputBuffer, _In_ SIZE_T OutputSize,
+ _Out_writes_bytes_opt_(OutputSize) PVOID OutputBuffer,
+ _Out_opt_ SIZE_T *OutputSizeReturned, _Inout_opt_ PIRP Irp);
+typedef _At_(*Result, __drv_allocatesMem(Mem))
+ NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO)(
+ _In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName,
+ _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace,
+ _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints,
+ _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess,
+ _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp);
+typedef _At_(AddrInfo, __drv_freesMem(Mem))
+ VOID(WSKAPI *PFN_WSK_FREE_ADDRESS_INFO)(_In_ PWSK_CLIENT Client,
+ _In_ PADDRINFOEXW AddrInfo);
+typedef NTSTATUS(WSKAPI *PFN_WSK_GET_NAME_INFO)(
+ _In_ PWSK_CLIENT Client, _In_ PSOCKADDR SockAddr, _In_ ULONG SockAddrLength,
+ _Out_opt_ PUNICODE_STRING NodeName, _Out_opt_ PUNICODE_STRING ServiceName,
+ _In_ ULONG Flags, _In_opt_ PEPROCESS OwningProcess,
+ _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp);
+typedef NTSTATUS(WSKAPI *PFN_WSK_CLIENT_EVENT)(
+ _In_opt_ PVOID ClientContext, _In_ ULONG EventType,
+ _In_reads_bytes_opt_(InformationLength) PVOID Information,
+ _In_ SIZE_T InformationLength);
+_Must_inspect_result_ NTSTATUS WskRegister(
+ _In_ PWSK_CLIENT_NPI WskClientNpi, _Out_ PWSK_REGISTRATION WskRegistration);
+_Must_inspect_result_ NTSTATUS WskCaptureProviderNPI(
+ _In_ PWSK_REGISTRATION WskRegistration, _In_ ULONG WaitTimeout,
+ _Out_ PWSK_PROVIDER_NPI WskProviderNpi);
+VOID WskReleaseProviderNPI(_In_ PWSK_REGISTRATION WskRegistration);
+VOID WskDeregister(_In_ PWSK_REGISTRATION WskRegistration);
+
+// ---------------------------------------------------------------
+// function pointer structs
+// ---------------------------------------------------------------
+
+typedef struct _WSK_CLIENT_CONNECTION_DISPATCH {
+ PFN_WSK_RECEIVE_EVENT WskReceiveEvent;
+ PFN_WSK_DISCONNECT_EVENT WskDisconnectEvent;
+ PFN_WSK_SEND_BACKLOG_EVENT WskSendBacklogEvent;
+} WSK_CLIENT_CONNECTION_DISPATCH, *PWSK_CLIENT_CONNECTION_DISPATCH;
+
+typedef struct _WSK_PROVIDER_BASIC_DISPATCH {
+ PFN_WSK_CONTROL_SOCKET WskControlSocket;
+ PFN_WSK_CLOSE_SOCKET WskCloseSocket;
+} WSK_PROVIDER_BASIC_DISPATCH, *PWSK_PROVIDER_BASIC_DISPATCH;
+
+typedef struct _WSK_PROVIDER_CONNECTION_DISPATCH {
+#ifdef __cplusplus
+ WSK_PROVIDER_BASIC_DISPATCH Basic;
+#else
+ WSK_PROVIDER_BASIC_DISPATCH;
+#endif
+ PFN_WSK_BIND WskBind;
+ PFN_WSK_CONNECT WskConnect;
+ PFN_WSK_GET_LOCAL_ADDRESS WskGetLocalAddress;
+ PFN_WSK_GET_REMOTE_ADDRESS WskGetRemoteAddress;
+ PFN_WSK_SEND WskSend;
+ PFN_WSK_RECEIVE WskReceive;
+ PFN_WSK_DISCONNECT WskDisconnect;
+ PFN_WSK_RELEASE_DATA_INDICATION_LIST WskRelease;
+ PFN_WSK_CONNECT_EX WskConnectEx;
+ PFN_WSK_SEND_EX WskSendEx;
+ PFN_WSK_RECEIVE_EX WskReceiveEx;
+} WSK_PROVIDER_CONNECTION_DISPATCH, *PWSK_PROVIDER_CONNECTION_DISPATCH;
+
+typedef struct _WSK_PROVIDER_LISTEN_DISPATCH {
+#ifdef __cplusplus
+ WSK_PROVIDER_BASIC_DISPATCH Basic;
+#else
+ WSK_PROVIDER_BASIC_DISPATCH;
+#endif
+ PFN_WSK_BIND WskBind;
+ PFN_WSK_ACCEPT WskAccept;
+ PFN_WSK_INSPECT_COMPLETE WskInspectComplete;
+ PFN_WSK_GET_LOCAL_ADDRESS WskGetLocalAddress;
+} WSK_PROVIDER_LISTEN_DISPATCH, *PWSK_PROVIDER_LISTEN_DISPATCH;
+
+typedef struct _WSK_PROVIDER_DATAGRAM_DISPATCH {
+#ifdef __cplusplus
+ WSK_PROVIDER_BASIC_DISPATCH Basic;
+#else
+ WSK_PROVIDER_BASIC_DISPATCH;
+#endif
+ PFN_WSK_BIND WskBind;
+ PFN_WSK_SEND_TO WskSendTo;
+ PFN_WSK_RECEIVE_FROM WskReceiveFrom;
+ PFN_WSK_RELEASE_DATAGRAM_INDICATION_LIST WskRelease;
+ PFN_WSK_GET_LOCAL_ADDRESS WskGetLocalAddress;
+ PFN_WSK_SEND_MESSAGES WskSendMessages;
+} WSK_PROVIDER_DATAGRAM_DISPATCH, *PWSK_PROVIDER_DATAGRAM_DISPATCH;
+
+typedef struct _WSK_PROVIDER_DISPATCH {
+ USHORT Version;
+ USHORT Reserved;
+ PFN_WSK_SOCKET WskSocket;
+ PFN_WSK_SOCKET_CONNECT WskSocketConnect;
+ PFN_WSK_CONTROL_CLIENT WskControlClient;
+ PFN_WSK_GET_ADDRESS_INFO WskGetAddressInfo;
+ PFN_WSK_FREE_ADDRESS_INFO WskFreeAddressInfo;
+ PFN_WSK_GET_NAME_INFO WskGetNameInfo;
+} WSK_PROVIDER_DISPATCH, *PWSK_PROVIDER_DISPATCH;
+
+typedef struct _WSK_CLIENT_DISPATCH {
+ USHORT Version;
+ USHORT Reserved;
+ PFN_WSK_CLIENT_EVENT WskClientEvent;
+} WSK_CLIENT_DISPATCH, *PWSK_CLIENT_DISPATCH;
+
+typedef struct _WSK_CLIENT_NPI {
+ PVOID ClientContext;
+ CONST WSK_CLIENT_DISPATCH *Dispatch;
+} WSK_CLIENT_NPI, *PWSK_CLIENT_NPI;
+
+typedef struct _WSK_PROVIDER_NPI {
+ PWSK_CLIENT Client;
+ CONST WSK_PROVIDER_DISPATCH *Dispatch;
+} WSK_PROVIDER_NPI, *PWSK_PROVIDER_NPI;
+
+#endif