Home | History | Annotate | Download | only in shill
      1 //
      2 // Copyright (C) 2013 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/socket_info_reader.h"
     18 
     19 #include <algorithm>
     20 #include <limits>
     21 
     22 #include <base/strings/string_number_conversions.h>
     23 #include <base/strings/string_split.h>
     24 #include <base/strings/string_util.h>
     25 
     26 #include "shill/file_reader.h"
     27 #include "shill/logging.h"
     28 
     29 using base::FilePath;
     30 using std::string;
     31 using std::vector;
     32 
     33 namespace shill {
     34 
     35 namespace Logging {
     36 static auto kModuleLogScope = ScopeLogger::kLink;
     37 static string ObjectID(SocketInfoReader* s) { return "(socket_info_reader)"; }
     38 }
     39 
     40 namespace {
     41 
     42 const char kTcpv4SocketInfoFilePath[] = "/proc/net/tcp";
     43 const char kTcpv6SocketInfoFilePath[] = "/proc/net/tcp6";
     44 
     45 }  // namespace
     46 
     47 SocketInfoReader::SocketInfoReader() {}
     48 
     49 SocketInfoReader::~SocketInfoReader() {}
     50 
     51 FilePath SocketInfoReader::GetTcpv4SocketInfoFilePath() const {
     52   return FilePath(kTcpv4SocketInfoFilePath);
     53 }
     54 
     55 FilePath SocketInfoReader::GetTcpv6SocketInfoFilePath() const {
     56   return FilePath(kTcpv6SocketInfoFilePath);
     57 }
     58 
     59 bool SocketInfoReader::LoadTcpSocketInfo(vector<SocketInfo>* info_list) {
     60   info_list->clear();
     61   bool v4_loaded = AppendSocketInfo(GetTcpv4SocketInfoFilePath(), info_list);
     62   bool v6_loaded = AppendSocketInfo(GetTcpv6SocketInfoFilePath(), info_list);
     63   // Return true if we can load either /proc/net/tcp or /proc/net/tcp6
     64   // successfully.
     65   return v4_loaded || v6_loaded;
     66 }
     67 
     68 bool SocketInfoReader::AppendSocketInfo(const FilePath& info_file_path,
     69                                         vector<SocketInfo>* info_list) {
     70   FileReader file_reader;
     71   if (!file_reader.Open(info_file_path)) {
     72     SLOG(this, 2) << __func__ << ": Failed to open '"
     73                   << info_file_path.value() << "'.";
     74     return false;
     75   }
     76 
     77   string line;
     78   while (file_reader.ReadLine(&line)) {
     79     SocketInfo socket_info;
     80     if (ParseSocketInfo(line, &socket_info))
     81       info_list->push_back(socket_info);
     82   }
     83   return true;
     84 }
     85 
     86 bool SocketInfoReader::ParseSocketInfo(const string& input,
     87                                        SocketInfo* socket_info) {
     88   vector<string> tokens = base::SplitString(input, base::kWhitespaceASCII,
     89                                             base::KEEP_WHITESPACE,
     90                                             base::SPLIT_WANT_NONEMPTY);
     91   if (tokens.size() < 10) {
     92     return false;
     93   }
     94 
     95   IPAddress ip_address(IPAddress::kFamilyUnknown);
     96   uint16_t port = 0;
     97 
     98   if (!ParseIPAddressAndPort(tokens[1], &ip_address, &port)) {
     99     return false;
    100   }
    101   socket_info->set_local_ip_address(ip_address);
    102   socket_info->set_local_port(port);
    103 
    104   if (!ParseIPAddressAndPort(tokens[2], &ip_address, &port)) {
    105     return false;
    106   }
    107   socket_info->set_remote_ip_address(ip_address);
    108   socket_info->set_remote_port(port);
    109 
    110   SocketInfo::ConnectionState connection_state =
    111       SocketInfo::kConnectionStateUnknown;
    112   if (!ParseConnectionState(tokens[3], &connection_state)) {
    113     return false;
    114   }
    115   socket_info->set_connection_state(connection_state);
    116 
    117   uint64_t transmit_queue_value = 0, receive_queue_value = 0;
    118   if (!ParseTransimitAndReceiveQueueValues(
    119       tokens[4], &transmit_queue_value, &receive_queue_value)) {
    120     return false;
    121   }
    122   socket_info->set_transmit_queue_value(transmit_queue_value);
    123   socket_info->set_receive_queue_value(receive_queue_value);
    124 
    125   SocketInfo::TimerState timer_state = SocketInfo::kTimerStateUnknown;
    126   if (!ParseTimerState(tokens[5], &timer_state)) {
    127     return false;
    128   }
    129   socket_info->set_timer_state(timer_state);
    130 
    131   return true;
    132 }
    133 
    134 bool SocketInfoReader::ParseIPAddressAndPort(
    135     const string& input, IPAddress* ip_address, uint16_t* port) {
    136   vector<string> tokens = base::SplitString(
    137       input, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
    138   if (tokens.size() != 2 ||
    139       !ParseIPAddress(tokens[0], ip_address) ||
    140       !ParsePort(tokens[1], port)) {
    141     return false;
    142   }
    143 
    144   return true;
    145 }
    146 
    147 bool SocketInfoReader::ParseIPAddress(const string& input,
    148                                       IPAddress* ip_address) {
    149   ByteString byte_string = ByteString::CreateFromHexString(input);
    150   if (byte_string.IsEmpty())
    151     return false;
    152 
    153   IPAddress::Family family;
    154   if (byte_string.GetLength() ==
    155       IPAddress::GetAddressLength(IPAddress::kFamilyIPv4)) {
    156     family = IPAddress::kFamilyIPv4;
    157   } else if (byte_string.GetLength() ==
    158              IPAddress::GetAddressLength(IPAddress::kFamilyIPv6)) {
    159     family = IPAddress::kFamilyIPv6;
    160   } else {
    161     return false;
    162   }
    163 
    164   // Linux kernel prints out IP addresses in network order via
    165   // /proc/net/tcp{,6}.
    166   byte_string.ConvertFromNetToCPUUInt32Array();
    167 
    168   *ip_address = IPAddress(family, byte_string);
    169   return true;
    170 }
    171 
    172 bool SocketInfoReader::ParsePort(const string& input, uint16_t* port) {
    173   int result = 0;
    174 
    175   if (input.size() != 4 || !base::HexStringToInt(input, &result) ||
    176       result < 0 || result > std::numeric_limits<uint16_t>::max()) {
    177     return false;
    178   }
    179 
    180   *port = result;
    181   return true;
    182 }
    183 
    184 bool SocketInfoReader::ParseTransimitAndReceiveQueueValues(
    185     const string& input,
    186     uint64_t* transmit_queue_value, uint64_t* receive_queue_value) {
    187   int64_t signed_transmit_queue_value = 0, signed_receive_queue_value = 0;
    188 
    189   vector<string> tokens = base::SplitString(
    190       input, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
    191   if (tokens.size() != 2 ||
    192       !base::HexStringToInt64(tokens[0], &signed_transmit_queue_value) ||
    193       !base::HexStringToInt64(tokens[1], &signed_receive_queue_value)) {
    194     return false;
    195   }
    196 
    197   *transmit_queue_value = static_cast<uint64_t>(signed_transmit_queue_value);
    198   *receive_queue_value = static_cast<uint64_t>(signed_receive_queue_value);
    199   return true;
    200 }
    201 
    202 bool SocketInfoReader::ParseConnectionState(
    203     const string& input, SocketInfo::ConnectionState* connection_state) {
    204   int result = 0;
    205 
    206   if (input.size() != 2 || !base::HexStringToInt(input, &result)) {
    207     return false;
    208   }
    209 
    210   if (result > 0 && result < SocketInfo::kConnectionStateMax) {
    211     *connection_state = static_cast<SocketInfo::ConnectionState>(result);
    212   } else {
    213     *connection_state = SocketInfo::kConnectionStateUnknown;
    214   }
    215   return true;
    216 }
    217 
    218 bool SocketInfoReader::ParseTimerState(
    219     const string& input, SocketInfo::TimerState* timer_state) {
    220   int result = 0;
    221 
    222   vector<string> tokens = base::SplitString(
    223       input, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
    224   if (tokens.size() != 2 || tokens[0].size() != 2 ||
    225       !base::HexStringToInt(tokens[0], &result)) {
    226     return false;
    227   }
    228 
    229   if (result < SocketInfo::kTimerStateMax) {
    230     *timer_state = static_cast<SocketInfo::TimerState>(result);
    231   } else {
    232     *timer_state = SocketInfo::kTimerStateUnknown;
    233   }
    234   return true;
    235 }
    236 
    237 }  // namespace shill
    238