1 /*
2  * Copyright (C) 2020 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 #include <sys/socket.h>
18 #include <unistd.h>
19 
20 // Needs to be included after sys/socket.h
21 #include <linux/vm_sockets.h>
22 
23 #include <iostream>
24 #include <optional>
25 
26 #include "android-base/file.h"
27 #include "android-base/logging.h"
28 #include "android-base/parseint.h"
29 #include "android-base/unique_fd.h"
30 #include "virt/VirtualizationTest.h"
31 
32 using namespace android::base;
33 using namespace android::os;
34 
35 namespace virt {
36 
37 static constexpr int kGuestPort = 45678;
38 static constexpr const char kVmConfigPath[] = "/data/local/tmp/virt-test/vsock_config.json";
39 static constexpr const char kTestMessage[] = "HelloWorld";
40 
41 TEST_F(VirtualizationTest, TestVsock) {
42     binder::Status status;
43 
44     unique_fd server_fd(TEMP_FAILURE_RETRY(socket(AF_VSOCK, SOCK_STREAM, 0)));
45     ASSERT_GE(server_fd, 0) << strerror(errno);
46 
47     struct sockaddr_vm server_sa = (struct sockaddr_vm){
48             .svm_family = AF_VSOCK,
49             .svm_port = kGuestPort,
50             .svm_cid = VMADDR_CID_ANY,
51     };
52 
53     int ret = TEMP_FAILURE_RETRY(bind(server_fd, (struct sockaddr *)&server_sa, sizeof(server_sa)));
54     ASSERT_EQ(ret, 0) << strerror(errno);
55 
56     LOG(INFO) << "Listening on port " << kGuestPort << "...";
57     ret = TEMP_FAILURE_RETRY(listen(server_fd, 1));
58     ASSERT_EQ(ret, 0) << strerror(errno);
59 
60     sp<IVirtualMachine> vm;
61     unique_fd vm_config_fd(open(kVmConfigPath, O_RDONLY | O_CLOEXEC));
62     status =
63             mVirtManager->startVm(ParcelFileDescriptor(std::move(vm_config_fd)), std::nullopt, &vm);
64     ASSERT_TRUE(status.isOk()) << "Error starting VM: " << status;
65 
66     int32_t cid;
67     status = vm->getCid(&cid);
68     ASSERT_TRUE(status.isOk()) << "Error getting CID: " << status;
69     LOG(INFO) << "VM starting with CID " << cid;
70 
71     LOG(INFO) << "Accepting connection...";
72     struct sockaddr_vm client_sa;
73     socklen_t client_sa_len = sizeof(client_sa);
74     unique_fd client_fd(
75             TEMP_FAILURE_RETRY(accept(server_fd, (struct sockaddr *)&client_sa, &client_sa_len)));
76     ASSERT_GE(client_fd, 0) << strerror(errno);
77     LOG(INFO) << "Connection from CID " << client_sa.svm_cid << " on port " << client_sa.svm_port;
78 
79     LOG(INFO) << "Reading message from the client...";
80     std::string msg;
81     ASSERT_TRUE(ReadFdToString(client_fd, &msg));
82 
83     LOG(INFO) << "Received message: " << msg;
84     ASSERT_EQ(msg, kTestMessage);
85 }
86 
87 } // namespace virt
88