// Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; const common = require('../common'); const assert = require('assert'); const net = require('net'); // Test allowHalfOpen { let clientReceivedFIN = 0; let serverConnections = 0; let clientSentFIN = 0; let serverReceivedFIN = 0; const host = common.localhostIPv4; function serverOnConnection(socket) { console.log(`'connection' ${++serverConnections} emitted on server`); const srvConn = serverConnections; socket.resume(); socket.on('data', common.mustCall(function socketOnData(data) { this.clientId = data.toString(); console.log( `server connection ${srvConn} is started by client ${this.clientId}`); })); // 'end' on each socket must not be emitted twice socket.on('end', common.mustCall(function socketOnEnd() { console.log(`Server received FIN sent by client ${this.clientId}`); if (++serverReceivedFIN < CLIENT_VARIANTS) return; setTimeout(() => { server.close(); console.log(`connection ${this.clientId} is closing the server: FIN ${serverReceivedFIN} received by server, FIN ${clientReceivedFIN} received by client FIN ${clientSentFIN} sent by client, FIN ${serverConnections} sent by server`.replace(/ {3,}/g, '')); }, 50); }, 1)); socket.end(); console.log(`Server has sent ${serverConnections} FIN`); } // These two levels of functions (and not arrows) are necessary in order to // bind the `index`, and the calling socket (`this`) function clientOnConnect(index) { return common.mustCall(function clientOnConnectInner() { const client = this; console.log(`'connect' emitted on Client ${index}`); client.resume(); client.on('end', common.mustCall(function clientOnEnd() { setTimeout(function closeServer() { // When allowHalfOpen is true, client must still be writable // after the server closes the connections, but not readable console.log(`client ${index} received FIN`); assert(!client.readable); assert(client.writable); assert(client.write(String(index))); client.end(); clientSentFIN++; console.log( `client ${index} sent FIN, ${clientSentFIN} have been sent`); }, 50); })); client.on('close', common.mustCall(function clientOnClose() { clientReceivedFIN++; console.log(`connection ${index} has been closed by both sides,` + ` ${clientReceivedFIN} clients have closed`); })); }); } function serverOnClose() { console.log(`Server has been closed: FIN ${serverReceivedFIN} received by server FIN ${clientReceivedFIN} received by client FIN ${clientSentFIN} sent by client FIN ${serverConnections} sent by server`.replace(/ {3,}/g, '')); } function serverOnListen() { const port = server.address().port; console.log(`Server started listening at ${host}:${port}`); const opts = { allowHalfOpen: true, host, port }; // 6 variations === CLIENT_VARIANTS net.connect(opts, clientOnConnect(1)); net.connect(opts).on('connect', clientOnConnect(2)); net.createConnection(opts, clientOnConnect(3)); net.createConnection(opts).on('connect', clientOnConnect(4)); new net.Socket(opts).connect(opts, clientOnConnect(5)); new net.Socket(opts).connect(opts).on('connect', clientOnConnect(6)); } const CLIENT_VARIANTS = 6; // The trigger const server = net.createServer({ allowHalfOpen: true }) .on('connection', common.mustCall(serverOnConnection, CLIENT_VARIANTS)) .on('close', common.mustCall(serverOnClose)) .listen(0, host, common.mustCall(serverOnListen)); }