OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright 2016 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 "webrtc/api/quictransport.h" | |
12 | |
13 #include <set> | |
14 #include <string> | |
15 #include <unordered_map> | |
16 #include <vector> | |
17 | |
18 #include "webrtc/api/quicdatachannel.h" | |
19 #include "webrtc/base/bytebuffer.h" | |
20 #include "webrtc/base/gunit.h" | |
21 #include "webrtc/p2p/base/faketransportcontroller.h" | |
22 #include "webrtc/p2p/quic/quictransportchannel.h" | |
23 #include "webrtc/p2p/quic/reliablequicstream.h" | |
24 | |
25 using webrtc::QuicDataChannel; | |
26 using webrtc::QuicTransport; | |
27 using cricket::FakeTransportChannel; | |
28 using cricket::QuicTransportChannel; | |
29 using cricket::ReliableQuicStream; | |
30 | |
31 // Timeout for asynchronous operations. | |
32 static const int kTimeoutMs = 1000; // milliseconds | |
33 | |
34 class QuicDataChannelForTest : public QuicDataChannel { | |
35 public: | |
36 QuicDataChannelForTest(QuicTransportChannel* quic_transport_channel, | |
37 const webrtc::DataChannelInit* config) | |
38 : QuicDataChannel(quic_transport_channel, | |
39 rtc::Thread::Current(), | |
40 rtc::Thread::Current(), | |
41 "testing", | |
42 config) {} | |
43 void OnIncomingStream(ReliableQuicStream* stream, | |
44 rtc::ByteBuffer* remaining_bytes) override { | |
45 stream_ids_.insert(stream->id()); | |
46 uint64_t message_id; | |
47 remaining_bytes->ReadVarint(&message_id); | |
48 std::string message; | |
49 remaining_bytes->ReadString(&message, remaining_bytes->Length()); | |
50 messages_[message_id] = message; | |
51 } | |
52 bool has_stream(net::QuicStreamId id) const { | |
53 return stream_ids_.find(id) != stream_ids_.end(); | |
54 } | |
55 bool has_message(uint64_t id, std::string message) const { | |
56 const auto& kv = messages_.find(id); | |
57 return kv != messages_.end() && kv->second == message; | |
58 } | |
59 | |
60 private: | |
61 std::set<net::QuicStreamId> stream_ids_; | |
62 std::unordered_map<uint64_t, std::string> messages_; | |
63 }; | |
64 | |
65 // A peer who creates one or more QuicDataChannels to send or receive data. | |
66 class QuicTransportPeer { | |
67 public: | |
68 QuicTransportPeer() | |
69 : ice_transport_channel_("data", 0), | |
70 quic_transport_channel_(&ice_transport_channel_) { | |
71 ice_transport_channel_.SetAsync(true); | |
72 } | |
73 | |
74 void GenerateCertificateAndFingerprint() { | |
75 rtc::scoped_refptr<rtc::RTCCertificate> local_cert = | |
76 rtc::RTCCertificate::Create(rtc::scoped_ptr<rtc::SSLIdentity>( | |
77 rtc::SSLIdentity::Generate("cert_name", rtc::KT_DEFAULT))); | |
78 quic_transport_channel_.SetLocalCertificate(local_cert); | |
79 local_fingerprint_.reset(CreateFingerprint(local_cert.get())); | |
80 } | |
81 | |
82 // Connects |ice_transport_channel_| to that of the other peer. | |
83 void Connect(QuicTransportPeer* other_peer) { | |
84 ice_transport_channel_.Connect(); | |
85 other_peer->ice_transport_channel_.Connect(); | |
86 ice_transport_channel_.SetDestination(&other_peer->ice_transport_channel_); | |
87 } | |
88 | |
89 rtc::scoped_ptr<rtc::SSLFingerprint>& local_fingerprint() { | |
90 return local_fingerprint_; | |
91 } | |
92 | |
93 QuicTransportChannel* quic_transport_channel() { | |
94 return &quic_transport_channel_; | |
95 } | |
96 | |
97 private: | |
98 // Creates a fingerprint from a certificate. | |
99 rtc::SSLFingerprint* CreateFingerprint(rtc::RTCCertificate* cert) { | |
100 std::string digest_algorithm; | |
101 cert->ssl_certificate().GetSignatureDigestAlgorithm(&digest_algorithm); | |
102 rtc::scoped_ptr<rtc::SSLFingerprint> fingerprint( | |
103 rtc::SSLFingerprint::Create(digest_algorithm, cert->identity())); | |
104 return fingerprint.release(); | |
105 } | |
106 | |
107 FakeTransportChannel ice_transport_channel_; | |
108 QuicTransportChannel quic_transport_channel_; | |
109 | |
110 rtc::scoped_ptr<rtc::SSLFingerprint> local_fingerprint_; | |
111 }; | |
112 | |
113 class QuicTransportTest : public testing::Test { | |
114 public: | |
115 QuicTransportTest() : quic_transport_(peer2_.quic_transport_channel()) {} | |
116 | |
117 void EstablishConnection() { | |
118 SetCryptoParameters(); | |
119 peer1_.Connect(&peer2_); | |
120 ASSERT_TRUE_WAIT(peer1_.quic_transport_channel()->writable() && | |
121 peer2_.quic_transport_channel()->writable(), | |
122 kTimeoutMs); | |
123 } | |
124 | |
125 // Sets crypto parameters required for the QUIC handshake. | |
126 void SetCryptoParameters() { | |
127 peer1_.GenerateCertificateAndFingerprint(); | |
128 peer2_.GenerateCertificateAndFingerprint(); | |
129 | |
130 peer1_.quic_transport_channel()->SetSslRole(rtc::SSL_CLIENT); | |
131 peer2_.quic_transport_channel()->SetSslRole(rtc::SSL_SERVER); | |
132 | |
133 rtc::scoped_ptr<rtc::SSLFingerprint>& peer1_fingerprint = | |
134 peer1_.local_fingerprint(); | |
135 rtc::scoped_ptr<rtc::SSLFingerprint>& peer2_fingerprint = | |
136 peer2_.local_fingerprint(); | |
137 | |
138 peer1_.quic_transport_channel()->SetRemoteFingerprint( | |
139 peer2_fingerprint->algorithm, | |
140 reinterpret_cast<const uint8_t*>(peer2_fingerprint->digest.data()), | |
141 peer2_fingerprint->digest.size()); | |
142 peer2_.quic_transport_channel()->SetRemoteFingerprint( | |
143 peer1_fingerprint->algorithm, | |
144 reinterpret_cast<const uint8_t*>(peer1_fingerprint->digest.data()), | |
145 peer1_fingerprint->digest.size()); | |
146 } | |
147 | |
148 protected: | |
149 QuicTransportPeer peer1_; | |
150 QuicTransportPeer peer2_; | |
151 | |
152 QuicTransport quic_transport_; | |
153 }; | |
154 | |
155 TEST_F(QuicTransportTest, ReceiveMessagesForSingleDataChannel) { | |
156 EstablishConnection(); | |
157 webrtc::DataChannelInit config; | |
158 config.id = 1337; | |
159 QuicDataChannelForTest peer2_data_channel(peer2_.quic_transport_channel(), | |
160 &config); | |
161 quic_transport_.RegisterDataChannel(&peer2_data_channel); | |
162 | |
163 ReliableQuicStream* stream1 = | |
164 peer1_.quic_transport_channel()->CreateQuicStream(); | |
165 rtc::ByteBuffer byte_buffer1(nullptr, 100, | |
166 rtc::ByteBuffer::ByteOrder::ORDER_HOST); | |
167 byte_buffer1.WriteVarint(1337); | |
168 byte_buffer1.WriteVarint(26); | |
169 byte_buffer1.WriteString("Testing"); | |
170 stream1->Write(byte_buffer1.Data(), byte_buffer1.Length()); | |
171 ASSERT_TRUE_WAIT(peer2_data_channel.has_stream(stream1->id()) && | |
172 peer2_data_channel.has_message(7, "Testing"), | |
173 kTimeoutMs); | |
174 | |
175 ReliableQuicStream* stream2 = | |
176 peer1_.quic_transport_channel()->CreateQuicStream(); | |
177 rtc::ByteBuffer byte_buffer2(nullptr, 100, | |
178 rtc::ByteBuffer::ByteOrder::ORDER_HOST); | |
179 byte_buffer2.WriteVarint(1337); | |
180 byte_buffer2.WriteVarint(402); | |
181 byte_buffer2.WriteString("Hello, World!"); | |
182 stream2->Write(byte_buffer2.Data(), byte_buffer2.Length()); | |
183 ASSERT_TRUE_WAIT(peer2_data_channel.has_stream(stream1->id()) && | |
184 peer2_data_channel.has_message(402, "Hello, World!"), | |
185 kTimeoutMs); | |
186 } | |
187 | |
188 TEST_F(QuicTransportTest, ReceiveMessagesForMultipleDataChannels) { | |
189 EstablishConnection(); | |
190 | |
191 std::vector<rtc::scoped_ptr<QuicDataChannelForTest>> data_channels; | |
192 for (int data_channel_id = 0; data_channel_id < 10; ++data_channel_id) { | |
193 webrtc::DataChannelInit config; | |
194 config.id = data_channel_id; | |
195 rtc::scoped_ptr<QuicDataChannelForTest> data_channel( | |
196 new QuicDataChannelForTest(peer2_.quic_transport_channel(), &config)); | |
197 quic_transport_.RegisterDataChannel(data_channel.get()); | |
198 data_channels.push_back(std::move(data_channel)); | |
199 } | |
200 | |
201 for (int data_channel_id = 0; data_channel_id < 10; ++data_channel_id) { | |
202 ReliableQuicStream* stream1 = | |
203 peer1_.quic_transport_channel()->CreateQuicStream(); | |
204 rtc::ByteBuffer byte_buffer1(nullptr, 100, | |
205 rtc::ByteBuffer::ByteOrder::ORDER_HOST); | |
206 byte_buffer1.WriteVarint(data_channel_id); | |
207 byte_buffer1.WriteVarint(26); | |
208 byte_buffer1.WriteString("Testing"); | |
209 stream1->Write(byte_buffer1.Data(), byte_buffer1.Length()); | |
210 | |
211 QuicDataChannelForTest* peer2_data_channel = | |
212 data_channels[data_channel_id].get(); | |
213 ASSERT_TRUE_WAIT(peer2_data_channel->has_stream(stream1->id()) && | |
214 peer2_data_channel->has_message(7, "Testing"), | |
215 kTimeoutMs); | |
216 | |
217 ReliableQuicStream* stream2 = | |
218 peer1_.quic_transport_channel()->CreateQuicStream(); | |
219 rtc::ByteBuffer byte_buffer2(nullptr, 100, | |
220 rtc::ByteBuffer::ByteOrder::ORDER_HOST); | |
221 byte_buffer2.WriteVarint(data_channel_id); | |
222 byte_buffer2.WriteVarint(402); | |
223 byte_buffer2.WriteString("Hello, World!"); | |
pthatcher1
2016/03/30 20:34:49
It's probably worth making a WriteMessage(dcid, ms
mikescarlett
2016/04/05 19:58:51
Added a helper method.
| |
224 stream2->Write(byte_buffer2.Data(), byte_buffer2.Length()); | |
225 ASSERT_TRUE_WAIT(peer2_data_channel->has_stream(stream1->id()) && | |
226 peer2_data_channel->has_message(402, "Hello, World!"), | |
227 kTimeoutMs); | |
228 } | |
229 } | |
OLD | NEW |