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