mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-11-13 15:27:21 +00:00
[idd] network: bind clipboard to input authority
This commit is contained in:
@@ -70,6 +70,12 @@ InputTargetState CInputHub::Source::GetState(
|
|||||||
return owner->GetState(Key(source));
|
return owner->GetState(Key(source));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CInputHub::Source::WithAuthority(const InputSourceId& source,
|
||||||
|
InputAuthorityAction action, void * opaque)
|
||||||
|
{
|
||||||
|
return owner->WithAuthority(Key(source), action, opaque);
|
||||||
|
}
|
||||||
|
|
||||||
void CInputHub::Source::Failed()
|
void CInputHub::Source::Failed()
|
||||||
{
|
{
|
||||||
owner->Failed(*this);
|
owner->Failed(*this);
|
||||||
@@ -565,6 +571,20 @@ InputTargetState CInputHub::GetState(const SourceKey& source)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CInputHub::WithAuthority(const SourceKey& source,
|
||||||
|
InputAuthorityAction action, void * opaque)
|
||||||
|
{
|
||||||
|
if (!action)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CSRWExclusiveLock lock(m_lock);
|
||||||
|
if (!SourceValid(source) || !CheckState() || !OwnerValid(source))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
action(opaque);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void CInputHub::Failed(Source& source)
|
void CInputHub::Failed(Source& source)
|
||||||
{
|
{
|
||||||
CSRWExclusiveLock lock(m_lock);
|
CSRWExclusiveLock lock(m_lock);
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ private:
|
|||||||
|
|
||||||
SourceKey Key(const InputSourceId& source) const;
|
SourceKey Key(const InputSourceId& source) const;
|
||||||
InputTargetState GetState(const InputSourceId& source) override;
|
InputTargetState GetState(const InputSourceId& source) override;
|
||||||
|
bool WithAuthority(const InputSourceId& source,
|
||||||
|
InputAuthorityAction action, void * opaque) override;
|
||||||
void Failed() override;
|
void Failed() override;
|
||||||
InputResult Claim(const InputSourceId& source) override;
|
InputResult Claim(const InputSourceId& source) override;
|
||||||
InputResult Touch(const InputSourceId& source) override;
|
InputResult Touch(const InputSourceId& source) override;
|
||||||
@@ -94,6 +96,8 @@ private:
|
|||||||
void AdvanceInteractionSerial();
|
void AdvanceInteractionSerial();
|
||||||
bool CheckState();
|
bool CheckState();
|
||||||
InputTargetState GetState(const SourceKey& source);
|
InputTargetState GetState(const SourceKey& source);
|
||||||
|
bool WithAuthority(const SourceKey& source,
|
||||||
|
InputAuthorityAction action, void * opaque);
|
||||||
void Failed(Source& source);
|
void Failed(Source& source);
|
||||||
InputResult Claim(const SourceKey& source);
|
InputResult Claim(const SourceKey& source);
|
||||||
InputResult Touch(const SourceKey& source);
|
InputResult Touch(const SourceKey& source);
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ struct InputTargetState
|
|||||||
uint8_t keyboardLEDs = 0;
|
uint8_t keyboardLEDs = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using InputAuthorityAction = void (*)(void * opaque);
|
||||||
|
|
||||||
enum class InputResult
|
enum class InputResult
|
||||||
{
|
{
|
||||||
ACCEPTED,
|
ACCEPTED,
|
||||||
@@ -52,6 +54,10 @@ public:
|
|||||||
virtual ~IInputTarget() = default;
|
virtual ~IInputTarget() = default;
|
||||||
|
|
||||||
virtual InputTargetState GetState(const InputSourceId& source) = 0;
|
virtual InputTargetState GetState(const InputSourceId& source) = 0;
|
||||||
|
// The action runs synchronously while input ownership cannot change and
|
||||||
|
// must not call back through this input target.
|
||||||
|
virtual bool WithAuthority(const InputSourceId& source,
|
||||||
|
InputAuthorityAction action, void * opaque) = 0;
|
||||||
virtual void Failed() = 0;
|
virtual void Failed() = 0;
|
||||||
virtual InputResult Claim(const InputSourceId& source) = 0;
|
virtual InputResult Claim(const InputSourceId& source) = 0;
|
||||||
virtual InputResult Touch(const InputSourceId& source) = 0;
|
virtual InputResult Touch(const InputSourceId& source) = 0;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "transport/network/CNetworkClipboard.h"
|
#include "transport/network/CNetworkClipboard.h"
|
||||||
|
|
||||||
|
#include "CDebug.h"
|
||||||
#include "CSRWLock.h"
|
#include "CSRWLock.h"
|
||||||
|
|
||||||
#include <LGProtocol/NetworkClipboard.h>
|
#include <LGProtocol/NetworkClipboard.h>
|
||||||
@@ -48,6 +49,7 @@ namespace
|
|||||||
constexpr uint32_t MAX_FILE_READ_LENGTH = KVMFR_CLIPBOARD_FILE_READ_BYTES;
|
constexpr uint32_t MAX_FILE_READ_LENGTH = KVMFR_CLIPBOARD_FILE_READ_BYTES;
|
||||||
constexpr uint32_t MIN_CHUNK_LENGTH =
|
constexpr uint32_t MIN_CHUNK_LENGTH =
|
||||||
(MAX_CHUNK_LENGTH + MAX_SEND_COUNT - 3U) / (MAX_SEND_COUNT - 2U);
|
(MAX_CHUNK_LENGTH + MAX_SEND_COUNT - 3U) / (MAX_SEND_COUNT - 2U);
|
||||||
|
constexpr uint32_t CLAIM_INPUT_REQUIRED = 4;
|
||||||
|
|
||||||
constexpr LGNetClipboardClaimFlags CLAIM_FLAGS =
|
constexpr LGNetClipboardClaimFlags CLAIM_FLAGS =
|
||||||
LG_NET_CLIPBOARD_CLAIM_READ | LG_NET_CLIPBOARD_CLAIM_WRITE;
|
LG_NET_CLIPBOARD_CLAIM_READ | LG_NET_CLIPBOARD_CLAIM_WRITE;
|
||||||
@@ -247,10 +249,12 @@ struct CNetworkClipboard::Impl
|
|||||||
|
|
||||||
struct TargetItem
|
struct TargetItem
|
||||||
{
|
{
|
||||||
uint64_t serial = 0;
|
uint64_t serial = 0;
|
||||||
KVMFRClipboardMessage record = {};
|
NetworkClipboardPeer peer = {};
|
||||||
std::vector<uint8_t> data = {};
|
uint64_t claimEpoch = 0;
|
||||||
bool wasBlocked = false;
|
KVMFRClipboardMessage record = {};
|
||||||
|
std::vector<uint8_t> data = {};
|
||||||
|
bool wasBlocked = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
CSRWLock m_lifecycleLock;
|
CSRWLock m_lifecycleLock;
|
||||||
@@ -388,20 +392,24 @@ struct CNetworkClipboard::Impl
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QueueSendBatchNL(std::vector<SendItem>& batch);
|
bool QueueSendBatchNL(std::vector<SendItem>& batch);
|
||||||
bool QueueTargetNL(TargetItem&& item);
|
bool QueueTargetNL(TargetItem&& item);
|
||||||
bool SelectBulkNL(
|
bool QueueOwnerTargetNL(TargetItem&& item);
|
||||||
|
bool PeerOwnsInput(const NetworkClipboardPeer& peer);
|
||||||
|
bool WithInputAuthority(const NetworkClipboardPeer& peer,
|
||||||
|
NetworkClipboardInputAction action, void * opaque);
|
||||||
|
bool SelectBulkNL(
|
||||||
const PeerState& peer, LGNetService service, uint32_t payloadLength) const;
|
const PeerState& peer, LGNetService service, uint32_t payloadLength) const;
|
||||||
bool PayloadFitsNL(const PeerState& peer, LGNetService service, bool bulk,
|
bool PayloadFitsNL(const PeerState& peer, LGNetService service, bool bulk,
|
||||||
uint32_t payloadLength) const;
|
uint32_t payloadLength) const;
|
||||||
uint32_t ChunkLengthNL(
|
uint32_t ChunkLengthNL(
|
||||||
const PeerState& peer, LGNetService service, uint32_t headerLength,
|
const PeerState& peer, LGNetService service, uint32_t headerLength,
|
||||||
bool bulk) const;
|
bool bulk) const;
|
||||||
bool BuildSendForDeliveryNL(SendItem& item,
|
bool BuildSendForDeliveryNL(SendItem& item,
|
||||||
const NetworkClipboardPeer& peer, LGNetService service,
|
const NetworkClipboardPeer& peer, LGNetService service,
|
||||||
uint16_t messageType, LGNetEnvelopeFlags flags, uint64_t componentEpoch,
|
uint16_t messageType, LGNetEnvelopeFlags flags, uint64_t componentEpoch,
|
||||||
uint64_t requestID, uint32_t payloadLength, bool bulk);
|
uint64_t requestID, uint32_t payloadLength, bool bulk);
|
||||||
bool BuildSendNL(SendItem& item, const NetworkClipboardPeer& peer,
|
bool BuildSendNL(SendItem& item, const NetworkClipboardPeer& peer,
|
||||||
LGNetService service, uint16_t messageType, LGNetEnvelopeFlags flags,
|
LGNetService service, uint16_t messageType, LGNetEnvelopeFlags flags,
|
||||||
uint64_t componentEpoch, uint64_t requestID, uint32_t payloadLength,
|
uint64_t componentEpoch, uint64_t requestID, uint32_t payloadLength,
|
||||||
bool preferBulk);
|
bool preferBulk);
|
||||||
@@ -412,6 +420,7 @@ struct CNetworkClipboard::Impl
|
|||||||
void NotifyTargetReady();
|
void NotifyTargetReady();
|
||||||
void NotifyFailure();
|
void NotifyFailure();
|
||||||
void DropOwnerNL(bool clearHelper);
|
void DropOwnerNL(bool clearHelper);
|
||||||
|
void ExpireOwnerNL(bool clearHelper, uint32_t detail);
|
||||||
void ResetTransfersNL();
|
void ResetTransfersNL();
|
||||||
void ClearRemoteTransfersNL(uint64_t offerID);
|
void ClearRemoteTransfersNL(uint64_t offerID);
|
||||||
bool PublishRemoteOfferNL();
|
bool PublishRemoteOfferNL();
|
||||||
@@ -433,13 +442,14 @@ struct CNetworkClipboard::Impl
|
|||||||
std::vector<SendItem>& batch, const KVMFRClipboardMessage& record);
|
std::vector<SendItem>& batch, const KVMFRClipboardMessage& record);
|
||||||
|
|
||||||
NetworkClipboardPacketResult HandleClaimNL(
|
NetworkClipboardPacketResult HandleClaimNL(
|
||||||
PeerState& peer, const LGNetPacketView& packet, uint64_t nowMs,
|
PeerState& peer, const LGNetPacketView& packet, bool inputOwner,
|
||||||
CSRWExclusiveLock& stateLock);
|
uint64_t nowMs, CSRWExclusiveLock& stateLock);
|
||||||
NetworkClipboardPacketResult HandleClipboardNL(
|
NetworkClipboardPacketResult HandleClipboardNL(
|
||||||
PeerState& peer, const LGNetPacketView& packet, bool bulk, uint64_t nowMs,
|
PeerState& peer, const LGNetPacketView& packet, bool bulk,
|
||||||
CSRWExclusiveLock& stateLock);
|
bool inputOwner, uint64_t nowMs, CSRWExclusiveLock& stateLock);
|
||||||
NetworkClipboardPacketResult HandleFileNL(
|
NetworkClipboardPacketResult HandleFileNL(
|
||||||
PeerState& peer, const LGNetPacketView& packet, bool bulk);
|
PeerState& peer, const LGNetPacketView& packet, bool bulk,
|
||||||
|
bool inputOwner);
|
||||||
|
|
||||||
ClipboardChannelResult HandleHelperClipboardNL(
|
ClipboardChannelResult HandleHelperClipboardNL(
|
||||||
const KVMFRClipboardMessage& record, const uint8_t * data);
|
const KVMFRClipboardMessage& record, const uint8_t * data);
|
||||||
@@ -620,6 +630,42 @@ bool CNetworkClipboard::Impl::QueueTargetNL(TargetItem&& item)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CNetworkClipboard::Impl::QueueOwnerTargetNL(TargetItem&& item)
|
||||||
|
{
|
||||||
|
if (!m_claimEpoch || !m_owner.client || !m_owner.generation)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
item.peer = m_owner;
|
||||||
|
item.claimEpoch = m_claimEpoch;
|
||||||
|
return QueueTargetNL(std::move(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNetworkClipboard::Impl::PeerOwnsInput(
|
||||||
|
const NetworkClipboardPeer& peer)
|
||||||
|
{
|
||||||
|
CSRWExclusiveLock callbackLock(m_senderCallbackLock);
|
||||||
|
INetworkClipboardSender * sender;
|
||||||
|
{
|
||||||
|
CSRWSharedLock lock(m_lock);
|
||||||
|
sender = m_sender;
|
||||||
|
}
|
||||||
|
return sender && sender->ClipboardPeerOwnsInput(peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNetworkClipboard::Impl::WithInputAuthority(
|
||||||
|
const NetworkClipboardPeer& peer, NetworkClipboardInputAction action,
|
||||||
|
void * opaque)
|
||||||
|
{
|
||||||
|
CSRWExclusiveLock callbackLock(m_senderCallbackLock);
|
||||||
|
INetworkClipboardSender * sender;
|
||||||
|
{
|
||||||
|
CSRWSharedLock lock(m_lock);
|
||||||
|
sender = m_sender;
|
||||||
|
}
|
||||||
|
return sender &&
|
||||||
|
sender->ClipboardWithInputAuthority(peer, action, opaque);
|
||||||
|
}
|
||||||
|
|
||||||
void CNetworkClipboard::Impl::PumpSends()
|
void CNetworkClipboard::Impl::PumpSends()
|
||||||
{
|
{
|
||||||
struct BlockedRoute
|
struct BlockedRoute
|
||||||
@@ -681,6 +727,25 @@ void CNetworkClipboard::Impl::PumpSends()
|
|||||||
|
|
||||||
{
|
{
|
||||||
CSRWExclusiveLock lock(m_lock);
|
CSRWExclusiveLock lock(m_lock);
|
||||||
|
if (result == NetworkClipboardSendResult::UNAUTHORIZED)
|
||||||
|
{
|
||||||
|
if (m_claimEpoch && SamePeer(m_owner, action.peer))
|
||||||
|
ExpireOwnerNL(true, CLAIM_INPUT_REQUIRED);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto pending = std::find_if(
|
||||||
|
m_sends.begin(), m_sends.end(),
|
||||||
|
[&action](const SendItem& item)
|
||||||
|
{ return item.serial == action.serial; });
|
||||||
|
if (pending != m_sends.end())
|
||||||
|
{
|
||||||
|
m_sendBytes -= pending->payload.size();
|
||||||
|
m_sends.erase(pending);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto pending = std::find_if(m_sends.begin(), m_sends.end(),
|
const auto pending = std::find_if(m_sends.begin(), m_sends.end(),
|
||||||
[&action](const SendItem& item)
|
[&action](const SendItem& item)
|
||||||
{ return item.serial == action.serial; });
|
{ return item.serial == action.serial; });
|
||||||
@@ -737,24 +802,63 @@ void CNetworkClipboard::Impl::PumpTargets()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ClipboardChannelResult result;
|
struct TargetContext
|
||||||
{
|
{
|
||||||
CSRWExclusiveLock callbackLock(m_targetCallbackLock);
|
Impl * owner = nullptr;
|
||||||
|
const TargetItem * action = nullptr;
|
||||||
|
ClipboardChannelResult result = ClipboardChannelResult::FAILED;
|
||||||
|
} context;
|
||||||
|
context.owner = this;
|
||||||
|
context.action = &action;
|
||||||
|
|
||||||
|
const auto deliver = [](void * value)
|
||||||
|
{
|
||||||
|
TargetContext& targetContext = *static_cast<TargetContext *>(value);
|
||||||
|
CSRWExclusiveLock callbackLock(
|
||||||
|
targetContext.owner->m_targetCallbackLock);
|
||||||
IClipboardTarget * target;
|
IClipboardTarget * target;
|
||||||
{
|
{
|
||||||
CSRWExclusiveLock lock(m_lock);
|
CSRWExclusiveLock lock(targetContext.owner->m_lock);
|
||||||
target = m_target;
|
target = targetContext.owner->m_target;
|
||||||
m_targetCallbackActive = target != nullptr;
|
targetContext.owner->m_targetCallbackActive = target != nullptr;
|
||||||
}
|
}
|
||||||
result = target ? target->SendClipboard(action.record,
|
targetContext.result = target ?
|
||||||
action.data.empty() ? nullptr : action.data.data()) :
|
target->SendClipboard(targetContext.action->record,
|
||||||
ClipboardChannelResult::FAILED;
|
targetContext.action->data.empty() ? nullptr :
|
||||||
|
targetContext.action->data.data()) :
|
||||||
|
ClipboardChannelResult::FAILED;
|
||||||
|
{
|
||||||
|
CSRWExclusiveLock lock(targetContext.owner->m_lock);
|
||||||
|
targetContext.owner->m_targetCallbackActive = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const bool authorized = !action.claimEpoch ||
|
||||||
|
WithInputAuthority(action.peer, deliver, &context);
|
||||||
|
if (!authorized)
|
||||||
|
{
|
||||||
{
|
{
|
||||||
CSRWExclusiveLock lock(m_lock);
|
CSRWExclusiveLock lock(m_lock);
|
||||||
m_targetCallbackActive = false;
|
if (!m_targets.empty() &&
|
||||||
|
m_targets.front().serial == action.serial)
|
||||||
|
{
|
||||||
|
if (m_claimEpoch == action.claimEpoch &&
|
||||||
|
SamePeer(m_owner, action.peer))
|
||||||
|
ExpireOwnerNL(true, CLAIM_INPUT_REQUIRED);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const TargetItem& item = m_targets.front();
|
||||||
|
m_targetBytes -= sizeof(item.record) + item.data.size();
|
||||||
|
m_targets.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
ReleaseHubOwner();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ClipboardChannelResult result = context.result;
|
||||||
|
|
||||||
{
|
{
|
||||||
CSRWExclusiveLock lock(m_lock);
|
CSRWExclusiveLock lock(m_lock);
|
||||||
if (m_targets.empty() || m_targets.front().serial != action.serial)
|
if (m_targets.empty() || m_targets.front().serial != action.serial)
|
||||||
@@ -827,7 +931,7 @@ void CNetworkClipboard::Impl::NotifyTargetReady()
|
|||||||
IClipboardTarget * target = nullptr;
|
IClipboardTarget * target = nullptr;
|
||||||
{
|
{
|
||||||
CSRWExclusiveLock lock(m_lock);
|
CSRWExclusiveLock lock(m_lock);
|
||||||
if (!m_receiveReadyPending)
|
if (!m_receiveReadyPending || m_hubReleasePending)
|
||||||
return;
|
return;
|
||||||
m_receiveReadyPending = false;
|
m_receiveReadyPending = false;
|
||||||
target = m_started ? m_target : nullptr;
|
target = m_started ? m_target : nullptr;
|
||||||
@@ -1128,7 +1232,7 @@ bool CNetworkClipboard::Impl::PublishRemoteOfferNL()
|
|||||||
item.record.type = KVMFR_CLIPBOARD_MESSAGE_OFFER;
|
item.record.type = KVMFR_CLIPBOARD_MESSAGE_OFFER;
|
||||||
item.record.clipboardGeneration = m_remoteOffer.offerID;
|
item.record.clipboardGeneration = m_remoteOffer.offerID;
|
||||||
item.record.token = m_remoteOffer.formatMask;
|
item.record.token = m_remoteOffer.formatMask;
|
||||||
if (!QueueTargetNL(std::move(item)))
|
if (!QueueOwnerTargetNL(std::move(item)))
|
||||||
return false;
|
return false;
|
||||||
m_remoteOffer.published = true;
|
m_remoteOffer.published = true;
|
||||||
return true;
|
return true;
|
||||||
@@ -1139,6 +1243,12 @@ void CNetworkClipboard::Impl::DropOwnerNL(bool clearHelper)
|
|||||||
if (!m_claimEpoch)
|
if (!m_claimEpoch)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (clearHelper)
|
||||||
|
{
|
||||||
|
m_targets.clear();
|
||||||
|
m_targetBytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool cleanupQueued = true;
|
bool cleanupQueued = true;
|
||||||
if (clearHelper && m_remoteOffer.published && m_remoteOffer.offerID)
|
if (clearHelper && m_remoteOffer.published && m_remoteOffer.offerID)
|
||||||
{
|
{
|
||||||
@@ -1227,11 +1337,34 @@ void CNetworkClipboard::Impl::DropOwnerNL(bool clearHelper)
|
|||||||
m_remoteOfferSerial = 0;
|
m_remoteOfferSerial = 0;
|
||||||
m_claimDeadline = 0;
|
m_claimDeadline = 0;
|
||||||
m_claimLeaseMs = 0;
|
m_claimLeaseMs = 0;
|
||||||
|
|
||||||
|
if (m_sourceBlocked)
|
||||||
|
m_receiveReadyPending = true;
|
||||||
|
m_sourceBlocked = false;
|
||||||
|
m_sourceBlockedService = 0;
|
||||||
|
m_sourceBlockedTransfer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNetworkClipboard::Impl::ExpireOwnerNL(
|
||||||
|
bool clearHelper, uint32_t detail)
|
||||||
|
{
|
||||||
|
if (!m_claimEpoch)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const NetworkClipboardPeer owner = m_owner;
|
||||||
|
const uint64_t epoch = m_claimEpoch;
|
||||||
|
const uint64_t serial = m_claimSerial;
|
||||||
|
DropOwnerNL(clearHelper);
|
||||||
|
m_claimSerial = serial;
|
||||||
|
if (!QueueClaimStatusNL(
|
||||||
|
owner, epoch, LG_NET_CLIPBOARD_CLAIM_EXPIRED, 0, 0, detail))
|
||||||
|
m_failed = true;
|
||||||
|
m_claimSerial = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleClaimNL(
|
NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleClaimNL(
|
||||||
PeerState& peer, const LGNetPacketView& packet, uint64_t nowMs,
|
PeerState& peer, const LGNetPacketView& packet, bool inputOwner,
|
||||||
CSRWExclusiveLock& stateLock)
|
uint64_t nowMs, CSRWExclusiveLock& stateLock)
|
||||||
{
|
{
|
||||||
if (!DeliveryFlags(
|
if (!DeliveryFlags(
|
||||||
packet.envelope, LG_NET_ENVELOPE_ACK_REQUIRED, false) ||
|
packet.envelope, LG_NET_ENVELOPE_ACK_REQUIRED, false) ||
|
||||||
@@ -1251,6 +1384,15 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleClaimNL(
|
|||||||
NetworkClipboardPacketResult::HANDLED :
|
NetworkClipboardPacketResult::HANDLED :
|
||||||
NetworkClipboardPacketResult::INVALID;
|
NetworkClipboardPacketResult::INVALID;
|
||||||
}
|
}
|
||||||
|
if (!inputOwner)
|
||||||
|
{
|
||||||
|
peer.lastClaimEpoch = claim.claimEpoch;
|
||||||
|
return QueueClaimStatusNL(peer.peer, claim.claimEpoch,
|
||||||
|
LG_NET_CLIPBOARD_CLAIM_REJECTED, 0, 0,
|
||||||
|
CLAIM_INPUT_REQUIRED) ?
|
||||||
|
NetworkClipboardPacketResult::HANDLED :
|
||||||
|
NetworkClipboardPacketResult::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
const bool exactOwner =
|
const bool exactOwner =
|
||||||
IsOwnerNL(peer.peer, claim.claimEpoch) && claim.ownerID == m_ownerID;
|
IsOwnerNL(peer.peer, claim.claimEpoch) && claim.ownerID == m_ownerID;
|
||||||
@@ -1350,17 +1492,20 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleClaimNL(
|
|||||||
}
|
}
|
||||||
|
|
||||||
NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleClipboardNL(
|
NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleClipboardNL(
|
||||||
PeerState& peer, const LGNetPacketView& packet, bool bulk, uint64_t nowMs,
|
PeerState& peer, const LGNetPacketView& packet, bool bulk,
|
||||||
CSRWExclusiveLock& stateLock)
|
bool inputOwner, uint64_t nowMs, CSRWExclusiveLock& stateLock)
|
||||||
{
|
{
|
||||||
const LGNetEnvelope& envelope = packet.envelope;
|
const LGNetEnvelope& envelope = packet.envelope;
|
||||||
if (envelope.messageType == LG_NET_CLIPBOARD_MESSAGE_CLAIM)
|
if (envelope.messageType == LG_NET_CLIPBOARD_MESSAGE_CLAIM)
|
||||||
{
|
{
|
||||||
if (bulk)
|
if (bulk)
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
return HandleClaimNL(peer, packet, nowMs, stateLock);
|
return HandleClaimNL(peer, packet, inputOwner, nowMs, stateLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!inputOwner)
|
||||||
|
return NetworkClipboardPacketResult::IGNORED;
|
||||||
|
|
||||||
const bool transferData =
|
const bool transferData =
|
||||||
envelope.messageType == LG_NET_CLIPBOARD_MESSAGE_DATA_BEGIN ||
|
envelope.messageType == LG_NET_CLIPBOARD_MESSAGE_DATA_BEGIN ||
|
||||||
envelope.messageType == LG_NET_CLIPBOARD_MESSAGE_DATA_CHUNK ||
|
envelope.messageType == LG_NET_CLIPBOARD_MESSAGE_DATA_CHUNK ||
|
||||||
@@ -1418,7 +1563,7 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleClipboardNL(
|
|||||||
item.record.version = KVMFR_CLIPBOARD_VERSION;
|
item.record.version = KVMFR_CLIPBOARD_VERSION;
|
||||||
item.record.type = KVMFR_CLIPBOARD_MESSAGE_CLEAR;
|
item.record.type = KVMFR_CLIPBOARD_MESSAGE_CLEAR;
|
||||||
item.record.clipboardGeneration = m_remoteOffer.offerID;
|
item.record.clipboardGeneration = m_remoteOffer.offerID;
|
||||||
if (!QueueTargetNL(std::move(item)))
|
if (!QueueOwnerTargetNL(std::move(item)))
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
}
|
}
|
||||||
ClearRemoteTransfersNL(m_remoteOffer.offerID);
|
ClearRemoteTransfersNL(m_remoteOffer.offerID);
|
||||||
@@ -1455,7 +1600,7 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleClipboardNL(
|
|||||||
clear.record.version = KVMFR_CLIPBOARD_VERSION;
|
clear.record.version = KVMFR_CLIPBOARD_VERSION;
|
||||||
clear.record.type = KVMFR_CLIPBOARD_MESSAGE_CLEAR;
|
clear.record.type = KVMFR_CLIPBOARD_MESSAGE_CLEAR;
|
||||||
clear.record.clipboardGeneration = m_remoteOffer.offerID;
|
clear.record.clipboardGeneration = m_remoteOffer.offerID;
|
||||||
if (!QueueTargetNL(std::move(clear)))
|
if (!QueueOwnerTargetNL(std::move(clear)))
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
}
|
}
|
||||||
ClearRemoteTransfersNL(m_remoteOffer.offerID);
|
ClearRemoteTransfersNL(m_remoteOffer.offerID);
|
||||||
@@ -1596,7 +1741,7 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleClipboardNL(
|
|||||||
item.record.clipboardGeneration = transfer.offerID;
|
item.record.clipboardGeneration = transfer.offerID;
|
||||||
item.record.transfer = transfer.localID;
|
item.record.transfer = transfer.localID;
|
||||||
item.record.format = transfer.format;
|
item.record.format = transfer.format;
|
||||||
if (!QueueTargetNL(std::move(item)))
|
if (!QueueOwnerTargetNL(std::move(item)))
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -1673,7 +1818,7 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleClipboardNL(
|
|||||||
{
|
{
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
}
|
}
|
||||||
if (!QueueTargetNL(std::move(item)))
|
if (!QueueOwnerTargetNL(std::move(item)))
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
|
|
||||||
transfer = FindClipboardWireNL(chunkValue.requestID);
|
transfer = FindClipboardWireNL(chunkValue.requestID);
|
||||||
@@ -1715,7 +1860,7 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleClipboardNL(
|
|||||||
item.record.flags = KVMFR_CLIPBOARD_FLAG_END;
|
item.record.flags = KVMFR_CLIPBOARD_FLAG_END;
|
||||||
if (!transfer->offset)
|
if (!transfer->offset)
|
||||||
item.record.flags |= KVMFR_CLIPBOARD_FLAG_BEGIN;
|
item.record.flags |= KVMFR_CLIPBOARD_FLAG_BEGIN;
|
||||||
if (!QueueTargetNL(std::move(item)))
|
if (!QueueOwnerTargetNL(std::move(item)))
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
m_clipboardTransfers.erase(
|
m_clipboardTransfers.erase(
|
||||||
std::remove_if(m_clipboardTransfers.begin(), m_clipboardTransfers.end(),
|
std::remove_if(m_clipboardTransfers.begin(), m_clipboardTransfers.end(),
|
||||||
@@ -1789,7 +1934,7 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleClipboardNL(
|
|||||||
item.record.clipboardGeneration = transfer->offerID;
|
item.record.clipboardGeneration = transfer->offerID;
|
||||||
item.record.transfer = transfer->localID;
|
item.record.transfer = transfer->localID;
|
||||||
item.record.format = transfer->format;
|
item.record.format = transfer->format;
|
||||||
if (!QueueTargetNL(std::move(item)))
|
if (!QueueOwnerTargetNL(std::move(item)))
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
m_clipboardTransfers.erase(
|
m_clipboardTransfers.erase(
|
||||||
std::remove_if(m_clipboardTransfers.begin(), m_clipboardTransfers.end(),
|
std::remove_if(m_clipboardTransfers.begin(), m_clipboardTransfers.end(),
|
||||||
@@ -1806,7 +1951,8 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleClipboardNL(
|
|||||||
}
|
}
|
||||||
|
|
||||||
NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleFileNL(
|
NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleFileNL(
|
||||||
PeerState& peer, const LGNetPacketView& packet, bool bulk)
|
PeerState& peer, const LGNetPacketView& packet, bool bulk,
|
||||||
|
bool inputOwner)
|
||||||
{
|
{
|
||||||
const LGNetEnvelope& envelope = packet.envelope;
|
const LGNetEnvelope& envelope = packet.envelope;
|
||||||
const bool transferData =
|
const bool transferData =
|
||||||
@@ -1820,7 +1966,7 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleFileNL(
|
|||||||
else if (envelope.messageType == LG_NET_FILE_MESSAGE_ACQUIRED ||
|
else if (envelope.messageType == LG_NET_FILE_MESSAGE_ACQUIRED ||
|
||||||
envelope.messageType == LG_NET_FILE_MESSAGE_STATUS)
|
envelope.messageType == LG_NET_FILE_MESSAGE_STATUS)
|
||||||
expected = LG_NET_ENVELOPE_RESPONSE;
|
expected = LG_NET_ENVELOPE_RESPONSE;
|
||||||
if (!IsOwnerNL(peer.peer, envelope.componentEpoch))
|
if (!inputOwner || !IsOwnerNL(peer.peer, envelope.componentEpoch))
|
||||||
return NetworkClipboardPacketResult::IGNORED;
|
return NetworkClipboardPacketResult::IGNORED;
|
||||||
if ((bulk && !transferData) || !DeliveryFlags(envelope, expected, bulk))
|
if ((bulk && !transferData) || !DeliveryFlags(envelope, expected, bulk))
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
@@ -1845,7 +1991,7 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleFileNL(
|
|||||||
clear.record.version = KVMFR_CLIPBOARD_VERSION;
|
clear.record.version = KVMFR_CLIPBOARD_VERSION;
|
||||||
clear.record.type = KVMFR_CLIPBOARD_MESSAGE_CLEAR;
|
clear.record.type = KVMFR_CLIPBOARD_MESSAGE_CLEAR;
|
||||||
clear.record.clipboardGeneration = m_remoteOffer.offerID;
|
clear.record.clipboardGeneration = m_remoteOffer.offerID;
|
||||||
if (!QueueTargetNL(std::move(clear)))
|
if (!QueueOwnerTargetNL(std::move(clear)))
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
}
|
}
|
||||||
ClearRemoteTransfersNL(m_remoteOffer.offerID);
|
ClearRemoteTransfersNL(m_remoteOffer.offerID);
|
||||||
@@ -1912,7 +2058,7 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleFileNL(
|
|||||||
item.record.clipboardGeneration = acquisition.offerID;
|
item.record.clipboardGeneration = acquisition.offerID;
|
||||||
item.record.transfer = acquisition.localID;
|
item.record.transfer = acquisition.localID;
|
||||||
item.record.format = KVMFR_CLIPBOARD_FORMAT_FILES;
|
item.record.format = KVMFR_CLIPBOARD_FORMAT_FILES;
|
||||||
if (!QueueTargetNL(std::move(item)))
|
if (!QueueOwnerTargetNL(std::move(item)))
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -1951,7 +2097,7 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleFileNL(
|
|||||||
item.record.transfer = acquisition->localID;
|
item.record.transfer = acquisition->localID;
|
||||||
item.record.format = KVMFR_CLIPBOARD_FORMAT_FILES;
|
item.record.format = KVMFR_CLIPBOARD_FORMAT_FILES;
|
||||||
item.record.token = KVMFR_CLIPBOARD_FILE_ERROR_NONE;
|
item.record.token = KVMFR_CLIPBOARD_FILE_ERROR_NONE;
|
||||||
if (!QueueTargetNL(std::move(item)))
|
if (!QueueOwnerTargetNL(std::move(item)))
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
acquisition = FindAcquisitionWireNL(lease.clientID);
|
acquisition = FindAcquisitionWireNL(lease.clientID);
|
||||||
if (acquisition)
|
if (acquisition)
|
||||||
@@ -1985,7 +2131,7 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleFileNL(
|
|||||||
item.record.clipboardGeneration = acquisition->offerID;
|
item.record.clipboardGeneration = acquisition->offerID;
|
||||||
item.record.transfer = localID;
|
item.record.transfer = localID;
|
||||||
item.record.format = KVMFR_CLIPBOARD_FORMAT_FILES;
|
item.record.format = KVMFR_CLIPBOARD_FORMAT_FILES;
|
||||||
if (!QueueTargetNL(std::move(item)))
|
if (!QueueOwnerTargetNL(std::move(item)))
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
const uint64_t offerID = acquisition->offerID;
|
const uint64_t offerID = acquisition->offerID;
|
||||||
m_fileAcquisitions.erase(
|
m_fileAcquisitions.erase(
|
||||||
@@ -2097,7 +2243,7 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleFileNL(
|
|||||||
item.record.flags =
|
item.record.flags =
|
||||||
transfer.operation == KVMFR_CLIPBOARD_FILE_OP_READ ? transfer.length : 0;
|
transfer.operation == KVMFR_CLIPBOARD_FILE_OP_READ ? transfer.length : 0;
|
||||||
item.record.token = transfer.operation;
|
item.record.token = transfer.operation;
|
||||||
if (!QueueTargetNL(std::move(item)))
|
if (!QueueOwnerTargetNL(std::move(item)))
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -2182,7 +2328,7 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleFileNL(
|
|||||||
{
|
{
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
}
|
}
|
||||||
if (!QueueTargetNL(std::move(item)))
|
if (!QueueOwnerTargetNL(std::move(item)))
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
|
|
||||||
transfer = FindFileWireNL(chunkValue.requestID);
|
transfer = FindFileWireNL(chunkValue.requestID);
|
||||||
@@ -2227,7 +2373,7 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleFileNL(
|
|||||||
if (!transfer->responseOffset)
|
if (!transfer->responseOffset)
|
||||||
item.record.flags |= KVMFR_CLIPBOARD_FLAG_BEGIN;
|
item.record.flags |= KVMFR_CLIPBOARD_FLAG_BEGIN;
|
||||||
item.record.token = transfer->operation;
|
item.record.token = transfer->operation;
|
||||||
if (!QueueTargetNL(std::move(item)))
|
if (!QueueOwnerTargetNL(std::move(item)))
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
m_fileTransfers.erase(
|
m_fileTransfers.erase(
|
||||||
std::remove_if(m_fileTransfers.begin(), m_fileTransfers.end(),
|
std::remove_if(m_fileTransfers.begin(), m_fileTransfers.end(),
|
||||||
@@ -2282,7 +2428,7 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleFileNL(
|
|||||||
item.record.transfer = localID;
|
item.record.transfer = localID;
|
||||||
item.record.format = KVMFR_CLIPBOARD_FORMAT_FILES;
|
item.record.format = KVMFR_CLIPBOARD_FORMAT_FILES;
|
||||||
item.record.token = KVMFR_CLIPBOARD_FILE_ERROR_CANCELLED;
|
item.record.token = KVMFR_CLIPBOARD_FILE_ERROR_CANCELLED;
|
||||||
if (!QueueTargetNL(std::move(item)))
|
if (!QueueOwnerTargetNL(std::move(item)))
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
m_fileTransfers.erase(
|
m_fileTransfers.erase(
|
||||||
std::remove_if(m_fileTransfers.begin(), m_fileTransfers.end(),
|
std::remove_if(m_fileTransfers.begin(), m_fileTransfers.end(),
|
||||||
@@ -2320,7 +2466,7 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleFileNL(
|
|||||||
item.record.transfer = localID;
|
item.record.transfer = localID;
|
||||||
item.record.format = KVMFR_CLIPBOARD_FORMAT_FILES;
|
item.record.format = KVMFR_CLIPBOARD_FORMAT_FILES;
|
||||||
item.record.token = error;
|
item.record.token = error;
|
||||||
if (!QueueTargetNL(std::move(item)))
|
if (!QueueOwnerTargetNL(std::move(item)))
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
m_fileAcquisitions.erase(
|
m_fileAcquisitions.erase(
|
||||||
std::remove_if(m_fileAcquisitions.begin(), m_fileAcquisitions.end(),
|
std::remove_if(m_fileAcquisitions.begin(), m_fileAcquisitions.end(),
|
||||||
@@ -2344,7 +2490,7 @@ NetworkClipboardPacketResult CNetworkClipboard::Impl::HandleFileNL(
|
|||||||
item.record.transfer = localID;
|
item.record.transfer = localID;
|
||||||
item.record.format = KVMFR_CLIPBOARD_FORMAT_FILES;
|
item.record.format = KVMFR_CLIPBOARD_FORMAT_FILES;
|
||||||
item.record.token = error;
|
item.record.token = error;
|
||||||
if (!QueueTargetNL(std::move(item)))
|
if (!QueueOwnerTargetNL(std::move(item)))
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
m_fileTransfers.erase(
|
m_fileTransfers.erase(
|
||||||
std::remove_if(m_fileTransfers.begin(), m_fileTransfers.end(),
|
std::remove_if(m_fileTransfers.begin(), m_fileTransfers.end(),
|
||||||
@@ -2441,8 +2587,10 @@ ClipboardChannelResult CNetworkClipboard::Impl::HandleHelperClipboardNL(
|
|||||||
QueueTargetNL(std::move(item));
|
QueueTargetNL(std::move(item));
|
||||||
return ClipboardChannelResult::ACCEPTED;
|
return ClipboardChannelResult::ACCEPTED;
|
||||||
}
|
}
|
||||||
return record.type == KVMFR_CLIPBOARD_MESSAGE_CANCEL &&
|
return ((record.type == KVMFR_CLIPBOARD_MESSAGE_CANCEL &&
|
||||||
ValidCancel(record) ?
|
ValidCancel(record)) ||
|
||||||
|
(record.type == KVMFR_CLIPBOARD_MESSAGE_DATA &&
|
||||||
|
ValidData(record))) ?
|
||||||
ClipboardChannelResult::ACCEPTED :
|
ClipboardChannelResult::ACCEPTED :
|
||||||
ClipboardChannelResult::FAILED;
|
ClipboardChannelResult::FAILED;
|
||||||
}
|
}
|
||||||
@@ -3247,6 +3395,40 @@ CNetworkClipboard::~CNetworkClipboard()
|
|||||||
DetachSender();
|
DetachSender();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CNetworkClipboard::PeerOwnsInput(
|
||||||
|
const NetworkClipboardPeer& peer)
|
||||||
|
{
|
||||||
|
return m_impl->PeerOwnsInput(peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNetworkClipboard::RevokeUnauthorizedOwner()
|
||||||
|
{
|
||||||
|
NetworkClipboardPeer owner = {};
|
||||||
|
uint64_t epoch = 0;
|
||||||
|
{
|
||||||
|
CSRWSharedLock lock(m_impl->m_lock);
|
||||||
|
if (!m_impl->m_claimEpoch)
|
||||||
|
return false;
|
||||||
|
owner = m_impl->m_owner;
|
||||||
|
epoch = m_impl->m_claimEpoch;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PeerOwnsInput(owner))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CSRWExclusiveLock lock(m_impl->m_lock);
|
||||||
|
if (m_impl->m_claimEpoch != epoch || !SamePeer(m_impl->m_owner, owner))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DEBUG_INFO("Revoking network clipboard owner without input control: "
|
||||||
|
"client=%u generation=%u claim=%llu",
|
||||||
|
static_cast<unsigned int>(owner.client),
|
||||||
|
static_cast<unsigned int>(owner.generation),
|
||||||
|
static_cast<unsigned long long>(epoch));
|
||||||
|
m_impl->ExpireOwnerNL(true, CLAIM_INPUT_REQUIRED);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool CNetworkClipboard::AttachSender(INetworkClipboardSender& sender)
|
bool CNetworkClipboard::AttachSender(INetworkClipboardSender& sender)
|
||||||
{
|
{
|
||||||
CSRWExclusiveLock lifecycleLock(m_impl->m_lifecycleLock);
|
CSRWExclusiveLock lifecycleLock(m_impl->m_lifecycleLock);
|
||||||
@@ -3370,7 +3552,10 @@ NetworkClipboardPacketResult CNetworkClipboard::HandlePacket(
|
|||||||
packet.payloadLength > LG_NET_MAX_PAYLOAD_LENGTH)
|
packet.payloadLength > LG_NET_MAX_PAYLOAD_LENGTH)
|
||||||
return NetworkClipboardPacketResult::INVALID;
|
return NetworkClipboardPacketResult::INVALID;
|
||||||
|
|
||||||
CSRWExclusiveLock processLock(m_impl->m_processLock);
|
CSRWExclusiveLock processLock(m_impl->m_processLock);
|
||||||
|
RevokeUnauthorizedOwner();
|
||||||
|
const bool inputOwner = PeerOwnsInput(peer);
|
||||||
|
|
||||||
NetworkClipboardPacketResult result;
|
NetworkClipboardPacketResult result;
|
||||||
{
|
{
|
||||||
CSRWExclusiveLock callbackLock(m_impl->m_targetCallbackLock);
|
CSRWExclusiveLock callbackLock(m_impl->m_targetCallbackLock);
|
||||||
@@ -3399,10 +3584,11 @@ NetworkClipboardPacketResult CNetworkClipboard::HandlePacket(
|
|||||||
|
|
||||||
result = packet.envelope.service == LG_NET_SERVICE_CLIPBOARD ?
|
result = packet.envelope.service == LG_NET_SERVICE_CLIPBOARD ?
|
||||||
m_impl->HandleClipboardNL(
|
m_impl->HandleClipboardNL(
|
||||||
*state, packet, bulk, GetTickCount64(), lock) :
|
*state, packet, bulk, inputOwner, GetTickCount64(), lock) :
|
||||||
m_impl->HandleFileNL(*state, packet, bulk);
|
m_impl->HandleFileNL(*state, packet, bulk, inputOwner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RevokeUnauthorizedOwner();
|
||||||
m_impl->PumpTargets();
|
m_impl->PumpTargets();
|
||||||
m_impl->PumpSends();
|
m_impl->PumpSends();
|
||||||
processLock.Unlock();
|
processLock.Unlock();
|
||||||
@@ -3417,20 +3603,11 @@ void CNetworkClipboard::Process(uint64_t nowMs)
|
|||||||
if (!processLock)
|
if (!processLock)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
RevokeUnauthorizedOwner();
|
||||||
{
|
{
|
||||||
CSRWExclusiveLock lock(m_impl->m_lock);
|
CSRWExclusiveLock lock(m_impl->m_lock);
|
||||||
if (m_impl->m_claimEpoch && DeadlineReached(nowMs, m_impl->m_claimDeadline))
|
if (m_impl->m_claimEpoch && DeadlineReached(nowMs, m_impl->m_claimDeadline))
|
||||||
{
|
m_impl->ExpireOwnerNL(true, 0);
|
||||||
const NetworkClipboardPeer owner = m_impl->m_owner;
|
|
||||||
const uint64_t epoch = m_impl->m_claimEpoch;
|
|
||||||
const uint64_t serial = m_impl->m_claimSerial;
|
|
||||||
m_impl->DropOwnerNL(true);
|
|
||||||
m_impl->m_claimSerial = serial;
|
|
||||||
if (!m_impl->QueueClaimStatusNL(
|
|
||||||
owner, epoch, LG_NET_CLIPBOARD_CLAIM_EXPIRED, 0, 0, 0))
|
|
||||||
m_impl->m_failed = true;
|
|
||||||
m_impl->m_claimSerial = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_impl->PumpTargets();
|
m_impl->PumpTargets();
|
||||||
@@ -3448,6 +3625,7 @@ void CNetworkClipboard::SendReady(
|
|||||||
CSRWExclusiveLock processLock = CSRWExclusiveLock::Try(m_impl->m_processLock);
|
CSRWExclusiveLock processLock = CSRWExclusiveLock::Try(m_impl->m_processLock);
|
||||||
if (!processLock)
|
if (!processLock)
|
||||||
return;
|
return;
|
||||||
|
RevokeUnauthorizedOwner();
|
||||||
{
|
{
|
||||||
CSRWSharedLock lock(m_impl->m_lock);
|
CSRWSharedLock lock(m_impl->m_lock);
|
||||||
if (!m_impl->FindPeerNL(peer))
|
if (!m_impl->FindPeerNL(peer))
|
||||||
@@ -3585,6 +3763,17 @@ ClipboardChannelResult CNetworkClipboard::SendClipboard(
|
|||||||
{
|
{
|
||||||
CSRWExclusiveLock processLock(m_impl->m_processLock);
|
CSRWExclusiveLock processLock(m_impl->m_processLock);
|
||||||
ClipboardChannelResult result;
|
ClipboardChannelResult result;
|
||||||
|
if (RevokeUnauthorizedOwner())
|
||||||
|
{
|
||||||
|
{
|
||||||
|
CSRWExclusiveLock lock(m_impl->m_lock);
|
||||||
|
m_impl->m_receiveReadyPending = true;
|
||||||
|
}
|
||||||
|
m_impl->PumpSends();
|
||||||
|
processLock.Unlock();
|
||||||
|
return ClipboardChannelResult::BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
CSRWExclusiveLock lock(m_impl->m_lock);
|
CSRWExclusiveLock lock(m_impl->m_lock);
|
||||||
if (!m_impl->m_started || !m_impl->m_target || !m_impl->m_stateKnown ||
|
if (!m_impl->m_started || !m_impl->m_target || !m_impl->m_stateKnown ||
|
||||||
@@ -3592,15 +3781,29 @@ ClipboardChannelResult CNetworkClipboard::SendClipboard(
|
|||||||
record.generation != m_impl->m_generation ||
|
record.generation != m_impl->m_generation ||
|
||||||
record.version != KVMFR_CLIPBOARD_VERSION || (record.length && !data))
|
record.version != KVMFR_CLIPBOARD_VERSION || (record.length && !data))
|
||||||
return ClipboardChannelResult::FAILED;
|
return ClipboardChannelResult::FAILED;
|
||||||
|
if (m_impl->m_hubReleasePending)
|
||||||
|
{
|
||||||
|
m_impl->m_receiveReadyPending = true;
|
||||||
|
return ClipboardChannelResult::BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
result = kvmfrClipboardFileMessageType(record.type) ?
|
result = kvmfrClipboardFileMessageType(record.type) ?
|
||||||
m_impl->HandleHelperFileNL(record, data) :
|
m_impl->HandleHelperFileNL(record, data) :
|
||||||
m_impl->HandleHelperClipboardNL(record, data);
|
m_impl->HandleHelperClipboardNL(record, data);
|
||||||
}
|
}
|
||||||
|
RevokeUnauthorizedOwner();
|
||||||
m_impl->PumpSends();
|
m_impl->PumpSends();
|
||||||
|
bool deferNotification = false;
|
||||||
|
{
|
||||||
|
CSRWSharedLock lock(m_impl->m_lock);
|
||||||
|
deferNotification = m_impl->m_hubReleasePending;
|
||||||
|
}
|
||||||
processLock.Unlock();
|
processLock.Unlock();
|
||||||
m_impl->NotifyTargetReady();
|
if (!deferNotification)
|
||||||
m_impl->NotifyFailure();
|
{
|
||||||
|
m_impl->NotifyTargetReady();
|
||||||
|
m_impl->NotifyFailure();
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,10 +45,13 @@ struct NetworkClipboardPeerInfo
|
|||||||
uint32_t fileBulkPayload = 0;
|
uint32_t fileBulkPayload = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using NetworkClipboardInputAction = void (*)(void * opaque);
|
||||||
|
|
||||||
enum class NetworkClipboardSendResult
|
enum class NetworkClipboardSendResult
|
||||||
{
|
{
|
||||||
ACCEPTED,
|
ACCEPTED,
|
||||||
BLOCKED,
|
BLOCKED,
|
||||||
|
UNAUTHORIZED,
|
||||||
FAILED,
|
FAILED,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -64,6 +67,10 @@ class INetworkClipboardSender
|
|||||||
public:
|
public:
|
||||||
virtual ~INetworkClipboardSender() = default;
|
virtual ~INetworkClipboardSender() = default;
|
||||||
|
|
||||||
|
virtual bool ClipboardPeerOwnsInput(
|
||||||
|
const NetworkClipboardPeer& peer) = 0;
|
||||||
|
virtual bool ClipboardWithInputAuthority(const NetworkClipboardPeer& peer,
|
||||||
|
NetworkClipboardInputAction action, void * opaque) = 0;
|
||||||
virtual bool ClipboardPeerInfo(
|
virtual bool ClipboardPeerInfo(
|
||||||
const NetworkClipboardPeer& peer, NetworkClipboardPeerInfo& info) = 0;
|
const NetworkClipboardPeer& peer, NetworkClipboardPeerInfo& info) = 0;
|
||||||
virtual NetworkClipboardSendResult SendClipboard(
|
virtual NetworkClipboardSendResult SendClipboard(
|
||||||
@@ -78,6 +85,9 @@ private:
|
|||||||
struct Impl;
|
struct Impl;
|
||||||
std::unique_ptr<Impl> m_impl;
|
std::unique_ptr<Impl> m_impl;
|
||||||
|
|
||||||
|
bool PeerOwnsInput(const NetworkClipboardPeer& peer);
|
||||||
|
bool RevokeUnauthorizedOwner();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CNetworkClipboard();
|
CNetworkClipboard();
|
||||||
~CNetworkClipboard() override;
|
~CNetworkClipboard() override;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include "platform/CPlatformInfo.h"
|
#include "platform/CPlatformInfo.h"
|
||||||
#include "VersionInfo.h"
|
#include "VersionInfo.h"
|
||||||
#include <LGProtocol/NetworkAuth.h>
|
#include <LGProtocol/NetworkAuth.h>
|
||||||
|
#include <LGProtocol/NetworkClipboard.h>
|
||||||
#include <LGProtocol/NetworkIdentity.h>
|
#include <LGProtocol/NetworkIdentity.h>
|
||||||
#include <LGProtocol/NetworkPacket.h>
|
#include <LGProtocol/NetworkPacket.h>
|
||||||
#include <LGProtocol/NetworkRoute.h>
|
#include <LGProtocol/NetworkRoute.h>
|
||||||
@@ -745,6 +746,96 @@ struct CNetworkServer::Impl
|
|||||||
return NetworkAudioSendResult::FAILED;
|
return NetworkAudioSendResult::FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<CNetworkSession> ClipboardInputSession(
|
||||||
|
const NetworkClipboardPeer& peer)
|
||||||
|
{
|
||||||
|
std::shared_ptr<CNetworkSession> session;
|
||||||
|
{
|
||||||
|
CSRWSharedLock guard(lock);
|
||||||
|
for (Connection * connection : connections)
|
||||||
|
{
|
||||||
|
if (connection->client != peer.client ||
|
||||||
|
connection->generation != peer.generation)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CSRWSharedLock connectionGuard(connection->lock);
|
||||||
|
const uint16_t inputMask = UINT16_C(1) << LG_NET_SERVICE_INPUT;
|
||||||
|
if (connection->closing ||
|
||||||
|
connection->handshake != HandshakeState::READY ||
|
||||||
|
!(connection->selectedServices & inputMask) ||
|
||||||
|
!connection->inputClaimantID || !connection->inputClaimEpoch)
|
||||||
|
return {};
|
||||||
|
session = connection->session;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClipboardPeerOwnsInput(const NetworkClipboardPeer& peer)
|
||||||
|
{
|
||||||
|
const std::shared_ptr<CNetworkSession> session =
|
||||||
|
ClipboardInputSession(peer);
|
||||||
|
return session && session->InputState().owned;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClipboardWithInputAuthority(const NetworkClipboardPeer& peer,
|
||||||
|
NetworkClipboardInputAction action, void * opaque)
|
||||||
|
{
|
||||||
|
if (!action)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const std::shared_ptr<CNetworkSession> session =
|
||||||
|
ClipboardInputSession(peer);
|
||||||
|
if (!session)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
struct AuthorityContext
|
||||||
|
{
|
||||||
|
Impl * owner = nullptr;
|
||||||
|
CNetworkSession * session = nullptr;
|
||||||
|
NetworkClipboardPeer peer = {};
|
||||||
|
NetworkClipboardInputAction action = nullptr;
|
||||||
|
void * opaque = nullptr;
|
||||||
|
bool invoked = false;
|
||||||
|
} context;
|
||||||
|
context.owner = this;
|
||||||
|
context.session = session.get();
|
||||||
|
context.peer = peer;
|
||||||
|
context.action = action;
|
||||||
|
context.opaque = opaque;
|
||||||
|
|
||||||
|
const auto invoke = [](void * value)
|
||||||
|
{
|
||||||
|
AuthorityContext& authorityContext =
|
||||||
|
*static_cast<AuthorityContext *>(value);
|
||||||
|
CSRWSharedLock guard(authorityContext.owner->lock);
|
||||||
|
for (Connection * connection : authorityContext.owner->connections)
|
||||||
|
{
|
||||||
|
if (connection->client != authorityContext.peer.client ||
|
||||||
|
connection->generation != authorityContext.peer.generation)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
{
|
||||||
|
CSRWSharedLock connectionGuard(connection->lock);
|
||||||
|
const uint16_t inputMask = UINT16_C(1) << LG_NET_SERVICE_INPUT;
|
||||||
|
if (connection->closing ||
|
||||||
|
connection->handshake != HandshakeState::READY ||
|
||||||
|
!(connection->selectedServices & inputMask) ||
|
||||||
|
!connection->inputClaimantID || !connection->inputClaimEpoch ||
|
||||||
|
connection->session.get() != authorityContext.session)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
authorityContext.action(authorityContext.opaque);
|
||||||
|
authorityContext.invoked = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return session->WithInputAuthority(invoke, &context) && context.invoked;
|
||||||
|
}
|
||||||
|
|
||||||
bool ClipboardPeerInfo(const NetworkClipboardPeer& peer,
|
bool ClipboardPeerInfo(const NetworkClipboardPeer& peer,
|
||||||
NetworkClipboardPeerInfo& info)
|
NetworkClipboardPeerInfo& info)
|
||||||
{
|
{
|
||||||
@@ -786,17 +877,12 @@ struct CNetworkServer::Impl
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkClipboardSendResult SendClipboard(
|
NetworkClipboardSendResult SendClipboardLocked(
|
||||||
const NetworkClipboardPeer& peer, bool bulk, LGNetService service,
|
const NetworkClipboardPeer& peer, bool bulk, LGNetService service,
|
||||||
uint16_t messageType, LGNetEnvelopeFlags flags,
|
uint16_t messageType, LGNetEnvelopeFlags flags,
|
||||||
uint64_t componentEpoch, uint64_t requestID,
|
uint64_t componentEpoch, uint64_t requestID,
|
||||||
const void * payload, uint32_t payloadLength)
|
const void * payload, uint32_t payloadLength)
|
||||||
{
|
{
|
||||||
if (service != LG_NET_SERVICE_CLIPBOARD &&
|
|
||||||
service != LG_NET_SERVICE_FILE)
|
|
||||||
return NetworkClipboardSendResult::FAILED;
|
|
||||||
|
|
||||||
CSRWSharedLock guard(lock);
|
|
||||||
for (Connection * connection : connections)
|
for (Connection * connection : connections)
|
||||||
{
|
{
|
||||||
if (connection->client != peer.client ||
|
if (connection->client != peer.client ||
|
||||||
@@ -823,6 +909,65 @@ struct CNetworkServer::Impl
|
|||||||
return NetworkClipboardSendResult::FAILED;
|
return NetworkClipboardSendResult::FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetworkClipboardSendResult SendClipboard(
|
||||||
|
const NetworkClipboardPeer& peer, bool bulk, LGNetService service,
|
||||||
|
uint16_t messageType, LGNetEnvelopeFlags flags,
|
||||||
|
uint64_t componentEpoch, uint64_t requestID,
|
||||||
|
const void * payload, uint32_t payloadLength)
|
||||||
|
{
|
||||||
|
if (service != LG_NET_SERVICE_CLIPBOARD &&
|
||||||
|
service != LG_NET_SERVICE_FILE)
|
||||||
|
return NetworkClipboardSendResult::FAILED;
|
||||||
|
|
||||||
|
const bool claimResult =
|
||||||
|
service == LG_NET_SERVICE_CLIPBOARD &&
|
||||||
|
messageType == LG_NET_CLIPBOARD_MESSAGE_CLAIM_RESULT;
|
||||||
|
if (claimResult)
|
||||||
|
{
|
||||||
|
CSRWSharedLock guard(lock);
|
||||||
|
return SendClipboardLocked(peer, bulk, service, messageType, flags,
|
||||||
|
componentEpoch, requestID, payload, payloadLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SendContext
|
||||||
|
{
|
||||||
|
Impl * owner = nullptr;
|
||||||
|
NetworkClipboardPeer peer = {};
|
||||||
|
bool bulk = false;
|
||||||
|
LGNetService service = 0;
|
||||||
|
uint16_t messageType = 0;
|
||||||
|
LGNetEnvelopeFlags flags = 0;
|
||||||
|
uint64_t componentEpoch = 0;
|
||||||
|
uint64_t requestID = 0;
|
||||||
|
const void * payload = nullptr;
|
||||||
|
uint32_t payloadLength = 0;
|
||||||
|
NetworkClipboardSendResult result =
|
||||||
|
NetworkClipboardSendResult::FAILED;
|
||||||
|
} context;
|
||||||
|
context.owner = this;
|
||||||
|
context.peer = peer;
|
||||||
|
context.bulk = bulk;
|
||||||
|
context.service = service;
|
||||||
|
context.messageType = messageType;
|
||||||
|
context.flags = flags;
|
||||||
|
context.componentEpoch = componentEpoch;
|
||||||
|
context.requestID = requestID;
|
||||||
|
context.payload = payload;
|
||||||
|
context.payloadLength = payloadLength;
|
||||||
|
|
||||||
|
const auto send = [](void * value)
|
||||||
|
{
|
||||||
|
SendContext& sendContext = *static_cast<SendContext *>(value);
|
||||||
|
sendContext.result = sendContext.owner->SendClipboardLocked(
|
||||||
|
sendContext.peer, sendContext.bulk, sendContext.service,
|
||||||
|
sendContext.messageType, sendContext.flags,
|
||||||
|
sendContext.componentEpoch, sendContext.requestID,
|
||||||
|
sendContext.payload, sendContext.payloadLength);
|
||||||
|
};
|
||||||
|
return ClipboardWithInputAuthority(peer, send, &context) ?
|
||||||
|
context.result : NetworkClipboardSendResult::UNAUTHORIZED;
|
||||||
|
}
|
||||||
|
|
||||||
bool VideoPeerInfo(const NetworkVideoPeer& peer,
|
bool VideoPeerInfo(const NetworkVideoPeer& peer,
|
||||||
NetworkVideoPeerInfo& info)
|
NetworkVideoPeerInfo& info)
|
||||||
{
|
{
|
||||||
@@ -3016,12 +3161,15 @@ retry:
|
|||||||
memset(connection.keyboardKeys, 0, sizeof(connection.keyboardKeys));
|
memset(connection.keyboardKeys, 0, sizeof(connection.keyboardKeys));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InvalidateInputClaim(Connection& connection,
|
void InvalidateInputClaim(Connection& connection,
|
||||||
uint64_t claimEpoch)
|
uint64_t claimEpoch)
|
||||||
{
|
{
|
||||||
CSRWExclusiveLock guard(connection.lock);
|
{
|
||||||
if (connection.inputClaimEpoch == claimEpoch)
|
CSRWExclusiveLock guard(connection.lock);
|
||||||
ClearInputStateLocked(connection, true);
|
if (connection.inputClaimEpoch == claimEpoch)
|
||||||
|
ClearInputStateLocked(connection, true);
|
||||||
|
}
|
||||||
|
clipboard.Process(GetTickCount64());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SendInputStatus(Connection& connection, uint16_t messageType,
|
bool SendInputStatus(Connection& connection, uint16_t messageType,
|
||||||
@@ -3131,6 +3279,7 @@ retry:
|
|||||||
ClearInputStateLocked(connection, false);
|
ClearInputStateLocked(connection, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clipboard.Process(GetTickCount64());
|
||||||
const LGNetInputStatusCode code = InputStatusCode(result);
|
const LGNetInputStatusCode code = InputStatusCode(result);
|
||||||
return SendInputStatus(connection, LG_NET_INPUT_MESSAGE_CLAIM_RESULT,
|
return SendInputStatus(connection, LG_NET_INPUT_MESSAGE_CLAIM_RESULT,
|
||||||
code, claim.claimEpoch, packet.envelope.requestID,
|
code, claim.claimEpoch, packet.envelope.requestID,
|
||||||
@@ -3233,6 +3382,9 @@ retry:
|
|||||||
if (result == InputResult::ACCEPTED &&
|
if (result == InputResult::ACCEPTED &&
|
||||||
packet.envelope.messageType == LG_NET_INPUT_MESSAGE_KEEPALIVE)
|
packet.envelope.messageType == LG_NET_INPUT_MESSAGE_KEEPALIVE)
|
||||||
return SendInputLEDs(connection);
|
return SendInputLEDs(connection);
|
||||||
|
if (result == InputResult::ACCEPTED &&
|
||||||
|
packet.envelope.messageType == LG_NET_INPUT_MESSAGE_RELEASE)
|
||||||
|
clipboard.Process(GetTickCount64());
|
||||||
|
|
||||||
const LGNetInputStatusCode code =
|
const LGNetInputStatusCode code =
|
||||||
packet.envelope.messageType == LG_NET_INPUT_MESSAGE_RELEASE &&
|
packet.envelope.messageType == LG_NET_INPUT_MESSAGE_RELEASE &&
|
||||||
@@ -5231,6 +5383,20 @@ NetworkAudioSendResult CNetworkServer::SendAudio(
|
|||||||
NetworkAudioSendResult::FAILED;
|
NetworkAudioSendResult::FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CNetworkServer::ClipboardPeerOwnsInput(
|
||||||
|
const NetworkClipboardPeer& peer)
|
||||||
|
{
|
||||||
|
return m_impl && m_impl->ClipboardPeerOwnsInput(peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNetworkServer::ClipboardWithInputAuthority(
|
||||||
|
const NetworkClipboardPeer& peer, NetworkClipboardInputAction action,
|
||||||
|
void * opaque)
|
||||||
|
{
|
||||||
|
return m_impl &&
|
||||||
|
m_impl->ClipboardWithInputAuthority(peer, action, opaque);
|
||||||
|
}
|
||||||
|
|
||||||
bool CNetworkServer::ClipboardPeerInfo(
|
bool CNetworkServer::ClipboardPeerInfo(
|
||||||
const NetworkClipboardPeer& peer, NetworkClipboardPeerInfo& info)
|
const NetworkClipboardPeer& peer, NetworkClipboardPeerInfo& info)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -59,6 +59,10 @@ public:
|
|||||||
uint64_t componentEpoch, uint64_t requestID,
|
uint64_t componentEpoch, uint64_t requestID,
|
||||||
const void * payload, uint32_t payloadLength) override;
|
const void * payload, uint32_t payloadLength) override;
|
||||||
|
|
||||||
|
bool ClipboardPeerOwnsInput(
|
||||||
|
const NetworkClipboardPeer& peer) override;
|
||||||
|
bool ClipboardWithInputAuthority(const NetworkClipboardPeer& peer,
|
||||||
|
NetworkClipboardInputAction action, void * opaque) override;
|
||||||
bool ClipboardPeerInfo(const NetworkClipboardPeer& peer,
|
bool ClipboardPeerInfo(const NetworkClipboardPeer& peer,
|
||||||
NetworkClipboardPeerInfo& info) override;
|
NetworkClipboardPeerInfo& info) override;
|
||||||
NetworkClipboardSendResult SendClipboard(
|
NetworkClipboardSendResult SendClipboard(
|
||||||
|
|||||||
@@ -116,6 +116,13 @@ InputTargetState CNetworkInputSource::GetState(
|
|||||||
return m_target ? m_target->GetState(source) : InputTargetState {};
|
return m_target ? m_target->GetState(source) : InputTargetState {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CNetworkInputSource::WithAuthority(const InputSourceId& source,
|
||||||
|
InputAuthorityAction action, void * opaque) const
|
||||||
|
{
|
||||||
|
CSRWSharedLock lock(m_lock);
|
||||||
|
return m_target && m_target->WithAuthority(source, action, opaque);
|
||||||
|
}
|
||||||
|
|
||||||
InputResult CNetworkInputSource::Claim(const InputSourceId& source)
|
InputResult CNetworkInputSource::Claim(const InputSourceId& source)
|
||||||
{
|
{
|
||||||
CSRWSharedLock lock(m_lock);
|
CSRWSharedLock lock(m_lock);
|
||||||
@@ -519,6 +526,13 @@ InputTargetState CNetworkSession::InputState() const
|
|||||||
return m_open ? m_input.GetState(m_source) : InputTargetState {};
|
return m_open ? m_input.GetState(m_source) : InputTargetState {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CNetworkSession::WithInputAuthority(
|
||||||
|
InputAuthorityAction action, void * opaque) const
|
||||||
|
{
|
||||||
|
CSRWSharedLock lock(m_lifecycleLock);
|
||||||
|
return m_open && m_input.WithAuthority(m_source, action, opaque);
|
||||||
|
}
|
||||||
|
|
||||||
InputResult CNetworkSession::ClaimInput()
|
InputResult CNetworkSession::ClaimInput()
|
||||||
{
|
{
|
||||||
CSRWSharedLock lock(m_lifecycleLock);
|
CSRWSharedLock lock(m_lifecycleLock);
|
||||||
|
|||||||
@@ -97,6 +97,8 @@ public:
|
|||||||
void Stop() override;
|
void Stop() override;
|
||||||
|
|
||||||
InputTargetState GetState(const InputSourceId& source) const;
|
InputTargetState GetState(const InputSourceId& source) const;
|
||||||
|
bool WithAuthority(const InputSourceId& source,
|
||||||
|
InputAuthorityAction action, void * opaque) const;
|
||||||
InputResult Claim(const InputSourceId& source);
|
InputResult Claim(const InputSourceId& source);
|
||||||
InputResult Touch(const InputSourceId& source);
|
InputResult Touch(const InputSourceId& source);
|
||||||
InputResult Release(const InputSourceId& source, bool reset);
|
InputResult Release(const InputSourceId& source, bool reset);
|
||||||
@@ -197,6 +199,8 @@ public:
|
|||||||
bool TakeControlStatus(NetworkControlStatus& status);
|
bool TakeControlStatus(NetworkControlStatus& status);
|
||||||
|
|
||||||
InputTargetState InputState() const;
|
InputTargetState InputState() const;
|
||||||
|
bool WithInputAuthority(
|
||||||
|
InputAuthorityAction action, void * opaque) const;
|
||||||
InputResult ClaimInput();
|
InputResult ClaimInput();
|
||||||
InputResult TouchInput();
|
InputResult TouchInput();
|
||||||
InputResult ReleaseInput(bool reset);
|
InputResult ReleaseInput(bool reset);
|
||||||
|
|||||||
Reference in New Issue
Block a user