Question

I'm trying to pass an open TCP socket connection from a Perl program as the stdin and stdout to an external application on Windows, similar to what inetd in the Unix world does.

What I have tried:

  1. "Replace" stdin and stdout by the socket using open or POSIX::dup2 and calling exec:

    # $socket is an open TCP socket
    open STDIN,  '<&', $socket or die "Unable to dup stdin: $^E";
    open STDOUT, '>&', $socket or die "Unable to dup stdout: $^E";
    close $socket;
    exec($program) or die "Unable to exec $command: $^E";
    
  2. Use IPC::open3:

    my $pid = open3(
        '>&'.$socket->fileno, 
        '<&'.$socket->fileno, 
        '<&'.fileno(STDERR), 
        $program);
    waitpid $pid, 0;
    

In both cases the executed program receives something that is not a socket (a pipe, perhaps?), which is a problem because it wants to use select. On Windows select works only on sockets.

What can I do to pass the socket to the external application?

By the way I'm using Strawberry Perl, not ActiveState.

Was it helpful?

Solution

Sadly, on Windows you can't always do this. After great pain, we gave up on being able to achieve this. See this question (Are TCP SOCKET handles inheritable?) for an explanation.

It is possible on a stock Windows installation: you have to make sure that the TCP socket is created non-overlapped, which is not the default for the WinSock functions. Then it can be marked inheritable and set as the stdin/stdout of a child process.

However, with certain well-known security products (firewalls, AV) installed, it's not possible to do this because they hook the TCP stack in a way that prevents TCP sockets from being inherited properly.

You can only really inherit Windows pipes, file handles, and so on safely. To give a socket to the child, it has to cooperate with the parent rather than dumbly receive it as stdin. The parent can launch the child, use WSADuplicateSocket to give the socket to the child's PID, pass the data about the socket to the child (perhaps to the child's stdin over a named pipe). The child then reconstitutes the socket using the passed data. So, if you're willing to reprogram the client to have an awareness of its parent, it can be done.

I'm not sure how this could be done on Perl, but see this interesting example for a starter. You'll have to import the native WSADuplicateSocket function and do it yourself, I'd imagine.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top