/* test ncm's socketpair for win32 */ #define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include typedef LONG NTSTATUS; typedef struct _IO_STATUS_BLOCK { union { NTSTATUS Status; PVOID Pointer; }; ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; typedef enum _FILE_INFORMATION_CLASS { // Query Set File/Directory FileModeInformation = 16 // Y Y F } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; typedef struct _FILE_MODE_INFORMATION { // Information Class 16 ULONG Mode; } FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION; // NtQueryInformationFile retrieves information about a file object. NTSTATUS NTAPI NtQueryInformationFile( IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG FileInformationLength, IN FILE_INFORMATION_CLASS FileInformationClass ); int dumb_socketpair(SOCKET socks[2], int make_overlapped); HANDLE hChild; BOOL WINAPI ctrl_c_handler(DWORD dwCtrlType) { fprintf(stderr, "terminate %d\n", TerminateProcess(hChild, 0)); fflush(stderr); return TRUE; } static void fatal(const char * msg) { fprintf(stderr, "%s (%d)\n", msg, WSAGetLastError()); exit(EXIT_FAILURE); } int main() { WSADATA wsadata; assert(WSAStartup(MAKEWORD(2, 2), &wsadata) == 0); SOCKET pair[2]; assert(dumb_socketpair(pair, 0) == 0); FILE_MODE_INFORMATION info; IO_STATUS_BLOCK io; NTSTATUS status; status = NtQueryInformationFile((HANDLE) pair[0], &io, &info, sizeof(info), FileModeInformation); fprintf(stderr, "pair[0] overlapped? %s\n", info.Mode == 0x20 ? "no" : "yes"); status = NtQueryInformationFile((HANDLE) pair[1], &io, &info, sizeof(info), FileModeInformation); fprintf(stderr, "pair[1] overlapped? %s\n", info.Mode == 0x20 ? "no" : "yes"); status = NtQueryInformationFile(GetStdHandle(STD_INPUT_HANDLE), &io, &info, sizeof(info), FileModeInformation); fprintf(stderr, "stdin overlapped? %s\n", info.Mode == 0x20 ? "no" : "yes"); status = NtQueryInformationFile((HANDLE) _get_osfhandle(_fileno(stdin)), &io, &info, sizeof(info), FileModeInformation); fprintf(stderr, "stdin overlapped? %s\n", info.Mode == 0x20 ? "no" : "yes"); #if 1 static char const cat[] = "e:\\build\\src\\sockio\\a.exe"; #else static char const cat[] = "d:\\msys\\1.0\\bin\\ssh.exe"; //"d:\\msys\\1.0\\bin\\cat.exe"; //"e:\\build\\src\\sockio\\echoer.exe"; static char const args[][2] = { /*"d:\\msys\\1.0\\bin\\ssh.exe",*/ {"brak"}, {NULL} }; #endif STARTUPINFO startup; PROCESS_INFORMATION procinfo; memset(&startup, 0, sizeof(startup)); startup.cb = sizeof(startup); // should dup handle before using for in/out/err so child can legally // close one without losing the others HANDLE hin, hout, herr; assert(DuplicateHandle(GetCurrentProcess(), (HANDLE) pair[0], GetCurrentProcess(), &hin, 0, TRUE, DUPLICATE_SAME_ACCESS) != 0); assert(DuplicateHandle(GetCurrentProcess(), (HANDLE) pair[0], GetCurrentProcess(), &hout, 0, TRUE, DUPLICATE_SAME_ACCESS) != 0); assert(DuplicateHandle(GetCurrentProcess(), (HANDLE) pair[0], GetCurrentProcess(), &herr, 0, TRUE, DUPLICATE_SAME_ACCESS) != 0); CloseHandle((HANDLE) pair[0]); startup.hStdInput = hin; startup.hStdOutput = hout; startup.hStdError = herr; startup.hStdError = GetStdHandle(STD_ERROR_HANDLE); startup.dwFlags = STARTF_USESTDHANDLES; assert(CreateProcess(cat, (char *) cat, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &procinfo) != 0); fprintf(stderr, "%d %d\n", (int) GetCurrentProcessId(), (int) GetCurrentThreadId()); fprintf(stderr, "%d, %d, %d, %d\n", (int) procinfo.hProcess, (int) procinfo.hThread, (int) procinfo.dwProcessId, (int) procinfo.dwThreadId); hChild = procinfo.hProcess; fflush(stderr); if (!SetConsoleCtrlHandler(ctrl_c_handler, TRUE)) { fprintf(stderr, "failed to set handler\n"); fflush(stderr); } #if 0 if (WaitForSingleObject(procinfo.hProcess, 100) == WAIT_OBJECT_0) { DWORD exitcode; GetExitCodeProcess(procinfo.hProcess, &exitcode); fprintf(stderr, "died early: %d\n", exitcode); return 1; } #endif #if 1 fd_set read; fd_set write; int rv; for (;;) { fprintf(stderr, "reading...\n"); fflush(stderr); int i = getc(stdin); if (i == EOF) break; char c = (char) i; if (c == '\n') continue; assert(send(pair[1], &c, 1, 0) == 1); FD_ZERO(&read); FD_ZERO(&write); FD_SET(pair[1], &read); //FD_SET(pair[1], &write); rv = select(max(pair[1], pair[1]) + 1, &read, &write, NULL, NULL); if (rv < 0) fatal("select < 0"); if (rv == 0) continue; fprintf(stderr, "parent working\n"); fflush(stderr); if (FD_ISSET(pair[1], &read)) { rv = recv(pair[1], &c, 1, 0); if (rv < 0) fatal("recv < 0"); fprintf(stderr, "rec '%c'\n", c); } if (FD_ISSET(pair[1], &write)) { } } #else for (;;) { fprintf(stderr, "reading...\n"); fflush(stderr); int i = getc(stdin); if (i == EOF) break; char c = (char) i; if (c == '\n') continue; fprintf(stderr, "got '%c'\n", c); fflush(stderr); assert(send(pair[1], &c, 1, 0) == 1); assert(recv(pair[1], &c, 1, 0) == 1); fprintf(stderr, "rec '%c'\n", c); fflush(stderr); } #endif TerminateProcess(procinfo.hProcess, 0); assert(WaitForSingleObject(procinfo.hProcess, 1000) == WAIT_OBJECT_0); CloseHandle(procinfo.hProcess); CloseHandle(procinfo.hThread); closesocket(pair[0]); closesocket(pair[1]); WSACleanup(); return 0; }