UDPSocketChild.cpp (7425B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=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/. */ 6 7 #include "UDPSocketChild.h" 8 9 #include "UDPSocket.h" 10 #include "mozilla/dom/ContentChild.h" 11 #include "mozilla/dom/PermissionMessageUtils.h" 12 #include "mozilla/ipc/BackgroundChild.h" 13 #include "mozilla/ipc/BackgroundUtils.h" 14 #include "mozilla/ipc/IPCStreamUtils.h" 15 #include "mozilla/ipc/PBackgroundChild.h" 16 #include "mozilla/ipc/PBackgroundSharedTypes.h" 17 #include "mozilla/net/NeckoChild.h" 18 19 using mozilla::net::gNeckoChild; 20 21 namespace mozilla::dom { 22 23 NS_IMPL_ISUPPORTS(UDPSocketChildBase, nsISupports) 24 25 UDPSocketChildBase::UDPSocketChildBase() : mIPCOpen(false) {} 26 27 UDPSocketChildBase::~UDPSocketChildBase() = default; 28 29 void UDPSocketChildBase::ReleaseIPDLReference() { 30 MOZ_ASSERT(mIPCOpen); 31 mIPCOpen = false; 32 mSocket = nullptr; 33 this->Release(); 34 } 35 36 void UDPSocketChildBase::AddIPDLReference() { 37 MOZ_ASSERT(!mIPCOpen); 38 mIPCOpen = true; 39 this->AddRef(); 40 } 41 42 NS_IMETHODIMP_(MozExternalRefCountType) UDPSocketChild::Release(void) { 43 nsrefcnt refcnt = UDPSocketChildBase::Release(); 44 if (refcnt == 1 && mIPCOpen) { 45 PUDPSocketChild::SendRequestDelete(); 46 return 1; 47 } 48 return refcnt; 49 } 50 51 UDPSocketChild::UDPSocketChild() : mBackgroundManager(nullptr), mLocalPort(0) {} 52 53 UDPSocketChild::~UDPSocketChild() = default; 54 55 nsresult UDPSocketChild::SetBackgroundSpinsEvents() { 56 using mozilla::ipc::BackgroundChild; 57 58 mBackgroundManager = BackgroundChild::GetOrCreateForCurrentThread(); 59 if (NS_WARN_IF(!mBackgroundManager)) { 60 return NS_ERROR_FAILURE; 61 } 62 63 return NS_OK; 64 } 65 66 nsresult UDPSocketChild::Bind(nsIUDPSocketInternal* aSocket, 67 nsIPrincipal* aPrincipal, const nsACString& aHost, 68 uint16_t aPort, bool aAddressReuse, 69 bool aLoopback, uint32_t recvBufferSize, 70 uint32_t sendBufferSize) { 71 UDPSOCKET_LOG( 72 ("%s: %s:%u", __FUNCTION__, PromiseFlatCString(aHost).get(), aPort)); 73 74 NS_ENSURE_ARG(aSocket); 75 76 if (NS_IsMainThread()) { 77 if (!gNeckoChild->SendPUDPSocketConstructor(this, aPrincipal, 78 mFilterName)) { 79 return NS_ERROR_FAILURE; 80 } 81 } else { 82 if (!mBackgroundManager) { 83 return NS_ERROR_NOT_AVAILABLE; 84 } 85 86 // If we want to support a passed-in principal here we'd need to 87 // convert it to a PrincipalInfo 88 MOZ_ASSERT(!aPrincipal); 89 if (!mBackgroundManager->SendPUDPSocketConstructor(this, Nothing(), 90 mFilterName)) { 91 return NS_ERROR_FAILURE; 92 } 93 } 94 95 mSocket = aSocket; 96 AddIPDLReference(); 97 98 SendBind(UDPAddressInfo(nsCString(aHost), aPort), aAddressReuse, aLoopback, 99 recvBufferSize, sendBufferSize); 100 return NS_OK; 101 } 102 103 void UDPSocketChild::Connect(nsIUDPSocketInternal* aSocket, 104 const nsACString& aHost, uint16_t aPort) { 105 UDPSOCKET_LOG( 106 ("%s: %s:%u", __FUNCTION__, PromiseFlatCString(aHost).get(), aPort)); 107 108 mSocket = aSocket; 109 110 SendConnect(UDPAddressInfo(nsCString(aHost), aPort)); 111 } 112 113 void UDPSocketChild::Close() { SendClose(); } 114 115 nsresult UDPSocketChild::SendWithAddress(const NetAddr* aAddr, 116 const uint8_t* aData, 117 uint32_t aByteLength) { 118 NS_ENSURE_ARG(aAddr); 119 NS_ENSURE_ARG(aData); 120 121 UDPSOCKET_LOG(("%s: %u bytes", __FUNCTION__, aByteLength)); 122 return SendDataInternal(UDPSocketAddr(*aAddr), aData, aByteLength); 123 } 124 125 nsresult UDPSocketChild::SendDataInternal(const UDPSocketAddr& aAddr, 126 const uint8_t* aData, 127 const uint32_t aByteLength) { 128 NS_ENSURE_ARG(aData); 129 130 FallibleTArray<uint8_t> fallibleArray; 131 if (!fallibleArray.InsertElementsAt(0, aData, aByteLength, fallible)) { 132 return NS_ERROR_OUT_OF_MEMORY; 133 } 134 135 SendOutgoingData(UDPData{std::move(fallibleArray)}, aAddr); 136 137 return NS_OK; 138 } 139 140 nsresult UDPSocketChild::SendBinaryStream(const nsACString& aHost, 141 uint16_t aPort, 142 nsIInputStream* aStream) { 143 NS_ENSURE_ARG(aStream); 144 145 mozilla::ipc::IPCStream stream; 146 if (NS_WARN_IF(!mozilla::ipc::SerializeIPCStream(do_AddRef(aStream), stream, 147 /* aAllowLazy */ false))) { 148 return NS_ERROR_UNEXPECTED; 149 } 150 151 UDPSOCKET_LOG( 152 ("%s: %s:%u", __FUNCTION__, PromiseFlatCString(aHost).get(), aPort)); 153 SendOutgoingData(UDPData(stream), 154 UDPSocketAddr(UDPAddressInfo(nsCString(aHost), aPort))); 155 156 return NS_OK; 157 } 158 159 void UDPSocketChild::JoinMulticast(const nsACString& aMulticastAddress, 160 const nsACString& aInterface) { 161 SendJoinMulticast(aMulticastAddress, aInterface); 162 } 163 164 void UDPSocketChild::LeaveMulticast(const nsACString& aMulticastAddress, 165 const nsACString& aInterface) { 166 SendLeaveMulticast(aMulticastAddress, aInterface); 167 } 168 169 nsresult UDPSocketChild::SetFilterName(const nsACString& aFilterName) { 170 if (!mFilterName.IsEmpty()) { 171 // filter name can only be set once. 172 return NS_ERROR_FAILURE; 173 } 174 mFilterName = aFilterName; 175 return NS_OK; 176 } 177 178 // PUDPSocketChild Methods 179 mozilla::ipc::IPCResult UDPSocketChild::RecvCallbackOpened( 180 const UDPAddressInfo& aAddressInfo) { 181 mLocalAddress = aAddressInfo.addr(); 182 mLocalPort = aAddressInfo.port(); 183 184 UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, mLocalAddress.get(), mLocalPort)); 185 nsresult rv = mSocket->CallListenerOpened(); 186 (void)NS_WARN_IF(NS_FAILED(rv)); 187 188 return IPC_OK(); 189 } 190 191 // PUDPSocketChild Methods 192 mozilla::ipc::IPCResult UDPSocketChild::RecvCallbackConnected( 193 const UDPAddressInfo& aAddressInfo) { 194 mLocalAddress = aAddressInfo.addr(); 195 mLocalPort = aAddressInfo.port(); 196 197 UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, mLocalAddress.get(), mLocalPort)); 198 nsresult rv = mSocket->CallListenerConnected(); 199 (void)NS_WARN_IF(NS_FAILED(rv)); 200 201 return IPC_OK(); 202 } 203 204 mozilla::ipc::IPCResult UDPSocketChild::RecvCallbackClosed() { 205 nsresult rv = mSocket->CallListenerClosed(); 206 (void)NS_WARN_IF(NS_FAILED(rv)); 207 208 return IPC_OK(); 209 } 210 211 mozilla::ipc::IPCResult UDPSocketChild::RecvCallbackReceivedData( 212 const UDPAddressInfo& aAddressInfo, nsTArray<uint8_t>&& aData) { 213 UDPSOCKET_LOG(("%s: %s:%u length %zu", __FUNCTION__, 214 aAddressInfo.addr().get(), aAddressInfo.port(), 215 aData.Length())); 216 nsresult rv = mSocket->CallListenerReceivedData(aAddressInfo.addr(), 217 aAddressInfo.port(), aData); 218 (void)NS_WARN_IF(NS_FAILED(rv)); 219 220 return IPC_OK(); 221 } 222 223 mozilla::ipc::IPCResult UDPSocketChild::RecvCallbackError( 224 const nsCString& aMessage, const nsCString& aFilename, 225 const uint32_t& aLineNumber) { 226 UDPSOCKET_LOG(("%s: %s:%s:%u", __FUNCTION__, aMessage.get(), aFilename.get(), 227 aLineNumber)); 228 nsresult rv = mSocket->CallListenerError(aMessage, aFilename, aLineNumber); 229 (void)NS_WARN_IF(NS_FAILED(rv)); 230 231 return IPC_OK(); 232 } 233 234 } // namespace mozilla::dom