mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-11-12 14:57:20 +00:00
[client] network: add QUIC transport foundation
This commit is contained in:
@@ -20,6 +20,9 @@ endfunction()
|
||||
|
||||
# Add/remove transports here!
|
||||
add_transport(LGMP)
|
||||
if(ENABLE_NETWORK)
|
||||
add_transport(Network)
|
||||
endif()
|
||||
if(ENABLE_SPICE)
|
||||
add_transport(SPICE)
|
||||
endif()
|
||||
|
||||
47
client/transports/Network/CMakeLists.txt
Normal file
47
client/transports/Network/CMakeLists.txt
Normal file
@@ -0,0 +1,47 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(transport_Network LANGUAGES C)
|
||||
|
||||
if(NOT TARGET msquic::msquic)
|
||||
find_package(msquic CONFIG REQUIRED)
|
||||
endif()
|
||||
|
||||
set(TRANSPORT_NETWORK_SOURCES
|
||||
connection.c
|
||||
known_hosts.c
|
||||
network.c
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND TRANSPORT_NETWORK_SOURCES
|
||||
platform/windows/fingerprint.c
|
||||
platform/windows/platform.c
|
||||
)
|
||||
else()
|
||||
find_package(OpenSSL REQUIRED COMPONENTS Crypto)
|
||||
list(APPEND TRANSPORT_NETWORK_SOURCES
|
||||
platform/linux/fingerprint.c
|
||||
platform/linux/platform.c
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(transport_Network STATIC ${TRANSPORT_NETWORK_SOURCES})
|
||||
|
||||
target_include_directories(transport_Network PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../src
|
||||
)
|
||||
|
||||
target_link_libraries(transport_Network PRIVATE
|
||||
lg_common
|
||||
msquic::msquic
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(transport_Network PRIVATE
|
||||
bcrypt
|
||||
crypt32
|
||||
)
|
||||
else()
|
||||
target_link_libraries(transport_Network PRIVATE
|
||||
OpenSSL::Crypto
|
||||
)
|
||||
endif()
|
||||
1203
client/transports/Network/connection.c
Normal file
1203
client/transports/Network/connection.c
Normal file
File diff suppressed because it is too large
Load Diff
73
client/transports/Network/connection.h
Normal file
73
client/transports/Network/connection.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* 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 "known_hosts.h"
|
||||
|
||||
#include "interface/transport.h"
|
||||
|
||||
#include "common/network/protocol.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct NetworkConnection NetworkConnection;
|
||||
|
||||
typedef void (*NetworkTrustDecisionFn)(void * opaque, bool trusted);
|
||||
typedef bool (*NetworkTrustPromptFn)(void * opaque, const char * endpoint,
|
||||
const char * fingerprint, NetworkTrustDecisionFn decision,
|
||||
void * decisionOpaque);
|
||||
typedef void (*NetworkTrustCancelFn)(void * opaque);
|
||||
/* The packet view and payload are borrowed for the duration of the callback. */
|
||||
typedef void (*NetworkPacketFn)(void * opaque,
|
||||
const LGNetPacketView * packet, bool datagram);
|
||||
typedef void (*NetworkConnectionStateFn)(void * opaque, bool connected,
|
||||
LG_TransportStatus reason);
|
||||
|
||||
typedef struct NetworkConnectionParams
|
||||
{
|
||||
const char * address;
|
||||
uint16_t port;
|
||||
const char * password;
|
||||
NetworkKnownHosts * knownHosts;
|
||||
NetworkTrustPromptFn trustPrompt;
|
||||
NetworkTrustCancelFn trustCancel;
|
||||
NetworkPacketFn packet;
|
||||
NetworkConnectionStateFn state;
|
||||
void * opaque;
|
||||
}
|
||||
NetworkConnectionParams;
|
||||
|
||||
bool networkConnectionCreate(NetworkConnection ** connection,
|
||||
const NetworkConnectionParams * params);
|
||||
void networkConnectionDestroy(NetworkConnection ** connection);
|
||||
|
||||
LG_TransportStatus networkConnectionConnect(NetworkConnection * connection,
|
||||
LG_TransportSession * session, LG_TransportCancelledFn cancelled,
|
||||
void * cancelledOpaque);
|
||||
void networkConnectionCancel(NetworkConnection * connection);
|
||||
void networkConnectionDisconnect(NetworkConnection * connection);
|
||||
bool networkConnectionValid(const NetworkConnection * connection);
|
||||
|
||||
LG_TransportStatus networkConnectionSend(NetworkConnection * connection,
|
||||
LGNetService service, uint16_t messageType, uint16_t serviceVersion,
|
||||
LGNetEnvelopeFlags flags, uint64_t componentEpoch, uint64_t requestID,
|
||||
const void * payload, uint32_t payloadLength);
|
||||
30
client/transports/Network/fingerprint.h
Normal file
30
client/transports/Network/fingerprint.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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 <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define NETWORK_FINGERPRINT_SIZE 32U
|
||||
|
||||
bool networkFingerprintSHA256(const uint8_t * data, size_t size,
|
||||
uint8_t fingerprint[NETWORK_FINGERPRINT_SIZE]);
|
||||
254
client/transports/Network/known_hosts.c
Normal file
254
client/transports/Network/known_hosts.c
Normal file
@@ -0,0 +1,254 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "known_hosts.h"
|
||||
#include "platform.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/filesystem.h"
|
||||
#include "common/paths.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define NETWORK_KNOWN_HOSTS_FILE "network_known_hosts"
|
||||
#define NETWORK_KNOWN_HOST_LINE 1024U
|
||||
|
||||
static char * knownHostsPath(const char * suffix)
|
||||
{
|
||||
const char * directory = lgConfigDir();
|
||||
const size_t dirLength = strlen(directory);
|
||||
const size_t nameLength = strlen(NETWORK_KNOWN_HOSTS_FILE);
|
||||
const size_t suffixLength = strlen(suffix);
|
||||
char * path = malloc(
|
||||
dirLength + 1U + nameLength + suffixLength + 1U);
|
||||
if (!path)
|
||||
return NULL;
|
||||
|
||||
snprintf(path, dirLength + 1U + nameLength + suffixLength + 1U,
|
||||
"%s/%s%s", directory, NETWORK_KNOWN_HOSTS_FILE, suffix);
|
||||
return path;
|
||||
}
|
||||
|
||||
static bool validField(const char * value)
|
||||
{
|
||||
if (!value || !*value)
|
||||
return false;
|
||||
|
||||
for (const unsigned char * c = (const unsigned char *)value; *c; ++c)
|
||||
if (*c == '\r' || *c == '\n' || *c == '\t')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool completeLine(const char * line, FILE * file)
|
||||
{
|
||||
const size_t length = strlen(line);
|
||||
return (length && line[length - 1U] == '\n') || feof(file);
|
||||
}
|
||||
|
||||
static bool writeLine(FILE * file, const char * line)
|
||||
{
|
||||
const size_t length = strlen(line);
|
||||
if (!length)
|
||||
return false;
|
||||
return fputs(line, file) >= 0 &&
|
||||
(line[length - 1U] == '\n' || fputc('\n', file) != EOF);
|
||||
}
|
||||
|
||||
bool networkKnownHostsInit(NetworkKnownHosts * knownHosts)
|
||||
{
|
||||
if (!knownHosts)
|
||||
return false;
|
||||
|
||||
memset(knownHosts, 0, sizeof(*knownHosts));
|
||||
LG_LOCK_INIT(knownHosts->lock);
|
||||
knownHosts->path = knownHostsPath("");
|
||||
return knownHosts->path != NULL;
|
||||
}
|
||||
|
||||
void networkKnownHostsFree(NetworkKnownHosts * knownHosts)
|
||||
{
|
||||
if (!knownHosts)
|
||||
return;
|
||||
|
||||
LG_LOCK_FREE(knownHosts->lock);
|
||||
free(knownHosts->path);
|
||||
knownHosts->path = NULL;
|
||||
}
|
||||
|
||||
NetworkKnownHostResult networkKnownHostsCheck(NetworkKnownHosts * knownHosts,
|
||||
const char * endpoint, const char * fingerprint)
|
||||
{
|
||||
if (!knownHosts || !knownHosts->path || !validField(endpoint) ||
|
||||
!validField(fingerprint))
|
||||
return NETWORK_KNOWN_HOST_ERROR;
|
||||
|
||||
LG_LOCK(knownHosts->lock);
|
||||
FILE * file = lgOpenFile(knownHosts->path, "r");
|
||||
if (!file)
|
||||
{
|
||||
const LGFileType type = lgPathType(knownHosts->path);
|
||||
LG_UNLOCK(knownHosts->lock);
|
||||
return type == LG_FILE_TYPE_MISSING ?
|
||||
NETWORK_KNOWN_HOST_UNKNOWN : NETWORK_KNOWN_HOST_ERROR;
|
||||
}
|
||||
|
||||
NetworkKnownHostResult result = NETWORK_KNOWN_HOST_UNKNOWN;
|
||||
char line[NETWORK_KNOWN_HOST_LINE];
|
||||
while (fgets(line, sizeof(line), file))
|
||||
{
|
||||
if (!completeLine(line, file))
|
||||
{
|
||||
result = NETWORK_KNOWN_HOST_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
char * separator = strchr(line, '\t');
|
||||
if (!separator)
|
||||
continue;
|
||||
|
||||
*separator++ = '\0';
|
||||
separator[strcspn(separator, "\r\n")] = '\0';
|
||||
if (strcmp(line, endpoint) != 0)
|
||||
continue;
|
||||
|
||||
if (strcmp(separator, fingerprint) != 0)
|
||||
{
|
||||
result = NETWORK_KNOWN_HOST_CHANGED;
|
||||
break;
|
||||
}
|
||||
result = NETWORK_KNOWN_HOST_MATCH;
|
||||
}
|
||||
|
||||
if (ferror(file))
|
||||
result = NETWORK_KNOWN_HOST_ERROR;
|
||||
|
||||
fclose(file);
|
||||
LG_UNLOCK(knownHosts->lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool rewriteKnownHosts(NetworkKnownHosts * knownHosts,
|
||||
const char * endpoint, const char * fingerprint)
|
||||
{
|
||||
if (!knownHosts || !knownHosts->path || !validField(endpoint) ||
|
||||
(fingerprint && !validField(fingerprint)))
|
||||
return false;
|
||||
|
||||
char * temporary = knownHostsPath(".tmp");
|
||||
if (!temporary)
|
||||
return false;
|
||||
|
||||
LG_LOCK(knownHosts->lock);
|
||||
FILE * source = lgOpenFile(knownHosts->path, "r");
|
||||
FILE * target = lgOpenFile(temporary, "w");
|
||||
bool found = false;
|
||||
bool result = target &&
|
||||
(source || lgPathType(knownHosts->path) == LG_FILE_TYPE_MISSING);
|
||||
char line[NETWORK_KNOWN_HOST_LINE];
|
||||
while (result && source && fgets(line, sizeof(line), source))
|
||||
{
|
||||
if (!completeLine(line, source))
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
char * separator = strchr(line, '\t');
|
||||
if (!separator)
|
||||
{
|
||||
result = writeLine(target, line);
|
||||
continue;
|
||||
}
|
||||
|
||||
*separator++ = '\0';
|
||||
if (strcmp(line, endpoint) != 0)
|
||||
{
|
||||
*--separator = '\t';
|
||||
result = writeLine(target, line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!fingerprint)
|
||||
continue;
|
||||
|
||||
separator[strcspn(separator, "\r\n")] = '\0';
|
||||
if (strcmp(separator, fingerprint) != 0)
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
found = true;
|
||||
result = fprintf(target, "%s\t%s\n", endpoint, fingerprint) > 0;
|
||||
}
|
||||
|
||||
if (source && ferror(source))
|
||||
result = false;
|
||||
if (result && fingerprint && !found)
|
||||
result = fprintf(target, "%s\t%s\n", endpoint, fingerprint) > 0;
|
||||
|
||||
if (target)
|
||||
{
|
||||
result = result && fflush(target) == 0;
|
||||
result = fclose(target) == 0 && result;
|
||||
}
|
||||
if (source)
|
||||
fclose(source);
|
||||
|
||||
if (result)
|
||||
result = networkPlatformReplaceFile(temporary, knownHosts->path);
|
||||
|
||||
if (!result)
|
||||
lgDeleteFile(temporary);
|
||||
LG_UNLOCK(knownHosts->lock);
|
||||
free(temporary);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool networkKnownHostsRemember(NetworkKnownHosts * knownHosts,
|
||||
const char * endpoint, const char * fingerprint)
|
||||
{
|
||||
const bool result = rewriteKnownHosts(
|
||||
knownHosts, endpoint, fingerprint);
|
||||
if (!result)
|
||||
DEBUG_ERROR("Failed to persist the network server fingerprint");
|
||||
return result;
|
||||
}
|
||||
|
||||
bool networkKnownHostsForget(NetworkKnownHosts * knownHosts,
|
||||
const char * endpoint)
|
||||
{
|
||||
return rewriteKnownHosts(knownHosts, endpoint, NULL);
|
||||
}
|
||||
|
||||
void networkFingerprintFormat(
|
||||
const uint8_t fingerprint[NETWORK_FINGERPRINT_SIZE],
|
||||
char text[NETWORK_FINGERPRINT_TEXT_SIZE])
|
||||
{
|
||||
static const char digits[] = "0123456789abcdef";
|
||||
for (size_t i = 0; i < NETWORK_FINGERPRINT_SIZE; ++i)
|
||||
{
|
||||
text[i * 2U ] = digits[fingerprint[i] >> 4];
|
||||
text[i * 2U + 1] = digits[fingerprint[i] & 0xf];
|
||||
}
|
||||
text[NETWORK_FINGERPRINT_TEXT_SIZE - 1U] = '\0';
|
||||
}
|
||||
59
client/transports/Network/known_hosts.h
Normal file
59
client/transports/Network/known_hosts.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 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 "fingerprint.h"
|
||||
|
||||
#include "common/locking.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define NETWORK_FINGERPRINT_TEXT_SIZE (NETWORK_FINGERPRINT_SIZE * 2U + 1U)
|
||||
|
||||
typedef enum NetworkKnownHostResult
|
||||
{
|
||||
NETWORK_KNOWN_HOST_UNKNOWN,
|
||||
NETWORK_KNOWN_HOST_MATCH,
|
||||
NETWORK_KNOWN_HOST_CHANGED,
|
||||
NETWORK_KNOWN_HOST_ERROR,
|
||||
}
|
||||
NetworkKnownHostResult;
|
||||
|
||||
typedef struct NetworkKnownHosts
|
||||
{
|
||||
LG_Lock lock;
|
||||
char * path;
|
||||
}
|
||||
NetworkKnownHosts;
|
||||
|
||||
bool networkKnownHostsInit(NetworkKnownHosts * knownHosts);
|
||||
void networkKnownHostsFree(NetworkKnownHosts * knownHosts);
|
||||
NetworkKnownHostResult networkKnownHostsCheck(NetworkKnownHosts * knownHosts,
|
||||
const char * endpoint, const char * fingerprint);
|
||||
bool networkKnownHostsRemember(NetworkKnownHosts * knownHosts,
|
||||
const char * endpoint, const char * fingerprint);
|
||||
bool networkKnownHostsForget(NetworkKnownHosts * knownHosts,
|
||||
const char * endpoint);
|
||||
|
||||
void networkFingerprintFormat(
|
||||
const uint8_t fingerprint[NETWORK_FINGERPRINT_SIZE],
|
||||
char text[NETWORK_FINGERPRINT_TEXT_SIZE]);
|
||||
569
client/transports/Network/network.c
Normal file
569
client/transports/Network/network.c
Normal file
@@ -0,0 +1,569 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "network.h"
|
||||
#include "connection.h"
|
||||
#include "known_hosts.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "interface/renderer.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/event.h"
|
||||
#include "common/locking.h"
|
||||
#include "common/network/protocol.h"
|
||||
#include "common/option.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define NETWORK_ADDRESS_MAX 255U
|
||||
#define NETWORK_ENDPOINT_TEXT_SIZE (NETWORK_ADDRESS_MAX + 9U)
|
||||
|
||||
struct NetworkTrustPrompt
|
||||
{
|
||||
MsgBoxHandle message;
|
||||
NetworkTrustDecisionFn decision;
|
||||
void * decisionOpaque;
|
||||
};
|
||||
|
||||
struct LG_Transport
|
||||
{
|
||||
NetworkConnection * connection;
|
||||
NetworkKnownHosts knownHosts;
|
||||
LGEvent * frameEvent;
|
||||
LGEvent * promptIdle;
|
||||
|
||||
LG_Lock callbackLock;
|
||||
LG_Lock stateLock;
|
||||
LG_Lock promptLock;
|
||||
|
||||
LG_VideoStatus videoStatus;
|
||||
LG_VideoStatusFn videoStatusFn;
|
||||
void * videoStatusOpaque;
|
||||
|
||||
bool rendererAttached;
|
||||
bool promptCallbackActive;
|
||||
struct NetworkTrustPrompt prompt;
|
||||
};
|
||||
|
||||
static bool networkAddressValidate(struct Option * option,
|
||||
const char ** error)
|
||||
{
|
||||
const char * address = option->value.x_string;
|
||||
if (address && *address && strlen(address) <= NETWORK_ADDRESS_MAX)
|
||||
{
|
||||
for (const unsigned char * c = (const unsigned char *)address; *c; ++c)
|
||||
if (*c < 0x20U || *c == 0x7fU)
|
||||
goto invalid;
|
||||
return true;
|
||||
}
|
||||
|
||||
invalid:
|
||||
*error = "The network address must be 1-255 characters without controls";
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool networkPortValidate(struct Option * option, const char ** error)
|
||||
{
|
||||
if (option->value.x_int > 0 && option->value.x_int <= UINT16_MAX)
|
||||
return true;
|
||||
|
||||
*error = "The network port must be between 1 and 65535";
|
||||
return false;
|
||||
}
|
||||
|
||||
static void networkSetup(void)
|
||||
{
|
||||
static struct Option options[] =
|
||||
{
|
||||
{
|
||||
.module = "network",
|
||||
.name = "address",
|
||||
.description = "Network server address",
|
||||
.type = OPTION_TYPE_STRING,
|
||||
.value.x_string = "127.0.0.1",
|
||||
.validator = networkAddressValidate,
|
||||
},
|
||||
{
|
||||
.module = "network",
|
||||
.name = "port",
|
||||
.description = "Network server UDP port",
|
||||
.type = OPTION_TYPE_INT,
|
||||
.value.x_int = LG_NET_DEFAULT_PORT,
|
||||
.validator = networkPortValidate,
|
||||
},
|
||||
{
|
||||
.module = "network",
|
||||
.name = "password",
|
||||
.description =
|
||||
"Reserved network password (empty uses no authentication)",
|
||||
.type = OPTION_TYPE_STRING,
|
||||
.value.x_string = NULL,
|
||||
},
|
||||
{
|
||||
.module = "network",
|
||||
.name = "forgetCertificate",
|
||||
.description = "Forget the saved certificate for this server",
|
||||
.type = OPTION_TYPE_BOOL,
|
||||
.value.x_bool = false,
|
||||
},
|
||||
{0}
|
||||
};
|
||||
|
||||
option_register(options);
|
||||
}
|
||||
|
||||
static void networkTrustDecision(bool trusted, void * opaque)
|
||||
{
|
||||
LG_Transport * this = opaque;
|
||||
NetworkTrustDecisionFn decision;
|
||||
void * decisionOpaque;
|
||||
|
||||
LG_LOCK(this->promptLock);
|
||||
decision = this->prompt.decision;
|
||||
decisionOpaque = this->prompt.decisionOpaque;
|
||||
this->prompt.message = NULL;
|
||||
this->prompt.decision = NULL;
|
||||
this->prompt.decisionOpaque = NULL;
|
||||
if (decision)
|
||||
{
|
||||
this->promptCallbackActive = true;
|
||||
lgResetEvent(this->promptIdle);
|
||||
}
|
||||
LG_UNLOCK(this->promptLock);
|
||||
|
||||
if (decision)
|
||||
decision(decisionOpaque, trusted);
|
||||
|
||||
LG_LOCK(this->promptLock);
|
||||
this->promptCallbackActive = false;
|
||||
lgSignalEvent(this->promptIdle);
|
||||
LG_UNLOCK(this->promptLock);
|
||||
}
|
||||
|
||||
static bool networkTrustPrompt(void * opaque, const char * endpoint,
|
||||
const char * fingerprint, NetworkTrustDecisionFn decision,
|
||||
void * decisionOpaque)
|
||||
{
|
||||
LG_Transport * this = opaque;
|
||||
|
||||
LG_LOCK(this->promptLock);
|
||||
if (this->prompt.message || this->prompt.decision ||
|
||||
this->promptCallbackActive)
|
||||
{
|
||||
LG_UNLOCK(this->promptLock);
|
||||
return false;
|
||||
}
|
||||
|
||||
this->prompt.decision = decision;
|
||||
this->prompt.decisionOpaque = decisionOpaque;
|
||||
this->prompt.message = app_confirmMsgBox(
|
||||
"Trust network server?", networkTrustDecision, this,
|
||||
"The identity of %s has not been seen before.\n\n"
|
||||
"SHA-256 fingerprint:\n%s\n\n"
|
||||
"Trust and remember this server?", endpoint, fingerprint);
|
||||
const bool queued = this->prompt.message != NULL;
|
||||
if (!queued)
|
||||
{
|
||||
this->prompt.decision = NULL;
|
||||
this->prompt.decisionOpaque = NULL;
|
||||
}
|
||||
LG_UNLOCK(this->promptLock);
|
||||
return queued;
|
||||
}
|
||||
|
||||
static void networkCancelTrustPrompt(void * opaque)
|
||||
{
|
||||
LG_Transport * this = opaque;
|
||||
MsgBoxHandle message;
|
||||
|
||||
LG_LOCK(this->promptLock);
|
||||
message = this->prompt.message;
|
||||
this->prompt.message = NULL;
|
||||
this->prompt.decision = NULL;
|
||||
this->prompt.decisionOpaque = NULL;
|
||||
LG_UNLOCK(this->promptLock);
|
||||
|
||||
if (message)
|
||||
app_msgBoxClose(message);
|
||||
lgWaitEvent(this->promptIdle, TIMEOUT_INFINITE);
|
||||
LG_LOCK(this->promptLock);
|
||||
LG_UNLOCK(this->promptLock);
|
||||
}
|
||||
|
||||
static void networkNotifyVideoStatus(LG_Transport * this)
|
||||
{
|
||||
LG_VideoStatusFn callback;
|
||||
void * opaque;
|
||||
LG_VideoStatus status;
|
||||
|
||||
LG_LOCK(this->callbackLock);
|
||||
LG_LOCK(this->stateLock);
|
||||
callback = this->videoStatusFn;
|
||||
opaque = this->videoStatusOpaque;
|
||||
status = this->videoStatus;
|
||||
LG_UNLOCK(this->stateLock);
|
||||
|
||||
if (callback)
|
||||
callback(opaque, &status);
|
||||
LG_UNLOCK(this->callbackLock);
|
||||
}
|
||||
|
||||
static uint64_t networkNextEpoch(uint64_t epoch)
|
||||
{
|
||||
++epoch;
|
||||
return epoch ? epoch : 1U;
|
||||
}
|
||||
|
||||
static void networkSetUnavailable(LG_VideoComponentStatus * status,
|
||||
LG_TransportStatus reason)
|
||||
{
|
||||
if (status->available)
|
||||
status->epoch = networkNextEpoch(status->epoch);
|
||||
status->available = false;
|
||||
status->reason = reason;
|
||||
}
|
||||
|
||||
static void networkConnectionState(void * opaque, bool connected,
|
||||
LG_TransportStatus reason)
|
||||
{
|
||||
LG_Transport * this = opaque;
|
||||
const LG_TransportStatus status = connected ?
|
||||
LG_TRANSPORT_UNAVAILABLE : reason;
|
||||
|
||||
LG_LOCK(this->stateLock);
|
||||
networkSetUnavailable(&this->videoStatus.frame, status);
|
||||
networkSetUnavailable(&this->videoStatus.pointer, status);
|
||||
LG_UNLOCK(this->stateLock);
|
||||
|
||||
lgSignalEvent(this->frameEvent);
|
||||
networkNotifyVideoStatus(this);
|
||||
}
|
||||
|
||||
static void networkPacket(void * opaque, const LGNetPacketView * packet,
|
||||
bool datagram)
|
||||
{
|
||||
(void)opaque;
|
||||
(void)packet;
|
||||
(void)datagram;
|
||||
/* Media and service dispatch is added behind this boundary in the next
|
||||
* implementation stage. The connection still validates all wire framing. */
|
||||
}
|
||||
|
||||
static bool networkCreate(LG_Transport ** result)
|
||||
{
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
LG_Transport * this = calloc(1, sizeof(*this));
|
||||
if (!this)
|
||||
return false;
|
||||
|
||||
LG_LOCK_INIT(this->callbackLock);
|
||||
LG_LOCK_INIT(this->stateLock);
|
||||
LG_LOCK_INIT(this->promptLock);
|
||||
|
||||
this->videoStatus.frame.epoch = 1;
|
||||
this->videoStatus.frame.reason = LG_TRANSPORT_DISCONNECTED;
|
||||
this->videoStatus.pointer.epoch = 1;
|
||||
this->videoStatus.pointer.reason = LG_TRANSPORT_DISCONNECTED;
|
||||
if (!networkKnownHostsInit(&this->knownHosts))
|
||||
goto fail;
|
||||
|
||||
this->frameEvent = lgCreateEvent(true, 0);
|
||||
this->promptIdle = lgCreateEvent(false, 0);
|
||||
if (!this->frameEvent || !this->promptIdle ||
|
||||
!lgSignalEvent(this->promptIdle))
|
||||
goto fail;
|
||||
|
||||
const char * address = option_get_string("network", "address");
|
||||
const uint16_t port = (uint16_t)option_get_int("network", "port");
|
||||
char endpoint[NETWORK_ENDPOINT_TEXT_SIZE];
|
||||
if (!address)
|
||||
goto fail;
|
||||
snprintf(endpoint, sizeof(endpoint), "[%s]:%u", address, port);
|
||||
if (option_get_bool("network", "forgetCertificate") &&
|
||||
!networkKnownHostsForget(&this->knownHosts, endpoint))
|
||||
{
|
||||
DEBUG_ERROR("Failed to forget the network server certificate");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
const NetworkConnectionParams params =
|
||||
{
|
||||
.address = address,
|
||||
.port = port,
|
||||
.password = option_get_string("network", "password"),
|
||||
.knownHosts = &this->knownHosts,
|
||||
.trustPrompt = networkTrustPrompt,
|
||||
.trustCancel = networkCancelTrustPrompt,
|
||||
.packet = networkPacket,
|
||||
.state = networkConnectionState,
|
||||
.opaque = this,
|
||||
};
|
||||
if (!networkConnectionCreate(&this->connection, ¶ms))
|
||||
goto fail;
|
||||
|
||||
*result = this;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
if (this->frameEvent)
|
||||
lgFreeEvent(this->frameEvent);
|
||||
if (this->promptIdle)
|
||||
lgFreeEvent(this->promptIdle);
|
||||
networkKnownHostsFree(&this->knownHosts);
|
||||
LG_LOCK_FREE(this->promptLock);
|
||||
LG_LOCK_FREE(this->stateLock);
|
||||
LG_LOCK_FREE(this->callbackLock);
|
||||
free(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void networkDisconnect(LG_Transport * this);
|
||||
|
||||
static void networkDestroy(LG_Transport ** transport)
|
||||
{
|
||||
if (!transport || !*transport)
|
||||
return;
|
||||
|
||||
LG_Transport * this = *transport;
|
||||
networkDisconnect(this);
|
||||
|
||||
LG_LOCK(this->callbackLock);
|
||||
LG_LOCK(this->stateLock);
|
||||
this->videoStatusFn = NULL;
|
||||
this->videoStatusOpaque = NULL;
|
||||
LG_UNLOCK(this->stateLock);
|
||||
LG_UNLOCK(this->callbackLock);
|
||||
|
||||
networkConnectionDestroy(&this->connection);
|
||||
lgFreeEvent(this->frameEvent);
|
||||
lgFreeEvent(this->promptIdle);
|
||||
networkKnownHostsFree(&this->knownHosts);
|
||||
LG_LOCK_FREE(this->promptLock);
|
||||
LG_LOCK_FREE(this->stateLock);
|
||||
LG_LOCK_FREE(this->callbackLock);
|
||||
free(this);
|
||||
*transport = NULL;
|
||||
}
|
||||
|
||||
static LG_TransportStatus networkConnectCancellable(LG_Transport * this,
|
||||
LG_TransportSession * session, LG_TransportCancelledFn cancelled,
|
||||
void * opaque)
|
||||
{
|
||||
return networkConnectionConnect(
|
||||
this->connection, session, cancelled, opaque);
|
||||
}
|
||||
|
||||
static LG_TransportStatus networkConnect(LG_Transport * this,
|
||||
LG_TransportSession * session)
|
||||
{
|
||||
return networkConnectCancellable(this, session, NULL, NULL);
|
||||
}
|
||||
|
||||
static void networkDisconnect(LG_Transport * this)
|
||||
{
|
||||
networkConnectionDisconnect(this->connection);
|
||||
lgSignalEvent(this->frameEvent);
|
||||
}
|
||||
|
||||
static bool networkSessionValid(LG_Transport * this)
|
||||
{
|
||||
return networkConnectionValid(this->connection);
|
||||
}
|
||||
|
||||
static void networkSetStatusListener(LG_Transport * this,
|
||||
LG_VideoStatusFn callback, void * opaque)
|
||||
{
|
||||
LG_VideoStatus status;
|
||||
|
||||
LG_LOCK(this->callbackLock);
|
||||
LG_LOCK(this->stateLock);
|
||||
this->videoStatusFn = callback;
|
||||
this->videoStatusOpaque = opaque;
|
||||
status = this->videoStatus;
|
||||
LG_UNLOCK(this->stateLock);
|
||||
|
||||
if (callback)
|
||||
callback(opaque, &status);
|
||||
LG_UNLOCK(this->callbackLock);
|
||||
}
|
||||
|
||||
static bool networkSupportsDMA(LG_Transport * this)
|
||||
{
|
||||
(void)this;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool networkAttachRenderer(LG_Transport * this,
|
||||
const LG_RendererInterop * interop)
|
||||
{
|
||||
const size_t requiredSize = offsetof(LG_RendererInterop,
|
||||
egl.sharedTextureImport) + sizeof(interop->egl.sharedTextureImport);
|
||||
if (!interop ||
|
||||
interop->version < LG_RENDERER_INTEROP_EGL_TEXTURE_VERSION ||
|
||||
interop->size < requiredSize ||
|
||||
interop->type != LG_RENDERER_INTEROP_EGL ||
|
||||
!interop->egl.display || !interop->egl.config ||
|
||||
!interop->egl.shareContext || !interop->egl.sharedTextureImport)
|
||||
{
|
||||
DEBUG_ERROR("The network transport requires EGL shared textures");
|
||||
return false;
|
||||
}
|
||||
|
||||
this->rendererAttached = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void networkDetachRenderer(LG_Transport * this)
|
||||
{
|
||||
this->rendererAttached = false;
|
||||
}
|
||||
|
||||
static LG_TransportStatus networkNextFrame(LG_Transport * this, bool useDMA,
|
||||
LG_TransportFrame * frame)
|
||||
{
|
||||
(void)useDMA;
|
||||
(void)frame;
|
||||
|
||||
if (!this->rendererAttached)
|
||||
return LG_TRANSPORT_ERROR;
|
||||
if (!networkSessionValid(this))
|
||||
return LG_TRANSPORT_DISCONNECTED;
|
||||
|
||||
lgWaitEvent(this->frameEvent, 100);
|
||||
return networkSessionValid(this) ?
|
||||
LG_TRANSPORT_UNAVAILABLE : LG_TRANSPORT_DISCONNECTED;
|
||||
}
|
||||
|
||||
static void networkGetFrameTiming(LG_Transport * this,
|
||||
const LG_TransportFrame * frame, LG_TransportFrameTiming * timing)
|
||||
{
|
||||
(void)this;
|
||||
(void)frame;
|
||||
memset(timing, 0, sizeof(*timing));
|
||||
}
|
||||
|
||||
static void networkReleaseFrame(LG_Transport * this,
|
||||
LG_TransportFrame * frame)
|
||||
{
|
||||
(void)this;
|
||||
(void)frame;
|
||||
}
|
||||
|
||||
static void networkCancelFrameWait(LG_Transport * this)
|
||||
{
|
||||
lgSignalEvent(this->frameEvent);
|
||||
}
|
||||
|
||||
static void networkStopFrame(LG_Transport * this)
|
||||
{
|
||||
lgSignalEvent(this->frameEvent);
|
||||
}
|
||||
|
||||
static const LG_FrameOps networkFrameOps =
|
||||
{
|
||||
.setStatusListener = networkSetStatusListener,
|
||||
.supportsDMA = networkSupportsDMA,
|
||||
.attachRenderer = networkAttachRenderer,
|
||||
.detachRenderer = networkDetachRenderer,
|
||||
.nextFrame = networkNextFrame,
|
||||
.getFrameTiming = networkGetFrameTiming,
|
||||
.releaseFrame = networkReleaseFrame,
|
||||
.cancelFrameWait = networkCancelFrameWait,
|
||||
.stopFrame = networkStopFrame,
|
||||
};
|
||||
|
||||
static const LG_VideoOps networkVideoOps =
|
||||
{
|
||||
.name = "network",
|
||||
.type = LG_VIDEO_TYPE_FRAME,
|
||||
.frame = &networkFrameOps,
|
||||
};
|
||||
|
||||
static const LG_VideoOps * networkGetVideoOps(LG_Transport * this)
|
||||
{
|
||||
(void)this;
|
||||
return &networkVideoOps;
|
||||
}
|
||||
|
||||
static const LG_InputOps * networkGetInputOps(LG_Transport * this,
|
||||
void ** opaque)
|
||||
{
|
||||
(void)this;
|
||||
*opaque = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const LG_AudioOps * networkGetAudioOps(LG_Transport * this,
|
||||
void ** opaque)
|
||||
{
|
||||
(void)this;
|
||||
*opaque = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const LG_ClipboardOps * networkGetClipboardOps(LG_Transport * this,
|
||||
void ** opaque)
|
||||
{
|
||||
(void)this;
|
||||
*opaque = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static LG_TransportStatus networkSendControl(LG_Transport * this,
|
||||
const LG_TransportControl * control, LG_TransportControlToken * token)
|
||||
{
|
||||
(void)control;
|
||||
(void)token;
|
||||
return networkSessionValid(this) ?
|
||||
LG_TRANSPORT_UNAVAILABLE : LG_TRANSPORT_DISCONNECTED;
|
||||
}
|
||||
|
||||
static LG_TransportStatus networkControlStatus(LG_Transport * this,
|
||||
LG_TransportControlToken token)
|
||||
{
|
||||
(void)token;
|
||||
return networkSessionValid(this) ?
|
||||
LG_TRANSPORT_UNAVAILABLE : LG_TRANSPORT_DISCONNECTED;
|
||||
}
|
||||
|
||||
const LG_TransportOps LGT_Network =
|
||||
{
|
||||
.name = "network",
|
||||
.setup = networkSetup,
|
||||
.create = networkCreate,
|
||||
.destroy = networkDestroy,
|
||||
.connect = networkConnect,
|
||||
.connectCancellable = networkConnectCancellable,
|
||||
.disconnect = networkDisconnect,
|
||||
.sessionValid = networkSessionValid,
|
||||
.getVideoOps = networkGetVideoOps,
|
||||
.getInputOps = networkGetInputOps,
|
||||
.getAudioOps = networkGetAudioOps,
|
||||
.getClipboardOps = networkGetClipboardOps,
|
||||
.sendControl = networkSendControl,
|
||||
.controlStatus = networkControlStatus,
|
||||
};
|
||||
25
client/transports/Network/network.h
Normal file
25
client/transports/Network/network.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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 "interface/transport.h"
|
||||
|
||||
extern const LG_TransportOps LGT_Network;
|
||||
25
client/transports/Network/platform.h
Normal file
25
client/transports/Network/platform.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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 <stdbool.h>
|
||||
|
||||
bool networkPlatformReplaceFile(const char * source, const char * target);
|
||||
40
client/transports/Network/platform/linux/fingerprint.c
Normal file
40
client/transports/Network/platform/linux/fingerprint.c
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "../../fingerprint.h"
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
bool networkFingerprintSHA256(const uint8_t * data, size_t size,
|
||||
uint8_t fingerprint[NETWORK_FINGERPRINT_SIZE])
|
||||
{
|
||||
EVP_MD_CTX * context = EVP_MD_CTX_new();
|
||||
if (!context)
|
||||
return false;
|
||||
|
||||
unsigned int outputSize = 0;
|
||||
const bool result =
|
||||
EVP_DigestInit_ex(context, EVP_sha256(), NULL) == 1 &&
|
||||
EVP_DigestUpdate(context, data, size) == 1 &&
|
||||
EVP_DigestFinal_ex(context, fingerprint, &outputSize) == 1 &&
|
||||
outputSize == NETWORK_FINGERPRINT_SIZE;
|
||||
EVP_MD_CTX_free(context);
|
||||
return result;
|
||||
}
|
||||
28
client/transports/Network/platform/linux/platform.c
Normal file
28
client/transports/Network/platform/linux/platform.c
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "../../platform.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
bool networkPlatformReplaceFile(const char * source, const char * target)
|
||||
{
|
||||
return rename(source, target) == 0;
|
||||
}
|
||||
39
client/transports/Network/platform/windows/fingerprint.c
Normal file
39
client/transports/Network/platform/windows/fingerprint.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "../../fingerprint.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <bcrypt.h>
|
||||
#include <wincrypt.h>
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
bool networkFingerprintSHA256(const uint8_t * data, size_t size,
|
||||
uint8_t fingerprint[NETWORK_FINGERPRINT_SIZE])
|
||||
{
|
||||
if (size > ULONG_MAX)
|
||||
return false;
|
||||
|
||||
DWORD outputSize = NETWORK_FINGERPRINT_SIZE;
|
||||
return CryptHashCertificate2(BCRYPT_SHA256_ALGORITHM, 0, NULL,
|
||||
data, (DWORD)size, fingerprint, &outputSize) &&
|
||||
outputSize == NETWORK_FINGERPRINT_SIZE;
|
||||
}
|
||||
44
client/transports/Network/platform/windows/platform.c
Normal file
44
client/transports/Network/platform/windows/platform.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "../../platform.h"
|
||||
|
||||
#include "common/win32.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
|
||||
bool networkPlatformReplaceFile(const char * source, const char * target)
|
||||
{
|
||||
wchar_t * sourceWide = lgUtf8ToWide(source);
|
||||
wchar_t * targetWide = lgUtf8ToWide(target);
|
||||
if (!sourceWide || !targetWide)
|
||||
{
|
||||
free(targetWide);
|
||||
free(sourceWide);
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool result = MoveFileExW(sourceWide, targetWide,
|
||||
MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
|
||||
free(targetWide);
|
||||
free(sourceWide);
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user