Skip to content

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

Closed
@devinivy

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 the documentations.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