Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=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 Modified version of nr_socket_local, adapted for NSPR
8 */
10 /* This Source Code Form is subject to the terms of the Mozilla Public
11 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
12 * You can obtain one at http://mozilla.org/MPL/2.0/. */
14 /*
15 Original code from nICEr and nrappkit.
17 nICEr copyright:
19 Copyright (c) 2007, Adobe Systems, Incorporated
20 All rights reserved.
22 Redistribution and use in source and binary forms, with or without
23 modification, are permitted provided that the following conditions are
24 met:
26 * Redistributions of source code must retain the above copyright
27 notice, this list of conditions and the following disclaimer.
29 * Redistributions in binary form must reproduce the above copyright
30 notice, this list of conditions and the following disclaimer in the
31 documentation and/or other materials provided with the distribution.
33 * Neither the name of Adobe Systems, Network Resonance nor the names of its
34 contributors may be used to endorse or promote products derived from
35 this software without specific prior written permission.
37 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
38 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
39 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
40 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
41 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
45 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50 nrappkit copyright:
52 Copyright (C) 2001-2003, Network Resonance, Inc.
53 Copyright (C) 2006, Network Resonance, Inc.
54 All Rights Reserved
56 Redistribution and use in source and binary forms, with or without
57 modification, are permitted provided that the following conditions
58 are met:
60 1. Redistributions of source code must retain the above copyright
61 notice, this list of conditions and the following disclaimer.
62 2. Redistributions in binary form must reproduce the above copyright
63 notice, this list of conditions and the following disclaimer in the
64 documentation and/or other materials provided with the distribution.
65 3. Neither the name of Network Resonance, Inc. nor the name of any
66 contributors to this software may be used to endorse or promote
67 products derived from this software without specific prior written
68 permission.
70 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
71 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
72 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
73 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
74 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
75 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
76 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
77 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
78 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
79 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
80 POSSIBILITY OF SUCH DAMAGE.
83 ekr@rtfm.com Thu Dec 20 20:14:49 2001
84 */
86 #include <csi_platform.h>
87 #include <stdio.h>
88 #include <string.h>
89 #include <sys/types.h>
90 #include <assert.h>
91 #include <errno.h>
93 #include "nspr.h"
94 #include "prerror.h"
95 #include "prio.h"
96 #include "prnetdb.h"
98 #include "mozilla/net/DNS.h"
99 #include "nsCOMPtr.h"
100 #include "nsASocketHandler.h"
101 #include "nsISocketTransportService.h"
102 #include "nsNetCID.h"
103 #include "nsISupportsImpl.h"
104 #include "nsServiceManagerUtils.h"
105 #include "nsComponentManagerUtils.h"
106 #include "nsXPCOM.h"
107 #include "nsXULAppAPI.h"
108 #include "runnable_utils.h"
110 extern "C" {
111 #include "nr_api.h"
112 #include "async_wait.h"
113 #include "nr_socket.h"
114 #include "nr_socket_local.h"
115 #include "stun_hint.h"
116 }
117 #include "nr_socket_prsock.h"
118 #include "simpletokenbucket.h"
120 // Implement the nsISupports ref counting
121 namespace mozilla {
123 // NrSocketBase implementation
124 // async_event APIs
125 int NrSocketBase::async_wait(int how, NR_async_cb cb, void *cb_arg,
126 char *function, int line) {
127 uint16_t flag;
129 switch (how) {
130 case NR_ASYNC_WAIT_READ:
131 flag = PR_POLL_READ;
132 break;
133 case NR_ASYNC_WAIT_WRITE:
134 flag = PR_POLL_WRITE;
135 break;
136 default:
137 return R_BAD_ARGS;
138 }
140 cbs_[how] = cb;
141 cb_args_[how] = cb_arg;
142 poll_flags_ |= flag;
144 return 0;
145 }
147 int NrSocketBase::cancel(int how) {
148 uint16_t flag;
150 switch (how) {
151 case NR_ASYNC_WAIT_READ:
152 flag = PR_POLL_READ;
153 break;
154 case NR_ASYNC_WAIT_WRITE:
155 flag = PR_POLL_WRITE;
156 break;
157 default:
158 return R_BAD_ARGS;
159 }
161 poll_flags_ &= ~flag;
163 return 0;
164 }
166 void NrSocketBase::fire_callback(int how) {
167 // This can't happen unless we are armed because we only set
168 // the flags if we are armed
169 MOZ_ASSERT(cbs_[how]);
171 // Now cancel so that we need to be re-armed. Note that
172 // the re-arming probably happens in the callback we are
173 // about to fire.
174 cancel(how);
176 cbs_[how](this, how, cb_args_[how]);
177 }
179 // NrSocket implementation
180 NS_IMPL_ISUPPORTS0(NrSocket)
183 // The nsASocket callbacks
184 void NrSocket::OnSocketReady(PRFileDesc *fd, int16_t outflags) {
185 if (outflags & PR_POLL_READ)
186 fire_callback(NR_ASYNC_WAIT_READ);
187 if (outflags & PR_POLL_WRITE)
188 fire_callback(NR_ASYNC_WAIT_WRITE);
189 }
191 void NrSocket::OnSocketDetached(PRFileDesc *fd) {
192 ; // TODO: Log?
193 }
195 void NrSocket::IsLocal(bool *aIsLocal) {
196 // TODO(jesup): better check? Does it matter? (likely no)
197 *aIsLocal = false;
198 }
200 // async_event APIs
201 int NrSocket::async_wait(int how, NR_async_cb cb, void *cb_arg,
202 char *function, int line) {
203 int r = NrSocketBase::async_wait(how, cb, cb_arg, function, line);
205 if (!r) {
206 mPollFlags = poll_flags();
207 }
209 return r;
210 }
212 int NrSocket::cancel(int how) {
213 int r = NrSocketBase::cancel(how);
215 if (!r) {
216 mPollFlags = poll_flags();
217 }
219 return r;
220 }
222 // Helper functions for addresses
223 static int nr_transport_addr_to_praddr(nr_transport_addr *addr,
224 PRNetAddr *naddr)
225 {
226 int _status;
228 memset(naddr, 0, sizeof(*naddr));
230 switch(addr->protocol){
231 case IPPROTO_TCP:
232 break;
233 case IPPROTO_UDP:
234 break;
235 default:
236 ABORT(R_BAD_ARGS);
237 }
239 switch(addr->ip_version){
240 case NR_IPV4:
241 naddr->inet.family = PR_AF_INET;
242 naddr->inet.port = addr->u.addr4.sin_port;
243 naddr->inet.ip = addr->u.addr4.sin_addr.s_addr;
244 break;
245 case NR_IPV6:
246 #if 0
247 naddr->ipv6.family = PR_AF_INET6;
248 naddr->ipv6.port = addr->u.addr6.sin6_port;
249 #ifdef LINUX
250 memcpy(naddr->ipv6.ip._S6_un._S6_u8,
251 &addr->u.addr6.sin6_addr.__in6_u.__u6_addr8, 16);
252 #else
253 memcpy(naddr->ipv6.ip._S6_un._S6_u8,
254 &addr->u.addr6.sin6_addr.__u6_addr.__u6_addr8, 16);
255 #endif
256 #else
257 // TODO: make IPv6 work
258 ABORT(R_INTERNAL);
259 #endif
260 break;
261 default:
262 ABORT(R_BAD_ARGS);
263 }
265 _status = 0;
266 abort:
267 return(_status);
268 }
270 //XXX schien@mozilla.com: copy from PRNetAddrToNetAddr,
271 // should be removed after fix the link error in signaling_unittests
272 static int praddr_to_netaddr(const PRNetAddr *prAddr, net::NetAddr *addr)
273 {
274 int _status;
276 switch (prAddr->raw.family) {
277 case PR_AF_INET:
278 addr->inet.family = AF_INET;
279 addr->inet.port = prAddr->inet.port;
280 addr->inet.ip = prAddr->inet.ip;
281 break;
282 case PR_AF_INET6:
283 addr->inet6.family = AF_INET6;
284 addr->inet6.port = prAddr->ipv6.port;
285 addr->inet6.flowinfo = prAddr->ipv6.flowinfo;
286 memcpy(&addr->inet6.ip, &prAddr->ipv6.ip, sizeof(addr->inet6.ip.u8));
287 addr->inet6.scope_id = prAddr->ipv6.scope_id;
288 break;
289 default:
290 MOZ_ASSERT(false);
291 ABORT(R_BAD_ARGS);
292 }
294 _status = 0;
295 abort:
296 return(_status);
297 }
299 static int nr_transport_addr_to_netaddr(nr_transport_addr *addr,
300 net::NetAddr *naddr)
301 {
302 int r, _status;
303 PRNetAddr praddr;
305 if((r = nr_transport_addr_to_praddr(addr, &praddr))) {
306 ABORT(r);
307 }
309 if((r = praddr_to_netaddr(&praddr, naddr))) {
310 ABORT(r);
311 }
313 _status = 0;
314 abort:
315 return(_status);
316 }
318 int nr_netaddr_to_transport_addr(const net::NetAddr *netaddr,
319 nr_transport_addr *addr, int protocol)
320 {
321 int _status;
322 int r;
324 switch(netaddr->raw.family) {
325 case AF_INET:
326 if ((r = nr_ip4_port_to_transport_addr(ntohl(netaddr->inet.ip),
327 ntohs(netaddr->inet.port),
328 protocol, addr)))
329 ABORT(r);
330 break;
331 case AF_INET6:
332 ABORT(R_BAD_ARGS);
333 default:
334 MOZ_ASSERT(false);
335 ABORT(R_BAD_ARGS);
336 }
337 _status=0;
338 abort:
339 return(_status);
340 }
342 int nr_praddr_to_transport_addr(const PRNetAddr *praddr,
343 nr_transport_addr *addr, int protocol,
344 int keep)
345 {
346 int _status;
347 int r;
348 struct sockaddr_in ip4;
350 switch(praddr->raw.family) {
351 case PR_AF_INET:
352 ip4.sin_family = PF_INET;
353 ip4.sin_addr.s_addr = praddr->inet.ip;
354 ip4.sin_port = praddr->inet.port;
355 if ((r = nr_sockaddr_to_transport_addr((sockaddr *)&ip4,
356 sizeof(ip4),
357 protocol, keep,
358 addr)))
359 ABORT(r);
360 break;
361 case PR_AF_INET6:
362 #if 0
363 r = nr_sockaddr_to_transport_addr((sockaddr *)&praddr->raw,
364 sizeof(struct sockaddr_in6),IPPROTO_UDP,keep,addr);
365 break;
366 #endif
367 ABORT(R_BAD_ARGS);
368 default:
369 MOZ_ASSERT(false);
370 ABORT(R_BAD_ARGS);
371 }
373 _status=0;
374 abort:
375 return(_status);
376 }
378 /*
379 * nr_transport_addr_get_addrstring_and_port
380 * convert nr_transport_addr to IP address string and port number
381 */
382 int nr_transport_addr_get_addrstring_and_port(nr_transport_addr *addr,
383 nsACString *host, int32_t *port) {
384 int r, _status;
385 char addr_string[64];
387 // We cannot directly use |nr_transport_addr.as_string| because it contains
388 // more than ip address, therefore, we need to explicity convert it
389 // from |nr_transport_addr_get_addrstring|.
390 if ((r=nr_transport_addr_get_addrstring(addr, addr_string, sizeof(addr_string)))) {
391 ABORT(r);
392 }
394 if ((r=nr_transport_addr_get_port(addr, port))) {
395 ABORT(r);
396 }
398 *host = addr_string;
400 _status=0;
401 abort:
402 return(_status);
403 }
405 // nr_socket APIs (as member functions)
406 int NrSocket::create(nr_transport_addr *addr) {
407 int r,_status;
409 PRStatus status;
410 PRNetAddr naddr;
412 nsresult rv;
413 nsCOMPtr<nsISocketTransportService> stservice =
414 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
416 if (!NS_SUCCEEDED(rv)) {
417 ABORT(R_INTERNAL);
418 }
420 if((r=nr_transport_addr_to_praddr(addr, &naddr)))
421 ABORT(r);
423 switch (addr->protocol) {
424 case IPPROTO_UDP:
425 if (!(fd_ = PR_NewUDPSocket())) {
426 r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create socket");
427 ABORT(R_INTERNAL);
428 }
429 break;
430 case IPPROTO_TCP:
431 if (!(fd_ = PR_NewTCPSocket())) {
432 r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create socket");
433 ABORT(R_INTERNAL);
434 }
435 break;
436 default:
437 ABORT(R_INTERNAL);
438 }
440 status = PR_Bind(fd_, &naddr);
441 if (status != PR_SUCCESS) {
442 r_log(LOG_GENERIC,LOG_CRIT,"Couldn't bind socket to address %s",
443 addr->as_string);
444 ABORT(R_INTERNAL);
445 }
447 r_log(LOG_GENERIC,LOG_DEBUG,"Creating socket %p with addr %s",
448 fd_, addr->as_string);
449 nr_transport_addr_copy(&my_addr_,addr);
451 /* If we have a wildcard port, patch up the addr */
452 if(nr_transport_addr_is_wildcard(addr)){
453 status = PR_GetSockName(fd_, &naddr);
454 if (status != PR_SUCCESS){
455 r_log(LOG_GENERIC, LOG_CRIT, "Couldn't get sock name for socket");
456 ABORT(R_INTERNAL);
457 }
459 if((r=nr_praddr_to_transport_addr(&naddr,&my_addr_,addr->protocol,1)))
460 ABORT(r);
461 }
464 // Set nonblocking
465 PRSocketOptionData option;
466 option.option = PR_SockOpt_Nonblocking;
467 option.value.non_blocking = PR_TRUE;
468 status = PR_SetSocketOption(fd_, &option);
469 if (status != PR_SUCCESS) {
470 r_log(LOG_GENERIC, LOG_CRIT, "Couldn't make socket nonblocking");
471 ABORT(R_INTERNAL);
472 }
474 // Remember our thread.
475 ststhread_ = do_QueryInterface(stservice, &rv);
476 if (!NS_SUCCEEDED(rv))
477 ABORT(R_INTERNAL);
479 // Finally, register with the STS
480 rv = stservice->AttachSocket(fd_, this);
481 if (!NS_SUCCEEDED(rv)) {
482 ABORT(R_INTERNAL);
483 }
485 _status = 0;
487 abort:
488 return(_status);
489 }
491 // This should be called on the STS thread.
492 int NrSocket::sendto(const void *msg, size_t len,
493 int flags, nr_transport_addr *to) {
494 ASSERT_ON_THREAD(ststhread_);
495 int r,_status;
496 PRNetAddr naddr;
497 int32_t status;
499 if ((r=nr_transport_addr_to_praddr(to, &naddr)))
500 ABORT(r);
502 if(fd_==nullptr)
503 ABORT(R_EOD);
505 if (nr_is_stun_request_message((UCHAR*)msg, len)) {
506 // Global rate limiting for stun requests, to mitigate the ice hammer DoS
507 // (see http://tools.ietf.org/html/draft-thomson-mmusic-ice-webrtc)
509 // Tolerate rate of 8k/sec, for one second.
510 static SimpleTokenBucket burst(8192*1, 8192);
511 // Tolerate rate of 3.6k/sec over twenty seconds.
512 static SimpleTokenBucket sustained(3686*20, 3686);
514 // Check number of tokens in each bucket.
515 if (burst.getTokens(UINT32_MAX) < len ||
516 sustained.getTokens(UINT32_MAX) < len) {
517 r_log(LOG_GENERIC, LOG_ERR,
518 "Global rate limit for STUN requests exceeded.");
519 MOZ_ASSERT(false,
520 "Global rate limit for STUN requests exceeded. Go bug "
521 "bcampen@mozilla.com if you weren't intentionally spamming "
522 "ICE candidates, or don't know what that means.");
523 ABORT(R_WOULDBLOCK);
524 }
526 // Take len tokens from both buckets.
527 // (not threadsafe, but no problem since this is only called from STS)
528 burst.getTokens(len);
529 sustained.getTokens(len);
530 }
532 // TODO: Convert flags?
533 status = PR_SendTo(fd_, msg, len, flags, &naddr, PR_INTERVAL_NO_WAIT);
534 if (status < 0 || (size_t)status != len) {
535 if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
536 ABORT(R_WOULDBLOCK);
538 r_log(LOG_GENERIC, LOG_INFO, "Error in sendto %s", to->as_string);
539 ABORT(R_IO_ERROR);
540 }
542 _status=0;
543 abort:
544 return(_status);
545 }
547 int NrSocket::recvfrom(void * buf, size_t maxlen,
548 size_t *len, int flags,
549 nr_transport_addr *from) {
550 ASSERT_ON_THREAD(ststhread_);
551 int r,_status;
552 PRNetAddr nfrom;
553 int32_t status;
555 status = PR_RecvFrom(fd_, buf, maxlen, flags, &nfrom, PR_INTERVAL_NO_WAIT);
556 if (status <= 0) {
557 r_log(LOG_GENERIC,LOG_ERR,"Error in recvfrom");
558 ABORT(R_IO_ERROR);
559 }
560 *len=status;
562 if((r=nr_praddr_to_transport_addr(&nfrom,from,my_addr_.protocol,0)))
563 ABORT(r);
565 //r_log(LOG_GENERIC,LOG_DEBUG,"Read %d bytes from %s",*len,addr->as_string);
567 _status=0;
568 abort:
569 return(_status);
570 }
572 int NrSocket::getaddr(nr_transport_addr *addrp) {
573 ASSERT_ON_THREAD(ststhread_);
574 return nr_transport_addr_copy(addrp, &my_addr_);
575 }
577 // Close the socket so that the STS will detach and then kill it
578 void NrSocket::close() {
579 ASSERT_ON_THREAD(ststhread_);
580 mCondition = NS_BASE_STREAM_CLOSED;
581 }
584 int NrSocket::connect(nr_transport_addr *addr) {
585 ASSERT_ON_THREAD(ststhread_);
586 int r,_status;
587 PRNetAddr naddr;
588 int32_t status;
590 if ((r=nr_transport_addr_to_praddr(addr, &naddr)))
591 ABORT(r);
593 if(!fd_)
594 ABORT(R_EOD);
596 // Note: this just means we tried to connect, not that we
597 // are actually live.
598 connect_invoked_ = true;
599 status = PR_Connect(fd_, &naddr, PR_INTERVAL_NO_WAIT);
601 if (status != PR_SUCCESS) {
602 if (PR_GetError() == PR_IN_PROGRESS_ERROR)
603 ABORT(R_WOULDBLOCK);
605 ABORT(R_IO_ERROR);
606 }
608 _status=0;
609 abort:
610 return(_status);
611 }
614 int NrSocket::write(const void *msg, size_t len, size_t *written) {
615 ASSERT_ON_THREAD(ststhread_);
616 int _status;
617 int32_t status;
619 if (!connect_invoked_)
620 ABORT(R_FAILED);
622 status = PR_Write(fd_, msg, len);
623 if (status < 0) {
624 if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
625 ABORT(R_WOULDBLOCK);
626 ABORT(R_IO_ERROR);
627 }
629 *written = status;
631 _status=0;
632 abort:
633 return _status;
634 }
636 int NrSocket::read(void* buf, size_t maxlen, size_t *len) {
637 ASSERT_ON_THREAD(ststhread_);
638 int _status;
639 int32_t status;
641 if (!connect_invoked_)
642 ABORT(R_FAILED);
644 status = PR_Read(fd_, buf, maxlen);
645 if (status < 0) {
646 if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
647 ABORT(R_WOULDBLOCK);
648 ABORT(R_IO_ERROR);
649 }
650 if (status == 0)
651 ABORT(R_EOD);
653 *len = (size_t)status; // Guaranteed to be > 0
654 _status = 0;
655 abort:
656 return(_status);
657 }
659 // NrSocketIpc Implementation
660 NS_IMPL_ISUPPORTS(NrSocketIpc, nsIUDPSocketInternal)
662 NrSocketIpc::NrSocketIpc(const nsCOMPtr<nsIEventTarget> &main_thread)
663 : err_(false),
664 state_(NR_INIT),
665 main_thread_(main_thread),
666 monitor_("NrSocketIpc") {
667 }
669 // IUDPSocketInternal interfaces
670 // callback while error happened in UDP socket operation
671 NS_IMETHODIMP NrSocketIpc::CallListenerError(const nsACString &type,
672 const nsACString &message,
673 const nsACString &filename,
674 uint32_t line_number,
675 uint32_t column_number) {
676 ASSERT_ON_THREAD(main_thread_);
677 MOZ_ASSERT(type.EqualsLiteral("onerror"));
679 r_log(LOG_GENERIC, LOG_ERR, "UDP socket error:%s at %s:%d:%d",
680 message.BeginReading(), filename.BeginReading(),
681 line_number, column_number);
683 ReentrantMonitorAutoEnter mon(monitor_);
684 err_ = true;
685 monitor_.NotifyAll();
687 return NS_OK;
688 }
690 // callback while receiving UDP packet
691 NS_IMETHODIMP NrSocketIpc::CallListenerReceivedData(const nsACString &type,
692 const nsACString &host,
693 uint16_t port, uint8_t *data,
694 uint32_t data_length) {
695 ASSERT_ON_THREAD(main_thread_);
696 MOZ_ASSERT(type.EqualsLiteral("ondata"));
698 PRNetAddr addr;
699 memset(&addr, 0, sizeof(addr));
701 {
702 ReentrantMonitorAutoEnter mon(monitor_);
704 if (PR_SUCCESS != PR_StringToNetAddr(host.BeginReading(), &addr)) {
705 err_ = true;
706 MOZ_ASSERT(false, "Failed to convert remote host to PRNetAddr");
707 return NS_OK;
708 }
710 // Use PR_IpAddrNull to avoid address being reset to 0.
711 if (PR_SUCCESS != PR_SetNetAddr(PR_IpAddrNull, addr.raw.family, port, &addr)) {
712 err_ = true;
713 MOZ_ASSERT(false, "Failed to set port in PRNetAddr");
714 return NS_OK;
715 }
716 }
718 nsAutoPtr<DataBuffer> buf(new DataBuffer(data, data_length));
719 RefPtr<nr_udp_message> msg(new nr_udp_message(addr, buf));
721 RUN_ON_THREAD(sts_thread_,
722 mozilla::WrapRunnable(nsRefPtr<NrSocketIpc>(this),
723 &NrSocketIpc::recv_callback_s,
724 msg),
725 NS_DISPATCH_NORMAL);
726 return NS_OK;
727 }
729 // callback while UDP socket is opened or closed
730 NS_IMETHODIMP NrSocketIpc::CallListenerVoid(const nsACString &type) {
731 ASSERT_ON_THREAD(main_thread_);
732 if (type.EqualsLiteral("onopen")) {
733 ReentrantMonitorAutoEnter mon(monitor_);
735 uint16_t port;
736 if (NS_FAILED(socket_child_->GetLocalPort(&port))) {
737 err_ = true;
738 MOZ_ASSERT(false, "Failed to get local port");
739 return NS_OK;
740 }
742 nsAutoCString address;
743 if(NS_FAILED(socket_child_->GetLocalAddress(address))) {
744 err_ = true;
745 MOZ_ASSERT(false, "Failed to get local address");
746 return NS_OK;
747 }
749 PRNetAddr praddr;
750 if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, port, &praddr)) {
751 err_ = true;
752 MOZ_ASSERT(false, "Failed to set port in PRNetAddr");
753 return NS_OK;
754 }
756 if (PR_SUCCESS != PR_StringToNetAddr(address.BeginReading(), &praddr)) {
757 err_ = true;
758 MOZ_ASSERT(false, "Failed to convert local host to PRNetAddr");
759 return NS_OK;
760 }
762 nr_transport_addr expected_addr;
763 if(nr_transport_addr_copy(&expected_addr, &my_addr_)) {
764 err_ = true;
765 MOZ_ASSERT(false, "Failed to copy my_addr_");
766 }
768 if (nr_praddr_to_transport_addr(&praddr, &my_addr_, IPPROTO_UDP, 1)) {
769 err_ = true;
770 MOZ_ASSERT(false, "Failed to copy local host to my_addr_");
771 }
773 if (nr_transport_addr_cmp(&expected_addr, &my_addr_,
774 NR_TRANSPORT_ADDR_CMP_MODE_ADDR)) {
775 err_ = true;
776 MOZ_ASSERT(false, "Address of opened socket is not expected");
777 }
779 mon.NotifyAll();
780 } else if (type.EqualsLiteral("onclose")) {
781 // Already handled in UpdateReadyState, nothing to do here
782 } else {
783 MOZ_ASSERT(false, "Received unexpected event");
784 }
786 return NS_OK;
787 }
789 // callback while UDP packet is sent
790 NS_IMETHODIMP NrSocketIpc::CallListenerSent(const nsACString &type,
791 nsresult result) {
792 ASSERT_ON_THREAD(main_thread_);
793 MOZ_ASSERT(type.EqualsLiteral("onsent"));
795 if (NS_FAILED(result)) {
796 ReentrantMonitorAutoEnter mon(monitor_);
797 err_ = true;
798 }
799 return NS_OK;
800 }
802 // callback for state update after every socket operation
803 NS_IMETHODIMP NrSocketIpc::UpdateReadyState(const nsACString &readyState) {
804 ASSERT_ON_THREAD(main_thread_);
806 ReentrantMonitorAutoEnter mon(monitor_);
808 if (readyState.EqualsLiteral("closed")) {
809 MOZ_ASSERT(state_ == NR_CONNECTED || state_ == NR_CLOSING);
810 state_ = NR_CLOSED;
811 }
813 return NS_OK;
814 }
816 // nr_socket public APIs
817 int NrSocketIpc::create(nr_transport_addr *addr) {
818 ASSERT_ON_THREAD(sts_thread_);
820 int r, _status;
821 nsresult rv;
822 int32_t port;
823 nsCString host;
825 ReentrantMonitorAutoEnter mon(monitor_);
827 if (state_ != NR_INIT) {
828 ABORT(R_INTERNAL);
829 }
831 sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
832 if (NS_FAILED(rv)) {
833 MOZ_ASSERT(false, "Failed to get STS thread");
834 ABORT(R_INTERNAL);
835 }
837 if ((r=nr_transport_addr_get_addrstring_and_port(addr, &host, &port))) {
838 ABORT(r);
839 }
841 // wildcard address will be resolved at NrSocketIpc::CallListenerVoid
842 if ((r=nr_transport_addr_copy(&my_addr_, addr))) {
843 ABORT(r);
844 }
846 state_ = NR_CONNECTING;
848 RUN_ON_THREAD(main_thread_,
849 mozilla::WrapRunnable(nsRefPtr<NrSocketIpc>(this),
850 &NrSocketIpc::create_m,
851 host, static_cast<uint16_t>(port)),
852 NS_DISPATCH_NORMAL);
854 // Wait until socket creation complete.
855 mon.Wait();
857 if (err_) {
858 ABORT(R_INTERNAL);
859 }
861 state_ = NR_CONNECTED;
863 _status = 0;
864 abort:
865 return(_status);
866 }
868 int NrSocketIpc::sendto(const void *msg, size_t len, int flags,
869 nr_transport_addr *to) {
870 ASSERT_ON_THREAD(sts_thread_);
872 ReentrantMonitorAutoEnter mon(monitor_);
874 //If send err happened before, simply return the error.
875 if (err_) {
876 return R_IO_ERROR;
877 }
879 if (!socket_child_) {
880 return R_EOD;
881 }
883 if (state_ != NR_CONNECTED) {
884 return R_INTERNAL;
885 }
887 int r;
888 net::NetAddr addr;
889 if ((r=nr_transport_addr_to_netaddr(to, &addr))) {
890 return r;
891 }
893 nsAutoPtr<DataBuffer> buf(new DataBuffer(static_cast<const uint8_t*>(msg), len));
895 RUN_ON_THREAD(main_thread_,
896 mozilla::WrapRunnable(nsRefPtr<NrSocketIpc>(this),
897 &NrSocketIpc::sendto_m,
898 addr, buf),
899 NS_DISPATCH_NORMAL);
900 return 0;
901 }
903 void NrSocketIpc::close() {
904 ASSERT_ON_THREAD(sts_thread_);
906 ReentrantMonitorAutoEnter mon(monitor_);
907 state_ = NR_CLOSING;
909 RUN_ON_THREAD(main_thread_,
910 mozilla::WrapRunnable(nsRefPtr<NrSocketIpc>(this),
911 &NrSocketIpc::close_m),
912 NS_DISPATCH_NORMAL);
914 //remove all enqueued messages
915 std::queue<RefPtr<nr_udp_message> > empty;
916 std::swap(received_msgs_, empty);
917 }
919 int NrSocketIpc::recvfrom(void *buf, size_t maxlen, size_t *len, int flags,
920 nr_transport_addr *from) {
921 ASSERT_ON_THREAD(sts_thread_);
923 ReentrantMonitorAutoEnter mon(monitor_);
925 int r, _status;
926 uint32_t consumed_len;
928 *len = 0;
930 if (state_ != NR_CONNECTED) {
931 ABORT(R_INTERNAL);
932 }
934 if (received_msgs_.empty()) {
935 ABORT(R_WOULDBLOCK);
936 }
938 {
939 RefPtr<nr_udp_message> msg(received_msgs_.front());
941 received_msgs_.pop();
943 if ((r=nr_praddr_to_transport_addr(&msg->from, from, IPPROTO_UDP, 0))) {
944 err_ = true;
945 MOZ_ASSERT(false, "Get bogus address for received UDP packet");
946 ABORT(r);
947 }
949 consumed_len = std::min(maxlen, msg->data->len());
950 if (consumed_len < msg->data->len()) {
951 r_log(LOG_GENERIC, LOG_DEBUG, "Partial received UDP packet will be discard");
952 }
954 memcpy(buf, msg->data->data(), consumed_len);
955 *len = consumed_len;
956 }
958 _status = 0;
959 abort:
960 return(_status);
961 }
963 int NrSocketIpc::getaddr(nr_transport_addr *addrp) {
964 ASSERT_ON_THREAD(sts_thread_);
966 ReentrantMonitorAutoEnter mon(monitor_);
968 if (state_ != NR_CONNECTED) {
969 return R_INTERNAL;
970 }
972 return nr_transport_addr_copy(addrp, &my_addr_);
973 }
975 int NrSocketIpc::connect(nr_transport_addr *addr) {
976 MOZ_ASSERT(false);
977 return R_INTERNAL;
978 }
980 int NrSocketIpc::write(const void *msg, size_t len, size_t *written) {
981 MOZ_ASSERT(false);
982 return R_INTERNAL;
983 }
985 int NrSocketIpc::read(void* buf, size_t maxlen, size_t *len) {
986 MOZ_ASSERT(false);
987 return R_INTERNAL;
988 }
990 // Main thread executors
991 void NrSocketIpc::create_m(const nsACString &host, const uint16_t port) {
992 ASSERT_ON_THREAD(main_thread_);
994 ReentrantMonitorAutoEnter mon(monitor_);
996 nsresult rv;
997 socket_child_ = do_CreateInstance("@mozilla.org/udp-socket-child;1", &rv);
998 if (NS_FAILED(rv)) {
999 err_ = true;
1000 MOZ_ASSERT(false, "Failed to create UDPSocketChild");
1001 }
1003 socket_child_->SetFilterName(nsCString("stun"));
1005 if (NS_FAILED(socket_child_->Bind(this, host, port))) {
1006 err_ = true;
1007 MOZ_ASSERT(false, "Failed to create UDP socket");
1008 }
1009 }
1011 void NrSocketIpc::sendto_m(const net::NetAddr &addr, nsAutoPtr<DataBuffer> buf) {
1012 ASSERT_ON_THREAD(main_thread_);
1014 MOZ_ASSERT(socket_child_);
1016 ReentrantMonitorAutoEnter mon(monitor_);
1018 if (NS_FAILED(socket_child_->SendWithAddress(&addr,
1019 buf->data(),
1020 buf->len()))) {
1021 err_ = true;
1022 }
1023 }
1025 void NrSocketIpc::close_m() {
1026 ASSERT_ON_THREAD(main_thread_);
1028 if (socket_child_) {
1029 socket_child_->Close();
1030 socket_child_ = nullptr;
1031 }
1032 }
1034 void NrSocketIpc::recv_callback_s(RefPtr<nr_udp_message> msg) {
1035 ASSERT_ON_THREAD(sts_thread_);
1037 {
1038 ReentrantMonitorAutoEnter mon(monitor_);
1039 if (state_ != NR_CONNECTED) {
1040 return;
1041 }
1042 }
1044 //enqueue received message
1045 received_msgs_.push(msg);
1047 if ((poll_flags() & PR_POLL_READ)) {
1048 fire_callback(NR_ASYNC_WAIT_READ);
1049 }
1050 }
1052 } // close namespace
1055 using namespace mozilla;
1057 // Bridge to the nr_socket interface
1058 static int nr_socket_local_destroy(void **objp);
1059 static int nr_socket_local_sendto(void *obj,const void *msg, size_t len,
1060 int flags, nr_transport_addr *to);
1061 static int nr_socket_local_recvfrom(void *obj,void * restrict buf,
1062 size_t maxlen, size_t *len, int flags, nr_transport_addr *from);
1063 static int nr_socket_local_getfd(void *obj, NR_SOCKET *fd);
1064 static int nr_socket_local_getaddr(void *obj, nr_transport_addr *addrp);
1065 static int nr_socket_local_close(void *obj);
1066 static int nr_socket_local_connect(void *sock, nr_transport_addr *addr);
1067 static int nr_socket_local_write(void *obj,const void *msg, size_t len,
1068 size_t *written);
1069 static int nr_socket_local_read(void *obj,void * restrict buf, size_t maxlen,
1070 size_t *len);
1072 static nr_socket_vtbl nr_socket_local_vtbl={
1073 1,
1074 nr_socket_local_destroy,
1075 nr_socket_local_sendto,
1076 nr_socket_local_recvfrom,
1077 nr_socket_local_getfd,
1078 nr_socket_local_getaddr,
1079 nr_socket_local_connect,
1080 nr_socket_local_write,
1081 nr_socket_local_read,
1082 nr_socket_local_close
1083 };
1085 int nr_socket_local_create(nr_transport_addr *addr, nr_socket **sockp) {
1086 NrSocketBase *sock = nullptr;
1088 // create IPC bridge for content process
1089 if (XRE_GetProcessType() == GeckoProcessType_Default) {
1090 sock = new NrSocket();
1091 } else {
1092 nsCOMPtr<nsIThread> main_thread;
1093 NS_GetMainThread(getter_AddRefs(main_thread));
1094 sock = new NrSocketIpc(main_thread.get());
1095 }
1097 int r, _status;
1099 r = sock->create(addr);
1100 if (r)
1101 ABORT(r);
1103 r = nr_socket_create_int(static_cast<void *>(sock),
1104 sock->vtbl(), sockp);
1105 if (r)
1106 ABORT(r);
1108 // Add a reference so that we can delete it in destroy()
1109 sock->AddRef();
1111 _status = 0;
1113 abort:
1114 if (_status) {
1115 delete sock;
1116 }
1117 return _status;
1118 }
1121 static int nr_socket_local_destroy(void **objp) {
1122 if(!objp || !*objp)
1123 return 0;
1125 NrSocketBase *sock = static_cast<NrSocketBase *>(*objp);
1126 *objp=0;
1128 sock->close(); // Signal STS that we want not to listen
1129 sock->Release(); // Decrement the ref count
1131 return 0;
1132 }
1134 static int nr_socket_local_sendto(void *obj,const void *msg, size_t len,
1135 int flags, nr_transport_addr *addr) {
1136 NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
1138 return sock->sendto(msg, len, flags, addr);
1139 }
1141 static int nr_socket_local_recvfrom(void *obj,void * restrict buf,
1142 size_t maxlen, size_t *len, int flags,
1143 nr_transport_addr *addr) {
1144 NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
1146 return sock->recvfrom(buf, maxlen, len, flags, addr);
1147 }
1149 static int nr_socket_local_getfd(void *obj, NR_SOCKET *fd) {
1150 NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
1152 *fd = sock;
1154 return 0;
1155 }
1157 static int nr_socket_local_getaddr(void *obj, nr_transport_addr *addrp) {
1158 NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
1160 return sock->getaddr(addrp);
1161 }
1164 static int nr_socket_local_close(void *obj) {
1165 NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
1167 sock->close();
1169 return 0;
1170 }
1172 static int nr_socket_local_write(void *obj, const void *msg, size_t len,
1173 size_t *written) {
1174 NrSocket *sock = static_cast<NrSocket *>(obj);
1176 return sock->write(msg, len, written);
1177 }
1179 static int nr_socket_local_read(void *obj, void * restrict buf, size_t maxlen,
1180 size_t *len) {
1181 NrSocket *sock = static_cast<NrSocket *>(obj);
1183 return sock->read(buf, maxlen, len);
1184 }
1186 static int nr_socket_local_connect(void *obj, nr_transport_addr *addr) {
1187 NrSocket *sock = static_cast<NrSocket *>(obj);
1189 return sock->connect(addr);
1190 }
1192 // Implement async api
1193 int NR_async_wait(NR_SOCKET sock, int how, NR_async_cb cb,void *cb_arg,
1194 char *function,int line) {
1195 NrSocketBase *s = static_cast<NrSocketBase *>(sock);
1197 return s->async_wait(how, cb, cb_arg, function, line);
1198 }
1200 int NR_async_cancel(NR_SOCKET sock,int how) {
1201 NrSocketBase *s = static_cast<NrSocketBase *>(sock);
1203 return s->cancel(how);
1204 }
1206 nr_socket_vtbl* NrSocketBase::vtbl() {
1207 return &nr_socket_local_vtbl;
1208 }