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

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
« no previous file with comments | « net/udp/udp_socket_libevent.h ('k') | net/udp/udp_socket_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
29
30 namespace net {
31
27 namespace { 32 namespace {
28 33
29 const int kBindRetries = 10; 34 const int kBindRetries = 10;
30 const int kPortStart = 1024; 35 const int kPortStart = 1024;
31 const int kPortEnd = 65535; 36 const int kPortEnd = 65535;
32 37
38 #if defined(OS_MACOSX)
39
40 // Returns IPv4 address in network order.
41 int GetIPv4AddressFromIndex(int socket, uint32 index, uint32* address){
42 if (!index) {
43 *address = htonl(INADDR_ANY);
44 return OK;
45 }
46 ifreq ifr;
47 ifr.ifr_addr.sa_family = AF_INET;
48 if (!if_indextoname(index, ifr.ifr_name))
49 return ERR_FAILED;
50 int rv = ioctl(socket, SIOCGIFADDR, &ifr);
51 if (!rv)
52 return MapSystemError(rv);
53 *address = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr.s_addr;
54 return OK;
55 }
56
57 #endif // OS_MACOSX
58
33 } // namespace 59 } // namespace
34 60
35 namespace net {
36
37 UDPSocketLibevent::UDPSocketLibevent( 61 UDPSocketLibevent::UDPSocketLibevent(
38 DatagramSocket::BindType bind_type, 62 DatagramSocket::BindType bind_type,
39 const RandIntCallback& rand_int_cb, 63 const RandIntCallback& rand_int_cb,
40 net::NetLog* net_log, 64 net::NetLog* net_log,
41 const net::NetLog::Source& source) 65 const net::NetLog::Source& source)
42 : socket_(kInvalidSocket), 66 : socket_(kInvalidSocket),
43 addr_family_(0), 67 addr_family_(0),
44 socket_options_(SOCKET_OPTION_MULTICAST_LOOP), 68 socket_options_(SOCKET_OPTION_MULTICAST_LOOP),
69 multicast_interface_(0),
45 multicast_time_to_live_(1), 70 multicast_time_to_live_(1),
46 bind_type_(bind_type), 71 bind_type_(bind_type),
47 rand_int_cb_(rand_int_cb), 72 rand_int_cb_(rand_int_cb),
48 read_watcher_(this), 73 read_watcher_(this),
49 write_watcher_(this), 74 write_watcher_(this),
50 read_buf_len_(0), 75 read_buf_len_(0),
51 recv_from_address_(NULL), 76 recv_from_address_(NULL),
52 write_buf_len_(0), 77 write_buf_len_(0),
53 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) { 78 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) {
54 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, 79 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
(...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 if (rv < 0) 542 if (rv < 0)
518 return MapSystemError(errno); 543 return MapSystemError(errno);
519 } 544 }
520 if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) { 545 if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) {
521 int rv; 546 int rv;
522 if (addr_family_ == AF_INET) { 547 if (addr_family_ == AF_INET) {
523 u_char ttl = multicast_time_to_live_; 548 u_char ttl = multicast_time_to_live_;
524 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL, 549 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL,
525 &ttl, sizeof(ttl)); 550 &ttl, sizeof(ttl));
526 } else { 551 } else {
527 // Signed interger. -1 to use route default. 552 // Signed integer. -1 to use route default.
528 int ttl = multicast_time_to_live_; 553 int ttl = multicast_time_to_live_;
529 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 554 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
530 &ttl, sizeof(ttl)); 555 &ttl, sizeof(ttl));
531 } 556 }
532 if (rv < 0) 557 if (rv < 0)
533 return MapSystemError(errno); 558 return MapSystemError(errno);
534 } 559 }
560 if (multicast_interface_ != 0) {
561 switch (addr_family_) {
562 case AF_INET: {
563 #if !defined(OS_MACOSX)
564 ip_mreqn mreq;
565 mreq.imr_ifindex = multicast_interface_;
566 mreq.imr_address.s_addr = htonl(INADDR_ANY);
567 #else
568 ip_mreq mreq;
569 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
570 &mreq.imr_interface.s_addr);
571 if (error != OK)
572 return error;
573 #endif
574 int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF,
575 reinterpret_cast<const char*>(&mreq), sizeof(mreq));
576 if (rv)
577 return MapSystemError(errno);
578 break;
579 }
580 case AF_INET6: {
581 uint32 interface_index = multicast_interface_;
582 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_IF,
583 reinterpret_cast<const char*>(&interface_index),
584 sizeof(interface_index));
585 if (rv)
586 return MapSystemError(errno);
587 break;
588 }
589 default:
590 NOTREACHED() << "Invalid address family";
591 return ERR_ADDRESS_INVALID;
592 }
593 }
535 return OK; 594 return OK;
536 } 595 }
537 596
538 int UDPSocketLibevent::DoBind(const IPEndPoint& address) { 597 int UDPSocketLibevent::DoBind(const IPEndPoint& address) {
539 SockaddrStorage storage; 598 SockaddrStorage storage;
540 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) 599 if (!address.ToSockAddr(storage.addr, &storage.addr_len))
541 return ERR_ADDRESS_INVALID; 600 return ERR_ADDRESS_INVALID;
542 int rv = bind(socket_, storage.addr, storage.addr_len); 601 int rv = bind(socket_, storage.addr, storage.addr_len);
543 return rv < 0 ? MapSystemError(errno) : rv; 602 return rv < 0 ? MapSystemError(errno) : rv;
544 } 603 }
(...skipping 14 matching lines...) Expand all
559 618
560 int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const { 619 int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const {
561 DCHECK(CalledOnValidThread()); 620 DCHECK(CalledOnValidThread());
562 if (!is_connected()) 621 if (!is_connected())
563 return ERR_SOCKET_NOT_CONNECTED; 622 return ERR_SOCKET_NOT_CONNECTED;
564 623
565 switch (group_address.size()) { 624 switch (group_address.size()) {
566 case kIPv4AddressSize: { 625 case kIPv4AddressSize: {
567 if (addr_family_ != AF_INET) 626 if (addr_family_ != AF_INET)
568 return ERR_ADDRESS_INVALID; 627 return ERR_ADDRESS_INVALID;
628
629 #if !defined(OS_MACOSX)
630 ip_mreqn mreq;
631 mreq.imr_ifindex = multicast_interface_;
632 mreq.imr_address.s_addr = htonl(INADDR_ANY);
633 #else
569 ip_mreq mreq; 634 ip_mreq mreq;
570 mreq.imr_interface.s_addr = INADDR_ANY; 635 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
636 &mreq.imr_interface.s_addr);
637 if (error != OK)
638 return error;
639 #endif
571 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize); 640 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
572 int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP, 641 int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
573 &mreq, sizeof(mreq)); 642 &mreq, sizeof(mreq));
574 if (rv < 0) 643 if (rv < 0)
575 return MapSystemError(errno); 644 return MapSystemError(errno);
576 return OK; 645 return OK;
577 } 646 }
578 case kIPv6AddressSize: { 647 case kIPv6AddressSize: {
579 if (addr_family_ != AF_INET6) 648 if (addr_family_ != AF_INET6)
580 return ERR_ADDRESS_INVALID; 649 return ERR_ADDRESS_INVALID;
581 ipv6_mreq mreq; 650 ipv6_mreq mreq;
582 mreq.ipv6mr_interface = 0; // 0 indicates default multicast interface. 651 mreq.ipv6mr_interface = multicast_interface_;
583 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize); 652 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
584 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP, 653 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP,
585 &mreq, sizeof(mreq)); 654 &mreq, sizeof(mreq));
586 if (rv < 0) 655 if (rv < 0)
587 return MapSystemError(errno); 656 return MapSystemError(errno);
588 return OK; 657 return OK;
589 } 658 }
590 default: 659 default:
591 NOTREACHED() << "Invalid address family"; 660 NOTREACHED() << "Invalid address family";
592 return ERR_ADDRESS_INVALID; 661 return ERR_ADDRESS_INVALID;
(...skipping 30 matching lines...) Expand all
623 if (rv < 0) 692 if (rv < 0)
624 return MapSystemError(errno); 693 return MapSystemError(errno);
625 return OK; 694 return OK;
626 } 695 }
627 default: 696 default:
628 NOTREACHED() << "Invalid address family"; 697 NOTREACHED() << "Invalid address family";
629 return ERR_ADDRESS_INVALID; 698 return ERR_ADDRESS_INVALID;
630 } 699 }
631 } 700 }
632 701
702 int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index) {
703 DCHECK(CalledOnValidThread());
704 if (is_connected())
705 return ERR_SOCKET_IS_CONNECTED;
706 multicast_interface_ = interface_index;
707 return OK;
708 }
709
633 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) { 710 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) {
634 DCHECK(CalledOnValidThread()); 711 DCHECK(CalledOnValidThread());
635 if (is_connected()) 712 if (is_connected())
636 return ERR_SOCKET_IS_CONNECTED; 713 return ERR_SOCKET_IS_CONNECTED;
637 714
638 if (time_to_live < 0 || time_to_live > 255) 715 if (time_to_live < 0 || time_to_live > 255)
639 return ERR_INVALID_ARGUMENT; 716 return ERR_INVALID_ARGUMENT;
640 multicast_time_to_live_ = time_to_live; 717 multicast_time_to_live_ = time_to_live;
641 return OK; 718 return OK;
642 } 719 }
(...skipping 23 matching lines...) Expand all
666 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS, 743 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS,
667 &dscp_and_ecn, sizeof(dscp_and_ecn)); 744 &dscp_and_ecn, sizeof(dscp_and_ecn));
668 } 745 }
669 if (rv < 0) 746 if (rv < 0)
670 return MapSystemError(errno); 747 return MapSystemError(errno);
671 748
672 return OK; 749 return OK;
673 } 750 }
674 751
675 } // namespace net 752 } // namespace net
OLDNEW
« no previous file with comments | « net/udp/udp_socket_libevent.h ('k') | net/udp/udp_socket_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698