Line data Source code
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 "nsIServiceManager.h"
8 : #include "UDPSocketParent.h"
9 : #include "nsComponentManagerUtils.h"
10 : #include "nsIUDPSocket.h"
11 : #include "nsINetAddr.h"
12 : #include "mozilla/Unused.h"
13 : #include "mozilla/ipc/InputStreamUtils.h"
14 : #include "mozilla/net/DNS.h"
15 : #include "mozilla/net/NeckoCommon.h"
16 : #include "mozilla/net/PNeckoParent.h"
17 : #include "nsIPermissionManager.h"
18 : #include "nsIScriptSecurityManager.h"
19 : #include "mozilla/ipc/PBackgroundParent.h"
20 : #include "mtransport/runnable_utils.h"
21 :
22 : namespace mozilla {
23 : namespace dom {
24 :
25 0 : NS_IMPL_ISUPPORTS(UDPSocketParent, nsIUDPSocketListener)
26 :
27 0 : UDPSocketParent::UDPSocketParent(PBackgroundParent* aManager)
28 : : mBackgroundManager(aManager)
29 0 : , mIPCOpen(true)
30 : {
31 0 : }
32 :
33 0 : UDPSocketParent::UDPSocketParent(PNeckoParent* aManager)
34 : : mBackgroundManager(nullptr)
35 0 : , mIPCOpen(true)
36 : {
37 0 : }
38 :
39 0 : UDPSocketParent::~UDPSocketParent()
40 : {
41 0 : }
42 :
43 : bool
44 0 : UDPSocketParent::Init(const IPC::Principal& aPrincipal,
45 : const nsACString& aFilter)
46 : {
47 0 : MOZ_ASSERT_IF(mBackgroundManager, !aPrincipal);
48 : // will be used once we move all UDPSocket to PBackground, or
49 : // if we add in Principal checking for mtransport
50 0 : Unused << mBackgroundManager;
51 :
52 0 : mPrincipal = aPrincipal;
53 0 : if (net::UsingNeckoIPCSecurity() &&
54 0 : mPrincipal &&
55 0 : !ContentParent::IgnoreIPCPrincipal()) {
56 : nsCOMPtr<nsIPermissionManager> permMgr =
57 0 : services::GetPermissionManager();
58 0 : if (!permMgr) {
59 0 : NS_WARNING("No PermissionManager available!");
60 0 : return false;
61 : }
62 :
63 0 : uint32_t permission = nsIPermissionManager::DENY_ACTION;
64 0 : permMgr->TestExactPermissionFromPrincipal(mPrincipal, "udp-socket",
65 0 : &permission);
66 0 : if (permission != nsIPermissionManager::ALLOW_ACTION) {
67 0 : return false;
68 : }
69 : }
70 :
71 0 : if (!aFilter.IsEmpty()) {
72 0 : nsAutoCString contractId(NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX);
73 0 : contractId.Append(aFilter);
74 : nsCOMPtr<nsISocketFilterHandler> filterHandler =
75 0 : do_GetService(contractId.get());
76 0 : if (filterHandler) {
77 0 : nsresult rv = filterHandler->NewFilter(getter_AddRefs(mFilter));
78 0 : if (NS_FAILED(rv)) {
79 0 : printf_stderr("Cannot create filter that content specified. "
80 0 : "filter name: %s, error code: %u.", aFilter.BeginReading(), static_cast<uint32_t>(rv));
81 0 : return false;
82 : }
83 : } else {
84 0 : printf_stderr("Content doesn't have a valid filter. "
85 0 : "filter name: %s.", aFilter.BeginReading());
86 0 : return false;
87 : }
88 : }
89 : // We don't have browser actors in xpcshell, and hence can't run automated
90 : // tests without this loophole.
91 0 : if (net::UsingNeckoIPCSecurity() && !mFilter &&
92 0 : (!mPrincipal || ContentParent::IgnoreIPCPrincipal())) {
93 0 : return false;
94 : }
95 0 : return true;
96 : }
97 :
98 : // PUDPSocketParent methods
99 :
100 : mozilla::ipc::IPCResult
101 0 : UDPSocketParent::RecvBind(const UDPAddressInfo& aAddressInfo,
102 : const bool& aAddressReuse, const bool& aLoopback,
103 : const uint32_t& recvBufferSize,
104 : const uint32_t& sendBufferSize)
105 : {
106 0 : UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, aAddressInfo.addr().get(), aAddressInfo.port()));
107 :
108 0 : if (NS_FAILED(BindInternal(aAddressInfo.addr(), aAddressInfo.port(),
109 : aAddressReuse, aLoopback, recvBufferSize,
110 : sendBufferSize))) {
111 0 : FireInternalError(__LINE__);
112 0 : return IPC_OK();
113 : }
114 :
115 0 : nsCOMPtr<nsINetAddr> localAddr;
116 0 : mSocket->GetLocalAddr(getter_AddRefs(localAddr));
117 :
118 0 : nsCString addr;
119 0 : if (NS_FAILED(localAddr->GetAddress(addr))) {
120 0 : FireInternalError(__LINE__);
121 0 : return IPC_OK();
122 : }
123 :
124 : uint16_t port;
125 0 : if (NS_FAILED(localAddr->GetPort(&port))) {
126 0 : FireInternalError(__LINE__);
127 0 : return IPC_OK();
128 : }
129 :
130 0 : UDPSOCKET_LOG(("%s: SendCallbackOpened: %s:%u", __FUNCTION__, addr.get(), port));
131 0 : mozilla::Unused << SendCallbackOpened(UDPAddressInfo(addr, port));
132 :
133 0 : return IPC_OK();
134 : }
135 :
136 : nsresult
137 0 : UDPSocketParent::BindInternal(const nsCString& aHost, const uint16_t& aPort,
138 : const bool& aAddressReuse, const bool& aLoopback,
139 : const uint32_t& recvBufferSize,
140 : const uint32_t& sendBufferSize)
141 : {
142 : nsresult rv;
143 :
144 0 : UDPSOCKET_LOG(("%s: [this=%p] %s:%u addressReuse: %d loopback: %d recvBufferSize: %"
145 : PRIu32 ", sendBufferSize: %" PRIu32,
146 : __FUNCTION__, this, nsCString(aHost).get(), aPort,
147 : aAddressReuse, aLoopback, recvBufferSize, sendBufferSize));
148 :
149 : nsCOMPtr<nsIUDPSocket> sock =
150 0 : do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
151 :
152 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
153 0 : return rv;
154 : }
155 :
156 0 : if (aHost.IsEmpty()) {
157 0 : rv = sock->Init(aPort, false, mPrincipal, aAddressReuse,
158 0 : /* optional_argc = */ 1);
159 : } else {
160 : PRNetAddr prAddr;
161 0 : PR_InitializeNetAddr(PR_IpAddrAny, aPort, &prAddr);
162 0 : PRStatus status = PR_StringToNetAddr(aHost.BeginReading(), &prAddr);
163 0 : if (status != PR_SUCCESS) {
164 0 : return NS_ERROR_FAILURE;
165 : }
166 :
167 : mozilla::net::NetAddr addr;
168 0 : PRNetAddrToNetAddr(&prAddr, &addr);
169 0 : rv = sock->InitWithAddress(&addr, mPrincipal, aAddressReuse,
170 0 : /* optional_argc = */ 1);
171 : }
172 :
173 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
174 0 : return rv;
175 : }
176 :
177 0 : nsCOMPtr<nsINetAddr> laddr;
178 0 : rv = sock->GetLocalAddr(getter_AddRefs(laddr));
179 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
180 0 : return rv;
181 : }
182 : uint16_t family;
183 0 : rv = laddr->GetFamily(&family);
184 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
185 0 : return rv;
186 : }
187 0 : if (family == nsINetAddr::FAMILY_INET) {
188 0 : rv = sock->SetMulticastLoopback(aLoopback);
189 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
190 0 : return rv;
191 : }
192 : }
193 : // TODO: once bug 1252759 is fixed query buffer first and only increase
194 0 : if (recvBufferSize != 0) {
195 0 : rv = sock->SetRecvBufferSize(recvBufferSize);
196 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
197 0 : UDPSOCKET_LOG(("%s: [this=%p] %s:%u failed to set recv buffer size to: %" PRIu32, __FUNCTION__, this, nsCString(aHost).get(), aPort, recvBufferSize));
198 : }
199 : }
200 0 : if (sendBufferSize != 0) {
201 0 : rv = sock->SetSendBufferSize(sendBufferSize);
202 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
203 0 : UDPSOCKET_LOG(("%s: [this=%p] %s:%u failed to set send buffer size to: %" PRIu32, __FUNCTION__, this, nsCString(aHost).get(), aPort, sendBufferSize));
204 : }
205 : }
206 :
207 : // register listener
208 0 : rv = sock->AsyncListen(this);
209 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
210 0 : return rv;
211 : }
212 :
213 0 : mSocket = sock;
214 :
215 0 : return NS_OK;
216 : }
217 :
218 :
219 0 : static nsCOMPtr<nsIEventTarget> GetSTSThread()
220 : {
221 : nsresult rv;
222 :
223 0 : nsCOMPtr<nsIEventTarget> sts_thread;
224 :
225 0 : sts_thread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
226 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
227 :
228 0 : return sts_thread;
229 : }
230 :
231 0 : static void CheckSTSThread()
232 : {
233 0 : DebugOnly<nsCOMPtr<nsIEventTarget>> sts_thread = GetSTSThread();
234 :
235 0 : ASSERT_ON_THREAD(sts_thread.value);
236 0 : }
237 :
238 :
239 : // Proxy the Connect() request to the STS thread, since it may block and
240 : // should be done there.
241 : mozilla::ipc::IPCResult
242 0 : UDPSocketParent::RecvConnect(const UDPAddressInfo& aAddressInfo)
243 : {
244 0 : nsCOMPtr<nsIEventTarget> target = GetCurrentThreadEventTarget();
245 : Unused <<
246 0 : NS_WARN_IF(NS_FAILED(GetSTSThread()->Dispatch(WrapRunnable(
247 : RefPtr<UDPSocketParent>(this),
248 : &UDPSocketParent::DoConnect,
249 : mSocket,
250 : target,
251 : aAddressInfo),
252 : NS_DISPATCH_NORMAL)));
253 0 : return IPC_OK();
254 : }
255 :
256 : void
257 0 : UDPSocketParent::DoSendConnectResponse(const UDPAddressInfo& aAddressInfo)
258 : {
259 : // can't use directly with WrapRunnable due to warnings
260 0 : mozilla::Unused << SendCallbackConnected(aAddressInfo);
261 0 : }
262 :
263 : void
264 0 : UDPSocketParent::SendConnectResponse(nsIEventTarget *aThread,
265 : const UDPAddressInfo& aAddressInfo)
266 : {
267 : Unused <<
268 0 : NS_WARN_IF(NS_FAILED(aThread->Dispatch(WrapRunnable(
269 : RefPtr<UDPSocketParent>(this),
270 : &UDPSocketParent::DoSendConnectResponse,
271 : aAddressInfo),
272 : NS_DISPATCH_NORMAL)));
273 0 : }
274 :
275 : // Runs on STS thread
276 : void
277 0 : UDPSocketParent::DoConnect(nsCOMPtr<nsIUDPSocket>& aSocket,
278 : nsCOMPtr<nsIEventTarget>& aReturnThread,
279 : const UDPAddressInfo& aAddressInfo)
280 : {
281 0 : UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, aAddressInfo.addr().get(), aAddressInfo.port()));
282 0 : if (NS_FAILED(ConnectInternal(aAddressInfo.addr(), aAddressInfo.port()))) {
283 0 : SendInternalError(aReturnThread, __LINE__);
284 0 : return;
285 : }
286 0 : CheckSTSThread();
287 :
288 0 : nsCOMPtr<nsINetAddr> localAddr;
289 0 : aSocket->GetLocalAddr(getter_AddRefs(localAddr));
290 :
291 0 : nsCString addr;
292 0 : if (NS_FAILED(localAddr->GetAddress(addr))) {
293 0 : SendInternalError(aReturnThread, __LINE__);
294 0 : return;
295 : }
296 :
297 : uint16_t port;
298 0 : if (NS_FAILED(localAddr->GetPort(&port))) {
299 0 : SendInternalError(aReturnThread, __LINE__);
300 0 : return;
301 : }
302 :
303 0 : UDPSOCKET_LOG(("%s: SendConnectResponse: %s:%u", __FUNCTION__, addr.get(), port));
304 0 : SendConnectResponse(aReturnThread, UDPAddressInfo(addr, port));
305 : }
306 :
307 : nsresult
308 0 : UDPSocketParent::ConnectInternal(const nsCString& aHost, const uint16_t& aPort)
309 : {
310 : nsresult rv;
311 :
312 0 : UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, nsCString(aHost).get(), aPort));
313 :
314 0 : if (!mSocket) {
315 0 : return NS_ERROR_NOT_AVAILABLE;
316 : }
317 :
318 : PRNetAddr prAddr;
319 0 : memset(&prAddr, 0, sizeof(prAddr));
320 0 : PR_InitializeNetAddr(PR_IpAddrAny, aPort, &prAddr);
321 0 : PRStatus status = PR_StringToNetAddr(aHost.BeginReading(), &prAddr);
322 0 : if (status != PR_SUCCESS) {
323 0 : return NS_ERROR_FAILURE;
324 : }
325 :
326 : mozilla::net::NetAddr addr;
327 0 : PRNetAddrToNetAddr(&prAddr, &addr);
328 :
329 0 : rv = mSocket->Connect(&addr);
330 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
331 0 : return rv;
332 : }
333 :
334 0 : return NS_OK;
335 : }
336 :
337 : mozilla::ipc::IPCResult
338 0 : UDPSocketParent::RecvOutgoingData(const UDPData& aData,
339 : const UDPSocketAddr& aAddr)
340 : {
341 0 : if (!mSocket) {
342 0 : NS_WARNING("sending socket is closed");
343 0 : FireInternalError(__LINE__);
344 0 : return IPC_OK();
345 : }
346 :
347 : nsresult rv;
348 0 : if (mFilter) {
349 0 : if (aAddr.type() != UDPSocketAddr::TNetAddr) {
350 0 : return IPC_OK();
351 : }
352 :
353 : // TODO, Packet filter doesn't support input stream yet.
354 0 : if (aData.type() != UDPData::TArrayOfuint8_t) {
355 0 : return IPC_OK();
356 : }
357 :
358 : bool allowed;
359 0 : const InfallibleTArray<uint8_t>& data(aData.get_ArrayOfuint8_t());
360 0 : rv = mFilter->FilterPacket(&aAddr.get_NetAddr(), data.Elements(),
361 0 : data.Length(), nsISocketFilter::SF_OUTGOING,
362 0 : &allowed);
363 :
364 : // Sending unallowed data, kill content.
365 0 : if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) {
366 0 : return IPC_FAIL(this, "Content tried to send non STUN packet");
367 : }
368 : }
369 :
370 0 : switch(aData.type()) {
371 : case UDPData::TArrayOfuint8_t:
372 0 : Send(aData.get_ArrayOfuint8_t(), aAddr);
373 0 : break;
374 : case UDPData::TIPCStream:
375 0 : Send(aData.get_IPCStream(), aAddr);
376 0 : break;
377 : default:
378 0 : MOZ_ASSERT(false, "Invalid data type!");
379 : return IPC_OK();
380 : }
381 :
382 0 : return IPC_OK();
383 : }
384 :
385 : void
386 0 : UDPSocketParent::Send(const InfallibleTArray<uint8_t>& aData,
387 : const UDPSocketAddr& aAddr)
388 : {
389 : nsresult rv;
390 : uint32_t count;
391 0 : switch(aAddr.type()) {
392 : case UDPSocketAddr::TUDPAddressInfo: {
393 0 : const UDPAddressInfo& addrInfo(aAddr.get_UDPAddressInfo());
394 0 : rv = mSocket->Send(addrInfo.addr(), addrInfo.port(),
395 0 : aData.Elements(), aData.Length(), &count);
396 0 : break;
397 : }
398 : case UDPSocketAddr::TNetAddr: {
399 0 : const NetAddr& addr(aAddr.get_NetAddr());
400 0 : rv = mSocket->SendWithAddress(&addr, aData.Elements(),
401 0 : aData.Length(), &count);
402 0 : break;
403 : }
404 : default:
405 0 : MOZ_ASSERT(false, "Invalid address type!");
406 : return;
407 : }
408 :
409 0 : if (NS_WARN_IF(NS_FAILED(rv)) || count == 0) {
410 0 : FireInternalError(__LINE__);
411 : }
412 0 : }
413 :
414 : void
415 0 : UDPSocketParent::Send(const IPCStream& aStream,
416 : const UDPSocketAddr& aAddr)
417 : {
418 0 : nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aStream);
419 :
420 0 : if (NS_WARN_IF(!stream)) {
421 0 : return;
422 : }
423 :
424 : nsresult rv;
425 0 : switch(aAddr.type()) {
426 : case UDPSocketAddr::TUDPAddressInfo: {
427 0 : const UDPAddressInfo& addrInfo(aAddr.get_UDPAddressInfo());
428 0 : rv = mSocket->SendBinaryStream(addrInfo.addr(), addrInfo.port(), stream);
429 0 : break;
430 : }
431 : case UDPSocketAddr::TNetAddr: {
432 0 : const NetAddr& addr(aAddr.get_NetAddr());
433 0 : rv = mSocket->SendBinaryStreamWithAddress(&addr, stream);
434 0 : break;
435 : }
436 : default:
437 0 : MOZ_ASSERT(false, "Invalid address type!");
438 : return;
439 : }
440 :
441 0 : if (NS_FAILED(rv)) {
442 0 : FireInternalError(__LINE__);
443 : }
444 : }
445 :
446 : mozilla::ipc::IPCResult
447 0 : UDPSocketParent::RecvJoinMulticast(const nsCString& aMulticastAddress,
448 : const nsCString& aInterface)
449 : {
450 0 : nsresult rv = mSocket->JoinMulticast(aMulticastAddress, aInterface);
451 :
452 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
453 0 : FireInternalError(__LINE__);
454 : }
455 :
456 0 : return IPC_OK();
457 : }
458 :
459 : mozilla::ipc::IPCResult
460 0 : UDPSocketParent::RecvLeaveMulticast(const nsCString& aMulticastAddress,
461 : const nsCString& aInterface)
462 : {
463 0 : nsresult rv = mSocket->LeaveMulticast(aMulticastAddress, aInterface);
464 :
465 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
466 0 : FireInternalError(__LINE__);
467 : }
468 :
469 0 : return IPC_OK();
470 : }
471 :
472 : mozilla::ipc::IPCResult
473 0 : UDPSocketParent::RecvClose()
474 : {
475 0 : if (!mSocket) {
476 0 : return IPC_OK();
477 : }
478 :
479 0 : nsresult rv = mSocket->Close();
480 0 : mSocket = nullptr;
481 :
482 0 : mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
483 :
484 0 : return IPC_OK();
485 : }
486 :
487 : mozilla::ipc::IPCResult
488 0 : UDPSocketParent::RecvRequestDelete()
489 : {
490 0 : mozilla::Unused << Send__delete__(this);
491 0 : return IPC_OK();
492 : }
493 :
494 : void
495 0 : UDPSocketParent::ActorDestroy(ActorDestroyReason why)
496 : {
497 0 : MOZ_ASSERT(mIPCOpen);
498 0 : mIPCOpen = false;
499 0 : if (mSocket) {
500 0 : mSocket->Close();
501 : }
502 0 : mSocket = nullptr;
503 0 : }
504 :
505 : // nsIUDPSocketListener
506 :
507 : NS_IMETHODIMP
508 0 : UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage)
509 : {
510 : // receiving packet from remote host, forward the message content to child process
511 0 : if (!mIPCOpen) {
512 0 : return NS_OK;
513 : }
514 :
515 : uint16_t port;
516 0 : nsCString ip;
517 0 : nsCOMPtr<nsINetAddr> fromAddr;
518 0 : aMessage->GetFromAddr(getter_AddRefs(fromAddr));
519 0 : fromAddr->GetPort(&port);
520 0 : fromAddr->GetAddress(ip);
521 :
522 0 : nsCString data;
523 0 : aMessage->GetData(data);
524 :
525 0 : const char* buffer = data.get();
526 0 : uint32_t len = data.Length();
527 0 : UDPSOCKET_LOG(("%s: %s:%u, length %u", __FUNCTION__, ip.get(), port, len));
528 :
529 0 : if (mFilter) {
530 : bool allowed;
531 : mozilla::net::NetAddr addr;
532 0 : fromAddr->GetNetAddr(&addr);
533 0 : nsresult rv = mFilter->FilterPacket(&addr,
534 : (const uint8_t*)buffer, len,
535 : nsISocketFilter::SF_INCOMING,
536 0 : &allowed);
537 : // Receiving unallowed data, drop.
538 0 : if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) {
539 0 : if (!allowed) {
540 0 : UDPSOCKET_LOG(("%s: not allowed", __FUNCTION__));
541 : }
542 0 : return NS_OK;
543 : }
544 : }
545 :
546 0 : FallibleTArray<uint8_t> fallibleArray;
547 0 : if (!fallibleArray.InsertElementsAt(0, buffer, len, fallible)) {
548 0 : FireInternalError(__LINE__);
549 0 : return NS_ERROR_OUT_OF_MEMORY;
550 : }
551 0 : InfallibleTArray<uint8_t> infallibleArray;
552 0 : infallibleArray.SwapElements(fallibleArray);
553 :
554 : // compose callback
555 0 : mozilla::Unused << SendCallbackReceivedData(UDPAddressInfo(ip, port), infallibleArray);
556 :
557 0 : return NS_OK;
558 : }
559 :
560 : NS_IMETHODIMP
561 0 : UDPSocketParent::OnStopListening(nsIUDPSocket* aSocket, nsresult aStatus)
562 : {
563 : // underlying socket is dead, send state update to child process
564 0 : if (mIPCOpen) {
565 0 : mozilla::Unused << SendCallbackClosed();
566 : }
567 0 : return NS_OK;
568 : }
569 :
570 : void
571 0 : UDPSocketParent::FireInternalError(uint32_t aLineNo)
572 : {
573 0 : if (!mIPCOpen) {
574 0 : return;
575 : }
576 :
577 0 : mozilla::Unused << SendCallbackError(NS_LITERAL_CSTRING("Internal error"),
578 0 : NS_LITERAL_CSTRING(__FILE__), aLineNo);
579 : }
580 :
581 : void
582 0 : UDPSocketParent::SendInternalError(nsIEventTarget *aThread,
583 : uint32_t aLineNo)
584 : {
585 0 : UDPSOCKET_LOG(("SendInternalError: %u", aLineNo));
586 : Unused <<
587 0 : NS_WARN_IF(NS_FAILED(aThread->Dispatch(WrapRunnable(
588 : RefPtr<UDPSocketParent>(this),
589 : &UDPSocketParent::FireInternalError,
590 : aLineNo),
591 : NS_DISPATCH_NORMAL)));
592 0 : }
593 :
594 : } // namespace dom
595 : } // namespace mozilla
|