tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nr_socket_tcp.cpp (8431B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
      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/. */
      6 
      7 /*
      8 Copyright (c) 2007, Adobe Systems, Incorporated
      9 Copyright (c) 2013, Mozilla
     10 
     11 All rights reserved.
     12 
     13 Redistribution and use in source and binary forms, with or without
     14 modification, are permitted provided that the following conditions are
     15 met:
     16 
     17 * Redistributions of source code must retain the above copyright
     18 notice, this list of conditions and the following disclaimer.
     19 
     20 * Redistributions in binary form must reproduce the above copyright
     21 notice, this list of conditions and the following disclaimer in the
     22 documentation and/or other materials provided with the distribution.
     23 
     24 * Neither the name of Adobe Systems, Network Resonance, Mozilla nor
     25 the names of its contributors may be used to endorse or promote
     26 products derived from this software without specific prior written
     27 permission.
     28 
     29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     30 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     31 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     32 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     33 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     34 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     35 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     36 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     37 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     38 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     39 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     40 */
     41 
     42 #include "nr_socket_tcp.h"
     43 
     44 #include "WebrtcTCPSocketWrapper.h"
     45 #include "mozilla/ErrorNames.h"
     46 
     47 namespace mozilla {
     48 using namespace net;
     49 
     50 using std::shared_ptr;
     51 
     52 class NrTcpSocketData {
     53 public:
     54  explicit NrTcpSocketData(nsTArray<uint8_t>&& aData)
     55      : mData(std::move(aData)) {
     56    MOZ_COUNT_CTOR(NrTcpSocketData);
     57  }
     58 
     59  MOZ_COUNTED_DTOR(NrTcpSocketData)
     60 
     61  const nsTArray<uint8_t>& GetData() const { return mData; }
     62 
     63 private:
     64  nsTArray<uint8_t> mData;
     65 };
     66 
     67 NrTcpSocket::NrTcpSocket(const shared_ptr<NrSocketProxyConfig>& aConfig)
     68    : mClosed(false),
     69      mReadOffset(0),
     70      mConfig(aConfig),
     71      mWebrtcTCPSocket(nullptr) {
     72  r_log(LOG_GENERIC, LOG_DEBUG, "NrTcpSocket::NrTcpSocket %p\n", this);
     73 }
     74 
     75 NrTcpSocket::~NrTcpSocket() {
     76  r_log(LOG_GENERIC, LOG_DEBUG, "NrTcpSocket::~NrTcpSocket %p\n", this);
     77  MOZ_ASSERT(!mWebrtcTCPSocket, "webrtc TCP socket not null");
     78 }
     79 
     80 int NrTcpSocket::create(nr_transport_addr* aAddr) {
     81  r_log(LOG_GENERIC, LOG_DEBUG, "NrTcpSocket::create %p\n", this);
     82  int32_t port;
     83  nsCString host;
     84 
     85  // Sanity check
     86  if (nr_transport_addr_get_addrstring_and_port(aAddr, &host, &port)) {
     87    return R_FAILED;
     88  }
     89 
     90  if (nr_transport_addr_copy(&my_addr_, aAddr)) {
     91    return R_FAILED;
     92  }
     93 
     94  return 0;
     95 }
     96 
     97 int NrTcpSocket::connect(const nr_transport_addr* aAddr) {
     98  r_log(LOG_GENERIC, LOG_DEBUG, "NrTcpSocket::connect %p\n", this);
     99 
    100  nsCString remote_host;
    101  int remote_port;
    102 
    103  if (NS_WARN_IF(nr_transport_addr_get_addrstring_and_port(aAddr, &remote_host,
    104                                                           &remote_port))) {
    105    return R_FAILED;
    106  }
    107 
    108  bool use_tls = aAddr->tls;
    109 
    110  nsCString local_addr;
    111  int local_port;
    112 
    113  if (NS_WARN_IF(nr_transport_addr_get_addrstring_and_port(
    114          &my_addr_, &local_addr, &local_port))) {
    115    return R_FAILED;
    116  }
    117 
    118  mWebrtcTCPSocket = new WebrtcTCPSocketWrapper(this);
    119 
    120  mWebrtcTCPSocket->AsyncOpen(remote_host, remote_port, local_addr, local_port,
    121                              use_tls, mConfig);
    122 
    123  // trigger nr_socket_buffered to set write/read callback
    124  return R_WOULDBLOCK;
    125 }
    126 
    127 void NrTcpSocket::close() {
    128  r_log(LOG_GENERIC, LOG_DEBUG, "NrTcpSocket::close %p\n", this);
    129 
    130  if (mClosed) {
    131    return;
    132  }
    133 
    134  mClosed = true;
    135 
    136  // We're not always open at this point.
    137  if (mWebrtcTCPSocket) {
    138    mWebrtcTCPSocket->Close();
    139    mWebrtcTCPSocket = nullptr;
    140  }
    141 }
    142 
    143 int NrTcpSocket::write(const void* aBuffer, size_t aCount, size_t* aWrote) {
    144  r_log(LOG_GENERIC, LOG_DEBUG, "NrTcpSocket::write %p count=%zu\n", this,
    145        aCount);
    146 
    147  if (mClosed) {
    148    return R_FAILED;
    149  }
    150 
    151  if (!aWrote) {
    152    return R_FAILED;
    153  }
    154 
    155  if (NS_WARN_IF(!mWebrtcTCPSocket)) {
    156    return R_FAILED;
    157  }
    158 
    159  *aWrote = aCount;
    160 
    161  if (aCount > 0) {
    162    nsTArray<uint8_t> writeData;
    163    writeData.SetLength(aCount);
    164    memcpy(writeData.Elements(), aBuffer, aCount);
    165 
    166    mWebrtcTCPSocket->SendWrite(std::move(writeData));
    167  }
    168 
    169  return 0;
    170 }
    171 
    172 int NrTcpSocket::read(void* aBuffer, size_t aCount, size_t* aRead) {
    173  r_log(LOG_GENERIC, LOG_DEBUG, "NrTcpSocket::read %p\n", this);
    174 
    175  if (mClosed) {
    176    return R_FAILED;
    177  }
    178 
    179  if (!aRead) {
    180    return R_FAILED;
    181  }
    182 
    183  *aRead = 0;
    184 
    185  if (mReadQueue.empty()) {
    186    return R_WOULDBLOCK;
    187  }
    188 
    189  while (aCount > 0 && !mReadQueue.empty()) {
    190    const NrTcpSocketData& data = mReadQueue.front();
    191 
    192    size_t remainingCount = data.GetData().Length() - mReadOffset;
    193    size_t amountToCopy = std::min(aCount, remainingCount);
    194 
    195    char* buffer = static_cast<char*>(aBuffer) + (*aRead);
    196 
    197    memcpy(buffer, data.GetData().Elements() + mReadOffset, amountToCopy);
    198 
    199    mReadOffset += amountToCopy;
    200    *aRead += amountToCopy;
    201    aCount -= amountToCopy;
    202 
    203    if (remainingCount == amountToCopy) {
    204      mReadOffset = 0;
    205      mReadQueue.pop_front();
    206    }
    207  }
    208 
    209  return 0;
    210 }
    211 
    212 int NrTcpSocket::getaddr(nr_transport_addr* aAddr) {
    213  r_log(LOG_GENERIC, LOG_DEBUG, "NrTcpSocket::getaddr %p\n", this);
    214  return nr_transport_addr_copy(aAddr, &my_addr_);
    215 }
    216 
    217 int NrTcpSocket::sendto(const void* aBuffer, size_t aCount, int aFlags,
    218                        const nr_transport_addr* aAddr) {
    219  // never call this
    220  MOZ_ASSERT(0);
    221  return R_FAILED;
    222 }
    223 
    224 int NrTcpSocket::recvfrom(void* aBuffer, size_t aCount, size_t* aRead,
    225                          int aFlags, nr_transport_addr* aAddr) {
    226  // never call this
    227  MOZ_ASSERT(0);
    228  return R_FAILED;
    229 }
    230 
    231 int NrTcpSocket::listen(int aBacklog) {
    232  r_log(LOG_GENERIC, LOG_DEBUG, "NrTcpSocket::listen %p\n", this);
    233  return R_INTERNAL;
    234 }
    235 
    236 int NrTcpSocket::accept(nr_transport_addr* aAddr, nr_socket** aSocket) {
    237  r_log(LOG_GENERIC, LOG_DEBUG, "NrTcpSocket::accept %p\n", this);
    238  return R_INTERNAL;
    239 }
    240 
    241 // WebrtcTCPSocketCallback
    242 void NrTcpSocket::OnClose(nsresult aReason) {
    243  nsCString errorName;
    244  GetErrorName(aReason, errorName);
    245 
    246  r_log(LOG_GENERIC, LOG_ERR, "NrTcpSocket::OnClose %p reason=%u name=%s\n",
    247        this, static_cast<uint32_t>(aReason), errorName.get());
    248 
    249  close();
    250 
    251  DoCallbacks();
    252 }
    253 
    254 void NrTcpSocket::OnConnected(const nsACString& aProxyType) {
    255  r_log(LOG_GENERIC, LOG_DEBUG, "NrTcpSocket::OnConnected %p\n", this);
    256  if (aProxyType != "" && aProxyType != "direct") {
    257    my_addr_.is_proxied = true;
    258  }
    259 
    260  DoCallbacks();
    261 }
    262 
    263 void NrTcpSocket::OnRead(nsTArray<uint8_t>&& aReadData) {
    264  r_log(LOG_GENERIC, LOG_DEBUG, "NrTcpSocket::OnRead %p read=%zu\n", this,
    265        aReadData.Length());
    266 
    267  mReadQueue.emplace_back(std::move(aReadData));
    268 
    269  DoCallbacks();
    270 }
    271 
    272 void NrTcpSocket::DoCallbacks() {
    273  size_t lastCount = -1;
    274  size_t currentCount = 0;
    275  while ((poll_flags() & PR_POLL_READ) != 0 &&
    276         // Make sure whatever is reading knows we're closed. This doesn't need
    277         // to happen for writes since ICE doesn't like a failing writable.
    278         (mClosed || (currentCount = CountUnreadBytes()) > 0) &&
    279         lastCount != currentCount) {
    280    fire_callback(NR_ASYNC_WAIT_READ);
    281    lastCount = currentCount;
    282  }
    283 
    284  // We're always ready to write after we're connected. The parent process will
    285  // buffer writes for us.
    286  if (!mClosed && mWebrtcTCPSocket && (poll_flags() & PR_POLL_WRITE) != 0) {
    287    fire_callback(NR_ASYNC_WAIT_WRITE);
    288  }
    289 }
    290 
    291 size_t NrTcpSocket::CountUnreadBytes() const {
    292  size_t count = 0;
    293 
    294  for (const NrTcpSocketData& data : mReadQueue) {
    295    count += data.GetData().Length();
    296  }
    297 
    298  MOZ_ASSERT(count >= mReadOffset, "offset exceeds read buffer length");
    299 
    300  count -= mReadOffset;
    301 
    302  return count;
    303 }
    304 
    305 void NrTcpSocket::AssignChannel_DoNotUse(WebrtcTCPSocketWrapper* aWrapper) {
    306  mWebrtcTCPSocket = aWrapper;
    307 }
    308 
    309 }  // namespace mozilla