Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : // Original author: ekr@rtfm.com
8 :
9 : #ifndef transportlayerloopback_h__
10 : #define transportlayerloopback_h__
11 :
12 : #include "nspr.h"
13 : #include "prio.h"
14 : #include "prlock.h"
15 :
16 : #include <memory>
17 : #include <queue>
18 :
19 :
20 : #include "nsAutoPtr.h"
21 : #include "nsCOMPtr.h"
22 : #include "nsITimer.h"
23 :
24 :
25 : #include "m_cpp_utils.h"
26 : #include "transportflow.h"
27 : #include "transportlayer.h"
28 :
29 : // A simple loopback transport layer that is used for testing.
30 : namespace mozilla {
31 :
32 : class TransportLayerLoopback : public TransportLayer {
33 : public:
34 : TransportLayerLoopback() :
35 : peer_(nullptr),
36 : timer_(nullptr),
37 : packets_(),
38 : packets_lock_(nullptr),
39 : deliverer_(nullptr),
40 : combinePackets_(false) {}
41 :
42 0 : ~TransportLayerLoopback() {
43 0 : while (!packets_.empty()) {
44 0 : QueuedPacket *packet = packets_.front();
45 0 : packets_.pop();
46 0 : delete packet;
47 : }
48 0 : if (packets_lock_) {
49 0 : PR_DestroyLock(packets_lock_);
50 : }
51 0 : timer_->Cancel();
52 0 : deliverer_->Detach();
53 0 : }
54 :
55 : // Init
56 : nsresult Init();
57 :
58 : // Connect to the other side
59 : void Connect(TransportLayerLoopback* peer);
60 :
61 : // Disconnect
62 : void Disconnect() {
63 : TransportLayerLoopback *peer = peer_;
64 :
65 : peer_ = nullptr;
66 : if (peer) {
67 : peer->Disconnect();
68 : }
69 : }
70 :
71 : void CombinePackets(bool combine) { combinePackets_ = combine; }
72 :
73 : // Overrides for TransportLayer
74 : TransportResult SendPacket(const unsigned char *data, size_t len) override;
75 :
76 : // Deliver queued packets
77 : void DeliverPackets();
78 :
79 0 : TRANSPORT_LAYER_ID("loopback")
80 :
81 : private:
82 : DISALLOW_COPY_ASSIGN(TransportLayerLoopback);
83 :
84 : // A queued packet
85 : class QueuedPacket {
86 : public:
87 0 : QueuedPacket() : data_(nullptr), len_(0) {}
88 0 : ~QueuedPacket() {
89 0 : delete [] data_;
90 0 : }
91 :
92 0 : void Assign(const unsigned char *data, size_t len) {
93 0 : data_ = new unsigned char[len];
94 0 : memcpy(static_cast<void *>(data_),
95 0 : static_cast<const void *>(data), len);
96 0 : len_ = len;
97 0 : }
98 :
99 0 : void Assign(const unsigned char *data1, size_t len1,
100 : const unsigned char *data2, size_t len2) {
101 0 : data_ = new unsigned char[len1 + len2];
102 0 : memcpy(static_cast<void *>(data_),
103 0 : static_cast<const void *>(data1), len1);
104 0 : memcpy(static_cast<void *>(data_ + len1),
105 0 : static_cast<const void *>(data2), len2);
106 0 : len_ = len1 + len2;
107 0 : }
108 :
109 0 : const unsigned char *data() const { return data_; }
110 0 : size_t len() const { return len_; }
111 :
112 : private:
113 : DISALLOW_COPY_ASSIGN(QueuedPacket);
114 :
115 : unsigned char *data_;
116 : size_t len_;
117 : };
118 :
119 : // A timer to deliver packets if some are available
120 : // Fires every 100 ms
121 : class Deliverer : public nsITimerCallback {
122 : public:
123 0 : explicit Deliverer(TransportLayerLoopback *layer) :
124 0 : layer_(layer) {}
125 0 : void Detach() {
126 0 : layer_ = nullptr;
127 0 : }
128 :
129 : NS_DECL_THREADSAFE_ISUPPORTS
130 : NS_DECL_NSITIMERCALLBACK
131 :
132 : private:
133 0 : virtual ~Deliverer() {
134 0 : }
135 :
136 : DISALLOW_COPY_ASSIGN(Deliverer);
137 :
138 : TransportLayerLoopback *layer_;
139 : };
140 :
141 : // Queue a packet for delivery
142 : nsresult QueuePacket(const unsigned char *data, size_t len);
143 :
144 : TransportLayerLoopback* peer_;
145 : nsCOMPtr<nsITimer> timer_;
146 : std::queue<QueuedPacket *> packets_;
147 : PRLock *packets_lock_;
148 : RefPtr<Deliverer> deliverer_;
149 : bool combinePackets_;
150 : };
151 :
152 : } // close namespace
153 : #endif
|