1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/mtransport/nr_socket_prsock.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1209 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 +/* 1.10 +Modified version of nr_socket_local, adapted for NSPR 1.11 +*/ 1.12 + 1.13 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.14 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.15 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.16 + 1.17 +/* 1.18 +Original code from nICEr and nrappkit. 1.19 + 1.20 +nICEr copyright: 1.21 + 1.22 +Copyright (c) 2007, Adobe Systems, Incorporated 1.23 +All rights reserved. 1.24 + 1.25 +Redistribution and use in source and binary forms, with or without 1.26 +modification, are permitted provided that the following conditions are 1.27 +met: 1.28 + 1.29 +* Redistributions of source code must retain the above copyright 1.30 + notice, this list of conditions and the following disclaimer. 1.31 + 1.32 +* Redistributions in binary form must reproduce the above copyright 1.33 + notice, this list of conditions and the following disclaimer in the 1.34 + documentation and/or other materials provided with the distribution. 1.35 + 1.36 +* Neither the name of Adobe Systems, Network Resonance nor the names of its 1.37 + contributors may be used to endorse or promote products derived from 1.38 + this software without specific prior written permission. 1.39 + 1.40 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.41 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.42 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.43 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.44 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.45 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.46 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.47 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.48 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.49 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.50 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.51 + 1.52 + 1.53 +nrappkit copyright: 1.54 + 1.55 + Copyright (C) 2001-2003, Network Resonance, Inc. 1.56 + Copyright (C) 2006, Network Resonance, Inc. 1.57 + All Rights Reserved 1.58 + 1.59 + Redistribution and use in source and binary forms, with or without 1.60 + modification, are permitted provided that the following conditions 1.61 + are met: 1.62 + 1.63 + 1. Redistributions of source code must retain the above copyright 1.64 + notice, this list of conditions and the following disclaimer. 1.65 + 2. Redistributions in binary form must reproduce the above copyright 1.66 + notice, this list of conditions and the following disclaimer in the 1.67 + documentation and/or other materials provided with the distribution. 1.68 + 3. Neither the name of Network Resonance, Inc. nor the name of any 1.69 + contributors to this software may be used to endorse or promote 1.70 + products derived from this software without specific prior written 1.71 + permission. 1.72 + 1.73 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 1.74 + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.75 + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.76 + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 1.77 + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.78 + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.79 + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.80 + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.81 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.82 + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1.83 + POSSIBILITY OF SUCH DAMAGE. 1.84 + 1.85 + 1.86 + ekr@rtfm.com Thu Dec 20 20:14:49 2001 1.87 +*/ 1.88 + 1.89 +#include <csi_platform.h> 1.90 +#include <stdio.h> 1.91 +#include <string.h> 1.92 +#include <sys/types.h> 1.93 +#include <assert.h> 1.94 +#include <errno.h> 1.95 + 1.96 +#include "nspr.h" 1.97 +#include "prerror.h" 1.98 +#include "prio.h" 1.99 +#include "prnetdb.h" 1.100 + 1.101 +#include "mozilla/net/DNS.h" 1.102 +#include "nsCOMPtr.h" 1.103 +#include "nsASocketHandler.h" 1.104 +#include "nsISocketTransportService.h" 1.105 +#include "nsNetCID.h" 1.106 +#include "nsISupportsImpl.h" 1.107 +#include "nsServiceManagerUtils.h" 1.108 +#include "nsComponentManagerUtils.h" 1.109 +#include "nsXPCOM.h" 1.110 +#include "nsXULAppAPI.h" 1.111 +#include "runnable_utils.h" 1.112 + 1.113 +extern "C" { 1.114 +#include "nr_api.h" 1.115 +#include "async_wait.h" 1.116 +#include "nr_socket.h" 1.117 +#include "nr_socket_local.h" 1.118 +#include "stun_hint.h" 1.119 +} 1.120 +#include "nr_socket_prsock.h" 1.121 +#include "simpletokenbucket.h" 1.122 + 1.123 +// Implement the nsISupports ref counting 1.124 +namespace mozilla { 1.125 + 1.126 +// NrSocketBase implementation 1.127 +// async_event APIs 1.128 +int NrSocketBase::async_wait(int how, NR_async_cb cb, void *cb_arg, 1.129 + char *function, int line) { 1.130 + uint16_t flag; 1.131 + 1.132 + switch (how) { 1.133 + case NR_ASYNC_WAIT_READ: 1.134 + flag = PR_POLL_READ; 1.135 + break; 1.136 + case NR_ASYNC_WAIT_WRITE: 1.137 + flag = PR_POLL_WRITE; 1.138 + break; 1.139 + default: 1.140 + return R_BAD_ARGS; 1.141 + } 1.142 + 1.143 + cbs_[how] = cb; 1.144 + cb_args_[how] = cb_arg; 1.145 + poll_flags_ |= flag; 1.146 + 1.147 + return 0; 1.148 +} 1.149 + 1.150 +int NrSocketBase::cancel(int how) { 1.151 + uint16_t flag; 1.152 + 1.153 + switch (how) { 1.154 + case NR_ASYNC_WAIT_READ: 1.155 + flag = PR_POLL_READ; 1.156 + break; 1.157 + case NR_ASYNC_WAIT_WRITE: 1.158 + flag = PR_POLL_WRITE; 1.159 + break; 1.160 + default: 1.161 + return R_BAD_ARGS; 1.162 + } 1.163 + 1.164 + poll_flags_ &= ~flag; 1.165 + 1.166 + return 0; 1.167 +} 1.168 + 1.169 +void NrSocketBase::fire_callback(int how) { 1.170 + // This can't happen unless we are armed because we only set 1.171 + // the flags if we are armed 1.172 + MOZ_ASSERT(cbs_[how]); 1.173 + 1.174 + // Now cancel so that we need to be re-armed. Note that 1.175 + // the re-arming probably happens in the callback we are 1.176 + // about to fire. 1.177 + cancel(how); 1.178 + 1.179 + cbs_[how](this, how, cb_args_[how]); 1.180 +} 1.181 + 1.182 +// NrSocket implementation 1.183 +NS_IMPL_ISUPPORTS0(NrSocket) 1.184 + 1.185 + 1.186 +// The nsASocket callbacks 1.187 +void NrSocket::OnSocketReady(PRFileDesc *fd, int16_t outflags) { 1.188 + if (outflags & PR_POLL_READ) 1.189 + fire_callback(NR_ASYNC_WAIT_READ); 1.190 + if (outflags & PR_POLL_WRITE) 1.191 + fire_callback(NR_ASYNC_WAIT_WRITE); 1.192 +} 1.193 + 1.194 +void NrSocket::OnSocketDetached(PRFileDesc *fd) { 1.195 + ; // TODO: Log? 1.196 +} 1.197 + 1.198 +void NrSocket::IsLocal(bool *aIsLocal) { 1.199 + // TODO(jesup): better check? Does it matter? (likely no) 1.200 + *aIsLocal = false; 1.201 +} 1.202 + 1.203 +// async_event APIs 1.204 +int NrSocket::async_wait(int how, NR_async_cb cb, void *cb_arg, 1.205 + char *function, int line) { 1.206 + int r = NrSocketBase::async_wait(how, cb, cb_arg, function, line); 1.207 + 1.208 + if (!r) { 1.209 + mPollFlags = poll_flags(); 1.210 + } 1.211 + 1.212 + return r; 1.213 +} 1.214 + 1.215 +int NrSocket::cancel(int how) { 1.216 + int r = NrSocketBase::cancel(how); 1.217 + 1.218 + if (!r) { 1.219 + mPollFlags = poll_flags(); 1.220 + } 1.221 + 1.222 + return r; 1.223 +} 1.224 + 1.225 +// Helper functions for addresses 1.226 +static int nr_transport_addr_to_praddr(nr_transport_addr *addr, 1.227 + PRNetAddr *naddr) 1.228 + { 1.229 + int _status; 1.230 + 1.231 + memset(naddr, 0, sizeof(*naddr)); 1.232 + 1.233 + switch(addr->protocol){ 1.234 + case IPPROTO_TCP: 1.235 + break; 1.236 + case IPPROTO_UDP: 1.237 + break; 1.238 + default: 1.239 + ABORT(R_BAD_ARGS); 1.240 + } 1.241 + 1.242 + switch(addr->ip_version){ 1.243 + case NR_IPV4: 1.244 + naddr->inet.family = PR_AF_INET; 1.245 + naddr->inet.port = addr->u.addr4.sin_port; 1.246 + naddr->inet.ip = addr->u.addr4.sin_addr.s_addr; 1.247 + break; 1.248 + case NR_IPV6: 1.249 +#if 0 1.250 + naddr->ipv6.family = PR_AF_INET6; 1.251 + naddr->ipv6.port = addr->u.addr6.sin6_port; 1.252 +#ifdef LINUX 1.253 + memcpy(naddr->ipv6.ip._S6_un._S6_u8, 1.254 + &addr->u.addr6.sin6_addr.__in6_u.__u6_addr8, 16); 1.255 +#else 1.256 + memcpy(naddr->ipv6.ip._S6_un._S6_u8, 1.257 + &addr->u.addr6.sin6_addr.__u6_addr.__u6_addr8, 16); 1.258 +#endif 1.259 +#else 1.260 + // TODO: make IPv6 work 1.261 + ABORT(R_INTERNAL); 1.262 +#endif 1.263 + break; 1.264 + default: 1.265 + ABORT(R_BAD_ARGS); 1.266 + } 1.267 + 1.268 + _status = 0; 1.269 + abort: 1.270 + return(_status); 1.271 + } 1.272 + 1.273 +//XXX schien@mozilla.com: copy from PRNetAddrToNetAddr, 1.274 +// should be removed after fix the link error in signaling_unittests 1.275 +static int praddr_to_netaddr(const PRNetAddr *prAddr, net::NetAddr *addr) 1.276 +{ 1.277 + int _status; 1.278 + 1.279 + switch (prAddr->raw.family) { 1.280 + case PR_AF_INET: 1.281 + addr->inet.family = AF_INET; 1.282 + addr->inet.port = prAddr->inet.port; 1.283 + addr->inet.ip = prAddr->inet.ip; 1.284 + break; 1.285 + case PR_AF_INET6: 1.286 + addr->inet6.family = AF_INET6; 1.287 + addr->inet6.port = prAddr->ipv6.port; 1.288 + addr->inet6.flowinfo = prAddr->ipv6.flowinfo; 1.289 + memcpy(&addr->inet6.ip, &prAddr->ipv6.ip, sizeof(addr->inet6.ip.u8)); 1.290 + addr->inet6.scope_id = prAddr->ipv6.scope_id; 1.291 + break; 1.292 + default: 1.293 + MOZ_ASSERT(false); 1.294 + ABORT(R_BAD_ARGS); 1.295 + } 1.296 + 1.297 + _status = 0; 1.298 +abort: 1.299 + return(_status); 1.300 +} 1.301 + 1.302 +static int nr_transport_addr_to_netaddr(nr_transport_addr *addr, 1.303 + net::NetAddr *naddr) 1.304 +{ 1.305 + int r, _status; 1.306 + PRNetAddr praddr; 1.307 + 1.308 + if((r = nr_transport_addr_to_praddr(addr, &praddr))) { 1.309 + ABORT(r); 1.310 + } 1.311 + 1.312 + if((r = praddr_to_netaddr(&praddr, naddr))) { 1.313 + ABORT(r); 1.314 + } 1.315 + 1.316 + _status = 0; 1.317 +abort: 1.318 + return(_status); 1.319 +} 1.320 + 1.321 +int nr_netaddr_to_transport_addr(const net::NetAddr *netaddr, 1.322 + nr_transport_addr *addr, int protocol) 1.323 + { 1.324 + int _status; 1.325 + int r; 1.326 + 1.327 + switch(netaddr->raw.family) { 1.328 + case AF_INET: 1.329 + if ((r = nr_ip4_port_to_transport_addr(ntohl(netaddr->inet.ip), 1.330 + ntohs(netaddr->inet.port), 1.331 + protocol, addr))) 1.332 + ABORT(r); 1.333 + break; 1.334 + case AF_INET6: 1.335 + ABORT(R_BAD_ARGS); 1.336 + default: 1.337 + MOZ_ASSERT(false); 1.338 + ABORT(R_BAD_ARGS); 1.339 + } 1.340 + _status=0; 1.341 + abort: 1.342 + return(_status); 1.343 + } 1.344 + 1.345 +int nr_praddr_to_transport_addr(const PRNetAddr *praddr, 1.346 + nr_transport_addr *addr, int protocol, 1.347 + int keep) 1.348 + { 1.349 + int _status; 1.350 + int r; 1.351 + struct sockaddr_in ip4; 1.352 + 1.353 + switch(praddr->raw.family) { 1.354 + case PR_AF_INET: 1.355 + ip4.sin_family = PF_INET; 1.356 + ip4.sin_addr.s_addr = praddr->inet.ip; 1.357 + ip4.sin_port = praddr->inet.port; 1.358 + if ((r = nr_sockaddr_to_transport_addr((sockaddr *)&ip4, 1.359 + sizeof(ip4), 1.360 + protocol, keep, 1.361 + addr))) 1.362 + ABORT(r); 1.363 + break; 1.364 + case PR_AF_INET6: 1.365 +#if 0 1.366 + r = nr_sockaddr_to_transport_addr((sockaddr *)&praddr->raw, 1.367 + sizeof(struct sockaddr_in6),IPPROTO_UDP,keep,addr); 1.368 + break; 1.369 +#endif 1.370 + ABORT(R_BAD_ARGS); 1.371 + default: 1.372 + MOZ_ASSERT(false); 1.373 + ABORT(R_BAD_ARGS); 1.374 + } 1.375 + 1.376 + _status=0; 1.377 + abort: 1.378 + return(_status); 1.379 + } 1.380 + 1.381 +/* 1.382 + * nr_transport_addr_get_addrstring_and_port 1.383 + * convert nr_transport_addr to IP address string and port number 1.384 + */ 1.385 +int nr_transport_addr_get_addrstring_and_port(nr_transport_addr *addr, 1.386 + nsACString *host, int32_t *port) { 1.387 + int r, _status; 1.388 + char addr_string[64]; 1.389 + 1.390 + // We cannot directly use |nr_transport_addr.as_string| because it contains 1.391 + // more than ip address, therefore, we need to explicity convert it 1.392 + // from |nr_transport_addr_get_addrstring|. 1.393 + if ((r=nr_transport_addr_get_addrstring(addr, addr_string, sizeof(addr_string)))) { 1.394 + ABORT(r); 1.395 + } 1.396 + 1.397 + if ((r=nr_transport_addr_get_port(addr, port))) { 1.398 + ABORT(r); 1.399 + } 1.400 + 1.401 + *host = addr_string; 1.402 + 1.403 + _status=0; 1.404 +abort: 1.405 + return(_status); 1.406 +} 1.407 + 1.408 +// nr_socket APIs (as member functions) 1.409 +int NrSocket::create(nr_transport_addr *addr) { 1.410 + int r,_status; 1.411 + 1.412 + PRStatus status; 1.413 + PRNetAddr naddr; 1.414 + 1.415 + nsresult rv; 1.416 + nsCOMPtr<nsISocketTransportService> stservice = 1.417 + do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); 1.418 + 1.419 + if (!NS_SUCCEEDED(rv)) { 1.420 + ABORT(R_INTERNAL); 1.421 + } 1.422 + 1.423 + if((r=nr_transport_addr_to_praddr(addr, &naddr))) 1.424 + ABORT(r); 1.425 + 1.426 + switch (addr->protocol) { 1.427 + case IPPROTO_UDP: 1.428 + if (!(fd_ = PR_NewUDPSocket())) { 1.429 + r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create socket"); 1.430 + ABORT(R_INTERNAL); 1.431 + } 1.432 + break; 1.433 + case IPPROTO_TCP: 1.434 + if (!(fd_ = PR_NewTCPSocket())) { 1.435 + r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create socket"); 1.436 + ABORT(R_INTERNAL); 1.437 + } 1.438 + break; 1.439 + default: 1.440 + ABORT(R_INTERNAL); 1.441 + } 1.442 + 1.443 + status = PR_Bind(fd_, &naddr); 1.444 + if (status != PR_SUCCESS) { 1.445 + r_log(LOG_GENERIC,LOG_CRIT,"Couldn't bind socket to address %s", 1.446 + addr->as_string); 1.447 + ABORT(R_INTERNAL); 1.448 + } 1.449 + 1.450 + r_log(LOG_GENERIC,LOG_DEBUG,"Creating socket %p with addr %s", 1.451 + fd_, addr->as_string); 1.452 + nr_transport_addr_copy(&my_addr_,addr); 1.453 + 1.454 + /* If we have a wildcard port, patch up the addr */ 1.455 + if(nr_transport_addr_is_wildcard(addr)){ 1.456 + status = PR_GetSockName(fd_, &naddr); 1.457 + if (status != PR_SUCCESS){ 1.458 + r_log(LOG_GENERIC, LOG_CRIT, "Couldn't get sock name for socket"); 1.459 + ABORT(R_INTERNAL); 1.460 + } 1.461 + 1.462 + if((r=nr_praddr_to_transport_addr(&naddr,&my_addr_,addr->protocol,1))) 1.463 + ABORT(r); 1.464 + } 1.465 + 1.466 + 1.467 + // Set nonblocking 1.468 + PRSocketOptionData option; 1.469 + option.option = PR_SockOpt_Nonblocking; 1.470 + option.value.non_blocking = PR_TRUE; 1.471 + status = PR_SetSocketOption(fd_, &option); 1.472 + if (status != PR_SUCCESS) { 1.473 + r_log(LOG_GENERIC, LOG_CRIT, "Couldn't make socket nonblocking"); 1.474 + ABORT(R_INTERNAL); 1.475 + } 1.476 + 1.477 + // Remember our thread. 1.478 + ststhread_ = do_QueryInterface(stservice, &rv); 1.479 + if (!NS_SUCCEEDED(rv)) 1.480 + ABORT(R_INTERNAL); 1.481 + 1.482 + // Finally, register with the STS 1.483 + rv = stservice->AttachSocket(fd_, this); 1.484 + if (!NS_SUCCEEDED(rv)) { 1.485 + ABORT(R_INTERNAL); 1.486 + } 1.487 + 1.488 + _status = 0; 1.489 + 1.490 +abort: 1.491 + return(_status); 1.492 +} 1.493 + 1.494 +// This should be called on the STS thread. 1.495 +int NrSocket::sendto(const void *msg, size_t len, 1.496 + int flags, nr_transport_addr *to) { 1.497 + ASSERT_ON_THREAD(ststhread_); 1.498 + int r,_status; 1.499 + PRNetAddr naddr; 1.500 + int32_t status; 1.501 + 1.502 + if ((r=nr_transport_addr_to_praddr(to, &naddr))) 1.503 + ABORT(r); 1.504 + 1.505 + if(fd_==nullptr) 1.506 + ABORT(R_EOD); 1.507 + 1.508 + if (nr_is_stun_request_message((UCHAR*)msg, len)) { 1.509 + // Global rate limiting for stun requests, to mitigate the ice hammer DoS 1.510 + // (see http://tools.ietf.org/html/draft-thomson-mmusic-ice-webrtc) 1.511 + 1.512 + // Tolerate rate of 8k/sec, for one second. 1.513 + static SimpleTokenBucket burst(8192*1, 8192); 1.514 + // Tolerate rate of 3.6k/sec over twenty seconds. 1.515 + static SimpleTokenBucket sustained(3686*20, 3686); 1.516 + 1.517 + // Check number of tokens in each bucket. 1.518 + if (burst.getTokens(UINT32_MAX) < len || 1.519 + sustained.getTokens(UINT32_MAX) < len) { 1.520 + r_log(LOG_GENERIC, LOG_ERR, 1.521 + "Global rate limit for STUN requests exceeded."); 1.522 + MOZ_ASSERT(false, 1.523 + "Global rate limit for STUN requests exceeded. Go bug " 1.524 + "bcampen@mozilla.com if you weren't intentionally spamming " 1.525 + "ICE candidates, or don't know what that means."); 1.526 + ABORT(R_WOULDBLOCK); 1.527 + } 1.528 + 1.529 + // Take len tokens from both buckets. 1.530 + // (not threadsafe, but no problem since this is only called from STS) 1.531 + burst.getTokens(len); 1.532 + sustained.getTokens(len); 1.533 + } 1.534 + 1.535 + // TODO: Convert flags? 1.536 + status = PR_SendTo(fd_, msg, len, flags, &naddr, PR_INTERVAL_NO_WAIT); 1.537 + if (status < 0 || (size_t)status != len) { 1.538 + if (PR_GetError() == PR_WOULD_BLOCK_ERROR) 1.539 + ABORT(R_WOULDBLOCK); 1.540 + 1.541 + r_log(LOG_GENERIC, LOG_INFO, "Error in sendto %s", to->as_string); 1.542 + ABORT(R_IO_ERROR); 1.543 + } 1.544 + 1.545 + _status=0; 1.546 +abort: 1.547 + return(_status); 1.548 +} 1.549 + 1.550 +int NrSocket::recvfrom(void * buf, size_t maxlen, 1.551 + size_t *len, int flags, 1.552 + nr_transport_addr *from) { 1.553 + ASSERT_ON_THREAD(ststhread_); 1.554 + int r,_status; 1.555 + PRNetAddr nfrom; 1.556 + int32_t status; 1.557 + 1.558 + status = PR_RecvFrom(fd_, buf, maxlen, flags, &nfrom, PR_INTERVAL_NO_WAIT); 1.559 + if (status <= 0) { 1.560 + r_log(LOG_GENERIC,LOG_ERR,"Error in recvfrom"); 1.561 + ABORT(R_IO_ERROR); 1.562 + } 1.563 + *len=status; 1.564 + 1.565 + if((r=nr_praddr_to_transport_addr(&nfrom,from,my_addr_.protocol,0))) 1.566 + ABORT(r); 1.567 + 1.568 + //r_log(LOG_GENERIC,LOG_DEBUG,"Read %d bytes from %s",*len,addr->as_string); 1.569 + 1.570 + _status=0; 1.571 +abort: 1.572 + return(_status); 1.573 +} 1.574 + 1.575 +int NrSocket::getaddr(nr_transport_addr *addrp) { 1.576 + ASSERT_ON_THREAD(ststhread_); 1.577 + return nr_transport_addr_copy(addrp, &my_addr_); 1.578 +} 1.579 + 1.580 +// Close the socket so that the STS will detach and then kill it 1.581 +void NrSocket::close() { 1.582 + ASSERT_ON_THREAD(ststhread_); 1.583 + mCondition = NS_BASE_STREAM_CLOSED; 1.584 +} 1.585 + 1.586 + 1.587 +int NrSocket::connect(nr_transport_addr *addr) { 1.588 + ASSERT_ON_THREAD(ststhread_); 1.589 + int r,_status; 1.590 + PRNetAddr naddr; 1.591 + int32_t status; 1.592 + 1.593 + if ((r=nr_transport_addr_to_praddr(addr, &naddr))) 1.594 + ABORT(r); 1.595 + 1.596 + if(!fd_) 1.597 + ABORT(R_EOD); 1.598 + 1.599 + // Note: this just means we tried to connect, not that we 1.600 + // are actually live. 1.601 + connect_invoked_ = true; 1.602 + status = PR_Connect(fd_, &naddr, PR_INTERVAL_NO_WAIT); 1.603 + 1.604 + if (status != PR_SUCCESS) { 1.605 + if (PR_GetError() == PR_IN_PROGRESS_ERROR) 1.606 + ABORT(R_WOULDBLOCK); 1.607 + 1.608 + ABORT(R_IO_ERROR); 1.609 + } 1.610 + 1.611 + _status=0; 1.612 +abort: 1.613 + return(_status); 1.614 +} 1.615 + 1.616 + 1.617 +int NrSocket::write(const void *msg, size_t len, size_t *written) { 1.618 + ASSERT_ON_THREAD(ststhread_); 1.619 + int _status; 1.620 + int32_t status; 1.621 + 1.622 + if (!connect_invoked_) 1.623 + ABORT(R_FAILED); 1.624 + 1.625 + status = PR_Write(fd_, msg, len); 1.626 + if (status < 0) { 1.627 + if (PR_GetError() == PR_WOULD_BLOCK_ERROR) 1.628 + ABORT(R_WOULDBLOCK); 1.629 + ABORT(R_IO_ERROR); 1.630 + } 1.631 + 1.632 + *written = status; 1.633 + 1.634 + _status=0; 1.635 +abort: 1.636 + return _status; 1.637 +} 1.638 + 1.639 +int NrSocket::read(void* buf, size_t maxlen, size_t *len) { 1.640 + ASSERT_ON_THREAD(ststhread_); 1.641 + int _status; 1.642 + int32_t status; 1.643 + 1.644 + if (!connect_invoked_) 1.645 + ABORT(R_FAILED); 1.646 + 1.647 + status = PR_Read(fd_, buf, maxlen); 1.648 + if (status < 0) { 1.649 + if (PR_GetError() == PR_WOULD_BLOCK_ERROR) 1.650 + ABORT(R_WOULDBLOCK); 1.651 + ABORT(R_IO_ERROR); 1.652 + } 1.653 + if (status == 0) 1.654 + ABORT(R_EOD); 1.655 + 1.656 + *len = (size_t)status; // Guaranteed to be > 0 1.657 + _status = 0; 1.658 +abort: 1.659 + return(_status); 1.660 +} 1.661 + 1.662 +// NrSocketIpc Implementation 1.663 +NS_IMPL_ISUPPORTS(NrSocketIpc, nsIUDPSocketInternal) 1.664 + 1.665 +NrSocketIpc::NrSocketIpc(const nsCOMPtr<nsIEventTarget> &main_thread) 1.666 + : err_(false), 1.667 + state_(NR_INIT), 1.668 + main_thread_(main_thread), 1.669 + monitor_("NrSocketIpc") { 1.670 +} 1.671 + 1.672 +// IUDPSocketInternal interfaces 1.673 +// callback while error happened in UDP socket operation 1.674 +NS_IMETHODIMP NrSocketIpc::CallListenerError(const nsACString &type, 1.675 + const nsACString &message, 1.676 + const nsACString &filename, 1.677 + uint32_t line_number, 1.678 + uint32_t column_number) { 1.679 + ASSERT_ON_THREAD(main_thread_); 1.680 + MOZ_ASSERT(type.EqualsLiteral("onerror")); 1.681 + 1.682 + r_log(LOG_GENERIC, LOG_ERR, "UDP socket error:%s at %s:%d:%d", 1.683 + message.BeginReading(), filename.BeginReading(), 1.684 + line_number, column_number); 1.685 + 1.686 + ReentrantMonitorAutoEnter mon(monitor_); 1.687 + err_ = true; 1.688 + monitor_.NotifyAll(); 1.689 + 1.690 + return NS_OK; 1.691 +} 1.692 + 1.693 +// callback while receiving UDP packet 1.694 +NS_IMETHODIMP NrSocketIpc::CallListenerReceivedData(const nsACString &type, 1.695 + const nsACString &host, 1.696 + uint16_t port, uint8_t *data, 1.697 + uint32_t data_length) { 1.698 + ASSERT_ON_THREAD(main_thread_); 1.699 + MOZ_ASSERT(type.EqualsLiteral("ondata")); 1.700 + 1.701 + PRNetAddr addr; 1.702 + memset(&addr, 0, sizeof(addr)); 1.703 + 1.704 + { 1.705 + ReentrantMonitorAutoEnter mon(monitor_); 1.706 + 1.707 + if (PR_SUCCESS != PR_StringToNetAddr(host.BeginReading(), &addr)) { 1.708 + err_ = true; 1.709 + MOZ_ASSERT(false, "Failed to convert remote host to PRNetAddr"); 1.710 + return NS_OK; 1.711 + } 1.712 + 1.713 + // Use PR_IpAddrNull to avoid address being reset to 0. 1.714 + if (PR_SUCCESS != PR_SetNetAddr(PR_IpAddrNull, addr.raw.family, port, &addr)) { 1.715 + err_ = true; 1.716 + MOZ_ASSERT(false, "Failed to set port in PRNetAddr"); 1.717 + return NS_OK; 1.718 + } 1.719 + } 1.720 + 1.721 + nsAutoPtr<DataBuffer> buf(new DataBuffer(data, data_length)); 1.722 + RefPtr<nr_udp_message> msg(new nr_udp_message(addr, buf)); 1.723 + 1.724 + RUN_ON_THREAD(sts_thread_, 1.725 + mozilla::WrapRunnable(nsRefPtr<NrSocketIpc>(this), 1.726 + &NrSocketIpc::recv_callback_s, 1.727 + msg), 1.728 + NS_DISPATCH_NORMAL); 1.729 + return NS_OK; 1.730 +} 1.731 + 1.732 +// callback while UDP socket is opened or closed 1.733 +NS_IMETHODIMP NrSocketIpc::CallListenerVoid(const nsACString &type) { 1.734 + ASSERT_ON_THREAD(main_thread_); 1.735 + if (type.EqualsLiteral("onopen")) { 1.736 + ReentrantMonitorAutoEnter mon(monitor_); 1.737 + 1.738 + uint16_t port; 1.739 + if (NS_FAILED(socket_child_->GetLocalPort(&port))) { 1.740 + err_ = true; 1.741 + MOZ_ASSERT(false, "Failed to get local port"); 1.742 + return NS_OK; 1.743 + } 1.744 + 1.745 + nsAutoCString address; 1.746 + if(NS_FAILED(socket_child_->GetLocalAddress(address))) { 1.747 + err_ = true; 1.748 + MOZ_ASSERT(false, "Failed to get local address"); 1.749 + return NS_OK; 1.750 + } 1.751 + 1.752 + PRNetAddr praddr; 1.753 + if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, port, &praddr)) { 1.754 + err_ = true; 1.755 + MOZ_ASSERT(false, "Failed to set port in PRNetAddr"); 1.756 + return NS_OK; 1.757 + } 1.758 + 1.759 + if (PR_SUCCESS != PR_StringToNetAddr(address.BeginReading(), &praddr)) { 1.760 + err_ = true; 1.761 + MOZ_ASSERT(false, "Failed to convert local host to PRNetAddr"); 1.762 + return NS_OK; 1.763 + } 1.764 + 1.765 + nr_transport_addr expected_addr; 1.766 + if(nr_transport_addr_copy(&expected_addr, &my_addr_)) { 1.767 + err_ = true; 1.768 + MOZ_ASSERT(false, "Failed to copy my_addr_"); 1.769 + } 1.770 + 1.771 + if (nr_praddr_to_transport_addr(&praddr, &my_addr_, IPPROTO_UDP, 1)) { 1.772 + err_ = true; 1.773 + MOZ_ASSERT(false, "Failed to copy local host to my_addr_"); 1.774 + } 1.775 + 1.776 + if (nr_transport_addr_cmp(&expected_addr, &my_addr_, 1.777 + NR_TRANSPORT_ADDR_CMP_MODE_ADDR)) { 1.778 + err_ = true; 1.779 + MOZ_ASSERT(false, "Address of opened socket is not expected"); 1.780 + } 1.781 + 1.782 + mon.NotifyAll(); 1.783 + } else if (type.EqualsLiteral("onclose")) { 1.784 + // Already handled in UpdateReadyState, nothing to do here 1.785 + } else { 1.786 + MOZ_ASSERT(false, "Received unexpected event"); 1.787 + } 1.788 + 1.789 + return NS_OK; 1.790 +} 1.791 + 1.792 +// callback while UDP packet is sent 1.793 +NS_IMETHODIMP NrSocketIpc::CallListenerSent(const nsACString &type, 1.794 + nsresult result) { 1.795 + ASSERT_ON_THREAD(main_thread_); 1.796 + MOZ_ASSERT(type.EqualsLiteral("onsent")); 1.797 + 1.798 + if (NS_FAILED(result)) { 1.799 + ReentrantMonitorAutoEnter mon(monitor_); 1.800 + err_ = true; 1.801 + } 1.802 + return NS_OK; 1.803 +} 1.804 + 1.805 +// callback for state update after every socket operation 1.806 +NS_IMETHODIMP NrSocketIpc::UpdateReadyState(const nsACString &readyState) { 1.807 + ASSERT_ON_THREAD(main_thread_); 1.808 + 1.809 + ReentrantMonitorAutoEnter mon(monitor_); 1.810 + 1.811 + if (readyState.EqualsLiteral("closed")) { 1.812 + MOZ_ASSERT(state_ == NR_CONNECTED || state_ == NR_CLOSING); 1.813 + state_ = NR_CLOSED; 1.814 + } 1.815 + 1.816 + return NS_OK; 1.817 +} 1.818 + 1.819 +// nr_socket public APIs 1.820 +int NrSocketIpc::create(nr_transport_addr *addr) { 1.821 + ASSERT_ON_THREAD(sts_thread_); 1.822 + 1.823 + int r, _status; 1.824 + nsresult rv; 1.825 + int32_t port; 1.826 + nsCString host; 1.827 + 1.828 + ReentrantMonitorAutoEnter mon(monitor_); 1.829 + 1.830 + if (state_ != NR_INIT) { 1.831 + ABORT(R_INTERNAL); 1.832 + } 1.833 + 1.834 + sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); 1.835 + if (NS_FAILED(rv)) { 1.836 + MOZ_ASSERT(false, "Failed to get STS thread"); 1.837 + ABORT(R_INTERNAL); 1.838 + } 1.839 + 1.840 + if ((r=nr_transport_addr_get_addrstring_and_port(addr, &host, &port))) { 1.841 + ABORT(r); 1.842 + } 1.843 + 1.844 + // wildcard address will be resolved at NrSocketIpc::CallListenerVoid 1.845 + if ((r=nr_transport_addr_copy(&my_addr_, addr))) { 1.846 + ABORT(r); 1.847 + } 1.848 + 1.849 + state_ = NR_CONNECTING; 1.850 + 1.851 + RUN_ON_THREAD(main_thread_, 1.852 + mozilla::WrapRunnable(nsRefPtr<NrSocketIpc>(this), 1.853 + &NrSocketIpc::create_m, 1.854 + host, static_cast<uint16_t>(port)), 1.855 + NS_DISPATCH_NORMAL); 1.856 + 1.857 + // Wait until socket creation complete. 1.858 + mon.Wait(); 1.859 + 1.860 + if (err_) { 1.861 + ABORT(R_INTERNAL); 1.862 + } 1.863 + 1.864 + state_ = NR_CONNECTED; 1.865 + 1.866 + _status = 0; 1.867 +abort: 1.868 + return(_status); 1.869 +} 1.870 + 1.871 +int NrSocketIpc::sendto(const void *msg, size_t len, int flags, 1.872 + nr_transport_addr *to) { 1.873 + ASSERT_ON_THREAD(sts_thread_); 1.874 + 1.875 + ReentrantMonitorAutoEnter mon(monitor_); 1.876 + 1.877 + //If send err happened before, simply return the error. 1.878 + if (err_) { 1.879 + return R_IO_ERROR; 1.880 + } 1.881 + 1.882 + if (!socket_child_) { 1.883 + return R_EOD; 1.884 + } 1.885 + 1.886 + if (state_ != NR_CONNECTED) { 1.887 + return R_INTERNAL; 1.888 + } 1.889 + 1.890 + int r; 1.891 + net::NetAddr addr; 1.892 + if ((r=nr_transport_addr_to_netaddr(to, &addr))) { 1.893 + return r; 1.894 + } 1.895 + 1.896 + nsAutoPtr<DataBuffer> buf(new DataBuffer(static_cast<const uint8_t*>(msg), len)); 1.897 + 1.898 + RUN_ON_THREAD(main_thread_, 1.899 + mozilla::WrapRunnable(nsRefPtr<NrSocketIpc>(this), 1.900 + &NrSocketIpc::sendto_m, 1.901 + addr, buf), 1.902 + NS_DISPATCH_NORMAL); 1.903 + return 0; 1.904 +} 1.905 + 1.906 +void NrSocketIpc::close() { 1.907 + ASSERT_ON_THREAD(sts_thread_); 1.908 + 1.909 + ReentrantMonitorAutoEnter mon(monitor_); 1.910 + state_ = NR_CLOSING; 1.911 + 1.912 + RUN_ON_THREAD(main_thread_, 1.913 + mozilla::WrapRunnable(nsRefPtr<NrSocketIpc>(this), 1.914 + &NrSocketIpc::close_m), 1.915 + NS_DISPATCH_NORMAL); 1.916 + 1.917 + //remove all enqueued messages 1.918 + std::queue<RefPtr<nr_udp_message> > empty; 1.919 + std::swap(received_msgs_, empty); 1.920 +} 1.921 + 1.922 +int NrSocketIpc::recvfrom(void *buf, size_t maxlen, size_t *len, int flags, 1.923 + nr_transport_addr *from) { 1.924 + ASSERT_ON_THREAD(sts_thread_); 1.925 + 1.926 + ReentrantMonitorAutoEnter mon(monitor_); 1.927 + 1.928 + int r, _status; 1.929 + uint32_t consumed_len; 1.930 + 1.931 + *len = 0; 1.932 + 1.933 + if (state_ != NR_CONNECTED) { 1.934 + ABORT(R_INTERNAL); 1.935 + } 1.936 + 1.937 + if (received_msgs_.empty()) { 1.938 + ABORT(R_WOULDBLOCK); 1.939 + } 1.940 + 1.941 + { 1.942 + RefPtr<nr_udp_message> msg(received_msgs_.front()); 1.943 + 1.944 + received_msgs_.pop(); 1.945 + 1.946 + if ((r=nr_praddr_to_transport_addr(&msg->from, from, IPPROTO_UDP, 0))) { 1.947 + err_ = true; 1.948 + MOZ_ASSERT(false, "Get bogus address for received UDP packet"); 1.949 + ABORT(r); 1.950 + } 1.951 + 1.952 + consumed_len = std::min(maxlen, msg->data->len()); 1.953 + if (consumed_len < msg->data->len()) { 1.954 + r_log(LOG_GENERIC, LOG_DEBUG, "Partial received UDP packet will be discard"); 1.955 + } 1.956 + 1.957 + memcpy(buf, msg->data->data(), consumed_len); 1.958 + *len = consumed_len; 1.959 + } 1.960 + 1.961 + _status = 0; 1.962 +abort: 1.963 + return(_status); 1.964 +} 1.965 + 1.966 +int NrSocketIpc::getaddr(nr_transport_addr *addrp) { 1.967 + ASSERT_ON_THREAD(sts_thread_); 1.968 + 1.969 + ReentrantMonitorAutoEnter mon(monitor_); 1.970 + 1.971 + if (state_ != NR_CONNECTED) { 1.972 + return R_INTERNAL; 1.973 + } 1.974 + 1.975 + return nr_transport_addr_copy(addrp, &my_addr_); 1.976 +} 1.977 + 1.978 +int NrSocketIpc::connect(nr_transport_addr *addr) { 1.979 + MOZ_ASSERT(false); 1.980 + return R_INTERNAL; 1.981 +} 1.982 + 1.983 +int NrSocketIpc::write(const void *msg, size_t len, size_t *written) { 1.984 + MOZ_ASSERT(false); 1.985 + return R_INTERNAL; 1.986 +} 1.987 + 1.988 +int NrSocketIpc::read(void* buf, size_t maxlen, size_t *len) { 1.989 + MOZ_ASSERT(false); 1.990 + return R_INTERNAL; 1.991 +} 1.992 + 1.993 +// Main thread executors 1.994 +void NrSocketIpc::create_m(const nsACString &host, const uint16_t port) { 1.995 + ASSERT_ON_THREAD(main_thread_); 1.996 + 1.997 + ReentrantMonitorAutoEnter mon(monitor_); 1.998 + 1.999 + nsresult rv; 1.1000 + socket_child_ = do_CreateInstance("@mozilla.org/udp-socket-child;1", &rv); 1.1001 + if (NS_FAILED(rv)) { 1.1002 + err_ = true; 1.1003 + MOZ_ASSERT(false, "Failed to create UDPSocketChild"); 1.1004 + } 1.1005 + 1.1006 + socket_child_->SetFilterName(nsCString("stun")); 1.1007 + 1.1008 + if (NS_FAILED(socket_child_->Bind(this, host, port))) { 1.1009 + err_ = true; 1.1010 + MOZ_ASSERT(false, "Failed to create UDP socket"); 1.1011 + } 1.1012 +} 1.1013 + 1.1014 +void NrSocketIpc::sendto_m(const net::NetAddr &addr, nsAutoPtr<DataBuffer> buf) { 1.1015 + ASSERT_ON_THREAD(main_thread_); 1.1016 + 1.1017 + MOZ_ASSERT(socket_child_); 1.1018 + 1.1019 + ReentrantMonitorAutoEnter mon(monitor_); 1.1020 + 1.1021 + if (NS_FAILED(socket_child_->SendWithAddress(&addr, 1.1022 + buf->data(), 1.1023 + buf->len()))) { 1.1024 + err_ = true; 1.1025 + } 1.1026 +} 1.1027 + 1.1028 +void NrSocketIpc::close_m() { 1.1029 + ASSERT_ON_THREAD(main_thread_); 1.1030 + 1.1031 + if (socket_child_) { 1.1032 + socket_child_->Close(); 1.1033 + socket_child_ = nullptr; 1.1034 + } 1.1035 +} 1.1036 + 1.1037 +void NrSocketIpc::recv_callback_s(RefPtr<nr_udp_message> msg) { 1.1038 + ASSERT_ON_THREAD(sts_thread_); 1.1039 + 1.1040 + { 1.1041 + ReentrantMonitorAutoEnter mon(monitor_); 1.1042 + if (state_ != NR_CONNECTED) { 1.1043 + return; 1.1044 + } 1.1045 + } 1.1046 + 1.1047 + //enqueue received message 1.1048 + received_msgs_.push(msg); 1.1049 + 1.1050 + if ((poll_flags() & PR_POLL_READ)) { 1.1051 + fire_callback(NR_ASYNC_WAIT_READ); 1.1052 + } 1.1053 +} 1.1054 + 1.1055 +} // close namespace 1.1056 + 1.1057 + 1.1058 +using namespace mozilla; 1.1059 + 1.1060 +// Bridge to the nr_socket interface 1.1061 +static int nr_socket_local_destroy(void **objp); 1.1062 +static int nr_socket_local_sendto(void *obj,const void *msg, size_t len, 1.1063 + int flags, nr_transport_addr *to); 1.1064 +static int nr_socket_local_recvfrom(void *obj,void * restrict buf, 1.1065 + size_t maxlen, size_t *len, int flags, nr_transport_addr *from); 1.1066 +static int nr_socket_local_getfd(void *obj, NR_SOCKET *fd); 1.1067 +static int nr_socket_local_getaddr(void *obj, nr_transport_addr *addrp); 1.1068 +static int nr_socket_local_close(void *obj); 1.1069 +static int nr_socket_local_connect(void *sock, nr_transport_addr *addr); 1.1070 +static int nr_socket_local_write(void *obj,const void *msg, size_t len, 1.1071 + size_t *written); 1.1072 +static int nr_socket_local_read(void *obj,void * restrict buf, size_t maxlen, 1.1073 + size_t *len); 1.1074 + 1.1075 +static nr_socket_vtbl nr_socket_local_vtbl={ 1.1076 + 1, 1.1077 + nr_socket_local_destroy, 1.1078 + nr_socket_local_sendto, 1.1079 + nr_socket_local_recvfrom, 1.1080 + nr_socket_local_getfd, 1.1081 + nr_socket_local_getaddr, 1.1082 + nr_socket_local_connect, 1.1083 + nr_socket_local_write, 1.1084 + nr_socket_local_read, 1.1085 + nr_socket_local_close 1.1086 +}; 1.1087 + 1.1088 +int nr_socket_local_create(nr_transport_addr *addr, nr_socket **sockp) { 1.1089 + NrSocketBase *sock = nullptr; 1.1090 + 1.1091 + // create IPC bridge for content process 1.1092 + if (XRE_GetProcessType() == GeckoProcessType_Default) { 1.1093 + sock = new NrSocket(); 1.1094 + } else { 1.1095 + nsCOMPtr<nsIThread> main_thread; 1.1096 + NS_GetMainThread(getter_AddRefs(main_thread)); 1.1097 + sock = new NrSocketIpc(main_thread.get()); 1.1098 + } 1.1099 + 1.1100 + int r, _status; 1.1101 + 1.1102 + r = sock->create(addr); 1.1103 + if (r) 1.1104 + ABORT(r); 1.1105 + 1.1106 + r = nr_socket_create_int(static_cast<void *>(sock), 1.1107 + sock->vtbl(), sockp); 1.1108 + if (r) 1.1109 + ABORT(r); 1.1110 + 1.1111 + // Add a reference so that we can delete it in destroy() 1.1112 + sock->AddRef(); 1.1113 + 1.1114 + _status = 0; 1.1115 + 1.1116 +abort: 1.1117 + if (_status) { 1.1118 + delete sock; 1.1119 + } 1.1120 + return _status; 1.1121 +} 1.1122 + 1.1123 + 1.1124 +static int nr_socket_local_destroy(void **objp) { 1.1125 + if(!objp || !*objp) 1.1126 + return 0; 1.1127 + 1.1128 + NrSocketBase *sock = static_cast<NrSocketBase *>(*objp); 1.1129 + *objp=0; 1.1130 + 1.1131 + sock->close(); // Signal STS that we want not to listen 1.1132 + sock->Release(); // Decrement the ref count 1.1133 + 1.1134 + return 0; 1.1135 +} 1.1136 + 1.1137 +static int nr_socket_local_sendto(void *obj,const void *msg, size_t len, 1.1138 + int flags, nr_transport_addr *addr) { 1.1139 + NrSocketBase *sock = static_cast<NrSocketBase *>(obj); 1.1140 + 1.1141 + return sock->sendto(msg, len, flags, addr); 1.1142 +} 1.1143 + 1.1144 +static int nr_socket_local_recvfrom(void *obj,void * restrict buf, 1.1145 + size_t maxlen, size_t *len, int flags, 1.1146 + nr_transport_addr *addr) { 1.1147 + NrSocketBase *sock = static_cast<NrSocketBase *>(obj); 1.1148 + 1.1149 + return sock->recvfrom(buf, maxlen, len, flags, addr); 1.1150 +} 1.1151 + 1.1152 +static int nr_socket_local_getfd(void *obj, NR_SOCKET *fd) { 1.1153 + NrSocketBase *sock = static_cast<NrSocketBase *>(obj); 1.1154 + 1.1155 + *fd = sock; 1.1156 + 1.1157 + return 0; 1.1158 +} 1.1159 + 1.1160 +static int nr_socket_local_getaddr(void *obj, nr_transport_addr *addrp) { 1.1161 + NrSocketBase *sock = static_cast<NrSocketBase *>(obj); 1.1162 + 1.1163 + return sock->getaddr(addrp); 1.1164 +} 1.1165 + 1.1166 + 1.1167 +static int nr_socket_local_close(void *obj) { 1.1168 + NrSocketBase *sock = static_cast<NrSocketBase *>(obj); 1.1169 + 1.1170 + sock->close(); 1.1171 + 1.1172 + return 0; 1.1173 +} 1.1174 + 1.1175 +static int nr_socket_local_write(void *obj, const void *msg, size_t len, 1.1176 + size_t *written) { 1.1177 + NrSocket *sock = static_cast<NrSocket *>(obj); 1.1178 + 1.1179 + return sock->write(msg, len, written); 1.1180 +} 1.1181 + 1.1182 +static int nr_socket_local_read(void *obj, void * restrict buf, size_t maxlen, 1.1183 + size_t *len) { 1.1184 + NrSocket *sock = static_cast<NrSocket *>(obj); 1.1185 + 1.1186 + return sock->read(buf, maxlen, len); 1.1187 +} 1.1188 + 1.1189 +static int nr_socket_local_connect(void *obj, nr_transport_addr *addr) { 1.1190 + NrSocket *sock = static_cast<NrSocket *>(obj); 1.1191 + 1.1192 + return sock->connect(addr); 1.1193 +} 1.1194 + 1.1195 +// Implement async api 1.1196 +int NR_async_wait(NR_SOCKET sock, int how, NR_async_cb cb,void *cb_arg, 1.1197 + char *function,int line) { 1.1198 + NrSocketBase *s = static_cast<NrSocketBase *>(sock); 1.1199 + 1.1200 + return s->async_wait(how, cb, cb_arg, function, line); 1.1201 +} 1.1202 + 1.1203 +int NR_async_cancel(NR_SOCKET sock,int how) { 1.1204 + NrSocketBase *s = static_cast<NrSocketBase *>(sock); 1.1205 + 1.1206 + return s->cancel(how); 1.1207 +} 1.1208 + 1.1209 +nr_socket_vtbl* NrSocketBase::vtbl() { 1.1210 + return &nr_socket_local_vtbl; 1.1211 +} 1.1212 +