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