Define TcpSocketMonitor with a single dump method
This patch adds a TcpSocketMonitor registered in Controllers and
implementing a single dump method for pretty printing socket info
dumped with SockDiag for all sockets on the system.
The dump method can be called with
$ adb shell dumpsys netd tcp_socket_info
Example of output is:
TcpSocketMonitor
uid=1021 saddr=192.168.2.29 daddr=192.168.2.228 sport=49766 dport=80 state=ESTABLISHED(1) rqueue=0 wqueue=339 rtt=0ms var_rtt=67373.1ms rcv_rtt=1.11372e+06ms unacked=1792 snd_cwnd=0
uid=0 saddr=192.168.2.29 daddr=8.8.4.4 sport=37050 dport=853 state=SYN-SENT(2) rqueue=0 wqueue=1 rtt=0ms var_rtt=134744ms rcv_rtt=1.11372e+06ms unacked=2816 snd_cwnd=0
uid=0 saddr=192.168.2.29 daddr=8.8.8.8 sport=38674 dport=853 state=SYN-SENT(2) rqueue=0 wqueue=1 rtt=1.9084e+06ms var_rtt=0.121ms rcv_rtt=1.90841e+06ms unacked=2816 snd_cwnd=0
uid=0 saddr=2001::0db8:4:fd00:51eb:5323:2a88:7e5a daddr=2001::0db8:4860::8844 sport=42521 dport=853 state=SYN-SENT(2) rqueue=0 wqueue=1 rtt=1.51824e+06ms var_rtt=1.61533e+06ms rcv_rtt=1.34365e+06ms unacked=2816 snd_cwnd=0
uid=0 saddr=2001::0db8:4:fd00:51eb:5323:2a88:7e5a daddr=2001::0db8:4860::8888 sport=44725 dport=853 state=SYN-SENT(2) rqueue=0 wqueue=1 rtt=0ms var_rtt=134744ms rcv_rtt=1.11372e+06ms unacked=2816 snd_cwnd=0
Bug: 64147860
Test: manual tests with newly introduced commands
Change-Id: Iad68cc141bc517f38c2c0ec3937269cb11fa8aa4
diff --git a/server/TcpSocketMonitor.cpp b/server/TcpSocketMonitor.cpp
new file mode 100644
index 0000000..3af7990
--- /dev/null
+++ b/server/TcpSocketMonitor.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "TcpSocketMonitor"
+
+#include "TcpSocketMonitor.h"
+#include "DumpWriter.h"
+
+#include "SockDiag.h"
+
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+#include <linux/tcp.h>
+
+namespace android {
+namespace net {
+
+constexpr const char* getTcpStateName(int t) {
+ switch (t) {
+ case TCP_ESTABLISHED:
+ return "ESTABLISHED";
+ case TCP_SYN_SENT:
+ return "SYN-SENT";
+ case TCP_SYN_RECV:
+ return "SYN-RECV";
+ case TCP_FIN_WAIT1:
+ return "FIN-WAIT-1";
+ case TCP_FIN_WAIT2:
+ return "FIN-WAIT-2";
+ case TCP_TIME_WAIT:
+ return "TIME-WAIT";
+ case TCP_CLOSE:
+ return "CLOSE";
+ case TCP_CLOSE_WAIT:
+ return "CLOSE-WAIT";
+ case TCP_LAST_ACK:
+ return "LAST-ACK";
+ case TCP_LISTEN:
+ return "LISTEN";
+ case TCP_CLOSING:
+ return "CLOSING";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static void tcpInfoPrint(DumpWriter &dw, const struct inet_diag_msg *sockinfo,
+ const struct tcp_info *tcpinfo) {
+ char saddr[INET6_ADDRSTRLEN] = {};
+ char daddr[INET6_ADDRSTRLEN] = {};
+ inet_ntop(sockinfo->idiag_family, &(sockinfo->id.idiag_src), saddr, sizeof(saddr));
+ inet_ntop(sockinfo->idiag_family, &(sockinfo->id.idiag_dst), daddr, sizeof(daddr));
+
+ dw.println(
+ "uid=%u saddr=%s daddr=%s sport=%u dport=%u tcp_state=%s(%u) "
+ "rqueue=%u wqueue=%u rtt=%gms var_rtt=%gms rcv_rtt=%gms unacked=%u snd_cwnd=%u",
+ sockinfo->idiag_uid,
+ saddr,
+ daddr,
+ ntohs(sockinfo->id.idiag_sport),
+ ntohs(sockinfo->id.idiag_dport),
+ getTcpStateName(sockinfo->idiag_state), sockinfo->idiag_state,
+ sockinfo->idiag_rqueue,
+ sockinfo->idiag_wqueue,
+ tcpinfo != nullptr ? tcpinfo->tcpi_rtt/1000.0 : 0,
+ tcpinfo != nullptr ? tcpinfo->tcpi_rttvar/1000.0 : 0,
+ tcpinfo != nullptr ? tcpinfo->tcpi_rcv_rtt/1000.0 : 0,
+ tcpinfo != nullptr ? tcpinfo->tcpi_unacked : 0,
+ tcpinfo != nullptr ? tcpinfo->tcpi_snd_cwnd : 0);
+}
+
+const String16 TcpSocketMonitor::DUMP_KEYWORD = String16("tcp_socket_info");
+
+void TcpSocketMonitor::dump(DumpWriter& dw) {
+ dw.println("TcpSocketMonitor");
+ dw.incIndent();
+
+ SockDiag sd;
+ if (!sd.open()) {
+ ALOGE("Error opening sock diag for dumping TCP socket info");
+ return;
+ }
+
+ const auto tcpInfoReader = [&dw](const struct inet_diag_msg *sockinfo,
+ const struct tcp_info *tcpinfo) {
+ tcpInfoPrint(dw, sockinfo, tcpinfo);
+ };
+
+ if (int ret = sd.getLiveTcpInfos(tcpInfoReader)) {
+ ALOGE("Failed to dump TCP socket info: %s", strerror(-ret));
+ return;
+ }
+
+ dw.decIndent();
+}
+
+} // namespace net
+} // namespace android