Commit 0a4ad0d3 authored by Fabrice de Gans-Riberi's avatar Fabrice de Gans-Riberi Committed by Chromium LUCI CQ

Add a //net-based implementation of Open Screen UdpSocket

This adds a //net-based implementation of the Open Screen UdpSocket
interface. Its main use is for unit tests that do not have or require
the network service.

Bug: 1110490
Change-Id: Ic542c3c29d05b5c58d36efb6fd31d0eeac3cefe5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2580908Reviewed-by: default avatarmark a. foltz <mfoltz@chromium.org>
Reviewed-by: default avatarJordan Bayles <jophba@chromium.org>
Commit-Queue: Fabrice de Gans-Riberi <fdegans@chromium.org>
Cr-Commit-Position: refs/heads/master@{#836822}
parent 8c62329f
......@@ -23,6 +23,25 @@ source_set("openscreen_platform") {
]
}
# //net-based implementation of UdpSocket.
# Incompatible with ":openscreen_platform_network_service".
source_set("openscreen_platform_net") {
testonly = true
sources = [
"net_udp_socket.cc",
"net_udp_socket.h",
]
public_deps = [ ":openscreen_platform" ]
deps = [
"//base",
"//net",
]
}
# Network service-based implementation of Open Screen platform.
# Incompatible with ":openscreen_platform_net".
source_set("openscreen_platform_network_service") {
sources = [
"network_context.cc",
......
// Copyright 2020 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 "components/openscreen_platform/net_udp_socket.h"
#include <algorithm>
#include <utility>
#include "base/bind.h"
#include "components/openscreen_platform/network_util.h"
#include "net/base/net_errors.h"
namespace openscreen {
// static
ErrorOr<std::unique_ptr<UdpSocket>> UdpSocket::Create(
TaskRunner* task_runner,
Client* client,
const IPEndpoint& local_endpoint) {
return ErrorOr<std::unique_ptr<UdpSocket>>(
std::make_unique<openscreen_platform::NetUdpSocket>(client,
local_endpoint));
}
} // namespace openscreen
namespace openscreen_platform {
NetUdpSocket::NetUdpSocket(openscreen::UdpSocket::Client* client,
const openscreen::IPEndpoint& local_endpoint)
: client_(client),
local_endpoint_(local_endpoint),
udp_socket_(net::DatagramSocket::DEFAULT_BIND,
nullptr /* net_log */,
net::NetLogSource()),
read_buffer_(base::MakeRefCounted<net::IOBuffer>(
openscreen::UdpPacket::kUdpMaxPacketSize)) {
DVLOG(1) << __func__;
DCHECK(client_);
}
NetUdpSocket::~NetUdpSocket() = default;
void NetUdpSocket::SendErrorToClient(openscreen::Error::Code openscreen_error,
int net_error) {
DVLOG(1) << __func__;
client_->OnError(
this, openscreen::Error(openscreen_error, net::ErrorToString(net_error)));
}
void NetUdpSocket::DoRead() {
DVLOG(3) << __func__;
while (HandleRecvFromResult(udp_socket_.RecvFrom(
read_buffer_.get(), openscreen::UdpPacket::kUdpMaxPacketSize,
&from_address_,
base::BindOnce(&NetUdpSocket::OnRecvFromCompleted,
base::Unretained(this))))) {
}
}
bool NetUdpSocket::HandleRecvFromResult(int result) {
DVLOG(3) << __func__;
if (result == net::ERR_IO_PENDING) {
return false;
}
if (result < 0) {
client_->OnRead(
this, openscreen::Error(openscreen::Error::Code::kSocketReadFailure,
net::ErrorToString(result)));
return false;
}
DCHECK_GT(result, 0);
openscreen::UdpPacket packet(read_buffer_->data(),
read_buffer_->data() + result);
packet.set_socket(this);
packet.set_source(openscreen_platform::ToOpenScreenEndPoint(from_address_));
client_->OnRead(this, std::move(packet));
return true;
}
void NetUdpSocket::OnRecvFromCompleted(int result) {
DVLOG(3) << __func__;
if (HandleRecvFromResult(result)) {
DoRead();
}
}
void NetUdpSocket::OnSendToCompleted(int result) {
DVLOG(3) << __func__;
send_pending_ = false;
if (result < 0) {
client_->OnSendError(
this, openscreen::Error(openscreen::Error::Code::kSocketSendFailure,
net::ErrorToString(result)));
}
}
bool NetUdpSocket::IsIPv4() const {
DVLOG(2) << __func__;
return local_endpoint_.address.IsV4();
}
bool NetUdpSocket::IsIPv6() const {
DVLOG(2) << __func__;
return local_endpoint_.address.IsV6();
}
openscreen::IPEndpoint NetUdpSocket::GetLocalEndpoint() const {
DVLOG(2) << __func__;
return local_endpoint_;
}
void NetUdpSocket::Bind() {
DVLOG(1) << __func__;
net::IPEndPoint endpoint =
openscreen_platform::ToNetEndPoint(local_endpoint_);
int result = udp_socket_.Open(endpoint.GetFamily());
if (result != net::OK) {
SendErrorToClient(openscreen::Error::Code::kSocketBindFailure, result);
return;
}
result = udp_socket_.Bind(endpoint);
net::IPEndPoint local_endpoint;
if (result == net::OK) {
result = udp_socket_.GetLocalAddress(&local_endpoint);
}
if (result != net::OK) {
SendErrorToClient(openscreen::Error::Code::kSocketBindFailure, result);
return;
}
local_endpoint_ = openscreen_platform::ToOpenScreenEndPoint(local_endpoint);
DoRead();
}
void NetUdpSocket::SetMulticastOutboundInterface(
openscreen::NetworkInterfaceIndex ifindex) {
DVLOG(1) << __func__;
const int result = udp_socket_.SetMulticastInterface(ifindex);
if (result != net::OK) {
SendErrorToClient(openscreen::Error::Code::kSocketOptionSettingFailure,
result);
}
}
void NetUdpSocket::JoinMulticastGroup(
const openscreen::IPAddress& address,
openscreen::NetworkInterfaceIndex ifindex) {
DVLOG(1) << __func__;
const int result = udp_socket_.SetMulticastInterface(ifindex);
if (result == net::OK) {
udp_socket_.JoinGroup(openscreen_platform::ToNetAddress(address));
} else {
SendErrorToClient(openscreen::Error::Code::kSocketOptionSettingFailure,
result);
}
}
void NetUdpSocket::SendMessage(const void* data,
size_t length,
const openscreen::IPEndpoint& dest) {
DVLOG(3) << __func__;
if (send_pending_) {
client_->OnSendError(this,
openscreen::Error(openscreen::Error::Code::kAgain));
return;
}
auto buffer = base::MakeRefCounted<net::IOBuffer>(length);
memcpy(buffer->data(), data, length);
const int result = udp_socket_.SendTo(
buffer.get(), length, openscreen_platform::ToNetEndPoint(dest),
base::BindOnce(&NetUdpSocket::OnSendToCompleted, base::Unretained(this)));
send_pending_ = true;
if (result != net::ERR_IO_PENDING) {
OnSendToCompleted(result);
}
}
void NetUdpSocket::SetDscp(openscreen::UdpSocket::DscpMode state) {
NOTIMPLEMENTED_LOG_ONCE();
}
} // namespace openscreen_platform
\ No newline at end of file
// Copyright 2020 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.
#ifndef COMPONENTS_OPENSCREEN_PLATFORM_NET_UDP_SOCKET_H_
#define COMPONENTS_OPENSCREEN_PLATFORM_NET_UDP_SOCKET_H_
#include <memory>
#include "net/base/io_buffer.h"
#include "net/base/ip_endpoint.h"
#include "net/socket/udp_socket.h"
#include "third_party/openscreen/src/platform/api/udp_socket.h"
namespace net {
class IPEndPoint;
}
namespace openscreen_platform {
class NetUdpSocket : public openscreen::UdpSocket {
public:
NetUdpSocket(Client* client, const openscreen::IPEndpoint& local_endpoint);
~NetUdpSocket() final;
NetUdpSocket& operator=(const NetUdpSocket&) = delete;
NetUdpSocket& operator=(NetUdpSocket&&) = delete;
private:
void SendErrorToClient(openscreen::Error::Code openscreen_error,
int net_error);
void DoRead();
bool HandleRecvFromResult(int result);
void OnRecvFromCompleted(int result);
void OnSendToCompleted(int result);
// openscreen::UdpSocket implementation.
bool IsIPv4() const final;
bool IsIPv6() const final;
openscreen::IPEndpoint GetLocalEndpoint() const final;
void Bind() final;
void SetMulticastOutboundInterface(
openscreen::NetworkInterfaceIndex ifindex) final;
void JoinMulticastGroup(const openscreen::IPAddress& address,
openscreen::NetworkInterfaceIndex ifindex) final;
void SendMessage(const void* data,
size_t length,
const openscreen::IPEndpoint& dest) final;
void SetDscp(openscreen::UdpSocket::DscpMode state) final;
Client* const client_;
// The local endpoint can change as a result of Bind() calls.
openscreen::IPEndpoint local_endpoint_;
net::UDPSocket udp_socket_;
scoped_refptr<net::IOBuffer> read_buffer_;
net::IPEndPoint from_address_;
bool send_pending_ = false;
};
} // namespace openscreen_platform
#endif // COMPONENTS_OPENSCREEN_PLATFORM_NET_UDP_SOCKET_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment