Node.js при использовании в качестве сервера создает объект именованного канала Windows и передает это дочернему процессу как файловый дескриптор 3:
- https://github.com/nodejs/node/blob/mai ... ss.js#L162
- https://github.com/nodejs/node/blob/639 ... ss.js#L381
Для следующей программы Node.js:
Код: Выделить всё
const { spawn } = require('child_process');
const child = spawn('child.exe', [], {
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
env: env
});
child.on('message', (message) => {
let m = JSON.stringify(message);
console.log(`message from child: ${m}`)
});
child.send({foo: 123, bar: "456"});
Код: Выделить всё
int main(int argc, char **argv)
{
HANDLE h = _get_osfhandle(3);
...
WriteFile(h, etc...);
...
ReadFile(h, etc...);
}
Теперь я пытаюсь сделать обратное: с хоста C++ создать и передать правильные структуры данных, чтобы гарантировать, что правильная вещь окажется как fd 3 в таблице fd дочернего процесса.
К сожалению, я не могу повторить это:
В родительском процессе , я создаю свою трубку следующим образом:
Код: Выделить всё
static constexpr auto PIPENAME = "\\\\?\\pipe\\echo.sock";
OVERLAPPED overlapped = {0};
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof sa;
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
HANDLE serverPipeHandle = CreateNamedPipeA(PIPENAME,
PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
| WRITE_DAC
| FILE_FLAG_FIRST_PIPE_INSTANCE,
PIPE_TYPE_BYTE
| PIPE_READMODE_BYTE
| PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
65536,
65536,
0,
&sa);
if (serverPipeHandle == INVALID_HANDLE_VALUE) {
printf("CreateNamedPipe failed, GLE=%lu.\n", GetLastError());
return 1;
}
HANDLE client_pipe;
client_pipe = CreateFileA(PIPENAME,
GENERIC_READ | GENERIC_WRITE | WRITE_DAC,
0,
&sa,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (!ConnectNamedPipe(serverPipeHandle, NULL)) {
if (GetLastError() != ERROR_PIPE_CONNECTED) {
printf("ConnectNamedPipe failed, GLE=%lu.\n", GetLastError());
}
}
Код: Выделить всё
auto h = _open_osfhandle((intptr_t) serverPipeHandle, 0);
// Prints: Handle=276 (or sometimes 260 or close numbers)
fprintf(stderr, "Handle=%llu \n", (std::uintptr_t) serverPipeHandle);
// Always prints: fd=3
fprintf(stderr, "fd=%d \n", h);
Код: Выделить всё
STARTUPINFOA si = {0};
ZeroMemory(&si, sizeof(STARTUPINFOA));
si.cb = sizeof(si);
PROCESS_INFORMATION pi = {0};
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
CreateProcess(NULL, app, NULL, NULL,
TRUE, // handle inheritance
CREATE_SUSPENDED, NULL, NULL,
&si, &pi);
ResumeThread(pi.hThread);
Чего мне не хватает, чтобы сделать его доступным?
Я попробовал:
- Явно пометить дескрипторы как наследуемые перед созданием процесса:
Код: Выделить всё
SetHandleInformation(serverPipeHandle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
SetHandleInformation(client_pipe, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
- Вызов DuplicationHandle после CreateProcess и перед ResumeThread:
Код: Выделить всё
HANDLE hFileDup;
DuplicateHandle(GetCurrentProcess(),
serverPipeHandle,
pi.hProcess,
&hFileDup,
0,
TRUE,
DUPLICATE_SAME_ACCESS);
- Вызов CreateProcessWithExplicitHandles, описанный в https://devblogs.microsoft.com/oldnewth ... 00/?p=8873 с массивом дескрипторов, содержащим как дескрипторы CreateNamedPipeA, так и CreateFileA.
- Пытаюсь открыть каждый fd в дочернем процессе, чтобы узнать, пойдет ли этот fd куда-нибудь еще:
Код: Выделить всё
for (int i = -1000; i < 1000; i++) {
auto hFile = (HANDLE) _get_osfhandle(i);
if (hFile != INVALID_HANDLE_VALUE) {
fprintf(stderr, "Trying %d ...", i);
fprintf(stderr, "success! \n");
}
}
Код: Выделить всё
Trying 0 ...success!
Trying 1 ...success!
Trying 2 ...success!
- Передача необработанного значения HANDLE моему дочернему процессу (например, 260 вместо 3). Это работает, но, к сожалению, не соответствует API node.js.
Подробнее здесь: https://stackoverflow.com/questions/793 ... -osfhandle
Мобильная версия