1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22'use strict'; 23const common = require('../common'); 24const assert = require('assert'); 25const net = require('net'); 26 27function pingPongTest(port, host) { 28 const N = 1000; 29 let count = 0; 30 let sentPongs = 0; 31 let sent_final_ping = false; 32 33 const server = net.createServer( 34 { allowHalfOpen: true }, 35 common.mustCall(onSocket) 36 ); 37 38 function onSocket(socket) { 39 assert.strictEqual(socket.server, server); 40 assert.strictEqual( 41 server, 42 server.getConnections(common.mustSucceed((connections) => { 43 assert.strictEqual(connections, 1); 44 })) 45 ); 46 47 socket.setNoDelay(); 48 socket.timeout = 0; 49 50 socket.setEncoding('utf8'); 51 socket.on('data', common.mustCall(function(data) { 52 // Since we never queue data (we're always waiting for the PING 53 // before sending a pong) the writeQueueSize should always be less 54 // than one message. 55 assert.ok(socket.bufferSize >= 0 && socket.bufferSize <= 4); 56 57 assert.strictEqual(socket.writable, true); 58 assert.strictEqual(socket.readable, true); 59 assert.ok(count <= N); 60 assert.strictEqual(data, 'PING'); 61 62 socket.write('PONG', common.mustCall(function() { 63 sentPongs++; 64 })); 65 }, N + 1)); 66 67 socket.on('end', common.mustCall(function() { 68 assert.strictEqual(socket.allowHalfOpen, true); 69 assert.strictEqual(socket.writable, true); // Because allowHalfOpen 70 assert.strictEqual(socket.readable, false); 71 socket.end(); 72 })); 73 74 socket.on('error', common.mustNotCall()); 75 76 socket.on('close', common.mustCall(function() { 77 assert.strictEqual(socket.writable, false); 78 assert.strictEqual(socket.readable, false); 79 socket.server.close(); 80 })); 81 } 82 83 84 server.listen(port, host, common.mustCall(function() { 85 if (this.address().port) 86 port = this.address().port; 87 88 const client = net.createConnection(port, host); 89 90 client.setEncoding('ascii'); 91 client.on('connect', common.mustCall(function() { 92 assert.strictEqual(client.readable, true); 93 assert.strictEqual(client.writable, true); 94 client.write('PING'); 95 })); 96 97 client.on('data', common.mustCall(function(data) { 98 assert.strictEqual(data, 'PONG'); 99 count += 1; 100 101 if (sent_final_ping) { 102 assert.strictEqual(client.writable, false); 103 assert.strictEqual(client.readable, true); 104 return; 105 } 106 assert.strictEqual(client.writable, true); 107 assert.strictEqual(client.readable, true); 108 109 if (count < N) { 110 client.write('PING'); 111 } else { 112 sent_final_ping = true; 113 client.write('PING'); 114 client.end(); 115 } 116 }, N + 1)); 117 118 client.on('close', common.mustCall(function() { 119 assert.strictEqual(count, N + 1); 120 assert.strictEqual(sentPongs, N + 1); 121 assert.strictEqual(sent_final_ping, true); 122 })); 123 124 client.on('error', common.mustNotCall()); 125 })); 126} 127 128/* All are run at once, so run on different ports */ 129const tmpdir = require('../common/tmpdir'); 130tmpdir.refresh(); 131pingPongTest(common.PIPE); 132pingPongTest(0); 133pingPongTest(0, 'localhost'); 134if (common.hasIPv6) 135 pingPongTest(0, '::1'); 136