// // Copyright (C) 2015 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #ifndef SHILL_ICMP_SESSION_H_ #define SHILL_ICMP_SESSION_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for FRIEND_TEST #include "shill/icmp.h" #include "shill/net/io_handler.h" namespace shill { class EventDispatcher; class IPAddress; // The IcmpSession class encapsulates the task of performing a stateful exchange // of echo requests and echo replies between this host and another (i.e. ping). // The Icmp class is used to perform the sending of echo requests. Each // IcmpSession object only allows one ICMP session to be running at one time. // Multiple ICMP sessions can be run concurrently by creating multiple // IcmpSession objects. class IcmpSession { public: // The result of an ICMP session is a vector of time deltas representing how // long it took to receive a echo reply for each sent echo request. The vector // is sorted in the order that the echo requests were sent. Zero time deltas // represent echo requests that we did not receive a corresponding reply for. using IcmpSessionResult = std::vector; using IcmpSessionResultCallback = base::Callback; explicit IcmpSession(EventDispatcher* dispatcher); // We always call IcmpSession::Stop in the destructor to clean up, in case an // ICMP session is still in progress. virtual ~IcmpSession(); // Starts an ICMP session, sending |kNumEchoRequestsToSend| echo requests to // |destination|, |kEchoRequestIntervalSeconds| apart. |result_callback| will // be called a) after all echo requests are sent and all echo replies are // received, or b) after |kTimeoutSeconds| have passed. |result_callback| will // only be invoked once on the first occurrence of either of these events. virtual bool Start(const IPAddress& destination, const IcmpSessionResultCallback& result_callback); // Stops the current ICMP session by closing the ICMP socket and resetting // callbacks. Does nothing if a ICMP session is not started. virtual void Stop(); bool IsStarted() { return icmp_->IsStarted(); } // Utility function that returns false iff |result| indicates that no echo // replies were received to any ICMP echo request that was sent during the // ICMP session that generated |result|. static bool AnyRepliesReceived(const IcmpSessionResult& result); // Utility function that returns the packet loss rate for the ICMP session // that generated |result| is greater than |percentage_threshold| percent. // The percentage packet loss determined by this function will be rounded // down to the closest integer percentage value. |percentage_threshold| is // expected to be a non-negative integer value. static bool IsPacketLossPercentageGreaterThan(const IcmpSessionResult& result, int percentage_threshold); private: using SentRecvTimePair = std::pair; friend class IcmpSessionTest; FRIEND_TEST(IcmpSessionTest, Constructor); // for |echo_id_| static uint16_t kNextUniqueEchoId; // unique across IcmpSession objects static const int kTotalNumEchoRequests; static const int kEchoRequestIntervalSeconds; static const size_t kTimeoutSeconds; // Sends a single echo request to |destination|. This function will call // itself repeatedly via the event loop every |kEchoRequestIntervalSeconds| // until |kNumEchoRequestToSend| echo requests are sent or the timeout is // reached. void TransmitEchoRequestTask(const IPAddress& destination); // Called when an ICMP packet is received. void OnEchoReplyReceived(InputData* data); // Helper function that generates the result of the current ICMP session. IcmpSessionResult GenerateIcmpResult(); // Called when the input handler |echo_reply_handler_| encounters an error. void OnEchoReplyError(const std::string& error_msg); // Calls |result_callback_| with the results collected so far, then stops the // IcmpSession. This function is called when the ICMP session successfully // completes, or when it times out. Does nothing if an ICMP session is not // started. void ReportResultAndStopSession(); base::WeakPtrFactory weak_ptr_factory_; EventDispatcher* dispatcher_; std::unique_ptr icmp_; const uint16_t echo_id_; // unique ID for this object's echo request/replies uint16_t current_sequence_number_; std::map seq_num_to_sent_recv_time_; std::set received_echo_reply_seq_numbers_; // Allow for an injectable tick clock for testing. base::TickClock* tick_clock_; base::DefaultTickClock default_tick_clock_; base::CancelableClosure timeout_callback_; IcmpSessionResultCallback result_callback_; IOHandler::InputCallback echo_reply_callback_; std::unique_ptr echo_reply_handler_; DISALLOW_COPY_AND_ASSIGN(IcmpSession); }; } // namespace shill #endif // SHILL_ICMP_SESSION_H_