Bumping manifests a=b2g-bump
[gecko.git] / dom / network / UDPSocketParent.cpp
bloba202f183f3b35872c992bc133ace982eda3f1515
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/. */
7 #include "nsIServiceManager.h"
8 #include "UDPSocketParent.h"
9 #include "nsComponentManagerUtils.h"
10 #include "nsIUDPSocket.h"
11 #include "nsINetAddr.h"
12 #include "mozilla/AppProcessChecker.h"
13 #include "mozilla/unused.h"
14 #include "mozilla/ipc/InputStreamUtils.h"
15 #include "mozilla/net/DNS.h"
16 #include "mozilla/net/NeckoCommon.h"
17 #include "mozilla/net/PNeckoParent.h"
19 namespace mozilla {
20 namespace dom {
22 NS_IMPL_ISUPPORTS(UDPSocketParent, nsIUDPSocketListener)
24 UDPSocketParent::~UDPSocketParent()
28 bool
29 UDPSocketParent::Init(const nsACString& aFilter)
31 if (!aFilter.IsEmpty()) {
32 nsAutoCString contractId(NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX);
33 contractId.Append(aFilter);
34 nsCOMPtr<nsIUDPSocketFilterHandler> filterHandler =
35 do_GetService(contractId.get());
36 if (filterHandler) {
37 nsresult rv = filterHandler->NewFilter(getter_AddRefs(mFilter));
38 if (NS_FAILED(rv)) {
39 printf_stderr("Cannot create filter that content specified. "
40 "filter name: %s, error code: %d.", aFilter.BeginReading(), rv);
41 return false;
43 } else {
44 printf_stderr("Content doesn't have a valid filter. "
45 "filter name: %s.", aFilter.BeginReading());
46 return false;
49 return true;
52 // PUDPSocketParent methods
54 bool
55 UDPSocketParent::RecvBind(const UDPAddressInfo& aAddressInfo,
56 const bool& aAddressReuse, const bool& aLoopback)
58 // We don't have browser actors in xpcshell, and hence can't run automated
59 // tests without this loophole.
60 if (net::UsingNeckoIPCSecurity() && !mFilter &&
61 !AssertAppProcessPermission(Manager()->Manager(), "udp-socket")) {
62 FireInternalError(__LINE__);
63 return false;
66 if (NS_FAILED(BindInternal(aAddressInfo.addr(), aAddressInfo.port(), aAddressReuse, aLoopback))) {
67 FireInternalError(__LINE__);
68 return true;
71 nsCOMPtr<nsINetAddr> localAddr;
72 mSocket->GetLocalAddr(getter_AddRefs(localAddr));
74 nsCString addr;
75 if (NS_FAILED(localAddr->GetAddress(addr))) {
76 FireInternalError(__LINE__);
77 return true;
80 uint16_t port;
81 if (NS_FAILED(localAddr->GetPort(&port))) {
82 FireInternalError(__LINE__);
83 return true;
86 mozilla::unused << SendCallbackOpened(UDPAddressInfo(addr, port));
88 return true;
91 nsresult
92 UDPSocketParent::BindInternal(const nsCString& aHost, const uint16_t& aPort,
93 const bool& aAddressReuse, const bool& aLoopback)
95 nsresult rv;
97 nsCOMPtr<nsIUDPSocket> sock =
98 do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
100 if (NS_WARN_IF(NS_FAILED(rv))) {
101 return rv;
104 if (aHost.IsEmpty()) {
105 rv = sock->Init(aPort, false, aAddressReuse, /* optional_argc = */ 1);
106 } else {
107 PRNetAddr prAddr;
108 PR_InitializeNetAddr(PR_IpAddrAny, aPort, &prAddr);
109 PRStatus status = PR_StringToNetAddr(aHost.BeginReading(), &prAddr);
110 if (status != PR_SUCCESS) {
111 return NS_ERROR_FAILURE;
114 mozilla::net::NetAddr addr;
115 PRNetAddrToNetAddr(&prAddr, &addr);
116 rv = sock->InitWithAddress(&addr, aAddressReuse, /* optional_argc = */ 1);
119 if (NS_WARN_IF(NS_FAILED(rv))) {
120 return rv;
123 rv = sock->SetMulticastLoopback(aLoopback);
124 if (NS_WARN_IF(NS_FAILED(rv))) {
125 return rv;
128 // register listener
129 rv = sock->AsyncListen(this);
130 if (NS_WARN_IF(NS_FAILED(rv))) {
131 return rv;
134 mSocket = sock;
136 return NS_OK;
139 bool
140 UDPSocketParent::RecvOutgoingData(const UDPData& aData,
141 const UDPSocketAddr& aAddr)
143 MOZ_ASSERT(mSocket);
145 nsresult rv;
146 if (mFilter) {
147 // TODO, Bug 933102, filter packets that are sent with hostname.
148 // Until then we simply throw away packets that are sent to a hostname.
149 if (aAddr.type() != UDPSocketAddr::TNetAddr) {
150 return true;
153 // TODO, Packet filter doesn't support input stream yet.
154 if (aData.type() != UDPData::TArrayOfuint8_t) {
155 return true;
158 bool allowed;
159 const InfallibleTArray<uint8_t>& data(aData.get_ArrayOfuint8_t());
160 rv = mFilter->FilterPacket(&aAddr.get_NetAddr(), data.Elements(),
161 data.Length(), nsIUDPSocketFilter::SF_OUTGOING,
162 &allowed);
164 // Sending unallowed data, kill content.
165 if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) {
166 return false;
170 switch(aData.type()) {
171 case UDPData::TArrayOfuint8_t:
172 Send(aData.get_ArrayOfuint8_t(), aAddr);
173 break;
174 case UDPData::TInputStreamParams:
175 Send(aData.get_InputStreamParams(), aAddr);
176 break;
177 default:
178 MOZ_ASSERT(false, "Invalid data type!");
179 return true;
182 return true;
185 void
186 UDPSocketParent::Send(const InfallibleTArray<uint8_t>& aData,
187 const UDPSocketAddr& aAddr)
189 nsresult rv;
190 uint32_t count;
191 switch(aAddr.type()) {
192 case UDPSocketAddr::TUDPAddressInfo: {
193 const UDPAddressInfo& addrInfo(aAddr.get_UDPAddressInfo());
194 rv = mSocket->Send(addrInfo.addr(), addrInfo.port(),
195 aData.Elements(), aData.Length(), &count);
196 break;
198 case UDPSocketAddr::TNetAddr: {
199 const NetAddr& addr(aAddr.get_NetAddr());
200 rv = mSocket->SendWithAddress(&addr, aData.Elements(),
201 aData.Length(), &count);
202 break;
204 default:
205 MOZ_ASSERT(false, "Invalid address type!");
206 return;
209 if (NS_WARN_IF(NS_FAILED(rv)) || count == 0) {
210 FireInternalError(__LINE__);
214 void
215 UDPSocketParent::Send(const InputStreamParams& aStream,
216 const UDPSocketAddr& aAddr)
218 nsTArray<mozilla::ipc::FileDescriptor> fds;
219 nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aStream, fds);
221 if (NS_WARN_IF(!stream)) {
222 return;
225 nsresult rv;
226 switch(aAddr.type()) {
227 case UDPSocketAddr::TUDPAddressInfo: {
228 const UDPAddressInfo& addrInfo(aAddr.get_UDPAddressInfo());
229 rv = mSocket->SendBinaryStream(addrInfo.addr(), addrInfo.port(), stream);
230 break;
232 case UDPSocketAddr::TNetAddr: {
233 const NetAddr& addr(aAddr.get_NetAddr());
234 rv = mSocket->SendBinaryStreamWithAddress(&addr, stream);
235 break;
237 default:
238 MOZ_ASSERT(false, "Invalid address type!");
239 return;
242 if (NS_FAILED(rv)) {
243 FireInternalError(__LINE__);
247 bool
248 UDPSocketParent::RecvJoinMulticast(const nsCString& aMulticastAddress,
249 const nsCString& aInterface)
251 nsresult rv = mSocket->JoinMulticast(aMulticastAddress, aInterface);
253 if (NS_WARN_IF(NS_FAILED(rv))) {
254 FireInternalError(__LINE__);
257 return true;
260 bool
261 UDPSocketParent::RecvLeaveMulticast(const nsCString& aMulticastAddress,
262 const nsCString& aInterface)
264 nsresult rv = mSocket->LeaveMulticast(aMulticastAddress, aInterface);
266 if (NS_WARN_IF(NS_FAILED(rv))) {
267 FireInternalError(__LINE__);
270 return true;
273 bool
274 UDPSocketParent::RecvClose()
276 if (!mSocket) {
277 return true;
280 nsresult rv = mSocket->Close();
281 mSocket = nullptr;
283 mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
285 return true;
288 bool
289 UDPSocketParent::RecvRequestDelete()
291 mozilla::unused << Send__delete__(this);
292 return true;
295 void
296 UDPSocketParent::ActorDestroy(ActorDestroyReason why)
298 MOZ_ASSERT(mIPCOpen);
299 mIPCOpen = false;
300 if (mSocket) {
301 mSocket->Close();
303 mSocket = nullptr;
306 // nsIUDPSocketListener
308 NS_IMETHODIMP
309 UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage)
311 // receiving packet from remote host, forward the message content to child process
312 if (!mIPCOpen) {
313 return NS_OK;
316 uint16_t port;
317 nsCString ip;
318 nsCOMPtr<nsINetAddr> fromAddr;
319 aMessage->GetFromAddr(getter_AddRefs(fromAddr));
320 fromAddr->GetPort(&port);
321 fromAddr->GetAddress(ip);
323 nsCString data;
324 aMessage->GetData(data);
326 const char* buffer = data.get();
327 uint32_t len = data.Length();
329 if (mFilter) {
330 bool allowed;
331 mozilla::net::NetAddr addr;
332 fromAddr->GetNetAddr(&addr);
333 nsresult rv = mFilter->FilterPacket(&addr,
334 (const uint8_t*)buffer, len,
335 nsIUDPSocketFilter::SF_INCOMING,
336 &allowed);
337 // Receiving unallowed data, drop.
338 if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) {
339 return NS_OK;
343 FallibleTArray<uint8_t> fallibleArray;
344 if (!fallibleArray.InsertElementsAt(0, buffer, len)) {
345 FireInternalError(__LINE__);
346 return NS_ERROR_OUT_OF_MEMORY;
348 InfallibleTArray<uint8_t> infallibleArray;
349 infallibleArray.SwapElements(fallibleArray);
351 // compose callback
352 mozilla::unused << SendCallbackReceivedData(UDPAddressInfo(ip, port), infallibleArray);
354 return NS_OK;
357 NS_IMETHODIMP
358 UDPSocketParent::OnStopListening(nsIUDPSocket* aSocket, nsresult aStatus)
360 // underlying socket is dead, send state update to child process
361 if (mIPCOpen) {
362 mozilla::unused << SendCallbackClosed();
364 return NS_OK;
367 void
368 UDPSocketParent::FireInternalError(uint32_t aLineNo)
370 if (!mIPCOpen) {
371 return;
374 mozilla::unused << SendCallbackError(NS_LITERAL_CSTRING("Internal error"),
375 NS_LITERAL_CSTRING(__FILE__), aLineNo);
378 } // namespace dom
379 } // namespace mozilla