nr_socket_prsock.cpp (49259B)
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 <assert.h> 87 #include <csi_platform.h> 88 #include <errno.h> 89 #include <stdio.h> 90 #include <string.h> 91 #include <sys/types.h> 92 93 #include "mozilla/ProfilerBandwidthCounter.h" 94 #include "mozilla/SyncRunnable.h" 95 #include "mozilla/net/DNS.h" 96 #include "nsASocketHandler.h" 97 #include "nsCOMPtr.h" 98 #include "nsComponentManagerUtils.h" 99 #include "nsDebug.h" 100 #include "nsISocketFilter.h" 101 #include "nsISocketTransportService.h" 102 #include "nsISupportsImpl.h" 103 #include "nsNetCID.h" 104 #include "nsNetUtil.h" 105 #include "nsServiceManagerUtils.h" 106 #include "nsTArray.h" 107 #include "nsXPCOM.h" 108 #include "nsXULAppAPI.h" 109 #include "nspr.h" 110 #include "prerror.h" 111 #include "prio.h" 112 #include "prnetdb.h" 113 #include "runnable_utils.h" 114 115 #if defined(MOZILLA_INTERNAL_API) 116 // csi_platform.h deep in nrappkit defines LOG_INFO and LOG_WARNING 117 # ifdef LOG_INFO 118 # define LOG_TEMP_INFO LOG_INFO 119 # undef LOG_INFO 120 # endif 121 # ifdef LOG_WARNING 122 # define LOG_TEMP_WARNING LOG_WARNING 123 # undef LOG_WARNING 124 # endif 125 # if defined(LOG_DEBUG) 126 # define LOG_TEMP_DEBUG LOG_DEBUG 127 # undef LOG_DEBUG 128 # endif 129 # undef strlcpy 130 131 # include "mozilla/dom/network/UDPSocketChild.h" 132 133 # ifdef LOG_TEMP_INFO 134 # define LOG_INFO LOG_TEMP_INFO 135 # endif 136 # ifdef LOG_TEMP_WARNING 137 # define LOG_WARNING LOG_TEMP_WARNING 138 # endif 139 140 # ifdef LOG_TEMP_DEBUG 141 # define LOG_DEBUG LOG_TEMP_DEBUG 142 # endif 143 # ifdef XP_WIN 144 # ifdef LOG_DEBUG 145 # undef LOG_DEBUG 146 # endif 147 // cloned from csi_platform.h. Win32 doesn't like how we hide symbols 148 # define LOG_DEBUG 7 149 # endif 150 #endif 151 152 extern "C" { 153 #include "async_wait.h" 154 #include "nr_api.h" 155 #include "nr_socket.h" 156 #include "nr_socket_local.h" 157 #include "stun_hint.h" 158 } 159 #include "nr_socket_proxy_config.h" 160 #include "nr_socket_prsock.h" 161 #include "nr_socket_tcp.h" 162 #include "simpletokenbucket.h" 163 #include "test_nr_socket.h" 164 165 // Implement the nsISupports ref counting 166 namespace mozilla { 167 168 #if defined(MOZILLA_INTERNAL_API) 169 class SingletonThreadHolder final { 170 private: 171 ~SingletonThreadHolder() { 172 r_log(LOG_GENERIC, LOG_DEBUG, "Deleting SingletonThreadHolder"); 173 if (mThread) { 174 // Likely a connection is somehow being held in CC or GC 175 NS_WARNING( 176 "SingletonThreads should be Released and shut down before exit!"); 177 mThread->Shutdown(); 178 mThread = nullptr; 179 } 180 } 181 182 DISALLOW_COPY_ASSIGN(SingletonThreadHolder); 183 184 public: 185 // Must be threadsafe for StaticRefPtr/ClearOnShutdown 186 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SingletonThreadHolder) 187 188 explicit SingletonThreadHolder(const nsACString& aName) : mName(aName) { 189 mParentThread = NS_GetCurrentThread(); 190 } 191 192 nsIThread* GetThread() { return mThread; } 193 194 /* 195 * Keep track of how many instances are using a SingletonThreadHolder. 196 * When no one is using it, shut it down 197 */ 198 void AddUse() { 199 MOZ_ASSERT(mParentThread == NS_GetCurrentThread()); 200 MOZ_ASSERT(int32_t(mUseCount) >= 0, "illegal refcnt"); 201 nsrefcnt count = ++mUseCount; 202 if (count == 1) { 203 // idle -> in-use 204 nsresult rv = NS_NewNamedThread(mName, getter_AddRefs(mThread)); 205 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv) && mThread, 206 "Should successfully create mtransport I/O thread"); 207 r_log(LOG_GENERIC, LOG_DEBUG, "Created wrapped SingletonThread %p", 208 mThread.get()); 209 } 210 r_log(LOG_GENERIC, LOG_DEBUG, "AddUse_i: %lu", (unsigned long)count); 211 } 212 213 void ReleaseUse() { 214 MOZ_ASSERT(mParentThread == NS_GetCurrentThread()); 215 nsrefcnt count = --mUseCount; 216 MOZ_ASSERT(int32_t(mUseCount) >= 0, "illegal refcnt"); 217 if (mThread && count == 0) { 218 // in-use -> idle -- no one forcing it to remain instantiated 219 r_log(LOG_GENERIC, LOG_DEBUG, "Shutting down wrapped SingletonThread %p", 220 mThread.get()); 221 mThread->AsyncShutdown(); 222 mThread = nullptr; 223 // It'd be nice to use a timer instead... But be careful of 224 // xpcom-shutdown-threads in that case 225 } 226 r_log(LOG_GENERIC, LOG_DEBUG, "ReleaseUse_i: %lu", (unsigned long)count); 227 } 228 229 private: 230 nsCString mName; 231 nsAutoRefCnt mUseCount; 232 nsCOMPtr<nsIThread> mParentThread; 233 nsCOMPtr<nsIThread> mThread; 234 }; 235 236 static StaticRefPtr<SingletonThreadHolder> sThread; 237 238 static void ClearSingletonOnShutdown() { 239 // We expect everybody to have done ReleaseUse() at the latest during 240 // xpcom-shutdown-threads. So we need to live longer than that. 241 ClearOnShutdown(&sThread, ShutdownPhase::XPCOMShutdownFinal); 242 } 243 #endif 244 245 static nsIThread* GetIOThreadAndAddUse_s() { 246 // Always runs on STS thread! 247 #if defined(MOZILLA_INTERNAL_API) 248 // We need to safely release this on shutdown to avoid leaks 249 if (!sThread) { 250 sThread = new SingletonThreadHolder("mtransport"_ns); 251 NS_DispatchToMainThread(mozilla::WrapRunnableNM(&ClearSingletonOnShutdown)); 252 } 253 // Mark that we're using the shared thread and need it to stick around 254 sThread->AddUse(); 255 return sThread->GetThread(); 256 #else 257 static nsCOMPtr<nsIThread> sThread; 258 if (!sThread) { 259 (void)NS_NewNamedThread("mtransport", getter_AddRefs(sThread)); 260 } 261 return sThread; 262 #endif 263 } 264 265 NrSocketIpc::NrSocketIpc(nsIEventTarget* aThread) : io_thread_(aThread) {} 266 267 static TimeStamp nr_socket_short_term_violation_time; 268 static TimeStamp nr_socket_long_term_violation_time; 269 270 TimeStamp NrSocketBase::short_term_violation_time() { 271 return nr_socket_short_term_violation_time; 272 } 273 274 TimeStamp NrSocketBase::long_term_violation_time() { 275 return nr_socket_long_term_violation_time; 276 } 277 278 // NrSocketBase implementation 279 // async_event APIs 280 int NrSocketBase::async_wait(int how, NR_async_cb cb, void* cb_arg, 281 char* function, int line) { 282 uint16_t flag; 283 284 switch (how) { 285 case NR_ASYNC_WAIT_READ: 286 flag = PR_POLL_READ; 287 break; 288 case NR_ASYNC_WAIT_WRITE: 289 flag = PR_POLL_WRITE; 290 break; 291 default: 292 return R_BAD_ARGS; 293 } 294 295 cbs_[how] = cb; 296 cb_args_[how] = cb_arg; 297 poll_flags_ |= flag; 298 299 return 0; 300 } 301 302 int NrSocketBase::cancel(int how) { 303 uint16_t flag; 304 305 switch (how) { 306 case NR_ASYNC_WAIT_READ: 307 flag = PR_POLL_READ; 308 break; 309 case NR_ASYNC_WAIT_WRITE: 310 flag = PR_POLL_WRITE; 311 break; 312 default: 313 return R_BAD_ARGS; 314 } 315 316 poll_flags_ &= ~flag; 317 318 return 0; 319 } 320 321 void NrSocketBase::fire_callback(int how) { 322 // This can't happen unless we are armed because we only set 323 // the flags if we are armed 324 MOZ_ASSERT(cbs_[how]); 325 326 // Now cancel so that we need to be re-armed. Note that 327 // the re-arming probably happens in the callback we are 328 // about to fire. 329 cancel(how); 330 331 cbs_[how](this, how, cb_args_[how]); 332 } 333 334 // NrSocket implementation 335 NS_IMPL_QUERY_INTERFACE0(NrSocket) 336 337 // The nsASocket callbacks 338 void NrSocket::OnSocketReady(PRFileDesc* fd, int16_t outflags) { 339 if (outflags & PR_POLL_READ & poll_flags()) fire_callback(NR_ASYNC_WAIT_READ); 340 if (outflags & PR_POLL_WRITE & poll_flags()) 341 fire_callback(NR_ASYNC_WAIT_WRITE); 342 if (outflags & (PR_POLL_ERR | PR_POLL_NVAL | PR_POLL_HUP)) 343 // TODO: Bug 946423: how do we notify the upper layers about this? 344 close(); 345 } 346 347 void NrSocket::OnSocketDetached(PRFileDesc* fd) { 348 r_log(LOG_GENERIC, LOG_DEBUG, "Socket %p detached", fd); 349 } 350 351 void NrSocket::IsLocal(bool* aIsLocal) { 352 // TODO(jesup): better check? Does it matter? (likely no) 353 *aIsLocal = false; 354 } 355 356 // async_event APIs 357 int NrSocket::async_wait(int how, NR_async_cb cb, void* cb_arg, char* function, 358 int line) { 359 int r = NrSocketBase::async_wait(how, cb, cb_arg, function, line); 360 361 if (!r) { 362 mPollFlags = poll_flags(); 363 } 364 365 return r; 366 } 367 368 int NrSocket::cancel(int how) { 369 int r = NrSocketBase::cancel(how); 370 371 if (!r) { 372 mPollFlags = poll_flags(); 373 } 374 375 return r; 376 } 377 378 // Helper functions for addresses 379 static int nr_transport_addr_to_praddr(const nr_transport_addr* addr, 380 PRNetAddr* naddr) { 381 int _status; 382 383 memset(naddr, 0, sizeof(*naddr)); 384 385 switch (addr->protocol) { 386 case IPPROTO_TCP: 387 break; 388 case IPPROTO_UDP: 389 break; 390 default: 391 ABORT(R_BAD_ARGS); 392 } 393 394 switch (addr->ip_version) { 395 case NR_IPV4: 396 naddr->inet.family = PR_AF_INET; 397 naddr->inet.port = addr->u.addr4.sin_port; 398 naddr->inet.ip = addr->u.addr4.sin_addr.s_addr; 399 break; 400 case NR_IPV6: 401 naddr->ipv6.family = PR_AF_INET6; 402 naddr->ipv6.port = addr->u.addr6.sin6_port; 403 naddr->ipv6.flowinfo = addr->u.addr6.sin6_flowinfo; 404 memcpy(&naddr->ipv6.ip, &addr->u.addr6.sin6_addr, sizeof(in6_addr)); 405 naddr->ipv6.scope_id = addr->u.addr6.sin6_scope_id; 406 break; 407 default: 408 ABORT(R_BAD_ARGS); 409 } 410 411 _status = 0; 412 abort: 413 return (_status); 414 } 415 416 // XXX schien@mozilla.com: copy from PRNetAddrToNetAddr, 417 // should be removed after fix the link error in signaling_unittests 418 static int praddr_to_netaddr(const PRNetAddr* prAddr, net::NetAddr* addr) { 419 int _status; 420 421 switch (prAddr->raw.family) { 422 case PR_AF_INET: 423 addr->inet.family = AF_INET; 424 addr->inet.port = prAddr->inet.port; 425 addr->inet.ip = prAddr->inet.ip; 426 break; 427 case PR_AF_INET6: 428 addr->inet6.family = AF_INET6; 429 addr->inet6.port = prAddr->ipv6.port; 430 addr->inet6.flowinfo = prAddr->ipv6.flowinfo; 431 memcpy(&addr->inet6.ip, &prAddr->ipv6.ip, sizeof(addr->inet6.ip.u8)); 432 addr->inet6.scope_id = prAddr->ipv6.scope_id; 433 break; 434 default: 435 MOZ_ASSERT(false); 436 ABORT(R_BAD_ARGS); 437 } 438 439 _status = 0; 440 abort: 441 return (_status); 442 } 443 444 static int nr_transport_addr_to_netaddr(const nr_transport_addr* addr, 445 net::NetAddr* naddr) { 446 int r, _status; 447 PRNetAddr praddr; 448 449 if ((r = nr_transport_addr_to_praddr(addr, &praddr))) { 450 ABORT(r); 451 } 452 453 if ((r = praddr_to_netaddr(&praddr, naddr))) { 454 ABORT(r); 455 } 456 457 _status = 0; 458 abort: 459 return (_status); 460 } 461 462 int nr_netaddr_to_transport_addr(const net::NetAddr* netaddr, 463 nr_transport_addr* addr, int protocol) { 464 int _status; 465 int r; 466 467 switch (netaddr->raw.family) { 468 case AF_INET: 469 if ((r = nr_ip4_port_to_transport_addr(ntohl(netaddr->inet.ip), 470 ntohs(netaddr->inet.port), 471 protocol, addr))) 472 ABORT(r); 473 break; 474 case AF_INET6: 475 if ((r = nr_ip6_port_to_transport_addr((in6_addr*)&netaddr->inet6.ip.u8, 476 ntohs(netaddr->inet6.port), 477 protocol, addr))) 478 ABORT(r); 479 break; 480 default: 481 MOZ_ASSERT(false); 482 ABORT(R_BAD_ARGS); 483 } 484 _status = 0; 485 abort: 486 return (_status); 487 } 488 489 int nr_praddr_to_transport_addr(const PRNetAddr* praddr, 490 nr_transport_addr* addr, int protocol, 491 int keep) { 492 int _status; 493 int r; 494 struct sockaddr_in ip4; 495 struct sockaddr_in6 ip6; 496 497 switch (praddr->raw.family) { 498 case PR_AF_INET: 499 ip4.sin_family = PF_INET; 500 ip4.sin_addr.s_addr = praddr->inet.ip; 501 ip4.sin_port = praddr->inet.port; 502 if ((r = nr_sockaddr_to_transport_addr((sockaddr*)&ip4, protocol, keep, 503 addr))) 504 ABORT(r); 505 break; 506 case PR_AF_INET6: 507 ip6.sin6_family = PF_INET6; 508 ip6.sin6_port = praddr->ipv6.port; 509 ip6.sin6_flowinfo = praddr->ipv6.flowinfo; 510 memcpy(&ip6.sin6_addr, &praddr->ipv6.ip, sizeof(in6_addr)); 511 ip6.sin6_scope_id = praddr->ipv6.scope_id; 512 if ((r = nr_sockaddr_to_transport_addr((sockaddr*)&ip6, protocol, keep, 513 addr))) 514 ABORT(r); 515 break; 516 default: 517 MOZ_ASSERT(false); 518 ABORT(R_BAD_ARGS); 519 } 520 521 _status = 0; 522 abort: 523 return (_status); 524 } 525 526 /* 527 * nr_transport_addr_get_addrstring_and_port 528 * convert nr_transport_addr to IP address string and port number 529 */ 530 int nr_transport_addr_get_addrstring_and_port(const nr_transport_addr* addr, 531 nsACString* host, int32_t* port) { 532 int r, _status; 533 char addr_string[64]; 534 535 // We cannot directly use |nr_transport_addr.as_string| because it contains 536 // more than ip address, therefore, we need to explicity convert it 537 // from |nr_transport_addr_get_addrstring|. 538 if ((r = nr_transport_addr_get_addrstring(addr, addr_string, 539 sizeof(addr_string)))) { 540 ABORT(r); 541 } 542 543 if ((r = nr_transport_addr_get_port(addr, port))) { 544 ABORT(r); 545 } 546 547 *host = addr_string; 548 549 _status = 0; 550 abort: 551 return (_status); 552 } 553 554 // nr_socket APIs (as member functions) 555 int NrSocket::create(nr_transport_addr* addr) { 556 int r, _status; 557 558 PRStatus status; 559 PRNetAddr naddr; 560 561 nsresult rv; 562 nsCOMPtr<nsISocketTransportService> stservice = 563 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); 564 565 if (!NS_SUCCEEDED(rv)) { 566 ABORT(R_INTERNAL); 567 } 568 569 if ((r = nr_transport_addr_to_praddr(addr, &naddr))) ABORT(r); 570 571 switch (addr->protocol) { 572 case IPPROTO_UDP: 573 if (!(fd_ = PR_OpenUDPSocket(naddr.raw.family))) { 574 r_log(LOG_GENERIC, LOG_CRIT, 575 "Couldn't create UDP socket, " 576 "family=%d, err=%d", 577 naddr.raw.family, PR_GetError()); 578 ABORT(R_INTERNAL); 579 } 580 break; 581 case IPPROTO_TCP: 582 // TODO: Rewrite this to use WebrtcTcpSocket. 583 // Also use the same logic for TLS. 584 if (my_addr_.fqdn[0] != '\0') ABORT(R_INTERNAL); 585 586 if (!(fd_ = PR_OpenTCPSocket(naddr.raw.family))) { 587 r_log(LOG_GENERIC, LOG_CRIT, 588 "Couldn't create TCP socket, " 589 "family=%d, err=%d", 590 naddr.raw.family, PR_GetError()); 591 ABORT(R_INTERNAL); 592 } 593 // Set ReuseAddr for TCP sockets to enable having several 594 // sockets bound to same local IP and port 595 PRSocketOptionData opt_reuseaddr; 596 opt_reuseaddr.option = PR_SockOpt_Reuseaddr; 597 opt_reuseaddr.value.reuse_addr = PR_TRUE; 598 status = PR_SetSocketOption(fd_, &opt_reuseaddr); 599 if (status != PR_SUCCESS) { 600 r_log(LOG_GENERIC, LOG_CRIT, 601 "Couldn't set reuse addr socket option: %d", status); 602 ABORT(R_INTERNAL); 603 } 604 // And also set ReusePort for platforms supporting this socket option 605 PRSocketOptionData opt_reuseport; 606 opt_reuseport.option = PR_SockOpt_Reuseport; 607 opt_reuseport.value.reuse_port = PR_TRUE; 608 status = PR_SetSocketOption(fd_, &opt_reuseport); 609 if (status != PR_SUCCESS) { 610 if (PR_GetError() != PR_OPERATION_NOT_SUPPORTED_ERROR) { 611 r_log(LOG_GENERIC, LOG_CRIT, 612 "Couldn't set reuse port socket option: %d", status); 613 ABORT(R_INTERNAL); 614 } 615 } 616 // Try to speedup packet delivery by disabling TCP Nagle 617 PRSocketOptionData opt_nodelay; 618 opt_nodelay.option = PR_SockOpt_NoDelay; 619 opt_nodelay.value.no_delay = PR_TRUE; 620 status = PR_SetSocketOption(fd_, &opt_nodelay); 621 if (status != PR_SUCCESS) { 622 r_log(LOG_GENERIC, LOG_WARNING, 623 "Couldn't set Nodelay socket option: %d", status); 624 } 625 break; 626 default: 627 ABORT(R_INTERNAL); 628 } 629 630 status = PR_Bind(fd_, &naddr); 631 if (status != PR_SUCCESS) { 632 r_log(LOG_GENERIC, LOG_CRIT, "Couldn't bind socket to address %s", 633 addr->as_string); 634 ABORT(R_INTERNAL); 635 } 636 637 r_log(LOG_GENERIC, LOG_DEBUG, "Creating socket %p with addr %s", fd_, 638 addr->as_string); 639 nr_transport_addr_copy(&my_addr_, addr); 640 641 /* If we have a wildcard port, patch up the addr */ 642 if (nr_transport_addr_is_wildcard(addr)) { 643 status = PR_GetSockName(fd_, &naddr); 644 if (status != PR_SUCCESS) { 645 r_log(LOG_GENERIC, LOG_CRIT, "Couldn't get sock name for socket"); 646 ABORT(R_INTERNAL); 647 } 648 649 if ((r = nr_praddr_to_transport_addr(&naddr, &my_addr_, addr->protocol, 1))) 650 ABORT(r); 651 } 652 653 // Set nonblocking 654 PRSocketOptionData opt_nonblock; 655 opt_nonblock.option = PR_SockOpt_Nonblocking; 656 opt_nonblock.value.non_blocking = PR_TRUE; 657 status = PR_SetSocketOption(fd_, &opt_nonblock); 658 if (status != PR_SUCCESS) { 659 r_log(LOG_GENERIC, LOG_CRIT, "Couldn't make socket nonblocking"); 660 ABORT(R_INTERNAL); 661 } 662 663 // Remember our thread. 664 ststhread_ = do_QueryInterface(stservice, &rv); 665 if (!NS_SUCCEEDED(rv)) ABORT(R_INTERNAL); 666 667 // Finally, register with the STS 668 rv = stservice->AttachSocket(fd_, this); 669 if (!NS_SUCCEEDED(rv)) { 670 r_log(LOG_GENERIC, LOG_CRIT, "Couldn't attach socket to STS, rv=%u", 671 static_cast<unsigned>(rv)); 672 ABORT(R_INTERNAL); 673 } 674 675 _status = 0; 676 677 abort: 678 return (_status); 679 } 680 681 static int ShouldDrop(size_t len) { 682 // Global rate limiting for stun requests, to mitigate the ice hammer DoS 683 // (see http://tools.ietf.org/html/draft-thomson-mmusic-ice-webrtc) 684 685 // Tolerate rate of 8k/sec, for one second. 686 static SimpleTokenBucket burst(16384 * 1, 16384); 687 // Tolerate rate of 7.2k/sec over twenty seconds. 688 static SimpleTokenBucket sustained(7372 * 20, 7372); 689 690 // Check number of tokens in each bucket. 691 if (burst.getTokens(UINT32_MAX) < len) { 692 r_log(LOG_GENERIC, LOG_ERR, 693 "Short term global rate limit for STUN requests exceeded."); 694 #ifdef MOZILLA_INTERNAL_API 695 nr_socket_short_term_violation_time = TimeStamp::Now(); 696 #endif 697 698 // Bug 1013007 699 #if !EARLY_BETA_OR_EARLIER 700 return R_WOULDBLOCK; 701 #else 702 MOZ_ASSERT(false, 703 "Short term global rate limit for STUN requests exceeded. Go " 704 "bug bcampen@mozilla.com if you weren't intentionally " 705 "spamming ICE candidates, or don't know what that means."); 706 #endif 707 } 708 709 if (sustained.getTokens(UINT32_MAX) < len) { 710 r_log(LOG_GENERIC, LOG_ERR, 711 "Long term global rate limit for STUN requests exceeded."); 712 #ifdef MOZILLA_INTERNAL_API 713 nr_socket_long_term_violation_time = TimeStamp::Now(); 714 #endif 715 // Bug 1013007 716 #if !EARLY_BETA_OR_EARLIER 717 return R_WOULDBLOCK; 718 #else 719 MOZ_ASSERT(false, 720 "Long term global rate limit for STUN requests exceeded. Go " 721 "bug bcampen@mozilla.com if you weren't intentionally " 722 "spamming ICE candidates, or don't know what that means."); 723 #endif 724 } 725 726 // Take len tokens from both buckets. 727 // (not threadsafe, but no problem since this is only called from STS) 728 burst.getTokens(len); 729 sustained.getTokens(len); 730 return 0; 731 } 732 733 // This should be called on the STS thread. 734 int NrSocket::sendto(const void* msg, size_t len, int flags, 735 const nr_transport_addr* to) { 736 ASSERT_ON_THREAD(ststhread_); 737 int r, _status; 738 PRNetAddr naddr; 739 int32_t status; 740 741 if ((r = nr_transport_addr_to_praddr(to, &naddr))) ABORT(r); 742 743 if (fd_ == nullptr) ABORT(R_EOD); 744 745 if (nr_is_stun_request_message((UCHAR*)msg, len) && ShouldDrop(len)) { 746 ABORT(R_WOULDBLOCK); 747 } 748 749 // TODO: Convert flags? 750 status = PR_SendTo(fd_, msg, len, flags, &naddr, PR_INTERVAL_NO_WAIT); 751 if (status < 0 || (size_t)status != len) { 752 if (PR_GetError() == PR_WOULD_BLOCK_ERROR) ABORT(R_WOULDBLOCK); 753 754 r_log(LOG_GENERIC, LOG_INFO, "Error in sendto %s: %d", to->as_string, 755 PR_GetError()); 756 ABORT(R_IO_ERROR); 757 } 758 759 mozilla::profiler_count_bandwidth_written_bytes(status); 760 _status = 0; 761 abort: 762 return (_status); 763 } 764 765 int NrSocket::recvfrom(void* buf, size_t maxlen, size_t* len, int flags, 766 nr_transport_addr* from) { 767 ASSERT_ON_THREAD(ststhread_); 768 int r, _status; 769 PRNetAddr nfrom; 770 int32_t status; 771 772 status = PR_RecvFrom(fd_, buf, maxlen, flags, &nfrom, PR_INTERVAL_NO_WAIT); 773 if (status <= 0) { 774 if (PR_GetError() == PR_WOULD_BLOCK_ERROR) ABORT(R_WOULDBLOCK); 775 r_log(LOG_GENERIC, LOG_INFO, "Error in recvfrom: %d", (int)PR_GetError()); 776 ABORT(R_IO_ERROR); 777 } 778 *len = status; 779 780 if ((r = nr_praddr_to_transport_addr(&nfrom, from, my_addr_.protocol, 0))) 781 ABORT(r); 782 783 // r_log(LOG_GENERIC,LOG_DEBUG,"Read %d bytes from %s",*len,addr->as_string); 784 mozilla::profiler_count_bandwidth_read_bytes(status); 785 786 _status = 0; 787 abort: 788 return (_status); 789 } 790 791 int NrSocket::getaddr(nr_transport_addr* addrp) { 792 ASSERT_ON_THREAD(ststhread_); 793 return nr_transport_addr_copy(addrp, &my_addr_); 794 } 795 796 // Close the socket so that the STS will detach and then kill it 797 void NrSocket::close() { 798 ASSERT_ON_THREAD(ststhread_); 799 mCondition = NS_BASE_STREAM_CLOSED; 800 cancel(NR_ASYNC_WAIT_READ); 801 cancel(NR_ASYNC_WAIT_WRITE); 802 } 803 804 int NrSocket::connect(const nr_transport_addr* addr) { 805 ASSERT_ON_THREAD(ststhread_); 806 int r, _status; 807 PRNetAddr naddr; 808 int32_t connect_status, getsockname_status; 809 810 if ((r = nr_transport_addr_to_praddr(addr, &naddr))) ABORT(r); 811 812 if (!fd_) ABORT(R_EOD); 813 814 // Note: this just means we tried to connect, not that we 815 // are actually live. 816 connect_invoked_ = true; 817 connect_status = PR_Connect(fd_, &naddr, PR_INTERVAL_NO_WAIT); 818 if (connect_status != PR_SUCCESS) { 819 if (PR_GetError() != PR_IN_PROGRESS_ERROR) { 820 r_log(LOG_GENERIC, LOG_CRIT, "PR_Connect failed: %d", PR_GetError()); 821 ABORT(R_IO_ERROR); 822 } 823 } 824 825 // If our local address is wildcard, then fill in the 826 // address now. 827 if (nr_transport_addr_is_wildcard(&my_addr_)) { 828 getsockname_status = PR_GetSockName(fd_, &naddr); 829 if (getsockname_status != PR_SUCCESS) { 830 r_log(LOG_GENERIC, LOG_CRIT, "Couldn't get sock name for socket"); 831 ABORT(R_INTERNAL); 832 } 833 834 if ((r = nr_praddr_to_transport_addr(&naddr, &my_addr_, addr->protocol, 1))) 835 ABORT(r); 836 } 837 838 // Now return the WOULDBLOCK if needed. 839 if (connect_status != PR_SUCCESS) { 840 ABORT(R_WOULDBLOCK); 841 } 842 843 _status = 0; 844 abort: 845 return (_status); 846 } 847 848 int NrSocket::write(const void* msg, size_t len, size_t* written) { 849 ASSERT_ON_THREAD(ststhread_); 850 int _status; 851 int32_t status; 852 853 if (!connect_invoked_) ABORT(R_FAILED); 854 855 status = PR_Write(fd_, msg, len); 856 if (status < 0) { 857 if (PR_GetError() == PR_WOULD_BLOCK_ERROR) ABORT(R_WOULDBLOCK); 858 r_log(LOG_GENERIC, LOG_INFO, "Error in write"); 859 ABORT(R_IO_ERROR); 860 } 861 862 *written = status; 863 864 _status = 0; 865 abort: 866 return _status; 867 } 868 869 int NrSocket::read(void* buf, size_t maxlen, size_t* len) { 870 ASSERT_ON_THREAD(ststhread_); 871 int _status; 872 int32_t status; 873 874 if (!connect_invoked_) ABORT(R_FAILED); 875 876 status = PR_Read(fd_, buf, maxlen); 877 if (status < 0) { 878 if (PR_GetError() == PR_WOULD_BLOCK_ERROR) ABORT(R_WOULDBLOCK); 879 r_log(LOG_GENERIC, LOG_INFO, "Error in read"); 880 ABORT(R_IO_ERROR); 881 } 882 if (status == 0) ABORT(R_EOD); 883 884 *len = (size_t)status; // Guaranteed to be > 0 885 _status = 0; 886 abort: 887 return (_status); 888 } 889 890 int NrSocket::listen(int backlog) { 891 ASSERT_ON_THREAD(ststhread_); 892 int32_t status; 893 int _status; 894 895 assert(fd_); 896 status = PR_Listen(fd_, backlog); 897 if (status != PR_SUCCESS) { 898 r_log(LOG_GENERIC, LOG_CRIT, "%s: PR_GetError() == %d", __FUNCTION__, 899 PR_GetError()); 900 ABORT(R_IO_ERROR); 901 } 902 903 _status = 0; 904 abort: 905 return (_status); 906 } 907 908 int NrSocket::accept(nr_transport_addr* addrp, nr_socket** sockp) { 909 ASSERT_ON_THREAD(ststhread_); 910 int _status, r; 911 PRStatus status; 912 PRFileDesc* prfd; 913 PRNetAddr nfrom; 914 NrSocket* sock = nullptr; 915 nsresult rv; 916 PRSocketOptionData opt_nonblock, opt_nodelay; 917 nsCOMPtr<nsISocketTransportService> stservice = 918 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); 919 920 if (NS_FAILED(rv)) { 921 ABORT(R_INTERNAL); 922 } 923 924 if (!fd_) ABORT(R_EOD); 925 926 prfd = PR_Accept(fd_, &nfrom, PR_INTERVAL_NO_WAIT); 927 928 if (!prfd) { 929 if (PR_GetError() == PR_WOULD_BLOCK_ERROR) ABORT(R_WOULDBLOCK); 930 931 ABORT(R_IO_ERROR); 932 } 933 934 sock = new NrSocket(); 935 936 sock->fd_ = prfd; 937 nr_transport_addr_copy(&sock->my_addr_, &my_addr_); 938 939 if ((r = nr_praddr_to_transport_addr(&nfrom, addrp, my_addr_.protocol, 0))) 940 ABORT(r); 941 942 // Set nonblocking 943 opt_nonblock.option = PR_SockOpt_Nonblocking; 944 opt_nonblock.value.non_blocking = PR_TRUE; 945 status = PR_SetSocketOption(prfd, &opt_nonblock); 946 if (status != PR_SUCCESS) { 947 r_log(LOG_GENERIC, LOG_CRIT, 948 "Failed to make accepted socket nonblocking: %d", status); 949 ABORT(R_INTERNAL); 950 } 951 // Disable TCP Nagle 952 opt_nodelay.option = PR_SockOpt_NoDelay; 953 opt_nodelay.value.no_delay = PR_TRUE; 954 status = PR_SetSocketOption(prfd, &opt_nodelay); 955 if (status != PR_SUCCESS) { 956 r_log(LOG_GENERIC, LOG_WARNING, 957 "Failed to set Nodelay on accepted socket: %d", status); 958 } 959 960 // Should fail only with OOM 961 if ((r = nr_socket_create_int(static_cast<void*>(sock), sock->vtbl(), sockp))) 962 ABORT(r); 963 964 // Remember our thread. 965 sock->ststhread_ = do_QueryInterface(stservice, &rv); 966 if (NS_FAILED(rv)) ABORT(R_INTERNAL); 967 968 // Finally, register with the STS 969 rv = stservice->AttachSocket(prfd, sock); 970 if (NS_FAILED(rv)) { 971 ABORT(R_INTERNAL); 972 } 973 974 sock->connect_invoked_ = true; 975 976 // Add a reference so that we can delete it in destroy() 977 sock->AddRef(); 978 _status = 0; 979 abort: 980 if (_status) { 981 delete sock; 982 } 983 984 return (_status); 985 } 986 987 NS_IMPL_ISUPPORTS(NrUdpSocketIpcProxy, nsIUDPSocketInternal) 988 989 nsresult NrUdpSocketIpcProxy::Init(const RefPtr<NrUdpSocketIpc>& socket) { 990 nsresult rv; 991 sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); 992 if (NS_FAILED(rv)) { 993 MOZ_ASSERT(false, "Failed to get STS thread"); 994 return rv; 995 } 996 997 socket_ = socket; 998 return NS_OK; 999 } 1000 1001 NrUdpSocketIpcProxy::~NrUdpSocketIpcProxy() { 1002 // Send our ref to STS to be released 1003 RUN_ON_THREAD(sts_thread_, mozilla::WrapRelease(socket_.forget()), 1004 NS_DISPATCH_NORMAL); 1005 } 1006 1007 // IUDPSocketInternal interfaces 1008 // callback while error happened in UDP socket operation 1009 NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerError(const nsACString& message, 1010 const nsACString& filename, 1011 uint32_t line_number) { 1012 return socket_->CallListenerError(message, filename, line_number); 1013 } 1014 1015 // callback while receiving UDP packet 1016 NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerReceivedData( 1017 const nsACString& host, uint16_t port, const nsTArray<uint8_t>& data) { 1018 return socket_->CallListenerReceivedData(host, port, data); 1019 } 1020 1021 // callback while UDP socket is opened 1022 NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerOpened() { 1023 return socket_->CallListenerOpened(); 1024 } 1025 1026 // callback while UDP socket is connected 1027 NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerConnected() { 1028 return socket_->CallListenerConnected(); 1029 } 1030 1031 // callback while UDP socket is closed 1032 NS_IMETHODIMP NrUdpSocketIpcProxy::CallListenerClosed() { 1033 return socket_->CallListenerClosed(); 1034 } 1035 1036 // NrUdpSocketIpc Implementation 1037 NrUdpSocketIpc::NrUdpSocketIpc() 1038 : NrSocketIpc(GetIOThreadAndAddUse_s()), 1039 monitor_("NrUdpSocketIpc"), 1040 err_(false), 1041 state_(NR_INIT) {} 1042 1043 NrUdpSocketIpc::~NrUdpSocketIpc() = default; 1044 1045 void NrUdpSocketIpc::Destroy() { 1046 #if defined(MOZILLA_INTERNAL_API) 1047 // destroy_i also dispatches back to STS to call ReleaseUse, to avoid shutting 1048 // down the IO thread before close() runs. 1049 // We use a NonOwning runnable because our refcount has already gone to 0. 1050 io_thread_->Dispatch(NewNonOwningRunnableMethod( 1051 "NrUdpSocketIpc::Destroy", this, &NrUdpSocketIpc::destroy_i)); 1052 #endif 1053 } 1054 1055 // IUDPSocketInternal interfaces 1056 // callback while error happened in UDP socket operation 1057 NS_IMETHODIMP NrUdpSocketIpc::CallListenerError(const nsACString& message, 1058 const nsACString& filename, 1059 uint32_t line_number) { 1060 ASSERT_ON_THREAD(io_thread_); 1061 1062 r_log(LOG_GENERIC, LOG_ERR, "UDP socket error:%s at %s:%d this=%p", 1063 message.BeginReading(), filename.BeginReading(), line_number, 1064 (void*)this); 1065 1066 ReentrantMonitorAutoEnter mon(monitor_); 1067 err_ = true; 1068 monitor_.NotifyAll(); 1069 1070 return NS_OK; 1071 } 1072 1073 // callback while receiving UDP packet 1074 NS_IMETHODIMP NrUdpSocketIpc::CallListenerReceivedData( 1075 const nsACString& host, uint16_t port, const nsTArray<uint8_t>& data) { 1076 ASSERT_ON_THREAD(io_thread_); 1077 1078 PRNetAddr addr; 1079 memset(&addr, 0, sizeof(addr)); 1080 1081 { 1082 ReentrantMonitorAutoEnter mon(monitor_); 1083 1084 if (PR_SUCCESS != PR_StringToNetAddr(host.BeginReading(), &addr)) { 1085 err_ = true; 1086 MOZ_ASSERT(false, "Failed to convert remote host to PRNetAddr"); 1087 return NS_OK; 1088 } 1089 1090 // Use PR_IpAddrNull to avoid address being reset to 0. 1091 if (PR_SUCCESS != 1092 PR_SetNetAddr(PR_IpAddrNull, addr.raw.family, port, &addr)) { 1093 err_ = true; 1094 MOZ_ASSERT(false, "Failed to set port in PRNetAddr"); 1095 return NS_OK; 1096 } 1097 } 1098 1099 auto buf = MakeUnique<MediaPacket>(); 1100 buf->Copy(data.Elements(), data.Length()); 1101 RefPtr<nr_udp_message> msg(new nr_udp_message(addr, std::move(buf))); 1102 1103 RUN_ON_THREAD(sts_thread_, 1104 mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this), 1105 &NrUdpSocketIpc::recv_callback_s, msg), 1106 NS_DISPATCH_NORMAL); 1107 return NS_OK; 1108 } 1109 1110 nsresult NrUdpSocketIpc::SetAddress() { 1111 uint16_t port = socket_child_->LocalPort(); 1112 1113 nsAutoCString address(socket_child_->LocalAddress()); 1114 1115 PRNetAddr praddr; 1116 if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, port, &praddr)) { 1117 err_ = true; 1118 MOZ_ASSERT(false, "Failed to set port in PRNetAddr"); 1119 return NS_OK; 1120 } 1121 1122 if (PR_SUCCESS != PR_StringToNetAddr(address.BeginReading(), &praddr)) { 1123 err_ = true; 1124 MOZ_ASSERT(false, "Failed to convert local host to PRNetAddr"); 1125 return NS_OK; 1126 } 1127 1128 nr_transport_addr expected_addr; 1129 if (nr_transport_addr_copy(&expected_addr, &my_addr_)) { 1130 err_ = true; 1131 MOZ_ASSERT(false, "Failed to copy my_addr_"); 1132 } 1133 1134 if (nr_praddr_to_transport_addr(&praddr, &my_addr_, IPPROTO_UDP, 1)) { 1135 err_ = true; 1136 MOZ_ASSERT(false, "Failed to copy local host to my_addr_"); 1137 } 1138 1139 if (!nr_transport_addr_is_wildcard(&expected_addr) && 1140 nr_transport_addr_cmp(&expected_addr, &my_addr_, 1141 NR_TRANSPORT_ADDR_CMP_MODE_ADDR)) { 1142 err_ = true; 1143 MOZ_ASSERT(false, "Address of opened socket is not expected"); 1144 } 1145 1146 return NS_OK; 1147 } 1148 1149 // callback while UDP socket is opened 1150 NS_IMETHODIMP NrUdpSocketIpc::CallListenerOpened() { 1151 ASSERT_ON_THREAD(io_thread_); 1152 ReentrantMonitorAutoEnter mon(monitor_); 1153 1154 r_log(LOG_GENERIC, LOG_DEBUG, "UDP socket opened this=%p", (void*)this); 1155 nsresult rv = SetAddress(); 1156 if (NS_FAILED(rv)) { 1157 return rv; 1158 } 1159 1160 mon.NotifyAll(); 1161 1162 return NS_OK; 1163 } 1164 1165 // callback while UDP socket is connected 1166 NS_IMETHODIMP NrUdpSocketIpc::CallListenerConnected() { 1167 ASSERT_ON_THREAD(io_thread_); 1168 1169 ReentrantMonitorAutoEnter mon(monitor_); 1170 1171 r_log(LOG_GENERIC, LOG_DEBUG, "UDP socket connected this=%p", (void*)this); 1172 MOZ_ASSERT(state_ == NR_CONNECTED); 1173 1174 nsresult rv = SetAddress(); 1175 if (NS_FAILED(rv)) { 1176 mon.NotifyAll(); 1177 return rv; 1178 } 1179 1180 r_log(LOG_GENERIC, LOG_INFO, "Exit UDP socket connected"); 1181 mon.NotifyAll(); 1182 1183 return NS_OK; 1184 } 1185 1186 // callback while UDP socket is closed 1187 NS_IMETHODIMP NrUdpSocketIpc::CallListenerClosed() { 1188 ASSERT_ON_THREAD(io_thread_); 1189 1190 ReentrantMonitorAutoEnter mon(monitor_); 1191 1192 r_log(LOG_GENERIC, LOG_DEBUG, "UDP socket closed this=%p", (void*)this); 1193 MOZ_ASSERT(state_ == NR_CONNECTED || state_ == NR_CLOSING); 1194 state_ = NR_CLOSED; 1195 1196 return NS_OK; 1197 } 1198 1199 // 1200 // NrSocketBase methods. 1201 // 1202 int NrUdpSocketIpc::create(nr_transport_addr* addr) { 1203 ASSERT_ON_THREAD(sts_thread_); 1204 1205 int r, _status; 1206 nsresult rv; 1207 int32_t port; 1208 nsCString host; 1209 1210 ReentrantMonitorAutoEnter mon(monitor_); 1211 1212 if (state_ != NR_INIT) { 1213 ABORT(R_INTERNAL); 1214 } 1215 1216 sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); 1217 if (NS_FAILED(rv)) { 1218 MOZ_ASSERT(false, "Failed to get STS thread"); 1219 ABORT(R_INTERNAL); 1220 } 1221 1222 if ((r = nr_transport_addr_get_addrstring_and_port(addr, &host, &port))) { 1223 ABORT(r); 1224 } 1225 1226 // wildcard address will be resolved at NrUdpSocketIpc::CallListenerVoid 1227 if ((r = nr_transport_addr_copy(&my_addr_, addr))) { 1228 ABORT(r); 1229 } 1230 1231 state_ = NR_CONNECTING; 1232 1233 MOZ_ASSERT(io_thread_); 1234 RUN_ON_THREAD(io_thread_, 1235 mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this), 1236 &NrUdpSocketIpc::create_i, host, 1237 static_cast<uint16_t>(port)), 1238 NS_DISPATCH_NORMAL); 1239 1240 // Wait until socket creation complete. 1241 mon.Wait(); 1242 1243 if (err_) { 1244 close(); 1245 ABORT(R_INTERNAL); 1246 } 1247 1248 state_ = NR_CONNECTED; 1249 1250 _status = 0; 1251 abort: 1252 return (_status); 1253 } 1254 1255 int NrUdpSocketIpc::sendto(const void* msg, size_t len, int flags, 1256 const nr_transport_addr* to) { 1257 ASSERT_ON_THREAD(sts_thread_); 1258 1259 ReentrantMonitorAutoEnter mon(monitor_); 1260 1261 // If send err happened before, simply return the error. 1262 if (err_) { 1263 return R_IO_ERROR; 1264 } 1265 1266 if (state_ != NR_CONNECTED) { 1267 return R_INTERNAL; 1268 } 1269 1270 int r; 1271 net::NetAddr addr; 1272 if ((r = nr_transport_addr_to_netaddr(to, &addr))) { 1273 return r; 1274 } 1275 1276 if (nr_is_stun_request_message((UCHAR*)msg, len) && ShouldDrop(len)) { 1277 return R_WOULDBLOCK; 1278 } 1279 1280 UniquePtr<MediaPacket> buf(new MediaPacket); 1281 buf->Copy(static_cast<const uint8_t*>(msg), len); 1282 1283 RUN_ON_THREAD( 1284 io_thread_, 1285 mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this), 1286 &NrUdpSocketIpc::sendto_i, addr, std::move(buf)), 1287 NS_DISPATCH_NORMAL); 1288 return 0; 1289 } 1290 1291 void NrUdpSocketIpc::close() { 1292 r_log(LOG_GENERIC, LOG_DEBUG, "NrUdpSocketIpc::close()"); 1293 1294 ASSERT_ON_THREAD(sts_thread_); 1295 1296 ReentrantMonitorAutoEnter mon(monitor_); 1297 state_ = NR_CLOSING; 1298 1299 RUN_ON_THREAD(io_thread_, 1300 mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this), 1301 &NrUdpSocketIpc::close_i), 1302 NS_DISPATCH_NORMAL); 1303 1304 // remove all enqueued messages 1305 std::queue<RefPtr<nr_udp_message>> empty; 1306 std::swap(received_msgs_, empty); 1307 } 1308 1309 int NrUdpSocketIpc::recvfrom(void* buf, size_t maxlen, size_t* len, int flags, 1310 nr_transport_addr* from) { 1311 ASSERT_ON_THREAD(sts_thread_); 1312 1313 ReentrantMonitorAutoEnter mon(monitor_); 1314 1315 int r, _status; 1316 uint32_t consumed_len; 1317 1318 *len = 0; 1319 1320 if (state_ != NR_CONNECTED) { 1321 ABORT(R_INTERNAL); 1322 } 1323 1324 if (received_msgs_.empty()) { 1325 ABORT(R_WOULDBLOCK); 1326 } 1327 1328 { 1329 RefPtr<nr_udp_message> msg(received_msgs_.front()); 1330 1331 received_msgs_.pop(); 1332 1333 if ((r = nr_praddr_to_transport_addr(&msg->from, from, IPPROTO_UDP, 0))) { 1334 err_ = true; 1335 MOZ_ASSERT(false, "Get bogus address for received UDP packet"); 1336 ABORT(r); 1337 } 1338 1339 consumed_len = std::min(maxlen, msg->data->len()); 1340 if (consumed_len < msg->data->len()) { 1341 r_log(LOG_GENERIC, LOG_DEBUG, 1342 "Partial received UDP packet will be discard"); 1343 } 1344 1345 memcpy(buf, msg->data->data(), consumed_len); 1346 *len = consumed_len; 1347 } 1348 1349 _status = 0; 1350 abort: 1351 return (_status); 1352 } 1353 1354 int NrUdpSocketIpc::getaddr(nr_transport_addr* addrp) { 1355 ASSERT_ON_THREAD(sts_thread_); 1356 1357 ReentrantMonitorAutoEnter mon(monitor_); 1358 1359 return nr_transport_addr_copy(addrp, &my_addr_); 1360 } 1361 1362 int NrUdpSocketIpc::connect(const nr_transport_addr* addr) { 1363 int r, _status; 1364 int32_t port; 1365 nsCString host; 1366 1367 ReentrantMonitorAutoEnter mon(monitor_); 1368 r_log(LOG_GENERIC, LOG_DEBUG, "NrUdpSocketIpc::connect(%s) this=%p", 1369 addr->as_string, (void*)this); 1370 1371 if ((r = nr_transport_addr_get_addrstring_and_port(addr, &host, &port))) { 1372 ABORT(r); 1373 } 1374 1375 RUN_ON_THREAD(io_thread_, 1376 mozilla::WrapRunnable(RefPtr<NrUdpSocketIpc>(this), 1377 &NrUdpSocketIpc::connect_i, host, 1378 static_cast<uint16_t>(port)), 1379 NS_DISPATCH_NORMAL); 1380 1381 // Wait until connect() completes. 1382 mon.Wait(); 1383 1384 r_log(LOG_GENERIC, LOG_DEBUG, 1385 "NrUdpSocketIpc::connect this=%p completed err_ = %s", (void*)this, 1386 err_ ? "true" : "false"); 1387 1388 if (err_) { 1389 ABORT(R_INTERNAL); 1390 } 1391 1392 _status = 0; 1393 abort: 1394 return _status; 1395 } 1396 1397 int NrUdpSocketIpc::write(const void* msg, size_t len, size_t* written) { 1398 MOZ_ASSERT(false); 1399 return R_INTERNAL; 1400 } 1401 1402 int NrUdpSocketIpc::read(void* buf, size_t maxlen, size_t* len) { 1403 MOZ_ASSERT(false); 1404 return R_INTERNAL; 1405 } 1406 1407 int NrUdpSocketIpc::listen(int backlog) { 1408 MOZ_ASSERT(false); 1409 return R_INTERNAL; 1410 } 1411 1412 int NrUdpSocketIpc::accept(nr_transport_addr* addrp, nr_socket** sockp) { 1413 MOZ_ASSERT(false); 1414 return R_INTERNAL; 1415 } 1416 1417 // IO thread executors 1418 void NrUdpSocketIpc::create_i(const nsACString& host, const uint16_t port) { 1419 ASSERT_ON_THREAD(io_thread_); 1420 1421 uint32_t minBuffSize = 0; 1422 RefPtr<dom::UDPSocketChild> socketChild = new dom::UDPSocketChild(); 1423 1424 // This can spin the event loop; don't do that with the monitor held 1425 socketChild->SetBackgroundSpinsEvents(); 1426 1427 ReentrantMonitorAutoEnter mon(monitor_); 1428 if (!socket_child_) { 1429 socket_child_ = socketChild; 1430 socket_child_->SetFilterName( 1431 nsCString(NS_NETWORK_SOCKET_FILTER_HANDLER_STUN_SUFFIX)); 1432 } else { 1433 socketChild = nullptr; 1434 } 1435 1436 RefPtr<NrUdpSocketIpcProxy> proxy(new NrUdpSocketIpcProxy); 1437 nsresult rv = proxy->Init(this); 1438 if (NS_FAILED(rv)) { 1439 err_ = true; 1440 mon.NotifyAll(); 1441 return; 1442 } 1443 1444 // XXX bug 1126232 - don't use null Principal! 1445 if (NS_FAILED(socket_child_->Bind(proxy, nullptr, host, port, 1446 /* addressReuse = */ false, 1447 /* loopback = */ false, 1448 /* recv buffer size */ minBuffSize, 1449 /* send buffer size */ minBuffSize))) { 1450 err_ = true; 1451 MOZ_ASSERT(false, "Failed to create UDP socket"); 1452 mon.NotifyAll(); 1453 return; 1454 } 1455 } 1456 1457 void NrUdpSocketIpc::connect_i(const nsACString& host, const uint16_t port) { 1458 ASSERT_ON_THREAD(io_thread_); 1459 nsresult rv; 1460 ReentrantMonitorAutoEnter mon(monitor_); 1461 1462 RefPtr<NrUdpSocketIpcProxy> proxy(new NrUdpSocketIpcProxy); 1463 rv = proxy->Init(this); 1464 if (NS_FAILED(rv)) { 1465 err_ = true; 1466 mon.NotifyAll(); 1467 return; 1468 } 1469 1470 socket_child_->Connect(proxy, host, port); 1471 } 1472 1473 void NrUdpSocketIpc::sendto_i(const net::NetAddr& addr, 1474 UniquePtr<MediaPacket> buf) { 1475 ASSERT_ON_THREAD(io_thread_); 1476 1477 ReentrantMonitorAutoEnter mon(monitor_); 1478 1479 if (!socket_child_) { 1480 MOZ_ASSERT(false); 1481 err_ = true; 1482 return; 1483 } 1484 if (NS_FAILED( 1485 socket_child_->SendWithAddress(&addr, buf->data(), buf->len()))) { 1486 err_ = true; 1487 } 1488 } 1489 1490 void NrUdpSocketIpc::close_i() { 1491 ASSERT_ON_THREAD(io_thread_); 1492 1493 if (socket_child_) { 1494 socket_child_->Close(); 1495 socket_child_ = nullptr; 1496 } 1497 } 1498 1499 #if defined(MOZILLA_INTERNAL_API) 1500 1501 static void ReleaseIOThread_s() { sThread->ReleaseUse(); } 1502 1503 void NrUdpSocketIpc::destroy_i() { 1504 close_i(); 1505 1506 RUN_ON_THREAD(sts_thread_, WrapRunnableNM(&ReleaseIOThread_s), 1507 NS_DISPATCH_NORMAL); 1508 } 1509 #endif 1510 1511 void NrUdpSocketIpc::recv_callback_s(RefPtr<nr_udp_message> msg) { 1512 ASSERT_ON_THREAD(sts_thread_); 1513 1514 { 1515 ReentrantMonitorAutoEnter mon(monitor_); 1516 if (state_ != NR_CONNECTED) { 1517 return; 1518 } 1519 } 1520 1521 // enqueue received message 1522 received_msgs_.push(msg); 1523 1524 if ((poll_flags() & PR_POLL_READ)) { 1525 fire_callback(NR_ASYNC_WAIT_READ); 1526 } 1527 } 1528 1529 } // namespace mozilla 1530 1531 using namespace mozilla; 1532 1533 // Bridge to the nr_socket interface 1534 static int nr_socket_local_destroy(void** objp); 1535 static int nr_socket_local_sendto(void* obj, const void* msg, size_t len, 1536 int flags, const nr_transport_addr* to); 1537 static int nr_socket_local_recvfrom(void* obj, void* restrict buf, 1538 size_t maxlen, size_t* len, int flags, 1539 nr_transport_addr* from); 1540 static int nr_socket_local_getfd(void* obj, NR_SOCKET* fd); 1541 static int nr_socket_local_getaddr(void* obj, nr_transport_addr* addrp); 1542 static int nr_socket_local_close(void* obj); 1543 static int nr_socket_local_connect(void* obj, const nr_transport_addr* addr); 1544 static int nr_socket_local_write(void* obj, const void* msg, size_t len, 1545 size_t* written); 1546 static int nr_socket_local_read(void* obj, void* restrict buf, size_t maxlen, 1547 size_t* len); 1548 static int nr_socket_local_listen(void* obj, int backlog); 1549 static int nr_socket_local_accept(void* obj, nr_transport_addr* addrp, 1550 nr_socket** sockp); 1551 1552 static nr_socket_vtbl nr_socket_local_vtbl = {2, 1553 nr_socket_local_destroy, 1554 nr_socket_local_sendto, 1555 nr_socket_local_recvfrom, 1556 nr_socket_local_getfd, 1557 nr_socket_local_getaddr, 1558 nr_socket_local_connect, 1559 nr_socket_local_write, 1560 nr_socket_local_read, 1561 nr_socket_local_close, 1562 nr_socket_local_listen, 1563 nr_socket_local_accept}; 1564 1565 /* static */ 1566 int NrSocketBase::CreateSocket( 1567 nr_transport_addr* addr, RefPtr<NrSocketBase>* sock, 1568 const std::shared_ptr<NrSocketProxyConfig>& config) { 1569 int r, _status; 1570 1571 if (IsForbiddenAddress(addr)) { 1572 ABORT(R_REJECTED); 1573 } 1574 1575 if (config && config->GetForceProxy() && addr->protocol == IPPROTO_UDP) { 1576 ABORT(R_REJECTED); 1577 } 1578 1579 // create IPC bridge for content process 1580 if (XRE_IsParentProcess()) { 1581 // TODO: Make NrTcpSocket work on the parent process 1582 *sock = new NrSocket(); 1583 } else if (XRE_IsSocketProcess()) { 1584 if (addr->protocol == IPPROTO_TCP) { 1585 *sock = new NrTcpSocket(config); 1586 } else { 1587 *sock = new NrSocket(); 1588 } 1589 } else { 1590 if (addr->protocol == IPPROTO_TCP) { 1591 *sock = new NrTcpSocket(config); 1592 } else { 1593 *sock = new NrUdpSocketIpc(); 1594 } 1595 } 1596 1597 r = (*sock)->create(addr); 1598 if (r) ABORT(r); 1599 1600 _status = 0; 1601 abort: 1602 if (_status) { 1603 *sock = nullptr; 1604 } 1605 return _status; 1606 } 1607 1608 // static 1609 bool NrSocketBase::IsForbiddenAddress(nr_transport_addr* addr) { 1610 int r, port; 1611 1612 r = nr_transport_addr_get_port(addr, &port); 1613 if (r) { 1614 return true; 1615 } 1616 1617 // allow auto assigned ports 1618 if (port != 0) { 1619 // Don't need to check an override scheme 1620 nsresult rv = NS_CheckPortSafety(port, nullptr); 1621 if (NS_FAILED(rv)) { 1622 return true; 1623 } 1624 } 1625 1626 return false; 1627 } 1628 1629 static int nr_socket_local_destroy(void** objp) { 1630 if (!objp || !*objp) return 0; 1631 1632 NrSocketBase* sock = static_cast<NrSocketBase*>(*objp); 1633 *objp = nullptr; 1634 1635 sock->close(); // Signal STS that we want not to listen 1636 sock->Release(); // Decrement the ref count 1637 1638 return 0; 1639 } 1640 1641 static int nr_socket_local_sendto(void* obj, const void* msg, size_t len, 1642 int flags, const nr_transport_addr* addr) { 1643 NrSocketBase* sock = static_cast<NrSocketBase*>(obj); 1644 1645 return sock->sendto(msg, len, flags, addr); 1646 } 1647 1648 static int nr_socket_local_recvfrom(void* obj, void* restrict buf, 1649 size_t maxlen, size_t* len, int flags, 1650 nr_transport_addr* addr) { 1651 NrSocketBase* sock = static_cast<NrSocketBase*>(obj); 1652 1653 return sock->recvfrom(buf, maxlen, len, flags, addr); 1654 } 1655 1656 static int nr_socket_local_getfd(void* obj, NR_SOCKET* fd) { 1657 NrSocketBase* sock = static_cast<NrSocketBase*>(obj); 1658 1659 *fd = sock; 1660 1661 return 0; 1662 } 1663 1664 static int nr_socket_local_getaddr(void* obj, nr_transport_addr* addrp) { 1665 NrSocketBase* sock = static_cast<NrSocketBase*>(obj); 1666 1667 return sock->getaddr(addrp); 1668 } 1669 1670 static int nr_socket_local_close(void* obj) { 1671 NrSocketBase* sock = static_cast<NrSocketBase*>(obj); 1672 1673 sock->close(); 1674 1675 return 0; 1676 } 1677 1678 static int nr_socket_local_write(void* obj, const void* msg, size_t len, 1679 size_t* written) { 1680 NrSocketBase* sock = static_cast<NrSocketBase*>(obj); 1681 1682 return sock->write(msg, len, written); 1683 } 1684 1685 static int nr_socket_local_read(void* obj, void* restrict buf, size_t maxlen, 1686 size_t* len) { 1687 NrSocketBase* sock = static_cast<NrSocketBase*>(obj); 1688 1689 return sock->read(buf, maxlen, len); 1690 } 1691 1692 static int nr_socket_local_connect(void* obj, const nr_transport_addr* addr) { 1693 NrSocketBase* sock = static_cast<NrSocketBase*>(obj); 1694 1695 return sock->connect(addr); 1696 } 1697 1698 static int nr_socket_local_listen(void* obj, int backlog) { 1699 NrSocketBase* sock = static_cast<NrSocketBase*>(obj); 1700 1701 return sock->listen(backlog); 1702 } 1703 1704 static int nr_socket_local_accept(void* obj, nr_transport_addr* addrp, 1705 nr_socket** sockp) { 1706 NrSocketBase* sock = static_cast<NrSocketBase*>(obj); 1707 1708 return sock->accept(addrp, sockp); 1709 } 1710 1711 // Implement async api 1712 int NR_async_wait(NR_SOCKET sock, int how, NR_async_cb cb, void* cb_arg, 1713 char* function, int line) { 1714 NrSocketBase* s = static_cast<NrSocketBase*>(sock); 1715 1716 return s->async_wait(how, cb, cb_arg, function, line); 1717 } 1718 1719 int NR_async_cancel(NR_SOCKET sock, int how) { 1720 NrSocketBase* s = static_cast<NrSocketBase*>(sock); 1721 1722 return s->cancel(how); 1723 } 1724 1725 nr_socket_vtbl* NrSocketBase::vtbl() { return &nr_socket_local_vtbl; }