From mboxrd@z Thu Jan 1 00:00:00 1970 From: Patrick Doyle To: cygwin Subject: Re: Why does scp leave ssh running? -- select() never returns Date: Wed, 29 Nov 2000 19:21:00 -0000 Message-id: <3A25C7DA.6F76C8DA@delcomsys.com> References: <3A22C383.5C16BBC8@delcomsys.com> X-SW-Source: 2000-11/msg01542.html 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 #include #include #include #include #include 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