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

Reply via email to