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"
25 NS_IMPL_ISUPPORTS(UDPSocketParent
, nsIUDPSocketListener
)
27 UDPSocketParent::UDPSocketParent()
30 mObserver
= new mozilla::net::OfflineObserver(this);
33 UDPSocketParent::~UDPSocketParent()
36 mObserver
->RemoveObserver();
41 UDPSocketParent::OfflineNotification(nsISupports
*aSubject
)
43 nsCOMPtr
<nsIAppOfflineInfo
> info(do_QueryInterface(aSubject
));
48 uint32_t targetAppId
= nsIScriptSecurityManager::UNKNOWN_APP_ID
;
49 info
->GetAppId(&targetAppId
);
52 uint32_t appId
= GetAppId();
53 if (appId
!= targetAppId
) {
57 // If the app is offline, close the socket
58 if (mSocket
&& NS_IsAppOffline(appId
)) {
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();
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());
87 nsresult rv
= filterHandler
->NewFilter(getter_AddRefs(mFilter
));
89 printf_stderr("Cannot create filter that content specified. "
90 "filter name: %s, error code: %u.", aFilter
.BeginReading(), static_cast<uint32_t>(rv
));
94 printf_stderr("Content doesn't have a valid filter. "
95 "filter name: %s.", aFilter
.BeginReading());
102 // PUDPSocketParent methods
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__
);
116 if (NS_FAILED(BindInternal(aAddressInfo
.addr(), aAddressInfo
.port(), aAddressReuse
, aLoopback
))) {
117 FireInternalError(__LINE__
);
121 nsCOMPtr
<nsINetAddr
> localAddr
;
122 mSocket
->GetLocalAddr(getter_AddRefs(localAddr
));
125 if (NS_FAILED(localAddr
->GetAddress(addr
))) {
126 FireInternalError(__LINE__
);
131 if (NS_FAILED(localAddr
->GetPort(&port
))) {
132 FireInternalError(__LINE__
);
136 mozilla::unused
<< SendCallbackOpened(UDPAddressInfo(addr
, port
));
142 UDPSocketParent::BindInternal(const nsCString
& aHost
, const uint16_t& aPort
,
143 const bool& aAddressReuse
, const bool& aLoopback
)
147 nsCOMPtr
<nsIUDPSocket
> sock
=
148 do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv
);
150 if (NS_WARN_IF(NS_FAILED(rv
))) {
154 if (aHost
.IsEmpty()) {
155 rv
= sock
->Init(aPort
, false, aAddressReuse
, /* optional_argc = */ 1);
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
))) {
173 rv
= sock
->SetMulticastLoopback(aLoopback
);
174 if (NS_WARN_IF(NS_FAILED(rv
))) {
179 rv
= sock
->AsyncListen(this);
180 if (NS_WARN_IF(NS_FAILED(rv
))) {
190 UDPSocketParent::RecvOutgoingData(const UDPData
& aData
,
191 const UDPSocketAddr
& aAddr
)
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
) {
203 // TODO, Packet filter doesn't support input stream yet.
204 if (aData
.type() != UDPData::TArrayOfuint8_t
) {
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
,
214 // Sending unallowed data, kill content.
215 if (NS_WARN_IF(NS_FAILED(rv
)) || !allowed
) {
220 switch(aData
.type()) {
221 case UDPData::TArrayOfuint8_t
:
222 Send(aData
.get_ArrayOfuint8_t(), aAddr
);
224 case UDPData::TInputStreamParams
:
225 Send(aData
.get_InputStreamParams(), aAddr
);
228 MOZ_ASSERT(false, "Invalid data type!");
236 UDPSocketParent::Send(const InfallibleTArray
<uint8_t>& aData
,
237 const UDPSocketAddr
& aAddr
)
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
);
248 case UDPSocketAddr::TNetAddr
: {
249 const NetAddr
& addr(aAddr
.get_NetAddr());
250 rv
= mSocket
->SendWithAddress(&addr
, aData
.Elements(),
251 aData
.Length(), &count
);
255 MOZ_ASSERT(false, "Invalid address type!");
259 if (NS_WARN_IF(NS_FAILED(rv
)) || count
== 0) {
260 FireInternalError(__LINE__
);
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
)) {
276 switch(aAddr
.type()) {
277 case UDPSocketAddr::TUDPAddressInfo
: {
278 const UDPAddressInfo
& addrInfo(aAddr
.get_UDPAddressInfo());
279 rv
= mSocket
->SendBinaryStream(addrInfo
.addr(), addrInfo
.port(), stream
);
282 case UDPSocketAddr::TNetAddr
: {
283 const NetAddr
& addr(aAddr
.get_NetAddr());
284 rv
= mSocket
->SendBinaryStreamWithAddress(&addr
, stream
);
288 MOZ_ASSERT(false, "Invalid address type!");
293 FireInternalError(__LINE__
);
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__
);
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__
);
324 UDPSocketParent::RecvClose()
330 nsresult rv
= mSocket
->Close();
333 mozilla::unused
<< NS_WARN_IF(NS_FAILED(rv
));
339 UDPSocketParent::RecvRequestDelete()
341 mozilla::unused
<< Send__delete__(this);
346 UDPSocketParent::ActorDestroy(ActorDestroyReason why
)
348 MOZ_ASSERT(mIPCOpen
);
356 // nsIUDPSocketListener
359 UDPSocketParent::OnPacketReceived(nsIUDPSocket
* aSocket
, nsIUDPMessage
* aMessage
)
361 // receiving packet from remote host, forward the message content to child process
368 nsCOMPtr
<nsINetAddr
> fromAddr
;
369 aMessage
->GetFromAddr(getter_AddRefs(fromAddr
));
370 fromAddr
->GetPort(&port
);
371 fromAddr
->GetAddress(ip
);
374 aMessage
->GetData(data
);
376 const char* buffer
= data
.get();
377 uint32_t len
= data
.Length();
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
,
387 // Receiving unallowed data, drop.
388 if (NS_WARN_IF(NS_FAILED(rv
)) || !allowed
) {
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
);
402 mozilla::unused
<< SendCallbackReceivedData(UDPAddressInfo(ip
, port
), infallibleArray
);
408 UDPSocketParent::OnStopListening(nsIUDPSocket
* aSocket
, nsresult aStatus
)
410 // underlying socket is dead, send state update to child process
412 mozilla::unused
<< SendCallbackClosed();
418 UDPSocketParent::FireInternalError(uint32_t aLineNo
)
424 mozilla::unused
<< SendCallbackError(NS_LITERAL_CSTRING("Internal error"),
425 NS_LITERAL_CSTRING(__FILE__
), aLineNo
);
429 } // namespace mozilla