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