summaryrefslogtreecommitdiffstats
path: root/net/udp
diff options
context:
space:
mode:
authorikarienator@chromium.org <ikarienator@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-30 00:53:18 +0000
committerikarienator@chromium.org <ikarienator@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-30 00:53:18 +0000
commit5f01ce2a2ae37642c94d7be68f9b32423f69eddd (patch)
tree7ab6ea1cb8fcaec943a64ee4cb530a5f68a5a490 /net/udp
parentcd756659546ef1bebf9f939b1bba4a1dd64be552 (diff)
downloadchromium_src-5f01ce2a2ae37642c94d7be68f9b32423f69eddd.zip
chromium_src-5f01ce2a2ae37642c94d7be68f9b32423f69eddd.tar.gz
chromium_src-5f01ce2a2ae37642c94d7be68f9b32423f69eddd.tar.bz2
Introduce Multicast Socket API
Allow Chrome Apps developer to receive multicast socket packets by exposing join/leave group ability to UDP socket. Introducing: 1. chrome.socket.joinGroup / chrome.socket.leaveGroup / chrome.socket.getJoinedGroups to manipulate multicast group membership. 2. Socket permission 'udp-multicast-membership'. 3. chrome.socket.setMulticastTimeToLive / chrome.socket.setMulticastLoopbackMode to control the multicast packet sending for UDP sender. To expose the ability of manipulating multicast group membership and controlling multicast packet sending, new methods are added into network stack (net::UDPSocket class): 1. JoinGroup/LeaveGroup 2. SetMulticastTimeToLive/SetMulticastLoopbackMode To demo the ability, a demo app is created: https://github.com/GoogleChrome/chrome-app-samples/pull/92 TEST=Open the demo app at /chrome-app-samples/multicast in two machines of the same network. Open them and chat, they can talk to each other. NOTRY=true BUG=140681 Review URL: https://chromiumcodereview.appspot.com/12684008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@197192 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/udp')
-rw-r--r--net/udp/udp_socket_libevent.cc137
-rw-r--r--net/udp/udp_socket_libevent.h48
-rw-r--r--net/udp/udp_socket_unittest.cc54
-rw-r--r--net/udp/udp_socket_win.cc134
-rw-r--r--net/udp/udp_socket_win.h46
5 files changed, 406 insertions, 13 deletions
diff --git a/net/udp/udp_socket_libevent.cc b/net/udp/udp_socket_libevent.cc
index 063da08..f713786 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())
+ 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;
+
+ 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
diff --git a/net/udp/udp_socket_libevent.h b/net/udp/udp_socket_libevent.h
index ce8a0f2..ceec17e 100644
--- a/net/udp/udp_socket_libevent.h
+++ b/net/udp/udp_socket_libevent.h
@@ -113,12 +113,51 @@ class NET_EXPORT UDPSocketLibevent : public base::NonThreadSafe {
// called before Bind().
void AllowBroadcast();
+ // Join the multicast group.
+ // |group_address| is the group address to join, could be either
+ // an IPv4 or IPv6 address.
+ // Return a network error code.
+ int JoinGroup(const IPAddressNumber& group_address) const;
+
+ // Leave the multicast group.
+ // |group_address| is the group address to leave, could be either
+ // an IPv4 or IPv6 address. If the socket hasn't joined the group,
+ // it will be ignored.
+ // It's optional to leave the multicast group before destroying
+ // the socket. It will be done by the OS.
+ // Return a network error code.
+ int LeaveGroup(const IPAddressNumber& group_address) const;
+
+ // Set the time-to-live option for UDP packets sent to the multicast
+ // group address. The default value of this option is 1.
+ // Cannot be negative or more than 255.
+ // Should be called before Bind().
+ // Return a network error code.
+ int SetMulticastTimeToLive(int time_to_live);
+
+ // Set the loopback flag for UDP socket. If this flag is true, the host
+ // will receive packets sent to the joined group from itself.
+ // The default value of this option is true.
+ // Should be called before Bind().
+ // Return a network error code.
+ //
+ // Note: the behavior of |SetMulticastLoopbackMode| is slightly
+ // different between Windows and Unix-like systems. The inconsistency only
+ // happens when there are more than one applications on the same host
+ // joined to the same multicast group while having different settings on
+ // multicast loopback mode. On Windows, the applications with loopback off
+ // will not RECEIVE the loopback packets; while on Unix-like systems, the
+ // applications with loopback off will not SEND the loopback packets to
+ // other applications on the same host. See MSDN: http://goo.gl/6vqbj
+ int SetMulticastLoopbackMode(bool loopback);
+
private:
static const int kInvalidSocket = -1;
enum SocketOptions {
- SOCKET_OPTION_REUSE_ADDRESS = 1 << 0,
- SOCKET_OPTION_BROADCAST = 1 << 1
+ SOCKET_OPTION_REUSE_ADDRESS = 1 << 0,
+ SOCKET_OPTION_BROADCAST = 1 << 1,
+ SOCKET_OPTION_MULTICAST_LOOP = 1 << 2
};
class ReadWatcher : public MessageLoopForIO::Watcher {
@@ -188,11 +227,16 @@ class NET_EXPORT UDPSocketLibevent : public base::NonThreadSafe {
int RandomBind(const IPEndPoint& address);
int socket_;
+ int addr_family_;
// Bitwise-or'd combination of SocketOptions. Specifies the set of
// options that should be applied to |socket_| before Bind().
int socket_options_;
+ // Multicast socket options cached for SetSocketOption.
+ // Cannot be used after Bind().
+ int multicast_time_to_live_;
+
// How to do source port binding, used only when UDPSocket is part of
// UDPClientSocket, since UDPServerSocket provides Bind.
DatagramSocket::BindType bind_type_;
diff --git a/net/udp/udp_socket_unittest.cc b/net/udp/udp_socket_unittest.cc
index 09a2806..d488bea 100644
--- a/net/udp/udp_socket_unittest.cc
+++ b/net/udp/udp_socket_unittest.cc
@@ -526,6 +526,60 @@ TEST_F(UDPSocketTest, CloseWithPendingRead) {
EXPECT_FALSE(callback.have_result());
}
+#if defined(OS_ANDROID)
+// Some Android devices do not support multicast socket.
+// The ones supporting multicast need WifiManager.MulitcastLock to enable it.
+// http://goo.gl/jjAk9
+#define MAYBE_JoinMulticastGroup DISABLED_JoinMulticastGroup
+#else
+#define MAYBE_JoinMulticastGroup JoinMulticastGroup
+#endif // defined(OS_ANDROID)
+
+TEST_F(UDPSocketTest, MAYBE_JoinMulticastGroup) {
+ const int kPort = 9999;
+ const char* const kGroup = "237.132.100.17";
+
+ IPEndPoint bind_address;
+ CreateUDPAddress("0.0.0.0", kPort, &bind_address);
+ IPAddressNumber group_ip;
+ EXPECT_TRUE(ParseIPLiteralToNumber(kGroup, &group_ip));
+
+ UDPSocket socket(DatagramSocket::DEFAULT_BIND,
+ RandIntCallback(),
+ NULL,
+ NetLog::Source());
+ EXPECT_EQ(OK, socket.Bind(bind_address));
+ EXPECT_EQ(OK, socket.JoinGroup(group_ip));
+ // Joining group multiple times.
+ EXPECT_NE(OK, socket.JoinGroup(group_ip));
+ EXPECT_EQ(OK, socket.LeaveGroup(group_ip));
+ // Leaving group multiple times.
+ EXPECT_NE(OK, socket.LeaveGroup(group_ip));
+
+ socket.Close();
+}
+
+TEST_F(UDPSocketTest, MulticastOptions) {
+ const int kPort = 9999;
+ IPEndPoint bind_address;
+ CreateUDPAddress("0.0.0.0", kPort, &bind_address);
+
+ UDPSocket socket(DatagramSocket::DEFAULT_BIND,
+ RandIntCallback(),
+ NULL,
+ NetLog::Source());
+ // Before binding.
+ EXPECT_EQ(OK, socket.SetMulticastLoopbackMode(false));
+ EXPECT_EQ(OK, socket.SetMulticastLoopbackMode(true));
+ EXPECT_EQ(OK, socket.SetMulticastTimeToLive(0));
+ EXPECT_EQ(OK, socket.SetMulticastTimeToLive(3));
+ EXPECT_NE(OK, socket.SetMulticastTimeToLive(-1));
+
+ EXPECT_EQ(OK, socket.Bind(bind_address));
+
+ socket.Close();
+}
+
} // namespace
} // namespace net
diff --git a/net/udp/udp_socket_win.cc b/net/udp/udp_socket_win.cc
index 5c6da9f..dd0f880 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
diff --git a/net/udp/udp_socket_win.h b/net/udp/udp_socket_win.h
index ce17050..807b403 100644
--- a/net/udp/udp_socket_win.h
+++ b/net/udp/udp_socket_win.h
@@ -115,10 +115,47 @@ class NET_EXPORT UDPSocketWin : NON_EXPORTED_BASE(public base::NonThreadSafe) {
// called before Bind().
void AllowBroadcast();
+ // Join the multicast group.
+ // |group_address| is the group address to join, could be either
+ // an IPv4 or IPv6 address.
+ // Return a network error code.
+ int JoinGroup(const IPAddressNumber& group_address) const;
+
+ // Leave the multicast group.
+ // |group_address| is the group address to leave, could be either
+ // an IPv4 or IPv6 address. If the socket hasn't joined the group,
+ // it will be ignored.
+ // It's optional to leave the multicast group before destroying
+ // the socket. It will be done by the OS.
+ // Return a network error code.
+ int LeaveGroup(const IPAddressNumber& group_address) const;
+
+ // Set the time-to-live option for UDP packets sent to the multicast
+ // group address. The default value of this option is 1.
+ // Cannot be negative or more than 255.
+ // Should be called before Bind().
+ int SetMulticastTimeToLive(int time_to_live);
+
+ // Set the loopback flag for UDP socket. If this flag is true, the host
+ // will receive packets sent to the joined group from itself.
+ // The default value of this option is true.
+ // Should be called before Bind().
+ //
+ // Note: the behavior of |SetMulticastLoopbackMode| is slightly
+ // different between Windows and Unix-like systems. The inconsistency only
+ // happens when there are more than one applications on the same host
+ // joined to the same multicast group while having different settings on
+ // multicast loopback mode. On Windows, the applications with loopback off
+ // will not RECEIVE the loopback packets; while on Unix-like systems, the
+ // applications with loopback off will not SEND the loopback packets to
+ // other applications on the same host. See MSDN: http://goo.gl/6vqbj
+ int SetMulticastLoopbackMode(bool loopback);
+
private:
enum SocketOptions {
- SOCKET_OPTION_REUSE_ADDRESS = 1 << 0,
- SOCKET_OPTION_BROADCAST = 1 << 1
+ SOCKET_OPTION_REUSE_ADDRESS = 1 << 0,
+ SOCKET_OPTION_BROADCAST = 1 << 1,
+ SOCKET_OPTION_MULTICAST_LOOP = 1 << 2
};
class Core;
@@ -160,11 +197,16 @@ class NET_EXPORT UDPSocketWin : NON_EXPORTED_BASE(public base::NonThreadSafe) {
bool ReceiveAddressToIPEndpoint(IPEndPoint* address) const;
SOCKET socket_;
+ int addr_family_;
// Bitwise-or'd combination of SocketOptions. Specifies the set of
// options that should be applied to |socket_| before Bind().
int socket_options_;
+ // Multicast socket options cached for SetSocketOption.
+ // Cannot be used after Bind().
+ int multicast_time_to_live_;
+
// How to do source port binding, used only when UDPSocket is part of
// UDPClientSocket, since UDPServerSocket provides Bind.
DatagramSocket::BindType bind_type_;