stdio_client: fix win implementation
parent
3fe1e049fb
commit
ac8e520bdd
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include "mcp_stdio_client.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#else
|
||||
|
@ -218,7 +218,7 @@ bool stdio_client::start_server_process() {
|
|||
throw std::runtime_error("Unsupported type");
|
||||
};
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#if defined(_WIN32)
|
||||
// Windows implementation
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
|
@ -272,33 +272,34 @@ bool stdio_client::start_server_process() {
|
|||
|
||||
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
|
||||
|
||||
// Prepare environment variables
|
||||
std::string env_block;
|
||||
// Add custom environment variables
|
||||
if (!env_vars_.empty()) {
|
||||
for (const auto& [key, value] : env_vars_.items()) {
|
||||
std::string env_var = key + "=" + convert_to_string(value);
|
||||
env_block += env_var + '\0';
|
||||
std::string env_var_value = convert_to_string(value);
|
||||
SetEnvironmentVariableA(key.c_str(), env_var_value.c_str());
|
||||
}
|
||||
env_block += '\0';
|
||||
}
|
||||
|
||||
std::string cmd_line = "cmd.exe /c " + command_;
|
||||
|
||||
char* cmd_line_ptr = _strdup(cmd_line.c_str());
|
||||
|
||||
// Create child process
|
||||
std::string cmd_line = command_;
|
||||
char* cmd_str = const_cast<char*>(cmd_line.c_str());
|
||||
|
||||
BOOL success = CreateProcessA(
|
||||
NULL, // Application name
|
||||
cmd_str, // Command line
|
||||
cmd_line_ptr, // Command line
|
||||
NULL, // Process security attributes
|
||||
NULL, // Thread security attributes
|
||||
TRUE, // Inherit handles
|
||||
CREATE_NO_WINDOW, // Creation flags
|
||||
env_vars_.empty() ? NULL : (LPVOID)env_block.c_str(), // Environment variables
|
||||
NULL, // Environment variables
|
||||
NULL, // Current directory
|
||||
&si, // Startup info
|
||||
&pi // Process info
|
||||
);
|
||||
|
||||
free(cmd_line_ptr);
|
||||
|
||||
if (!success) {
|
||||
LOG_ERROR("Failed to create process: ", GetLastError());
|
||||
CloseHandle(child_stdin_read);
|
||||
|
@ -323,7 +324,8 @@ bool stdio_client::start_server_process() {
|
|||
|
||||
// Set non-blocking mode
|
||||
DWORD mode = PIPE_NOWAIT;
|
||||
SetNamedPipeHandleState(stdout_pipe_[0], &mode, NULL, NULL);
|
||||
DWORD timeout = 100; // milliseconds
|
||||
SetNamedPipeHandleState(stdout_pipe_[0], &mode, NULL, &timeout);
|
||||
|
||||
#else
|
||||
// POSIX implementation
|
||||
|
@ -459,7 +461,7 @@ bool stdio_client::start_server_process() {
|
|||
// Wait for a while to ensure process starts
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#if defined(_WIN32)
|
||||
// Check if process is still running
|
||||
DWORD exit_code;
|
||||
if (GetExitCodeProcess(process_handle_, &exit_code) && exit_code != STILL_ACTIVE) {
|
||||
|
@ -491,7 +493,7 @@ void stdio_client::stop_server_process() {
|
|||
|
||||
running_ = false;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#if defined(_WIN32)
|
||||
// Windows implementation
|
||||
// Close pipes
|
||||
if (stdin_pipe_[1] != NULL) {
|
||||
|
@ -584,15 +586,21 @@ void stdio_client::read_thread_func() {
|
|||
char buffer[buffer_size];
|
||||
std::string data_buffer;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#if defined(_WIN32)
|
||||
// Windows implementation
|
||||
DWORD bytes_read;
|
||||
int retry_count = 0;
|
||||
|
||||
// Give the process some startup time (similar to UNIX implementation)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
while (running_) {
|
||||
// Read data
|
||||
BOOL success = ReadFile(stdout_pipe_[0], buffer, buffer_size - 1, &bytes_read, NULL);
|
||||
|
||||
if (success && bytes_read > 0) {
|
||||
// Successfully read data
|
||||
retry_count = 0; // Reset retry count
|
||||
buffer[bytes_read] = '\0';
|
||||
data_buffer.append(buffer, bytes_read);
|
||||
|
||||
|
@ -644,21 +652,56 @@ void stdio_client::read_thread_func() {
|
|||
}
|
||||
} else if (!success) {
|
||||
DWORD error = GetLastError();
|
||||
if (error == ERROR_BROKEN_PIPE || error == ERROR_NO_DATA) {
|
||||
// Pipe is closed or no data available
|
||||
LOG_WARNING("Pipe closed by server or no data available");
|
||||
break;
|
||||
} else if (error != ERROR_IO_PENDING) {
|
||||
LOG_ERROR("Error reading from pipe: ", error);
|
||||
|
||||
if (error == ERROR_BROKEN_PIPE) {
|
||||
// The pipe is closed - check if the process is still running
|
||||
DWORD exit_code;
|
||||
if (GetExitCodeProcess(process_handle_, &exit_code) && exit_code != STILL_ACTIVE) {
|
||||
LOG_WARNING("Service process exited, exit code: ", exit_code);
|
||||
break;
|
||||
}
|
||||
|
||||
// No data to read in non-blocking mode
|
||||
// The pipe is closed but the process is still running - it might be a temporary state
|
||||
retry_count++;
|
||||
if (retry_count > 5) {
|
||||
LOG_ERROR("The pipe is closed but the process is still running, retry count has reached the limit");
|
||||
break;
|
||||
}
|
||||
|
||||
// Retry after a short delay
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50 * retry_count));
|
||||
} else if (error == ERROR_NO_DATA) {
|
||||
// Simulate UNIX's EAGAIN/EWOULDBLOCK behavior
|
||||
// The pipe is temporarily empty - this is normal for non-blocking mode
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
} else if (error != ERROR_IO_PENDING) {
|
||||
// Other errors, log and retry
|
||||
LOG_ERROR("Error reading from pipe: ", error);
|
||||
retry_count++;
|
||||
|
||||
if (retry_count > 10) {
|
||||
LOG_ERROR("Read error retry count has reached the limit, exiting read loop");
|
||||
break;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20 * retry_count));
|
||||
} else {
|
||||
// No data to read in non-blocking mode
|
||||
// IO_PENDING is the normal state for asynchronous IO
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
} else {
|
||||
// ReadFile successfully but no data - similar to reading 0 bytes but not EOF on UNIX
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
// Periodically check if the process is still running (similar to UNIX's waitpid check)
|
||||
if (retry_count > 3) {
|
||||
DWORD exit_code;
|
||||
if (GetExitCodeProcess(process_handle_, &exit_code) && exit_code != STILL_ACTIVE) {
|
||||
LOG_WARNING("Service process exited, exit code: ", exit_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
// POSIX implementation
|
||||
|
@ -743,7 +786,7 @@ json stdio_client::send_jsonrpc(const request& req) {
|
|||
json req_json = req.to_json();
|
||||
std::string req_str = req_json.dump() + "\n";
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#if defined(_WIN32)
|
||||
// Windows implementation
|
||||
DWORD bytes_written;
|
||||
BOOL success = WriteFile(stdin_pipe_[1], req_str.c_str(), static_cast<DWORD>(req_str.size()), &bytes_written, NULL);
|
||||
|
|
Loading…
Reference in New Issue