blob: b8fd2fab4d10a556f2972bcfc7b305ade9c4a730 [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 CHROMEOS_SERVICES_SECURE_CHANNEL_CONNECTION_ATTEMPT_H_
#define CHROMEOS_SERVICES_SECURE_CHANNEL_CONNECTION_ATTEMPT_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/macros.h"
#include "base/time/clock.h"
#include "chromeos/components/multidevice/logging/logging.h"
#include "chromeos/services/secure_channel/client_connection_parameters.h"
#include "chromeos/services/secure_channel/connection_attempt_delegate.h"
#include "chromeos/services/secure_channel/connection_attempt_details.h"
#include "chromeos/services/secure_channel/connection_details.h"
#include "chromeos/services/secure_channel/pending_connection_request.h"
#include "chromeos/services/secure_channel/pending_connection_request_delegate.h"
namespace chromeos {
namespace secure_channel {
class AuthenticatedChannel;
// ConnectionAttempt represents an ongoing attempt to connect to a given device
// over a given medium. Each ConnectionAttempt is comprised of one or
// more PendingConnectionRequests and notifies its delegate when the attempt has
// succeeded or failed.
template <typename FailureDetailType>
class ConnectionAttempt : public PendingConnectionRequestDelegate {
public:
// Extracts all of the ClientConnectionParameters owned by |attempt|'s
// PendingConnectionRequests. This function deletes |attempt| as part of this
// process to ensure that it is no longer used after extraction is complete.
static std::vector<std::unique_ptr<ClientConnectionParameters>>
ExtractClientConnectionParameters(
std::unique_ptr<ConnectionAttempt<FailureDetailType>> attempt) {
return attempt->ExtractClientConnectionParameters();
}
virtual ~ConnectionAttempt() = default;
const ConnectionAttemptDetails& connection_attempt_details() const {
return connection_attempt_details_;
}
// Associates |request| with this attempt. If the attempt succeeds, |request|
// will be notified of success; on failure, |request| will be notified of a
// connection failure. Returns whether adding the request was successful.
bool AddPendingConnectionRequest(
std::unique_ptr<PendingConnectionRequest<FailureDetailType>> request) {
if (!request) {
PA_LOG(ERROR) << "ConnectionAttempt::AddPendingConnectionRequest(): "
<< "Received invalid request.";
return false;
}
if (has_notified_delegate_of_success_) {
PA_LOG(ERROR) << "ConnectionAttempt::AddPendingConnectionRequest(): "
<< "Tried to add an additional request,but the attempt had "
<< "already finished.";
return false;
}
ProcessAddingNewConnectionRequest(std::move(request));
return true;
}
protected:
ConnectionAttempt(ConnectionAttemptDelegate* delegate,
base::Clock* clock,
const ConnectionAttemptDetails& connection_attempt_details)
: delegate_(delegate),
clock_(clock),
connection_attempt_details_(connection_attempt_details),
start_attempt_timestamp_(clock_->Now()) {
DCHECK(delegate);
}
// Derived types should use this function to associate the request with this
// attempt.
virtual void ProcessAddingNewConnectionRequest(
std::unique_ptr<PendingConnectionRequest<FailureDetailType>> request) = 0;
// Extracts the ClientConnectionParameters from all child
// PendingConnectionRequests.
virtual std::vector<std::unique_ptr<ClientConnectionParameters>>
ExtractClientConnectionParameters() = 0;
// Derived types can override this function to process the amount of time that
// this connection attempt has taken to produce a successful connection.
virtual void ProcessSuccessfulConnectionDuration(
const base::TimeDelta& duration) {}
void OnConnectionAttemptSucceeded(
std::unique_ptr<AuthenticatedChannel> authenticated_channel) {
if (has_notified_delegate_of_success_) {
PA_LOG(ERROR) << "ConnectionAttempt::OnConnectionAttemptSucceeded(): "
<< "Tried to alert delegate of a successful connection, "
<< "but the attempt had already finished.";
return;
}
has_notified_delegate_of_success_ = true;
ProcessSuccessfulConnectionDuration(clock_->Now() -
start_attempt_timestamp_);
delegate_->OnConnectionAttemptSucceeded(
connection_attempt_details_.GetAssociatedConnectionDetails(),
std::move(authenticated_channel));
}
void OnConnectionAttemptFinishedWithoutConnection() {
if (has_notified_delegate_of_success_) {
PA_LOG(ERROR) << "ConnectionAttempt::"
<< "OnConnectionAttemptFinishedWithoutConnection(): "
<< "Tried to alert delegate of a failed connection, "
<< "but the attempt had already finished.";
return;
}
delegate_->OnConnectionAttemptFinishedWithoutConnection(
connection_attempt_details_);
}
private:
ConnectionAttemptDelegate* delegate_;
base::Clock* clock_;
const ConnectionAttemptDetails connection_attempt_details_;
const base::Time start_attempt_timestamp_;
bool has_notified_delegate_of_success_ = false;
DISALLOW_COPY_AND_ASSIGN(ConnectionAttempt);
};
} // namespace secure_channel
} // namespace chromeos
#endif // CHROMEOS_SERVICES_SECURE_CHANNEL_CONNECTION_ATTEMPT_H_