listen-relearn-tcp.js (5199B)
1 const path = require('path'); 2 const dgram = require('dgram'); 3 const { 4 spawnDaemon, 5 killDaemon, 6 killAllDaemons, 7 connectApi, 8 apiCommand, 9 createUdpEchoServer, 10 TIMEOUT 11 } = require('./helpers'); 12 13 const CONFIG_PATH = path.join(__dirname, 'config-tcp.ini'); 14 const API_PORT = 9123; 15 16 function sendUdpFromPort(srcPort, dstPort, message) { 17 return new Promise((resolve, reject) => { 18 const sock = dgram.createSocket('udp4'); 19 sock.bind(srcPort, '127.0.0.1', () => { 20 const buf = Buffer.from(message); 21 sock.send(buf, 0, buf.length, dstPort, '127.0.0.1', (err) => { 22 if (err) { 23 sock.close(); 24 reject(err); 25 } else { 26 setTimeout(() => { 27 sock.close(); 28 resolve(); 29 }, 50); 30 } 31 }); 32 }); 33 sock.on('error', reject); 34 }); 35 } 36 37 async function runTest() { 38 let daemon = null; 39 let apiSock = null; 40 let echoServer = null; 41 let returnCode = 0; 42 43 console.log('=== Listen Socket Re-learn Test ==='); 44 console.log('Testing: listen socket re-learns remote address when different client sends\n'); 45 46 try { 47 console.log('1. Spawning daemon...'); 48 daemon = await spawnDaemon(CONFIG_PATH); 49 console.log(` Daemon started (PID: ${daemon.pid})`); 50 51 console.log('2. Connecting to API...'); 52 apiSock = await connectApi(API_PORT); 53 console.log(' Connected to API'); 54 55 console.log('3. Authenticating...'); 56 let resp = await apiCommand(apiSock, 'auth', 'finwo', 'testsecret'); 57 console.log(` Auth response: ${resp}`); 58 if (resp !== 'OK') throw new Error('Authentication failed'); 59 60 console.log('4. Creating session...'); 61 resp = await apiCommand(apiSock, 'session.create', 'test-relearn', '60'); 62 console.log(` Session create: ${resp}`); 63 64 console.log('5. Creating listen socket...'); 65 resp = await apiCommand(apiSock, 'session.socket.create.listen', 'test-relearn', 'listener'); 66 const listenPort = resp[0]; 67 console.log(` Listen socket port: ${listenPort}`); 68 69 console.log('6. Starting echo server...'); 70 echoServer = await createUdpEchoServer(); 71 console.log(` Echo server on port: ${echoServer.port}`); 72 73 console.log('7. Creating connect socket to echo server...'); 74 resp = await apiCommand(apiSock, 'session.socket.create.connect', 'test-relearn', 'relay', '127.0.0.1', echoServer.port); 75 console.log(` Connect socket: ${resp}`); 76 77 console.log('8. Creating forward: listener -> relay...'); 78 resp = await apiCommand(apiSock, 'session.forward.create', 'test-relearn', 'listener', 'relay'); 79 console.log(` Forward create: ${resp}`); 80 81 console.log('9. First client sending "from-A" from port 50001...'); 82 await sendUdpFromPort(50001, listenPort, 'from-A'); 83 console.log(' Sent "from-A"'); 84 85 let messages = echoServer.getMessages(); 86 let start = Date.now(); 87 while (messages.length === 0 && Date.now() - start < TIMEOUT) { 88 await new Promise(r => setTimeout(r, 50)); 89 messages = echoServer.getMessages(); 90 } 91 92 if (messages.length === 0) { 93 throw new Error('Timeout: no message received from first client'); 94 } 95 96 const msgA = messages[0]; 97 console.log(` Received: "${msgA.data}" from ${msgA.rinfo.address}:${msgA.rinfo.port}`); 98 99 if (msgA.data !== 'from-A') { 100 throw new Error(`Expected "from-A", got "${msgA.data}"`); 101 } 102 console.log(' ā First client connection established, listen socket learned address'); 103 104 echoServer.clearMessages(); 105 106 console.log('10. Second client sending "from-B" from port 50002...'); 107 await sendUdpFromPort(50002, listenPort, 'from-B'); 108 console.log(' Sent "from-B"'); 109 110 messages = echoServer.getMessages(); 111 start = Date.now(); 112 while (messages.length === 0 && Date.now() - start < TIMEOUT) { 113 await new Promise(r => setTimeout(r, 50)); 114 messages = echoServer.getMessages(); 115 } 116 117 if (messages.length === 0) { 118 throw new Error('Timeout: no message received from second client'); 119 } 120 121 const msgB = messages[0]; 122 console.log(` Received: "${msgB.data}" from ${msgB.rinfo.address}:${msgB.rinfo.port}`); 123 124 if (msgB.data === 'from-B') { 125 console.log('\nā PASS: Listen socket correctly re-learned new remote address'); 126 console.log(' Second client (from port 50002) was able to communicate'); 127 console.log(' through the same listen socket after the first client.'); 128 } else if (msgB.data === 'from-A') { 129 console.log('\nā FAIL: Listen socket did NOT re-learn new remote address'); 130 console.log(' The second client\'s packet was sent back to the first client'); 131 console.log(' instead of the second client. This is the bug to fix.'); 132 console.log(` Expected to receive from port 50002, but responses went to port ${msgA.rinfo.port}`); 133 } else { 134 throw new Error(`Unexpected message: "${msgB.data}"`); 135 } 136 137 } catch (err) { 138 console.error(`\nā FAIL: ${err.message}`); 139 returnCode = 1; 140 } finally { 141 if (echoServer) echoServer.socket.close(); 142 if (apiSock) apiSock.end(); 143 if (daemon) await killDaemon(daemon); 144 await killAllDaemons(); 145 process.exit(returnCode); 146 } 147 } 148 149 runTest();