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..5209244dbeb1b943a10aa800a73ebd2e8e2985db 100644 |
| --- a/net/udp/udp_socket_libevent.cc |
| +++ b/net/udp/udp_socket_libevent.cc |
| @@ -41,7 +41,9 @@ UDPSocketLibevent::UDPSocketLibevent( |
| net::NetLog* net_log, |
| const net::NetLog::Source& source) |
| : socket_(kInvalidSocket), |
| - 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), |
| read_watcher_(this), |
| @@ -363,7 +365,8 @@ void UDPSocketLibevent::LogRead(int result, |
| } |
| int UDPSocketLibevent::CreateSocket(const IPEndPoint& address) { |
| - socket_ = socket(address.GetSockAddrFamily(), SOCK_DGRAM, 0); |
| + addr_family_ = address.GetSockAddrFamily(); |
| + socket_ = socket(addr_family_, SOCK_DGRAM, 0); |
| if (socket_ == kInvalidSocket) |
| return MapSystemError(errno); |
| if (SetNonBlocking(socket_)) { |
| @@ -476,11 +479,31 @@ 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)); |
| +#endif // defined(OS_MACOSX) |
| + if (rv < 0) |
| + return MapSystemError(errno); |
| + } |
| + |
| + if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) { |
| + uint8 loop = 0; |
|
wtc
2013/04/17 22:06:50
BUG: it seems that this variable needs to be a u_i
Bei Zhang
2013/04/19 19:40:14
Done. Now we use different branches for IPv4 and I
|
| + int ip_family = |
|
wtc
2013/04/17 22:06:50
This variable should be named 'level' or 'protocol
Bei Zhang
2013/04/19 19:40:14
Done.
|
| + addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; |
| + int option = |
| + addr_family_ == AF_INET ? IP_MULTICAST_LOOP: IPV6_MULTICAST_LOOP; |
| + int rv = setsockopt(socket_, ip_family, option, &loop, sizeof(loop)); |
| + if (rv < 0) |
| + return MapSystemError(errno); |
| + } |
| + if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) { |
| + uint8 ttl = multicast_time_to_live_; |
| + int ip_family = |
| + addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; |
| + int option = |
| + addr_family_ == AF_INET ? IP_MULTICAST_TTL: IP_MULTICAST_TTL; |
|
wtc
2013/04/17 22:06:50
BUG?: I think we need to use IPV6_MULTICAST_HOPS f
Bei Zhang
2013/04/19 19:40:14
Done.
|
| + int rv = setsockopt(socket_, ip_family, option, &ttl, sizeof(ttl)); |
| if (rv < 0) |
| return MapSystemError(errno); |
| } |
| @@ -509,4 +532,92 @@ int UDPSocketLibevent::RandomBind(const IPEndPoint& address) { |
| return DoBind(IPEndPoint(ip, 0)); |
| } |
| +int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const { |
| + DCHECK(CalledOnValidThread()); |
| + DCHECK(is_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, |
| + &mreq, sizeof(mreq)); |
| + if (rv < 0) |
| + return MapSystemError(errno); |
| + 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_JOIN_GROUP, |
| + &mreq, sizeof(mreq)); |
| + if (rv < 0) |
| + return MapSystemError(errno); |
| + return OK; |
| + } |
| + default: |
| + NOTREACHED() << "Invalid address family"; |
| + return ERR_ADDRESS_INVALID; |
| + } |
| +} |
| + |
| +int UDPSocketLibevent::LeaveGroup(const IPAddressNumber& group_address) const { |
| + DCHECK(CalledOnValidThread()); |
| + DCHECK(is_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, |
| + &mreq, sizeof(mreq)); |
| + if (rv < 0) |
| + return MapSystemError(errno); |
| + 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_LEAVE_GROUP, |
| + &mreq, sizeof(mreq)); |
| + if (rv < 0) |
| + return MapSystemError(errno); |
| + return OK; |
| + } |
| + default: |
| + NOTREACHED() << "Invalid address family"; |
| + return ERR_ADDRESS_INVALID; |
| + } |
| +} |
| + |
| +int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) { |
| + DCHECK(CalledOnValidThread()); |
| + DCHECK(!is_connected()); |
| + if (time_to_live < 0 || time_to_live > 255) |
| + return ERR_INVALID_ARGUMENT; |
| + multicast_time_to_live_ = time_to_live; |
| + return OK; |
| +} |
| + |
| +int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback) { |
| + DCHECK(CalledOnValidThread()); |
| + DCHECK(!is_connected()); |
| + if (loopback) |
| + socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP; |
| + else |
| + socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP; |
| + return OK; |
| +} |
| } // namespace net |