mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-05-23 15:37:34 +08:00
TransferListener now can accept rogue transfers
This commit is contained in:
@@ -50,6 +50,11 @@ public:
|
||||
*/
|
||||
virtual void release() { }
|
||||
|
||||
/**
|
||||
* Whether this is a rogue transfer
|
||||
*/
|
||||
virtual bool isRogueTransfer() const { return false; }
|
||||
|
||||
MonotonicTime getMonotonicTimestamp() const { return ts_mono_; }
|
||||
UtcTime getUtcTimestamp() const { return ts_utc_; }
|
||||
TransferType getTransferType() const { return transfer_type_; }
|
||||
@@ -68,6 +73,7 @@ class UAVCAN_EXPORT SingleFrameIncomingTransfer : public IncomingTransfer
|
||||
public:
|
||||
explicit SingleFrameIncomingTransfer(const RxFrame& frm);
|
||||
virtual int read(unsigned offset, uint8_t* data, unsigned len) const;
|
||||
virtual bool isRogueTransfer() const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -93,6 +99,7 @@ class UAVCAN_EXPORT TransferListenerBase : public LinkedListNode<TransferListene
|
||||
MapBase<TransferBufferManagerKey, TransferReceiver>& receivers_;
|
||||
ITransferBufferManager& bufmgr_;
|
||||
TransferPerfCounter& perf_;
|
||||
bool allow_rogue_transfers_;
|
||||
|
||||
class TimedOutReceiverPredicate
|
||||
{
|
||||
@@ -119,17 +126,25 @@ protected:
|
||||
, receivers_(receivers)
|
||||
, bufmgr_(bufmgr)
|
||||
, perf_(perf)
|
||||
, allow_rogue_transfers_(false)
|
||||
{ }
|
||||
|
||||
virtual ~TransferListenerBase() { }
|
||||
|
||||
void handleReception(TransferReceiver& receiver, const RxFrame& frame, TransferBufferAccessor& tba);
|
||||
void handleRogueTransferReception(const RxFrame& frame);
|
||||
|
||||
virtual void handleIncomingTransfer(IncomingTransfer& transfer) = 0;
|
||||
|
||||
public:
|
||||
const DataTypeDescriptor& getDataTypeDescriptor() const { return data_type_; }
|
||||
|
||||
/**
|
||||
* By default, rogue transfers will be ignored.
|
||||
* This option allows to enable reception of rogue transfers.
|
||||
*/
|
||||
void allowRogueTransfers() { allow_rogue_transfers_ = true; }
|
||||
|
||||
void cleanup(MonotonicTime ts);
|
||||
|
||||
virtual void handleFrame(const RxFrame& frame);
|
||||
|
||||
@@ -50,6 +50,11 @@ int SingleFrameIncomingTransfer::read(unsigned offset, uint8_t* data, unsigned l
|
||||
return int(len);
|
||||
}
|
||||
|
||||
bool SingleFrameIncomingTransfer::isRogueTransfer() const
|
||||
{
|
||||
return (getTransferType() == TransferTypeMessageBroadcast) && getSrcNodeID().isBroadcast();
|
||||
}
|
||||
|
||||
/*
|
||||
* MultiFrameIncomingTransfer
|
||||
*/
|
||||
@@ -172,6 +177,16 @@ void TransferListenerBase::handleReception(TransferReceiver& receiver, const RxF
|
||||
}
|
||||
}
|
||||
|
||||
void TransferListenerBase::handleRogueTransferReception(const RxFrame& frame)
|
||||
{
|
||||
if (allow_rogue_transfers_)
|
||||
{
|
||||
perf_.addRxTransfer();
|
||||
SingleFrameIncomingTransfer it(frame);
|
||||
handleIncomingTransfer(it);
|
||||
}
|
||||
}
|
||||
|
||||
void TransferListenerBase::cleanup(MonotonicTime ts)
|
||||
{
|
||||
receivers_.removeWhere(TimedOutReceiverPredicate(ts, bufmgr_));
|
||||
@@ -180,26 +195,40 @@ void TransferListenerBase::cleanup(MonotonicTime ts)
|
||||
|
||||
void TransferListenerBase::handleFrame(const RxFrame& frame)
|
||||
{
|
||||
const TransferBufferManagerKey key(frame.getSrcNodeID(), frame.getTransferType());
|
||||
|
||||
TransferReceiver* recv = receivers_.access(key);
|
||||
if (recv == NULL)
|
||||
if (frame.getSrcNodeID().isUnicast()) // Normal transfer
|
||||
{
|
||||
if (!frame.isFirst())
|
||||
{
|
||||
return;
|
||||
}
|
||||
const TransferBufferManagerKey key(frame.getSrcNodeID(), frame.getTransferType());
|
||||
|
||||
TransferReceiver new_recv;
|
||||
recv = receivers_.insert(key, new_recv);
|
||||
TransferReceiver* recv = receivers_.access(key);
|
||||
if (recv == NULL)
|
||||
{
|
||||
UAVCAN_TRACE("TransferListener", "Receiver registration failed; frame %s", frame.toString().c_str());
|
||||
return;
|
||||
if (!frame.isFirst())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TransferReceiver new_recv;
|
||||
recv = receivers_.insert(key, new_recv);
|
||||
if (recv == NULL)
|
||||
{
|
||||
UAVCAN_TRACE("TransferListener", "Receiver registration failed; frame %s", frame.toString().c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
TransferBufferAccessor tba(bufmgr_, key);
|
||||
handleReception(*recv, frame, tba);
|
||||
}
|
||||
else if (frame.getSrcNodeID().isBroadcast() &&
|
||||
frame.isFirst() &&
|
||||
frame.isLast() &&
|
||||
frame.getDstNodeID().isBroadcast()) // Rogue transfer
|
||||
{
|
||||
handleRogueTransferReception(frame);
|
||||
}
|
||||
else
|
||||
{
|
||||
UAVCAN_TRACE("TransferListenerBase", "Invalid frame: %s", frame.toString().c_str()); // Invalid frame
|
||||
}
|
||||
TransferBufferAccessor tba(bufmgr_, key);
|
||||
handleReception(*recv, frame, tba);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -243,3 +243,38 @@ TEST(TransferListener, MaximumTransferLength)
|
||||
|
||||
ASSERT_TRUE(subscriber.isEmpty());
|
||||
}
|
||||
|
||||
|
||||
TEST(TransferListener, RogueTransfers)
|
||||
{
|
||||
const uavcan::DataTypeDescriptor type(uavcan::DataTypeKindMessage, 123, uavcan::DataTypeSignature(123456789), "A");
|
||||
|
||||
uavcan::PoolManager<1> poolmgr;
|
||||
uavcan::TransferPerfCounter perf;
|
||||
TestListener<0, 0, 0> subscriber(perf, type, poolmgr);
|
||||
|
||||
TransferListenerEmulator emulator(subscriber, type);
|
||||
const Transfer transfers[] =
|
||||
{
|
||||
emulator.makeTransfer(uavcan::TransferTypeMessageUnicast, 0, "12345678"), // Invalid - not broadcast
|
||||
emulator.makeTransfer(uavcan::TransferTypeMessageBroadcast, 0, "12345678"), // Valid
|
||||
emulator.makeTransfer(uavcan::TransferTypeMessageBroadcast, 0, "123456789"), // Invalid - not SFT
|
||||
emulator.makeTransfer(uavcan::TransferTypeMessageBroadcast, 0, "") // Valid
|
||||
};
|
||||
|
||||
emulator.send(transfers);
|
||||
|
||||
// Nothing will be received, because rogue transfers are disabled by default
|
||||
ASSERT_TRUE(subscriber.isEmpty());
|
||||
|
||||
subscriber.allowRogueTransfers();
|
||||
|
||||
// Re-send everything again
|
||||
emulator.send(transfers);
|
||||
|
||||
// Now the rogue transfers are enabled
|
||||
ASSERT_TRUE(subscriber.matchAndPop(transfers[1])); // Only SFT broadcast will be accepted
|
||||
ASSERT_TRUE(subscriber.matchAndPop(transfers[3]));
|
||||
|
||||
ASSERT_TRUE(subscriber.isEmpty());
|
||||
}
|
||||
|
||||
@@ -129,6 +129,14 @@ public:
|
||||
const Transfer rx(transfer, Base::getDataTypeDescriptor());
|
||||
transfers_.push(rx);
|
||||
std::cout << "Received transfer: " << rx.toString() << std::endl;
|
||||
|
||||
const bool single_frame = dynamic_cast<uavcan::SingleFrameIncomingTransfer*>(&transfer) != NULL;
|
||||
|
||||
const bool rogue = single_frame &&
|
||||
transfer.getSrcNodeID().isBroadcast() &&
|
||||
(transfer.getTransferType() == uavcan::TransferTypeMessageBroadcast);
|
||||
|
||||
ASSERT_EQ(rogue, transfer.isRogueTransfer());
|
||||
}
|
||||
|
||||
bool matchAndPop(const Transfer& reference)
|
||||
|
||||
Reference in New Issue
Block a user