summaryrefslogtreecommitdiffstats
path: root/net/udp/udp_socket_libevent.cc
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/udp_socket_libevent.cc
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/udp_socket_libevent.cc')
-rw-r--r--net/udp/udp_socket_libevent.cc137
1 files changed, 132 insertions, 5 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