implement generic I/O async request object to replace file-specific async requests, refactor lwIP network stack to dispatch requests through IRPs with cancellation support, add cancellation polling to lwIP accept and receive operations using LwipSocketWaitRecvNetbuf and LwipSocketWaitAccept, introduce NetSubmitSocketIrp for routing socket operations via device IRPs, track network IRP statistics with SYS_NET_IRP_STATS, add process module lock spinlock and reference counting for process modules, implement dynamic module loading and unloading via user module handles, add POSIX dynamic loader APIs including dlopen, dlsym, dlerror, and dlclose, introduce PosixStart entry point for posix applications, add new native smoke tests for net IRPs.
This commit is contained in:
1 parent
ed3d065abd
commit
1f5477cf66
32 files changed
+3713
-551
No files matched your search
+761
-36
@@ -2,25 +2,591 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <kernel/net_socket.h>
|
||||
#include <ntlite/ddi/net_stack.h>
|
||||
#include <kernel/ke_event.h>
|
||||
#include <kernel/ke_irp.h>
|
||||
#include <kernel/ke_process.h>
|
||||
#include <kernel/ke_sched.h>
|
||||
#include <kernel/ke_semaphore.h>
|
||||
#include <kernel/ke_spinlock.h>
|
||||
#include <kernel/ke_thread.h>
|
||||
#include <kernel/mm_virt.h>
|
||||
#include <kernel/ob_object.h>
|
||||
#include <ntlite/ddi/io_driver.h>
|
||||
#include <ntlite/ddi/net_stack.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
#define NET_SOCKET_IO_MAX_BYTES (1024u * 1024u)
|
||||
#define NET_SOCKET_UDP_MAX_BYTES 65507u
|
||||
#define NET_SOCKET_RAW_MAX_BYTES 65535u
|
||||
|
||||
// Implements the net Socket Destroy operation.
|
||||
static SPINLOCK gNetIrpStatsLock = SPINLOCK_INIT;
|
||||
static NET_IRP_STATS gNetIrpStats;
|
||||
|
||||
// Records that a socket operation entered the IRP boundary.
|
||||
static void NetIrpStatsSubmit(uint32_t operation) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNetIrpStatsLock);
|
||||
gNetIrpStats.Submitted++;
|
||||
if (operation < NetSocketIrpOperationCount)
|
||||
gNetIrpStats.ByOperation[operation]++;
|
||||
KeReleaseSpinlock(&gNetIrpStatsLock, flags);
|
||||
}
|
||||
|
||||
// Records that a submitted socket IRP returned pending to the socket facade.
|
||||
static void NetIrpStatsPending(void) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNetIrpStatsLock);
|
||||
gNetIrpStats.Pending++;
|
||||
KeReleaseSpinlock(&gNetIrpStatsLock, flags);
|
||||
}
|
||||
|
||||
// Records the final status of a socket IRP after synchronous wait completion.
|
||||
static void NetIrpStatsComplete(KSTATUS status, bool asynchronous) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNetIrpStatsLock);
|
||||
gNetIrpStats.Completed++;
|
||||
if (asynchronous)
|
||||
gNetIrpStats.CompletedAsynchronously++;
|
||||
else
|
||||
gNetIrpStats.CompletedSynchronously++;
|
||||
|
||||
if (status == STATUS_CANCELLED)
|
||||
gNetIrpStats.Cancelled++;
|
||||
else if (status == STATUS_WOULD_BLOCK)
|
||||
gNetIrpStats.WouldBlock++;
|
||||
else if (status == STATUS_TIMEOUT)
|
||||
gNetIrpStats.Timeout++;
|
||||
else if (KFAILED(status))
|
||||
gNetIrpStats.Failed++;
|
||||
|
||||
KeReleaseSpinlock(&gNetIrpStatsLock, flags);
|
||||
}
|
||||
|
||||
// Returns a stable snapshot of socket IRP diagnostics.
|
||||
__declspec(dllexport) void NetQueryIrpStats(NET_IRP_STATS* out) {
|
||||
if (!out)
|
||||
return;
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNetIrpStatsLock);
|
||||
*out = gNetIrpStats;
|
||||
KeReleaseSpinlock(&gNetIrpStatsLock, flags);
|
||||
}
|
||||
|
||||
// Records that a public async socket request requested cancellation.
|
||||
static void NetIrpStatsCancelRequested(void) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&gNetIrpStatsLock);
|
||||
gNetIrpStats.CancelRequested++;
|
||||
KeReleaseSpinlock(&gNetIrpStatsLock, flags);
|
||||
}
|
||||
|
||||
struct NET_ASYNC_SOCKET_REQUEST_OBJECT {
|
||||
IO_ASYNC_REQUEST_OBJECT Async;
|
||||
|
||||
PROCESS* OwnerProcess;
|
||||
SOCKET_OBJECT* Socket;
|
||||
uint32_t Operation;
|
||||
uint32_t SocketFlags;
|
||||
uint32_t Backlog;
|
||||
uint32_t ShutdownHow;
|
||||
uint32_t Option;
|
||||
uint32_t PollEvents;
|
||||
|
||||
void* KernelBuffer;
|
||||
void* UserBuffer;
|
||||
size_t Length;
|
||||
|
||||
SYS_SOCKET_ADDRESS_K Address;
|
||||
size_t AddressSize;
|
||||
SYS_SOCKET_ADDRESS_K* AddressOut;
|
||||
size_t* AddressSizeInOut;
|
||||
|
||||
void* OptionValue;
|
||||
void* UserOptionValue;
|
||||
size_t OptionValueSize;
|
||||
size_t* OptionActualSizeOut;
|
||||
|
||||
uint32_t* HandleOut;
|
||||
uint32_t* PollReturnedEventsOut;
|
||||
|
||||
MM_LOCKED_USER_BUFFER* LockedAddressOut;
|
||||
MM_LOCKED_USER_BUFFER* LockedAddressSize;
|
||||
MM_LOCKED_USER_BUFFER* LockedOptionValue;
|
||||
MM_LOCKED_USER_BUFFER* LockedOptionActualSize;
|
||||
MM_LOCKED_USER_BUFFER* LockedHandleOut;
|
||||
MM_LOCKED_USER_BUFFER* LockedPollReturnedEvents;
|
||||
};
|
||||
|
||||
|
||||
static SPINLOCK gAsyncSocketInitLock = SPINLOCK_INIT;
|
||||
static int gAsyncSocketInitState;
|
||||
static SPINLOCK gAsyncSocketQueueLock = SPINLOCK_INIT;
|
||||
static LIST_ENTRY gAsyncSocketQueue;
|
||||
static SEMAPHORE* gAsyncSocketSemaphore;
|
||||
|
||||
// Releases operation-specific user locks that the common async object does not own.
|
||||
static void NetAsyncSocketReleaseExtraLocks(NET_ASYNC_SOCKET_REQUEST_OBJECT* req) {
|
||||
if (!req)
|
||||
return;
|
||||
|
||||
if (req->LockedAddressOut) {
|
||||
MmUnlockUserBuffer(req->LockedAddressOut);
|
||||
req->LockedAddressOut = (MM_LOCKED_USER_BUFFER*)0;
|
||||
}
|
||||
if (req->LockedAddressSize) {
|
||||
MmUnlockUserBuffer(req->LockedAddressSize);
|
||||
req->LockedAddressSize = (MM_LOCKED_USER_BUFFER*)0;
|
||||
}
|
||||
if (req->LockedOptionValue) {
|
||||
MmUnlockUserBuffer(req->LockedOptionValue);
|
||||
req->LockedOptionValue = (MM_LOCKED_USER_BUFFER*)0;
|
||||
}
|
||||
if (req->LockedOptionActualSize) {
|
||||
MmUnlockUserBuffer(req->LockedOptionActualSize);
|
||||
req->LockedOptionActualSize = (MM_LOCKED_USER_BUFFER*)0;
|
||||
}
|
||||
if (req->LockedHandleOut) {
|
||||
MmUnlockUserBuffer(req->LockedHandleOut);
|
||||
req->LockedHandleOut = (MM_LOCKED_USER_BUFFER*)0;
|
||||
}
|
||||
if (req->LockedPollReturnedEvents) {
|
||||
MmUnlockUserBuffer(req->LockedPollReturnedEvents);
|
||||
req->LockedPollReturnedEvents = (MM_LOCKED_USER_BUFFER*)0;
|
||||
}
|
||||
}
|
||||
|
||||
// Releases heap storage no longer needed after a socket operation has finished.
|
||||
static void NetAsyncSocketReleaseKernelStorage(NET_ASYNC_SOCKET_REQUEST_OBJECT* req) {
|
||||
if (!req)
|
||||
return;
|
||||
|
||||
if (req->KernelBuffer) {
|
||||
MmFreePool(req->KernelBuffer);
|
||||
req->KernelBuffer = (void*)0;
|
||||
}
|
||||
if (req->OptionValue) {
|
||||
MmFreePool(req->OptionValue);
|
||||
req->OptionValue = (void*)0;
|
||||
}
|
||||
}
|
||||
|
||||
// Releases socket-specific references owned by an async socket request.
|
||||
static void NetAsyncSocketRequestCleanup(IO_ASYNC_REQUEST_OBJECT* async, void* context) {
|
||||
(void)context;
|
||||
NET_ASYNC_SOCKET_REQUEST_OBJECT* req =
|
||||
(NET_ASYNC_SOCKET_REQUEST_OBJECT*)async;
|
||||
|
||||
NetAsyncSocketReleaseExtraLocks(req);
|
||||
NetAsyncSocketReleaseKernelStorage(req);
|
||||
|
||||
if (req->Socket) {
|
||||
ObDereferenceObject(&req->Socket->Header);
|
||||
req->Socket = (SOCKET_OBJECT*)0;
|
||||
}
|
||||
if (req->OwnerProcess) {
|
||||
ObDereferenceObject(&req->OwnerProcess->Header);
|
||||
req->OwnerProcess = (PROCESS*)0;
|
||||
}
|
||||
}
|
||||
|
||||
// Cancels an async socket request from the shared async I/O handle.
|
||||
static KSTATUS NetCancelAsyncSocketRequest(IO_ASYNC_REQUEST_OBJECT* async, void* context) {
|
||||
(void)context;
|
||||
if (!async)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
NetIrpStatsCancelRequested();
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&gAsyncSocketQueueLock);
|
||||
IO_ASYNC_REQUEST_STATE state = IoAsyncRequestGetState(async);
|
||||
|
||||
if (state == IoAsyncRequestQueued) {
|
||||
ListRemove(&async->Link);
|
||||
IoAsyncRequestRequestCancel(async);
|
||||
IoAsyncRequestSetState(async, IoAsyncRequestCancelled);
|
||||
KeReleaseSpinlock(&gAsyncSocketQueueLock, flags);
|
||||
|
||||
IoCompleteAsyncRequest(async, STATUS_CANCELLED, 0);
|
||||
ObDereferenceObject(&async->Header);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (state == IoAsyncRequestRunning) {
|
||||
IoAsyncRequestRequestCancel(async);
|
||||
KeReleaseSpinlock(&gAsyncSocketQueueLock, flags);
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
KeReleaseSpinlock(&gAsyncSocketQueueLock, flags);
|
||||
return STATUS_OBJECT_DEAD;
|
||||
}
|
||||
|
||||
// Removes one queued async socket request for the worker.
|
||||
static NET_ASYNC_SOCKET_REQUEST_OBJECT* NetAsyncSocketDequeue(void) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&gAsyncSocketQueueLock);
|
||||
LIST_ENTRY* node = ListPopHead(&gAsyncSocketQueue);
|
||||
if (!node) {
|
||||
KeReleaseSpinlock(&gAsyncSocketQueueLock, flags);
|
||||
return (NET_ASYNC_SOCKET_REQUEST_OBJECT*)0;
|
||||
}
|
||||
|
||||
NET_ASYNC_SOCKET_REQUEST_OBJECT* req =
|
||||
(NET_ASYNC_SOCKET_REQUEST_OBJECT*)CONTAINING_RECORD(node, IO_ASYNC_REQUEST_OBJECT, Link);
|
||||
if (IoAsyncRequestIsCancelRequested(&req->Async))
|
||||
IoAsyncRequestSetState(&req->Async, IoAsyncRequestCancelled);
|
||||
else
|
||||
IoAsyncRequestSetState(&req->Async, IoAsyncRequestRunning);
|
||||
KeReleaseSpinlock(&gAsyncSocketQueueLock, flags);
|
||||
return req;
|
||||
}
|
||||
|
||||
// Publishes a remote address output for accept and recvfrom.
|
||||
static size_t NetAsyncSocketPublishAddress(NET_ASYNC_SOCKET_REQUEST_OBJECT* req,
|
||||
const SYS_SOCKET_ADDRESS_K* address) {
|
||||
if (!req || !req->AddressOut || !address)
|
||||
return 0;
|
||||
|
||||
memcpy(req->AddressOut, address, sizeof(*address));
|
||||
if (req->AddressSizeInOut)
|
||||
*req->AddressSizeInOut = sizeof(*address);
|
||||
return sizeof(*address);
|
||||
}
|
||||
|
||||
// Executes one queued async socket operation on the worker thread.
|
||||
static void NetAsyncSocketExecute(NET_ASYNC_SOCKET_REQUEST_OBJECT* req,
|
||||
KSTATUS* statusOut,
|
||||
size_t* informationOut) {
|
||||
KSTATUS status = STATUS_INVALID_PARAMETER;
|
||||
size_t information = 0;
|
||||
|
||||
if (!req || !statusOut || !informationOut)
|
||||
return;
|
||||
|
||||
switch (req->Operation) {
|
||||
case SYS_ASYNC_SOCKET_OP_BIND:
|
||||
status = NetSocketBind(req->Socket, &req->Address, req->AddressSize);
|
||||
break;
|
||||
|
||||
case SYS_ASYNC_SOCKET_OP_LISTEN:
|
||||
status = NetSocketListen(req->Socket, req->Backlog);
|
||||
break;
|
||||
|
||||
case SYS_ASYNC_SOCKET_OP_ACCEPT: {
|
||||
SOCKET_OBJECT* accepted = (SOCKET_OBJECT*)0;
|
||||
SYS_SOCKET_ADDRESS_K remote;
|
||||
memset(&remote, 0, sizeof(remote));
|
||||
status = NetSocketAccept(req->Socket, &accepted, req->AddressOut ? &remote : (SYS_SOCKET_ADDRESS_K*)0, &req->Async);
|
||||
if (KSUCCESS(status)) {
|
||||
uint32_t handle = 0;
|
||||
status = KeAllocateHandleWithRights(req->OwnerProcess,
|
||||
&accepted->Header,
|
||||
HANDLE_RIGHT_READ | HANDLE_RIGHT_WRITE | HANDLE_RIGHT_QUERY,
|
||||
&handle);
|
||||
ObDereferenceObject(&accepted->Header);
|
||||
if (KSUCCESS(status)) {
|
||||
if (req->HandleOut)
|
||||
*req->HandleOut = handle;
|
||||
information = handle;
|
||||
(void)NetAsyncSocketPublishAddress(req, &remote);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SYS_ASYNC_SOCKET_OP_CONNECT:
|
||||
status = NetSocketConnect(req->Socket, &req->Address, req->AddressSize, &req->Async);
|
||||
break;
|
||||
|
||||
case SYS_ASYNC_SOCKET_OP_SEND: {
|
||||
size_t sent = 0;
|
||||
status = NetSocketSend(req->Socket, req->KernelBuffer, req->Length, req->SocketFlags, &sent);
|
||||
information = sent;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYS_ASYNC_SOCKET_OP_RECV: {
|
||||
size_t received = 0;
|
||||
status = NetSocketReceive(req->Socket, req->KernelBuffer, req->Length, req->SocketFlags, &received, &req->Async);
|
||||
if (KSUCCESS(status) && received)
|
||||
memcpy(req->UserBuffer, req->KernelBuffer, received);
|
||||
information = received;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYS_ASYNC_SOCKET_OP_SEND_TO: {
|
||||
size_t sent = 0;
|
||||
status = NetSocketSendTo(req->Socket, req->KernelBuffer, req->Length,
|
||||
req->SocketFlags, &req->Address, req->AddressSize, &sent);
|
||||
information = sent;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYS_ASYNC_SOCKET_OP_RECV_FROM: {
|
||||
size_t received = 0;
|
||||
SYS_SOCKET_ADDRESS_K remote;
|
||||
memset(&remote, 0, sizeof(remote));
|
||||
status = NetSocketReceiveFrom(req->Socket, req->KernelBuffer, req->Length,
|
||||
req->SocketFlags,
|
||||
req->AddressOut ? &remote : (SYS_SOCKET_ADDRESS_K*)0,
|
||||
&received,
|
||||
&req->Async);
|
||||
if (KSUCCESS(status) && received)
|
||||
memcpy(req->UserBuffer, req->KernelBuffer, received);
|
||||
if (KSUCCESS(status))
|
||||
(void)NetAsyncSocketPublishAddress(req, &remote);
|
||||
information = received;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYS_ASYNC_SOCKET_OP_SHUTDOWN:
|
||||
status = NetSocketShutdown(req->Socket, req->ShutdownHow);
|
||||
break;
|
||||
|
||||
case SYS_ASYNC_SOCKET_OP_SET_OPT:
|
||||
status = NetSocketSetOption(req->Socket, req->Option, req->OptionValue, req->OptionValueSize);
|
||||
break;
|
||||
|
||||
case SYS_ASYNC_SOCKET_OP_GET_OPT: {
|
||||
size_t actual = 0;
|
||||
status = NetSocketGetOption(req->Socket, req->Option, req->OptionValue, req->OptionValueSize, &actual);
|
||||
if (KSUCCESS(status) && actual && req->UserOptionValue)
|
||||
memcpy(req->UserOptionValue, req->OptionValue, actual);
|
||||
if ((KSUCCESS(status) || status == STATUS_BUFFER_TOO_SMALL) && req->OptionActualSizeOut)
|
||||
*req->OptionActualSizeOut = actual;
|
||||
information = actual;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYS_ASYNC_SOCKET_OP_POLL: {
|
||||
uint32_t returnedEvents = 0;
|
||||
status = NetSocketPoll(req->Socket, req->PollEvents, &returnedEvents);
|
||||
if (req->PollReturnedEventsOut)
|
||||
*req->PollReturnedEventsOut = returnedEvents;
|
||||
information = returnedEvents;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
|
||||
*statusOut = status;
|
||||
*informationOut = information;
|
||||
}
|
||||
|
||||
// Worker for public async socket requests.
|
||||
static void NetAsyncSocketWorker(void* arg) {
|
||||
(void)arg;
|
||||
|
||||
for (;;) {
|
||||
KSTATUS waitStatus = KeWaitSemaphore(gAsyncSocketSemaphore);
|
||||
if (!KSUCCESS(waitStatus)) {
|
||||
KeYield();
|
||||
continue;
|
||||
}
|
||||
|
||||
NET_ASYNC_SOCKET_REQUEST_OBJECT* req = NetAsyncSocketDequeue();
|
||||
if (!req)
|
||||
continue;
|
||||
|
||||
KSTATUS status = STATUS_CANCELLED;
|
||||
size_t information = 0;
|
||||
if (!IoAsyncRequestIsCancelRequested(&req->Async) &&
|
||||
IoAsyncRequestGetState(&req->Async) != IoAsyncRequestCancelled) {
|
||||
NetAsyncSocketExecute(req, &status, &information);
|
||||
}
|
||||
|
||||
NetAsyncSocketReleaseExtraLocks(req);
|
||||
NetAsyncSocketReleaseKernelStorage(req);
|
||||
IoCompleteAsyncRequest(&req->Async, status, information);
|
||||
ObDereferenceObject(&req->Async.Header);
|
||||
}
|
||||
}
|
||||
|
||||
// Starts the async socket worker on first use.
|
||||
static KSTATUS NetEnsureAsyncSocketWorkerStarted(void) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&gAsyncSocketInitLock);
|
||||
if (gAsyncSocketInitState == 2) {
|
||||
KeReleaseSpinlock(&gAsyncSocketInitLock, flags);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
if (gAsyncSocketInitState == 1) {
|
||||
KeReleaseSpinlock(&gAsyncSocketInitLock, flags);
|
||||
while (gAsyncSocketInitState == 1)
|
||||
KeYield();
|
||||
return (gAsyncSocketInitState == 2) ? STATUS_SUCCESS : STATUS_FAILURE;
|
||||
}
|
||||
|
||||
gAsyncSocketInitState = 1;
|
||||
KeReleaseSpinlock(&gAsyncSocketInitLock, flags);
|
||||
|
||||
LIST_INIT(&gAsyncSocketQueue);
|
||||
|
||||
KSTATUS status = KeSemaphoreCreate(0, 0x7fffffff, &gAsyncSocketSemaphore);
|
||||
if (KSUCCESS(status)) {
|
||||
THREAD* worker = (THREAD*)0;
|
||||
status = KeCreateKernelThread((uintptr_t)NetAsyncSocketWorker,
|
||||
0,
|
||||
PriorityNormal,
|
||||
&worker);
|
||||
(void)worker;
|
||||
}
|
||||
|
||||
flags = KeAcquireSpinlock(&gAsyncSocketInitLock);
|
||||
gAsyncSocketInitState = KSUCCESS(status) ? 2 : 0;
|
||||
KeReleaseSpinlock(&gAsyncSocketInitLock, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
// Submits a public async socket request to the socket worker.
|
||||
KSTATUS NetSocketSubmitAsyncKernel(const NET_ASYNC_SOCKET_SUBMIT* submit,
|
||||
NET_ASYNC_SOCKET_REQUEST_OBJECT** requestOut) {
|
||||
if (requestOut)
|
||||
*requestOut = (NET_ASYNC_SOCKET_REQUEST_OBJECT*)0;
|
||||
if (!submit || !submit->OwnerProcess || !submit->Socket || !submit->Iosb)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
KSTATUS status = NetEnsureAsyncSocketWorkerStarted();
|
||||
if (!KSUCCESS(status))
|
||||
return status;
|
||||
|
||||
IO_ASYNC_REQUEST_OBJECT* async = (IO_ASYNC_REQUEST_OBJECT*)0;
|
||||
status = IoCreateAsyncRequest(sizeof(NET_ASYNC_SOCKET_REQUEST_OBJECT),
|
||||
NetAsyncSocketRequestCleanup,
|
||||
(void*)0,
|
||||
NetCancelAsyncSocketRequest,
|
||||
(void*)0,
|
||||
&async);
|
||||
if (!KSUCCESS(status))
|
||||
return status;
|
||||
|
||||
NET_ASYNC_SOCKET_REQUEST_OBJECT* req = (NET_ASYNC_SOCKET_REQUEST_OBJECT*)async;
|
||||
req->OwnerProcess = submit->OwnerProcess;
|
||||
req->Socket = submit->Socket;
|
||||
req->Operation = submit->Operation;
|
||||
req->SocketFlags = submit->SocketFlags;
|
||||
req->Backlog = submit->Backlog;
|
||||
req->ShutdownHow = submit->ShutdownHow;
|
||||
req->Option = submit->Option;
|
||||
req->PollEvents = submit->PollEvents;
|
||||
req->KernelBuffer = submit->KernelBuffer;
|
||||
req->UserBuffer = submit->UserBuffer;
|
||||
req->Length = submit->Length;
|
||||
req->Address = submit->Address;
|
||||
req->AddressSize = submit->AddressSize;
|
||||
req->AddressOut = submit->AddressOut;
|
||||
req->AddressSizeInOut = submit->AddressSizeInOut;
|
||||
req->OptionValue = submit->OptionValue;
|
||||
req->UserOptionValue = submit->UserOptionValue;
|
||||
req->OptionValueSize = submit->OptionValueSize;
|
||||
req->OptionActualSizeOut = submit->OptionActualSizeOut;
|
||||
req->HandleOut = submit->HandleOut;
|
||||
req->PollReturnedEventsOut = submit->PollReturnedEventsOut;
|
||||
req->LockedAddressOut = submit->LockedAddressOut;
|
||||
req->LockedAddressSize = submit->LockedAddressSize;
|
||||
req->LockedOptionValue = submit->LockedOptionValue;
|
||||
req->LockedOptionActualSize = submit->LockedOptionActualSize;
|
||||
req->LockedHandleOut = submit->LockedHandleOut;
|
||||
req->LockedPollReturnedEvents = submit->LockedPollReturnedEvents;
|
||||
|
||||
ObReferenceObject(&req->OwnerProcess->Header);
|
||||
ObReferenceObject(&req->Socket->Header);
|
||||
IoInitializeAsyncRequestCompletion(&req->Async,
|
||||
submit->Iosb,
|
||||
submit->CompletionEvent,
|
||||
submit->CompletionApc,
|
||||
submit->LockedBuffer,
|
||||
submit->LockedIosb);
|
||||
|
||||
ObReferenceObject(&req->Async.Header);
|
||||
uintptr_t qflags = KeAcquireSpinlock(&gAsyncSocketQueueLock);
|
||||
ListInsertTail(&gAsyncSocketQueue, &req->Async.Link);
|
||||
KeReleaseSpinlock(&gAsyncSocketQueueLock, qflags);
|
||||
KeSignalSemaphore(gAsyncSocketSemaphore);
|
||||
|
||||
if (requestOut)
|
||||
*requestOut = req;
|
||||
else
|
||||
ObDereferenceObject(&req->Async.Header);
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
// Returns the object header embedded in a socket async request.
|
||||
OBJECT* NetAsyncSocketRequestObject(NET_ASYNC_SOCKET_REQUEST_OBJECT* request) {
|
||||
return request ? &request->Async.Header : (OBJECT*)0;
|
||||
}
|
||||
|
||||
// Submits a socket provider request through the active stack DEVICE_OBJECT.
|
||||
static KSTATUS NetSubmitSocketIrp(const NET_STACK_PROVIDER* provider,
|
||||
NET_SOCKET_IRP_REQUEST* request,
|
||||
IO_ASYNC_REQUEST_OBJECT* async) {
|
||||
if (!provider || !provider->StackDevice || !request)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (request->Size != sizeof(*request))
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (request->Operation == NetSocketIrpInvalid ||
|
||||
request->Operation >= NetSocketIrpOperationCount)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
request->CancelRequested = async ? &async->CancelRequested : (volatile uint8_t*)0;
|
||||
|
||||
EVENT* event = NULL;
|
||||
KSTATUS st = KeEventCreate(EventAutoReset, 0, &event);
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
IRP irp;
|
||||
IoInitializeIrp(&irp, 1);
|
||||
IoBuildDeviceIoControlIrp(&irp,
|
||||
IRP_MJ_INTERNAL_DEVICE_CONTROL,
|
||||
NET_IOCTL_SOCKET,
|
||||
request,
|
||||
sizeof(*request),
|
||||
NULL,
|
||||
0);
|
||||
irp.CompletionEvent = event;
|
||||
|
||||
NetIrpStatsSubmit(request->Operation);
|
||||
st = IoSubmitIrp(provider->StackDevice, &irp);
|
||||
|
||||
bool asynchronous = false;
|
||||
if (st == STATUS_PENDING) {
|
||||
asynchronous = true;
|
||||
NetIrpStatsPending();
|
||||
(void)KeWaitForEvent(event, 0);
|
||||
st = irp.Status;
|
||||
}
|
||||
|
||||
NetIrpStatsComplete(st, asynchronous);
|
||||
ObDereferenceObject(&event->Header);
|
||||
return st;
|
||||
}
|
||||
|
||||
|
||||
// Closes a provider socket through the IRP path while object teardown is still safe.
|
||||
static void NetSocketCloseProvider(const NET_STACK_PROVIDER* provider, void* providerSocket) {
|
||||
if (!provider || !providerSocket)
|
||||
return;
|
||||
|
||||
NET_SOCKET_IRP_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Operation = NetSocketIrpClose;
|
||||
request.u.Close.Socket = providerSocket;
|
||||
(void)NetSubmitSocketIrp(provider, &request, (IO_ASYNC_REQUEST_OBJECT*)0);
|
||||
}
|
||||
|
||||
// Releases provider state owned by a process socket object.
|
||||
static void NetSocketDestroy(OBJECT* object) {
|
||||
SOCKET_OBJECT* socket = (SOCKET_OBJECT*)object;
|
||||
if (socket->Provider && socket->ProviderSocket) {
|
||||
socket->Provider->SocketClose(socket->ProviderSocket);
|
||||
NetSocketCloseProvider(socket->Provider, socket->ProviderSocket);
|
||||
socket->ProviderSocket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocates a process-visible socket object around provider-owned state.
|
||||
static KSTATUS NetSocketAllocate(const NET_STACK_PROVIDER* provider,
|
||||
void* providerSocket,
|
||||
uint32_t domain,
|
||||
@@ -44,6 +610,7 @@ static KSTATUS NetSocketAllocate(const NET_STACK_PROVIDER* provider,
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Returns the provider and provider-private state behind a live socket object.
|
||||
static KSTATUS NetSocketGetProviderSocket(SOCKET_OBJECT* socket,
|
||||
const NET_STACK_PROVIDER** providerOut,
|
||||
void** providerSocketOut) {
|
||||
@@ -57,7 +624,7 @@ static KSTATUS NetSocketGetProviderSocket(SOCKET_OBJECT* socket,
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Implements the net Socket Create operation.
|
||||
// Creates a socket by submitting a create request to the active stack device.
|
||||
KSTATUS NetSocketCreate(uint32_t domain, uint32_t type, uint32_t protocol, SOCKET_OBJECT** out) {
|
||||
if (!out)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
@@ -68,7 +635,16 @@ KSTATUS NetSocketCreate(uint32_t domain, uint32_t type, uint32_t protocol, SOCKE
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = provider->SocketCreate(domain, type, protocol, &providerSocket);
|
||||
NET_SOCKET_IRP_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Operation = NetSocketIrpCreate;
|
||||
request.u.Create.Domain = domain;
|
||||
request.u.Create.Type = type;
|
||||
request.u.Create.Protocol = protocol;
|
||||
request.u.Create.ProviderSocketOut = &providerSocket;
|
||||
|
||||
KSTATUS st = NetSubmitSocketIrp(provider, &request, (IO_ASYNC_REQUEST_OBJECT*)0);
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
if (!providerSocket)
|
||||
@@ -76,28 +652,49 @@ KSTATUS NetSocketCreate(uint32_t domain, uint32_t type, uint32_t protocol, SOCKE
|
||||
|
||||
st = NetSocketAllocate(provider, providerSocket, domain, type, protocol, out);
|
||||
if (!KSUCCESS(st))
|
||||
provider->SocketClose(providerSocket);
|
||||
NetSocketCloseProvider(provider, providerSocket);
|
||||
return st;
|
||||
}
|
||||
|
||||
// Implements the net Socket Bind operation.
|
||||
// Binds a socket address through the stack device IRP path.
|
||||
KSTATUS NetSocketBind(SOCKET_OBJECT* socket, const SYS_SOCKET_ADDRESS_K* address, size_t addressSize) {
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->Bind(providerSocket, address, addressSize) : st;
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
NET_SOCKET_IRP_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Operation = NetSocketIrpBind;
|
||||
request.u.Bind.Socket = providerSocket;
|
||||
request.u.Bind.Address = address;
|
||||
request.u.Bind.AddressSize = addressSize;
|
||||
return NetSubmitSocketIrp(provider, &request, (IO_ASYNC_REQUEST_OBJECT*)0);
|
||||
}
|
||||
|
||||
// Implements the net Socket Listen operation.
|
||||
// Marks a stream socket as listening through the stack device IRP path.
|
||||
KSTATUS NetSocketListen(SOCKET_OBJECT* socket, uint32_t backlog) {
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->Listen(providerSocket, backlog) : st;
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
NET_SOCKET_IRP_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Operation = NetSocketIrpListen;
|
||||
request.u.Listen.Socket = providerSocket;
|
||||
request.u.Listen.Backlog = backlog;
|
||||
return NetSubmitSocketIrp(provider, &request, (IO_ASYNC_REQUEST_OBJECT*)0);
|
||||
}
|
||||
|
||||
// Implements the net Socket Accept operation.
|
||||
KSTATUS NetSocketAccept(SOCKET_OBJECT* socket, SOCKET_OBJECT** acceptedOut, SYS_SOCKET_ADDRESS_K* remoteOut) {
|
||||
// Accepts a provider socket through IRP and wraps the result in a process socket object.
|
||||
KSTATUS NetSocketAccept(SOCKET_OBJECT* socket, SOCKET_OBJECT** acceptedOut,
|
||||
SYS_SOCKET_ADDRESS_K* remoteOut,
|
||||
IO_ASYNC_REQUEST_OBJECT* async) {
|
||||
if (!acceptedOut)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
*acceptedOut = NULL;
|
||||
@@ -109,7 +706,15 @@ KSTATUS NetSocketAccept(SOCKET_OBJECT* socket, SOCKET_OBJECT** acceptedOut, SYS_
|
||||
return st;
|
||||
|
||||
void* acceptedProviderSocket = NULL;
|
||||
st = provider->Accept(providerSocket, &acceptedProviderSocket, remoteOut);
|
||||
NET_SOCKET_IRP_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Operation = NetSocketIrpAccept;
|
||||
request.u.Accept.Socket = providerSocket;
|
||||
request.u.Accept.AcceptedOut = &acceptedProviderSocket;
|
||||
request.u.Accept.RemoteOut = remoteOut;
|
||||
|
||||
st = NetSubmitSocketIrp(provider, &request, async);
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
if (!acceptedProviderSocket)
|
||||
@@ -122,19 +727,32 @@ KSTATUS NetSocketAccept(SOCKET_OBJECT* socket, SOCKET_OBJECT** acceptedOut, SYS_
|
||||
socket->Protocol,
|
||||
acceptedOut);
|
||||
if (!KSUCCESS(st))
|
||||
provider->SocketClose(acceptedProviderSocket);
|
||||
NetSocketCloseProvider(provider, acceptedProviderSocket);
|
||||
return st;
|
||||
}
|
||||
|
||||
// Implements the net Socket Connect operation.
|
||||
KSTATUS NetSocketConnect(SOCKET_OBJECT* socket, const SYS_SOCKET_ADDRESS_K* address, size_t addressSize) {
|
||||
|
||||
// Connects a socket through the stack device IRP path.
|
||||
KSTATUS NetSocketConnect(SOCKET_OBJECT* socket, const SYS_SOCKET_ADDRESS_K* address,
|
||||
size_t addressSize, IO_ASYNC_REQUEST_OBJECT* async) {
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->Connect(providerSocket, address, addressSize) : st;
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
NET_SOCKET_IRP_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Operation = NetSocketIrpConnect;
|
||||
request.u.Connect.Socket = providerSocket;
|
||||
request.u.Connect.Address = address;
|
||||
request.u.Connect.AddressSize = addressSize;
|
||||
return NetSubmitSocketIrp(provider, &request, async);
|
||||
}
|
||||
|
||||
// Implements the net Socket Send operation.
|
||||
|
||||
// Sends stream bytes through the stack device IRP path.
|
||||
KSTATUS NetSocketSend(SOCKET_OBJECT* socket, const void* buffer, size_t length, uint32_t flags, size_t* sentOut) {
|
||||
if (sentOut)
|
||||
*sentOut = 0;
|
||||
@@ -146,11 +764,25 @@ KSTATUS NetSocketSend(SOCKET_OBJECT* socket, const void* buffer, size_t length,
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->Send(providerSocket, buffer, length, flags, sentOut) : st;
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
NET_SOCKET_IRP_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Operation = NetSocketIrpSend;
|
||||
request.u.Send.Socket = providerSocket;
|
||||
request.u.Send.Buffer = buffer;
|
||||
request.u.Send.Length = length;
|
||||
request.u.Send.Flags = flags;
|
||||
request.u.Send.SentOut = sentOut;
|
||||
return NetSubmitSocketIrp(provider, &request, (IO_ASYNC_REQUEST_OBJECT*)0);
|
||||
}
|
||||
|
||||
// Implements the net Socket Receive operation.
|
||||
KSTATUS NetSocketReceive(SOCKET_OBJECT* socket, void* buffer, size_t length, uint32_t flags, size_t* receivedOut) {
|
||||
// Receives stream bytes through the stack device IRP path.
|
||||
KSTATUS NetSocketReceive(SOCKET_OBJECT* socket, void* buffer, size_t length,
|
||||
uint32_t flags, size_t* receivedOut,
|
||||
IO_ASYNC_REQUEST_OBJECT* async) {
|
||||
if (receivedOut)
|
||||
*receivedOut = 0;
|
||||
if (!buffer && length)
|
||||
@@ -161,9 +793,23 @@ KSTATUS NetSocketReceive(SOCKET_OBJECT* socket, void* buffer, size_t length, uin
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->Receive(providerSocket, buffer, length, flags, receivedOut) : st;
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
NET_SOCKET_IRP_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Operation = NetSocketIrpReceive;
|
||||
request.u.Receive.Socket = providerSocket;
|
||||
request.u.Receive.Buffer = buffer;
|
||||
request.u.Receive.Length = length;
|
||||
request.u.Receive.Flags = flags;
|
||||
request.u.Receive.ReceivedOut = receivedOut;
|
||||
return NetSubmitSocketIrp(provider, &request, async);
|
||||
}
|
||||
|
||||
|
||||
// Sends datagram bytes through the stack device IRP path.
|
||||
KSTATUS NetSocketSendTo(SOCKET_OBJECT* socket, const void* buffer, size_t length, uint32_t flags,
|
||||
const SYS_SOCKET_ADDRESS_K* remote, size_t remoteSize, size_t* sentOut) {
|
||||
if (sentOut)
|
||||
@@ -180,11 +826,27 @@ KSTATUS NetSocketSendTo(SOCKET_OBJECT* socket, const void* buffer, size_t length
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->SendTo(providerSocket, buffer, length, flags, remote, remoteSize, sentOut) : st;
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
NET_SOCKET_IRP_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Operation = NetSocketIrpSendTo;
|
||||
request.u.SendTo.Socket = providerSocket;
|
||||
request.u.SendTo.Buffer = buffer;
|
||||
request.u.SendTo.Length = length;
|
||||
request.u.SendTo.Flags = flags;
|
||||
request.u.SendTo.Remote = remote;
|
||||
request.u.SendTo.RemoteSize = remoteSize;
|
||||
request.u.SendTo.SentOut = sentOut;
|
||||
return NetSubmitSocketIrp(provider, &request, (IO_ASYNC_REQUEST_OBJECT*)0);
|
||||
}
|
||||
|
||||
KSTATUS NetSocketReceiveFrom(SOCKET_OBJECT* socket, void* buffer, size_t length, uint32_t flags,
|
||||
SYS_SOCKET_ADDRESS_K* remoteOut, size_t* receivedOut) {
|
||||
// Receives datagram bytes through the stack device IRP path.
|
||||
KSTATUS NetSocketReceiveFrom(SOCKET_OBJECT* socket, void* buffer, size_t length,
|
||||
uint32_t flags, SYS_SOCKET_ADDRESS_K* remoteOut,
|
||||
size_t* receivedOut, IO_ASYNC_REQUEST_OBJECT* async) {
|
||||
if (receivedOut)
|
||||
*receivedOut = 0;
|
||||
if (!buffer && length)
|
||||
@@ -199,34 +861,80 @@ KSTATUS NetSocketReceiveFrom(SOCKET_OBJECT* socket, void* buffer, size_t length,
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->ReceiveFrom(providerSocket, buffer, length, flags, remoteOut, receivedOut) : st;
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
NET_SOCKET_IRP_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Operation = NetSocketIrpReceiveFrom;
|
||||
request.u.ReceiveFrom.Socket = providerSocket;
|
||||
request.u.ReceiveFrom.Buffer = buffer;
|
||||
request.u.ReceiveFrom.Length = length;
|
||||
request.u.ReceiveFrom.Flags = flags;
|
||||
request.u.ReceiveFrom.RemoteOut = remoteOut;
|
||||
request.u.ReceiveFrom.ReceivedOut = receivedOut;
|
||||
return NetSubmitSocketIrp(provider, &request, async);
|
||||
}
|
||||
|
||||
// Implements the net Socket Shutdown operation.
|
||||
|
||||
// Shuts down one or both socket directions through the stack device IRP path.
|
||||
KSTATUS NetSocketShutdown(SOCKET_OBJECT* socket, uint32_t how) {
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->Shutdown(providerSocket, how) : st;
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
NET_SOCKET_IRP_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Operation = NetSocketIrpShutdown;
|
||||
request.u.Shutdown.Socket = providerSocket;
|
||||
request.u.Shutdown.How = how;
|
||||
return NetSubmitSocketIrp(provider, &request, (IO_ASYNC_REQUEST_OBJECT*)0);
|
||||
}
|
||||
|
||||
// Implements the net Socket Set Option operation.
|
||||
// Sets a socket option through the stack device IRP path.
|
||||
KSTATUS NetSocketSetOption(SOCKET_OBJECT* socket, uint32_t option, const void* value, size_t valueSize) {
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->SetOption(providerSocket, option, value, valueSize) : st;
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
NET_SOCKET_IRP_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Operation = NetSocketIrpSetOption;
|
||||
request.u.SetOption.Socket = providerSocket;
|
||||
request.u.SetOption.Option = option;
|
||||
request.u.SetOption.Value = value;
|
||||
request.u.SetOption.ValueSize = valueSize;
|
||||
return NetSubmitSocketIrp(provider, &request, (IO_ASYNC_REQUEST_OBJECT*)0);
|
||||
}
|
||||
|
||||
// Implements the net Socket Get Option operation.
|
||||
// Reads a socket option through the stack device IRP path.
|
||||
KSTATUS NetSocketGetOption(SOCKET_OBJECT* socket, uint32_t option, void* value, size_t valueSize, size_t* actualSizeOut) {
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->GetOption(providerSocket, option, value, valueSize, actualSizeOut) : st;
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
NET_SOCKET_IRP_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Operation = NetSocketIrpGetOption;
|
||||
request.u.GetOption.Socket = providerSocket;
|
||||
request.u.GetOption.Option = option;
|
||||
request.u.GetOption.Value = value;
|
||||
request.u.GetOption.ValueSize = valueSize;
|
||||
request.u.GetOption.ActualSizeOut = actualSizeOut;
|
||||
return NetSubmitSocketIrp(provider, &request, (IO_ASYNC_REQUEST_OBJECT*)0);
|
||||
}
|
||||
|
||||
// Implements the net Socket Poll operation.
|
||||
// Polls socket readiness through the stack device IRP path.
|
||||
KSTATUS NetSocketPoll(SOCKET_OBJECT* socket, uint32_t events, uint32_t* returnedEventsOut) {
|
||||
if (!returnedEventsOut)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
@@ -235,10 +943,20 @@ KSTATUS NetSocketPoll(SOCKET_OBJECT* socket, uint32_t events, uint32_t* returned
|
||||
const NET_STACK_PROVIDER* provider = NULL;
|
||||
void* providerSocket = NULL;
|
||||
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
||||
return KSUCCESS(st) ? provider->Poll(providerSocket, events, returnedEventsOut) : st;
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
NET_SOCKET_IRP_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Operation = NetSocketIrpPoll;
|
||||
request.u.Poll.Socket = providerSocket;
|
||||
request.u.Poll.Events = events;
|
||||
request.u.Poll.ReturnedEventsOut = returnedEventsOut;
|
||||
return NetSubmitSocketIrp(provider, &request, (IO_ASYNC_REQUEST_OBJECT*)0);
|
||||
}
|
||||
|
||||
// Implements the net Resolve Host operation.
|
||||
// Resolves a host name through the stack device IRP path.
|
||||
KSTATUS NetResolveHost(const char* name, uint32_t family, SYS_SOCKET_ADDRESS_K* addressOut) {
|
||||
if (!name || !addressOut)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
@@ -247,5 +965,12 @@ KSTATUS NetResolveHost(const char* name, uint32_t family, SYS_SOCKET_ADDRESS_K*
|
||||
if (!provider)
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
|
||||
return provider->ResolveHost(name, family, addressOut);
|
||||
NET_SOCKET_IRP_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Operation = NetSocketIrpResolveHost;
|
||||
request.u.ResolveHost.Name = name;
|
||||
request.u.ResolveHost.Family = family;
|
||||
request.u.ResolveHost.AddressOut = addressOut;
|
||||
return NetSubmitSocketIrp(provider, &request, (IO_ASYNC_REQUEST_OBJECT*)0);
|
||||
}
|
||||
Reference in new issue
Block a user