ipc: Tidy Windows mainloop code

This commit is contained in:
Jakob Bornecrantz 2022-11-16 21:07:47 +00:00
parent 8271d213f5
commit fb15e8aa50

View file

@ -32,30 +32,74 @@
#include <conio.h>
/*
*
* Static functions.
*
*/
static void
ipc_server_create_another_pipe_instance(struct ipc_server *vs, struct ipc_server_mainloop *ml)
static bool
create_pipe_instance(struct ipc_server_mainloop *ml, bool first)
{
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);
}
DWORD dwOpenMode = PIPE_ACCESS_DUPLEX;
DWORD dwPipeMode = PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT | PIPE_REJECT_REMOTE_CLIENTS;
if (first) {
dwOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
}
ml->pipe_handle = CreateNamedPipeA( //
ml->pipe_name, //
dwOpenMode, //
dwPipeMode, //
IPC_MAX_CLIENTS, //
IPC_BUF_SIZE, //
IPC_BUF_SIZE, //
0, //
nullptr); //
if (ml->pipe_handle != INVALID_HANDLE_VALUE) {
return true;
}
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));
}
return false;
}
static void
create_another_pipe_instance(struct ipc_server *vs, struct ipc_server_mainloop *ml)
{
if (!create_pipe_instance(ml, false)) {
ipc_server_handle_failure(vs);
}
}
static void
handle_connected_client(struct ipc_server *vs, struct ipc_server_mainloop *ml)
{
DWORD mode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
BOOL bRet;
bRet = SetNamedPipeHandleState(ml->pipe_handle, &mode, nullptr, nullptr);
if (bRet) {
ipc_server_start_client_listener_thread(vs, ml->pipe_handle);
create_another_pipe_instance(vs, ml);
return;
}
DWORD err = GetLastError();
U_LOG_E("SetNamedPipeHandleState(PIPE_READMODE_MESSAGE | PIPE_WAIT) failed: %d %s", err, ipc_winerror(err));
ipc_server_handle_failure(vs);
}
/*
*
* Exported functions
@ -74,33 +118,22 @@ ipc_server_mainloop_poll(struct ipc_server *vs, struct ipc_server_mainloop *ml)
}
if (!ml->pipe_handle) {
ipc_server_create_another_pipe_instance(vs, ml);
create_another_pipe_instance(vs, ml);
}
if (!ml->pipe_handle) {
return;
return; // Errors already logged.
}
if (ConnectNamedPipe(ml->pipe_handle, NULL)) {
U_LOG_E("ConnectNamedPipe unexpected return TRUE (last error: %d). Treating as failure...",
GetLastError());
if (ConnectNamedPipe(ml->pipe_handle, nullptr)) {
DWORD err = GetLastError();
U_LOG_E("ConnectNamedPipe unexpected return TRUE treating as failure: %d %s", err, ipc_winerror(err));
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;
}
case ERROR_PIPE_CONNECTED: handle_connected_client(vs, ml); return;
default:
U_LOG_E("ConnectNamedPipe failed: %d %s", err, ipc_winerror(err));
ipc_server_handle_failure(vs);
@ -127,20 +160,21 @@ ipc_server_mainloop_init(struct ipc_server_mainloop *ml)
}
ml->pipe_name = _strdup(pipe_name);
if (!ml->pipe_name) {
if (ml->pipe_name == nullptr) {
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));
goto err;
}
if (!create_pipe_instance(ml, true)) {
U_LOG_E("CreateNamedPipeA \"%s\" first instance failed, see above.", ml->pipe_name);
goto err;
}
return 0;
err:
ipc_server_mainloop_deinit(ml);
return -1;
}