Bumping manifests a=b2g-bump
[gecko.git] / dom / network / UDPSocketParent.cpp
blob96ce3f97ee9dde48c59920a92a9cada555a18de8
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"
18 #include "nsNetUtil.h"
19 #include "mozilla/dom/ContentParent.h"
20 #include "mozilla/dom/TabParent.h"
22 namespace mozilla {
23 namespace dom {
25 NS_IMPL_ISUPPORTS(UDPSocketParent, nsIUDPSocketListener)
27 UDPSocketParent::UDPSocketParent()
28 : mIPCOpen(true)
30 mObserver = new mozilla::net::OfflineObserver(this);
33 UDPSocketParent::~UDPSocketParent()
35 if (mObserver) {
36 mObserver->RemoveObserver();
40 nsresult
41 UDPSocketParent::OfflineNotification(nsISupports *aSubject)
43 nsCOMPtr<nsIAppOfflineInfo> info(do_QueryInterface(aSubject));
44 if (!info) {
45 return NS_OK;
48 uint32_t targetAppId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
49 info->GetAppId(&targetAppId);
51 // Obtain App ID
52 uint32_t appId = GetAppId();
53 if (appId != targetAppId) {
54 return NS_OK;
57 // If the app is offline, close the socket
58 if (mSocket && NS_IsAppOffline(appId)) {
59 mSocket->Close();
62 return NS_OK;
65 uint32_t
66 UDPSocketParent::GetAppId()
68 uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
69 const PContentParent *content = Manager()->Manager();
70 const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
71 if (browsers.Length() > 0) {
72 TabParent *tab = static_cast<TabParent*>(browsers[0]);
73 appId = tab->OwnAppId();
75 return appId;
78 bool
79 UDPSocketParent::Init(const nsACString& aFilter)
81 if (!aFilter.IsEmpty()) {
82 nsAutoCString contractId(NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX);
83 contractId.Append(aFilter);
84 nsCOMPtr<nsIUDPSocketFilterHandler> filterHandler =
85 do_GetService(contractId.get());
86 if (filterHandler) {
87 nsresult rv = filterHandler->NewFilter(getter_AddRefs(mFilter));
88 if (NS_FAILED(rv)) {
89 printf_stderr("Cannot create filter that content specified. "
90 "filter name: %s, error code: %u.", aFilter.BeginReading(), static_cast<uint32_t>(rv));
91 return false;
93 } else {
94 printf_stderr("Content doesn't have a valid filter. "
95 "filter name: %s.", aFilter.BeginReading());
96 return false;
99 return true;
102 // PUDPSocketParent methods
104 bool
105 UDPSocketParent::RecvBind(const UDPAddressInfo& aAddressInfo,
106 const bool& aAddressReuse, const bool& aLoopback)
108 // We don't have browser actors in xpcshell, and hence can't run automated
109 // tests without this loophole.
110 if (net::UsingNeckoIPCSecurity() && !mFilter &&
111 !AssertAppProcessPermission(Manager()->Manager(), "udp-socket")) {
112 FireInternalError(__LINE__);
113 return false;
116 if (NS_FAILED(BindInternal(aAddressInfo.addr(), aAddressInfo.port(), aAddressReuse, aLoopback))) {
117 FireInternalError(__LINE__);
118 return true;
121 nsCOMPtr<nsINetAddr> localAddr;
122 mSocket->GetLocalAddr(getter_AddRefs(localAddr));
124 nsCString addr;
125 if (NS_FAILED(localAddr->GetAddress(addr))) {
126 FireInternalError(__LINE__);
127 return true;
130 uint16_t port;
131 if (NS_FAILED(localAddr->GetPort(&port))) {
132 FireInternalError(__LINE__);
133 return true;
136 mozilla::unused << SendCallbackOpened(UDPAddressInfo(addr, port));
138 return true;
141 nsresult
142 UDPSocketParent::BindInternal(const nsCString& aHost, const uint16_t& aPort,
143 const bool& aAddressReuse, const bool& aLoopback)
145 nsresult rv;
147 nsCOMPtr<nsIUDPSocket> sock =
148 do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
150 if (NS_WARN_IF(NS_FAILED(rv))) {
151 return rv;
154 if (aHost.IsEmpty()) {
155 rv = sock->Init(aPort, false, aAddressReuse, /* optional_argc = */ 1);
156 } else {
157 PRNetAddr prAddr;
158 PR_InitializeNetAddr(PR_IpAddrAny, aPort, &prAddr);
159 PRStatus status = PR_StringToNetAddr(aHost.BeginReading(), &prAddr);
160 if (status != PR_SUCCESS) {
161 return NS_ERROR_FAILURE;
164 mozilla::net::NetAddr addr;
165 PRNetAddrToNetAddr(&prAddr, &addr);
166 rv = sock->InitWithAddress(&addr, aAddressReuse, /* optional_argc = */ 1);
169 if (NS_WARN_IF(NS_FAILED(rv))) {
170 return rv;
173 rv = sock->SetMulticastLoopback(aLoopback);
174 if (NS_WARN_IF(NS_FAILED(rv))) {
175 return rv;
178 // register listener
179 rv = sock->AsyncListen(this);
180 if (NS_WARN_IF(NS_FAILED(rv))) {
181 return rv;
184 mSocket = sock;
186 return NS_OK;
189 bool
190 UDPSocketParent::RecvOutgoingData(const UDPData& aData,
191 const UDPSocketAddr& aAddr)
193 MOZ_ASSERT(mSocket);
195 nsresult rv;
196 if (mFilter) {
197 // TODO, Bug 933102, filter packets that are sent with hostname.
198 // Until then we simply throw away packets that are sent to a hostname.
199 if (aAddr.type() != UDPSocketAddr::TNetAddr) {
200 return true;
203 // TODO, Packet filter doesn't support input stream yet.
204 if (aData.type() != UDPData::TArrayOfuint8_t) {
205 return true;
208 bool allowed;
209 const InfallibleTArray<uint8_t>& data(aData.get_ArrayOfuint8_t());
210 rv = mFilter->FilterPacket(&aAddr.get_NetAddr(), data.Elements(),
211 data.Length(), nsIUDPSocketFilter::SF_OUTGOING,
212 &allowed);
214 // Sending unallowed data, kill content.
215 if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) {
216 return false;
220 switch(aData.type()) {
221 case UDPData::TArrayOfuint8_t:
222 Send(aData.get_ArrayOfuint8_t(), aAddr);
223 break;
224 case UDPData::TInputStreamParams:
225 Send(aData.get_InputStreamParams(), aAddr);
226 break;
227 default:
228 MOZ_ASSERT(false, "Invalid data type!");
229 return true;
232 return true;
235 void
236 UDPSocketParent::Send(const InfallibleTArray<uint8_t>& aData,
237 const UDPSocketAddr& aAddr)
239 nsresult rv;
240 uint32_t count;
241 switch(aAddr.type()) {
242 case UDPSocketAddr::TUDPAddressInfo: {
243 const UDPAddressInfo& addrInfo(aAddr.get_UDPAddressInfo());
244 rv = mSocket->Send(addrInfo.addr(), addrInfo.port(),
245 aData.Elements(), aData.Length(), &count);
246 break;
248 case UDPSocketAddr::TNetAddr: {
249 const NetAddr& addr(aAddr.get_NetAddr());
250 rv = mSocket->SendWithAddress(&addr, aData.Elements(),
251 aData.Length(), &count);
252 break;
254 default:
255 MOZ_ASSERT(false, "Invalid address type!");
256 return;
259 if (NS_WARN_IF(NS_FAILED(rv)) || count == 0) {
260 FireInternalError(__LINE__);
264 void
265 UDPSocketParent::Send(const InputStreamParams& aStream,
266 const UDPSocketAddr& aAddr)
268 nsTArray<mozilla::ipc::FileDescriptor> fds;
269 nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aStream, fds);
271 if (NS_WARN_IF(!stream)) {
272 return;
275 nsresult rv;
276 switch(aAddr.type()) {
277 case UDPSocketAddr::TUDPAddressInfo: {
278 const UDPAddressInfo& addrInfo(aAddr.get_UDPAddressInfo());
279 rv = mSocket->SendBinaryStream(addrInfo.addr(), addrInfo.port(), stream);
280 break;
282 case UDPSocketAddr::TNetAddr: {
283 const NetAddr& addr(aAddr.get_NetAddr());
284 rv = mSocket->SendBinaryStreamWithAddress(&addr, stream);
285 break;
287 default:
288 MOZ_ASSERT(false, "Invalid address type!");
289 return;
292 if (NS_FAILED(rv)) {
293 FireInternalError(__LINE__);
297 bool
298 UDPSocketParent::RecvJoinMulticast(const nsCString& aMulticastAddress,
299 const nsCString& aInterface)
301 nsresult rv = mSocket->JoinMulticast(aMulticastAddress, aInterface);
303 if (NS_WARN_IF(NS_FAILED(rv))) {
304 FireInternalError(__LINE__);
307 return true;
310 bool
311 UDPSocketParent::RecvLeaveMulticast(const nsCString& aMulticastAddress,
312 const nsCString& aInterface)
314 nsresult rv = mSocket->LeaveMulticast(aMulticastAddress, aInterface);
316 if (NS_WARN_IF(NS_FAILED(rv))) {
317 FireInternalError(__LINE__);
320 return true;
323 bool
324 UDPSocketParent::RecvClose()
326 if (!mSocket) {
327 return true;
330 nsresult rv = mSocket->Close();
331 mSocket = nullptr;
333 mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
335 return true;
338 bool
339 UDPSocketParent::RecvRequestDelete()
341 mozilla::unused << Send__delete__(this);
342 return true;
345 void
346 UDPSocketParent::ActorDestroy(ActorDestroyReason why)
348 MOZ_ASSERT(mIPCOpen);
349 mIPCOpen = false;
350 if (mSocket) {
351 mSocket->Close();
353 mSocket = nullptr;
356 // nsIUDPSocketListener
358 NS_IMETHODIMP
359 UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage)
361 // receiving packet from remote host, forward the message content to child process
362 if (!mIPCOpen) {
363 return NS_OK;
366 uint16_t port;
367 nsCString ip;
368 nsCOMPtr<nsINetAddr> fromAddr;
369 aMessage->GetFromAddr(getter_AddRefs(fromAddr));
370 fromAddr->GetPort(&port);
371 fromAddr->GetAddress(ip);
373 nsCString data;
374 aMessage->GetData(data);
376 const char* buffer = data.get();
377 uint32_t len = data.Length();
379 if (mFilter) {
380 bool allowed;
381 mozilla::net::NetAddr addr;
382 fromAddr->GetNetAddr(&addr);
383 nsresult rv = mFilter->FilterPacket(&addr,
384 (const uint8_t*)buffer, len,
385 nsIUDPSocketFilter::SF_INCOMING,
386 &allowed);
387 // Receiving unallowed data, drop.
388 if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) {
389 return NS_OK;
393 FallibleTArray<uint8_t> fallibleArray;
394 if (!fallibleArray.InsertElementsAt(0, buffer, len)) {
395 FireInternalError(__LINE__);
396 return NS_ERROR_OUT_OF_MEMORY;
398 InfallibleTArray<uint8_t> infallibleArray;
399 infallibleArray.SwapElements(fallibleArray);
401 // compose callback
402 mozilla::unused << SendCallbackReceivedData(UDPAddressInfo(ip, port), infallibleArray);
404 return NS_OK;
407 NS_IMETHODIMP
408 UDPSocketParent::OnStopListening(nsIUDPSocket* aSocket, nsresult aStatus)
410 // underlying socket is dead, send state update to child process
411 if (mIPCOpen) {
412 mozilla::unused << SendCallbackClosed();
414 return NS_OK;
417 void
418 UDPSocketParent::FireInternalError(uint32_t aLineNo)
420 if (!mIPCOpen) {
421 return;
424 mozilla::unused << SendCallbackError(NS_LITERAL_CSTRING("Internal error"),
425 NS_LITERAL_CSTRING(__FILE__), aLineNo);
428 } // namespace dom
429 } // namespace mozilla