media/mtransport/nr_socket_prsock.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial