blob: f00c99a716966da40471d86c066f34561b2783ee [file] [log] [blame]
// Copyright (c) 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 QUICHE_QUIC_QBONE_BONNET_ICMP_REACHABLE_H_
#define QUICHE_QUIC_QBONE_BONNET_ICMP_REACHABLE_H_
#include <netinet/icmp6.h>
#include <memory>
#include "absl/strings/string_view.h"
#include "quiche/quic/core/io/quic_event_loop.h"
#include "quiche/quic/core/quic_alarm.h"
#include "quiche/quic/core/quic_alarm_factory.h"
#include "quiche/quic/core/quic_clock.h"
#include "quiche/quic/core/quic_time.h"
#include "quiche/quic/platform/api/quic_ip_address.h"
#include "quiche/quic/platform/api/quic_mutex.h"
#include "quiche/quic/qbone/bonnet/icmp_reachable_interface.h"
#include "quiche/quic/qbone/platform/kernel_interface.h"
namespace quic {
extern const char kUnknownSource[];
extern const char kNoSource[];
// IcmpReachable schedules itself with an EpollServer, periodically sending
// ICMPv6 Echo Requests to the given |destination| on the interface that the
// given |source| is bound to. Echo Requests are sent once every |timeout|.
// On Echo Replies, timeouts, and I/O errors, the given |stats| object will
// be called back with details of the event.
class IcmpReachable : public IcmpReachableInterface {
public:
enum Status { REACHABLE, UNREACHABLE };
struct ReachableEvent {
Status status;
QuicTime::Delta response_time;
std::string source;
};
class StatsInterface {
public:
StatsInterface() = default;
StatsInterface(const StatsInterface&) = delete;
StatsInterface& operator=(const StatsInterface&) = delete;
StatsInterface(StatsInterface&&) = delete;
StatsInterface& operator=(StatsInterface&&) = delete;
virtual ~StatsInterface() = default;
virtual void OnEvent(ReachableEvent event) = 0;
virtual void OnReadError(int error) = 0;
virtual void OnWriteError(int error) = 0;
};
// |source| is the IPv6 address bound to the interface that IcmpReachable will
// send Echo Requests on.
// |destination| is the IPv6 address of the destination of the Echo Requests.
// |timeout| is the duration IcmpReachable will wait between Echo Requests.
// If no Echo Response is received by the next Echo Request, it will
// be considered a timeout.
// |kernel| is not owned, but should outlive this instance.
// |epoll_server| is not owned, but should outlive this instance.
// IcmpReachable's Init() must be called from within the Epoll
// Server's thread.
// |stats| is not owned, but should outlive this instance. It will be called
// back on Echo Replies, timeouts, and I/O errors.
IcmpReachable(QuicIpAddress source, QuicIpAddress destination,
QuicTime::Delta timeout, KernelInterface* kernel,
QuicEventLoop* event_loop, StatsInterface* stats);
~IcmpReachable() override;
// Initializes this reachability probe. Must be called from within the
// |epoll_server|'s thread.
bool Init() QUIC_LOCKS_EXCLUDED(header_lock_) override;
void OnAlarm() QUIC_LOCKS_EXCLUDED(header_lock_);
static absl::string_view StatusName(Status status);
private:
class EpollCallback : public QuicSocketEventListener {
public:
explicit EpollCallback(IcmpReachable* reachable) : reachable_(reachable) {}
EpollCallback(const EpollCallback&) = delete;
EpollCallback& operator=(const EpollCallback&) = delete;
EpollCallback(EpollCallback&&) = delete;
EpollCallback& operator=(EpollCallback&&) = delete;
void OnSocketEvent(QuicEventLoop* event_loop, SocketFd fd,
QuicSocketEventMask events) override;
private:
IcmpReachable* reachable_;
};
class AlarmCallback : public QuicAlarm::DelegateWithoutContext {
public:
explicit AlarmCallback(IcmpReachable* reachable) : reachable_(reachable) {}
void OnAlarm() override { reachable_->OnAlarm(); }
private:
IcmpReachable* reachable_;
};
bool OnEvent(int fd) QUIC_LOCKS_EXCLUDED(header_lock_);
const QuicTime::Delta timeout_;
QuicEventLoop* event_loop_;
const QuicClock* clock_;
std::unique_ptr<QuicAlarmFactory> alarm_factory_;
EpollCallback cb_;
std::unique_ptr<QuicAlarm> alarm_;
sockaddr_in6 src_{};
sockaddr_in6 dst_{};
KernelInterface* kernel_;
StatsInterface* stats_;
int send_fd_;
int recv_fd_;
QuicMutex header_lock_;
icmp6_hdr icmp_header_ QUIC_GUARDED_BY(header_lock_){};
QuicTime start_ = QuicTime::Zero();
QuicTime end_ = QuicTime::Zero();
};
} // namespace quic
#endif // QUICHE_QUIC_QBONE_BONNET_ICMP_REACHABLE_H_