// // PacketReceiver.h // libraries/networking/src // // Created by Stephen Birarda on 1/23/2014. // Update by Ryan Huffman on 7/8/2015. // Copyright 2014 High Fidelity, Inc. // Copyright 2021 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #ifndef hifi_PacketReceiver_h #define hifi_PacketReceiver_h #include #include #include #include #include #include #include #include #include "NLPacket.h" #include "NLPacketList.h" #include "ReceivedMessage.h" #include "udt/PacketHeaders.h" class EntityEditPacketSender; class Node; class OctreePacketProcessor; namespace std { template <> struct hash> { size_t operator()(const std::pair& pair) const { return hash()(pair.first) ^ hash()(pair.second); } }; } class PacketReceiver : public QObject { Q_OBJECT public: class ListenerReference : public QEnableSharedFromThis { public: virtual bool invokeDirectly(const QSharedPointer& receivedMessagePointer, const QSharedPointer& sourceNode) = 0; bool invokeWithQt(const QSharedPointer& receivedMessagePointer, const QSharedPointer& sourceNode); virtual bool isSourced() const = 0; virtual QObject* getObject() const = 0; }; typedef QSharedPointer ListenerReferencePointer; template static ListenerReferencePointer makeUnsourcedListenerReference(T* target, void (T::*slot)(QSharedPointer)); template static ListenerReferencePointer makeSourcedListenerReference(T* target, void (T::*slot)(QSharedPointer, QSharedPointer)); public: using PacketTypeList = std::vector; PacketReceiver(QObject* parent = 0); PacketReceiver(const PacketReceiver&) = delete; PacketReceiver& operator=(const PacketReceiver&) = delete; void setShouldDropPackets(bool shouldDropPackets) { _shouldDropPackets = shouldDropPackets; } // If deliverPending is false, ReceivedMessage will only be delivered once all packets for the message have // been received. If deliverPending is true, ReceivedMessage will be delivered as soon as the first packet // for the message is received. bool registerListener(PacketType type, const ListenerReferencePointer& listener, bool deliverPending = false); bool registerListenerForTypes(PacketTypeList types, const ListenerReferencePointer& listener); void unregisterListener(QObject* listener); void handleVerifiedPacket(std::unique_ptr packet); void handleVerifiedMessagePacket(std::unique_ptr message); void handleMessageFailure(SockAddr from, udt::Packet::MessageNumber messageNumber); private: template class UnsourcedListenerReference : public ListenerReference { public: inline UnsourcedListenerReference(T* target, void (T::*slot)(QSharedPointer)); virtual bool invokeDirectly(const QSharedPointer& receivedMessagePointer, const QSharedPointer& sourceNode) override; virtual bool isSourced() const override { return false; } virtual QObject* getObject() const override { return _target; } private: QPointer _target; void (T::*_slot)(QSharedPointer); }; template class SourcedListenerReference : public ListenerReference { public: inline SourcedListenerReference(T* target, void (T::*slot)(QSharedPointer, QSharedPointer)); virtual bool invokeDirectly(const QSharedPointer& receivedMessagePointer, const QSharedPointer& sourceNode) override; virtual bool isSourced() const override { return true; } virtual QObject* getObject() const override { return _target; } private: QPointer _target; void (T::*_slot)(QSharedPointer, QSharedPointer); }; struct Listener { ListenerReferencePointer listener; bool deliverPending; }; void handleVerifiedMessage(QSharedPointer message, bool justReceived); // these are brutal hacks for now - ideally GenericThread / ReceivedPacketProcessor // should be changed to have a true event loop and be able to handle our QMetaMethod::invoke void registerDirectListenerForTypes(PacketTypeList types, const ListenerReferencePointer& listener); void registerDirectListener(PacketType type, const ListenerReferencePointer& listener); bool matchingMethodForListener(PacketType type, const ListenerReferencePointer& listener) const; void registerVerifiedListener(PacketType type, const ListenerReferencePointer& listener, bool deliverPending = false); QMutex _packetListenerLock; QHash _messageListenerMap; bool _shouldDropPackets = false; QMutex _directConnectSetMutex; QSet _directlyConnectedObjects; std::unordered_map, QSharedPointer> _pendingMessages; friend class EntityEditPacketSender; friend class OctreePacketProcessor; }; template PacketReceiver::ListenerReferencePointer PacketReceiver::makeUnsourcedListenerReference(T* target, void (T::* slot)(QSharedPointer)) { return QSharedPointer>::create(target, slot); } template PacketReceiver::ListenerReferencePointer PacketReceiver::makeSourcedListenerReference(T* target, void (T::* slot)(QSharedPointer, QSharedPointer)) { return QSharedPointer>::create(target, slot); } template PacketReceiver::UnsourcedListenerReference::UnsourcedListenerReference(T* target, void (T::*slot)(QSharedPointer)) : _target(target),_slot(slot) { } template bool PacketReceiver::UnsourcedListenerReference::invokeDirectly(const QSharedPointer& receivedMessagePointer, const QSharedPointer&) { if (_target.isNull()) { return false; } (_target->*_slot)(receivedMessagePointer); return true; } template PacketReceiver::SourcedListenerReference::SourcedListenerReference(T* target, void (T::*slot)(QSharedPointer, QSharedPointer)) : _target(target),_slot(slot) { } template bool PacketReceiver::SourcedListenerReference::invokeDirectly(const QSharedPointer& receivedMessagePointer, const QSharedPointer& sourceNode) { if (_target.isNull()) { return false; } (_target->*_slot)(receivedMessagePointer, sourceNode); return true; } #endif // hifi_PacketReceiver_h