mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-22 15:11:31 +00:00
[clipboard] lgmp: make payload streams mandatory
Carry DATA and FILE_DATA only through the duplex SPSC streams. Keep LGMP queues for control and status. Remove grants, commits, ACKs, and queue-payload transport negotiation. Poll adaptively while ownership or release is active. Preserve FIFO release and graceful draining. Quarantine payloads crossed by a newer OFFER or CLEAR, and retire data-plane state on detach.
This commit is contained in:
@@ -40,7 +40,6 @@
|
|||||||
#define CLIPBOARD_PENDING_MAX 128U
|
#define CLIPBOARD_PENDING_MAX 128U
|
||||||
#define CLIPBOARD_PENDING_NORMAL_MAX 64U
|
#define CLIPBOARD_PENDING_NORMAL_MAX 64U
|
||||||
#define CLIPBOARD_DRAIN_MAX 64U
|
#define CLIPBOARD_DRAIN_MAX 64U
|
||||||
#define CLIPBOARD_GRANTS KVMFR_CLIPBOARD_SLOT_COUNT
|
|
||||||
#define CLIPBOARD_IDLE_POLL_MS 10U
|
#define CLIPBOARD_IDLE_POLL_MS 10U
|
||||||
#define CLIPBOARD_ACTIVE_POLL_MS 1U
|
#define CLIPBOARD_ACTIVE_POLL_MS 1U
|
||||||
#define CLIPBOARD_KEEPALIVE_US UINT64_C(200000)
|
#define CLIPBOARD_KEEPALIVE_US UINT64_C(200000)
|
||||||
@@ -51,14 +50,6 @@ struct PendingRecord
|
|||||||
KVMFRClipboardMessage record;
|
KVMFRClipboardMessage record;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Grant
|
|
||||||
{
|
|
||||||
KVMFRClipboardSlotHeader * header;
|
|
||||||
uint8_t * data;
|
|
||||||
uint32_t token;
|
|
||||||
bool available;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FileTransfer
|
struct FileTransfer
|
||||||
{
|
{
|
||||||
struct FileTransfer * next;
|
struct FileTransfer * next;
|
||||||
@@ -106,8 +97,7 @@ struct LGMPClipboard
|
|||||||
bool statusValid;
|
bool statusValid;
|
||||||
bool claimed;
|
bool claimed;
|
||||||
bool ownerConfirmed;
|
bool ownerConfirmed;
|
||||||
KVMFRClipboardTransportFlags transports;
|
bool releasing;
|
||||||
KVMFRClipboardTransportFlags claimTransport;
|
|
||||||
KVMFRStreamDescriptor hostToClientDescriptor;
|
KVMFRStreamDescriptor hostToClientDescriptor;
|
||||||
KVMFRStreamDescriptor clientToHostDescriptor;
|
KVMFRStreamDescriptor clientToHostDescriptor;
|
||||||
uint32_t clientID;
|
uint32_t clientID;
|
||||||
@@ -122,7 +112,6 @@ struct LGMPClipboard
|
|||||||
unsigned pendingHead;
|
unsigned pendingHead;
|
||||||
unsigned pendingCount;
|
unsigned pendingCount;
|
||||||
|
|
||||||
struct Grant grants[CLIPBOARD_GRANTS];
|
|
||||||
bool writeBlocked;
|
bool writeBlocked;
|
||||||
LG_ClipboardRequest writeBlockedRequest;
|
LG_ClipboardRequest writeBlockedRequest;
|
||||||
LG_ClipboardRequest writeTransfer;
|
LG_ClipboardRequest writeTransfer;
|
||||||
@@ -136,9 +125,7 @@ struct LGMPClipboard
|
|||||||
|
|
||||||
bool held;
|
bool held;
|
||||||
bool heldReady;
|
bool heldReady;
|
||||||
bool heldStream;
|
|
||||||
enum HeldPhase heldPhase;
|
enum HeldPhase heldPhase;
|
||||||
LGMPMessage heldMessage;
|
|
||||||
LGMPStreamBuffer heldStreamBuffer;
|
LGMPStreamBuffer heldStreamBuffer;
|
||||||
KVMFRClipboardMessage heldRecord;
|
KVMFRClipboardMessage heldRecord;
|
||||||
bool heldFile;
|
bool heldFile;
|
||||||
@@ -229,12 +216,6 @@ static void detachStreamsNL(LGMPClipboard * clipboard)
|
|||||||
static bool attachStreamsNL(LGMPClipboard * clipboard,
|
static bool attachStreamsNL(LGMPClipboard * clipboard,
|
||||||
const KVMFRClipboardStatus * status)
|
const KVMFRClipboardStatus * status)
|
||||||
{
|
{
|
||||||
if (!(status->transports & KVMFR_CLIPBOARD_TRANSPORT_STREAM))
|
|
||||||
{
|
|
||||||
detachStreamsNL(clipboard);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clipboard->hostToClientStream && clipboard->clientToHostStream &&
|
if (clipboard->hostToClientStream && clipboard->clientToHostStream &&
|
||||||
!memcmp(&clipboard->hostToClientDescriptor, &status->hostToClient,
|
!memcmp(&clipboard->hostToClientDescriptor, &status->hostToClient,
|
||||||
sizeof(status->hostToClient)) &&
|
sizeof(status->hostToClient)) &&
|
||||||
@@ -659,14 +640,6 @@ static bool enqueueTypeNL(LGMPClipboard * clipboard,
|
|||||||
return enqueueRecordNL(clipboard, record);
|
return enqueueRecordNL(clipboard, record);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct Grant * availableGrantNL(LGMPClipboard * clipboard)
|
|
||||||
{
|
|
||||||
for (unsigned i = 0; i < CLIPBOARD_GRANTS; ++i)
|
|
||||||
if (clipboard->grants[i].available)
|
|
||||||
return &clipboard->grants[i];
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool streamWriteNL(LGMPClipboard * clipboard,
|
static bool streamWriteNL(LGMPClipboard * clipboard,
|
||||||
const KVMFRClipboardMessage * record, const void * data)
|
const KVMFRClipboardMessage * record, const void * data)
|
||||||
{
|
{
|
||||||
@@ -725,32 +698,12 @@ static bool enqueueDataNL(LGMPClipboard * clipboard,
|
|||||||
|
|
||||||
record.version = KVMFR_CLIPBOARD_VERSION;
|
record.version = KVMFR_CLIPBOARD_VERSION;
|
||||||
record.generation = clipboard->claimGeneration;
|
record.generation = clipboard->claimGeneration;
|
||||||
if (clipboard->claimTransport == KVMFR_CLIPBOARD_TRANSPORT_STREAM)
|
|
||||||
return streamWriteNL(clipboard, &record, data);
|
return streamWriteNL(clipboard, &record, data);
|
||||||
if (clipboard->claimTransport != KVMFR_CLIPBOARD_TRANSPORT_LEGACY ||
|
|
||||||
clipboard->pendingCount >= CLIPBOARD_PENDING_NORMAL_MAX)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
struct Grant * grant = availableGrantNL(clipboard);
|
|
||||||
if (!grant)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
memcpy(grant->header, &record, sizeof(record));
|
|
||||||
if (record.length)
|
|
||||||
memcpy(grant->data, data, record.length);
|
|
||||||
|
|
||||||
KVMFRClipboardMessage commit = record;
|
|
||||||
commit.type = KVMFR_CLIPBOARD_MESSAGE_COMMIT;
|
|
||||||
commit.token = grant->token;
|
|
||||||
pendingAt(clipboard, clipboard->pendingCount++)->record = commit;
|
|
||||||
grant->available = false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool streamWritableNL(LGMPClipboard * clipboard)
|
static bool streamWritableNL(LGMPClipboard * clipboard)
|
||||||
{
|
{
|
||||||
if (!clipboard->clientToHostStream ||
|
if (!clipboard->clientToHostStream || !clipboard->claimed)
|
||||||
clipboard->claimTransport != KVMFR_CLIPBOARD_TRANSPORT_STREAM)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
LGMPStreamBuffer buffer = { 0 };
|
LGMPStreamBuffer buffer = { 0 };
|
||||||
@@ -777,11 +730,7 @@ static bool streamWritableNL(LGMPClipboard * clipboard)
|
|||||||
|
|
||||||
static bool dataWritableNL(LGMPClipboard * clipboard)
|
static bool dataWritableNL(LGMPClipboard * clipboard)
|
||||||
{
|
{
|
||||||
if (clipboard->claimTransport == KVMFR_CLIPBOARD_TRANSPORT_STREAM)
|
|
||||||
return streamWritableNL(clipboard);
|
return streamWritableNL(clipboard);
|
||||||
return clipboard->claimTransport == KVMFR_CLIPBOARD_TRANSPORT_LEGACY &&
|
|
||||||
clipboard->pendingCount < CLIPBOARD_PENDING_NORMAL_MAX &&
|
|
||||||
availableGrantNL(clipboard);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clearWriteNL(LGMPClipboard * clipboard)
|
static void clearWriteNL(LGMPClipboard * clipboard)
|
||||||
@@ -810,43 +759,43 @@ static void clearReadNL(LGMPClipboard * clipboard)
|
|||||||
clipboard->readBegan = false;
|
clipboard->readBegan = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clearProtocolNL(LGMPClipboard * clipboard)
|
static void clearDataPlaneNL(LGMPClipboard * clipboard)
|
||||||
{
|
{
|
||||||
clipboard->claimed = false;
|
|
||||||
clipboard->ownerConfirmed = false;
|
|
||||||
clipboard->claimTransport = 0;
|
|
||||||
clipboard->publishedClaimGeneration = 0;
|
|
||||||
clipboard->pendingHead = 0;
|
|
||||||
clipboard->pendingCount = 0;
|
|
||||||
clipboard->remoteClipboardGeneration = 0;
|
clipboard->remoteClipboardGeneration = 0;
|
||||||
clipboard->remoteFormats = 0;
|
clipboard->remoteFormats = 0;
|
||||||
clearWriteNL(clipboard);
|
clearWriteNL(clipboard);
|
||||||
clearReadNL(clipboard);
|
clearReadNL(clipboard);
|
||||||
clearFilesNL(clipboard);
|
clearFilesNL(clipboard);
|
||||||
memset(clipboard->grants, 0, sizeof(clipboard->grants));
|
}
|
||||||
|
|
||||||
|
static void clearProtocolNL(LGMPClipboard * clipboard)
|
||||||
|
{
|
||||||
|
clipboard->claimed = false;
|
||||||
|
clipboard->ownerConfirmed = false;
|
||||||
|
clipboard->releasing = false;
|
||||||
|
clipboard->publishedClaimGeneration = 0;
|
||||||
|
clipboard->pendingHead = 0;
|
||||||
|
clipboard->pendingCount = 0;
|
||||||
|
clearDataPlaneNL(clipboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ensureClaimNL(LGMPClipboard * clipboard)
|
static bool ensureClaimNL(LGMPClipboard * clipboard)
|
||||||
{
|
{
|
||||||
if (clipboard->claimed)
|
if (clipboard->claimed)
|
||||||
return true;
|
return true;
|
||||||
if (!clipboard->connected || !clipboard->available ||
|
if (clipboard->releasing || !clipboard->connected ||
|
||||||
!clipboard->transports)
|
!clipboard->available ||
|
||||||
|
!clipboard->hostToClientStream || !clipboard->clientToHostStream)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
KVMFRClipboardMessage claim = { 0 };
|
KVMFRClipboardMessage claim = { 0 };
|
||||||
nextNonzero(&clipboard->claimGeneration);
|
nextNonzero(&clipboard->claimGeneration);
|
||||||
claim.type = KVMFR_CLIPBOARD_MESSAGE_CLAIM;
|
claim.type = KVMFR_CLIPBOARD_MESSAGE_CLAIM;
|
||||||
claim.token = clipboard->endpointGeneration;
|
claim.token = clipboard->endpointGeneration;
|
||||||
claim.flags =
|
|
||||||
(clipboard->transports & KVMFR_CLIPBOARD_TRANSPORT_STREAM) ?
|
|
||||||
KVMFR_CLIPBOARD_TRANSPORT_STREAM :
|
|
||||||
KVMFR_CLIPBOARD_TRANSPORT_LEGACY;
|
|
||||||
if (!enqueueRecordNL(clipboard, claim))
|
if (!enqueueRecordNL(clipboard, claim))
|
||||||
return false;
|
return false;
|
||||||
clipboard->claimed = true;
|
clipboard->claimed = true;
|
||||||
clipboard->ownerConfirmed = false;
|
clipboard->ownerConfirmed = false;
|
||||||
clipboard->claimTransport = claim.flags;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -892,13 +841,10 @@ static void connectionLostNL(LGMPClipboard * clipboard)
|
|||||||
clipboard->connected = false;
|
clipboard->connected = false;
|
||||||
clipboard->available = false;
|
clipboard->available = false;
|
||||||
clipboard->statusValid = false;
|
clipboard->statusValid = false;
|
||||||
clipboard->transports = 0;
|
|
||||||
detachStreamsNL(clipboard);
|
detachStreamsNL(clipboard);
|
||||||
clearProtocolNL(clipboard);
|
clearProtocolNL(clipboard);
|
||||||
clipboard->held = false;
|
clipboard->held = false;
|
||||||
clipboard->heldReady = false;
|
clipboard->heldReady = false;
|
||||||
clipboard->heldStream = false;
|
|
||||||
memset(&clipboard->heldMessage, 0, sizeof(clipboard->heldMessage));
|
|
||||||
memset(&clipboard->heldStreamBuffer, 0,
|
memset(&clipboard->heldStreamBuffer, 0,
|
||||||
sizeof(clipboard->heldStreamBuffer));
|
sizeof(clipboard->heldStreamBuffer));
|
||||||
memset(&clipboard->heldRecord, 0, sizeof(clipboard->heldRecord));
|
memset(&clipboard->heldRecord, 0, sizeof(clipboard->heldRecord));
|
||||||
@@ -930,36 +876,20 @@ static bool validStatus(const KVMFRClipboardStatus * status)
|
|||||||
{
|
{
|
||||||
const uint32_t validFlags = KVMFR_CLIPBOARD_STATUS_AVAILABLE |
|
const uint32_t validFlags = KVMFR_CLIPBOARD_STATUS_AVAILABLE |
|
||||||
KVMFR_CLIPBOARD_STATUS_HAS_OWNER;
|
KVMFR_CLIPBOARD_STATUS_HAS_OWNER;
|
||||||
const KVMFRStreamDescriptor emptyDescriptor = { 0 };
|
const uint32_t emptyReserved[6] = { 0 };
|
||||||
const uint32_t emptyReserved[4] = { 0 };
|
|
||||||
if (status->version != KVMFR_CLIPBOARD_VERSION ||
|
if (status->version != KVMFR_CLIPBOARD_VERSION ||
|
||||||
status->flags & ~validFlags || !status->generation ||
|
status->flags & ~validFlags || !status->generation ||
|
||||||
status->formats & ~KVMFR_CLIPBOARD_FORMAT_MASK_ALL ||
|
status->formats & ~KVMFR_CLIPBOARD_FORMAT_MASK_ALL ||
|
||||||
!status->lease ||
|
!status->lease ||
|
||||||
status->slotBytes != KVMFR_CLIPBOARD_DATA_BYTES ||
|
status->slotBytes != KVMFR_CLIPBOARD_DATA_BYTES ||
|
||||||
!status->transports ||
|
status->streamVersion != KVMFR_CLIPBOARD_STREAM_VERSION ||
|
||||||
status->transports & ~KVMFR_CLIPBOARD_TRANSPORT_ALL ||
|
|
||||||
memcmp(status->reserved, emptyReserved, sizeof(emptyReserved)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const bool streams =
|
|
||||||
(status->transports & KVMFR_CLIPBOARD_TRANSPORT_STREAM) != 0;
|
|
||||||
if (streams)
|
|
||||||
{
|
|
||||||
if (status->streamVersion != KVMFR_CLIPBOARD_STREAM_VERSION ||
|
|
||||||
status->streamSlotCount != KVMFR_CLIPBOARD_STREAM_SLOT_COUNT ||
|
status->streamSlotCount != KVMFR_CLIPBOARD_STREAM_SLOT_COUNT ||
|
||||||
|
memcmp(status->reserved, emptyReserved, sizeof(emptyReserved)) ||
|
||||||
!validStreamDescriptor(&status->hostToClient,
|
!validStreamDescriptor(&status->hostToClient,
|
||||||
LGMP_STREAM_HOST_TO_CLIENT) ||
|
LGMP_STREAM_HOST_TO_CLIENT) ||
|
||||||
!validStreamDescriptor(&status->clientToHost,
|
!validStreamDescriptor(&status->clientToHost,
|
||||||
LGMP_STREAM_CLIENT_TO_HOST))
|
LGMP_STREAM_CLIENT_TO_HOST))
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
else if (status->streamVersion || status->streamSlotCount ||
|
|
||||||
memcmp(&status->hostToClient, &emptyDescriptor,
|
|
||||||
sizeof(emptyDescriptor)) ||
|
|
||||||
memcmp(&status->clientToHost, &emptyDescriptor,
|
|
||||||
sizeof(emptyDescriptor)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const bool available =
|
const bool available =
|
||||||
(status->flags & KVMFR_CLIPBOARD_STATUS_AVAILABLE) != 0;
|
(status->flags & KVMFR_CLIPBOARD_STATUS_AVAILABLE) != 0;
|
||||||
@@ -967,16 +897,12 @@ static bool validStatus(const KVMFRClipboardStatus * status)
|
|||||||
(status->flags & KVMFR_CLIPBOARD_STATUS_HAS_OWNER) != 0;
|
(status->flags & KVMFR_CLIPBOARD_STATUS_HAS_OWNER) != 0;
|
||||||
if (!available && (status->formats || owner))
|
if (!available && (status->formats || owner))
|
||||||
return false;
|
return false;
|
||||||
return owner ? status->ownerClientID && status->ownerGeneration &&
|
return owner ? status->ownerClientID && status->ownerGeneration :
|
||||||
kvmfrClipboardTransportValid(status->ownerTransport) &&
|
!status->ownerClientID && !status->ownerGeneration;
|
||||||
(status->transports & status->ownerTransport) :
|
|
||||||
!status->ownerClientID && !status->ownerGeneration &&
|
|
||||||
!status->ownerTransport;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool validateRecord(const LGMPClipboard * clipboard,
|
static bool validateRecord(const LGMPClipboard * clipboard,
|
||||||
const KVMFRClipboardMessage * record, size_t size,
|
const KVMFRClipboardMessage * record, size_t size, bool stream)
|
||||||
KVMFRClipboardQueueType queueType, bool stream)
|
|
||||||
{
|
{
|
||||||
if (size < sizeof(*record) ||
|
if (size < sizeof(*record) ||
|
||||||
record->version != KVMFR_CLIPBOARD_VERSION ||
|
record->version != KVMFR_CLIPBOARD_VERSION ||
|
||||||
@@ -990,15 +916,10 @@ static bool validateRecord(const LGMPClipboard * clipboard,
|
|||||||
if (record->type == KVMFR_CLIPBOARD_MESSAGE_DATA ||
|
if (record->type == KVMFR_CLIPBOARD_MESSAGE_DATA ||
|
||||||
record->type == KVMFR_CLIPBOARD_MESSAGE_FILE_DATA)
|
record->type == KVMFR_CLIPBOARD_MESSAGE_FILE_DATA)
|
||||||
{
|
{
|
||||||
const size_t expected = sizeof(*record) +
|
if (!stream || size != sizeof(*record) + record->length)
|
||||||
(stream ? record->length : KVMFR_CLIPBOARD_DATA_BYTES);
|
|
||||||
if (size != expected || queueType != KVMFR_CLIPBOARD_QUEUE_DATA ||
|
|
||||||
stream != (clipboard->claimTransport ==
|
|
||||||
KVMFR_CLIPBOARD_TRANSPORT_STREAM))
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (queueType != KVMFR_CLIPBOARD_QUEUE_MESSAGE ||
|
else if (stream || size != sizeof(*record) || record->length ||
|
||||||
size != sizeof(*record) || record->length ||
|
|
||||||
(record->flags &&
|
(record->flags &&
|
||||||
record->type != KVMFR_CLIPBOARD_MESSAGE_FILE_REQUEST))
|
record->type != KVMFR_CLIPBOARD_MESSAGE_FILE_REQUEST))
|
||||||
return false;
|
return false;
|
||||||
@@ -1500,32 +1421,27 @@ static void applyStatusNL(LGMPClipboard * clipboard,
|
|||||||
const bool wasValid = clipboard->statusValid;
|
const bool wasValid = clipboard->statusValid;
|
||||||
const bool wasAvailable = clipboard->available;
|
const bool wasAvailable = clipboard->available;
|
||||||
const uint32_t oldGeneration = clipboard->endpointGeneration;
|
const uint32_t oldGeneration = clipboard->endpointGeneration;
|
||||||
const KVMFRClipboardTransportFlags oldTransports =
|
|
||||||
clipboard->transports;
|
|
||||||
clipboard->statusValid = true;
|
clipboard->statusValid = true;
|
||||||
clipboard->statusSerial = serial;
|
clipboard->statusSerial = serial;
|
||||||
const bool streamsAttached = attachStreamsNL(clipboard, status);
|
const bool streamsAttached = attachStreamsNL(clipboard, status);
|
||||||
const bool endpointAvailable =
|
const bool endpointAvailable =
|
||||||
(status->flags & KVMFR_CLIPBOARD_STATUS_AVAILABLE) != 0;
|
(status->flags & KVMFR_CLIPBOARD_STATUS_AVAILABLE) != 0;
|
||||||
clipboard->endpointGeneration = status->generation;
|
clipboard->endpointGeneration = status->generation;
|
||||||
clipboard->transports = status->transports;
|
|
||||||
if (!streamsAttached)
|
|
||||||
clipboard->transports &= ~KVMFR_CLIPBOARD_TRANSPORT_STREAM;
|
|
||||||
|
|
||||||
const bool owned = (status->flags & KVMFR_CLIPBOARD_STATUS_HAS_OWNER) &&
|
const bool hasOwner =
|
||||||
clipboard->claimed && status->ownerClientID == clipboard->clientID &&
|
(status->flags & KVMFR_CLIPBOARD_STATUS_HAS_OWNER) != 0;
|
||||||
status->ownerGeneration == clipboard->claimGeneration &&
|
const bool owned = hasOwner &&
|
||||||
status->ownerTransport == clipboard->claimTransport;
|
(clipboard->claimed || clipboard->releasing) &&
|
||||||
const bool ownedByOther =
|
status->ownerClientID == clipboard->clientID &&
|
||||||
(status->flags & KVMFR_CLIPBOARD_STATUS_HAS_OWNER) && !owned;
|
status->ownerGeneration == clipboard->claimGeneration;
|
||||||
const bool selectedUnavailable = clipboard->claimed &&
|
const bool ownedByOther = hasOwner && !owned;
|
||||||
!(clipboard->transports & clipboard->claimTransport);
|
const bool selectedUnavailable =
|
||||||
clipboard->available = endpointAvailable && !ownedByOther &&
|
(clipboard->claimed || clipboard->releasing) && !streamsAttached;
|
||||||
clipboard->transports;
|
clipboard->available = endpointAvailable && streamsAttached &&
|
||||||
|
!ownedByOther && !clipboard->releasing;
|
||||||
bool restore = false;
|
bool restore = false;
|
||||||
|
|
||||||
if (owned && clipboard->claimTransport ==
|
if (owned)
|
||||||
KVMFR_CLIPBOARD_TRANSPORT_STREAM)
|
|
||||||
{
|
{
|
||||||
const LGMP_STATUS activate = activateStreamsNL(clipboard);
|
const LGMP_STATUS activate = activateStreamsNL(clipboard);
|
||||||
if (activate != LGMP_OK)
|
if (activate != LGMP_OK)
|
||||||
@@ -1540,26 +1456,36 @@ static void applyStatusNL(LGMPClipboard * clipboard,
|
|||||||
ownedByOther || selectedUnavailable)
|
ownedByOther || selectedUnavailable)
|
||||||
{
|
{
|
||||||
clearProtocolNL(clipboard);
|
clearProtocolNL(clipboard);
|
||||||
restore = endpointAvailable && !ownedByOther;
|
restore = endpointAvailable && streamsAttached && !ownedByOther;
|
||||||
}
|
}
|
||||||
else if (status->flags & KVMFR_CLIPBOARD_STATUS_HAS_OWNER)
|
else if (hasOwner)
|
||||||
clipboard->ownerConfirmed = owned;
|
clipboard->ownerConfirmed = owned;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (clipboard->claimed && clipboard->ownerConfirmed)
|
if (clipboard->releasing)
|
||||||
|
{
|
||||||
|
clipboard->releasing = false;
|
||||||
|
clipboard->ownerConfirmed = false;
|
||||||
|
clipboard->available = endpointAvailable && streamsAttached;
|
||||||
|
}
|
||||||
|
else if (clipboard->claimed && clipboard->ownerConfirmed)
|
||||||
{
|
{
|
||||||
clearProtocolNL(clipboard);
|
clearProtocolNL(clipboard);
|
||||||
restore = endpointAvailable;
|
restore = endpointAvailable && streamsAttached;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
clipboard->ownerConfirmed = false;
|
clipboard->ownerConfirmed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!wasAvailable && clipboard->available && !clipboard->claimed &&
|
||||||
|
clipboard->events)
|
||||||
|
restore = true;
|
||||||
|
|
||||||
if (restore && !restoreClipboardNL(clipboard))
|
if (restore && !restoreClipboardNL(clipboard))
|
||||||
clearProtocolNL(clipboard);
|
clearProtocolNL(clipboard);
|
||||||
|
|
||||||
*changed = !wasValid || wasAvailable != clipboard->available ||
|
*changed = !wasValid || wasAvailable != clipboard->available ||
|
||||||
oldGeneration != clipboard->endpointGeneration ||
|
oldGeneration != clipboard->endpointGeneration;
|
||||||
oldTransports != clipboard->transports;
|
|
||||||
if (*changed)
|
if (*changed)
|
||||||
nextNonzero(&clipboard->providerGeneration);
|
nextNonzero(&clipboard->providerGeneration);
|
||||||
}
|
}
|
||||||
@@ -1600,7 +1526,6 @@ static bool processHeld(LGMPClipboard * clipboard)
|
|||||||
const uint8_t * data;
|
const uint8_t * data;
|
||||||
enum HeldPhase phase;
|
enum HeldPhase phase;
|
||||||
bool file;
|
bool file;
|
||||||
bool stream;
|
|
||||||
LGMPStreamBuffer streamBuffer;
|
LGMPStreamBuffer streamBuffer;
|
||||||
LG_ClipboardFileRequest fileRequest;
|
LG_ClipboardFileRequest fileRequest;
|
||||||
LG_LOCK(clipboard->lock);
|
LG_LOCK(clipboard->lock);
|
||||||
@@ -1610,11 +1535,9 @@ static bool processHeld(LGMPClipboard * clipboard)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
record = clipboard->heldRecord;
|
record = clipboard->heldRecord;
|
||||||
stream = clipboard->heldStream;
|
|
||||||
streamBuffer = clipboard->heldStreamBuffer;
|
streamBuffer = clipboard->heldStreamBuffer;
|
||||||
data = !record.length ? NULL : stream ?
|
data = !record.length ? NULL :
|
||||||
(const uint8_t *)streamBuffer.data + sizeof(record) :
|
(const uint8_t *)streamBuffer.data + sizeof(record);
|
||||||
(const uint8_t *)clipboard->heldMessage.mem + sizeof(record);
|
|
||||||
phase = clipboard->heldPhase;
|
phase = clipboard->heldPhase;
|
||||||
file = clipboard->heldFile;
|
file = clipboard->heldFile;
|
||||||
fileRequest = clipboard->heldFileRequest;
|
fileRequest = clipboard->heldFileRequest;
|
||||||
@@ -1702,13 +1625,9 @@ static bool processHeld(LGMPClipboard * clipboard)
|
|||||||
else if (matchingRead)
|
else if (matchingRead)
|
||||||
clearReadNL(clipboard);
|
clearReadNL(clipboard);
|
||||||
|
|
||||||
const LGMP_STATUS done = stream ?
|
const LGMP_STATUS done = lgmpClientStreamReadRelease(
|
||||||
lgmpClientStreamReadRelease(
|
clipboard->hostToClientStream, &streamBuffer);
|
||||||
clipboard->hostToClientStream, &streamBuffer) :
|
|
||||||
lgmpClientMessageDone(clipboard->queue);
|
|
||||||
clipboard->held = false;
|
clipboard->held = false;
|
||||||
clipboard->heldStream = false;
|
|
||||||
memset(&clipboard->heldMessage, 0, sizeof(clipboard->heldMessage));
|
|
||||||
memset(&clipboard->heldStreamBuffer, 0,
|
memset(&clipboard->heldStreamBuffer, 0,
|
||||||
sizeof(clipboard->heldStreamBuffer));
|
sizeof(clipboard->heldStreamBuffer));
|
||||||
memset(&clipboard->heldRecord, 0, sizeof(clipboard->heldRecord));
|
memset(&clipboard->heldRecord, 0, sizeof(clipboard->heldRecord));
|
||||||
@@ -1731,7 +1650,7 @@ static bool processStream(LGMPClipboard * clipboard, bool * processed)
|
|||||||
*processed = false;
|
*processed = false;
|
||||||
LG_LOCK(clipboard->lock);
|
LG_LOCK(clipboard->lock);
|
||||||
if (!clipboard->connected || clipboard->held ||
|
if (!clipboard->connected || clipboard->held ||
|
||||||
clipboard->claimTransport != KVMFR_CLIPBOARD_TRANSPORT_STREAM ||
|
(!clipboard->claimed && !clipboard->releasing) ||
|
||||||
!clipboard->hostToClientStream)
|
!clipboard->hostToClientStream)
|
||||||
{
|
{
|
||||||
LG_UNLOCK(clipboard->lock);
|
LG_UNLOCK(clipboard->lock);
|
||||||
@@ -1756,12 +1675,23 @@ static bool processStream(LGMPClipboard * clipboard, bool * processed)
|
|||||||
}
|
}
|
||||||
*processed = true;
|
*processed = true;
|
||||||
|
|
||||||
|
if (clipboard->releasing)
|
||||||
|
{
|
||||||
|
status = lgmpClientStreamReadRelease(
|
||||||
|
clipboard->hostToClientStream, &buffer);
|
||||||
|
if (status != LGMP_OK && status != LGMP_ERR_STREAM_UNBOUND &&
|
||||||
|
status != LGMP_ERR_STREAM_STALE)
|
||||||
|
connectionFailed(clipboard, status);
|
||||||
|
LG_UNLOCK(clipboard->lock);
|
||||||
|
return status == LGMP_OK || status == LGMP_ERR_STREAM_UNBOUND ||
|
||||||
|
status == LGMP_ERR_STREAM_STALE;
|
||||||
|
}
|
||||||
|
|
||||||
KVMFRClipboardMessage record = { 0 };
|
KVMFRClipboardMessage record = { 0 };
|
||||||
if (buffer.data && buffer.size >= sizeof(record))
|
if (buffer.data && buffer.size >= sizeof(record))
|
||||||
memcpy(&record, buffer.data, sizeof(record));
|
memcpy(&record, buffer.data, sizeof(record));
|
||||||
const bool valid = buffer.data &&
|
const bool valid = buffer.data &&
|
||||||
validateRecord(clipboard, &record, buffer.size,
|
validateRecord(clipboard, &record, buffer.size, true);
|
||||||
KVMFR_CLIPBOARD_QUEUE_DATA, true);
|
|
||||||
if (!valid)
|
if (!valid)
|
||||||
{
|
{
|
||||||
KVMFRClipboardMessage cancellation = { 0 };
|
KVMFRClipboardMessage cancellation = { 0 };
|
||||||
@@ -1810,7 +1740,6 @@ static bool processStream(LGMPClipboard * clipboard, bool * processed)
|
|||||||
record.transfer = clipboard->readRequest;
|
record.transfer = clipboard->readRequest;
|
||||||
clipboard->held = true;
|
clipboard->held = true;
|
||||||
clipboard->heldReady = true;
|
clipboard->heldReady = true;
|
||||||
clipboard->heldStream = true;
|
|
||||||
clipboard->heldStreamBuffer = buffer;
|
clipboard->heldStreamBuffer = buffer;
|
||||||
clipboard->heldRecord = record;
|
clipboard->heldRecord = record;
|
||||||
clipboard->heldFile = file;
|
clipboard->heldFile = file;
|
||||||
@@ -1875,66 +1804,16 @@ static bool processMessage(LGMPClipboard * clipboard, bool * processed)
|
|||||||
return status == LGMP_OK;
|
return status == LGMP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == KVMFR_CLIPBOARD_QUEUE_GRANT)
|
if (!clipboard->claimed)
|
||||||
{
|
{
|
||||||
uint64_t fileReady[CLIPBOARD_PENDING_MAX];
|
|
||||||
size_t fileReadyCount = 0;
|
|
||||||
KVMFRClipboardSlotHeader * header = message.mem;
|
|
||||||
const uint32_t token = KVMFR_CLIPBOARD_QUEUE_SERIAL(message.udata);
|
|
||||||
const bool valid = clipboard->claimTransport ==
|
|
||||||
KVMFR_CLIPBOARD_TRANSPORT_LEGACY &&
|
|
||||||
message.size ==
|
|
||||||
sizeof(*header) + KVMFR_CLIPBOARD_DATA_BYTES &&
|
|
||||||
header->version == KVMFR_CLIPBOARD_VERSION &&
|
|
||||||
header->type == KVMFR_CLIPBOARD_MESSAGE_GRANT &&
|
|
||||||
header->generation == clipboard->claimGeneration &&
|
|
||||||
header->size == KVMFR_CLIPBOARD_DATA_BYTES &&
|
|
||||||
header->token == token && token > 0 &&
|
|
||||||
token <= KVMFR_CLIPBOARD_SLOT_COUNT &&
|
|
||||||
!header->sequence && !header->clipboardGeneration &&
|
|
||||||
!header->transfer && !header->offset && !header->format &&
|
|
||||||
!header->flags && !header->length;
|
|
||||||
bool stored = false;
|
|
||||||
if (valid)
|
|
||||||
{
|
|
||||||
struct Grant * grant = &clipboard->grants[token - 1];
|
|
||||||
if (!grant->available)
|
|
||||||
{
|
|
||||||
grant->header = header;
|
|
||||||
grant->data = (uint8_t *)(header + 1);
|
|
||||||
grant->token = token;
|
|
||||||
grant->available = true;
|
|
||||||
stored = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
status = lgmpClientMessageDone(clipboard->queue);
|
status = lgmpClientMessageDone(clipboard->queue);
|
||||||
const bool ready = stored && clipboard->writeBlocked;
|
|
||||||
const LG_ClipboardRequest request = clipboard->writeBlockedRequest;
|
|
||||||
if (ready)
|
|
||||||
clipboard->writeBlocked = false;
|
|
||||||
if (stored)
|
|
||||||
for (struct FileTransfer * transfer = clipboard->fileWrites;
|
|
||||||
transfer && fileReadyCount < CLIPBOARD_PENDING_MAX;
|
|
||||||
transfer = transfer->next)
|
|
||||||
if (transfer->blocked)
|
|
||||||
{
|
|
||||||
transfer->blocked = false;
|
|
||||||
fileReady[fileReadyCount++] = transfer->request.request;
|
|
||||||
}
|
|
||||||
if (status != LGMP_OK)
|
if (status != LGMP_OK)
|
||||||
connectionFailed(clipboard, status);
|
connectionFailed(clipboard, status);
|
||||||
LG_UNLOCK(clipboard->lock);
|
LG_UNLOCK(clipboard->lock);
|
||||||
if (!stored)
|
|
||||||
DEBUG_WARN("Ignoring invalid LGMP clipboard grant");
|
|
||||||
if (ready)
|
|
||||||
dispatchReady(clipboard, request);
|
|
||||||
for (size_t i = 0; i < fileReadyCount; ++i)
|
|
||||||
dispatchFileReady(clipboard, fileReady[i]);
|
|
||||||
return status == LGMP_OK;
|
return status == LGMP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((type != KVMFR_CLIPBOARD_QUEUE_MESSAGE &&
|
if (type != KVMFR_CLIPBOARD_QUEUE_MESSAGE ||
|
||||||
type != KVMFR_CLIPBOARD_QUEUE_DATA) ||
|
|
||||||
message.size < sizeof(KVMFRClipboardMessage))
|
message.size < sizeof(KVMFRClipboardMessage))
|
||||||
{
|
{
|
||||||
status = lgmpClientMessageDone(clipboard->queue);
|
status = lgmpClientMessageDone(clipboard->queue);
|
||||||
@@ -1947,8 +1826,7 @@ static bool processMessage(LGMPClipboard * clipboard, bool * processed)
|
|||||||
|
|
||||||
KVMFRClipboardMessage record;
|
KVMFRClipboardMessage record;
|
||||||
memcpy(&record, message.mem, sizeof(record));
|
memcpy(&record, message.mem, sizeof(record));
|
||||||
const bool valid = validateRecord(
|
const bool valid = validateRecord(clipboard, &record, message.size, false);
|
||||||
clipboard, &record, message.size, type, false);
|
|
||||||
if (!valid)
|
if (!valid)
|
||||||
{
|
{
|
||||||
KVMFRClipboardMessage cancellation = { 0 };
|
KVMFRClipboardMessage cancellation = { 0 };
|
||||||
@@ -1967,47 +1845,6 @@ static bool processMessage(LGMPClipboard * clipboard, bool * processed)
|
|||||||
return status == LGMP_OK;
|
return status == LGMP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (record.type == KVMFR_CLIPBOARD_MESSAGE_DATA ||
|
|
||||||
record.type == KVMFR_CLIPBOARD_MESSAGE_FILE_DATA)
|
|
||||||
{
|
|
||||||
LG_ClipboardFileRequest fileRequest = { 0 };
|
|
||||||
const bool file = record.type == KVMFR_CLIPBOARD_MESSAGE_FILE_DATA;
|
|
||||||
const bool chunkValid = file ? validateFileReadChunkNL(
|
|
||||||
clipboard, &record, &fileRequest) :
|
|
||||||
validateReadChunkNL(clipboard, &record);
|
|
||||||
if (!chunkValid)
|
|
||||||
{
|
|
||||||
KVMFRClipboardMessage cancellation = { 0 };
|
|
||||||
bool queued = false;
|
|
||||||
const bool cancelled = file && rejectMalformedFileReadNL(
|
|
||||||
clipboard, &record, &cancellation, &queued);
|
|
||||||
status = lgmpClientMessageDone(clipboard->queue);
|
|
||||||
if (status != LGMP_OK)
|
|
||||||
connectionFailed(clipboard, status);
|
|
||||||
LG_UNLOCK(clipboard->lock);
|
|
||||||
if (cancelled)
|
|
||||||
dispatchFileCancel(clipboard, &cancellation);
|
|
||||||
if (queued)
|
|
||||||
signalWorker(clipboard);
|
|
||||||
DEBUG_WARN("Ignoring stale or malformed LGMP clipboard data");
|
|
||||||
return status == LGMP_OK;
|
|
||||||
}
|
|
||||||
if (!file)
|
|
||||||
record.transfer = clipboard->readRequest;
|
|
||||||
clipboard->held = true;
|
|
||||||
clipboard->heldReady = true;
|
|
||||||
clipboard->heldStream = false;
|
|
||||||
clipboard->heldMessage = message;
|
|
||||||
clipboard->heldRecord = record;
|
|
||||||
clipboard->heldFile = file;
|
|
||||||
clipboard->heldFileRequest = fileRequest;
|
|
||||||
clipboard->heldPhase =
|
|
||||||
(record.flags & KVMFR_CLIPBOARD_FLAG_BEGIN) ? HELD_PHASE_BEGIN :
|
|
||||||
record.length ? HELD_PHASE_CHUNK : HELD_PHASE_END;
|
|
||||||
LG_UNLOCK(clipboard->lock);
|
|
||||||
return processHeld(clipboard);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = lgmpClientMessageDone(clipboard->queue);
|
status = lgmpClientMessageDone(clipboard->queue);
|
||||||
if (status != LGMP_OK)
|
if (status != LGMP_OK)
|
||||||
{
|
{
|
||||||
@@ -2308,9 +2145,25 @@ static bool processMessage(LGMPClipboard * clipboard, bool * processed)
|
|||||||
static int clipboardThread(void * opaque)
|
static int clipboardThread(void * opaque)
|
||||||
{
|
{
|
||||||
LGMPClipboard * clipboard = opaque;
|
LGMPClipboard * clipboard = opaque;
|
||||||
|
LGMPStreamPollState streamPoll;
|
||||||
|
const LGMP_STATUS pollStatus = lgmpStreamPollInit(&streamPoll,
|
||||||
|
(struct LGMPStreamPollConfig)
|
||||||
|
{
|
||||||
|
.spinCount = 32U,
|
||||||
|
.minWaitUs = 50U,
|
||||||
|
.maxWaitUs = 1000U,
|
||||||
|
});
|
||||||
|
if (pollStatus != LGMP_OK)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to initialize LGMP clipboard polling: %s",
|
||||||
|
lgmpStatusString(pollStatus));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while (!atomic_load_explicit(&clipboard->stop, memory_order_acquire))
|
while (!atomic_load_explicit(&clipboard->stop, memory_order_acquire))
|
||||||
{
|
{
|
||||||
bool running = true;
|
bool running = true;
|
||||||
|
bool streamProgress = false;
|
||||||
unsigned drained = 0;
|
unsigned drained = 0;
|
||||||
for (; drained < CLIPBOARD_DRAIN_MAX; ++drained)
|
for (; drained < CLIPBOARD_DRAIN_MAX; ++drained)
|
||||||
{
|
{
|
||||||
@@ -2334,6 +2187,7 @@ static int clipboardThread(void * opaque)
|
|||||||
running = false;
|
running = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
streamProgress |= streamProcessed;
|
||||||
dispatchRetiredFiles(clipboard);
|
dispatchRetiredFiles(clipboard);
|
||||||
if (!queueProcessed && !streamProcessed)
|
if (!queueProcessed && !streamProcessed)
|
||||||
break;
|
break;
|
||||||
@@ -2362,6 +2216,8 @@ static int clipboardThread(void * opaque)
|
|||||||
const bool writable =
|
const bool writable =
|
||||||
(clipboard->writeBlocked || blockedFile) &&
|
(clipboard->writeBlocked || blockedFile) &&
|
||||||
dataWritableNL(clipboard);
|
dataWritableNL(clipboard);
|
||||||
|
if (writable)
|
||||||
|
streamProgress = true;
|
||||||
if (clipboard->writeBlocked && writable)
|
if (clipboard->writeBlocked && writable)
|
||||||
{
|
{
|
||||||
readyRequest = clipboard->writeBlockedRequest;
|
readyRequest = clipboard->writeBlockedRequest;
|
||||||
@@ -2380,6 +2236,8 @@ static int clipboardThread(void * opaque)
|
|||||||
clipboard->pendingCount || clipboard->held ||
|
clipboard->pendingCount || clipboard->held ||
|
||||||
clipboard->writeBlocked || clipboard->fileReads ||
|
clipboard->writeBlocked || clipboard->fileReads ||
|
||||||
clipboard->fileWrites;
|
clipboard->fileWrites;
|
||||||
|
const bool streamActive = clipboard->connected &&
|
||||||
|
(clipboard->claimed || clipboard->releasing);
|
||||||
LG_UNLOCK(clipboard->lock);
|
LG_UNLOCK(clipboard->lock);
|
||||||
|
|
||||||
if (readyRequest != LG_CLIPBOARD_REQUEST_INVALID)
|
if (readyRequest != LG_CLIPBOARD_REQUEST_INVALID)
|
||||||
@@ -2390,10 +2248,31 @@ static int clipboardThread(void * opaque)
|
|||||||
if (atomic_load_explicit(&clipboard->stop, memory_order_acquire))
|
if (atomic_load_explicit(&clipboard->stop, memory_order_acquire))
|
||||||
break;
|
break;
|
||||||
if (drained == CLIPBOARD_DRAIN_MAX)
|
if (drained == CLIPBOARD_DRAIN_MAX)
|
||||||
|
{
|
||||||
|
if (streamProgress)
|
||||||
|
lgmpStreamPollActivity(&streamPoll);
|
||||||
continue;
|
continue;
|
||||||
lgWaitEvent(clipboard->event,
|
}
|
||||||
|
|
||||||
|
bool signaled;
|
||||||
|
if (streamActive)
|
||||||
|
{
|
||||||
|
if (streamProgress)
|
||||||
|
lgmpStreamPollActivity(&streamPoll);
|
||||||
|
const uint32_t waitUs = lgmpStreamPollIdle(&streamPoll);
|
||||||
|
if (!waitUs)
|
||||||
|
continue;
|
||||||
|
signaled = lgWaitEventNS(clipboard->event, waitUs * 1000U);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lgmpStreamPollActivity(&streamPoll);
|
||||||
|
signaled = lgWaitEvent(clipboard->event,
|
||||||
active ? CLIPBOARD_ACTIVE_POLL_MS : CLIPBOARD_IDLE_POLL_MS);
|
active ? CLIPBOARD_ACTIVE_POLL_MS : CLIPBOARD_IDLE_POLL_MS);
|
||||||
}
|
}
|
||||||
|
if (signaled)
|
||||||
|
lgmpStreamPollActivity(&streamPoll);
|
||||||
|
}
|
||||||
dispatchRetiredFiles(clipboard);
|
dispatchRetiredFiles(clipboard);
|
||||||
notifyStatus(clipboard);
|
notifyStatus(clipboard);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2481,9 +2360,9 @@ bool lgmpClipboard_connect(LGMPClipboard * clipboard, uint32_t clientID)
|
|||||||
clipboard->connected = true;
|
clipboard->connected = true;
|
||||||
clipboard->available = false;
|
clipboard->available = false;
|
||||||
clipboard->statusValid = false;
|
clipboard->statusValid = false;
|
||||||
clipboard->transports = 0;
|
|
||||||
clipboard->claimed = false;
|
clipboard->claimed = false;
|
||||||
clipboard->ownerConfirmed = false;
|
clipboard->ownerConfirmed = false;
|
||||||
|
clipboard->releasing = false;
|
||||||
clipboard->clientID = clientID;
|
clipboard->clientID = clientID;
|
||||||
clipboard->endpointGeneration = 0;
|
clipboard->endpointGeneration = 0;
|
||||||
clipboard->statusSerial = 0;
|
clipboard->statusSerial = 0;
|
||||||
@@ -2496,7 +2375,6 @@ bool lgmpClipboard_connect(LGMPClipboard * clipboard, uint32_t clientID)
|
|||||||
clipboard->remoteClipboardGeneration = 0;
|
clipboard->remoteClipboardGeneration = 0;
|
||||||
clearReadNL(clipboard);
|
clearReadNL(clipboard);
|
||||||
clipboard->publishedClaimGeneration = 0;
|
clipboard->publishedClaimGeneration = 0;
|
||||||
memset(clipboard->grants, 0, sizeof(clipboard->grants));
|
|
||||||
atomic_store_explicit(&clipboard->stop, false, memory_order_release);
|
atomic_store_explicit(&clipboard->stop, false, memory_order_release);
|
||||||
|
|
||||||
LGThread * thread;
|
LGThread * thread;
|
||||||
@@ -2596,10 +2474,8 @@ void lgmpClipboard_disconnect(LGMPClipboard * clipboard)
|
|||||||
LG_LOCK(clipboard->lock);
|
LG_LOCK(clipboard->lock);
|
||||||
if (clipboard->held)
|
if (clipboard->held)
|
||||||
{
|
{
|
||||||
const LGMP_STATUS status = clipboard->heldStream ?
|
const LGMP_STATUS status = lgmpClientStreamReadRelease(
|
||||||
lgmpClientStreamReadRelease(clipboard->hostToClientStream,
|
clipboard->hostToClientStream, &clipboard->heldStreamBuffer);
|
||||||
&clipboard->heldStreamBuffer) : clipboard->queue ?
|
|
||||||
lgmpClientMessageDone(clipboard->queue) : LGMP_OK;
|
|
||||||
if (status != LGMP_OK && status != LGMP_ERR_STREAM_STALE &&
|
if (status != LGMP_OK && status != LGMP_ERR_STREAM_STALE &&
|
||||||
status != LGMP_ERR_STREAM_UNBOUND)
|
status != LGMP_ERR_STREAM_UNBOUND)
|
||||||
DEBUG_WARN("Failed to release held clipboard data during "
|
DEBUG_WARN("Failed to release held clipboard data during "
|
||||||
@@ -2611,10 +2487,8 @@ void lgmpClipboard_disconnect(LGMPClipboard * clipboard)
|
|||||||
clipboard->thread = NULL;
|
clipboard->thread = NULL;
|
||||||
clipboard->event = NULL;
|
clipboard->event = NULL;
|
||||||
clipboard->held = false;
|
clipboard->held = false;
|
||||||
clipboard->heldStream = false;
|
|
||||||
memset(&clipboard->heldStreamBuffer, 0,
|
memset(&clipboard->heldStreamBuffer, 0,
|
||||||
sizeof(clipboard->heldStreamBuffer));
|
sizeof(clipboard->heldStreamBuffer));
|
||||||
clipboard->transports = 0;
|
|
||||||
detachStreamsNL(clipboard);
|
detachStreamsNL(clipboard);
|
||||||
clearProtocolNL(clipboard);
|
clearProtocolNL(clipboard);
|
||||||
LG_UNLOCK(clipboard->lock);
|
LG_UNLOCK(clipboard->lock);
|
||||||
@@ -2688,20 +2562,30 @@ static bool attach(void * opaque, const LG_ClipboardEventOps * events,
|
|||||||
static void detach(void * opaque)
|
static void detach(void * opaque)
|
||||||
{
|
{
|
||||||
LGMPClipboard * clipboard = opaque;
|
LGMPClipboard * clipboard = opaque;
|
||||||
bool wake = false;
|
bool releaseQueued = false;
|
||||||
|
bool releaseRequired = false;
|
||||||
LG_LOCK(clipboard->eventLock);
|
LG_LOCK(clipboard->eventLock);
|
||||||
LG_LOCK(clipboard->lock);
|
LG_LOCK(clipboard->lock);
|
||||||
clipboard->events = NULL;
|
clipboard->events = NULL;
|
||||||
clipboard->eventOpaque = NULL;
|
clipboard->eventOpaque = NULL;
|
||||||
if (clipboard->claimed)
|
if (clipboard->claimed)
|
||||||
{
|
{
|
||||||
wake = enqueueTypeNL(
|
releaseRequired = true;
|
||||||
clipboard, KVMFR_CLIPBOARD_MESSAGE_RELEASE);
|
KVMFRClipboardMessage release = { 0 };
|
||||||
|
release.type = KVMFR_CLIPBOARD_MESSAGE_RELEASE;
|
||||||
|
releaseQueued = enqueueUrgentRecordNL(clipboard, release);
|
||||||
clipboard->claimed = false;
|
clipboard->claimed = false;
|
||||||
|
clipboard->releasing = true;
|
||||||
|
clipboard->available = false;
|
||||||
}
|
}
|
||||||
|
clearDataPlaneNL(clipboard);
|
||||||
|
if (clipboard->held)
|
||||||
|
clipboard->heldReady = true;
|
||||||
LG_UNLOCK(clipboard->lock);
|
LG_UNLOCK(clipboard->lock);
|
||||||
LG_UNLOCK(clipboard->eventLock);
|
LG_UNLOCK(clipboard->eventLock);
|
||||||
if (wake)
|
if (!releaseQueued && releaseRequired)
|
||||||
|
DEBUG_WARN("Failed to queue LGMP clipboard release; ownership will "
|
||||||
|
"expire");
|
||||||
signalWorker(clipboard);
|
signalWorker(clipboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,10 +31,10 @@
|
|||||||
#define KVMFR_CLIPBOARD_VERSION 4U
|
#define KVMFR_CLIPBOARD_VERSION 4U
|
||||||
#define KVMFR_CLIPBOARD_STREAM_VERSION 1U
|
#define KVMFR_CLIPBOARD_STREAM_VERSION 1U
|
||||||
|
|
||||||
/* Physical transport geometry. Keep these independent from the maximum
|
/* Physical stream geometry. Keep these independent from the maximum logical
|
||||||
* logical request and representation sizes below: one response may span
|
* request and representation sizes below: one response may span several
|
||||||
* several stream slots. The legacy grant transport uses the same geometry so
|
* stream slots. The generic names are also used by the Helper/IDD clipboard
|
||||||
* it remains a bounded fallback while stream adoption is staged. */
|
* ring, which intentionally has the same geometry. */
|
||||||
#define KVMFR_CLIPBOARD_STREAM_SLOT_COUNT 4U
|
#define KVMFR_CLIPBOARD_STREAM_SLOT_COUNT 4U
|
||||||
#define KVMFR_CLIPBOARD_STREAM_SLOT_BYTES (256U * 1024U)
|
#define KVMFR_CLIPBOARD_STREAM_SLOT_BYTES (256U * 1024U)
|
||||||
#define KVMFR_CLIPBOARD_STREAM_WINDOW_BYTES \
|
#define KVMFR_CLIPBOARD_STREAM_WINDOW_BYTES \
|
||||||
@@ -131,16 +131,13 @@ enum
|
|||||||
KVMFR_CLIPBOARD_MESSAGE_CLEAR = 5,
|
KVMFR_CLIPBOARD_MESSAGE_CLEAR = 5,
|
||||||
KVMFR_CLIPBOARD_MESSAGE_REQUEST = 6,
|
KVMFR_CLIPBOARD_MESSAGE_REQUEST = 6,
|
||||||
KVMFR_CLIPBOARD_MESSAGE_DATA = 7,
|
KVMFR_CLIPBOARD_MESSAGE_DATA = 7,
|
||||||
KVMFR_CLIPBOARD_MESSAGE_COMMIT = 8,
|
KVMFR_CLIPBOARD_MESSAGE_CANCEL = 8,
|
||||||
KVMFR_CLIPBOARD_MESSAGE_CANCEL = 9,
|
KVMFR_CLIPBOARD_MESSAGE_FILE_ACQUIRE = 9,
|
||||||
KVMFR_CLIPBOARD_MESSAGE_ACK = 10,
|
KVMFR_CLIPBOARD_MESSAGE_FILE_ACQUIRED = 10,
|
||||||
KVMFR_CLIPBOARD_MESSAGE_GRANT = 11,
|
KVMFR_CLIPBOARD_MESSAGE_FILE_RELEASE = 11,
|
||||||
KVMFR_CLIPBOARD_MESSAGE_FILE_ACQUIRE = 12,
|
KVMFR_CLIPBOARD_MESSAGE_FILE_REQUEST = 12,
|
||||||
KVMFR_CLIPBOARD_MESSAGE_FILE_ACQUIRED = 13,
|
KVMFR_CLIPBOARD_MESSAGE_FILE_DATA = 13,
|
||||||
KVMFR_CLIPBOARD_MESSAGE_FILE_RELEASE = 14,
|
KVMFR_CLIPBOARD_MESSAGE_FILE_CANCEL = 14
|
||||||
KVMFR_CLIPBOARD_MESSAGE_FILE_REQUEST = 15,
|
|
||||||
KVMFR_CLIPBOARD_MESSAGE_FILE_DATA = 16,
|
|
||||||
KVMFR_CLIPBOARD_MESSAGE_FILE_CANCEL = 17
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef uint32_t KVMFRClipboardMessageType;
|
typedef uint32_t KVMFRClipboardMessageType;
|
||||||
@@ -153,30 +150,12 @@ enum
|
|||||||
|
|
||||||
typedef uint32_t KVMFRClipboardFlags;
|
typedef uint32_t KVMFRClipboardFlags;
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
KVMFR_CLIPBOARD_TRANSPORT_LEGACY = 1U << 0,
|
|
||||||
KVMFR_CLIPBOARD_TRANSPORT_STREAM = 1U << 1,
|
|
||||||
KVMFR_CLIPBOARD_TRANSPORT_ALL =
|
|
||||||
KVMFR_CLIPBOARD_TRANSPORT_LEGACY |
|
|
||||||
KVMFR_CLIPBOARD_TRANSPORT_STREAM,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef uint32_t KVMFRClipboardTransportFlags;
|
|
||||||
|
|
||||||
static inline int kvmfrClipboardTransportValid(
|
|
||||||
KVMFRClipboardTransportFlags transport)
|
|
||||||
{
|
|
||||||
return transport && !(transport & (transport - 1U)) &&
|
|
||||||
!(transport & ~KVMFR_CLIPBOARD_TRANSPORT_ALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bidirectional control record. Client-to-host records must fit LGMP's
|
* Bidirectional control record. Client-to-host records must fit LGMP's
|
||||||
* 64-byte client message area. Host-to-client records use a small payload
|
* 64-byte client message area. Host-to-client records use a small payload
|
||||||
* pool and the same layout. CLAIM flags select exactly one transport offered
|
* pool and the same layout. DATA and FILE_DATA records are carried only by
|
||||||
* by KVMFRClipboardStatus. The selected transport is fixed until RELEASE and
|
* the duplex streams advertised in KVMFRClipboardStatus; all other records
|
||||||
* a subsequent CLAIM with a new generation.
|
* use the clipboard queue. CLAIM flags are reserved and must be zero.
|
||||||
*/
|
*/
|
||||||
typedef struct KVMFRClipboardMessage
|
typedef struct KVMFRClipboardMessage
|
||||||
{
|
{
|
||||||
@@ -369,14 +348,12 @@ static inline int kvmfrClipboardFileMessageValid(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Type-specific fields:
|
/* Type-specific fields:
|
||||||
* CLAIM: flags selects exactly one KVMFRClipboardTransportFlags value and
|
* CLAIM: token is the endpoint generation from the latest status.
|
||||||
* token is the endpoint generation from the latest status.
|
|
||||||
* OFFER: token is KVMFRClipboardFormatFlags.
|
* OFFER: token is KVMFRClipboardFormatFlags.
|
||||||
* REQUEST: format and transfer identify the requested representation.
|
* REQUEST: format and transfer identify the requested representation.
|
||||||
* DATA: size is an optional total hint on BEGIN and authoritative on END;
|
* DATA: size is an optional total hint on BEGIN and authoritative on END;
|
||||||
* offset/length describe this record's borrowed payload.
|
* offset/length describe this record's borrowed payload.
|
||||||
* CANCEL: token is a KVMFRClipboardCancelReason-compatible reason.
|
* CANCEL: token is a KVMFRClipboardCancelReason-compatible reason. */
|
||||||
* ACK/GRANT: token identifies the acknowledged or writable legacy slot. */
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@@ -386,11 +363,8 @@ enum
|
|||||||
|
|
||||||
typedef uint32_t KVMFRClipboardStatusFlags;
|
typedef uint32_t KVMFRClipboardStatusFlags;
|
||||||
|
|
||||||
/* transports advertises available data planes. When HAS_OWNER is set,
|
/* The duplex stream descriptors are always valid. Their slot size includes
|
||||||
* ownerTransport identifies the single data plane selected by that owner's
|
* KVMFRClipboardSlotHeader as well as slotBytes of payload. */
|
||||||
* CLAIM. Stream descriptors are valid only when STREAM is advertised; their
|
|
||||||
* slot size includes KVMFRClipboardSlotHeader as well as slotBytes of payload.
|
|
||||||
*/
|
|
||||||
typedef struct KVMFRClipboardStatus
|
typedef struct KVMFRClipboardStatus
|
||||||
{
|
{
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
@@ -401,11 +375,9 @@ typedef struct KVMFRClipboardStatus
|
|||||||
uint32_t lease;
|
uint32_t lease;
|
||||||
KVMFRClipboardFormatFlags formats;
|
KVMFRClipboardFormatFlags formats;
|
||||||
uint32_t slotBytes;
|
uint32_t slotBytes;
|
||||||
KVMFRClipboardTransportFlags transports;
|
|
||||||
KVMFRClipboardTransportFlags ownerTransport;
|
|
||||||
uint32_t streamVersion;
|
uint32_t streamVersion;
|
||||||
uint32_t streamSlotCount;
|
uint32_t streamSlotCount;
|
||||||
uint32_t reserved[4];
|
uint32_t reserved[6];
|
||||||
KVMFRStreamDescriptor hostToClient;
|
KVMFRStreamDescriptor hostToClient;
|
||||||
KVMFRStreamDescriptor clientToHost;
|
KVMFRStreamDescriptor clientToHost;
|
||||||
}
|
}
|
||||||
@@ -420,9 +392,7 @@ typedef KVMFRClipboardMessage KVMFRClipboardSlotHeader;
|
|||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
KVMFR_CLIPBOARD_QUEUE_STATUS = 1,
|
KVMFR_CLIPBOARD_QUEUE_STATUS = 1,
|
||||||
KVMFR_CLIPBOARD_QUEUE_MESSAGE = 2,
|
KVMFR_CLIPBOARD_QUEUE_MESSAGE = 2
|
||||||
KVMFR_CLIPBOARD_QUEUE_GRANT = 3,
|
|
||||||
KVMFR_CLIPBOARD_QUEUE_DATA = 4
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef uint32_t KVMFRClipboardQueueType;
|
typedef uint32_t KVMFRClipboardQueueType;
|
||||||
@@ -438,8 +408,8 @@ static_assert(sizeof(KVMFRClipboardMessage) == 64,
|
|||||||
"KVMFR clipboard control message layout changed");
|
"KVMFR clipboard control message layout changed");
|
||||||
static_assert(sizeof(KVMFRClipboardFileEntry) == 40,
|
static_assert(sizeof(KVMFRClipboardFileEntry) == 40,
|
||||||
"KVMFR clipboard file entry layout changed");
|
"KVMFR clipboard file entry layout changed");
|
||||||
static_assert(offsetof(KVMFRClipboardStatus, transports) == 32,
|
static_assert(offsetof(KVMFRClipboardStatus, streamVersion) == 32,
|
||||||
"KVMFR clipboard transport status layout changed");
|
"KVMFR clipboard stream status layout changed");
|
||||||
static_assert(offsetof(KVMFRClipboardStatus, hostToClient) == 64,
|
static_assert(offsetof(KVMFRClipboardStatus, hostToClient) == 64,
|
||||||
"KVMFR clipboard stream discovery layout changed");
|
"KVMFR clipboard stream discovery layout changed");
|
||||||
static_assert(sizeof(KVMFRClipboardStatus) == 128,
|
static_assert(sizeof(KVMFRClipboardStatus) == 128,
|
||||||
@@ -453,8 +423,8 @@ _Static_assert(sizeof(KVMFRClipboardMessage) == 64,
|
|||||||
"KVMFR clipboard control message layout changed");
|
"KVMFR clipboard control message layout changed");
|
||||||
_Static_assert(sizeof(KVMFRClipboardFileEntry) == 40,
|
_Static_assert(sizeof(KVMFRClipboardFileEntry) == 40,
|
||||||
"KVMFR clipboard file entry layout changed");
|
"KVMFR clipboard file entry layout changed");
|
||||||
_Static_assert(offsetof(KVMFRClipboardStatus, transports) == 32,
|
_Static_assert(offsetof(KVMFRClipboardStatus, streamVersion) == 32,
|
||||||
"KVMFR clipboard transport status layout changed");
|
"KVMFR clipboard stream status layout changed");
|
||||||
_Static_assert(offsetof(KVMFRClipboardStatus, hostToClient) == 64,
|
_Static_assert(offsetof(KVMFRClipboardStatus, hostToClient) == 64,
|
||||||
"KVMFR clipboard stream discovery layout changed");
|
"KVMFR clipboard stream discovery layout changed");
|
||||||
_Static_assert(sizeof(KVMFRClipboardStatus) == 128,
|
_Static_assert(sizeof(KVMFRClipboardStatus) == 128,
|
||||||
|
|||||||
@@ -49,11 +49,11 @@ namespace
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool EmptyControl(const KVMFRClipboardMessage& message,
|
bool EmptyControl(const KVMFRClipboardMessage& message,
|
||||||
bool keepToken = false, bool keepFlags = false)
|
bool keepToken = false)
|
||||||
{
|
{
|
||||||
return !message.clipboardGeneration && !message.transfer &&
|
return !message.clipboardGeneration && !message.transfer &&
|
||||||
!message.offset && !message.size && !message.format &&
|
!message.offset && !message.size && !message.format &&
|
||||||
(keepFlags || !message.flags) && (keepToken || !message.token) &&
|
!message.flags && (keepToken || !message.token) &&
|
||||||
!message.length && !message.sequence;
|
!message.length && !message.sequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,10 +177,6 @@ void CLGMPClipboardTransport::DeInit()
|
|||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
DeInitStreams();
|
DeInitStreams();
|
||||||
for (PLGMPMemory& memory : m_dataMemory)
|
|
||||||
lgmpHostMemFree(&memory);
|
|
||||||
for (PLGMPMemory& memory : m_grantMemory)
|
|
||||||
lgmpHostMemFree(&memory);
|
|
||||||
for (PLGMPMemory& memory : m_messageMemory)
|
for (PLGMPMemory& memory : m_messageMemory)
|
||||||
lgmpHostMemFree(&memory);
|
lgmpHostMemFree(&memory);
|
||||||
for (PLGMPMemory& memory : m_statusMemory)
|
for (PLGMPMemory& memory : m_statusMemory)
|
||||||
@@ -242,7 +238,7 @@ void CLGMPClipboardTransport::DeInitStreams()
|
|||||||
m_hostToClientDescriptor = {};
|
m_hostToClientDescriptor = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CLGMPClipboardTransport::BindStreams(uint32_t clientID)
|
bool CLGMPClipboardTransport::BindStreams(uint32_t clientID) const
|
||||||
{
|
{
|
||||||
if (!m_hostToClientStream || !m_clientToHostStream)
|
if (!m_hostToClientStream || !m_clientToHostStream)
|
||||||
return false;
|
return false;
|
||||||
@@ -301,7 +297,7 @@ bool CLGMPClipboardTransport::TryUnbindStreams()
|
|||||||
return complete;
|
return complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLGMPClipboardTransport::ForceUnbindStreams()
|
void CLGMPClipboardTransport::ForceUnbindStreams() const
|
||||||
{
|
{
|
||||||
if (m_clientToHostStream)
|
if (m_clientToHostStream)
|
||||||
{
|
{
|
||||||
@@ -321,7 +317,7 @@ void CLGMPClipboardTransport::ForceUnbindStreams()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLGMPClipboardTransport::Wake()
|
void CLGMPClipboardTransport::Wake() const
|
||||||
{
|
{
|
||||||
if (m_wakeEvent)
|
if (m_wakeEvent)
|
||||||
SetEvent(m_wakeEvent);
|
SetEvent(m_wakeEvent);
|
||||||
@@ -557,7 +553,7 @@ bool CLGMPClipboardTransport::QueueInternalTarget(
|
|||||||
const KVMFRClipboardMessage& record)
|
const KVMFRClipboardMessage& record)
|
||||||
{
|
{
|
||||||
if (!m_pendingTarget.valid && !m_internalTargetCount)
|
if (!m_pendingTarget.valid && !m_internalTargetCount)
|
||||||
return BeginTarget(record, nullptr, -2);
|
return BeginTarget(record, nullptr, false);
|
||||||
if (m_internalTargetCount == INTERNAL_TARGET_COUNT)
|
if (m_internalTargetCount == INTERNAL_TARGET_COUNT)
|
||||||
{
|
{
|
||||||
m_failed = true;
|
m_failed = true;
|
||||||
@@ -576,7 +572,7 @@ bool CLGMPClipboardTransport::PumpInternalTarget()
|
|||||||
for (unsigned i = 1; i < m_internalTargetCount; ++i)
|
for (unsigned i = 1; i < m_internalTargetCount; ++i)
|
||||||
m_internalTarget[i - 1] = m_internalTarget[i];
|
m_internalTarget[i - 1] = m_internalTarget[i];
|
||||||
m_internalTarget[--m_internalTargetCount] = {};
|
m_internalTarget[--m_internalTargetCount] = {};
|
||||||
return BeginTarget(record, nullptr, -2);
|
return BeginTarget(record, nullptr, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLGMPClipboardTransport::ClearStreamTargets()
|
void CLGMPClipboardTransport::ClearStreamTargets()
|
||||||
@@ -606,8 +602,7 @@ bool CLGMPClipboardTransport::QueueStreamTarget(
|
|||||||
bool CLGMPClipboardTransport::ProcessStreamTarget(
|
bool CLGMPClipboardTransport::ProcessStreamTarget(
|
||||||
const KVMFRClipboardMessage& record, const uint8_t * data)
|
const KVMFRClipboardMessage& record, const uint8_t * data)
|
||||||
{
|
{
|
||||||
if (!m_ownerClientID ||
|
if (!m_ownerClientID)
|
||||||
m_ownerTransport != KVMFR_CLIPBOARD_TRANSPORT_STREAM)
|
|
||||||
return true;
|
return true;
|
||||||
if (m_ownerReleasing && !m_releaseClearHelper)
|
if (m_ownerReleasing && !m_releaseClearHelper)
|
||||||
return true;
|
return true;
|
||||||
@@ -638,7 +633,7 @@ bool CLGMPClipboardTransport::ProcessStreamTarget(
|
|||||||
|
|
||||||
KVMFRClipboardMessage forwarded = record;
|
KVMFRClipboardMessage forwarded = record;
|
||||||
forwarded.generation = m_endpointGeneration;
|
forwarded.generation = m_endpointGeneration;
|
||||||
if (!BeginTarget(forwarded, data, -2))
|
if (!BeginTarget(forwarded, data, false))
|
||||||
{
|
{
|
||||||
ReleaseOwner("failed to stage clipboard stream data", true);
|
ReleaseOwner("failed to stage clipboard stream data", true);
|
||||||
return true;
|
return true;
|
||||||
@@ -666,9 +661,7 @@ bool CLGMPClipboardTransport::PumpStreamTarget()
|
|||||||
bool CLGMPClipboardTransport::DrainStream(bool& received)
|
bool CLGMPClipboardTransport::DrainStream(bool& received)
|
||||||
{
|
{
|
||||||
received = false;
|
received = false;
|
||||||
if (!m_ownerClientID ||
|
if (!m_ownerClientID || !m_clientToHostStream)
|
||||||
m_ownerTransport != KVMFR_CLIPBOARD_TRANSPORT_STREAM ||
|
|
||||||
!m_clientToHostStream)
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
for (unsigned drained = 0;
|
for (unsigned drained = 0;
|
||||||
@@ -744,12 +737,6 @@ void CLGMPClipboardTransport::ReleaseOwner(
|
|||||||
m_ownerDrainDeadline = GetTickCount64() + STREAM_DRAIN_TIMEOUT_MS;
|
m_ownerDrainDeadline = GetTickCount64() + STREAM_DRAIN_TIMEOUT_MS;
|
||||||
m_replayPending = false;
|
m_replayPending = false;
|
||||||
ClearOutboundBlock();
|
ClearOutboundBlock();
|
||||||
for (Grant& grant : m_grants)
|
|
||||||
{
|
|
||||||
grant.generation = 0;
|
|
||||||
grant.offered = false;
|
|
||||||
grant.committed = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (force)
|
else if (force)
|
||||||
{
|
{
|
||||||
@@ -757,12 +744,6 @@ void CLGMPClipboardTransport::ReleaseOwner(
|
|||||||
m_ownerReleaseReason = reason;
|
m_ownerReleaseReason = reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_ownerTransport != KVMFR_CLIPBOARD_TRANSPORT_STREAM)
|
|
||||||
{
|
|
||||||
FinishOwnerRelease();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (force)
|
if (force)
|
||||||
{
|
{
|
||||||
ForceUnbindStreams();
|
ForceUnbindStreams();
|
||||||
@@ -789,7 +770,6 @@ void CLGMPClipboardTransport::FinishOwnerRelease()
|
|||||||
const bool clearHelper = m_releaseClearHelper;
|
const bool clearHelper = m_releaseClearHelper;
|
||||||
m_ownerClientID = 0;
|
m_ownerClientID = 0;
|
||||||
m_ownerGeneration = 0;
|
m_ownerGeneration = 0;
|
||||||
m_ownerTransport = 0;
|
|
||||||
m_ownerReleasing = false;
|
m_ownerReleasing = false;
|
||||||
m_releaseClearHelper = false;
|
m_releaseClearHelper = false;
|
||||||
m_ownerReleaseReason = nullptr;
|
m_ownerReleaseReason = nullptr;
|
||||||
@@ -827,12 +807,6 @@ bool CLGMPClipboardTransport::RetryOwnerRelease()
|
|||||||
if (!m_ownerReleasing)
|
if (!m_ownerReleasing)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (m_ownerTransport != KVMFR_CLIPBOARD_TRANSPORT_STREAM)
|
|
||||||
{
|
|
||||||
FinishOwnerRelease();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetTickCount64() >= m_ownerDrainDeadline)
|
if (GetTickCount64() >= m_ownerDrainDeadline)
|
||||||
{
|
{
|
||||||
DEBUG_WARN("Timed out draining clipboard streams for owner %u "
|
DEBUG_WARN("Timed out draining clipboard streams for owner %u "
|
||||||
@@ -947,14 +921,10 @@ bool CLGMPClipboardTransport::PublishStatus()
|
|||||||
clipboardStatus.generation = m_endpointGeneration;
|
clipboardStatus.generation = m_endpointGeneration;
|
||||||
clipboardStatus.lease = static_cast<uint32_t>(OWNER_LEASE_MS);
|
clipboardStatus.lease = static_cast<uint32_t>(OWNER_LEASE_MS);
|
||||||
clipboardStatus.slotBytes = KVMFR_CLIPBOARD_DATA_BYTES;
|
clipboardStatus.slotBytes = KVMFR_CLIPBOARD_DATA_BYTES;
|
||||||
if (m_hostToClientStream && m_clientToHostStream)
|
|
||||||
{
|
|
||||||
clipboardStatus.transports = KVMFR_CLIPBOARD_TRANSPORT_STREAM;
|
|
||||||
clipboardStatus.streamVersion = KVMFR_CLIPBOARD_STREAM_VERSION;
|
clipboardStatus.streamVersion = KVMFR_CLIPBOARD_STREAM_VERSION;
|
||||||
clipboardStatus.streamSlotCount = KVMFR_CLIPBOARD_STREAM_SLOT_COUNT;
|
clipboardStatus.streamSlotCount = KVMFR_CLIPBOARD_STREAM_SLOT_COUNT;
|
||||||
clipboardStatus.hostToClient = m_hostToClientDescriptor;
|
clipboardStatus.hostToClient = m_hostToClientDescriptor;
|
||||||
clipboardStatus.clientToHost = m_clientToHostDescriptor;
|
clipboardStatus.clientToHost = m_clientToHostDescriptor;
|
||||||
}
|
|
||||||
if (m_available)
|
if (m_available)
|
||||||
{
|
{
|
||||||
clipboardStatus.flags |= KVMFR_CLIPBOARD_STATUS_AVAILABLE;
|
clipboardStatus.flags |= KVMFR_CLIPBOARD_STATUS_AVAILABLE;
|
||||||
@@ -965,7 +935,6 @@ bool CLGMPClipboardTransport::PublishStatus()
|
|||||||
clipboardStatus.flags |= KVMFR_CLIPBOARD_STATUS_HAS_OWNER;
|
clipboardStatus.flags |= KVMFR_CLIPBOARD_STATUS_HAS_OWNER;
|
||||||
clipboardStatus.ownerClientID = m_ownerClientID;
|
clipboardStatus.ownerClientID = m_ownerClientID;
|
||||||
clipboardStatus.ownerGeneration = m_ownerGeneration;
|
clipboardStatus.ownerGeneration = m_ownerGeneration;
|
||||||
clipboardStatus.ownerTransport = m_ownerTransport;
|
|
||||||
}
|
}
|
||||||
memcpy(lgmpHostMemPtr(memory), &clipboardStatus,
|
memcpy(lgmpHostMemPtr(memory), &clipboardStatus,
|
||||||
sizeof(clipboardStatus));
|
sizeof(clipboardStatus));
|
||||||
@@ -990,48 +959,6 @@ bool CLGMPClipboardTransport::PublishStatus()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CLGMPClipboardTransport::PostGrants()
|
|
||||||
{
|
|
||||||
if (!m_available || !m_ownerClientID || m_ownerReleasing ||
|
|
||||||
m_ownerTransport != KVMFR_CLIPBOARD_TRANSPORT_LEGACY)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < MEMORY_COUNT; ++i)
|
|
||||||
{
|
|
||||||
Grant& grant = m_grants[i];
|
|
||||||
if (grant.offered || grant.committed ||
|
|
||||||
lgmpHostQueuePayloadPending(m_queue, m_grantMemory[i]))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
KVMFRClipboardSlotHeader header = {};
|
|
||||||
header.version = KVMFR_CLIPBOARD_VERSION;
|
|
||||||
header.type = KVMFR_CLIPBOARD_MESSAGE_GRANT;
|
|
||||||
header.generation = m_ownerGeneration;
|
|
||||||
header.size = KVMFR_CLIPBOARD_DATA_BYTES;
|
|
||||||
header.token = i + 1;
|
|
||||||
memcpy(lgmpHostMemPtr(m_grantMemory[i]), &header, sizeof(header));
|
|
||||||
|
|
||||||
const PostResult result = PostForOwner(
|
|
||||||
KVMFR_CLIPBOARD_QUEUE_UDATA(
|
|
||||||
KVMFR_CLIPBOARD_QUEUE_GRANT, i + 1), m_grantMemory[i]);
|
|
||||||
if (result == PostResult::POSTED)
|
|
||||||
{
|
|
||||||
grant.generation = m_ownerGeneration;
|
|
||||||
grant.offered = true;
|
|
||||||
}
|
|
||||||
else if (result == PostResult::BUSY)
|
|
||||||
return true;
|
|
||||||
else if (result == PostResult::GONE)
|
|
||||||
{
|
|
||||||
ReleaseOwner("subscriber disappeared", true, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CLGMPClipboardTransport::ReplayClipboard()
|
bool CLGMPClipboardTransport::ReplayClipboard()
|
||||||
{
|
{
|
||||||
if (!m_replayPending || !m_ownerClientID || m_ownerReleasing)
|
if (!m_replayPending || !m_ownerClientID || m_ownerReleasing)
|
||||||
@@ -1066,15 +993,11 @@ bool CLGMPClipboardTransport::ReplayClipboard()
|
|||||||
bool CLGMPClipboardTransport::ValidateClaim(
|
bool CLGMPClipboardTransport::ValidateClaim(
|
||||||
const KVMFRClipboardMessage& message) const
|
const KVMFRClipboardMessage& message) const
|
||||||
{
|
{
|
||||||
KVMFRClipboardTransportFlags transports = 0;
|
|
||||||
if (m_hostToClientStream && m_clientToHostStream)
|
|
||||||
transports = KVMFR_CLIPBOARD_TRANSPORT_STREAM;
|
|
||||||
return message.version == KVMFR_CLIPBOARD_VERSION &&
|
return message.version == KVMFR_CLIPBOARD_VERSION &&
|
||||||
message.type == KVMFR_CLIPBOARD_MESSAGE_CLAIM &&
|
message.type == KVMFR_CLIPBOARD_MESSAGE_CLAIM &&
|
||||||
message.generation && message.token == m_endpointGeneration &&
|
message.generation && message.token == m_endpointGeneration &&
|
||||||
kvmfrClipboardTransportValid(message.flags) &&
|
m_hostToClientStream && m_clientToHostStream &&
|
||||||
(message.flags & transports) &&
|
EmptyControl(message, true);
|
||||||
EmptyControl(message, true, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CLGMPClipboardTransport::ValidateOwnedControl(
|
bool CLGMPClipboardTransport::ValidateOwnedControl(
|
||||||
@@ -1103,17 +1026,6 @@ bool CLGMPClipboardTransport::ValidateOwnedControl(
|
|||||||
case KVMFR_CLIPBOARD_MESSAGE_FILE_CANCEL:
|
case KVMFR_CLIPBOARD_MESSAGE_FILE_CANCEL:
|
||||||
return ValidateInboundRecord(message);
|
return ValidateInboundRecord(message);
|
||||||
|
|
||||||
case KVMFR_CLIPBOARD_MESSAGE_COMMIT:
|
|
||||||
return m_ownerTransport == KVMFR_CLIPBOARD_TRANSPORT_LEGACY &&
|
|
||||||
message.token >= 1 && message.token <= MEMORY_COUNT &&
|
|
||||||
message.clipboardGeneration && message.transfer &&
|
|
||||||
(kvmfrClipboardRepresentationFormatValid(message.format) ||
|
|
||||||
message.format == KVMFR_CLIPBOARD_FORMAT_FILES) &&
|
|
||||||
message.length <= KVMFR_CLIPBOARD_DATA_BYTES &&
|
|
||||||
!(message.flags & ~(KVMFR_CLIPBOARD_FLAG_BEGIN |
|
|
||||||
KVMFR_CLIPBOARD_FLAG_END)) &&
|
|
||||||
AddValid(message.offset, message.length);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1266,12 +1178,16 @@ void CLGMPClipboardTransport::ApplyInbound(
|
|||||||
case KVMFR_CLIPBOARD_MESSAGE_OFFER:
|
case KVMFR_CLIPBOARD_MESSAGE_OFFER:
|
||||||
m_clientClipboardGeneration = message.clipboardGeneration;
|
m_clientClipboardGeneration = message.clipboardGeneration;
|
||||||
m_clientFormats = message.token;
|
m_clientFormats = message.token;
|
||||||
|
if (m_clientToHelper.Active())
|
||||||
|
m_discardClientToHelper = m_clientToHelper.transfer;
|
||||||
m_clientToHelper.Clear();
|
m_clientToHelper.Clear();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KVMFR_CLIPBOARD_MESSAGE_CLEAR:
|
case KVMFR_CLIPBOARD_MESSAGE_CLEAR:
|
||||||
m_clientClipboardGeneration = 0;
|
m_clientClipboardGeneration = 0;
|
||||||
m_clientFormats = 0;
|
m_clientFormats = 0;
|
||||||
|
if (m_clientToHelper.Active())
|
||||||
|
m_discardClientToHelper = m_clientToHelper.transfer;
|
||||||
m_clientToHelper.Clear();
|
m_clientToHelper.Clear();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1352,7 +1268,8 @@ void CLGMPClipboardTransport::ApplyOutbound(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CLGMPClipboardTransport::BeginTarget(
|
bool CLGMPClipboardTransport::BeginTarget(
|
||||||
const KVMFRClipboardMessage& message, const uint8_t * data, int grant)
|
const KVMFRClipboardMessage& message, const uint8_t * data,
|
||||||
|
bool acknowledge)
|
||||||
{
|
{
|
||||||
if (m_pendingTarget.valid ||
|
if (m_pendingTarget.valid ||
|
||||||
(message.length && !data) ||
|
(message.length && !data) ||
|
||||||
@@ -1360,8 +1277,7 @@ bool CLGMPClipboardTransport::BeginTarget(
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_pendingTarget.valid = true;
|
m_pendingTarget.valid = true;
|
||||||
m_pendingTarget.acknowledge = grant >= -1;
|
m_pendingTarget.acknowledge = acknowledge;
|
||||||
m_pendingTarget.grant = grant;
|
|
||||||
m_pendingTarget.record = message;
|
m_pendingTarget.record = message;
|
||||||
if (message.length)
|
if (message.length)
|
||||||
memcpy(m_pendingTarget.data, data, message.length);
|
memcpy(m_pendingTarget.data, data, message.length);
|
||||||
@@ -1371,15 +1287,12 @@ bool CLGMPClipboardTransport::BeginTarget(
|
|||||||
void CLGMPClipboardTransport::FinishTarget(bool accepted)
|
void CLGMPClipboardTransport::FinishTarget(bool accepted)
|
||||||
{
|
{
|
||||||
const KVMFRClipboardMessage message = m_pendingTarget.record;
|
const KVMFRClipboardMessage message = m_pendingTarget.record;
|
||||||
const int grant = m_pendingTarget.grant;
|
|
||||||
if (accepted)
|
if (accepted)
|
||||||
{
|
{
|
||||||
ApplyInbound(message);
|
ApplyInbound(message);
|
||||||
if (m_ownerClientID && !m_ownerReleasing)
|
if (m_ownerClientID && !m_ownerReleasing)
|
||||||
RenewLease();
|
RenewLease();
|
||||||
}
|
}
|
||||||
if (grant >= 0 && static_cast<unsigned>(grant) < MEMORY_COUNT)
|
|
||||||
m_grants[grant] = {};
|
|
||||||
m_pendingTarget.Clear();
|
m_pendingTarget.Clear();
|
||||||
|
|
||||||
if (!accepted)
|
if (!accepted)
|
||||||
@@ -1426,9 +1339,6 @@ void CLGMPClipboardTransport::DropPendingTarget()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
const bool acknowledge = m_pendingTarget.acknowledge;
|
const bool acknowledge = m_pendingTarget.acknowledge;
|
||||||
const int grant = m_pendingTarget.grant;
|
|
||||||
if (grant >= 0 && static_cast<unsigned>(grant) < MEMORY_COUNT)
|
|
||||||
m_grants[grant] = {};
|
|
||||||
m_pendingTarget.Clear();
|
m_pendingTarget.Clear();
|
||||||
if (acknowledge && m_queue)
|
if (acknowledge && m_queue)
|
||||||
{
|
{
|
||||||
@@ -1453,8 +1363,7 @@ bool CLGMPClipboardTransport::ProcessMessage(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.flags == KVMFR_CLIPBOARD_TRANSPORT_STREAM &&
|
if (!BindStreams(clientID))
|
||||||
!BindStreams(clientID))
|
|
||||||
{
|
{
|
||||||
DeInitStreams();
|
DeInitStreams();
|
||||||
m_failed = true;
|
m_failed = true;
|
||||||
@@ -1465,7 +1374,6 @@ bool CLGMPClipboardTransport::ProcessMessage(
|
|||||||
|
|
||||||
m_ownerClientID = clientID;
|
m_ownerClientID = clientID;
|
||||||
m_ownerGeneration = message.generation;
|
m_ownerGeneration = message.generation;
|
||||||
m_ownerTransport = message.flags;
|
|
||||||
RenewLease();
|
RenewLease();
|
||||||
m_statusDirty = true;
|
m_statusDirty = true;
|
||||||
m_replayPending = m_cachedValid;
|
m_replayPending = m_cachedValid;
|
||||||
@@ -1511,66 +1419,6 @@ bool CLGMPClipboardTransport::ProcessMessage(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.type == KVMFR_CLIPBOARD_MESSAGE_COMMIT)
|
|
||||||
{
|
|
||||||
const unsigned grantIndex = message.token - 1;
|
|
||||||
Grant& grant = m_grants[grantIndex];
|
|
||||||
if (!grant.offered || grant.committed ||
|
|
||||||
grant.generation != m_ownerGeneration)
|
|
||||||
{
|
|
||||||
ReleaseOwner("invalid clipboard grant", true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t * slot = static_cast<const uint8_t *>(
|
|
||||||
lgmpHostMemPtr(m_grantMemory[grantIndex]));
|
|
||||||
KVMFRClipboardMessage dataMessage = {};
|
|
||||||
memcpy(&dataMessage, slot, sizeof(dataMessage));
|
|
||||||
const bool fileData = dataMessage.type ==
|
|
||||||
KVMFR_CLIPBOARD_MESSAGE_FILE_DATA;
|
|
||||||
const bool matchesCommit =
|
|
||||||
dataMessage.version == KVMFR_CLIPBOARD_VERSION &&
|
|
||||||
(dataMessage.type == KVMFR_CLIPBOARD_MESSAGE_DATA ||
|
|
||||||
fileData) &&
|
|
||||||
dataMessage.generation == m_ownerGeneration &&
|
|
||||||
dataMessage.clipboardGeneration == message.clipboardGeneration &&
|
|
||||||
dataMessage.transfer == message.transfer &&
|
|
||||||
dataMessage.offset == message.offset &&
|
|
||||||
dataMessage.size == message.size &&
|
|
||||||
dataMessage.format == message.format &&
|
|
||||||
dataMessage.flags == message.flags &&
|
|
||||||
dataMessage.length == message.length &&
|
|
||||||
dataMessage.sequence == message.sequence;
|
|
||||||
const bool staleFileData = fileData && m_files.IsStaleTerminal(
|
|
||||||
dataMessage, CLGMPClipboardFiles::Direction::CLIENT_TO_HELPER);
|
|
||||||
const bool validData = fileData ?
|
|
||||||
(staleFileData || m_files.Validate(dataMessage,
|
|
||||||
CLGMPClipboardFiles::Direction::CLIENT_TO_HELPER, 0, false)) :
|
|
||||||
(!dataMessage.token &&
|
|
||||||
kvmfrClipboardTransferFromHelper(dataMessage.transfer) &&
|
|
||||||
ValidateChunk(m_clientToHelper, dataMessage));
|
|
||||||
if (!matchesCommit || !validData)
|
|
||||||
{
|
|
||||||
ReleaseOwner("invalid clipboard commit", true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (staleFileData)
|
|
||||||
{
|
|
||||||
grant = {};
|
|
||||||
RenewLease();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
grant.committed = true;
|
|
||||||
dataMessage.generation = m_endpointGeneration;
|
|
||||||
RenewLease();
|
|
||||||
BeginTarget(dataMessage,
|
|
||||||
slot + sizeof(KVMFRClipboardSlotHeader),
|
|
||||||
static_cast<int>(grantIndex));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_files.IsStaleTerminal(message,
|
if (m_files.IsStaleTerminal(message,
|
||||||
CLGMPClipboardFiles::Direction::CLIENT_TO_HELPER))
|
CLGMPClipboardFiles::Direction::CLIENT_TO_HELPER))
|
||||||
{
|
{
|
||||||
@@ -1601,7 +1449,7 @@ bool CLGMPClipboardTransport::ProcessMessage(
|
|||||||
KVMFRClipboardMessage forwarded = message;
|
KVMFRClipboardMessage forwarded = message;
|
||||||
forwarded.generation = m_endpointGeneration;
|
forwarded.generation = m_endpointGeneration;
|
||||||
RenewLease();
|
RenewLease();
|
||||||
BeginTarget(forwarded, nullptr, -1);
|
BeginTarget(forwarded, nullptr, true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1692,8 +1540,6 @@ ClipboardChannelResult CLGMPClipboardTransport::SendData(
|
|||||||
|
|
||||||
KVMFRClipboardMessage message = record;
|
KVMFRClipboardMessage message = record;
|
||||||
message.generation = m_ownerGeneration;
|
message.generation = m_ownerGeneration;
|
||||||
if (m_ownerTransport == KVMFR_CLIPBOARD_TRANSPORT_STREAM)
|
|
||||||
{
|
|
||||||
LGMPStreamBuffer buffer = {};
|
LGMPStreamBuffer buffer = {};
|
||||||
LGMP_STATUS status =
|
LGMP_STATUS status =
|
||||||
lgmpHostStreamWriteAcquire(m_hostToClientStream, &buffer);
|
lgmpHostStreamWriteAcquire(m_hostToClientStream, &buffer);
|
||||||
@@ -1750,38 +1596,6 @@ ClipboardChannelResult CLGMPClipboardTransport::SendData(
|
|||||||
}
|
}
|
||||||
Fail("lgmpHostStreamWriteCommit", status);
|
Fail("lgmpHostStreamWriteCommit", status);
|
||||||
return ClipboardChannelResult::FAILED;
|
return ClipboardChannelResult::FAILED;
|
||||||
}
|
|
||||||
|
|
||||||
if (m_ownerTransport != KVMFR_CLIPBOARD_TRANSPORT_LEGACY)
|
|
||||||
return ClipboardChannelResult::FAILED;
|
|
||||||
|
|
||||||
PLGMPMemory memory = FindAvailable(m_dataMemory);
|
|
||||||
if (!memory)
|
|
||||||
return ClipboardChannelResult::BUSY;
|
|
||||||
|
|
||||||
uint8_t * slot = static_cast<uint8_t *>(lgmpHostMemPtr(memory));
|
|
||||||
memcpy(slot, &message, sizeof(message));
|
|
||||||
if (message.length)
|
|
||||||
memcpy(slot + sizeof(KVMFRClipboardSlotHeader), data, message.length);
|
|
||||||
|
|
||||||
const uint32_t serial = Seq::Next(m_dataSerial);
|
|
||||||
const PostResult result = PostForOwner(
|
|
||||||
KVMFR_CLIPBOARD_QUEUE_UDATA(
|
|
||||||
KVMFR_CLIPBOARD_QUEUE_DATA, serial), memory);
|
|
||||||
if (result == PostResult::POSTED)
|
|
||||||
{
|
|
||||||
m_dataSerial = serial;
|
|
||||||
ApplyOutbound(record);
|
|
||||||
return ClipboardChannelResult::ACCEPTED;
|
|
||||||
}
|
|
||||||
if (result == PostResult::BUSY)
|
|
||||||
return ClipboardChannelResult::BUSY;
|
|
||||||
if (result == PostResult::GONE)
|
|
||||||
{
|
|
||||||
ReleaseOwner("subscriber disappeared", true, true);
|
|
||||||
return ClipboardChannelResult::ACCEPTED;
|
|
||||||
}
|
|
||||||
return ClipboardChannelResult::FAILED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClipboardChannelResult CLGMPClipboardTransport::SendClipboard(
|
ClipboardChannelResult CLGMPClipboardTransport::SendClipboard(
|
||||||
@@ -2002,6 +1816,24 @@ DWORD CALLBACK CLGMPClipboardTransport::ThreadProc(void * context)
|
|||||||
|
|
||||||
void CLGMPClipboardTransport::Thread()
|
void CLGMPClipboardTransport::Thread()
|
||||||
{
|
{
|
||||||
|
LGMPStreamPollState streamPoll = {};
|
||||||
|
const LGMPStreamPollConfig pollConfig =
|
||||||
|
{
|
||||||
|
32U,
|
||||||
|
50U,
|
||||||
|
1000U,
|
||||||
|
};
|
||||||
|
const LGMP_STATUS pollStatus = lgmpStreamPollInit(&streamPoll,
|
||||||
|
pollConfig);
|
||||||
|
if (pollStatus != LGMP_OK)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to initialize LGMP clipboard polling: %s",
|
||||||
|
lgmpStatusString(pollStatus));
|
||||||
|
if (m_target)
|
||||||
|
m_target->ClipboardFailed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool notifyFailed = false;
|
bool notifyFailed = false;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@@ -2034,7 +1866,7 @@ void CLGMPClipboardTransport::Thread()
|
|||||||
!DrainStream(streamReceived) ||
|
!DrainStream(streamReceived) ||
|
||||||
!RetryOwnerRelease() ||
|
!RetryOwnerRelease() ||
|
||||||
!PublishStatus() ||
|
!PublishStatus() ||
|
||||||
!ReplayClipboard() || !PostGrants())
|
!ReplayClipboard())
|
||||||
{
|
{
|
||||||
notifyFailed = true;
|
notifyFailed = true;
|
||||||
break;
|
break;
|
||||||
@@ -2048,10 +1880,15 @@ void CLGMPClipboardTransport::Thread()
|
|||||||
if (m_pendingTarget.valid || m_internalTargetCount ||
|
if (m_pendingTarget.valid || m_internalTargetCount ||
|
||||||
m_streamTargetCount || m_ownerClientID)
|
m_streamTargetCount || m_ownerClientID)
|
||||||
timeout = ACTIVE_POLL_MS;
|
timeout = ACTIVE_POLL_MS;
|
||||||
if (m_ownerTransport == KVMFR_CLIPBOARD_TRANSPORT_STREAM)
|
if (m_ownerClientID)
|
||||||
timeout = STREAM_POLL_MS;
|
{
|
||||||
if (streamReceived)
|
if (streamReceived)
|
||||||
timeout = 0;
|
lgmpStreamPollActivity(&streamPoll);
|
||||||
|
const uint32_t waitUs = lgmpStreamPollIdle(&streamPoll);
|
||||||
|
timeout = waitUs ? (waitUs + 999U) / 1000U : 0U;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
lgmpStreamPollActivity(&streamPoll);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClipboardReceiveReady may synchronously retry SendClipboard, which
|
// ClipboardReceiveReady may synchronously retry SendClipboard, which
|
||||||
@@ -2064,6 +1901,11 @@ void CLGMPClipboardTransport::Thread()
|
|||||||
_countof(handles), handles, FALSE, timeout);
|
_countof(handles), handles, FALSE, timeout);
|
||||||
if (wait == WAIT_FIRST_OBJECT_VALUE)
|
if (wait == WAIT_FIRST_OBJECT_VALUE)
|
||||||
break;
|
break;
|
||||||
|
if (wait == WAIT_FIRST_OBJECT_VALUE + 1)
|
||||||
|
{
|
||||||
|
lgmpStreamPollActivity(&streamPoll);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (wait != WAIT_FIRST_OBJECT_VALUE + 1 && wait != WAIT_TIMEOUT)
|
if (wait != WAIT_FIRST_OBJECT_VALUE + 1 && wait != WAIT_TIMEOUT)
|
||||||
{
|
{
|
||||||
DEBUG_ERROR_HR(GetLastError(),
|
DEBUG_ERROR_HR(GetLastError(),
|
||||||
|
|||||||
@@ -41,14 +41,14 @@ class CLGMPHost;
|
|||||||
class CLGMPClipboardTransport final : public IClipboardSource
|
class CLGMPClipboardTransport final : public IClipboardSource
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
static constexpr unsigned MEMORY_COUNT = KVMFR_CLIPBOARD_SLOT_COUNT;
|
static constexpr unsigned MEMORY_COUNT =
|
||||||
|
KVMFR_CLIPBOARD_STREAM_SLOT_COUNT;
|
||||||
static constexpr unsigned INTERNAL_TARGET_COUNT =
|
static constexpr unsigned INTERNAL_TARGET_COUNT =
|
||||||
CLGMPClipboardFiles::MAX_ACQUISITIONS +
|
CLGMPClipboardFiles::MAX_ACQUISITIONS +
|
||||||
CLGMPClipboardFiles::MAX_REQUESTS + 3;
|
CLGMPClipboardFiles::MAX_REQUESTS + 3;
|
||||||
static constexpr ULONGLONG OWNER_LEASE_MS = 1000;
|
static constexpr ULONGLONG OWNER_LEASE_MS = 1000;
|
||||||
static constexpr ULONGLONG STREAM_DRAIN_TIMEOUT_MS = 1000;
|
static constexpr ULONGLONG STREAM_DRAIN_TIMEOUT_MS = 1000;
|
||||||
static constexpr DWORD ACTIVE_POLL_MS = 5;
|
static constexpr DWORD ACTIVE_POLL_MS = 5;
|
||||||
static constexpr DWORD STREAM_POLL_MS = 1;
|
|
||||||
static constexpr DWORD IDLE_POLL_MS = 50;
|
static constexpr DWORD IDLE_POLL_MS = 50;
|
||||||
static constexpr unsigned STREAM_TARGET_COUNT =
|
static constexpr unsigned STREAM_TARGET_COUNT =
|
||||||
KVMFR_CLIPBOARD_STREAM_SLOT_COUNT;
|
KVMFR_CLIPBOARD_STREAM_SLOT_COUNT;
|
||||||
@@ -78,18 +78,10 @@ private:
|
|||||||
bool Active() const { return transfer != 0; }
|
bool Active() const { return transfer != 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Grant
|
|
||||||
{
|
|
||||||
uint32_t generation = 0;
|
|
||||||
bool offered = false;
|
|
||||||
bool committed = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PendingTarget
|
struct PendingTarget
|
||||||
{
|
{
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
bool acknowledge = false;
|
bool acknowledge = false;
|
||||||
int grant = -1;
|
|
||||||
KVMFRClipboardMessage record = {};
|
KVMFRClipboardMessage record = {};
|
||||||
uint8_t data[KVMFR_CLIPBOARD_DATA_BYTES] = {};
|
uint8_t data[KVMFR_CLIPBOARD_DATA_BYTES] = {};
|
||||||
|
|
||||||
@@ -97,7 +89,6 @@ private:
|
|||||||
{
|
{
|
||||||
valid = false;
|
valid = false;
|
||||||
acknowledge = false;
|
acknowledge = false;
|
||||||
grant = -1;
|
|
||||||
record = {};
|
record = {};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -117,8 +108,6 @@ private:
|
|||||||
PLGMPHostStream m_clientToHostStream = nullptr;
|
PLGMPHostStream m_clientToHostStream = nullptr;
|
||||||
PLGMPMemory m_statusMemory [MEMORY_COUNT] = {};
|
PLGMPMemory m_statusMemory [MEMORY_COUNT] = {};
|
||||||
PLGMPMemory m_messageMemory[MEMORY_COUNT] = {};
|
PLGMPMemory m_messageMemory[MEMORY_COUNT] = {};
|
||||||
PLGMPMemory m_grantMemory [MEMORY_COUNT] = {};
|
|
||||||
PLGMPMemory m_dataMemory [MEMORY_COUNT] = {};
|
|
||||||
|
|
||||||
CSRWLock m_lifecycleLock;
|
CSRWLock m_lifecycleLock;
|
||||||
CSRWLock m_lock;
|
CSRWLock m_lock;
|
||||||
@@ -138,10 +127,8 @@ private:
|
|||||||
uint32_t m_endpointGeneration = 0;
|
uint32_t m_endpointGeneration = 0;
|
||||||
uint32_t m_ownerClientID = 0;
|
uint32_t m_ownerClientID = 0;
|
||||||
uint32_t m_ownerGeneration = 0;
|
uint32_t m_ownerGeneration = 0;
|
||||||
KVMFRClipboardTransportFlags m_ownerTransport = 0;
|
|
||||||
uint32_t m_statusSerial = 0;
|
uint32_t m_statusSerial = 0;
|
||||||
uint32_t m_messageSerial = 0;
|
uint32_t m_messageSerial = 0;
|
||||||
uint32_t m_dataSerial = 0;
|
|
||||||
uint32_t m_helperFormats = 0;
|
uint32_t m_helperFormats = 0;
|
||||||
uint32_t m_clientFormats = 0;
|
uint32_t m_clientFormats = 0;
|
||||||
uint32_t m_blockedOwnerClientID = 0;
|
uint32_t m_blockedOwnerClientID = 0;
|
||||||
@@ -158,7 +145,6 @@ private:
|
|||||||
KVMFRStreamDescriptor m_clientToHostDescriptor = {};
|
KVMFRStreamDescriptor m_clientToHostDescriptor = {};
|
||||||
Transfer m_clientToHelper;
|
Transfer m_clientToHelper;
|
||||||
Transfer m_helperToClient;
|
Transfer m_helperToClient;
|
||||||
Grant m_grants[MEMORY_COUNT];
|
|
||||||
PendingTarget m_pendingTarget;
|
PendingTarget m_pendingTarget;
|
||||||
StreamTarget m_streamTarget[STREAM_TARGET_COUNT];
|
StreamTarget m_streamTarget[STREAM_TARGET_COUNT];
|
||||||
unsigned m_streamTargetHead = 0;
|
unsigned m_streamTargetHead = 0;
|
||||||
@@ -171,13 +157,13 @@ private:
|
|||||||
void DeInit();
|
void DeInit();
|
||||||
bool InitializeStreams();
|
bool InitializeStreams();
|
||||||
void DeInitStreams();
|
void DeInitStreams();
|
||||||
bool BindStreams(uint32_t clientID);
|
bool BindStreams(uint32_t clientID) const;
|
||||||
bool TryUnbindStreams();
|
bool TryUnbindStreams();
|
||||||
void ForceUnbindStreams();
|
void ForceUnbindStreams() const;
|
||||||
|
|
||||||
static DWORD CALLBACK ThreadProc(void * context);
|
static DWORD CALLBACK ThreadProc(void * context);
|
||||||
void Thread();
|
void Thread();
|
||||||
void Wake();
|
void Wake() const;
|
||||||
|
|
||||||
bool IsOwner(uint32_t clientID, uint32_t generation) const;
|
bool IsOwner(uint32_t clientID, uint32_t generation) const;
|
||||||
bool OwnerSubscribed() const;
|
bool OwnerSubscribed() const;
|
||||||
@@ -210,7 +196,6 @@ private:
|
|||||||
PLGMPMemory FindAvailable(PLGMPMemory (&memory)[MEMORY_COUNT]) const;
|
PLGMPMemory FindAvailable(PLGMPMemory (&memory)[MEMORY_COUNT]) const;
|
||||||
PostResult PostForOwner(uint64_t udata, PLGMPMemory memory);
|
PostResult PostForOwner(uint64_t udata, PLGMPMemory memory);
|
||||||
bool PublishStatus();
|
bool PublishStatus();
|
||||||
bool PostGrants();
|
|
||||||
bool ReplayClipboard();
|
bool ReplayClipboard();
|
||||||
bool DrainMessage();
|
bool DrainMessage();
|
||||||
bool ProcessMessage(uint32_t clientID,
|
bool ProcessMessage(uint32_t clientID,
|
||||||
@@ -231,7 +216,7 @@ private:
|
|||||||
void ApplyInbound(const KVMFRClipboardMessage& message);
|
void ApplyInbound(const KVMFRClipboardMessage& message);
|
||||||
void ApplyOutbound(const KVMFRClipboardMessage& message);
|
void ApplyOutbound(const KVMFRClipboardMessage& message);
|
||||||
bool BeginTarget(const KVMFRClipboardMessage& message,
|
bool BeginTarget(const KVMFRClipboardMessage& message,
|
||||||
const uint8_t * data, int grant);
|
const uint8_t * data, bool acknowledge);
|
||||||
|
|
||||||
ClipboardChannelResult SendControl(
|
ClipboardChannelResult SendControl(
|
||||||
const KVMFRClipboardMessage& record);
|
const KVMFRClipboardMessage& record);
|
||||||
|
|||||||
Reference in New Issue
Block a user