[client/idd] network: add clipboard and bulk transfer

This commit is contained in:
Geoffrey McRae
2026-10-01 01:56:48 +10:00
parent a43227cba6
commit d24d11c3b7
15 changed files with 10384 additions and 253 deletions

View File

@@ -7,6 +7,7 @@ endif()
set(TRANSPORT_NETWORK_SOURCES
audio.c
clipboard.c
connection.c
control.c
cursor.c

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
/**
* 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/clipboard.h"
#include <LGProtocol/NetworkProtocol.h>
#include <stdbool.h>
typedef struct NetworkClipboard NetworkClipboard;
bool networkClipboardCreate(NetworkClipboard ** clipboard,
NetworkConnection * connection);
void networkClipboardDestroy(NetworkClipboard ** clipboard);
void networkClipboardConnectionState(NetworkClipboard * clipboard,
bool connected);
void networkClipboardConnect(NetworkClipboard * clipboard);
void networkClipboardDisconnect(NetworkClipboard * clipboard);
void networkClipboardProcess(NetworkClipboard * clipboard);
void networkClipboardSendReady(NetworkClipboard * clipboard,
LGNetService service, NetworkPacketDelivery delivery);
bool networkClipboardPacket(NetworkClipboard * clipboard,
const LGNetPacketView * packet, NetworkPacketDelivery delivery);
const LG_ClipboardOps * networkClipboardGetOps(void);

File diff suppressed because it is too large Load Diff

View File

@@ -31,6 +31,14 @@
typedef struct NetworkConnection NetworkConnection;
typedef enum NetworkPacketDelivery
{
NETWORK_PACKET_DELIVERY_RELIABLE,
NETWORK_PACKET_DELIVERY_DATAGRAM,
NETWORK_PACKET_DELIVERY_BULK,
}
NetworkPacketDelivery;
typedef void (*NetworkTrustDecisionFn)(void * opaque, bool trusted);
typedef bool (*NetworkTrustPromptFn)(void * opaque, const char * endpoint,
const char * fingerprint, NetworkTrustDecisionFn decision,
@@ -38,11 +46,11 @@ typedef bool (*NetworkTrustPromptFn)(void * opaque, const char * endpoint,
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);
const LGNetPacketView * packet, NetworkPacketDelivery delivery);
typedef void (*NetworkConnectionStateFn)(void * opaque, bool connected,
LG_TransportStatus reason);
typedef void (*NetworkSendReadyFn)(void * opaque, LGNetService service,
bool datagram);
NetworkPacketDelivery delivery);
typedef struct NetworkConnectionParams
{
@@ -85,3 +93,7 @@ LG_TransportStatus networkConnectionSendDatagram(
uint16_t messageType, uint16_t serviceVersion,
LGNetEnvelopeFlags flags, uint64_t componentEpoch, uint64_t requestID,
const void * payload, uint32_t payloadLength, bool discardIfBlocked);
LG_TransportStatus networkConnectionSendBulk(NetworkConnection * connection,
LGNetService service, uint16_t messageType, uint16_t serviceVersion,
LGNetEnvelopeFlags flags, uint64_t componentEpoch, uint64_t requestID,
const void * payload, uint32_t payloadLength);

View File

@@ -20,6 +20,7 @@
#include "network.h"
#include "audio.h"
#include "clipboard.h"
#include "connection.h"
#include "control.h"
#include "cursor.h"
@@ -43,13 +44,18 @@
#include <stdlib.h>
#include <string.h>
#define NETWORK_ADDRESS_MAX 255U
#define NETWORK_ENDPOINT_TEXT_SIZE (NETWORK_ADDRESS_MAX + 9U)
#define NETWORK_MAX_PAYLOAD \
#define NETWORK_ADDRESS_MAX 255U
#define NETWORK_ENDPOINT_TEXT_SIZE (NETWORK_ADDRESS_MAX + 9U)
#define NETWORK_MAX_PAYLOAD \
(LG_NET_CURSOR_SHAPE_HEADER_WIRE_SIZE + LG_NET_CURSOR_MAX_SHAPE_LENGTH)
#define NETWORK_MAX_DATAGRAM 1136U
#define NETWORK_AUDIO_MAX_PAYLOAD \
#define NETWORK_MAX_DATAGRAM 1136U
#define NETWORK_AUDIO_MAX_PAYLOAD \
(LG_NET_AUDIO_DATA_HEADER_WIRE_SIZE + 65536U)
#define NETWORK_TRANSFER_CHUNK (256U * 1024U)
#define NETWORK_CLIPBOARD_MAX_PAYLOAD \
(LG_NET_CLIPBOARD_CHUNK_HEADER_WIRE_SIZE + NETWORK_TRANSFER_CHUNK)
#define NETWORK_FILE_MAX_PAYLOAD \
(LG_NET_FILE_CHUNK_HEADER_WIRE_SIZE + NETWORK_TRANSFER_CHUNK)
static const LGNetCapability NETWORK_CAPABILITIES[] =
{
@@ -101,6 +107,30 @@ static const LGNetCapability NETWORK_CAPABILITIES[] =
.maxBidirectionalStreams = 0,
.maxUnidirectionalStreams = 0,
},
{
.service = LG_NET_SERVICE_CLIPBOARD,
.versionMin = LG_NET_CLIPBOARD_VERSION_MIN,
.versionMax = LG_NET_CLIPBOARD_VERSION_CURRENT,
.flags = LG_NET_CAPABILITY_RELIABLE |
LG_NET_CAPABILITY_BULK,
.features = 0,
.maxPayloadLength = NETWORK_CLIPBOARD_MAX_PAYLOAD,
.maxDatagramPayload = 0,
.maxBidirectionalStreams = 0,
.maxUnidirectionalStreams = 1,
},
{
.service = LG_NET_SERVICE_FILE,
.versionMin = LG_NET_FILE_VERSION_MIN,
.versionMax = LG_NET_FILE_VERSION_CURRENT,
.flags = LG_NET_CAPABILITY_RELIABLE |
LG_NET_CAPABILITY_BULK,
.features = 0,
.maxPayloadLength = NETWORK_FILE_MAX_PAYLOAD,
.maxDatagramPayload = 0,
.maxBidirectionalStreams = 0,
.maxUnidirectionalStreams = 1,
},
{
.service = LG_NET_SERVICE_CONTROL,
.versionMin = LG_NET_CONTROL_VERSION_MIN,
@@ -125,6 +155,7 @@ struct LG_Transport
{
NetworkConnection * connection;
NetworkAudio * audio;
NetworkClipboard * clipboard;
NetworkControl * control;
NetworkCursor * cursor;
NetworkInput * input;
@@ -341,6 +372,7 @@ static void networkConnectionState(void * opaque, bool connected,
networkInputConnectionState(this->input, connected);
networkAudioConnectionState(this->audio, connected);
networkClipboardConnectionState(this->clipboard, connected);
networkControlConnectionState(this->control, connected);
networkRecoveryConnectionState(this->recovery, connected);
const bool cursorAvailable =
@@ -359,28 +391,39 @@ static void networkConnectionState(void * opaque, bool connected,
}
static void networkPacket(void * opaque, const LGNetPacketView * packet,
bool datagram)
NetworkPacketDelivery delivery)
{
LG_Transport * this = opaque;
bool valid;
LG_Transport * this = opaque;
const bool datagram =
delivery == NETWORK_PACKET_DELIVERY_DATAGRAM;
bool valid;
switch (packet->envelope.service)
{
case LG_NET_SERVICE_RECOVERY:
valid = networkRecoveryPacket(this->recovery, packet, datagram);
valid = delivery != NETWORK_PACKET_DELIVERY_BULK &&
networkRecoveryPacket(this->recovery, packet, datagram);
break;
case LG_NET_SERVICE_CURSOR:
valid = networkCursorPacket(this->cursor, packet, datagram);
valid = delivery != NETWORK_PACKET_DELIVERY_BULK &&
networkCursorPacket(this->cursor, packet, datagram);
break;
case LG_NET_SERVICE_INPUT:
valid = networkInputPacket(this->input, packet, datagram);
valid = delivery != NETWORK_PACKET_DELIVERY_BULK &&
networkInputPacket(this->input, packet, datagram);
break;
case LG_NET_SERVICE_AUDIO:
valid = datagram ?
networkAudioDatagram(this->audio, packet) :
networkAudioPacket(this->audio, packet);
valid = delivery != NETWORK_PACKET_DELIVERY_BULK &&
(datagram ? networkAudioDatagram(this->audio, packet) :
networkAudioPacket(this->audio, packet));
break;
case LG_NET_SERVICE_CLIPBOARD:
case LG_NET_SERVICE_FILE:
valid = delivery != NETWORK_PACKET_DELIVERY_DATAGRAM &&
networkClipboardPacket(this->clipboard, packet, delivery);
break;
case LG_NET_SERVICE_CONTROL:
valid = networkControlPacket(this->control, packet, datagram);
valid = delivery != NETWORK_PACKET_DELIVERY_BULK &&
networkControlPacket(this->control, packet, datagram);
break;
default:
valid = false;
@@ -397,11 +440,17 @@ static void networkPacket(void * opaque, const LGNetPacketView * packet,
}
static void networkSendReady(void * opaque, LGNetService service,
bool datagram)
NetworkPacketDelivery delivery)
{
LG_Transport * this = opaque;
if (service == LG_NET_SERVICE_AUDIO)
LG_Transport * this = opaque;
const bool datagram =
delivery == NETWORK_PACKET_DELIVERY_DATAGRAM;
if (service == LG_NET_SERVICE_AUDIO &&
delivery != NETWORK_PACKET_DELIVERY_BULK)
networkAudioSendReady(this->audio, datagram);
if ((service == LG_NET_SERVICE_CLIPBOARD ||
service == LG_NET_SERVICE_FILE) && !datagram)
networkClipboardSendReady(this->clipboard, service, delivery);
lgSignalEvent(this->frameEvent);
}
@@ -463,6 +512,7 @@ static bool networkCreate(LG_Transport ** result)
if (!networkConnectionCreate(&this->connection, &params))
goto fail;
if (!networkAudioCreate(&this->audio, this->connection) ||
!networkClipboardCreate(&this->clipboard, this->connection) ||
!networkControlCreate(&this->control, this->connection) ||
!networkCursorCreate(&this->cursor, this->connection) ||
!networkInputCreate(&this->input, this->connection) ||
@@ -477,6 +527,7 @@ fail:
networkInputDestroy(&this->input);
networkCursorDestroy(&this->cursor);
networkControlDestroy(&this->control);
networkClipboardDestroy(&this->clipboard);
networkAudioDestroy(&this->audio);
networkConnectionDestroy(&this->connection);
if (this->frameEvent)
@@ -512,6 +563,7 @@ static void networkDestroy(LG_Transport ** transport)
networkInputDestroy(&this->input);
networkCursorDestroy(&this->cursor);
networkControlDestroy(&this->control);
networkClipboardDestroy(&this->clipboard);
networkAudioDestroy(&this->audio);
networkConnectionDestroy(&this->connection);
lgFreeEvent(this->frameEvent);
@@ -542,6 +594,7 @@ static void networkDisconnect(LG_Transport * this)
{
networkInputConnectionState(this->input, false);
networkAudioConnectionState(this->audio, false);
networkClipboardConnectionState(this->clipboard, false);
networkControlConnectionState(this->control, false);
networkRecoveryConnectionState(this->recovery, false);
networkCursorConnectionState(this->cursor, false);
@@ -728,9 +781,14 @@ static const LG_AudioOps * networkGetAudioOps(LG_Transport * this,
static const LG_ClipboardOps * networkGetClipboardOps(LG_Transport * this,
void ** opaque)
{
(void)this;
*opaque = NULL;
return NULL;
if (!networkConnectionServiceAvailable(this->connection,
LG_NET_SERVICE_CLIPBOARD, LG_NET_CAPABILITY_RELIABLE) ||
!networkConnectionServiceAvailable(this->connection,
LG_NET_SERVICE_FILE, LG_NET_CAPABILITY_RELIABLE))
return NULL;
*opaque = this->clipboard;
return networkClipboardGetOps();
}
static LG_TransportStatus networkSendControl(LG_Transport * this,