Chromium Code Reviews| 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 |