• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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