tor-browser

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

StunAddrsRequestParent.cpp (7955B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "StunAddrsRequestParent.h"
      6 
      7 #include "../mdns_service/mdns_service.h"
      8 #include "../runnable_utils.h"
      9 #include "mozilla/StaticPtr.h"
     10 #include "nsIThread.h"
     11 #include "nsNetUtil.h"
     12 #include "transport/nricectx.h"
     13 #include "transport/nricemediastream.h"  // needed only for including nricectx.h
     14 #include "transport/nricestunaddr.h"
     15 
     16 extern "C" {
     17 #include "local_addr.h"
     18 }
     19 
     20 using namespace mozilla::ipc;
     21 
     22 namespace mozilla::net {
     23 
     24 static void mdns_service_resolved(void* cb, const char* hostname,
     25                                  const char* addr) {
     26  StunAddrsRequestParent* self = static_cast<StunAddrsRequestParent*>(cb);
     27  self->OnQueryComplete(nsCString(hostname), Some(nsCString(addr)));
     28 }
     29 
     30 void mdns_service_timedout(void* cb, const char* hostname) {
     31  StunAddrsRequestParent* self = static_cast<StunAddrsRequestParent*>(cb);
     32  self->OnQueryComplete(nsCString(hostname), Nothing());
     33 }
     34 
     35 StunAddrsRequestParent::StunAddrsRequestParent() : mIPCClosed(false) {
     36  NS_GetMainThread(getter_AddRefs(mMainThread));
     37 
     38  nsresult res;
     39  mSTSThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &res);
     40  MOZ_ASSERT(mSTSThread);
     41 }
     42 
     43 StunAddrsRequestParent::~StunAddrsRequestParent() {
     44  ASSERT_ON_THREAD(mMainThread);
     45 }
     46 
     47 mozilla::ipc::IPCResult StunAddrsRequestParent::RecvGetStunAddrs() {
     48  ASSERT_ON_THREAD(mMainThread);
     49 
     50  if (mIPCClosed) {
     51    return IPC_OK();
     52  }
     53 
     54  RUN_ON_THREAD(mSTSThread,
     55                WrapRunnable(RefPtr<StunAddrsRequestParent>(this),
     56                             &StunAddrsRequestParent::GetStunAddrs_s),
     57                NS_DISPATCH_NORMAL);
     58 
     59  return IPC_OK();
     60 }
     61 
     62 mozilla::ipc::IPCResult StunAddrsRequestParent::RecvRegisterMDNSHostname(
     63    const nsACString& aHostname, const nsACString& aAddress) {
     64  ASSERT_ON_THREAD(mMainThread);
     65 
     66  if (mIPCClosed) {
     67    return IPC_OK();
     68  }
     69 
     70  if (mSharedMDNSService) {
     71    mSharedMDNSService->RegisterHostname(aHostname.BeginReading(),
     72                                         aAddress.BeginReading());
     73  }
     74 
     75  return IPC_OK();
     76 }
     77 
     78 mozilla::ipc::IPCResult StunAddrsRequestParent::RecvQueryMDNSHostname(
     79    const nsACString& aHostname) {
     80  ASSERT_ON_THREAD(mMainThread);
     81 
     82  if (mIPCClosed) {
     83    return IPC_OK();
     84  }
     85 
     86  if (mSharedMDNSService) {
     87    mSharedMDNSService->QueryHostname(this, aHostname.BeginReading());
     88  }
     89 
     90  return IPC_OK();
     91 }
     92 
     93 mozilla::ipc::IPCResult StunAddrsRequestParent::RecvUnregisterMDNSHostname(
     94    const nsACString& aHostname) {
     95  ASSERT_ON_THREAD(mMainThread);
     96 
     97  if (mIPCClosed) {
     98    return IPC_OK();
     99  }
    100 
    101  if (mSharedMDNSService) {
    102    mSharedMDNSService->UnregisterHostname(aHostname.BeginReading());
    103  }
    104 
    105  return IPC_OK();
    106 }
    107 
    108 mozilla::ipc::IPCResult StunAddrsRequestParent::Recv__delete__() {
    109  // see note below in ActorDestroy
    110  mIPCClosed = true;
    111  return IPC_OK();
    112 }
    113 
    114 void StunAddrsRequestParent::OnQueryComplete(const nsACString& hostname,
    115                                             const Maybe<nsCString>& address) {
    116  RUN_ON_THREAD(mMainThread,
    117                WrapRunnable(RefPtr<StunAddrsRequestParent>(this),
    118                             &StunAddrsRequestParent::OnQueryComplete_m,
    119                             nsCString(hostname), address),
    120                NS_DISPATCH_NORMAL);
    121 }
    122 
    123 void StunAddrsRequestParent::ActorDestroy(ActorDestroyReason why) {
    124  // We may still have refcount>0 if we haven't made it through
    125  // GetStunAddrs_s and SendStunAddrs_m yet, but child process
    126  // has crashed.  We must not send any more msgs to child, or
    127  // IPDL will kill chrome process, too.
    128  mIPCClosed = true;
    129 
    130  // We need to stop the mDNS service here to ensure that we don't
    131  // end up with any messages queued for the main thread after the
    132  // destructors run. Because of Bug 1569311, all of the
    133  // StunAddrsRequestParent instances end up being destroyed one
    134  // after the other, so it is ok to free the shared service when
    135  // the first one is destroyed rather than waiting for the last one.
    136  // If this behaviour changes, we would potentially end up starting
    137  // and stopping instances repeatedly and should add a refcount and
    138  // a way of cancelling pending queries to avoid churn in that case.
    139  if (mSharedMDNSService) {
    140    mSharedMDNSService = nullptr;
    141  }
    142 }
    143 
    144 void StunAddrsRequestParent::GetStunAddrs_s() {
    145  ASSERT_ON_THREAD(mSTSThread);
    146 
    147  // get the stun addresses while on STS thread
    148  NrIceStunAddrArray addrs = NrIceCtx::GetStunAddrs();
    149 
    150  if (mIPCClosed) {
    151    return;
    152  }
    153 
    154  // in order to return the result over IPC, we need to be on main thread
    155  RUN_ON_THREAD(
    156      mMainThread,
    157      WrapRunnable(RefPtr<StunAddrsRequestParent>(this),
    158                   &StunAddrsRequestParent::SendStunAddrs_m, std::move(addrs)),
    159      NS_DISPATCH_NORMAL);
    160 }
    161 
    162 void StunAddrsRequestParent::SendStunAddrs_m(const NrIceStunAddrArray& addrs) {
    163  ASSERT_ON_THREAD(mMainThread);
    164 
    165  if (mIPCClosed) {
    166    // nothing to do: child probably crashed
    167    return;
    168  }
    169 
    170  // This means that the mDNS service will continue running until shutdown
    171  // once started. The StunAddrsRequestParent destructor does not run until
    172  // shutdown anyway (see Bug 1569311), so there is not much we can do about
    173  // this here. One option would be to add a check if there are no hostnames
    174  // registered after UnregisterHostname is called, and if so, stop the mDNS
    175  // service at that time (see Bug 1569955.)
    176  if (!mSharedMDNSService) {
    177    std::ostringstream o;
    178    char buffer[16];
    179    for (auto& addr : addrs) {
    180      if (addr.localAddr().addr.ip_version == NR_IPV4 &&
    181          !nr_transport_addr_is_loopback(&addr.localAddr().addr)) {
    182        nr_transport_addr_get_addrstring(&addr.localAddr().addr, buffer, 16);
    183        o << buffer << ";";
    184      }
    185    }
    186    std::string addrstring = o.str();
    187    if (!addrstring.empty()) {
    188      mSharedMDNSService = new MDNSServiceWrapper(addrstring);
    189    }
    190  }
    191 
    192  // send the new addresses back to the child
    193  (void)SendOnStunAddrsAvailable(addrs);
    194 }
    195 
    196 void StunAddrsRequestParent::OnQueryComplete_m(
    197    const nsACString& hostname, const Maybe<nsCString>& address) {
    198  ASSERT_ON_THREAD(mMainThread);
    199 
    200  if (mIPCClosed) {
    201    // nothing to do: child probably crashed
    202    return;
    203  }
    204 
    205  // send the hostname and address back to the child
    206  (void)SendOnMDNSQueryComplete(hostname, address);
    207 }
    208 
    209 StaticRefPtr<StunAddrsRequestParent::MDNSServiceWrapper>
    210    StunAddrsRequestParent::mSharedMDNSService;
    211 
    212 NS_IMPL_ADDREF(StunAddrsRequestParent)
    213 NS_IMPL_RELEASE(StunAddrsRequestParent)
    214 
    215 StunAddrsRequestParent::MDNSServiceWrapper::MDNSServiceWrapper(
    216    const std::string& ifaddr)
    217    : ifaddr(ifaddr) {}
    218 
    219 void StunAddrsRequestParent::MDNSServiceWrapper::RegisterHostname(
    220    const char* hostname, const char* address) {
    221  StartIfRequired();
    222  if (mMDNSService) {
    223    mdns_service_register_hostname(mMDNSService, hostname, address);
    224  }
    225 }
    226 
    227 void StunAddrsRequestParent::MDNSServiceWrapper::QueryHostname(
    228    void* data, const char* hostname) {
    229  StartIfRequired();
    230  if (mMDNSService) {
    231    mdns_service_query_hostname(mMDNSService, data, mdns_service_resolved,
    232                                mdns_service_timedout, hostname);
    233  }
    234 }
    235 
    236 void StunAddrsRequestParent::MDNSServiceWrapper::UnregisterHostname(
    237    const char* hostname) {
    238  StartIfRequired();
    239  if (mMDNSService) {
    240    mdns_service_unregister_hostname(mMDNSService, hostname);
    241  }
    242 }
    243 
    244 StunAddrsRequestParent::MDNSServiceWrapper::~MDNSServiceWrapper() {
    245  if (mMDNSService) {
    246    mdns_service_stop(mMDNSService);
    247    mMDNSService = nullptr;
    248  }
    249 }
    250 
    251 void StunAddrsRequestParent::MDNSServiceWrapper::StartIfRequired() {
    252  if (!mMDNSService) {
    253    mMDNSService = mdns_service_start(ifaddr.c_str());
    254  }
    255 }
    256 
    257 NS_IMPL_ADDREF(StunAddrsRequestParent::MDNSServiceWrapper)
    258 NS_IMPL_RELEASE(StunAddrsRequestParent::MDNSServiceWrapper)
    259 
    260 }  // namespace mozilla::net