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
5 #include "cast/streaming/environment.h"
6
7 #include <algorithm>
8 #include <utility>
9
10 #include "cast/streaming/rtp_defines.h"
11 #include "platform/api/task_runner.h"
12 #include "util/osp_logging.h"
13
14 namespace openscreen {
15 namespace cast {
16
Environment(ClockNowFunctionPtr now_function,TaskRunner * task_runner,const IPEndpoint & local_endpoint)17 Environment::Environment(ClockNowFunctionPtr now_function,
18 TaskRunner* task_runner,
19 const IPEndpoint& local_endpoint)
20 : now_function_(now_function), task_runner_(task_runner) {
21 OSP_DCHECK(now_function_);
22 OSP_DCHECK(task_runner_);
23 ErrorOr<std::unique_ptr<UdpSocket>> result =
24 UdpSocket::Create(task_runner_, this, local_endpoint);
25 if (result.is_error()) {
26 OSP_LOG_ERROR << "Unable to create a UDP socket bound to " << local_endpoint
27 << ": " << result.error();
28 return;
29 }
30 const_cast<std::unique_ptr<UdpSocket>&>(socket_) = std::move(result.value());
31 OSP_DCHECK(socket_);
32 socket_->Bind();
33 }
34
35 Environment::~Environment() = default;
36
GetBoundLocalEndpoint() const37 IPEndpoint Environment::GetBoundLocalEndpoint() const {
38 if (socket_) {
39 return socket_->GetLocalEndpoint();
40 }
41 return IPEndpoint{};
42 }
43
SetSocketSubscriber(SocketSubscriber * subscriber)44 void Environment::SetSocketSubscriber(SocketSubscriber* subscriber) {
45 socket_subscriber_ = subscriber;
46 }
47
ConsumeIncomingPackets(PacketConsumer * packet_consumer)48 void Environment::ConsumeIncomingPackets(PacketConsumer* packet_consumer) {
49 OSP_DCHECK(packet_consumer);
50 OSP_DCHECK(!packet_consumer_);
51 packet_consumer_ = packet_consumer;
52 }
53
DropIncomingPackets()54 void Environment::DropIncomingPackets() {
55 packet_consumer_ = nullptr;
56 }
57
GetMaxPacketSize() const58 int Environment::GetMaxPacketSize() const {
59 // Return hard-coded values for UDP over wired Ethernet (which is a smaller
60 // MTU than typical defaults for UDP over 802.11 wireless). Performance would
61 // be more-optimized if the network were probed for the actual value. See
62 // discussion in rtp_defines.h.
63 switch (remote_endpoint_.address.version()) {
64 case IPAddress::Version::kV4:
65 return kMaxRtpPacketSizeForIpv4UdpOnEthernet;
66 case IPAddress::Version::kV6:
67 return kMaxRtpPacketSizeForIpv6UdpOnEthernet;
68 default:
69 OSP_NOTREACHED();
70 }
71 }
72
SendPacket(absl::Span<const uint8_t> packet)73 void Environment::SendPacket(absl::Span<const uint8_t> packet) {
74 OSP_DCHECK(remote_endpoint_.address);
75 OSP_DCHECK_NE(remote_endpoint_.port, 0);
76 if (socket_) {
77 socket_->SendMessage(packet.data(), packet.size(), remote_endpoint_);
78 }
79 }
80
81 Environment::PacketConsumer::~PacketConsumer() = default;
82
OnBound(UdpSocket * socket)83 void Environment::OnBound(UdpSocket* socket) {
84 OSP_DCHECK(socket == socket_.get());
85 state_ = SocketState::kReady;
86
87 if (socket_subscriber_) {
88 socket_subscriber_->OnSocketReady();
89 }
90 }
91
OnError(UdpSocket * socket,Error error)92 void Environment::OnError(UdpSocket* socket, Error error) {
93 OSP_DCHECK(socket == socket_.get());
94 // Usually OnError() is only called for non-recoverable Errors. However,
95 // OnSendError() and OnRead() delegate to this method, to handle their hard
96 // error cases as well. So, return early here if |error| is recoverable.
97 if (error.ok() || error.code() == Error::Code::kAgain) {
98 return;
99 }
100
101 state_ = SocketState::kInvalid;
102 if (socket_subscriber_) {
103 socket_subscriber_->OnSocketInvalid(error);
104 } else {
105 // Default behavior when there are no subscribers.
106 OSP_LOG_ERROR << "For UDP socket bound to " << socket_->GetLocalEndpoint()
107 << ": " << error;
108 }
109 }
110
OnSendError(UdpSocket * socket,Error error)111 void Environment::OnSendError(UdpSocket* socket, Error error) {
112 OnError(socket, error);
113 }
114
OnRead(UdpSocket * socket,ErrorOr<UdpPacket> packet_or_error)115 void Environment::OnRead(UdpSocket* socket,
116 ErrorOr<UdpPacket> packet_or_error) {
117 if (!packet_consumer_) {
118 return;
119 }
120
121 if (packet_or_error.is_error()) {
122 OnError(socket, packet_or_error.error());
123 return;
124 }
125
126 // Ideally, the arrival time would come from the operating system's network
127 // stack (e.g., by using the SO_TIMESTAMP sockopt on POSIX systems). However,
128 // there would still be the problem of mapping the timestamp to a value in
129 // terms of Clock::time_point. So, just sample the Clock here and call that
130 // the "arrival time." While this can add variance within the system, it
131 // should be minimal, assuming not too much time has elapsed between the
132 // actual packet receive event and the when this code here is executing.
133 const Clock::time_point arrival_time = now_function_();
134
135 UdpPacket packet = std::move(packet_or_error.value());
136 packet_consumer_->OnReceivedPacket(
137 packet.source(), arrival_time,
138 std::move(static_cast<std::vector<uint8_t>&>(packet)));
139 }
140
141 } // namespace cast
142 } // namespace openscreen
143