udp_socket.cc 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/openscreen_platform/udp_socket.h"
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/containers/span.h"
  8. #include "components/openscreen_platform/network_context.h"
  9. #include "components/openscreen_platform/network_util.h"
  10. #include "mojo/public/cpp/bindings/pending_remote.h"
  11. #include "net/base/address_family.h"
  12. #include "net/base/ip_endpoint.h"
  13. #include "net/base/net_errors.h"
  14. #include "services/network/public/mojom/network_context.mojom.h"
  15. #include "third_party/openscreen/src/platform/base/udp_packet.h"
  16. // Open Screen expects us to provide linked implementations of some of its
  17. // static create methods, which have to be in their namespace.
  18. namespace openscreen {
  19. // static
  20. ErrorOr<std::unique_ptr<UdpSocket>> UdpSocket::Create(
  21. TaskRunner* task_runner,
  22. Client* client,
  23. const IPEndpoint& local_endpoint) {
  24. network::mojom::NetworkContext* const network_context =
  25. openscreen_platform::GetNetworkContext();
  26. if (!network_context) {
  27. return Error::Code::kInitializationFailure;
  28. }
  29. mojo::PendingRemote<network::mojom::UDPSocketListener> listener_remote;
  30. mojo::PendingReceiver<network::mojom::UDPSocketListener> pending_listener =
  31. listener_remote.InitWithNewPipeAndPassReceiver();
  32. mojo::Remote<network::mojom::UDPSocket> socket;
  33. network_context->CreateUDPSocket(socket.BindNewPipeAndPassReceiver(),
  34. std::move(listener_remote));
  35. return ErrorOr<std::unique_ptr<UdpSocket>>(
  36. std::make_unique<openscreen_platform::UdpSocket>(
  37. client, local_endpoint, std::move(socket),
  38. std::move(pending_listener)));
  39. }
  40. } // namespace openscreen
  41. namespace openscreen_platform {
  42. namespace {
  43. using openscreen::Error;
  44. using openscreen::IPAddress;
  45. using openscreen::IPEndpoint;
  46. using openscreen::UdpPacket;
  47. constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
  48. net::DefineNetworkTrafficAnnotation("openscreen_message", R"(
  49. semantics {
  50. sender: "Open Screen"
  51. description:
  52. "Open Screen messages are used by the third_party Open Screen "
  53. "library, in accordance to the specification defined by the Open "
  54. "Screen protocol. The protocol is available publicly at: "
  55. "https://github.com/webscreens/openscreenprotocol"
  56. trigger:
  57. "Any message that needs to be sent or received by the Open Screen "
  58. "library."
  59. data:
  60. "Messages defined by the Open Screen Protocol specification."
  61. destination: OTHER
  62. destination_other:
  63. "The connection is made to an Open Screen endpoint on the LAN "
  64. "selected by the user, i.e. via a dialog."
  65. }
  66. policy {
  67. cookies_allowed: NO
  68. setting:
  69. "This request cannot be disabled, but it would not be sent if user "
  70. "does not connect to a Open Screen endpoint on the local network."
  71. policy_exception_justification: "Not implemented."
  72. })");
  73. } // namespace
  74. UdpSocket::UdpSocket(
  75. Client* client,
  76. const IPEndpoint& local_endpoint,
  77. mojo::Remote<network::mojom::UDPSocket> udp_socket,
  78. mojo::PendingReceiver<network::mojom::UDPSocketListener> pending_listener)
  79. : client_(client),
  80. local_endpoint_(local_endpoint),
  81. udp_socket_(std::move(udp_socket)),
  82. pending_listener_(std::move(pending_listener)) {
  83. DCHECK(client_);
  84. }
  85. UdpSocket::~UdpSocket() = default;
  86. bool UdpSocket::IsIPv4() const {
  87. return local_endpoint_.address.IsV4();
  88. }
  89. bool UdpSocket::IsIPv6() const {
  90. return local_endpoint_.address.IsV6();
  91. }
  92. IPEndpoint UdpSocket::GetLocalEndpoint() const {
  93. return local_endpoint_;
  94. }
  95. void UdpSocket::Bind() {
  96. udp_socket_->Bind(
  97. openscreen_platform::ToNetEndPoint(local_endpoint_),
  98. nullptr /* socket_options */,
  99. base::BindOnce(&UdpSocket::BindCallback, weak_ptr_factory_.GetWeakPtr()));
  100. }
  101. // mojom::UDPSocket doesn't have a concept of network interface indices, so
  102. // this is a noop.
  103. void UdpSocket::SetMulticastOutboundInterface(
  104. openscreen::NetworkInterfaceIndex ifindex) {}
  105. // mojom::UDPSocket doesn't have a concept of network interface indices, so
  106. // the ifindex argument is ignored here.
  107. void UdpSocket::JoinMulticastGroup(const IPAddress& address,
  108. openscreen::NetworkInterfaceIndex ifindex) {
  109. const auto join_address = openscreen_platform::ToNetAddress(address);
  110. udp_socket_->JoinGroup(join_address,
  111. base::BindOnce(&UdpSocket::JoinGroupCallback,
  112. weak_ptr_factory_.GetWeakPtr()));
  113. }
  114. void UdpSocket::SendMessage(const void* data,
  115. size_t length,
  116. const IPEndpoint& dest) {
  117. const auto send_to_address = openscreen_platform::ToNetEndPoint(dest);
  118. base::span<const uint8_t> data_span(static_cast<const uint8_t*>(data),
  119. length);
  120. udp_socket_->SendTo(
  121. send_to_address, data_span,
  122. net::MutableNetworkTrafficAnnotationTag(kTrafficAnnotation),
  123. base::BindOnce(&UdpSocket::SendCallback, weak_ptr_factory_.GetWeakPtr()));
  124. }
  125. // mojom::UDPSocket doesn't have a concept of DSCP, so this is a noop.
  126. void UdpSocket::SetDscp(openscreen::UdpSocket::DscpMode state) {}
  127. void UdpSocket::OnReceived(
  128. int32_t net_result,
  129. const absl::optional<net::IPEndPoint>& source_endpoint,
  130. absl::optional<base::span<const uint8_t>> data) {
  131. if (net_result != net::OK) {
  132. client_->OnRead(this, Error::Code::kSocketReadFailure);
  133. } else if (data) {
  134. UdpPacket packet(data->begin(), data->end());
  135. packet.set_socket(this);
  136. if (source_endpoint) {
  137. packet.set_source(
  138. openscreen_platform::ToOpenScreenEndPoint(source_endpoint.value()));
  139. }
  140. client_->OnRead(this, std::move(packet));
  141. }
  142. udp_socket_->ReceiveMore(1);
  143. }
  144. void UdpSocket::BindCallback(int32_t result,
  145. const absl::optional<net::IPEndPoint>& address) {
  146. if (result != net::OK) {
  147. client_->OnError(this, Error(Error::Code::kSocketBindFailure,
  148. net::ErrorToString(result)));
  149. return;
  150. }
  151. // This is an approximate value for number of packets, and may need to be
  152. // adjusted when we have real world data.
  153. constexpr int kNumPacketsReadyFor = 30;
  154. udp_socket_->ReceiveMore(kNumPacketsReadyFor);
  155. if (address) {
  156. local_endpoint_ =
  157. openscreen_platform::ToOpenScreenEndPoint(address.value());
  158. if (pending_listener_.is_valid()) {
  159. listener_.Bind(std::move(pending_listener_));
  160. }
  161. }
  162. client_->OnBound(this);
  163. }
  164. void UdpSocket::JoinGroupCallback(int32_t result) {
  165. if (result != net::OK) {
  166. client_->OnError(this, Error(Error::Code::kSocketOptionSettingFailure,
  167. net::ErrorToString(result)));
  168. }
  169. }
  170. void UdpSocket::SendCallback(int32_t result) {
  171. if (result != net::OK) {
  172. client_->OnSendError(this, Error(Error::Code::kSocketSendFailure,
  173. net::ErrorToString(result)));
  174. }
  175. }
  176. } // namespace openscreen_platform