blob: 548cbff51f54bdc5ebace88edf1d1aa934ea9799 [file] [log] [blame]
// Copyright 2018 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_IMPL_QUIC_QUIC_CLIENT_H_
#define OSP_IMPL_QUIC_QUIC_CLIENT_H_
#include <cstdint>
#include <map>
#include <memory>
#include <vector>
#include "osp/impl/quic/quic_connection_factory.h"
#include "osp/impl/quic/quic_service_common.h"
#include "osp/public/protocol_connection_client.h"
#include "platform/api/task_runner.h"
#include "platform/api/time.h"
#include "platform/base/ip_address.h"
#include "util/alarm.h"
namespace openscreen {
namespace osp {
// This class is the default implementation of ProtocolConnectionClient for the
// library. It manages connections to other endpoints as well as the lifetime
// of each incoming and outgoing stream. It works in conjunction with a
// QuicConnectionFactory implementation and MessageDemuxer.
// QuicConnectionFactory provides the actual ability to make a new QUIC
// connection with another endpoint. Incoming data is given to the QuicClient
// by the underlying QUIC implementation (through QuicConnectionFactory) and
// this is in turn handed to MessageDemuxer for routing CBOR messages.
//
// The two most significant methods of this class are Connect and
// CreateProtocolConnection. Both will return a new QUIC stream to a given
// endpoint to which the caller can write but the former is allowed to be
// asynchronous. If there isn't currently a connection to the specified
// endpoint, Connect will start a connection attempt and store the callback for
// when the connection completes. CreateProtocolConnection simply returns
// nullptr if there's no existing connection.
class QuicClient final : public ProtocolConnectionClient,
public ServiceConnectionDelegate::ServiceDelegate {
public:
QuicClient(MessageDemuxer* demuxer,
std::unique_ptr<QuicConnectionFactory> connection_factory,
ProtocolConnectionServiceObserver* observer,
ClockNowFunctionPtr now_function,
TaskRunner* task_runner);
~QuicClient() override;
// ProtocolConnectionClient overrides.
bool Start() override;
bool Stop() override;
ConnectRequest Connect(const IPEndpoint& endpoint,
ConnectionRequestCallback* request) override;
std::unique_ptr<ProtocolConnection> CreateProtocolConnection(
uint64_t endpoint_id) override;
// QuicProtocolConnection::Owner overrides.
void OnConnectionDestroyed(QuicProtocolConnection* connection) override;
// ServiceConnectionDelegate::ServiceDelegate overrides.
uint64_t OnCryptoHandshakeComplete(ServiceConnectionDelegate* delegate,
uint64_t connection_id) override;
void OnIncomingStream(
std::unique_ptr<QuicProtocolConnection> connection) override;
void OnConnectionClosed(uint64_t endpoint_id,
uint64_t connection_id) override;
void OnDataReceived(uint64_t endpoint_id,
uint64_t connection_id,
const uint8_t* data,
size_t data_size) override;
private:
struct PendingConnectionData {
explicit PendingConnectionData(ServiceConnectionData&& data);
PendingConnectionData(PendingConnectionData&&) noexcept;
~PendingConnectionData();
PendingConnectionData& operator=(PendingConnectionData&&) noexcept;
ServiceConnectionData data;
// Pairs of request IDs and the associated connection callback.
std::vector<std::pair<uint64_t, ConnectionRequestCallback*>> callbacks;
};
ConnectRequest CreatePendingConnection(const IPEndpoint& endpoint,
ConnectionRequestCallback* request);
uint64_t StartConnectionRequest(const IPEndpoint& endpoint,
ConnectionRequestCallback* request);
void CloseAllConnections();
std::unique_ptr<QuicProtocolConnection> MakeProtocolConnection(
QuicConnection* connection,
ServiceConnectionDelegate* delegate,
uint64_t endpoint_id);
void CancelConnectRequest(uint64_t request_id) override;
// Deletes dead QUIC connections then returns the time interval before this
// method should be run again.
void Cleanup();
std::unique_ptr<QuicConnectionFactory> connection_factory_;
// Maps an IPEndpoint to a generated endpoint ID. This is used to insulate
// callers from post-handshake changes to a connections actual peer endpoint.
std::map<IPEndpoint, uint64_t> endpoint_map_;
// Value that will be used for the next new endpoint in a Connect call.
uint64_t next_endpoint_id_ = 0;
// Maps request IDs to their callbacks. The callback is paired with the
// IPEndpoint it originally requested to connect to so cancelling the request
// can also remove a pending connection.
std::map<uint64_t, std::pair<IPEndpoint, ConnectionRequestCallback*>>
request_map_;
// Value that will be used for the next new connection request.
uint64_t next_request_id_ = 1;
// Maps endpoint addresses to data about connections that haven't successfully
// completed the QUIC handshake.
std::map<IPEndpoint, PendingConnectionData> pending_connections_;
// Maps endpoint IDs to data about connections that have successfully
// completed the QUIC handshake.
std::map<uint64_t, ServiceConnectionData> connections_;
// Connections (endpoint IDs) that need to be destroyed, but have to wait for
// the next event loop due to the underlying QUIC implementation's way of
// referencing them.
std::vector<uint64_t> delete_connections_;
Alarm cleanup_alarm_;
};
} // namespace osp
} // namespace openscreen
#endif // OSP_IMPL_QUIC_QUIC_CLIENT_H_