The open source OpenXR runtime
at main 691 lines 16 kB view raw
1// Copyright 2020-2023, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief Main hub of the remote driver. 6 * @author Jakob Bornecrantz <jakob@collabora.com> 7 * @ingroup drv_remote 8 */ 9 10#include "r_internal.h" 11 12#include "util/u_var.h" 13#include "util/u_misc.h" 14#include "util/u_debug.h" 15#include "util/u_space_overseer.h" 16 17#include <stdio.h> 18#include <stdlib.h> 19#include <string.h> 20 21#if defined(XRT_OS_WINDOWS) 22#include <winsock2.h> 23#include <ws2tcpip.h> 24#include "xrt/xrt_windows.h" 25#else 26#include <unistd.h> 27#include <sys/socket.h> 28#include <sys/types.h> 29#include <netdb.h> 30#include <arpa/inet.h> 31#include <netinet/in.h> 32#include <netinet/tcp.h> 33#endif 34 35#ifndef _BSD_SOURCE 36#define _BSD_SOURCE // same, but for musl // NOLINT 37#endif 38 39#ifndef __USE_MISC 40#define __USE_MISC // SOL_TCP on C11 41#endif 42 43// Define the format to use to print a socket descriptor 44#ifdef XRT_OS_WINDOWS 45// On Windows, this is a SOCKET, aka an unsigned long long 46#define R_SOCKET_FMT "%llu" 47#else 48// On non-Windows, this is a file descriptor, aka an int 49#define R_SOCKET_FMT "%i" 50#endif 51 52 53/* 54 * 55 * Small helpers. 56 * 57 */ 58 59DEBUG_GET_ONCE_LOG_OPTION(remote_log, "REMOTE_LOG", U_LOGGING_INFO) 60 61#define R_TRACE(R, ...) U_LOG_IFL_T((R)->rc.log_level, __VA_ARGS__) 62#define R_DEBUG(R, ...) U_LOG_IFL_D((R)->rc.log_level, __VA_ARGS__) 63#define R_INFO(R, ...) U_LOG_IFL_I((R)->rc.log_level, __VA_ARGS__) 64#define R_WARN(R, ...) U_LOG_IFL_W((R)->rc.log_level, __VA_ARGS__) 65#define R_ERROR(R, ...) U_LOG_IFL_E((R)->rc.log_level, __VA_ARGS__) 66 67#define RC_TRACE(RC, ...) U_LOG_IFL_T((RC)->log_level, __VA_ARGS__) 68#define RC_DEBUG(RC, ...) U_LOG_IFL_D((RC)->log_level, __VA_ARGS__) 69#define RC_INFO(RC, ...) U_LOG_IFL_I((RC)->log_level, __VA_ARGS__) 70#define RC_WARN(RC, ...) U_LOG_IFL_W((RC)->log_level, __VA_ARGS__) 71#define RC_ERROR(RC, ...) U_LOG_IFL_E((RC)->log_level, __VA_ARGS__) 72 73 74/* 75 * 76 * Platform socket wrapper functions. 77 * 78 */ 79 80#if defined(XRT_OS_WINDOWS) 81 82static inline void 83socket_close(r_socket_t id) 84{ 85 closesocket(id); 86} 87 88static inline r_socket_t 89socket_create(void) 90{ 91 return socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 92} 93 94static inline int 95socket_set_opt(r_socket_t id, int flag) 96{ 97 return setsockopt(id, SOL_SOCKET, SO_REUSEADDR, (const char *)&flag, sizeof(flag)); 98} 99 100static inline ssize_t 101socket_read(r_socket_t id, void *ptr, size_t size, size_t current) 102{ 103 return recv(id, (char *)ptr, (int)(size - current), 0); 104} 105 106static inline ssize_t 107socket_write(r_socket_t id, void *ptr, size_t size, size_t current) 108{ 109 return send(id, (const char *)ptr, (int)(size - current), 0); 110} 111 112#elif defined(XRT_OS_UNIX) 113 114static inline void 115socket_close(r_socket_t id) 116{ 117 close(id); 118} 119 120static inline r_socket_t 121socket_create(void) 122{ 123 return socket(AF_INET, SOCK_STREAM, 0); 124} 125 126static inline int 127socket_set_opt(r_socket_t id, int flag) 128{ 129 return setsockopt(id, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); 130} 131 132static inline ssize_t 133socket_read(r_socket_t id, void *ptr, size_t size, size_t current) 134{ 135 return read(id, ptr, size - current); 136} 137 138static inline ssize_t 139socket_write(r_socket_t id, void *ptr, size_t size, size_t current) 140{ 141 return write(id, ptr, size - current); 142} 143 144#endif // XRT_OS_UNIX 145 146 147/* 148 * 149 * Helper functions. 150 * 151 */ 152 153static r_socket_t 154setup_accept_fd(struct r_hub *r) 155{ 156 struct sockaddr_in server_address = {0}; 157#if defined(XRT_OS_WINDOWS) 158 // Initialize Winsock. 159 WSADATA wsaData; 160 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { 161 int error = WSAGetLastError(); 162 R_ERROR(r, "Failed to do WSAStartup %d", error); 163 return error; 164 } 165#endif 166 r_socket_t ret = socket_create(); 167 168 if (ret < 0) { 169 R_ERROR(r, "socket: " R_SOCKET_FMT, ret); 170 goto cleanup; 171 } 172 173 r->accept_fd = ret; 174 175 int flag = 1; 176 ret = socket_set_opt(r->accept_fd, flag); 177 if (ret < 0) { 178 R_ERROR(r, "setsockopt: " R_SOCKET_FMT, ret); 179 socket_close(r->accept_fd); 180 r->accept_fd = -1; 181 goto cleanup; 182 } 183 184 server_address.sin_family = AF_INET; 185 server_address.sin_addr.s_addr = htonl(INADDR_ANY); 186 server_address.sin_port = htons(r->port); 187 188 ret = bind(r->accept_fd, (struct sockaddr *)&server_address, sizeof(server_address)); 189 if (ret < 0) { 190 R_ERROR(r, "bind: " R_SOCKET_FMT, ret); 191 socket_close(r->accept_fd); 192 r->accept_fd = -1; 193 goto cleanup; 194 } 195 196 R_INFO(r, "Listen address %s on port %d", inet_ntoa(server_address.sin_addr), r->port); 197 198 listen(r->accept_fd, 5); 199 200 return 0; 201cleanup: 202#if defined(XRT_OS_WINDOWS) 203 WSACleanup(); 204#endif 205 return ret; 206} 207 208static bool 209wait_for_read_and_to_continue(struct r_hub *r, r_socket_t socket) 210{ 211 fd_set set; 212 int ret = 0; 213 214 // To be more roboust 215 if (socket < 0) { 216 return false; 217 } 218 219 while (os_thread_helper_is_running(&r->oth) && ret == 0) { 220 // Select can modify timeout, reset each loop. 221 struct timeval timeout = {.tv_sec = 1, .tv_usec = 0}; 222 223 // Reset each loop. 224 FD_ZERO(&set); 225 FD_SET(socket, &set); 226 227 ret = select((int)socket + 1, &set, NULL, NULL, &timeout); 228 } 229 230 if (ret < 0) { 231 R_ERROR(r, "select: %i", ret); 232 return false; 233 } else if (ret > 0) { 234 return true; 235 } else { 236 return false; 237 } 238} 239 240static r_socket_t 241do_accept(struct r_hub *r) 242{ 243 struct sockaddr_in addr = {0}; 244 r_socket_t ret = 0; 245 if (!wait_for_read_and_to_continue(r, r->accept_fd)) { 246 R_ERROR(r, "Failed to wait for id " R_SOCKET_FMT, r->accept_fd); 247 return -1; 248 } 249 250 socklen_t addr_length = (socklen_t)sizeof(addr); 251 ret = accept(r->accept_fd, (struct sockaddr *)&addr, &addr_length); 252 if (ret < 0) { 253 R_ERROR(r, "accept: " R_SOCKET_FMT, ret); 254 return ret; 255 } 256 257 r_socket_t conn_fd = ret; 258 259 int flags = 1; 260 ret = socket_set_opt(r->accept_fd, flags); 261 if (ret < 0) { 262 R_ERROR(r, "setsockopt: " R_SOCKET_FMT, ret); 263 socket_close(conn_fd); 264 return ret; 265 } 266 267 r->rc.fd = conn_fd; 268 269 R_INFO(r, "Connection received! " R_SOCKET_FMT, r->rc.fd); 270 271 return 0; 272} 273 274static ssize_t 275read_one(struct r_hub *r, struct r_remote_data *data) 276{ 277 struct r_remote_connection *rc = &r->rc; 278 279 const size_t size = sizeof(*data); 280 size_t current = 0; 281 282 while (current < size) { 283 void *ptr = (uint8_t *)data + current; 284 285 if (!wait_for_read_and_to_continue(r, rc->fd)) { 286 return -1; 287 } 288 289 ssize_t ret = socket_read(rc->fd, ptr, size, current); 290 if (ret < 0) { 291#if defined(XRT_OS_WINDOWS) 292 RC_ERROR(rc, "recv: %i", WSAGetLastError()); 293#else 294 RC_ERROR(rc, "read: %zi", ret); 295#endif 296 return ret; 297 } else if (ret > 0) { 298 current += (size_t)ret; 299 } else { 300 R_INFO(r, "Disconnected!"); 301 return -1; 302 } 303 } 304 305 return 0; 306} 307 308static void * 309run_thread(void *ptr) 310{ 311 struct r_hub *r = (struct r_hub *)ptr; 312 r_socket_t ret; 313 314 ret = setup_accept_fd(r); 315 if (ret < 0) { 316 R_INFO(r, "Leaving thread"); 317 return NULL; 318 } 319 320 while (os_thread_helper_is_running(&r->oth)) { 321 R_INFO(r, "Listening on port '%i'.", r->port); 322 323 ret = do_accept(r); 324 if (ret < 0) { 325 R_INFO(r, "Leaving thread"); 326 return NULL; 327 } 328 329 r_remote_connection_write_one(&r->rc, &r->reset); 330 r_remote_connection_write_one(&r->rc, &r->latest); 331 332 while (true) { 333 struct r_remote_data data; 334 335 ret = read_one(r, &data); 336 if (ret < 0) { 337 break; 338 } 339 340 r->latest = data; 341 } 342 } 343 344 R_INFO(r, "Leaving thread"); 345 346 return NULL; 347} 348 349static xrt_result_t 350r_hub_system_devices_get_roles(struct xrt_system_devices *xsysd, struct xrt_system_roles *out_roles) 351{ 352 struct r_hub *r = (struct r_hub *)xsysd; 353 354 struct xrt_system_roles roles = XRT_SYSTEM_ROLES_INIT; 355 roles.generation_id = 1; 356 roles.left = r->left_index; 357 roles.right = r->right_index; 358 359 *out_roles = roles; 360 361 return XRT_SUCCESS; 362} 363 364static void 365r_hub_system_devices_destroy(struct xrt_system_devices *xsysd) 366{ 367 struct r_hub *r = (struct r_hub *)xsysd; 368 369 R_DEBUG(r, "Destroying"); 370 371 // Stop the thread first. 372 os_thread_helper_stop_and_wait(&r->oth); 373 374 // Destroy all of the devices now. 375 for (uint32_t i = 0; i < ARRAY_SIZE(r->base.xdevs); i++) { 376 xrt_device_destroy(&r->base.xdevs[i]); 377 } 378 379 // Should be safe to destroy the sockets now. 380 if (r->accept_fd >= 0) { 381 socket_close(r->accept_fd); 382 r->accept_fd = -1; 383 } 384 385 if (r->rc.fd >= 0) { 386 socket_close(r->rc.fd); 387 r->rc.fd = -1; 388 } 389 390 free(r); 391 392#if defined(XRT_OS_WINDOWS) 393 // Clean up Winsock. 394 WSACleanup(); 395#endif 396} 397 398 399/* 400 * 401 * 'Exported' create function. 402 * 403 */ 404 405xrt_result_t 406r_create_devices(uint16_t port, 407 uint32_t view_count, 408 struct xrt_session_event_sink *broadcast, 409 struct xrt_system_devices **out_xsysd, 410 struct xrt_space_overseer **out_xso) 411{ 412 struct r_hub *r = U_TYPED_CALLOC(struct r_hub); 413 int ret; 414 415 r->base.destroy = r_hub_system_devices_destroy; 416 r->base.get_roles = r_hub_system_devices_get_roles; 417 r->origin.type = XRT_TRACKING_TYPE_RGB; 418 r->origin.initial_offset = (struct xrt_pose)XRT_POSE_IDENTITY; 419 r->reset.header = R_HEADER_VALUE; 420 r->reset.head.center = (struct xrt_pose)XRT_POSE_IDENTITY; 421 r->reset.head.center.position.y = 1.6f; 422 r->reset.left.active = true; 423 r->reset.left.hand_tracking_active = true; 424 r->reset.left.pose.position.x = -0.2f; 425 r->reset.left.pose.position.y = 1.3f; 426 r->reset.left.pose.position.z = -0.5f; 427 r->reset.left.pose.orientation.w = 1.0f; 428 429 r->reset.right.active = true; 430 r->reset.right.hand_tracking_active = true; 431 r->reset.right.pose.position.x = 0.2f; 432 r->reset.right.pose.position.y = 1.3f; 433 r->reset.right.pose.position.z = -0.5f; 434 r->reset.right.pose.orientation.w = 1.0f; 435 r->latest = r->reset; 436 r->rc.log_level = debug_get_log_option_remote_log(); 437 r->gui.hmd = true; 438 r->gui.left = true; 439 r->gui.right = true; 440 r->port = port; 441 r->view_count = view_count; 442 r->accept_fd = -1; 443 r->rc.fd = -1; 444 445 snprintf(r->origin.name, sizeof(r->origin.name), "Remote Simulator"); 446 447 ret = os_thread_helper_init(&r->oth); 448 if (ret != 0) { 449 R_ERROR(r, "Failed to init threading!"); 450 r_hub_system_devices_destroy(&r->base); 451 return XRT_ERROR_ALLOCATION; 452 } 453 454 ret = os_thread_helper_start(&r->oth, run_thread, r); 455 if (ret != 0) { 456 R_ERROR(r, "Failed to start thread!"); 457 r_hub_system_devices_destroy(&r->base); 458 return XRT_ERROR_ALLOCATION; 459 } 460 461 462 /* 463 * Setup system devices. 464 */ 465 466 struct xrt_device *head = r_hmd_create(r); 467 struct xrt_device *left = r_device_create(r, true); 468 struct xrt_device *right = r_device_create(r, false); 469 470 r->base.xdevs[r->base.xdev_count++] = head; 471 r->left_index = (int32_t)r->base.xdev_count; 472 r->base.xdevs[r->base.xdev_count++] = left; 473 r->right_index = (int32_t)r->base.xdev_count; 474 r->base.xdevs[r->base.xdev_count++] = right; 475 476 r->base.static_roles.head = head; 477 r->base.static_roles.hand_tracking.conforming.left = left; 478 r->base.static_roles.hand_tracking.conforming.right = right; 479 480 481 /* 482 * Space overseer. 483 */ 484 485 struct u_space_overseer *uso = u_space_overseer_create(broadcast); 486 struct xrt_space_overseer *xso = (struct xrt_space_overseer *)uso; 487 assert(uso != NULL); 488 489 struct xrt_space *root = xso->semantic.root; // Convenience 490 struct xrt_space *offset = NULL; 491 u_space_overseer_create_offset_space(uso, root, &r->origin.initial_offset, &offset); 492 493 for (uint32_t i = 0; i < r->base.xdev_count; i++) { 494 u_space_overseer_link_space_to_device(uso, offset, r->base.xdevs[i]); 495 } 496 497 // Unreference now 498 xrt_space_reference(&offset, NULL); 499 500 // Set root as stage space. 501 xrt_space_reference(&xso->semantic.stage, root); 502 503 // Local 1.6 meters up. 504 struct xrt_pose local_offset = {XRT_QUAT_IDENTITY, {0.0f, 1.6f, 0.0f}}; 505 u_space_overseer_create_offset_space(uso, root, &local_offset, &xso->semantic.local); 506 507 // Local floor at the same place as local except at floor height. 508 struct xrt_pose local_floor_offset = local_offset; 509 local_floor_offset.position.y = 0.0f; 510 u_space_overseer_create_offset_space(uso, root, &local_floor_offset, &xso->semantic.local_floor); 511 512 // Make view space be the head pose. 513 u_space_overseer_create_pose_space(uso, head, XRT_INPUT_GENERIC_HEAD_POSE, &xso->semantic.view); 514 515 516 /* 517 * Setup variable tracker. 518 */ 519 520 u_var_add_root(r, "Remote Hub", true); 521 // u_var_add_gui_header(r, &r->gui.hmd, "MHD"); 522 u_var_add_pose(r, &r->latest.head.center, "head.center"); 523 // u_var_add_gui_header(r, &r->gui.left, "Left"); 524 u_var_add_bool(r, &r->latest.left.active, "left.active"); 525 u_var_add_pose(r, &r->latest.left.pose, "left.pose"); 526 // u_var_add_gui_header(r, &r->gui.right, "Right"); 527 u_var_add_bool(r, &r->latest.right.active, "right.active"); 528 u_var_add_pose(r, &r->latest.right.pose, "right.pose"); 529 530 /* 531 * Done now. 532 */ 533 534 *out_xsysd = &r->base; 535 *out_xso = xso; 536 537 return XRT_SUCCESS; 538} 539 540 541/* 542 * 543 * 'Exported' connection functions. 544 * 545 */ 546 547r_socket_t 548r_remote_connection_init(struct r_remote_connection *rc, const char *ip_addr, uint16_t port) 549{ 550 struct sockaddr_in addr = {0}; 551 r_socket_t sock_fd; 552 r_socket_t conn_fd; 553 int ret; 554 555 // Set log level. 556 rc->log_level = debug_get_log_option_remote_log(); 557 558#if defined(XRT_OS_WINDOWS) 559 // Initialize Winsock. 560 WSADATA wsaData; 561 ret = WSAStartup(MAKEWORD(2, 2), &wsaData); 562 if (ret != 0) { 563 RC_ERROR(rc, "Failed to do WSAStartup %i", WSAGetLastError()); 564 return ret; 565 } 566#endif 567 568 // Address 569 addr.sin_family = AF_INET; 570 addr.sin_port = htons(port); 571 572 // inet_pton/InetPton resolves "localhost" as 0.0.0.0 or 255.255.255.255, and it causes connection error. To 573 // avoid this issue, the following logic converts "localhost" to "127.0.0.1" first. 574 if (strcmp("localhost", ip_addr) == 0) { 575 ret = inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr); 576 } else { 577 ret = inet_pton(AF_INET, ip_addr, &addr.sin_addr); 578 } 579 if (ret < 0) { 580 RC_ERROR(rc, "Failed to do inet pton for %s: %i", ip_addr, ret); 581 goto cleanup; 582 } 583 584 sock_fd = socket_create(); 585#if defined(XRT_OS_WINDOWS) 586 if (sock_fd == INVALID_SOCKET) { 587 RC_ERROR(rc, "Failed to create socket %i", WSAGetLastError()); 588 goto cleanup; 589 } 590#else 591 if (sock_fd < 0) { 592 RC_ERROR(rc, "Failed to create socket: %i", ret); 593 goto cleanup; 594 } 595#endif 596 597 conn_fd = sock_fd; 598 599 ret = connect(conn_fd, (struct sockaddr *)&addr, sizeof(addr)); 600 // If connect operation succeed, both Windows and POSIX returns 0. 601 if (ret != 0) { 602#if defined(XRT_OS_WINDOWS) 603 RC_ERROR(rc, "Failed to connect id " R_SOCKET_FMT " and addr %s with failure %d", conn_fd, 604 inet_ntoa(addr.sin_addr), WSAGetLastError()); 605#else 606 RC_ERROR(rc, "Failed to connect id " R_SOCKET_FMT " and addr %s with failure %d", conn_fd, 607 inet_ntoa(addr.sin_addr), ret); 608#endif 609 socket_close(conn_fd); 610 goto cleanup; 611 } 612 613 int flags = 1; 614 ret = socket_set_opt(conn_fd, flags); 615 if (ret < 0) { 616 RC_ERROR(rc, "Failed to setsockopt: %i", ret); 617 socket_close(conn_fd); 618 goto cleanup; 619 } 620 621 rc->fd = conn_fd; 622 623 return 0; 624 625cleanup: 626#if defined(XRT_OS_WINDOWS) 627 WSACleanup(); 628#endif 629 return ret; 630} 631 632int 633r_remote_connection_read_one(struct r_remote_connection *rc, struct r_remote_data *data) 634{ 635 const size_t size = sizeof(*data); 636 size_t current = 0; 637 638 while (current < size) { 639 void *ptr = (uint8_t *)data + current; 640 ssize_t ret = socket_read(rc->fd, ptr, size, current); 641 if (ret < 0) { 642 RC_ERROR(rc, "read: %zi", ret); 643 return ret; 644 } 645 if (ret > 0) { 646 current += (size_t)ret; 647 } else { 648 RC_INFO(rc, "Disconnected!"); 649 return -1; 650 } 651 } 652 653 if (data->header != R_HEADER_VALUE) { 654 RC_ERROR(rc, "Protocol version mismatch (expected 0x%08" PRIx64 ", got 0x%08" PRIx64, R_HEADER_VALUE, 655 data->header); 656 return -1; 657 } 658 659 return 0; 660} 661 662int 663r_remote_connection_write_one(struct r_remote_connection *rc, const struct r_remote_data *data) 664{ 665 const size_t size = sizeof(*data); 666 size_t current = 0; 667 668 if (data->header != R_HEADER_VALUE) { 669 RC_ERROR(rc, "Protocol version mismatch (expected 0x%08" PRIx64 ", got 0x%08" PRIx64, R_HEADER_VALUE, 670 data->header); 671 return -1; 672 } 673 674 while (current < size) { 675 void *ptr = (uint8_t *)data + current; 676 677 ssize_t ret = socket_write(rc->fd, ptr, size, current); 678 if (ret < 0) { 679 RC_ERROR(rc, "write: %zi", ret); 680 return ret; 681 } 682 if (ret > 0) { 683 current += (size_t)ret; 684 } else { 685 RC_INFO(rc, "Disconnected!"); 686 return -1; 687 } 688 } 689 690 return 0; 691}