At 2007-12-11T19:44:54-0500, Stephen Leake wrote: > Hmm. If we want Windows to be an ssh server, it must handle this case.
Well, not quite this case. mtn serve --stdio on a console guarantees that the stdio handles are console handles, and we know we can't treat them like sockets. > That is, the client does: > > mtn sync ssh:my.windows.box.org > > then on 'my.window.box.org', ssh runs the command > > mtn serve --sdtio > > and stdio for mtn is _not_ a socket. Actually, I have no idea what > mechanism ssh uses to spawn mtn in this case. But if we advertise > "--stdio", it aught to handle the non-socket case. > > Hmm. I guess I should look in the ssh source to see what it does here; > it might be instructive. ...but ssh might be different. I don't know what it does, either. Did you look into this yet? > Or we can just say "mtn can't be an ssh server on Windows". That would > work for me, but it would be disappointing. It'd be nice to have the server side working with ssh, but I think having the client side will be an 80%+ solution--ssh servers on Windows seem to be fairly uncommon in my experience. > Ok. Can you send me that code? I'm at the point of implementing some > simple standalone debug code. Maybe I could start with yours. Attached. Try not to be too shocked, it's a fearsome trainwreck of write-only test code. Cheers, -mjg -- Matthew Gregan |/ /| [EMAIL PROTECTED]
/* test ncm's socketpair for win32 */ #define WIN32_LEAN_AND_MEAN #include <io.h> #include <windows.h> #include <winsock2.h> #include <assert.h> #include <stdio.h> #include <stdlib.h> 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; }
#include <stdio.h> #include <stdlib.h> #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <winsock2.h> static void fatal(const char * msg) { fprintf(stderr, "%s (%d)\n", msg, WSAGetLastError()); exit(EXIT_FAILURE); } static void socket_init(void) { WORD version; WSADATA data; int rv; version = MAKEWORD(2, 2); rv = WSAStartup(version, &data); if (rv) fatal("wsastartup"); if (LOBYTE(data.wVersion) == 2 || HIBYTE(data.wVersion) == 2) return; WSACleanup(); fatal("winsock version problem"); } static void socket_deinit(void) { WSACleanup(); } int main(int argc, char * argv[]) { fd_set read; fd_set write; SOCKET rfd; SOCKET wfd; int rv; char buf[4096]; socket_init(); rfd = (SOCKET) GetStdHandle(STD_INPUT_HANDLE); wfd = (SOCKET) GetStdHandle(STD_OUTPUT_HANDLE); for (;;) { FD_ZERO(&read); FD_ZERO(&write); FD_SET(rfd, &read); //FD_SET(wfd, &write); rv = select(max(rfd, wfd) + 1, &read, &write, NULL, NULL); if (rv < 0) fatal("select < 0"); if (rv == 0) continue; fprintf(stderr, "working\n"); fflush(stderr); if (FD_ISSET(rfd, &read)) { rv = recv(rfd, &buf, sizeof(buf), 0); if (rv < 0) fatal("recv < 0"); buf[0] = buf[0] + 3; rv = send(wfd, buf, rv, 0); if (rv < 0) fatal("resend < 0"); } if (FD_ISSET(wfd, &write)) { } } socket_deinit(); return 0; }
_______________________________________________ Monotone-devel mailing list Monotone-devel@nongnu.org http://lists.nongnu.org/mailman/listinfo/monotone-devel