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