blob: 2d53119da38cb5d2f821f80cd8a5e1b5100ac092 [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 Benichicbaa36b2018-01-17 12:11:43 +090067static void tcpInfoPrint(DumpWriter &dw, Fwmark mark, const struct inet_diag_msg *sockinfo,
Hugo Benichi7b314e12018-01-15 21:54:00 +090068 const struct tcp_info *tcpinfo) {
Hugo Benichia9e3c5d2018-01-18 10:33:22 +090069 char saddr[INET6_ADDRSTRLEN] = {};
70 char daddr[INET6_ADDRSTRLEN] = {};
71 inet_ntop(sockinfo->idiag_family, &(sockinfo->id.idiag_src), saddr, sizeof(saddr));
72 inet_ntop(sockinfo->idiag_family, &(sockinfo->id.idiag_dst), daddr, sizeof(daddr));
Hugo Benichi7b314e12018-01-15 21:54:00 +090073
Hugo Benichia9e3c5d2018-01-18 10:33:22 +090074 dw.println(
75 "netId=%d uid=%u mark=0x%x saddr=%s daddr=%s sport=%u dport=%u tcp_state=%s(%u) "
76 "rqueue=%u wqueue=%u rtt=%gms var_rtt=%gms rcv_rtt=%gms unacked=%u snd_cwnd=%u",
77 mark.netId,
78 sockinfo->idiag_uid,
79 mark.intValue,
80 saddr,
81 daddr,
82 ntohs(sockinfo->id.idiag_sport),
83 ntohs(sockinfo->id.idiag_dport),
84 getTcpStateName(sockinfo->idiag_state), sockinfo->idiag_state,
85 sockinfo->idiag_rqueue,
86 sockinfo->idiag_wqueue,
87 tcpinfo != nullptr ? tcpinfo->tcpi_rtt/1000.0 : 0,
88 tcpinfo != nullptr ? tcpinfo->tcpi_rttvar/1000.0 : 0,
89 tcpinfo != nullptr ? tcpinfo->tcpi_rcv_rtt/1000.0 : 0,
90 tcpinfo != nullptr ? tcpinfo->tcpi_unacked : 0,
91 tcpinfo != nullptr ? tcpinfo->tcpi_snd_cwnd : 0);
Hugo Benichi7b314e12018-01-15 21:54:00 +090092}
93
94const String16 TcpSocketMonitor::DUMP_KEYWORD = String16("tcp_socket_info");
Hugo Benichia9e3c5d2018-01-18 10:33:22 +090095const milliseconds TcpSocketMonitor::kDefaultPollingInterval = milliseconds(30000);
Hugo Benichi7b314e12018-01-15 21:54:00 +090096
97void TcpSocketMonitor::dump(DumpWriter& dw) {
Hugo Benichia9e3c5d2018-01-18 10:33:22 +090098 std::lock_guard<std::mutex> guard(mLock);
99
Hugo Benichi7b314e12018-01-15 21:54:00 +0900100 dw.println("TcpSocketMonitor");
101 dw.incIndent();
102
Hugo Benichia9e3c5d2018-01-18 10:33:22 +0900103 const auto now = steady_clock::now();
104 const auto d = duration_cast<milliseconds>(now - mLastPoll);
105 dw.println("last poll %lld ms ago", d.count());
106
Hugo Benichi7b314e12018-01-15 21:54:00 +0900107 SockDiag sd;
108 if (!sd.open()) {
Hugo Benichia9e3c5d2018-01-18 10:33:22 +0900109 ALOGE("Error opening sock diag for dumping TCP socket info");
110 return;
Hugo Benichi7b314e12018-01-15 21:54:00 +0900111 }
112
Hugo Benichicbaa36b2018-01-17 12:11:43 +0900113 const auto tcpInfoReader = [&dw](Fwmark mark, const struct inet_diag_msg *sockinfo,
Hugo Benichi7b314e12018-01-15 21:54:00 +0900114 const struct tcp_info *tcpinfo) {
Hugo Benichicbaa36b2018-01-17 12:11:43 +0900115 tcpInfoPrint(dw, mark, sockinfo, tcpinfo);
Hugo Benichi7b314e12018-01-15 21:54:00 +0900116 };
117
118 if (int ret = sd.getLiveTcpInfos(tcpInfoReader)) {
119 ALOGE("Failed to dump TCP socket info: %s", strerror(-ret));
120 return;
121 }
122
123 dw.decIndent();
124}
125
Hugo Benichia9e3c5d2018-01-18 10:33:22 +0900126void TcpSocketMonitor::setPollingInterval(milliseconds nextSleepDurationMs) {
127 std::lock_guard<std::mutex> guard(mLock);
128
129 mNextSleepDurationMs = nextSleepDurationMs;
130
131 ALOGD("tcpinfo polling interval set to %lld ms", mNextSleepDurationMs.count());
132}
133
134void TcpSocketMonitor::resumePolling() {
135 {
136 std::lock_guard<std::mutex> guard(mLock);
137
138 if (!mIsSuspended) {
139 return;
140 }
141
142 mIsSuspended = false;
143
144 ALOGD("resuming tcpinfo polling with polling interval set to %lld ms",
145 mNextSleepDurationMs.count());
146 }
147
148 mCv.notify_all();
149}
150
151void TcpSocketMonitor::suspendPolling() {
152 std::lock_guard<std::mutex> guard(mLock);
153
154 if (!mIsSuspended) {
155 ALOGD("suspending tcpinfo polling");
156 mIsSuspended = true;
157 }
158}
159
160void TcpSocketMonitor::poll() {
161 std::lock_guard<std::mutex> guard(mLock);
162
163 if (mIsSuspended) {
164 return;
165 }
166
167 const auto now = steady_clock::now();
168
169 SockDiag sd;
170 if (!sd.open()) {
171 ALOGE("Error opening sock diag for polling TCP socket info");
172 return;
173 }
174
175 const auto tcpInfoReader = [](Fwmark mark, const struct inet_diag_msg *sockinfo,
176 const struct tcp_info *tcpinfo) {
177 if (sockinfo == nullptr || tcpinfo == nullptr || mark.intValue == 0) {
178 return;
179 }
180
181 // TODO: process socket stats
182 };
183
184 if (int ret = sd.getLiveTcpInfos(tcpInfoReader)) {
185 ALOGE("Failed to poll TCP socket info: %s", strerror(-ret));
186 return;
187 }
188
189 mLastPoll = now;
190}
191
192void TcpSocketMonitor::waitForNextPoll() {
193 bool isSuspended;
194 milliseconds nextSleepDurationMs;
195 {
196 std::lock_guard<std::mutex> guard(mLock);
197 isSuspended = mIsSuspended;
198 nextSleepDurationMs= mNextSleepDurationMs;
199 }
200
201 std::unique_lock<std::mutex> ul(mLock);
202 if (isSuspended) {
203 mCv.wait(ul);
204 } else {
205 mCv.wait_for(ul, nextSleepDurationMs);
206 }
207}
208
209bool TcpSocketMonitor::isRunning() {
210 std::lock_guard<std::mutex> guard(mLock);
211 return mIsRunning;
212}
213
214TcpSocketMonitor::TcpSocketMonitor() {
215 std::lock_guard<std::mutex> guard(mLock);
216
217 mNextSleepDurationMs = kDefaultPollingInterval;
218 mIsSuspended = true;
219 mIsRunning = true;
220 mPollingThread = std::thread([this] {
221 while (isRunning()) {
222 poll();
223 waitForNextPoll();
224 }
225 });
226}
227
228TcpSocketMonitor::~TcpSocketMonitor() {
229 {
230 std::lock_guard<std::mutex> guard(mLock);
231 mIsRunning = false;
232 mIsSuspended = true;
233 }
234 mCv.notify_all();
235 mPollingThread.join();
236}
237
Hugo Benichi7b314e12018-01-15 21:54:00 +0900238} // namespace net
239} // namespace android