1c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
2c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Copyright (C) 2013 The Android Open Source Project
3c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
4c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Licensed under the Apache License, Version 2.0 (the "License");
5c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// you may not use this file except in compliance with the License.
6c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// You may obtain a copy of the License at
7c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
8c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//      http://www.apache.org/licenses/LICENSE-2.0
9c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
10c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Unless required by applicable law or agreed to in writing, software
11c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// distributed under the License is distributed on an "AS IS" BASIS,
12c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// See the License for the specific language governing permissions and
14c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// limitations under the License.
15c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu//
163e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
173e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan#include "shill/socket_info_reader.h"
183e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
193e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan#include <algorithm>
203e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan#include <limits>
213e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
22a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan#include <base/strings/string_number_conversions.h>
23a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan#include <base/strings/string_split.h>
243a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko#include <base/strings/string_util.h>
253e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
263e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan#include "shill/file_reader.h"
273e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan#include "shill/logging.h"
283e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
293e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chanusing base::FilePath;
303e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chanusing std::string;
313e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chanusing std::vector;
323e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
333e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Channamespace shill {
343e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
35c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silbersteinnamespace Logging {
36c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silbersteinstatic auto kModuleLogScope = ScopeLogger::kLink;
371a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewartstatic string ObjectID(SocketInfoReader* s) { return "(socket_info_reader)"; }
38c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein}
39c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein
403e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Channamespace {
413e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
42320d04a93dcde82899b4457351d00aad4528e4c9Ben Chanconst char kTcpv4SocketInfoFilePath[] = "/proc/net/tcp";
43320d04a93dcde82899b4457351d00aad4528e4c9Ben Chanconst char kTcpv6SocketInfoFilePath[] = "/proc/net/tcp6";
443e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
453e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan}  // namespace
463e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
473e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben ChanSocketInfoReader::SocketInfoReader() {}
483e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
493e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben ChanSocketInfoReader::~SocketInfoReader() {}
503e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
51320d04a93dcde82899b4457351d00aad4528e4c9Ben ChanFilePath SocketInfoReader::GetTcpv4SocketInfoFilePath() const {
52320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  return FilePath(kTcpv4SocketInfoFilePath);
53320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan}
54320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan
55320d04a93dcde82899b4457351d00aad4528e4c9Ben ChanFilePath SocketInfoReader::GetTcpv6SocketInfoFilePath() const {
56320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  return FilePath(kTcpv6SocketInfoFilePath);
57320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan}
58320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan
591a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewartbool SocketInfoReader::LoadTcpSocketInfo(vector<SocketInfo>* info_list) {
60320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  info_list->clear();
61320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  bool v4_loaded = AppendSocketInfo(GetTcpv4SocketInfoFilePath(), info_list);
62320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  bool v6_loaded = AppendSocketInfo(GetTcpv6SocketInfoFilePath(), info_list);
63320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  // Return true if we can load either /proc/net/tcp or /proc/net/tcp6
64320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  // successfully.
65320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  return v4_loaded || v6_loaded;
663e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan}
673e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
681a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewartbool SocketInfoReader::AppendSocketInfo(const FilePath& info_file_path,
691a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart                                        vector<SocketInfo>* info_list) {
703e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  FileReader file_reader;
713e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  if (!file_reader.Open(info_file_path)) {
72c9c31d8497c3f053c2160408cc386010fc125fadRebecca Silberstein    SLOG(this, 2) << __func__ << ": Failed to open '"
733e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan                  << info_file_path.value() << "'.";
743e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    return false;
753e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  }
763e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
773e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  string line;
783e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  while (file_reader.ReadLine(&line)) {
793e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    SocketInfo socket_info;
803e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    if (ParseSocketInfo(line, &socket_info))
813e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan      info_list->push_back(socket_info);
823e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  }
833e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  return true;
843e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan}
853e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
861a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewartbool SocketInfoReader::ParseSocketInfo(const string& input,
871a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart                                       SocketInfo* socket_info) {
883a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko  vector<string> tokens = base::SplitString(input, base::kWhitespaceASCII,
893a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko                                            base::KEEP_WHITESPACE,
903a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko                                            base::SPLIT_WANT_NONEMPTY);
913e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  if (tokens.size() < 10) {
923e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    return false;
933e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  }
943e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
953e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  IPAddress ip_address(IPAddress::kFamilyUnknown);
967fab89734d88724a288e96a9996b15548c5294c7Ben Chan  uint16_t port = 0;
973e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
983e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  if (!ParseIPAddressAndPort(tokens[1], &ip_address, &port)) {
993e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    return false;
1003e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  }
1013e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  socket_info->set_local_ip_address(ip_address);
1023e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  socket_info->set_local_port(port);
1033e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
1043e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  if (!ParseIPAddressAndPort(tokens[2], &ip_address, &port)) {
1053e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    return false;
1063e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  }
1073e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  socket_info->set_remote_ip_address(ip_address);
1083e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  socket_info->set_remote_port(port);
1093e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
1103e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  SocketInfo::ConnectionState connection_state =
1113e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan      SocketInfo::kConnectionStateUnknown;
1123e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  if (!ParseConnectionState(tokens[3], &connection_state)) {
1133e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    return false;
1143e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  }
1153e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  socket_info->set_connection_state(connection_state);
1163e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
1177fab89734d88724a288e96a9996b15548c5294c7Ben Chan  uint64_t transmit_queue_value = 0, receive_queue_value = 0;
1183e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  if (!ParseTransimitAndReceiveQueueValues(
1193e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan      tokens[4], &transmit_queue_value, &receive_queue_value)) {
1203e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    return false;
1213e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  }
1223e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  socket_info->set_transmit_queue_value(transmit_queue_value);
1233e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  socket_info->set_receive_queue_value(receive_queue_value);
1243e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
1253e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  SocketInfo::TimerState timer_state = SocketInfo::kTimerStateUnknown;
1263e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  if (!ParseTimerState(tokens[5], &timer_state)) {
1273e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    return false;
1283e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  }
1293e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  socket_info->set_timer_state(timer_state);
1303e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
1313e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  return true;
1323e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan}
1333e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
1343e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chanbool SocketInfoReader::ParseIPAddressAndPort(
1351a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart    const string& input, IPAddress* ip_address, uint16_t* port) {
1363a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko  vector<string> tokens = base::SplitString(
1373a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko      input, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
1383e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  if (tokens.size() != 2 ||
1393e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan      !ParseIPAddress(tokens[0], ip_address) ||
1403e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan      !ParsePort(tokens[1], port)) {
1413e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    return false;
1423e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  }
1433e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
1443e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  return true;
1453e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan}
1463e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
1471a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewartbool SocketInfoReader::ParseIPAddress(const string& input,
1481a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart                                      IPAddress* ip_address) {
149320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  ByteString byte_string = ByteString::CreateFromHexString(input);
150320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  if (byte_string.IsEmpty())
1513e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    return false;
1523e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
1533e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  IPAddress::Family family;
154320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  if (byte_string.GetLength() ==
155320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan      IPAddress::GetAddressLength(IPAddress::kFamilyIPv4)) {
1563e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    family = IPAddress::kFamilyIPv4;
157320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  } else if (byte_string.GetLength() ==
158320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan             IPAddress::GetAddressLength(IPAddress::kFamilyIPv6)) {
1593e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    family = IPAddress::kFamilyIPv6;
160320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  } else {
1613e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    return false;
162320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  }
1633e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
164320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  // Linux kernel prints out IP addresses in network order via
165320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  // /proc/net/tcp{,6}.
166320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  byte_string.ConvertFromNetToCPUUInt32Array();
1673e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
168320d04a93dcde82899b4457351d00aad4528e4c9Ben Chan  *ip_address = IPAddress(family, byte_string);
1693e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  return true;
1703e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan}
1713e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
1721a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewartbool SocketInfoReader::ParsePort(const string& input, uint16_t* port) {
1733e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  int result = 0;
1743e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
1753e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  if (input.size() != 4 || !base::HexStringToInt(input, &result) ||
1767fab89734d88724a288e96a9996b15548c5294c7Ben Chan      result < 0 || result > std::numeric_limits<uint16_t>::max()) {
1773e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    return false;
1783e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  }
1793e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
1803e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  *port = result;
1813e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  return true;
1823e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan}
1833e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
1843e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chanbool SocketInfoReader::ParseTransimitAndReceiveQueueValues(
1851a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart    const string& input,
1861a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart    uint64_t* transmit_queue_value, uint64_t* receive_queue_value) {
1877fab89734d88724a288e96a9996b15548c5294c7Ben Chan  int64_t signed_transmit_queue_value = 0, signed_receive_queue_value = 0;
1883e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
1893a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko  vector<string> tokens = base::SplitString(
1903a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko      input, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
1913e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  if (tokens.size() != 2 ||
1923e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan      !base::HexStringToInt64(tokens[0], &signed_transmit_queue_value) ||
1933e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan      !base::HexStringToInt64(tokens[1], &signed_receive_queue_value)) {
1943e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    return false;
1953e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  }
1963e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
1977fab89734d88724a288e96a9996b15548c5294c7Ben Chan  *transmit_queue_value = static_cast<uint64_t>(signed_transmit_queue_value);
1987fab89734d88724a288e96a9996b15548c5294c7Ben Chan  *receive_queue_value = static_cast<uint64_t>(signed_receive_queue_value);
1993e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  return true;
2003e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan}
2013e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
2023e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chanbool SocketInfoReader::ParseConnectionState(
2031a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart    const string& input, SocketInfo::ConnectionState* connection_state) {
2043e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  int result = 0;
2053e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
2063e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  if (input.size() != 2 || !base::HexStringToInt(input, &result)) {
2073e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    return false;
2083e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  }
2093e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
2103e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  if (result > 0 && result < SocketInfo::kConnectionStateMax) {
2113e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    *connection_state = static_cast<SocketInfo::ConnectionState>(result);
2123e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  } else {
2133e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    *connection_state = SocketInfo::kConnectionStateUnknown;
2143e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  }
2153e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  return true;
2163e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan}
2173e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
2183e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chanbool SocketInfoReader::ParseTimerState(
2191a212a6b98b22ad1d69652bb26a9e94138635476Paul Stewart    const string& input, SocketInfo::TimerState* timer_state) {
2203e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  int result = 0;
2213e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
2223a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko  vector<string> tokens = base::SplitString(
2233a62e235646ec19bee71e8dbee5208282dcd13b5Alex Vakulenko      input, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
2243e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  if (tokens.size() != 2 || tokens[0].size() != 2 ||
2253e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan      !base::HexStringToInt(tokens[0], &result)) {
2263e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    return false;
2273e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  }
2283e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
2293e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  if (result < SocketInfo::kTimerStateMax) {
2303e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    *timer_state = static_cast<SocketInfo::TimerState>(result);
2313e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  } else {
2323e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan    *timer_state = SocketInfo::kTimerStateUnknown;
2333e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  }
2343e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan  return true;
2353e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan}
2363e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan
2373e4bf16679baaddd8ff149b7ca872e1ee12f57b7Ben Chan}  // namespace shill
238