본문 바로가기

컴퓨터/언어,프로그래밍

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/

'컴퓨터 > 언어,프로그래밍' 카테고리의 다른 글

dup( ), dup2( )  (0) 2009.05.27
Dup2 를 이용한 Redirection 과 원상복귀  (0) 2009.05.27
간단한 pipe()에 대한 소스  (0) 2009.05.27
dup2()  (0) 2009.05.27
dup2  (1) 2009.05.27
제주삼다수, 2L,... 오뚜기 진라면 매운... 상하목장 유기농 흰... 남양 프렌치카페 카... 고려인삼유통 홍삼 ... 종근당건강 오메가3... 요이치 카링 유무선...