• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Flags: --expose-internals
2'use strict';
3
4const common = require('../common');
5const assert = require('assert');
6const net = require('net');
7const fs = require('fs');
8const { getSystemErrorName } = require('util');
9const { internalBinding } = require('internal/test/binding');
10const { TCP, constants: TCPConstants } = internalBinding('tcp_wrap');
11const { Pipe, constants: PipeConstants } = internalBinding('pipe_wrap');
12
13const tmpdir = require('../common/tmpdir');
14tmpdir.refresh();
15
16function closeServer() {
17  return common.mustCall(function() {
18    this.close();
19  });
20}
21
22// server.listen(pipe) creates a new pipe wrap,
23// so server.close() doesn't actually unlink this existing pipe.
24// It needs to be unlinked separately via handle.close()
25function closePipeServer(handle) {
26  return common.mustCall(function() {
27    this.close();
28    handle.close();
29  });
30}
31
32let counter = 0;
33
34// Avoid conflict with listen-path
35function randomPipePath() {
36  return `${common.PIPE}-listen-handle-${counter++}`;
37}
38
39function randomHandle(type) {
40  let handle, errno, handleName;
41  if (type === 'tcp') {
42    handle = new TCP(TCPConstants.SOCKET);
43    errno = handle.bind('0.0.0.0', 0);
44    handleName = 'arbitrary tcp port';
45  } else {
46    const path = randomPipePath();
47    handle = new Pipe(PipeConstants.SOCKET);
48    errno = handle.bind(path);
49    handleName = `pipe ${path}`;
50  }
51
52  if (errno < 0) {
53    assert.fail(`unable to bind ${handleName}: ${getSystemErrorName(errno)}`);
54  }
55
56  if (!common.isWindows) {  // `fd` doesn't work on Windows.
57    // err >= 0 but fd = -1, should not happen
58    assert.notStrictEqual(handle.fd, -1,
59                          `Bound ${handleName} has fd -1 and errno ${errno}`);
60  }
61  return handle;
62}
63
64// Not a public API, used by child_process
65{
66  // Test listen(tcp)
67  net.createServer()
68    .listen(randomHandle('tcp'))
69    .on('listening', closeServer());
70  // Test listen(tcp, cb)
71  net.createServer()
72    .listen(randomHandle('tcp'), closeServer());
73}
74
75function randomPipes(number) {
76  const arr = [];
77  for (let i = 0; i < number; ++i) {
78    arr.push(randomHandle('pipe'));
79  }
80  return arr;
81}
82
83// Not a public API, used by child_process
84if (!common.isWindows) {  // Windows doesn't support {fd: <n>}
85  const handles = randomPipes(2);  // Generate pipes in advance
86  // Test listen(pipe)
87  net.createServer()
88    .listen(handles[0])
89    .on('listening', closePipeServer(handles[0]));
90  // Test listen(pipe, cb)
91  net.createServer()
92    .listen(handles[1], closePipeServer(handles[1]));
93}
94
95{
96  // Test listen({handle: tcp}, cb)
97  net.createServer()
98    .listen({ handle: randomHandle('tcp') }, closeServer());
99  // Test listen({handle: tcp})
100  net.createServer()
101    .listen({ handle: randomHandle('tcp') })
102    .on('listening', closeServer());
103  // Test listen({_handle: tcp}, cb)
104  net.createServer()
105    .listen({ _handle: randomHandle('tcp') }, closeServer());
106  // Test listen({_handle: tcp})
107  net.createServer()
108    .listen({ _handle: randomHandle('tcp') })
109    .on('listening', closeServer());
110}
111
112if (!common.isWindows) {  // Windows doesn't support {fd: <n>}
113  // Test listen({fd: tcp.fd}, cb)
114  net.createServer()
115    .listen({ fd: randomHandle('tcp').fd }, closeServer());
116  // Test listen({fd: tcp.fd})
117  net.createServer()
118    .listen({ fd: randomHandle('tcp').fd })
119    .on('listening', closeServer());
120}
121
122if (!common.isWindows) {  // Windows doesn't support {fd: <n>}
123  const handles = randomPipes(6);  // Generate pipes in advance
124  // Test listen({handle: pipe}, cb)
125  net.createServer()
126    .listen({ handle: handles[0] }, closePipeServer(handles[0]));
127  // Test listen({handle: pipe})
128  net.createServer()
129    .listen({ handle: handles[1] })
130    .on('listening', closePipeServer(handles[1]));
131  // Test listen({_handle: pipe}, cb)
132  net.createServer()
133    .listen({ _handle: handles[2] }, closePipeServer(handles[2]));
134  // Test listen({_handle: pipe})
135  net.createServer()
136    .listen({ _handle: handles[3] })
137    .on('listening', closePipeServer(handles[3]));
138  // Test listen({fd: pipe.fd}, cb)
139  net.createServer()
140    .listen({ fd: handles[4].fd }, closePipeServer(handles[4]));
141  // Test listen({fd: pipe.fd})
142  net.createServer()
143    .listen({ fd: handles[5].fd })
144    .on('listening', closePipeServer(handles[5]));
145}
146
147if (!common.isWindows) {  // Windows doesn't support {fd: <n>}
148  // Test invalid fd
149  const fd = fs.openSync(__filename, 'r');
150  net.createServer()
151    .listen({ fd }, common.mustNotCall())
152    .on('error', common.mustCall(function(err) {
153      assert.strictEqual(String(err), 'Error: listen EINVAL: invalid argument');
154      this.close();
155    }));
156}
157