OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/udp/udp_socket_libevent.h" | 5 #include "net/udp/udp_socket_libevent.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <netdb.h> | 9 #include <netdb.h> |
10 #include <sys/socket.h> | 10 #include <sys/socket.h> |
(...skipping 23 matching lines...) Expand all Loading... | |
34 } // namespace net | 34 } // namespace net |
35 | 35 |
36 namespace net { | 36 namespace net { |
37 | 37 |
38 UDPSocketLibevent::UDPSocketLibevent( | 38 UDPSocketLibevent::UDPSocketLibevent( |
39 DatagramSocket::BindType bind_type, | 39 DatagramSocket::BindType bind_type, |
40 const RandIntCallback& rand_int_cb, | 40 const RandIntCallback& rand_int_cb, |
41 net::NetLog* net_log, | 41 net::NetLog* net_log, |
42 const net::NetLog::Source& source) | 42 const net::NetLog::Source& source) |
43 : socket_(kInvalidSocket), | 43 : socket_(kInvalidSocket), |
44 sock_addr_family_(0), | |
44 socket_options_(0), | 45 socket_options_(0), |
46 multicast_time_to_live_(1), | |
47 multicast_loopback_mode_(true), | |
45 bind_type_(bind_type), | 48 bind_type_(bind_type), |
46 rand_int_cb_(rand_int_cb), | 49 rand_int_cb_(rand_int_cb), |
47 read_watcher_(this), | 50 read_watcher_(this), |
48 write_watcher_(this), | 51 write_watcher_(this), |
49 read_buf_len_(0), | 52 read_buf_len_(0), |
50 recv_from_address_(NULL), | 53 recv_from_address_(NULL), |
51 write_buf_len_(0), | 54 write_buf_len_(0), |
52 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) { | 55 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) { |
53 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, | 56 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, |
54 source.ToEventParametersCallback()); | 57 source.ToEventParametersCallback()); |
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
356 CreateNetLogUDPDataTranferCallback( | 359 CreateNetLogUDPDataTranferCallback( |
357 result, bytes, | 360 result, bytes, |
358 is_address_valid ? &address : NULL)); | 361 is_address_valid ? &address : NULL)); |
359 } | 362 } |
360 | 363 |
361 base::StatsCounter read_bytes("udp.read_bytes"); | 364 base::StatsCounter read_bytes("udp.read_bytes"); |
362 read_bytes.Add(result); | 365 read_bytes.Add(result); |
363 } | 366 } |
364 | 367 |
365 int UDPSocketLibevent::CreateSocket(const IPEndPoint& address) { | 368 int UDPSocketLibevent::CreateSocket(const IPEndPoint& address) { |
366 socket_ = socket(address.GetSockAddrFamily(), SOCK_DGRAM, 0); | 369 sock_addr_family_ = address.GetSockAddrFamily(); |
370 socket_ = socket(sock_addr_family_, SOCK_DGRAM, 0); | |
367 if (socket_ == kInvalidSocket) | 371 if (socket_ == kInvalidSocket) |
368 return MapSystemError(errno); | 372 return MapSystemError(errno); |
369 if (SetNonBlocking(socket_)) { | 373 if (SetNonBlocking(socket_)) { |
370 const int err = MapSystemError(errno); | 374 const int err = MapSystemError(errno); |
371 Close(); | 375 Close(); |
372 return err; | 376 return err; |
373 } | 377 } |
374 return OK; | 378 return OK; |
375 } | 379 } |
376 | 380 |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
469 return MapSystemError(errno); | 473 return MapSystemError(errno); |
470 } | 474 } |
471 if (socket_options_ & SOCKET_OPTION_BROADCAST) { | 475 if (socket_options_ & SOCKET_OPTION_BROADCAST) { |
472 int rv; | 476 int rv; |
473 #if defined(OS_MACOSX) | 477 #if defined(OS_MACOSX) |
474 // SO_REUSEPORT on OSX permits multiple processes to each receive | 478 // SO_REUSEPORT on OSX permits multiple processes to each receive |
475 // UDP multicast or broadcast datagrams destined for the bound | 479 // UDP multicast or broadcast datagrams destined for the bound |
476 // port. | 480 // port. |
477 rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &true_value, | 481 rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &true_value, |
478 sizeof(true_value)); | 482 sizeof(true_value)); |
483 #else | |
484 rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &true_value, | |
485 sizeof(true_value)); | |
mmenke
2013/04/16 18:09:49
This needs to be done on OSX, too.
Bei Zhang
2013/04/17 17:53:03
It's done in the other #if branch.
| |
486 #endif // defined(OS_MACOSX) | |
479 if (rv < 0) | 487 if (rv < 0) |
480 return MapSystemError(errno); | 488 return MapSystemError(errno); |
481 #endif // defined(OS_MACOSX) | 489 } |
482 rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &true_value, | 490 if (multicast_time_to_live_ != 1) { |
483 sizeof(true_value)); | 491 int rv = SetMulticastTimeToLive(multicast_time_to_live_); |
484 if (rv < 0) | 492 if (rv != OK) |
485 return MapSystemError(errno); | 493 return rv; |
494 } | |
495 if (!multicast_loopback_mode_) { | |
496 int rv = SetMulticastLoopbackMode(multicast_loopback_mode_); | |
497 if (rv != OK) | |
498 return rv; | |
486 } | 499 } |
487 return OK; | 500 return OK; |
488 } | 501 } |
489 | 502 |
490 int UDPSocketLibevent::DoBind(const IPEndPoint& address) { | 503 int UDPSocketLibevent::DoBind(const IPEndPoint& address) { |
491 SockaddrStorage storage; | 504 SockaddrStorage storage; |
492 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) | 505 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) |
493 return ERR_UNEXPECTED; | 506 return ERR_UNEXPECTED; |
494 int rv = bind(socket_, storage.addr, storage.addr_len); | 507 int rv = bind(socket_, storage.addr, storage.addr_len); |
495 return rv < 0 ? MapSystemError(errno) : rv; | 508 return rv < 0 ? MapSystemError(errno) : rv; |
496 } | 509 } |
497 | 510 |
498 int UDPSocketLibevent::RandomBind(const IPEndPoint& address) { | 511 int UDPSocketLibevent::RandomBind(const IPEndPoint& address) { |
499 DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null()); | 512 DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null()); |
500 | 513 |
501 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s. | 514 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s. |
502 IPAddressNumber ip(address.address().size()); | 515 IPAddressNumber ip(address.address().size()); |
503 | 516 |
504 for (int i = 0; i < kBindRetries; ++i) { | 517 for (int i = 0; i < kBindRetries; ++i) { |
505 int rv = DoBind(IPEndPoint(ip, rand_int_cb_.Run(kPortStart, kPortEnd))); | 518 int rv = DoBind(IPEndPoint(ip, rand_int_cb_.Run(kPortStart, kPortEnd))); |
506 if (rv == OK || rv != ERR_ADDRESS_IN_USE) | 519 if (rv == OK || rv != ERR_ADDRESS_IN_USE) |
507 return rv; | 520 return rv; |
508 } | 521 } |
509 return DoBind(IPEndPoint(ip, 0)); | 522 return DoBind(IPEndPoint(ip, 0)); |
510 } | 523 } |
511 | 524 |
525 int UDPSocketLibevent::JoinGroup( | |
526 const net::IPAddressNumber& group_address) const { | |
527 DCHECK(CalledOnValidThread()); | |
528 DCHECK(is_connected()); | |
529 | |
530 int rv = -1; | |
mmenke
2013/04/16 18:09:49
Sending a -1 through MapSystemError on fall throug
Bei Zhang
2013/04/17 17:53:03
Done.
| |
531 switch (group_address.size()) { | |
532 case kIPv4AddressSize: { | |
533 if (sock_addr_family_ != AF_INET) | |
534 return ERR_ADDRESS_INVALID; | |
535 ip_mreq mreq; | |
536 memset(&mreq, 0, sizeof(mreq)); | |
537 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize); | |
mmenke
2013/04/16 18:09:49
Seems like we should be explicitely using IN_ADDRA
Bei Zhang
2013/04/17 17:53:03
Done.
| |
538 rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP, | |
539 &mreq, sizeof(mreq)); | |
540 break; | |
541 } | |
542 case kIPv6AddressSize: { | |
543 if (sock_addr_family_ != AF_INET6) | |
544 return ERR_ADDRESS_INVALID; | |
545 ipv6_mreq mreq; | |
546 memset(&mreq, 0, sizeof(mreq)); | |
547 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize); | |
548 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP, | |
549 &mreq, sizeof(mreq)); | |
mmenke
2013/04/16 18:09:49
Seems like we should be explicitely using in6addr_
Bei Zhang
2013/04/17 17:53:03
Done.
| |
550 break; | |
551 } | |
552 } | |
553 | |
554 return MapSystemError(rv); | |
555 } | |
556 | |
557 int UDPSocketLibevent::LeaveGroup( | |
558 const net::IPAddressNumber& group_address) const { | |
559 DCHECK(CalledOnValidThread()); | |
560 DCHECK(is_connected()); | |
561 | |
562 int rv = -1; | |
563 switch (group_address.size()) { | |
564 case kIPv4AddressSize: { | |
565 if (sock_addr_family_ != AF_INET) | |
566 return ERR_ADDRESS_INVALID; | |
567 ip_mreq mreq; | |
568 memset(&mreq, 0, sizeof(mreq)); | |
569 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize); | |
570 rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP, | |
571 &mreq, sizeof(mreq)); | |
572 break; | |
573 } | |
574 case kIPv6AddressSize: { | |
575 if (sock_addr_family_ != AF_INET6) | |
576 return ERR_ADDRESS_INVALID; | |
577 ipv6_mreq mreq; | |
578 memset(&mreq, 0, sizeof(mreq)); | |
579 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize); | |
580 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_LEAVE_GROUP, | |
581 &mreq, sizeof(mreq)); | |
582 break; | |
583 } | |
584 } | |
585 | |
586 return MapSystemError(rv); | |
587 } | |
588 | |
589 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) { | |
590 DCHECK(CalledOnValidThread()); | |
591 if (time_to_live < 0 || time_to_live > 255) | |
592 return ERR_INVALID_ARGUMENT; | |
593 if (is_connected()) { | |
mmenke
2013/04/16 18:09:49
Do we need these to be dynamically configurable?
Bei Zhang
2013/04/17 17:53:03
I thought about this for a while. I think you are
| |
594 uint8 ttl = time_to_live; | |
595 int ip_family = sock_addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; | |
596 return MapSystemError(setsockopt(socket_, | |
597 ip_family, | |
598 IP_MULTICAST_TTL, | |
599 &ttl, sizeof(ttl))); | |
600 } else { | |
mmenke
2013/04/16 18:09:49
Preferred style in Chrome is not to have an else h
Bei Zhang
2013/04/17 17:53:03
Done.
| |
601 multicast_time_to_live_ = time_to_live; | |
602 return OK; | |
603 } | |
604 } | |
605 | |
606 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback) { | |
607 DCHECK(CalledOnValidThread()); | |
608 if (is_connected()) { | |
609 uint8 loop = loopback; | |
610 int ip_family = sock_addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; | |
611 return MapSystemError(setsockopt(socket_, | |
612 ip_family, | |
613 IP_MULTICAST_LOOP, | |
614 &loop, sizeof(loop))); | |
615 } else { | |
616 multicast_loopback_mode_ = loopback; | |
617 return OK; | |
618 } | |
619 } | |
512 } // namespace net | 620 } // namespace net |
OLD | NEW |