Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(210)

Side by Side Diff: net/udp/udp_socket_libevent.cc

Issue 99923004: Add support of IP_MULTICAST_IF in UDP sockets. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 <net/if.h>
11 #include <netinet/in.h>
12 #include <sys/ioctl.h>
10 #include <sys/socket.h> 13 #include <sys/socket.h>
11 #include <netinet/in.h>
12 14
13 #include "base/callback.h" 15 #include "base/callback.h"
14 #include "base/logging.h" 16 #include "base/logging.h"
15 #include "base/message_loop/message_loop.h" 17 #include "base/message_loop/message_loop.h"
16 #include "base/metrics/stats_counters.h" 18 #include "base/metrics/stats_counters.h"
17 #include "base/posix/eintr_wrapper.h" 19 #include "base/posix/eintr_wrapper.h"
18 #include "base/rand_util.h" 20 #include "base/rand_util.h"
19 #include "net/base/io_buffer.h" 21 #include "net/base/io_buffer.h"
20 #include "net/base/ip_endpoint.h" 22 #include "net/base/ip_endpoint.h"
21 #include "net/base/net_errors.h" 23 #include "net/base/net_errors.h"
22 #include "net/base/net_log.h" 24 #include "net/base/net_log.h"
23 #include "net/base/net_util.h" 25 #include "net/base/net_util.h"
24 #include "net/socket/socket_descriptor.h" 26 #include "net/socket/socket_descriptor.h"
25 #include "net/udp/udp_net_log_parameters.h" 27 #include "net/udp/udp_net_log_parameters.h"
26 28
27 namespace { 29 namespace {
28 30
29 const int kBindRetries = 10; 31 const int kBindRetries = 10;
30 const int kPortStart = 1024; 32 const int kPortStart = 1024;
31 const int kPortEnd = 65535; 33 const int kPortEnd = 65535;
32 34
35 #if defined(OS_MACOSX)
36 uint32 GetIPv4AddressFromIndex(int socket, uint32 index){
szym 2013/12/04 00:52:15 Add comment: // Returns IPv4 address in network or
Vitaly Buka (NO REVIEWS) 2013/12/04 09:39:36 Done.
37 if (!index)
38 return htonl(INADDR_ANY);
39 ifreq ifr;
40 ifr.ifr_addr.sa_family = AF_INET;
41 if (!if_indextoname(index, ifr.ifr_name))
42 return htonl(INADDR_ANY);
43 if (ioctl(socket, SIOCGIFADDR, &ifr))
44 return htonl(INADDR_ANY);
szym 2013/12/04 00:52:15 I am a bit concerned about this failure mode. If
Vitaly Buka (NO REVIEWS) 2013/12/04 01:00:49 For current use-cases returning error is not a pro
Vitaly Buka (NO REVIEWS) 2013/12/04 09:39:36 Done.
45 return reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr.s_addr;
46 }
47 #endif // OS_MACOSX
48
33 } // namespace 49 } // namespace
34 50
35 namespace net { 51 namespace net {
36 52
37 UDPSocketLibevent::UDPSocketLibevent( 53 UDPSocketLibevent::UDPSocketLibevent(
38 DatagramSocket::BindType bind_type, 54 DatagramSocket::BindType bind_type,
39 const RandIntCallback& rand_int_cb, 55 const RandIntCallback& rand_int_cb,
40 net::NetLog* net_log, 56 net::NetLog* net_log,
41 const net::NetLog::Source& source) 57 const net::NetLog::Source& source)
42 : socket_(kInvalidSocket), 58 : socket_(kInvalidSocket),
43 addr_family_(0), 59 addr_family_(0),
44 socket_options_(SOCKET_OPTION_MULTICAST_LOOP), 60 socket_options_(SOCKET_OPTION_MULTICAST_LOOP),
61 multicast_interface_(0),
45 multicast_time_to_live_(1), 62 multicast_time_to_live_(1),
46 bind_type_(bind_type), 63 bind_type_(bind_type),
47 rand_int_cb_(rand_int_cb), 64 rand_int_cb_(rand_int_cb),
48 read_watcher_(this), 65 read_watcher_(this),
49 write_watcher_(this), 66 write_watcher_(this),
50 read_buf_len_(0), 67 read_buf_len_(0),
51 recv_from_address_(NULL), 68 recv_from_address_(NULL),
52 write_buf_len_(0), 69 write_buf_len_(0),
53 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) { 70 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) {
54 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, 71 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
(...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 if (rv < 0) 534 if (rv < 0)
518 return MapSystemError(errno); 535 return MapSystemError(errno);
519 } 536 }
520 if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) { 537 if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) {
521 int rv; 538 int rv;
522 if (addr_family_ == AF_INET) { 539 if (addr_family_ == AF_INET) {
523 u_char ttl = multicast_time_to_live_; 540 u_char ttl = multicast_time_to_live_;
524 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL, 541 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL,
525 &ttl, sizeof(ttl)); 542 &ttl, sizeof(ttl));
526 } else { 543 } else {
527 // Signed interger. -1 to use route default. 544 // Signed integer. -1 to use route default.
528 int ttl = multicast_time_to_live_; 545 int ttl = multicast_time_to_live_;
529 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 546 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
530 &ttl, sizeof(ttl)); 547 &ttl, sizeof(ttl));
531 } 548 }
532 if (rv < 0) 549 if (rv < 0)
533 return MapSystemError(errno); 550 return MapSystemError(errno);
534 } 551 }
552 if (multicast_interface_ != 0) {
553 switch (addr_family_) {
554 case AF_INET: {
555 #if !defined(OS_MACOSX)
556 ip_mreqn mreq;
557 mreq.imr_ifindex = multicast_interface_;
558 mreq.imr_address.s_addr = htonl(INADDR_ANY);
559 #else
560 ip_mreq mreq;
561 mreq.imr_interface.s_addr =
562 GetIPv4AddressFromIndex(socket_, multicast_interface_);
563 #endif
564 int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF,
565 reinterpret_cast<const char*>(&mreq), sizeof(mreq));
566 if (rv)
567 return MapSystemError(errno);
568 break;
569 }
570 case AF_INET6: {
571 uint32 interface_index = multicast_interface_;
572 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_IF,
573 reinterpret_cast<const char*>(&interface_index),
574 sizeof(interface_index));
575 if (rv)
576 return MapSystemError(errno);
577 break;
578 }
579 default:
580 NOTREACHED() << "Invalid address family";
581 return ERR_ADDRESS_INVALID;
582 }
583 }
535 return OK; 584 return OK;
536 } 585 }
537 586
538 int UDPSocketLibevent::DoBind(const IPEndPoint& address) { 587 int UDPSocketLibevent::DoBind(const IPEndPoint& address) {
539 SockaddrStorage storage; 588 SockaddrStorage storage;
540 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) 589 if (!address.ToSockAddr(storage.addr, &storage.addr_len))
541 return ERR_ADDRESS_INVALID; 590 return ERR_ADDRESS_INVALID;
542 int rv = bind(socket_, storage.addr, storage.addr_len); 591 int rv = bind(socket_, storage.addr, storage.addr_len);
543 return rv < 0 ? MapSystemError(errno) : rv; 592 return rv < 0 ? MapSystemError(errno) : rv;
544 } 593 }
(...skipping 14 matching lines...) Expand all
559 608
560 int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const { 609 int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const {
561 DCHECK(CalledOnValidThread()); 610 DCHECK(CalledOnValidThread());
562 if (!is_connected()) 611 if (!is_connected())
563 return ERR_SOCKET_NOT_CONNECTED; 612 return ERR_SOCKET_NOT_CONNECTED;
564 613
565 switch (group_address.size()) { 614 switch (group_address.size()) {
566 case kIPv4AddressSize: { 615 case kIPv4AddressSize: {
567 if (addr_family_ != AF_INET) 616 if (addr_family_ != AF_INET)
568 return ERR_ADDRESS_INVALID; 617 return ERR_ADDRESS_INVALID;
618
619 #if !defined(OS_MACOSX)
620 ip_mreqn mreq;
621 mreq.imr_ifindex = multicast_interface_;
622 mreq.imr_address.s_addr = htonl(INADDR_ANY);
623 #else
569 ip_mreq mreq; 624 ip_mreq mreq;
570 mreq.imr_interface.s_addr = INADDR_ANY; 625 mreq.imr_interface.s_addr =
626 GetIPv4AddressFromIndex(socket_, multicast_interface_);
627 #endif
571 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize); 628 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
572 int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP, 629 int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
573 &mreq, sizeof(mreq)); 630 &mreq, sizeof(mreq));
574 if (rv < 0) 631 if (rv < 0)
575 return MapSystemError(errno); 632 return MapSystemError(errno);
576 return OK; 633 return OK;
577 } 634 }
578 case kIPv6AddressSize: { 635 case kIPv6AddressSize: {
579 if (addr_family_ != AF_INET6) 636 if (addr_family_ != AF_INET6)
580 return ERR_ADDRESS_INVALID; 637 return ERR_ADDRESS_INVALID;
581 ipv6_mreq mreq; 638 ipv6_mreq mreq;
582 mreq.ipv6mr_interface = 0; // 0 indicates default multicast interface. 639 mreq.ipv6mr_interface = multicast_interface_;
583 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize); 640 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
584 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP, 641 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP,
585 &mreq, sizeof(mreq)); 642 &mreq, sizeof(mreq));
586 if (rv < 0) 643 if (rv < 0)
587 return MapSystemError(errno); 644 return MapSystemError(errno);
588 return OK; 645 return OK;
589 } 646 }
590 default: 647 default:
591 NOTREACHED() << "Invalid address family"; 648 NOTREACHED() << "Invalid address family";
592 return ERR_ADDRESS_INVALID; 649 return ERR_ADDRESS_INVALID;
(...skipping 30 matching lines...) Expand all
623 if (rv < 0) 680 if (rv < 0)
624 return MapSystemError(errno); 681 return MapSystemError(errno);
625 return OK; 682 return OK;
626 } 683 }
627 default: 684 default:
628 NOTREACHED() << "Invalid address family"; 685 NOTREACHED() << "Invalid address family";
629 return ERR_ADDRESS_INVALID; 686 return ERR_ADDRESS_INVALID;
630 } 687 }
631 } 688 }
632 689
690 int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index) {
691 DCHECK(CalledOnValidThread());
692 if (is_connected())
693 return ERR_SOCKET_IS_CONNECTED;
694 multicast_interface_ = interface_index;
695 return OK;
696 }
697
633 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) { 698 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) {
634 DCHECK(CalledOnValidThread()); 699 DCHECK(CalledOnValidThread());
635 if (is_connected()) 700 if (is_connected())
636 return ERR_SOCKET_IS_CONNECTED; 701 return ERR_SOCKET_IS_CONNECTED;
637 702
638 if (time_to_live < 0 || time_to_live > 255) 703 if (time_to_live < 0 || time_to_live > 255)
639 return ERR_INVALID_ARGUMENT; 704 return ERR_INVALID_ARGUMENT;
640 multicast_time_to_live_ = time_to_live; 705 multicast_time_to_live_ = time_to_live;
641 return OK; 706 return OK;
642 } 707 }
(...skipping 23 matching lines...) Expand all
666 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS, 731 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS,
667 &dscp_and_ecn, sizeof(dscp_and_ecn)); 732 &dscp_and_ecn, sizeof(dscp_and_ecn));
668 } 733 }
669 if (rv < 0) 734 if (rv < 0)
670 return MapSystemError(errno); 735 return MapSystemError(errno);
671 736
672 return OK; 737 return OK;
673 } 738 }
674 739
675 } // namespace net 740 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698