media/mtransport/test/buffered_stun_socket_unittest.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 // Original author: ekr@rtfm.com
     9 #include <iostream>
    11 #include "nspr.h"
    12 #include "nss.h"
    13 #include "ssl.h"
    15 #include "mozilla/Scoped.h"
    17 extern "C" {
    18 #include "nr_api.h"
    19 #include "nr_socket.h"
    20 #include "nr_socket_buffered_stun.h"
    21 #include "transport_addr.h"
    22 #include "stun.h"
    23 }
    25 #include "databuffer.h"
    26 #include "mtransport_test_utils.h"
    28 #include "nr_socket_prsock.h"
    30 #define GTEST_HAS_RTTI 0
    31 #include "gtest/gtest.h"
    32 #include "gtest_utils.h"
    34 using namespace mozilla;
    35 MtransportTestUtils *test_utils;
    37 static uint8_t kStunMessage[] = {
    38   0x00, 0x01, 0x00, 0x08, 0x21, 0x12, 0xa4, 0x42,
    39   0x9b, 0x90, 0xbe, 0x2c, 0xae, 0x1a, 0x0c, 0xa8,
    40   0xa0, 0xd6, 0x8b, 0x08, 0x80, 0x28, 0x00, 0x04,
    41   0xdb, 0x35, 0x5f, 0xaa
    42 };
    43 static size_t kStunMessageLen = sizeof(kStunMessage);
    45 class DummySocket : public NrSocketBase {
    46  public:
    47   DummySocket()
    48       : writable_(UINT_MAX),
    49         write_buffer_(nullptr),
    50         readable_(UINT_MAX),
    51         read_buffer_(nullptr),
    52         cb_(nullptr),
    53         cb_arg_(nullptr),
    54         self_(nullptr) {}
    56   // the nr_socket APIs
    57   virtual int create(nr_transport_addr *addr) {
    58     return 0;
    59   }
    61   virtual int sendto(const void *msg, size_t len,
    62                      int flags, nr_transport_addr *to) {
    63     MOZ_CRASH();
    64     return 0;
    65   }
    67   virtual int recvfrom(void * buf, size_t maxlen,
    68                        size_t *len, int flags,
    69                        nr_transport_addr *from) {
    70     MOZ_CRASH();
    71     return 0;
    72   }
    74   virtual int getaddr(nr_transport_addr *addrp) {
    75     MOZ_CRASH();
    76     return 0;
    77   }
    79   virtual void close() {
    80   }
    82   virtual int connect(nr_transport_addr *addr) {
    83     return 0;
    84   }
    86   virtual int write(const void *msg, size_t len, size_t *written) {
    87     // Shouldn't be anything here.
    88     EXPECT_EQ(nullptr, write_buffer_.get());
    90     size_t to_write = std::min(len, writable_);
    92     if (to_write) {
    93       write_buffer_ = new DataBuffer(
    94           static_cast<const uint8_t *>(msg), to_write);
    95       *written = to_write;
    96     }
    98     return 0;
    99   }
   101   virtual int read(void* buf, size_t maxlen, size_t *len) {
   102     if (!read_buffer_.get()) {
   103       return R_WOULDBLOCK;
   104     }
   106     size_t to_read = std::min(read_buffer_->len(),
   107                               std::min(maxlen, readable_));
   109     memcpy(buf, read_buffer_->data(), to_read);
   110     *len = to_read;
   112     if (to_read < read_buffer_->len()) {
   113       read_buffer_ = new DataBuffer(read_buffer_->data() + to_read,
   114                                     read_buffer_->len() - to_read);
   115     } else {
   116       read_buffer_ = nullptr;
   117     }
   119     return 0;
   120   }
   122   // Implementations of the async_event APIs.
   123   // These are no-ops because we handle scheduling manually
   124   // for test purposes.
   125   virtual int async_wait(int how, NR_async_cb cb, void *cb_arg,
   126                          char *function, int line) {
   127     EXPECT_EQ(nullptr, cb_);
   128     cb_ = cb;
   129     cb_arg_ = cb_arg;
   131     return 0;
   132   }
   134   virtual int cancel(int how) {
   135     cb_ = nullptr;
   136     cb_arg_ = nullptr;
   138     return 0;
   139   }
   142   // Read/Manipulate the current state.
   143   void CheckWriteBuffer(uint8_t *data, size_t len) {
   144     if (!len) {
   145       EXPECT_EQ(nullptr, write_buffer_.get());
   146     } else {
   147       EXPECT_NE(nullptr, write_buffer_.get());
   148       ASSERT_EQ(len, write_buffer_->len());
   149       ASSERT_EQ(0, memcmp(data, write_buffer_->data(), len));
   150     }
   151   }
   153   void ClearWriteBuffer() {
   154     write_buffer_ = nullptr;
   155   }
   157   void SetWritable(size_t val) {
   158     writable_ = val;
   159   }
   161   void FireWritableCb() {
   162     NR_async_cb cb = cb_;
   163     void *cb_arg = cb_arg_;
   165     cb_ = nullptr;
   166     cb_arg_ = nullptr;
   168     cb(this, NR_ASYNC_WAIT_WRITE, cb_arg);
   169   }
   171   void SetReadBuffer(uint8_t *data, size_t len) {
   172     EXPECT_EQ(nullptr, write_buffer_.get());
   173     read_buffer_ = new DataBuffer(data, len);
   174   }
   176   void ClearReadBuffer() {
   177     read_buffer_ = nullptr;
   178   }
   180   void SetReadable(size_t val) {
   181     readable_ = val;
   182   }
   184   nr_socket *get_nr_socket() {
   185     if (!self_) {
   186       int r = nr_socket_create_int(this, vtbl(), &self_);
   187       AddRef();
   188       if (r)
   189         return nullptr;
   190     }
   192     return self_;
   193   }
   195   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DummySocket);
   197  private:
   198   DISALLOW_COPY_ASSIGN(DummySocket);
   200   size_t writable_;  // Amount we allow someone to write.
   201   ScopedDeletePtr<DataBuffer> write_buffer_;
   202   size_t readable_;   // Amount we allow someone to read.
   203   ScopedDeletePtr<DataBuffer> read_buffer_;
   205   NR_async_cb cb_;
   206   void *cb_arg_;
   207   nr_socket *self_;
   208 };
   210 class BufferedStunSocketTest : public ::testing::Test {
   211  public:
   212   BufferedStunSocketTest()
   213       : dummy_(nullptr),
   214         test_socket_(nullptr) {}
   216   ~BufferedStunSocketTest() {
   217     nr_socket_destroy(&test_socket_);
   218   }
   220   void SetUp() {
   221     ScopedDeletePtr<DummySocket> dummy(new DummySocket());
   223     int r = nr_socket_buffered_stun_create(
   224         dummy->get_nr_socket(),
   225         kStunMessageLen,
   226         &test_socket_);
   227     ASSERT_EQ(0, r);
   228     dummy_ = dummy.forget();  // Now owned by test_socket_.
   230     r = nr_ip4_str_port_to_transport_addr(
   231         (char *)"192.0.2.133", 3333, IPPROTO_TCP, &remote_addr_);
   232     ASSERT_EQ(0, r);
   234     r = nr_socket_connect(test_socket_,
   235                           &remote_addr_);
   236     ASSERT_EQ(0, r);
   237   }
   239   nr_socket *socket() { return test_socket_; }
   241  protected:
   242   DummySocket *dummy_;
   243   nr_socket *test_socket_;
   244   nr_transport_addr remote_addr_;
   245 };
   248 TEST_F(BufferedStunSocketTest, TestCreate) {
   249 }
   251 TEST_F(BufferedStunSocketTest, TestSendTo) {
   252   int r = nr_socket_sendto(test_socket_,
   253                            kStunMessage,
   254                            kStunMessageLen,
   255                            0, &remote_addr_);
   256   ASSERT_EQ(0, r);
   258   dummy_->CheckWriteBuffer(kStunMessage, kStunMessageLen);
   259 }
   261 TEST_F(BufferedStunSocketTest, TestSendToBuffered) {
   262   dummy_->SetWritable(0);
   264   int r = nr_socket_sendto(test_socket_,
   265                            kStunMessage,
   266                            kStunMessageLen,
   267                            0, &remote_addr_);
   268   ASSERT_EQ(0, r);
   270   dummy_->CheckWriteBuffer(nullptr, 0);
   272   dummy_->SetWritable(kStunMessageLen);
   273   dummy_->FireWritableCb();
   274   dummy_->CheckWriteBuffer(kStunMessage, kStunMessageLen);
   275 }
   277 TEST_F(BufferedStunSocketTest, TestSendFullThenDrain) {
   278   dummy_->SetWritable(0);
   280   for (;;) {
   281     int r = nr_socket_sendto(test_socket_,
   282                              kStunMessage,
   283                              kStunMessageLen,
   284                              0, &remote_addr_);
   285     if (r == R_WOULDBLOCK)
   286       break;
   288     ASSERT_EQ(0, r);
   289   }
   291   // Nothing was written.
   292   dummy_->CheckWriteBuffer(nullptr, 0);
   294   // Now flush.
   295   dummy_->SetWritable(kStunMessageLen);
   296   dummy_->FireWritableCb();
   297   dummy_->ClearWriteBuffer();
   299   // Verify we can write something.
   300   int r = nr_socket_sendto(test_socket_,
   301                              kStunMessage,
   302                              kStunMessageLen,
   303                              0, &remote_addr_);
   304   ASSERT_EQ(0, r);
   306   // And that it appears.
   307   dummy_->CheckWriteBuffer(kStunMessage, kStunMessageLen);
   308 }
   310 TEST_F(BufferedStunSocketTest, TestSendToPartialBuffered) {
   311   dummy_->SetWritable(10);
   313   int r = nr_socket_sendto(test_socket_,
   314                            kStunMessage,
   315                            kStunMessageLen,
   316                            0, &remote_addr_);
   317   ASSERT_EQ(0, r);
   319   dummy_->CheckWriteBuffer(kStunMessage, 10);
   320   dummy_->ClearWriteBuffer();
   322   dummy_->SetWritable(kStunMessageLen);
   323   dummy_->FireWritableCb();
   324   dummy_->CheckWriteBuffer(kStunMessage + 10, kStunMessageLen - 10);
   325 }
   327 TEST_F(BufferedStunSocketTest, TestSendToReject) {
   328   dummy_->SetWritable(0);
   330   int r = nr_socket_sendto(test_socket_,
   331                            kStunMessage,
   332                            kStunMessageLen,
   333                            0, &remote_addr_);
   334   ASSERT_EQ(0, r);
   336   dummy_->CheckWriteBuffer(nullptr, 0);
   338   r = nr_socket_sendto(test_socket_,
   339                        kStunMessage,
   340                        kStunMessageLen,
   341                        0, &remote_addr_);
   342   ASSERT_EQ(R_WOULDBLOCK, r);
   344   dummy_->CheckWriteBuffer(nullptr, 0);
   345 }
   347 TEST_F(BufferedStunSocketTest, TestSendToWrongAddr) {
   348   nr_transport_addr addr;
   350   int r = nr_ip4_str_port_to_transport_addr(
   351       (char *)"192.0.2.134", 3333, IPPROTO_TCP, &addr);
   352   ASSERT_EQ(0, r);
   354   r = nr_socket_sendto(test_socket_,
   355                        kStunMessage,
   356                        kStunMessageLen,
   357                        0, &addr);
   358   ASSERT_EQ(R_BAD_DATA, r);
   359 }
   361 TEST_F(BufferedStunSocketTest, TestReceiveRecvFrom) {
   362   dummy_->SetReadBuffer(kStunMessage, kStunMessageLen);
   364   unsigned char tmp[2048];
   365   size_t len;
   366   nr_transport_addr addr;
   368   int r = nr_socket_recvfrom(test_socket_,
   369                              tmp, sizeof(tmp), &len, 0,
   370                              &addr);
   371   ASSERT_EQ(0, r);
   372   ASSERT_EQ(kStunMessageLen, len);
   373   ASSERT_EQ(0, memcmp(kStunMessage, tmp, kStunMessageLen));
   374   ASSERT_EQ(0, nr_transport_addr_cmp(&addr, &remote_addr_,
   375                                      NR_TRANSPORT_ADDR_CMP_MODE_ALL));
   376 }
   378 TEST_F(BufferedStunSocketTest, TestReceiveRecvFromPartial) {
   379   dummy_->SetReadBuffer(kStunMessage, 15);
   381   unsigned char tmp[2048];
   382   size_t len;
   383   nr_transport_addr addr;
   385   int r = nr_socket_recvfrom(test_socket_,
   386                              tmp, sizeof(tmp), &len, 0,
   387                              &addr);
   388   ASSERT_EQ(R_WOULDBLOCK, r);
   391   dummy_->SetReadBuffer(kStunMessage + 15, kStunMessageLen - 15);
   393   r = nr_socket_recvfrom(test_socket_,
   394                          tmp, sizeof(tmp), &len, 0,
   395                          &addr);
   396   ASSERT_EQ(0, r);
   397   ASSERT_EQ(kStunMessageLen, len);
   398   ASSERT_EQ(0, memcmp(kStunMessage, tmp, kStunMessageLen));
   399   ASSERT_EQ(0, nr_transport_addr_cmp(&addr, &remote_addr_,
   400                                      NR_TRANSPORT_ADDR_CMP_MODE_ALL));
   402   r = nr_socket_recvfrom(test_socket_,
   403                          tmp, sizeof(tmp), &len, 0,
   404                          &addr);
   405   ASSERT_EQ(R_WOULDBLOCK, r);
   406 }
   409 TEST_F(BufferedStunSocketTest, TestReceiveRecvFromGarbage) {
   410   uint8_t garbage[50];
   411   memset(garbage, 0xff, sizeof(garbage));
   413   dummy_->SetReadBuffer(garbage, sizeof(garbage));
   415   unsigned char tmp[2048];
   416   size_t len;
   417   nr_transport_addr addr;
   418   int r = nr_socket_recvfrom(test_socket_,
   419                              tmp, sizeof(tmp), &len, 0,
   420                              &addr);
   421   ASSERT_EQ(R_BAD_DATA, r);
   423   r = nr_socket_recvfrom(test_socket_,
   424                          tmp, sizeof(tmp), &len, 0,
   425                          &addr);
   426   ASSERT_EQ(R_FAILED, r);
   427 }
   429 TEST_F(BufferedStunSocketTest, TestReceiveRecvFromTooShort) {
   430   dummy_->SetReadBuffer(kStunMessage, kStunMessageLen);
   432   unsigned char tmp[2048];
   433   size_t len;
   434   nr_transport_addr addr;
   436   int r = nr_socket_recvfrom(test_socket_,
   437                              tmp, kStunMessageLen - 1, &len, 0,
   438                              &addr);
   439   ASSERT_EQ(R_BAD_ARGS, r);
   440 }
   442 TEST_F(BufferedStunSocketTest, TestReceiveRecvFromReallyLong) {
   443   uint8_t garbage[4096];
   444   memset(garbage, 0xff, sizeof(garbage));
   445   memcpy(garbage, kStunMessage, kStunMessageLen);
   446   nr_stun_message_header *hdr = reinterpret_cast<nr_stun_message_header *>
   447       (garbage);
   448   hdr->length = htons(3000);
   450   dummy_->SetReadBuffer(garbage, sizeof(garbage));
   452   unsigned char tmp[4096];
   453   size_t len;
   454   nr_transport_addr addr;
   456   int r = nr_socket_recvfrom(test_socket_,
   457                              tmp, kStunMessageLen - 1, &len, 0,
   458                              &addr);
   459   ASSERT_EQ(R_BAD_DATA, r);
   460 }
   464 int main(int argc, char **argv)
   465 {
   466   test_utils = new MtransportTestUtils();
   467   NSS_NoDB_Init(nullptr);
   468   NSS_SetDomesticPolicy();
   470   // Start the tests
   471   ::testing::InitGoogleTest(&argc, argv);
   473   int rv = RUN_ALL_TESTS();
   475   delete test_utils;
   476   return rv;
   477 }

mercurial