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 #ifndef CAST_STREAMING_ENVIRONMENT_H_
6 #define CAST_STREAMING_ENVIRONMENT_H_
7 
8 #include <stdint.h>
9 
10 #include <functional>
11 #include <memory>
12 #include <vector>
13 
14 #include "absl/types/span.h"
15 #include "platform/api/time.h"
16 #include "platform/api/udp_socket.h"
17 #include "platform/base/ip_address.h"
18 
19 namespace openscreen {
20 namespace cast {
21 
22 // Provides the common environment for operating system resources shared by
23 // multiple components.
24 class Environment : public UdpSocket::Client {
25  public:
26   class PacketConsumer {
27    public:
28     virtual void OnReceivedPacket(const IPEndpoint& source,
29                                   Clock::time_point arrival_time,
30                                   std::vector<uint8_t> packet) = 0;
31 
32    protected:
33     virtual ~PacketConsumer();
34   };
35 
36   // Consumers of the environment's UDP socket should be careful to check the
37   // socket's state before accessing its methods, especially
38   // GetBoundLocalEndpoint(). If the environment is |kStarting|, the
39   // local endpoint may not be set yet and will be zero initialized.
40   enum class SocketState {
41     // Socket is still initializing. Usually the UDP socket bind is
42     // the last piece.
43     kStarting,
44 
45     // The socket is ready for use and has been bound.
46     kReady,
47 
48     // The socket is either closed (normally or due to an error) or in an
49     // invalid state. Currently the environment does not create a new socket
50     // in this case, so to be used again the environment itself needs to be
51     // recreated.
52     kInvalid
53   };
54 
55   // Classes concerned with the Environment's UDP socket state may inherit from
56   // |Subscriber| and then |Subscribe|.
57   class SocketSubscriber {
58    public:
59     // Event that occurs when the environment is ready for use.
60     virtual void OnSocketReady() = 0;
61 
62     // Event that occurs when the environment has experienced a fatal error.
63     virtual void OnSocketInvalid(Error error) = 0;
64   };
65 
66   // Construct with the given clock source and TaskRunner. Creates and
67   // internally-owns a UdpSocket, and immediately binds it to the given
68   // |local_endpoint|. If embedders do not care what interface/address the UDP
69   // socket is bound on, they may omit that argument.
70   Environment(ClockNowFunctionPtr now_function,
71               TaskRunner* task_runner,
72               const IPEndpoint& local_endpoint = IPEndpoint::kAnyV6());
73 
74   ~Environment() override;
75 
now_function()76   ClockNowFunctionPtr now_function() const { return now_function_; }
now()77   Clock::time_point now() const { return now_function_(); }
task_runner()78   TaskRunner* task_runner() const { return task_runner_; }
79 
80   // Returns the local endpoint the socket is bound to, or the zero IPEndpoint
81   // if socket creation/binding failed.
82   //
83   // Note: This method is virtual to allow unit tests to fake that there really
84   // is a bound socket.
85   virtual IPEndpoint GetBoundLocalEndpoint() const;
86 
87   // Get/Set the remote endpoint. This is separate from the constructor because
88   // the remote endpoint is, in some cases, discovered only after receiving a
89   // packet.
remote_endpoint()90   const IPEndpoint& remote_endpoint() const { return remote_endpoint_; }
set_remote_endpoint(const IPEndpoint & endpoint)91   void set_remote_endpoint(const IPEndpoint& endpoint) {
92     remote_endpoint_ = endpoint;
93   }
94 
95   // Returns the current state of the UDP socket. This method is virtual
96   // to allow tests to simulate socket state.
socket_state()97   SocketState socket_state() const { return state_; }
set_socket_state_for_testing(SocketState state)98   void set_socket_state_for_testing(SocketState state) { state_ = state; }
99 
100   // Subscribe to socket changes. Callers can unsubscribe by passing
101   // nullptr.
102   void SetSocketSubscriber(SocketSubscriber* subscriber);
103 
104   // Start/Resume delivery of incoming packets to the given |packet_consumer|.
105   // Delivery will continue until DropIncomingPackets() is called.
106   void ConsumeIncomingPackets(PacketConsumer* packet_consumer);
107 
108   // Stop delivery of incoming packets, dropping any that do come in. All
109   // internal references to the PacketConsumer that was provided in the last
110   // call to ConsumeIncomingPackets() are cleared.
111   void DropIncomingPackets();
112 
113   // Returns the maximum packet size for the network. This will always return a
114   // value of at least kRequiredNetworkPacketSize.
115   int GetMaxPacketSize() const;
116 
117   // Sends the given |packet| to the remote endpoint, best-effort.
118   // set_remote_endpoint() must be called beforehand with a valid IPEndpoint.
119   //
120   // Note: This method is virtual to allow unit tests to intercept packets
121   // before they actually head-out through the socket.
122   virtual void SendPacket(absl::Span<const uint8_t> packet);
123 
124  protected:
Environment()125   Environment() : now_function_(nullptr), task_runner_(nullptr) {}
126 
127   // Protected so that they can be set by the MockEnvironment for testing.
128   ClockNowFunctionPtr now_function_;
129   TaskRunner* task_runner_;
130 
131  private:
132   // UdpSocket::Client implementation.
133   void OnBound(UdpSocket* socket) final;
134   void OnError(UdpSocket* socket, Error error) final;
135   void OnSendError(UdpSocket* socket, Error error) final;
136   void OnRead(UdpSocket* socket, ErrorOr<UdpPacket> packet_or_error) final;
137 
138   // The UDP socket bound to the local endpoint that was passed into the
139   // constructor, or null if socket creation failed.
140   const std::unique_ptr<UdpSocket> socket_;
141 
142   // These are externally set/cleared. Behaviors are described in getter/setter
143   // method comments above.
144   IPEndpoint local_endpoint_{};
145   IPEndpoint remote_endpoint_{};
146   PacketConsumer* packet_consumer_ = nullptr;
147   SocketState state_ = SocketState::kStarting;
148   SocketSubscriber* socket_subscriber_ = nullptr;
149 };
150 
151 }  // namespace cast
152 }  // namespace openscreen
153 
154 #endif  // CAST_STREAMING_ENVIRONMENT_H_
155