[client/idd] network: add negotiated input service

This commit is contained in:
Geoffrey McRae
2026-09-30 18:51:14 +10:00
parent f15c0af653
commit 5138f470b7
11 changed files with 2790 additions and 386 deletions

View File

@@ -7,6 +7,7 @@ endif()
set(TRANSPORT_NETWORK_SOURCES set(TRANSPORT_NETWORK_SOURCES
connection.c connection.c
input.c
known_hosts.c known_hosts.c
network.c network.c
) )

View File

@@ -25,6 +25,11 @@
#include "common/event.h" #include "common/event.h"
#include "common/locking.h" #include "common/locking.h"
#include <LGProtocol/NetworkPacket.h>
#include <LGProtocol/NetworkRoute.h>
#include <LGProtocol/NetworkSequence.h>
#include <LGProtocol/NetworkStream.h>
#include <msquic.h> #include <msquic.h>
#if !defined(QUIC_API_VERSION_2) #if !defined(QUIC_API_VERSION_2)
@@ -36,18 +41,18 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define NETWORK_CONNECT_POLL_MS 50U #define NETWORK_CONNECT_POLL_MS 50U
#define NETWORK_HANDSHAKE_TIMEOUT_MS 5000U #define NETWORK_HANDSHAKE_TIMEOUT_MS 5000U
#define NETWORK_IDLE_TIMEOUT_MS 10000U #define NETWORK_IDLE_TIMEOUT_MS 10000U
#define NETWORK_KEEPALIVE_INTERVAL_MS 1000U #define NETWORK_KEEPALIVE_INTERVAL_MS 1000U
#define NETWORK_INITIAL_RTT_MS 1U #define NETWORK_INITIAL_RTT_MS 1U
#define NETWORK_MAX_PEER_STREAMS 16U #define NETWORK_MAX_PEER_STREAMS 16U
#define NETWORK_MAX_HEADER_SIZE 4096U #define NETWORK_MAX_CONTROL_PAYLOAD (1024U * 1024U)
#define NETWORK_MAX_CONTROL_PAYLOAD (1024U * 1024U) #define NETWORK_MAX_CONTROL_BUFFER \
#define NETWORK_MAX_CONTROL_BUFFER \ (2U * (LG_NET_ENVELOPE_WIRE_SIZE + NETWORK_MAX_CONTROL_PAYLOAD))
(2U * (NETWORK_MAX_HEADER_SIZE + NETWORK_MAX_CONTROL_PAYLOAD)) #define NETWORK_MAX_DATAGRAM_PAYLOAD 1136U
#define NETWORK_MAX_DATAGRAM_PAYLOAD 1136U #define NETWORK_HELLO_REQUEST_ID UINT64_C(1)
#define NETWORK_HELLO_REQUEST_ID UINT64_C(1) #define NETWORK_SEQUENCE_CONNECTION_EPOCH UINT64_C(1)
struct NetworkSend struct NetworkSend
{ {
@@ -83,35 +88,41 @@ struct NetworkConnection
NetworkConnectionStateFn state; NetworkConnectionStateFn state;
void * opaque; void * opaque;
LGNetCapability offeredCapabilities[LG_NET_SERVICE_USB + 1U];
uint32_t offeredCapabilityCount;
uint16_t offeredServices;
bool certificatePending; bool certificatePending;
char pendingFingerprint[NETWORK_FINGERPRINT_TEXT_SIZE]; char pendingFingerprint[NETWORK_FINGERPRINT_TEXT_SIZE];
LG_TransportStatus connectStatus; LG_TransportStatus connectStatus;
bool connecting; bool connecting;
LG_TransportSession session; LG_TransportSession session;
uint64_t sessionEpoch; uint64_t sessionEpoch;
uint64_t sendSequence; uint64_t sendSequence;
uint64_t datagramSendSequence; uint64_t datagramSendSequence;
uint64_t receiveSequence; uint64_t receiveSequence;
bool helloAcknowledged; LGNetSequenceTracker datagramReceive;
bool authenticationComplete; bool helloAcknowledged;
bool capabilitiesComplete; bool authenticationComplete;
bool connectFailed; bool capabilitiesComplete;
uint32_t expectedCapabilities; bool connectFailed;
uint32_t receivedCapabilities; uint32_t expectedCapabilities;
uint16_t receivedServices; uint32_t receivedCapabilities;
uint16_t reliableServices; uint16_t receivedServices;
uint16_t datagramServices; uint16_t reliableServices;
uint32_t maxPayloadLength; uint16_t datagramServices;
uint32_t maxDatagramPayload; uint16_t serviceVersions[LG_NET_SERVICE_USB + 1U];
uint16_t maxDatagramSendLength; uint32_t maxPayloadLength;
bool datagramSendEnabled; uint32_t maxDatagramPayload;
uint32_t serviceMaxPayload[LG_NET_SERVICE_USB + 1U]; uint16_t maxDatagramSendLength;
uint32_t serviceMaxDatagram[LG_NET_SERVICE_USB + 1U]; bool datagramSendEnabled;
uint32_t serviceMaxPayload[LG_NET_SERVICE_USB + 1U];
uint32_t serviceMaxDatagram[LG_NET_SERVICE_USB + 1U];
uint8_t * receiveData; LGNetStreamParser receiveParser;
size_t receiveSize; uint8_t * receiveData;
size_t receiveCapacity; uint8_t * receivePayload;
}; };
static QUIC_STATUS QUIC_API networkConnectionCallback(HQUIC handle, static QUIC_STATUS QUIC_API networkConnectionCallback(HQUIC handle,
@@ -144,52 +155,23 @@ static char * networkEndpoint(const char * address, uint16_t port)
return endpoint; return endpoint;
} }
static uint16_t networkServiceVersion(LGNetService service) static bool networkCapabilityOfferValid(
const LGNetCapability * capability)
{ {
switch (service) const LGNetServiceVersionInfo * version = capability ?
{ lgNetServiceVersionInfo(capability->service) : NULL;
case LG_NET_SERVICE_CORE: if (!lgNetCapabilityValid(capability) ||
return LG_NET_CORE_VERSION_CURRENT; !version ||
capability->service <= LG_NET_SERVICE_CORE ||
capability->service >= LG_NET_SERVICE_USB ||
capability->flags & LG_NET_CAPABILITY_SELECTED ||
capability->versionMin < version->minimum ||
capability->versionMax > version->maximum ||
!(capability->flags & (LG_NET_CAPABILITY_RELIABLE |
LG_NET_CAPABILITY_DATAGRAM | LG_NET_CAPABILITY_BULK)))
return false;
case LG_NET_SERVICE_RECOVERY: return true;
return LG_NET_RECOVERY_VERSION_CURRENT;
case LG_NET_SERVICE_VIDEO:
return LG_NET_VIDEO_VERSION_CURRENT;
case LG_NET_SERVICE_CURSOR:
return LG_NET_CURSOR_VERSION_CURRENT;
case LG_NET_SERVICE_INPUT:
return LG_NET_INPUT_VERSION_CURRENT;
case LG_NET_SERVICE_AUDIO:
return LG_NET_AUDIO_VERSION_CURRENT;
case LG_NET_SERVICE_CLIPBOARD:
return LG_NET_CLIPBOARD_VERSION_CURRENT;
case LG_NET_SERVICE_FILE:
return LG_NET_FILE_VERSION_CURRENT;
case LG_NET_SERVICE_USB:
return LG_NET_USB_VERSION_RESERVED;
}
return 0;
}
static uint16_t networkReadU16(const uint8_t * data)
{
return (uint16_t)data[0] | (uint16_t)((uint16_t)data[1] << 8);
}
static uint32_t networkReadU32(const uint8_t * data)
{
return (uint32_t)data[0] |
((uint32_t)data[1] << 8) |
((uint32_t)data[2] << 16) |
((uint32_t)data[3] << 24);
} }
static void networkConnectionSetState(NetworkConnection * this, static void networkConnectionSetState(NetworkConnection * this,
@@ -229,13 +211,15 @@ static bool networkConnectionSendPacket(NetworkConnection * this,
LGNetEnvelopeFlags flags, uint64_t componentEpoch, uint64_t requestID, LGNetEnvelopeFlags flags, uint64_t componentEpoch, uint64_t requestID,
const void * payload, uint32_t payloadLength, bool allowConnecting) const void * payload, uint32_t payloadLength, bool allowConnecting)
{ {
LGNetEnvelope routeEnvelope;
lgNetEnvelopeInit(&routeEnvelope, service, messageType, serviceVersion,
LG_NET_MESSAGE_VERSION_CURRENT);
if (payloadLength > NETWORK_MAX_CONTROL_PAYLOAD || if (payloadLength > NETWORK_MAX_CONTROL_PAYLOAD ||
(payloadLength && !payload) || (payloadLength && !payload) ||
!lgNetServiceKnown(service) ||
!lgNetMessageKnown(service, messageType) ||
serviceVersion != networkServiceVersion(service) ||
(flags & (flags &
(LG_NET_ENVELOPE_DATAGRAM | LG_NET_ENVELOPE_EARLY_DATA)) || (LG_NET_ENVELOPE_DATAGRAM | LG_NET_ENVELOPE_EARLY_DATA)) ||
!lgNetEnvelopeRouteValid(&routeEnvelope, LG_NET_ROLE_CLIENT,
LG_NET_ROUTE_DELIVERY_RELIABLE) ||
atomic_load_explicit(&this->stopping, memory_order_acquire)) atomic_load_explicit(&this->stopping, memory_order_acquire))
return false; return false;
@@ -245,20 +229,20 @@ static bool networkConnectionSendPacket(NetworkConnection * this,
if (!send) if (!send)
return false; return false;
LGNetEnvelope envelope; LGNetPacketParameters parameters;
lgNetEnvelopeInit(&envelope, service, messageType, serviceVersion, lgNetPacketParametersInit(&parameters, service, messageType, serviceVersion,
LG_NET_MESSAGE_VERSION_CURRENT); LG_NET_MESSAGE_VERSION_CURRENT);
envelope.flags = flags | LG_NET_ENVELOPE_RELIABLE; parameters.flags = flags | LG_NET_ENVELOPE_RELIABLE;
envelope.payloadLength = payloadLength; parameters.componentEpoch = componentEpoch;
envelope.componentEpoch = componentEpoch; parameters.requestID = requestID;
envelope.requestID = requestID;
LG_LOCK(this->lock); LG_LOCK(this->lock);
HQUIC stream = this->controlStream; HQUIC stream = this->controlStream;
const bool serviceReady = const bool serviceReady =
allowConnecting || service == LG_NET_SERVICE_CORE || allowConnecting || service == LG_NET_SERVICE_CORE ||
((this->receivedServices & (UINT16_C(1) << service)) && ((this->receivedServices & (UINT16_C(1) << service)) &&
(this->reliableServices & (UINT16_C(1) << service))); (this->reliableServices & (UINT16_C(1) << service)) &&
this->serviceVersions[service] == serviceVersion);
const uint32_t maxPayloadLength = allowConnecting ? const uint32_t maxPayloadLength = allowConnecting ?
NETWORK_MAX_CONTROL_PAYLOAD : NETWORK_MAX_CONTROL_PAYLOAD :
service == LG_NET_SERVICE_CORE ? service == LG_NET_SERVICE_CORE ?
@@ -273,10 +257,13 @@ static bool networkConnectionSendPacket(NetworkConnection * this,
return false; return false;
} }
envelope.sessionEpoch = this->sessionEpoch; parameters.sessionEpoch = this->sessionEpoch;
envelope.sequence = ++this->sendSequence; parameters.sequence = ++this->sendSequence;
if (!lgNetPacketEncode(send->data, packetSize, &envelope, payload)) size_t wireSize;
if (!lgNetPacketConstruct(send->data, packetSize, &wireSize,
&parameters, payload, payloadLength) || wireSize != packetSize)
{ {
--this->sendSequence;
LG_UNLOCK(this->lock); LG_UNLOCK(this->lock);
free(send); free(send);
return false; return false;
@@ -287,6 +274,8 @@ static bool networkConnectionSendPacket(NetworkConnection * this,
const QUIC_STATUS status = this->api->StreamSend(stream, const QUIC_STATUS status = this->api->StreamSend(stream,
&send->buffer, 1, QUIC_SEND_FLAG_NONE, send); &send->buffer, 1, QUIC_SEND_FLAG_NONE, send);
if (QUIC_FAILED(status))
--this->sendSequence;
LG_UNLOCK(this->lock); LG_UNLOCK(this->lock);
if (QUIC_FAILED(status)) if (QUIC_FAILED(status))
@@ -303,20 +292,41 @@ static bool networkConnectionSendHello(NetworkConnection * this)
lgNetHelloInit(&hello, LG_NET_ROLE_CLIENT); lgNetHelloInit(&hello, LG_NET_ROLE_CLIENT);
hello.maxPayloadLength = NETWORK_MAX_CONTROL_PAYLOAD; hello.maxPayloadLength = NETWORK_MAX_CONTROL_PAYLOAD;
hello.maxDatagramPayload = NETWORK_MAX_DATAGRAM_PAYLOAD; hello.maxDatagramPayload = NETWORK_MAX_DATAGRAM_PAYLOAD;
if (this->password && *this->password) hello.capabilityCount = this->offeredCapabilityCount;
{ hello.authModes = this->password && *this->password ?
DEBUG_ERROR("Network password authentication is not implemented yet"); LG_NET_AUTH_MODE_FLAG(LG_NET_AUTH_PASSWORD) :
return false; LG_NET_AUTH_MODE_FLAG(LG_NET_AUTH_NONE);
}
uint8_t payload[LG_NET_HELLO_WIRE_SIZE]; uint8_t payload[LG_NET_HELLO_WIRE_SIZE];
if (!lgNetHelloEncode(payload, sizeof(payload), &hello)) if (!lgNetHelloEncode(payload, sizeof(payload), &hello))
return false; return false;
return networkConnectionSendPacket(this, LG_NET_SERVICE_CORE, if (!networkConnectionSendPacket(this, LG_NET_SERVICE_CORE,
LG_NET_CORE_MESSAGE_HELLO, LG_NET_CORE_VERSION_CURRENT, LG_NET_CORE_MESSAGE_HELLO, LG_NET_CORE_VERSION_CURRENT,
LG_NET_ENVELOPE_FINAL, 0, NETWORK_HELLO_REQUEST_ID, LG_NET_ENVELOPE_FINAL, 0, NETWORK_HELLO_REQUEST_ID,
payload, sizeof(payload), true); payload, sizeof(payload), true))
return false;
for (LGNetService service = LG_NET_SERVICE_RECOVERY;
service < LG_NET_SERVICE_USB; ++service)
{
if (!(this->offeredServices & (UINT16_C(1) << service)))
continue;
uint8_t capabilityPayload[LG_NET_CAPABILITY_WIRE_SIZE];
if (!lgNetCapabilityEncode(capabilityPayload,
sizeof(capabilityPayload), &this->offeredCapabilities[service]) ||
!networkConnectionSendPacket(this, LG_NET_SERVICE_CORE,
LG_NET_CORE_MESSAGE_CAPABILITY, LG_NET_CORE_VERSION_CURRENT,
LG_NET_ENVELOPE_FINAL, 0, NETWORK_HELLO_REQUEST_ID,
capabilityPayload, sizeof(capabilityPayload), true))
return false;
}
return networkConnectionSendPacket(this, LG_NET_SERVICE_CORE,
LG_NET_CORE_MESSAGE_CAPABILITIES_DONE,
LG_NET_CORE_VERSION_CURRENT, LG_NET_ENVELOPE_FINAL,
0, NETWORK_HELLO_REQUEST_ID, NULL, 0, true);
} }
static void networkConnectionReady(NetworkConnection * this) static void networkConnectionReady(NetworkConnection * this)
@@ -349,26 +359,53 @@ static bool networkConnectionHandleCapability(NetworkConnection * this,
packet->payload, packet->payloadLength) != LG_NET_PARSE_OK) packet->payload, packet->payloadLength) != LG_NET_PARSE_OK)
return false; return false;
if (capability.service <= LG_NET_SERVICE_CORE ||
capability.service >= LG_NET_SERVICE_USB)
return false;
LG_LOCK(this->lock); LG_LOCK(this->lock);
const uint16_t serviceMask =
UINT16_C(1) << capability.service;
const LGNetCapability offered =
this->offeredCapabilities[capability.service];
const LGNetCapabilityFlags selectedFlags =
capability.flags &
(LG_NET_CAPABILITY_RELIABLE | LG_NET_CAPABILITY_DATAGRAM |
LG_NET_CAPABILITY_BULK | LG_NET_CAPABILITY_MULTI_CLIENT);
const LGNetCapabilityFlags offeredFlags =
offered.flags &
(LG_NET_CAPABILITY_RELIABLE | LG_NET_CAPABILITY_DATAGRAM |
LG_NET_CAPABILITY_BULK | LG_NET_CAPABILITY_MULTI_CLIENT);
if (!this->helloAcknowledged || this->capabilitiesComplete || if (!this->helloAcknowledged || this->capabilitiesComplete ||
this->receivedCapabilities >= this->expectedCapabilities || this->receivedCapabilities >= this->expectedCapabilities ||
capability.service <= LG_NET_SERVICE_CORE || !(this->offeredServices & serviceMask) ||
capability.service > LG_NET_SERVICE_USB ||
!(capability.flags & LG_NET_CAPABILITY_SELECTED) || !(capability.flags & LG_NET_CAPABILITY_SELECTED) ||
capability.versionMin != networkServiceVersion(capability.service) || capability.flags & LG_NET_CAPABILITY_REQUIRED ||
!(selectedFlags & LG_NET_CAPABILITY_RELIABLE) ||
selectedFlags & ~offeredFlags ||
capability.features & ~offered.features ||
capability.versionMin < offered.versionMin ||
capability.versionMin > offered.versionMax ||
capability.maxPayloadLength > offered.maxPayloadLength ||
capability.maxPayloadLength > this->maxPayloadLength || capability.maxPayloadLength > this->maxPayloadLength ||
capability.maxDatagramPayload > offered.maxDatagramPayload ||
capability.maxDatagramPayload > this->maxDatagramPayload || capability.maxDatagramPayload > this->maxDatagramPayload ||
(this->receivedServices & (UINT16_C(1) << capability.service))) capability.maxBidirectionalStreams >
offered.maxBidirectionalStreams ||
capability.maxUnidirectionalStreams >
offered.maxUnidirectionalStreams ||
(this->receivedServices & serviceMask))
{ {
LG_UNLOCK(this->lock); LG_UNLOCK(this->lock);
return false; return false;
} }
this->receivedServices |= UINT16_C(1) << capability.service; this->receivedServices |= serviceMask;
if (capability.flags & LG_NET_CAPABILITY_RELIABLE) if (capability.flags & LG_NET_CAPABILITY_RELIABLE)
this->reliableServices |= UINT16_C(1) << capability.service; this->reliableServices |= UINT16_C(1) << capability.service;
if (capability.flags & LG_NET_CAPABILITY_DATAGRAM) if (capability.flags & LG_NET_CAPABILITY_DATAGRAM)
this->datagramServices |= UINT16_C(1) << capability.service; this->datagramServices |= UINT16_C(1) << capability.service;
this->serviceVersions[capability.service] = capability.versionMin;
this->serviceMaxPayload[capability.service] = this->serviceMaxPayload[capability.service] =
capability.maxPayloadLength; capability.maxPayloadLength;
this->serviceMaxDatagram[capability.service] = this->serviceMaxDatagram[capability.service] =
@@ -378,6 +415,34 @@ static bool networkConnectionHandleCapability(NetworkConnection * this,
return true; return true;
} }
static bool networkConnectionRequiredCapabilitiesSelected(
const NetworkConnection * this)
{
for (LGNetService service = LG_NET_SERVICE_RECOVERY;
service < LG_NET_SERVICE_USB; ++service)
{
const uint16_t serviceMask = UINT16_C(1) << service;
if ((this->offeredServices & serviceMask) &&
(this->offeredCapabilities[service].flags &
LG_NET_CAPABILITY_REQUIRED) &&
!(this->receivedServices & serviceMask))
return false;
}
return true;
}
static void networkConnectionSetSessionFeatures(NetworkConnection * this)
{
const uint16_t services =
this->receivedServices & this->reliableServices;
if (services & (UINT16_C(1) << LG_NET_SERVICE_INPUT))
this->session.features |= LG_TRANSPORT_FEATURE_INPUT;
if (services & (UINT16_C(1) << LG_NET_SERVICE_CLIPBOARD))
this->session.features |= LG_TRANSPORT_FEATURE_CLIPBOARD;
if (services & (UINT16_C(1) << LG_NET_SERVICE_AUDIO))
this->session.features |= LG_TRANSPORT_FEATURE_AUDIO;
}
static bool networkConnectionHandleCore(NetworkConnection * this, static bool networkConnectionHandleCore(NetworkConnection * this,
const LGNetPacketView * packet) const LGNetPacketView * packet)
{ {
@@ -385,7 +450,8 @@ static bool networkConnectionHandleCore(NetworkConnection * this,
LG_NET_ENVELOPE_RESPONSE | LG_NET_ENVELOPE_RESPONSE |
LG_NET_ENVELOPE_FINAL | LG_NET_ENVELOPE_FINAL |
LG_NET_ENVELOPE_RELIABLE; LG_NET_ENVELOPE_RELIABLE;
uint64_t sessionEpoch;
uint64_t sessionEpoch;
LG_LOCK(this->lock); LG_LOCK(this->lock);
sessionEpoch = this->sessionEpoch; sessionEpoch = this->sessionEpoch;
LG_UNLOCK(this->lock); LG_UNLOCK(this->lock);
@@ -422,8 +488,11 @@ static bool networkConnectionHandleCore(NetworkConnection * this,
this->sessionEpoch = acknowledgement.sessionEpoch; this->sessionEpoch = acknowledgement.sessionEpoch;
this->maxPayloadLength = acknowledgement.maxPayloadLength; this->maxPayloadLength = acknowledgement.maxPayloadLength;
this->maxDatagramPayload = acknowledgement.maxDatagramPayload; this->maxDatagramPayload = acknowledgement.maxDatagramPayload;
const bool sequenceReady = lgNetSequenceTrackerInit(
&this->datagramReceive, acknowledgement.sessionEpoch,
NETWORK_SEQUENCE_CONNECTION_EPOCH, 64, false);
LG_UNLOCK(this->lock); LG_UNLOCK(this->lock);
return true; return sequenceReady;
} }
case LG_NET_CORE_MESSAGE_CAPABILITY: case LG_NET_CORE_MESSAGE_CAPABILITY:
@@ -448,8 +517,11 @@ static bool networkConnectionHandleCore(NetworkConnection * this,
ready = !this->capabilitiesComplete && ready = !this->capabilitiesComplete &&
this->helloAcknowledged && this->helloAcknowledged &&
this->authenticationComplete && this->authenticationComplete &&
this->receivedCapabilities == this->expectedCapabilities; this->receivedCapabilities == this->expectedCapabilities &&
networkConnectionRequiredCapabilitiesSelected(this);
this->capabilitiesComplete = ready; this->capabilitiesComplete = ready;
if (ready)
networkConnectionSetSessionFeatures(this);
LG_UNLOCK(this->lock); LG_UNLOCK(this->lock);
if (ready) if (ready)
networkConnectionReady(this); networkConnectionReady(this);
@@ -484,6 +556,8 @@ static bool networkConnectionHandlePacket(NetworkConnection * this,
(UINT16_C(1) << packet->envelope.service)) && (UINT16_C(1) << packet->envelope.service)) &&
(this->reliableServices & (this->reliableServices &
(UINT16_C(1) << packet->envelope.service)) && (UINT16_C(1) << packet->envelope.service)) &&
packet->envelope.serviceVersion ==
this->serviceVersions[packet->envelope.service] &&
packet->payloadLength <= packet->payloadLength <=
this->serviceMaxPayload[packet->envelope.service]; this->serviceMaxPayload[packet->envelope.service];
LG_UNLOCK(this->lock); LG_UNLOCK(this->lock);
@@ -503,7 +577,7 @@ static bool networkConnectionValidateControl(NetworkConnection * this,
maxPayloadLength = this->maxPayloadLength; maxPayloadLength = this->maxPayloadLength;
LG_UNLOCK(this->lock); LG_UNLOCK(this->lock);
return packet->envelope.headerSize <= NETWORK_MAX_HEADER_SIZE && return packet->envelope.headerSize == LG_NET_ENVELOPE_WIRE_SIZE &&
packet->payloadLength <= maxPayloadLength && packet->payloadLength <= maxPayloadLength &&
packet->envelope.messageVersion == LG_NET_MESSAGE_VERSION_CURRENT && packet->envelope.messageVersion == LG_NET_MESSAGE_VERSION_CURRENT &&
(packet->envelope.flags & (packet->envelope.flags &
@@ -511,11 +585,8 @@ static bool networkConnectionValidateControl(NetworkConnection * this,
(LG_NET_ENVELOPE_RELIABLE | LG_NET_ENVELOPE_FINAL) && (LG_NET_ENVELOPE_RELIABLE | LG_NET_ENVELOPE_FINAL) &&
!(packet->envelope.flags & !(packet->envelope.flags &
(LG_NET_ENVELOPE_DATAGRAM | LG_NET_ENVELOPE_EARLY_DATA)) && (LG_NET_ENVELOPE_DATAGRAM | LG_NET_ENVELOPE_EARLY_DATA)) &&
lgNetServiceKnown(packet->envelope.service) && lgNetEnvelopeRouteValid(&packet->envelope, LG_NET_ROLE_SERVER,
lgNetMessageKnown(packet->envelope.service, LG_NET_ROUTE_DELIVERY_RELIABLE);
packet->envelope.messageType) &&
packet->envelope.serviceVersion ==
networkServiceVersion(packet->envelope.service);
} }
static bool networkConnectionDecodeDatagram(NetworkConnection * this, static bool networkConnectionDecodeDatagram(NetworkConnection * this,
@@ -526,117 +597,67 @@ static bool networkConnectionDecodeDatagram(NetworkConnection * this,
buffer->Length) != LG_NET_PARSE_OK || buffer->Length) != LG_NET_PARSE_OK ||
packet->wireSize != buffer->Length || packet->wireSize != buffer->Length ||
packet->envelope.service == LG_NET_SERVICE_CORE || packet->envelope.service == LG_NET_SERVICE_CORE ||
!lgNetServiceKnown(packet->envelope.service) || !lgNetEnvelopeRouteValid(&packet->envelope, LG_NET_ROLE_SERVER,
!lgNetMessageKnown(packet->envelope.service, LG_NET_ROUTE_DELIVERY_DATAGRAM))
packet->envelope.messageType) || return false;
packet->envelope.serviceVersion !=
networkServiceVersion(packet->envelope.service)) if (!atomic_load_explicit(
&this->sessionValid, memory_order_acquire) ||
packet->envelope.headerSize != LG_NET_ENVELOPE_WIRE_SIZE ||
!packet->envelope.sequence ||
packet->envelope.messageVersion != LG_NET_MESSAGE_VERSION_CURRENT ||
(packet->envelope.flags &
(LG_NET_ENVELOPE_DATAGRAM | LG_NET_ENVELOPE_FINAL)) !=
(LG_NET_ENVELOPE_DATAGRAM | LG_NET_ENVELOPE_FINAL) ||
(packet->envelope.flags &
(LG_NET_ENVELOPE_RELIABLE | LG_NET_ENVELOPE_EARLY_DATA)))
return false; return false;
uint64_t sessionEpoch;
uint16_t receivedServices;
uint16_t datagramServices;
uint32_t serviceMaxDatagram;
LG_LOCK(this->lock); LG_LOCK(this->lock);
sessionEpoch = this->sessionEpoch; const uint16_t serviceMask = UINT16_C(1) << packet->envelope.service;
receivedServices = this->receivedServices; const bool valid =
datagramServices = this->datagramServices; packet->envelope.sessionEpoch == this->sessionEpoch &&
serviceMaxDatagram = (this->receivedServices & serviceMask) &&
this->serviceMaxDatagram[packet->envelope.service]; (this->datagramServices & serviceMask) &&
packet->envelope.serviceVersion ==
this->serviceVersions[packet->envelope.service] &&
this->serviceMaxDatagram[packet->envelope.service] &&
packet->payloadLength <=
this->serviceMaxDatagram[packet->envelope.service] &&
lgNetSequenceAccepted(lgNetSequenceTrackerCheck(
&this->datagramReceive, packet->envelope.sessionEpoch,
NETWORK_SEQUENCE_CONNECTION_EPOCH, packet->envelope.sequence));
LG_UNLOCK(this->lock); LG_UNLOCK(this->lock);
return valid;
return atomic_load_explicit(
&this->sessionValid, memory_order_acquire) &&
(receivedServices & (UINT16_C(1) << packet->envelope.service)) &&
(datagramServices & (UINT16_C(1) << packet->envelope.service)) &&
serviceMaxDatagram &&
packet->envelope.headerSize <= NETWORK_MAX_HEADER_SIZE &&
packet->payloadLength <= serviceMaxDatagram &&
packet->envelope.sessionEpoch == sessionEpoch &&
packet->envelope.sequence != 0 &&
packet->envelope.messageVersion == LG_NET_MESSAGE_VERSION_CURRENT &&
(packet->envelope.flags & LG_NET_ENVELOPE_DATAGRAM) &&
!(packet->envelope.flags &
(LG_NET_ENVELOPE_RELIABLE | LG_NET_ENVELOPE_EARLY_DATA));
} }
static bool networkConnectionReserveReceive(NetworkConnection * this, static bool networkConnectionDrainReceive(NetworkConnection * this)
size_t additional)
{ {
if (this->receiveSize > NETWORK_MAX_CONTROL_BUFFER || for (;;)
additional > NETWORK_MAX_CONTROL_BUFFER - this->receiveSize)
return false;
const size_t required = this->receiveSize + additional;
if (required <= this->receiveCapacity)
return true;
size_t capacity = this->receiveCapacity ? this->receiveCapacity : 4096U;
while (capacity < required)
{ {
const size_t next = capacity * 2U; LGNetStreamPacket streamPacket;
if (next < capacity || next > NETWORK_MAX_CONTROL_BUFFER) const LGNetStreamResult result = lgNetStreamParserNext(
&this->receiveParser, &streamPacket, NULL);
if (result == LG_NET_STREAM_NEED_DATA)
return true;
if (result != LG_NET_STREAM_PACKET)
return false;
LGNetPacketView packet =
{ {
capacity = NETWORK_MAX_CONTROL_BUFFER; .envelope = streamPacket.envelope,
break; .payload = streamPacket.payload[0].data,
.payloadLength = streamPacket.payloadLength,
.wireSize = streamPacket.wireSize,
};
if (streamPacket.payload[1].size)
{
memcpy(this->receivePayload, streamPacket.payload[0].data,
streamPacket.payload[0].size);
memcpy(this->receivePayload + streamPacket.payload[0].size,
streamPacket.payload[1].data, streamPacket.payload[1].size);
packet.payload = this->receivePayload;
} }
capacity = next;
}
uint8_t * data = realloc(this->receiveData, capacity);
if (!data)
return false;
this->receiveData = data;
this->receiveCapacity = capacity;
return true;
}
static bool networkConnectionReceive(NetworkConnection * this,
const QUIC_BUFFER * buffers, uint32_t count)
{
if (count && !buffers)
return false;
size_t additional = 0;
for (uint32_t i = 0; i < count; ++i)
{
if (buffers[i].Length && !buffers[i].Buffer)
return false;
if (buffers[i].Length > SIZE_MAX - additional)
return false;
additional += buffers[i].Length;
}
if (!networkConnectionReserveReceive(this, additional))
return false;
for (uint32_t i = 0; i < count; ++i)
{
if (!buffers[i].Length)
continue;
memcpy(this->receiveData + this->receiveSize,
buffers[i].Buffer, buffers[i].Length);
this->receiveSize += buffers[i].Length;
}
while (this->receiveSize >= LG_NET_ENVELOPE_WIRE_SIZE)
{
const uint16_t headerSize = networkReadU16(this->receiveData + 8U);
const uint32_t payloadSize = networkReadU32(this->receiveData + 24U);
if (headerSize < LG_NET_ENVELOPE_WIRE_SIZE ||
headerSize > NETWORK_MAX_HEADER_SIZE ||
payloadSize > NETWORK_MAX_CONTROL_PAYLOAD ||
payloadSize > NETWORK_MAX_CONTROL_BUFFER - headerSize)
return false;
const size_t packetSize = (size_t)headerSize + payloadSize;
if (packetSize > this->receiveSize)
break;
LGNetPacketView packet;
if (lgNetPacketDecode(&packet, this->receiveData,
packetSize) != LG_NET_PARSE_OK)
return false;
LG_LOCK(this->lock); LG_LOCK(this->lock);
const bool sequenceValid = this->receiveSequence != UINT64_MAX && const bool sequenceValid = this->receiveSequence != UINT64_MAX &&
@@ -645,14 +666,39 @@ static bool networkConnectionReceive(NetworkConnection * this,
this->receiveSequence = packet.envelope.sequence; this->receiveSequence = packet.envelope.sequence;
LG_UNLOCK(this->lock); LG_UNLOCK(this->lock);
if (!sequenceValid || !networkConnectionValidateControl(this, &packet) || if (!sequenceValid || !networkConnectionValidateControl(this, &packet) ||
!networkConnectionHandlePacket(this, &packet, false)) !networkConnectionHandlePacket(this, &packet, false) ||
!lgNetStreamParserConsume(&this->receiveParser))
return false; return false;
this->receiveSize -= packetSize;
memmove(this->receiveData, this->receiveData + packetSize,
this->receiveSize);
} }
return true; }
static bool networkConnectionReceive(NetworkConnection * this,
const QUIC_BUFFER * buffers, uint32_t count)
{
if (count && !buffers)
return false;
for (uint32_t i = 0; i < count; ++i)
{
if (buffers[i].Length && !buffers[i].Buffer)
return false;
size_t offset = 0;
while (offset < buffers[i].Length)
{
size_t accepted;
if (!lgNetStreamParserAppend(&this->receiveParser,
buffers[i].Buffer + offset, buffers[i].Length - offset,
&accepted))
return false;
offset += accepted;
if (!networkConnectionDrainReceive(this))
return false;
if (!accepted && offset < buffers[i].Length)
return false;
}
}
return networkConnectionDrainReceive(this);
} }
static void networkConnectionTrustDecision(void * opaque, bool trusted) static void networkConnectionTrustDecision(void * opaque, bool trusted)
@@ -922,7 +968,9 @@ bool networkConnectionCreate(NetworkConnection ** result,
const NetworkConnectionParams * params) const NetworkConnectionParams * params)
{ {
if (!result || !params || !params->address || !params->knownHosts || if (!result || !params || !params->address || !params->knownHosts ||
(!!params->trustPrompt != !!params->trustCancel)) (!!params->trustPrompt != !!params->trustCancel) ||
params->capabilityCount > LG_NET_MAX_CAPABILITY_RECORDS ||
(params->capabilityCount && !params->capabilities))
return false; return false;
NetworkConnection * this = calloc(1, sizeof(*this)); NetworkConnection * this = calloc(1, sizeof(*this));
@@ -934,6 +982,20 @@ bool networkConnectionCreate(NetworkConnection ** result,
atomic_init(&this->stopping, false); atomic_init(&this->stopping, false);
atomic_init(&this->sessionValid, false); atomic_init(&this->sessionValid, false);
for (uint32_t index = 0; index < params->capabilityCount; ++index)
{
const LGNetCapability * capability = &params->capabilities[index];
if (!networkCapabilityOfferValid(capability))
goto fail;
const uint16_t serviceMask = UINT16_C(1) << capability->service;
if (this->offeredServices & serviceMask)
goto fail;
this->offeredCapabilities[capability->service] = *capability;
this->offeredServices |= serviceMask;
++this->offeredCapabilityCount;
}
this->address = networkDuplicate(params->address); this->address = networkDuplicate(params->address);
this->password = networkDuplicate(params->password); this->password = networkDuplicate(params->password);
this->endpoint = networkEndpoint(params->address, params->port); this->endpoint = networkEndpoint(params->address, params->port);
@@ -954,6 +1016,13 @@ bool networkConnectionCreate(NetworkConnection ** result,
if (!this->connectEvent || !this->closeEvent) if (!this->connectEvent || !this->closeEvent)
goto fail; goto fail;
this->receiveData = malloc(NETWORK_MAX_CONTROL_BUFFER);
this->receivePayload = malloc(NETWORK_MAX_CONTROL_PAYLOAD);
if (!this->receiveData || !this->receivePayload ||
!lgNetStreamParserInit(&this->receiveParser, this->receiveData,
NETWORK_MAX_CONTROL_BUFFER, NETWORK_MAX_CONTROL_PAYLOAD))
goto fail;
if (QUIC_FAILED(MsQuicOpen2(&this->api))) if (QUIC_FAILED(MsQuicOpen2(&this->api)))
goto fail; goto fail;
@@ -1037,6 +1106,7 @@ void networkConnectionDestroy(NetworkConnection ** connection)
lgFreeEvent(this->connectEvent); lgFreeEvent(this->connectEvent);
LG_LOCK_FREE(this->stateCallbackLock); LG_LOCK_FREE(this->stateCallbackLock);
LG_LOCK_FREE(this->lock); LG_LOCK_FREE(this->lock);
free(this->receivePayload);
free(this->receiveData); free(this->receiveData);
free(this->endpoint); free(this->endpoint);
free(this->password); free(this->password);
@@ -1084,9 +1154,10 @@ LG_TransportStatus networkConnectionConnect(NetworkConnection * this,
this->maxDatagramPayload = 0; this->maxDatagramPayload = 0;
this->maxDatagramSendLength = 0; this->maxDatagramSendLength = 0;
this->datagramSendEnabled = false; this->datagramSendEnabled = false;
memset(this->serviceVersions, 0, sizeof(this->serviceVersions));
memset(this->serviceMaxPayload, 0, sizeof(this->serviceMaxPayload)); memset(this->serviceMaxPayload, 0, sizeof(this->serviceMaxPayload));
memset(this->serviceMaxDatagram, 0, sizeof(this->serviceMaxDatagram)); memset(this->serviceMaxDatagram, 0, sizeof(this->serviceMaxDatagram));
this->receiveSize = 0; lgNetStreamParserReset(&this->receiveParser);
memset(&this->session, 0, sizeof(this->session)); memset(&this->session, 0, sizeof(this->session));
snprintf(this->session.version, sizeof(this->session.version), snprintf(this->session.version, sizeof(this->session.version),
"LG network protocol %u", LG_NET_PROTOCOL_VERSION_CURRENT); "LG network protocol %u", LG_NET_PROTOCOL_VERSION_CURRENT);
@@ -1237,6 +1308,23 @@ bool networkConnectionServiceAvailable(NetworkConnection * this,
return available; return available;
} }
bool networkConnectionServiceVersion(NetworkConnection * this,
LGNetService service, uint16_t * version)
{
if (!version || !networkConnectionValid(this) ||
service <= LG_NET_SERVICE_CORE || service >= LG_NET_SERVICE_USB)
return false;
LG_LOCK(this->lock);
const uint16_t serviceMask = UINT16_C(1) << service;
const bool available =
(this->receivedServices & serviceMask) != 0;
if (available)
*version = this->serviceVersions[service];
LG_UNLOCK(this->lock);
return available;
}
LG_TransportStatus networkConnectionSend(NetworkConnection * this, LG_TransportStatus networkConnectionSend(NetworkConnection * this,
LGNetService service, uint16_t messageType, uint16_t serviceVersion, LGNetService service, uint16_t messageType, uint16_t serviceVersion,
LGNetEnvelopeFlags flags, uint64_t componentEpoch, uint64_t requestID, LGNetEnvelopeFlags flags, uint64_t componentEpoch, uint64_t requestID,
@@ -1258,28 +1346,28 @@ LG_TransportStatus networkConnectionSendDatagram(NetworkConnection * this,
{ {
if (!this || !networkConnectionValid(this)) if (!this || !networkConnectionValid(this))
return LG_TRANSPORT_DISCONNECTED; return LG_TRANSPORT_DISCONNECTED;
if ((payloadLength && !payload) || LGNetEnvelope routeEnvelope;
!lgNetServiceKnown(service) || service == LG_NET_SERVICE_CORE || lgNetEnvelopeInit(&routeEnvelope, service, messageType, serviceVersion,
!lgNetMessageKnown(service, messageType) ||
serviceVersion != networkServiceVersion(service) ||
flags & (LG_NET_ENVELOPE_RELIABLE | LG_NET_ENVELOPE_DATAGRAM |
LG_NET_ENVELOPE_EARLY_DATA))
return LG_TRANSPORT_ERROR;
const size_t packetSize = LG_NET_ENVELOPE_WIRE_SIZE +
payloadLength;
struct NetworkSend * send = malloc(sizeof(*send) + packetSize);
if (!send)
return LG_TRANSPORT_ERROR;
LGNetEnvelope envelope;
lgNetEnvelopeInit(&envelope, service, messageType, serviceVersion,
LG_NET_MESSAGE_VERSION_CURRENT); LG_NET_MESSAGE_VERSION_CURRENT);
envelope.flags = flags | LG_NET_ENVELOPE_DATAGRAM | if ((payloadLength && !payload) || service == LG_NET_SERVICE_CORE ||
flags & (LG_NET_ENVELOPE_RELIABLE | LG_NET_ENVELOPE_DATAGRAM |
LG_NET_ENVELOPE_EARLY_DATA) ||
!lgNetEnvelopeRouteValid(&routeEnvelope, LG_NET_ROLE_CLIENT,
LG_NET_ROUTE_DELIVERY_DATAGRAM))
return LG_TRANSPORT_ERROR;
if (payloadLength > LG_NET_MAX_PAYLOAD_LENGTH)
return LG_TRANSPORT_ERROR;
const size_t packetSize = LG_NET_ENVELOPE_WIRE_SIZE + payloadLength;
LGNetPacketParameters parameters;
lgNetPacketParametersInit(&parameters, service, messageType, serviceVersion,
LG_NET_MESSAGE_VERSION_CURRENT);
parameters.flags = flags | LG_NET_ENVELOPE_DATAGRAM |
LG_NET_ENVELOPE_FINAL; LG_NET_ENVELOPE_FINAL;
envelope.payloadLength = payloadLength; parameters.componentEpoch = componentEpoch;
envelope.componentEpoch = componentEpoch; parameters.requestID = requestID;
envelope.requestID = requestID;
LG_LOCK(this->lock); LG_LOCK(this->lock);
const uint16_t serviceMask = UINT16_C(1) << service; const uint16_t serviceMask = UINT16_C(1) << service;
@@ -1288,20 +1376,30 @@ LG_TransportStatus networkConnectionSendDatagram(NetworkConnection * this,
!atomic_load_explicit(&this->sessionValid, memory_order_acquire) || !atomic_load_explicit(&this->sessionValid, memory_order_acquire) ||
!(this->receivedServices & serviceMask) || !(this->receivedServices & serviceMask) ||
!(this->datagramServices & serviceMask) || !(this->datagramServices & serviceMask) ||
this->serviceVersions[service] != serviceVersion ||
!this->datagramSendEnabled || !this->datagramSendEnabled ||
payloadLength > this->serviceMaxDatagram[service] || payloadLength > this->serviceMaxDatagram[service] ||
packetSize > this->maxDatagramSendLength || packetSize > this->maxDatagramSendLength ||
this->datagramSendSequence == UINT64_MAX) this->datagramSendSequence == UINT64_MAX)
{ {
LG_UNLOCK(this->lock); LG_UNLOCK(this->lock);
free(send);
return LG_TRANSPORT_UNAVAILABLE; return LG_TRANSPORT_UNAVAILABLE;
} }
envelope.sessionEpoch = this->sessionEpoch; struct NetworkSend * send = malloc(sizeof(*send) + packetSize);
envelope.sequence = ++this->datagramSendSequence; if (!send)
if (!lgNetPacketEncode(send->data, packetSize, &envelope, payload))
{ {
LG_UNLOCK(this->lock);
return LG_TRANSPORT_ERROR;
}
parameters.sessionEpoch = this->sessionEpoch;
parameters.sequence = ++this->datagramSendSequence;
size_t wireSize;
if (!lgNetPacketConstruct(send->data, packetSize, &wireSize,
&parameters, payload, payloadLength) || wireSize != packetSize)
{
--this->datagramSendSequence;
LG_UNLOCK(this->lock); LG_UNLOCK(this->lock);
free(send); free(send);
return LG_TRANSPORT_ERROR; return LG_TRANSPORT_ERROR;
@@ -1314,6 +1412,8 @@ LG_TransportStatus networkConnectionSendDatagram(NetworkConnection * this,
sendFlags |= QUIC_SEND_FLAG_CANCEL_ON_BLOCKED; sendFlags |= QUIC_SEND_FLAG_CANCEL_ON_BLOCKED;
const QUIC_STATUS status = this->api->DatagramSend(connection, const QUIC_STATUS status = this->api->DatagramSend(connection,
&send->buffer, 1, sendFlags, send); &send->buffer, 1, sendFlags, send);
if (QUIC_FAILED(status))
--this->datagramSendSequence;
LG_UNLOCK(this->lock); LG_UNLOCK(this->lock);
if (QUIC_FAILED(status)) if (QUIC_FAILED(status))

View File

@@ -52,6 +52,8 @@ typedef struct NetworkConnectionParams
NetworkTrustCancelFn trustCancel; NetworkTrustCancelFn trustCancel;
NetworkPacketFn packet; NetworkPacketFn packet;
NetworkConnectionStateFn state; NetworkConnectionStateFn state;
const LGNetCapability * capabilities;
uint32_t capabilityCount;
void * opaque; void * opaque;
} }
NetworkConnectionParams; NetworkConnectionParams;
@@ -68,6 +70,8 @@ void networkConnectionDisconnect(NetworkConnection * connection);
bool networkConnectionValid(const NetworkConnection * connection); bool networkConnectionValid(const NetworkConnection * connection);
bool networkConnectionServiceAvailable(NetworkConnection * connection, bool networkConnectionServiceAvailable(NetworkConnection * connection,
LGNetService service, LGNetCapabilityFlags required); LGNetService service, LGNetCapabilityFlags required);
bool networkConnectionServiceVersion(NetworkConnection * connection,
LGNetService service, uint16_t * version);
LG_TransportStatus networkConnectionSend(NetworkConnection * connection, LG_TransportStatus networkConnectionSend(NetworkConnection * connection,
LGNetService service, uint16_t messageType, uint16_t serviceVersion, LGNetService service, uint16_t messageType, uint16_t serviceVersion,

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,41 @@
/**
* Looking Glass
* Copyright © 2017-2026 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma once
#include "connection.h"
#include "interface/input.h"
#include <LGProtocol/NetworkProtocol.h>
#include <stdbool.h>
typedef struct NetworkInput NetworkInput;
bool networkInputCreate(NetworkInput ** input,
NetworkConnection * connection);
void networkInputDestroy(NetworkInput ** input);
const LG_InputOps * networkInputGetOps(void);
void networkInputConnectionState(NetworkInput * input, bool connected);
bool networkInputPacket(NetworkInput * input,
const LGNetPacketView * packet, bool datagram);

View File

@@ -20,6 +20,7 @@
#include "network.h" #include "network.h"
#include "connection.h" #include "connection.h"
#include "input.h"
#include "known_hosts.h" #include "known_hosts.h"
#include "app.h" #include "app.h"
@@ -39,6 +40,24 @@
#define NETWORK_ADDRESS_MAX 255U #define NETWORK_ADDRESS_MAX 255U
#define NETWORK_ENDPOINT_TEXT_SIZE (NETWORK_ADDRESS_MAX + 9U) #define NETWORK_ENDPOINT_TEXT_SIZE (NETWORK_ADDRESS_MAX + 9U)
#define NETWORK_MAX_PAYLOAD (1024U * 1024U)
#define NETWORK_MAX_DATAGRAM 1136U
static const LGNetCapability NETWORK_CAPABILITIES[] =
{
{
.service = LG_NET_SERVICE_INPUT,
.versionMin = LG_NET_INPUT_VERSION_MIN,
.versionMax = LG_NET_INPUT_VERSION_CURRENT,
.flags = LG_NET_CAPABILITY_RELIABLE |
LG_NET_CAPABILITY_DATAGRAM,
.features = 0,
.maxPayloadLength = NETWORK_MAX_PAYLOAD,
.maxDatagramPayload = NETWORK_MAX_DATAGRAM,
.maxBidirectionalStreams = 0,
.maxUnidirectionalStreams = 0,
},
};
struct NetworkTrustPrompt struct NetworkTrustPrompt
{ {
@@ -50,6 +69,7 @@ struct NetworkTrustPrompt
struct LG_Transport struct LG_Transport
{ {
NetworkConnection * connection; NetworkConnection * connection;
NetworkInput * input;
NetworkKnownHosts knownHosts; NetworkKnownHosts knownHosts;
LGEvent * frameEvent; LGEvent * frameEvent;
LGEvent * promptIdle; LGEvent * promptIdle;
@@ -252,6 +272,8 @@ static void networkConnectionState(void * opaque, bool connected,
const LG_TransportStatus status = connected ? const LG_TransportStatus status = connected ?
LG_TRANSPORT_UNAVAILABLE : reason; LG_TRANSPORT_UNAVAILABLE : reason;
networkInputConnectionState(this->input, connected);
LG_LOCK(this->stateLock); LG_LOCK(this->stateLock);
networkSetUnavailable(&this->videoStatus.frame, status); networkSetUnavailable(&this->videoStatus.frame, status);
networkSetUnavailable(&this->videoStatus.pointer, status); networkSetUnavailable(&this->videoStatus.pointer, status);
@@ -264,11 +286,13 @@ static void networkConnectionState(void * opaque, bool connected,
static void networkPacket(void * opaque, const LGNetPacketView * packet, static void networkPacket(void * opaque, const LGNetPacketView * packet,
bool datagram) bool datagram)
{ {
(void)opaque; LG_Transport * this = opaque;
(void)packet; if (packet->envelope.service == LG_NET_SERVICE_INPUT &&
(void)datagram; !networkInputPacket(this->input, packet, datagram))
/* Media and service dispatch is added behind this boundary in the next {
* implementation stage. The connection still validates all wire framing. */ DEBUG_ERROR("Invalid network input message");
networkConnectionCancel(this->connection);
}
} }
static bool networkCreate(LG_Transport ** result) static bool networkCreate(LG_Transport ** result)
@@ -312,23 +336,30 @@ static bool networkCreate(LG_Transport ** result)
const NetworkConnectionParams params = const NetworkConnectionParams params =
{ {
.address = address, .address = address,
.port = port, .port = port,
.password = option_get_string("network", "password"), .password = option_get_string("network", "password"),
.knownHosts = &this->knownHosts, .knownHosts = &this->knownHosts,
.trustPrompt = networkTrustPrompt, .trustPrompt = networkTrustPrompt,
.trustCancel = networkCancelTrustPrompt, .trustCancel = networkCancelTrustPrompt,
.packet = networkPacket, .packet = networkPacket,
.state = networkConnectionState, .state = networkConnectionState,
.opaque = this, .capabilities = NETWORK_CAPABILITIES,
.capabilityCount = sizeof(NETWORK_CAPABILITIES) /
sizeof(NETWORK_CAPABILITIES[0]),
.opaque = this,
}; };
if (!networkConnectionCreate(&this->connection, &params)) if (!networkConnectionCreate(&this->connection, &params))
goto fail; goto fail;
if (!networkInputCreate(&this->input, this->connection))
goto fail;
*result = this; *result = this;
return true; return true;
fail: fail:
networkInputDestroy(&this->input);
networkConnectionDestroy(&this->connection);
if (this->frameEvent) if (this->frameEvent)
lgFreeEvent(this->frameEvent); lgFreeEvent(this->frameEvent);
if (this->promptIdle) if (this->promptIdle)
@@ -358,6 +389,7 @@ static void networkDestroy(LG_Transport ** transport)
LG_UNLOCK(this->stateLock); LG_UNLOCK(this->stateLock);
LG_UNLOCK(this->callbackLock); LG_UNLOCK(this->callbackLock);
networkInputDestroy(&this->input);
networkConnectionDestroy(&this->connection); networkConnectionDestroy(&this->connection);
lgFreeEvent(this->frameEvent); lgFreeEvent(this->frameEvent);
lgFreeEvent(this->promptIdle); lgFreeEvent(this->promptIdle);
@@ -385,6 +417,7 @@ static LG_TransportStatus networkConnect(LG_Transport * this,
static void networkDisconnect(LG_Transport * this) static void networkDisconnect(LG_Transport * this)
{ {
networkInputConnectionState(this->input, false);
networkConnectionDisconnect(this->connection); networkConnectionDisconnect(this->connection);
lgSignalEvent(this->frameEvent); lgSignalEvent(this->frameEvent);
} }
@@ -512,9 +545,8 @@ static const LG_VideoOps * networkGetVideoOps(LG_Transport * this)
static const LG_InputOps * networkGetInputOps(LG_Transport * this, static const LG_InputOps * networkGetInputOps(LG_Transport * this,
void ** opaque) void ** opaque)
{ {
(void)this; *opaque = this->input;
*opaque = NULL; return networkInputGetOps();
return NULL;
} }
static const LG_AudioOps * networkGetAudioOps(LG_Transport * this, static const LG_AudioOps * networkGetAudioOps(LG_Transport * this,

View File

@@ -72,6 +72,7 @@
<ClCompile Include="..\..\repos\LGProtocol\src\network\packet.c" /> <ClCompile Include="..\..\repos\LGProtocol\src\network\packet.c" />
<ClCompile Include="..\..\repos\LGProtocol\src\network\protocol.c" /> <ClCompile Include="..\..\repos\LGProtocol\src\network\protocol.c" />
<ClCompile Include="..\..\repos\LGProtocol\src\network\route.c" /> <ClCompile Include="..\..\repos\LGProtocol\src\network\route.c" />
<ClCompile Include="..\..\repos\LGProtocol\src\network\sequence.c" />
<ClCompile Include="..\..\repos\LGProtocol\src\network\services.c" /> <ClCompile Include="..\..\repos\LGProtocol\src\network\services.c" />
<ClCompile Include="..\..\repos\LGProtocol\src\network\stream.c" /> <ClCompile Include="..\..\repos\LGProtocol\src\network\stream.c" />
<ClCompile Include="..\..\repos\LGProtocol\src\network\wire.c" /> <ClCompile Include="..\..\repos\LGProtocol\src\network\wire.c" />

View File

@@ -33,6 +33,9 @@
<ClCompile Include="..\..\repos\LGProtocol\src\network\route.c"> <ClCompile Include="..\..\repos\LGProtocol\src\network\route.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\repos\LGProtocol\src\network\sequence.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\repos\LGProtocol\src\network\services.c"> <ClCompile Include="..\..\repos\LGProtocol\src\network\services.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>

File diff suppressed because it is too large Load Diff

View File

@@ -230,6 +230,35 @@ IInputSource * CNetworkTransport::Input()
return (m_config.services & TRANSPORT_SERVICE_INPUT) ? &m_input : nullptr; return (m_config.services & TRANSPORT_SERVICE_INPUT) ? &m_input : nullptr;
} }
bool CNetworkTransport::ServiceEnabled(LGNetService service) const
{
switch (service)
{
case LG_NET_SERVICE_RECOVERY:
case LG_NET_SERVICE_CURSOR:
return (m_config.services & TRANSPORT_SERVICE_CONTROL) != 0;
case LG_NET_SERVICE_INPUT:
return (m_config.services & TRANSPORT_SERVICE_INPUT) != 0;
case LG_NET_SERVICE_AUDIO:
return (m_config.services & TRANSPORT_SERVICE_AUDIO) != 0;
case LG_NET_SERVICE_CLIPBOARD:
case LG_NET_SERVICE_FILE:
return (m_config.services & TRANSPORT_SERVICE_CLIPBOARD) != 0;
case LG_NET_SERVICE_VIDEO:
return (m_config.services & TRANSPORT_SERVICE_FRAME) != 0;
case LG_NET_SERVICE_CORE:
case LG_NET_SERVICE_USB:
return false;
}
return false;
}
bool CNetworkTransport::ControlSnapshot( bool CNetworkTransport::ControlSnapshot(
NetworkControlSnapshot& state) const NetworkControlSnapshot& state) const
{ {

View File

@@ -93,6 +93,7 @@ public:
IInputSource * Input() override; IInputSource * Input() override;
const NetworkSettings& Settings() const { return m_settings; } const NetworkSettings& Settings() const { return m_settings; }
bool ServiceEnabled(LGNetService service) const;
bool ControlSnapshot(NetworkControlSnapshot& state) const; bool ControlSnapshot(NetworkControlSnapshot& state) const;
// The QUIC provider calls these only after authenticating a peer. Keeping // The QUIC provider calls these only after authenticating a peer. Keeping