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