• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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