diff --git a/client/transports/Network/connection.c b/client/transports/Network/connection.c index f659c0b1..8f28bc40 100644 --- a/client/transports/Network/connection.c +++ b/client/transports/Network/connection.c @@ -191,6 +191,7 @@ struct NetworkConnection bool authResultReceived; bool authKeyValid; bool capabilitiesComplete; + bool guestInfoReceived; bool connectFailed; uint32_t expectedCapabilities; uint32_t receivedCapabilities; @@ -263,6 +264,50 @@ static char * networkEndpoint(const char * address, uint16_t port) return endpoint; } +static bool networkGuestText(char * destination, size_t capacity, + const uint8_t * source, uint16_t length) +{ + if (!destination || !capacity || length >= capacity || + (length && (!source || memchr(source, 0, length)))) + return false; + + if (length) + memcpy(destination, source, length); + destination[length] = 0; + return true; +} + +static bool networkGuestOS(LGNetCoreGuestOS source, + LG_TransportGuestOS * destination) +{ + if (!destination) + return false; + + switch (source) + { + case LG_NET_CORE_GUEST_OS_LINUX: + *destination = LG_TRANSPORT_OS_LINUX; + return true; + + case LG_NET_CORE_GUEST_OS_BSD: + *destination = LG_TRANSPORT_OS_BSD; + return true; + + case LG_NET_CORE_GUEST_OS_OSX: + *destination = LG_TRANSPORT_OS_OSX; + return true; + + case LG_NET_CORE_GUEST_OS_WINDOWS: + *destination = LG_TRANSPORT_OS_WINDOWS; + return true; + + case LG_NET_CORE_GUEST_OS_OTHER: + *destination = LG_TRANSPORT_OS_OTHER; + return true; + } + return false; +} + static bool networkCapabilityOfferValid( const LGNetCapability * capability) { @@ -1086,6 +1131,7 @@ static bool networkConnectionReadyToActivateNL( return this->helloAcknowledged && this->authenticationComplete && this->capabilitiesComplete && + this->guestInfoReceived && this->receivedCapabilities == this->expectedCapabilities && networkConnectionRequiredCapabilitiesSelected(this); } @@ -1438,16 +1484,75 @@ static bool networkConnectionHandleCore(NetworkConnection * this, if (packet->envelope.flags != responseFlags || packet->envelope.requestID != NETWORK_HELLO_REQUEST_ID || packet->envelope.componentEpoch != 0 || - packet->envelope.sessionEpoch != sessionEpoch) + packet->envelope.sessionEpoch != sessionEpoch || + packet->envelope.serviceVersion != LG_NET_CORE_VERSION_CURRENT) return false; return networkConnectionHandleCapability(this, packet); + case LG_NET_CORE_MESSAGE_GUEST_INFO: + { + LGNetCoreGuestInfo info; + if (packet->envelope.flags != responseFlags || + packet->envelope.requestID != NETWORK_HELLO_REQUEST_ID || + packet->envelope.componentEpoch != 0 || + packet->envelope.sessionEpoch != sessionEpoch || + packet->envelope.serviceVersion != LG_NET_CORE_VERSION_CURRENT || + lgNetCoreGuestInfoDecode(&info, + packet->payload, packet->payloadLength) != LG_NET_PARSE_OK) + return false; + + LG_TransportSession guest = { 0 }; + if (!networkGuestOS(info.os, &guest.os) || + !networkGuestText(guest.version, sizeof(guest.version), + info.version, info.versionLength) || + !networkGuestText(guest.osName, sizeof(guest.osName), + info.osName, info.osNameLength) || + !networkGuestText(guest.capture, sizeof(guest.capture), + info.capture, info.captureLength) || + !networkGuestText(guest.cpuModel, sizeof(guest.cpuModel), + info.cpuModel, info.cpuModelLength)) + return false; + memcpy(guest.uuid, info.uuid, sizeof(guest.uuid)); + guest.uuidValid = networkBytesNonzero(guest.uuid, sizeof(guest.uuid)); + guest.cpus = info.processors; + guest.cores = info.cores; + guest.sockets = info.sockets; + + LG_LOCK(this->lock); + const bool valid = this->helloAcknowledged && + this->authenticationComplete && !this->capabilitiesComplete && + !this->guestInfoReceived && + this->receivedCapabilities == this->expectedCapabilities && + networkConnectionRequiredCapabilitiesSelected(this); + if (valid) + { + memcpy(this->session.version, guest.version, + sizeof(this->session.version)); + memcpy(this->session.uuid, guest.uuid, sizeof(this->session.uuid)); + memcpy(this->session.osName, guest.osName, + sizeof(this->session.osName)); + memcpy(this->session.capture, guest.capture, + sizeof(this->session.capture)); + memcpy(this->session.cpuModel, guest.cpuModel, + sizeof(this->session.cpuModel)); + this->session.uuidValid = guest.uuidValid; + this->session.os = guest.os; + this->session.cpus = guest.cpus; + this->session.cores = guest.cores; + this->session.sockets = guest.sockets; + this->guestInfoReceived = true; + } + LG_UNLOCK(this->lock); + return valid; + } + case LG_NET_CORE_MESSAGE_CAPABILITIES_DONE: { if (packet->envelope.flags != responseFlags || packet->envelope.requestID != NETWORK_HELLO_REQUEST_ID || packet->envelope.componentEpoch != 0 || packet->envelope.sessionEpoch != sessionEpoch || + packet->envelope.serviceVersion != LG_NET_CORE_VERSION_CURRENT || packet->payloadLength) return false; @@ -1455,6 +1560,7 @@ static bool networkConnectionHandleCore(NetworkConnection * this, LG_LOCK(this->lock); const bool valid = !this->capabilitiesComplete && this->helloAcknowledged && + this->guestInfoReceived && this->receivedCapabilities == this->expectedCapabilities && networkConnectionRequiredCapabilitiesSelected(this); this->capabilitiesComplete = valid; @@ -2689,6 +2795,7 @@ LG_TransportStatus networkConnectionConnect(NetworkConnection * this, this->helloAcknowledged = false; this->authenticationComplete = false; this->capabilitiesComplete = false; + this->guestInfoReceived = false; this->connectFailed = false; this->expectedCapabilities = 0; this->receivedCapabilities = 0; @@ -2713,8 +2820,6 @@ LG_TransportStatus networkConnectionConnect(NetworkConnection * this, memset(this->serviceMaxDatagram, 0, sizeof(this->serviceMaxDatagram)); lgNetStreamParserReset(&this->receiveParser); memset(&this->session, 0, sizeof(this->session)); - snprintf(this->session.version, sizeof(this->session.version), - "LG network protocol %u", LG_NET_PROTOCOL_VERSION_CURRENT); snprintf(this->session.name, sizeof(this->session.name), "%s", this->endpoint); this->session.os = LG_TRANSPORT_OS_OTHER; diff --git a/idd/LGIdd/transport/network/CNetworkServer.cpp b/idd/LGIdd/transport/network/CNetworkServer.cpp index 05df7834..0b27c579 100644 --- a/idd/LGIdd/transport/network/CNetworkServer.cpp +++ b/idd/LGIdd/transport/network/CNetworkServer.cpp @@ -27,6 +27,7 @@ #include "CDebug.h" #include "CSRWLock.h" +#include "platform/CPlatformInfo.h" #include "VersionInfo.h" #include #include @@ -174,6 +175,35 @@ namespace return false; } + size_t UTF8PrefixLength(const uint8_t * value, size_t length, + size_t maximum) + { + size_t prefix = (std::min)(length, maximum); + while (prefix && prefix < length && + (value[prefix] & UINT8_C(0xC0)) == UINT8_C(0x80)) + --prefix; + + return prefix; + } + + size_t ConsumeUTF8Field(const uint8_t * value, size_t length, + size_t fieldMaximum, size_t& remaining) + { + const size_t maximum = (std::min)(fieldMaximum, remaining); + const size_t result = UTF8PrefixLength(value, length, maximum); + remaining -= result; + return result; + } + + uint8_t TopologyCount(int count) + { + if (count <= 0) + return 0; + + return static_cast((std::min)(count, + static_cast(UINT8_MAX))); + } + bool MakeAddress(const std::wstring& source, uint16_t port, QUIC_ADDR& address) { @@ -2059,6 +2089,71 @@ retry: return sent; } + bool SendGuestInformation(Connection& connection, uint64_t requestID) + { + static const char CAPTURE[] = "Looking Glass IDD Driver"; + + uint32_t maxPayload; + { + CSRWSharedLock guard(connection.lock); + if (connection.closing) + return false; + maxPayload = connection.maxPayload; + } + if (maxPayload < LG_NET_CORE_GUEST_INFO_HEADER_WIRE_SIZE) + return false; + + const std::string& osName = CPlatformInfo::GetProductName(); + const std::string& cpuModel = CPlatformInfo::GetCPUModel(); + LGNetCoreGuestInfo info = {}; + memcpy(info.uuid, CPlatformInfo::GetUUID(), sizeof(info.uuid)); + info.os = LG_NET_CORE_GUEST_OS_WINDOWS; + info.processors = TopologyCount(CPlatformInfo::GetProcCount()); + info.cores = TopologyCount(CPlatformInfo::GetCoreCount()); + info.sockets = TopologyCount(CPlatformInfo::GetSocketCount()); + info.version = reinterpret_cast(LG_VERSION_STR); + info.osName = reinterpret_cast(osName.data()); + info.capture = reinterpret_cast(CAPTURE); + info.cpuModel = reinterpret_cast(cpuModel.data()); + + size_t remaining = maxPayload - + LG_NET_CORE_GUEST_INFO_HEADER_WIRE_SIZE; + info.versionLength = static_cast(ConsumeUTF8Field( + info.version, strlen(LG_VERSION_STR), + LG_NET_CORE_GUEST_MAX_VERSION_LENGTH, remaining)); + info.osNameLength = static_cast(ConsumeUTF8Field( + info.osName, osName.size(), LG_NET_CORE_GUEST_MAX_OS_NAME_LENGTH, + remaining)); + info.captureLength = static_cast(ConsumeUTF8Field( + info.capture, strlen(CAPTURE), LG_NET_CORE_GUEST_MAX_CAPTURE_LENGTH, + remaining)); + info.cpuModelLength = static_cast(ConsumeUTF8Field( + info.cpuModel, cpuModel.size(), + LG_NET_CORE_GUEST_MAX_CPU_MODEL_LENGTH, remaining)); + + const size_t payloadSize = lgNetCoreGuestInfoSize(&info); + if (!payloadSize || payloadSize > maxPayload) + return false; + + std::vector payload; + try + { + payload.resize(payloadSize); + } + catch (...) + { + return false; + } + + return lgNetCoreGuestInfoEncode( + payload.data(), payload.size(), &info) && + SendPacket(connection, LG_NET_SERVICE_CORE, + LG_NET_CORE_MESSAGE_GUEST_INFO, + LG_NET_ENVELOPE_RESPONSE | LG_NET_ENVELOPE_FINAL, + 0, requestID, payload.data(), + static_cast(payload.size())); + } + bool PublishCapabilities(Connection& connection) { LGNetCapability selected[NETWORK_SERVICE_COUNT] = {}; @@ -2148,6 +2243,8 @@ retry: return false; if (videoSelected && !video.PeerConnected(VideoPeer(connection))) return false; + if (!SendGuestInformation(connection, requestID)) + return false; if (!SendPacket(connection, LG_NET_SERVICE_CORE, LG_NET_CORE_MESSAGE_CAPABILITIES_DONE, LG_NET_ENVELOPE_RESPONSE | LG_NET_ENVELOPE_FINAL, diff --git a/repos/LGProtocol b/repos/LGProtocol index 82f05ec6..a2a41197 160000 --- a/repos/LGProtocol +++ b/repos/LGProtocol @@ -1 +1 @@ -Subproject commit 82f05ec6645f000b460ed6182da106b5c571b5a8 +Subproject commit a2a41197d00129c21fd6e7d40968837854f39103