media/mtransport/nr_socket_prsock.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:fd47d58553e4
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 */
9
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/. */
13
14 /*
15 Original code from nICEr and nrappkit.
16
17 nICEr copyright:
18
19 Copyright (c) 2007, Adobe Systems, Incorporated
20 All rights reserved.
21
22 Redistribution and use in source and binary forms, with or without
23 modification, are permitted provided that the following conditions are
24 met:
25
26 * Redistributions of source code must retain the above copyright
27 notice, this list of conditions and the following disclaimer.
28
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.
32
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.
36
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.
48
49
50 nrappkit copyright:
51
52 Copyright (C) 2001-2003, Network Resonance, Inc.
53 Copyright (C) 2006, Network Resonance, Inc.
54 All Rights Reserved
55
56 Redistribution and use in source and binary forms, with or without
57 modification, are permitted provided that the following conditions
58 are met:
59
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.
69
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.
81
82
83 ekr@rtfm.com Thu Dec 20 20:14:49 2001
84 */
85
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>
92
93 #include "nspr.h"
94 #include "prerror.h"
95 #include "prio.h"
96 #include "prnetdb.h"
97
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"
109
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"
119
120 // Implement the nsISupports ref counting
121 namespace mozilla {
122
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;
128
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 }
139
140 cbs_[how] = cb;
141 cb_args_[how] = cb_arg;
142 poll_flags_ |= flag;
143
144 return 0;
145 }
146
147 int NrSocketBase::cancel(int how) {
148 uint16_t flag;
149
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 }
160
161 poll_flags_ &= ~flag;
162
163 return 0;
164 }
165
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]);
170
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);
175
176 cbs_[how](this, how, cb_args_[how]);
177 }
178
179 // NrSocket implementation
180 NS_IMPL_ISUPPORTS0(NrSocket)
181
182
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 }
190
191 void NrSocket::OnSocketDetached(PRFileDesc *fd) {
192 ; // TODO: Log?
193 }
194
195 void NrSocket::IsLocal(bool *aIsLocal) {
196 // TODO(jesup): better check? Does it matter? (likely no)
197 *aIsLocal = false;
198 }
199
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);
204
205 if (!r) {
206 mPollFlags = poll_flags();
207 }
208
209 return r;
210 }
211
212 int NrSocket::cancel(int how) {
213 int r = NrSocketBase::cancel(how);
214
215 if (!r) {
216 mPollFlags = poll_flags();
217 }
218
219 return r;
220 }
221
222 // Helper functions for addresses
223 static int nr_transport_addr_to_praddr(nr_transport_addr *addr,
224 PRNetAddr *naddr)
225 {
226 int _status;
227
228 memset(naddr, 0, sizeof(*naddr));
229
230 switch(addr->protocol){
231 case IPPROTO_TCP:
232 break;
233 case IPPROTO_UDP:
234 break;
235 default:
236 ABORT(R_BAD_ARGS);
237 }
238
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 }
264
265 _status = 0;
266 abort:
267 return(_status);
268 }
269
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;
275
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 }
293
294 _status = 0;
295 abort:
296 return(_status);
297 }
298
299 static int nr_transport_addr_to_netaddr(nr_transport_addr *addr,
300 net::NetAddr *naddr)
301 {
302 int r, _status;
303 PRNetAddr praddr;
304
305 if((r = nr_transport_addr_to_praddr(addr, &praddr))) {
306 ABORT(r);
307 }
308
309 if((r = praddr_to_netaddr(&praddr, naddr))) {
310 ABORT(r);
311 }
312
313 _status = 0;
314 abort:
315 return(_status);
316 }
317
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;
323
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 }
341
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;
349
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 }
372
373 _status=0;
374 abort:
375 return(_status);
376 }
377
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];
386
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 }
393
394 if ((r=nr_transport_addr_get_port(addr, port))) {
395 ABORT(r);
396 }
397
398 *host = addr_string;
399
400 _status=0;
401 abort:
402 return(_status);
403 }
404
405 // nr_socket APIs (as member functions)
406 int NrSocket::create(nr_transport_addr *addr) {
407 int r,_status;
408
409 PRStatus status;
410 PRNetAddr naddr;
411
412 nsresult rv;
413 nsCOMPtr<nsISocketTransportService> stservice =
414 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
415
416 if (!NS_SUCCEEDED(rv)) {
417 ABORT(R_INTERNAL);
418 }
419
420 if((r=nr_transport_addr_to_praddr(addr, &naddr)))
421 ABORT(r);
422
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 }
439
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 }
446
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);
450
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 }
458
459 if((r=nr_praddr_to_transport_addr(&naddr,&my_addr_,addr->protocol,1)))
460 ABORT(r);
461 }
462
463
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 }
473
474 // Remember our thread.
475 ststhread_ = do_QueryInterface(stservice, &rv);
476 if (!NS_SUCCEEDED(rv))
477 ABORT(R_INTERNAL);
478
479 // Finally, register with the STS
480 rv = stservice->AttachSocket(fd_, this);
481 if (!NS_SUCCEEDED(rv)) {
482 ABORT(R_INTERNAL);
483 }
484
485 _status = 0;
486
487 abort:
488 return(_status);
489 }
490
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;
498
499 if ((r=nr_transport_addr_to_praddr(to, &naddr)))
500 ABORT(r);
501
502 if(fd_==nullptr)
503 ABORT(R_EOD);
504
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)
508
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);
513
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 }
525
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 }
531
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);
537
538 r_log(LOG_GENERIC, LOG_INFO, "Error in sendto %s", to->as_string);
539 ABORT(R_IO_ERROR);
540 }
541
542 _status=0;
543 abort:
544 return(_status);
545 }
546
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;
554
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;
561
562 if((r=nr_praddr_to_transport_addr(&nfrom,from,my_addr_.protocol,0)))
563 ABORT(r);
564
565 //r_log(LOG_GENERIC,LOG_DEBUG,"Read %d bytes from %s",*len,addr->as_string);
566
567 _status=0;
568 abort:
569 return(_status);
570 }
571
572 int NrSocket::getaddr(nr_transport_addr *addrp) {
573 ASSERT_ON_THREAD(ststhread_);
574 return nr_transport_addr_copy(addrp, &my_addr_);
575 }
576
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 }
582
583
584 int NrSocket::connect(nr_transport_addr *addr) {
585 ASSERT_ON_THREAD(ststhread_);
586 int r,_status;
587 PRNetAddr naddr;
588 int32_t status;
589
590 if ((r=nr_transport_addr_to_praddr(addr, &naddr)))
591 ABORT(r);
592
593 if(!fd_)
594 ABORT(R_EOD);
595
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);
600
601 if (status != PR_SUCCESS) {
602 if (PR_GetError() == PR_IN_PROGRESS_ERROR)
603 ABORT(R_WOULDBLOCK);
604
605 ABORT(R_IO_ERROR);
606 }
607
608 _status=0;
609 abort:
610 return(_status);
611 }
612
613
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;
618
619 if (!connect_invoked_)
620 ABORT(R_FAILED);
621
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 }
628
629 *written = status;
630
631 _status=0;
632 abort:
633 return _status;
634 }
635
636 int NrSocket::read(void* buf, size_t maxlen, size_t *len) {
637 ASSERT_ON_THREAD(ststhread_);
638 int _status;
639 int32_t status;
640
641 if (!connect_invoked_)
642 ABORT(R_FAILED);
643
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);
652
653 *len = (size_t)status; // Guaranteed to be > 0
654 _status = 0;
655 abort:
656 return(_status);
657 }
658
659 // NrSocketIpc Implementation
660 NS_IMPL_ISUPPORTS(NrSocketIpc, nsIUDPSocketInternal)
661
662 NrSocketIpc::NrSocketIpc(const nsCOMPtr<nsIEventTarget> &main_thread)
663 : err_(false),
664 state_(NR_INIT),
665 main_thread_(main_thread),
666 monitor_("NrSocketIpc") {
667 }
668
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"));
678
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);
682
683 ReentrantMonitorAutoEnter mon(monitor_);
684 err_ = true;
685 monitor_.NotifyAll();
686
687 return NS_OK;
688 }
689
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"));
697
698 PRNetAddr addr;
699 memset(&addr, 0, sizeof(addr));
700
701 {
702 ReentrantMonitorAutoEnter mon(monitor_);
703
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 }
709
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 }
717
718 nsAutoPtr<DataBuffer> buf(new DataBuffer(data, data_length));
719 RefPtr<nr_udp_message> msg(new nr_udp_message(addr, buf));
720
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 }
728
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_);
734
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 }
741
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 }
748
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 }
755
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 }
761
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 }
767
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 }
772
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 }
778
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 }
785
786 return NS_OK;
787 }
788
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"));
794
795 if (NS_FAILED(result)) {
796 ReentrantMonitorAutoEnter mon(monitor_);
797 err_ = true;
798 }
799 return NS_OK;
800 }
801
802 // callback for state update after every socket operation
803 NS_IMETHODIMP NrSocketIpc::UpdateReadyState(const nsACString &readyState) {
804 ASSERT_ON_THREAD(main_thread_);
805
806 ReentrantMonitorAutoEnter mon(monitor_);
807
808 if (readyState.EqualsLiteral("closed")) {
809 MOZ_ASSERT(state_ == NR_CONNECTED || state_ == NR_CLOSING);
810 state_ = NR_CLOSED;
811 }
812
813 return NS_OK;
814 }
815
816 // nr_socket public APIs
817 int NrSocketIpc::create(nr_transport_addr *addr) {
818 ASSERT_ON_THREAD(sts_thread_);
819
820 int r, _status;
821 nsresult rv;
822 int32_t port;
823 nsCString host;
824
825 ReentrantMonitorAutoEnter mon(monitor_);
826
827 if (state_ != NR_INIT) {
828 ABORT(R_INTERNAL);
829 }
830
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 }
836
837 if ((r=nr_transport_addr_get_addrstring_and_port(addr, &host, &port))) {
838 ABORT(r);
839 }
840
841 // wildcard address will be resolved at NrSocketIpc::CallListenerVoid
842 if ((r=nr_transport_addr_copy(&my_addr_, addr))) {
843 ABORT(r);
844 }
845
846 state_ = NR_CONNECTING;
847
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);
853
854 // Wait until socket creation complete.
855 mon.Wait();
856
857 if (err_) {
858 ABORT(R_INTERNAL);
859 }
860
861 state_ = NR_CONNECTED;
862
863 _status = 0;
864 abort:
865 return(_status);
866 }
867
868 int NrSocketIpc::sendto(const void *msg, size_t len, int flags,
869 nr_transport_addr *to) {
870 ASSERT_ON_THREAD(sts_thread_);
871
872 ReentrantMonitorAutoEnter mon(monitor_);
873
874 //If send err happened before, simply return the error.
875 if (err_) {
876 return R_IO_ERROR;
877 }
878
879 if (!socket_child_) {
880 return R_EOD;
881 }
882
883 if (state_ != NR_CONNECTED) {
884 return R_INTERNAL;
885 }
886
887 int r;
888 net::NetAddr addr;
889 if ((r=nr_transport_addr_to_netaddr(to, &addr))) {
890 return r;
891 }
892
893 nsAutoPtr<DataBuffer> buf(new DataBuffer(static_cast<const uint8_t*>(msg), len));
894
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 }
902
903 void NrSocketIpc::close() {
904 ASSERT_ON_THREAD(sts_thread_);
905
906 ReentrantMonitorAutoEnter mon(monitor_);
907 state_ = NR_CLOSING;
908
909 RUN_ON_THREAD(main_thread_,
910 mozilla::WrapRunnable(nsRefPtr<NrSocketIpc>(this),
911 &NrSocketIpc::close_m),
912 NS_DISPATCH_NORMAL);
913
914 //remove all enqueued messages
915 std::queue<RefPtr<nr_udp_message> > empty;
916 std::swap(received_msgs_, empty);
917 }
918
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_);
922
923 ReentrantMonitorAutoEnter mon(monitor_);
924
925 int r, _status;
926 uint32_t consumed_len;
927
928 *len = 0;
929
930 if (state_ != NR_CONNECTED) {
931 ABORT(R_INTERNAL);
932 }
933
934 if (received_msgs_.empty()) {
935 ABORT(R_WOULDBLOCK);
936 }
937
938 {
939 RefPtr<nr_udp_message> msg(received_msgs_.front());
940
941 received_msgs_.pop();
942
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 }
948
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 }
953
954 memcpy(buf, msg->data->data(), consumed_len);
955 *len = consumed_len;
956 }
957
958 _status = 0;
959 abort:
960 return(_status);
961 }
962
963 int NrSocketIpc::getaddr(nr_transport_addr *addrp) {
964 ASSERT_ON_THREAD(sts_thread_);
965
966 ReentrantMonitorAutoEnter mon(monitor_);
967
968 if (state_ != NR_CONNECTED) {
969 return R_INTERNAL;
970 }
971
972 return nr_transport_addr_copy(addrp, &my_addr_);
973 }
974
975 int NrSocketIpc::connect(nr_transport_addr *addr) {
976 MOZ_ASSERT(false);
977 return R_INTERNAL;
978 }
979
980 int NrSocketIpc::write(const void *msg, size_t len, size_t *written) {
981 MOZ_ASSERT(false);
982 return R_INTERNAL;
983 }
984
985 int NrSocketIpc::read(void* buf, size_t maxlen, size_t *len) {
986 MOZ_ASSERT(false);
987 return R_INTERNAL;
988 }
989
990 // Main thread executors
991 void NrSocketIpc::create_m(const nsACString &host, const uint16_t port) {
992 ASSERT_ON_THREAD(main_thread_);
993
994 ReentrantMonitorAutoEnter mon(monitor_);
995
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 }
1002
1003 socket_child_->SetFilterName(nsCString("stun"));
1004
1005 if (NS_FAILED(socket_child_->Bind(this, host, port))) {
1006 err_ = true;
1007 MOZ_ASSERT(false, "Failed to create UDP socket");
1008 }
1009 }
1010
1011 void NrSocketIpc::sendto_m(const net::NetAddr &addr, nsAutoPtr<DataBuffer> buf) {
1012 ASSERT_ON_THREAD(main_thread_);
1013
1014 MOZ_ASSERT(socket_child_);
1015
1016 ReentrantMonitorAutoEnter mon(monitor_);
1017
1018 if (NS_FAILED(socket_child_->SendWithAddress(&addr,
1019 buf->data(),
1020 buf->len()))) {
1021 err_ = true;
1022 }
1023 }
1024
1025 void NrSocketIpc::close_m() {
1026 ASSERT_ON_THREAD(main_thread_);
1027
1028 if (socket_child_) {
1029 socket_child_->Close();
1030 socket_child_ = nullptr;
1031 }
1032 }
1033
1034 void NrSocketIpc::recv_callback_s(RefPtr<nr_udp_message> msg) {
1035 ASSERT_ON_THREAD(sts_thread_);
1036
1037 {
1038 ReentrantMonitorAutoEnter mon(monitor_);
1039 if (state_ != NR_CONNECTED) {
1040 return;
1041 }
1042 }
1043
1044 //enqueue received message
1045 received_msgs_.push(msg);
1046
1047 if ((poll_flags() & PR_POLL_READ)) {
1048 fire_callback(NR_ASYNC_WAIT_READ);
1049 }
1050 }
1051
1052 } // close namespace
1053
1054
1055 using namespace mozilla;
1056
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);
1071
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 };
1084
1085 int nr_socket_local_create(nr_transport_addr *addr, nr_socket **sockp) {
1086 NrSocketBase *sock = nullptr;
1087
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 }
1096
1097 int r, _status;
1098
1099 r = sock->create(addr);
1100 if (r)
1101 ABORT(r);
1102
1103 r = nr_socket_create_int(static_cast<void *>(sock),
1104 sock->vtbl(), sockp);
1105 if (r)
1106 ABORT(r);
1107
1108 // Add a reference so that we can delete it in destroy()
1109 sock->AddRef();
1110
1111 _status = 0;
1112
1113 abort:
1114 if (_status) {
1115 delete sock;
1116 }
1117 return _status;
1118 }
1119
1120
1121 static int nr_socket_local_destroy(void **objp) {
1122 if(!objp || !*objp)
1123 return 0;
1124
1125 NrSocketBase *sock = static_cast<NrSocketBase *>(*objp);
1126 *objp=0;
1127
1128 sock->close(); // Signal STS that we want not to listen
1129 sock->Release(); // Decrement the ref count
1130
1131 return 0;
1132 }
1133
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);
1137
1138 return sock->sendto(msg, len, flags, addr);
1139 }
1140
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);
1145
1146 return sock->recvfrom(buf, maxlen, len, flags, addr);
1147 }
1148
1149 static int nr_socket_local_getfd(void *obj, NR_SOCKET *fd) {
1150 NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
1151
1152 *fd = sock;
1153
1154 return 0;
1155 }
1156
1157 static int nr_socket_local_getaddr(void *obj, nr_transport_addr *addrp) {
1158 NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
1159
1160 return sock->getaddr(addrp);
1161 }
1162
1163
1164 static int nr_socket_local_close(void *obj) {
1165 NrSocketBase *sock = static_cast<NrSocketBase *>(obj);
1166
1167 sock->close();
1168
1169 return 0;
1170 }
1171
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);
1175
1176 return sock->write(msg, len, written);
1177 }
1178
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);
1182
1183 return sock->read(buf, maxlen, len);
1184 }
1185
1186 static int nr_socket_local_connect(void *obj, nr_transport_addr *addr) {
1187 NrSocket *sock = static_cast<NrSocket *>(obj);
1188
1189 return sock->connect(addr);
1190 }
1191
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);
1196
1197 return s->async_wait(how, cb, cb_arg, function, line);
1198 }
1199
1200 int NR_async_cancel(NR_SOCKET sock,int how) {
1201 NrSocketBase *s = static_cast<NrSocketBase *>(sock);
1202
1203 return s->cancel(how);
1204 }
1205
1206 nr_socket_vtbl* NrSocketBase::vtbl() {
1207 return &nr_socket_local_vtbl;
1208 }
1209

mercurial