The open source OpenXR runtime
at main 254 lines 7.0 kB view raw
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}