This is the mail archive of the cygwin@sources.redhat.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Why does scp leave ssh running? -- select() never returns


Patrick Doyle wrote:
> 
> When I run
> 
> scp somefile host:.
> 
> I am left with a copy of SSH running.  ...

I believe that have traced this problem down to the call to select() in
ssh.  Basically, it appears that ssh calls select() on a pipe.  If the
writer of that pipe closes it, select() never returns.  I have attached
code to the end of this email demonstrating this phenomenon.

I believe that I have traced this down to the call to PeekNamedPipe() in
"select.cc".  For some reason, on my W98 box, PeekNamedPipe() does not
return an error when the other end of the pipe is closed.

So, a few questions...
1) Is this behavior (of PeekNamedPipe()) a W9x bug?  (That is, does it
work correctly on NT/2K?)

2) What is the expected behavior of select() on a pipe when the writer
closes the pipe?  The code in ssh seems to imply that it should return,
probably with the "read" bit set for the closed pipe.

3) Does anybody have any ideas of how I might work around this problem,
preferably in cygwin?  (Otherwise, I could change the call to select()
"clientloop.c" to include a timeout).

4) Would folks mind trying this code and confirming if I am on the right
track or not?

Thanks for any help and/or advice...

--wpd

code follows... sorry about the leftover #ifdef debug stuff.

/************************************************************************
 * Simple program that demonstrates the "problem" with select(). 
Basically,
 * when a process is blocked on a select() call to read from a pipe, and
the
 * writer for the pipe closes it, the select call never returns (unless,
 * presumably, the timeout is set.
 *
 * This code demonstrats this phenomenon by creating a pipe, forking
 * a subprocess, closing the write side of the pipe (in the parent
process)
 * and performing a select() on the read side of the pipe.  Meanwhile,
the
 * child process closes the pipe, either after a timeout, or upon
receipt
 * if a SIGHUP.

************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/select.h>
#include <signal.h>

void
sighup(int x)
{
  /* do nothing */
}

int
main(int argc, char *argv[])
{
  int pid;
  int timeout;
  int pipe_fd[2];
  char buf[256];
  int bytes_read;
  int input_fd;
  fd_set readset;

  if (argc < 2) {
    timeout = 5;
  } else {
    if (sscanf(argv[1], "%d", &timeout) != 1 || timeout < 0) {
      fprintf(stderr, "usage: test1 [timeout]\n");
      exit(1);
    }
  }

  if (pipe(pipe_fd) < 0) {
    perror("pipe");
    exit(1);
  }
  if ((pid = fork()) == 0) {
    /* We are the child -- wait the specified timeout, write something
     * to the pipe, wait again, then close the pipe.
     */
    if (timeout == 0) {
      signal(SIGHUP, sighup);
      printf("Waiting for signal\n");
      sigpause(0);
    } else {
      sleep(timeout);
    }
#if 0
    printf("child: about to write to pipe\n");
    if (write(pipe_fd[1], "hello", sizeof("hello")) != sizeof("hello"))
{
      perror("child: write");
      exit(1);
    }
    if (timeout == 0) {
      signal(SIGHUP, sighup);
      printf("Waiting for signal\n");
      sigpause(0);
    } else {
      sleep(timeout);
    }
#endif
    if (close(pipe_fd[1]) < 0) {
      perror("child: close: pipe");
      exit(1);
    }
    printf("child: pipe closed, exiting\n");
    /* Exit successfully */
    exit(0);
  } else if (pid < 0) {
    /* The fork failed for some reason */
    perror("fork");
    exit(1);
  }
  /* We are the parent */
  close(pipe_fd[1]);
#if 1
  input_fd = pipe_fd[0];
#else
  input_fd = 0; /* Read from stdin */
#endif

  printf("parent: about to select on fd %d for reading\n", input_fd);
  FD_ZERO(&readset);
  FD_SET(input_fd, &readset);
  if (select(pipe_fd[0] + 1, &readset, 0, 0, 0) < 0) {
    perror("select");
    exit(1);
  }

  printf("parent: About to read from fd %d\n", input_fd);
  if ((bytes_read = read(input_fd, buf, sizeof(buf))) < 0) {
    perror("parent: read");
    exit(1);
  }
  buf[bytes_read] = 0;

  printf("read buffer of length %d: %s\n", bytes_read, buf);
  close(pipe_fd[0]);
  exit(0);
}

--
Want to unsubscribe from this list?
Send a message to cygwin-unsubscribe@sourceware.cygnus.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]