| Index: net/udp/udp_socket_win.cc
 | 
| diff --git a/net/udp/udp_socket_win.cc b/net/udp/udp_socket_win.cc
 | 
| index 5c6da9fc47c154dfd9e40ad682e980512eb19002..dd0f88008d36c052dfdabceb9e73799ba0c0fa62 100644
 | 
| --- a/net/udp/udp_socket_win.cc
 | 
| +++ b/net/udp/udp_socket_win.cc
 | 
| @@ -163,7 +163,9 @@ UDPSocketWin::UDPSocketWin(DatagramSocket::BindType bind_type,
 | 
|                             net::NetLog* net_log,
 | 
|                             const net::NetLog::Source& source)
 | 
|      : socket_(INVALID_SOCKET),
 | 
| -      socket_options_(0),
 | 
| +      addr_family_(0),
 | 
| +      socket_options_(SOCKET_OPTION_MULTICAST_LOOP),
 | 
| +      multicast_time_to_live_(1),
 | 
|        bind_type_(bind_type),
 | 
|        rand_int_cb_(rand_int_cb),
 | 
|        recv_from_address_(NULL),
 | 
| @@ -355,7 +357,8 @@ int UDPSocketWin::Bind(const IPEndPoint& address) {
 | 
|  }
 | 
|  
 | 
|  int UDPSocketWin::CreateSocket(const IPEndPoint& address) {
 | 
| -  socket_ = WSASocket(address.GetSockAddrFamily(), SOCK_DGRAM, IPPROTO_UDP,
 | 
| +  addr_family_ = address.GetSockAddrFamily();
 | 
| +  socket_ = WSASocket(addr_family_, SOCK_DGRAM, IPPROTO_UDP,
 | 
|                        NULL, 0, WSA_FLAG_OVERLAPPED);
 | 
|    if (socket_ == INVALID_SOCKET)
 | 
|      return MapSystemError(WSAGetLastError());
 | 
| @@ -575,14 +578,36 @@ int UDPSocketWin::SetSocketOptions() {
 | 
|                          reinterpret_cast<const char*>(&true_value),
 | 
|                          sizeof(true_value));
 | 
|      if (rv < 0)
 | 
| -      return MapSystemError(errno);
 | 
| +      return MapSystemError(WSAGetLastError());
 | 
|    }
 | 
|    if (socket_options_ & SOCKET_OPTION_BROADCAST) {
 | 
|      int rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST,
 | 
|                          reinterpret_cast<const char*>(&true_value),
 | 
|                          sizeof(true_value));
 | 
|      if (rv < 0)
 | 
| -      return MapSystemError(errno);
 | 
| +      return MapSystemError(WSAGetLastError());
 | 
| +  }
 | 
| +  if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) {
 | 
| +    DWORD loop = 0;
 | 
| +    int protocol_level =
 | 
| +        addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
 | 
| +    int option =
 | 
| +        addr_family_ == AF_INET ? IP_MULTICAST_LOOP: IPV6_MULTICAST_LOOP;
 | 
| +    int rv = setsockopt(socket_, protocol_level, option,
 | 
| +                        reinterpret_cast<const char*>(&loop), sizeof(loop));
 | 
| +    if (rv < 0)
 | 
| +      return MapSystemError(WSAGetLastError());
 | 
| +  }
 | 
| +  if (multicast_time_to_live_ != 1) {
 | 
| +    DWORD hops = multicast_time_to_live_;
 | 
| +    int protocol_level =
 | 
| +        addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
 | 
| +    int option =
 | 
| +        addr_family_ == AF_INET ? IP_MULTICAST_TTL: IPV6_MULTICAST_HOPS;
 | 
| +    int rv = setsockopt(socket_, protocol_level, option,
 | 
| +                        reinterpret_cast<const char*>(&hops), sizeof(hops));
 | 
| +    if (rv < 0)
 | 
| +      return MapSystemError(WSAGetLastError());
 | 
|    }
 | 
|    return OK;
 | 
|  }
 | 
| @@ -614,4 +639,105 @@ bool UDPSocketWin::ReceiveAddressToIPEndpoint(IPEndPoint* address) const {
 | 
|    return address->FromSockAddr(storage.addr, storage.addr_len);
 | 
|  }
 | 
|  
 | 
| +int UDPSocketWin::JoinGroup(
 | 
| +    const IPAddressNumber& group_address) const {
 | 
| +  DCHECK(CalledOnValidThread());
 | 
| +  if (!is_connected())
 | 
| +    return ERR_SOCKET_NOT_CONNECTED;
 | 
| +
 | 
| +  switch (group_address.size()) {
 | 
| +    case kIPv4AddressSize: {
 | 
| +      if (addr_family_ != AF_INET)
 | 
| +        return ERR_ADDRESS_INVALID;
 | 
| +      ip_mreq mreq;
 | 
| +      mreq.imr_interface.s_addr = INADDR_ANY;
 | 
| +      memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
 | 
| +      int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
 | 
| +                          reinterpret_cast<const char*>(&mreq),
 | 
| +                          sizeof(mreq));
 | 
| +      if (rv)
 | 
| +        return MapSystemError(WSAGetLastError());
 | 
| +      return OK;
 | 
| +    }
 | 
| +    case kIPv6AddressSize: {
 | 
| +      if (addr_family_ != AF_INET6)
 | 
| +        return ERR_ADDRESS_INVALID;
 | 
| +      ipv6_mreq mreq;
 | 
| +      mreq.ipv6mr_interface = 0;  // 0 indicates default multicast interface.
 | 
| +      memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
 | 
| +      int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
 | 
| +                          reinterpret_cast<const char*>(&mreq),
 | 
| +                          sizeof(mreq));
 | 
| +      if (rv)
 | 
| +        return MapSystemError(WSAGetLastError());
 | 
| +      return OK;
 | 
| +    }
 | 
| +    default:
 | 
| +      NOTREACHED() << "Invalid address family";
 | 
| +      return ERR_ADDRESS_INVALID;
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +int UDPSocketWin::LeaveGroup(
 | 
| +    const IPAddressNumber& group_address) const {
 | 
| +  DCHECK(CalledOnValidThread());
 | 
| +  if (!is_connected())
 | 
| +    return ERR_SOCKET_NOT_CONNECTED;
 | 
| +
 | 
| +  switch (group_address.size()) {
 | 
| +    case kIPv4AddressSize: {
 | 
| +      if (addr_family_ != AF_INET)
 | 
| +        return ERR_ADDRESS_INVALID;
 | 
| +      ip_mreq mreq;
 | 
| +      mreq.imr_interface.s_addr = INADDR_ANY;
 | 
| +      memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
 | 
| +      int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP,
 | 
| +                      reinterpret_cast<const char*>(&mreq),
 | 
| +                      sizeof(mreq));
 | 
| +      if (rv)
 | 
| +        return MapSystemError(WSAGetLastError());
 | 
| +      return OK;
 | 
| +    }
 | 
| +    case kIPv6AddressSize: {
 | 
| +      if (addr_family_ != AF_INET6)
 | 
| +        return ERR_ADDRESS_INVALID;
 | 
| +      ipv6_mreq mreq;
 | 
| +      mreq.ipv6mr_interface = 0;  // 0 indicates default multicast interface.
 | 
| +      memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
 | 
| +      int rv = setsockopt(socket_, IPPROTO_IPV6, IP_DROP_MEMBERSHIP,
 | 
| +                      reinterpret_cast<const char*>(&mreq),
 | 
| +                      sizeof(mreq));
 | 
| +      if (rv)
 | 
| +        return MapSystemError(WSAGetLastError());
 | 
| +      return OK;
 | 
| +    }
 | 
| +    default:
 | 
| +      NOTREACHED() << "Invalid address family";
 | 
| +      return ERR_ADDRESS_INVALID;
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +int UDPSocketWin::SetMulticastTimeToLive(int time_to_live) {
 | 
| +  DCHECK(CalledOnValidThread());
 | 
| +  if (is_connected())
 | 
| +    return ERR_UNEXPECTED;
 | 
| +
 | 
| +  if (time_to_live < 0 || time_to_live > 255)
 | 
| +    return ERR_INVALID_ARGUMENT;
 | 
| +  multicast_time_to_live_ = time_to_live;
 | 
| +  return OK;
 | 
| +}
 | 
| +
 | 
| +int UDPSocketWin::SetMulticastLoopbackMode(bool loopback) {
 | 
| +  DCHECK(CalledOnValidThread());
 | 
| +  if (is_connected())
 | 
| +    return ERR_UNEXPECTED;
 | 
| +
 | 
| +  if (loopback)
 | 
| +    socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
 | 
| +  else
 | 
| +    socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
 | 
| +  return OK;
 | 
| +}
 | 
| +
 | 
|  }  // namespace net
 | 
| 
 |