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..91dec1ec10ef6f21efae6f34ddb309e5d65c565b 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,40 @@ 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)) { |
+ int rv; |
+ if (addr_family_ == AF_INET) { |
+ u_char loop = 0; |
+ rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_LOOP, |
+ &loop, sizeof(loop)); |
+ } else { |
+ u_int loop = 0; |
+ rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, |
+ &loop, sizeof(loop)); |
+ } |
+ if (rv < 0) |
+ return MapSystemError(errno); |
+ } |
+ if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) { |
+ int rv; |
+ if (addr_family_ == AF_INET) { |
+ u_char ttl = multicast_time_to_live_; |
+ rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL, |
+ &ttl, sizeof(ttl)); |
+ } else { |
+ // Signed interger. -1 to use route default. |
+ int ttl = multicast_time_to_live_; |
+ rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, |
+ &ttl, sizeof(ttl)); |
+ } |
if (rv < 0) |
return MapSystemError(errno); |
} |
@@ -509,4 +541,99 @@ int UDPSocketLibevent::RandomBind(const IPEndPoint& address) { |
return DoBind(IPEndPoint(ip, 0)); |
} |
+int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const { |
+ DCHECK(CalledOnValidThread()); |
+ if(!is_connected()) |
wtc
2013/04/23 22:15:26
Add a space between "if" and the opening parenthes
Bei Zhang
2013/04/24 16:50:50
Done.
|
+ 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, |
+ &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()); |
+ |
+ 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, |
+ &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()); |
+ if(is_connected()) |
+ return ERR_UNEXPECTED; |
wtc
2013/04/23 22:15:26
We should add a new error code ERR_SOCKET_IS_CONNE
Bei Zhang
2013/04/24 16:50:50
Created a bug at http://crbug.com/235066 .
On 201
|
+ |
+ 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()); |
+ 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 |