mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2024-12-29 11:06:18 +00:00
ipc: Add Windows support
This commit is contained in:
parent
7669d2c545
commit
d0f713c4c4
|
@ -241,7 +241,7 @@ option_with_deps(XRT_HAVE_KIMERA_SLAM "Enable Kimera support" DEPENDS kimera_vio
|
|||
option(XRT_FEATURE_COLOR_LOG "Enable logging in color on supported platforms" ON)
|
||||
option_with_deps(XRT_FEATURE_COMPOSITOR_MAIN "Build main compositor host functionality" DEPENDS XRT_HAVE_VULKAN "XRT_HAVE_WAYLAND OR XRT_HAVE_XCB OR ANDROID OR WIN32")
|
||||
option_with_deps(XRT_FEATURE_COMPOSITOR_NULL "Build testing null compositor" DEPENDS XRT_HAVE_VULKAN)
|
||||
option_with_deps(XRT_FEATURE_IPC "Enable the build of the IPC layer" DEPENDS "NOT WIN32")
|
||||
option(XRT_FEATURE_IPC "Enable the build of the IPC layer" ON)
|
||||
option_with_deps(XRT_FEATURE_OPENXR "Build OpenXR runtime target" DEPENDS "XRT_FEATURE_COMPOSITOR_MAIN OR XRT_FEATURE_COMPOSITOR_NULL")
|
||||
option_with_deps(XRT_FEATURE_RENDERDOC "Enable RenderDoc API" DEPENDS "RT_LIBRARY OR WIN32")
|
||||
option_with_deps(XRT_FEATURE_SERVICE "Enable separate service module for OpenXR runtime" DEPENDS XRT_FEATURE_IPC XRT_FEATURE_OPENXR)
|
||||
|
|
|
@ -39,6 +39,11 @@ add_library(ipc_shared STATIC ${IPC_COMMON_SOURCES})
|
|||
target_include_directories(
|
||||
ipc_shared PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
target_sources(ipc_shared PRIVATE shared/ipc_utils_windows.cpp)
|
||||
endif()
|
||||
|
||||
target_link_libraries(ipc_shared PRIVATE aux_util)
|
||||
|
||||
if(RT_LIBRARY)
|
||||
|
@ -61,6 +66,13 @@ add_library(
|
|||
target_include_directories(
|
||||
ipc_client PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
if(WIN32)
|
||||
if(XRT_SERVICE_EXECUTABLE)
|
||||
target_compile_definitions(
|
||||
ipc_client PUBLIC XRT_SERVICE_EXECUTABLE="${XRT_SERVICE_EXECUTABLE}.exe"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
target_link_libraries(ipc_client PRIVATE aux_util ipc_shared)
|
||||
|
||||
###
|
||||
|
@ -111,4 +123,9 @@ elseif(XRT_HAVE_LINUX)
|
|||
target_sources(
|
||||
ipc_server PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/server/ipc_server_mainloop_linux.c
|
||||
)
|
||||
elseif(WIN32)
|
||||
target_sources(
|
||||
ipc_server
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/server/ipc_server_mainloop_windows.cpp
|
||||
)
|
||||
endif()
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
#include "xrt/xrt_defines.h"
|
||||
#include "xrt/xrt_config_os.h"
|
||||
|
||||
#include "util/u_misc.h"
|
||||
#include "util/u_handles.h"
|
||||
#include "util/u_trace_marker.h"
|
||||
|
||||
#include "os/os_time.h"
|
||||
|
||||
#include "util/u_wait.h"
|
||||
|
@ -25,9 +29,11 @@
|
|||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#if !defined(XRT_OS_WINDOWS)
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
@ -711,15 +717,10 @@ ipc_compositor_layer_commit(struct xrt_compositor *xc, int64_t frame_id, xrt_gra
|
|||
// Reset.
|
||||
icc->layers.layer_count = 0;
|
||||
|
||||
#ifdef XRT_GRAPHICS_SYNC_HANDLE_IS_FD
|
||||
// Need to consume this handle.
|
||||
if (valid_sync) {
|
||||
close(sync_handle);
|
||||
sync_handle = XRT_GRAPHICS_SYNC_HANDLE_INVALID;
|
||||
u_graphics_sync_unref(&sync_handle);
|
||||
}
|
||||
#else
|
||||
#error "Not yet implemented for this platform"
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
* @ingroup ipc_client
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "xrt/xrt_instance.h"
|
||||
#include "xrt/xrt_gfx_native.h"
|
||||
#include "xrt/xrt_handles.h"
|
||||
|
@ -25,6 +29,7 @@
|
|||
#include "util/u_file.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#if !defined(XRT_OS_WINDOWS)
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -34,6 +39,7 @@
|
|||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef XRT_GRAPHICS_BUFFER_HANDLE_IS_AHARDWAREBUFFER
|
||||
|
@ -104,12 +110,132 @@ ipc_connect(struct ipc_connection *ipc_c)
|
|||
return false;
|
||||
}
|
||||
|
||||
ipc_c->imc.socket_fd = socket;
|
||||
ipc_c->imc.ipc_handle = socket;
|
||||
ipc_c->imc.log_level = ipc_c->log_level;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#elif defined(XRT_OS_WINDOWS)
|
||||
|
||||
#if defined(NO_XRT_SERVICE_LAUNCH) || !defined(XRT_SERVICE_EXECUTABLE)
|
||||
static HANDLE
|
||||
ipc_connect_pipe(struct ipc_connection *ipc_c, const char *pipe_name)
|
||||
{
|
||||
HANDLE pipe_inst = CreateFileA(pipe_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (pipe_inst == INVALID_HANDLE_VALUE) {
|
||||
DWORD err = GetLastError();
|
||||
IPC_ERROR(ipc_c, "Connect to %s failed: %d %s", pipe_name, err, ipc_winerror(err));
|
||||
}
|
||||
return pipe_inst;
|
||||
}
|
||||
#else
|
||||
// N.B. quality of life fallback to try launch the XRT_SERVICE_EXECUTABLE if pipe is not found
|
||||
static HANDLE
|
||||
ipc_connect_pipe(struct ipc_connection *ipc_c, const char *pipe_name)
|
||||
{
|
||||
HANDLE pipe_inst = CreateFileA(pipe_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (pipe_inst != INVALID_HANDLE_VALUE) {
|
||||
return pipe_inst;
|
||||
}
|
||||
DWORD err = GetLastError();
|
||||
IPC_ERROR(ipc_c, "Connect to %s failed: %d %s", pipe_name, err, ipc_winerror(err));
|
||||
if (err != ERROR_FILE_NOT_FOUND) {
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
IPC_INFO(ipc_c, "Trying to launch " XRT_SERVICE_EXECUTABLE "...");
|
||||
HMODULE hmod;
|
||||
if (!GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||
(LPCSTR)ipc_connect_pipe, &hmod)) {
|
||||
IPC_ERROR(ipc_c, "GetModuleHandleExA failed: %d %s", err, ipc_winerror(err));
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
char service_path[MAX_PATH];
|
||||
if (!GetModuleFileNameA(hmod, service_path, sizeof(service_path))) {
|
||||
IPC_ERROR(ipc_c, "GetModuleFileNameA failed: %d %s", err, ipc_winerror(err));
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
char *p = strrchr(service_path, '\\');
|
||||
if (!p) {
|
||||
IPC_ERROR(ipc_c, "failed to parse the path %s", service_path);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
strcpy(p + 1, XRT_SERVICE_EXECUTABLE);
|
||||
STARTUPINFOA si = {.cb = sizeof(si)};
|
||||
PROCESS_INFORMATION pi;
|
||||
if (!CreateProcessA(NULL, service_path, NULL, NULL, false, 0, NULL, NULL, &si, &pi)) {
|
||||
*p = 0;
|
||||
p = strrchr(service_path, '\\');
|
||||
if (!p) {
|
||||
err = GetLastError();
|
||||
IPC_INFO(ipc_c, XRT_SERVICE_EXECUTABLE " not found in %s: %d %s", service_path, err,
|
||||
ipc_winerror(err));
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
strcpy(p + 1, "service\\" XRT_SERVICE_EXECUTABLE);
|
||||
if (!CreateProcessA(NULL, service_path, NULL, NULL, false, 0, NULL, NULL, &si, &pi)) {
|
||||
err = GetLastError();
|
||||
IPC_INFO(ipc_c, XRT_SERVICE_EXECUTABLE " not found at %s: %d %s", service_path, err,
|
||||
ipc_winerror(err));
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
IPC_INFO(ipc_c, "Launched %s (pid %d)... Waiting for %s...", service_path, pi.dwProcessId, pipe_name);
|
||||
CloseHandle(pi.hThread);
|
||||
for (int i = 0;; i++) {
|
||||
pipe_inst = CreateFileA(pipe_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (pipe_inst != INVALID_HANDLE_VALUE) {
|
||||
IPC_INFO(ipc_c, "Connected to %s after %d msec on try %d!", pipe_name, i * 100, i + 1);
|
||||
break;
|
||||
}
|
||||
err = GetLastError();
|
||||
if (err != ERROR_FILE_NOT_FOUND || WaitForSingleObject(pi.hProcess, 100) != WAIT_TIMEOUT) {
|
||||
IPC_ERROR(ipc_c, "Connect to %s failed: %d %s", pipe_name, err, ipc_winerror(err));
|
||||
break;
|
||||
}
|
||||
}
|
||||
CloseHandle(pi.hProcess);
|
||||
return pipe_inst;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool
|
||||
ipc_connect(struct ipc_connection *ipc_c)
|
||||
{
|
||||
ipc_c->log_level = debug_get_log_option_ipc_log();
|
||||
|
||||
const char pipe_prefix[] = "\\\\.\\pipe\\";
|
||||
#define prefix_len sizeof(pipe_prefix) - 1
|
||||
char pipe_name[MAX_PATH + prefix_len];
|
||||
strcpy(pipe_name, pipe_prefix);
|
||||
|
||||
if (u_file_get_path_in_runtime_dir(XRT_IPC_MSG_SOCK_FILENAME, pipe_name + prefix_len, MAX_PATH) == -1) {
|
||||
U_LOG_E("u_file_get_path_in_runtime_dir failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE pipe_inst = ipc_connect_pipe(ipc_c, pipe_name);
|
||||
if (pipe_inst == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
DWORD mode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
|
||||
if (!SetNamedPipeHandleState(pipe_inst, &mode, NULL, NULL)) {
|
||||
DWORD err = GetLastError();
|
||||
IPC_ERROR(ipc_c, "SetNamedPipeHandleState(PIPE_READMODE_MESSAGE | PIPE_WAIT) failed: %d %s", err,
|
||||
ipc_winerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
ipc_c->imc.ipc_handle = pipe_inst;
|
||||
ipc_c->imc.log_level = ipc_c->log_level;
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
getpid()
|
||||
{
|
||||
return GetCurrentProcessId();
|
||||
}
|
||||
|
||||
#else
|
||||
static bool
|
||||
|
@ -135,7 +261,7 @@ ipc_connect(struct ipc_connection *ipc_c)
|
|||
int size = u_file_get_path_in_runtime_dir(XRT_IPC_MSG_SOCK_FILENAME, sock_file, PATH_MAX);
|
||||
if (size == -1) {
|
||||
IPC_ERROR(ipc_c, "Could not get socket file name");
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
|
@ -149,7 +275,7 @@ ipc_connect(struct ipc_connection *ipc_c)
|
|||
return false;
|
||||
}
|
||||
|
||||
ipc_c->imc.socket_fd = socket;
|
||||
ipc_c->imc.ipc_handle = socket;
|
||||
ipc_c->imc.log_level = ipc_c->log_level;
|
||||
|
||||
return true;
|
||||
|
@ -299,8 +425,7 @@ ipc_instance_create(struct xrt_instance_info *i_info, struct xrt_instance **out_
|
|||
ii->base.get_prober = ipc_client_instance_get_prober;
|
||||
ii->base.destroy = ipc_client_instance_destroy;
|
||||
|
||||
// FDs needs to be set to something negative.
|
||||
ii->ipc_c.imc.socket_fd = -1;
|
||||
ii->ipc_c.imc.ipc_handle = XRT_IPC_HANDLE_INVALID;
|
||||
ii->ipc_c.ism_handle = XRT_SHMEM_HANDLE_INVALID;
|
||||
|
||||
os_mutex_init(&ii->ipc_c.mutex);
|
||||
|
@ -340,11 +465,16 @@ ipc_instance_create(struct xrt_instance_info *i_info, struct xrt_instance **out_
|
|||
return xret;
|
||||
}
|
||||
|
||||
const int flags = MAP_SHARED;
|
||||
const int access = PROT_READ | PROT_WRITE;
|
||||
const size_t size = sizeof(struct ipc_shared_memory);
|
||||
|
||||
#ifdef XRT_OS_WINDOWS
|
||||
ii->ipc_c.ism = MapViewOfFile(ii->ipc_c.ism_handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, size);
|
||||
#else
|
||||
const int flags = MAP_SHARED;
|
||||
const int access = PROT_READ | PROT_WRITE;
|
||||
|
||||
ii->ipc_c.ism = mmap(NULL, size, access, flags, ii->ipc_c.ism_handle, 0);
|
||||
#endif
|
||||
if (ii->ipc_c.ism == NULL) {
|
||||
IPC_ERROR((&ii->ipc_c), "Failed to mmap shm!");
|
||||
free(ii);
|
||||
|
|
|
@ -236,6 +236,23 @@ struct ipc_server_mainloop
|
|||
#define XRT_IPC_GOT_IMPL
|
||||
#endif
|
||||
|
||||
#if defined(XRT_OS_WINDOWS) || defined(XRT_DOXYGEN)
|
||||
/*!
|
||||
* @name Desktop Windows Mainloop Members
|
||||
* @{
|
||||
*/
|
||||
|
||||
//! Named Pipe that we accept connections on.
|
||||
HANDLE pipe_handle;
|
||||
|
||||
//! Name of the Pipe that we accept connections on.
|
||||
char *pipe_name;
|
||||
|
||||
/*! @} */
|
||||
|
||||
#define XRT_IPC_GOT_IMPL
|
||||
#endif
|
||||
|
||||
#ifndef XRT_IPC_GOT_IMPL
|
||||
#error "Need port"
|
||||
#endif
|
||||
|
@ -397,11 +414,11 @@ ipc_server_client_destroy_compositor(volatile struct ipc_client_state *ics);
|
|||
* @{
|
||||
*/
|
||||
/*!
|
||||
* Start a thread for a client connected at the other end of the file descriptor @p fd.
|
||||
* Start a thread for a client connected at the other end of the ipc handle @p ipc_handle.
|
||||
* @memberof ipc_server
|
||||
*/
|
||||
void
|
||||
ipc_server_start_client_listener_thread(struct ipc_server *vs, int fd);
|
||||
ipc_server_start_client_listener_thread(struct ipc_server *vs, xrt_ipc_handle_t ipc_handle);
|
||||
|
||||
/*!
|
||||
* Perform whatever needs to be done when the mainloop polling encounters a failure.
|
||||
|
|
|
@ -637,7 +637,7 @@ ipc_handle_system_get_client_info(volatile struct ipc_client_state *_ics,
|
|||
}
|
||||
volatile struct ipc_client_state *ics = &_ics->server->threads[id].ics;
|
||||
|
||||
if (ics->imc.socket_fd <= 0) {
|
||||
if (!xrt_ipc_handle_is_valid(ics->imc.ipc_handle)) {
|
||||
return XRT_ERROR_IPC_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -707,7 +707,7 @@ ipc_handle_system_toggle_io_client(volatile struct ipc_client_state *_ics, uint3
|
|||
|
||||
ics = &_ics->server->threads[client_id].ics;
|
||||
|
||||
if (ics->imc.socket_fd <= 0) {
|
||||
if (!xrt_ipc_handle_is_valid(ics->imc.ipc_handle)) {
|
||||
return XRT_ERROR_IPC_FAILURE;
|
||||
}
|
||||
|
||||
|
|
160
src/xrt/ipc/server/ipc_server_mainloop_windows.cpp
Normal file
160
src/xrt/ipc/server/ipc_server_mainloop_windows.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
// Copyright 2022, Magic Leap, Inc.
|
||||
// Copyright 2020-2022, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Server mainloop details on Windows.
|
||||
* @author Julian Petrov <jpetrov@magicleap.com>
|
||||
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup ipc_server
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "xrt/xrt_device.h"
|
||||
#include "xrt/xrt_instance.h"
|
||||
#include "xrt/xrt_compositor.h"
|
||||
#include "xrt/xrt_config_have.h"
|
||||
#include "xrt/xrt_config_os.h"
|
||||
|
||||
#include "os/os_time.h"
|
||||
#include "util/u_var.h"
|
||||
#include "util/u_misc.h"
|
||||
#include "util/u_debug.h"
|
||||
#include "util/u_trace_marker.h"
|
||||
#include "util/u_file.h"
|
||||
|
||||
#include "shared/ipc_shmem.h"
|
||||
#include "server/ipc_server.h"
|
||||
|
||||
#include <conio.h>
|
||||
|
||||
/*
|
||||
*
|
||||
* Static functions.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
ipc_server_create_another_pipe_instance(struct ipc_server *vs, struct ipc_server_mainloop *ml)
|
||||
{
|
||||
ml->pipe_handle =
|
||||
CreateNamedPipeA(ml->pipe_name, PIPE_ACCESS_DUPLEX,
|
||||
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT | PIPE_REJECT_REMOTE_CLIENTS,
|
||||
IPC_MAX_CLIENTS, IPC_BUF_SIZE, IPC_BUF_SIZE, 0, NULL);
|
||||
if (ml->pipe_handle == INVALID_HANDLE_VALUE) {
|
||||
DWORD err = GetLastError();
|
||||
if (err == ERROR_PIPE_BUSY) {
|
||||
U_LOG_W("CreateNamedPipeA failed: %d %s An existing client must disconnect first!", err,
|
||||
ipc_winerror(err));
|
||||
} else {
|
||||
U_LOG_E("CreateNamedPipeA failed: %d %s", err, ipc_winerror(err));
|
||||
ipc_server_handle_failure(vs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Exported functions
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
ipc_server_mainloop_poll(struct ipc_server *vs, struct ipc_server_mainloop *ml)
|
||||
{
|
||||
IPC_TRACE_MARKER();
|
||||
|
||||
if (_kbhit()) {
|
||||
U_LOG_E("console input! exiting...");
|
||||
ipc_server_handle_shutdown_signal(vs);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ml->pipe_handle) {
|
||||
ipc_server_create_another_pipe_instance(vs, ml);
|
||||
}
|
||||
if (!ml->pipe_handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ConnectNamedPipe(ml->pipe_handle, NULL)) {
|
||||
U_LOG_E("ConnectNamedPipe unexpected return TRUE (last error: %d). Treating as failure...",
|
||||
GetLastError());
|
||||
ipc_server_handle_failure(vs);
|
||||
return;
|
||||
}
|
||||
switch (DWORD err = GetLastError()) {
|
||||
case ERROR_PIPE_LISTENING: return;
|
||||
case ERROR_PIPE_CONNECTED: {
|
||||
DWORD mode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
|
||||
if (!SetNamedPipeHandleState(ml->pipe_handle, &mode, NULL, NULL)) {
|
||||
err = GetLastError();
|
||||
U_LOG_E("SetNamedPipeHandleState(PIPE_READMODE_MESSAGE | PIPE_WAIT) failed: %d %s", err,
|
||||
ipc_winerror(err));
|
||||
ipc_server_handle_failure(vs);
|
||||
return;
|
||||
}
|
||||
ipc_server_start_client_listener_thread(vs, ml->pipe_handle);
|
||||
ipc_server_create_another_pipe_instance(vs, ml);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
U_LOG_E("ConnectNamedPipe failed: %d %s", err, ipc_winerror(err));
|
||||
ipc_server_handle_failure(vs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ipc_server_mainloop_init(struct ipc_server_mainloop *ml)
|
||||
{
|
||||
IPC_TRACE_MARKER();
|
||||
|
||||
ml->pipe_handle = INVALID_HANDLE_VALUE;
|
||||
ml->pipe_name = nullptr;
|
||||
|
||||
constexpr char pipe_prefix[] = "\\\\.\\pipe\\";
|
||||
constexpr int prefix_len = sizeof(pipe_prefix) - 1;
|
||||
char pipe_name[MAX_PATH + prefix_len];
|
||||
strcpy(pipe_name, pipe_prefix);
|
||||
|
||||
if (u_file_get_path_in_runtime_dir(XRT_IPC_MSG_SOCK_FILENAME, pipe_name + prefix_len, MAX_PATH) == -1) {
|
||||
U_LOG_E("u_file_get_path_in_runtime_dir failed!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ml->pipe_name = _strdup(pipe_name);
|
||||
if (!ml->pipe_name) {
|
||||
U_LOG_E("_strdup(\"%s\") failed!", pipe_name);
|
||||
} else {
|
||||
ml->pipe_handle = CreateNamedPipeA(ml->pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE,
|
||||
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT |
|
||||
PIPE_REJECT_REMOTE_CLIENTS,
|
||||
IPC_MAX_CLIENTS, IPC_BUF_SIZE, IPC_BUF_SIZE, 0, NULL);
|
||||
if (ml->pipe_handle != INVALID_HANDLE_VALUE) {
|
||||
return 0;
|
||||
}
|
||||
DWORD err = GetLastError();
|
||||
U_LOG_E("CreateNamedPipeA \"%s\" first instance failed: %d %s", ml->pipe_name, err, ipc_winerror(err));
|
||||
}
|
||||
ipc_server_mainloop_deinit(ml);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
ipc_server_mainloop_deinit(struct ipc_server_mainloop *ml)
|
||||
{
|
||||
IPC_TRACE_MARKER();
|
||||
|
||||
if (ml->pipe_handle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(ml->pipe_handle);
|
||||
ml->pipe_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (ml->pipe_name) {
|
||||
free(ml->pipe_name);
|
||||
ml->pipe_name = nullptr;
|
||||
}
|
||||
}
|
|
@ -15,6 +15,8 @@
|
|||
#include "server/ipc_server.h"
|
||||
#include "ipc_server_generated.h"
|
||||
|
||||
#ifndef XRT_OS_WINDOWS
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
@ -34,7 +36,7 @@
|
|||
static int
|
||||
setup_epoll(volatile struct ipc_client_state *ics)
|
||||
{
|
||||
int listen_socket = ics->imc.socket_fd;
|
||||
int listen_socket = ics->imc.ipc_handle;
|
||||
assert(listen_socket >= 0);
|
||||
|
||||
int ret = epoll_create1(EPOLL_CLOEXEC);
|
||||
|
@ -101,7 +103,7 @@ client_loop(volatile struct ipc_client_state *ics)
|
|||
|
||||
// Finally get the data that is waiting for us.
|
||||
//! @todo replace this call
|
||||
ssize_t len = recv(ics->imc.socket_fd, &buf, IPC_BUF_SIZE, 0);
|
||||
ssize_t len = recv(ics->imc.ipc_handle, &buf, IPC_BUF_SIZE, 0);
|
||||
if (len < 4) {
|
||||
IPC_ERROR(ics->server, "Invalid packet received, disconnecting client.");
|
||||
break;
|
||||
|
@ -140,6 +142,62 @@ client_loop(volatile struct ipc_client_state *ics)
|
|||
ipc_server_deactivate_session(ics);
|
||||
}
|
||||
|
||||
#else // XRT_OS_WINDOWS
|
||||
|
||||
static void
|
||||
client_loop(volatile struct ipc_client_state *ics)
|
||||
{
|
||||
IPC_INFO(ics->server, "Client connected");
|
||||
|
||||
uint8_t buf[IPC_BUF_SIZE];
|
||||
|
||||
while (ics->server->running) {
|
||||
DWORD len;
|
||||
if (!ReadFile(ics->imc.ipc_handle, buf, sizeof(buf), &len, NULL)) {
|
||||
DWORD err = GetLastError();
|
||||
if (err == ERROR_BROKEN_PIPE) {
|
||||
IPC_INFO(ics->server, "ReadFile from pipe: %d %s", err, ipc_winerror(err));
|
||||
} else {
|
||||
IPC_ERROR(ics->server, "ReadFile from pipe failed: %d %s", err, ipc_winerror(err));
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (len < sizeof(ipc_command_t)) {
|
||||
IPC_ERROR(ics->server, "Invalid packet received, disconnecting client.");
|
||||
break;
|
||||
} else {
|
||||
// Check the first 4 bytes of the message and dispatch.
|
||||
ipc_command_t *ipc_command = (ipc_command_t *)buf;
|
||||
xrt_result_t result = ipc_dispatch(ics, ipc_command);
|
||||
if (result != XRT_SUCCESS) {
|
||||
IPC_ERROR(ics->server, "During packet handling, disconnecting client.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Multiple threads might be looking at these fields.
|
||||
os_mutex_lock(&ics->server->global_state.lock);
|
||||
|
||||
ipc_message_channel_close((struct ipc_message_channel *)&ics->imc);
|
||||
|
||||
ics->server->threads[ics->server_thread_index].state = IPC_THREAD_STOPPING;
|
||||
ics->server_thread_index = -1;
|
||||
memset((void *)&ics->client_state, 0, sizeof(struct ipc_app_state));
|
||||
|
||||
os_mutex_unlock(&ics->server->global_state.lock);
|
||||
|
||||
ipc_server_client_destroy_compositor(ics);
|
||||
|
||||
// Should we stop the server when a client disconnects?
|
||||
if (ics->server->exit_on_disconnect) {
|
||||
ics->server->running = false;
|
||||
}
|
||||
|
||||
ipc_server_deactivate_session(ics);
|
||||
}
|
||||
|
||||
#endif // XRT_OS_WINDOWS
|
||||
|
||||
/*
|
||||
*
|
||||
|
|
|
@ -30,14 +30,10 @@
|
|||
#include "server/ipc_server.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
@ -196,7 +192,7 @@ handle_binding(struct ipc_shared_memory *ism,
|
|||
isbp->name = xbp->name;
|
||||
|
||||
// Copy the initial state and also count the number in input_pairs.
|
||||
size_t input_pair_start = input_pair_index;
|
||||
uint32_t input_pair_start = input_pair_index;
|
||||
for (size_t k = 0; k < xbp->input_count; k++) {
|
||||
ism->input_pairs[input_pair_index++] = xbp->inputs[k];
|
||||
}
|
||||
|
@ -208,7 +204,7 @@ handle_binding(struct ipc_shared_memory *ism,
|
|||
}
|
||||
|
||||
// Copy the initial state and also count the number in outputs.
|
||||
size_t output_pair_start = output_pair_index;
|
||||
uint32_t output_pair_start = output_pair_index;
|
||||
for (size_t k = 0; k < xbp->output_count; k++) {
|
||||
ism->output_pairs[output_pair_index++] = xbp->outputs[k];
|
||||
}
|
||||
|
@ -309,7 +305,7 @@ init_shm(struct ipc_server *s)
|
|||
|
||||
// Setup the tracking origin.
|
||||
isdev->tracking_origin_index = (uint32_t)-1;
|
||||
for (size_t k = 0; k < XRT_SYSTEM_MAX_DEVICES; k++) {
|
||||
for (uint32_t k = 0; k < XRT_SYSTEM_MAX_DEVICES; k++) {
|
||||
if (xdev->tracking_origin != s->xtracks[k]) {
|
||||
continue;
|
||||
}
|
||||
|
@ -324,7 +320,7 @@ init_shm(struct ipc_server *s)
|
|||
xrt_device_update_inputs(xdev);
|
||||
|
||||
// Bindings
|
||||
size_t binding_start = binding_index;
|
||||
uint32_t binding_start = binding_index;
|
||||
for (size_t k = 0; k < xdev->binding_profile_count; k++) {
|
||||
handle_binding(ism, &xdev->binding_profiles[k], &ism->binding_profiles[binding_index++],
|
||||
&input_pair_index, &output_pair_index);
|
||||
|
@ -337,7 +333,7 @@ init_shm(struct ipc_server *s)
|
|||
}
|
||||
|
||||
// Copy the initial state and also count the number in inputs.
|
||||
size_t input_start = input_index;
|
||||
uint32_t input_start = input_index;
|
||||
for (size_t k = 0; k < xdev->input_count; k++) {
|
||||
ism->inputs[input_index++] = xdev->inputs[k];
|
||||
}
|
||||
|
@ -349,7 +345,7 @@ init_shm(struct ipc_server *s)
|
|||
}
|
||||
|
||||
// Copy the initial state and also count the number in outputs.
|
||||
size_t output_start = output_index;
|
||||
uint32_t output_start = output_index;
|
||||
for (size_t k = 0; k < xdev->output_count; k++) {
|
||||
ism->outputs[output_index++] = xdev->outputs[k];
|
||||
}
|
||||
|
@ -392,7 +388,7 @@ ipc_server_handle_shutdown_signal(struct ipc_server *vs)
|
|||
}
|
||||
|
||||
void
|
||||
ipc_server_start_client_listener_thread(struct ipc_server *vs, int fd)
|
||||
ipc_server_start_client_listener_thread(struct ipc_server *vs, xrt_ipc_handle_t ipc_handle)
|
||||
{
|
||||
volatile struct ipc_client_state *ics = NULL;
|
||||
int32_t cs_index = -1;
|
||||
|
@ -410,7 +406,7 @@ ipc_server_start_client_listener_thread(struct ipc_server *vs, int fd)
|
|||
}
|
||||
}
|
||||
if (ics == NULL) {
|
||||
close(fd);
|
||||
xrt_ipc_handle_close(ipc_handle);
|
||||
|
||||
// Unlock when we are done.
|
||||
os_mutex_unlock(&vs->global_state.lock);
|
||||
|
@ -422,7 +418,7 @@ ipc_server_start_client_listener_thread(struct ipc_server *vs, int fd)
|
|||
struct ipc_thread *it = &vs->threads[cs_index];
|
||||
if (it->state != IPC_THREAD_READY && it->state != IPC_THREAD_STOPPING) {
|
||||
// we should not get here
|
||||
close(fd);
|
||||
xrt_ipc_handle_close(ipc_handle);
|
||||
|
||||
// Unlock when we are done.
|
||||
os_mutex_unlock(&vs->global_state.lock);
|
||||
|
@ -438,7 +434,7 @@ ipc_server_start_client_listener_thread(struct ipc_server *vs, int fd)
|
|||
}
|
||||
|
||||
it->state = IPC_THREAD_STARTING;
|
||||
ics->imc.socket_fd = fd;
|
||||
ics->imc.ipc_handle = ipc_handle;
|
||||
ics->server = vs;
|
||||
ics->server_thread_index = cs_index;
|
||||
ics->io_active = true;
|
||||
|
|
|
@ -41,6 +41,10 @@
|
|||
// example: v21.0.0-560-g586d33b5
|
||||
#define IPC_VERSION_NAME_LEN 64
|
||||
|
||||
#ifdef XRT_OS_WINDOWS
|
||||
typedef int pid_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
*
|
||||
* Shared memory structs.
|
||||
|
|
|
@ -78,6 +78,28 @@ ipc_shmem_create(size_t size, xrt_shmem_handle_t *out_handle, void **out_map)
|
|||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
#elif defined(XRT_OS_WINDOWS)
|
||||
|
||||
xrt_result_t
|
||||
ipc_shmem_create(size_t size, xrt_shmem_handle_t *out_handle, void **out_map)
|
||||
{
|
||||
*out_handle = NULL;
|
||||
LARGE_INTEGER sz = {.QuadPart = size};
|
||||
HANDLE handle = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, sz.HighPart, sz.LowPart, NULL);
|
||||
if (handle == NULL) {
|
||||
return XRT_ERROR_IPC_FAILURE;
|
||||
}
|
||||
|
||||
xrt_result_t result = ipc_shmem_map(handle, size, out_map);
|
||||
if (result != XRT_SUCCESS) {
|
||||
CloseHandle(handle);
|
||||
return result;
|
||||
}
|
||||
|
||||
*out_handle = handle;
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "OS not yet supported"
|
||||
#endif
|
||||
|
@ -110,6 +132,30 @@ ipc_shmem_map(xrt_shmem_handle_t handle, size_t size, void **out_map)
|
|||
*out_map = ptr;
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
#elif defined(XRT_OS_WINDOWS)
|
||||
void
|
||||
ipc_shmem_destroy(xrt_shmem_handle_t *handle_ptr)
|
||||
{
|
||||
if (handle_ptr == NULL) {
|
||||
return;
|
||||
}
|
||||
xrt_shmem_handle_t handle = *handle_ptr;
|
||||
CloseHandle(handle);
|
||||
*handle_ptr = NULL;
|
||||
}
|
||||
|
||||
xrt_result_t
|
||||
ipc_shmem_map(xrt_shmem_handle_t handle, size_t size, void **out_map)
|
||||
{
|
||||
void *ptr = MapViewOfFile(handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, size);
|
||||
if (ptr == NULL) {
|
||||
return XRT_ERROR_IPC_FAILURE;
|
||||
}
|
||||
*out_map = ptr;
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
// BUGBUG: unmap?
|
||||
#else
|
||||
#error "OS not yet supported"
|
||||
#endif
|
||||
|
|
|
@ -15,8 +15,10 @@
|
|||
#include "shared/ipc_protocol.h"
|
||||
|
||||
#include <errno.h>
|
||||
#if !defined(XRT_OS_WINDOWS)
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -37,14 +39,15 @@
|
|||
#define IPC_WARN(d, ...) U_LOG_IFL_W(d->log_level, __VA_ARGS__)
|
||||
#define IPC_ERROR(d, ...) U_LOG_IFL_E(d->log_level, __VA_ARGS__)
|
||||
|
||||
#if !defined(XRT_OS_WINDOWS)
|
||||
void
|
||||
ipc_message_channel_close(struct ipc_message_channel *imc)
|
||||
{
|
||||
if (imc->socket_fd < 0) {
|
||||
if (imc->ipc_handle < 0) {
|
||||
return;
|
||||
}
|
||||
close(imc->socket_fd);
|
||||
imc->socket_fd = -1;
|
||||
close(imc->ipc_handle);
|
||||
imc->ipc_handle = -1;
|
||||
}
|
||||
|
||||
xrt_result_t
|
||||
|
@ -62,11 +65,11 @@ ipc_send(struct ipc_message_channel *imc, const void *data, size_t size)
|
|||
msg.msg_iovlen = 1;
|
||||
msg.msg_flags = 0;
|
||||
|
||||
ssize_t ret = sendmsg(imc->socket_fd, &msg, MSG_NOSIGNAL);
|
||||
ssize_t ret = sendmsg(imc->ipc_handle, &msg, MSG_NOSIGNAL);
|
||||
if (ret < 0) {
|
||||
int code = errno;
|
||||
IPC_ERROR(imc, "ERROR: Sending plain message on socket %d failed with error: '%i' '%s'!",
|
||||
(int)imc->socket_fd, code, strerror(code));
|
||||
(int)imc->ipc_handle, code, strerror(code));
|
||||
return XRT_ERROR_IPC_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -90,12 +93,12 @@ ipc_receive(struct ipc_message_channel *imc, void *out_data, size_t size)
|
|||
msg.msg_iovlen = 1;
|
||||
msg.msg_flags = 0;
|
||||
|
||||
ssize_t len = recvmsg(imc->socket_fd, &msg, MSG_NOSIGNAL);
|
||||
ssize_t len = recvmsg(imc->ipc_handle, &msg, MSG_NOSIGNAL);
|
||||
|
||||
if (len < 0) {
|
||||
int code = errno;
|
||||
IPC_ERROR(imc, "ERROR: Receiving plain message on socket '%d' failed with error: '%i' '%s'!",
|
||||
(int)imc->socket_fd, code, strerror(code));
|
||||
(int)imc->ipc_handle, code, strerror(code));
|
||||
return XRT_ERROR_IPC_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -135,7 +138,7 @@ ipc_receive_fds(struct ipc_message_channel *imc, void *out_data, size_t size, in
|
|||
msg.msg_control = u.buf;
|
||||
msg.msg_controllen = cmsg_size;
|
||||
|
||||
ssize_t len = recvmsg(imc->socket_fd, &msg, MSG_NOSIGNAL);
|
||||
ssize_t len = recvmsg(imc->ipc_handle, &msg, MSG_NOSIGNAL);
|
||||
if (len < 0) {
|
||||
IPC_ERROR(imc, "recvmsg failed with error: '%s'!", strerror(errno));
|
||||
return XRT_ERROR_IPC_FAILURE;
|
||||
|
@ -187,10 +190,10 @@ ipc_send_fds(struct ipc_message_channel *imc, const void *data, size_t size, con
|
|||
|
||||
memcpy(CMSG_DATA(cmsg), handles, fds_size);
|
||||
|
||||
ssize_t ret = sendmsg(imc->socket_fd, &msg, MSG_NOSIGNAL);
|
||||
ssize_t ret = sendmsg(imc->ipc_handle, &msg, MSG_NOSIGNAL);
|
||||
if (ret < 0) {
|
||||
IPC_ERROR(imc, "ERROR: sending %d FDs on socket %d failed with error: '%i' '%s'!", (int)handle_count,
|
||||
imc->socket_fd, errno, strerror(errno));
|
||||
imc->ipc_handle, errno, strerror(errno));
|
||||
for (uint32_t i = 0; i < handle_count; i++) {
|
||||
IPC_ERROR(imc, "\tfd #%i: %i", i, handles[i]);
|
||||
}
|
||||
|
@ -199,6 +202,8 @@ ipc_send_fds(struct ipc_message_channel *imc, const void *data, size_t size, con
|
|||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
xrt_result_t
|
||||
ipc_receive_handles_shmem(struct ipc_message_channel *imc,
|
||||
void *out_data,
|
||||
|
@ -244,7 +249,7 @@ ipc_receive_handles_graphics_buffer(struct ipc_message_channel *imc,
|
|||
}
|
||||
bool failed = false;
|
||||
for (uint32_t i = 0; i < handle_count; ++i) {
|
||||
int err = AHardwareBuffer_recvHandleFromUnixSocket(imc->socket_fd, &(out_handles[i]));
|
||||
int err = AHardwareBuffer_recvHandleFromUnixSocket(imc->ipc_handle, &(out_handles[i]));
|
||||
if (err != 0) {
|
||||
failed = true;
|
||||
}
|
||||
|
@ -266,7 +271,7 @@ ipc_send_handles_graphics_buffer(struct ipc_message_channel *imc,
|
|||
}
|
||||
bool failed = false;
|
||||
for (uint32_t i = 0; i < handle_count; ++i) {
|
||||
int err = AHardwareBuffer_sendHandleToUnixSocket(handles[i], imc->socket_fd);
|
||||
int err = AHardwareBuffer_sendHandleToUnixSocket(handles[i], imc->ipc_handle);
|
||||
if (err != 0) {
|
||||
failed = true;
|
||||
}
|
||||
|
@ -303,6 +308,7 @@ ipc_send_handles_graphics_buffer(struct ipc_message_channel *imc,
|
|||
return ipc_send_fds(imc, data, size, handles, handle_count);
|
||||
}
|
||||
|
||||
#elif defined(XRT_OS_WINDOWS)
|
||||
#else
|
||||
#error "Need port to transport these graphics buffers"
|
||||
#endif
|
||||
|
@ -344,6 +350,7 @@ ipc_send_handles_graphics_sync(struct ipc_message_channel *imc,
|
|||
return ipc_send_fds(imc, data, size, handles, handle_count);
|
||||
}
|
||||
|
||||
#elif defined(XRT_OS_WINDOWS)
|
||||
#else
|
||||
#error "Need port to transport these graphics buffers"
|
||||
#endif
|
||||
|
|
|
@ -27,7 +27,7 @@ extern "C" {
|
|||
*/
|
||||
struct ipc_message_channel
|
||||
{
|
||||
int socket_fd;
|
||||
xrt_ipc_handle_t ipc_handle;
|
||||
enum u_logging_level log_level;
|
||||
};
|
||||
|
||||
|
@ -111,6 +111,57 @@ ipc_receive_fds(struct ipc_message_channel *imc, void *out_data, size_t size, in
|
|||
*/
|
||||
xrt_result_t
|
||||
ipc_send_fds(struct ipc_message_channel *imc, const void *data, size_t size, const int *handles, uint32_t handle_count);
|
||||
#elif defined(XRT_OS_WINDOWS)
|
||||
/*!
|
||||
* Receive a message along with a known number of file HANDLEs over the IPC
|
||||
* channel.
|
||||
*
|
||||
* @param imc Message channel to use
|
||||
* @param[out] out_data Pointer to the buffer to fill with data. Must not be
|
||||
* null.
|
||||
* @param[in] size Maximum size to read, must be greater than 0
|
||||
* @param[out] out_handles Array of file HANDLEs to populate. Must not be
|
||||
* null.
|
||||
* @param[in] handle_count Number of elements to receive into @p out_handles,
|
||||
* must be greater than 0 and must match the value provided at the other end.
|
||||
*
|
||||
* @public @memberof ipc_message_channel
|
||||
*/
|
||||
xrt_result_t
|
||||
ipc_receive_fds(
|
||||
struct ipc_message_channel *imc, void *out_data, size_t size, HANDLE *out_handles, uint32_t handle_count);
|
||||
|
||||
/*!
|
||||
* Send a message along with file HANDLEs over the IPC channel.
|
||||
*
|
||||
* @param imc Message channel to use
|
||||
* @param[in] data Pointer to the data buffer to send. Must not be
|
||||
* null: use a filler message if necessary.
|
||||
* @param[in] size Size of data pointed-to by @p data, must be greater than 0
|
||||
* @param[out] handles Array of file HANDLEs to send. Must not be
|
||||
* null.
|
||||
* @param[in] handle_count Number of elements in @p handles, must be greater
|
||||
* than 0. If this is variable, it must also be separately transmitted ahead of
|
||||
* time, because the receiver must have the same value in its receive call.
|
||||
*
|
||||
* @public @memberof ipc_message_channel
|
||||
*/
|
||||
xrt_result_t
|
||||
ipc_send_fds(
|
||||
struct ipc_message_channel *imc, const void *data, size_t size, const HANDLE *handles, uint32_t handle_count);
|
||||
|
||||
/*!
|
||||
* Helper to convert windows error codes to human readable strings for logging
|
||||
* N.B. This routine is not thread safe
|
||||
*
|
||||
* @param err windows error code
|
||||
* @return human readable string corresponding to the error code
|
||||
*
|
||||
* @public @memberof ipc_message_channel
|
||||
*/
|
||||
const char *
|
||||
ipc_winerror(DWORD err);
|
||||
|
||||
#endif // XRT_OS_UNIX
|
||||
/*!
|
||||
* @}
|
||||
|
|
201
src/xrt/ipc/shared/ipc_utils_windows.cpp
Normal file
201
src/xrt/ipc/shared/ipc_utils_windows.cpp
Normal file
|
@ -0,0 +1,201 @@
|
|||
// Copyright 2022, Magic Leap, Inc.
|
||||
// Copyright 2020-2022, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief IPC util helpers on Windows, for internal use only
|
||||
* @author Julian Petrov <jpetrov@magicleap.com>
|
||||
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
* @author Pete Black <pblack@collabora.com>
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup ipc_shared
|
||||
*/
|
||||
|
||||
#include "xrt/xrt_config_os.h"
|
||||
|
||||
#include "shared/ipc_utils.h"
|
||||
#include "shared/ipc_protocol.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "util/u_logging.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
/*
|
||||
*
|
||||
* Logging
|
||||
*
|
||||
*/
|
||||
|
||||
#define IPC_TRACE(d, ...) U_LOG_IFL_T(d->log_level, __VA_ARGS__)
|
||||
#define IPC_DEBUG(d, ...) U_LOG_IFL_D(d->log_level, __VA_ARGS__)
|
||||
#define IPC_INFO(d, ...) U_LOG_IFL_I(d->log_level, __VA_ARGS__)
|
||||
#define IPC_WARN(d, ...) U_LOG_IFL_W(d->log_level, __VA_ARGS__)
|
||||
#define IPC_ERROR(d, ...) U_LOG_IFL_E(d->log_level, __VA_ARGS__)
|
||||
|
||||
const char *
|
||||
ipc_winerror(DWORD err)
|
||||
{
|
||||
static char s_buf[4096]; // N.B. Not thread-safe. If needed, use a thread var
|
||||
if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, LANG_SYSTEM_DEFAULT, s_buf, sizeof(s_buf), NULL)) {
|
||||
s_buf[0] = 0;
|
||||
}
|
||||
return s_buf;
|
||||
}
|
||||
|
||||
void
|
||||
ipc_message_channel_close(struct ipc_message_channel *imc)
|
||||
{
|
||||
if (imc->ipc_handle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(imc->ipc_handle);
|
||||
imc->ipc_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
xrt_result_t
|
||||
ipc_send(struct ipc_message_channel *imc, const void *data, size_t size)
|
||||
{
|
||||
DWORD len;
|
||||
if (!WriteFile(imc->ipc_handle, data, DWORD(size), &len, NULL)) {
|
||||
DWORD err = GetLastError();
|
||||
IPC_ERROR(imc, "WriteFile on pipe %p failed: %d %s", imc->ipc_handle, err, ipc_winerror(err));
|
||||
return XRT_ERROR_IPC_FAILURE;
|
||||
}
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
xrt_result_t
|
||||
ipc_receive(struct ipc_message_channel *imc, void *out_data, size_t size)
|
||||
{
|
||||
DWORD len;
|
||||
if (!ReadFile(imc->ipc_handle, out_data, DWORD(size), &len, NULL)) {
|
||||
DWORD err = GetLastError();
|
||||
IPC_ERROR(imc, "ReadFile from pipe %p failed: %d %s", imc->ipc_handle, err, ipc_winerror(err));
|
||||
return XRT_ERROR_IPC_FAILURE;
|
||||
}
|
||||
return XRT_SUCCESS;
|
||||
}
|
||||
|
||||
xrt_result_t
|
||||
ipc_receive_fds(
|
||||
struct ipc_message_channel *imc, void *out_data, size_t size, HANDLE *out_handles, uint32_t handle_count)
|
||||
{
|
||||
auto rc = ipc_receive(imc, out_data, size);
|
||||
if (rc != XRT_SUCCESS || !handle_count) {
|
||||
return rc;
|
||||
}
|
||||
return ipc_receive(imc, out_handles, handle_count * sizeof(*out_handles));
|
||||
}
|
||||
|
||||
HANDLE
|
||||
open_target_process_dup_handle(struct ipc_message_channel *imc)
|
||||
{
|
||||
DWORD flags;
|
||||
if (!GetNamedPipeInfo(imc->ipc_handle, &flags, NULL, NULL, NULL)) {
|
||||
DWORD err = GetLastError();
|
||||
IPC_ERROR(imc, "GetNamedPipeInfo(%p) failed: %d %s", imc->ipc_handle, err, ipc_winerror(err));
|
||||
return NULL;
|
||||
}
|
||||
ULONG pid;
|
||||
if (flags & PIPE_SERVER_END) {
|
||||
if (!GetNamedPipeClientProcessId(imc->ipc_handle, &pid)) {
|
||||
DWORD err = GetLastError();
|
||||
IPC_ERROR(imc, "GetNamedPipeClientProcessId(%p) failed: %d %s", imc->ipc_handle, err,
|
||||
ipc_winerror(err));
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
if (!GetNamedPipeServerProcessId(imc->ipc_handle, &pid)) {
|
||||
DWORD err = GetLastError();
|
||||
IPC_ERROR(imc, "GetNamedPipeServerProcessId(%p) failed: %d %s", imc->ipc_handle, err,
|
||||
ipc_winerror(err));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
HANDLE h = OpenProcess(PROCESS_DUP_HANDLE, false, pid);
|
||||
if (!h) {
|
||||
DWORD err = GetLastError();
|
||||
IPC_ERROR(imc, "OpenProcess(PROCESS_DUP_HANDLE, pid %d) failed: %d %s", pid, err, ipc_winerror(err));
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
xrt_result_t
|
||||
ipc_send_fds(
|
||||
struct ipc_message_channel *imc, const void *data, size_t size, const HANDLE *handles, uint32_t handle_count)
|
||||
{
|
||||
auto rc = ipc_send(imc, data, size);
|
||||
if (rc != XRT_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
if (!handle_count) {
|
||||
return ipc_send(imc, nullptr, 0);
|
||||
}
|
||||
HANDLE target_process = open_target_process_dup_handle(imc);
|
||||
if (!target_process) {
|
||||
DWORD err = GetLastError();
|
||||
IPC_ERROR(imc, "open_target_process_dup_handle failed: %d %s", err, ipc_winerror(err));
|
||||
return XRT_ERROR_IPC_FAILURE;
|
||||
}
|
||||
|
||||
HANDLE current_process = GetCurrentProcess();
|
||||
std::vector<HANDLE> v;
|
||||
v.reserve(handle_count);
|
||||
for (uint32_t i = 0; i < handle_count; i++) {
|
||||
HANDLE handle;
|
||||
if (!DuplicateHandle(current_process, handles[i], target_process, &handle, 0, false,
|
||||
DUPLICATE_SAME_ACCESS)) {
|
||||
DWORD err = GetLastError();
|
||||
IPC_ERROR(imc, "DuplicateHandle(%p) failed: %d %s", handles[i], err, ipc_winerror(err));
|
||||
CloseHandle(target_process);
|
||||
return XRT_ERROR_IPC_FAILURE;
|
||||
}
|
||||
v.push_back(handle);
|
||||
}
|
||||
CloseHandle(target_process);
|
||||
return ipc_send(imc, v.data(), v.size() * sizeof(*v.data()));
|
||||
}
|
||||
|
||||
xrt_result_t
|
||||
ipc_receive_handles_graphics_sync(struct ipc_message_channel *imc,
|
||||
void *out_data,
|
||||
size_t size,
|
||||
xrt_graphics_sync_handle_t *out_handles,
|
||||
uint32_t handle_count)
|
||||
{
|
||||
return ipc_receive_fds(imc, out_data, size, out_handles, handle_count);
|
||||
}
|
||||
|
||||
xrt_result_t
|
||||
ipc_send_handles_graphics_sync(struct ipc_message_channel *imc,
|
||||
const void *data,
|
||||
size_t size,
|
||||
const xrt_graphics_sync_handle_t *handles,
|
||||
uint32_t handle_count)
|
||||
{
|
||||
return ipc_send_fds(imc, data, size, handles, handle_count);
|
||||
}
|
||||
|
||||
xrt_result_t
|
||||
ipc_receive_handles_graphics_buffer(struct ipc_message_channel *imc,
|
||||
void *out_data,
|
||||
size_t size,
|
||||
xrt_graphics_buffer_handle_t *out_handles,
|
||||
uint32_t handle_count)
|
||||
{
|
||||
return ipc_receive_fds(imc, out_data, size, out_handles, handle_count);
|
||||
}
|
||||
|
||||
xrt_result_t
|
||||
ipc_send_handles_graphics_buffer(struct ipc_message_channel *imc,
|
||||
const void *data,
|
||||
size_t size,
|
||||
const xrt_graphics_buffer_handle_t *handles,
|
||||
uint32_t handle_count)
|
||||
{
|
||||
return ipc_send_fds(imc, data, size, handles, handle_count);
|
||||
}
|
|
@ -216,9 +216,9 @@ do_connect(struct ipc_connection *ipc_c)
|
|||
* Connenct.
|
||||
*/
|
||||
|
||||
ipc_c->imc.socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (ipc_c->imc.socket_fd < 0) {
|
||||
ret = ipc_c->imc.socket_fd;
|
||||
ipc_c->imc.ipc_handle = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (ipc_c->imc.ipc_handle < 0) {
|
||||
ret = ipc_c->imc.ipc_handle;
|
||||
PE("Socket create error '%i'!\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ do_connect(struct ipc_connection *ipc_c)
|
|||
addr.sun_family = AF_UNIX;
|
||||
strcpy(addr.sun_path, sock_file);
|
||||
|
||||
ret = connect(ipc_c->imc.socket_fd, // socket
|
||||
ret = connect(ipc_c->imc.ipc_handle, // socket
|
||||
(struct sockaddr *)&addr, // address
|
||||
sizeof(addr)); // size
|
||||
if (ret < 0) {
|
||||
|
|
Loading…
Reference in a new issue