blob: 660c915a46efb102c4ff1d2473757475862a1a25 [file] [log] [blame]
Cody Schuffelen134ff032019-11-22 00:25:32 -08001/*
2 * Copyright (C) 2017 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#include "host/commands/ivserver/qemu_client.h"
17
18#include <glog/logging.h>
19
20namespace ivserver {
21
22std::unique_ptr<QemuClient> QemuClient::New(const VSoCSharedMemory& shmem,
23 const cvd::SharedFD& socket) {
24 std::unique_ptr<QemuClient> res;
25 if (!socket->IsOpen()) {
26 LOG(WARNING) << "Invalid socket passed to QemuClient: "
27 << socket->StrError();
28 return res;
29 }
30
31 res.reset(new QemuClient(std::move(socket)));
32 if (!res->PerformHandshake(shmem)) {
33 LOG(ERROR) << "Qemu handshake failed. Dropping connection.";
34 res.reset();
35 }
36
37 return res;
38}
39
40QemuClient::QemuClient(cvd::SharedFD socket) : client_socket_(socket) {}
41
42// Once the QemuClient object is constructed, invoking the following
43// method will perform the actual handshake with a QEMU instance.
44bool QemuClient::PerformHandshake(const VSoCSharedMemory& shmem) {
45 LOG(INFO) << "New QEmu client connected.";
46 // 1. The protocol version number, currently zero. The client should
47 // close the connection on receipt of versions it can't handle.
48 int64_t msg = QemuConstants::kIvshMemProtocolVersion;
49 int rval = client_socket_->Send(&msg, sizeof(msg), MSG_NOSIGNAL);
50 if (rval != sizeof(msg)) {
51 LOG(ERROR) << "Failed to send protocol version: "
52 << client_socket_->StrError();
53 return false;
54 }
55
56 // 2. The client's ID. This is unique among all clients of this server.
57 // IDs must be between 0 and 65535, because the Doorbell register
58 // provides only 16 bits for them.
59 msg = QemuConstants::kGuestID;
60 rval = client_socket_->Send(&msg, sizeof(msg), MSG_NOSIGNAL);
61 if (rval != sizeof(msg)) {
62 LOG(ERROR) << "Failed to send VM Id: " << client_socket_->StrError();
63 return false;
64 }
65
66 // 3. Connect notifications for existing other clients, if any. This is
67 // a peer ID (number between 0 and 65535 other than the client's ID),
68 // repeated N times. Each repetition is accompanied by one file
69 // descriptor. These are for interrupting the peer with that ID using
70 // vector 0,..,N-1, in order. If the client is configured for fewer
71 // vectors, it closes the extra file descriptors. If it is configured
72 // for more, the extra vectors remain unconnected.
73 for (const auto& region_data : shmem.Regions()) {
74 if (!SendSocketInfo(kHostID, region_data.host_fd)) {
75 LOG(ERROR) << "Failed to send Host Side FD for region "
76 << region_data.device_name << ": " << client_socket_->StrError();
77 return false;
78 }
79 }
80
81 // 4. Interrupt setup. This is the client's own ID, repeated N times.
82 // Each repetition is accompanied by one file descriptor. These are
83 // for receiving interrupts from peers using vector 0,..,N-1, in
84 // order. If the client is configured for fewer vectors, it closes
85 // the extra file descriptors. If it is configured for more, the
86 // extra vectors remain unconnected.
87 for (const auto& region_data : shmem.Regions()) {
88 if (!SendSocketInfo(kGuestID, region_data.guest_fd)) {
89 LOG(ERROR) << "Failed to send Guest Side FD for region "
90 << region_data.device_name << ": " << client_socket_->StrError();
91 return false;
92 }
93 }
94
95 // 5. The number -1, accompanied by the file descriptor for the shared
96 // memory.
97 if (!SendSocketInfo(kSharedMem, shmem.SharedMemFD())) {
98 LOG(ERROR) << "Failed to send Shared Memory socket: "
99 << client_socket_->StrError();
100 return false;
101 }
102
103
104 LOG(INFO) << "QEmu handshake completed.";
105 return true;
106}
107
108bool QemuClient::SendSocketInfo(QemuConstants message,
109 const cvd::SharedFD& socket) {
110 struct iovec vec {
111 &message, sizeof(message)
112 };
113 cvd::InbandMessageHeader hdr{nullptr, 0, &vec, 1, 0};
114 cvd::SharedFD fds[] = {socket};
115 int rval = client_socket_->SendMsgAndFDs(hdr, 0, fds);
116 if (rval == -1) {
117 LOG(ERROR) << "failed to send shared_mem_fd: "
118 << client_socket_->StrError();
119 return false;
120 }
121 return true;
122}
123
124} // namespace ivserver