• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
19 #include <iomanip>
20 #include <thread>
21 #include <vector>
22 
23 #include <arpa/inet.h>
24 #include <netinet/tcp.h>
25 #include <linux/tcp.h>
26 
27 #include "Controllers.h"
28 #include "DumpWriter.h"
29 #include "SockDiag.h"
30 #include "TcpSocketMonitor.h"
31 
32 namespace android {
33 namespace net {
34 
35 using std::chrono::duration_cast;
36 using std::chrono::steady_clock;
37 
getTcpStateName(int t)38 constexpr 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 
67 // 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) + sizeof((ptr)->fld)) < len) ? \
71         (ptr)->fld : zero)
72 
tcpInfoPrint(DumpWriter & dw,Fwmark mark,const struct inet_diag_msg * sockinfo,const struct tcp_info * tcpinfo,uint32_t tcpinfoLen)73 static void tcpInfoPrint(DumpWriter &dw, Fwmark mark, const struct inet_diag_msg *sockinfo,
74                          const struct tcp_info *tcpinfo, uint32_t tcpinfoLen) {
75     char saddr[INET6_ADDRSTRLEN] = {};
76     char daddr[INET6_ADDRSTRLEN] = {};
77     inet_ntop(sockinfo->idiag_family, &(sockinfo->id.idiag_src), saddr, sizeof(saddr));
78     inet_ntop(sockinfo->idiag_family, &(sockinfo->id.idiag_dst), daddr, sizeof(daddr));
79 
80     dw.println(
81             "netId=%d uid=%u mark=0x%x saddr=%s daddr=%s sport=%u dport=%u tcp_state=%s(%u) "
82             "rtt=%gms sent=%u lost=%u",
83             mark.netId,
84             sockinfo->idiag_uid,
85             mark.intValue,
86             saddr,
87             daddr,
88             ntohs(sockinfo->id.idiag_sport),
89             ntohs(sockinfo->id.idiag_dport),
90             getTcpStateName(sockinfo->idiag_state), sockinfo->idiag_state,
91             TCPINFO_GET(tcpinfo, tcpi_rtt, tcpinfoLen, 0) / 1000.0,
92             TCPINFO_GET(tcpinfo, tcpi_segs_out, tcpinfoLen, 0),
93             TCPINFO_GET(tcpinfo, tcpi_lost, tcpinfoLen, 0));
94 }
95 
96 const String16 TcpSocketMonitor::DUMP_KEYWORD = String16("tcp_socket_info");
97 const milliseconds TcpSocketMonitor::kDefaultPollingInterval = milliseconds(30000);
98 
dump(DumpWriter & dw)99 void TcpSocketMonitor::dump(DumpWriter& dw) {
100     std::lock_guard<std::mutex> guard(mLock);
101 
102     dw.println("TcpSocketMonitor");
103     dw.incIndent();
104 
105     const auto now = steady_clock::now();
106     const auto d = duration_cast<milliseconds>(now - mLastPoll);
107     dw.println("running=%d, suspended=%d, last poll %lld ms ago",
108             mIsRunning, mIsSuspended, d.count());
109 
110     if (!mNetworkStats.empty()) {
111         dw.blankline();
112         dw.println("Network stats:");
113         for (auto const& stats : mNetworkStats) {
114             if (stats.second.nSockets == 0) {
115                 continue;
116             }
117             dw.println("netId=%d sent=%d lost=%d rttMs=%gms sentAckDiff=%gms",
118                     stats.first,
119                     stats.second.sent,
120                     stats.second.lost,
121                     stats.second.rttUs / 1000.0 / stats.second.nSockets,
122                     stats.second.sentAckDiffMs / stats.second.nSockets);
123         }
124     }
125 
126     if (!mSocketEntries.empty()) {
127         dw.blankline();
128         dw.println("Socket entries:");
129         for (auto const& stats : mSocketEntries) {
130             dw.println("netId=%u uid=%u cookie=%ld",
131                     stats.second.mark.netId, stats.second.uid, stats.first);
132         }
133     }
134 
135     SockDiag sd;
136     if (sd.open()) {
137         dw.blankline();
138         dw.println("Current socket dump:");
139         const auto tcpInfoReader = [&dw](Fwmark mark, const struct inet_diag_msg *sockinfo,
140                                          const struct tcp_info *tcpinfo, uint32_t tcpinfoLen) {
141             tcpInfoPrint(dw, mark, sockinfo, tcpinfo, tcpinfoLen);
142         };
143 
144         if (int ret = sd.getLiveTcpInfos(tcpInfoReader)) {
145             ALOGE("Failed to dump TCP socket info: %s", strerror(-ret));
146         }
147     } else {
148         ALOGE("Error opening sock diag for dumping TCP socket info");
149     }
150 
151     dw.decIndent();
152 }
153 
setPollingInterval(milliseconds nextSleepDurationMs)154 void TcpSocketMonitor::setPollingInterval(milliseconds nextSleepDurationMs) {
155     std::lock_guard<std::mutex> guard(mLock);
156 
157     mNextSleepDurationMs = nextSleepDurationMs;
158 
159     ALOGD("tcpinfo polling interval set to %lld ms", mNextSleepDurationMs.count());
160 }
161 
resumePolling()162 void TcpSocketMonitor::resumePolling() {
163     bool wasSuspended;
164     {
165         std::lock_guard<std::mutex> guard(mLock);
166 
167         wasSuspended = mIsSuspended;
168         mIsSuspended = false;
169         ALOGD("resuming tcpinfo polling (interval=%lldms)", mNextSleepDurationMs.count());
170     }
171 
172     if (wasSuspended) {
173         mCv.notify_all();
174     }
175 }
176 
suspendPolling()177 void TcpSocketMonitor::suspendPolling() {
178     std::lock_guard<std::mutex> guard(mLock);
179 
180     bool wasSuspended = mIsSuspended;
181     mIsSuspended = true;
182     ALOGD("suspending tcpinfo polling");
183 
184     if (!wasSuspended) {
185         mSocketEntries.clear();
186     }
187 }
188 
poll()189 void TcpSocketMonitor::poll() {
190     std::lock_guard<std::mutex> guard(mLock);
191 
192     if (mIsSuspended) {
193         return;
194     }
195 
196     SockDiag sd;
197     if (!sd.open()) {
198         ALOGE("Error opening sock diag for polling TCP socket info");
199         return;
200     }
201 
202     const auto now = steady_clock::now();
203     const auto tcpInfoReader = [this, now](Fwmark mark, const struct inet_diag_msg *sockinfo,
204                                            const struct tcp_info *tcpinfo,
205                                            uint32_t tcpinfoLen) NO_THREAD_SAFETY_ANALYSIS {
206         if (sockinfo == nullptr || tcpinfo == nullptr || tcpinfoLen == 0 || mark.intValue == 0) {
207             return;
208         }
209         updateSocketStats(now, mark, sockinfo, tcpinfo, tcpinfoLen);
210     };
211 
212     // Reset mNetworkStats
213     mNetworkStats.clear();
214 
215     if (int ret = sd.getLiveTcpInfos(tcpInfoReader)) {
216         ALOGE("Failed to poll TCP socket info: %s", strerror(-ret));
217         return;
218     }
219 
220     // Remove any SocketEntry not updated
221     for (auto it = mSocketEntries.cbegin(); it != mSocketEntries.cend();) {
222         if (it->second.lastUpdate < now) {
223             it = mSocketEntries.erase(it);
224         } else {
225             it++;
226         }
227     }
228 
229     const auto listener = gCtls->eventReporter.getNetdEventListener();
230     if (listener != nullptr) {
231         std::vector<int> netIds;
232         std::vector<int> sentPackets;
233         std::vector<int> lostPackets;
234         std::vector<int> rtts;
235         std::vector<int> sentAckDiffs;
236         for (auto const& stats : mNetworkStats) {
237             int32_t nSockets = stats.second.nSockets;
238             if (nSockets == 0) {
239                 continue;
240             }
241             netIds.push_back(stats.first);
242             sentPackets.push_back(stats.second.sent);
243             lostPackets.push_back(stats.second.lost);
244             rtts.push_back(stats.second.rttUs / nSockets);
245             sentAckDiffs.push_back(stats.second.sentAckDiffMs / nSockets);
246         }
247         listener->onTcpSocketStatsEvent(netIds, sentPackets, lostPackets, rtts, sentAckDiffs);
248     }
249 
250     mLastPoll = now;
251 }
252 
waitForNextPoll()253 void TcpSocketMonitor::waitForNextPoll() {
254     bool isSuspended;
255     milliseconds nextSleepDurationMs;
256     {
257         std::lock_guard<std::mutex> guard(mLock);
258         isSuspended = mIsSuspended;
259         nextSleepDurationMs= mNextSleepDurationMs;
260     }
261 
262     std::unique_lock<std::mutex> ul(mLock);
263     if (isSuspended) {
264         mCv.wait(ul);
265     } else {
266         mCv.wait_for(ul, nextSleepDurationMs);
267     }
268 }
269 
isRunning()270 bool TcpSocketMonitor::isRunning() {
271     std::lock_guard<std::mutex> guard(mLock);
272     return mIsRunning;
273 }
274 
updateSocketStats(time_point now,Fwmark mark,const struct inet_diag_msg * sockinfo,const struct tcp_info * tcpinfo,uint32_t tcpinfoLen)275 void TcpSocketMonitor::updateSocketStats(time_point now, Fwmark mark,
276                                          const struct inet_diag_msg *sockinfo,
277                                          const struct tcp_info *tcpinfo,
278                                          uint32_t tcpinfoLen) NO_THREAD_SAFETY_ANALYSIS {
279     int32_t lastAck = TCPINFO_GET(tcpinfo, tcpi_last_ack_recv, tcpinfoLen, 0);
280     int32_t lastSent = TCPINFO_GET(tcpinfo, tcpi_last_data_sent, tcpinfoLen, 0);
281     TcpStats diff = {
282         .sent = TCPINFO_GET(tcpinfo, tcpi_segs_out, tcpinfoLen, 0),
283         .lost = TCPINFO_GET(tcpinfo, tcpi_lost, tcpinfoLen, 0),
284         .rttUs = TCPINFO_GET(tcpinfo, tcpi_rtt, tcpinfoLen, 0),
285         .sentAckDiffMs = lastAck - lastSent,
286         .nSockets = 1,
287     };
288 
289     {
290         // Update socket stats with the newest entry, computing the diff w.r.t the previous entry.
291         const uint64_t cookie = (static_cast<uint64_t>(sockinfo->id.idiag_cookie[0]) << 32)
292                 | static_cast<uint64_t>(sockinfo->id.idiag_cookie[1]);
293         const SocketEntry previous = mSocketEntries[cookie];
294         mSocketEntries[cookie] = {
295             .sent = diff.sent,
296             .lost = diff.lost,
297             .lastUpdate = now,
298             .mark = mark,
299             .uid = sockinfo->idiag_uid,
300         };
301 
302         diff.sent -= previous.sent;
303         diff.lost -= previous.lost;
304     }
305 
306     {
307         // Aggregate the diff per network id.
308         auto& stats = mNetworkStats[mark.netId];
309         stats.sent += diff.sent;
310         stats.lost += diff.lost;
311         stats.rttUs += diff.rttUs;
312         stats.sentAckDiffMs += diff.sentAckDiffMs;
313         stats.nSockets += diff.nSockets;
314     }
315 }
316 
TcpSocketMonitor()317 TcpSocketMonitor::TcpSocketMonitor() {
318     std::lock_guard<std::mutex> guard(mLock);
319 
320     mNextSleepDurationMs = kDefaultPollingInterval;
321     mIsRunning = true;
322     mIsSuspended = true;
323     mPollingThread = std::thread([this] {
324         (void) this;
325         while (isRunning()) {
326             poll();
327             waitForNextPoll();
328         }
329     });
330 }
331 
~TcpSocketMonitor()332 TcpSocketMonitor::~TcpSocketMonitor() {
333     {
334         std::lock_guard<std::mutex> guard(mLock);
335         mIsRunning = false;
336         mIsSuspended = true;
337     }
338     mCv.notify_all();
339     mPollingThread.join();
340 }
341 
342 }  // namespace net
343 }  // namespace android
344