Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(704)

Side by Side Diff: webrtc/media/sctp/sctpdataengine_unittest.cc

Issue 2564333002: Reland of: Separating SCTP code from BaseChannel/MediaChannel. (Closed)
Patch Set: Merge with master. Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/media/sctp/sctpdataengine.cc ('k') | webrtc/media/sctp/sctptransport.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include <errno.h>
12 #include <stdarg.h>
13 #include <stdio.h>
14
15 #include <memory>
16 #include <string>
17 #include <vector>
18
19 #include "webrtc/base/bind.h"
20 #include "webrtc/base/copyonwritebuffer.h"
21 #include "webrtc/base/criticalsection.h"
22 #include "webrtc/base/gunit.h"
23 #include "webrtc/base/helpers.h"
24 #include "webrtc/base/messagehandler.h"
25 #include "webrtc/base/messagequeue.h"
26 #include "webrtc/base/ssladapter.h"
27 #include "webrtc/base/thread.h"
28 #include "webrtc/media/base/mediachannel.h"
29 #include "webrtc/media/base/mediaconstants.h"
30 #include "webrtc/media/sctp/sctpdataengine.h"
31
32 namespace cricket {
33 enum {
34 MSG_PACKET = 1,
35 };
36
37 // Fake NetworkInterface that sends/receives sctp packets. The one in
38 // webrtc/media/base/fakenetworkinterface.h only works with rtp/rtcp.
39 class SctpFakeNetworkInterface : public MediaChannel::NetworkInterface,
40 public rtc::MessageHandler {
41 public:
42 explicit SctpFakeNetworkInterface(rtc::Thread* thread)
43 : thread_(thread),
44 dest_(NULL) {
45 }
46
47 void SetDestination(DataMediaChannel* dest) { dest_ = dest; }
48
49 protected:
50 // Called to send raw packet down the wire (e.g. SCTP an packet).
51 virtual bool SendPacket(rtc::CopyOnWriteBuffer* packet,
52 const rtc::PacketOptions& options) {
53 LOG(LS_VERBOSE) << "SctpFakeNetworkInterface::SendPacket";
54
55 rtc::CopyOnWriteBuffer* buffer = new rtc::CopyOnWriteBuffer(*packet);
56 thread_->Post(RTC_FROM_HERE, this, MSG_PACKET,
57 rtc::WrapMessageData(buffer));
58 LOG(LS_VERBOSE) << "SctpFakeNetworkInterface::SendPacket, Posted message.";
59 return true;
60 }
61
62 // Called when a raw packet has been recieved. This passes the data to the
63 // code that will interpret the packet. e.g. to get the content payload from
64 // an SCTP packet.
65 virtual void OnMessage(rtc::Message* msg) {
66 LOG(LS_VERBOSE) << "SctpFakeNetworkInterface::OnMessage";
67 std::unique_ptr<rtc::CopyOnWriteBuffer> buffer(
68 static_cast<rtc::TypedMessageData<rtc::CopyOnWriteBuffer*>*>(
69 msg->pdata)->data());
70 if (dest_) {
71 dest_->OnPacketReceived(buffer.get(), rtc::PacketTime());
72 }
73 delete msg->pdata;
74 }
75
76 // Unsupported functions required to exist by NetworkInterface.
77 // TODO(ldixon): Refactor parent NetworkInterface class so these are not
78 // required. They are RTC specific and should be in an appropriate subclass.
79 virtual bool SendRtcp(rtc::CopyOnWriteBuffer* packet,
80 const rtc::PacketOptions& options) {
81 LOG(LS_WARNING) << "Unsupported: SctpFakeNetworkInterface::SendRtcp.";
82 return false;
83 }
84 virtual int SetOption(SocketType type, rtc::Socket::Option opt,
85 int option) {
86 LOG(LS_WARNING) << "Unsupported: SctpFakeNetworkInterface::SetOption.";
87 return 0;
88 }
89 virtual void SetDefaultDSCPCode(rtc::DiffServCodePoint dscp) {
90 LOG(LS_WARNING) << "Unsupported: SctpFakeNetworkInterface::SetOption.";
91 }
92
93 private:
94 // Not owned by this class.
95 rtc::Thread* thread_;
96 DataMediaChannel* dest_;
97 };
98
99 // This is essentially a buffer to hold recieved data. It stores only the last
100 // received data. Calling OnDataReceived twice overwrites old data with the
101 // newer one.
102 // TODO(ldixon): Implement constraints, and allow new data to be added to old
103 // instead of replacing it.
104 class SctpFakeDataReceiver : public sigslot::has_slots<> {
105 public:
106 SctpFakeDataReceiver() : received_(false) {}
107
108 void Clear() {
109 received_ = false;
110 last_data_ = "";
111 last_params_ = ReceiveDataParams();
112 }
113
114 virtual void OnDataReceived(const ReceiveDataParams& params,
115 const char* data,
116 size_t length) {
117 received_ = true;
118 last_data_ = std::string(data, length);
119 last_params_ = params;
120 }
121
122 bool received() const { return received_; }
123 std::string last_data() const { return last_data_; }
124 ReceiveDataParams last_params() const { return last_params_; }
125
126 private:
127 bool received_;
128 std::string last_data_;
129 ReceiveDataParams last_params_;
130 };
131
132 class SignalReadyToSendObserver : public sigslot::has_slots<> {
133 public:
134 SignalReadyToSendObserver() : signaled_(false), writable_(false) {}
135
136 void OnSignaled(bool writable) {
137 signaled_ = true;
138 writable_ = writable;
139 }
140
141 bool IsSignaled(bool writable) {
142 return signaled_ && (writable_ == writable);
143 }
144
145 private:
146 bool signaled_;
147 bool writable_;
148 };
149
150 class SignalChannelClosedObserver : public sigslot::has_slots<> {
151 public:
152 SignalChannelClosedObserver() {}
153 void BindSelf(SctpDataMediaChannel* channel) {
154 channel->SignalStreamClosedRemotely.connect(
155 this, &SignalChannelClosedObserver::OnStreamClosed);
156 }
157 void OnStreamClosed(uint32_t stream) { streams_.push_back(stream); }
158
159 int StreamCloseCount(uint32_t stream) {
160 return std::count(streams_.begin(), streams_.end(), stream);
161 }
162
163 bool WasStreamClosed(uint32_t stream) {
164 return std::find(streams_.begin(), streams_.end(), stream)
165 != streams_.end();
166 }
167
168 private:
169 std::vector<uint32_t> streams_;
170 };
171
172 class SignalChannelClosedReopener : public sigslot::has_slots<> {
173 public:
174 SignalChannelClosedReopener(SctpDataMediaChannel* channel,
175 SctpDataMediaChannel* peer)
176 : channel_(channel), peer_(peer) {}
177
178 void OnStreamClosed(int stream) {
179 StreamParams p(StreamParams::CreateLegacy(stream));
180 channel_->AddSendStream(p);
181 channel_->AddRecvStream(p);
182 peer_->AddSendStream(p);
183 peer_->AddRecvStream(p);
184 streams_.push_back(stream);
185 }
186
187 int StreamCloseCount(int stream) {
188 return std::count(streams_.begin(), streams_.end(), stream);
189 }
190
191 private:
192 SctpDataMediaChannel* channel_;
193 SctpDataMediaChannel* peer_;
194 std::vector<int> streams_;
195 };
196
197 // SCTP Data Engine testing framework.
198 class SctpDataMediaChannelTest : public testing::Test,
199 public sigslot::has_slots<> {
200 protected:
201 // usrsctp uses the NSS random number generator on non-Android platforms,
202 // so we need to initialize SSL.
203 static void SetUpTestCase() {
204 }
205
206 virtual void SetUp() { engine_.reset(new SctpDataEngine()); }
207
208 void SetupConnectedChannels() {
209 net1_.reset(new SctpFakeNetworkInterface(rtc::Thread::Current()));
210 net2_.reset(new SctpFakeNetworkInterface(rtc::Thread::Current()));
211 recv1_.reset(new SctpFakeDataReceiver());
212 recv2_.reset(new SctpFakeDataReceiver());
213 chan1_ready_to_send_count_ = 0;
214 chan2_ready_to_send_count_ = 0;
215 chan1_.reset(CreateChannel(net1_.get(), recv1_.get()));
216 chan1_->set_debug_name_for_testing("chan1/connector");
217 chan1_->SignalReadyToSend.connect(
218 this, &SctpDataMediaChannelTest::OnChan1ReadyToSend);
219 chan2_.reset(CreateChannel(net2_.get(), recv2_.get()));
220 chan2_->set_debug_name_for_testing("chan2/listener");
221 chan2_->SignalReadyToSend.connect(
222 this, &SctpDataMediaChannelTest::OnChan2ReadyToSend);
223 // Setup two connected channels ready to send and receive.
224 net1_->SetDestination(chan2_.get());
225 net2_->SetDestination(chan1_.get());
226
227 LOG(LS_VERBOSE) << "Channel setup ----------------------------- ";
228 AddStream(1);
229 AddStream(2);
230
231 LOG(LS_VERBOSE) << "Connect the channels -----------------------------";
232 // chan1 wants to setup a data connection.
233 chan1_->SetReceive(true);
234 // chan1 will have sent chan2 a request to setup a data connection. After
235 // chan2 accepts the offer, chan2 connects to chan1 with the following.
236 chan2_->SetReceive(true);
237 chan2_->SetSend(true);
238 // Makes sure that network packets are delivered and simulates a
239 // deterministic and realistic small timing delay between the SetSend calls.
240 ProcessMessagesUntilIdle();
241
242 // chan1 and chan2 are now connected so chan1 enables sending to complete
243 // the creation of the connection.
244 chan1_->SetSend(true);
245 }
246
247 virtual void TearDown() {
248 channel1()->SetSend(false);
249 channel2()->SetSend(false);
250
251 // Process messages until idle to prevent a sent packet from being dropped
252 // and causing memory leaks (not being deleted by the receiver).
253 ProcessMessagesUntilIdle();
254 }
255
256 bool AddStream(int ssrc) {
257 bool ret = true;
258 StreamParams p(StreamParams::CreateLegacy(ssrc));
259 ret = ret && chan1_->AddSendStream(p);
260 ret = ret && chan1_->AddRecvStream(p);
261 ret = ret && chan2_->AddSendStream(p);
262 ret = ret && chan2_->AddRecvStream(p);
263 return ret;
264 }
265
266 SctpDataMediaChannel* CreateChannel(SctpFakeNetworkInterface* net,
267 SctpFakeDataReceiver* recv) {
268 cricket::MediaConfig config;
269 SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(
270 engine_->CreateChannel(DCT_SCTP, config));
271 channel->SetInterface(net);
272 // When data is received, pass it to the SctpFakeDataReceiver.
273 channel->SignalDataReceived.connect(
274 recv, &SctpFakeDataReceiver::OnDataReceived);
275 return channel;
276 }
277
278 bool SendData(SctpDataMediaChannel* chan,
279 uint32_t ssrc,
280 const std::string& msg,
281 SendDataResult* result) {
282 SendDataParams params;
283 params.ssrc = ssrc;
284
285 return chan->SendData(params, rtc::CopyOnWriteBuffer(
286 &msg[0], msg.length()), result);
287 }
288
289 bool ReceivedData(const SctpFakeDataReceiver* recv,
290 uint32_t ssrc,
291 const std::string& msg) {
292 return (recv->received() &&
293 recv->last_params().ssrc == ssrc &&
294 recv->last_data() == msg);
295 }
296
297 bool ProcessMessagesUntilIdle() {
298 rtc::Thread* thread = rtc::Thread::Current();
299 while (!thread->empty()) {
300 rtc::Message msg;
301 if (thread->Get(&msg, rtc::Thread::kForever)) {
302 thread->Dispatch(&msg);
303 }
304 }
305 return !thread->IsQuitting();
306 }
307
308 SctpDataMediaChannel* channel1() { return chan1_.get(); }
309 SctpDataMediaChannel* channel2() { return chan2_.get(); }
310 SctpFakeDataReceiver* receiver1() { return recv1_.get(); }
311 SctpFakeDataReceiver* receiver2() { return recv2_.get(); }
312
313 int channel1_ready_to_send_count() { return chan1_ready_to_send_count_; }
314 int channel2_ready_to_send_count() { return chan2_ready_to_send_count_; }
315 private:
316 std::unique_ptr<SctpDataEngine> engine_;
317 std::unique_ptr<SctpFakeNetworkInterface> net1_;
318 std::unique_ptr<SctpFakeNetworkInterface> net2_;
319 std::unique_ptr<SctpFakeDataReceiver> recv1_;
320 std::unique_ptr<SctpFakeDataReceiver> recv2_;
321 std::unique_ptr<SctpDataMediaChannel> chan1_;
322 std::unique_ptr<SctpDataMediaChannel> chan2_;
323
324 int chan1_ready_to_send_count_;
325 int chan2_ready_to_send_count_;
326
327 void OnChan1ReadyToSend(bool send) {
328 if (send)
329 ++chan1_ready_to_send_count_;
330 }
331 void OnChan2ReadyToSend(bool send) {
332 if (send)
333 ++chan2_ready_to_send_count_;
334 }
335 };
336
337 // Verifies that SignalReadyToSend is fired.
338 TEST_F(SctpDataMediaChannelTest, SignalReadyToSend) {
339 SetupConnectedChannels();
340
341 SignalReadyToSendObserver signal_observer_1;
342 SignalReadyToSendObserver signal_observer_2;
343
344 channel1()->SignalReadyToSend.connect(&signal_observer_1,
345 &SignalReadyToSendObserver::OnSignaled);
346 channel2()->SignalReadyToSend.connect(&signal_observer_2,
347 &SignalReadyToSendObserver::OnSignaled);
348
349 SendDataResult result;
350 ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result));
351 EXPECT_EQ(SDR_SUCCESS, result);
352 EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000);
353 ASSERT_TRUE(SendData(channel2(), 2, "hi chan1", &result));
354 EXPECT_EQ(SDR_SUCCESS, result);
355 EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi chan1"), 1000);
356
357 EXPECT_TRUE_WAIT(signal_observer_1.IsSignaled(true), 1000);
358 EXPECT_TRUE_WAIT(signal_observer_2.IsSignaled(true), 1000);
359 }
360
361 TEST_F(SctpDataMediaChannelTest, SendData) {
362 SetupConnectedChannels();
363
364 SendDataResult result;
365 LOG(LS_VERBOSE) << "chan1 sending: 'hello?' -----------------------------";
366 ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result));
367 EXPECT_EQ(SDR_SUCCESS, result);
368 EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000);
369 LOG(LS_VERBOSE) << "recv2.received=" << receiver2()->received()
370 << ", recv2.last_params.ssrc="
371 << receiver2()->last_params().ssrc
372 << ", recv2.last_params.timestamp="
373 << receiver2()->last_params().ssrc
374 << ", recv2.last_params.seq_num="
375 << receiver2()->last_params().seq_num
376 << ", recv2.last_data=" << receiver2()->last_data();
377
378 LOG(LS_VERBOSE) << "chan2 sending: 'hi chan1' -----------------------------";
379 ASSERT_TRUE(SendData(channel2(), 2, "hi chan1", &result));
380 EXPECT_EQ(SDR_SUCCESS, result);
381 EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi chan1"), 1000);
382 LOG(LS_VERBOSE) << "recv1.received=" << receiver1()->received()
383 << ", recv1.last_params.ssrc="
384 << receiver1()->last_params().ssrc
385 << ", recv1.last_params.timestamp="
386 << receiver1()->last_params().ssrc
387 << ", recv1.last_params.seq_num="
388 << receiver1()->last_params().seq_num
389 << ", recv1.last_data=" << receiver1()->last_data();
390 }
391
392 // Sends a lot of large messages at once and verifies SDR_BLOCK is returned.
393 TEST_F(SctpDataMediaChannelTest, SendDataBlocked) {
394 SetupConnectedChannels();
395
396 SendDataResult result;
397 SendDataParams params;
398 params.ssrc = 1;
399
400 std::vector<char> buffer(1024 * 64, 0);
401
402 for (size_t i = 0; i < 100; ++i) {
403 channel1()->SendData(
404 params, rtc::CopyOnWriteBuffer(&buffer[0], buffer.size()), &result);
405 if (result == SDR_BLOCK)
406 break;
407 }
408
409 EXPECT_EQ(SDR_BLOCK, result);
410 }
411
412 TEST_F(SctpDataMediaChannelTest, ClosesRemoteStream) {
413 SetupConnectedChannels();
414 SignalChannelClosedObserver chan_1_sig_receiver, chan_2_sig_receiver;
415 chan_1_sig_receiver.BindSelf(channel1());
416 chan_2_sig_receiver.BindSelf(channel2());
417
418 SendDataResult result;
419 ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result));
420 EXPECT_EQ(SDR_SUCCESS, result);
421 EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000);
422 ASSERT_TRUE(SendData(channel2(), 2, "hi chan1", &result));
423 EXPECT_EQ(SDR_SUCCESS, result);
424 EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi chan1"), 1000);
425
426 // Close channel 1. Channel 2 should notify us.
427 channel1()->RemoveSendStream(1);
428 EXPECT_TRUE_WAIT(chan_2_sig_receiver.WasStreamClosed(1), 1000);
429 }
430
431 TEST_F(SctpDataMediaChannelTest, ClosesTwoRemoteStreams) {
432 SetupConnectedChannels();
433 AddStream(3);
434 SignalChannelClosedObserver chan_1_sig_receiver, chan_2_sig_receiver;
435 chan_1_sig_receiver.BindSelf(channel1());
436 chan_2_sig_receiver.BindSelf(channel2());
437
438 SendDataResult result;
439 ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result));
440 EXPECT_EQ(SDR_SUCCESS, result);
441 EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000);
442 ASSERT_TRUE(SendData(channel2(), 2, "hi chan1", &result));
443 EXPECT_EQ(SDR_SUCCESS, result);
444 EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi chan1"), 1000);
445
446 // Close two streams on one side.
447 channel2()->RemoveSendStream(2);
448 channel2()->RemoveSendStream(3);
449 EXPECT_TRUE_WAIT(chan_1_sig_receiver.WasStreamClosed(2), 1000);
450 EXPECT_TRUE_WAIT(chan_1_sig_receiver.WasStreamClosed(3), 1000);
451 }
452
453 TEST_F(SctpDataMediaChannelTest, ClosesStreamsOnBothSides) {
454 SetupConnectedChannels();
455 AddStream(3);
456 AddStream(4);
457 SignalChannelClosedObserver chan_1_sig_receiver, chan_2_sig_receiver;
458 chan_1_sig_receiver.BindSelf(channel1());
459 chan_2_sig_receiver.BindSelf(channel2());
460
461 SendDataResult result;
462 ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result));
463 EXPECT_EQ(SDR_SUCCESS, result);
464 EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000);
465 ASSERT_TRUE(SendData(channel2(), 2, "hi chan1", &result));
466 EXPECT_EQ(SDR_SUCCESS, result);
467 EXPECT_TRUE_WAIT(ReceivedData(receiver1(), 2, "hi chan1"), 1000);
468
469 // Close one stream on channel1(), while closing three streams on
470 // channel2(). They will conflict (only one side can close anything at a
471 // time, apparently). Test the resolution of the conflict.
472 channel1()->RemoveSendStream(1);
473
474 channel2()->RemoveSendStream(2);
475 channel2()->RemoveSendStream(3);
476 channel2()->RemoveSendStream(4);
477 EXPECT_TRUE_WAIT(chan_2_sig_receiver.WasStreamClosed(1), 1000);
478 EXPECT_TRUE_WAIT(chan_1_sig_receiver.WasStreamClosed(2), 1000);
479 EXPECT_TRUE_WAIT(chan_1_sig_receiver.WasStreamClosed(3), 1000);
480 EXPECT_TRUE_WAIT(chan_1_sig_receiver.WasStreamClosed(4), 1000);
481 }
482
483 TEST_F(SctpDataMediaChannelTest, EngineSignalsRightChannel) {
484 SetupConnectedChannels();
485 EXPECT_TRUE_WAIT(channel1()->socket() != NULL, 1000);
486 struct socket *sock = const_cast<struct socket*>(channel1()->socket());
487 int prior_count = channel1_ready_to_send_count();
488 SctpDataMediaChannel::SendThresholdCallback(sock, 0);
489 EXPECT_GT(channel1_ready_to_send_count(), prior_count);
490 }
491
492 TEST_F(SctpDataMediaChannelTest, RefusesHighNumberedChannels) {
493 SetupConnectedChannels();
494 EXPECT_TRUE(AddStream(kMaxSctpSid));
495 EXPECT_FALSE(AddStream(kMaxSctpSid + 1));
496 }
497
498 // Flaky, see webrtc:4453.
499 TEST_F(SctpDataMediaChannelTest, DISABLED_ReusesAStream) {
500 // Shut down channel 1, then open it up again for reuse.
501 SetupConnectedChannels();
502 SendDataResult result;
503 SignalChannelClosedObserver chan_2_sig_receiver;
504 chan_2_sig_receiver.BindSelf(channel2());
505
506 ASSERT_TRUE(SendData(channel1(), 1, "hello?", &result));
507 EXPECT_EQ(SDR_SUCCESS, result);
508 EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hello?"), 1000);
509
510 channel1()->RemoveSendStream(1);
511 EXPECT_TRUE_WAIT(chan_2_sig_receiver.WasStreamClosed(1), 1000);
512 // Channel 1 is gone now.
513
514 // Create a new channel 1.
515 AddStream(1);
516 ASSERT_TRUE(SendData(channel1(), 1, "hi?", &result));
517 EXPECT_EQ(SDR_SUCCESS, result);
518 EXPECT_TRUE_WAIT(ReceivedData(receiver2(), 1, "hi?"), 1000);
519 channel1()->RemoveSendStream(1);
520 EXPECT_TRUE_WAIT(chan_2_sig_receiver.StreamCloseCount(1) == 2, 1000);
521 }
522
523 } // namespace cricket
OLDNEW
« no previous file with comments | « webrtc/media/sctp/sctpdataengine.cc ('k') | webrtc/media/sctp/sctptransport.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698