| Index: net/udp/udp_socket_libevent.cc
|
| diff --git a/net/udp/udp_socket_libevent.cc b/net/udp/udp_socket_libevent.cc
|
| index 7ef9c3c6b79681cfa99a5e2acafd7325a8ac66ad..2880fa13248a4464ae1905274e00535f961ee7b8 100644
|
| --- a/net/udp/udp_socket_libevent.cc
|
| +++ b/net/udp/udp_socket_libevent.cc
|
| @@ -7,8 +7,10 @@
|
| #include <errno.h>
|
| #include <fcntl.h>
|
| #include <netdb.h>
|
| -#include <sys/socket.h>
|
| +#include <net/if.h>
|
| #include <netinet/in.h>
|
| +#include <sys/ioctl.h>
|
| +#include <sys/socket.h>
|
|
|
| #include "base/callback.h"
|
| #include "base/logging.h"
|
| @@ -24,15 +26,37 @@
|
| #include "net/socket/socket_descriptor.h"
|
| #include "net/udp/udp_net_log_parameters.h"
|
|
|
| +
|
| +namespace net {
|
| +
|
| namespace {
|
|
|
| const int kBindRetries = 10;
|
| const int kPortStart = 1024;
|
| const int kPortEnd = 65535;
|
|
|
| -} // namespace
|
| +#if defined(OS_MACOSX)
|
|
|
| -namespace net {
|
| +// Returns IPv4 address in network order.
|
| +int GetIPv4AddressFromIndex(int socket, uint32 index, uint32* address){
|
| + if (!index) {
|
| + *address = htonl(INADDR_ANY);
|
| + return OK;
|
| + }
|
| + ifreq ifr;
|
| + ifr.ifr_addr.sa_family = AF_INET;
|
| + if (!if_indextoname(index, ifr.ifr_name))
|
| + return ERR_FAILED;
|
| + int rv = ioctl(socket, SIOCGIFADDR, &ifr);
|
| + if (!rv)
|
| + return MapSystemError(rv);
|
| + *address = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr.s_addr;
|
| + return OK;
|
| +}
|
| +
|
| +#endif // OS_MACOSX
|
| +
|
| +} // namespace
|
|
|
| UDPSocketLibevent::UDPSocketLibevent(
|
| DatagramSocket::BindType bind_type,
|
| @@ -42,6 +66,7 @@ UDPSocketLibevent::UDPSocketLibevent(
|
| : socket_(kInvalidSocket),
|
| addr_family_(0),
|
| socket_options_(SOCKET_OPTION_MULTICAST_LOOP),
|
| + multicast_interface_(0),
|
| multicast_time_to_live_(1),
|
| bind_type_(bind_type),
|
| rand_int_cb_(rand_int_cb),
|
| @@ -524,7 +549,7 @@ int UDPSocketLibevent::SetSocketOptions() {
|
| rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL,
|
| &ttl, sizeof(ttl));
|
| } else {
|
| - // Signed interger. -1 to use route default.
|
| + // Signed integer. -1 to use route default.
|
| int ttl = multicast_time_to_live_;
|
| rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
|
| &ttl, sizeof(ttl));
|
| @@ -532,6 +557,40 @@ int UDPSocketLibevent::SetSocketOptions() {
|
| if (rv < 0)
|
| return MapSystemError(errno);
|
| }
|
| + if (multicast_interface_ != 0) {
|
| + switch (addr_family_) {
|
| + case AF_INET: {
|
| +#if !defined(OS_MACOSX)
|
| + ip_mreqn mreq;
|
| + mreq.imr_ifindex = multicast_interface_;
|
| + mreq.imr_address.s_addr = htonl(INADDR_ANY);
|
| +#else
|
| + ip_mreq mreq;
|
| + int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
|
| + &mreq.imr_interface.s_addr);
|
| + if (error != OK)
|
| + return error;
|
| +#endif
|
| + int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF,
|
| + reinterpret_cast<const char*>(&mreq), sizeof(mreq));
|
| + if (rv)
|
| + return MapSystemError(errno);
|
| + break;
|
| + }
|
| + case AF_INET6: {
|
| + uint32 interface_index = multicast_interface_;
|
| + int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_IF,
|
| + reinterpret_cast<const char*>(&interface_index),
|
| + sizeof(interface_index));
|
| + if (rv)
|
| + return MapSystemError(errno);
|
| + break;
|
| + }
|
| + default:
|
| + NOTREACHED() << "Invalid address family";
|
| + return ERR_ADDRESS_INVALID;
|
| + }
|
| + }
|
| return OK;
|
| }
|
|
|
| @@ -566,8 +625,18 @@ int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const {
|
| case kIPv4AddressSize: {
|
| if (addr_family_ != AF_INET)
|
| return ERR_ADDRESS_INVALID;
|
| +
|
| +#if !defined(OS_MACOSX)
|
| + ip_mreqn mreq;
|
| + mreq.imr_ifindex = multicast_interface_;
|
| + mreq.imr_address.s_addr = htonl(INADDR_ANY);
|
| +#else
|
| ip_mreq mreq;
|
| - mreq.imr_interface.s_addr = INADDR_ANY;
|
| + int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
|
| + &mreq.imr_interface.s_addr);
|
| + if (error != OK)
|
| + return error;
|
| +#endif
|
| memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
|
| int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
| &mreq, sizeof(mreq));
|
| @@ -579,7 +648,7 @@ int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const {
|
| if (addr_family_ != AF_INET6)
|
| return ERR_ADDRESS_INVALID;
|
| ipv6_mreq mreq;
|
| - mreq.ipv6mr_interface = 0; // 0 indicates default multicast interface.
|
| + mreq.ipv6mr_interface = multicast_interface_;
|
| memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
|
| int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP,
|
| &mreq, sizeof(mreq));
|
| @@ -630,6 +699,14 @@ int UDPSocketLibevent::LeaveGroup(const IPAddressNumber& group_address) const {
|
| }
|
| }
|
|
|
| +int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index) {
|
| + DCHECK(CalledOnValidThread());
|
| + if (is_connected())
|
| + return ERR_SOCKET_IS_CONNECTED;
|
| + multicast_interface_ = interface_index;
|
| + return OK;
|
| +}
|
| +
|
| int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) {
|
| DCHECK(CalledOnValidThread());
|
| if (is_connected())
|
|
|