1 // Copyright (c) 2019 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef QUICHE_QUIC_QBONE_BONNET_ICMP_REACHABLE_H_ 6 #define QUICHE_QUIC_QBONE_BONNET_ICMP_REACHABLE_H_ 7 8 #include <netinet/icmp6.h> 9 10 #include <memory> 11 12 #include "absl/strings/string_view.h" 13 #include "quiche/quic/core/io/quic_event_loop.h" 14 #include "quiche/quic/core/quic_alarm.h" 15 #include "quiche/quic/core/quic_alarm_factory.h" 16 #include "quiche/quic/core/quic_clock.h" 17 #include "quiche/quic/core/quic_time.h" 18 #include "quiche/quic/platform/api/quic_ip_address.h" 19 #include "quiche/quic/platform/api/quic_mutex.h" 20 #include "quiche/quic/qbone/bonnet/icmp_reachable_interface.h" 21 #include "quiche/quic/qbone/platform/kernel_interface.h" 22 23 namespace quic { 24 25 extern const char kUnknownSource[]; 26 extern const char kNoSource[]; 27 28 // IcmpReachable schedules itself with an EpollServer, periodically sending 29 // ICMPv6 Echo Requests to the given |destination| on the interface that the 30 // given |source| is bound to. Echo Requests are sent once every |timeout|. 31 // On Echo Replies, timeouts, and I/O errors, the given |stats| object will 32 // be called back with details of the event. 33 class IcmpReachable : public IcmpReachableInterface { 34 public: 35 enum Status { REACHABLE, UNREACHABLE }; 36 37 struct ReachableEvent { 38 Status status; 39 QuicTime::Delta response_time; 40 std::string source; 41 }; 42 43 class StatsInterface { 44 public: 45 StatsInterface() = default; 46 47 StatsInterface(const StatsInterface&) = delete; 48 StatsInterface& operator=(const StatsInterface&) = delete; 49 50 StatsInterface(StatsInterface&&) = delete; 51 StatsInterface& operator=(StatsInterface&&) = delete; 52 53 virtual ~StatsInterface() = default; 54 55 virtual void OnEvent(ReachableEvent event) = 0; 56 57 virtual void OnReadError(int error) = 0; 58 59 virtual void OnWriteError(int error) = 0; 60 }; 61 62 // |source| is the IPv6 address bound to the interface that IcmpReachable will 63 // send Echo Requests on. 64 // |destination| is the IPv6 address of the destination of the Echo Requests. 65 // |timeout| is the duration IcmpReachable will wait between Echo Requests. 66 // If no Echo Response is received by the next Echo Request, it will 67 // be considered a timeout. 68 // |kernel| is not owned, but should outlive this instance. 69 // |epoll_server| is not owned, but should outlive this instance. 70 // IcmpReachable's Init() must be called from within the Epoll 71 // Server's thread. 72 // |stats| is not owned, but should outlive this instance. It will be called 73 // back on Echo Replies, timeouts, and I/O errors. 74 IcmpReachable(QuicIpAddress source, QuicIpAddress destination, 75 QuicTime::Delta timeout, KernelInterface* kernel, 76 QuicEventLoop* event_loop, StatsInterface* stats); 77 78 ~IcmpReachable() override; 79 80 // Initializes this reachability probe. Must be called from within the 81 // |epoll_server|'s thread. 82 bool Init() QUIC_LOCKS_EXCLUDED(header_lock_) override; 83 84 void OnAlarm() QUIC_LOCKS_EXCLUDED(header_lock_); 85 86 static absl::string_view StatusName(Status status); 87 88 private: 89 class EpollCallback : public QuicSocketEventListener { 90 public: EpollCallback(IcmpReachable * reachable)91 explicit EpollCallback(IcmpReachable* reachable) : reachable_(reachable) {} 92 93 EpollCallback(const EpollCallback&) = delete; 94 EpollCallback& operator=(const EpollCallback&) = delete; 95 96 EpollCallback(EpollCallback&&) = delete; 97 EpollCallback& operator=(EpollCallback&&) = delete; 98 99 void OnSocketEvent(QuicEventLoop* event_loop, SocketFd fd, 100 QuicSocketEventMask events) override; 101 102 private: 103 IcmpReachable* reachable_; 104 }; 105 106 class AlarmCallback : public QuicAlarm::DelegateWithoutContext { 107 public: AlarmCallback(IcmpReachable * reachable)108 explicit AlarmCallback(IcmpReachable* reachable) : reachable_(reachable) {} 109 OnAlarm()110 void OnAlarm() override { reachable_->OnAlarm(); } 111 112 private: 113 IcmpReachable* reachable_; 114 }; 115 116 bool OnEvent(int fd) QUIC_LOCKS_EXCLUDED(header_lock_); 117 118 const QuicTime::Delta timeout_; 119 120 QuicEventLoop* event_loop_; 121 const QuicClock* clock_; 122 std::unique_ptr<QuicAlarmFactory> alarm_factory_; 123 124 EpollCallback cb_; 125 std::unique_ptr<QuicAlarm> alarm_; 126 127 sockaddr_in6 src_{}; 128 sockaddr_in6 dst_{}; 129 130 KernelInterface* kernel_; 131 132 StatsInterface* stats_; 133 134 int send_fd_; 135 int recv_fd_; 136 137 QuicMutex header_lock_; QUIC_GUARDED_BY(header_lock_)138 icmp6_hdr icmp_header_ QUIC_GUARDED_BY(header_lock_){}; 139 140 QuicTime start_ = QuicTime::Zero(); 141 QuicTime end_ = QuicTime::Zero(); 142 }; 143 144 } // namespace quic 145 146 #endif // QUICHE_QUIC_QBONE_BONNET_ICMP_REACHABLE_H_ 147