blob: de46b422d16c5f59612672999c09edbf62825adf [file] [log] [blame]
Ben Chan3e4bf162013-04-03 18:14:51 -07001// Copyright (c) 2013 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/socket_info_reader.h"
6
7#include <algorithm>
8#include <limits>
9
Ben Chana0ddf462014-02-06 11:32:42 -080010#include <base/strings/string_number_conversions.h>
11#include <base/strings/string_split.h>
Ben Chan3e4bf162013-04-03 18:14:51 -070012
13#include "shill/file_reader.h"
14#include "shill/logging.h"
15
16using base::FilePath;
17using std::string;
18using std::vector;
19
20namespace shill {
21
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070022namespace Logging {
23static auto kModuleLogScope = ScopeLogger::kLink;
Paul Stewart1a212a62015-06-16 13:13:10 -070024static string ObjectID(SocketInfoReader* s) { return "(socket_info_reader)"; }
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070025}
26
Ben Chan3e4bf162013-04-03 18:14:51 -070027namespace {
28
Ben Chan320d04a2013-04-09 13:10:53 -070029const char kTcpv4SocketInfoFilePath[] = "/proc/net/tcp";
30const char kTcpv6SocketInfoFilePath[] = "/proc/net/tcp6";
Ben Chan3e4bf162013-04-03 18:14:51 -070031
32} // namespace
33
34SocketInfoReader::SocketInfoReader() {}
35
36SocketInfoReader::~SocketInfoReader() {}
37
Ben Chan320d04a2013-04-09 13:10:53 -070038FilePath SocketInfoReader::GetTcpv4SocketInfoFilePath() const {
39 return FilePath(kTcpv4SocketInfoFilePath);
Ben Chan3e4bf162013-04-03 18:14:51 -070040}
41
Ben Chan320d04a2013-04-09 13:10:53 -070042FilePath SocketInfoReader::GetTcpv6SocketInfoFilePath() const {
43 return FilePath(kTcpv6SocketInfoFilePath);
44}
45
Paul Stewart1a212a62015-06-16 13:13:10 -070046bool SocketInfoReader::LoadTcpSocketInfo(vector<SocketInfo>* info_list) {
Ben Chan320d04a2013-04-09 13:10:53 -070047 info_list->clear();
48 bool v4_loaded = AppendSocketInfo(GetTcpv4SocketInfoFilePath(), info_list);
49 bool v6_loaded = AppendSocketInfo(GetTcpv6SocketInfoFilePath(), info_list);
50 // Return true if we can load either /proc/net/tcp or /proc/net/tcp6
51 // successfully.
52 return v4_loaded || v6_loaded;
53}
54
Paul Stewart1a212a62015-06-16 13:13:10 -070055bool SocketInfoReader::AppendSocketInfo(const FilePath& info_file_path,
56 vector<SocketInfo>* info_list) {
Ben Chan3e4bf162013-04-03 18:14:51 -070057 FileReader file_reader;
58 if (!file_reader.Open(info_file_path)) {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070059 SLOG(this, 2) << __func__ << ": Failed to open '"
Ben Chan3e4bf162013-04-03 18:14:51 -070060 << info_file_path.value() << "'.";
61 return false;
62 }
63
Ben Chan3e4bf162013-04-03 18:14:51 -070064 string line;
65 while (file_reader.ReadLine(&line)) {
66 SocketInfo socket_info;
67 if (ParseSocketInfo(line, &socket_info))
68 info_list->push_back(socket_info);
69 }
70 return true;
71}
72
Paul Stewart1a212a62015-06-16 13:13:10 -070073bool SocketInfoReader::ParseSocketInfo(const string& input,
74 SocketInfo* socket_info) {
Ben Chan3e4bf162013-04-03 18:14:51 -070075 vector<string> tokens;
76 base::SplitStringAlongWhitespace(input, &tokens);
77 if (tokens.size() < 10) {
78 return false;
79 }
80
81 IPAddress ip_address(IPAddress::kFamilyUnknown);
Ben Chan7fab8972014-08-10 17:14:46 -070082 uint16_t port = 0;
Ben Chan3e4bf162013-04-03 18:14:51 -070083
84 if (!ParseIPAddressAndPort(tokens[1], &ip_address, &port)) {
85 return false;
86 }
87 socket_info->set_local_ip_address(ip_address);
88 socket_info->set_local_port(port);
89
90 if (!ParseIPAddressAndPort(tokens[2], &ip_address, &port)) {
91 return false;
92 }
93 socket_info->set_remote_ip_address(ip_address);
94 socket_info->set_remote_port(port);
95
96 SocketInfo::ConnectionState connection_state =
97 SocketInfo::kConnectionStateUnknown;
98 if (!ParseConnectionState(tokens[3], &connection_state)) {
99 return false;
100 }
101 socket_info->set_connection_state(connection_state);
102
Ben Chan7fab8972014-08-10 17:14:46 -0700103 uint64_t transmit_queue_value = 0, receive_queue_value = 0;
Ben Chan3e4bf162013-04-03 18:14:51 -0700104 if (!ParseTransimitAndReceiveQueueValues(
105 tokens[4], &transmit_queue_value, &receive_queue_value)) {
106 return false;
107 }
108 socket_info->set_transmit_queue_value(transmit_queue_value);
109 socket_info->set_receive_queue_value(receive_queue_value);
110
111 SocketInfo::TimerState timer_state = SocketInfo::kTimerStateUnknown;
112 if (!ParseTimerState(tokens[5], &timer_state)) {
113 return false;
114 }
115 socket_info->set_timer_state(timer_state);
116
117 return true;
118}
119
120bool SocketInfoReader::ParseIPAddressAndPort(
Paul Stewart1a212a62015-06-16 13:13:10 -0700121 const string& input, IPAddress* ip_address, uint16_t* port) {
Ben Chan3e4bf162013-04-03 18:14:51 -0700122 vector<string> tokens;
123
124 base::SplitString(input, ':', &tokens);
125 if (tokens.size() != 2 ||
126 !ParseIPAddress(tokens[0], ip_address) ||
127 !ParsePort(tokens[1], port)) {
128 return false;
129 }
130
131 return true;
132}
133
Paul Stewart1a212a62015-06-16 13:13:10 -0700134bool SocketInfoReader::ParseIPAddress(const string& input,
135 IPAddress* ip_address) {
Ben Chan320d04a2013-04-09 13:10:53 -0700136 ByteString byte_string = ByteString::CreateFromHexString(input);
137 if (byte_string.IsEmpty())
Ben Chan3e4bf162013-04-03 18:14:51 -0700138 return false;
139
140 IPAddress::Family family;
Ben Chan320d04a2013-04-09 13:10:53 -0700141 if (byte_string.GetLength() ==
142 IPAddress::GetAddressLength(IPAddress::kFamilyIPv4)) {
Ben Chan3e4bf162013-04-03 18:14:51 -0700143 family = IPAddress::kFamilyIPv4;
Ben Chan320d04a2013-04-09 13:10:53 -0700144 } else if (byte_string.GetLength() ==
145 IPAddress::GetAddressLength(IPAddress::kFamilyIPv6)) {
Ben Chan3e4bf162013-04-03 18:14:51 -0700146 family = IPAddress::kFamilyIPv6;
Ben Chan320d04a2013-04-09 13:10:53 -0700147 } else {
Ben Chan3e4bf162013-04-03 18:14:51 -0700148 return false;
Ben Chan320d04a2013-04-09 13:10:53 -0700149 }
Ben Chan3e4bf162013-04-03 18:14:51 -0700150
Ben Chan320d04a2013-04-09 13:10:53 -0700151 // Linux kernel prints out IP addresses in network order via
152 // /proc/net/tcp{,6}.
153 byte_string.ConvertFromNetToCPUUInt32Array();
Ben Chan3e4bf162013-04-03 18:14:51 -0700154
Ben Chan320d04a2013-04-09 13:10:53 -0700155 *ip_address = IPAddress(family, byte_string);
Ben Chan3e4bf162013-04-03 18:14:51 -0700156 return true;
157}
158
Paul Stewart1a212a62015-06-16 13:13:10 -0700159bool SocketInfoReader::ParsePort(const string& input, uint16_t* port) {
Ben Chan3e4bf162013-04-03 18:14:51 -0700160 int result = 0;
161
162 if (input.size() != 4 || !base::HexStringToInt(input, &result) ||
Ben Chan7fab8972014-08-10 17:14:46 -0700163 result < 0 || result > std::numeric_limits<uint16_t>::max()) {
Ben Chan3e4bf162013-04-03 18:14:51 -0700164 return false;
165 }
166
167 *port = result;
168 return true;
169}
170
171bool SocketInfoReader::ParseTransimitAndReceiveQueueValues(
Paul Stewart1a212a62015-06-16 13:13:10 -0700172 const string& input,
173 uint64_t* transmit_queue_value, uint64_t* receive_queue_value) {
Ben Chan3e4bf162013-04-03 18:14:51 -0700174 vector<string> tokens;
Ben Chan7fab8972014-08-10 17:14:46 -0700175 int64_t signed_transmit_queue_value = 0, signed_receive_queue_value = 0;
Ben Chan3e4bf162013-04-03 18:14:51 -0700176
177 base::SplitString(input, ':', &tokens);
178 if (tokens.size() != 2 ||
179 !base::HexStringToInt64(tokens[0], &signed_transmit_queue_value) ||
180 !base::HexStringToInt64(tokens[1], &signed_receive_queue_value)) {
181 return false;
182 }
183
Ben Chan7fab8972014-08-10 17:14:46 -0700184 *transmit_queue_value = static_cast<uint64_t>(signed_transmit_queue_value);
185 *receive_queue_value = static_cast<uint64_t>(signed_receive_queue_value);
Ben Chan3e4bf162013-04-03 18:14:51 -0700186 return true;
187}
188
189bool SocketInfoReader::ParseConnectionState(
Paul Stewart1a212a62015-06-16 13:13:10 -0700190 const string& input, SocketInfo::ConnectionState* connection_state) {
Ben Chan3e4bf162013-04-03 18:14:51 -0700191 int result = 0;
192
193 if (input.size() != 2 || !base::HexStringToInt(input, &result)) {
194 return false;
195 }
196
197 if (result > 0 && result < SocketInfo::kConnectionStateMax) {
198 *connection_state = static_cast<SocketInfo::ConnectionState>(result);
199 } else {
200 *connection_state = SocketInfo::kConnectionStateUnknown;
201 }
202 return true;
203}
204
205bool SocketInfoReader::ParseTimerState(
Paul Stewart1a212a62015-06-16 13:13:10 -0700206 const string& input, SocketInfo::TimerState* timer_state) {
Ben Chan3e4bf162013-04-03 18:14:51 -0700207 vector<string> tokens;
208 int result = 0;
209
210 base::SplitString(input, ':', &tokens);
211 if (tokens.size() != 2 || tokens[0].size() != 2 ||
212 !base::HexStringToInt(tokens[0], &result)) {
213 return false;
214 }
215
216 if (result < SocketInfo::kTimerStateMax) {
217 *timer_state = static_cast<SocketInfo::TimerState>(result);
218 } else {
219 *timer_state = SocketInfo::kTimerStateUnknown;
220 }
221 return true;
222}
223
224} // namespace shill