This is the mail archive of the cygwin 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]
Other format: [Raw text]

Socket inheritance with fork/dup2/exec


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 <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/


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