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;
ObjectID(SocketInfoReader * s)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
SocketInfoReader()47 SocketInfoReader::SocketInfoReader() {}
48
~SocketInfoReader()49 SocketInfoReader::~SocketInfoReader() {}
50
GetTcpv4SocketInfoFilePath() const51 FilePath SocketInfoReader::GetTcpv4SocketInfoFilePath() const {
52 return FilePath(kTcpv4SocketInfoFilePath);
53 }
54
GetTcpv6SocketInfoFilePath() const55 FilePath SocketInfoReader::GetTcpv6SocketInfoFilePath() const {
56 return FilePath(kTcpv6SocketInfoFilePath);
57 }
58
LoadTcpSocketInfo(vector<SocketInfo> * info_list)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
AppendSocketInfo(const FilePath & info_file_path,vector<SocketInfo> * info_list)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
ParseSocketInfo(const string & input,SocketInfo * socket_info)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
ParseIPAddressAndPort(const string & input,IPAddress * ip_address,uint16_t * port)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
ParseIPAddress(const string & input,IPAddress * ip_address)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
ParsePort(const string & input,uint16_t * port)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
ParseTransimitAndReceiveQueueValues(const string & input,uint64_t * transmit_queue_value,uint64_t * receive_queue_value)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
ParseConnectionState(const string & input,SocketInfo::ConnectionState * connection_state)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
ParseTimerState(const string & input,SocketInfo::TimerState * timer_state)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