Chromium Code Reviews| Index: net/udp/udp_socket_libevent.cc |
| diff --git a/net/udp/udp_socket_libevent.cc b/net/udp/udp_socket_libevent.cc |
| index 990aa5758cca8f463ec0caf615432091a2847ac1..6a589364134e57bcb501de9096d107be02834763 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" |
| @@ -30,6 +32,20 @@ const int kBindRetries = 10; |
| const int kPortStart = 1024; |
| const int kPortEnd = 65535; |
| +#if defined(OS_MACOSX) |
| +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.
|
| + if (!index) |
| + return htonl(INADDR_ANY); |
| + ifreq ifr; |
| + ifr.ifr_addr.sa_family = AF_INET; |
| + if (!if_indextoname(index, ifr.ifr_name)) |
| + return htonl(INADDR_ANY); |
| + if (ioctl(socket, SIOCGIFADDR, &ifr)) |
| + 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.
|
| + return reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr.s_addr; |
| +} |
| +#endif // OS_MACOSX |
| + |
| } // namespace |
| namespace net { |
| @@ -42,6 +58,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 +541,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 +549,38 @@ 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; |
| + mreq.imr_interface.s_addr = |
| + GetIPv4AddressFromIndex(socket_, multicast_interface_); |
| +#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 +615,16 @@ 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; |
| + mreq.imr_interface.s_addr = |
| + GetIPv4AddressFromIndex(socket_, multicast_interface_); |
| +#endif |
| memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize); |
| int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP, |
| &mreq, sizeof(mreq)); |
| @@ -579,7 +636,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 +687,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()) |