252 lines
10 KiB
C
252 lines
10 KiB
C
// Kernel socket layer. This file owns process socket objects and provider-neutral socket dispatch.
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
#include <kernel/net_socket.h>
|
|
#include <ntlite/ddi/net_stack.h>
|
|
#include <kernel/ob_object.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 void NetSocketDestroy(OBJECT* object) {
|
|
SOCKET_OBJECT* socket = (SOCKET_OBJECT*)object;
|
|
if (socket->Provider && socket->ProviderSocket) {
|
|
socket->Provider->SocketClose(socket->ProviderSocket);
|
|
socket->ProviderSocket = NULL;
|
|
}
|
|
}
|
|
|
|
static KSTATUS NetSocketAllocate(const NET_STACK_PROVIDER* provider,
|
|
void* providerSocket,
|
|
uint32_t domain,
|
|
uint32_t type,
|
|
uint32_t protocol,
|
|
SOCKET_OBJECT** out) {
|
|
if (!provider || !providerSocket || !out)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
SOCKET_OBJECT* socket = (SOCKET_OBJECT*)ObAllocateObject(ObjectTypeSocket, sizeof(SOCKET_OBJECT));
|
|
if (!socket)
|
|
return STATUS_NO_MEMORY;
|
|
|
|
socket->Header.Destroy = NetSocketDestroy;
|
|
socket->Provider = provider;
|
|
socket->ProviderSocket = providerSocket;
|
|
socket->Domain = domain;
|
|
socket->Type = type;
|
|
socket->Protocol = protocol;
|
|
*out = socket;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static KSTATUS NetSocketGetProviderSocket(SOCKET_OBJECT* socket,
|
|
const NET_STACK_PROVIDER** providerOut,
|
|
void** providerSocketOut) {
|
|
if (!socket || !providerOut || !providerSocketOut)
|
|
return STATUS_INVALID_PARAMETER;
|
|
if (!socket->Provider || !socket->ProviderSocket)
|
|
return STATUS_OBJECT_DEAD;
|
|
|
|
*providerOut = socket->Provider;
|
|
*providerSocketOut = socket->ProviderSocket;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// Implements the net Socket Create operation.
|
|
KSTATUS NetSocketCreate(uint32_t domain, uint32_t type, uint32_t protocol, SOCKET_OBJECT** out) {
|
|
if (!out)
|
|
return STATUS_INVALID_PARAMETER;
|
|
*out = NULL;
|
|
|
|
const NET_STACK_PROVIDER* provider = NetGetStackProvider();
|
|
if (!provider)
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
void* providerSocket = NULL;
|
|
KSTATUS st = provider->SocketCreate(domain, type, protocol, &providerSocket);
|
|
if (!KSUCCESS(st))
|
|
return st;
|
|
if (!providerSocket)
|
|
return STATUS_FAILURE;
|
|
|
|
st = NetSocketAllocate(provider, providerSocket, domain, type, protocol, out);
|
|
if (!KSUCCESS(st))
|
|
provider->SocketClose(providerSocket);
|
|
return st;
|
|
}
|
|
|
|
// Implements the net Socket Bind operation.
|
|
KSTATUS NetSocketBind(SOCKET_OBJECT* socket, const SYS_SOCKET_ADDRESS_IPV4_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;
|
|
}
|
|
|
|
// Implements the net Socket Listen operation.
|
|
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;
|
|
}
|
|
|
|
// Implements the net Socket Accept operation.
|
|
KSTATUS NetSocketAccept(SOCKET_OBJECT* socket, SOCKET_OBJECT** acceptedOut, SYS_SOCKET_ADDRESS_IPV4_K* remoteOut) {
|
|
if (!acceptedOut)
|
|
return STATUS_INVALID_PARAMETER;
|
|
*acceptedOut = NULL;
|
|
|
|
const NET_STACK_PROVIDER* provider = NULL;
|
|
void* providerSocket = NULL;
|
|
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
|
if (!KSUCCESS(st))
|
|
return st;
|
|
|
|
void* acceptedProviderSocket = NULL;
|
|
st = provider->Accept(providerSocket, &acceptedProviderSocket, remoteOut);
|
|
if (!KSUCCESS(st))
|
|
return st;
|
|
if (!acceptedProviderSocket)
|
|
return STATUS_FAILURE;
|
|
|
|
st = NetSocketAllocate(provider,
|
|
acceptedProviderSocket,
|
|
socket->Domain,
|
|
socket->Type,
|
|
socket->Protocol,
|
|
acceptedOut);
|
|
if (!KSUCCESS(st))
|
|
provider->SocketClose(acceptedProviderSocket);
|
|
return st;
|
|
}
|
|
|
|
// Implements the net Socket Connect operation.
|
|
KSTATUS NetSocketConnect(SOCKET_OBJECT* socket, const SYS_SOCKET_ADDRESS_IPV4_K* address, size_t addressSize) {
|
|
const NET_STACK_PROVIDER* provider = NULL;
|
|
void* providerSocket = NULL;
|
|
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
|
return KSUCCESS(st) ? provider->Connect(providerSocket, address, addressSize) : st;
|
|
}
|
|
|
|
// Implements the net Socket Send operation.
|
|
KSTATUS NetSocketSend(SOCKET_OBJECT* socket, const void* buffer, size_t length, uint32_t flags, size_t* sentOut) {
|
|
if (sentOut)
|
|
*sentOut = 0;
|
|
if (!buffer && length)
|
|
return STATUS_INVALID_PARAMETER;
|
|
if (length > NET_SOCKET_IO_MAX_BYTES)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
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;
|
|
}
|
|
|
|
// Implements the net Socket Receive operation.
|
|
KSTATUS NetSocketReceive(SOCKET_OBJECT* socket, void* buffer, size_t length, uint32_t flags, size_t* receivedOut) {
|
|
if (receivedOut)
|
|
*receivedOut = 0;
|
|
if (!buffer && length)
|
|
return STATUS_INVALID_PARAMETER;
|
|
if (length > NET_SOCKET_IO_MAX_BYTES)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
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;
|
|
}
|
|
|
|
KSTATUS NetSocketSendTo(SOCKET_OBJECT* socket, const void* buffer, size_t length, uint32_t flags,
|
|
const SYS_SOCKET_ADDRESS_IPV4_K* remote, size_t remoteSize, size_t* sentOut) {
|
|
if (sentOut)
|
|
*sentOut = 0;
|
|
if (!buffer && length)
|
|
return STATUS_INVALID_PARAMETER;
|
|
if (socket && socket->Type == SYS_SOCK_DGRAM && length > NET_SOCKET_UDP_MAX_BYTES)
|
|
return STATUS_INVALID_PARAMETER;
|
|
if (socket && socket->Type == SYS_SOCK_RAW && length > NET_SOCKET_RAW_MAX_BYTES)
|
|
return STATUS_INVALID_PARAMETER;
|
|
if (socket && socket->Type != SYS_SOCK_DGRAM && socket->Type != SYS_SOCK_RAW)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
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;
|
|
}
|
|
|
|
KSTATUS NetSocketReceiveFrom(SOCKET_OBJECT* socket, void* buffer, size_t length, uint32_t flags,
|
|
SYS_SOCKET_ADDRESS_IPV4_K* remoteOut, size_t* receivedOut) {
|
|
if (receivedOut)
|
|
*receivedOut = 0;
|
|
if (!buffer && length)
|
|
return STATUS_INVALID_PARAMETER;
|
|
if (socket && socket->Type == SYS_SOCK_DGRAM && length > NET_SOCKET_UDP_MAX_BYTES)
|
|
return STATUS_INVALID_PARAMETER;
|
|
if (socket && socket->Type == SYS_SOCK_RAW && length > NET_SOCKET_RAW_MAX_BYTES)
|
|
return STATUS_INVALID_PARAMETER;
|
|
if (socket && socket->Type != SYS_SOCK_DGRAM && socket->Type != SYS_SOCK_RAW)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
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;
|
|
}
|
|
|
|
// Implements the net Socket Shutdown operation.
|
|
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;
|
|
}
|
|
|
|
// Implements the net Socket Set Option operation.
|
|
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;
|
|
}
|
|
|
|
// Implements the net Socket Get Option operation.
|
|
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;
|
|
}
|
|
|
|
// Implements the net Socket Poll operation.
|
|
KSTATUS NetSocketPoll(SOCKET_OBJECT* socket, uint32_t events, uint32_t* returnedEventsOut) {
|
|
if (!returnedEventsOut)
|
|
return STATUS_INVALID_PARAMETER;
|
|
*returnedEventsOut = 0;
|
|
|
|
const NET_STACK_PROVIDER* provider = NULL;
|
|
void* providerSocket = NULL;
|
|
KSTATUS st = NetSocketGetProviderSocket(socket, &provider, &providerSocket);
|
|
return KSUCCESS(st) ? provider->Poll(providerSocket, events, returnedEventsOut) : st;
|
|
}
|
|
|
|
// Implements the net Resolve Host Ipv4 operation.
|
|
KSTATUS NetResolveHostIpv4(const char* name, SYS_SOCKET_ADDRESS_IPV4_K* addressOut) {
|
|
if (!name || !addressOut)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
const NET_STACK_PROVIDER* provider = NetGetStackProvider();
|
|
if (!provider)
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
return provider->ResolveHostIpv4(name, addressOut);
|
|
}
|