X-Spam-Check-By: sourceware.org Message-Id: <200706212245.l5LMjELU006807@chi.hcst.net> Date: Thu, 21 Jun 2007 22:45:14 -0000 To: Subject: Socket inheritance with fork/dup2/exec From: "Jim Powers" X-Mailer: TWIG 2.7.4 X-Client-IP: 69.81.191.244 Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT cygwin DOT com Mail-Followup-To: cygwin AT cygwin DOT com Delivered-To: mailing list cygwin AT cygwin DOT com Hi, I am redirecting the stdout of a child process to a socket via the standard fork/dup2/exec paradigm and then reading and displaying the output. This works fine if the exec'd child process is compiled using gcc under cygwin. However, it fails with an "Invalid file handle" error when compiled using VC8 under windows. I've included both the parent and child code below. I am running cygwin 1.5.24 and gcc3.4.4. -- Jim Powers Powers Consulting Services, Inc. jim dot powers at powers-consulting dot com -------- parent.c -------- #include #include #include #include #include #ifndef STDIN_FILENO #define STDIN_FILENO 0 #endif #ifndef STDOUT_FILENO #define STDOUT_FILENO 1 #endif #ifndef STDERR_FILENO #define STDERR_FILENO 2 #endif void set_blocking(int fd); void set_nonblocking(int fd); int main(int argc, char **argv) { int i; pid_t pid; int to_child_pipe[2]; int from_child_pipe[2]; int f_in, f_out, n; char buffer[512]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, to_child_pipe) || socketpair(AF_UNIX, SOCK_STREAM, 0, from_child_pipe) ) { fprintf(stderr, "socketpair error (%d)\n", errno); exit(1); } pid = fork(); if (pid == -1) { fprintf(stderr, "fork error (%d)\n", errno); exit(1); } if (pid == 0) { /* CHILD */ if ( dup2(to_child_pipe[0], STDIN_FILENO) < 0 || close(to_child_pipe[1]) < 0 || close(from_child_pipe[0]) < 0 || dup2(from_child_pipe[1], STDOUT_FILENO) < 0 ) { fprintf(stderr, "dup2/close error (%d)\n", errno); exit(1); } if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]); if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]); set_blocking(STDIN_FILENO); set_nonblocking(STDIN_FILENO); execvp(argv[1], &argv[1]); fprintf(stderr, "execvp error (%d) on '%s'", errno, argv[1]); exit(1); } /* PARENT */ if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) { fprintf(stderr, "close error (%d) on child handles", errno); exit(1); } f_in = from_child_pipe[0]; f_out = to_child_pipe[1]; /* read and display data from child process */ while (1) { n = read(f_in, buffer, sizeof(buffer) - 1); if (n == 0) break; if (n == -1) { if (errno != ECONNABORTED && errno != ECONNRESET) fprintf(stderr, "read error (%d)\n", errno); break; } buffer[n] = '\0'; printf("%s", buffer); fflush(NULL); } exit(1); } void set_blocking(int fd) { int val; if ((val = fcntl(fd, F_GETFL, 0)) == -1) return; if (val & O_NONBLOCK) { val &= ~O_NONBLOCK; fcntl(fd, F_SETFL, val); } } void set_nonblocking(int fd) { int val; if ((val = fcntl(fd, F_GETFL, 0)) == -1) return; if (!(val & O_NONBLOCK)) { val |= O_NONBLOCK; fcntl(fd, F_SETFL, val); } } ------- child.c ------- #include #include void ErrorExit(LPTSTR lpszFunction); main(int argc, char **argv) { char str[] = "hello"; int i; DWORD btw = (DWORD)strlen(str); DWORD bw; STARTUPINFO si; OVERLAPPED ol; HANDLE hStdout; ZeroMemory(&ol, sizeof(ol)); hStdout = GetStdHandle(STD_OUTPUT_HANDLE); for (i=0; i<5; i++) { if (! WriteFile(hStdout, str, btw, &bw, &ol) ) { ErrorExit("WriteFile"); exit(1); } Sleep(1000); } } void ErrorExit(LPTSTR lpszFunction) { LPVOID lpMsgBuf; DWORD dw = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); fprintf(stderr, "%s error (%d): %s\n", lpszFunction, dw, lpMsgBuf); ExitProcess(dw); } -- Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple Problem reports: http://cygwin.com/problems.html Documentation: http://cygwin.com/docs.html FAQ: http://cygwin.com/faq/