Home | History | Annotate | Download | only in udp
      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
      3 // found in the LICENSE file.
      4 
      5 #include "net/udp/udp_socket_libevent.h"
      6 
      7 #include <errno.h>
      8 #include <fcntl.h>
      9 #include <netdb.h>
     10 #include <net/if.h>
     11 #include <netinet/in.h>
     12 #include <sys/ioctl.h>
     13 #include <sys/socket.h>
     14 
     15 #include "base/callback.h"
     16 #include "base/logging.h"
     17 #include "base/message_loop/message_loop.h"
     18 #include "base/metrics/sparse_histogram.h"
     19 #include "base/metrics/stats_counters.h"
     20 #include "base/posix/eintr_wrapper.h"
     21 #include "base/rand_util.h"
     22 #include "net/base/io_buffer.h"
     23 #include "net/base/ip_endpoint.h"
     24 #include "net/base/net_errors.h"
     25 #include "net/base/net_log.h"
     26 #include "net/base/net_util.h"
     27 #include "net/socket/socket_descriptor.h"
     28 #include "net/udp/udp_net_log_parameters.h"
     29 
     30 
     31 namespace net {
     32 
     33 namespace {
     34 
     35 const int kBindRetries = 10;
     36 const int kPortStart = 1024;
     37 const int kPortEnd = 65535;
     38 
     39 #if defined(OS_MACOSX)
     40 
     41 // Returns IPv4 address in network order.
     42 int GetIPv4AddressFromIndex(int socket, uint32 index, uint32* address){
     43   if (!index) {
     44     *address = htonl(INADDR_ANY);
     45     return OK;
     46   }
     47   ifreq ifr;
     48   ifr.ifr_addr.sa_family = AF_INET;
     49   if (!if_indextoname(index, ifr.ifr_name))
     50     return ERR_FAILED;
     51   int rv = ioctl(socket, SIOCGIFADDR, &ifr);
     52   if (!rv)
     53     return MapSystemError(rv);
     54   *address = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr.s_addr;
     55   return OK;
     56 }
     57 
     58 #endif  // OS_MACOSX
     59 
     60 }  // namespace
     61 
     62 UDPSocketLibevent::UDPSocketLibevent(
     63     DatagramSocket::BindType bind_type,
     64     const RandIntCallback& rand_int_cb,
     65     net::NetLog* net_log,
     66     const net::NetLog::Source& source)
     67         : socket_(kInvalidSocket),
     68           addr_family_(0),
     69           socket_options_(SOCKET_OPTION_MULTICAST_LOOP),
     70           multicast_interface_(0),
     71           multicast_time_to_live_(1),
     72           bind_type_(bind_type),
     73           rand_int_cb_(rand_int_cb),
     74           read_watcher_(this),
     75           write_watcher_(this),
     76           read_buf_len_(0),
     77           recv_from_address_(NULL),
     78           write_buf_len_(0),
     79           net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) {
     80   net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
     81                       source.ToEventParametersCallback());
     82   if (bind_type == DatagramSocket::RANDOM_BIND)
     83     DCHECK(!rand_int_cb.is_null());
     84 }
     85 
     86 UDPSocketLibevent::~UDPSocketLibevent() {
     87   Close();
     88   net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
     89 }
     90 
     91 void UDPSocketLibevent::Close() {
     92   DCHECK(CalledOnValidThread());
     93 
     94   if (!is_connected())
     95     return;
     96 
     97   // Zero out any pending read/write callback state.
     98   read_buf_ = NULL;
     99   read_buf_len_ = 0;
    100   read_callback_.Reset();
    101   recv_from_address_ = NULL;
    102   write_buf_ = NULL;
    103   write_buf_len_ = 0;
    104   write_callback_.Reset();
    105   send_to_address_.reset();
    106 
    107   bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
    108   DCHECK(ok);
    109   ok = write_socket_watcher_.StopWatchingFileDescriptor();
    110   DCHECK(ok);
    111 
    112   if (IGNORE_EINTR(close(socket_)) < 0)
    113     PLOG(ERROR) << "close";
    114 
    115   socket_ = kInvalidSocket;
    116   addr_family_ = 0;
    117 }
    118 
    119 int UDPSocketLibevent::GetPeerAddress(IPEndPoint* address) const {
    120   DCHECK(CalledOnValidThread());
    121   DCHECK(address);
    122   if (!is_connected())
    123     return ERR_SOCKET_NOT_CONNECTED;
    124 
    125   if (!remote_address_.get()) {
    126     SockaddrStorage storage;
    127     if (getpeername(socket_, storage.addr, &storage.addr_len))
    128       return MapSystemError(errno);
    129     scoped_ptr<IPEndPoint> address(new IPEndPoint());
    130     if (!address->FromSockAddr(storage.addr, storage.addr_len))
    131       return ERR_FAILED;
    132     remote_address_.reset(address.release());
    133   }
    134 
    135   *address = *remote_address_;
    136   return OK;
    137 }
    138 
    139 int UDPSocketLibevent::GetLocalAddress(IPEndPoint* address) const {
    140   DCHECK(CalledOnValidThread());
    141   DCHECK(address);
    142   if (!is_connected())
    143     return ERR_SOCKET_NOT_CONNECTED;
    144 
    145   if (!local_address_.get()) {
    146     SockaddrStorage storage;
    147     if (getsockname(socket_, storage.addr, &storage.addr_len))
    148       return MapSystemError(errno);
    149     scoped_ptr<IPEndPoint> address(new IPEndPoint());
    150     if (!address->FromSockAddr(storage.addr, storage.addr_len))
    151       return ERR_FAILED;
    152     local_address_.reset(address.release());
    153     net_log_.AddEvent(NetLog::TYPE_UDP_LOCAL_ADDRESS,
    154                       CreateNetLogUDPConnectCallback(local_address_.get()));
    155   }
    156 
    157   *address = *local_address_;
    158   return OK;
    159 }
    160 
    161 int UDPSocketLibevent::Read(IOBuffer* buf,
    162                             int buf_len,
    163                             const CompletionCallback& callback) {
    164   return RecvFrom(buf, buf_len, NULL, callback);
    165 }
    166 
    167 int UDPSocketLibevent::RecvFrom(IOBuffer* buf,
    168                                 int buf_len,
    169                                 IPEndPoint* address,
    170                                 const CompletionCallback& callback) {
    171   DCHECK(CalledOnValidThread());
    172   DCHECK_NE(kInvalidSocket, socket_);
    173   DCHECK(read_callback_.is_null());
    174   DCHECK(!recv_from_address_);
    175   DCHECK(!callback.is_null());  // Synchronous operation not supported
    176   DCHECK_GT(buf_len, 0);
    177 
    178   int nread = InternalRecvFrom(buf, buf_len, address);
    179   if (nread != ERR_IO_PENDING)
    180     return nread;
    181 
    182   if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
    183           socket_, true, base::MessageLoopForIO::WATCH_READ,
    184           &read_socket_watcher_, &read_watcher_)) {
    185     PLOG(ERROR) << "WatchFileDescriptor failed on read";
    186     int result = MapSystemError(errno);
    187     LogRead(result, NULL, 0, NULL);
    188     return result;
    189   }
    190 
    191   read_buf_ = buf;
    192   read_buf_len_ = buf_len;
    193   recv_from_address_ = address;
    194   read_callback_ = callback;
    195   return ERR_IO_PENDING;
    196 }
    197 
    198 int UDPSocketLibevent::Write(IOBuffer* buf,
    199                              int buf_len,
    200                              const CompletionCallback& callback) {
    201   return SendToOrWrite(buf, buf_len, NULL, callback);
    202 }
    203 
    204 int UDPSocketLibevent::SendTo(IOBuffer* buf,
    205                               int buf_len,
    206                               const IPEndPoint& address,
    207                               const CompletionCallback& callback) {
    208   return SendToOrWrite(buf, buf_len, &address, callback);
    209 }
    210 
    211 int UDPSocketLibevent::SendToOrWrite(IOBuffer* buf,
    212                                      int buf_len,
    213                                      const IPEndPoint* address,
    214                                      const CompletionCallback& callback) {
    215   DCHECK(CalledOnValidThread());
    216   DCHECK_NE(kInvalidSocket, socket_);
    217   DCHECK(write_callback_.is_null());
    218   DCHECK(!callback.is_null());  // Synchronous operation not supported
    219   DCHECK_GT(buf_len, 0);
    220 
    221   int result = InternalSendTo(buf, buf_len, address);
    222   if (result != ERR_IO_PENDING)
    223     return result;
    224 
    225   if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
    226           socket_, true, base::MessageLoopForIO::WATCH_WRITE,
    227           &write_socket_watcher_, &write_watcher_)) {
    228     DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno;
    229     int result = MapSystemError(errno);
    230     LogWrite(result, NULL, NULL);
    231     return result;
    232   }
    233 
    234   write_buf_ = buf;
    235   write_buf_len_ = buf_len;
    236   DCHECK(!send_to_address_.get());
    237   if (address) {
    238     send_to_address_.reset(new IPEndPoint(*address));
    239   }
    240   write_callback_ = callback;
    241   return ERR_IO_PENDING;
    242 }
    243 
    244 int UDPSocketLibevent::Connect(const IPEndPoint& address) {
    245   net_log_.BeginEvent(NetLog::TYPE_UDP_CONNECT,
    246                       CreateNetLogUDPConnectCallback(&address));
    247   int rv = InternalConnect(address);
    248   if (rv != OK)
    249     Close();
    250   net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv);
    251   return rv;
    252 }
    253 
    254 int UDPSocketLibevent::InternalConnect(const IPEndPoint& address) {
    255   DCHECK(CalledOnValidThread());
    256   DCHECK(!is_connected());
    257   DCHECK(!remote_address_.get());
    258   int addr_family = address.GetSockAddrFamily();
    259   int rv = CreateSocket(addr_family);
    260   if (rv < 0)
    261     return rv;
    262 
    263   if (bind_type_ == DatagramSocket::RANDOM_BIND) {
    264     // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s,
    265     // representing INADDR_ANY or in6addr_any.
    266     size_t addr_size =
    267         addr_family == AF_INET ? kIPv4AddressSize : kIPv6AddressSize;
    268     IPAddressNumber addr_any(addr_size);
    269     rv = RandomBind(addr_any);
    270   }
    271   // else connect() does the DatagramSocket::DEFAULT_BIND
    272 
    273   if (rv < 0) {
    274     UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", rv);
    275     Close();
    276     return rv;
    277   }
    278 
    279   SockaddrStorage storage;
    280   if (!address.ToSockAddr(storage.addr, &storage.addr_len)) {
    281     Close();
    282     return ERR_ADDRESS_INVALID;
    283   }
    284 
    285   rv = HANDLE_EINTR(connect(socket_, storage.addr, storage.addr_len));
    286   if (rv < 0) {
    287     // Close() may change the current errno. Map errno beforehand.
    288     int result = MapSystemError(errno);
    289     Close();
    290     return result;
    291   }
    292 
    293   remote_address_.reset(new IPEndPoint(address));
    294   return rv;
    295 }
    296 
    297 int UDPSocketLibevent::Bind(const IPEndPoint& address) {
    298   DCHECK(CalledOnValidThread());
    299   DCHECK(!is_connected());
    300   int rv = CreateSocket(address.GetSockAddrFamily());
    301   if (rv < 0)
    302     return rv;
    303 
    304   rv = SetSocketOptions();
    305   if (rv < 0) {
    306     Close();
    307     return rv;
    308   }
    309   rv = DoBind(address);
    310   if (rv < 0) {
    311     Close();
    312     return rv;
    313   }
    314   local_address_.reset();
    315   return rv;
    316 }
    317 
    318 bool UDPSocketLibevent::SetReceiveBufferSize(int32 size) {
    319   DCHECK(CalledOnValidThread());
    320   int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF,
    321                       reinterpret_cast<const char*>(&size), sizeof(size));
    322   DCHECK(!rv) << "Could not set socket receive buffer size: " << errno;
    323   return rv == 0;
    324 }
    325 
    326 bool UDPSocketLibevent::SetSendBufferSize(int32 size) {
    327   DCHECK(CalledOnValidThread());
    328   int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
    329                       reinterpret_cast<const char*>(&size), sizeof(size));
    330   DCHECK(!rv) << "Could not set socket send buffer size: " << errno;
    331   return rv == 0;
    332 }
    333 
    334 void UDPSocketLibevent::AllowAddressReuse() {
    335   DCHECK(CalledOnValidThread());
    336   DCHECK(!is_connected());
    337 
    338   socket_options_ |= SOCKET_OPTION_REUSE_ADDRESS;
    339 }
    340 
    341 void UDPSocketLibevent::AllowBroadcast() {
    342   DCHECK(CalledOnValidThread());
    343   DCHECK(!is_connected());
    344 
    345   socket_options_ |= SOCKET_OPTION_BROADCAST;
    346 }
    347 
    348 void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
    349   if (!socket_->read_callback_.is_null())
    350     socket_->DidCompleteRead();
    351 }
    352 
    353 void UDPSocketLibevent::WriteWatcher::OnFileCanWriteWithoutBlocking(int) {
    354   if (!socket_->write_callback_.is_null())
    355     socket_->DidCompleteWrite();
    356 }
    357 
    358 void UDPSocketLibevent::DoReadCallback(int rv) {
    359   DCHECK_NE(rv, ERR_IO_PENDING);
    360   DCHECK(!read_callback_.is_null());
    361 
    362   // since Run may result in Read being called, clear read_callback_ up front.
    363   CompletionCallback c = read_callback_;
    364   read_callback_.Reset();
    365   c.Run(rv);
    366 }
    367 
    368 void UDPSocketLibevent::DoWriteCallback(int rv) {
    369   DCHECK_NE(rv, ERR_IO_PENDING);
    370   DCHECK(!write_callback_.is_null());
    371 
    372   // since Run may result in Write being called, clear write_callback_ up front.
    373   CompletionCallback c = write_callback_;
    374   write_callback_.Reset();
    375   c.Run(rv);
    376 }
    377 
    378 void UDPSocketLibevent::DidCompleteRead() {
    379   int result =
    380       InternalRecvFrom(read_buf_.get(), read_buf_len_, recv_from_address_);
    381   if (result != ERR_IO_PENDING) {
    382     read_buf_ = NULL;
    383     read_buf_len_ = 0;
    384     recv_from_address_ = NULL;
    385     bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
    386     DCHECK(ok);
    387     DoReadCallback(result);
    388   }
    389 }
    390 
    391 void UDPSocketLibevent::LogRead(int result,
    392                                 const char* bytes,
    393                                 socklen_t addr_len,
    394                                 const sockaddr* addr) const {
    395   if (result < 0) {
    396     net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR, result);
    397     return;
    398   }
    399 
    400   if (net_log_.IsLoggingAllEvents()) {
    401     DCHECK(addr_len > 0);
    402     DCHECK(addr);
    403 
    404     IPEndPoint address;
    405     bool is_address_valid = address.FromSockAddr(addr, addr_len);
    406     net_log_.AddEvent(
    407         NetLog::TYPE_UDP_BYTES_RECEIVED,
    408         CreateNetLogUDPDataTranferCallback(
    409             result, bytes,
    410             is_address_valid ? &address : NULL));
    411   }
    412 
    413   base::StatsCounter read_bytes("udp.read_bytes");
    414   read_bytes.Add(result);
    415 }
    416 
    417 int UDPSocketLibevent::CreateSocket(int addr_family) {
    418   addr_family_ = addr_family;
    419   socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, 0);
    420   if (socket_ == kInvalidSocket)
    421     return MapSystemError(errno);
    422   if (SetNonBlocking(socket_)) {
    423     const int err = MapSystemError(errno);
    424     Close();
    425     return err;
    426   }
    427   return OK;
    428 }
    429 
    430 void UDPSocketLibevent::DidCompleteWrite() {
    431   int result =
    432       InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get());
    433 
    434   if (result != ERR_IO_PENDING) {
    435     write_buf_ = NULL;
    436     write_buf_len_ = 0;
    437     send_to_address_.reset();
    438     write_socket_watcher_.StopWatchingFileDescriptor();
    439     DoWriteCallback(result);
    440   }
    441 }
    442 
    443 void UDPSocketLibevent::LogWrite(int result,
    444                                  const char* bytes,
    445                                  const IPEndPoint* address) const {
    446   if (result < 0) {
    447     net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR, result);
    448     return;
    449   }
    450 
    451   if (net_log_.IsLoggingAllEvents()) {
    452     net_log_.AddEvent(
    453         NetLog::TYPE_UDP_BYTES_SENT,
    454         CreateNetLogUDPDataTranferCallback(result, bytes, address));
    455   }
    456 
    457   base::StatsCounter write_bytes("udp.write_bytes");
    458   write_bytes.Add(result);
    459 }
    460 
    461 int UDPSocketLibevent::InternalRecvFrom(IOBuffer* buf, int buf_len,
    462                                         IPEndPoint* address) {
    463   int bytes_transferred;
    464   int flags = 0;
    465 
    466   SockaddrStorage storage;
    467 
    468   bytes_transferred =
    469       HANDLE_EINTR(recvfrom(socket_,
    470                             buf->data(),
    471                             buf_len,
    472                             flags,
    473                             storage.addr,
    474                             &storage.addr_len));
    475   int result;
    476   if (bytes_transferred >= 0) {
    477     result = bytes_transferred;
    478     if (address && !address->FromSockAddr(storage.addr, storage.addr_len))
    479       result = ERR_FAILED;
    480   } else {
    481     result = MapSystemError(errno);
    482   }
    483   if (result != ERR_IO_PENDING)
    484     LogRead(result, buf->data(), storage.addr_len, storage.addr);
    485   return result;
    486 }
    487 
    488 int UDPSocketLibevent::InternalSendTo(IOBuffer* buf, int buf_len,
    489                                       const IPEndPoint* address) {
    490   SockaddrStorage storage;
    491   struct sockaddr* addr = storage.addr;
    492   if (!address) {
    493     addr = NULL;
    494     storage.addr_len = 0;
    495   } else {
    496     if (!address->ToSockAddr(storage.addr, &storage.addr_len)) {
    497       int result = ERR_FAILED;
    498       LogWrite(result, NULL, NULL);
    499       return result;
    500     }
    501   }
    502 
    503   int result = HANDLE_EINTR(sendto(socket_,
    504                             buf->data(),
    505                             buf_len,
    506                             0,
    507                             addr,
    508                             storage.addr_len));
    509   if (result < 0)
    510     result = MapSystemError(errno);
    511   if (result != ERR_IO_PENDING)
    512     LogWrite(result, buf->data(), address);
    513   return result;
    514 }
    515 
    516 int UDPSocketLibevent::SetSocketOptions() {
    517   int true_value = 1;
    518   if (socket_options_ & SOCKET_OPTION_REUSE_ADDRESS) {
    519     int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &true_value,
    520                         sizeof(true_value));
    521     if (rv < 0)
    522       return MapSystemError(errno);
    523   }
    524   if (socket_options_ & SOCKET_OPTION_BROADCAST) {
    525     int rv;
    526 #if defined(OS_MACOSX)
    527     // SO_REUSEPORT on OSX permits multiple processes to each receive
    528     // UDP multicast or broadcast datagrams destined for the bound
    529     // port.
    530     rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &true_value,
    531                     sizeof(true_value));
    532 #else
    533     rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &true_value,
    534                     sizeof(true_value));
    535 #endif  // defined(OS_MACOSX)
    536     if (rv < 0)
    537       return MapSystemError(errno);
    538   }
    539 
    540   if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) {
    541     int rv;
    542     if (addr_family_ == AF_INET) {
    543       u_char loop = 0;
    544       rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_LOOP,
    545                       &loop, sizeof(loop));
    546     } else {
    547       u_int loop = 0;
    548       rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
    549                       &loop, sizeof(loop));
    550     }
    551     if (rv < 0)
    552       return MapSystemError(errno);
    553   }
    554   if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) {
    555     int rv;
    556     if (addr_family_ == AF_INET) {
    557       u_char ttl = multicast_time_to_live_;
    558       rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL,
    559                       &ttl, sizeof(ttl));
    560     } else {
    561       // Signed integer. -1 to use route default.
    562       int ttl = multicast_time_to_live_;
    563       rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
    564                       &ttl, sizeof(ttl));
    565     }
    566     if (rv < 0)
    567       return MapSystemError(errno);
    568   }
    569   if (multicast_interface_ != 0) {
    570     switch (addr_family_) {
    571       case AF_INET: {
    572 #if !defined(OS_MACOSX)
    573         ip_mreqn mreq;
    574         mreq.imr_ifindex = multicast_interface_;
    575         mreq.imr_address.s_addr = htonl(INADDR_ANY);
    576 #else
    577         ip_mreq mreq;
    578         int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
    579                                             &mreq.imr_interface.s_addr);
    580         if (error != OK)
    581           return error;
    582 #endif
    583         int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF,
    584                             reinterpret_cast<const char*>(&mreq), sizeof(mreq));
    585         if (rv)
    586           return MapSystemError(errno);
    587         break;
    588       }
    589       case AF_INET6: {
    590         uint32 interface_index = multicast_interface_;
    591         int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_IF,
    592                             reinterpret_cast<const char*>(&interface_index),
    593                             sizeof(interface_index));
    594         if (rv)
    595           return MapSystemError(errno);
    596         break;
    597       }
    598       default:
    599         NOTREACHED() << "Invalid address family";
    600         return ERR_ADDRESS_INVALID;
    601     }
    602   }
    603   return OK;
    604 }
    605 
    606 int UDPSocketLibevent::DoBind(const IPEndPoint& address) {
    607   SockaddrStorage storage;
    608   if (!address.ToSockAddr(storage.addr, &storage.addr_len))
    609     return ERR_ADDRESS_INVALID;
    610   int rv = bind(socket_, storage.addr, storage.addr_len);
    611   if (rv == 0)
    612     return OK;
    613   int last_error = errno;
    614   UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketBindErrorFromPosix", last_error);
    615   return MapSystemError(last_error);
    616 }
    617 
    618 int UDPSocketLibevent::RandomBind(const IPAddressNumber& address) {
    619   DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null());
    620 
    621   for (int i = 0; i < kBindRetries; ++i) {
    622     int rv = DoBind(IPEndPoint(address,
    623                                rand_int_cb_.Run(kPortStart, kPortEnd)));
    624     if (rv == OK || rv != ERR_ADDRESS_IN_USE)
    625       return rv;
    626   }
    627   return DoBind(IPEndPoint(address, 0));
    628 }
    629 
    630 int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const {
    631   DCHECK(CalledOnValidThread());
    632   if (!is_connected())
    633     return ERR_SOCKET_NOT_CONNECTED;
    634 
    635   switch (group_address.size()) {
    636     case kIPv4AddressSize: {
    637       if (addr_family_ != AF_INET)
    638         return ERR_ADDRESS_INVALID;
    639 
    640 #if !defined(OS_MACOSX)
    641       ip_mreqn mreq;
    642       mreq.imr_ifindex = multicast_interface_;
    643       mreq.imr_address.s_addr = htonl(INADDR_ANY);
    644 #else
    645       ip_mreq mreq;
    646       int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
    647                                             &mreq.imr_interface.s_addr);
    648       if (error != OK)
    649         return error;
    650 #endif
    651       memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
    652       int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
    653                           &mreq, sizeof(mreq));
    654       if (rv < 0)
    655         return MapSystemError(errno);
    656       return OK;
    657     }
    658     case kIPv6AddressSize: {
    659       if (addr_family_ != AF_INET6)
    660         return ERR_ADDRESS_INVALID;
    661       ipv6_mreq mreq;
    662       mreq.ipv6mr_interface = multicast_interface_;
    663       memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
    664       int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP,
    665                           &mreq, sizeof(mreq));
    666       if (rv < 0)
    667         return MapSystemError(errno);
    668       return OK;
    669     }
    670     default:
    671       NOTREACHED() << "Invalid address family";
    672       return ERR_ADDRESS_INVALID;
    673   }
    674 }
    675 
    676 int UDPSocketLibevent::LeaveGroup(const IPAddressNumber& group_address) const {
    677   DCHECK(CalledOnValidThread());
    678 
    679   if (!is_connected())
    680     return ERR_SOCKET_NOT_CONNECTED;
    681 
    682   switch (group_address.size()) {
    683     case kIPv4AddressSize: {
    684       if (addr_family_ != AF_INET)
    685         return ERR_ADDRESS_INVALID;
    686       ip_mreq mreq;
    687       mreq.imr_interface.s_addr = INADDR_ANY;
    688       memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
    689       int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP,
    690                           &mreq, sizeof(mreq));
    691       if (rv < 0)
    692         return MapSystemError(errno);
    693       return OK;
    694     }
    695     case kIPv6AddressSize: {
    696       if (addr_family_ != AF_INET6)
    697         return ERR_ADDRESS_INVALID;
    698       ipv6_mreq mreq;
    699       mreq.ipv6mr_interface = 0;  // 0 indicates default multicast interface.
    700       memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
    701       int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
    702                           &mreq, sizeof(mreq));
    703       if (rv < 0)
    704         return MapSystemError(errno);
    705       return OK;
    706     }
    707     default:
    708       NOTREACHED() << "Invalid address family";
    709       return ERR_ADDRESS_INVALID;
    710   }
    711 }
    712 
    713 int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index) {
    714   DCHECK(CalledOnValidThread());
    715   if (is_connected())
    716     return ERR_SOCKET_IS_CONNECTED;
    717   multicast_interface_ = interface_index;
    718   return OK;
    719 }
    720 
    721 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) {
    722   DCHECK(CalledOnValidThread());
    723   if (is_connected())
    724     return ERR_SOCKET_IS_CONNECTED;
    725 
    726   if (time_to_live < 0 || time_to_live > 255)
    727     return ERR_INVALID_ARGUMENT;
    728   multicast_time_to_live_ = time_to_live;
    729   return OK;
    730 }
    731 
    732 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback) {
    733   DCHECK(CalledOnValidThread());
    734   if (is_connected())
    735     return ERR_SOCKET_IS_CONNECTED;
    736 
    737   if (loopback)
    738     socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
    739   else
    740     socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
    741   return OK;
    742 }
    743 
    744 int UDPSocketLibevent::SetDiffServCodePoint(DiffServCodePoint dscp) {
    745   if (dscp == DSCP_NO_CHANGE) {
    746     return OK;
    747   }
    748   int rv;
    749   int dscp_and_ecn = dscp << 2;
    750   if (addr_family_ == AF_INET) {
    751     rv = setsockopt(socket_, IPPROTO_IP, IP_TOS,
    752                     &dscp_and_ecn, sizeof(dscp_and_ecn));
    753   } else {
    754     rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS,
    755                     &dscp_and_ecn, sizeof(dscp_and_ecn));
    756   }
    757   if (rv < 0)
    758     return MapSystemError(errno);
    759 
    760   return OK;
    761 }
    762 
    763 }  // namespace net
    764