Home | History | Annotate | Download | only in shill
      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;
     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 
     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 
     61 PassiveLinkMonitor::~PassiveLinkMonitor() {
     62   Stop();
     63 }
     64 
     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 
     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 
     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 
    102 void PassiveLinkMonitor::StopArpClient() {
    103   arp_client_->Stop();
    104   receive_request_handler_.reset();
    105 }
    106 
    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 
    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 
    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