Skip to content

Handing spawn() stdio as socket wont duplex properly #15714

Description

@devinivy
  • Version: At least v6.9.1 and v8.5.0
  • Platform: Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53 PDT 2015; x86_64

I'm trying to implement a sort of PassThrough-style stream that can be used as mock stdio for ChildProcess.spawn(). PassThrough itself isn't appropriate because it doesn't have a file descriptor. So I'm doing this by creating a socket that speaks to an echo server. What I'm finding is that the server receives the data and successfully pipes it, but the passthrough socket never seems to receive it.

I've poked around the node internals a bit to figure-out why, but I don't have much to share at this time. It looks like spawn() may create another socket that's readable and not writable, and uses the socket I passed as its handle [here]. But my socket remains readable and writable as I would expect, so I still can't explain the behavior!

Possibly related to #9413. Here's some code to reproduce the issue and play with.

'use strict';

const ChildProcess = require('child_process');
const Net = require('net');

const makePassThrough = (cb) => {

    const srv = Net.createServer((sock) => {

        sock.on('data', (data) => console.log('server sock saw data:', data.toString()));
        sock.once('close', () => console.log('server sock closed'));
        sock.once('end', () => console.log('server sock ended'));
        sock.once('error', (err) => console.log('server sock errored', err));
        sock.once('timeout', () => console.log('server sock timed-out'));

        sock.pipe(sock);
    });

    srv.once('close', () => console.log('server closed'));
    srv.once('error', cb);
    srv.listen(() => {

        const sock = new Net.Socket();

        sock.once('close', () => console.log('client sock closed'));
        sock.once('end', () => console.log('client sock ended'));
        sock.once('error', (err) => console.log('client sock errored', err));
        sock.once('timeout', () => console.log('client sock timed-out'));

        sock.once('error', cb);
        sock.connect(srv.address().port, () => cb(null, sock));
    });
};

makePassThrough((err, stdout) => {

    if (err) {
        throw err;
    }

    stdout.on('data', (data) => console.log('subproc stdout saw data:', data.toString()));

    const subproc = ChildProcess.spawn('echo', ['is anybody out there?'], {
        stdio: ['ignore', stdout, 'ignore']
    });

    subproc.on('close', process.exit);
});

/* Program outputs the following,
      $ node index.js 
      server sock saw data: is anybody out there?
      # Does not exit
*/

For my purposes I'm all set– I can use stdio: 'pipe' and pipe the process's stdio thru actual passthrough streams. This is still a curiosity, though!

Metadata

Metadata

Assignees

No one assigned

    Labels

    child_processIssues and PRs related to the child_process subsystem.docIssues and PRs related to Node.js documentation.good first issueIssues that are suitable for first-time contributors.help wantedIssues that need assistance from volunteers or PRs that need help to proceed.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions