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