• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2015 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #ifndef SHILL_ICMP_SESSION_H_
18 #define SHILL_ICMP_SESSION_H_
19 
20 #if defined(__ANDROID__)
21 #include <linux/icmp.h>
22 #else
23 #include <netinet/ip_icmp.h>
24 #endif  // __ANDROID__
25 
26 #include <map>
27 #include <memory>
28 #include <set>
29 #include <string>
30 #include <utility>
31 #include <vector>
32 
33 #include <base/callback.h>
34 #include <base/cancelable_callback.h>
35 #include <base/macros.h>
36 #include <base/memory/weak_ptr.h>
37 #include <base/time/default_tick_clock.h>
38 #include <base/time/tick_clock.h>
39 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
40 
41 #include "shill/icmp.h"
42 #include "shill/net/io_handler.h"
43 
44 namespace shill {
45 
46 class EventDispatcher;
47 class IPAddress;
48 
49 // The IcmpSession class encapsulates the task of performing a stateful exchange
50 // of echo requests and echo replies between this host and another (i.e. ping).
51 // The Icmp class is used to perform the sending of echo requests. Each
52 // IcmpSession object only allows one ICMP session to be running at one time.
53 // Multiple ICMP sessions can be run concurrently by creating multiple
54 // IcmpSession objects.
55 class IcmpSession {
56  public:
57   // The result of an ICMP session is a vector of time deltas representing how
58   // long it took to receive a echo reply for each sent echo request. The vector
59   // is sorted in the order that the echo requests were sent. Zero time deltas
60   // represent echo requests that we did not receive a corresponding reply for.
61   using IcmpSessionResult = std::vector<base::TimeDelta>;
62   using IcmpSessionResultCallback =
63       base::Callback<void(const IcmpSessionResult&)>;
64 
65   explicit IcmpSession(EventDispatcher* dispatcher);
66 
67   // We always call IcmpSession::Stop in the destructor to clean up, in case an
68   // ICMP session is still in progress.
69   virtual ~IcmpSession();
70 
71   // Starts an ICMP session, sending |kNumEchoRequestsToSend| echo requests to
72   // |destination|, |kEchoRequestIntervalSeconds| apart. |result_callback| will
73   // be called a) after all echo requests are sent and all echo replies are
74   // received, or b) after |kTimeoutSeconds| have passed. |result_callback| will
75   // only be invoked once on the first occurrence of either of these events.
76   virtual bool Start(const IPAddress& destination,
77                      const IcmpSessionResultCallback& result_callback);
78 
79   // Stops the current ICMP session by closing the ICMP socket and resetting
80   // callbacks. Does nothing if a ICMP session is not started.
81   virtual void Stop();
82 
IsStarted()83   bool IsStarted() { return icmp_->IsStarted(); }
84 
85   // Utility function that returns false iff |result| indicates that no echo
86   // replies were received to any ICMP echo request that was sent during the
87   // ICMP session that generated |result|.
88   static bool AnyRepliesReceived(const IcmpSessionResult& result);
89 
90   // Utility function that returns the packet loss rate for the ICMP session
91   // that generated |result| is greater than |percentage_threshold| percent.
92   // The percentage packet loss determined by this function will be rounded
93   // down to the closest integer percentage value. |percentage_threshold| is
94   // expected to be a non-negative integer value.
95   static bool IsPacketLossPercentageGreaterThan(const IcmpSessionResult& result,
96                                                 int percentage_threshold);
97 
98  private:
99   using SentRecvTimePair = std::pair<base::TimeTicks, base::TimeTicks>;
100 
101   friend class IcmpSessionTest;
102 
103   FRIEND_TEST(IcmpSessionTest, Constructor);  // for |echo_id_|
104 
105   static uint16_t kNextUniqueEchoId;  // unique across IcmpSession objects
106   static const int kTotalNumEchoRequests;
107   static const int kEchoRequestIntervalSeconds;
108   static const size_t kTimeoutSeconds;
109 
110   // Sends a single echo request to |destination|. This function will call
111   // itself repeatedly via the event loop every |kEchoRequestIntervalSeconds|
112   // until |kNumEchoRequestToSend| echo requests are sent or the timeout is
113   // reached.
114   void TransmitEchoRequestTask(const IPAddress& destination);
115 
116   // Called when an ICMP packet is received.
117   void OnEchoReplyReceived(InputData* data);
118 
119   // Helper function that generates the result of the current ICMP session.
120   IcmpSessionResult GenerateIcmpResult();
121 
122   // Called when the input handler |echo_reply_handler_| encounters an error.
123   void OnEchoReplyError(const std::string& error_msg);
124 
125   // Calls |result_callback_| with the results collected so far, then stops the
126   // IcmpSession. This function is called when the ICMP session successfully
127   // completes, or when it times out. Does nothing if an ICMP session is not
128   // started.
129   void ReportResultAndStopSession();
130 
131   base::WeakPtrFactory<IcmpSession> weak_ptr_factory_;
132   EventDispatcher* dispatcher_;
133   std::unique_ptr<Icmp> icmp_;
134   const uint16_t echo_id_;  // unique ID for this object's echo request/replies
135   uint16_t current_sequence_number_;
136   std::map<uint16_t, SentRecvTimePair> seq_num_to_sent_recv_time_;
137   std::set<uint16_t> received_echo_reply_seq_numbers_;
138   // Allow for an injectable tick clock for testing.
139   base::TickClock* tick_clock_;
140   base::DefaultTickClock default_tick_clock_;
141   base::CancelableClosure timeout_callback_;
142   IcmpSessionResultCallback result_callback_;
143   IOHandler::InputCallback echo_reply_callback_;
144   std::unique_ptr<IOHandler> echo_reply_handler_;
145 
146   DISALLOW_COPY_AND_ASSIGN(IcmpSession);
147 };
148 
149 }  // namespace shill
150 
151 #endif  // SHILL_ICMP_SESSION_H_
152