1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/mtransport/test/buffered_stun_socket_unittest.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,477 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +// Original author: ekr@rtfm.com 1.11 + 1.12 +#include <iostream> 1.13 + 1.14 +#include "nspr.h" 1.15 +#include "nss.h" 1.16 +#include "ssl.h" 1.17 + 1.18 +#include "mozilla/Scoped.h" 1.19 + 1.20 +extern "C" { 1.21 +#include "nr_api.h" 1.22 +#include "nr_socket.h" 1.23 +#include "nr_socket_buffered_stun.h" 1.24 +#include "transport_addr.h" 1.25 +#include "stun.h" 1.26 +} 1.27 + 1.28 +#include "databuffer.h" 1.29 +#include "mtransport_test_utils.h" 1.30 + 1.31 +#include "nr_socket_prsock.h" 1.32 + 1.33 +#define GTEST_HAS_RTTI 0 1.34 +#include "gtest/gtest.h" 1.35 +#include "gtest_utils.h" 1.36 + 1.37 +using namespace mozilla; 1.38 +MtransportTestUtils *test_utils; 1.39 + 1.40 +static uint8_t kStunMessage[] = { 1.41 + 0x00, 0x01, 0x00, 0x08, 0x21, 0x12, 0xa4, 0x42, 1.42 + 0x9b, 0x90, 0xbe, 0x2c, 0xae, 0x1a, 0x0c, 0xa8, 1.43 + 0xa0, 0xd6, 0x8b, 0x08, 0x80, 0x28, 0x00, 0x04, 1.44 + 0xdb, 0x35, 0x5f, 0xaa 1.45 +}; 1.46 +static size_t kStunMessageLen = sizeof(kStunMessage); 1.47 + 1.48 +class DummySocket : public NrSocketBase { 1.49 + public: 1.50 + DummySocket() 1.51 + : writable_(UINT_MAX), 1.52 + write_buffer_(nullptr), 1.53 + readable_(UINT_MAX), 1.54 + read_buffer_(nullptr), 1.55 + cb_(nullptr), 1.56 + cb_arg_(nullptr), 1.57 + self_(nullptr) {} 1.58 + 1.59 + // the nr_socket APIs 1.60 + virtual int create(nr_transport_addr *addr) { 1.61 + return 0; 1.62 + } 1.63 + 1.64 + virtual int sendto(const void *msg, size_t len, 1.65 + int flags, nr_transport_addr *to) { 1.66 + MOZ_CRASH(); 1.67 + return 0; 1.68 + } 1.69 + 1.70 + virtual int recvfrom(void * buf, size_t maxlen, 1.71 + size_t *len, int flags, 1.72 + nr_transport_addr *from) { 1.73 + MOZ_CRASH(); 1.74 + return 0; 1.75 + } 1.76 + 1.77 + virtual int getaddr(nr_transport_addr *addrp) { 1.78 + MOZ_CRASH(); 1.79 + return 0; 1.80 + } 1.81 + 1.82 + virtual void close() { 1.83 + } 1.84 + 1.85 + virtual int connect(nr_transport_addr *addr) { 1.86 + return 0; 1.87 + } 1.88 + 1.89 + virtual int write(const void *msg, size_t len, size_t *written) { 1.90 + // Shouldn't be anything here. 1.91 + EXPECT_EQ(nullptr, write_buffer_.get()); 1.92 + 1.93 + size_t to_write = std::min(len, writable_); 1.94 + 1.95 + if (to_write) { 1.96 + write_buffer_ = new DataBuffer( 1.97 + static_cast<const uint8_t *>(msg), to_write); 1.98 + *written = to_write; 1.99 + } 1.100 + 1.101 + return 0; 1.102 + } 1.103 + 1.104 + virtual int read(void* buf, size_t maxlen, size_t *len) { 1.105 + if (!read_buffer_.get()) { 1.106 + return R_WOULDBLOCK; 1.107 + } 1.108 + 1.109 + size_t to_read = std::min(read_buffer_->len(), 1.110 + std::min(maxlen, readable_)); 1.111 + 1.112 + memcpy(buf, read_buffer_->data(), to_read); 1.113 + *len = to_read; 1.114 + 1.115 + if (to_read < read_buffer_->len()) { 1.116 + read_buffer_ = new DataBuffer(read_buffer_->data() + to_read, 1.117 + read_buffer_->len() - to_read); 1.118 + } else { 1.119 + read_buffer_ = nullptr; 1.120 + } 1.121 + 1.122 + return 0; 1.123 + } 1.124 + 1.125 + // Implementations of the async_event APIs. 1.126 + // These are no-ops because we handle scheduling manually 1.127 + // for test purposes. 1.128 + virtual int async_wait(int how, NR_async_cb cb, void *cb_arg, 1.129 + char *function, int line) { 1.130 + EXPECT_EQ(nullptr, cb_); 1.131 + cb_ = cb; 1.132 + cb_arg_ = cb_arg; 1.133 + 1.134 + return 0; 1.135 + } 1.136 + 1.137 + virtual int cancel(int how) { 1.138 + cb_ = nullptr; 1.139 + cb_arg_ = nullptr; 1.140 + 1.141 + return 0; 1.142 + } 1.143 + 1.144 + 1.145 + // Read/Manipulate the current state. 1.146 + void CheckWriteBuffer(uint8_t *data, size_t len) { 1.147 + if (!len) { 1.148 + EXPECT_EQ(nullptr, write_buffer_.get()); 1.149 + } else { 1.150 + EXPECT_NE(nullptr, write_buffer_.get()); 1.151 + ASSERT_EQ(len, write_buffer_->len()); 1.152 + ASSERT_EQ(0, memcmp(data, write_buffer_->data(), len)); 1.153 + } 1.154 + } 1.155 + 1.156 + void ClearWriteBuffer() { 1.157 + write_buffer_ = nullptr; 1.158 + } 1.159 + 1.160 + void SetWritable(size_t val) { 1.161 + writable_ = val; 1.162 + } 1.163 + 1.164 + void FireWritableCb() { 1.165 + NR_async_cb cb = cb_; 1.166 + void *cb_arg = cb_arg_; 1.167 + 1.168 + cb_ = nullptr; 1.169 + cb_arg_ = nullptr; 1.170 + 1.171 + cb(this, NR_ASYNC_WAIT_WRITE, cb_arg); 1.172 + } 1.173 + 1.174 + void SetReadBuffer(uint8_t *data, size_t len) { 1.175 + EXPECT_EQ(nullptr, write_buffer_.get()); 1.176 + read_buffer_ = new DataBuffer(data, len); 1.177 + } 1.178 + 1.179 + void ClearReadBuffer() { 1.180 + read_buffer_ = nullptr; 1.181 + } 1.182 + 1.183 + void SetReadable(size_t val) { 1.184 + readable_ = val; 1.185 + } 1.186 + 1.187 + nr_socket *get_nr_socket() { 1.188 + if (!self_) { 1.189 + int r = nr_socket_create_int(this, vtbl(), &self_); 1.190 + AddRef(); 1.191 + if (r) 1.192 + return nullptr; 1.193 + } 1.194 + 1.195 + return self_; 1.196 + } 1.197 + 1.198 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DummySocket); 1.199 + 1.200 + private: 1.201 + DISALLOW_COPY_ASSIGN(DummySocket); 1.202 + 1.203 + size_t writable_; // Amount we allow someone to write. 1.204 + ScopedDeletePtr<DataBuffer> write_buffer_; 1.205 + size_t readable_; // Amount we allow someone to read. 1.206 + ScopedDeletePtr<DataBuffer> read_buffer_; 1.207 + 1.208 + NR_async_cb cb_; 1.209 + void *cb_arg_; 1.210 + nr_socket *self_; 1.211 +}; 1.212 + 1.213 +class BufferedStunSocketTest : public ::testing::Test { 1.214 + public: 1.215 + BufferedStunSocketTest() 1.216 + : dummy_(nullptr), 1.217 + test_socket_(nullptr) {} 1.218 + 1.219 + ~BufferedStunSocketTest() { 1.220 + nr_socket_destroy(&test_socket_); 1.221 + } 1.222 + 1.223 + void SetUp() { 1.224 + ScopedDeletePtr<DummySocket> dummy(new DummySocket()); 1.225 + 1.226 + int r = nr_socket_buffered_stun_create( 1.227 + dummy->get_nr_socket(), 1.228 + kStunMessageLen, 1.229 + &test_socket_); 1.230 + ASSERT_EQ(0, r); 1.231 + dummy_ = dummy.forget(); // Now owned by test_socket_. 1.232 + 1.233 + r = nr_ip4_str_port_to_transport_addr( 1.234 + (char *)"192.0.2.133", 3333, IPPROTO_TCP, &remote_addr_); 1.235 + ASSERT_EQ(0, r); 1.236 + 1.237 + r = nr_socket_connect(test_socket_, 1.238 + &remote_addr_); 1.239 + ASSERT_EQ(0, r); 1.240 + } 1.241 + 1.242 + nr_socket *socket() { return test_socket_; } 1.243 + 1.244 + protected: 1.245 + DummySocket *dummy_; 1.246 + nr_socket *test_socket_; 1.247 + nr_transport_addr remote_addr_; 1.248 +}; 1.249 + 1.250 + 1.251 +TEST_F(BufferedStunSocketTest, TestCreate) { 1.252 +} 1.253 + 1.254 +TEST_F(BufferedStunSocketTest, TestSendTo) { 1.255 + int r = nr_socket_sendto(test_socket_, 1.256 + kStunMessage, 1.257 + kStunMessageLen, 1.258 + 0, &remote_addr_); 1.259 + ASSERT_EQ(0, r); 1.260 + 1.261 + dummy_->CheckWriteBuffer(kStunMessage, kStunMessageLen); 1.262 +} 1.263 + 1.264 +TEST_F(BufferedStunSocketTest, TestSendToBuffered) { 1.265 + dummy_->SetWritable(0); 1.266 + 1.267 + int r = nr_socket_sendto(test_socket_, 1.268 + kStunMessage, 1.269 + kStunMessageLen, 1.270 + 0, &remote_addr_); 1.271 + ASSERT_EQ(0, r); 1.272 + 1.273 + dummy_->CheckWriteBuffer(nullptr, 0); 1.274 + 1.275 + dummy_->SetWritable(kStunMessageLen); 1.276 + dummy_->FireWritableCb(); 1.277 + dummy_->CheckWriteBuffer(kStunMessage, kStunMessageLen); 1.278 +} 1.279 + 1.280 +TEST_F(BufferedStunSocketTest, TestSendFullThenDrain) { 1.281 + dummy_->SetWritable(0); 1.282 + 1.283 + for (;;) { 1.284 + int r = nr_socket_sendto(test_socket_, 1.285 + kStunMessage, 1.286 + kStunMessageLen, 1.287 + 0, &remote_addr_); 1.288 + if (r == R_WOULDBLOCK) 1.289 + break; 1.290 + 1.291 + ASSERT_EQ(0, r); 1.292 + } 1.293 + 1.294 + // Nothing was written. 1.295 + dummy_->CheckWriteBuffer(nullptr, 0); 1.296 + 1.297 + // Now flush. 1.298 + dummy_->SetWritable(kStunMessageLen); 1.299 + dummy_->FireWritableCb(); 1.300 + dummy_->ClearWriteBuffer(); 1.301 + 1.302 + // Verify we can write something. 1.303 + int r = nr_socket_sendto(test_socket_, 1.304 + kStunMessage, 1.305 + kStunMessageLen, 1.306 + 0, &remote_addr_); 1.307 + ASSERT_EQ(0, r); 1.308 + 1.309 + // And that it appears. 1.310 + dummy_->CheckWriteBuffer(kStunMessage, kStunMessageLen); 1.311 +} 1.312 + 1.313 +TEST_F(BufferedStunSocketTest, TestSendToPartialBuffered) { 1.314 + dummy_->SetWritable(10); 1.315 + 1.316 + int r = nr_socket_sendto(test_socket_, 1.317 + kStunMessage, 1.318 + kStunMessageLen, 1.319 + 0, &remote_addr_); 1.320 + ASSERT_EQ(0, r); 1.321 + 1.322 + dummy_->CheckWriteBuffer(kStunMessage, 10); 1.323 + dummy_->ClearWriteBuffer(); 1.324 + 1.325 + dummy_->SetWritable(kStunMessageLen); 1.326 + dummy_->FireWritableCb(); 1.327 + dummy_->CheckWriteBuffer(kStunMessage + 10, kStunMessageLen - 10); 1.328 +} 1.329 + 1.330 +TEST_F(BufferedStunSocketTest, TestSendToReject) { 1.331 + dummy_->SetWritable(0); 1.332 + 1.333 + int r = nr_socket_sendto(test_socket_, 1.334 + kStunMessage, 1.335 + kStunMessageLen, 1.336 + 0, &remote_addr_); 1.337 + ASSERT_EQ(0, r); 1.338 + 1.339 + dummy_->CheckWriteBuffer(nullptr, 0); 1.340 + 1.341 + r = nr_socket_sendto(test_socket_, 1.342 + kStunMessage, 1.343 + kStunMessageLen, 1.344 + 0, &remote_addr_); 1.345 + ASSERT_EQ(R_WOULDBLOCK, r); 1.346 + 1.347 + dummy_->CheckWriteBuffer(nullptr, 0); 1.348 +} 1.349 + 1.350 +TEST_F(BufferedStunSocketTest, TestSendToWrongAddr) { 1.351 + nr_transport_addr addr; 1.352 + 1.353 + int r = nr_ip4_str_port_to_transport_addr( 1.354 + (char *)"192.0.2.134", 3333, IPPROTO_TCP, &addr); 1.355 + ASSERT_EQ(0, r); 1.356 + 1.357 + r = nr_socket_sendto(test_socket_, 1.358 + kStunMessage, 1.359 + kStunMessageLen, 1.360 + 0, &addr); 1.361 + ASSERT_EQ(R_BAD_DATA, r); 1.362 +} 1.363 + 1.364 +TEST_F(BufferedStunSocketTest, TestReceiveRecvFrom) { 1.365 + dummy_->SetReadBuffer(kStunMessage, kStunMessageLen); 1.366 + 1.367 + unsigned char tmp[2048]; 1.368 + size_t len; 1.369 + nr_transport_addr addr; 1.370 + 1.371 + int r = nr_socket_recvfrom(test_socket_, 1.372 + tmp, sizeof(tmp), &len, 0, 1.373 + &addr); 1.374 + ASSERT_EQ(0, r); 1.375 + ASSERT_EQ(kStunMessageLen, len); 1.376 + ASSERT_EQ(0, memcmp(kStunMessage, tmp, kStunMessageLen)); 1.377 + ASSERT_EQ(0, nr_transport_addr_cmp(&addr, &remote_addr_, 1.378 + NR_TRANSPORT_ADDR_CMP_MODE_ALL)); 1.379 +} 1.380 + 1.381 +TEST_F(BufferedStunSocketTest, TestReceiveRecvFromPartial) { 1.382 + dummy_->SetReadBuffer(kStunMessage, 15); 1.383 + 1.384 + unsigned char tmp[2048]; 1.385 + size_t len; 1.386 + nr_transport_addr addr; 1.387 + 1.388 + int r = nr_socket_recvfrom(test_socket_, 1.389 + tmp, sizeof(tmp), &len, 0, 1.390 + &addr); 1.391 + ASSERT_EQ(R_WOULDBLOCK, r); 1.392 + 1.393 + 1.394 + dummy_->SetReadBuffer(kStunMessage + 15, kStunMessageLen - 15); 1.395 + 1.396 + r = nr_socket_recvfrom(test_socket_, 1.397 + tmp, sizeof(tmp), &len, 0, 1.398 + &addr); 1.399 + ASSERT_EQ(0, r); 1.400 + ASSERT_EQ(kStunMessageLen, len); 1.401 + ASSERT_EQ(0, memcmp(kStunMessage, tmp, kStunMessageLen)); 1.402 + ASSERT_EQ(0, nr_transport_addr_cmp(&addr, &remote_addr_, 1.403 + NR_TRANSPORT_ADDR_CMP_MODE_ALL)); 1.404 + 1.405 + r = nr_socket_recvfrom(test_socket_, 1.406 + tmp, sizeof(tmp), &len, 0, 1.407 + &addr); 1.408 + ASSERT_EQ(R_WOULDBLOCK, r); 1.409 +} 1.410 + 1.411 + 1.412 +TEST_F(BufferedStunSocketTest, TestReceiveRecvFromGarbage) { 1.413 + uint8_t garbage[50]; 1.414 + memset(garbage, 0xff, sizeof(garbage)); 1.415 + 1.416 + dummy_->SetReadBuffer(garbage, sizeof(garbage)); 1.417 + 1.418 + unsigned char tmp[2048]; 1.419 + size_t len; 1.420 + nr_transport_addr addr; 1.421 + int r = nr_socket_recvfrom(test_socket_, 1.422 + tmp, sizeof(tmp), &len, 0, 1.423 + &addr); 1.424 + ASSERT_EQ(R_BAD_DATA, r); 1.425 + 1.426 + r = nr_socket_recvfrom(test_socket_, 1.427 + tmp, sizeof(tmp), &len, 0, 1.428 + &addr); 1.429 + ASSERT_EQ(R_FAILED, r); 1.430 +} 1.431 + 1.432 +TEST_F(BufferedStunSocketTest, TestReceiveRecvFromTooShort) { 1.433 + dummy_->SetReadBuffer(kStunMessage, kStunMessageLen); 1.434 + 1.435 + unsigned char tmp[2048]; 1.436 + size_t len; 1.437 + nr_transport_addr addr; 1.438 + 1.439 + int r = nr_socket_recvfrom(test_socket_, 1.440 + tmp, kStunMessageLen - 1, &len, 0, 1.441 + &addr); 1.442 + ASSERT_EQ(R_BAD_ARGS, r); 1.443 +} 1.444 + 1.445 +TEST_F(BufferedStunSocketTest, TestReceiveRecvFromReallyLong) { 1.446 + uint8_t garbage[4096]; 1.447 + memset(garbage, 0xff, sizeof(garbage)); 1.448 + memcpy(garbage, kStunMessage, kStunMessageLen); 1.449 + nr_stun_message_header *hdr = reinterpret_cast<nr_stun_message_header *> 1.450 + (garbage); 1.451 + hdr->length = htons(3000); 1.452 + 1.453 + dummy_->SetReadBuffer(garbage, sizeof(garbage)); 1.454 + 1.455 + unsigned char tmp[4096]; 1.456 + size_t len; 1.457 + nr_transport_addr addr; 1.458 + 1.459 + int r = nr_socket_recvfrom(test_socket_, 1.460 + tmp, kStunMessageLen - 1, &len, 0, 1.461 + &addr); 1.462 + ASSERT_EQ(R_BAD_DATA, r); 1.463 +} 1.464 + 1.465 + 1.466 + 1.467 +int main(int argc, char **argv) 1.468 +{ 1.469 + test_utils = new MtransportTestUtils(); 1.470 + NSS_NoDB_Init(nullptr); 1.471 + NSS_SetDomesticPolicy(); 1.472 + 1.473 + // Start the tests 1.474 + ::testing::InitGoogleTest(&argc, argv); 1.475 + 1.476 + int rv = RUN_ALL_TESTS(); 1.477 + 1.478 + delete test_utils; 1.479 + return rv; 1.480 +}