blob: 50e3d491c9c0309423d472da5ad1abb5781c9952 [file] [log] [blame]
// Copyright 2021 The Chromium OS 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 SHILL_VPN_VPN_CONNECTION_H_
#define SHILL_VPN_VPN_CONNECTION_H_
#include <memory>
#include <string>
#include <utility>
#include <base/callback.h>
#include "shill/event_dispatcher.h"
#include "shill/ipconfig.h"
#include "shill/mockable.h"
#include "shill/process_manager.h"
#include "shill/service.h"
namespace shill {
// A VPNConnection is a base class represents a VPN connection. It contains a
// state, which is driven by either external calls (Connect()/Disconnect()) or
// internal events (Notify*() functions). Different with VPNDriver, this class
// is supposed to be created before connecting to a VPN service and be destroyed
// after the connection is finished.
class VPNConnection {
public:
enum class State {
// This instance is just initialized.
kIdle,
// This instance is trying to connect to a VPN service.
kConnecting,
// The VPN connection has been established.
kConnected,
// The VPN connection is not available now. It means either a failure or a
// disconnection initiated by the user.
kDisconnecting,
// Resources have been released and this instance can be destroyed safely.
kStopped,
};
struct Callbacks {
// The state has been changed from kConnecting to kConnected. Use
// RepeatingCallback here since some VPNs may do a reconnect by themselves.
// and thus kConnected state can be entered for several times.
using OnConnectedCallback = base::RepeatingCallback<void(
const std::string& link_name,
int interface_index,
const IPConfig::Properties& ip_properties)>;
// The state has been changed to kDisconnecting caused by a failure
// unexpectedly (i.e., Disconnect() is not called).
using OnFailureCallback = base::OnceCallback<void(Service::ConnectFailure)>;
// The state has been change to kStopped.
using OnStoppedCallback = base::OnceClosure;
Callbacks(OnConnectedCallback on_connected,
OnFailureCallback on_failure,
OnStoppedCallback on_stopped)
: on_connected_cb(on_connected),
on_failure_cb(std::move(on_failure)),
on_stopped_cb(std::move(on_stopped)) {}
OnConnectedCallback on_connected_cb;
OnFailureCallback on_failure_cb;
OnStoppedCallback on_stopped_cb;
};
explicit VPNConnection(std::unique_ptr<Callbacks> callbacks,
EventDispatcher* dispatcher);
// Note that we cannot guarantee that when destructor is called, the state is
// kIdle or kStopped, so the derived class should check the state and release
// resources (e.g., call OnDisconnect()) if needed.
virtual ~VPNConnection() = default;
void Connect();
void Disconnect();
void ResetCallbacks(std::unique_ptr<Callbacks> callbacks);
State state() { return state_; }
bool IsConnectingOrConnected() const;
private:
// Implemented by the derived class for the real connect/disconnect logic.
// Note that these functions will be invoked asynchronously by a PostTask() in
// Connect()/Disconnect().
// In OnConnect(), the derived class is supposed to initiate the connection,
// and call NotifyConnected() on connected, or NotifyFailure() on a failure.
virtual void OnConnect() = 0;
// In OnDisconnect(), the derived class is supposed to disconnect the
// connection (if connected) or stop the connecting procedure (if connecting),
// and clean up all the resources used in this connection. Once the cleanup is
// done, the derived class should call NotifyStopped(). Note that this
// function will be called not only when the user initiates the disconnection,
// but also in NotifyFailure().
virtual void OnDisconnect() = 0;
protected:
// This group of functions should be called by the derived class to indicate
// an event, change the state, and invoke the corresponding callback. See the
// comments above for the callbacks for their meanings. Note that the
// callbacks will be invoked asynchronously by a PostTask() in these
// functions.
void NotifyConnected(const std::string& link_name,
int interface_index,
const IPConfig::Properties& ip_properties);
// Note that NotifyFailure() will also invoke OnDisconnect() on the derived
// class (by a PostTask()), and thus the derived class don't need to do any
// clean up other than calling this function on failures.
mockable void NotifyFailure(Service::ConnectFailure reason,
const std::string& detail);
void NotifyStopped();
private:
// For able to modify |state_| in the tests.
friend class IPsecConnectionUnderTest;
friend class L2TPConnectionUnderTest;
friend class VPNConnectionUnderTest;
std::unique_ptr<Callbacks> callbacks_;
State state_;
EventDispatcher* dispatcher_;
base::WeakPtrFactory<VPNConnection> weak_factory_{this};
};
std::ostream& operator<<(std::ostream& stream,
const VPNConnection::State& state);
} // namespace shill
#endif // SHILL_VPN_VPN_CONNECTION_H_