1/* eslint-disable node-core/require-common-first, node-core/required-modules */ 2'use strict'; 3const { internalBinding } = require('internal/test/binding'); 4const { JSUDPWrap } = internalBinding('js_udp_wrap'); 5const EventEmitter = require('events'); 6 7// FakeUDPWrap is a testing utility that emulates a UDP connection 8// for the sake of making UDP tests more deterministic. 9class FakeUDPWrap extends EventEmitter { 10 constructor() { 11 super(); 12 13 this._handle = new JSUDPWrap(); 14 15 this._handle.onreadstart = () => this._startReading(); 16 this._handle.onreadstop = () => this._stopReading(); 17 this._handle.onwrite = 18 (wrap, buffers, addr) => this._write(wrap, buffers, addr); 19 this._handle.getsockname = (obj) => { 20 Object.assign(obj, { address: '127.0.0.1', family: 'IPv4', port: 1337 }); 21 return 0; 22 }; 23 24 this.reading = false; 25 this.bufferedReceived = []; 26 this.emitBufferedImmediate = null; 27 } 28 29 _emitBuffered = () => { 30 if (!this.reading) return; 31 if (this.bufferedReceived.length > 0) { 32 this.emitReceived(this.bufferedReceived.shift()); 33 this.emitBufferedImmediate = setImmediate(this._emitBuffered); 34 } else { 35 this.emit('wantRead'); 36 } 37 }; 38 39 _startReading() { 40 this.reading = true; 41 this.emitBufferedImmediate = setImmediate(this._emitBuffered); 42 } 43 44 _stopReading() { 45 this.reading = false; 46 clearImmediate(this.emitBufferedImmediate); 47 } 48 49 _write(wrap, buffers, addr) { 50 this.emit('send', { buffers, addr }); 51 setImmediate(() => this._handle.onSendDone(wrap, 0)); 52 } 53 54 afterBind() { 55 this._handle.onAfterBind(); 56 } 57 58 emitReceived(info) { 59 if (!this.reading) { 60 this.bufferedReceived.push(info); 61 return; 62 } 63 64 const { 65 buffers, 66 addr: { 67 family = 4, 68 address = '127.0.0.1', 69 port = 1337, 70 }, 71 flags = 0 72 } = info; 73 74 let familyInt; 75 switch (family) { 76 case 'IPv4': familyInt = 4; break; 77 case 'IPv6': familyInt = 6; break; 78 default: throw new Error('bad family'); 79 } 80 81 for (const buffer of buffers) { 82 this._handle.emitReceived(buffer, familyInt, address, port, flags); 83 } 84 } 85} 86 87function makeUDPPair() { 88 const serverSide = new FakeUDPWrap(); 89 const clientSide = new FakeUDPWrap(); 90 91 serverSide.on('send', 92 (chk) => setImmediate(() => clientSide.emitReceived(chk))); 93 clientSide.on('send', 94 (chk) => setImmediate(() => serverSide.emitReceived(chk))); 95 96 return { serverSide, clientSide }; 97} 98 99module.exports = { 100 FakeUDPWrap, 101 makeUDPPair 102}; 103