diff options
Diffstat (limited to 'chromium/net/udp/udp_socket_libevent.cc')
-rw-r--r-- | chromium/net/udp/udp_socket_libevent.cc | 148 |
1 files changed, 128 insertions, 20 deletions
diff --git a/chromium/net/udp/udp_socket_libevent.cc b/chromium/net/udp/udp_socket_libevent.cc index 5ed52f57090..ef2bae06a06 100644 --- a/chromium/net/udp/udp_socket_libevent.cc +++ b/chromium/net/udp/udp_socket_libevent.cc @@ -7,12 +7,15 @@ #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" #include "base/message_loop/message_loop.h" +#include "base/metrics/sparse_histogram.h" #include "base/metrics/stats_counters.h" #include "base/posix/eintr_wrapper.h" #include "base/rand_util.h" @@ -24,15 +27,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 +67,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), @@ -83,7 +109,7 @@ void UDPSocketLibevent::Close() { ok = write_socket_watcher_.StopWatchingFileDescriptor(); DCHECK(ok); - if (HANDLE_EINTR(close(socket_)) < 0) + if (IGNORE_EINTR(close(socket_)) < 0) PLOG(ERROR) << "close"; socket_ = kInvalidSocket; @@ -229,15 +255,23 @@ int UDPSocketLibevent::InternalConnect(const IPEndPoint& address) { DCHECK(CalledOnValidThread()); DCHECK(!is_connected()); DCHECK(!remote_address_.get()); - int rv = CreateSocket(address); + int addr_family = address.GetSockAddrFamily(); + int rv = CreateSocket(addr_family); if (rv < 0) return rv; - if (bind_type_ == DatagramSocket::RANDOM_BIND) - rv = RandomBind(address); + if (bind_type_ == DatagramSocket::RANDOM_BIND) { + // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s, + // representing INADDR_ANY or in6addr_any. + size_t addr_size = + addr_family == AF_INET ? kIPv4AddressSize : kIPv6AddressSize; + IPAddressNumber addr_any(addr_size); + rv = RandomBind(addr_any); + } // else connect() does the DatagramSocket::DEFAULT_BIND if (rv < 0) { + UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", rv); Close(); return rv; } @@ -263,7 +297,7 @@ int UDPSocketLibevent::InternalConnect(const IPEndPoint& address) { int UDPSocketLibevent::Bind(const IPEndPoint& address) { DCHECK(CalledOnValidThread()); DCHECK(!is_connected()); - int rv = CreateSocket(address); + int rv = CreateSocket(address.GetSockAddrFamily()); if (rv < 0) return rv; @@ -380,8 +414,8 @@ void UDPSocketLibevent::LogRead(int result, read_bytes.Add(result); } -int UDPSocketLibevent::CreateSocket(const IPEndPoint& address) { - addr_family_ = address.GetSockAddrFamily(); +int UDPSocketLibevent::CreateSocket(int addr_family) { + addr_family_ = addr_family; socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, 0); if (socket_ == kInvalidSocket) return MapSystemError(errno); @@ -524,7 +558,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 +566,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; } @@ -540,21 +608,23 @@ int UDPSocketLibevent::DoBind(const IPEndPoint& address) { if (!address.ToSockAddr(storage.addr, &storage.addr_len)) return ERR_ADDRESS_INVALID; int rv = bind(socket_, storage.addr, storage.addr_len); - return rv < 0 ? MapSystemError(errno) : rv; + if (rv == 0) + return OK; + int last_error = errno; + UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketBindErrorFromPosix", last_error); + return MapSystemError(last_error); } -int UDPSocketLibevent::RandomBind(const IPEndPoint& address) { +int UDPSocketLibevent::RandomBind(const IPAddressNumber& address) { DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null()); - // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s. - IPAddressNumber ip(address.address().size()); - for (int i = 0; i < kBindRetries; ++i) { - int rv = DoBind(IPEndPoint(ip, rand_int_cb_.Run(kPortStart, kPortEnd))); + int rv = DoBind(IPEndPoint(address, + rand_int_cb_.Run(kPortStart, kPortEnd))); if (rv == OK || rv != ERR_ADDRESS_IN_USE) return rv; } - return DoBind(IPEndPoint(ip, 0)); + return DoBind(IPEndPoint(address, 0)); } int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const { @@ -566,8 +636,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 +659,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 +710,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()) @@ -652,4 +740,24 @@ int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback) { socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP; return OK; } + +int UDPSocketLibevent::SetDiffServCodePoint(DiffServCodePoint dscp) { + if (dscp == DSCP_NO_CHANGE) { + return OK; + } + int rv; + int dscp_and_ecn = dscp << 2; + if (addr_family_ == AF_INET) { + rv = setsockopt(socket_, IPPROTO_IP, IP_TOS, + &dscp_and_ecn, sizeof(dscp_and_ecn)); + } else { + rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS, + &dscp_and_ecn, sizeof(dscp_and_ecn)); + } + if (rv < 0) + return MapSystemError(errno); + + return OK; +} + } // namespace net |