• 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 #include "shill/passive_link_monitor.h"
18 
19 #include <string>
20 
21 #include <base/bind.h>
22 
23 #include "shill/arp_client.h"
24 #include "shill/arp_packet.h"
25 #include "shill/connection.h"
26 #include "shill/event_dispatcher.h"
27 #include "shill/logging.h"
28 #include "shill/net/byte_string.h"
29 
30 using base::Bind;
31 using base::Unretained;
32 using std::string;
33 
34 namespace shill {
35 
36 namespace Logging {
37 static auto kModuleLogScope = ScopeLogger::kLink;
ObjectID(Connection * c)38 static string ObjectID(Connection* c) { return c->interface_name(); }
39 }
40 
41 // static.
42 const int PassiveLinkMonitor::kDefaultMonitorCycles = 40;
43 const int PassiveLinkMonitor::kCyclePeriodMilliseconds = 25000;
44 const int PassiveLinkMonitor::kMinArpRequestsPerCycle = 5;
45 
PassiveLinkMonitor(const ConnectionRefPtr & connection,EventDispatcher * dispatcher,const ResultCallback & result_callback)46 PassiveLinkMonitor::PassiveLinkMonitor(const ConnectionRefPtr& connection,
47                                        EventDispatcher* dispatcher,
48                                        const ResultCallback& result_callback)
49     : connection_(connection),
50       dispatcher_(dispatcher),
51       // Connection is not provided when this is used as a mock for testing
52       // purpose.
53       arp_client_(
54           new ArpClient(connection ? connection->interface_index() : 0)),
55       result_callback_(result_callback),
56       num_cycles_to_monitor_(kDefaultMonitorCycles),
57       num_requests_received_(0),
58       num_cycles_passed_(0) {
59 }
60 
~PassiveLinkMonitor()61 PassiveLinkMonitor::~PassiveLinkMonitor() {
62   Stop();
63 }
64 
Start(int num_cycles)65 bool PassiveLinkMonitor::Start(int num_cycles) {
66   SLOG(connection_.get(), 2) << "In " << __func__ << ".";
67   Stop();
68 
69   if (!StartArpClient()) {
70     return false;
71   }
72   // Start the monitor cycle.
73   monitor_cycle_timeout_callback_.Reset(
74       Bind(&PassiveLinkMonitor::CycleTimeoutHandler, Unretained(this)));
75   dispatcher_->PostDelayedTask(monitor_cycle_timeout_callback_.callback(),
76                                kCyclePeriodMilliseconds);
77   num_cycles_to_monitor_ = num_cycles;
78   return true;
79 }
80 
Stop()81 void PassiveLinkMonitor::Stop() {
82   SLOG(connection_.get(), 2) << "In " << __func__ << ".";
83   StopArpClient();
84   num_requests_received_ = 0;
85   num_cycles_passed_ = 0;
86   monitor_cycle_timeout_callback_.Cancel();
87   monitor_completed_callback_.Cancel();
88 }
89 
StartArpClient()90 bool PassiveLinkMonitor::StartArpClient() {
91   if (!arp_client_->StartRequestListener()) {
92     return false;
93   }
94   receive_request_handler_.reset(
95       dispatcher_->CreateReadyHandler(
96           arp_client_->socket(),
97           IOHandler::kModeInput,
98           Bind(&PassiveLinkMonitor::ReceiveRequest, Unretained(this))));
99   return true;
100 }
101 
StopArpClient()102 void PassiveLinkMonitor::StopArpClient() {
103   arp_client_->Stop();
104   receive_request_handler_.reset();
105 }
106 
ReceiveRequest(int fd)107 void PassiveLinkMonitor::ReceiveRequest(int fd) {
108   SLOG(connection_.get(), 2) << "In " << __func__ << ".";
109   ArpPacket packet;
110   ByteString sender;
111 
112   if (!arp_client_->ReceivePacket(&packet, &sender)) {
113     return;
114   }
115 
116   if (packet.IsReply()) {
117     SLOG(connection_.get(), 4) << "This is not a request packet.  Ignoring.";
118     return;
119   }
120 
121   num_requests_received_++;
122   // Stop ARP client if we receive enough requests for the current cycle.
123   if (num_requests_received_ >= kMinArpRequestsPerCycle) {
124     StopArpClient();
125   }
126 }
127 
CycleTimeoutHandler()128 void PassiveLinkMonitor::CycleTimeoutHandler() {
129   bool status = false;
130   if (num_requests_received_ >= kMinArpRequestsPerCycle) {
131     num_requests_received_ = 0;
132     num_cycles_passed_++;
133     if (num_cycles_passed_ < num_cycles_to_monitor_) {
134       // Continue on with the next cycle.
135       StartArpClient();
136       dispatcher_->PostDelayedTask(monitor_cycle_timeout_callback_.callback(),
137                                    kCyclePeriodMilliseconds);
138       return;
139     }
140     // Monitor completed.
141     status = true;
142   }
143 
144   // Post a task to perform cleanup and invoke result callback, since this
145   // function is invoked from the callback that will be cancelled during
146   // cleanup.
147   monitor_completed_callback_.Reset(
148       Bind(&PassiveLinkMonitor::MonitorCompleted, Unretained(this), status));
149   dispatcher_->PostTask(monitor_completed_callback_.callback());
150 }
151 
MonitorCompleted(bool status)152 void PassiveLinkMonitor::MonitorCompleted(bool status) {
153   // Stop the monitoring before invoking result callback, so that the ARP client
154   // is stopped by the time result callback is invoked.
155   Stop();
156   result_callback_.Run(status);
157 }
158 
159 }  // namespace shill
160