michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // Original author: ekr@rtfm.com michael@0: michael@0: #ifndef transportlayerloopback_h__ michael@0: #define transportlayerloopback_h__ michael@0: michael@0: #include "nspr.h" michael@0: #include "prio.h" michael@0: #include "prlock.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: michael@0: #include "nsAutoPtr.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsITimer.h" michael@0: michael@0: michael@0: #include "m_cpp_utils.h" michael@0: #include "transportflow.h" michael@0: #include "transportlayer.h" michael@0: michael@0: // A simple loopback transport layer that is used for testing. michael@0: namespace mozilla { michael@0: michael@0: class TransportLayerLoopback : public TransportLayer { michael@0: public: michael@0: TransportLayerLoopback() : michael@0: peer_(nullptr), michael@0: timer_(nullptr), michael@0: packets_(), michael@0: packets_lock_(nullptr), michael@0: deliverer_(nullptr) {} michael@0: michael@0: ~TransportLayerLoopback() { michael@0: while (!packets_.empty()) { michael@0: QueuedPacket *packet = packets_.front(); michael@0: packets_.pop(); michael@0: delete packet; michael@0: } michael@0: if (packets_lock_) { michael@0: PR_DestroyLock(packets_lock_); michael@0: } michael@0: timer_->Cancel(); michael@0: deliverer_->Detach(); michael@0: } michael@0: michael@0: // Init michael@0: nsresult Init(); michael@0: michael@0: // Connect to the other side michael@0: void Connect(TransportLayerLoopback* peer); michael@0: michael@0: // Disconnect michael@0: void Disconnect() { michael@0: TransportLayerLoopback *peer = peer_; michael@0: michael@0: peer_ = nullptr; michael@0: if (peer) { michael@0: peer->Disconnect(); michael@0: } michael@0: } michael@0: michael@0: // Overrides for TransportLayer michael@0: virtual TransportResult SendPacket(const unsigned char *data, size_t len); michael@0: michael@0: // Deliver queued packets michael@0: void DeliverPackets(); michael@0: michael@0: TRANSPORT_LAYER_ID("loopback") michael@0: michael@0: private: michael@0: DISALLOW_COPY_ASSIGN(TransportLayerLoopback); michael@0: michael@0: // A queued packet michael@0: class QueuedPacket { michael@0: public: michael@0: QueuedPacket() : data_(nullptr), len_(0) {} michael@0: ~QueuedPacket() { michael@0: delete [] data_; michael@0: } michael@0: michael@0: void Assign(const unsigned char *data, size_t len) { michael@0: data_ = new unsigned char[len]; michael@0: memcpy(static_cast(data_), michael@0: static_cast(data), len); michael@0: len_ = len; michael@0: } michael@0: michael@0: const unsigned char *data() const { return data_; } michael@0: size_t len() const { return len_; } michael@0: michael@0: private: michael@0: DISALLOW_COPY_ASSIGN(QueuedPacket); michael@0: michael@0: unsigned char *data_; michael@0: size_t len_; michael@0: }; michael@0: michael@0: // A timer to deliver packets if some are available michael@0: // Fires every 100 ms michael@0: class Deliverer : public nsITimerCallback { michael@0: public: michael@0: Deliverer(TransportLayerLoopback *layer) : michael@0: layer_(layer) {} michael@0: virtual ~Deliverer() { michael@0: } michael@0: void Detach() { michael@0: layer_ = nullptr; michael@0: } michael@0: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSITIMERCALLBACK michael@0: michael@0: private: michael@0: DISALLOW_COPY_ASSIGN(Deliverer); michael@0: michael@0: TransportLayerLoopback *layer_; michael@0: }; michael@0: michael@0: // Queue a packet for delivery michael@0: nsresult QueuePacket(const unsigned char *data, size_t len); michael@0: michael@0: TransportLayerLoopback* peer_; michael@0: nsCOMPtr timer_; michael@0: std::queue packets_; michael@0: PRLock *packets_lock_; michael@0: nsRefPtr deliverer_; michael@0: }; michael@0: michael@0: } // close namespace michael@0: #endif