blob: 21550963ff19e546e283f5da2c0e2fba9bbfbe68 [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 Chan3e4bf162013-04-03 18:14:51 -070010#include <base/string_number_conversions.h>
11#include <base/string_split.h>
12
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
22namespace {
23
Ben Chan320d04a2013-04-09 13:10:53 -070024const char kTcpv4SocketInfoFilePath[] = "/proc/net/tcp";
25const char kTcpv6SocketInfoFilePath[] = "/proc/net/tcp6";
Ben Chan3e4bf162013-04-03 18:14:51 -070026
27} // namespace
28
29SocketInfoReader::SocketInfoReader() {}
30
31SocketInfoReader::~SocketInfoReader() {}
32
Ben Chan320d04a2013-04-09 13:10:53 -070033FilePath SocketInfoReader::GetTcpv4SocketInfoFilePath() const {
34 return FilePath(kTcpv4SocketInfoFilePath);
Ben Chan3e4bf162013-04-03 18:14:51 -070035}
36
Ben Chan320d04a2013-04-09 13:10:53 -070037FilePath SocketInfoReader::GetTcpv6SocketInfoFilePath() const {
38 return FilePath(kTcpv6SocketInfoFilePath);
39}
40
41bool SocketInfoReader::LoadTcpSocketInfo(vector<SocketInfo> *info_list) {
42 info_list->clear();
43 bool v4_loaded = AppendSocketInfo(GetTcpv4SocketInfoFilePath(), info_list);
44 bool v6_loaded = AppendSocketInfo(GetTcpv6SocketInfoFilePath(), info_list);
45 // Return true if we can load either /proc/net/tcp or /proc/net/tcp6
46 // successfully.
47 return v4_loaded || v6_loaded;
48}
49
50bool SocketInfoReader::AppendSocketInfo(const FilePath &info_file_path,
51 vector<SocketInfo> *info_list) {
Ben Chan3e4bf162013-04-03 18:14:51 -070052 FileReader file_reader;
53 if (!file_reader.Open(info_file_path)) {
54 SLOG(Link, 2) << __func__ << ": Failed to open '"
55 << info_file_path.value() << "'.";
56 return false;
57 }
58
Ben Chan3e4bf162013-04-03 18:14:51 -070059 string line;
60 while (file_reader.ReadLine(&line)) {
61 SocketInfo socket_info;
62 if (ParseSocketInfo(line, &socket_info))
63 info_list->push_back(socket_info);
64 }
65 return true;
66}
67
68bool SocketInfoReader::ParseSocketInfo(const string &input,
69 SocketInfo *socket_info) {
70 vector<string> tokens;
71 base::SplitStringAlongWhitespace(input, &tokens);
72 if (tokens.size() < 10) {
73 return false;
74 }
75
76 IPAddress ip_address(IPAddress::kFamilyUnknown);
77 uint16 port = 0;
78
79 if (!ParseIPAddressAndPort(tokens[1], &ip_address, &port)) {
80 return false;
81 }
82 socket_info->set_local_ip_address(ip_address);
83 socket_info->set_local_port(port);
84
85 if (!ParseIPAddressAndPort(tokens[2], &ip_address, &port)) {
86 return false;
87 }
88 socket_info->set_remote_ip_address(ip_address);
89 socket_info->set_remote_port(port);
90
91 SocketInfo::ConnectionState connection_state =
92 SocketInfo::kConnectionStateUnknown;
93 if (!ParseConnectionState(tokens[3], &connection_state)) {
94 return false;
95 }
96 socket_info->set_connection_state(connection_state);
97
98 uint64 transmit_queue_value = 0, receive_queue_value = 0;
99 if (!ParseTransimitAndReceiveQueueValues(
100 tokens[4], &transmit_queue_value, &receive_queue_value)) {
101 return false;
102 }
103 socket_info->set_transmit_queue_value(transmit_queue_value);
104 socket_info->set_receive_queue_value(receive_queue_value);
105
106 SocketInfo::TimerState timer_state = SocketInfo::kTimerStateUnknown;
107 if (!ParseTimerState(tokens[5], &timer_state)) {
108 return false;
109 }
110 socket_info->set_timer_state(timer_state);
111
112 return true;
113}
114
115bool SocketInfoReader::ParseIPAddressAndPort(
116 const string &input, IPAddress *ip_address, uint16 *port) {
117 vector<string> tokens;
118
119 base::SplitString(input, ':', &tokens);
120 if (tokens.size() != 2 ||
121 !ParseIPAddress(tokens[0], ip_address) ||
122 !ParsePort(tokens[1], port)) {
123 return false;
124 }
125
126 return true;
127}
128
129bool SocketInfoReader::ParseIPAddress(const string &input,
130 IPAddress *ip_address) {
Ben Chan320d04a2013-04-09 13:10:53 -0700131 ByteString byte_string = ByteString::CreateFromHexString(input);
132 if (byte_string.IsEmpty())
Ben Chan3e4bf162013-04-03 18:14:51 -0700133 return false;
134
135 IPAddress::Family family;
Ben Chan320d04a2013-04-09 13:10:53 -0700136 if (byte_string.GetLength() ==
137 IPAddress::GetAddressLength(IPAddress::kFamilyIPv4)) {
Ben Chan3e4bf162013-04-03 18:14:51 -0700138 family = IPAddress::kFamilyIPv4;
Ben Chan320d04a2013-04-09 13:10:53 -0700139 } else if (byte_string.GetLength() ==
140 IPAddress::GetAddressLength(IPAddress::kFamilyIPv6)) {
Ben Chan3e4bf162013-04-03 18:14:51 -0700141 family = IPAddress::kFamilyIPv6;
Ben Chan320d04a2013-04-09 13:10:53 -0700142 } else {
Ben Chan3e4bf162013-04-03 18:14:51 -0700143 return false;
Ben Chan320d04a2013-04-09 13:10:53 -0700144 }
Ben Chan3e4bf162013-04-03 18:14:51 -0700145
Ben Chan320d04a2013-04-09 13:10:53 -0700146 // Linux kernel prints out IP addresses in network order via
147 // /proc/net/tcp{,6}.
148 byte_string.ConvertFromNetToCPUUInt32Array();
Ben Chan3e4bf162013-04-03 18:14:51 -0700149
Ben Chan320d04a2013-04-09 13:10:53 -0700150 *ip_address = IPAddress(family, byte_string);
Ben Chan3e4bf162013-04-03 18:14:51 -0700151 return true;
152}
153
154bool SocketInfoReader::ParsePort(const string &input, uint16 *port) {
155 int result = 0;
156
157 if (input.size() != 4 || !base::HexStringToInt(input, &result) ||
158 result < 0 || result > std::numeric_limits<uint16>::max()) {
159 return false;
160 }
161
162 *port = result;
163 return true;
164}
165
166bool SocketInfoReader::ParseTransimitAndReceiveQueueValues(
167 const string &input,
168 uint64 *transmit_queue_value, uint64 *receive_queue_value) {
169 vector<string> tokens;
170 int64 signed_transmit_queue_value = 0, signed_receive_queue_value = 0;
171
172 base::SplitString(input, ':', &tokens);
173 if (tokens.size() != 2 ||
174 !base::HexStringToInt64(tokens[0], &signed_transmit_queue_value) ||
175 !base::HexStringToInt64(tokens[1], &signed_receive_queue_value)) {
176 return false;
177 }
178
179 *transmit_queue_value = static_cast<uint64>(signed_transmit_queue_value);
180 *receive_queue_value = static_cast<uint64>(signed_receive_queue_value);
181 return true;
182}
183
184bool SocketInfoReader::ParseConnectionState(
185 const string &input, SocketInfo::ConnectionState *connection_state) {
186 int result = 0;
187
188 if (input.size() != 2 || !base::HexStringToInt(input, &result)) {
189 return false;
190 }
191
192 if (result > 0 && result < SocketInfo::kConnectionStateMax) {
193 *connection_state = static_cast<SocketInfo::ConnectionState>(result);
194 } else {
195 *connection_state = SocketInfo::kConnectionStateUnknown;
196 }
197 return true;
198}
199
200bool SocketInfoReader::ParseTimerState(
201 const string &input, SocketInfo::TimerState *timer_state) {
202 vector<string> tokens;
203 int result = 0;
204
205 base::SplitString(input, ':', &tokens);
206 if (tokens.size() != 2 || tokens[0].size() != 2 ||
207 !base::HexStringToInt(tokens[0], &result)) {
208 return false;
209 }
210
211 if (result < SocketInfo::kTimerStateMax) {
212 *timer_state = static_cast<SocketInfo::TimerState>(result);
213 } else {
214 *timer_state = SocketInfo::kTimerStateUnknown;
215 }
216 return true;
217}
218
219} // namespace shill