|
View:
New views
8 Messages
—
Rating Filter:
Alert me
|
|
|
Socket inheritance with fork/dup2/execHi,
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 <stdio.h> #include <stdarg.h> #include <errno.h> #include <sys/fcntl.h> #include <sys/socket.h> #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 <stdio.h> #include <Windows.h> 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/ |
|
|
Re: Socket inheritance with fork/dup2/execJim Powers wrote:
> 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'm fairly sure this isn't supposed to work. Unix domain sockets (AF_UNIX/AF_LOCAL) don't actually exist in any Windows API so Cygwin emulates them with an underlying AF_INET socket. So when your MSVCRT program tries to WriteFile to a socket it fails, because you have to use the Winsock API for that. In short, Windows is not unix, and handles aren't fds. You can probably make this work if you use pipe() instead of a socketpair() as that maps directly onto a Windows anonymous pipe, which is a file handle that can be written to. You could also use a named pipe, which is the closest Windows has to a unix domain socket, but there is no corresponding POSIX api for that and so you'd be breaking abstraction as you'd have to deal with raw Win32 APIs in your POSIX parent app, which is ugly (and not how Cygwin was designed to work either.) Brian -- 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/ |
|
|
Re: Socket inheritance with fork/dup2/execOn 6/21/07, Brian Dessent wrote:
> Jim Powers wrote: > > > 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'm fairly sure this isn't supposed to work. Unix domain sockets > (AF_UNIX/AF_LOCAL) don't actually exist in any Windows API so Cygwin > emulates them with an underlying AF_INET socket. So when your MSVCRT > program tries to WriteFile to a socket it fails, because you have to use > the Winsock API for that. In short, Windows is not unix, and handles > aren't fds. Actually, in windows API you can WriteFile() to a socket (as an optional feature, but the default socket provider supports it). The problem here is that cygwin opens the underlying socket in overlapped mode, and the windows API requires treating overlapped handles differently than non-overlapped. If you'll always be using the same child, that you have full control over, then you can write the child to use overlapped semantics. But if you want to be able to pass the socket to an arbitrary child process then you're out of luck, because the windows API provides no way for the child to discover that it needs to use overlapped semantics, forcing the child to attempt non-overlapped semantics and fail. I once wrote a patch to cygwin in an attempt to get around this. It mostly worked, but windows API calls that were not documented to be able to block (eg setsockopt()) started blocking on non-overlapped sockets. Don't you just love the windows API? See: http://cygwin.com/ml/cygwin-patches/2006-q2/msg00039.html > You can probably make this work if you use pipe() instead of a > socketpair() as that maps directly onto a Windows anonymous pipe, which > is a file handle that can be written to. You could also use a named > pipe, which is the closest Windows has to a unix domain socket, but > there is no corresponding POSIX api for that and so you'd be breaking > abstraction as you'd have to deal with raw Win32 APIs in your POSIX > parent app, which is ugly (and not how Cygwin was designed to work > either.) Actually, pipe() is implemented in cygwin using win32 named pipes, not anonymous pipes, as I recall. But, you are right that using pipe() should solve this particular problem. Lev -- 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/ |
|
|
Re: Socket inheritance with fork/dup2/execLev Bishop wrote:
> Actually, pipe() is implemented in cygwin using win32 named pipes, > not anonymous pipes, as I recall. But, you are right that using pipe() > should solve this particular problem. Hmm, that does appear to be the case. Unless I'm mistaken anonymous pipes are just a degenerate form of named pipes created by the system in a given namespace (\Device\NamedPipe\Win32Pipes.$DWORD.$DWORD ?) so I guess you could say they're all the same thing anyway. :) Brian -- 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/ |
|
|
Re: Socket inheritance with fork/dup2/execOn Jun 21 22:45, Jim Powers wrote:
> 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. This is almost certainly a drawback of the method used for duplicating sockets to child processes used in Cygwin 1.5.24 and before (WSADuplicateSocket/WSASocket). This only works reliable if the child knows that the descriptor is a socket. Usually server applications using sockets don't duplicate the socket to the child processes, but instead use pipes or pseudo terminals on the local connection, so that's not a standard problem. However, the next version of Cygwin will use standard DuplicateHandle calls as for normal file handles. Consequentially your your test application appears to work with a Cygwin built from CVS: $ ./sock-cyg-win-parent ./sock-cyg-win-child.exe hellohellohellohellohello^C You could try a developer snapshot from http://cygwin.com/snapshots/ As a workaround for Cygwin 1.5.x, use pipes, as already noted, or pseudo terminals. Corinna -- Corinna Vinschen Please, send mails regarding Cygwin to Cygwin Project Co-Leader cygwin AT cygwin DOT com Red Hat -- 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/ |
|
|
Re: Socket inheritance with fork/dup2/execOn 6/22/07, Corinna Vinschen wrote:
> However, the next version of Cygwin will use standard DuplicateHandle > calls as for normal file handles. Consequentially your > your test application appears to work with a Cygwin built from CVS: But MSDN says: You should not use DuplicateHandle to duplicate handles to the following objects: * I/O completion ports. No error is returned, but the duplicate handle cannot be used. * Sockets. No error is returned, but the duplicate handle may not be recognized by Winsock at the target process. Also, using DuplicateHandle interferes with internal reference counting on the underlying object. To duplicate a socket handle, use the WSADuplicateSocket function. -- 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/ |
|
|
Re: Socket inheritance with fork/dup2/execCorinna,
I took your suggestion and downloaded the latest sanpshot (cygwin1- 20070616.dll) and that fixed the problem. The Win32 version of the client compiled with VC8 now works fine. Thanks!! Jim Corinna Vinschen <corinna-cygwin@...> said: > On Jun 21 22:45, Jim Powers wrote: > > 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. > > This is almost certainly a drawback of the method used for duplicating > sockets to child processes used in Cygwin 1.5.24 and before > (WSADuplicateSocket/WSASocket). This only works reliable if the child > knows that the descriptor is a socket. Usually server applications > using sockets don't duplicate the socket to the child processes, but > instead use pipes or pseudo terminals on the local connection, so that's > not a standard problem. > > However, the next version of Cygwin will use standard DuplicateHandle > calls as for normal file handles. Consequentially your > your test application appears to work with a Cygwin built from CVS: > > $ ./sock-cyg-win-parent ./sock-cyg-win-child.exe > hellohellohellohellohello^C > > You could try a developer snapshot from http://cygwin.com/snapshots/ > > As a workaround for Cygwin 1.5.x, use pipes, as already noted, or pseudo > terminals. > > > Corinna > > -- > Corinna Vinschen Please, send mails regarding Cygwin to > Cygwin Project Co-Leader cygwin AT cygwin DOT com > Red Hat > > -- > 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/ > -- Jim Powers Powers Consulting Services, Inc. jim.powers@... 937-271-5523 -- 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/ |
|
|
Re: Socket inheritance with fork/dup2/execOn Jun 22 11:34, Lev Bishop wrote:
> On 6/22/07, Corinna Vinschen wrote: > > >However, the next version of Cygwin will use standard DuplicateHandle > >calls as for normal file handles. Consequentially your > >your test application appears to work with a Cygwin built from CVS: > > But MSDN says: > You should not use DuplicateHandle to duplicate handles to the > following objects: > > * I/O completion ports. No error is returned, but the duplicate > handle cannot be used. > * Sockets. No error is returned, but the duplicate handle may not > be recognized by > Winsock at the target process. Also, using DuplicateHandle interferes > with internal reference counting on the underlying object. To > duplicate a socket handle, use the > WSADuplicateSocket function. I see this mentioned on the MSDN web pages, but I don't see this on my very recent MSDN Library DVD. Only I/O completion ports are mentioned as not being duplicatable by DuplicateHandle. Sockets are in the list of duplicatable objects. It would be really weird, too, since it was never a problem to duplicate a socket on NT. We only ever had problems on 95/98/Me. These 95/98/Me problems were the reason to switch Cygwin from using DuplicateHandle on sockets to WSADuplicateSocket/WSASocket back in 2000. Corinna -- Corinna Vinschen Please, send mails regarding Cygwin to Cygwin Project Co-Leader cygwin AT cygwin DOT com Red Hat -- 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/ |
| Free embeddable forum powered by Nabble | Forum Help |