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"
22 NS_IMPL_ISUPPORTS(UDPSocketParent
, nsIUDPSocketListener
)
24 UDPSocketParent::~UDPSocketParent()
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());
37 nsresult rv
= filterHandler
->NewFilter(getter_AddRefs(mFilter
));
39 printf_stderr("Cannot create filter that content specified. "
40 "filter name: %s, error code: %d.", aFilter
.BeginReading(), rv
);
44 printf_stderr("Content doesn't have a valid filter. "
45 "filter name: %s.", aFilter
.BeginReading());
52 // PUDPSocketParent methods
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__
);
66 if (NS_FAILED(BindInternal(aAddressInfo
.addr(), aAddressInfo
.port(), aAddressReuse
, aLoopback
))) {
67 FireInternalError(__LINE__
);
71 nsCOMPtr
<nsINetAddr
> localAddr
;
72 mSocket
->GetLocalAddr(getter_AddRefs(localAddr
));
75 if (NS_FAILED(localAddr
->GetAddress(addr
))) {
76 FireInternalError(__LINE__
);
81 if (NS_FAILED(localAddr
->GetPort(&port
))) {
82 FireInternalError(__LINE__
);
86 mozilla::unused
<< SendCallbackOpened(UDPAddressInfo(addr
, port
));
92 UDPSocketParent::BindInternal(const nsCString
& aHost
, const uint16_t& aPort
,
93 const bool& aAddressReuse
, const bool& aLoopback
)
97 nsCOMPtr
<nsIUDPSocket
> sock
=
98 do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv
);
100 if (NS_WARN_IF(NS_FAILED(rv
))) {
104 if (aHost
.IsEmpty()) {
105 rv
= sock
->Init(aPort
, false, aAddressReuse
, /* optional_argc = */ 1);
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
))) {
123 rv
= sock
->SetMulticastLoopback(aLoopback
);
124 if (NS_WARN_IF(NS_FAILED(rv
))) {
129 rv
= sock
->AsyncListen(this);
130 if (NS_WARN_IF(NS_FAILED(rv
))) {
140 UDPSocketParent::RecvOutgoingData(const UDPData
& aData
,
141 const UDPSocketAddr
& aAddr
)
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
) {
153 // TODO, Packet filter doesn't support input stream yet.
154 if (aData
.type() != UDPData::TArrayOfuint8_t
) {
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
,
164 // Sending unallowed data, kill content.
165 if (NS_WARN_IF(NS_FAILED(rv
)) || !allowed
) {
170 switch(aData
.type()) {
171 case UDPData::TArrayOfuint8_t
:
172 Send(aData
.get_ArrayOfuint8_t(), aAddr
);
174 case UDPData::TInputStreamParams
:
175 Send(aData
.get_InputStreamParams(), aAddr
);
178 MOZ_ASSERT(false, "Invalid data type!");
186 UDPSocketParent::Send(const InfallibleTArray
<uint8_t>& aData
,
187 const UDPSocketAddr
& aAddr
)
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
);
198 case UDPSocketAddr::TNetAddr
: {
199 const NetAddr
& addr(aAddr
.get_NetAddr());
200 rv
= mSocket
->SendWithAddress(&addr
, aData
.Elements(),
201 aData
.Length(), &count
);
205 MOZ_ASSERT(false, "Invalid address type!");
209 if (NS_WARN_IF(NS_FAILED(rv
)) || count
== 0) {
210 FireInternalError(__LINE__
);
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
)) {
226 switch(aAddr
.type()) {
227 case UDPSocketAddr::TUDPAddressInfo
: {
228 const UDPAddressInfo
& addrInfo(aAddr
.get_UDPAddressInfo());
229 rv
= mSocket
->SendBinaryStream(addrInfo
.addr(), addrInfo
.port(), stream
);
232 case UDPSocketAddr::TNetAddr
: {
233 const NetAddr
& addr(aAddr
.get_NetAddr());
234 rv
= mSocket
->SendBinaryStreamWithAddress(&addr
, stream
);
238 MOZ_ASSERT(false, "Invalid address type!");
243 FireInternalError(__LINE__
);
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__
);
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__
);
274 UDPSocketParent::RecvClose()
280 nsresult rv
= mSocket
->Close();
283 mozilla::unused
<< NS_WARN_IF(NS_FAILED(rv
));
289 UDPSocketParent::RecvRequestDelete()
291 mozilla::unused
<< Send__delete__(this);
296 UDPSocketParent::ActorDestroy(ActorDestroyReason why
)
298 MOZ_ASSERT(mIPCOpen
);
306 // nsIUDPSocketListener
309 UDPSocketParent::OnPacketReceived(nsIUDPSocket
* aSocket
, nsIUDPMessage
* aMessage
)
311 // receiving packet from remote host, forward the message content to child process
318 nsCOMPtr
<nsINetAddr
> fromAddr
;
319 aMessage
->GetFromAddr(getter_AddRefs(fromAddr
));
320 fromAddr
->GetPort(&port
);
321 fromAddr
->GetAddress(ip
);
324 aMessage
->GetData(data
);
326 const char* buffer
= data
.get();
327 uint32_t len
= data
.Length();
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
,
337 // Receiving unallowed data, drop.
338 if (NS_WARN_IF(NS_FAILED(rv
)) || !allowed
) {
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
);
352 mozilla::unused
<< SendCallbackReceivedData(UDPAddressInfo(ip
, port
), infallibleArray
);
358 UDPSocketParent::OnStopListening(nsIUDPSocket
* aSocket
, nsresult aStatus
)
360 // underlying socket is dead, send state update to child process
362 mozilla::unused
<< SendCallbackClosed();
368 UDPSocketParent::FireInternalError(uint32_t aLineNo
)
374 mozilla::unused
<< SendCallbackError(NS_LITERAL_CSTRING("Internal error"),
375 NS_LITERAL_CSTRING(__FILE__
), aLineNo
);
379 } // namespace mozilla