The open source OpenXR runtime
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v21.0.0 348 lines 9.0 kB view raw
1// Copyright 2020, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief IPC util helpers, for internal use only 6 * @author Ryan Pavlik <ryan.pavlik@collabora.com> 7 * @author Pete Black <pblack@collabora.com> 8 * @author Jakob Bornecrantz <jakob@collabora.com> 9 * @ingroup ipc_shared 10 */ 11 12#include "xrt/xrt_config_os.h" 13 14#include "shared/ipc_utils.h" 15#include "shared/ipc_protocol.h" 16 17#include <errno.h> 18#include <sys/socket.h> 19#include <unistd.h> 20 21#include <stdio.h> 22#include <string.h> 23#include <stdint.h> 24#include <assert.h> 25 26#include "util/u_logging.h" 27 28/* 29 * 30 * Logging 31 * 32 */ 33 34#define IPC_TRACE(d, ...) U_LOG_IFL_T(d->ll, __VA_ARGS__) 35#define IPC_DEBUG(d, ...) U_LOG_IFL_D(d->ll, __VA_ARGS__) 36#define IPC_INFO(d, ...) U_LOG_IFL_I(d->ll, __VA_ARGS__) 37#define IPC_WARN(d, ...) U_LOG_IFL_W(d->ll, __VA_ARGS__) 38#define IPC_ERROR(d, ...) U_LOG_IFL_E(d->ll, __VA_ARGS__) 39 40void 41ipc_message_channel_close(struct ipc_message_channel *imc) 42{ 43 if (imc->socket_fd < 0) { 44 return; 45 } 46 close(imc->socket_fd); 47 imc->socket_fd = -1; 48} 49 50xrt_result_t 51ipc_send(struct ipc_message_channel *imc, const void *data, size_t size) 52{ 53 struct msghdr msg = {0}; 54 struct iovec iov = {0}; 55 56 iov.iov_base = (void *)data; 57 iov.iov_len = size; 58 59 msg.msg_name = NULL; 60 msg.msg_namelen = 0; 61 msg.msg_iov = &iov; 62 msg.msg_iovlen = 1; 63 msg.msg_flags = 0; 64 65 ssize_t ret = sendmsg(imc->socket_fd, &msg, MSG_NOSIGNAL); 66 if (ret < 0) { 67 int code = errno; 68 IPC_ERROR(imc, "ERROR: Sending plain message on socket %d failed with error: '%i' '%s'!", 69 (int)imc->socket_fd, code, strerror(code)); 70 return XRT_ERROR_IPC_FAILURE; 71 } 72 73 return XRT_SUCCESS; 74} 75 76xrt_result_t 77ipc_receive(struct ipc_message_channel *imc, void *out_data, size_t size) 78{ 79 80 // wait for the response 81 struct iovec iov = {0}; 82 struct msghdr msg = {0}; 83 84 iov.iov_base = out_data; 85 iov.iov_len = size; 86 87 msg.msg_name = 0; 88 msg.msg_namelen = 0; 89 msg.msg_iov = &iov; 90 msg.msg_iovlen = 1; 91 msg.msg_flags = 0; 92 93 ssize_t len = recvmsg(imc->socket_fd, &msg, MSG_NOSIGNAL); 94 95 if (len < 0) { 96 int code = errno; 97 IPC_ERROR(imc, "ERROR: Receiving plain message on socket '%d' failed with error: '%i' '%s'!", 98 (int)imc->socket_fd, code, strerror(code)); 99 return XRT_ERROR_IPC_FAILURE; 100 } 101 102 if ((size_t)len != size) { 103 IPC_ERROR(imc, "recvmsg failed with error: wrong size '%i', expected '%i'!", (int)len, (int)size); 104 return XRT_ERROR_IPC_FAILURE; 105 } 106 107 return XRT_SUCCESS; 108} 109 110union imcontrol_buf { 111 uint8_t buf[512]; 112 struct cmsghdr align; 113}; 114 115xrt_result_t 116ipc_receive_fds(struct ipc_message_channel *imc, void *out_data, size_t size, int *out_handles, uint32_t num_handles) 117{ 118 assert(imc != NULL); 119 assert(out_data != NULL); 120 assert(size != 0); 121 assert(out_handles != NULL); 122 assert(num_handles != 0); 123 union imcontrol_buf u; 124 const size_t fds_size = sizeof(int) * num_handles; 125 const size_t cmsg_size = CMSG_SPACE(fds_size); 126 memset(u.buf, 0, cmsg_size); 127 128 struct iovec iov = {0}; 129 iov.iov_base = out_data; 130 iov.iov_len = size; 131 132 struct msghdr msg = {0}; 133 msg.msg_iov = &iov; 134 msg.msg_iovlen = 1; 135 msg.msg_control = u.buf; 136 msg.msg_controllen = cmsg_size; 137 138 ssize_t len = recvmsg(imc->socket_fd, &msg, MSG_NOSIGNAL); 139 if (len < 0) { 140 IPC_ERROR(imc, "recvmsg failed with error: '%s'!", strerror(errno)); 141 return XRT_ERROR_IPC_FAILURE; 142 } 143 144 if (len == 0) { 145 IPC_ERROR(imc, "recvmsg failed with error: no data!"); 146 return XRT_ERROR_IPC_FAILURE; 147 } 148 // Did the other side actually send file descriptors. 149 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); 150 if (cmsg == NULL) { 151 return XRT_SUCCESS; 152 } 153 154 memcpy(out_handles, (int *)CMSG_DATA(cmsg), fds_size); 155 return XRT_SUCCESS; 156} 157 158xrt_result_t 159ipc_send_fds(struct ipc_message_channel *imc, const void *data, size_t size, const int *handles, uint32_t num_handles) 160{ 161 assert(imc != NULL); 162 assert(data != NULL); 163 assert(size != 0); 164 assert(handles != NULL); 165 166 union imcontrol_buf u = {0}; 167 size_t cmsg_size = CMSG_SPACE(sizeof(int) * num_handles); 168 169 struct iovec iov = {0}; 170 iov.iov_base = (void *)data; 171 iov.iov_len = size; 172 173 struct msghdr msg = {0}; 174 msg.msg_name = NULL; 175 msg.msg_namelen = 0; 176 msg.msg_iov = &iov; 177 msg.msg_iovlen = 1; 178 msg.msg_flags = 0; 179 msg.msg_control = u.buf; 180 msg.msg_controllen = cmsg_size; 181 182 const size_t fds_size = sizeof(int) * num_handles; 183 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); 184 cmsg->cmsg_level = SOL_SOCKET; 185 cmsg->cmsg_type = SCM_RIGHTS; 186 cmsg->cmsg_len = CMSG_LEN(fds_size); 187 188 memcpy(CMSG_DATA(cmsg), handles, fds_size); 189 190 ssize_t ret = sendmsg(imc->socket_fd, &msg, MSG_NOSIGNAL); 191 if (ret < 0) { 192 IPC_ERROR(imc, "ERROR: sending %d FDs on socket %d failed with error: '%i' '%s'!", (int)num_handles, 193 imc->socket_fd, errno, strerror(errno)); 194 for (uint32_t i = 0; i < num_handles; i++) { 195 IPC_ERROR(imc, "\tfd #%i: %i", i, handles[i]); 196 } 197 return XRT_ERROR_IPC_FAILURE; 198 } 199 return XRT_SUCCESS; 200} 201 202xrt_result_t 203ipc_receive_handles_shmem( 204 struct ipc_message_channel *imc, void *out_data, size_t size, xrt_shmem_handle_t *out_handles, uint32_t num_handles) 205{ 206 return ipc_receive_fds(imc, out_data, size, out_handles, num_handles); 207} 208 209xrt_result_t 210ipc_send_handles_shmem(struct ipc_message_channel *imc, 211 const void *data, 212 size_t size, 213 const xrt_shmem_handle_t *handles, 214 uint32_t num_handles) 215{ 216 return ipc_send_fds(imc, data, size, handles, num_handles); 217} 218 219 220/* 221 * 222 * AHardwareBuffer graphics buffer functions. 223 * 224 */ 225 226#if defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_AHARDWAREBUFFER) 227 228#include <android/hardware_buffer.h> 229 230 231xrt_result_t 232ipc_receive_handles_graphics_buffer(struct ipc_message_channel *imc, 233 void *out_data, 234 size_t size, 235 xrt_graphics_buffer_handle_t *out_handles, 236 uint32_t num_handles) 237{ 238 xrt_result_t result = ipc_receive(imc, out_data, size); 239 if (result != XRT_SUCCESS) { 240 return result; 241 } 242 bool failed = false; 243 for (uint32_t i = 0; i < num_handles; ++i) { 244 int err = AHardwareBuffer_recvHandleFromUnixSocket(imc->socket_fd, &(out_handles[i])); 245 if (err != 0) { 246 failed = true; 247 } 248 } 249 return failed ? XRT_ERROR_IPC_FAILURE : XRT_SUCCESS; 250} 251 252 253xrt_result_t 254ipc_send_handles_graphics_buffer(struct ipc_message_channel *imc, 255 const void *data, 256 size_t size, 257 const xrt_graphics_buffer_handle_t *handles, 258 uint32_t num_handles) 259{ 260 xrt_result_t result = ipc_send(imc, data, size); 261 if (result != XRT_SUCCESS) { 262 return result; 263 } 264 bool failed = false; 265 for (uint32_t i = 0; i < num_handles; ++i) { 266 int err = AHardwareBuffer_sendHandleToUnixSocket(handles[i], imc->socket_fd); 267 if (err != 0) { 268 failed = true; 269 } 270 } 271 return failed ? XRT_ERROR_IPC_FAILURE : XRT_SUCCESS; 272} 273 274 275/* 276 * 277 * FD graphics buffer functions. 278 * 279 */ 280 281#elif defined(XRT_GRAPHICS_BUFFER_HANDLE_IS_FD) 282 283xrt_result_t 284ipc_receive_handles_graphics_buffer(struct ipc_message_channel *imc, 285 void *out_data, 286 size_t size, 287 xrt_graphics_buffer_handle_t *out_handles, 288 uint32_t num_handles) 289{ 290 return ipc_receive_fds(imc, out_data, size, out_handles, num_handles); 291} 292 293xrt_result_t 294ipc_send_handles_graphics_buffer(struct ipc_message_channel *imc, 295 const void *data, 296 size_t size, 297 const xrt_graphics_buffer_handle_t *handles, 298 uint32_t num_handles) 299{ 300 return ipc_send_fds(imc, data, size, handles, num_handles); 301} 302 303#else 304#error "Need port to transport these graphics buffers" 305#endif 306 307 308/* 309 * 310 * FD graphics sync functions. 311 * 312 */ 313 314#if defined(XRT_GRAPHICS_SYNC_HANDLE_IS_FD) 315 316xrt_result_t 317ipc_receive_handles_graphics_sync(struct ipc_message_channel *imc, 318 void *out_data, 319 size_t size, 320 xrt_graphics_sync_handle_t *out_handles, 321 uint32_t num_handles) 322{ 323 //! @todo Temporary hack to send no handles. 324 if (num_handles == 0) { 325 return ipc_receive(imc, out_data, size); 326 } else { 327 return ipc_receive_fds(imc, out_data, size, out_handles, num_handles); 328 } 329} 330 331xrt_result_t 332ipc_send_handles_graphics_sync(struct ipc_message_channel *imc, 333 const void *data, 334 size_t size, 335 const xrt_graphics_sync_handle_t *handles, 336 uint32_t num_handles) 337{ 338 //! @todo Temporary hack to send no handles. 339 if (num_handles == 0) { 340 return ipc_send(imc, data, size); 341 } else { 342 return ipc_send_fds(imc, data, size, handles, num_handles); 343 } 344} 345 346#else 347#error "Need port to transport these graphics buffers" 348#endif