Implement Cast Streaming mirroring, DLNA casting, daemon+GUI, and breadd integration
Some checks failed
dev release / build (push) Failing after 12s
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:
parent
887c29002f
commit
8c745d18e0
283 changed files with 36788 additions and 0 deletions
54
breadcast-caststream-sys/vendor/openscreen/platform/api/connection.h
vendored
Normal file
54
breadcast-caststream-sys/vendor/openscreen/platform/api/connection.h
vendored
Normal 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_
|
||||
26
breadcast-caststream-sys/vendor/openscreen/platform/api/export.h
vendored
Normal file
26
breadcast-caststream-sys/vendor/openscreen/platform/api/export.h
vendored
Normal 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_
|
||||
62
breadcast-caststream-sys/vendor/openscreen/platform/api/logging.h
vendored
Normal file
62
breadcast-caststream-sys/vendor/openscreen/platform/api/logging.h
vendored
Normal 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_
|
||||
24
breadcast-caststream-sys/vendor/openscreen/platform/api/network_interface.h
vendored
Normal file
24
breadcast-caststream-sys/vendor/openscreen/platform/api/network_interface.h
vendored
Normal 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_
|
||||
64
breadcast-caststream-sys/vendor/openscreen/platform/api/task_runner.h
vendored
Normal file
64
breadcast-caststream-sys/vendor/openscreen/platform/api/task_runner.h
vendored
Normal 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_
|
||||
23
breadcast-caststream-sys/vendor/openscreen/platform/api/task_runner_deleter.cc
vendored
Normal file
23
breadcast-caststream-sys/vendor/openscreen/platform/api/task_runner_deleter.cc
vendored
Normal 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
|
||||
64
breadcast-caststream-sys/vendor/openscreen/platform/api/task_runner_deleter.h
vendored
Normal file
64
breadcast-caststream-sys/vendor/openscreen/platform/api/task_runner_deleter.h
vendored
Normal 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_
|
||||
37
breadcast-caststream-sys/vendor/openscreen/platform/api/time.h
vendored
Normal file
37
breadcast-caststream-sys/vendor/openscreen/platform/api/time.h
vendored
Normal 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_
|
||||
12
breadcast-caststream-sys/vendor/openscreen/platform/api/tls_connection.cc
vendored
Normal file
12
breadcast-caststream-sys/vendor/openscreen/platform/api/tls_connection.cc
vendored
Normal 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
|
||||
29
breadcast-caststream-sys/vendor/openscreen/platform/api/tls_connection.h
vendored
Normal file
29
breadcast-caststream-sys/vendor/openscreen/platform/api/tls_connection.h
vendored
Normal 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_
|
||||
14
breadcast-caststream-sys/vendor/openscreen/platform/api/tls_connection_factory.cc
vendored
Normal file
14
breadcast-caststream-sys/vendor/openscreen/platform/api/tls_connection_factory.cc
vendored
Normal 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
|
||||
82
breadcast-caststream-sys/vendor/openscreen/platform/api/tls_connection_factory.h
vendored
Normal file
82
breadcast-caststream-sys/vendor/openscreen/platform/api/tls_connection_factory.h
vendored
Normal 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_
|
||||
61
breadcast-caststream-sys/vendor/openscreen/platform/api/trace_event.cc
vendored
Normal file
61
breadcast-caststream-sys/vendor/openscreen/platform/api/trace_event.cc
vendored
Normal 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
|
||||
75
breadcast-caststream-sys/vendor/openscreen/platform/api/trace_event.h
vendored
Normal file
75
breadcast-caststream-sys/vendor/openscreen/platform/api/trace_event.h
vendored
Normal 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_
|
||||
13
breadcast-caststream-sys/vendor/openscreen/platform/api/trace_logging_platform.cc
vendored
Normal file
13
breadcast-caststream-sys/vendor/openscreen/platform/api/trace_logging_platform.cc
vendored
Normal 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
|
||||
52
breadcast-caststream-sys/vendor/openscreen/platform/api/trace_logging_platform.h
vendored
Normal file
52
breadcast-caststream-sys/vendor/openscreen/platform/api/trace_logging_platform.h
vendored
Normal 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_
|
||||
14
breadcast-caststream-sys/vendor/openscreen/platform/api/udp_socket.cc
vendored
Normal file
14
breadcast-caststream-sys/vendor/openscreen/platform/api/udp_socket.cc
vendored
Normal 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
|
||||
140
breadcast-caststream-sys/vendor/openscreen/platform/api/udp_socket.h
vendored
Normal file
140
breadcast-caststream-sys/vendor/openscreen/platform/api/udp_socket.h
vendored
Normal 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_
|
||||
20
breadcast-caststream-sys/vendor/openscreen/platform/base/compiler_specific.h
vendored
Normal file
20
breadcast-caststream-sys/vendor/openscreen/platform/base/compiler_specific.h
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// 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_BASE_COMPILER_SPECIFIC_H_
|
||||
#define PLATFORM_BASE_COMPILER_SPECIFIC_H_
|
||||
|
||||
#ifdef NOINLINE
|
||||
#define OSP_NOINLINE NOINLINE
|
||||
#elif __has_cpp_attribute(clang::noinline)
|
||||
#define OSP_NOINLINE [[clang::noinline]]
|
||||
#elif __has_cpp_attribute(gnu::noinline)
|
||||
#define OSP_NOINLINE [[gnu::noinline]]
|
||||
#elif __has_cpp_attribute(msvc::noinline)
|
||||
#define OSP_NOINLINE [[msvc::noinline]]
|
||||
#else
|
||||
#define OSP_NOINLINE __attribute__((noinline))
|
||||
#endif
|
||||
|
||||
#endif // PLATFORM_BASE_COMPILER_SPECIFIC_H_
|
||||
306
breadcast-caststream-sys/vendor/openscreen/platform/base/error.cc
vendored
Normal file
306
breadcast-caststream-sys/vendor/openscreen/platform/base/error.cc
vendored
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
// 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.
|
||||
|
||||
#include "platform/base/error.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
Error::Error() = default;
|
||||
|
||||
Error::Error(const Error& error) = default;
|
||||
|
||||
Error::Error(Error&& error) noexcept = default;
|
||||
|
||||
Error::Error(Code code) : code_(code) {}
|
||||
|
||||
Error::Error(Code code, const std::string& message)
|
||||
: code_(code), message_(message) {}
|
||||
|
||||
Error::Error(Code code, std::string&& message)
|
||||
: code_(code), message_(std::move(message)) {}
|
||||
|
||||
Error::~Error() = default;
|
||||
|
||||
Error& Error::operator=(const Error& other) = default;
|
||||
|
||||
Error& Error::operator=(Error&& other) = default;
|
||||
|
||||
bool Error::operator==(const Error& other) const {
|
||||
return code_ == other.code_ && message_ == other.message_;
|
||||
}
|
||||
|
||||
bool Error::operator!=(const Error& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool Error::operator==(Code code) const {
|
||||
return code_ == code;
|
||||
}
|
||||
|
||||
bool Error::operator!=(Code code) const {
|
||||
return !(*this == code);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Error::Code& code) {
|
||||
if (code == Error::Code::kNone) {
|
||||
return os << "Success";
|
||||
}
|
||||
os << "Failure: ";
|
||||
switch (code) {
|
||||
case Error::Code::kAgain:
|
||||
return os << "Transient";
|
||||
case Error::Code::kCborParsing:
|
||||
return os << "CborParsing";
|
||||
case Error::Code::kCborEncoding:
|
||||
return os << "CborEncoding";
|
||||
case Error::Code::kCborIncompleteMessage:
|
||||
return os << "CborIncompleteMessage";
|
||||
case Error::Code::kCborInvalidMessage:
|
||||
return os << "CborInvalidMessage";
|
||||
case Error::Code::kCborInvalidResponseId:
|
||||
return os << "CborInvalidResponseId";
|
||||
case Error::Code::kNoAvailableReceivers:
|
||||
return os << "NoAvailableReceivers";
|
||||
case Error::Code::kRequestCancelled:
|
||||
return os << "RequestCancelled";
|
||||
case Error::Code::kNoPresentationFound:
|
||||
return os << "NoPresentationFound";
|
||||
case Error::Code::kPreviousStartInProgress:
|
||||
return os << "PreviousStartInProgress";
|
||||
case Error::Code::kUnknownStartError:
|
||||
return os << "UnknownStartError";
|
||||
case Error::Code::kUnknownRequestId:
|
||||
return os << "UnknownRequestId";
|
||||
case Error::Code::kAddressInUse:
|
||||
return os << "AddressInUse";
|
||||
case Error::Code::kDomainNameTooLong:
|
||||
return os << "DomainNameTooLong";
|
||||
case Error::Code::kDomainNameLabelTooLong:
|
||||
return os << "DomainNameLabelTooLong";
|
||||
case Error::Code::kIOFailure:
|
||||
return os << "IOFailure";
|
||||
case Error::Code::kInitializationFailure:
|
||||
return os << "InitializationFailure";
|
||||
case Error::Code::kInvalidIPV4Address:
|
||||
return os << "InvalidIPV4Address";
|
||||
case Error::Code::kInvalidIPV6Address:
|
||||
return os << "InvalidIPV6Address";
|
||||
case Error::Code::kConnectionFailed:
|
||||
return os << "ConnectionFailed";
|
||||
case Error::Code::kSocketOptionSettingFailure:
|
||||
return os << "SocketOptionSettingFailure";
|
||||
case Error::Code::kSocketAcceptFailure:
|
||||
return os << "SocketAcceptFailure";
|
||||
case Error::Code::kSocketBindFailure:
|
||||
return os << "SocketBindFailure";
|
||||
case Error::Code::kSocketClosedFailure:
|
||||
return os << "SocketClosedFailure";
|
||||
case Error::Code::kSocketConnectFailure:
|
||||
return os << "SocketConnectFailure";
|
||||
case Error::Code::kSocketInvalidState:
|
||||
return os << "SocketInvalidState";
|
||||
case Error::Code::kSocketListenFailure:
|
||||
return os << "SocketListenFailure";
|
||||
case Error::Code::kSocketReadFailure:
|
||||
return os << "SocketReadFailure";
|
||||
case Error::Code::kSocketSendFailure:
|
||||
return os << "SocketSendFailure";
|
||||
case Error::Code::kMdnsRegisterFailure:
|
||||
return os << "MdnsRegisterFailure";
|
||||
case Error::Code::kMdnsReadFailure:
|
||||
return os << "MdnsReadFailure";
|
||||
case Error::Code::kMdnsNonConformingFailure:
|
||||
return os << "kMdnsNonConformingFailure";
|
||||
case Error::Code::kParseError:
|
||||
return os << "ParseError";
|
||||
case Error::Code::kUnknownMessageType:
|
||||
return os << "UnknownMessageType";
|
||||
case Error::Code::kNoActiveConnection:
|
||||
return os << "NoActiveConnection";
|
||||
case Error::Code::kAlreadyClosed:
|
||||
return os << "AlreadyClosed";
|
||||
case Error::Code::kNoStartedPresentation:
|
||||
return os << "NoStartedPresentation";
|
||||
case Error::Code::kPresentationAlreadyStarted:
|
||||
return os << "PresentationAlreadyStarted";
|
||||
case Error::Code::kInvalidConnectionState:
|
||||
return os << "InvalidConnectionState";
|
||||
case Error::Code::kJsonParseError:
|
||||
return os << "JsonParseError";
|
||||
case Error::Code::kJsonWriteError:
|
||||
return os << "JsonWriteError";
|
||||
case Error::Code::kFatalSSLError:
|
||||
return os << "FatalSSLError";
|
||||
case Error::Code::kRSAKeyGenerationFailure:
|
||||
return os << "RSAKeyGenerationFailure";
|
||||
case Error::Code::kRSAKeyParseError:
|
||||
return os << "RSAKeyParseError";
|
||||
case Error::Code::kEVPInitializationError:
|
||||
return os << "EVPInitializationError";
|
||||
case Error::Code::kCertificateCreationError:
|
||||
return os << "CertificateCreationError";
|
||||
case Error::Code::kCertificateValidationError:
|
||||
return os << "CertificateValidationError";
|
||||
case Error::Code::kSha256HashFailure:
|
||||
return os << "Sha256HashFailure";
|
||||
case Error::Code::kFileLoadFailure:
|
||||
return os << "FileLoadFailure";
|
||||
case Error::Code::kErrCertsMissing:
|
||||
return os << "ErrCertsMissing";
|
||||
case Error::Code::kErrCertsParse:
|
||||
return os << "ErrCertsParse";
|
||||
case Error::Code::kErrCertsRestrictions:
|
||||
return os << "ErrCertsRestrictions";
|
||||
case Error::Code::kErrCertsDateInvalid:
|
||||
return os << "ErrCertsDateInvalid";
|
||||
case Error::Code::kErrCertsVerifyGeneric:
|
||||
return os << "ErrCertsVerifyGeneric";
|
||||
case Error::Code::kErrCertsVerifyUntrustedCert:
|
||||
return os << "kErrCertsVerifyUntrustedCert";
|
||||
case Error::Code::kErrCrlInvalid:
|
||||
return os << "ErrCrlInvalid";
|
||||
case Error::Code::kErrCertsRevoked:
|
||||
return os << "ErrCertsRevoked";
|
||||
case Error::Code::kErrCertsPathlen:
|
||||
return os << "ErrCertsPathlen";
|
||||
case Error::Code::kErrCertSerialize:
|
||||
return os << "ErrCertSerialize";
|
||||
case Error::Code::kCastV2PeerCertEmpty:
|
||||
return os << "kCastV2PeerCertEmpty";
|
||||
case Error::Code::kCastV2WrongPayloadType:
|
||||
return os << "kCastV2WrongPayloadType";
|
||||
case Error::Code::kCastV2NoPayload:
|
||||
return os << "kCastV2NoPayload";
|
||||
case Error::Code::kCastV2PayloadParsingFailed:
|
||||
return os << "kCastV2PayloadParsingFailed";
|
||||
case Error::Code::kCastV2MessageError:
|
||||
return os << "CastV2kMessageError";
|
||||
case Error::Code::kCastV2NoResponse:
|
||||
return os << "kCastV2NoResponse";
|
||||
case Error::Code::kCastV2FingerprintNotFound:
|
||||
return os << "kCastV2FingerprintNotFound";
|
||||
case Error::Code::kCastV2CertNotSignedByTrustedCa:
|
||||
return os << "kCastV2CertNotSignedByTrustedCa";
|
||||
case Error::Code::kCastV2CannotExtractPublicKey:
|
||||
return os << "kCastV2CannotExtractPublicKey";
|
||||
case Error::Code::kCastV2SignedBlobsMismatch:
|
||||
return os << "kCastV2SignedBlobsMismatch";
|
||||
case Error::Code::kCastV2TlsCertValidityPeriodTooLong:
|
||||
return os << "kCastV2TlsCertValidityPeriodTooLong";
|
||||
case Error::Code::kCastV2TlsCertValidStartDateInFuture:
|
||||
return os << "kCastV2TlsCertValidStartDateInFuture";
|
||||
case Error::Code::kCastV2TlsCertExpired:
|
||||
return os << "kCastV2TlsCertExpired";
|
||||
case Error::Code::kCastV2SenderNonceMismatch:
|
||||
return os << "kCastV2SenderNonceMismatch";
|
||||
case Error::Code::kCastV2DigestUnsupported:
|
||||
return os << "kCastV2DigestUnsupported";
|
||||
case Error::Code::kCastV2SignatureEmpty:
|
||||
return os << "kCastV2SignatureEmpty";
|
||||
case Error::Code::kCastV2ChannelNotOpen:
|
||||
return os << "kCastV2ChannelNotOpen";
|
||||
case Error::Code::kCastV2AuthenticationError:
|
||||
return os << "kCastV2AuthenticationError";
|
||||
case Error::Code::kCastV2ConnectError:
|
||||
return os << "kCastV2ConnectError";
|
||||
case Error::Code::kCastV2CastSocketError:
|
||||
return os << "kCastV2CastSocketError";
|
||||
case Error::Code::kCastV2TransportError:
|
||||
return os << "kCastV2TransportError";
|
||||
case Error::Code::kCastV2InvalidMessage:
|
||||
return os << "kCastV2InvalidMessage";
|
||||
case Error::Code::kCastV2InvalidChannelId:
|
||||
return os << "kCastV2InvalidChannelId";
|
||||
case Error::Code::kCastV2ConnectTimeout:
|
||||
return os << "kCastV2ConnectTimeout";
|
||||
case Error::Code::kCastV2PingTimeout:
|
||||
return os << "kCastV2PingTimeout";
|
||||
case Error::Code::kCastV2ChannelPolicyMismatch:
|
||||
return os << "kCastV2ChannelPolicyMismatch";
|
||||
case Error::Code::kCreateSignatureFailed:
|
||||
return os << "kCreateSignatureFailed";
|
||||
case Error::Code::kUpdateReceivedRecordFailure:
|
||||
return os << "kUpdateReceivedRecordFailure";
|
||||
case Error::Code::kRecordPublicationError:
|
||||
return os << "kRecordPublicationError";
|
||||
case Error::Code::kProcessReceivedRecordFailure:
|
||||
return os << "ProcessReceivedRecordFailure";
|
||||
case Error::Code::kUnknownError:
|
||||
return os << "UnknownError";
|
||||
case Error::Code::kNotImplemented:
|
||||
return os << "NotImplemented";
|
||||
case Error::Code::kInsufficientBuffer:
|
||||
return os << "InsufficientBuffer";
|
||||
case Error::Code::kParameterInvalid:
|
||||
return os << "ParameterInvalid";
|
||||
case Error::Code::kParameterOutOfRange:
|
||||
return os << "ParameterOutOfRange";
|
||||
case Error::Code::kParameterNullPointer:
|
||||
return os << "ParameterNullPointer";
|
||||
case Error::Code::kIndexOutOfBounds:
|
||||
return os << "IndexOutOfBounds";
|
||||
case Error::Code::kItemAlreadyExists:
|
||||
return os << "ItemAlreadyExists";
|
||||
case Error::Code::kItemNotFound:
|
||||
return os << "ItemNotFound";
|
||||
case Error::Code::kOperationInvalid:
|
||||
return os << "OperationInvalid";
|
||||
case Error::Code::kOperationInProgress:
|
||||
return os << "OperationInProgress";
|
||||
case Error::Code::kOperationCancelled:
|
||||
return os << "OperationCancelled";
|
||||
case Error::Code::kInterrupted:
|
||||
return os << "Interrupted";
|
||||
case Error::Code::kUnknownCodec:
|
||||
return os << "UnknownCodec";
|
||||
case Error::Code::kInvalidCodecParameter:
|
||||
return os << "InvalidCodecParameter";
|
||||
case Error::Code::kSocketFailure:
|
||||
return os << "SocketFailure";
|
||||
case Error::Code::kUnencryptedOffer:
|
||||
return os << "UnencryptedOffer";
|
||||
case Error::Code::kRemotingNotSupported:
|
||||
return os << "RemotingNotSupported";
|
||||
case Error::Code::kNoStreamSelected:
|
||||
return os << "NoStreamSelected";
|
||||
case Error::Code::kAnswerTimeout:
|
||||
return os << "AnswerTimeout";
|
||||
case Error::Code::kInvalidAnswer:
|
||||
return os << "InvalidAnswer";
|
||||
case Error::Code::kMessageTimeout:
|
||||
return os << "MessageTimeout";
|
||||
case Error::Code::kNone:
|
||||
break;
|
||||
}
|
||||
|
||||
// Unused 'return' to get around failure on GCC.
|
||||
return os;
|
||||
}
|
||||
|
||||
std::string Error::ToString() const {
|
||||
std::stringstream ss;
|
||||
ss << *this;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string ToString(openscreen::Error::Code code) {
|
||||
std::ostringstream ss;
|
||||
ss << code;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const Error& error) {
|
||||
out << error.code() << " = \"" << error.message() << "\"";
|
||||
return out;
|
||||
}
|
||||
|
||||
// static
|
||||
const Error& Error::None() {
|
||||
static Error& error = *new Error(Code::kNone);
|
||||
return error;
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
432
breadcast-caststream-sys/vendor/openscreen/platform/base/error.h
vendored
Normal file
432
breadcast-caststream-sys/vendor/openscreen/platform/base/error.h
vendored
Normal file
|
|
@ -0,0 +1,432 @@
|
|||
// 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_BASE_ERROR_H_
|
||||
#define PLATFORM_BASE_ERROR_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
// Represents an error returned by an OSP library operation. An error has a
|
||||
// code and an optional message.
|
||||
class Error {
|
||||
public:
|
||||
// TODO(crbug.com/openscreen/65): Group/rename OSP-specific errors
|
||||
// NOTE: new values should be added to the end of the of enum and existing
|
||||
// values should not be changed.
|
||||
enum class Code : int8_t {
|
||||
// No error occurred.
|
||||
kNone = 0,
|
||||
|
||||
// A transient condition prevented the operation from proceeding (e.g.,
|
||||
// cannot send on a non-blocking socket without blocking). This indicates
|
||||
// the caller should try again later.
|
||||
kAgain = -1,
|
||||
|
||||
// CBOR errors.
|
||||
kCborParsing = 1,
|
||||
kCborEncoding = 2,
|
||||
kCborIncompleteMessage = 3,
|
||||
kCborInvalidResponseId = 4,
|
||||
kCborInvalidMessage = 5,
|
||||
|
||||
// Presentation start errors.
|
||||
kNoAvailableReceivers = 6,
|
||||
kRequestCancelled = 7,
|
||||
kNoPresentationFound = 8,
|
||||
kPreviousStartInProgress = 9,
|
||||
kUnknownStartError = 10,
|
||||
kUnknownRequestId = 11,
|
||||
|
||||
kAddressInUse = 12,
|
||||
kDomainNameTooLong = 13,
|
||||
kDomainNameLabelTooLong = 14,
|
||||
|
||||
kIOFailure = 15,
|
||||
kInitializationFailure = 16,
|
||||
kInvalidIPV4Address = 17,
|
||||
kInvalidIPV6Address = 18,
|
||||
kConnectionFailed = 19,
|
||||
|
||||
kSocketOptionSettingFailure = 20,
|
||||
kSocketAcceptFailure = 21,
|
||||
kSocketBindFailure = 22,
|
||||
kSocketClosedFailure = 23,
|
||||
kSocketConnectFailure = 24,
|
||||
kSocketInvalidState = 25,
|
||||
kSocketListenFailure = 26,
|
||||
kSocketReadFailure = 27,
|
||||
kSocketSendFailure = 28,
|
||||
|
||||
// MDNS errors.
|
||||
kMdnsRegisterFailure = 29,
|
||||
kMdnsReadFailure = 30,
|
||||
kMdnsNonConformingFailure = 31,
|
||||
|
||||
kParseError = 32,
|
||||
kUnknownMessageType = 33,
|
||||
|
||||
kNoActiveConnection = 34,
|
||||
kAlreadyClosed = 35,
|
||||
kInvalidConnectionState = 36,
|
||||
kNoStartedPresentation = 37,
|
||||
kPresentationAlreadyStarted = 38,
|
||||
|
||||
kJsonParseError = 39,
|
||||
kJsonWriteError = 40,
|
||||
|
||||
// OpenSSL errors.
|
||||
|
||||
// Was unable to generate an RSA key.
|
||||
kRSAKeyGenerationFailure = 41,
|
||||
kRSAKeyParseError = 42,
|
||||
|
||||
// Was unable to initialize an EVP_PKEY type.
|
||||
kEVPInitializationError = 43,
|
||||
|
||||
// Was unable to generate a certificate.
|
||||
kCertificateCreationError = 44,
|
||||
|
||||
// Certificate failed validation.
|
||||
kCertificateValidationError = 45,
|
||||
|
||||
// Failed to produce a hashing digest.
|
||||
kSha256HashFailure = 46,
|
||||
|
||||
// A non-recoverable SSL library error has occurred.
|
||||
kFatalSSLError = 47,
|
||||
kFileLoadFailure = 48,
|
||||
|
||||
// Cast certificate errors.
|
||||
|
||||
// Certificates were not provided for verification.
|
||||
kErrCertsMissing = 49,
|
||||
|
||||
// The certificates provided could not be parsed.
|
||||
kErrCertsParse = 50,
|
||||
|
||||
// Key usage is missing or is not set to Digital Signature.
|
||||
// This error could also be thrown if the CN is missing.
|
||||
kErrCertsRestrictions = 51,
|
||||
|
||||
// The current date is before the notBefore date or after the notAfter date.
|
||||
kErrCertsDateInvalid = 52,
|
||||
|
||||
// The certificate failed to chain to a trusted root.
|
||||
kErrCertsVerifyGeneric = 53,
|
||||
|
||||
// The certificate was not found in the trust store.
|
||||
kErrCertsVerifyUntrustedCert = 54,
|
||||
|
||||
// The CRL is missing or failed to verify.
|
||||
kErrCrlInvalid = 55,
|
||||
|
||||
// One of the certificates in the chain is revoked.
|
||||
kErrCertsRevoked = 56,
|
||||
|
||||
// The pathlen constraint of the root certificate was exceeded.
|
||||
kErrCertsPathlen = 57,
|
||||
|
||||
// The certificate provided could not be serialized.
|
||||
kErrCertSerialize = 58,
|
||||
|
||||
// Cast authentication errors.
|
||||
kCastV2PeerCertEmpty = 59,
|
||||
kCastV2WrongPayloadType = 60,
|
||||
kCastV2NoPayload = 61,
|
||||
kCastV2PayloadParsingFailed = 62,
|
||||
kCastV2MessageError = 63,
|
||||
kCastV2NoResponse = 64,
|
||||
kCastV2FingerprintNotFound = 65,
|
||||
kCastV2CertNotSignedByTrustedCa = 66,
|
||||
kCastV2CannotExtractPublicKey = 67,
|
||||
kCastV2SignedBlobsMismatch = 68,
|
||||
kCastV2TlsCertValidityPeriodTooLong = 69,
|
||||
kCastV2TlsCertValidStartDateInFuture = 70,
|
||||
kCastV2TlsCertExpired = 71,
|
||||
kCastV2SenderNonceMismatch = 72,
|
||||
kCastV2DigestUnsupported = 73,
|
||||
kCastV2SignatureEmpty = 74,
|
||||
|
||||
// Cast channel errors.
|
||||
kCastV2ChannelNotOpen = 75,
|
||||
kCastV2AuthenticationError = 76,
|
||||
kCastV2ConnectError = 77,
|
||||
kCastV2CastSocketError = 78,
|
||||
kCastV2TransportError = 79,
|
||||
kCastV2InvalidMessage = 80,
|
||||
kCastV2InvalidChannelId = 81,
|
||||
kCastV2ConnectTimeout = 82,
|
||||
kCastV2PingTimeout = 83,
|
||||
kCastV2ChannelPolicyMismatch = 84,
|
||||
|
||||
kCreateSignatureFailed = 85,
|
||||
|
||||
// Discovery errors.
|
||||
kUpdateReceivedRecordFailure = 86,
|
||||
kRecordPublicationError = 87,
|
||||
kProcessReceivedRecordFailure = 88,
|
||||
|
||||
// Generic errors.
|
||||
kUnknownError = 89,
|
||||
kNotImplemented = 90,
|
||||
kInsufficientBuffer = 91,
|
||||
kParameterInvalid = 92,
|
||||
kParameterOutOfRange = 93,
|
||||
kParameterNullPointer = 94,
|
||||
kIndexOutOfBounds = 95,
|
||||
kItemAlreadyExists = 96,
|
||||
kItemNotFound = 97,
|
||||
kOperationInvalid = 98,
|
||||
kOperationInProgress = 99,
|
||||
kOperationCancelled = 100,
|
||||
kInterrupted = 101,
|
||||
|
||||
// Cast streaming errors.
|
||||
kUnknownCodec = 102,
|
||||
kInvalidCodecParameter = 103,
|
||||
kSocketFailure = 104,
|
||||
kUnencryptedOffer = 105,
|
||||
kRemotingNotSupported = 106,
|
||||
kNoStreamSelected = 107,
|
||||
|
||||
// An Answer timeout means that the receiver failed to reply to our Offer
|
||||
// within a reasonable amount of time.
|
||||
kAnswerTimeout = 108,
|
||||
|
||||
// Received an ANSWER, but it was invalid.
|
||||
kInvalidAnswer = 109,
|
||||
|
||||
// A generic message timeout occured.
|
||||
kMessageTimeout = 110,
|
||||
};
|
||||
|
||||
Error();
|
||||
Error(const Error& error);
|
||||
Error(Error&& error) noexcept;
|
||||
|
||||
Error(Code code); // NOLINT
|
||||
Error(Code code, const std::string& message);
|
||||
Error(Code code, std::string&& message);
|
||||
~Error();
|
||||
|
||||
Error& operator=(const Error& other);
|
||||
Error& operator=(Error&& other);
|
||||
bool operator==(const Error& other) const;
|
||||
bool operator!=(const Error& other) const;
|
||||
|
||||
// Special case comparison with codes. Without this case, comparisons will
|
||||
// not work as expected, e.g.
|
||||
// const Error foo(Error::Code::kItemNotFound, "Didn't find an item");
|
||||
// foo == Error::Code::kItemNotFound is actually false.
|
||||
bool operator==(Code code) const;
|
||||
bool operator!=(Code code) const;
|
||||
bool ok() const { return code_ == Code::kNone; }
|
||||
|
||||
Code code() const { return code_; }
|
||||
const std::string& message() const { return message_; }
|
||||
std::string& message() { return message_; }
|
||||
|
||||
static const Error& None();
|
||||
|
||||
std::string ToString() const;
|
||||
|
||||
private:
|
||||
Code code_ = Code::kNone;
|
||||
std::string message_;
|
||||
};
|
||||
|
||||
std::string ToString(openscreen::Error::Code code);
|
||||
std::ostream& operator<<(std::ostream& os, const Error::Code& code);
|
||||
std::ostream& operator<<(std::ostream& out, const Error& error);
|
||||
|
||||
// A convenience function to return a single value from a function that can
|
||||
// return a value or an error. For normal results, construct with a ValueType*
|
||||
// (ErrorOr takes ownership) and the Error will be kNone with an empty message.
|
||||
// For Error results, construct with an error code and value.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// ErrorOr<Bar> Foo::DoSomething() {
|
||||
// if (success) {
|
||||
// return Bar();
|
||||
// } else {
|
||||
// return Error(kBadThingHappened, "No can do");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// TODO(mfoltz): Add support for type conversions.
|
||||
template <typename ValueType>
|
||||
class ErrorOr {
|
||||
public:
|
||||
static ErrorOr<ValueType> None() {
|
||||
static ErrorOr<ValueType> error(Error::Code::kNone);
|
||||
return error;
|
||||
}
|
||||
|
||||
ErrorOr(const ValueType& value) : value_(value), is_value_(true) {} // NOLINT
|
||||
ErrorOr(ValueType&& value) noexcept // NOLINT
|
||||
: value_(std::move(value)), is_value_(true) {}
|
||||
|
||||
ErrorOr(const Error& error) : error_(error), is_value_(false) { // NOLINT
|
||||
assert(error_.code() != Error::Code::kNone);
|
||||
}
|
||||
ErrorOr(Error&& error) noexcept // NOLINT
|
||||
: error_(std::move(error)), is_value_(false) {
|
||||
assert(error_.code() != Error::Code::kNone);
|
||||
}
|
||||
ErrorOr(Error::Code code) : error_(code), is_value_(false) { // NOLINT
|
||||
assert(error_.code() != Error::Code::kNone);
|
||||
}
|
||||
ErrorOr(Error::Code code, std::string message)
|
||||
: error_(code, std::move(message)), is_value_(false) {
|
||||
assert(error_.code() != Error::Code::kNone);
|
||||
}
|
||||
|
||||
ErrorOr(const ErrorOr& other) = delete;
|
||||
ErrorOr(ErrorOr&& other) noexcept : is_value_(other.is_value_) {
|
||||
// NB: Both `value_` and `error_` are uninitialized memory at this point!
|
||||
// Unlike the other constructors, the compiler will not auto-generate
|
||||
// constructor calls for either union member because neither appeared in
|
||||
// this constructor's initializer list.
|
||||
if (other.is_value_) {
|
||||
new (&value_) ValueType(std::move(other.value_));
|
||||
} else {
|
||||
new (&error_) Error(std::move(other.error_));
|
||||
}
|
||||
}
|
||||
|
||||
ErrorOr& operator=(const ErrorOr& other) = delete;
|
||||
ErrorOr& operator=(ErrorOr&& other) noexcept {
|
||||
this->~ErrorOr<ValueType>();
|
||||
new (this) ErrorOr<ValueType>(std::move(other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
~ErrorOr() {
|
||||
// NB: `value_` or `error_` must be explicitly destroyed since the compiler
|
||||
// will not auto-generate the destructor calls for union members.
|
||||
if (is_value_) {
|
||||
value_.~ValueType();
|
||||
} else {
|
||||
error_.~Error();
|
||||
}
|
||||
}
|
||||
|
||||
bool is_error() const { return !is_value_; }
|
||||
bool is_value() const { return is_value_; }
|
||||
|
||||
// Unlike Error, we CAN provide an operator bool here, since it is
|
||||
// more obvious to callers that ErrorOr<Foo> will be true if it's Foo.
|
||||
operator bool() const { return is_value_; }
|
||||
|
||||
const Error& error() const {
|
||||
assert(!is_value_);
|
||||
return error_;
|
||||
}
|
||||
Error& error() {
|
||||
assert(!is_value_);
|
||||
return error_;
|
||||
}
|
||||
|
||||
const ValueType& value() const {
|
||||
assert(is_value_);
|
||||
return value_;
|
||||
}
|
||||
ValueType& value() {
|
||||
assert(is_value_);
|
||||
return value_;
|
||||
}
|
||||
|
||||
// Move only value or fallback
|
||||
ValueType&& value(ValueType&& fallback) {
|
||||
if (is_value()) {
|
||||
return std::move(value());
|
||||
}
|
||||
return std::forward<ValueType>(fallback);
|
||||
}
|
||||
|
||||
// Copy only value or fallback
|
||||
ValueType value(ValueType fallback) const {
|
||||
if (is_value()) {
|
||||
return value();
|
||||
}
|
||||
return std::move(fallback);
|
||||
}
|
||||
|
||||
private:
|
||||
// Only one of these is an active member, determined by `is_value_`. Since
|
||||
// they are union'ed, they must be explicitly constructed and destroyed.
|
||||
union {
|
||||
ValueType value_;
|
||||
Error error_;
|
||||
};
|
||||
|
||||
// If true, `value_` is initialized and active. Otherwise, `error_` is
|
||||
// initialized and active.
|
||||
const bool is_value_;
|
||||
};
|
||||
|
||||
// Define comparison operators using SFINAE.
|
||||
template <typename ValueType>
|
||||
bool operator<(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) {
|
||||
// Handle the cases where one side is an error.
|
||||
if (lhs.is_error() != rhs.is_error()) {
|
||||
return lhs.is_error();
|
||||
}
|
||||
|
||||
// Handle the case where both sides are errors.
|
||||
if (lhs.is_error()) {
|
||||
return static_cast<int8_t>(lhs.error().code()) <
|
||||
static_cast<int8_t>(rhs.error().code());
|
||||
}
|
||||
|
||||
// Handle the case where both are values.
|
||||
return lhs.value() < rhs.value();
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool operator>(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool operator<=(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool operator>=(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool operator==(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) {
|
||||
// Handle the cases where one side is an error.
|
||||
if (lhs.is_error() != rhs.is_error()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle the case where both sides are errors.
|
||||
if (lhs.is_error()) {
|
||||
return lhs.error() == rhs.error();
|
||||
}
|
||||
|
||||
// Handle the case where both are values.
|
||||
return lhs.value() == rhs.value();
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool operator!=(const ErrorOr<ValueType>& lhs, const ErrorOr<ValueType>& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_BASE_ERROR_H_
|
||||
98
breadcast-caststream-sys/vendor/openscreen/platform/base/interface_info.cc
vendored
Normal file
98
breadcast-caststream-sys/vendor/openscreen/platform/base/interface_info.cc
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
// 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.
|
||||
|
||||
#include "platform/base/interface_info.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
InterfaceInfo::InterfaceInfo() = default;
|
||||
InterfaceInfo::InterfaceInfo(NetworkInterfaceIndex index,
|
||||
const uint8_t hardware_address[6],
|
||||
std::string name,
|
||||
Type type,
|
||||
std::vector<IPSubnet> addresses)
|
||||
: index(index),
|
||||
hardware_address{hardware_address[0], hardware_address[1],
|
||||
hardware_address[2], hardware_address[3],
|
||||
hardware_address[4], hardware_address[5]},
|
||||
name(std::move(name)),
|
||||
type(type),
|
||||
addresses(std::move(addresses)) {}
|
||||
InterfaceInfo::~InterfaceInfo() = default;
|
||||
|
||||
IPSubnet::IPSubnet() = default;
|
||||
IPSubnet::IPSubnet(IPAddress address, uint8_t prefix_length)
|
||||
: address(std::move(address)), prefix_length(prefix_length) {}
|
||||
IPSubnet::~IPSubnet() = default;
|
||||
|
||||
IPAddress InterfaceInfo::GetIpAddressV4() const {
|
||||
for (const auto& address : addresses) {
|
||||
if (address.address.IsV4()) {
|
||||
return address.address;
|
||||
}
|
||||
}
|
||||
return IPAddress{};
|
||||
}
|
||||
|
||||
IPAddress InterfaceInfo::GetIpAddressV6() const {
|
||||
for (const auto& address : addresses) {
|
||||
if (address.address.IsV6()) {
|
||||
return address.address;
|
||||
}
|
||||
}
|
||||
return IPAddress{};
|
||||
}
|
||||
|
||||
bool InterfaceInfo::HasHardwareAddress() const {
|
||||
return std::any_of(hardware_address.begin(), hardware_address.end(),
|
||||
[](uint8_t e) { return e != 0; });
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const IPSubnet& subnet) {
|
||||
if (subnet.address.IsV6()) {
|
||||
out << '[';
|
||||
}
|
||||
out << subnet.address;
|
||||
if (subnet.address.IsV6()) {
|
||||
out << ']';
|
||||
}
|
||||
return out << '/' << std::dec << static_cast<int>(subnet.prefix_length);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, InterfaceInfo::Type type) {
|
||||
switch (type) {
|
||||
case InterfaceInfo::Type::kEthernet:
|
||||
out << "Ethernet";
|
||||
break;
|
||||
case InterfaceInfo::Type::kWifi:
|
||||
out << "Wifi";
|
||||
break;
|
||||
case InterfaceInfo::Type::kLoopback:
|
||||
out << "Loopback";
|
||||
break;
|
||||
case InterfaceInfo::Type::kOther:
|
||||
out << "Other";
|
||||
break;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const InterfaceInfo& info) {
|
||||
out << '{' << info.index << " (a.k.a. " << info.name
|
||||
<< "); media_type=" << info.type << "; MAC=" << std::hex
|
||||
<< static_cast<int>(info.hardware_address[0]);
|
||||
for (size_t i = 1; i < info.hardware_address.size(); ++i) {
|
||||
out << ':' << static_cast<int>(info.hardware_address[i]);
|
||||
}
|
||||
for (const IPSubnet& ip : info.addresses) {
|
||||
out << "; " << ip;
|
||||
}
|
||||
return out << '}';
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
86
breadcast-caststream-sys/vendor/openscreen/platform/base/interface_info.h
vendored
Normal file
86
breadcast-caststream-sys/vendor/openscreen/platform/base/interface_info.h
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
// 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_BASE_INTERFACE_INFO_H_
|
||||
#define PLATFORM_BASE_INTERFACE_INFO_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "platform/base/ip_address.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
// Unique identifier, usually provided by the operating system, for identifying
|
||||
// a specific network interface. This value is used with UdpSocket to join
|
||||
// multicast groups, or to make multicast broadcasts. An implementation may
|
||||
// choose to make these values anything its UdpSocket implementation will
|
||||
// recognize.
|
||||
using NetworkInterfaceIndex = int64_t;
|
||||
enum : NetworkInterfaceIndex { kInvalidNetworkInterfaceIndex = -1 };
|
||||
|
||||
struct IPSubnet {
|
||||
IPAddress address;
|
||||
|
||||
// Prefix length of `address`, which is another way of specifying a subnet
|
||||
// mask. For example, 192.168.0.10/24 is a common representation of the
|
||||
// address 192.168.0.10 with a 24-bit prefix (this describes a range of IPv4
|
||||
// addresses from 192.168.0.0 through 192.168.0.255). Likewise, for IPv6
|
||||
// addresses such as 2001:db8::/96, the concept is the same (this specifies
|
||||
// the range of addresses having the same leading 96 bits).
|
||||
uint8_t prefix_length = 0;
|
||||
|
||||
IPSubnet();
|
||||
IPSubnet(IPAddress address, uint8_t prefix);
|
||||
~IPSubnet();
|
||||
};
|
||||
|
||||
struct InterfaceInfo {
|
||||
enum class Type : uint32_t { kEthernet = 0, kWifi, kLoopback, kOther };
|
||||
|
||||
// Interface index, typically as specified by the operating system,
|
||||
// identifying this interface on the host machine.
|
||||
NetworkInterfaceIndex index = kInvalidNetworkInterfaceIndex;
|
||||
|
||||
// MAC address of the interface. Typically 6 or 16 bytes. Empty if
|
||||
// unavailable.
|
||||
std::vector<uint8_t> hardware_address;
|
||||
|
||||
// Interface name (e.g. eth0) if available.
|
||||
std::string name;
|
||||
|
||||
// Hardware type of the interface.
|
||||
Type type = Type::kOther;
|
||||
|
||||
// All IP addresses associated with the interface.
|
||||
std::vector<IPSubnet> addresses;
|
||||
|
||||
// Returns an IPAddress of the given type associated with this network
|
||||
// interface, or the false IPAddress if the associated address family is not
|
||||
// supported on this interface.
|
||||
IPAddress GetIpAddressV4() const;
|
||||
IPAddress GetIpAddressV6() const;
|
||||
|
||||
// Returns true if `hardware_address` is non-zero.
|
||||
bool HasHardwareAddress() const;
|
||||
|
||||
InterfaceInfo();
|
||||
InterfaceInfo(NetworkInterfaceIndex index,
|
||||
const uint8_t hardware_address[6],
|
||||
std::string name,
|
||||
Type type,
|
||||
std::vector<IPSubnet> addresses);
|
||||
~InterfaceInfo();
|
||||
};
|
||||
|
||||
// Human-readable output (e.g., for logging).
|
||||
std::ostream& operator<<(std::ostream& out, InterfaceInfo::Type type);
|
||||
std::ostream& operator<<(std::ostream& out, const IPSubnet& subnet);
|
||||
std::ostream& operator<<(std::ostream& out, const InterfaceInfo& info);
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_BASE_INTERFACE_INFO_H_
|
||||
343
breadcast-caststream-sys/vendor/openscreen/platform/base/ip_address.cc
vendored
Normal file
343
breadcast-caststream-sys/vendor/openscreen/platform/base/ip_address.cc
vendored
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
// 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.
|
||||
|
||||
#include "platform/base/ip_address.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <charconv>
|
||||
#include <cinttypes>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if BUILDFLAG(IS_POSIX)
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
IPAddress::IPAddress(Version version, std::span<const uint8_t> bytes)
|
||||
: version_(version) {
|
||||
assert(bytes.size() >= size());
|
||||
std::copy_n(bytes.begin(), size(), bytes_.begin());
|
||||
}
|
||||
|
||||
bool IPAddress::operator==(const IPAddress& o) const {
|
||||
return version_ == o.version_ &&
|
||||
std::equal(bytes_.begin(), bytes_.begin() + size(),
|
||||
o.bytes_.begin()) &&
|
||||
scope_id_ == o.scope_id_;
|
||||
}
|
||||
|
||||
bool IPAddress::operator!=(const IPAddress& o) const {
|
||||
return !(*this == o);
|
||||
}
|
||||
|
||||
IPAddress::operator bool() const {
|
||||
return std::any_of(bytes_.begin(), bytes_.begin() + size(),
|
||||
[](uint8_t byte) { return byte; });
|
||||
}
|
||||
|
||||
void IPAddress::CopyTo(std::span<uint8_t> bytes) const {
|
||||
assert(bytes.size() >= size());
|
||||
std::copy_n(bytes_.begin(), size(), bytes.begin());
|
||||
}
|
||||
|
||||
bool IPAddress::IsLinkLocal() const {
|
||||
if (!IsV6()) {
|
||||
return false;
|
||||
}
|
||||
// Link-local addresses start with fe80::/10
|
||||
return (bytes_[0] == 0xfe) && ((bytes_[1] & 0xc0) == 0x80);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
ErrorOr<IPAddress> ParseV4(std::string_view s) {
|
||||
uint8_t octets[4];
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (i > 0) {
|
||||
if (s.empty() || s.front() != '.') {
|
||||
return Error::Code::kInvalidIPV4Address;
|
||||
}
|
||||
s.remove_prefix(1);
|
||||
}
|
||||
const auto result =
|
||||
std::from_chars(s.data(), s.data() + s.size(), octets[i]);
|
||||
if (result.ec != std::errc()) {
|
||||
return Error::Code::kInvalidIPV4Address;
|
||||
}
|
||||
s.remove_prefix(result.ptr - s.data());
|
||||
}
|
||||
|
||||
if (!s.empty()) {
|
||||
return Error::Code::kInvalidIPV4Address;
|
||||
}
|
||||
|
||||
return IPAddress(octets[0], octets[1], octets[2], octets[3]);
|
||||
}
|
||||
|
||||
// Returns the zero-expansion of a double-colon in `s` if `s` is a
|
||||
// well-formatted IPv6 address. If `s` is ill-formatted, returns *any* string
|
||||
// that is ill-formatted.
|
||||
std::string ExpandIPv6DoubleColon(std::string_view s) {
|
||||
constexpr std::string_view kDoubleColon = "::";
|
||||
const size_t double_colon_position = s.find(kDoubleColon);
|
||||
if (double_colon_position == std::string::npos) {
|
||||
return std::string(s); // Nothing to expand.
|
||||
}
|
||||
if (double_colon_position != s.rfind(kDoubleColon)) {
|
||||
return {}; // More than one occurrence of double colons is illegal.
|
||||
}
|
||||
|
||||
std::ostringstream expanded;
|
||||
const int num_single_colons = std::count(s.begin(), s.end(), ':') - 2;
|
||||
int num_zero_groups_to_insert = 8 - num_single_colons;
|
||||
if (double_colon_position != 0) {
|
||||
// abcd:0123:4567::f000:1
|
||||
// ^^^^^^^^^^^^^^^
|
||||
expanded << s.substr(0, double_colon_position + 1);
|
||||
--num_zero_groups_to_insert;
|
||||
}
|
||||
if (double_colon_position != (s.size() - 2)) {
|
||||
--num_zero_groups_to_insert;
|
||||
}
|
||||
while (--num_zero_groups_to_insert > 0) {
|
||||
expanded << "0:";
|
||||
}
|
||||
expanded << '0';
|
||||
if (double_colon_position != (s.size() - 2)) {
|
||||
// abcd:0123:4567::f000:1
|
||||
// ^^^^^^^
|
||||
expanded << s.substr(double_colon_position + 1);
|
||||
}
|
||||
return expanded.str();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ErrorOr<IPAddress> ParseV6(std::string_view s) {
|
||||
std::string_view address_part = s;
|
||||
uint32_t scope_id = 0;
|
||||
|
||||
// Handle link-local addresses with scope ID, e.g., fe80::1%eth0
|
||||
const size_t scope_pos = s.find('%');
|
||||
if (scope_pos != std::string::npos) {
|
||||
address_part = s.substr(0, scope_pos);
|
||||
std::string_view scope_name = s.substr(scope_pos + 1);
|
||||
#if BUILDFLAG(IS_POSIX)
|
||||
scope_id = if_nametoindex(std::string(scope_name).c_str());
|
||||
#endif
|
||||
if (scope_id == 0) {
|
||||
// If if_nametoindex failed or is not available, try parsing as a number.
|
||||
unsigned int parsed_id = 0;
|
||||
const auto result = std::from_chars(
|
||||
scope_name.data(), scope_name.data() + scope_name.size(), parsed_id);
|
||||
|
||||
if (result.ec == std::errc() &&
|
||||
result.ptr == scope_name.data() + scope_name.size() &&
|
||||
parsed_id > 0) {
|
||||
scope_id = parsed_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (scope_id == 0) {
|
||||
return Error::Code::kInvalidIPV6Address;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string scan_input = ExpandIPv6DoubleColon(address_part);
|
||||
std::string_view scan_view(scan_input);
|
||||
uint16_t hextets[8];
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
if (i > 0) {
|
||||
if (scan_view.empty() || scan_view.front() != ':') {
|
||||
return Error::Code::kInvalidIPV6Address;
|
||||
}
|
||||
scan_view.remove_prefix(1);
|
||||
}
|
||||
const auto result = std::from_chars(
|
||||
scan_view.data(), scan_view.data() + scan_view.size(), hextets[i], 16);
|
||||
if (result.ec != std::errc()) {
|
||||
return Error::Code::kInvalidIPV6Address;
|
||||
}
|
||||
scan_view.remove_prefix(result.ptr - scan_view.data());
|
||||
}
|
||||
|
||||
if (!scan_view.empty()) {
|
||||
return Error::Code::kInvalidIPV6Address;
|
||||
}
|
||||
|
||||
IPAddress address(hextets);
|
||||
if (scope_id != 0) {
|
||||
if (!address.IsLinkLocal()) {
|
||||
return Error::Code::kInvalidIPV6Address;
|
||||
}
|
||||
address.scope_id_ = scope_id;
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
// static
|
||||
ErrorOr<IPAddress> IPAddress::Parse(std::string_view s) {
|
||||
ErrorOr<IPAddress> v4 = ParseV4(s);
|
||||
|
||||
return v4 ? std::move(v4) : ParseV6(s);
|
||||
}
|
||||
|
||||
// static
|
||||
const IPEndpoint IPEndpoint::kAnyV4() {
|
||||
return IPEndpoint{};
|
||||
}
|
||||
|
||||
// static
|
||||
const IPEndpoint IPEndpoint::kAnyV6() {
|
||||
return IPEndpoint{IPAddress::kAnyV6(), 0};
|
||||
}
|
||||
|
||||
IPEndpoint::operator bool() const {
|
||||
return address || port;
|
||||
}
|
||||
|
||||
// static
|
||||
ErrorOr<IPEndpoint> IPEndpoint::Parse(std::string_view s) {
|
||||
// Look for the colon that separates the IP address from the port number. Note
|
||||
// that this check also guards against the case where `s` is the empty string.
|
||||
const auto colon_pos = s.rfind(':');
|
||||
if (colon_pos == std::string::npos) {
|
||||
return Error(Error::Code::kParseError, "missing colon separator");
|
||||
}
|
||||
// The colon cannot be the first nor the last character in `s` because that
|
||||
// would mean there is no address part or port part.
|
||||
if (colon_pos == 0) {
|
||||
return Error(Error::Code::kParseError, "missing address before colon");
|
||||
}
|
||||
if (colon_pos == (s.size() - 1)) {
|
||||
return Error(Error::Code::kParseError, "missing port after colon");
|
||||
}
|
||||
|
||||
ErrorOr<IPAddress> address(Error::Code::kParseError);
|
||||
if (s[0] == '[' && s[colon_pos - 1] == ']') {
|
||||
// [abcd:beef:1:1::2600]:8080
|
||||
// ^^^^^^^^^^^^^^^^^^^^^
|
||||
address = ParseV6(s.substr(1, colon_pos - 2));
|
||||
} else {
|
||||
// 127.0.0.1:22
|
||||
// ^^^^^^^^^
|
||||
address = ParseV4(s.substr(0, colon_pos));
|
||||
}
|
||||
if (address.is_error()) {
|
||||
return Error(Error::Code::kParseError, "invalid address part");
|
||||
}
|
||||
|
||||
const std::string_view port_part = s.substr(colon_pos + 1);
|
||||
int port;
|
||||
const auto result = std::from_chars(
|
||||
port_part.data(), port_part.data() + port_part.size(), port);
|
||||
if (result.ec != std::errc() ||
|
||||
result.ptr != port_part.data() + port_part.size() || port < 0 ||
|
||||
port > std::numeric_limits<uint16_t>::max()) {
|
||||
return Error(Error::Code::kParseError, "invalid port part");
|
||||
}
|
||||
|
||||
return IPEndpoint{address.value(), static_cast<uint16_t>(port)};
|
||||
}
|
||||
|
||||
bool operator==(const IPEndpoint& a, const IPEndpoint& b) {
|
||||
return (a.address == b.address) && (a.port == b.port);
|
||||
}
|
||||
|
||||
bool operator!=(const IPEndpoint& a, const IPEndpoint& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
bool IPAddress::operator<(const IPAddress& other) const {
|
||||
if (version() != other.version()) {
|
||||
return version() < other.version();
|
||||
}
|
||||
|
||||
if (IsV4()) {
|
||||
return memcmp(bytes_.data(), other.bytes_.data(), 4) < 0;
|
||||
} else {
|
||||
const int cmp = memcmp(bytes_.data(), other.bytes_.data(), 16);
|
||||
if (cmp != 0) {
|
||||
return cmp < 0;
|
||||
}
|
||||
return scope_id_ < other.scope_id_;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator<(const IPEndpoint& a, const IPEndpoint& b) {
|
||||
if (a.address != b.address) {
|
||||
return a.address < b.address;
|
||||
}
|
||||
|
||||
return a.port < b.port;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const IPAddress& address) {
|
||||
char separator;
|
||||
size_t values_per_separator;
|
||||
int value_width;
|
||||
if (address.IsV4()) {
|
||||
out << std::dec;
|
||||
separator = '.';
|
||||
values_per_separator = 1;
|
||||
value_width = 0;
|
||||
} else if (address.IsV6()) {
|
||||
out << std::hex << std::setfill('0') << std::right;
|
||||
separator = ':';
|
||||
values_per_separator = 2;
|
||||
value_width = 2;
|
||||
}
|
||||
std::span<const uint8_t> bytes = address.bytes();
|
||||
for (size_t i = 0; i < bytes.size(); ++i) {
|
||||
if (i > 0 && (i % values_per_separator == 0)) {
|
||||
out << separator;
|
||||
}
|
||||
out << std::setw(value_width) << static_cast<int>(bytes[i]);
|
||||
}
|
||||
if (address.IsLinkLocal() && address.GetScopeId() != 0) {
|
||||
#if BUILDFLAG(IS_POSIX)
|
||||
char ifname[IF_NAMESIZE];
|
||||
if (if_indextoname(address.GetScopeId(), ifname)) {
|
||||
out << '%' << ifname;
|
||||
} else {
|
||||
out << '%' << address.GetScopeId();
|
||||
}
|
||||
#else
|
||||
out << '%' << address.GetScopeId();
|
||||
#endif
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const IPEndpoint& endpoint) {
|
||||
if (endpoint.address.IsV6()) {
|
||||
out << '[';
|
||||
}
|
||||
out << endpoint.address;
|
||||
if (endpoint.address.IsV6()) {
|
||||
out << ']';
|
||||
}
|
||||
return out << ':' << std::dec << static_cast<int>(endpoint.port);
|
||||
}
|
||||
|
||||
std::string IPEndpoint::ToString() const {
|
||||
std::ostringstream name;
|
||||
name << *this;
|
||||
return name.str();
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
209
breadcast-caststream-sys/vendor/openscreen/platform/base/ip_address.h
vendored
Normal file
209
breadcast-caststream-sys/vendor/openscreen/platform/base/ip_address.h
vendored
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
// 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_BASE_IP_ADDRESS_H_
|
||||
#define PLATFORM_BASE_IP_ADDRESS_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
#include "platform/base/error.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
class IPAddress {
|
||||
public:
|
||||
enum class Version {
|
||||
kV4,
|
||||
kV6,
|
||||
};
|
||||
|
||||
static constexpr IPAddress kAnyV4() { return IPAddress{0, 0, 0, 0}; }
|
||||
static constexpr IPAddress kAnyV6() {
|
||||
return IPAddress{0, 0, 0, 0, 0, 0, 0, 0};
|
||||
}
|
||||
static constexpr IPAddress kV4LoopbackAddress() {
|
||||
return IPAddress{127, 0, 0, 1};
|
||||
}
|
||||
static constexpr IPAddress kV6LoopbackAddress() {
|
||||
return IPAddress{0, 0, 0, 0, 0, 0, 0, 1};
|
||||
}
|
||||
static constexpr size_t kV4Size = 4;
|
||||
static constexpr size_t kV6Size = 16;
|
||||
|
||||
constexpr IPAddress() : version_(Version::kV4), bytes_({}) {}
|
||||
|
||||
// `bytes` contains 4 octets for IPv4, or 8 hextets (16 bytes of big-endian
|
||||
// shorts) for IPv6.
|
||||
// TODO(jophba): delete once usage is removed in Chromium's network_util.cc.
|
||||
inline IPAddress(Version version, const uint8_t* bytes) : version_(version) {
|
||||
std::copy_n(bytes, size(), bytes_.begin());
|
||||
}
|
||||
|
||||
IPAddress(Version version, std::span<const uint8_t> bytes);
|
||||
|
||||
// IPv4 constructors (IPAddress from 4 octets).
|
||||
explicit constexpr IPAddress(std::span<const uint8_t, 4> bytes)
|
||||
: version_(Version::kV4),
|
||||
bytes_{{bytes[0], bytes[1], bytes[2], bytes[3]}} {}
|
||||
|
||||
constexpr IPAddress(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4)
|
||||
: version_(Version::kV4), bytes_{{b1, b2, b3, b4}} {}
|
||||
|
||||
// IPv6 constructors (IPAddress from 8 hextets).
|
||||
explicit constexpr IPAddress(std::span<const uint16_t, 8> hextets)
|
||||
: IPAddress(hextets[0],
|
||||
hextets[1],
|
||||
hextets[2],
|
||||
hextets[3],
|
||||
hextets[4],
|
||||
hextets[5],
|
||||
hextets[6],
|
||||
hextets[7]) {}
|
||||
|
||||
constexpr IPAddress(uint16_t h0,
|
||||
uint16_t h1,
|
||||
uint16_t h2,
|
||||
uint16_t h3,
|
||||
uint16_t h4,
|
||||
uint16_t h5,
|
||||
uint16_t h6,
|
||||
uint16_t h7)
|
||||
: version_(Version::kV6),
|
||||
bytes_{{
|
||||
static_cast<uint8_t>(h0 >> 8),
|
||||
static_cast<uint8_t>(h0),
|
||||
static_cast<uint8_t>(h1 >> 8),
|
||||
static_cast<uint8_t>(h1),
|
||||
static_cast<uint8_t>(h2 >> 8),
|
||||
static_cast<uint8_t>(h2),
|
||||
static_cast<uint8_t>(h3 >> 8),
|
||||
static_cast<uint8_t>(h3),
|
||||
static_cast<uint8_t>(h4 >> 8),
|
||||
static_cast<uint8_t>(h4),
|
||||
static_cast<uint8_t>(h5 >> 8),
|
||||
static_cast<uint8_t>(h5),
|
||||
static_cast<uint8_t>(h6 >> 8),
|
||||
static_cast<uint8_t>(h6),
|
||||
static_cast<uint8_t>(h7 >> 8),
|
||||
static_cast<uint8_t>(h7),
|
||||
}} {}
|
||||
|
||||
// IPv6 constructor with scope ID.
|
||||
explicit constexpr IPAddress(std::span<const uint8_t, 16> bytes,
|
||||
uint32_t scope_id)
|
||||
: version_(Version::kV6), scope_id_(scope_id) {
|
||||
for (size_t i = 0; i < 16; ++i) {
|
||||
bytes_[i] = bytes[i];
|
||||
}
|
||||
}
|
||||
|
||||
constexpr IPAddress(const IPAddress& o) noexcept = default;
|
||||
constexpr IPAddress(IPAddress&& o) noexcept = default;
|
||||
~IPAddress() = default;
|
||||
|
||||
constexpr IPAddress& operator=(const IPAddress& o) noexcept = default;
|
||||
constexpr IPAddress& operator=(IPAddress&& o) noexcept = default;
|
||||
|
||||
bool operator==(const IPAddress& o) const;
|
||||
bool operator!=(const IPAddress& o) const;
|
||||
|
||||
// IP address comparison rules are based on the following two principles:
|
||||
// 1. newer versions are greater, e.g. IPv6 > IPv4
|
||||
// 2. higher numerical values are greater, e.g. 192.168.0.1 > 10.0.0.1
|
||||
bool operator<(const IPAddress& other) const;
|
||||
bool operator>(const IPAddress& other) const { return other < *this; }
|
||||
bool operator<=(const IPAddress& other) const { return !(other < *this); }
|
||||
bool operator>=(const IPAddress& other) const { return !(*this < other); }
|
||||
explicit operator bool() const;
|
||||
|
||||
Version version() const { return version_; }
|
||||
size_t size() const { return (version_ == Version::kV4) ? kV4Size : kV6Size; }
|
||||
bool IsV4() const { return version_ == Version::kV4; }
|
||||
bool IsV6() const { return version_ == Version::kV6; }
|
||||
|
||||
// Returns true if the address is an IPv6 link-local address.
|
||||
bool IsLinkLocal() const;
|
||||
|
||||
// Returns the scope ID for link-local IPv6 addresses. Returns 0 for
|
||||
// non-link-local addresses.
|
||||
uint32_t GetScopeId() const { return scope_id_; }
|
||||
|
||||
// These methods assume `x` is the appropriate size, but due to various
|
||||
// callers' casting needs we can't check them like the constructors above.
|
||||
// Callers should instead make any necessary checks themselves.
|
||||
void CopyTo(std::span<uint8_t> bytes) const;
|
||||
|
||||
// TODO(jophba): delete once usage is removed in Chromium's network_util.cc.
|
||||
inline void CopyToV4(uint8_t* x) const { CopyTo(std::span(x, kV4Size)); }
|
||||
inline void CopyToV6(uint8_t* x) const { CopyTo(std::span(x, kV6Size)); }
|
||||
|
||||
// In some instances, we want direct access to the underlying byte storage,
|
||||
// in order to avoid making multiple copies.
|
||||
std::span<const uint8_t> bytes() const {
|
||||
return {bytes_.data(), (version_ == Version::kV4) ? kV4Size : kV6Size};
|
||||
}
|
||||
|
||||
// Parses a text representation of an IPv4 address (e.g. "192.168.0.1") or an
|
||||
// IPv6 address (e.g. "abcd::1234").
|
||||
static ErrorOr<IPAddress> Parse(std::string_view s);
|
||||
|
||||
private:
|
||||
friend ErrorOr<IPAddress> ParseV6(std::string_view s);
|
||||
|
||||
Version version_;
|
||||
std::array<uint8_t, 16> bytes_;
|
||||
uint32_t scope_id_ = 0;
|
||||
};
|
||||
|
||||
struct IPEndpoint {
|
||||
public:
|
||||
IPAddress address;
|
||||
uint16_t port = 0;
|
||||
|
||||
// Used with various socket types to indicate "any" address.
|
||||
static const IPEndpoint kAnyV4();
|
||||
static const IPEndpoint kAnyV6();
|
||||
explicit operator bool() const;
|
||||
|
||||
// Parses a text representation of an IPv4/IPv6 address and port (e.g.
|
||||
// "192.168.0.1:8080" or "[abcd::1234]:8080").
|
||||
static ErrorOr<IPEndpoint> Parse(std::string_view s);
|
||||
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
bool operator==(const IPEndpoint& a, const IPEndpoint& b);
|
||||
bool operator!=(const IPEndpoint& a, const IPEndpoint& b);
|
||||
|
||||
bool operator<(const IPEndpoint& a, const IPEndpoint& b);
|
||||
inline bool operator>(const IPEndpoint& a, const IPEndpoint& b) {
|
||||
return b < a;
|
||||
}
|
||||
inline bool operator<=(const IPEndpoint& a, const IPEndpoint& b) {
|
||||
return !(a > b);
|
||||
}
|
||||
inline bool operator>=(const IPEndpoint& a, const IPEndpoint& b) {
|
||||
return !(a < b);
|
||||
}
|
||||
|
||||
// Outputs a string of the form:
|
||||
// 123.234.34.56
|
||||
// or fe80:0000:0000:0000:1234:5678:9abc:def0
|
||||
std::ostream& operator<<(std::ostream& out, const IPAddress& address);
|
||||
|
||||
// Outputs a string of the form:
|
||||
// 123.234.34.56:443
|
||||
// or [fe80:0000:0000:0000:1234:5678:9abc:def0]:8080
|
||||
std::ostream& operator<<(std::ostream& out, const IPEndpoint& endpoint);
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_BASE_IP_ADDRESS_H_
|
||||
54
breadcast-caststream-sys/vendor/openscreen/platform/base/location.cc
vendored
Normal file
54
breadcast-caststream-sys/vendor/openscreen/platform/base/location.cc
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2012 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/base/location.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "platform/base/compiler_specific.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
Location::Location() = default;
|
||||
Location::Location(const Location&) = default;
|
||||
Location::Location(Location&&) noexcept = default;
|
||||
|
||||
Location::Location(const void* program_counter)
|
||||
: program_counter_(program_counter) {}
|
||||
|
||||
Location& Location::operator=(const Location& other) = default;
|
||||
Location& Location::operator=(Location&& other) = default;
|
||||
|
||||
std::string Location::ToString() const {
|
||||
if (program_counter_ == nullptr) {
|
||||
return "pc:nullptr";
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << "pc:" << program_counter_;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define RETURN_ADDRESS() \
|
||||
__builtin_extract_return_addr(__builtin_return_address(0))
|
||||
#else
|
||||
#define RETURN_ADDRESS() nullptr
|
||||
#endif
|
||||
|
||||
// static
|
||||
OSP_NOINLINE Location Location::CreateFromHere() {
|
||||
return Location(RETURN_ADDRESS());
|
||||
}
|
||||
|
||||
// static
|
||||
OSP_NOINLINE const void* GetProgramCounter() {
|
||||
return RETURN_ADDRESS();
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const Location& location) {
|
||||
return out << location.ToString();
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
65
breadcast-caststream-sys/vendor/openscreen/platform/base/location.h
vendored
Normal file
65
breadcast-caststream-sys/vendor/openscreen/platform/base/location.h
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) 2012 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_BASE_LOCATION_H_
|
||||
#define PLATFORM_BASE_LOCATION_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
// NOTE: lifted from Chromium's base Location implementation, forked to work
|
||||
// with our base library.
|
||||
|
||||
// Instances of the location class include basic information about a position
|
||||
// in program source, for example the place where an object was constructed.
|
||||
class Location {
|
||||
public:
|
||||
Location();
|
||||
Location(const Location&);
|
||||
Location(Location&&) noexcept;
|
||||
|
||||
// Initializes the program counter
|
||||
explicit Location(const void* program_counter);
|
||||
|
||||
Location& operator=(const Location& other);
|
||||
Location& operator=(Location&& other);
|
||||
|
||||
// Comparator for hash map insertion. The program counter should uniquely
|
||||
// identify a location.
|
||||
bool operator==(const Location& other) const {
|
||||
return program_counter_ == other.program_counter_;
|
||||
}
|
||||
|
||||
// The address of the code generating this Location object. Should always be
|
||||
// valid except for default initialized Location objects, which will be
|
||||
// nullptr.
|
||||
const void* program_counter() const { return program_counter_; }
|
||||
|
||||
// Converts to the most user-readable form possible. This will return
|
||||
// "pc:<hex address>".
|
||||
std::string ToString() const;
|
||||
|
||||
static Location CreateFromHere();
|
||||
|
||||
private:
|
||||
#if defined(__clang__)
|
||||
[[clang::annotate("raw_ptr_exclusion")]]
|
||||
#endif
|
||||
const void* program_counter_ = nullptr;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const Location& location);
|
||||
|
||||
const void* GetProgramCounter();
|
||||
|
||||
#define CURRENT_LOCATION ::openscreen::Location::CreateFromHere()
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_BASE_LOCATION_H_
|
||||
39
breadcast-caststream-sys/vendor/openscreen/platform/base/span.h
vendored
Normal file
39
breadcast-caststream-sys/vendor/openscreen/platform/base/span.h
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// 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_BASE_SPAN_H_
|
||||
#define PLATFORM_BASE_SPAN_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "platform/base/type_util.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
// In Open Screen code, use these aliases for the most common types of Spans.
|
||||
// TODO(crbug.com/364687926): rename to byte_view.h and remove Span alias.
|
||||
using ByteView = std::span<const uint8_t>;
|
||||
using ByteBuffer = std::span<uint8_t>;
|
||||
template <typename T>
|
||||
using Span = std::span<T>;
|
||||
|
||||
inline ByteView ByteViewFromString(std::string_view str) {
|
||||
return ByteView(reinterpret_cast<const uint8_t*>(str.data()), str.size());
|
||||
}
|
||||
|
||||
inline std::string ByteViewToString(ByteView bytes) {
|
||||
return std::string(reinterpret_cast<const char*>(bytes.data()), bytes.size());
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_BASE_SPAN_H_
|
||||
20
breadcast-caststream-sys/vendor/openscreen/platform/base/tls_connect_options.h
vendored
Normal file
20
breadcast-caststream-sys/vendor/openscreen/platform/base/tls_connect_options.h
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// 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_BASE_TLS_CONNECT_OPTIONS_H_
|
||||
#define PLATFORM_BASE_TLS_CONNECT_OPTIONS_H_
|
||||
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
struct TlsConnectOptions {
|
||||
// This option allows TLS connections to devices without
|
||||
// a known hostname, and will typically be “true” for cast code.
|
||||
// For example, the cast_socket always sets true.
|
||||
bool unsafely_skip_certificate_validation;
|
||||
};
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_BASE_TLS_CONNECT_OPTIONS_H_
|
||||
22
breadcast-caststream-sys/vendor/openscreen/platform/base/tls_credentials.cc
vendored
Normal file
22
breadcast-caststream-sys/vendor/openscreen/platform/base/tls_credentials.cc
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// 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/base/tls_credentials.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
TlsCredentials::TlsCredentials() = default;
|
||||
|
||||
TlsCredentials::TlsCredentials(std::vector<uint8_t> der_rsa_private_key,
|
||||
std::vector<uint8_t> der_rsa_public_key,
|
||||
std::vector<uint8_t> der_x509_cert)
|
||||
: der_rsa_private_key(std::move(der_rsa_private_key)),
|
||||
der_rsa_public_key(std::move(der_rsa_public_key)),
|
||||
der_x509_cert(std::move(der_x509_cert)) {}
|
||||
|
||||
TlsCredentials::~TlsCredentials() = default;
|
||||
|
||||
} // namespace openscreen
|
||||
33
breadcast-caststream-sys/vendor/openscreen/platform/base/tls_credentials.h
vendored
Normal file
33
breadcast-caststream-sys/vendor/openscreen/platform/base/tls_credentials.h
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
// 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_BASE_TLS_CREDENTIALS_H_
|
||||
#define PLATFORM_BASE_TLS_CREDENTIALS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
struct TlsCredentials {
|
||||
TlsCredentials();
|
||||
TlsCredentials(std::vector<uint8_t> der_rsa_private_key,
|
||||
std::vector<uint8_t> der_rsa_public_key,
|
||||
std::vector<uint8_t> der_x509_cert);
|
||||
~TlsCredentials();
|
||||
|
||||
// DER-encoded RSA private key.
|
||||
std::vector<uint8_t> der_rsa_private_key;
|
||||
|
||||
// DER-encoded RSA public key.
|
||||
std::vector<uint8_t> der_rsa_public_key;
|
||||
|
||||
// DER-encoded X509 Certificate that is based on the above keys.
|
||||
std::vector<uint8_t> der_x509_cert;
|
||||
};
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_BASE_TLS_CREDENTIALS_H_
|
||||
19
breadcast-caststream-sys/vendor/openscreen/platform/base/tls_listen_options.h
vendored
Normal file
19
breadcast-caststream-sys/vendor/openscreen/platform/base/tls_listen_options.h
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// 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_BASE_TLS_LISTEN_OPTIONS_H_
|
||||
#define PLATFORM_BASE_TLS_LISTEN_OPTIONS_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
struct TlsListenOptions {
|
||||
uint32_t backlog_size;
|
||||
};
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_BASE_TLS_LISTEN_OPTIONS_H_
|
||||
72
breadcast-caststream-sys/vendor/openscreen/platform/base/trace_logging_activation.cc
vendored
Normal file
72
breadcast-caststream-sys/vendor/openscreen/platform/base/trace_logging_activation.cc
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// 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/base/trace_logging_activation.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <thread>
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
namespace {
|
||||
|
||||
// If tracing is active, this is a valid pointer to an object that implements
|
||||
// the TraceLoggingPlatform interface. If tracing is not active, this is
|
||||
// nullptr.
|
||||
std::atomic<TraceLoggingPlatform*> g_current_destination{};
|
||||
|
||||
// The count of threads currently calling into the current TraceLoggingPlatform.
|
||||
std::atomic<int> g_use_count{};
|
||||
|
||||
inline TraceLoggingPlatform* PinCurrentDestination() {
|
||||
// NOTE: It's important to increment the global use count *before* loading the
|
||||
// pointer, to ensure the referent is pinned-down (i.e., any thread executing
|
||||
// StopTracing() stays blocked) until CurrentTracingDestination's destructor
|
||||
// calls UnpinCurrentDestination().
|
||||
g_use_count.fetch_add(1);
|
||||
return g_current_destination.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline void UnpinCurrentDestination() {
|
||||
g_use_count.fetch_sub(1);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void StartTracing(TraceLoggingPlatform* destination) {
|
||||
assert(destination);
|
||||
auto* const old_destination = g_current_destination.exchange(destination);
|
||||
(void)old_destination; // Prevent "unused variable" compiler warnings.
|
||||
assert(old_destination == nullptr || old_destination == destination);
|
||||
}
|
||||
|
||||
void StopTracing() {
|
||||
auto* const old_destination = g_current_destination.exchange(nullptr);
|
||||
if (!old_destination) {
|
||||
return; // Already stopped.
|
||||
}
|
||||
|
||||
// Block the current thread until the global use count goes to zero. At that
|
||||
// point, there can no longer be any dangling references. Theoretically, this
|
||||
// loop may never terminate; but in practice, that should never happen. If it
|
||||
// did happen, that would mean one or more CPU cores are continuously spending
|
||||
// most of their time executing the TraceLoggingPlatform methods, yet those
|
||||
// methods are supposed to be super-cheap and take near-zero time to execute!
|
||||
[[maybe_unused]] int iters = 0;
|
||||
while (g_use_count.load(std::memory_order_relaxed) != 0) {
|
||||
assert(iters < 1024);
|
||||
std::this_thread::yield();
|
||||
++iters;
|
||||
}
|
||||
}
|
||||
|
||||
CurrentTracingDestination::CurrentTracingDestination()
|
||||
: destination_(PinCurrentDestination()) {}
|
||||
|
||||
CurrentTracingDestination::~CurrentTracingDestination() {
|
||||
UnpinCurrentDestination();
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
58
breadcast-caststream-sys/vendor/openscreen/platform/base/trace_logging_activation.h
vendored
Normal file
58
breadcast-caststream-sys/vendor/openscreen/platform/base/trace_logging_activation.h
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
// 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_BASE_TRACE_LOGGING_ACTIVATION_H_
|
||||
#define PLATFORM_BASE_TRACE_LOGGING_ACTIVATION_H_
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
class TraceLoggingPlatform;
|
||||
|
||||
// Start or Stop trace logging. It is illegal to call StartTracing() a second
|
||||
// time without having called StopTracing() to stop the prior tracing session.
|
||||
//
|
||||
// Note that StopTracing() may block until all threads have returned from any
|
||||
// in-progress calls into the TraceLoggingPlatform's methods.
|
||||
void StartTracing(TraceLoggingPlatform* destination);
|
||||
void StopTracing();
|
||||
|
||||
// An immutable, non-copyable and non-movable smart pointer that references the
|
||||
// current trace logging destination. If tracing was active when this class was
|
||||
// intantiated, the pointer is valid for the life of the instance, and can be
|
||||
// used to directly invoke the methods of the TraceLoggingPlatform API. If
|
||||
// tracing was not active when this class was intantiated, the pointer is null
|
||||
// for the life of the instance and must not be dereferenced.
|
||||
//
|
||||
// An instance should be short-lived, as a platform's call to StopTracing() will
|
||||
// be blocked until there are no instances remaining.
|
||||
//
|
||||
// NOTE: This is generally not used directly, but instead via the
|
||||
// util/trace_logging macros.
|
||||
class CurrentTracingDestination {
|
||||
public:
|
||||
CurrentTracingDestination();
|
||||
~CurrentTracingDestination();
|
||||
|
||||
explicit operator bool() const noexcept { return !!destination_; }
|
||||
TraceLoggingPlatform* operator->() const noexcept { return destination_; }
|
||||
|
||||
private:
|
||||
CurrentTracingDestination(const CurrentTracingDestination&) = delete;
|
||||
CurrentTracingDestination(CurrentTracingDestination&&) noexcept = delete;
|
||||
CurrentTracingDestination& operator=(const CurrentTracingDestination&) =
|
||||
delete;
|
||||
CurrentTracingDestination& operator=(CurrentTracingDestination&&) noexcept =
|
||||
delete;
|
||||
|
||||
// The destination at the time this class was constructed, and is valid for
|
||||
// the lifetime of this class. This is nullptr if tracing was inactive.
|
||||
#if defined(__clang__)
|
||||
[[clang::annotate("raw_ptr_exclusion")]]
|
||||
#endif
|
||||
TraceLoggingPlatform* const destination_;
|
||||
};
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_BASE_TRACE_LOGGING_ACTIVATION_H_
|
||||
62
breadcast-caststream-sys/vendor/openscreen/platform/base/trace_logging_types.cc
vendored
Normal file
62
breadcast-caststream-sys/vendor/openscreen/platform/base/trace_logging_types.cc
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// 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/base/trace_logging_types.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
std::string TraceIdHierarchy::ToString() const {
|
||||
std::stringstream ss;
|
||||
ss << "[" << std::hex << (HasRoot() ? root : 0) << ":"
|
||||
<< (HasParent() ? parent : 0) << ":" << (HasCurrent() ? current : 0)
|
||||
<< std::dec << "]";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const TraceIdHierarchy& ids) {
|
||||
return out << ids.ToString();
|
||||
}
|
||||
|
||||
bool operator==(const TraceIdHierarchy& lhs, const TraceIdHierarchy& rhs) {
|
||||
return lhs.current == rhs.current && lhs.parent == rhs.parent &&
|
||||
lhs.root == rhs.root;
|
||||
}
|
||||
|
||||
bool operator!=(const TraceIdHierarchy& lhs, const TraceIdHierarchy& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
const char* ToString(TraceCategory category) {
|
||||
switch (category) {
|
||||
case TraceCategory::kAny:
|
||||
return "any";
|
||||
case TraceCategory::kMdns:
|
||||
return "mdns";
|
||||
case TraceCategory::kQuic:
|
||||
return "quic";
|
||||
case TraceCategory::kSsl:
|
||||
return "ssl";
|
||||
case TraceCategory::kPresentation:
|
||||
return "presentation";
|
||||
case TraceCategory::kStandaloneReceiver:
|
||||
return "standalone_receiver";
|
||||
case TraceCategory::kDiscovery:
|
||||
return "discovery";
|
||||
case TraceCategory::kStandaloneSender:
|
||||
return "standalone_sender";
|
||||
case TraceCategory::kReceiver:
|
||||
return "receiver";
|
||||
case TraceCategory::kSender:
|
||||
return "sender";
|
||||
}
|
||||
|
||||
// OSP_NOTREACHED is not available in platform/base.
|
||||
std::abort();
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
71
breadcast-caststream-sys/vendor/openscreen/platform/base/trace_logging_types.h
vendored
Normal file
71
breadcast-caststream-sys/vendor/openscreen/platform/base/trace_logging_types.h
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// 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_BASE_TRACE_LOGGING_TYPES_H_
|
||||
#define PLATFORM_BASE_TRACE_LOGGING_TYPES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
// Define TraceId type here since other TraceLogging files import it.
|
||||
using TraceId = uint64_t;
|
||||
|
||||
// kEmptyTraceId is the Trace ID when tracing at a global level, not inside any
|
||||
// tracing block - ie this will be the parent ID for a top level tracing block.
|
||||
inline constexpr TraceId kEmptyTraceId = 0x0;
|
||||
|
||||
// kUnsetTraceId is the Trace ID passed in to the tracing library when no user-
|
||||
// specified value is desired.
|
||||
inline constexpr TraceId kUnsetTraceId = std::numeric_limits<TraceId>::max();
|
||||
|
||||
// A class to represent the current TraceId Hierarchy and for the user to
|
||||
// pass around as needed.
|
||||
struct TraceIdHierarchy {
|
||||
TraceId current = kUnsetTraceId;
|
||||
TraceId parent = kUnsetTraceId;
|
||||
TraceId root = kUnsetTraceId;
|
||||
|
||||
static constexpr TraceIdHierarchy Empty() {
|
||||
return {kEmptyTraceId, kEmptyTraceId, kEmptyTraceId};
|
||||
}
|
||||
|
||||
bool HasCurrent() const { return current != kUnsetTraceId; }
|
||||
bool HasParent() const { return parent != kUnsetTraceId; }
|
||||
bool HasRoot() const { return root != kUnsetTraceId; }
|
||||
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const TraceIdHierarchy& ids);
|
||||
|
||||
bool operator==(const TraceIdHierarchy& lhs, const TraceIdHierarchy& rhs);
|
||||
|
||||
bool operator!=(const TraceIdHierarchy& lhs, const TraceIdHierarchy& rhs);
|
||||
|
||||
// Supported trace category
|
||||
enum class TraceCategory : int {
|
||||
kAny,
|
||||
kMdns,
|
||||
kQuic,
|
||||
kSsl,
|
||||
kPresentation,
|
||||
kStandaloneReceiver,
|
||||
kDiscovery,
|
||||
kStandaloneSender,
|
||||
kReceiver,
|
||||
kSender
|
||||
};
|
||||
|
||||
const char* ToString(TraceCategory category);
|
||||
|
||||
enum class FlowType { kFlowBegin, kFlowStep, kFlowEnd };
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_BASE_TRACE_LOGGING_TYPES_H_
|
||||
55
breadcast-caststream-sys/vendor/openscreen/platform/base/trivial_clock_traits.cc
vendored
Normal file
55
breadcast-caststream-sys/vendor/openscreen/platform/base/trivial_clock_traits.cc
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// 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/base/trivial_clock_traits.h"
|
||||
|
||||
namespace openscreen {
|
||||
namespace {
|
||||
|
||||
constexpr char kMicrosecondsUnits[] = " µs";
|
||||
constexpr char kMicrosecondsTicksUnits[] = " µs-ticks";
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string ToString(const TrivialClockTraits::duration& d) {
|
||||
return std::to_string(d.count()) + kMicrosecondsUnits;
|
||||
}
|
||||
|
||||
std::string ToString(const TrivialClockTraits::time_point& tp) {
|
||||
return std::to_string(tp.time_since_epoch().count()) +
|
||||
kMicrosecondsTicksUnits;
|
||||
}
|
||||
|
||||
namespace clock_operators {
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const TrivialClockTraits::duration& d) {
|
||||
return os << d.count() << kMicrosecondsUnits;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const TrivialClockTraits::time_point& tp) {
|
||||
return os << tp.time_since_epoch().count() << kMicrosecondsTicksUnits;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const std::chrono::hours& hrs) {
|
||||
return (os << hrs.count() << " hours");
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const std::chrono::minutes& mins) {
|
||||
return (os << mins.count() << " minutes");
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const std::chrono::seconds& secs) {
|
||||
return (os << secs.count() << " seconds");
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const std::chrono::milliseconds& millis) {
|
||||
return (os << millis.count() << " ms");
|
||||
}
|
||||
|
||||
} // namespace clock_operators
|
||||
|
||||
} // namespace openscreen
|
||||
98
breadcast-caststream-sys/vendor/openscreen/platform/base/trivial_clock_traits.h
vendored
Normal file
98
breadcast-caststream-sys/vendor/openscreen/platform/base/trivial_clock_traits.h
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
// 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_BASE_TRIVIAL_CLOCK_TRAITS_H_
|
||||
#define PLATFORM_BASE_TRIVIAL_CLOCK_TRAITS_H_
|
||||
|
||||
#include <chrono>
|
||||
#include <ostream>
|
||||
#include <ratio>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
// The Open Screen monotonic clock traits description, providing all the C++14
|
||||
// requirements of a TrivialClock, for use with STL <chrono>.
|
||||
class TrivialClockTraits {
|
||||
public:
|
||||
// TrivialClock named requirements: std::chrono templates can/may use these.
|
||||
// NOTE: unless you are specifically integrating with the clock, you probably
|
||||
// don't want to use these types, and instead should reference the std::chrono
|
||||
// types directly.
|
||||
using duration = std::chrono::microseconds;
|
||||
using rep = duration::rep;
|
||||
using period = duration::period;
|
||||
using time_point = std::chrono::time_point<TrivialClockTraits, duration>;
|
||||
static constexpr bool is_steady = true;
|
||||
|
||||
// Helper method for named requirements.
|
||||
template <typename D>
|
||||
static constexpr duration to_duration(D d) {
|
||||
return std::chrono::duration_cast<duration>(d);
|
||||
}
|
||||
|
||||
// Time point values from the clock use microsecond precision, as a reasonably
|
||||
// high-resolution clock is required. The time source must tick forward at
|
||||
// least 10000 times per second.
|
||||
using kRequiredResolution = std::ratio<1, 10000>;
|
||||
|
||||
// In <chrono>, a clock type is just some type properties plus a static now()
|
||||
// function. So, there's nothing to instantiate here.
|
||||
TrivialClockTraits() = delete;
|
||||
~TrivialClockTraits() = delete;
|
||||
|
||||
// "Trivially copyable" is necessary for using the time types in
|
||||
// std::atomic<>.
|
||||
static_assert(std::is_trivially_copyable<duration>(),
|
||||
"duration is not trivially copyable");
|
||||
static_assert(std::is_trivially_copyable<time_point>(),
|
||||
"time_point is not trivially copyable");
|
||||
};
|
||||
|
||||
// Convenience type definition, for injecting time sources into classes (e.g.,
|
||||
// &Clock::now versus something else for testing).
|
||||
using ClockNowFunctionPtr = TrivialClockTraits::time_point (*)();
|
||||
|
||||
// Convenience for serializing to string, e.g. for tracing. Outputs a string of
|
||||
// the form "123µs".
|
||||
std::string ToString(const TrivialClockTraits::duration& d);
|
||||
|
||||
// Convenience for serializing to string, e.g. for tracing. Outputs a string of
|
||||
// the form "123µs-ticks".
|
||||
std::string ToString(const TrivialClockTraits::time_point& tp);
|
||||
|
||||
// Explicit namespace for inclusion of custom time-related operator<<
|
||||
// implementations. These operators may be included in a file for use by adding:
|
||||
// using clock_operators::operator<<;
|
||||
//
|
||||
// NOTE: in some cases, resolution of these operators may still fail, most
|
||||
// notably in Google Test/Mock when attempting to serialize to an EXPECT_*
|
||||
// or ASSERT_* call. In this case, the manual "ToString" functions above must
|
||||
// be called instead.
|
||||
namespace clock_operators {
|
||||
|
||||
// Logging convenience for durations. Outputs a string of the form "123µs".
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const TrivialClockTraits::duration& d);
|
||||
|
||||
// Logging convenience for time points. Outputs a string of the form
|
||||
// "123µs-ticks".
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const TrivialClockTraits::time_point& tp);
|
||||
|
||||
// Logging (and gtest pretty-printing) for several commonly-used chrono types.
|
||||
std::ostream& operator<<(std::ostream& os, const std::chrono::hours&);
|
||||
std::ostream& operator<<(std::ostream& os, const std::chrono::minutes&);
|
||||
std::ostream& operator<<(std::ostream& os, const std::chrono::seconds&);
|
||||
std::ostream& operator<<(std::ostream& os, const std::chrono::milliseconds&);
|
||||
std::ostream& operator<<(std::ostream& os, const std::chrono::microseconds& d);
|
||||
// Note: The ostream output operator for std::chrono::microseconds is handled by
|
||||
// the one for TrivialClockTraits::duration above since they are the same type.
|
||||
|
||||
} // namespace clock_operators
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_BASE_TRIVIAL_CLOCK_TRAITS_H_
|
||||
24
breadcast-caststream-sys/vendor/openscreen/platform/base/type_util.h
vendored
Normal file
24
breadcast-caststream-sys/vendor/openscreen/platform/base/type_util.h
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2024 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_BASE_TYPE_UTIL_H_
|
||||
#define PLATFORM_BASE_TYPE_UTIL_H_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// File for defining generally useful type predicates for templatized classes
|
||||
// and functions.
|
||||
namespace openscreen::internal {
|
||||
|
||||
template <typename T>
|
||||
using EnableIfArithmetic =
|
||||
std::enable_if_t<std::is_arithmetic<T>::value>; // NOLINT
|
||||
|
||||
template <typename From, typename To>
|
||||
using EnableIfConvertible = std::enable_if_t<
|
||||
std::is_convertible<From (*)[], To (*)[]>::value>; // NOLINT
|
||||
|
||||
} // namespace openscreen::internal
|
||||
|
||||
#endif // PLATFORM_BASE_TYPE_UTIL_H_
|
||||
30
breadcast-caststream-sys/vendor/openscreen/platform/base/udp_packet.cc
vendored
Normal file
30
breadcast-caststream-sys/vendor/openscreen/platform/base/udp_packet.cc
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// 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/base/udp_packet.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
UdpPacket::UdpPacket() : std::vector<uint8_t>() {}
|
||||
|
||||
UdpPacket::UdpPacket(size_type size, uint8_t fill_value)
|
||||
: std::vector<uint8_t>(size, fill_value) {
|
||||
assert(size <= kUdpMaxPacketSize);
|
||||
}
|
||||
|
||||
UdpPacket::UdpPacket(UdpPacket&& other) noexcept = default;
|
||||
|
||||
UdpPacket::UdpPacket(std::initializer_list<uint8_t> init)
|
||||
: std::vector<uint8_t>(init) {
|
||||
assert(size() <= kUdpMaxPacketSize);
|
||||
}
|
||||
|
||||
UdpPacket::~UdpPacket() = default;
|
||||
|
||||
UdpPacket& UdpPacket::operator=(UdpPacket&& other) = default;
|
||||
|
||||
} // namespace openscreen
|
||||
54
breadcast-caststream-sys/vendor/openscreen/platform/base/udp_packet.h
vendored
Normal file
54
breadcast-caststream-sys/vendor/openscreen/platform/base/udp_packet.h
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// 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_BASE_UDP_PACKET_H_
|
||||
#define PLATFORM_BASE_UDP_PACKET_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "platform/base/ip_address.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
// A move-only std::vector of bytes that may not exceed the maximum possible
|
||||
// size of a UDP packet. Implicit copy construction/assignment is disabled to
|
||||
// prevent hidden copies (i.e., those not explicitly coded).
|
||||
class UdpPacket : public std::vector<uint8_t> {
|
||||
public:
|
||||
// C++14 vector constructors, sans Allocator foo, and no copy ctor.
|
||||
UdpPacket();
|
||||
explicit UdpPacket(size_type size, uint8_t fill_value = {});
|
||||
template <typename InputIt>
|
||||
UdpPacket(InputIt first, InputIt last) : std::vector<uint8_t>(first, last) {}
|
||||
UdpPacket(std::initializer_list<uint8_t> init);
|
||||
UdpPacket(const UdpPacket&) = delete;
|
||||
UdpPacket(UdpPacket&& other) noexcept;
|
||||
|
||||
~UdpPacket();
|
||||
|
||||
UdpPacket& operator=(UdpPacket&& other);
|
||||
UdpPacket& operator=(const UdpPacket&) = delete;
|
||||
|
||||
const IPEndpoint& source() const { return source_; }
|
||||
void set_source(IPEndpoint endpoint) { source_ = std::move(endpoint); }
|
||||
|
||||
const IPEndpoint& destination() const { return destination_; }
|
||||
void set_destination(IPEndpoint endpoint) {
|
||||
destination_ = std::move(endpoint);
|
||||
}
|
||||
|
||||
static constexpr size_type kUdpMaxPacketSize = 1 << 16;
|
||||
|
||||
private:
|
||||
IPEndpoint source_ = {};
|
||||
IPEndpoint destination_ = {};
|
||||
};
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_BASE_UDP_PACKET_H_
|
||||
32
breadcast-caststream-sys/vendor/openscreen/platform/impl/logging.h
vendored
Normal file
32
breadcast-caststream-sys/vendor/openscreen/platform/impl/logging.h
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// 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_IMPL_LOGGING_H_
|
||||
#define PLATFORM_IMPL_LOGGING_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "util/osp_logging.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
// Append logging output to a named FIFO having the given `filename`. If the
|
||||
// file does not exist, an attempt is made to auto-create it. If unsuccessful,
|
||||
// abort the program. If this is never called, logging continues to output to
|
||||
// the default destination (stderr).
|
||||
void SetLogFifoOrDie(const char* filename);
|
||||
|
||||
// Set the global logging level. If this is never called, kWarning is the
|
||||
// default.
|
||||
void SetLogLevel(LogLevel level);
|
||||
|
||||
// Returns the current global logging level.
|
||||
LogLevel GetLogLevel();
|
||||
|
||||
// Log a trace message. Used by the text trace logging platform.
|
||||
void LogTraceMessage(const std::string& message);
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_IMPL_LOGGING_H_
|
||||
161
breadcast-caststream-sys/vendor/openscreen/platform/impl/logging_posix.cc
vendored
Normal file
161
breadcast-caststream-sys/vendor/openscreen/platform/impl/logging_posix.cc
vendored
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
// 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 <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "platform/impl/logging.h"
|
||||
#include "platform/impl/logging_test.h"
|
||||
#include "util/trace_logging.h"
|
||||
|
||||
#if OSP_DCHECK_IS_ON()
|
||||
#include <execinfo.h>
|
||||
|
||||
#include <array>
|
||||
#endif
|
||||
|
||||
namespace openscreen {
|
||||
namespace {
|
||||
|
||||
int g_log_fd = STDERR_FILENO;
|
||||
LogLevel g_log_level = LogLevel::kWarning;
|
||||
std::vector<std::string>* g_log_messages_for_test = nullptr;
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const LogLevel& level) {
|
||||
const char* level_string = "";
|
||||
switch (level) {
|
||||
case LogLevel::kVerbose:
|
||||
level_string = "VERBOSE";
|
||||
break;
|
||||
case LogLevel::kInfo:
|
||||
level_string = "INFO";
|
||||
break;
|
||||
case LogLevel::kWarning:
|
||||
level_string = "WARNING";
|
||||
break;
|
||||
case LogLevel::kError:
|
||||
level_string = "ERROR";
|
||||
break;
|
||||
case LogLevel::kFatal:
|
||||
level_string = "FATAL";
|
||||
break;
|
||||
}
|
||||
os << level_string;
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void SetLogFifoOrDie(const char* filename) {
|
||||
if (g_log_fd != STDERR_FILENO) {
|
||||
close(g_log_fd);
|
||||
g_log_fd = STDERR_FILENO;
|
||||
}
|
||||
|
||||
// Note: The use of OSP_CHECK/OSP_LOG_* here will log to stderr.
|
||||
struct stat st {};
|
||||
int open_result = -1;
|
||||
if (stat(filename, &st) == -1 && errno == ENOENT) {
|
||||
if (mkfifo(filename, 0644) == 0) {
|
||||
open_result = open(filename, O_WRONLY);
|
||||
OSP_CHECK_NE(open_result, -1)
|
||||
<< "open(" << filename << ") failed: " << strerror(errno);
|
||||
} else {
|
||||
OSP_LOG_FATAL << "mkfifo(" << filename << ") failed: " << strerror(errno);
|
||||
}
|
||||
} else if (S_ISFIFO(st.st_mode)) {
|
||||
open_result = open(filename, O_WRONLY);
|
||||
OSP_CHECK_NE(open_result, -1)
|
||||
<< "open(" << filename << ") failed: " << strerror(errno);
|
||||
} else {
|
||||
OSP_LOG_FATAL << "not a FIFO special file: " << filename;
|
||||
}
|
||||
|
||||
// Direct all logging to the opened FIFO file.
|
||||
g_log_fd = open_result;
|
||||
}
|
||||
|
||||
void SetLogLevel(LogLevel level) {
|
||||
g_log_level = level;
|
||||
}
|
||||
|
||||
LogLevel GetLogLevel() {
|
||||
return g_log_level;
|
||||
}
|
||||
|
||||
bool IsLoggingOn(LogLevel level, const std::string_view file) {
|
||||
// Possible future enhancement: Use glob patterns passed on the command-line
|
||||
// to use a different logging level for certain files, like in Chromium.
|
||||
return level >= g_log_level;
|
||||
}
|
||||
|
||||
void LogWithLevel(LogLevel level,
|
||||
const char* file,
|
||||
int line,
|
||||
std::stringstream message) {
|
||||
if (level < g_log_level)
|
||||
return;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "[" << level << ":" << file << "(" << line << "):T" << std::hex
|
||||
<< TRACE_CURRENT_ID << "] " << message.rdbuf() << std::endl;
|
||||
|
||||
// NOTE: backtrace() is only supported in modern versions of Android (33+), so
|
||||
// it is just disabled here.
|
||||
#if OSP_DCHECK_IS_ON() && !BUILDFLAG(IS_ANDROID)
|
||||
if (level == LogLevel::kFatal) {
|
||||
constexpr size_t kMaxCallstackSize = 128;
|
||||
std::array<void*, kMaxCallstackSize> callstack = {};
|
||||
|
||||
// Get the return addresses and attempt to symbolize them.
|
||||
const int num_frames = backtrace(callstack.data(), callstack.size());
|
||||
char** strs = backtrace_symbols(callstack.data(), num_frames);
|
||||
|
||||
if (num_frames > 0) {
|
||||
ss << "Debug stack trace for fatal error:" << std::endl;
|
||||
for (int i = 0; i < num_frames; ++i) {
|
||||
ss << strs[i] << std::endl;
|
||||
}
|
||||
}
|
||||
free(strs);
|
||||
}
|
||||
#endif
|
||||
const auto ss_str = ss.str();
|
||||
const auto bytes_written = write(g_log_fd, ss_str.c_str(), ss_str.size());
|
||||
OSP_CHECK(bytes_written);
|
||||
if (g_log_messages_for_test) {
|
||||
g_log_messages_for_test->push_back(ss_str);
|
||||
}
|
||||
}
|
||||
|
||||
void LogTraceMessage(const std::string& message) {
|
||||
const std::string to_write = message + '\n';
|
||||
const auto bytes_written = write(g_log_fd, to_write.c_str(), to_write.size());
|
||||
OSP_CHECK(bytes_written);
|
||||
}
|
||||
|
||||
[[noreturn]] void Break() {
|
||||
// Generally this will just resolve to an abort anyways, but gives the
|
||||
// compiler a chance to perform a more appropriate, target specific trap
|
||||
// as appropriate.
|
||||
#if defined(_DEBUG)
|
||||
__builtin_trap();
|
||||
#else
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void SetLogBufferForTest(std::vector<std::string>* messages) {
|
||||
g_log_messages_for_test = messages;
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
24
breadcast-caststream-sys/vendor/openscreen/platform/impl/logging_test.h
vendored
Normal file
24
breadcast-caststream-sys/vendor/openscreen/platform/impl/logging_test.h
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2020 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_IMPL_LOGGING_TEST_H_
|
||||
#define PLATFORM_IMPL_LOGGING_TEST_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// These functions should only be called from logging unittests.
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
// Append logging output to `messages`. Each log entry will be written as a new
|
||||
// element including a newline. Pass nullptr to stop appending output. Calling
|
||||
// this does not affect the behavior of SetLogFifoOrDie(). Normally this should
|
||||
// only be called for tests as it creates an append-only buffer of log messages
|
||||
// in memory.
|
||||
void SetLogBufferForTest(std::vector<std::string>* messages);
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_IMPL_LOGGING_TEST_H_
|
||||
31
breadcast-caststream-sys/vendor/openscreen/platform/impl/network_interface.cc
vendored
Normal file
31
breadcast-caststream-sys/vendor/openscreen/platform/impl/network_interface.cc
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2020 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/impl/network_interface.h"
|
||||
|
||||
#include "platform/base/ip_address.h"
|
||||
#include "util/std_util.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
// Returns an InterfaceInfo associated with the system's loopback interface.
|
||||
std::optional<InterfaceInfo> GetLoopbackInterfaceForTesting() {
|
||||
const std::vector<InterfaceInfo> interfaces = GetNetworkInterfaces();
|
||||
auto it = std::find_if(
|
||||
interfaces.begin(), interfaces.end(), [](const InterfaceInfo& info) {
|
||||
return info.type == InterfaceInfo::Type::kLoopback &&
|
||||
ContainsIf(info.addresses, [](const IPSubnet& subnet) {
|
||||
return subnet.address == IPAddress::kV4LoopbackAddress() ||
|
||||
subnet.address == IPAddress::kV6LoopbackAddress();
|
||||
});
|
||||
});
|
||||
|
||||
if (it == interfaces.end()) {
|
||||
return std::nullopt;
|
||||
} else {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
23
breadcast-caststream-sys/vendor/openscreen/platform/impl/network_interface.h
vendored
Normal file
23
breadcast-caststream-sys/vendor/openscreen/platform/impl/network_interface.h
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// 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_IMPL_NETWORK_INTERFACE_H_
|
||||
#define PLATFORM_IMPL_NETWORK_INTERFACE_H_
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "platform/base/interface_info.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
// Implements the platform API.
|
||||
std::vector<InterfaceInfo> GetNetworkInterfaces();
|
||||
|
||||
// Returns the system's loopback interface. Used for unit tests.
|
||||
std::optional<InterfaceInfo> GetLoopbackInterfaceForTesting();
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_IMPL_NETWORK_INTERFACE_H_
|
||||
384
breadcast-caststream-sys/vendor/openscreen/platform/impl/network_interface_linux.cc
vendored
Normal file
384
breadcast-caststream-sys/vendor/openscreen/platform/impl/network_interface_linux.cc
vendored
Normal file
|
|
@ -0,0 +1,384 @@
|
|||
// 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.
|
||||
|
||||
// clang-format: off
|
||||
#include <net/if.h>
|
||||
#include <sys/socket.h>
|
||||
// clang-format: on
|
||||
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/wireless.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "platform/api/network_interface.h"
|
||||
#include "platform/base/ip_address.h"
|
||||
#include "platform/base/span.h"
|
||||
#include "platform/impl/network_interface.h"
|
||||
#include "platform/impl/scoped_pipe.h"
|
||||
#include "util/osp_logging.h"
|
||||
|
||||
namespace openscreen {
|
||||
namespace {
|
||||
|
||||
constexpr int kNetlinkRecvmsgBufSize = 8192;
|
||||
|
||||
// Safely reads the system name for the interface from the (probably)
|
||||
// null-terminated string `kernel_name` and returns a std::string.
|
||||
std::string GetInterfaceName(std::string_view kernel_name) {
|
||||
OSP_CHECK_LT(kernel_name.length(), IFNAMSIZ);
|
||||
return std::string(kernel_name);
|
||||
}
|
||||
|
||||
// Returns the type of the interface identified by the name `ifname`, if it can
|
||||
// be determined, otherwise returns InterfaceInfo::Type::kOther.
|
||||
InterfaceInfo::Type GetInterfaceType(const std::string& ifname) {
|
||||
// Determine type after name has been set.
|
||||
ScopedFd s(socket(AF_INET6, SOCK_DGRAM, 0));
|
||||
if (!s) {
|
||||
s = ScopedFd(socket(AF_INET, SOCK_DGRAM, 0));
|
||||
if (!s)
|
||||
return InterfaceInfo::Type::kOther;
|
||||
}
|
||||
|
||||
// Note: This uses Wireless Extensions to test the interface, which is
|
||||
// deprecated. However, it's much easier than using the new nl80211
|
||||
// interface for this purpose. If Wireless Extensions are ever actually
|
||||
// removed though, this will need to use nl80211.
|
||||
struct iwreq wr {};
|
||||
static_assert(sizeof(wr.ifr_name) == IFNAMSIZ,
|
||||
"expected size of interface name fields");
|
||||
OSP_CHECK_LT(ifname.size(), IFNAMSIZ);
|
||||
wr.ifr_name[IFNAMSIZ - 1] = 0;
|
||||
strncpy(wr.ifr_name, ifname.c_str(), IFNAMSIZ - 1);
|
||||
if (ioctl(s.get(), SIOCGIWNAME, &wr) != -1)
|
||||
return InterfaceInfo::Type::kWifi;
|
||||
|
||||
struct ethtool_cmd ecmd {};
|
||||
ecmd.cmd = ETHTOOL_GSET;
|
||||
struct ifreq ifr {};
|
||||
static_assert(sizeof(ifr.ifr_name) == IFNAMSIZ,
|
||||
"expected size of interface name fields");
|
||||
OSP_CHECK_LT(ifname.size(), IFNAMSIZ);
|
||||
wr.ifr_name[IFNAMSIZ - 1] = 0;
|
||||
strncpy(ifr.ifr_name, ifname.c_str(), IFNAMSIZ - 1);
|
||||
ifr.ifr_data = reinterpret_cast<char*>(&ecmd);
|
||||
if (ioctl(s.get(), SIOCETHTOOL, &ifr) != -1) {
|
||||
return InterfaceInfo::Type::kEthernet;
|
||||
}
|
||||
|
||||
return InterfaceInfo::Type::kOther;
|
||||
}
|
||||
|
||||
// Reads an interface's name, hardware address, and type from `rta` and places
|
||||
// the results in `info`. `rta` is the first attribute structure returned as
|
||||
// part of an RTM_NEWLINK message. `attrlen` is the total length of the buffer
|
||||
// pointed to by `rta`.
|
||||
void GetInterfaceAttributes(struct rtattr* rta,
|
||||
unsigned int attrlen,
|
||||
bool is_loopback,
|
||||
InterfaceInfo* info) {
|
||||
for (; RTA_OK(rta, attrlen); rta = RTA_NEXT(rta, attrlen)) {
|
||||
if (rta->rta_type == IFLA_IFNAME) {
|
||||
info->name =
|
||||
GetInterfaceName(reinterpret_cast<const char*>(RTA_DATA(rta)));
|
||||
} else if (rta->rta_type == IFLA_ADDRESS) {
|
||||
ByteView address_bytes(reinterpret_cast<uint8_t*>(RTA_DATA(rta)),
|
||||
RTA_PAYLOAD(rta));
|
||||
info->hardware_address.assign(address_bytes.begin(), address_bytes.end());
|
||||
}
|
||||
}
|
||||
|
||||
if (is_loopback) {
|
||||
info->type = InterfaceInfo::Type::kLoopback;
|
||||
} else {
|
||||
info->type = GetInterfaceType(info->name);
|
||||
}
|
||||
}
|
||||
|
||||
// Reads the IPv4 or IPv6 address that comes from an RTM_NEWADDR message and
|
||||
// places the result in `address`. `rta` is the first attribute structure
|
||||
// returned by the message and `attrlen` is the total length of the buffer
|
||||
// pointed to by `rta`. `ifname` is the name of the interface to which we
|
||||
// believe the address belongs based on interface index matching. It is only
|
||||
// used for sanity checking.
|
||||
std::optional<IPAddress> GetIPAddressOrNull(struct rtattr* rta,
|
||||
unsigned int attrlen,
|
||||
IPAddress::Version version,
|
||||
const std::string& ifname) {
|
||||
const size_t expected_address_size = version == IPAddress::Version::kV4
|
||||
? IPAddress::kV4Size
|
||||
: IPAddress::kV6Size;
|
||||
|
||||
bool have_local = false;
|
||||
IPAddress address;
|
||||
IPAddress local;
|
||||
for (; RTA_OK(rta, attrlen); rta = RTA_NEXT(rta, attrlen)) {
|
||||
if (rta->rta_type == IFA_LABEL) {
|
||||
const char* const label = reinterpret_cast<const char*>(RTA_DATA(rta));
|
||||
if (ifname != label) {
|
||||
OSP_LOG_ERROR << "Interface label mismatch! Expected: " << ifname
|
||||
<< ", Have: " << label;
|
||||
return std::nullopt;
|
||||
}
|
||||
} else if (rta->rta_type == IFA_ADDRESS) {
|
||||
OSP_CHECK_EQ(expected_address_size, RTA_PAYLOAD(rta));
|
||||
address =
|
||||
IPAddress(version, std::span(static_cast<uint8_t*>(RTA_DATA(rta)),
|
||||
expected_address_size));
|
||||
} else if (rta->rta_type == IFA_LOCAL) {
|
||||
OSP_CHECK_EQ(expected_address_size, RTA_PAYLOAD(rta));
|
||||
have_local = true;
|
||||
local = IPAddress(version, std::span(static_cast<uint8_t*>(RTA_DATA(rta)),
|
||||
expected_address_size));
|
||||
}
|
||||
}
|
||||
return have_local ? local : address;
|
||||
}
|
||||
|
||||
std::vector<InterfaceInfo> GetLinkInfo() {
|
||||
ScopedFd fd(socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE));
|
||||
if (!fd) {
|
||||
OSP_LOG_WARN << "netlink socket() failed: " << errno << " - "
|
||||
<< strerror(errno);
|
||||
return {};
|
||||
}
|
||||
|
||||
{
|
||||
// nl_pid = 0 for the kernel.
|
||||
struct sockaddr_nl peer {};
|
||||
peer.nl_family = AF_NETLINK;
|
||||
struct {
|
||||
struct nlmsghdr header {};
|
||||
struct ifinfomsg msg {};
|
||||
} request;
|
||||
|
||||
request.header.nlmsg_len = sizeof(request);
|
||||
request.header.nlmsg_type = RTM_GETLINK;
|
||||
request.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
|
||||
request.header.nlmsg_seq = 0;
|
||||
request.header.nlmsg_pid = 0;
|
||||
request.msg.ifi_family = AF_UNSPEC;
|
||||
struct iovec iov {
|
||||
&request, request.header.nlmsg_len
|
||||
};
|
||||
struct msghdr msg {};
|
||||
msg.msg_name = &peer;
|
||||
msg.msg_namelen = sizeof(peer);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = nullptr;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_flags = 0;
|
||||
if (sendmsg(fd.get(), &msg, 0) < 0) {
|
||||
OSP_LOG_ERROR << "netlink sendmsg() failed: " << errno << " - "
|
||||
<< strerror(errno);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<InterfaceInfo> info_list;
|
||||
{
|
||||
char buf[kNetlinkRecvmsgBufSize]{};
|
||||
struct iovec iov {
|
||||
buf, sizeof(buf)
|
||||
};
|
||||
struct sockaddr_nl source_address {};
|
||||
struct msghdr msg {};
|
||||
struct nlmsghdr* netlink_header = nullptr;
|
||||
|
||||
msg.msg_name = &source_address;
|
||||
msg.msg_namelen = sizeof(source_address);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1, msg.msg_control = nullptr, msg.msg_controllen = 0,
|
||||
msg.msg_flags = 0;
|
||||
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
size_t len = recvmsg(fd.get(), &msg, 0);
|
||||
|
||||
for (netlink_header = reinterpret_cast<struct nlmsghdr*>(buf);
|
||||
NLMSG_OK(netlink_header, len);
|
||||
netlink_header = NLMSG_NEXT(netlink_header, len)) {
|
||||
// The end of multipart message.
|
||||
if (netlink_header->nlmsg_type == NLMSG_DONE) {
|
||||
done = true;
|
||||
break;
|
||||
} else if (netlink_header->nlmsg_type == NLMSG_ERROR) {
|
||||
done = true;
|
||||
OSP_LOG_ERROR << "netlink error msg: "
|
||||
<< reinterpret_cast<struct nlmsgerr*>(
|
||||
NLMSG_DATA(netlink_header))
|
||||
->error;
|
||||
continue;
|
||||
} else if ((netlink_header->nlmsg_flags & NLM_F_MULTI) == 0) {
|
||||
// If this is not a multi-part message, we don't need to wait for an
|
||||
// NLMSG_DONE message; this is the only message.
|
||||
done = true;
|
||||
}
|
||||
|
||||
// RTM_NEWLINK messages describe existing network links on the host.
|
||||
if (netlink_header->nlmsg_type != RTM_NEWLINK)
|
||||
continue;
|
||||
|
||||
struct ifinfomsg* interface_info =
|
||||
static_cast<struct ifinfomsg*>(NLMSG_DATA(netlink_header));
|
||||
// Only process interfaces which are active (up).
|
||||
if (!(interface_info->ifi_flags & IFF_UP)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
info_list.emplace_back();
|
||||
InterfaceInfo& info = info_list.back();
|
||||
info.index = interface_info->ifi_index;
|
||||
GetInterfaceAttributes(IFLA_RTA(interface_info),
|
||||
IFLA_PAYLOAD(netlink_header),
|
||||
interface_info->ifi_flags & IFF_LOOPBACK, &info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return info_list;
|
||||
}
|
||||
|
||||
void PopulateSubnetsOrClearList(std::vector<InterfaceInfo>& info_list) {
|
||||
ScopedFd fd(socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE));
|
||||
if (!fd) {
|
||||
OSP_LOG_ERROR << "netlink socket() failed: " << errno << " - "
|
||||
<< strerror(errno);
|
||||
info_list.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
// nl_pid = 0 for the kernel.
|
||||
struct sockaddr_nl peer {};
|
||||
peer.nl_family = AF_NETLINK;
|
||||
struct {
|
||||
struct nlmsghdr header {};
|
||||
struct ifaddrmsg msg {};
|
||||
} request;
|
||||
|
||||
request.header.nlmsg_len = sizeof(request);
|
||||
request.header.nlmsg_type = RTM_GETADDR;
|
||||
request.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
|
||||
request.header.nlmsg_seq = 1;
|
||||
request.header.nlmsg_pid = 0;
|
||||
request.msg.ifa_family = AF_UNSPEC;
|
||||
struct iovec iov {
|
||||
&request, request.header.nlmsg_len
|
||||
};
|
||||
struct msghdr msg {};
|
||||
msg.msg_name = &peer;
|
||||
msg.msg_namelen = sizeof(peer);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = nullptr;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_flags = 0;
|
||||
if (sendmsg(fd.get(), &msg, 0) < 0) {
|
||||
OSP_LOG_ERROR << "sendmsg failed: " << errno << " - " << strerror(errno);
|
||||
info_list.clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
char buf[kNetlinkRecvmsgBufSize]{};
|
||||
struct iovec iov {
|
||||
buf, sizeof(buf)
|
||||
};
|
||||
struct sockaddr_nl source_address {};
|
||||
struct msghdr msg {};
|
||||
struct nlmsghdr* netlink_header = nullptr;
|
||||
|
||||
msg.msg_name = &source_address;
|
||||
msg.msg_namelen = sizeof(source_address);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = nullptr;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_flags = 0;
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
size_t len = recvmsg(fd.get(), &msg, 0);
|
||||
|
||||
for (netlink_header = reinterpret_cast<struct nlmsghdr*>(buf);
|
||||
NLMSG_OK(netlink_header, len);
|
||||
netlink_header = NLMSG_NEXT(netlink_header, len)) {
|
||||
if (netlink_header->nlmsg_type == NLMSG_DONE) {
|
||||
done = true;
|
||||
break;
|
||||
} else if (netlink_header->nlmsg_type == NLMSG_ERROR) {
|
||||
done = true;
|
||||
OSP_LOG_ERROR << "netlink error msg: "
|
||||
<< reinterpret_cast<struct nlmsgerr*>(
|
||||
NLMSG_DATA(netlink_header))
|
||||
->error;
|
||||
continue;
|
||||
} else if ((netlink_header->nlmsg_flags & NLM_F_MULTI) == 0) {
|
||||
// If this is not a multi-part message, we don't need to wait for an
|
||||
// NLMSG_DONE message; this is the only message.
|
||||
done = true;
|
||||
}
|
||||
|
||||
if (netlink_header->nlmsg_type != RTM_NEWADDR)
|
||||
continue;
|
||||
|
||||
struct ifaddrmsg* interface_address =
|
||||
static_cast<struct ifaddrmsg*>(NLMSG_DATA(netlink_header));
|
||||
|
||||
const auto it = std::find_if(
|
||||
info_list.begin(), info_list.end(),
|
||||
[index = interface_address->ifa_index](const InterfaceInfo& info) {
|
||||
return info.index == index;
|
||||
});
|
||||
if (it == info_list.end()) {
|
||||
OSP_DVLOG << "skipping address for interface "
|
||||
<< interface_address->ifa_index;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (interface_address->ifa_family == AF_INET ||
|
||||
interface_address->ifa_family == AF_INET6) {
|
||||
const auto address_or_null = GetIPAddressOrNull(
|
||||
IFA_RTA(interface_address), IFA_PAYLOAD(netlink_header),
|
||||
interface_address->ifa_family == AF_INET
|
||||
? IPAddress::Version::kV4
|
||||
: IPAddress::Version::kV6,
|
||||
it->name);
|
||||
if (address_or_null) {
|
||||
it->addresses.emplace_back(*address_or_null,
|
||||
interface_address->ifa_prefixlen);
|
||||
}
|
||||
} else {
|
||||
OSP_LOG_ERROR << "Unknown address family: "
|
||||
<< interface_address->ifa_family;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::vector<InterfaceInfo> GetNetworkInterfaces() {
|
||||
std::vector<InterfaceInfo> interfaces = GetLinkInfo();
|
||||
PopulateSubnetsOrClearList(interfaces);
|
||||
return interfaces;
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
137
breadcast-caststream-sys/vendor/openscreen/platform/impl/platform_client_posix.cc
vendored
Normal file
137
breadcast-caststream-sys/vendor/openscreen/platform/impl/platform_client_posix.cc
vendored
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
// Copyright (c) 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/impl/platform_client_posix.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "platform/base/trivial_clock_traits.h"
|
||||
#include "platform/impl/udp_socket_reader_posix.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
using clock_operators::operator<<;
|
||||
|
||||
// static
|
||||
PlatformClientPosix* PlatformClientPosix::instance_ = nullptr;
|
||||
|
||||
// static
|
||||
void PlatformClientPosix::Create(Clock::duration networking_operation_timeout,
|
||||
std::unique_ptr<TaskRunnerImpl> task_runner) {
|
||||
SetInstance(new PlatformClientPosix(networking_operation_timeout,
|
||||
std::move(task_runner)));
|
||||
}
|
||||
|
||||
// static
|
||||
void PlatformClientPosix::Create(Clock::duration networking_operation_timeout) {
|
||||
SetInstance(new PlatformClientPosix(networking_operation_timeout));
|
||||
}
|
||||
|
||||
// static
|
||||
void PlatformClientPosix::ShutDown() {
|
||||
OSP_CHECK(instance_);
|
||||
delete instance_;
|
||||
instance_ = nullptr;
|
||||
}
|
||||
|
||||
UdpSocketReaderPosix* PlatformClientPosix::udp_socket_reader() {
|
||||
std::call_once(udp_socket_reader_initialization_, [this]() {
|
||||
udp_socket_reader_ =
|
||||
std::make_unique<UdpSocketReaderPosix>(*socket_handle_waiter());
|
||||
});
|
||||
return udp_socket_reader_.get();
|
||||
}
|
||||
|
||||
TaskRunner& PlatformClientPosix::GetTaskRunner() {
|
||||
return *task_runner_;
|
||||
}
|
||||
|
||||
PlatformClientPosix::~PlatformClientPosix() {
|
||||
OSP_DVLOG << "Shutting down the Task Runner...";
|
||||
task_runner_->RequestStopSoon();
|
||||
if (task_runner_thread_ && task_runner_thread_->joinable()) {
|
||||
task_runner_thread_->join();
|
||||
OSP_DVLOG << "\tTask Runner shutdown complete!";
|
||||
}
|
||||
|
||||
OSP_DVLOG << "Shutting down network operations...";
|
||||
networking_loop_running_.store(false);
|
||||
networking_loop_thread_.join();
|
||||
OSP_DVLOG << "\tNetwork operation shutdown complete!";
|
||||
}
|
||||
|
||||
// static
|
||||
void PlatformClientPosix::SetInstance(PlatformClientPosix* instance) {
|
||||
OSP_CHECK(!instance_);
|
||||
instance_ = instance;
|
||||
}
|
||||
|
||||
PlatformClientPosix::PlatformClientPosix(
|
||||
Clock::duration networking_operation_timeout)
|
||||
: task_runner_(new TaskRunnerImpl(Clock::now)),
|
||||
networking_loop_timeout_(networking_operation_timeout),
|
||||
networking_loop_thread_(&PlatformClientPosix::RunNetworkLoopUntilStopped,
|
||||
this),
|
||||
task_runner_thread_(
|
||||
std::thread(&TaskRunnerImpl::RunUntilStopped, task_runner_.get())) {}
|
||||
|
||||
PlatformClientPosix::PlatformClientPosix(
|
||||
Clock::duration networking_operation_timeout,
|
||||
std::unique_ptr<TaskRunnerImpl> task_runner)
|
||||
: task_runner_(std::move(task_runner)),
|
||||
networking_loop_timeout_(networking_operation_timeout),
|
||||
networking_loop_thread_(&PlatformClientPosix::RunNetworkLoopUntilStopped,
|
||||
this) {}
|
||||
|
||||
SocketHandleWaiterPosix* PlatformClientPosix::socket_handle_waiter() {
|
||||
std::call_once(waiter_initialization_, [this]() {
|
||||
waiter_ = std::make_unique<SocketHandleWaiterPosix>(&Clock::now);
|
||||
waiter_created_.store(true);
|
||||
});
|
||||
return waiter_.get();
|
||||
}
|
||||
|
||||
void PlatformClientPosix::RunNetworkLoopUntilStopped() {
|
||||
#if OSP_DCHECK_IS_ON()
|
||||
Clock::time_point last_time = Clock::now();
|
||||
int iterations = 0;
|
||||
#endif
|
||||
while (networking_loop_running_.load()) {
|
||||
#if OSP_DCHECK_IS_ON()
|
||||
++iterations;
|
||||
const Clock::time_point current_time = Clock::now();
|
||||
const Clock::duration delta = current_time - last_time;
|
||||
if (delta > std::chrono::seconds(1)) {
|
||||
OSP_DCHECK_GT(iterations, 0);
|
||||
OSP_VLOG << "network loop execution time averaged "
|
||||
<< (delta / iterations) << " over the last second.";
|
||||
last_time = current_time;
|
||||
iterations = 0;
|
||||
}
|
||||
#endif
|
||||
if (!waiter_created_.load()) {
|
||||
std::this_thread::sleep_for(networking_loop_timeout_);
|
||||
continue;
|
||||
}
|
||||
const Error process_error =
|
||||
socket_handle_waiter()->ProcessHandles(networking_loop_timeout_);
|
||||
|
||||
// We may receive an "again" error code if there were no sockets to process.
|
||||
if (process_error.code() == Error::Code::kAgain) {
|
||||
std::this_thread::sleep_for(networking_loop_timeout_);
|
||||
continue;
|
||||
|
||||
// If there is a socket error it should be handled elsewhere. Just log
|
||||
// the error here.
|
||||
} else if (!process_error.ok()) {
|
||||
OSP_LOG_ERROR << "error occurred while processing handles. error="
|
||||
<< process_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
130
breadcast-caststream-sys/vendor/openscreen/platform/impl/platform_client_posix.h
vendored
Normal file
130
breadcast-caststream-sys/vendor/openscreen/platform/impl/platform_client_posix.h
vendored
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
// Copyright (c) 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_IMPL_PLATFORM_CLIENT_POSIX_H_
|
||||
#define PLATFORM_IMPL_PLATFORM_CLIENT_POSIX_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "platform/api/time.h"
|
||||
#include "platform/impl/socket_handle_waiter_posix.h"
|
||||
#include "platform/impl/task_runner.h"
|
||||
|
||||
// LOCAL PATCH (breadcast): upstream also wires up a TlsDataRouterPosix here
|
||||
// for TlsConnectionFactory support. breadcast only uses this vendored subset
|
||||
// of openscreen for the Cast Streaming UDP RTP/RTCP data path -- the TLS
|
||||
// CASTV2 control channel is handled by the existing rust_cast-based Rust
|
||||
// code -- so the TLS data router (and the BoringSSL-flavored util/crypto/*
|
||||
// helpers it pulls in) has been stripped entirely rather than ported. See
|
||||
// vendor/openscreen/PATCHES.md.
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
class UdpSocketReaderPosix;
|
||||
|
||||
// Creates and provides access to singletons used by the default platform
|
||||
// implementation. An instance must be created before an application uses any
|
||||
// public modules in the Open Screen Library.
|
||||
//
|
||||
// ShutDown() should be called to destroy the PlatformClientPosix's singletons
|
||||
// and TaskRunner to save resources when library APIs are not in use.
|
||||
// ShutDown() calls TaskRunner::RunUntilStopped() to run any pending cleanup
|
||||
// tasks.
|
||||
//
|
||||
// Create and ShutDown must be called in the same sequence.
|
||||
//
|
||||
// FIXME: Remove Create and Shutdown and use the ctor/dtor directly.
|
||||
class PlatformClientPosix {
|
||||
public:
|
||||
// Initializes the platform implementation.
|
||||
//
|
||||
// `networking_loop_interval` sets the minimum amount of time that should pass
|
||||
// between iterations of the loop used to handle networking operations. Higher
|
||||
// values will result in less time being spent on these operations, but also
|
||||
// less performant networking operations. Be careful setting values larger
|
||||
// than a few hundred microseconds.
|
||||
//
|
||||
// `networking_operation_timeout` sets how much time may be spent on a
|
||||
// single networking operation type.
|
||||
//
|
||||
// `task_runner` is a client-provided TaskRunner implementation.
|
||||
static void Create(Clock::duration networking_operation_timeout,
|
||||
std::unique_ptr<TaskRunnerImpl> task_runner);
|
||||
|
||||
// Initializes the platform implementation and creates a new TaskRunner (which
|
||||
// starts a new thread).
|
||||
static void Create(Clock::duration networking_operation_timeout);
|
||||
|
||||
// Shuts down and deletes the PlatformClient instance currently stored as a
|
||||
// singleton. This method is expected to be called before program exit. After
|
||||
// calling this method, if the client wishes to continue using the platform
|
||||
// library, Create() must be called again.
|
||||
static void ShutDown();
|
||||
|
||||
static PlatformClientPosix* GetInstance() { return instance_; }
|
||||
|
||||
PlatformClientPosix(const PlatformClientPosix&) = delete;
|
||||
PlatformClientPosix(PlatformClientPosix&&) noexcept = delete;
|
||||
PlatformClientPosix& operator=(const PlatformClientPosix&) = delete;
|
||||
PlatformClientPosix& operator=(PlatformClientPosix&&) = delete;
|
||||
|
||||
// This method is thread-safe.
|
||||
// FIXME: Rename to GetUdpSocketReader()
|
||||
UdpSocketReaderPosix* udp_socket_reader();
|
||||
|
||||
// Returns the TaskRunner associated with this PlatformClient.
|
||||
// NOTE: This method is expected to be thread safe.
|
||||
TaskRunner& GetTaskRunner();
|
||||
|
||||
protected:
|
||||
// Called by ShutDown().
|
||||
~PlatformClientPosix();
|
||||
|
||||
static void SetInstance(PlatformClientPosix* client);
|
||||
|
||||
private:
|
||||
explicit PlatformClientPosix(Clock::duration networking_operation_timeout);
|
||||
|
||||
PlatformClientPosix(Clock::duration networking_operation_timeout,
|
||||
std::unique_ptr<TaskRunnerImpl> task_runner);
|
||||
|
||||
// This method is thread-safe.
|
||||
SocketHandleWaiterPosix* socket_handle_waiter();
|
||||
|
||||
void RunNetworkLoopUntilStopped();
|
||||
|
||||
std::unique_ptr<TaskRunnerImpl> task_runner_;
|
||||
|
||||
// Track whether the associated instance variable has been created yet.
|
||||
std::atomic_bool waiter_created_{false};
|
||||
|
||||
// Parameters for networking loop.
|
||||
std::atomic_bool networking_loop_running_{true};
|
||||
Clock::duration networking_loop_timeout_;
|
||||
|
||||
// Flags used to ensure that initialization of below instance objects occurs
|
||||
// only once across all threads.
|
||||
std::once_flag waiter_initialization_;
|
||||
std::once_flag udp_socket_reader_initialization_;
|
||||
|
||||
// Instance objects are created at runtime when they are first needed.
|
||||
std::unique_ptr<SocketHandleWaiterPosix> waiter_;
|
||||
std::unique_ptr<UdpSocketReaderPosix> udp_socket_reader_;
|
||||
|
||||
// Threads for running TaskRunner and OperationLoop instances.
|
||||
// NOTE: These must be declared last to avoid nondterministic failures.
|
||||
std::thread networking_loop_thread_;
|
||||
std::optional<std::thread> task_runner_thread_;
|
||||
|
||||
static PlatformClientPosix* instance_;
|
||||
};
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_IMPL_PLATFORM_CLIENT_POSIX_H_
|
||||
71
breadcast-caststream-sys/vendor/openscreen/platform/impl/scoped_pipe.h
vendored
Normal file
71
breadcast-caststream-sys/vendor/openscreen/platform/impl/scoped_pipe.h
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// 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_IMPL_SCOPED_PIPE_H_
|
||||
#define PLATFORM_IMPL_SCOPED_PIPE_H_
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
struct IntFdTraits {
|
||||
using PipeType = int;
|
||||
static constexpr int kInvalidValue = -1;
|
||||
|
||||
static void Close(PipeType pipe) { close(pipe); }
|
||||
};
|
||||
|
||||
// This class wraps file descriptor and uses RAII to ensure it is closed
|
||||
// properly when control leaves its scope. It is parameterized by a traits type
|
||||
// which defines the value type of the file descriptor, an invalid value, and a
|
||||
// closing function.
|
||||
//
|
||||
// This class is move-only as it represents ownership of the wrapped file
|
||||
// descriptor. It is not thread-safe.
|
||||
template <typename Traits>
|
||||
class ScopedPipe {
|
||||
public:
|
||||
using PipeType = typename Traits::PipeType;
|
||||
|
||||
ScopedPipe() : pipe_(Traits::kInvalidValue) {}
|
||||
explicit ScopedPipe(PipeType pipe) : pipe_(pipe) {}
|
||||
ScopedPipe(const ScopedPipe&) = delete;
|
||||
ScopedPipe(ScopedPipe&& other) : pipe_(other.release()) {}
|
||||
~ScopedPipe() {
|
||||
if (pipe_ != Traits::kInvalidValue)
|
||||
Traits::Close(release());
|
||||
}
|
||||
|
||||
ScopedPipe& operator=(ScopedPipe&& other) {
|
||||
if (pipe_ != Traits::kInvalidValue)
|
||||
Traits::Close(release());
|
||||
pipe_ = other.release();
|
||||
return *this;
|
||||
}
|
||||
|
||||
PipeType get() const { return pipe_; }
|
||||
PipeType release() {
|
||||
PipeType pipe = pipe_;
|
||||
pipe_ = Traits::kInvalidValue;
|
||||
return pipe;
|
||||
}
|
||||
|
||||
bool operator==(const ScopedPipe& other) const {
|
||||
return pipe_ == other.pipe_;
|
||||
}
|
||||
bool operator!=(const ScopedPipe& other) const { return !(*this == other); }
|
||||
|
||||
explicit operator bool() const { return pipe_ != Traits::kInvalidValue; }
|
||||
|
||||
private:
|
||||
PipeType pipe_;
|
||||
};
|
||||
|
||||
using ScopedFd = ScopedPipe<IntFdTraits>;
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_IMPL_SCOPED_PIPE_H_
|
||||
129
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_address_posix.cc
vendored
Normal file
129
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_address_posix.cc
vendored
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
// 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/impl/socket_address_posix.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "util/osp_logging.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
SocketAddressPosix::SocketAddressPosix(const struct sockaddr& address) {
|
||||
if (address.sa_family == AF_INET) {
|
||||
std::copy_n(reinterpret_cast<const uint8_t*>(&address),
|
||||
sizeof(struct sockaddr_in),
|
||||
reinterpret_cast<uint8_t*>(&internal_address_.v4));
|
||||
RecomputeEndpoint(IPAddress::Version::kV4);
|
||||
} else if (address.sa_family == AF_INET6) {
|
||||
std::copy_n(reinterpret_cast<const uint8_t*>(&address),
|
||||
sizeof(struct sockaddr_in6),
|
||||
reinterpret_cast<uint8_t*>(&internal_address_.v6));
|
||||
RecomputeEndpoint(IPAddress::Version::kV6);
|
||||
} else {
|
||||
// Not IPv4 or IPv6.
|
||||
OSP_NOTREACHED();
|
||||
}
|
||||
}
|
||||
|
||||
SocketAddressPosix::SocketAddressPosix(const IPEndpoint& endpoint)
|
||||
: endpoint_(endpoint) {
|
||||
if (endpoint.address.IsV4()) {
|
||||
internal_address_.v4 = ToSockAddrIn(endpoint);
|
||||
} else {
|
||||
internal_address_.v6 = ToSockAddrIn6(endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
struct sockaddr* SocketAddressPosix::address() {
|
||||
switch (version()) {
|
||||
case IPAddress::Version::kV4:
|
||||
return reinterpret_cast<struct sockaddr*>(&internal_address_.v4);
|
||||
case IPAddress::Version::kV6:
|
||||
return reinterpret_cast<struct sockaddr*>(&internal_address_.v6);
|
||||
default:
|
||||
OSP_NOTREACHED();
|
||||
}
|
||||
}
|
||||
|
||||
const struct sockaddr* SocketAddressPosix::address() const {
|
||||
switch (version()) {
|
||||
case IPAddress::Version::kV4:
|
||||
return reinterpret_cast<const struct sockaddr*>(&internal_address_.v4);
|
||||
case IPAddress::Version::kV6:
|
||||
return reinterpret_cast<const struct sockaddr*>(&internal_address_.v6);
|
||||
default:
|
||||
OSP_NOTREACHED();
|
||||
}
|
||||
}
|
||||
|
||||
socklen_t SocketAddressPosix::size() const {
|
||||
switch (version()) {
|
||||
case IPAddress::Version::kV4:
|
||||
return sizeof(struct sockaddr_in);
|
||||
case IPAddress::Version::kV6:
|
||||
return sizeof(struct sockaddr_in6);
|
||||
default:
|
||||
OSP_NOTREACHED();
|
||||
}
|
||||
}
|
||||
|
||||
void SocketAddressPosix::RecomputeEndpoint() {
|
||||
RecomputeEndpoint(endpoint_.address.version());
|
||||
}
|
||||
|
||||
void SocketAddressPosix::RecomputeEndpoint(IPAddress::Version version) {
|
||||
switch (version) {
|
||||
case IPAddress::Version::kV4:
|
||||
endpoint_.address = GetIPAddressFromSockAddr(internal_address_.v4);
|
||||
endpoint_.port = ntohs(internal_address_.v4.sin_port);
|
||||
break;
|
||||
case IPAddress::Version::kV6:
|
||||
endpoint_.address = GetIPAddressFromSockAddr(internal_address_.v6);
|
||||
endpoint_.port = ntohs(internal_address_.v6.sin6_port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IPAddress GetIPAddressFromSockAddr(const struct sockaddr_in& sa) {
|
||||
static_assert(IPAddress::kV4Size == sizeof(sa.sin_addr.s_addr),
|
||||
"IPv4 address size mismatch.");
|
||||
return IPAddress(
|
||||
IPAddress::Version::kV4,
|
||||
std::span<const uint8_t>(
|
||||
reinterpret_cast<const uint8_t*>(&sa.sin_addr.s_addr), 4));
|
||||
}
|
||||
|
||||
IPAddress GetIPAddressFromSockAddr(const struct sockaddr_in6& sa) {
|
||||
return IPAddress(std::span<const uint8_t, 16>(sa.sin6_addr.s6_addr, 16),
|
||||
sa.sin6_scope_id);
|
||||
}
|
||||
|
||||
struct sockaddr_in ToSockAddrIn(const IPEndpoint& endpoint) {
|
||||
OSP_CHECK(endpoint.address.IsV4());
|
||||
struct sockaddr_in out{};
|
||||
out.sin_family = AF_INET;
|
||||
out.sin_port = htons(endpoint.port);
|
||||
endpoint.address.CopyTo(
|
||||
std::span<uint8_t>(reinterpret_cast<uint8_t*>(&out.sin_addr.s_addr), 4));
|
||||
return out;
|
||||
}
|
||||
|
||||
struct sockaddr_in6 ToSockAddrIn6(const IPEndpoint& endpoint) {
|
||||
OSP_CHECK(endpoint.address.IsV6());
|
||||
struct sockaddr_in6 out{};
|
||||
out.sin6_family = AF_INET6;
|
||||
out.sin6_flowinfo = 0;
|
||||
out.sin6_scope_id = 0;
|
||||
if (endpoint.address.IsLinkLocal() && endpoint.address.GetScopeId() != 0) {
|
||||
out.sin6_scope_id = endpoint.address.GetScopeId();
|
||||
}
|
||||
out.sin6_port = htons(endpoint.port);
|
||||
endpoint.address.CopyTo(
|
||||
std::span<uint8_t>(reinterpret_cast<uint8_t*>(&out.sin6_addr), 16));
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
66
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_address_posix.h
vendored
Normal file
66
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_address_posix.h
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
// 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_IMPL_SOCKET_ADDRESS_POSIX_H_
|
||||
#define PLATFORM_IMPL_SOCKET_ADDRESS_POSIX_H_
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "platform/base/ip_address.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
class SocketAddressPosix {
|
||||
public:
|
||||
explicit SocketAddressPosix(const struct sockaddr& address);
|
||||
explicit SocketAddressPosix(const IPEndpoint& endpoint);
|
||||
|
||||
SocketAddressPosix(const SocketAddressPosix&) = default;
|
||||
SocketAddressPosix(SocketAddressPosix&&) noexcept = default;
|
||||
SocketAddressPosix& operator=(const SocketAddressPosix&) = default;
|
||||
SocketAddressPosix& operator=(SocketAddressPosix&&) noexcept = default;
|
||||
|
||||
struct sockaddr* address();
|
||||
const struct sockaddr* address() const;
|
||||
socklen_t size() const;
|
||||
IPAddress::Version version() const { return endpoint_.address.version(); }
|
||||
IPEndpoint endpoint() const { return endpoint_; }
|
||||
|
||||
// Recomputes `endpoint_` if `internal_address_` is written to directly, e.g.
|
||||
// by a system call.
|
||||
void RecomputeEndpoint();
|
||||
|
||||
private:
|
||||
void RecomputeEndpoint(IPAddress::Version version);
|
||||
|
||||
// The way the sockaddr_* family works in POSIX is pretty unintuitive. The
|
||||
// sockaddr_in and sockaddr_in6 structs can be reinterpreted as type
|
||||
// sockaddr, however they don't have a common parent--the types are unrelated.
|
||||
// Our solution for this is to wrap sockaddr_in* in a union, so that our code
|
||||
// can be simplified since most platform APIs just take a sockaddr.
|
||||
union SocketAddressIn {
|
||||
struct sockaddr_in v4;
|
||||
struct sockaddr_in6 v6;
|
||||
};
|
||||
|
||||
SocketAddressIn internal_address_;
|
||||
IPEndpoint endpoint_;
|
||||
};
|
||||
|
||||
IPAddress GetIPAddressFromSockAddr(const struct sockaddr_in& sa);
|
||||
IPAddress GetIPAddressFromSockAddr(const struct sockaddr_in6& sa);
|
||||
|
||||
struct sockaddr_in ToSockAddrIn(const IPEndpoint& endpoint);
|
||||
struct sockaddr_in6 ToSockAddrIn6(const IPEndpoint& endpoint);
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_IMPL_SOCKET_ADDRESS_POSIX_H_
|
||||
27
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_handle.h
vendored
Normal file
27
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_handle.h
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// 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_IMPL_SOCKET_HANDLE_H_
|
||||
#define PLATFORM_IMPL_SOCKET_HANDLE_H_
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
// A SocketHandle is the handle used to access a Socket by the underlying
|
||||
// platform.
|
||||
struct SocketHandle;
|
||||
|
||||
struct SocketHandleHash {
|
||||
size_t operator()(const SocketHandle& handle) const;
|
||||
};
|
||||
|
||||
bool operator==(const SocketHandle& lhs, const SocketHandle& rhs);
|
||||
inline bool operator!=(const SocketHandle& lhs, const SocketHandle& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_IMPL_SOCKET_HANDLE_H_
|
||||
22
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_handle_posix.cc
vendored
Normal file
22
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_handle_posix.cc
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// 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/impl/socket_handle_posix.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
SocketHandle::SocketHandle(int descriptor) : fd(descriptor) {}
|
||||
|
||||
bool operator==(const SocketHandle& lhs, const SocketHandle& rhs) {
|
||||
return lhs.fd == rhs.fd;
|
||||
}
|
||||
|
||||
size_t SocketHandleHash::operator()(const SocketHandle& handle) const {
|
||||
return std::hash<int>()(handle.fd);
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
19
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_handle_posix.h
vendored
Normal file
19
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_handle_posix.h
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// 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_IMPL_SOCKET_HANDLE_POSIX_H_
|
||||
#define PLATFORM_IMPL_SOCKET_HANDLE_POSIX_H_
|
||||
|
||||
#include "platform/impl/socket_handle.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
struct SocketHandle {
|
||||
explicit SocketHandle(int descriptor);
|
||||
int fd;
|
||||
};
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_IMPL_SOCKET_HANDLE_POSIX_H_
|
||||
170
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_handle_waiter.cc
vendored
Normal file
170
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_handle_waiter.cc
vendored
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
// 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/impl/socket_handle_waiter.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
|
||||
#include "platform/impl/socket_handle_posix.h"
|
||||
#include "util/osp_logging.h"
|
||||
#include "util/std_util.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
SocketHandleWaiter::SocketHandleWaiter(ClockNowFunctionPtr now_function)
|
||||
: now_function_(now_function) {}
|
||||
|
||||
SocketHandleWaiter::Subscriber::~Subscriber() = default;
|
||||
SocketHandleWaiter::~SocketHandleWaiter() = default;
|
||||
|
||||
void SocketHandleWaiter::Subscribe(Subscriber* subscriber,
|
||||
SocketHandleRef handle,
|
||||
uint32_t flags) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (handle_mappings_.find(handle) == handle_mappings_.end()) {
|
||||
handle_mappings_.emplace(handle, SocketSubscription{subscriber, flags});
|
||||
}
|
||||
}
|
||||
|
||||
void SocketHandleWaiter::Unsubscribe(Subscriber* subscriber,
|
||||
SocketHandleRef handle) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
auto iterator = handle_mappings_.find(handle);
|
||||
if (handle_mappings_.find(handle) != handle_mappings_.end()) {
|
||||
handle_mappings_.erase(iterator);
|
||||
}
|
||||
}
|
||||
|
||||
void SocketHandleWaiter::UnsubscribeAll(Subscriber* subscriber) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
for (auto it = handle_mappings_.begin(); it != handle_mappings_.end();) {
|
||||
if (it->second.subscriber == subscriber) {
|
||||
it = handle_mappings_.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SocketHandleWaiter::OnHandleDeletion(
|
||||
Subscriber* subscriber,
|
||||
SocketHandleRef handle,
|
||||
bool disable_locking_for_testing) OSP_NO_THREAD_SAFETY_ANALYSIS {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
auto it = handle_mappings_.find(handle);
|
||||
if (it != handle_mappings_.end()) {
|
||||
handle_mappings_.erase(it);
|
||||
if (!disable_locking_for_testing) {
|
||||
handles_being_deleted_.push_back(handle);
|
||||
|
||||
OSP_DVLOG << "Starting to block for handle deletion";
|
||||
// This code will allow us to block completion of the socket destructor
|
||||
// (and subsequent invalidation of pointers to this socket) until we no
|
||||
// longer are waiting on a SELECT(...) call to it, since we only signal
|
||||
// this condition variable's wait(...) to proceed outside of SELECT(...).
|
||||
while (Contains(handles_being_deleted_, handle)) {
|
||||
handle_deletion_block_.wait(lock);
|
||||
}
|
||||
OSP_DVLOG << "\tDone blocking for handle deletion!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SocketHandleWaiter::ProcessReadyHandles(
|
||||
std::vector<HandleWithSubscription>* handles,
|
||||
Clock::duration timeout) {
|
||||
if (handles->empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Clock::time_point start_time = now_function_();
|
||||
// Process the stalest handles one by one until we hit our timeout.
|
||||
do {
|
||||
Clock::time_point oldest_time = Clock::time_point::max();
|
||||
HandleWithSubscription& oldest_handle = handles->at(0);
|
||||
for (HandleWithSubscription& handle : *handles) {
|
||||
// Skip already processed handles.
|
||||
if (handle.subscription->last_updated >= start_time) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Select the oldest handle.
|
||||
if (handle.subscription->last_updated < oldest_time) {
|
||||
oldest_time = handle.subscription->last_updated;
|
||||
oldest_handle = handle;
|
||||
}
|
||||
}
|
||||
|
||||
// Already processed all handles.
|
||||
if (oldest_time == Clock::time_point::max()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process the oldest handle.
|
||||
oldest_handle.subscription->last_updated = now_function_();
|
||||
oldest_handle.subscription->subscriber->ProcessReadyHandle(
|
||||
oldest_handle.ready_handle.handle, oldest_handle.ready_handle.flags);
|
||||
} while (now_function_() - start_time <= timeout);
|
||||
}
|
||||
|
||||
Error SocketHandleWaiter::ProcessHandles(Clock::duration timeout) {
|
||||
Clock::time_point start_time = now_function_();
|
||||
std::vector<HandleWithFlags> handles;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
handles_being_deleted_.clear();
|
||||
handle_deletion_block_.notify_all();
|
||||
handles.reserve(handle_mappings_.size());
|
||||
for (auto& pair : handle_mappings_) {
|
||||
uint32_t flags = pair.second.flags;
|
||||
// Remove the write flag if there is no pending write.
|
||||
if (flags & kWritable) {
|
||||
const bool has_pending_write =
|
||||
pair.second.subscriber->HasPendingWrite(pair.first);
|
||||
if (!has_pending_write) {
|
||||
flags &= ~kWritable;
|
||||
}
|
||||
}
|
||||
handles.push_back(HandleWithFlags{.handle = pair.first, .flags = flags});
|
||||
}
|
||||
}
|
||||
if (handles.empty()) {
|
||||
return Error::Code::kAgain;
|
||||
}
|
||||
|
||||
Clock::time_point current_time = now_function_();
|
||||
Clock::duration remaining_timeout = timeout - (current_time - start_time);
|
||||
ErrorOr<std::vector<HandleWithFlags>> changed_handles =
|
||||
AwaitSocketsReady(handles, remaining_timeout);
|
||||
|
||||
std::vector<HandleWithSubscription> ready_handles;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
handles_being_deleted_.clear();
|
||||
handle_deletion_block_.notify_all();
|
||||
if (changed_handles) {
|
||||
auto& ch = changed_handles.value();
|
||||
ready_handles.reserve(ch.size());
|
||||
for (const auto& handle : ch) {
|
||||
auto mapping_it = handle_mappings_.find(handle.handle);
|
||||
if (mapping_it != handle_mappings_.end()) {
|
||||
ready_handles.push_back(
|
||||
HandleWithSubscription{handle, &(mapping_it->second)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed_handles.is_error()) {
|
||||
return changed_handles.error();
|
||||
}
|
||||
|
||||
current_time = now_function_();
|
||||
remaining_timeout = timeout - (current_time - start_time);
|
||||
ProcessReadyHandles(&ready_handles, remaining_timeout);
|
||||
}
|
||||
return Error::None();
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
151
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_handle_waiter.h
vendored
Normal file
151
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_handle_waiter.h
vendored
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
// 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_IMPL_SOCKET_HANDLE_WAITER_H_
|
||||
#define PLATFORM_IMPL_SOCKET_HANDLE_WAITER_H_
|
||||
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "platform/api/time.h"
|
||||
#include "platform/base/error.h"
|
||||
#include "platform/impl/socket_handle.h"
|
||||
#include "util/raw_ptr.h"
|
||||
#include "util/thread_annotations.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
// The class responsible for calling platform-level method to watch UDP sockets
|
||||
// for available read data. Reading from these sockets is handled at a higher
|
||||
// layer.
|
||||
class SocketHandleWaiter {
|
||||
public:
|
||||
using SocketHandleRef = std::reference_wrapper<const SocketHandle>;
|
||||
|
||||
// Used to manage what types of events subscribers are subscribed to.
|
||||
enum Flags {
|
||||
kReadable = 1 << 0,
|
||||
kWritable = 1 << 1,
|
||||
};
|
||||
|
||||
// Common flag configurations.
|
||||
static inline constexpr uint32_t kReadWriteFlags =
|
||||
Flags::kReadable | Flags::kWritable;
|
||||
|
||||
class Subscriber {
|
||||
public:
|
||||
virtual ~Subscriber();
|
||||
|
||||
// Provides a socket handle to the subscriber which has data waiting to be
|
||||
// processed.
|
||||
virtual void ProcessReadyHandle(SocketHandleRef handle, uint32_t flags) = 0;
|
||||
|
||||
// Method used to optimize event notifications. Generally speaking,
|
||||
// sockets are ready for writing very often, causing the network event
|
||||
// loop to be really busy -- a select() call may complete as frequently as
|
||||
// every few nanoseconds -- so we really only want to be notified that a
|
||||
// socket is ready for writing when we actually have something to write.
|
||||
//
|
||||
// NOTE: this is only used if the subscriber is subscribed to write events.
|
||||
virtual bool HasPendingWrite(SocketHandleRef handle) = 0;
|
||||
};
|
||||
|
||||
explicit SocketHandleWaiter(ClockNowFunctionPtr now_function);
|
||||
SocketHandleWaiter(const SocketHandleWaiter&) = delete;
|
||||
SocketHandleWaiter(SocketHandleWaiter&&) noexcept = delete;
|
||||
SocketHandleWaiter& operator=(const SocketHandleWaiter&) = delete;
|
||||
SocketHandleWaiter& operator=(SocketHandleWaiter&&) = delete;
|
||||
virtual ~SocketHandleWaiter();
|
||||
|
||||
// Start notifying `subscriber` whenever `handle` has an event. May be called
|
||||
// multiple times, to be notified for multiple handles, but should not be
|
||||
// called multiple times for the same handle.
|
||||
void Subscribe(Subscriber* subscriber,
|
||||
SocketHandleRef handle,
|
||||
uint32_t flags);
|
||||
|
||||
// Stop receiving notifications for one of the handles currently subscribed
|
||||
// to.
|
||||
void Unsubscribe(Subscriber* subscriber, SocketHandleRef handle);
|
||||
|
||||
// Stop receiving notifications for all handles currently subscribed to, or
|
||||
// no-op if there are no subscriptions.
|
||||
void UnsubscribeAll(Subscriber* subscriber);
|
||||
|
||||
// Called when a handle will be deleted to ensure that deletion can proceed
|
||||
// safely.
|
||||
void OnHandleDeletion(Subscriber* subscriber,
|
||||
SocketHandleRef handle,
|
||||
bool disable_locking_for_testing = false)
|
||||
OSP_NO_THREAD_SAFETY_ANALYSIS;
|
||||
|
||||
// Gets all socket handles to process, checks them for readable data, and
|
||||
// handles any changes that have occurred.
|
||||
Error ProcessHandles(Clock::duration timeout);
|
||||
|
||||
protected:
|
||||
struct HandleWithFlags {
|
||||
SocketHandleRef handle;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
// Waits until data is available in one of the provided sockets or the
|
||||
// provided timeout has passed - whichever is first. If any sockets have data
|
||||
// available, they are returned.
|
||||
//
|
||||
// NOTE: The handle `flags` are checked against the subscriber's
|
||||
// HasPendingWrite() method to ensure that the kWritable flag is only passed
|
||||
// if there is a pending write before this method is called. The subscriber
|
||||
// may be deleted while this method is being invoked, however the handle
|
||||
// itself is guaranteed to not be deleted until the invocation of this method
|
||||
// has been completed.
|
||||
virtual ErrorOr<std::vector<HandleWithFlags>> AwaitSocketsReady(
|
||||
const std::vector<HandleWithFlags>& sockets,
|
||||
const Clock::duration& timeout) = 0;
|
||||
|
||||
private:
|
||||
struct SocketSubscription {
|
||||
raw_ptr<Subscriber> subscriber = nullptr;
|
||||
// Subscribers are only informed of flags that they are interested in.
|
||||
uint32_t flags = 0;
|
||||
Clock::time_point last_updated = Clock::time_point::min();
|
||||
};
|
||||
|
||||
struct HandleWithSubscription {
|
||||
HandleWithFlags ready_handle;
|
||||
// Reference to the original subscription in the unordered map, so
|
||||
// we can keep track of when we updated this socket handle.
|
||||
raw_ptr<SocketSubscription> subscription;
|
||||
};
|
||||
|
||||
// Call the subscriber associated with each changed handle. Handles are only
|
||||
// processed until `timeout` is exceeded. Must be called with `mutex_` held.
|
||||
void ProcessReadyHandles(std::vector<HandleWithSubscription>* handles,
|
||||
Clock::duration timeout);
|
||||
|
||||
// Guards against concurrent access to all other class data members.
|
||||
std::mutex mutex_;
|
||||
|
||||
// Blocks deletion of handles until they are no longer being watched.
|
||||
std::condition_variable handle_deletion_block_;
|
||||
|
||||
// Set of handles currently being deleted, for ensuring handle_deletion_block_
|
||||
// does not exit prematurely.
|
||||
std::vector<SocketHandleRef> handles_being_deleted_ OSP_GUARDED_BY(mutex_);
|
||||
|
||||
// Set of all socket handles currently being watched, mapped to the subscriber
|
||||
// that is watching them.
|
||||
std::unordered_map<SocketHandleRef, SocketSubscription, SocketHandleHash>
|
||||
handle_mappings_ OSP_GUARDED_BY(mutex_);
|
||||
|
||||
const ClockNowFunctionPtr now_function_;
|
||||
};
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_IMPL_SOCKET_HANDLE_WAITER_H_
|
||||
102
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_handle_waiter_posix.cc
vendored
Normal file
102
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_handle_waiter_posix.cc
vendored
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
// 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/impl/socket_handle_waiter_posix.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "platform/base/error.h"
|
||||
#include "platform/impl/socket_handle_posix.h"
|
||||
#include "platform/impl/timeval_posix.h"
|
||||
#include "platform/impl/udp_socket_posix.h"
|
||||
#include "util/osp_logging.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
SocketHandleWaiterPosix::SocketHandleWaiterPosix(
|
||||
ClockNowFunctionPtr now_function)
|
||||
: SocketHandleWaiter(now_function) {}
|
||||
|
||||
SocketHandleWaiterPosix::~SocketHandleWaiterPosix() = default;
|
||||
|
||||
ErrorOr<std::vector<SocketHandleWaiterPosix::HandleWithFlags>>
|
||||
SocketHandleWaiterPosix::AwaitSocketsReady(
|
||||
const std::vector<SocketHandleWaiterPosix::HandleWithFlags>& sockets,
|
||||
const Clock::duration& timeout) {
|
||||
int max_fd = -1;
|
||||
fd_set read_handles{};
|
||||
fd_set write_handles{};
|
||||
|
||||
FD_ZERO(&read_handles);
|
||||
FD_ZERO(&write_handles);
|
||||
for (const HandleWithFlags& hwf : sockets) {
|
||||
if (hwf.flags & Flags::kReadable) {
|
||||
FD_SET(hwf.handle.get().fd, &read_handles);
|
||||
}
|
||||
|
||||
// Only add the socket to the write_handles list if it is configured for
|
||||
// write events and also has a pending write. This keeps us from polling
|
||||
// select every few nanoseconds.
|
||||
if (hwf.flags & Flags::kWritable) {
|
||||
FD_SET(hwf.handle.get().fd, &write_handles);
|
||||
}
|
||||
max_fd = std::max(max_fd, hwf.handle.get().fd);
|
||||
}
|
||||
if (max_fd < 0) {
|
||||
return Error::Code::kIOFailure;
|
||||
}
|
||||
|
||||
struct timeval tv {
|
||||
ToTimeval(timeout)
|
||||
};
|
||||
// This value is set to 'max_fd + 1' by convention. Also, select() is
|
||||
// level-triggered so incomplete reads/writes by the caller are fine and will
|
||||
// be picked up again on the next select() call. For more information, see:
|
||||
// http://man7.org/linux/man-pages/man2/select.2.html
|
||||
const int max_fd_to_watch = max_fd + 1;
|
||||
const int rv =
|
||||
select(max_fd_to_watch, &read_handles, &write_handles, nullptr, &tv);
|
||||
if (rv == -1) {
|
||||
// This is the case when an error condition is hit within the select(...)
|
||||
// command.
|
||||
return Error::Code::kIOFailure;
|
||||
} else if (rv == 0) {
|
||||
// This occurs when no sockets have a pending read.
|
||||
return Error::Code::kAgain;
|
||||
}
|
||||
|
||||
std::vector<HandleWithFlags> changed_handles;
|
||||
for (const HandleWithFlags& hwf : sockets) {
|
||||
uint32_t flags = 0;
|
||||
if (FD_ISSET(hwf.handle.get().fd, &read_handles)) {
|
||||
flags |= Flags::kReadable;
|
||||
}
|
||||
if (FD_ISSET(hwf.handle.get().fd, &write_handles)) {
|
||||
flags |= Flags::kWritable;
|
||||
}
|
||||
if (flags) {
|
||||
changed_handles.push_back({hwf.handle, flags});
|
||||
}
|
||||
}
|
||||
return changed_handles;
|
||||
}
|
||||
|
||||
void SocketHandleWaiterPosix::RunUntilStopped() {
|
||||
const bool was_running = is_running_.exchange(true);
|
||||
OSP_CHECK(!was_running);
|
||||
|
||||
constexpr Clock::duration kHandleReadyTimeout = std::chrono::milliseconds(50);
|
||||
while (is_running_) {
|
||||
ProcessHandles(kHandleReadyTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
void SocketHandleWaiterPosix::RequestStopSoon() {
|
||||
is_running_.store(false);
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
45
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_handle_waiter_posix.h
vendored
Normal file
45
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_handle_waiter_posix.h
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// 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_IMPL_SOCKET_HANDLE_WAITER_POSIX_H_
|
||||
#define PLATFORM_IMPL_SOCKET_HANDLE_WAITER_POSIX_H_
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "platform/impl/socket_handle_waiter.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
class SocketHandleWaiterPosix : public SocketHandleWaiter {
|
||||
public:
|
||||
using SocketHandleRef = SocketHandleWaiter::SocketHandleRef;
|
||||
using HandleWithFlags = SocketHandleWaiter::HandleWithFlags;
|
||||
|
||||
explicit SocketHandleWaiterPosix(ClockNowFunctionPtr now_function);
|
||||
~SocketHandleWaiterPosix() override;
|
||||
|
||||
// Runs the Wait function in a loop until the below RequestStopSoon function
|
||||
// is called.
|
||||
void RunUntilStopped();
|
||||
|
||||
// Signals for the RunUntilStopped loop to cease running.
|
||||
void RequestStopSoon();
|
||||
|
||||
protected:
|
||||
ErrorOr<std::vector<HandleWithFlags>> AwaitSocketsReady(
|
||||
const std::vector<HandleWithFlags>& sockets,
|
||||
const Clock::duration& timeout) override;
|
||||
|
||||
private:
|
||||
// Atomic so that we can perform atomic exchanges.
|
||||
std::atomic_bool is_running_;
|
||||
};
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_IMPL_SOCKET_HANDLE_WAITER_POSIX_H_
|
||||
37
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_state.h
vendored
Normal file
37
breadcast-caststream-sys/vendor/openscreen/platform/impl/socket_state.h
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// 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_IMPL_SOCKET_STATE_H_
|
||||
#define PLATFORM_IMPL_SOCKET_STATE_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
// TcpSocketState should be used by TCP and TLS sockets for indicating
|
||||
// current state. NOTE: socket state transitions should only happen in
|
||||
// the listed order. New states should be added in appropriate order.
|
||||
enum class TcpSocketState {
|
||||
// Socket is not connected.
|
||||
kNotConnected = 0,
|
||||
|
||||
// Socket is actively listening for incoming connections.
|
||||
kListening,
|
||||
|
||||
// Socket is currently being connected.
|
||||
kConnecting,
|
||||
|
||||
// Socket is actively connected to a remote address.
|
||||
kConnected,
|
||||
|
||||
// The socket connection has been terminated, either by Close() or
|
||||
// by the remote side.
|
||||
kClosed
|
||||
};
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_IMPL_SOCKET_STATE_H_
|
||||
197
breadcast-caststream-sys/vendor/openscreen/platform/impl/task_runner.cc
vendored
Normal file
197
breadcast-caststream-sys/vendor/openscreen/platform/impl/task_runner.cc
vendored
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
// 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/impl/task_runner.h"
|
||||
|
||||
#include <csignal>
|
||||
#include <thread>
|
||||
|
||||
#include "util/osp_logging.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
namespace {
|
||||
|
||||
// This is mutated by the signal handler installed by RunUntilSignaled(), and is
|
||||
// checked by RunUntilStopped().
|
||||
//
|
||||
// Per the C++14 spec, passing visible changes to memory between a signal
|
||||
// handler and a program thread must be done through a volatile variable.
|
||||
volatile enum {
|
||||
kNotRunning,
|
||||
kNotSignaled,
|
||||
kSignaled
|
||||
} g_signal_state = kNotRunning;
|
||||
|
||||
void OnReceivedSignal(int signal) {
|
||||
g_signal_state = kSignaled;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TaskRunnerImpl::TaskWaiter::~TaskWaiter() = default;
|
||||
|
||||
TaskRunnerImpl::TaskRunnerImpl(ClockNowFunctionPtr now_function,
|
||||
TaskWaiter* event_waiter,
|
||||
Clock::duration waiter_timeout)
|
||||
: now_function_(now_function),
|
||||
is_running_(false),
|
||||
task_waiter_(event_waiter),
|
||||
waiter_timeout_(waiter_timeout) {}
|
||||
|
||||
TaskRunnerImpl::~TaskRunnerImpl() {
|
||||
// Ensure no thread is currently executing inside RunUntilStopped().
|
||||
OSP_CHECK_EQ(task_runner_thread_id_, std::thread::id());
|
||||
}
|
||||
|
||||
void TaskRunnerImpl::PostPackagedTask(Task task) {
|
||||
std::lock_guard<std::mutex> lock(task_mutex_);
|
||||
tasks_.emplace_back(std::move(task));
|
||||
if (task_waiter_) {
|
||||
task_waiter_->OnTaskPosted();
|
||||
} else {
|
||||
run_loop_wakeup_.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void TaskRunnerImpl::PostPackagedTaskWithDelay(Task task,
|
||||
Clock::duration delay) {
|
||||
std::lock_guard<std::mutex> lock(task_mutex_);
|
||||
if (delay <= Clock::duration::zero()) {
|
||||
tasks_.emplace_back(std::move(task));
|
||||
} else {
|
||||
delayed_tasks_.emplace(
|
||||
std::make_pair(now_function_() + delay, std::move(task)));
|
||||
}
|
||||
if (task_waiter_) {
|
||||
task_waiter_->OnTaskPosted();
|
||||
} else {
|
||||
run_loop_wakeup_.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
bool TaskRunnerImpl::IsRunningOnTaskRunner() {
|
||||
return task_runner_thread_id_ == std::this_thread::get_id();
|
||||
}
|
||||
|
||||
void TaskRunnerImpl::RunUntilStopped() {
|
||||
OSP_CHECK(!is_running_);
|
||||
task_runner_thread_id_ = std::this_thread::get_id();
|
||||
is_running_ = true;
|
||||
|
||||
OSP_DVLOG << "Running tasks until stopped...";
|
||||
// Main loop: Run until the `is_running_` flag is set back to false by the
|
||||
// "quit task" posted by RequestStopSoon(), or the process received a
|
||||
// termination signal.
|
||||
while (is_running_) {
|
||||
ScheduleDelayedTasks();
|
||||
if (GrabMoreRunnableTasks()) {
|
||||
RunRunnableTasks();
|
||||
}
|
||||
if (g_signal_state == kSignaled) {
|
||||
is_running_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
OSP_DVLOG << "Finished running, entering flushing phase...";
|
||||
// Flushing phase: Ensure all immediately-runnable tasks are run before
|
||||
// returning. Since running some tasks might cause more immediately-runnable
|
||||
// tasks to be posted, loop until there is no more work.
|
||||
//
|
||||
// If there is bad code that posts tasks indefinitely, this loop will never
|
||||
// break. However, that also means there is a code path spinning a CPU core at
|
||||
// 100% all the time. Rather than mitigate this problem scenario, purposely
|
||||
// let it manifest here in the hopes that unit testing will reveal it (e.g., a
|
||||
// unit test that never finishes running).
|
||||
while (GrabMoreRunnableTasks()) {
|
||||
RunRunnableTasks();
|
||||
}
|
||||
OSP_DVLOG << "Finished flushing...";
|
||||
task_runner_thread_id_ = std::thread::id();
|
||||
}
|
||||
|
||||
void TaskRunnerImpl::RunUntilSignaled() {
|
||||
OSP_CHECK_EQ(g_signal_state, kNotRunning)
|
||||
<< __func__ << " may not be invoked concurrently.";
|
||||
g_signal_state = kNotSignaled;
|
||||
const auto old_sigint_handler = std::signal(SIGINT, &OnReceivedSignal);
|
||||
const auto old_sigterm_handler = std::signal(SIGTERM, &OnReceivedSignal);
|
||||
#if defined(SIGHUP)
|
||||
const auto old_sighup_handler = std::signal(SIGHUP, &OnReceivedSignal);
|
||||
#endif
|
||||
|
||||
RunUntilStopped();
|
||||
|
||||
std::signal(SIGINT, old_sigint_handler);
|
||||
std::signal(SIGTERM, old_sigterm_handler);
|
||||
#if defined(SIGHUP)
|
||||
std::signal(SIGHUP, old_sighup_handler);
|
||||
#endif
|
||||
OSP_DVLOG << "Received signal, setting state to not running...";
|
||||
g_signal_state = kNotRunning;
|
||||
}
|
||||
|
||||
void TaskRunnerImpl::RequestStopSoon() {
|
||||
PostTask([this]() { is_running_ = false; });
|
||||
}
|
||||
|
||||
void TaskRunnerImpl::RunRunnableTasks() {
|
||||
for (TaskWithMetadata& running_task : running_tasks_) {
|
||||
// Move the task to the stack so that its bound state is freed immediately
|
||||
// after being run.
|
||||
TaskWithMetadata task = std::move(running_task);
|
||||
task();
|
||||
}
|
||||
running_tasks_.clear();
|
||||
}
|
||||
|
||||
void TaskRunnerImpl::ScheduleDelayedTasks() {
|
||||
std::lock_guard<std::mutex> lock(task_mutex_);
|
||||
|
||||
// Getting the time can be expensive on some platforms, so only get it once.
|
||||
const auto current_time = now_function_();
|
||||
const auto end_of_range = delayed_tasks_.upper_bound(current_time);
|
||||
for (auto it = delayed_tasks_.begin(); it != end_of_range; ++it) {
|
||||
tasks_.push_back(std::move(it->second));
|
||||
}
|
||||
delayed_tasks_.erase(delayed_tasks_.begin(), end_of_range);
|
||||
}
|
||||
|
||||
bool TaskRunnerImpl::GrabMoreRunnableTasks() OSP_NO_THREAD_SAFETY_ANALYSIS {
|
||||
OSP_CHECK(running_tasks_.empty());
|
||||
|
||||
std::unique_lock<std::mutex> lock(task_mutex_);
|
||||
if (!tasks_.empty()) {
|
||||
running_tasks_.swap(tasks_);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_running_) {
|
||||
return false; // Stop was requested. Don't wait for more tasks.
|
||||
}
|
||||
|
||||
if (task_waiter_) {
|
||||
Clock::duration timeout = waiter_timeout_;
|
||||
if (!delayed_tasks_.empty()) {
|
||||
Clock::duration next_task_delta =
|
||||
delayed_tasks_.begin()->first - now_function_();
|
||||
if (next_task_delta < timeout) {
|
||||
timeout = next_task_delta;
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
task_waiter_->WaitForTaskToBePosted(timeout);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (delayed_tasks_.empty()) {
|
||||
run_loop_wakeup_.wait(lock);
|
||||
} else {
|
||||
run_loop_wakeup_.wait_for(lock,
|
||||
delayed_tasks_.begin()->first - now_function_());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
150
breadcast-caststream-sys/vendor/openscreen/platform/impl/task_runner.h
vendored
Normal file
150
breadcast-caststream-sys/vendor/openscreen/platform/impl/task_runner.h
vendored
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
// 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_IMPL_TASK_RUNNER_H_
|
||||
#define PLATFORM_IMPL_TASK_RUNNER_H_
|
||||
|
||||
#include <condition_variable> // NOLINT
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "platform/api/task_runner.h"
|
||||
#include "platform/api/time.h"
|
||||
#include "platform/base/error.h"
|
||||
#include "util/raw_ptr.h"
|
||||
#include "util/thread_annotations.h"
|
||||
#include "util/trace_logging.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
class TaskRunnerImpl : public TaskRunner {
|
||||
public:
|
||||
using Task = TaskRunner::Task;
|
||||
|
||||
class TaskWaiter {
|
||||
public:
|
||||
virtual ~TaskWaiter();
|
||||
|
||||
// These calls should be thread-safe. The absolute minimum is that
|
||||
// OnTaskPosted must be safe to call from another thread while this is
|
||||
// inside WaitForTaskToBePosted. NOTE: There may be spurious wakeups from
|
||||
// WaitForTaskToBePosted depending on whether the specific implementation
|
||||
// chooses to clear queued WakeUps before entering WaitForTaskToBePosted.
|
||||
|
||||
// Blocks until some event occurs, which means new tasks may have been
|
||||
// posted. Wait may only block up to `timeout` where 0 means don't block at
|
||||
// all (not block forever).
|
||||
virtual Error WaitForTaskToBePosted(Clock::duration timeout) = 0;
|
||||
|
||||
// If a WaitForTaskToBePosted call is currently blocking, unblock it
|
||||
// immediately.
|
||||
virtual void OnTaskPosted() = 0;
|
||||
};
|
||||
|
||||
explicit TaskRunnerImpl(
|
||||
ClockNowFunctionPtr now_function,
|
||||
TaskWaiter* event_waiter = nullptr,
|
||||
Clock::duration waiter_timeout = std::chrono::milliseconds(100));
|
||||
TaskRunnerImpl(const TaskRunnerImpl&) = delete;
|
||||
TaskRunnerImpl(TaskRunnerImpl&&) noexcept = delete;
|
||||
TaskRunnerImpl& operator=(const TaskRunnerImpl&) = delete;
|
||||
TaskRunnerImpl& operator=(TaskRunnerImpl&&) = delete;
|
||||
|
||||
// TaskRunner overrides
|
||||
~TaskRunnerImpl() override;
|
||||
void PostPackagedTask(Task task) override;
|
||||
void PostPackagedTaskWithDelay(Task task, Clock::duration delay) override;
|
||||
bool IsRunningOnTaskRunner() override;
|
||||
|
||||
// Blocks the current thread, executing tasks from the queue with the desired
|
||||
// timing; and does not return until some time after RequestStopSoon() is
|
||||
// called.
|
||||
virtual void RunUntilStopped();
|
||||
|
||||
// Blocks the current thread, executing tasks from the queue with the desired
|
||||
// timing; and does not return until some time after the current process is
|
||||
// signaled with SIGINT or SIGTERM, or after RequestStopSoon() is called.
|
||||
virtual void RunUntilSignaled();
|
||||
|
||||
// Thread-safe method for requesting the TaskRunner to stop running after all
|
||||
// non-delayed tasks in the queue have run. This behavior allows final
|
||||
// clean-up tasks to be executed before the TaskRunner stops.
|
||||
//
|
||||
// If any non-delayed tasks post additional non-delayed tasks, those will be
|
||||
// run as well before returning.
|
||||
virtual void RequestStopSoon();
|
||||
|
||||
private:
|
||||
#if defined(ENABLE_TRACE_LOGGING)
|
||||
// Wrapper around a Task used to store the TraceId Metadata along with the
|
||||
// task itself, and to set the current TraceIdHierarchy before executing the
|
||||
// task.
|
||||
class TaskWithMetadata {
|
||||
public:
|
||||
// NOTE: 'explicit' keyword omitted so that conversion construtor can be
|
||||
// used. This simplifies switching between 'Task' and 'TaskWithMetadata'
|
||||
// based on the compilation flag.
|
||||
TaskWithMetadata(Task task) // NOLINT
|
||||
: task_(std::move(task)), trace_ids_(TRACE_HIERARCHY) {}
|
||||
|
||||
void operator()() {
|
||||
TRACE_SET_HIERARCHY(trace_ids_);
|
||||
std::move(task_)();
|
||||
}
|
||||
|
||||
private:
|
||||
Task task_;
|
||||
TraceIdHierarchy trace_ids_;
|
||||
};
|
||||
#else // !defined(ENABLE_TRACE_LOGGING)
|
||||
using TaskWithMetadata = Task;
|
||||
#endif // defined(ENABLE_TRACE_LOGGING)
|
||||
|
||||
// Helper that runs all tasks in `running_tasks_` and then clears it.
|
||||
void RunRunnableTasks();
|
||||
|
||||
// Look at all tasks in the delayed task queue, then schedule them if the
|
||||
// minimum delay time has elapsed.
|
||||
void ScheduleDelayedTasks();
|
||||
|
||||
// Transfers all ready-to-run tasks from `tasks_` to `running_tasks_`. If
|
||||
// there are no ready-to-run tasks, and `is_running_` is true, this method
|
||||
// will block waiting for new tasks. Returns true if any tasks were
|
||||
// transferred.
|
||||
bool GrabMoreRunnableTasks() OSP_NO_THREAD_SAFETY_ANALYSIS;
|
||||
|
||||
const ClockNowFunctionPtr now_function_;
|
||||
|
||||
// Flag that indicates whether the task runner loop should continue. This is
|
||||
// only meant to be read/written on the thread executing RunUntilStopped().
|
||||
bool is_running_;
|
||||
|
||||
// This mutex is used for `tasks_` and `delayed_tasks_`, and also for
|
||||
// notifying the run loop to wake up when it is waiting for a task to be added
|
||||
// to the queue in `run_loop_wakeup_`.
|
||||
std::mutex task_mutex_;
|
||||
std::vector<TaskWithMetadata> tasks_ OSP_GUARDED_BY(task_mutex_);
|
||||
std::multimap<Clock::time_point, TaskWithMetadata> delayed_tasks_ OSP_GUARDED_BY(task_mutex_);
|
||||
|
||||
// When `task_waiter_` is nullptr, `run_loop_wakeup_` is used for sleeping the
|
||||
// task runner. Otherwise, `run_loop_wakeup_` isn't used and `task_waiter_`
|
||||
// is used instead (along with `waiter_timeout_`).
|
||||
std::condition_variable run_loop_wakeup_;
|
||||
const raw_ptr<TaskWaiter> task_waiter_;
|
||||
Clock::duration waiter_timeout_;
|
||||
|
||||
// To prevent excessive re-allocation of the underlying array of the `tasks_`
|
||||
// vector, use an A/B vector-swap mechanism. `running_tasks_` starts out
|
||||
// empty, and is swapped with `tasks_` when it is time to run the Tasks.
|
||||
std::vector<TaskWithMetadata> running_tasks_;
|
||||
|
||||
std::thread::id task_runner_thread_id_;
|
||||
};
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_IMPL_TASK_RUNNER_H_
|
||||
72
breadcast-caststream-sys/vendor/openscreen/platform/impl/text_trace_logging_platform.cc
vendored
Normal file
72
breadcast-caststream-sys/vendor/openscreen/platform/impl/text_trace_logging_platform.cc
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// 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/impl/text_trace_logging_platform.h"
|
||||
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
|
||||
#include "platform/impl/logging.h"
|
||||
#include "util/chrono_helpers.h"
|
||||
#include "util/osp_logging.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
using clock_operators::operator<<;
|
||||
|
||||
bool TextTraceLoggingPlatform::IsTraceLoggingEnabled(TraceCategory category) {
|
||||
return true;
|
||||
}
|
||||
|
||||
TextTraceLoggingPlatform::TextTraceLoggingPlatform() {
|
||||
StartTracing(this);
|
||||
}
|
||||
|
||||
TextTraceLoggingPlatform::~TextTraceLoggingPlatform() {
|
||||
StopTracing();
|
||||
}
|
||||
|
||||
void TextTraceLoggingPlatform::LogTrace(TraceEvent event,
|
||||
Clock::time_point end_time) {
|
||||
const auto total_runtime = (end_time - event.start_time);
|
||||
std::stringstream ss;
|
||||
ss << "[TRACE" << " (" << std::dec << total_runtime << ")] " << event;
|
||||
LogTraceMessage(ss.str());
|
||||
}
|
||||
|
||||
void TextTraceLoggingPlatform::LogAsyncStart(TraceEvent event) {
|
||||
std::stringstream ss;
|
||||
ss << "[ASYNC TRACE START] " << event;
|
||||
LogTraceMessage(ss.str());
|
||||
}
|
||||
|
||||
void TextTraceLoggingPlatform::LogAsyncEnd(TraceEvent event) {
|
||||
std::stringstream ss;
|
||||
ss << "[ASYNC TRACE END] " << event;
|
||||
LogTraceMessage(ss.str());
|
||||
}
|
||||
|
||||
void TextTraceLoggingPlatform::LogFlow(TraceEvent event, FlowType type) {
|
||||
std::stringstream ss;
|
||||
ss << "[FLOW";
|
||||
if (!event.flow_ids.empty()) {
|
||||
ss << " #" << std::hex << event.flow_ids[0] << std::dec;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case FlowType::kFlowBegin:
|
||||
ss << " BEGIN";
|
||||
break;
|
||||
case FlowType::kFlowStep:
|
||||
ss << " STEP";
|
||||
break;
|
||||
case FlowType::kFlowEnd:
|
||||
ss << " END";
|
||||
break;
|
||||
}
|
||||
ss << "] " << event.ToString();
|
||||
LogTraceMessage(ss.str());
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
30
breadcast-caststream-sys/vendor/openscreen/platform/impl/text_trace_logging_platform.h
vendored
Normal file
30
breadcast-caststream-sys/vendor/openscreen/platform/impl/text_trace_logging_platform.h
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// 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_IMPL_TEXT_TRACE_LOGGING_PLATFORM_H_
|
||||
#define PLATFORM_IMPL_TEXT_TRACE_LOGGING_PLATFORM_H_
|
||||
|
||||
#include "platform/api/trace_logging_platform.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
class TextTraceLoggingPlatform : public TraceLoggingPlatform {
|
||||
public:
|
||||
TextTraceLoggingPlatform();
|
||||
~TextTraceLoggingPlatform() override;
|
||||
|
||||
bool IsTraceLoggingEnabled(TraceCategory category) override;
|
||||
|
||||
void LogTrace(TraceEvent event, Clock::time_point end_time) override;
|
||||
|
||||
void LogAsyncStart(TraceEvent event) override;
|
||||
|
||||
void LogAsyncEnd(TraceEvent event) override;
|
||||
|
||||
void LogFlow(TraceEvent event, FlowType type) override;
|
||||
};
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_IMPL_TEXT_TRACE_LOGGING_PLATFORM_H_
|
||||
49
breadcast-caststream-sys/vendor/openscreen/platform/impl/time.cc
vendored
Normal file
49
breadcast-caststream-sys/vendor/openscreen/platform/impl/time.cc
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// 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.
|
||||
|
||||
#include "platform/api/time.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <ratio>
|
||||
|
||||
#include "util/chrono_helpers.h"
|
||||
#include "util/osp_logging.h"
|
||||
|
||||
using std::chrono::high_resolution_clock;
|
||||
using std::chrono::steady_clock;
|
||||
using std::chrono::system_clock;
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
Clock::time_point Clock::now() noexcept {
|
||||
constexpr bool kSteadyIsGoodEnough =
|
||||
std::ratio_less_equal_v<steady_clock::period, Clock::kRequiredResolution>;
|
||||
constexpr bool kHighResIsGoodEnough =
|
||||
std::ratio_less_equal_v<high_resolution_clock::period,
|
||||
Clock::kRequiredResolution> &&
|
||||
high_resolution_clock::is_steady;
|
||||
static_assert(kSteadyIsGoodEnough || kHighResIsGoodEnough,
|
||||
"No suitable default clock (steady + high enough resolution) "
|
||||
"on this platform");
|
||||
|
||||
// 'if constexpr' guarantees compile-time branching.
|
||||
// We prefer steady_clock if it meets the requirements (usually cheaper).
|
||||
if constexpr (kSteadyIsGoodEnough) {
|
||||
return Clock::time_point(
|
||||
Clock::to_duration(steady_clock::now().time_since_epoch()));
|
||||
} else {
|
||||
return Clock::time_point(
|
||||
Clock::to_duration(high_resolution_clock::now().time_since_epoch()));
|
||||
}
|
||||
}
|
||||
|
||||
std::chrono::seconds GetWallTimeSinceUnixEpoch() noexcept {
|
||||
// C++20 guarantees that system_clock uses the Unix Epoch (1970-01-01).
|
||||
// Use floor to truncate sub-second precision safely.
|
||||
return std::chrono::floor<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch());
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
22
breadcast-caststream-sys/vendor/openscreen/platform/impl/timeval_posix.cc
vendored
Normal file
22
breadcast-caststream-sys/vendor/openscreen/platform/impl/timeval_posix.cc
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// 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/impl/timeval_posix.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "util/chrono_helpers.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
struct timeval ToTimeval(const Clock::duration& timeout) {
|
||||
struct timeval tv {};
|
||||
const auto whole_seconds = to_seconds(timeout);
|
||||
tv.tv_sec = whole_seconds.count();
|
||||
tv.tv_usec = to_microseconds(timeout - whole_seconds).count();
|
||||
|
||||
return tv;
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
18
breadcast-caststream-sys/vendor/openscreen/platform/impl/timeval_posix.h
vendored
Normal file
18
breadcast-caststream-sys/vendor/openscreen/platform/impl/timeval_posix.h
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// 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_IMPL_TIMEVAL_POSIX_H_
|
||||
#define PLATFORM_IMPL_TIMEVAL_POSIX_H_
|
||||
|
||||
#include <sys/time.h> // timeval
|
||||
|
||||
#include "platform/api/time.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
struct timeval ToTimeval(const Clock::duration& timeout);
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_IMPL_TIMEVAL_POSIX_H_
|
||||
665
breadcast-caststream-sys/vendor/openscreen/platform/impl/udp_socket_posix.cc
vendored
Normal file
665
breadcast-caststream-sys/vendor/openscreen/platform/impl/udp_socket_posix.cc
vendored
Normal file
|
|
@ -0,0 +1,665 @@
|
|||
// 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.
|
||||
|
||||
#include "platform/impl/udp_socket_posix.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "platform/api/network_interface.h"
|
||||
#include "platform/api/task_runner.h"
|
||||
#include "platform/base/error.h"
|
||||
#include "platform/impl/socket_address_posix.h"
|
||||
#include "platform/impl/udp_socket_reader_posix.h"
|
||||
#include "util/osp_logging.h"
|
||||
|
||||
namespace openscreen {
|
||||
namespace {
|
||||
|
||||
// 64 KB is the maximum possible UDP datagram size.
|
||||
constexpr int kMaxUdpBufferSize = 64 << 10;
|
||||
|
||||
constexpr bool IsPowerOf2(uint32_t x) {
|
||||
return (x > 0) && ((x & (x - 1)) == 0);
|
||||
}
|
||||
|
||||
static_assert(IsPowerOf2(alignof(struct cmsghdr)),
|
||||
"std::align requires power-of-2 alignment");
|
||||
|
||||
using IPv4NetworkInterfaceIndex = decltype(ip_mreqn().imr_ifindex);
|
||||
using IPv6NetworkInterfaceIndex = decltype(ipv6_mreq().ipv6mr_interface);
|
||||
|
||||
ErrorOr<int> CreateNonBlockingUdpSocket(int domain) {
|
||||
int fd = socket(domain, SOCK_DGRAM, 0);
|
||||
if (fd == -1) {
|
||||
return Error(Error::Code::kInitializationFailure, strerror(errno));
|
||||
}
|
||||
// On non-Linux, the SOCK_NONBLOCK option is not available, so use the
|
||||
// more-portable method of calling fcntl() to set this behavior.
|
||||
if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) == -1) {
|
||||
close(fd);
|
||||
return Error(Error::Code::kInitializationFailure, strerror(errno));
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
UdpSocketPosix::UdpSocketPosix(TaskRunner& task_runner,
|
||||
Client* client,
|
||||
SocketHandle handle,
|
||||
const IPEndpoint& local_endpoint,
|
||||
PlatformClientPosix* platform_client)
|
||||
: task_runner_(task_runner),
|
||||
client_(client),
|
||||
handle_(handle),
|
||||
local_endpoint_(local_endpoint),
|
||||
platform_client_(platform_client) {
|
||||
if (handle_.fd >= 0) {
|
||||
if (platform_client_) {
|
||||
platform_client_->udp_socket_reader()->OnCreate(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UdpSocketPosix::~UdpSocketPosix() {
|
||||
Close();
|
||||
}
|
||||
|
||||
const SocketHandle& UdpSocketPosix::GetHandle() const {
|
||||
return handle_;
|
||||
}
|
||||
|
||||
// static
|
||||
ErrorOr<std::unique_ptr<UdpSocket>> UdpSocket::Create(
|
||||
TaskRunner& task_runner,
|
||||
Client* client,
|
||||
const IPEndpoint& endpoint) {
|
||||
static std::atomic_bool in_create{false};
|
||||
const bool in_create_local = in_create.exchange(true);
|
||||
OSP_CHECK(!in_create_local)
|
||||
<< "Another UdpSocket::Create call is in progress. Calls to this method "
|
||||
"must be seralized.";
|
||||
|
||||
if (in_create_local) {
|
||||
return Error::Code::kAgain;
|
||||
}
|
||||
|
||||
int domain;
|
||||
switch (endpoint.address.version()) {
|
||||
case Version::kV4:
|
||||
domain = AF_INET;
|
||||
break;
|
||||
case Version::kV6:
|
||||
domain = AF_INET6;
|
||||
break;
|
||||
}
|
||||
const ErrorOr<int> fd = CreateNonBlockingUdpSocket(domain);
|
||||
if (!fd) {
|
||||
in_create = false;
|
||||
return fd.error();
|
||||
}
|
||||
|
||||
std::unique_ptr<UdpSocket> socket = std::make_unique<UdpSocketPosix>(
|
||||
task_runner, client, SocketHandle(fd.value()), endpoint);
|
||||
in_create = false;
|
||||
return socket;
|
||||
}
|
||||
|
||||
bool UdpSocketPosix::IsIPv4() const {
|
||||
return local_endpoint_.address.IsV4();
|
||||
}
|
||||
|
||||
bool UdpSocketPosix::IsIPv6() const {
|
||||
return local_endpoint_.address.IsV6();
|
||||
}
|
||||
|
||||
IPEndpoint UdpSocketPosix::GetLocalEndpoint() const {
|
||||
if (local_endpoint_.port == 0) {
|
||||
// Note: If the getsockname() call fails, just assume that's because the
|
||||
// socket isn't bound yet. In this case, leave the original value in-place.
|
||||
switch (local_endpoint_.address.version()) {
|
||||
case UdpSocket::Version::kV4: {
|
||||
struct sockaddr_in address {};
|
||||
socklen_t address_len = sizeof(address);
|
||||
if (getsockname(handle_.fd,
|
||||
reinterpret_cast<struct sockaddr*>(&address),
|
||||
&address_len) == 0) {
|
||||
OSP_CHECK_EQ(address.sin_family, AF_INET);
|
||||
local_endpoint_.address = GetIPAddressFromSockAddr(address);
|
||||
local_endpoint_.port = ntohs(address.sin_port);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case UdpSocket::Version::kV6: {
|
||||
struct sockaddr_in6 address {};
|
||||
socklen_t address_len = sizeof(address);
|
||||
if (getsockname(handle_.fd,
|
||||
reinterpret_cast<struct sockaddr*>(&address),
|
||||
&address_len) == 0) {
|
||||
OSP_CHECK_EQ(address.sin6_family, AF_INET6);
|
||||
local_endpoint_.address = GetIPAddressFromSockAddr(address);
|
||||
local_endpoint_.port = ntohs(address.sin6_port);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return local_endpoint_;
|
||||
}
|
||||
|
||||
void UdpSocketPosix::Bind() {
|
||||
OSP_CHECK(task_runner_->IsRunningOnTaskRunner());
|
||||
if (is_closed()) {
|
||||
OnError(Error::Code::kSocketClosedFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
// This is effectively a boolean passed to setsockopt() to allow a future
|
||||
// bind() on the same socket to succeed, even if the address is already in
|
||||
// use. This is pretty much universally the desired behavior.
|
||||
constexpr int reuse_addr = 1;
|
||||
if (setsockopt(handle_.fd, SOL_SOCKET, SO_REUSEADDR, &reuse_addr,
|
||||
sizeof(reuse_addr)) == -1) {
|
||||
OnError(Error::Code::kSocketOptionSettingFailure);
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_APPLE)
|
||||
// On Mac, SO_REUSEADDR is not enough to allow a bind() on a reusable
|
||||
// multicast socket. We need to also set the option SO_REUSEPORT.
|
||||
constexpr int reuse_port = 1;
|
||||
if (setsockopt(handle_.fd, SOL_SOCKET, SO_REUSEPORT, &reuse_port,
|
||||
sizeof(reuse_port)) == -1) {
|
||||
OnError(Error::Code::kSocketOptionSettingFailure);
|
||||
}
|
||||
#endif // BUILDFLAG(IS_APPLE)
|
||||
|
||||
bool is_bound = false;
|
||||
switch (local_endpoint_.address.version()) {
|
||||
case UdpSocket::Version::kV4: {
|
||||
struct sockaddr_in address = ToSockAddrIn(local_endpoint_);
|
||||
if (bind(handle_.fd, reinterpret_cast<struct sockaddr*>(&address),
|
||||
sizeof(address)) != -1) {
|
||||
is_bound = true;
|
||||
}
|
||||
} break;
|
||||
|
||||
case UdpSocket::Version::kV6: {
|
||||
struct sockaddr_in6 address = ToSockAddrIn6(local_endpoint_);
|
||||
if (bind(handle_.fd, reinterpret_cast<struct sockaddr*>(&address),
|
||||
sizeof(address)) != -1) {
|
||||
is_bound = true;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
if (is_bound) {
|
||||
client_->OnBound(this);
|
||||
} else {
|
||||
OnError(Error::Code::kSocketBindFailure);
|
||||
}
|
||||
}
|
||||
|
||||
void UdpSocketPosix::SetMulticastOutboundInterface(
|
||||
NetworkInterfaceIndex ifindex) {
|
||||
OSP_CHECK(task_runner_->IsRunningOnTaskRunner());
|
||||
if (is_closed()) {
|
||||
OnError(Error::Code::kSocketClosedFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (local_endpoint_.address.version()) {
|
||||
case UdpSocket::Version::kV4: {
|
||||
struct ip_mreqn multicast_properties {};
|
||||
// Appropriate address is set based on `imr_ifindex` when set.
|
||||
multicast_properties.imr_address.s_addr = INADDR_ANY;
|
||||
multicast_properties.imr_multiaddr.s_addr = INADDR_ANY;
|
||||
multicast_properties.imr_ifindex =
|
||||
static_cast<IPv4NetworkInterfaceIndex>(ifindex);
|
||||
if (setsockopt(handle_.fd, IPPROTO_IP, IP_MULTICAST_IF,
|
||||
&multicast_properties,
|
||||
sizeof(multicast_properties)) == -1) {
|
||||
OnError(Error::Code::kSocketOptionSettingFailure);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case UdpSocket::Version::kV6: {
|
||||
const auto index = static_cast<IPv6NetworkInterfaceIndex>(ifindex);
|
||||
if (setsockopt(handle_.fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index,
|
||||
sizeof(index)) == -1) {
|
||||
OnError(Error::Code::kSocketOptionSettingFailure);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
OSP_NOTREACHED();
|
||||
}
|
||||
|
||||
void UdpSocketPosix::JoinMulticastGroup(const IPAddress& address,
|
||||
NetworkInterfaceIndex ifindex) {
|
||||
OSP_CHECK(task_runner_->IsRunningOnTaskRunner());
|
||||
if (is_closed()) {
|
||||
OnError(Error::Code::kSocketClosedFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (local_endpoint_.address.version()) {
|
||||
case UdpSocket::Version::kV4: {
|
||||
// Passed as data to setsockopt(). 1 means return IP_PKTINFO control data
|
||||
// in recvmsg() calls.
|
||||
const int enable_pktinfo = 1;
|
||||
if (setsockopt(handle_.fd, IPPROTO_IP, IP_PKTINFO, &enable_pktinfo,
|
||||
sizeof(enable_pktinfo)) == -1) {
|
||||
OnError(Error::Code::kSocketOptionSettingFailure);
|
||||
return;
|
||||
}
|
||||
struct ip_mreqn multicast_properties {};
|
||||
// Appropriate address is set based on `imr_ifindex` when set.
|
||||
multicast_properties.imr_address.s_addr = INADDR_ANY;
|
||||
multicast_properties.imr_ifindex =
|
||||
static_cast<IPv4NetworkInterfaceIndex>(ifindex);
|
||||
|
||||
#if BUILDFLAG(IS_APPLE)
|
||||
// On macOS, we must specify the interface address, not just the index,
|
||||
// because it ignores imr_ifindex in ip_mreqn (interpreting it as
|
||||
// ip_mreq).
|
||||
const std::vector<InterfaceInfo> interfaces = GetNetworkInterfaces();
|
||||
const auto it = std::find_if(interfaces.begin(), interfaces.end(),
|
||||
[ifindex](const InterfaceInfo& info) {
|
||||
return info.index == ifindex;
|
||||
});
|
||||
|
||||
if (it != interfaces.end()) {
|
||||
for (const auto& ip_net : it->addresses) {
|
||||
if (ip_net.address.version() == IPAddress::Version::kV4) {
|
||||
ip_net.address.CopyToV4(
|
||||
reinterpret_cast<uint8_t*>(&multicast_properties.imr_address));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static_assert(sizeof(multicast_properties.imr_multiaddr) == 4u,
|
||||
"IPv4 address requires exactly 4 bytes");
|
||||
address.CopyTo(std::span<uint8_t>(
|
||||
reinterpret_cast<uint8_t*>(&multicast_properties.imr_multiaddr), 4));
|
||||
if (setsockopt(handle_.fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
||||
&multicast_properties,
|
||||
sizeof(multicast_properties)) == -1) {
|
||||
OnError(Error::Code::kSocketOptionSettingFailure);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case UdpSocket::Version::kV6: {
|
||||
// Passed as data to setsockopt(). 1 means return IPV6_PKTINFO control
|
||||
// data in recvmsg() calls.
|
||||
const int enable_pktinfo = 1;
|
||||
if (setsockopt(handle_.fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
|
||||
&enable_pktinfo, sizeof(enable_pktinfo)) == -1) {
|
||||
OnError(Error::Code::kSocketOptionSettingFailure);
|
||||
return;
|
||||
}
|
||||
struct ipv6_mreq multicast_properties = {
|
||||
{/* filled-in below */},
|
||||
static_cast<IPv6NetworkInterfaceIndex>(ifindex),
|
||||
};
|
||||
static_assert(sizeof(multicast_properties.ipv6mr_multiaddr) == 16u,
|
||||
"IPv6 address requires exactly 16 bytes");
|
||||
address.CopyTo(std::span<uint8_t>(
|
||||
reinterpret_cast<uint8_t*>(&multicast_properties.ipv6mr_multiaddr),
|
||||
16));
|
||||
// Portability note: All platforms support IPV6_JOIN_GROUP, which is
|
||||
// synonymous with IPV6_ADD_MEMBERSHIP.
|
||||
if (setsockopt(handle_.fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
|
||||
&multicast_properties,
|
||||
sizeof(multicast_properties)) == -1) {
|
||||
OnError(Error::Code::kSocketOptionSettingFailure);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
OSP_NOTREACHED();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Examine `posix_errno` to determine whether the specific cause of a failure
|
||||
// was transient or hard, and return the appropriate error response.
|
||||
Error ChooseError(decltype(errno) posix_errno, Error::Code hard_error_code) {
|
||||
if (posix_errno == EAGAIN || posix_errno == EWOULDBLOCK ||
|
||||
posix_errno == ENOBUFS) {
|
||||
return Error(Error::Code::kAgain, strerror(errno));
|
||||
}
|
||||
return Error(hard_error_code, strerror(errno));
|
||||
}
|
||||
|
||||
IPAddress GetIPAddressFromPktInfo(const in_pktinfo& pktinfo) {
|
||||
static_assert(IPAddress::kV4Size == sizeof(pktinfo.ipi_addr),
|
||||
"IPv4 address size mismatch.");
|
||||
return IPAddress(IPAddress::Version::kV4,
|
||||
std::span<const uint8_t>(
|
||||
reinterpret_cast<const uint8_t*>(&pktinfo.ipi_addr), 4));
|
||||
}
|
||||
|
||||
uint16_t GetPortFromFromSockAddr(const sockaddr_in& sa) {
|
||||
return ntohs(sa.sin_port);
|
||||
}
|
||||
|
||||
IPAddress GetIPAddressFromPktInfo(const in6_pktinfo& pktinfo) {
|
||||
return IPAddress(std::span<const uint8_t, 16>(pktinfo.ipi6_addr.s6_addr, 16),
|
||||
pktinfo.ipi6_ifindex);
|
||||
}
|
||||
|
||||
uint16_t GetPortFromFromSockAddr(const sockaddr_in6& sa) {
|
||||
return ntohs(sa.sin6_port);
|
||||
}
|
||||
|
||||
template <class PktInfoType>
|
||||
bool IsPacketInfo(cmsghdr* cmh);
|
||||
|
||||
template <>
|
||||
bool IsPacketInfo<in_pktinfo>(cmsghdr* cmh) {
|
||||
return cmh->cmsg_level == IPPROTO_IP && cmh->cmsg_type == IP_PKTINFO;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool IsPacketInfo<in6_pktinfo>(cmsghdr* cmh) {
|
||||
return cmh->cmsg_level == IPPROTO_IPV6 && cmh->cmsg_type == IPV6_PKTINFO;
|
||||
}
|
||||
|
||||
template <class SockAddrType, class PktInfoType>
|
||||
ErrorOr<UdpPacket> ReceiveMessageInternal(int fd) {
|
||||
// Try to determine the size of the incoming packet. If we cannot,
|
||||
// it's not a fatal error, we will just allocate kMaxUdpBufferSize
|
||||
// and shrink-to-fit below.
|
||||
int upper_bound_bytes = -1;
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
// Returns the exact size of the datagram, or -1 on error.
|
||||
upper_bound_bytes = recv(fd, nullptr, 0, MSG_PEEK | MSG_TRUNC);
|
||||
#elif BUILDFLAG(IS_APPLE)
|
||||
// Can't use recv(MSG_TRUNC) (not supported). Can't use ioctl(FIONREAD)
|
||||
// (returns size in socket queue instead next message size). Use
|
||||
// getsocktopt(...NREAD...) to get the datagram size if possible.
|
||||
// Ref: https://www.unix.com/man-page/mojave/2/getsockopt/
|
||||
socklen_t optlen = sizeof(upper_bound_bytes);
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_NREAD, &upper_bound_bytes, &optlen) == -1) {
|
||||
upper_bound_bytes = -1;
|
||||
}
|
||||
#endif // BUILDFLAG(IS_LINUX)
|
||||
if (upper_bound_bytes > 0) {
|
||||
upper_bound_bytes = std::min(upper_bound_bytes, kMaxUdpBufferSize);
|
||||
} else {
|
||||
upper_bound_bytes = kMaxUdpBufferSize;
|
||||
}
|
||||
|
||||
UdpPacket packet(upper_bound_bytes);
|
||||
struct msghdr msg {};
|
||||
SockAddrType sa{};
|
||||
msg.msg_name = &sa;
|
||||
msg.msg_namelen = sizeof(sa);
|
||||
iovec iov = {packet.data(), packet.size()};
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
// Although we don't do anything with the control buffer, on Linux
|
||||
// it is required for the message to be properly read.
|
||||
#if BUILDFLAG(IS_LINUX)
|
||||
alignas(alignof(cmsghdr)) uint8_t control_buffer[2048];
|
||||
msg.msg_control = control_buffer;
|
||||
msg.msg_controllen = sizeof(control_buffer);
|
||||
#endif // BUILDFLAG(IS_LINUX)
|
||||
|
||||
const ssize_t bytes_received = recvmsg(fd, &msg, 0);
|
||||
if (bytes_received == -1) {
|
||||
OSP_DVLOG << "Failed to read from socket.";
|
||||
return ChooseError(errno, Error::Code::kSocketReadFailure);
|
||||
}
|
||||
// We may not populate the entire packet.
|
||||
OSP_CHECK_LE(static_cast<size_t>(bytes_received), packet.size());
|
||||
packet.resize(bytes_received);
|
||||
|
||||
IPEndpoint source_endpoint = {.address = GetIPAddressFromSockAddr(sa),
|
||||
.port = GetPortFromFromSockAddr(sa)};
|
||||
packet.set_source(std::move(source_endpoint));
|
||||
|
||||
// For multicast sockets, the packet's original destination address may be
|
||||
// the host address (since we called bind()) but it may also be a
|
||||
// multicast address. This may be relevant for handling multicast data;
|
||||
// specifically, mDNSResponder requires this information to work properly.
|
||||
|
||||
socklen_t sa_len = sizeof(sa);
|
||||
if (((msg.msg_flags & MSG_CTRUNC) != 0)) {
|
||||
return Error(Error::Code::kSocketReadFailure, "Packet was truncated");
|
||||
}
|
||||
|
||||
if ((getsockname(fd, reinterpret_cast<sockaddr*>(&sa), &sa_len) == -1)) {
|
||||
return Error(Error::Code::kSocketReadFailure, "Failed to get socket name");
|
||||
}
|
||||
for (cmsghdr* cmh = CMSG_FIRSTHDR(&msg); cmh; cmh = CMSG_NXTHDR(&msg, cmh)) {
|
||||
if (IsPacketInfo<PktInfoType>(cmh)) {
|
||||
PktInfoType* pktinfo = reinterpret_cast<PktInfoType*>(CMSG_DATA(cmh));
|
||||
IPEndpoint destination_endpoint = {
|
||||
.address = GetIPAddressFromPktInfo(*pktinfo),
|
||||
.port = GetPortFromFromSockAddr(sa)};
|
||||
packet.set_destination(std::move(destination_endpoint));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return std::move(packet);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void UdpSocketPosix::ReceiveMessage() {
|
||||
// WARNING: This method may be called on a different thread from the thread
|
||||
// calling into all the other methods.
|
||||
|
||||
if (is_closed()) {
|
||||
task_runner_->PostTask([weak_this = weak_factory_.GetWeakPtr()] {
|
||||
if (auto* self = weak_this.get()) {
|
||||
if (auto* client = self->client_.get()) {
|
||||
client->OnRead(self, Error::Code::kSocketClosedFailure);
|
||||
}
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
ErrorOr<UdpPacket> read_result = Error::Code::kUnknownError;
|
||||
switch (local_endpoint_.address.version()) {
|
||||
case UdpSocket::Version::kV4: {
|
||||
read_result = ReceiveMessageInternal<sockaddr_in, in_pktinfo>(handle_.fd);
|
||||
break;
|
||||
}
|
||||
case UdpSocket::Version::kV6: {
|
||||
read_result =
|
||||
ReceiveMessageInternal<sockaddr_in6, in6_pktinfo>(handle_.fd);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
OSP_NOTREACHED();
|
||||
}
|
||||
}
|
||||
|
||||
task_runner_->PostTask([weak_this = weak_factory_.GetWeakPtr(),
|
||||
result = std::move(read_result)]() mutable {
|
||||
if (auto* self = weak_this.get()) {
|
||||
if (auto* client = self->client_.get()) {
|
||||
client->OnRead(self, std::move(result));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void UdpSocketPosix::SendMessage(ByteView data, const IPEndpoint& dest) {
|
||||
OSP_CHECK(task_runner_->IsRunningOnTaskRunner());
|
||||
if (is_closed()) {
|
||||
if (client_) {
|
||||
client_->OnSendError(this, Error::Code::kSocketClosedFailure);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
struct iovec iov = {
|
||||
reinterpret_cast<void*>(const_cast<uint8_t*>(data.data())), data.size()};
|
||||
struct msghdr msg {};
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = nullptr;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_flags = 0;
|
||||
|
||||
ssize_t num_bytes_sent = -2;
|
||||
switch (dest.address.version()) {
|
||||
case UdpSocket::Version::kV4: {
|
||||
struct sockaddr_in sa {};
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = htons(dest.port);
|
||||
dest.address.CopyTo(std::span<uint8_t>(
|
||||
reinterpret_cast<uint8_t*>(&sa.sin_addr.s_addr), 4));
|
||||
msg.msg_name = &sa;
|
||||
msg.msg_namelen = sizeof(sa);
|
||||
num_bytes_sent = sendmsg(handle_.fd, &msg, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case UdpSocket::Version::kV6: {
|
||||
struct sockaddr_in6 sa {};
|
||||
sa.sin6_family = AF_INET6;
|
||||
sa.sin6_port = htons(dest.port);
|
||||
dest.address.CopyTo(std::span<uint8_t>(
|
||||
reinterpret_cast<uint8_t*>(&sa.sin6_addr.s6_addr), 16));
|
||||
if (dest.address.IsLinkLocal() && dest.address.GetScopeId() != 0) {
|
||||
sa.sin6_scope_id = dest.address.GetScopeId();
|
||||
}
|
||||
msg.msg_name = &sa;
|
||||
msg.msg_namelen = sizeof(sa);
|
||||
num_bytes_sent = sendmsg(handle_.fd, &msg, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_bytes_sent == -1) {
|
||||
if (client_) {
|
||||
client_->OnSendError(this,
|
||||
ChooseError(errno, Error::Code::kSocketSendFailure));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanity-check: UDP datagram sendmsg() is all or nothing.
|
||||
OSP_CHECK_EQ(static_cast<size_t>(num_bytes_sent), data.size());
|
||||
}
|
||||
|
||||
void UdpSocketPosix::SetDscp(UdpSocket::DscpMode mode) {
|
||||
OSP_CHECK(task_runner_->IsRunningOnTaskRunner());
|
||||
if (is_closed()) {
|
||||
OnError(Error::Code::kSocketClosedFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
int level;
|
||||
int option;
|
||||
switch (local_endpoint_.address.version()) {
|
||||
case UdpSocket::Version::kV4:
|
||||
level = IPPROTO_IP;
|
||||
option = IP_TOS;
|
||||
break;
|
||||
case UdpSocket::Version::kV6:
|
||||
level = IPPROTO_IPV6;
|
||||
option = IPV6_TCLASS;
|
||||
break;
|
||||
}
|
||||
|
||||
// The DSCP value is a 6-bit field, while the IP_TOS and IPV6_TCLASS fields
|
||||
// are 8-bit fields that expect the DSCP value in the six most significant
|
||||
// digits.
|
||||
const int value = static_cast<int>(mode) << 2;
|
||||
if (setsockopt(handle_.fd, level, option, &value, sizeof(value)) == -1) {
|
||||
OnError(Error::Code::kSocketOptionSettingFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
OSP_DVLOG << __func__ << ": successfully set DSCP to "
|
||||
<< static_cast<int>(mode);
|
||||
}
|
||||
|
||||
void UdpSocketPosix::OnError(Error::Code error_code) {
|
||||
// The call to Close() may change `errno`, so save it here.
|
||||
const auto original_errno = errno;
|
||||
|
||||
// Close the socket unless the error code represents a transient condition.
|
||||
if (error_code != Error::Code::kNone && error_code != Error::Code::kAgain) {
|
||||
Close();
|
||||
}
|
||||
|
||||
if (client_) {
|
||||
// Call the thread-safe strerror_r() to get the human-readable form of
|
||||
// `errno`. This is a real mess: 1. Since there seems to be no constant
|
||||
// defined for the maximum buffer size in the standard library, 1024 is
|
||||
// used, as suggested by the man page for strerror_r(). 2. There are two
|
||||
// possible versions of this function: The POSIX one returns int(0) on
|
||||
// success, while the legacy GNU-specific one will provide a non-null char
|
||||
// pointer (that may or may not be within the `buffer`).
|
||||
char buffer[1024];
|
||||
const auto result = strerror_r(original_errno, buffer, sizeof(buffer));
|
||||
const char* errno_str;
|
||||
if (std::is_convertible<decltype(result), int>::value &&
|
||||
!result) { // Case 1: POSIX strerror_r() success.
|
||||
errno_str = buffer;
|
||||
} else if (std::is_convertible<decltype(result), const char*>::value &&
|
||||
result) { // Case 2: GNU strerror_r() success.
|
||||
errno_str = reinterpret_cast<const char*>(result);
|
||||
} else { // Case 3: strerror_r() failed (either version).
|
||||
buffer[0] = '\0';
|
||||
errno_str = buffer;
|
||||
}
|
||||
|
||||
std::stringstream stream;
|
||||
stream << "endpoint: " << local_endpoint_ << ", error: " << errno_str;
|
||||
client_->OnError(this, Error(error_code, stream.str()));
|
||||
}
|
||||
}
|
||||
|
||||
void UdpSocketPosix::Close() {
|
||||
if (handle_.fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Notify the UdpSocketReaderPosix that the socket handle is about to be
|
||||
// closed.
|
||||
if (platform_client_) {
|
||||
platform_client_->udp_socket_reader()->OnDestroy(this);
|
||||
}
|
||||
|
||||
// It's now safe to close the socket, since no other thread (e.g., from
|
||||
// UdpSocketReaderPosix) should be inside ReceiveMessage() at this point.
|
||||
close(handle_.fd);
|
||||
handle_.fd = -1;
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
90
breadcast-caststream-sys/vendor/openscreen/platform/impl/udp_socket_posix.h
vendored
Normal file
90
breadcast-caststream-sys/vendor/openscreen/platform/impl/udp_socket_posix.h
vendored
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
// 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_IMPL_UDP_SOCKET_POSIX_H_
|
||||
#define PLATFORM_IMPL_UDP_SOCKET_POSIX_H_
|
||||
|
||||
#include "platform/api/udp_socket.h"
|
||||
#include "platform/impl/platform_client_posix.h"
|
||||
#include "platform/impl/socket_handle_posix.h"
|
||||
#include "util/raw_ptr.h"
|
||||
#include "util/raw_ref.h"
|
||||
#include "util/weak_ptr.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
class UdpSocketReaderPosix;
|
||||
|
||||
// Threading: All public methods must be called on the same thread--the one
|
||||
// executing the TaskRunner. All non-public methods, except ReceiveMessage(),
|
||||
// are also assumed to be called on that thread.
|
||||
class UdpSocketPosix : public UdpSocket {
|
||||
public:
|
||||
// Creates a new UdpSocketPosix. The provided client and task_runner must
|
||||
// exist for the duration of this socket's lifetime.
|
||||
UdpSocketPosix(TaskRunner& task_runner,
|
||||
Client* client,
|
||||
SocketHandle handle,
|
||||
const IPEndpoint& local_endpoint,
|
||||
PlatformClientPosix* platform_client =
|
||||
PlatformClientPosix::GetInstance());
|
||||
UdpSocketPosix(const UdpSocketPosix&) = delete;
|
||||
UdpSocketPosix(UdpSocketPosix&&) noexcept = delete;
|
||||
UdpSocketPosix& operator=(const UdpSocketPosix&) = delete;
|
||||
UdpSocketPosix& operator=(UdpSocketPosix&&) = delete;
|
||||
~UdpSocketPosix() override;
|
||||
|
||||
// Implementations of UdpSocket methods.
|
||||
bool IsIPv4() const override;
|
||||
bool IsIPv6() const override;
|
||||
IPEndpoint GetLocalEndpoint() const override;
|
||||
void Bind() override;
|
||||
void SetMulticastOutboundInterface(NetworkInterfaceIndex ifindex) override;
|
||||
void JoinMulticastGroup(const IPAddress& address,
|
||||
NetworkInterfaceIndex ifindex) override;
|
||||
void SendMessage(ByteView data, const IPEndpoint& dest) override;
|
||||
void SetDscp(DscpMode mode) override;
|
||||
|
||||
const SocketHandle& GetHandle() const;
|
||||
|
||||
protected:
|
||||
friend class UdpSocketReaderPosix;
|
||||
|
||||
// Called by UdpSocketReaderPosix to perform a non-blocking read on the socket
|
||||
// and then dispatch the packet to this socket's Client. This method is the
|
||||
// only one in this class possibly being called from another thread.
|
||||
void ReceiveMessage();
|
||||
|
||||
private:
|
||||
// Helper to close the socket if `error` is fatal, in addition to dispatching
|
||||
// an Error to the `client_`.
|
||||
void OnError(Error::Code error);
|
||||
|
||||
bool is_closed() const { return handle_.fd < 0; }
|
||||
void Close();
|
||||
|
||||
// Task runner to use for queuing `client_` callbacks.
|
||||
const raw_ref<TaskRunner> task_runner_;
|
||||
|
||||
// Client to use for callbacks. This can be nullptr if the user does not want
|
||||
// any callbacks (for example, in the send-only case).
|
||||
const raw_ptr<Client> client_;
|
||||
|
||||
// Holds the POSIX file descriptor, or -1 if the socket is closed.
|
||||
SocketHandle handle_;
|
||||
|
||||
// Cached value of current local endpoint. This can change (e.g., when the
|
||||
// operating system auto-assigns a free local port when Bind() is called). If
|
||||
// the port is zero, getsockname() is called to try to resolve it. Once the
|
||||
// port is non-zero, it is assumed never to change again.
|
||||
mutable IPEndpoint local_endpoint_;
|
||||
|
||||
WeakPtrFactory<UdpSocketPosix> weak_factory_{this};
|
||||
|
||||
const raw_ptr<PlatformClientPosix> platform_client_;
|
||||
};
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_IMPL_UDP_SOCKET_POSIX_H_
|
||||
78
breadcast-caststream-sys/vendor/openscreen/platform/impl/udp_socket_reader_posix.cc
vendored
Normal file
78
breadcast-caststream-sys/vendor/openscreen/platform/impl/udp_socket_reader_posix.cc
vendored
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// 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/impl/udp_socket_reader_posix.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
|
||||
#include "platform/impl/socket_handle_posix.h"
|
||||
#include "platform/impl/udp_socket_posix.h"
|
||||
#include "util/osp_logging.h"
|
||||
#include "util/std_util.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
UdpSocketReaderPosix::UdpSocketReaderPosix(SocketHandleWaiter& waiter)
|
||||
: waiter_(waiter) {}
|
||||
|
||||
UdpSocketReaderPosix::~UdpSocketReaderPosix() {
|
||||
waiter_->UnsubscribeAll(this);
|
||||
}
|
||||
|
||||
void UdpSocketReaderPosix::ProcessReadyHandle(SocketHandleRef handle,
|
||||
uint32_t flags) {
|
||||
OSP_CHECK(flags & SocketHandleWaiter::Flags::kReadable);
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
// NOTE: Because sockets_ is expected to remain small, the performance here
|
||||
// is better than using an unordered_set.
|
||||
for (UdpSocketPosix* socket : sockets_) {
|
||||
if (socket->GetHandle() == handle) {
|
||||
socket->ReceiveMessage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool UdpSocketReaderPosix::HasPendingWrite(SocketHandleRef handle) {
|
||||
OSP_NOTREACHED();
|
||||
}
|
||||
|
||||
void UdpSocketReaderPosix::OnCreate(UdpSocket* socket) {
|
||||
UdpSocketPosix* read_socket = static_cast<UdpSocketPosix*>(socket);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
sockets_.push_back(read_socket);
|
||||
}
|
||||
// We only care about read events.
|
||||
waiter_->Subscribe(this, std::cref(read_socket->GetHandle()),
|
||||
SocketHandleWaiter::kReadable);
|
||||
}
|
||||
|
||||
void UdpSocketReaderPosix::OnDestroy(UdpSocket* socket) {
|
||||
UdpSocketPosix* destroyed_socket = static_cast<UdpSocketPosix*>(socket);
|
||||
OnDelete(destroyed_socket);
|
||||
}
|
||||
|
||||
void UdpSocketReaderPosix::OnDelete(UdpSocketPosix* socket,
|
||||
bool disable_locking_for_testing) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
auto it = std::find(sockets_.begin(), sockets_.end(), socket);
|
||||
if (it != sockets_.end()) {
|
||||
sockets_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
waiter_->OnHandleDeletion(this, std::cref(socket->GetHandle()),
|
||||
disable_locking_for_testing);
|
||||
}
|
||||
|
||||
bool UdpSocketReaderPosix::IsMappedReadForTesting(
|
||||
UdpSocketPosix* socket) const {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
return Contains(sockets_, socket);
|
||||
}
|
||||
|
||||
} // namespace openscreen
|
||||
82
breadcast-caststream-sys/vendor/openscreen/platform/impl/udp_socket_reader_posix.h
vendored
Normal file
82
breadcast-caststream-sys/vendor/openscreen/platform/impl/udp_socket_reader_posix.h
vendored
Normal 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_IMPL_UDP_SOCKET_READER_POSIX_H_
|
||||
#define PLATFORM_IMPL_UDP_SOCKET_READER_POSIX_H_
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "platform/api/task_runner.h"
|
||||
#include "platform/api/time.h"
|
||||
#include "platform/impl/socket_handle.h"
|
||||
#include "platform/impl/socket_handle_waiter.h"
|
||||
#include "platform/impl/udp_socket_posix.h"
|
||||
#include "util/raw_ptr.h"
|
||||
#include "util/raw_ref.h"
|
||||
#include "util/thread_annotations.h"
|
||||
|
||||
namespace openscreen {
|
||||
|
||||
// This is the class responsible for watching sockets for readable data, then
|
||||
// calling the function associated with these sockets once that data is read.
|
||||
// NOTE: This class will only function as intended while its RunUntilStopped
|
||||
// method is running.
|
||||
class UdpSocketReaderPosix : public SocketHandleWaiter::Subscriber {
|
||||
public:
|
||||
using SocketHandleRef = SocketHandleWaiter::SocketHandleRef;
|
||||
|
||||
// Creates a new instance of this object.
|
||||
// NOTE: The provided NetworkWaiter must outlive this object.
|
||||
explicit UdpSocketReaderPosix(SocketHandleWaiter& waiter);
|
||||
UdpSocketReaderPosix(const UdpSocketReaderPosix&) = delete;
|
||||
UdpSocketReaderPosix(UdpSocketReaderPosix&&) noexcept = delete;
|
||||
UdpSocketReaderPosix& operator=(const UdpSocketReaderPosix&) = delete;
|
||||
UdpSocketReaderPosix& operator=(UdpSocketReaderPosix&&) = delete;
|
||||
~UdpSocketReaderPosix() override;
|
||||
|
||||
// Waits for `socket` to be readable and then calls the socket's
|
||||
// RecieveMessage(...) method to process the available packet.
|
||||
// NOTE: The first read on any newly watched socket may be delayed up to 50
|
||||
// ms.
|
||||
void OnCreate(UdpSocket* socket);
|
||||
|
||||
// Cancels any pending wait on reading `socket`. Following this call, any
|
||||
// pending reads will proceed but their associated callbacks will not fire.
|
||||
// NOTE: This method will block until a delete is safe.
|
||||
// NOTE: If a socket callback is removed in the middle of a wait call, data
|
||||
// may be read on this socket and but the callback may not be called. If a
|
||||
// socket callback is added in the middle of a wait call, the new socket may
|
||||
// not be watched until after this wait call ends.
|
||||
virtual void OnDestroy(UdpSocket* socket);
|
||||
|
||||
// SocketHandleWaiter::Subscriber overrides.
|
||||
void ProcessReadyHandle(SocketHandleRef handle, uint32_t flags) override;
|
||||
|
||||
// NOTE: we don't subscribe to write events from the socket handle waiter.
|
||||
bool HasPendingWrite(SocketHandleRef handle) override;
|
||||
protected:
|
||||
bool IsMappedReadForTesting(UdpSocketPosix* socket) const;
|
||||
|
||||
private:
|
||||
// Helper method to allow for OnDestroy calls without blocking.
|
||||
void OnDelete(UdpSocketPosix* socket,
|
||||
bool disable_locking_for_testing = false);
|
||||
|
||||
// The set of all sockets that are being read from
|
||||
std::vector<raw_ptr<UdpSocketPosix>> sockets_ OSP_GUARDED_BY(mutex_);
|
||||
|
||||
// Mutex to protect against concurrent modification of socket info.
|
||||
mutable std::mutex mutex_;
|
||||
|
||||
// NetworkWaiter watching this NetworkReader.
|
||||
const raw_ref<SocketHandleWaiter> waiter_;
|
||||
|
||||
friend class TestingUdpSocketReader;
|
||||
};
|
||||
|
||||
} // namespace openscreen
|
||||
|
||||
#endif // PLATFORM_IMPL_UDP_SOCKET_READER_POSIX_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue