Add the number of struct tcp_info bytes read from Netlink
This patch adds to the SockDiag TcpInfoReader callback the number of
bytes read from Netlink when parsing a struct tcp_info attribute with
attribute id INET_DIAG_INFO.
On different kernels, struct tcp_info will have different fields and
different sizes when serialized. A generic sock_diag struct tcp_info
handler can use the attribute byte size to distinguish between different
fields and safely read data inside struct tcp_info.
Bug: 64147860
Test: tested manually on sailfish with 3.18 kernel,
using $ adb shell dumpsys netd tcp_socket_info
Change-Id: I45da9ed787dc7f0c4873ce1132b5f8094bcffd0a
diff --git a/server/TcpSocketMonitor.cpp b/server/TcpSocketMonitor.cpp
index 2d53119..4a0a217 100644
--- a/server/TcpSocketMonitor.cpp
+++ b/server/TcpSocketMonitor.cpp
@@ -64,8 +64,13 @@
}
}
+// Helper macro for reading fields into struct tcp_info and handling different struct tcp_info
+// versions in the kernel.
+#define tcpinfo_get(ptr, fld, len, zero) \
+ (((ptr) != nullptr && offsetof(struct tcp_info, fld) < len) ? (ptr)->fld : zero)
+
static void tcpInfoPrint(DumpWriter &dw, Fwmark mark, const struct inet_diag_msg *sockinfo,
- const struct tcp_info *tcpinfo) {
+ const struct tcp_info *tcpinfo, uint32_t tcpinfoLen) {
char saddr[INET6_ADDRSTRLEN] = {};
char daddr[INET6_ADDRSTRLEN] = {};
inet_ntop(sockinfo->idiag_family, &(sockinfo->id.idiag_src), saddr, sizeof(saddr));
@@ -73,7 +78,7 @@
dw.println(
"netId=%d uid=%u mark=0x%x 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",
+ "rqueue=%u wqueue=%u rtt=%gms var_rtt=%gms rcv_rtt=%gms unacked=%u snd_cwnd=%u",
mark.netId,
sockinfo->idiag_uid,
mark.intValue,
@@ -84,11 +89,11 @@
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);
+ tcpinfo_get(tcpinfo, tcpi_rtt, tcpinfoLen, 0) / 1000.0,
+ tcpinfo_get(tcpinfo, tcpi_rttvar, tcpinfoLen, 0) / 1000.0,
+ tcpinfo_get(tcpinfo, tcpi_rcv_rtt, tcpinfoLen, 0) / 1000.0,
+ tcpinfo_get(tcpinfo, tcpi_unacked, tcpinfoLen, 0),
+ tcpinfo_get(tcpinfo, tcpi_data_segs_out, tcpinfoLen, 0));
}
const String16 TcpSocketMonitor::DUMP_KEYWORD = String16("tcp_socket_info");
@@ -111,8 +116,8 @@
}
const auto tcpInfoReader = [&dw](Fwmark mark, const struct inet_diag_msg *sockinfo,
- const struct tcp_info *tcpinfo) {
- tcpInfoPrint(dw, mark, sockinfo, tcpinfo);
+ const struct tcp_info *tcpinfo, uint32_t tcpinfoLen) {
+ tcpInfoPrint(dw, mark, sockinfo, tcpinfo, tcpinfoLen);
};
if (int ret = sd.getLiveTcpInfos(tcpInfoReader)) {
@@ -173,8 +178,8 @@
}
const auto tcpInfoReader = [](Fwmark mark, const struct inet_diag_msg *sockinfo,
- const struct tcp_info *tcpinfo) {
- if (sockinfo == nullptr || tcpinfo == nullptr || mark.intValue == 0) {
+ const struct tcp_info *tcpinfo, uint32_t tcpinfoLen) {
+ if (sockinfo == nullptr || tcpinfo == nullptr || tcpinfoLen == 0 || mark.intValue == 0) {
return;
}