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