delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2007/06/21/18:45:44

X-Spam-Check-By: sourceware.org
Message-Id: <200706212245.l5LMjELU006807@chi.hcst.net>
Date: Thu, 21 Jun 2007 22:45:14 -0000
To: <cygwin AT cygwin DOT com>
Subject: Socket inheritance with fork/dup2/exec
From: "Jim Powers" <jim DOT powers AT powers-consulting DOT com>
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: <cygwin.cygwin.com>
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sourceware.org/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
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 <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/

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019