The open source OpenXR runtime
1// Copyright 2022, Magic Leap, Inc.
2// Copyright 2020-2023, Collabora, Ltd.
3// SPDX-License-Identifier: BSL-1.0
4/*!
5 * @file
6 * @brief IPC message channel functions for Windows.
7 * @author Julian Petrov <jpetrov@magicleap.com>
8 * @author Rylie Pavlik <rylie.pavlik@collabora.com>
9 * @author Pete Black <pblack@collabora.com>
10 * @author Jakob Bornecrantz <jakob@collabora.com>
11 * @ingroup ipc_shared
12 */
13
14#include "xrt/xrt_config_os.h"
15
16#ifndef XRT_OS_WINDOWS
17#error "This file is only for Windows"
18#endif
19
20#include "util/u_windows.h"
21#include "util/u_logging.h"
22
23#include "shared/ipc_utils.h"
24#include "shared/ipc_protocol.h"
25#include "shared/ipc_message_channel.h"
26
27#include <stdio.h>
28#include <string.h>
29#include <stdint.h>
30#include <assert.h>
31
32#include <vector>
33
34
35/*
36 *
37 * Logging
38 *
39 */
40
41#define IPC_TRACE(d, ...) U_LOG_IFL_T(d->log_level, __VA_ARGS__)
42#define IPC_DEBUG(d, ...) U_LOG_IFL_D(d->log_level, __VA_ARGS__)
43#define IPC_INFO(d, ...) U_LOG_IFL_I(d->log_level, __VA_ARGS__)
44#define IPC_WARN(d, ...) U_LOG_IFL_W(d->log_level, __VA_ARGS__)
45#define IPC_ERROR(d, ...) U_LOG_IFL_E(d->log_level, __VA_ARGS__)
46
47
48/*
49 *
50 * Helpers.
51 *
52 */
53
54static HANDLE
55open_target_process_dup_handle(struct ipc_message_channel *imc)
56{
57 DWORD flags;
58 if (!GetNamedPipeInfo(imc->ipc_handle, &flags, NULL, NULL, NULL)) {
59 DWORD err = GetLastError();
60 IPC_ERROR(imc, "GetNamedPipeInfo(%p) failed: %d %s", imc->ipc_handle, err, ipc_winerror(err));
61 return NULL;
62 }
63
64 ULONG pid;
65 if (flags & PIPE_SERVER_END) {
66 if (!GetNamedPipeClientProcessId(imc->ipc_handle, &pid)) {
67 DWORD err = GetLastError();
68 IPC_ERROR(imc, "GetNamedPipeClientProcessId(%p) failed: %d %s", imc->ipc_handle, err,
69 ipc_winerror(err));
70 return NULL;
71 }
72 } else {
73 if (!GetNamedPipeServerProcessId(imc->ipc_handle, &pid)) {
74 DWORD err = GetLastError();
75 IPC_ERROR(imc, "GetNamedPipeServerProcessId(%p) failed: %d %s", imc->ipc_handle, err,
76 ipc_winerror(err));
77 return NULL;
78 }
79 }
80
81 HANDLE h = OpenProcess(PROCESS_DUP_HANDLE, false, pid);
82 if (!h) {
83 DWORD err = GetLastError();
84 IPC_ERROR(imc, "OpenProcess(PROCESS_DUP_HANDLE, pid %d) failed: %d %s", pid, err, ipc_winerror(err));
85 }
86
87 return h;
88}
89
90
91/*
92 *
93 * 'Exported' functions.
94 *
95 */
96
97void
98ipc_message_channel_close(struct ipc_message_channel *imc)
99{
100 if (imc->ipc_handle != INVALID_HANDLE_VALUE) {
101 CloseHandle(imc->ipc_handle);
102 imc->ipc_handle = INVALID_HANDLE_VALUE;
103 }
104}
105
106xrt_result_t
107ipc_send(struct ipc_message_channel *imc, const void *data, size_t size)
108{
109 DWORD len;
110 if (!WriteFile(imc->ipc_handle, data, DWORD(size), &len, NULL)) {
111 DWORD err = GetLastError();
112 IPC_ERROR(imc, "WriteFile on pipe %p failed: %d %s", imc->ipc_handle, err, ipc_winerror(err));
113 return XRT_ERROR_IPC_FAILURE;
114 }
115 return XRT_SUCCESS;
116}
117
118xrt_result_t
119ipc_receive(struct ipc_message_channel *imc, void *out_data, size_t size)
120{
121 DWORD len;
122 if (!ReadFile(imc->ipc_handle, out_data, DWORD(size), &len, NULL)) {
123 DWORD err = GetLastError();
124 IPC_ERROR(imc, "ReadFile from pipe %p failed: %d %s", imc->ipc_handle, err, ipc_winerror(err));
125 return XRT_ERROR_IPC_FAILURE;
126 }
127 return XRT_SUCCESS;
128}
129
130
131/*
132 *
133 * Handle sending functions.
134 *
135 */
136
137xrt_result_t
138ipc_receive_handles(
139 struct ipc_message_channel *imc, void *out_data, size_t size, HANDLE *out_handles, uint32_t handle_count)
140{
141 auto rc = ipc_receive(imc, out_data, size);
142 if (rc != XRT_SUCCESS) {
143 return rc;
144 }
145 return ipc_receive(imc, out_handles, handle_count * sizeof(*out_handles));
146}
147
148xrt_result_t
149ipc_send_handles(
150 struct ipc_message_channel *imc, const void *data, size_t size, const HANDLE *handles, uint32_t handle_count)
151{
152 xrt_result_t xret = ipc_send(imc, data, size);
153 if (xret != XRT_SUCCESS) {
154 return xret;
155 }
156
157 if (!handle_count) {
158 return ipc_send(imc, nullptr, 0);
159 }
160
161 HANDLE target_process = open_target_process_dup_handle(imc);
162 if (!target_process) {
163 DWORD err = GetLastError();
164 IPC_ERROR(imc, "open_target_process_dup_handle failed: %d %s", err, ipc_winerror(err));
165 return XRT_ERROR_IPC_FAILURE;
166 }
167
168 HANDLE current_process = GetCurrentProcess();
169 std::vector<HANDLE> v;
170 v.reserve(handle_count);
171 for (uint32_t i = 0; i < handle_count; i++) {
172 HANDLE handle;
173 if ((size_t)handles[i] & 1) {
174 // This handle cannot be duplicated.
175 handle = handles[i];
176 } else if (!DuplicateHandle(current_process, handles[i], target_process, &handle, 0, false,
177 DUPLICATE_SAME_ACCESS)) {
178 DWORD err = GetLastError();
179 IPC_ERROR(imc, "DuplicateHandle(%p) failed: %d %s", handles[i], err, ipc_winerror(err));
180 CloseHandle(target_process);
181 return XRT_ERROR_IPC_FAILURE;
182 }
183 v.push_back(handle);
184 }
185 CloseHandle(target_process);
186 return ipc_send(imc, v.data(), v.size() * sizeof(*v.data()));
187}
188
189
190/*
191 *
192 * Typed handle functions.
193 *
194 */
195
196xrt_result_t
197ipc_receive_handles_shmem(struct ipc_message_channel *imc,
198 void *out_data,
199 size_t size,
200 xrt_shmem_handle_t *out_handles,
201 uint32_t handle_count)
202{
203 return ipc_receive_handles(imc, out_data, size, out_handles, handle_count);
204}
205
206xrt_result_t
207ipc_send_handles_shmem(struct ipc_message_channel *imc,
208 const void *data,
209 size_t size,
210 const xrt_shmem_handle_t *handles,
211 uint32_t handle_count)
212{
213 return ipc_send_handles(imc, data, size, handles, handle_count);
214}
215
216xrt_result_t
217ipc_receive_handles_graphics_sync(struct ipc_message_channel *imc,
218 void *out_data,
219 size_t size,
220 xrt_graphics_sync_handle_t *out_handles,
221 uint32_t handle_count)
222{
223 return ipc_receive_handles(imc, out_data, size, out_handles, handle_count);
224}
225
226xrt_result_t
227ipc_send_handles_graphics_sync(struct ipc_message_channel *imc,
228 const void *data,
229 size_t size,
230 const xrt_graphics_sync_handle_t *handles,
231 uint32_t handle_count)
232{
233 return ipc_send_handles(imc, data, size, handles, handle_count);
234}
235
236xrt_result_t
237ipc_receive_handles_graphics_buffer(struct ipc_message_channel *imc,
238 void *out_data,
239 size_t size,
240 xrt_graphics_buffer_handle_t *out_handles,
241 uint32_t handle_count)
242{
243 return ipc_receive_handles(imc, out_data, size, out_handles, handle_count);
244}
245
246xrt_result_t
247ipc_send_handles_graphics_buffer(struct ipc_message_channel *imc,
248 const void *data,
249 size_t size,
250 const xrt_graphics_buffer_handle_t *handles,
251 uint32_t handle_count)
252{
253 return ipc_send_handles(imc, data, size, handles, handle_count);
254}