blob: 4a0a217409442f37a6d04473a642839aa5332fa1 [file] [log] [blame]
Hugo Benichi7b314e12018-01-15 21:54:00 +09001/*
2 * Copyright (C) 2018 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#define LOG_TAG "TcpSocketMonitor"
18
Hugo Benichia9e3c5d2018-01-18 10:33:22 +090019#include <iomanip>
20#include <thread>
Hugo Benichi7b314e12018-01-15 21:54:00 +090021
22#include <arpa/inet.h>
23#include <netinet/tcp.h>
24#include <linux/tcp.h>
25
Hugo Benichia9e3c5d2018-01-18 10:33:22 +090026#include "DumpWriter.h"
27#include "Fwmark.h"
28#include "SockDiag.h"
29#include "TcpSocketMonitor.h"
30
Hugo Benichi7b314e12018-01-15 21:54:00 +090031namespace android {
32namespace net {
33
Hugo Benichia9e3c5d2018-01-18 10:33:22 +090034using std::chrono::duration_cast;
35using std::chrono::milliseconds;
36using std::chrono::steady_clock;
37
Hugo Benichi7b314e12018-01-15 21:54:00 +090038constexpr const char* getTcpStateName(int t) {
39 switch (t) {
40 case TCP_ESTABLISHED:
41 return "ESTABLISHED";
42 case TCP_SYN_SENT:
43 return "SYN-SENT";
44 case TCP_SYN_RECV:
45 return "SYN-RECV";
46 case TCP_FIN_WAIT1:
47 return "FIN-WAIT-1";
48 case TCP_FIN_WAIT2:
49 return "FIN-WAIT-2";
50 case TCP_TIME_WAIT:
51 return "TIME-WAIT";
52 case TCP_CLOSE:
53 return "CLOSE";
54 case TCP_CLOSE_WAIT:
55 return "CLOSE-WAIT";
56 case TCP_LAST_ACK:
57 return "LAST-ACK";
58 case TCP_LISTEN:
59 return "LISTEN";
60 case TCP_CLOSING:
61 return "CLOSING";
62 default:
63 return "UNKNOWN";
64 }
65}
66
Hugo Benichi54bfc7c2018-01-23 14:16:52 +090067// Helper macro for reading fields into struct tcp_info and handling different struct tcp_info
68// versions in the kernel.
69#define tcpinfo_get(ptr, fld, len, zero) \
70 (((ptr) != nullptr && offsetof(struct tcp_info, fld) < len) ? (ptr)->fld : zero)
71
Hugo Benichicbaa36b2018-01-17 12:11:43 +090072static void tcpInfoPrint(DumpWriter &dw, Fwmark mark, const struct inet_diag_msg *sockinfo,
Hugo Benichi54bfc7c2018-01-23 14:16:52 +090073 const struct tcp_info *tcpinfo, uint32_t tcpinfoLen) {
Hugo Benichia9e3c5d2018-01-18 10:33:22 +090074 char saddr[INET6_ADDRSTRLEN] = {};
75 char daddr[INET6_ADDRSTRLEN] = {};
76 inet_ntop(sockinfo->idiag_family, &(sockinfo->id.idiag_src), saddr, sizeof(saddr));
77 inet_ntop(sockinfo->idiag_family, &(sockinfo->id.idiag_dst), daddr, sizeof(daddr));
Hugo Benichi7b314e12018-01-15 21:54:00 +090078
Hugo Benichia9e3c5d2018-01-18 10:33:22 +090079 dw.println(
80 "netId=%d uid=%u mark=0x%x saddr=%s daddr=%s sport=%u dport=%u tcp_state=%s(%u) "
Hugo Benichi54bfc7c2018-01-23 14:16:52 +090081 "rqueue=%u wqueue=%u rtt=%gms var_rtt=%gms rcv_rtt=%gms unacked=%u snd_cwnd=%u",
Hugo Benichia9e3c5d2018-01-18 10:33:22 +090082 mark.netId,
83 sockinfo->idiag_uid,
84 mark.intValue,
85 saddr,
86 daddr,
87 ntohs(sockinfo->id.idiag_sport),
88 ntohs(sockinfo->id.idiag_dport),
89 getTcpStateName(sockinfo->idiag_state), sockinfo->idiag_state,
90 sockinfo->idiag_rqueue,
91 sockinfo->idiag_wqueue,
Hugo Benichi54bfc7c2018-01-23 14:16:52 +090092 tcpinfo_get(tcpinfo, tcpi_rtt, tcpinfoLen, 0) / 1000.0,
93 tcpinfo_get(tcpinfo, tcpi_rttvar, tcpinfoLen, 0) / 1000.0,
94 tcpinfo_get(tcpinfo, tcpi_rcv_rtt, tcpinfoLen, 0) / 1000.0,
95 tcpinfo_get(tcpinfo, tcpi_unacked, tcpinfoLen, 0),
96 tcpinfo_get(tcpinfo, tcpi_data_segs_out, tcpinfoLen, 0));
Hugo Benichi7b314e12018-01-15 21:54:00 +090097}
98
99const String16 TcpSocketMonitor::DUMP_KEYWORD = String16("tcp_socket_info");
Hugo Benichia9e3c5d2018-01-18 10:33:22 +0900100const milliseconds TcpSocketMonitor::kDefaultPollingInterval = milliseconds(30000);
Hugo Benichi7b314e12018-01-15 21:54:00 +0900101
102void TcpSocketMonitor::dump(DumpWriter& dw) {
Hugo Benichia9e3c5d2018-01-18 10:33:22 +0900103 std::lock_guard<std::mutex> guard(mLock);
104
Hugo Benichi7b314e12018-01-15 21:54:00 +0900105 dw.println("TcpSocketMonitor");
106 dw.incIndent();
107
Hugo Benichia9e3c5d2018-01-18 10:33:22 +0900108 const auto now = steady_clock::now();
109 const auto d = duration_cast<milliseconds>(now - mLastPoll);
110 dw.println("last poll %lld ms ago", d.count());
111
Hugo Benichi7b314e12018-01-15 21:54:00 +0900112 SockDiag sd;
113 if (!sd.open()) {
Hugo Benichia9e3c5d2018-01-18 10:33:22 +0900114 ALOGE("Error opening sock diag for dumping TCP socket info");
115 return;
Hugo Benichi7b314e12018-01-15 21:54:00 +0900116 }
117
Hugo Benichicbaa36b2018-01-17 12:11:43 +0900118 const auto tcpInfoReader = [&dw](Fwmark mark, const struct inet_diag_msg *sockinfo,
Hugo Benichi54bfc7c2018-01-23 14:16:52 +0900119 const struct tcp_info *tcpinfo, uint32_t tcpinfoLen) {
120 tcpInfoPrint(dw, mark, sockinfo, tcpinfo, tcpinfoLen);
Hugo Benichi7b314e12018-01-15 21:54:00 +0900121 };
122
123 if (int ret = sd.getLiveTcpInfos(tcpInfoReader)) {
124 ALOGE("Failed to dump TCP socket info: %s", strerror(-ret));
125 return;
126 }
127
128 dw.decIndent();
129}
130
Hugo Benichia9e3c5d2018-01-18 10:33:22 +0900131void TcpSocketMonitor::setPollingInterval(milliseconds nextSleepDurationMs) {
132 std::lock_guard<std::mutex> guard(mLock);
133
134 mNextSleepDurationMs = nextSleepDurationMs;
135
136 ALOGD("tcpinfo polling interval set to %lld ms", mNextSleepDurationMs.count());
137}
138
139void TcpSocketMonitor::resumePolling() {
140 {
141 std::lock_guard<std::mutex> guard(mLock);
142
143 if (!mIsSuspended) {
144 return;
145 }
146
147 mIsSuspended = false;
148
149 ALOGD("resuming tcpinfo polling with polling interval set to %lld ms",
150 mNextSleepDurationMs.count());
151 }
152
153 mCv.notify_all();
154}
155
156void TcpSocketMonitor::suspendPolling() {
157 std::lock_guard<std::mutex> guard(mLock);
158
159 if (!mIsSuspended) {
160 ALOGD("suspending tcpinfo polling");
161 mIsSuspended = true;
162 }
163}
164
165void TcpSocketMonitor::poll() {
166 std::lock_guard<std::mutex> guard(mLock);
167
168 if (mIsSuspended) {
169 return;
170 }
171
172 const auto now = steady_clock::now();
173
174 SockDiag sd;
175 if (!sd.open()) {
176 ALOGE("Error opening sock diag for polling TCP socket info");
177 return;
178 }
179
180 const auto tcpInfoReader = [](Fwmark mark, const struct inet_diag_msg *sockinfo,
Hugo Benichi54bfc7c2018-01-23 14:16:52 +0900181 const struct tcp_info *tcpinfo, uint32_t tcpinfoLen) {
182 if (sockinfo == nullptr || tcpinfo == nullptr || tcpinfoLen == 0 || mark.intValue == 0) {
Hugo Benichia9e3c5d2018-01-18 10:33:22 +0900183 return;
184 }
185
186 // TODO: process socket stats
187 };
188
189 if (int ret = sd.getLiveTcpInfos(tcpInfoReader)) {
190 ALOGE("Failed to poll TCP socket info: %s", strerror(-ret));
191 return;
192 }
193
194 mLastPoll = now;
195}
196
197void TcpSocketMonitor::waitForNextPoll() {
198 bool isSuspended;
199 milliseconds nextSleepDurationMs;
200 {
201 std::lock_guard<std::mutex> guard(mLock);
202 isSuspended = mIsSuspended;
203 nextSleepDurationMs= mNextSleepDurationMs;
204 }
205
206 std::unique_lock<std::mutex> ul(mLock);
207 if (isSuspended) {
208 mCv.wait(ul);
209 } else {
210 mCv.wait_for(ul, nextSleepDurationMs);
211 }
212}
213
214bool TcpSocketMonitor::isRunning() {
215 std::lock_guard<std::mutex> guard(mLock);
216 return mIsRunning;
217}
218
219TcpSocketMonitor::TcpSocketMonitor() {
220 std::lock_guard<std::mutex> guard(mLock);
221
222 mNextSleepDurationMs = kDefaultPollingInterval;
223 mIsSuspended = true;
224 mIsRunning = true;
225 mPollingThread = std::thread([this] {
226 while (isRunning()) {
227 poll();
228 waitForNextPoll();
229 }
230 });
231}
232
233TcpSocketMonitor::~TcpSocketMonitor() {
234 {
235 std::lock_guard<std::mutex> guard(mLock);
236 mIsRunning = false;
237 mIsSuspended = true;
238 }
239 mCv.notify_all();
240 mPollingThread.join();
241}
242
Hugo Benichi7b314e12018-01-15 21:54:00 +0900243} // namespace net
244} // namespace android