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 |