UnixSocket: support the vsock address family
This change adds the support of vsock family to UnixSocket. A vsock
socket name is in the format of vsock://$CID:$PORT.
For example:
`PERFETTO_PRODUCER_SOCK_NAME=vsock://-1:10000 traced` starts traced with
the producer socket listening on the "ANY" CID and port 10000.
See vsock(7) for special CID values that may be used for vsock.
Bug: 284258446
Change-Id: Ie6f8e4a9f55c0550dba48818e6e26642763fad8d
diff --git a/src/base/unix_socket_unittest.cc b/src/base/unix_socket_unittest.cc
index 3210c49..6ed65d5 100644
--- a/src/base/unix_socket_unittest.cc
+++ b/src/base/unix_socket_unittest.cc
@@ -1014,6 +1014,57 @@
ASSERT_EQ(0, connect(cli.fd(), reinterpret_cast<struct sockaddr*>(&addr),
addr_len));
}
+
+bool VsockLoopBackAddrSupported() {
+ auto sock =
+ UnixSocketRaw::CreateMayFail(SockFamily::kVsock, SockType::kStream);
+ return sock.Bind("vsock://1:10000");
+}
+
+TEST_F(UnixSocketTest, VSockStream) {
+ if (!VsockLoopBackAddrSupported())
+ GTEST_SKIP() << "vsock testing skipped: loopback address unsupported";
+
+ // Use the loopback CID (1) and a random unprileged port number.
+ StackString<128> sock_name("vsock://1:%d", 1024 + rand() % 10000);
+
+ // Set up the server.
+ auto srv =
+ UnixSocket::Listen(sock_name.ToStdString(), &event_listener_,
+ &task_runner_, SockFamily::kVsock, SockType::kStream);
+ ASSERT_TRUE(srv && srv->is_listening());
+
+ std::unique_ptr<UnixSocket> prod;
+ EXPECT_CALL(event_listener_, OnNewIncomingConnection(srv.get(), _))
+ .WillOnce(Invoke([&](UnixSocket*, UnixSocket* s) {
+ // OnDisconnect() might spuriously happen depending on the dtor order.
+ EXPECT_CALL(event_listener_, OnDisconnect(s)).Times(AtLeast(0));
+ EXPECT_CALL(event_listener_, OnDataAvailable(s))
+ .WillRepeatedly(Invoke([](UnixSocket* prod_sock) {
+ prod_sock->ReceiveString(); // Read connection EOF;
+ }));
+ ASSERT_TRUE(s->SendStr("welcome"));
+ }));
+
+ // Set up the client.
+ prod =
+ UnixSocket::Connect(sock_name.ToStdString(), &event_listener_,
+ &task_runner_, SockFamily::kVsock, SockType::kStream);
+ auto checkpoint = task_runner_.CreateCheckpoint("prod_connected");
+ EXPECT_CALL(event_listener_, OnDisconnect(prod.get())).Times(AtLeast(0));
+ EXPECT_CALL(event_listener_, OnConnect(prod.get(), true));
+ EXPECT_CALL(event_listener_, OnDataAvailable(prod.get()))
+ .WillRepeatedly(Invoke([checkpoint](UnixSocket* s) {
+ auto str = s->ReceiveString();
+ if (str == "")
+ return; // Connection EOF.
+ ASSERT_EQ("welcome", str);
+ checkpoint();
+ }));
+
+ task_runner_.RunUntilCheckpoint("prod_connected");
+ ASSERT_TRUE(Mock::VerifyAndClearExpectations(prod.get()));
+}
#endif // OS_LINUX || OS_ANDROID
TEST_F(UnixSocketTest, GetSockFamily) {
@@ -1025,6 +1076,10 @@
ASSERT_EQ(GetSockFamily("127.0.0.1:80"), SockFamily::kInet);
ASSERT_EQ(GetSockFamily("[effe::acca]:1234"), SockFamily::kInet6);
ASSERT_EQ(GetSockFamily("[::1]:123456"), SockFamily::kInet6);
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+ ASSERT_EQ(GetSockFamily("vsock://-1:10000"), SockFamily::kVsock);
+#endif
}
} // namespace