blob: 7faf873f87a9e244486420a86c397b49ac8550e5 [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.
#include <netinet/icmp6.h>
#include "absl/strings/string_view.h"
#include "quic/platform/api/quic_ip_address.h"
#include "quic/platform/api/quic_mutex.h"
#include "quic/qbone/bonnet/icmp_reachable_interface.h"
#include "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 {
struct ReachableEvent {
Status status;
absl::Duration response_time;
std::string source;
class StatsInterface {
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,
absl::Duration timeout,
KernelInterface* kernel,
QuicEpollServer* epoll_server,
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;
int64 /* allow-non-std-int */ OnAlarm()
QUIC_LOCKS_EXCLUDED(header_lock_) override;
static absl::string_view StatusName(Status status);
class EpollCallback : public QuicEpollCallbackInterface {
explicit EpollCallback(IcmpReachable* reachable) : reachable_(reachable) {}
EpollCallback(const EpollCallback&) = delete;
EpollCallback& operator=(const EpollCallback&) = delete;
EpollCallback(EpollCallback&&) = delete;
EpollCallback& operator=(EpollCallback&&) = delete;
void OnRegistration(QuicEpollServer* eps,
int fd,
int event_mask) override{};
void OnModification(int fd, int event_mask) override{};
void OnEvent(int fd, QuicEpollEvent* event) override;
void OnUnregistration(int fd, bool replaced) override{};
void OnShutdown(QuicEpollServer* eps, int fd) override;
std::string Name() const override;
IcmpReachable* reachable_;
bool OnEvent(int fd) QUIC_LOCKS_EXCLUDED(header_lock_);
const absl::Duration timeout_;
EpollCallback cb_;
sockaddr_in6 src_{};
sockaddr_in6 dst_{};
KernelInterface* kernel_;
QuicEpollServer* epoll_server_;
StatsInterface* stats_;
int send_fd_;
int recv_fd_;
QuicMutex header_lock_;
icmp6_hdr icmp_header_ QUIC_GUARDED_BY(header_lock_){};
absl::Time start_ = absl::InfinitePast();
absl::Time end_ = absl::InfinitePast();
} // namespace quic