 Chromium Code Reviews
 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 063da08c387963b60066b3d1459aa82b9703a970..1c0f80d5b7bf5ef4c67416741e3f277b7243782f 100644 | 
| --- a/net/udp/udp_socket_libevent.cc | 
| +++ b/net/udp/udp_socket_libevent.cc | 
| @@ -41,7 +41,10 @@ UDPSocketLibevent::UDPSocketLibevent( | 
| net::NetLog* net_log, | 
| const net::NetLog::Source& source) | 
| : socket_(kInvalidSocket), | 
| + sock_addr_family_(0), | 
| socket_options_(0), | 
| + multicast_time_to_live_(1), | 
| + multicast_loopback_mode_(true), | 
| bind_type_(bind_type), | 
| rand_int_cb_(rand_int_cb), | 
| read_watcher_(this), | 
| @@ -363,7 +366,8 @@ void UDPSocketLibevent::LogRead(int result, | 
| } | 
| int UDPSocketLibevent::CreateSocket(const IPEndPoint& address) { | 
| - socket_ = socket(address.GetSockAddrFamily(), SOCK_DGRAM, 0); | 
| + sock_addr_family_ = address.GetSockAddrFamily(); | 
| + socket_ = socket(sock_addr_family_, SOCK_DGRAM, 0); | 
| if (socket_ == kInvalidSocket) | 
| return MapSystemError(errno); | 
| if (SetNonBlocking(socket_)) { | 
| @@ -476,14 +480,23 @@ int UDPSocketLibevent::SetSocketOptions() { | 
| // port. | 
| rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &true_value, | 
| sizeof(true_value)); | 
| - if (rv < 0) | 
| - return MapSystemError(errno); | 
| -#endif // defined(OS_MACOSX) | 
| +#else | 
| rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &true_value, | 
| sizeof(true_value)); | 
| 
mmenke
2013/04/16 18:09:49
This needs to be done on OSX, too.
 
Bei Zhang
2013/04/17 17:53:03
It's done in the other #if branch.
 | 
| +#endif // defined(OS_MACOSX) | 
| if (rv < 0) | 
| return MapSystemError(errno); | 
| } | 
| + if (multicast_time_to_live_ != 1) { | 
| + int rv = SetMulticastTimeToLive(multicast_time_to_live_); | 
| + if (rv != OK) | 
| + return rv; | 
| + } | 
| + if (!multicast_loopback_mode_) { | 
| + int rv = SetMulticastLoopbackMode(multicast_loopback_mode_); | 
| + if (rv != OK) | 
| + return rv; | 
| + } | 
| return OK; | 
| } | 
| @@ -509,4 +522,99 @@ int UDPSocketLibevent::RandomBind(const IPEndPoint& address) { | 
| return DoBind(IPEndPoint(ip, 0)); | 
| } | 
| +int UDPSocketLibevent::JoinGroup( | 
| + const net::IPAddressNumber& group_address) const { | 
| + DCHECK(CalledOnValidThread()); | 
| + DCHECK(is_connected()); | 
| + | 
| + int rv = -1; | 
| 
mmenke
2013/04/16 18:09:49
Sending a -1 through MapSystemError on fall throug
 
Bei Zhang
2013/04/17 17:53:03
Done.
 | 
| + switch (group_address.size()) { | 
| + case kIPv4AddressSize: { | 
| + if (sock_addr_family_ != AF_INET) | 
| + return ERR_ADDRESS_INVALID; | 
| + ip_mreq mreq; | 
| + memset(&mreq, 0, sizeof(mreq)); | 
| + memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize); | 
| 
mmenke
2013/04/16 18:09:49
Seems like we should be explicitely using IN_ADDRA
 
Bei Zhang
2013/04/17 17:53:03
Done.
 | 
| + rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP, | 
| + &mreq, sizeof(mreq)); | 
| + break; | 
| + } | 
| + case kIPv6AddressSize: { | 
| + if (sock_addr_family_ != AF_INET6) | 
| + return ERR_ADDRESS_INVALID; | 
| + ipv6_mreq mreq; | 
| + memset(&mreq, 0, sizeof(mreq)); | 
| + memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize); | 
| + rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP, | 
| + &mreq, sizeof(mreq)); | 
| 
mmenke
2013/04/16 18:09:49
Seems like we should be explicitely using in6addr_
 
Bei Zhang
2013/04/17 17:53:03
Done.
 | 
| + break; | 
| + } | 
| + } | 
| + | 
| + return MapSystemError(rv); | 
| +} | 
| + | 
| +int UDPSocketLibevent::LeaveGroup( | 
| + const net::IPAddressNumber& group_address) const { | 
| + DCHECK(CalledOnValidThread()); | 
| + DCHECK(is_connected()); | 
| + | 
| + int rv = -1; | 
| + switch (group_address.size()) { | 
| + case kIPv4AddressSize: { | 
| + if (sock_addr_family_ != AF_INET) | 
| + return ERR_ADDRESS_INVALID; | 
| + ip_mreq mreq; | 
| + memset(&mreq, 0, sizeof(mreq)); | 
| + memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize); | 
| + rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP, | 
| + &mreq, sizeof(mreq)); | 
| + break; | 
| + } | 
| + case kIPv6AddressSize: { | 
| + if (sock_addr_family_ != AF_INET6) | 
| + return ERR_ADDRESS_INVALID; | 
| + ipv6_mreq mreq; | 
| + memset(&mreq, 0, sizeof(mreq)); | 
| + memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize); | 
| + rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_LEAVE_GROUP, | 
| + &mreq, sizeof(mreq)); | 
| + break; | 
| + } | 
| + } | 
| + | 
| + return MapSystemError(rv); | 
| +} | 
| + | 
| +int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) { | 
| + DCHECK(CalledOnValidThread()); | 
| + if (time_to_live < 0 || time_to_live > 255) | 
| + return ERR_INVALID_ARGUMENT; | 
| + if (is_connected()) { | 
| 
mmenke
2013/04/16 18:09:49
Do we need these to be dynamically configurable?
 
Bei Zhang
2013/04/17 17:53:03
I thought about this for a while. I think you are
 | 
| + uint8 ttl = time_to_live; | 
| + int ip_family = sock_addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; | 
| + return MapSystemError(setsockopt(socket_, | 
| + ip_family, | 
| + IP_MULTICAST_TTL, | 
| + &ttl, sizeof(ttl))); | 
| + } else { | 
| 
mmenke
2013/04/16 18:09:49
Preferred style in Chrome is not to have an else h
 
Bei Zhang
2013/04/17 17:53:03
Done.
 | 
| + multicast_time_to_live_ = time_to_live; | 
| + return OK; | 
| + } | 
| +} | 
| + | 
| +int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback) { | 
| + DCHECK(CalledOnValidThread()); | 
| + if (is_connected()) { | 
| + uint8 loop = loopback; | 
| + int ip_family = sock_addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; | 
| + return MapSystemError(setsockopt(socket_, | 
| + ip_family, | 
| + IP_MULTICAST_LOOP, | 
| + &loop, sizeof(loop))); | 
| + } else { | 
| + multicast_loopback_mode_ = loopback; | 
| + return OK; | 
| + } | 
| +} | 
| } // namespace net |