OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "build/build_config.h" | |
6 | |
7 #if defined(OS_WIN) | |
8 #include <winsock2.h> // for htonl | |
9 #else | |
10 #include <arpa/inet.h> | |
11 #endif | |
12 | |
13 #include <deque> | |
14 #include <vector> | |
15 | |
16 #include "content/common/p2p_messages.h" | |
17 #include "net/base/io_buffer.h" | |
18 #include "net/base/ip_endpoint.h" | |
19 #include "net/base/net_errors.h" | |
20 #include "net/udp/datagram_server_socket.h" | |
21 #include "content/browser/renderer_host/p2p_socket_host_udp.h" | |
jam
2011/04/08 23:38:57
nit: should move up
Sergey Ulanov
2011/04/09 00:52:36
Done.
| |
22 #include "testing/gmock/include/gmock/gmock.h" | |
23 #include "testing/gtest/include/gtest/gtest.h" | |
24 | |
25 using ::testing::_; | |
26 using ::testing::DeleteArg; | |
27 using ::testing::DoAll; | |
28 using ::testing::Return; | |
29 | |
30 namespace { | |
31 | |
32 const char kTestLocalIpAddress[] = "123.44.22.4"; | |
33 const char kTestIpAddress1[] = "123.44.22.31"; | |
34 const int kTestPort1 = 234; | |
35 const char kTestIpAddress2[] = "133.11.22.33"; | |
36 const int kTestPort2 = 543; | |
37 | |
38 const int kStunHeaderSize = 20; | |
39 const uint16 kStunBindingRequest = 0x0001; | |
40 const uint16 kStunBindingResponse = 0x0102; | |
41 const uint16 kStunBindingError = 0x0111; | |
42 const uint32 kStunMagicCookie = 0x2112A442; | |
43 | |
44 class FakeDatagramServerSocket : public net::DatagramServerSocket { | |
45 public: | |
46 typedef std::pair<net::IPEndPoint, std::vector<char> > UDPPacket; | |
47 | |
48 // P2PSocketHostUdp destroyes a socket on errors so sent packets | |
49 // need to be stored outside of this object. | |
50 explicit FakeDatagramServerSocket(std::deque<UDPPacket>* sent_packets) | |
51 : sent_packets_(sent_packets), recv_callback_(NULL) { | |
52 } | |
53 | |
54 virtual void Close() OVERRIDE { | |
55 } | |
56 | |
57 virtual int GetPeerAddress(net::IPEndPoint* address) const OVERRIDE { | |
58 NOTREACHED(); | |
59 return net::ERR_SOCKET_NOT_CONNECTED; | |
60 } | |
61 | |
62 virtual int GetLocalAddress(net::IPEndPoint* address) const OVERRIDE { | |
63 *address = address_; | |
64 return 0; | |
65 } | |
66 | |
67 virtual int Listen(const net::IPEndPoint& address) OVERRIDE { | |
68 address_ = address; | |
69 return 0; | |
70 } | |
71 | |
72 virtual int RecvFrom(net::IOBuffer* buf, int buf_len, | |
73 net::IPEndPoint* address, | |
74 net::CompletionCallback* callback) OVERRIDE { | |
75 CHECK(!recv_callback_); | |
76 if (incoming_packets_.size() > 0) { | |
77 scoped_refptr<net::IOBuffer> buffer(buf); | |
78 int size = std::min( | |
79 static_cast<int>(incoming_packets_.front().second.size()), buf_len); | |
80 memcpy(buffer->data(), &*incoming_packets_.front().second.begin(), size); | |
81 *address = incoming_packets_.front().first; | |
82 incoming_packets_.pop_front(); | |
83 return size; | |
84 } else { | |
85 recv_callback_ = callback; | |
86 recv_buffer_ = buf; | |
87 recv_size_ = buf_len; | |
88 recv_address_ = address; | |
89 return net::ERR_IO_PENDING; | |
90 } | |
91 } | |
92 | |
93 virtual int SendTo(net::IOBuffer* buf, int buf_len, | |
94 const net::IPEndPoint& address, | |
95 net::CompletionCallback* callback) OVERRIDE { | |
96 scoped_refptr<net::IOBuffer> buffer(buf); | |
97 std::vector<char> data_vector(buffer->data(), buffer->data() + buf_len); | |
98 sent_packets_->push_back(UDPPacket(address, data_vector)); | |
99 return buf_len; | |
100 } | |
101 | |
102 void ReceivePacket(const net::IPEndPoint& address, std::vector<char> data) { | |
103 if (recv_callback_) { | |
104 int size = std::min(recv_size_, static_cast<int>(data.size())); | |
105 memcpy(recv_buffer_->data(), &*data.begin(), size); | |
106 *recv_address_ = address; | |
107 net::CompletionCallback* cb = recv_callback_; | |
108 recv_callback_ = NULL; | |
109 recv_buffer_ = NULL; | |
110 cb->Run(size); | |
111 } else { | |
112 incoming_packets_.push_back(UDPPacket(address, data)); | |
113 } | |
114 } | |
115 | |
116 private: | |
117 net::IPEndPoint address_; | |
118 std::deque<UDPPacket>* sent_packets_; | |
119 std::deque<UDPPacket> incoming_packets_; | |
120 | |
121 scoped_refptr<net::IOBuffer> recv_buffer_; | |
122 net::IPEndPoint* recv_address_; | |
123 int recv_size_; | |
124 net::CompletionCallback* recv_callback_; | |
125 }; | |
126 | |
127 class MockIPCSender : public IPC::Message::Sender { | |
128 public: | |
129 MOCK_METHOD1(Send, bool(IPC::Message* msg)); | |
130 }; | |
131 | |
132 MATCHER_P(MatchMessage, type, "") { | |
133 return arg->type() == type; | |
134 } | |
135 | |
136 } // namespace | |
137 | |
138 class P2PSocketHostUdpTest : public testing::Test { | |
139 protected: | |
140 void SetUp() OVERRIDE { | |
141 EXPECT_CALL(sender_, Send( | |
142 MatchMessage(static_cast<uint32>(P2PMsg_OnSocketCreated::ID)))) | |
143 .WillOnce(DoAll(DeleteArg<0>(), Return(true))); | |
144 | |
145 socket_host_.reset(new P2PSocketHostUdp(&sender_, 0, 0)); | |
146 socket_ = new FakeDatagramServerSocket(&sent_packets_); | |
147 socket_host_->socket_.reset(socket_); | |
148 | |
149 net::IPAddressNumber local_ip; | |
150 ASSERT_TRUE(net::ParseIPLiteralToNumber(kTestLocalIpAddress, &local_ip)); | |
151 local_address_ = net::IPEndPoint(local_ip, kTestPort1); | |
152 socket_host_->Init(local_address_); | |
153 | |
154 net::IPAddressNumber ip1; | |
155 ASSERT_TRUE(net::ParseIPLiteralToNumber(kTestIpAddress1, &ip1)); | |
156 dest1_ = net::IPEndPoint(ip1, kTestPort1); | |
157 net::IPAddressNumber ip2; | |
158 ASSERT_TRUE(net::ParseIPLiteralToNumber(kTestIpAddress2, &ip2)); | |
159 dest2_ = net::IPEndPoint(ip2, kTestPort2); | |
160 } | |
161 | |
162 void CreateRandomPacket(std::vector<char>* packet) { | |
163 size_t size = kStunHeaderSize + rand() % 1000; | |
164 packet->resize(size); | |
165 for (size_t i = 0; i < size; i++) { | |
166 (*packet)[i] = rand() % 256; | |
167 } | |
168 // Always set the first bit to ensure that generated packet is not | |
169 // valid STUN packet. | |
170 (*packet)[0] = (*packet)[0] | 0x80; | |
171 } | |
172 | |
173 void CreateStunPacket(std::vector<char>* packet, uint16 type) { | |
174 CreateRandomPacket(packet); | |
175 *reinterpret_cast<uint16*>(&*packet->begin()) = htons(type); | |
176 *reinterpret_cast<uint16*>(&*packet->begin() + 2) = | |
177 htons(packet->size() - kStunHeaderSize); | |
178 *reinterpret_cast<uint32*>(&*packet->begin() + 4) = htonl(kStunMagicCookie); | |
179 } | |
180 | |
181 void CreateStunRequest(std::vector<char>* packet) { | |
182 CreateStunPacket(packet, kStunBindingRequest); | |
183 } | |
184 | |
185 void CreateStunResponse(std::vector<char>* packet) { | |
186 CreateStunPacket(packet, kStunBindingResponse); | |
187 } | |
188 | |
189 void CreateStunError(std::vector<char>* packet) { | |
190 CreateStunPacket(packet, kStunBindingError); | |
191 } | |
192 | |
193 std::deque<FakeDatagramServerSocket::UDPPacket> sent_packets_; | |
194 FakeDatagramServerSocket* socket_; // Owned by |socket_host_|. | |
195 scoped_ptr<P2PSocketHostUdp> socket_host_; | |
196 MockIPCSender sender_; | |
197 | |
198 net::IPEndPoint local_address_; | |
199 | |
200 net::IPEndPoint dest1_; | |
201 net::IPEndPoint dest2_; | |
202 }; | |
203 | |
204 // Verify that we can send STUN messages before we receive anything | |
205 // from the other side. | |
206 TEST_F(P2PSocketHostUdpTest, SendStunNoAuth) { | |
207 std::vector<char> packet1; | |
208 CreateStunRequest(&packet1); | |
209 socket_host_->Send(dest1_, packet1); | |
210 | |
211 std::vector<char> packet2; | |
212 CreateStunResponse(&packet2); | |
213 socket_host_->Send(dest1_, packet2); | |
214 | |
215 std::vector<char> packet3; | |
216 CreateStunError(&packet3); | |
217 socket_host_->Send(dest1_, packet3); | |
218 | |
219 ASSERT_EQ(sent_packets_.size(), 3U); | |
220 ASSERT_EQ(sent_packets_[0].second, packet1); | |
221 ASSERT_EQ(sent_packets_[1].second, packet2); | |
222 ASSERT_EQ(sent_packets_[2].second, packet3); | |
223 } | |
224 | |
225 // Verify that no data packets can be sent before STUN binding has | |
226 // finished. | |
227 TEST_F(P2PSocketHostUdpTest, SendDataNoAuth) { | |
228 EXPECT_CALL(sender_, Send( | |
229 MatchMessage(static_cast<uint32>(P2PMsg_OnError::ID)))) | |
230 .WillOnce(DoAll(DeleteArg<0>(), Return(true))); | |
231 | |
232 std::vector<char> packet; | |
233 CreateRandomPacket(&packet); | |
234 socket_host_->Send(dest1_, packet); | |
235 | |
236 ASSERT_EQ(sent_packets_.size(), 0U); | |
237 } | |
238 | |
239 // Verify that we can send data after we've received STUN request | |
240 // from the other side. | |
241 TEST_F(P2PSocketHostUdpTest, SendAfterStunRequest) { | |
242 EXPECT_CALL(sender_, Send( | |
243 MatchMessage(static_cast<uint32>(P2PMsg_OnDataReceived::ID)))) | |
244 .WillOnce(DoAll(DeleteArg<0>(), Return(true))); | |
245 | |
246 // Receive packet from |dest1_|. | |
247 std::vector<char> request_packet; | |
248 CreateStunRequest(&request_packet); | |
249 socket_->ReceivePacket(dest1_, request_packet); | |
250 | |
251 // Now we should be able to send any data to |dest1_|. | |
252 std::vector<char> packet; | |
253 CreateRandomPacket(&packet); | |
254 socket_host_->Send(dest1_, packet); | |
255 | |
256 ASSERT_EQ(1U, sent_packets_.size()); | |
257 ASSERT_EQ(dest1_, sent_packets_[0].first); | |
258 } | |
259 | |
260 // Verify that we can send data after we've received STUN response | |
261 // from the other side. | |
262 TEST_F(P2PSocketHostUdpTest, SendAfterStunResponse) { | |
263 EXPECT_CALL(sender_, Send( | |
264 MatchMessage(static_cast<uint32>(P2PMsg_OnDataReceived::ID)))) | |
265 .WillOnce(DoAll(DeleteArg<0>(), Return(true))); | |
266 | |
267 // Receive packet from |dest1_|. | |
268 std::vector<char> request_packet; | |
269 CreateStunRequest(&request_packet); | |
270 socket_->ReceivePacket(dest1_, request_packet); | |
271 | |
272 // Now we should be able to send any data to |dest1_|. | |
273 std::vector<char> packet; | |
274 CreateRandomPacket(&packet); | |
275 socket_host_->Send(dest1_, packet); | |
276 | |
277 ASSERT_EQ(1U, sent_packets_.size()); | |
278 ASSERT_EQ(dest1_, sent_packets_[0].first); | |
279 } | |
280 | |
281 // Verify messages still cannot be sent to an unathorized host after | |
282 // successful binding with different host. | |
283 TEST_F(P2PSocketHostUdpTest, SendAfterStunResponseDifferentHost) { | |
284 EXPECT_CALL(sender_, Send( | |
285 MatchMessage(static_cast<uint32>(P2PMsg_OnDataReceived::ID)))) | |
286 .WillOnce(DoAll(DeleteArg<0>(), Return(true))); | |
287 | |
288 // Receive packet from |dest1_|. | |
289 std::vector<char> request_packet; | |
290 CreateStunRequest(&request_packet); | |
291 socket_->ReceivePacket(dest1_, request_packet); | |
292 | |
293 // Should fail when trying to send the same packet to |dest2_|. | |
294 std::vector<char> packet; | |
295 CreateRandomPacket(&packet); | |
296 EXPECT_CALL(sender_, Send( | |
297 MatchMessage(static_cast<uint32>(P2PMsg_OnError::ID)))) | |
298 .WillOnce(DoAll(DeleteArg<0>(), Return(true))); | |
299 socket_host_->Send(dest2_, packet); | |
300 } | |
OLD | NEW |