mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-26 08:31:44 +00:00
161 lines
4.3 KiB
C++
161 lines
4.3 KiB
C++
|
// 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;
|
||
|
}
|
||
|
}
|