// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "extensions/browser/api/sockets_udp/sockets_udp_api.h" #include "content/public/common/socket_permission_request.h" #include "extensions/browser/api/socket/udp_socket.h" #include "extensions/browser/api/sockets_udp/udp_socket_event_dispatcher.h" #include "extensions/common/api/sockets/sockets_manifest_data.h" #include "net/base/net_errors.h" namespace extensions { namespace core_api { using content::SocketPermissionRequest; const char kSocketNotFoundError[] = "Socket not found"; const char kPermissionError[] = "App does not have permission"; const char kWildcardAddress[] = "*"; const int kWildcardPort = 0; UDPSocketAsyncApiFunction::~UDPSocketAsyncApiFunction() {} scoped_ptr UDPSocketAsyncApiFunction::CreateSocketResourceManager() { return scoped_ptr( new SocketResourceManager()).Pass(); } ResumableUDPSocket* UDPSocketAsyncApiFunction::GetUdpSocket(int socket_id) { return static_cast(GetSocket(socket_id)); } UDPSocketExtensionWithDnsLookupFunction:: ~UDPSocketExtensionWithDnsLookupFunction() {} scoped_ptr UDPSocketExtensionWithDnsLookupFunction::CreateSocketResourceManager() { return scoped_ptr( new SocketResourceManager()).Pass(); } ResumableUDPSocket* UDPSocketExtensionWithDnsLookupFunction::GetUdpSocket( int socket_id) { return static_cast(GetSocket(socket_id)); } linked_ptr CreateSocketInfo( int socket_id, ResumableUDPSocket* socket) { linked_ptr socket_info( new sockets_udp::SocketInfo()); // This represents what we know about the socket, and does not call through // to the system. socket_info->socket_id = socket_id; if (!socket->name().empty()) { socket_info->name.reset(new std::string(socket->name())); } socket_info->persistent = socket->persistent(); if (socket->buffer_size() > 0) { socket_info->buffer_size.reset(new int(socket->buffer_size())); } socket_info->paused = socket->paused(); // Grab the local address as known by the OS. net::IPEndPoint localAddress; if (socket->GetLocalAddress(&localAddress)) { socket_info->local_address.reset( new std::string(localAddress.ToStringWithoutPort())); socket_info->local_port.reset(new int(localAddress.port())); } return socket_info; } void SetSocketProperties(ResumableUDPSocket* socket, sockets_udp::SocketProperties* properties) { if (properties->name.get()) { socket->set_name(*properties->name.get()); } if (properties->persistent.get()) { socket->set_persistent(*properties->persistent.get()); } if (properties->buffer_size.get()) { socket->set_buffer_size(*properties->buffer_size.get()); } } SocketsUdpCreateFunction::SocketsUdpCreateFunction() {} SocketsUdpCreateFunction::~SocketsUdpCreateFunction() {} bool SocketsUdpCreateFunction::Prepare() { params_ = sockets_udp::Create::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(params_.get()); return true; } void SocketsUdpCreateFunction::Work() { ResumableUDPSocket* socket = new ResumableUDPSocket(extension_->id()); sockets_udp::SocketProperties* properties = params_.get()->properties.get(); if (properties) { SetSocketProperties(socket, properties); } sockets_udp::CreateInfo create_info; create_info.socket_id = AddSocket(socket); results_ = sockets_udp::Create::Results::Create(create_info); } SocketsUdpUpdateFunction::SocketsUdpUpdateFunction() {} SocketsUdpUpdateFunction::~SocketsUdpUpdateFunction() {} bool SocketsUdpUpdateFunction::Prepare() { params_ = sockets_udp::Update::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(params_.get()); return true; } void SocketsUdpUpdateFunction::Work() { ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id); if (!socket) { error_ = kSocketNotFoundError; return; } SetSocketProperties(socket, ¶ms_.get()->properties); results_ = sockets_udp::Update::Results::Create(); } SocketsUdpSetPausedFunction::SocketsUdpSetPausedFunction() : socket_event_dispatcher_(NULL) {} SocketsUdpSetPausedFunction::~SocketsUdpSetPausedFunction() {} bool SocketsUdpSetPausedFunction::Prepare() { params_ = core_api::sockets_udp::SetPaused::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(params_.get()); socket_event_dispatcher_ = UDPSocketEventDispatcher::Get(browser_context()); DCHECK(socket_event_dispatcher_) << "There is no socket event dispatcher. " "If this assertion is failing during a test, then it is likely that " "TestExtensionSystem is failing to provide an instance of " "UDPSocketEventDispatcher."; return socket_event_dispatcher_ != NULL; } void SocketsUdpSetPausedFunction::Work() { ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id); if (!socket) { error_ = kSocketNotFoundError; return; } if (socket->paused() != params_->paused) { socket->set_paused(params_->paused); if (socket->IsBound() && !params_->paused) { socket_event_dispatcher_->OnSocketResume(extension_->id(), params_->socket_id); } } results_ = sockets_udp::SetPaused::Results::Create(); } SocketsUdpBindFunction::SocketsUdpBindFunction() : socket_event_dispatcher_(NULL) {} SocketsUdpBindFunction::~SocketsUdpBindFunction() {} bool SocketsUdpBindFunction::Prepare() { params_ = sockets_udp::Bind::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(params_.get()); socket_event_dispatcher_ = UDPSocketEventDispatcher::Get(browser_context()); DCHECK(socket_event_dispatcher_) << "There is no socket event dispatcher. " "If this assertion is failing during a test, then it is likely that " "TestExtensionSystem is failing to provide an instance of " "UDPSocketEventDispatcher."; return socket_event_dispatcher_ != NULL; } void SocketsUdpBindFunction::AsyncWorkStart() { ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id); if (!socket) { error_ = kSocketNotFoundError; AsyncWorkCompleted(); return; } content::SocketPermissionRequest param( SocketPermissionRequest::UDP_BIND, params_->address, params_->port); if (!SocketsManifestData::CheckRequest(extension(), param)) { error_ = kPermissionError; AsyncWorkCompleted(); return; } int net_result = socket->Bind(params_->address, params_->port); results_ = sockets_udp::Bind::Results::Create(net_result); if (net_result == net::OK) { socket_event_dispatcher_->OnSocketBind(extension_->id(), params_->socket_id); } else { error_ = net::ErrorToString(net_result); AsyncWorkCompleted(); return; } OpenFirewallHole(params_->address, params_->socket_id, socket); } SocketsUdpSendFunction::SocketsUdpSendFunction() : io_buffer_size_(0) {} SocketsUdpSendFunction::~SocketsUdpSendFunction() {} bool SocketsUdpSendFunction::Prepare() { params_ = sockets_udp::Send::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(params_.get()); io_buffer_size_ = params_->data.size(); io_buffer_ = new net::WrappedIOBuffer(params_->data.data()); return true; } void SocketsUdpSendFunction::AsyncWorkStart() { ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id); if (!socket) { error_ = kSocketNotFoundError; AsyncWorkCompleted(); return; } content::SocketPermissionRequest param( SocketPermissionRequest::UDP_SEND_TO, params_->address, params_->port); if (!SocketsManifestData::CheckRequest(extension(), param)) { error_ = kPermissionError; AsyncWorkCompleted(); return; } StartDnsLookup(params_->address); } void SocketsUdpSendFunction::AfterDnsLookup(int lookup_result) { if (lookup_result == net::OK) { StartSendTo(); } else { SetSendResult(lookup_result, -1); } } void SocketsUdpSendFunction::StartSendTo() { ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id); if (!socket) { error_ = kSocketNotFoundError; AsyncWorkCompleted(); return; } socket->SendTo(io_buffer_, io_buffer_size_, resolved_address_, params_->port, base::Bind(&SocketsUdpSendFunction::OnCompleted, this)); } void SocketsUdpSendFunction::OnCompleted(int net_result) { if (net_result >= net::OK) { SetSendResult(net::OK, net_result); } else { SetSendResult(net_result, -1); } } void SocketsUdpSendFunction::SetSendResult(int net_result, int bytes_sent) { CHECK(net_result <= net::OK) << "Network status code must be < 0"; sockets_udp::SendInfo send_info; send_info.result_code = net_result; if (net_result == net::OK) { send_info.bytes_sent.reset(new int(bytes_sent)); } if (net_result != net::OK) error_ = net::ErrorToString(net_result); results_ = sockets_udp::Send::Results::Create(send_info); AsyncWorkCompleted(); } SocketsUdpCloseFunction::SocketsUdpCloseFunction() {} SocketsUdpCloseFunction::~SocketsUdpCloseFunction() {} bool SocketsUdpCloseFunction::Prepare() { params_ = sockets_udp::Close::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(params_.get()); return true; } void SocketsUdpCloseFunction::Work() { ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id); if (!socket) { error_ = kSocketNotFoundError; return; } socket->Disconnect(); RemoveSocket(params_->socket_id); results_ = sockets_udp::Close::Results::Create(); } SocketsUdpGetInfoFunction::SocketsUdpGetInfoFunction() {} SocketsUdpGetInfoFunction::~SocketsUdpGetInfoFunction() {} bool SocketsUdpGetInfoFunction::Prepare() { params_ = sockets_udp::GetInfo::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(params_.get()); return true; } void SocketsUdpGetInfoFunction::Work() { ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id); if (!socket) { error_ = kSocketNotFoundError; return; } linked_ptr socket_info = CreateSocketInfo(params_->socket_id, socket); results_ = sockets_udp::GetInfo::Results::Create(*socket_info); } SocketsUdpGetSocketsFunction::SocketsUdpGetSocketsFunction() {} SocketsUdpGetSocketsFunction::~SocketsUdpGetSocketsFunction() {} bool SocketsUdpGetSocketsFunction::Prepare() { return true; } void SocketsUdpGetSocketsFunction::Work() { std::vector > socket_infos; base::hash_set* resource_ids = GetSocketIds(); if (resource_ids != NULL) { for (base::hash_set::iterator it = resource_ids->begin(); it != resource_ids->end(); ++it) { int socket_id = *it; ResumableUDPSocket* socket = GetUdpSocket(socket_id); if (socket) { socket_infos.push_back(CreateSocketInfo(socket_id, socket)); } } } results_ = sockets_udp::GetSockets::Results::Create(socket_infos); } SocketsUdpJoinGroupFunction::SocketsUdpJoinGroupFunction() {} SocketsUdpJoinGroupFunction::~SocketsUdpJoinGroupFunction() {} bool SocketsUdpJoinGroupFunction::Prepare() { params_ = sockets_udp::JoinGroup::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(params_.get()); return true; } void SocketsUdpJoinGroupFunction::Work() { ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id); if (!socket) { error_ = kSocketNotFoundError; return; } content::SocketPermissionRequest param( SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, kWildcardAddress, kWildcardPort); if (!SocketsManifestData::CheckRequest(extension(), param)) { error_ = kPermissionError; return; } int net_result = socket->JoinGroup(params_->address); if (net_result != net::OK) error_ = net::ErrorToString(net_result); results_ = sockets_udp::JoinGroup::Results::Create(net_result); } SocketsUdpLeaveGroupFunction::SocketsUdpLeaveGroupFunction() {} SocketsUdpLeaveGroupFunction::~SocketsUdpLeaveGroupFunction() {} bool SocketsUdpLeaveGroupFunction::Prepare() { params_ = core_api::sockets_udp::LeaveGroup::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(params_.get()); return true; } void SocketsUdpLeaveGroupFunction::Work() { ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id); if (!socket) { error_ = kSocketNotFoundError; return; } content::SocketPermissionRequest param( SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, kWildcardAddress, kWildcardPort); if (!SocketsManifestData::CheckRequest(extension(), param)) { error_ = kPermissionError; return; } int net_result = socket->LeaveGroup(params_->address); if (net_result != net::OK) error_ = net::ErrorToString(net_result); results_ = sockets_udp::LeaveGroup::Results::Create(net_result); } SocketsUdpSetMulticastTimeToLiveFunction:: SocketsUdpSetMulticastTimeToLiveFunction() {} SocketsUdpSetMulticastTimeToLiveFunction:: ~SocketsUdpSetMulticastTimeToLiveFunction() {} bool SocketsUdpSetMulticastTimeToLiveFunction::Prepare() { params_ = core_api::sockets_udp::SetMulticastTimeToLive::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(params_.get()); return true; } void SocketsUdpSetMulticastTimeToLiveFunction::Work() { ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id); if (!socket) { error_ = kSocketNotFoundError; return; } int net_result = socket->SetMulticastTimeToLive(params_->ttl); if (net_result != net::OK) error_ = net::ErrorToString(net_result); results_ = sockets_udp::SetMulticastTimeToLive::Results::Create(net_result); } SocketsUdpSetMulticastLoopbackModeFunction:: SocketsUdpSetMulticastLoopbackModeFunction() {} SocketsUdpSetMulticastLoopbackModeFunction:: ~SocketsUdpSetMulticastLoopbackModeFunction() {} bool SocketsUdpSetMulticastLoopbackModeFunction::Prepare() { params_ = core_api::sockets_udp::SetMulticastLoopbackMode::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(params_.get()); return true; } void SocketsUdpSetMulticastLoopbackModeFunction::Work() { ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id); if (!socket) { error_ = kSocketNotFoundError; return; } int net_result = socket->SetMulticastLoopbackMode(params_->enabled); if (net_result != net::OK) error_ = net::ErrorToString(net_result); results_ = sockets_udp::SetMulticastLoopbackMode::Results::Create(net_result); } SocketsUdpGetJoinedGroupsFunction::SocketsUdpGetJoinedGroupsFunction() {} SocketsUdpGetJoinedGroupsFunction::~SocketsUdpGetJoinedGroupsFunction() {} bool SocketsUdpGetJoinedGroupsFunction::Prepare() { params_ = core_api::sockets_udp::GetJoinedGroups::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(params_.get()); return true; } void SocketsUdpGetJoinedGroupsFunction::Work() { ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id); if (!socket) { error_ = kSocketNotFoundError; return; } content::SocketPermissionRequest param( SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, kWildcardAddress, kWildcardPort); if (!SocketsManifestData::CheckRequest(extension(), param)) { error_ = kPermissionError; return; } const std::vector& groups = socket->GetJoinedGroups(); results_ = sockets_udp::GetJoinedGroups::Results::Create(groups); } SocketsUdpSetBroadcastFunction::SocketsUdpSetBroadcastFunction() { } SocketsUdpSetBroadcastFunction::~SocketsUdpSetBroadcastFunction() { } bool SocketsUdpSetBroadcastFunction::Prepare() { params_ = core_api::sockets_udp::SetBroadcast::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(params_.get()); return true; } void SocketsUdpSetBroadcastFunction::Work() { ResumableUDPSocket* socket = GetUdpSocket(params_->socket_id); if (!socket) { error_ = kSocketNotFoundError; return; } int net_result = socket->SetBroadcast(params_->enabled); if (net_result != net::OK) { error_ = net::ErrorToString(net_result); } results_ = sockets_udp::SetBroadcast::Results::Create(net_result); } } // namespace core_api } // namespace extensions