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