You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
6.7 KiB

// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef OSP_PUBLIC_PRESENTATION_PRESENTATION_CONNECTION_H_
#define OSP_PUBLIC_PRESENTATION_PRESENTATION_CONNECTION_H_
#include <cstdint>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "osp/public/message_demuxer.h"
#include "platform/api/time.h"
#include "platform/base/error.h"
#include "platform/base/ip_address.h"
#include "platform/base/macros.h"
#include "util/osp_logging.h"
namespace openscreen {
namespace osp {
class ProtocolConnection;
enum class TerminationReason {
kReceiverTerminateCalled = 0,
kReceiverUserTerminated,
kControllerTerminateCalled,
kControllerUserTerminated,
kReceiverPresentationReplaced,
kReceiverIdleTooLong,
kReceiverPresentationUnloaded,
kReceiverShuttingDown,
kReceiverError,
};
class Connection {
public:
enum class CloseReason {
kClosed = 0,
kDiscarded,
kError,
};
enum class State {
// The library is currently attempting to connect to the presentation.
kConnecting,
// The connection to the presentation is open and communication is possible.
kConnected,
// The connection is closed or could not be opened. No communication is
// possible but it may be possible to reopen the connection via
// ReconnectPresentation.
kClosed,
// The connection is closed and the receiver has been terminated.
kTerminated,
};
// An object to receive callbacks related to a single Connection.
class Delegate {
public:
Delegate() = default;
virtual ~Delegate() = default;
// State changes.
virtual void OnConnected() = 0;
// Explicit close by other endpoint.
virtual void OnClosedByRemote() = 0;
// Closed because the script connection object was discarded.
virtual void OnDiscarded() = 0;
// Closed because of an error.
virtual void OnError(const absl::string_view message) = 0;
// Terminated through a different connection.
virtual void OnTerminated() = 0;
// A UTF-8 string message was received.
virtual void OnStringMessage(const absl::string_view message) = 0;
// A binary message was received.
virtual void OnBinaryMessage(const std::vector<uint8_t>& data) = 0;
private:
OSP_DISALLOW_COPY_AND_ASSIGN(Delegate);
};
// Allows different close, termination, and destruction behavior for both
// possible parents: controller and receiver. This is different from the
// normal delegate above, which would be supplied by the embedder to link it's
// presentation connection functionality.
class ParentDelegate {
public:
ParentDelegate() = default;
virtual ~ParentDelegate() = default;
virtual Error CloseConnection(Connection* connection,
CloseReason reason) = 0;
virtual Error OnPresentationTerminated(const std::string& presentation_id,
TerminationReason reason) = 0;
virtual void OnConnectionDestroyed(Connection* connection) = 0;
private:
OSP_DISALLOW_COPY_AND_ASSIGN(ParentDelegate);
};
struct PresentationInfo {
std::string id;
std::string url;
};
// Constructs a new connection using |delegate| for callbacks.
Connection(const PresentationInfo& info,
Delegate* delegate,
ParentDelegate* parent_delegate);
~Connection();
// Returns the ID and URL of this presentation.
const PresentationInfo& presentation_info() const { return presentation_; }
State state() const { return state_; }
ProtocolConnection* get_protocol_connection() const {
return protocol_connection_.get();
}
// These methods should only be called when we are connected.
uint64_t endpoint_id() const {
OSP_CHECK(endpoint_id_);
return endpoint_id_.value();
}
uint64_t connection_id() const {
OSP_CHECK(connection_id_);
return connection_id_.value();
}
// Sends a UTF-8 string message.
Error SendString(absl::string_view message);
// Sends a binary message.
Error SendBinary(std::vector<uint8_t>&& data);
// Closes the connection. This can be based on an explicit request from the
// embedder or because the connection object is being discarded (page
// navigated, object GC'd, etc.).
Error Close(CloseReason reason);
// Terminates the presentation associated with this connection.
void Terminate(TerminationReason reason);
void OnConnecting();
// Called by the receiver when the OnPresentationStarted logic happens. This
// notifies the delegate and updates our internal stream and ids.
void OnConnected(uint64_t connection_id,
uint64_t endpoint_id,
std::unique_ptr<ProtocolConnection> stream);
void OnClosedByError(Error cause);
void OnClosedByRemote();
void OnTerminated();
Delegate* get_delegate() { return delegate_; }
private:
// Helper method that handles closing down our internal state.
// Returns whether or not the connection state changed (and thus
// whether or not delegates should be informed).
bool OnClosed();
PresentationInfo presentation_;
State state_ = State::kConnecting;
Delegate* delegate_;
ParentDelegate* parent_delegate_;
absl::optional<uint64_t> connection_id_;
absl::optional<uint64_t> endpoint_id_;
std::unique_ptr<ProtocolConnection> protocol_connection_;
OSP_DISALLOW_COPY_AND_ASSIGN(Connection);
};
class ConnectionManager final : public MessageDemuxer::MessageCallback {
public:
explicit ConnectionManager(MessageDemuxer* demuxer);
void AddConnection(Connection* connection);
void RemoveConnection(Connection* connection);
// MessasgeDemuxer::MessageCallback overrides.
ErrorOr<size_t> OnStreamMessage(uint64_t endpoint_id,
uint64_t connection_id,
msgs::Type message_type,
const uint8_t* buffer,
size_t buffer_size,
Clock::time_point now) override;
Connection* GetConnection(uint64_t connection_id);
private:
// TODO(btolsch): Connection IDs were changed to be per-endpoint, but this
// table then needs to be <endpoint id, connection id> since connection id is
// still not unique globally.
std::map<uint64_t, Connection*> connections_;
MessageDemuxer::MessageWatch message_watch_;
MessageDemuxer::MessageWatch close_request_watch_;
MessageDemuxer::MessageWatch close_event_watch_;
OSP_DISALLOW_COPY_AND_ASSIGN(ConnectionManager);
};
} // namespace osp
} // namespace openscreen
#endif // OSP_PUBLIC_PRESENTATION_PRESENTATION_CONNECTION_H_