| Index: content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
 | 
| diff --git a/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
 | 
| index 50221d9222c4f7dfe3e7f2c87e3218020c864d48..38e2bc283a3974655e791510c4b4676f9d162667 100644
 | 
| --- a/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
 | 
| +++ b/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
 | 
| @@ -11,6 +11,7 @@
 | 
|  #include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
 | 
|  #include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
 | 
|  #include "content/public/browser/browser_thread.h"
 | 
| +#include "content/public/browser/content_browser_client.h"
 | 
|  #include "content/public/common/process_type.h"
 | 
|  #include "content/public/common/socket_permission_request.h"
 | 
|  #include "ipc/ipc_message_macros.h"
 | 
| @@ -60,6 +61,8 @@ PepperUDPSocketMessageFilter::PepperUDPSocketMessageFilter(
 | 
|      : socket_options_(0),
 | 
|        rcvbuf_size_(0),
 | 
|        sndbuf_size_(0),
 | 
| +      multicast_ttl_(0),
 | 
| +      can_use_multicast_(PP_ERROR_FAILED),
 | 
|        closed_(false),
 | 
|        remaining_recv_slots_(UDPSocketResourceBase::kPluginReceiveBufferSlots),
 | 
|        external_plugin_(host->external_plugin()),
 | 
| @@ -95,6 +98,8 @@ PepperUDPSocketMessageFilter::OverrideTaskRunnerForMessage(
 | 
|        return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
 | 
|      case PpapiHostMsg_UDPSocket_Bind::ID:
 | 
|      case PpapiHostMsg_UDPSocket_SendTo::ID:
 | 
| +    case PpapiHostMsg_UDPSocket_JoinGroup::ID:
 | 
| +    case PpapiHostMsg_UDPSocket_LeaveGroup::ID:
 | 
|        return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
 | 
|    }
 | 
|    return NULL;
 | 
| @@ -113,6 +118,10 @@ int32_t PepperUDPSocketMessageFilter::OnResourceMessageReceived(
 | 
|                                          OnMsgClose)
 | 
|      PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
 | 
|          PpapiHostMsg_UDPSocket_RecvSlotAvailable, OnMsgRecvSlotAvailable)
 | 
| +    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_JoinGroup,
 | 
| +                                      OnMsgJoinGroup)
 | 
| +    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_LeaveGroup,
 | 
| +                                      OnMsgLeaveGroup)
 | 
|    PPAPI_END_MESSAGE_MAP()
 | 
|    return PP_ERROR_FAILED;
 | 
|  }
 | 
| @@ -151,7 +160,7 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
 | 
|        if (!value.GetBool(&boolean_value))
 | 
|          return PP_ERROR_BADARGUMENT;
 | 
|  
 | 
| -      // If the socket is already connected, proxy the value to TCPSocket.
 | 
| +      // If the socket is already bound, proxy the value to UDPSocket.
 | 
|        if (socket_.get())
 | 
|          return NetErrorToPepperError(socket_->SetBroadcast(boolean_value));
 | 
|  
 | 
| @@ -171,7 +180,7 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
 | 
|                ppapi::proxy::UDPSocketResourceBase::kMaxSendBufferSize)
 | 
|          return PP_ERROR_BADARGUMENT;
 | 
|  
 | 
| -      // If the socket is already connected, proxy the value to UDPSocket.
 | 
| +      // If the socket is already bound, proxy the value to UDPSocket.
 | 
|        if (socket_.get()) {
 | 
|          return NetErrorToPepperError(
 | 
|              socket_->SetSendBufferSize(integer_value));
 | 
| @@ -190,7 +199,7 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
 | 
|                ppapi::proxy::UDPSocketResourceBase::kMaxReceiveBufferSize)
 | 
|          return PP_ERROR_BADARGUMENT;
 | 
|  
 | 
| -      // If the socket is already connected, proxy the value to UDPSocket.
 | 
| +      // If the socket is already bound, proxy the value to UDPSocket.
 | 
|        if (socket_.get()) {
 | 
|          return NetErrorToPepperError(
 | 
|              socket_->SetReceiveBufferSize(integer_value));
 | 
| @@ -201,6 +210,48 @@ int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
 | 
|        rcvbuf_size_ = integer_value;
 | 
|        return PP_OK;
 | 
|      }
 | 
| +    case PP_UDPSOCKET_OPTION_MULTICAST_LOOP: {
 | 
| +      bool boolean_value = false;
 | 
| +      if (!value.GetBool(&boolean_value))
 | 
| +        return PP_ERROR_BADARGUMENT;
 | 
| +
 | 
| +      // If the socket is already bound, proxy the value to UDPSocket.
 | 
| +      if (socket_) {
 | 
| +        if (can_use_multicast_ != PP_OK)
 | 
| +          return can_use_multicast_;
 | 
| +
 | 
| +        return NetErrorToPepperError(
 | 
| +            socket_->SetMulticastLoopbackMode(boolean_value));
 | 
| +      }
 | 
| +
 | 
| +      // UDPSocket instance is not yet created, so remember the value here.
 | 
| +      if (boolean_value) {
 | 
| +        socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
 | 
| +      } else {
 | 
| +        socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
 | 
| +      }
 | 
| +      return PP_OK;
 | 
| +    }
 | 
| +    case PP_UDPSOCKET_OPTION_MULTICAST_TTL: {
 | 
| +      int32_t integer_value = 0;
 | 
| +      if (!value.GetInt32(&integer_value) ||
 | 
| +          integer_value < 0 || integer_value > 255)
 | 
| +        return PP_ERROR_BADARGUMENT;
 | 
| +
 | 
| +      // If the socket is already bound, proxy the value to UDPSocket.
 | 
| +      if (socket_) {
 | 
| +        if (can_use_multicast_ != PP_OK)
 | 
| +          return can_use_multicast_;
 | 
| +
 | 
| +        return NetErrorToPepperError(
 | 
| +            socket_->SetMulticastTimeToLive(integer_value));
 | 
| +      }
 | 
| +
 | 
| +      // UDPSocket instance is not yet created, so remember the value here.
 | 
| +      socket_options_ |= SOCKET_OPTION_MULTICAST_TTL;
 | 
| +      multicast_ttl_ = integer_value;
 | 
| +      return PP_OK;
 | 
| +    }
 | 
|      default: {
 | 
|        NOTREACHED();
 | 
|        return PP_ERROR_BADARGUMENT;
 | 
| @@ -214,6 +265,12 @@ int32_t PepperUDPSocketMessageFilter::OnMsgBind(
 | 
|    DCHECK_CURRENTLY_ON(BrowserThread::UI);
 | 
|    DCHECK(context);
 | 
|  
 | 
| +  // Check for permissions to use multicast APIS. This check must be done while
 | 
| +  // on the UI thread, so we cache the value here to be used later on.
 | 
| +  PP_NetAddress_Private any_addr;
 | 
| +  NetAddressPrivateImpl::GetAnyAddress(PP_FALSE, &any_addr);
 | 
| +  can_use_multicast_ = CanUseMulticastAPI(any_addr);
 | 
| +
 | 
|    SocketPermissionRequest request =
 | 
|        pepper_socket_utils::CreateSocketPermissionRequest(
 | 
|            SocketPermissionRequest::UDP_BIND, addr);
 | 
| @@ -286,6 +343,48 @@ int32_t PepperUDPSocketMessageFilter::OnMsgRecvSlotAvailable(
 | 
|    return PP_OK;
 | 
|  }
 | 
|  
 | 
| +int32_t PepperUDPSocketMessageFilter::OnMsgJoinGroup(
 | 
| +    const ppapi::host::HostMessageContext* context,
 | 
| +    const PP_NetAddress_Private& addr) {
 | 
| +  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 | 
| +
 | 
| +  int32_t ret = CanUseMulticastAPI(addr);
 | 
| +  if (ret != PP_OK)
 | 
| +    return ret;
 | 
| +
 | 
| +  if (!socket_)
 | 
| +    return PP_ERROR_FAILED;
 | 
| +
 | 
| +  net::IPAddressNumber group;
 | 
| +  uint16 port;
 | 
| +
 | 
| +  if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &group, &port))
 | 
| +    return PP_ERROR_ADDRESS_INVALID;
 | 
| +
 | 
| +  return NetErrorToPepperError(socket_->JoinGroup(group));
 | 
| +}
 | 
| +
 | 
| +int32_t PepperUDPSocketMessageFilter::OnMsgLeaveGroup(
 | 
| +    const ppapi::host::HostMessageContext* context,
 | 
| +    const PP_NetAddress_Private& addr) {
 | 
| +  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 | 
| +
 | 
| +  int32_t ret = CanUseMulticastAPI(addr);
 | 
| +  if (ret != PP_OK)
 | 
| +    return ret;
 | 
| +
 | 
| +  if (!socket_)
 | 
| +    return PP_ERROR_FAILED;
 | 
| +
 | 
| +  net::IPAddressNumber group;
 | 
| +  uint16 port;
 | 
| +
 | 
| +  if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &group, &port))
 | 
| +    return PP_ERROR_ADDRESS_INVALID;
 | 
| +
 | 
| +  return NetErrorToPepperError(socket_->LeaveGroup(group));
 | 
| +}
 | 
| +
 | 
|  void PepperUDPSocketMessageFilter::DoBind(
 | 
|      const ppapi::host::ReplyMessageContext& context,
 | 
|      const PP_NetAddress_Private& addr) {
 | 
| @@ -343,6 +442,30 @@ void PepperUDPSocketMessageFilter::DoBind(
 | 
|        return;
 | 
|      }
 | 
|    }
 | 
| +  if (socket_options_ & SOCKET_OPTION_MULTICAST_LOOP) {
 | 
| +    if (can_use_multicast_ != PP_OK) {
 | 
| +      SendBindError(context, NetErrorToPepperError(can_use_multicast_));
 | 
| +      return;
 | 
| +    }
 | 
| +
 | 
| +    int net_result = socket->SetMulticastLoopbackMode(true);
 | 
| +    if (net_result != net::OK) {
 | 
| +      SendBindError(context, NetErrorToPepperError(net_result));
 | 
| +      return;
 | 
| +    }
 | 
| +  }
 | 
| +  if (socket_options_ & SOCKET_OPTION_MULTICAST_TTL) {
 | 
| +    if (can_use_multicast_ != PP_OK) {
 | 
| +      SendBindError(context, NetErrorToPepperError(can_use_multicast_));
 | 
| +      return;
 | 
| +    }
 | 
| +
 | 
| +    int net_result = socket->SetMulticastTimeToLive(multicast_ttl_);
 | 
| +    if (net_result != net::OK) {
 | 
| +      SendBindError(context, NetErrorToPepperError(net_result));
 | 
| +      return;
 | 
| +    }
 | 
| +  }
 | 
|  
 | 
|    {
 | 
|      int net_result = socket->Bind(end_point);
 | 
| @@ -570,4 +693,30 @@ void PepperUDPSocketMessageFilter::SendSendToError(
 | 
|    SendSendToReply(context, result, 0);
 | 
|  }
 | 
|  
 | 
| +int32_t PepperUDPSocketMessageFilter::CanUseMulticastAPI(
 | 
| +    const PP_NetAddress_Private& addr) {
 | 
| +  // Check for Dev API.
 | 
| +  // TODO(etrunko): remove check when Multicast API reaches beta/stable.
 | 
| +  // https://crbug.com/464452
 | 
| +  ContentBrowserClient* content_browser_client = GetContentClient()->browser();
 | 
| +  if (!content_browser_client->IsPluginAllowedToUseDevChannelAPIs(nullptr,
 | 
| +                                                                  GURL())) {
 | 
| +    return PP_ERROR_NOTSUPPORTED;
 | 
| +  }
 | 
| +
 | 
| +  // Check for plugin permissions.
 | 
| +  SocketPermissionRequest request =
 | 
| +      pepper_socket_utils::CreateSocketPermissionRequest(
 | 
| +          SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, addr);
 | 
| +  if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_,
 | 
| +                                             private_api_,
 | 
| +                                             &request,
 | 
| +                                             render_process_id_,
 | 
| +                                             render_frame_id_)) {
 | 
| +    return PP_ERROR_NOACCESS;
 | 
| +  }
 | 
| +
 | 
| +  return PP_OK;
 | 
| +}
 | 
| +
 | 
|  }  // namespace content
 | 
| 
 |