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