diff options
author | ikarienator@chromium.org <ikarienator@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-30 00:53:18 +0000 |
---|---|---|
committer | ikarienator@chromium.org <ikarienator@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-30 00:53:18 +0000 |
commit | 5f01ce2a2ae37642c94d7be68f9b32423f69eddd (patch) | |
tree | 7ab6ea1cb8fcaec943a64ee4cb530a5f68a5a490 /net/udp/udp_socket_libevent.cc | |
parent | cd756659546ef1bebf9f939b1bba4a1dd64be552 (diff) | |
download | chromium_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.cc | 137 |
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 |