1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
// Flags: --expose-internals
'use strict';
const common = require('../common');
if (common.isWindows)
common.skip('Does not support wrapping sockets with fd on Windows');
const assert = require('assert');
const net = require('net');
const path = require('path');
const { internalBinding } = require('internal/test/binding');
const { Pipe, constants: PipeConstants } = internalBinding('pipe_wrap');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
function testClients(getSocketOpt, getConnectOpt, getConnectCb) {
const cloneOptions = (index) =>
({ ...getSocketOpt(index), ...getConnectOpt(index) });
return [
net.connect(cloneOptions(0), getConnectCb(0)),
net.connect(cloneOptions(1))
.on('connect', getConnectCb(1)),
net.createConnection(cloneOptions(2), getConnectCb(2)),
net.createConnection(cloneOptions(3))
.on('connect', getConnectCb(3)),
new net.Socket(getSocketOpt(4)).connect(getConnectOpt(4), getConnectCb(4)),
new net.Socket(getSocketOpt(5)).connect(getConnectOpt(5))
.on('connect', getConnectCb(5)),
];
}
const CLIENT_VARIANTS = 6; // Same length as array above
const forAllClients = (cb) => common.mustCall(cb, CLIENT_VARIANTS);
// Test Pipe fd is wrapped correctly
{
// Use relative path to avoid hitting 108-char length limit
// for socket paths in libuv.
const prefix = path.relative('.', `${common.PIPE}-net-connect-options-fd`);
const serverPath = `${prefix}-server`;
let counter = 0;
let socketCounter = 0;
const handleMap = new Map();
const server = net.createServer()
.on('connection', forAllClients(function serverOnConnection(socket) {
let clientFd;
socket.on('data', common.mustCall(function(data) {
clientFd = data.toString();
console.error(`[Pipe]Received data from fd ${clientFd}`);
socket.end();
}));
socket.on('end', common.mustCall(function() {
counter++;
console.error(`[Pipe]Received end from fd ${clientFd}, total ${counter}`);
if (counter === CLIENT_VARIANTS) {
setTimeout(() => {
console.error(`[Pipe]Server closed by fd ${clientFd}`);
server.close();
}, 10);
}
}, 1));
}))
.on('close', function() {
setTimeout(() => {
for (const pair of handleMap) {
console.error(`[Pipe]Clean up handle with fd ${pair[1].fd}`);
pair[1].close(); // clean up handles
}
}, 10);
})
.on('error', function(err) {
console.error(err);
assert.fail(`[Pipe server]${err}`);
})
.listen({ path: serverPath }, common.mustCall(function serverOnListen() {
const getSocketOpt = (index) => {
const handle = new Pipe(PipeConstants.SOCKET);
const err = handle.bind(`${prefix}-client-${socketCounter++}`);
assert(err >= 0, String(err));
assert.notStrictEqual(handle.fd, -1);
handleMap.set(index, handle);
console.error(`[Pipe]Bound handle with Pipe ${handle.fd}`);
return { fd: handle.fd, readable: true, writable: true };
};
const getConnectOpt = () => ({
path: serverPath
});
const getConnectCb = (index) => common.mustCall(function clientOnConnect() {
// Test if it's wrapping an existing fd
assert(handleMap.has(index));
const oldHandle = handleMap.get(index);
assert.strictEqual(oldHandle.fd, this._handle.fd);
this.write(String(oldHandle.fd));
console.error(`[Pipe]Sending data through fd ${oldHandle.fd}`);
this.on('error', function(err) {
console.error(err);
assert.fail(`[Pipe Client]${err}`);
});
});
testClients(getSocketOpt, getConnectOpt, getConnectCb);
}));
}
|