Implement Cast Streaming mirroring, DLNA casting, daemon+GUI, and breadd integration
Some checks failed
dev release / build (push) Failing after 12s

Builds out the full v1 scope: a vendored+patched openscreen subset for
low-latency Cast Streaming (Mirroring receiver 0F5096E8) alongside the
existing Cast V2/HLS and new DLNA/AVTransport casting paths, breadcastd's
Idle/Casting state machine with a private IPC socket, the breadcast GTK4
popup as a thin IPC client, and bread.cast.*/bread.command.cast.* breadd
integration (device discovery, start/stop, mirroring lifecycle events).
Also adds bakery/systemd/Forgejo CI packaging.

Validated end-to-end against a real Chromecast/Google TV: negotiated
Cast Streaming session, live pipeline playback, and daemon+GUI click-to-cast/
stop through the actual popup.
This commit is contained in:
Breadway 2026-08-03 09:07:21 +08:00
parent 887c29002f
commit 8c745d18e0
283 changed files with 36788 additions and 0 deletions

View file

@ -0,0 +1,54 @@
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PLATFORM_API_CONNECTION_H_
#define PLATFORM_API_CONNECTION_H_
#include <cstdint>
#include <vector>
#include "platform/base/error.h"
#include "platform/base/ip_address.h"
#include "platform/base/span.h"
namespace openscreen {
// Represents a connection between two endpoints. This class provides an
// interface for sending and receiving byte data over a connection.
class Connection {
public:
// Client callbacks are run via the TaskRunner used by TlsConnectionFactory.
class Client {
public:
// Called when `connection` experiences an error, such as a read error.
virtual void OnError(Connection* connection, const Error& error) = 0;
// Called when a `block` arrives on `connection`.
virtual void OnRead(Connection* connection, std::vector<uint8_t> block) = 0;
protected:
virtual ~Client() = default;
};
virtual ~Connection() = default;
// Sets the Client associated with this instance. This should be called as
// soon as the factory provides a new Connection instance via
// TlsConnectionFactory::OnAccepted(), OnConnected() or CreateSocket().
// Pass nullptr to unset the Client.
virtual void SetClient(Client* client) = 0;
// Sends a message. Returns true iff the message will be sent.
[[nodiscard]] virtual bool Send(ByteView data) = 0;
// Get the connected remote address.
virtual IPEndpoint GetRemoteEndpoint() const = 0;
protected:
Connection() = default;
};
} // namespace openscreen
#endif // PLATFORM_API_CONNECTION_H_

View file

@ -0,0 +1,26 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PLATFORM_API_EXPORT_H_
#define PLATFORM_API_EXPORT_H_
#if defined(WIN32)
#if defined(OPENSCREEN_SHARED_IMPLEMENTATION)
#define OPENSCREEN_EXPORT __declspec(dllexport)
#else
#define OPENSCREEN_EXPORT __declspec(dllimport)
#endif // defined(OPENSCREEN_SHARED_IMPLEMENTATION)
#else
#if defined(OPENSCREEN_SHARED_IMPLEMENTATION)
#define OPENSCREEN_EXPORT __attribute__((visibility("default")))
#else
#define OPENSCREEN_EXPORT
#endif // defined(OPENSCREEN_SHARED_IMPLEMENTATION)
#endif // defined(WIN32)
#endif // PLATFORM_API_EXPORT_H_

View file

@ -0,0 +1,62 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PLATFORM_API_LOGGING_H_
#define PLATFORM_API_LOGGING_H_
#include <sstream>
namespace openscreen {
enum class LogLevel {
// Very detailed information, often used for evaluating performance or
// debugging production issues in-the-wild.
kVerbose = 0,
// Used occasionally to note events of interest, but not for indicating any
// problems. This is also used for general console messaging in Open Screen's
// standalone executables.
kInfo = 1,
// Indicates a problem that may or may not lead to an operational failure.
kWarning = 2,
// Indicates an operational failure that may or may not cause a component to
// stop working.
kError = 3,
// Indicates a logic flaw, corruption, impossible/unanticipated situation, or
// operational failure so serious that Open Screen will soon call Break() to
// abort the current process. Examples: security/privacy risks, memory
// management issues, API contract violations.
kFatal = 4,
};
// Returns true if `level` is at or above the level where the embedder will
// record/emit log entries from the code in `file`.
bool IsLoggingOn(LogLevel level, const std::string_view file);
// Record a log entry, consisting of its logging level, location and message.
// The embedder may filter-out entries according to its own policy, but this
// function will not be called if IsLoggingOn(level, file) returns false.
// Whenever `level` is kFatal, Open Screen will call Break() immediately after
// this returns.
//
// `message` is passed as a string stream to avoid unnecessary string copies.
// Embedders can call its rdbuf() or str() methods to access the log message.
void LogWithLevel(LogLevel level,
const char* file,
int line,
std::stringstream message);
// Breaks into the debugger, if one is present. Otherwise, aborts the current
// process (i.e., this function should not return). In production builds, an
// embedder could invoke its infrastructure for performing "dumps," consisting
// of thread stack traces and other relevant process state information, before
// aborting the process.
[[noreturn]] void Break();
} // namespace openscreen
#endif // PLATFORM_API_LOGGING_H_

View file

@ -0,0 +1,24 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PLATFORM_API_NETWORK_INTERFACE_H_
#define PLATFORM_API_NETWORK_INTERFACE_H_
#include <vector>
#include "platform/base/interface_info.h"
namespace openscreen {
// Returns an InterfaceInfo for each currently active network interface on the
// system. No two entries in this vector can have the same NetworkInterfaceIndex
// value.
//
// This can return an empty vector if there are no active network interfaces or
// an error occurred querying the system for them.
std::vector<InterfaceInfo> GetNetworkInterfaces();
} // namespace openscreen
#endif // PLATFORM_API_NETWORK_INTERFACE_H_

View file

@ -0,0 +1,64 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PLATFORM_API_TASK_RUNNER_H_
#define PLATFORM_API_TASK_RUNNER_H_
#include <future>
#include <utility>
#include "platform/api/time.h"
namespace openscreen {
// A thread-safe API surface that allows for posting tasks. The underlying
// implementation may be single or multi-threaded, and all complication should
// be handled by the implementation class. The implementation must guarantee:
// (1) Tasks shall not overlap in time/CPU.
// (2) Tasks shall run sequentially, e.g. posting task A then B implies
// that A shall run before B.
// (3) If task A is posted before task B, then any mutation in A happens-before
// B runs (even if A and B run on different threads).
class TaskRunner {
public:
using Task = std::packaged_task<void()>;
virtual ~TaskRunner() = default;
// Takes any callable target (function, lambda-expression, std::bind result,
// etc.) that should be run at the first convenient time.
template <typename Functor>
inline void PostTask(Functor f) {
PostPackagedTask(Task(std::move(f)));
}
// Takes any callable target (function, lambda-expression, std::bind result,
// etc.) that should be run no sooner than `delay` time from now. Note that
// the Task might run after an additional delay, especially under heavier
// system load. There is no deadline concept.
template <typename Functor>
inline void PostTaskWithDelay(Functor f, Clock::duration delay) {
PostPackagedTaskWithDelay(Task(std::move(f)), delay);
}
// Implementations should provide the behavior explained in the comments above
// for PostTask[WithDelay](). Client code may also call these directly when
// passing an existing Task object.
virtual void PostPackagedTask(Task task) = 0;
virtual void PostPackagedTaskWithDelay(Task task, Clock::duration delay) = 0;
// Return true if the calling thread is the thread that task runner is using
// to run tasks, false otherwise.
virtual bool IsRunningOnTaskRunner() = 0;
// Posts a task to delete `object`.
template <class T>
void DeleteSoon(const T* object) {
PostTask([object] { delete static_cast<const T*>(object); });
}
};
} // namespace openscreen
#endif // PLATFORM_API_TASK_RUNNER_H_

View file

@ -0,0 +1,23 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "platform/api/task_runner_deleter.h"
namespace openscreen {
TaskRunnerDeleter::TaskRunnerDeleter() = default;
TaskRunnerDeleter::TaskRunnerDeleter(TaskRunner& task_runner)
: task_runner_(&task_runner) {}
TaskRunnerDeleter::~TaskRunnerDeleter() = default;
TaskRunnerDeleter::TaskRunnerDeleter(const TaskRunnerDeleter&) = default;
TaskRunnerDeleter& TaskRunnerDeleter::operator=(const TaskRunnerDeleter&) =
default;
TaskRunnerDeleter::TaskRunnerDeleter(TaskRunnerDeleter&&) noexcept = default;
TaskRunnerDeleter& TaskRunnerDeleter::operator=(TaskRunnerDeleter&&) noexcept =
default;
} // namespace openscreen

View file

@ -0,0 +1,64 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PLATFORM_API_TASK_RUNNER_DELETER_H_
#define PLATFORM_API_TASK_RUNNER_DELETER_H_
#include <memory>
#include <utility>
#include "platform/api/task_runner.h"
namespace openscreen {
// Helper that deletes an object on the provided TaskRunner.
//
// Usage with std::unique_ptr:
//
// std::unique_ptr<Foo, TaskRunnerDeleter> some_foo;
// ...
// some_foo = TaskRunnerDeleter::MakeUnique(
// task_runner, foo_arg1, foo_arg2, ...);
struct TaskRunnerDeleter {
TaskRunnerDeleter();
explicit TaskRunnerDeleter(TaskRunner& task_runner);
~TaskRunnerDeleter();
TaskRunnerDeleter(const TaskRunnerDeleter&);
TaskRunnerDeleter& operator=(const TaskRunnerDeleter&);
TaskRunnerDeleter(TaskRunnerDeleter&&) noexcept;
TaskRunnerDeleter& operator=(TaskRunnerDeleter&&) noexcept;
// For compatibility with std:: deleters.
template <typename T>
void operator()(const T* ptr) {
if (task_runner_ && ptr)
task_runner_->DeleteSoon(ptr);
}
template <typename Type, typename Deleter = TaskRunnerDeleter>
static std::unique_ptr<Type, Deleter> WrapUnique(TaskRunner& task_runner,
Type* t) {
return std::unique_ptr<Type, Deleter>(t, TaskRunnerDeleter(task_runner));
}
template <typename Type,
typename Deleter = TaskRunnerDeleter,
typename... Args>
static std::unique_ptr<Type, Deleter> MakeUnique(TaskRunner& task_runner,
Args&&... args) {
return std::unique_ptr<Type, Deleter>(
new Type(std::forward<Args>(args)...),
TaskRunnerDeleter(task_runner)); // NOLINT
}
#if defined(__clang__)
[[clang::annotate("raw_ptr_exclusion")]]
#endif
TaskRunner* task_runner_ = nullptr;
};
} // namespace openscreen
#endif // PLATFORM_API_TASK_RUNNER_DELETER_H_

View file

@ -0,0 +1,37 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PLATFORM_API_TIME_H_
#define PLATFORM_API_TIME_H_
#include <chrono>
#include "platform/base/trivial_clock_traits.h"
namespace openscreen {
// The "reasonably high-resolution" source of monotonic time from the embedder,
// exhibiting the traits described in TrivialClockTraits. This class is not
// instantiated. It only contains a static now() function.
//
// For example, the default platform implementation bases this on
// std::chrono::steady_clock or std::chrono::high_resolution_clock, but an
// embedder may choose to use a different source of time (e.g., the embedder's
// time library, a simulated time source, or a mock).
class Clock : public TrivialClockTraits {
public:
// Returns the current time.
static time_point now() noexcept;
};
// Returns the number of seconds since UNIX epoch (1 Jan 1970, midnight)
// according to the wall clock, which is subject to adjustments (e.g., via NTP).
// Note that this is NOT necessarily the same time source as Clock::now() above,
// and is NOT guaranteed to be monotonically non-decreasing; it is "calendar
// time."
std::chrono::seconds GetWallTimeSinceUnixEpoch() noexcept;
} // namespace openscreen
#endif // PLATFORM_API_TIME_H_

View file

@ -0,0 +1,12 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "platform/api/tls_connection.h"
namespace openscreen {
TlsConnection::TlsConnection() = default;
} // namespace openscreen

View file

@ -0,0 +1,29 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PLATFORM_API_TLS_CONNECTION_H_
#define PLATFORM_API_TLS_CONNECTION_H_
#include <cstdint>
#include <vector>
#include "platform/api/connection.h"
#include "platform/base/error.h"
#include "platform/base/ip_address.h"
#include "platform/base/span.h"
namespace openscreen {
class TlsConnection : public Connection {
public:
// Get the connected remote address.
virtual IPEndpoint GetRemoteEndpoint() const = 0;
protected:
TlsConnection();
};
} // namespace openscreen
#endif // PLATFORM_API_TLS_CONNECTION_H_

View file

@ -0,0 +1,14 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "platform/api/tls_connection_factory.h"
namespace openscreen {
TlsConnectionFactory::TlsConnectionFactory() = default;
TlsConnectionFactory::~TlsConnectionFactory() = default;
TlsConnectionFactory::Client::~Client() = default;
} // namespace openscreen

View file

@ -0,0 +1,82 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PLATFORM_API_TLS_CONNECTION_FACTORY_H_
#define PLATFORM_API_TLS_CONNECTION_FACTORY_H_
#include <stdint.h>
#include <memory>
#include <vector>
#include "platform/base/ip_address.h"
namespace openscreen {
class TaskRunner;
class TlsConnection;
struct TlsConnectOptions;
struct TlsCredentials;
struct TlsListenOptions;
// We expect a single factory to be able to handle an arbitrary number of
// calls using the same client and task runner.
class TlsConnectionFactory {
public:
// Client callbacks are ran on the provided TaskRunner.
class Client {
public:
// Provides a new `connection` that resulted from listening on the local
// socket. `der_x509_peer_cert` is the DER-encoded X509 certificate from the
// peer if present, or empty if the peer didn't provide one.
virtual void OnAccepted(TlsConnectionFactory* factory,
std::vector<uint8_t> der_x509_peer_cert,
std::unique_ptr<TlsConnection> connection) = 0;
// Provides a new `connection` that resulted from connecting to a remote
// endpoint. `der_x509_peer_cert` is the DER-encoded X509 certificate from
// the peer.
virtual void OnConnected(TlsConnectionFactory* factory,
std::vector<uint8_t> der_x509_peer_cert,
std::unique_ptr<TlsConnection> connection) = 0;
virtual void OnConnectionFailed(TlsConnectionFactory* factory,
const IPEndpoint& remote_address) = 0;
// Called when a non-recoverable error occurs.
virtual void OnError(TlsConnectionFactory* factory, const Error& error) = 0;
protected:
virtual ~Client();
};
// The connection factory requires a client for yielding creation results
// asynchronously, as well as a task runner it can use to for running
// callbacks both on the factory and on created TlsConnection instances.
static std::unique_ptr<TlsConnectionFactory> CreateFactory(
Client& client,
TaskRunner& task_runner);
virtual ~TlsConnectionFactory();
// Fires an OnConnected or OnConnectionFailed event.
virtual void Connect(const IPEndpoint& remote_address,
const TlsConnectOptions& options) = 0;
// Set the TlsCredentials used for listening for new connections. Currently,
// having different certificates on different address is not supported. This
// must be called before the first call to Listen.
virtual void SetListenCredentials(const TlsCredentials& credentials) = 0;
// Fires an OnAccepted or OnConnectionFailed event.
virtual void Listen(const IPEndpoint& local_address,
const TlsListenOptions& options) = 0;
protected:
TlsConnectionFactory();
};
} // namespace openscreen
#endif // PLATFORM_API_TLS_CONNECTION_FACTORY_H_

View file

@ -0,0 +1,61 @@
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "platform/api/trace_event.h"
#include <sstream>
namespace openscreen {
TraceEvent::TraceEvent(TraceCategory category,
Clock::time_point start_time,
const char* name,
const char* file_name,
uint32_t line_number)
: category(category),
start_time(start_time),
name(name),
file_name(file_name),
line_number(line_number) {}
TraceEvent::TraceEvent() = default;
TraceEvent::TraceEvent(TraceEvent&&) noexcept = default;
TraceEvent::TraceEvent(const TraceEvent&) = default;
TraceEvent& TraceEvent::operator=(TraceEvent&&) = default;
TraceEvent& TraceEvent::operator=(const TraceEvent&) = default;
TraceEvent::~TraceEvent() = default;
std::string TraceEvent::ToString() const {
std::ostringstream oss;
oss << ids << " " << openscreen::ToString(category) << "::" << name << " <"
<< file_name << ":" << line_number << ">";
// We only support two arguments in total.
if (!arguments.empty()) {
oss << " { " << arguments[0].first << ": " << arguments[0].second;
if (arguments.size() > 1) {
oss << ", " << arguments[1].first << ": " << arguments[1].second;
}
oss << " }";
}
return oss.str();
}
void TraceEvent::TruncateStrings() {
for (auto& argument : arguments) {
if (argument.second.size() > kMaxStringLength) {
argument.second.resize(kMaxStringLength);
// Populate last three digits with ellipses to indicate that
// we truncated this string.
argument.second.replace(kMaxStringLength - 3, 3, "...");
}
}
}
std::ostream& operator<<(std::ostream& out, const TraceEvent& event) {
return out << event.ToString();
}
} // namespace openscreen

View file

@ -0,0 +1,75 @@
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PLATFORM_API_TRACE_EVENT_H_
#define PLATFORM_API_TRACE_EVENT_H_
#include <string>
#include <utility>
#include <vector>
#include "platform/api/time.h"
#include "platform/base/error.h"
#include "platform/base/trace_logging_activation.h"
#include "platform/base/trace_logging_types.h"
namespace openscreen {
// A collection of common properties of trace events.
struct TraceEvent {
// Constructor with only the required fields.
TraceEvent(TraceCategory category,
Clock::time_point start_time,
const char* name,
const char* file_name,
uint32_t line_number);
TraceEvent();
TraceEvent(TraceEvent&&) noexcept;
TraceEvent(const TraceEvent&);
TraceEvent& operator=(TraceEvent&&);
TraceEvent& operator=(const TraceEvent&);
~TraceEvent();
std::string ToString() const;
// May be called to truncate all std::strings on this object.
static const size_t kMaxStringLength = 1024;
void TruncateStrings();
// The category of this event.
TraceCategory category;
// Timestamp for when the event was created.
Clock::time_point start_time;
// Name of this operation.
const char* name = nullptr;
// Name of the file the log was generated in.
const char* file_name = nullptr;
// Line number the log was generated on.
uint32_t line_number = 0;
// The trace ids of this event and its ancestors.
TraceIdHierarchy ids;
// Flow IDs associated with this event.
std::vector<uint64_t> flow_ids;
// Optional result of the trace event.
Error::Code result = Error::Code::kNone;
// Optional list of arguments. May contain 0, 1, or 2 arguments.
// Excess arguments will remain unused.
using Argument = std::pair<const char*, std::string>;
std::vector<Argument> arguments;
};
std::ostream& operator<<(std::ostream& out, const TraceEvent& event);
} // namespace openscreen
#endif // PLATFORM_API_TRACE_EVENT_H_

View file

@ -0,0 +1,13 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "platform/api/trace_logging_platform.h"
namespace openscreen {
TraceLoggingPlatform::~TraceLoggingPlatform() = default;
void TraceLoggingPlatform::LogFlow(TraceEvent event, FlowType type) {}
} // namespace openscreen

View file

@ -0,0 +1,52 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PLATFORM_API_TRACE_LOGGING_PLATFORM_H_
#define PLATFORM_API_TRACE_LOGGING_PLATFORM_H_
#include <string>
#include <utility>
#include <vector>
#include "platform/api/time.h"
#include "platform/api/trace_event.h"
#include "platform/base/error.h"
#include "platform/base/trace_logging_activation.h"
#include "platform/base/trace_logging_types.h"
namespace openscreen {
// Optional platform API to support logging trace events from Open Screen. To
// use this, implement the TraceLoggingPlatform interface and call
// StartTracing() and StopTracing() to turn tracing on/off (see
// platform/base/trace_logging_activation.h).
//
// All methods must be thread-safe and re-entrant.
class TraceLoggingPlatform {
public:
virtual ~TraceLoggingPlatform();
// Determines whether trace logging is enabled for the given category. Note
// that if any categories are supported, this function should return "true"
// when called with TraceCategory::kAny.
virtual bool IsTraceLoggingEnabled(TraceCategory category) = 0;
// Log a synchronous trace.
virtual void LogTrace(TraceEvent event, Clock::time_point end_time) = 0;
// Log an asynchronous trace start.
virtual void LogAsyncStart(TraceEvent event) = 0;
// Log an asynchronous trace end.
virtual void LogAsyncEnd(TraceEvent event) = 0;
// Log a flow event.
// TODO(crbug.com/479316209): fast-follow: make non-optional once implemented
// in Chromium.
virtual void LogFlow(TraceEvent event, FlowType type);
};
} // namespace openscreen
#endif // PLATFORM_API_TRACE_LOGGING_PLATFORM_H_

View file

@ -0,0 +1,14 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "platform/api/udp_socket.h"
namespace openscreen {
UdpSocket::UdpSocket() = default;
UdpSocket::~UdpSocket() = default;
UdpSocket::Client::~Client() = default;
} // namespace openscreen

View file

@ -0,0 +1,140 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PLATFORM_API_UDP_SOCKET_H_
#define PLATFORM_API_UDP_SOCKET_H_
#include <stddef.h> // size_t
#include <stdint.h> // uint8_t
#include <memory>
#include "platform/api/network_interface.h"
#include "platform/base/error.h"
#include "platform/base/ip_address.h"
#include "platform/base/span.h"
#include "platform/base/udp_packet.h"
namespace openscreen {
class TaskRunner;
// An open UDP socket for sending/receiving datagrams to/from either specific
// endpoints or over IP multicast.
//
// Usage: The socket is created and opened by calling the Create() method. This
// returns a unique pointer that auto-closes/destroys the socket when it goes
// out-of-scope.
class UdpSocket {
public:
// Client for the UdpSocket class.
class Client {
public:
// Method called when the UDP socket is bound. Default implementation
// does nothing, as clients may not care about the socket bind state.
virtual void OnBound(UdpSocket* socket) {}
// Method called on socket configuration operations when an error occurs.
// These specific APIs are:
// UdpSocket::Bind()
// UdpSocket::SetMulticastOutboundInterface(...)
// UdpSocket::JoinMulticastGroup(...)
// UdpSocket::SetDscp(...)
virtual void OnError(UdpSocket* socket, const Error& error) = 0;
// Method called when an error occurs during a SendMessage call.
virtual void OnSendError(UdpSocket* socket, const Error& error) = 0;
// Method called when a packet is read.
virtual void OnRead(UdpSocket* socket, ErrorOr<UdpPacket> packet) = 0;
protected:
virtual ~Client();
};
// Common, modern code points for use with DSCP. This list is non-inclusive,
// callers are encouraged to check validity of an integer code point by
// ensuring it is in the bounds of [kBestEffort, kMaxValue] inclusive.
// https://www.rfc-editor.org/rfc/rfc2474.html
enum class DscpMode : uint8_t {
// Best-effort, no differentiated treatment.
kBestEffort = 0,
// Assured Forwarding code points.
// https://datatracker.ietf.org/doc/html/rfc2597#section-6
kAF11 = 10,
kAF12 = 12,
kAF13 = 14,
kAF21 = 18,
kAF22 = 20,
kAF23 = 22,
kAF31 = 26,
kAF32 = 28,
kAF33 = 30,
kAF41 = 34,
kAF42 = 36,
kAF43 = 38,
// Expedited Forwarding (EF) code point.
// https://www.rfc-editor.org/rfc/rfc3246.html
kEF = 46,
// As a 6-bit value, DSCP ranges from [0, 63] inclusive.
kMaxValue = 63,
};
using Version = IPAddress::Version;
// Creates a new, scoped UdpSocket within the IPv4 or IPv6 family.
// `local_endpoint` may be zero (see comments for Bind()). This method must be
// defined in the platform-level implementation. All `client` methods called
// will be queued on the provided `task_runner`. For this reason, the provided
// TaskRunner and Client must exist for the duration of the created socket's
// lifetime.
static ErrorOr<std::unique_ptr<UdpSocket>> Create(
TaskRunner& task_runner,
Client* client,
const IPEndpoint& local_endpoint);
virtual ~UdpSocket();
// Returns true if `socket` belongs to the IPv4/IPv6 address family.
virtual bool IsIPv4() const = 0;
virtual bool IsIPv6() const = 0;
// Returns the current local endpoint's address and port. Initially, this will
// be the same as the value that was passed into Create(). However, it can
// later change after certain operations, such as Bind(), are executed.
virtual IPEndpoint GetLocalEndpoint() const = 0;
// Binds to the address specified in the constructor. If the local endpoint's
// address is zero, the operating system will bind to all interfaces. If the
// local endpoint's port is zero, the operating system will automatically find
// a free local port and bind to it. Future calls to GetLocalEndpoint() will
// reflect the resolved port.
virtual void Bind() = 0;
// Sets the device to use for outgoing multicast packets on the socket.
virtual void SetMulticastOutboundInterface(NetworkInterfaceIndex ifindex) = 0;
// Joins to the multicast group at the given address, using the specified
// interface.
virtual void JoinMulticastGroup(const IPAddress& address,
NetworkInterfaceIndex ifindex) = 0;
// Sends a message. If the message is not sent, Client::OnSendError() will be
// called to indicate this. Error::Code::kAgain indicates the operation would
// block, which can be expected during normal operation.
virtual void SendMessage(ByteView data, const IPEndpoint& dest) = 0;
// Sets the DSCP value to use for all messages sent from this socket.
virtual void SetDscp(DscpMode mode) = 0;
protected:
UdpSocket();
};
} // namespace openscreen
#endif // PLATFORM_API_UDP_SOCKET_H_