• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22'use strict';
23
24const {
25  ArrayIsArray,
26  ArrayPrototypeIndexOf,
27  Boolean,
28  Error,
29  Number,
30  NumberIsNaN,
31  NumberParseInt,
32  ObjectDefineProperty,
33  ObjectSetPrototypeOf,
34  Symbol,
35} = primordials;
36
37const EventEmitter = require('events');
38const stream = require('stream');
39let debug = require('internal/util/debuglog').debuglog('net', (fn) => {
40  debug = fn;
41});
42const { deprecate } = require('internal/util');
43const {
44  isIP,
45  isIPv4,
46  isIPv6,
47  normalizedArgsSymbol,
48  makeSyncWrite
49} = require('internal/net');
50const assert = require('internal/assert');
51const {
52  UV_EADDRINUSE,
53  UV_EINVAL,
54  UV_ENOTCONN
55} = internalBinding('uv');
56
57const { Buffer } = require('buffer');
58const { guessHandleType } = internalBinding('util');
59const { ShutdownWrap } = internalBinding('stream_wrap');
60const {
61  TCP,
62  TCPConnectWrap,
63  constants: TCPConstants
64} = internalBinding('tcp_wrap');
65const {
66  Pipe,
67  PipeConnectWrap,
68  constants: PipeConstants
69} = internalBinding('pipe_wrap');
70const {
71  newAsyncId,
72  defaultTriggerAsyncIdScope,
73  symbols: { async_id_symbol, owner_symbol }
74} = require('internal/async_hooks');
75const {
76  writevGeneric,
77  writeGeneric,
78  onStreamRead,
79  kAfterAsyncWrite,
80  kHandle,
81  kUpdateTimer,
82  setStreamTimeout,
83  kBuffer,
84  kBufferCb,
85  kBufferGen
86} = require('internal/stream_base_commons');
87const {
88  codes: {
89    ERR_INVALID_ADDRESS_FAMILY,
90    ERR_INVALID_ARG_TYPE,
91    ERR_INVALID_ARG_VALUE,
92    ERR_INVALID_FD_TYPE,
93    ERR_INVALID_IP_ADDRESS,
94    ERR_INVALID_OPT_VALUE,
95    ERR_SERVER_ALREADY_LISTEN,
96    ERR_SERVER_NOT_RUNNING,
97    ERR_SOCKET_CLOSED
98  },
99  errnoException,
100  exceptionWithHostPort,
101  uvExceptionWithHostPort
102} = require('internal/errors');
103const { isUint8Array } = require('internal/util/types');
104const {
105  validateInt32,
106  validatePort,
107  validateString
108} = require('internal/validators');
109const kLastWriteQueueSize = Symbol('lastWriteQueueSize');
110const {
111  DTRACE_NET_SERVER_CONNECTION,
112  DTRACE_NET_STREAM_END
113} = require('internal/dtrace');
114
115// Lazy loaded to improve startup performance.
116let cluster;
117let dns;
118let BlockList;
119let SocketAddress;
120
121const { clearTimeout } = require('timers');
122const { kTimeout } = require('internal/timers');
123
124const DEFAULT_IPV4_ADDR = '0.0.0.0';
125const DEFAULT_IPV6_ADDR = '::';
126
127const isWindows = process.platform === 'win32';
128
129const noop = () => {};
130
131function getFlags(ipv6Only) {
132  return ipv6Only === true ? TCPConstants.UV_TCP_IPV6ONLY : 0;
133}
134
135function createHandle(fd, is_server) {
136  validateInt32(fd, 'fd', 0);
137  const type = guessHandleType(fd);
138  if (type === 'PIPE') {
139    return new Pipe(
140      is_server ? PipeConstants.SERVER : PipeConstants.SOCKET
141    );
142  }
143
144  if (type === 'TCP') {
145    return new TCP(
146      is_server ? TCPConstants.SERVER : TCPConstants.SOCKET
147    );
148  }
149
150  throw new ERR_INVALID_FD_TYPE(type);
151}
152
153
154function getNewAsyncId(handle) {
155  return (!handle || typeof handle.getAsyncId !== 'function') ?
156    newAsyncId() : handle.getAsyncId();
157}
158
159
160function isPipeName(s) {
161  return typeof s === 'string' && toNumber(s) === false;
162}
163
164/**
165 * Creates a new TCP or IPC server
166 * @param {{
167 *   allowHalfOpen?: boolean;
168 *   pauseOnConnect?: boolean;
169 *   }} [options]
170 * @param {Function} [connectionListener]
171 * @returns {Server}
172 */
173
174function createServer(options, connectionListener) {
175  return new Server(options, connectionListener);
176}
177
178
179// Target API:
180//
181// let s = net.connect({port: 80, host: 'google.com'}, function() {
182//   ...
183// });
184//
185// There are various forms:
186//
187// connect(options, [cb])
188// connect(port, [host], [cb])
189// connect(path, [cb]);
190//
191function connect(...args) {
192  const normalized = normalizeArgs(args);
193  const options = normalized[0];
194  debug('createConnection', normalized);
195  const socket = new Socket(options);
196
197  if (options.timeout) {
198    socket.setTimeout(options.timeout);
199  }
200
201  return socket.connect(normalized);
202}
203
204
205// Returns an array [options, cb], where options is an object,
206// cb is either a function or null.
207// Used to normalize arguments of Socket.prototype.connect() and
208// Server.prototype.listen(). Possible combinations of parameters:
209//   (options[...][, cb])
210//   (path[...][, cb])
211//   ([port][, host][...][, cb])
212// For Socket.prototype.connect(), the [...] part is ignored
213// For Server.prototype.listen(), the [...] part is [, backlog]
214// but will not be handled here (handled in listen())
215function normalizeArgs(args) {
216  let arr;
217
218  if (args.length === 0) {
219    arr = [{}, null];
220    arr[normalizedArgsSymbol] = true;
221    return arr;
222  }
223
224  const arg0 = args[0];
225  let options = {};
226  if (typeof arg0 === 'object' && arg0 !== null) {
227    // (options[...][, cb])
228    options = arg0;
229  } else if (isPipeName(arg0)) {
230    // (path[...][, cb])
231    options.path = arg0;
232  } else {
233    // ([port][, host][...][, cb])
234    options.port = arg0;
235    if (args.length > 1 && typeof args[1] === 'string') {
236      options.host = args[1];
237    }
238  }
239
240  const cb = args[args.length - 1];
241  if (typeof cb !== 'function')
242    arr = [options, null];
243  else
244    arr = [options, cb];
245
246  arr[normalizedArgsSymbol] = true;
247  return arr;
248}
249
250
251// Called when creating new Socket, or when re-using a closed Socket
252function initSocketHandle(self) {
253  self._undestroy();
254  self._sockname = null;
255
256  // Handle creation may be deferred to bind() or connect() time.
257  if (self._handle) {
258    self._handle[owner_symbol] = self;
259    self._handle.onread = onStreamRead;
260    self[async_id_symbol] = getNewAsyncId(self._handle);
261
262    let userBuf = self[kBuffer];
263    if (userBuf) {
264      const bufGen = self[kBufferGen];
265      if (bufGen !== null) {
266        userBuf = bufGen();
267        if (!isUint8Array(userBuf))
268          return;
269        self[kBuffer] = userBuf;
270      }
271      self._handle.useUserBuffer(userBuf);
272    }
273  }
274}
275
276
277const kBytesRead = Symbol('kBytesRead');
278const kBytesWritten = Symbol('kBytesWritten');
279const kSetNoDelay = Symbol('kSetNoDelay');
280
281function Socket(options) {
282  if (!(this instanceof Socket)) return new Socket(options);
283
284  this.connecting = false;
285  // Problem with this is that users can supply their own handle, that may not
286  // have _handle.getAsyncId(). In this case an[async_id_symbol] should
287  // probably be supplied by async_hooks.
288  this[async_id_symbol] = -1;
289  this._hadError = false;
290  this[kHandle] = null;
291  this._parent = null;
292  this._host = null;
293  this[kSetNoDelay] = false;
294  this[kLastWriteQueueSize] = 0;
295  this[kTimeout] = null;
296  this[kBuffer] = null;
297  this[kBufferCb] = null;
298  this[kBufferGen] = null;
299
300  if (typeof options === 'number')
301    options = { fd: options }; // Legacy interface.
302  else
303    options = { ...options };
304
305  const { allowHalfOpen } = options;
306
307  // Prevent the "no-half-open enforcer" from being inherited from `Duplex`.
308  options.allowHalfOpen = true;
309  // For backwards compat do not emit close on destroy.
310  options.emitClose = false;
311  options.autoDestroy = false;
312  // Handle strings directly.
313  options.decodeStrings = false;
314  stream.Duplex.call(this, options);
315
316  // Default to *not* allowing half open sockets.
317  this.allowHalfOpen = Boolean(allowHalfOpen);
318
319  if (options.handle) {
320    this._handle = options.handle; // private
321    this[async_id_symbol] = getNewAsyncId(this._handle);
322  } else if (options.fd !== undefined) {
323    const { fd } = options;
324    let err;
325
326    // createHandle will throw ERR_INVALID_FD_TYPE if `fd` is not
327    // a valid `PIPE` or `TCP` descriptor
328    this._handle = createHandle(fd, false);
329
330    err = this._handle.open(fd);
331
332    // While difficult to fabricate, in some architectures
333    // `open` may return an error code for valid file descriptors
334    // which cannot be opened. This is difficult to test as most
335    // un-openable fds will throw on `createHandle`
336    if (err)
337      throw errnoException(err, 'open');
338
339    this[async_id_symbol] = this._handle.getAsyncId();
340
341    if ((fd === 1 || fd === 2) &&
342        (this._handle instanceof Pipe) && isWindows) {
343      // Make stdout and stderr blocking on Windows
344      err = this._handle.setBlocking(true);
345      if (err)
346        throw errnoException(err, 'setBlocking');
347
348      this._writev = null;
349      this._write = makeSyncWrite(fd);
350      // makeSyncWrite adjusts this value like the original handle would, so
351      // we need to let it do that by turning it into a writable, own
352      // property.
353      ObjectDefineProperty(this._handle, 'bytesWritten', {
354        value: 0, writable: true
355      });
356    }
357  }
358
359  const onread = options.onread;
360  if (onread !== null && typeof onread === 'object' &&
361      (isUint8Array(onread.buffer) || typeof onread.buffer === 'function') &&
362      typeof onread.callback === 'function') {
363    if (typeof onread.buffer === 'function') {
364      this[kBuffer] = true;
365      this[kBufferGen] = onread.buffer;
366    } else {
367      this[kBuffer] = onread.buffer;
368    }
369    this[kBufferCb] = onread.callback;
370  }
371
372  // Shut down the socket when we're finished with it.
373  this.on('end', onReadableStreamEnd);
374
375  initSocketHandle(this);
376
377  this._pendingData = null;
378  this._pendingEncoding = '';
379
380  // If we have a handle, then start the flow of data into the
381  // buffer.  if not, then this will happen when we connect
382  if (this._handle && options.readable !== false) {
383    if (options.pauseOnCreate) {
384      // Stop the handle from reading and pause the stream
385      this._handle.reading = false;
386      this._handle.readStop();
387      this.readableFlowing = false;
388    } else if (!options.manualStart) {
389      this.read(0);
390    }
391  }
392
393  // Reserve properties
394  this.server = null;
395  this._server = null;
396
397  // Used after `.destroy()`
398  this[kBytesRead] = 0;
399  this[kBytesWritten] = 0;
400}
401ObjectSetPrototypeOf(Socket.prototype, stream.Duplex.prototype);
402ObjectSetPrototypeOf(Socket, stream.Duplex);
403
404// Refresh existing timeouts.
405Socket.prototype._unrefTimer = function _unrefTimer() {
406  for (let s = this; s !== null; s = s._parent) {
407    if (s[kTimeout])
408      s[kTimeout].refresh();
409  }
410};
411
412
413// The user has called .end(), and all the bytes have been
414// sent out to the other side.
415Socket.prototype._final = function(cb) {
416  // If still connecting - defer handling `_final` until 'connect' will happen
417  if (this.pending) {
418    debug('_final: not yet connected');
419    return this.once('connect', () => this._final(cb));
420  }
421
422  if (!this._handle)
423    return cb();
424
425  debug('_final: not ended, call shutdown()');
426
427  const req = new ShutdownWrap();
428  req.oncomplete = afterShutdown;
429  req.handle = this._handle;
430  req.callback = cb;
431  const err = this._handle.shutdown(req);
432
433  if (err === 1 || err === UV_ENOTCONN)  // synchronous finish
434    return afterShutdown.call(req, 0);
435  else if (err !== 0)
436    return this.destroy(errnoException(err, 'shutdown'));
437};
438
439
440function afterShutdown(status) {
441  const self = this.handle[owner_symbol];
442
443  debug('afterShutdown destroyed=%j', self.destroyed,
444        self._readableState);
445
446  this.callback();
447
448  // Callback may come after call to destroy.
449  if (self.destroyed)
450    return;
451
452  if (!self.readable || self.readableEnded) {
453    debug('readableState ended, destroying');
454    self.destroy();
455  }
456}
457
458// Provide a better error message when we call end() as a result
459// of the other side sending a FIN.  The standard 'write after end'
460// is overly vague, and makes it seem like the user's code is to blame.
461function writeAfterFIN(chunk, encoding, cb) {
462  if (typeof encoding === 'function') {
463    cb = encoding;
464    encoding = null;
465  }
466
467  // eslint-disable-next-line no-restricted-syntax
468  const er = new Error('This socket has been ended by the other party');
469  er.code = 'EPIPE';
470  process.nextTick(emitErrorNT, this, er);
471  if (typeof cb === 'function') {
472    defaultTriggerAsyncIdScope(this[async_id_symbol], process.nextTick, cb, er);
473  }
474
475  return false;
476}
477
478Socket.prototype.setTimeout = setStreamTimeout;
479
480
481Socket.prototype._onTimeout = function() {
482  const handle = this._handle;
483  const lastWriteQueueSize = this[kLastWriteQueueSize];
484  if (lastWriteQueueSize > 0 && handle) {
485    // `lastWriteQueueSize !== writeQueueSize` means there is
486    // an active write in progress, so we suppress the timeout.
487    const { writeQueueSize } = handle;
488    if (lastWriteQueueSize !== writeQueueSize) {
489      this[kLastWriteQueueSize] = writeQueueSize;
490      this._unrefTimer();
491      return;
492    }
493  }
494  debug('_onTimeout');
495  this.emit('timeout');
496};
497
498
499Socket.prototype.setNoDelay = function(enable) {
500  if (!this._handle) {
501    this.once('connect',
502              enable ? this.setNoDelay : () => this.setNoDelay(enable));
503    return this;
504  }
505
506  // Backwards compatibility: assume true when `enable` is omitted
507  const newValue = enable === undefined ? true : !!enable;
508  if (this._handle.setNoDelay && newValue !== this[kSetNoDelay]) {
509    this[kSetNoDelay] = newValue;
510    this._handle.setNoDelay(newValue);
511  }
512
513  return this;
514};
515
516
517Socket.prototype.setKeepAlive = function(setting, msecs) {
518  if (!this._handle) {
519    this.once('connect', () => this.setKeepAlive(setting, msecs));
520    return this;
521  }
522
523  if (this._handle.setKeepAlive)
524    this._handle.setKeepAlive(setting, ~~(msecs / 1000));
525
526  return this;
527};
528
529
530Socket.prototype.address = function() {
531  return this._getsockname();
532};
533
534
535ObjectDefineProperty(Socket.prototype, '_connecting', {
536  get: function() {
537    return this.connecting;
538  }
539});
540
541ObjectDefineProperty(Socket.prototype, 'pending', {
542  get() {
543    return !this._handle || this.connecting;
544  },
545  configurable: true
546});
547
548
549ObjectDefineProperty(Socket.prototype, 'readyState', {
550  get: function() {
551    if (this.connecting) {
552      return 'opening';
553    } else if (this.readable && this.writable) {
554      return 'open';
555    } else if (this.readable && !this.writable) {
556      return 'readOnly';
557    } else if (!this.readable && this.writable) {
558      return 'writeOnly';
559    }
560    return 'closed';
561  }
562});
563
564
565ObjectDefineProperty(Socket.prototype, 'bufferSize', {
566  get: function() {
567    if (this._handle) {
568      return this.writableLength;
569    }
570  }
571});
572
573ObjectDefineProperty(Socket.prototype, kUpdateTimer, {
574  get: function() {
575    return this._unrefTimer;
576  }
577});
578
579
580function tryReadStart(socket) {
581  // Not already reading, start the flow
582  debug('Socket._handle.readStart');
583  socket._handle.reading = true;
584  const err = socket._handle.readStart();
585  if (err)
586    socket.destroy(errnoException(err, 'read'));
587}
588
589// Just call handle.readStart until we have enough in the buffer
590Socket.prototype._read = function(n) {
591  debug('_read');
592
593  if (this.connecting || !this._handle) {
594    debug('_read wait for connection');
595    this.once('connect', () => this._read(n));
596  } else if (!this._handle.reading) {
597    tryReadStart(this);
598  }
599};
600
601
602Socket.prototype.end = function(data, encoding, callback) {
603  stream.Duplex.prototype.end.call(this,
604                                   data, encoding, callback);
605  DTRACE_NET_STREAM_END(this);
606  return this;
607};
608
609
610Socket.prototype.pause = function() {
611  if (this[kBuffer] && !this.connecting && this._handle &&
612      this._handle.reading) {
613    this._handle.reading = false;
614    if (!this.destroyed) {
615      const err = this._handle.readStop();
616      if (err)
617        this.destroy(errnoException(err, 'read'));
618    }
619  }
620  return stream.Duplex.prototype.pause.call(this);
621};
622
623
624Socket.prototype.resume = function() {
625  if (this[kBuffer] && !this.connecting && this._handle &&
626      !this._handle.reading) {
627    tryReadStart(this);
628  }
629  return stream.Duplex.prototype.resume.call(this);
630};
631
632
633Socket.prototype.read = function(n) {
634  if (this[kBuffer] && !this.connecting && this._handle &&
635      !this._handle.reading) {
636    tryReadStart(this);
637  }
638  return stream.Duplex.prototype.read.call(this, n);
639};
640
641
642// Called when the 'end' event is emitted.
643function onReadableStreamEnd() {
644  if (!this.allowHalfOpen) {
645    this.write = writeAfterFIN;
646    if (this.writable)
647      this.end();
648    else if (!this.writableLength)
649      this.destroy();
650  } else if (!this.destroyed && !this.writable && !this.writableLength)
651    this.destroy();
652}
653
654
655Socket.prototype.destroySoon = function() {
656  if (this.writable)
657    this.end();
658
659  if (this.writableFinished)
660    this.destroy();
661  else
662    this.once('finish', this.destroy);
663};
664
665
666Socket.prototype._destroy = function(exception, cb) {
667  debug('destroy');
668
669  this.connecting = false;
670
671  for (let s = this; s !== null; s = s._parent) {
672    clearTimeout(s[kTimeout]);
673  }
674
675  debug('close');
676  if (this._handle) {
677    if (this !== process.stderr)
678      debug('close handle');
679    const isException = exception ? true : false;
680    // `bytesRead` and `kBytesWritten` should be accessible after `.destroy()`
681    this[kBytesRead] = this._handle.bytesRead;
682    this[kBytesWritten] = this._handle.bytesWritten;
683
684    this._handle.close(() => {
685      debug('emit close');
686      this.emit('close', isException);
687    });
688    this._handle.onread = noop;
689    this._handle = null;
690    this._sockname = null;
691    cb(exception);
692  } else {
693    cb(exception);
694    process.nextTick(emitCloseNT, this);
695  }
696
697  if (this._server) {
698    debug('has server');
699    this._server._connections--;
700    if (this._server._emitCloseIfDrained) {
701      this._server._emitCloseIfDrained();
702    }
703  }
704};
705
706Socket.prototype._getpeername = function() {
707  if (!this._peername) {
708    if (!this._handle || !this._handle.getpeername) {
709      return {};
710    }
711    const out = {};
712    const err = this._handle.getpeername(out);
713    if (err) return {};  // FIXME(bnoordhuis) Throw?
714    this._peername = out;
715  }
716  return this._peername;
717};
718
719function protoGetter(name, callback) {
720  ObjectDefineProperty(Socket.prototype, name, {
721    configurable: false,
722    enumerable: true,
723    get: callback
724  });
725}
726
727protoGetter('bytesRead', function bytesRead() {
728  return this._handle ? this._handle.bytesRead : this[kBytesRead];
729});
730
731protoGetter('remoteAddress', function remoteAddress() {
732  return this._getpeername().address;
733});
734
735protoGetter('remoteFamily', function remoteFamily() {
736  return this._getpeername().family;
737});
738
739protoGetter('remotePort', function remotePort() {
740  return this._getpeername().port;
741});
742
743
744Socket.prototype._getsockname = function() {
745  if (!this._handle || !this._handle.getsockname) {
746    return {};
747  }
748  if (!this._sockname) {
749    const out = {};
750    const err = this._handle.getsockname(out);
751    if (err) return {};  // FIXME(bnoordhuis) Throw?
752    this._sockname = out;
753  }
754  return this._sockname;
755};
756
757
758protoGetter('localAddress', function localAddress() {
759  return this._getsockname().address;
760});
761
762
763protoGetter('localPort', function localPort() {
764  return this._getsockname().port;
765});
766
767
768Socket.prototype[kAfterAsyncWrite] = function() {
769  this[kLastWriteQueueSize] = 0;
770};
771
772Socket.prototype._writeGeneric = function(writev, data, encoding, cb) {
773  // If we are still connecting, then buffer this for later.
774  // The Writable logic will buffer up any more writes while
775  // waiting for this one to be done.
776  if (this.connecting) {
777    this._pendingData = data;
778    this._pendingEncoding = encoding;
779    this.once('connect', function connect() {
780      this._writeGeneric(writev, data, encoding, cb);
781    });
782    return;
783  }
784  this._pendingData = null;
785  this._pendingEncoding = '';
786
787  if (!this._handle) {
788    cb(new ERR_SOCKET_CLOSED());
789    return false;
790  }
791
792  this._unrefTimer();
793
794  let req;
795  if (writev)
796    req = writevGeneric(this, data, cb);
797  else
798    req = writeGeneric(this, data, encoding, cb);
799  if (req.async)
800    this[kLastWriteQueueSize] = req.bytes;
801};
802
803
804Socket.prototype._writev = function(chunks, cb) {
805  this._writeGeneric(true, chunks, '', cb);
806};
807
808
809Socket.prototype._write = function(data, encoding, cb) {
810  this._writeGeneric(false, data, encoding, cb);
811};
812
813
814// Legacy alias. Having this is probably being overly cautious, but it doesn't
815// really hurt anyone either. This can probably be removed safely if desired.
816protoGetter('_bytesDispatched', function _bytesDispatched() {
817  return this._handle ? this._handle.bytesWritten : this[kBytesWritten];
818});
819
820protoGetter('bytesWritten', function bytesWritten() {
821  let bytes = this._bytesDispatched;
822  const data = this._pendingData;
823  const encoding = this._pendingEncoding;
824  const writableBuffer = this.writableBuffer;
825
826  if (!writableBuffer)
827    return undefined;
828
829  for (const el of writableBuffer) {
830    bytes += el.chunk instanceof Buffer ?
831      el.chunk.length :
832      Buffer.byteLength(el.chunk, el.encoding);
833  }
834
835  if (ArrayIsArray(data)) {
836    // Was a writev, iterate over chunks to get total length
837    for (let i = 0; i < data.length; i++) {
838      const chunk = data[i];
839
840      if (data.allBuffers || chunk instanceof Buffer)
841        bytes += chunk.length;
842      else
843        bytes += Buffer.byteLength(chunk.chunk, chunk.encoding);
844    }
845  } else if (data) {
846    // Writes are either a string or a Buffer.
847    if (typeof data !== 'string')
848      bytes += data.length;
849    else
850      bytes += Buffer.byteLength(data, encoding);
851  }
852
853  return bytes;
854});
855
856
857function checkBindError(err, port, handle) {
858  // EADDRINUSE may not be reported until we call listen() or connect().
859  // To complicate matters, a failed bind() followed by listen() or connect()
860  // will implicitly bind to a random port. Ergo, check that the socket is
861  // bound to the expected port before calling listen() or connect().
862  //
863  // FIXME(bnoordhuis) Doesn't work for pipe handles, they don't have a
864  // getsockname() method. Non-issue for now, the cluster module doesn't
865  // really support pipes anyway.
866  if (err === 0 && port > 0 && handle.getsockname) {
867    const out = {};
868    err = handle.getsockname(out);
869    if (err === 0 && port !== out.port) {
870      debug(`checkBindError, bound to ${out.port} instead of ${port}`);
871      err = UV_EADDRINUSE;
872    }
873  }
874  return err;
875}
876
877
878function internalConnect(
879  self, address, port, addressType, localAddress, localPort, flags) {
880  // TODO return promise from Socket.prototype.connect which
881  // wraps _connectReq.
882
883  assert(self.connecting);
884
885  let err;
886
887  if (localAddress || localPort) {
888    if (addressType === 4) {
889      localAddress = localAddress || DEFAULT_IPV4_ADDR;
890      err = self._handle.bind(localAddress, localPort);
891    } else { // addressType === 6
892      localAddress = localAddress || DEFAULT_IPV6_ADDR;
893      err = self._handle.bind6(localAddress, localPort, flags);
894    }
895    debug('binding to localAddress: %s and localPort: %d (addressType: %d)',
896          localAddress, localPort, addressType);
897
898    err = checkBindError(err, localPort, self._handle);
899    if (err) {
900      const ex = exceptionWithHostPort(err, 'bind', localAddress, localPort);
901      self.destroy(ex);
902      return;
903    }
904  }
905
906  if (addressType === 6 || addressType === 4) {
907    const req = new TCPConnectWrap();
908    req.oncomplete = afterConnect;
909    req.address = address;
910    req.port = port;
911    req.localAddress = localAddress;
912    req.localPort = localPort;
913
914    if (addressType === 4)
915      err = self._handle.connect(req, address, port);
916    else
917      err = self._handle.connect6(req, address, port);
918  } else {
919    const req = new PipeConnectWrap();
920    req.address = address;
921    req.oncomplete = afterConnect;
922
923    err = self._handle.connect(req, address, afterConnect);
924  }
925
926  if (err) {
927    const sockname = self._getsockname();
928    let details;
929
930    if (sockname) {
931      details = sockname.address + ':' + sockname.port;
932    }
933
934    const ex = exceptionWithHostPort(err, 'connect', address, port, details);
935    self.destroy(ex);
936  }
937}
938
939
940Socket.prototype.connect = function(...args) {
941  let normalized;
942  // If passed an array, it's treated as an array of arguments that have
943  // already been normalized (so we don't normalize more than once). This has
944  // been solved before in https://github.com/nodejs/node/pull/12342, but was
945  // reverted as it had unintended side effects.
946  if (ArrayIsArray(args[0]) && args[0][normalizedArgsSymbol]) {
947    normalized = args[0];
948  } else {
949    normalized = normalizeArgs(args);
950  }
951  const options = normalized[0];
952  const cb = normalized[1];
953
954  if (this.write !== Socket.prototype.write)
955    this.write = Socket.prototype.write;
956
957  if (this.destroyed) {
958    this._handle = null;
959    this._peername = null;
960    this._sockname = null;
961  }
962
963  const { path } = options;
964  const pipe = !!path;
965  debug('pipe', pipe, path);
966
967  if (!this._handle) {
968    this._handle = pipe ?
969      new Pipe(PipeConstants.SOCKET) :
970      new TCP(TCPConstants.SOCKET);
971    initSocketHandle(this);
972  }
973
974  if (cb !== null) {
975    this.once('connect', cb);
976  }
977
978  this._unrefTimer();
979
980  this.connecting = true;
981  this.writable = true;
982
983  if (pipe) {
984    validateString(path, 'options.path');
985    defaultTriggerAsyncIdScope(
986      this[async_id_symbol], internalConnect, this, path
987    );
988  } else {
989    lookupAndConnect(this, options);
990  }
991  return this;
992};
993
994
995function lookupAndConnect(self, options) {
996  const { localAddress, localPort } = options;
997  const host = options.host || 'localhost';
998  let { port } = options;
999
1000  if (localAddress && !isIP(localAddress)) {
1001    throw new ERR_INVALID_IP_ADDRESS(localAddress);
1002  }
1003
1004  if (localPort && typeof localPort !== 'number') {
1005    throw new ERR_INVALID_ARG_TYPE('options.localPort', 'number', localPort);
1006  }
1007
1008  if (typeof port !== 'undefined') {
1009    if (typeof port !== 'number' && typeof port !== 'string') {
1010      throw new ERR_INVALID_ARG_TYPE('options.port',
1011                                     ['number', 'string'], port);
1012    }
1013    validatePort(port);
1014  }
1015  port |= 0;
1016
1017  // If host is an IP, skip performing a lookup
1018  const addressType = isIP(host);
1019  if (addressType) {
1020    defaultTriggerAsyncIdScope(self[async_id_symbol], process.nextTick, () => {
1021      if (self.connecting)
1022        defaultTriggerAsyncIdScope(
1023          self[async_id_symbol],
1024          internalConnect,
1025          self, host, port, addressType, localAddress, localPort
1026        );
1027    });
1028    return;
1029  }
1030
1031  if (options.lookup && typeof options.lookup !== 'function')
1032    throw new ERR_INVALID_ARG_TYPE('options.lookup',
1033                                   'Function', options.lookup);
1034
1035
1036  if (dns === undefined) dns = require('dns');
1037  const dnsopts = {
1038    family: options.family,
1039    hints: options.hints || 0
1040  };
1041
1042  if (!isWindows &&
1043      dnsopts.family !== 4 &&
1044      dnsopts.family !== 6 &&
1045      dnsopts.hints === 0) {
1046    dnsopts.hints = dns.ADDRCONFIG;
1047  }
1048
1049  debug('connect: find host', host);
1050  debug('connect: dns options', dnsopts);
1051  self._host = host;
1052  const lookup = options.lookup || dns.lookup;
1053  defaultTriggerAsyncIdScope(self[async_id_symbol], function() {
1054    lookup(host, dnsopts, function emitLookup(err, ip, addressType) {
1055      self.emit('lookup', err, ip, addressType, host);
1056
1057      // It's possible we were destroyed while looking this up.
1058      // XXX it would be great if we could cancel the promise returned by
1059      // the look up.
1060      if (!self.connecting) return;
1061
1062      if (err) {
1063        // net.createConnection() creates a net.Socket object and immediately
1064        // calls net.Socket.connect() on it (that's us). There are no event
1065        // listeners registered yet so defer the error event to the next tick.
1066        process.nextTick(connectErrorNT, self, err);
1067      } else if (!isIP(ip)) {
1068        err = new ERR_INVALID_IP_ADDRESS(ip);
1069        process.nextTick(connectErrorNT, self, err);
1070      } else if (addressType !== 4 && addressType !== 6) {
1071        err = new ERR_INVALID_ADDRESS_FAMILY(addressType,
1072                                             options.host,
1073                                             options.port);
1074        process.nextTick(connectErrorNT, self, err);
1075      } else {
1076        self._unrefTimer();
1077        defaultTriggerAsyncIdScope(
1078          self[async_id_symbol],
1079          internalConnect,
1080          self, ip, port, addressType, localAddress, localPort
1081        );
1082      }
1083    });
1084  });
1085}
1086
1087
1088function connectErrorNT(self, err) {
1089  self.destroy(err);
1090}
1091
1092
1093Socket.prototype.ref = function() {
1094  if (!this._handle) {
1095    this.once('connect', this.ref);
1096    return this;
1097  }
1098
1099  if (typeof this._handle.ref === 'function') {
1100    this._handle.ref();
1101  }
1102
1103  return this;
1104};
1105
1106
1107Socket.prototype.unref = function() {
1108  if (!this._handle) {
1109    this.once('connect', this.unref);
1110    return this;
1111  }
1112
1113  if (typeof this._handle.unref === 'function') {
1114    this._handle.unref();
1115  }
1116
1117  return this;
1118};
1119
1120
1121function afterConnect(status, handle, req, readable, writable) {
1122  const self = handle[owner_symbol];
1123
1124  // Callback may come after call to destroy
1125  if (self.destroyed) {
1126    return;
1127  }
1128
1129  debug('afterConnect');
1130
1131  assert(self.connecting);
1132  self.connecting = false;
1133  self._sockname = null;
1134
1135  if (status === 0) {
1136    if (self.readable && !readable) {
1137      self.push(null);
1138      self.read();
1139    }
1140    if (self.writable && !writable) {
1141      self.end();
1142    }
1143    self._unrefTimer();
1144
1145    self.emit('connect');
1146    self.emit('ready');
1147
1148    // Start the first read, or get an immediate EOF.
1149    // this doesn't actually consume any bytes, because len=0.
1150    if (readable && !self.isPaused())
1151      self.read(0);
1152
1153  } else {
1154    self.connecting = false;
1155    let details;
1156    if (req.localAddress && req.localPort) {
1157      details = req.localAddress + ':' + req.localPort;
1158    }
1159    const ex = exceptionWithHostPort(status,
1160                                     'connect',
1161                                     req.address,
1162                                     req.port,
1163                                     details);
1164    if (details) {
1165      ex.localAddress = req.localAddress;
1166      ex.localPort = req.localPort;
1167    }
1168    self.destroy(ex);
1169  }
1170}
1171
1172
1173function Server(options, connectionListener) {
1174  if (!(this instanceof Server))
1175    return new Server(options, connectionListener);
1176
1177  EventEmitter.call(this);
1178
1179  if (typeof options === 'function') {
1180    connectionListener = options;
1181    options = {};
1182    this.on('connection', connectionListener);
1183  } else if (options == null || typeof options === 'object') {
1184    options = { ...options };
1185
1186    if (typeof connectionListener === 'function') {
1187      this.on('connection', connectionListener);
1188    }
1189  } else {
1190    throw new ERR_INVALID_ARG_TYPE('options', 'Object', options);
1191  }
1192
1193  this._connections = 0;
1194
1195  ObjectDefineProperty(this, 'connections', {
1196    get: deprecate(() => {
1197
1198      if (this._usingWorkers) {
1199        return null;
1200      }
1201      return this._connections;
1202    }, 'Server.connections property is deprecated. ' +
1203       'Use Server.getConnections method instead.', 'DEP0020'),
1204    set: deprecate((val) => (this._connections = val),
1205                   'Server.connections property is deprecated.',
1206                   'DEP0020'),
1207    configurable: true, enumerable: false
1208  });
1209
1210  this[async_id_symbol] = -1;
1211  this._handle = null;
1212  this._usingWorkers = false;
1213  this._workers = [];
1214  this._unref = false;
1215
1216  this.allowHalfOpen = options.allowHalfOpen || false;
1217  this.pauseOnConnect = !!options.pauseOnConnect;
1218}
1219ObjectSetPrototypeOf(Server.prototype, EventEmitter.prototype);
1220ObjectSetPrototypeOf(Server, EventEmitter);
1221
1222
1223function toNumber(x) { return (x = Number(x)) >= 0 ? x : false; }
1224
1225// Returns handle if it can be created, or error code if it can't
1226function createServerHandle(address, port, addressType, fd, flags) {
1227  let err = 0;
1228  // Assign handle in listen, and clean up if bind or listen fails
1229  let handle;
1230
1231  let isTCP = false;
1232  if (typeof fd === 'number' && fd >= 0) {
1233    try {
1234      handle = createHandle(fd, true);
1235    } catch (e) {
1236      // Not a fd we can listen on.  This will trigger an error.
1237      debug('listen invalid fd=%d:', fd, e.message);
1238      return UV_EINVAL;
1239    }
1240
1241    err = handle.open(fd);
1242    if (err)
1243      return err;
1244
1245    assert(!address && !port);
1246  } else if (port === -1 && addressType === -1) {
1247    handle = new Pipe(PipeConstants.SERVER);
1248    if (isWindows) {
1249      const instances = NumberParseInt(process.env.NODE_PENDING_PIPE_INSTANCES);
1250      if (!NumberIsNaN(instances)) {
1251        handle.setPendingInstances(instances);
1252      }
1253    }
1254  } else {
1255    handle = new TCP(TCPConstants.SERVER);
1256    isTCP = true;
1257  }
1258
1259  if (address || port || isTCP) {
1260    debug('bind to', address || 'any');
1261    if (!address) {
1262      // Try binding to ipv6 first
1263      err = handle.bind6(DEFAULT_IPV6_ADDR, port, flags);
1264      if (err) {
1265        handle.close();
1266        // Fallback to ipv4
1267        return createServerHandle(DEFAULT_IPV4_ADDR, port);
1268      }
1269    } else if (addressType === 6) {
1270      err = handle.bind6(address, port, flags);
1271    } else {
1272      err = handle.bind(address, port);
1273    }
1274  }
1275
1276  if (err) {
1277    handle.close();
1278    return err;
1279  }
1280
1281  return handle;
1282}
1283
1284function setupListenHandle(address, port, addressType, backlog, fd, flags) {
1285  debug('setupListenHandle', address, port, addressType, backlog, fd);
1286
1287  // If there is not yet a handle, we need to create one and bind.
1288  // In the case of a server sent via IPC, we don't need to do this.
1289  if (this._handle) {
1290    debug('setupListenHandle: have a handle already');
1291  } else {
1292    debug('setupListenHandle: create a handle');
1293
1294    let rval = null;
1295
1296    // Try to bind to the unspecified IPv6 address, see if IPv6 is available
1297    if (!address && typeof fd !== 'number') {
1298      rval = createServerHandle(DEFAULT_IPV6_ADDR, port, 6, fd, flags);
1299
1300      if (typeof rval === 'number') {
1301        rval = null;
1302        address = DEFAULT_IPV4_ADDR;
1303        addressType = 4;
1304      } else {
1305        address = DEFAULT_IPV6_ADDR;
1306        addressType = 6;
1307      }
1308    }
1309
1310    if (rval === null)
1311      rval = createServerHandle(address, port, addressType, fd, flags);
1312
1313    if (typeof rval === 'number') {
1314      const error = uvExceptionWithHostPort(rval, 'listen', address, port);
1315      process.nextTick(emitErrorNT, this, error);
1316      return;
1317    }
1318    this._handle = rval;
1319  }
1320
1321  this[async_id_symbol] = getNewAsyncId(this._handle);
1322  this._handle.onconnection = onconnection;
1323  this._handle[owner_symbol] = this;
1324
1325  // Use a backlog of 512 entries. We pass 511 to the listen() call because
1326  // the kernel does: backlogsize = roundup_pow_of_two(backlogsize + 1);
1327  // which will thus give us a backlog of 512 entries.
1328  const err = this._handle.listen(backlog || 511);
1329
1330  if (err) {
1331    const ex = uvExceptionWithHostPort(err, 'listen', address, port);
1332    this._handle.close();
1333    this._handle = null;
1334    defaultTriggerAsyncIdScope(this[async_id_symbol],
1335                               process.nextTick,
1336                               emitErrorNT,
1337                               this,
1338                               ex);
1339    return;
1340  }
1341
1342  // Generate connection key, this should be unique to the connection
1343  this._connectionKey = addressType + ':' + address + ':' + port;
1344
1345  // Unref the handle if the server was unref'ed prior to listening
1346  if (this._unref)
1347    this.unref();
1348
1349  defaultTriggerAsyncIdScope(this[async_id_symbol],
1350                             process.nextTick,
1351                             emitListeningNT,
1352                             this);
1353}
1354
1355Server.prototype._listen2 = setupListenHandle;  // legacy alias
1356
1357function emitErrorNT(self, err) {
1358  self.emit('error', err);
1359}
1360
1361
1362function emitListeningNT(self) {
1363  // Ensure handle hasn't closed
1364  if (self._handle)
1365    self.emit('listening');
1366}
1367
1368
1369function listenInCluster(server, address, port, addressType,
1370                         backlog, fd, exclusive, flags) {
1371  exclusive = !!exclusive;
1372
1373  if (cluster === undefined) cluster = require('cluster');
1374
1375  if (cluster.isMaster || exclusive) {
1376    // Will create a new handle
1377    // _listen2 sets up the listened handle, it is still named like this
1378    // to avoid breaking code that wraps this method
1379    server._listen2(address, port, addressType, backlog, fd, flags);
1380    return;
1381  }
1382
1383  const serverQuery = {
1384    address: address,
1385    port: port,
1386    addressType: addressType,
1387    fd: fd,
1388    flags,
1389  };
1390
1391  // Get the master's server handle, and listen on it
1392  cluster._getServer(server, serverQuery, listenOnMasterHandle);
1393
1394  function listenOnMasterHandle(err, handle) {
1395    err = checkBindError(err, port, handle);
1396
1397    if (err) {
1398      const ex = exceptionWithHostPort(err, 'bind', address, port);
1399      return server.emit('error', ex);
1400    }
1401
1402    // Reuse master's server handle
1403    server._handle = handle;
1404    // _listen2 sets up the listened handle, it is still named like this
1405    // to avoid breaking code that wraps this method
1406    server._listen2(address, port, addressType, backlog, fd, flags);
1407  }
1408}
1409
1410
1411Server.prototype.listen = function(...args) {
1412  const normalized = normalizeArgs(args);
1413  let options = normalized[0];
1414  const cb = normalized[1];
1415
1416  if (this._handle) {
1417    throw new ERR_SERVER_ALREADY_LISTEN();
1418  }
1419
1420  if (cb !== null) {
1421    this.once('listening', cb);
1422  }
1423  const backlogFromArgs =
1424    // (handle, backlog) or (path, backlog) or (port, backlog)
1425    toNumber(args.length > 1 && args[1]) ||
1426    toNumber(args.length > 2 && args[2]);  // (port, host, backlog)
1427
1428  options = options._handle || options.handle || options;
1429  const flags = getFlags(options.ipv6Only);
1430  // (handle[, backlog][, cb]) where handle is an object with a handle
1431  if (options instanceof TCP) {
1432    this._handle = options;
1433    this[async_id_symbol] = this._handle.getAsyncId();
1434    listenInCluster(this, null, -1, -1, backlogFromArgs);
1435    return this;
1436  }
1437  // (handle[, backlog][, cb]) where handle is an object with a fd
1438  if (typeof options.fd === 'number' && options.fd >= 0) {
1439    listenInCluster(this, null, null, null, backlogFromArgs, options.fd);
1440    return this;
1441  }
1442
1443  // ([port][, host][, backlog][, cb]) where port is omitted,
1444  // that is, listen(), listen(null), listen(cb), or listen(null, cb)
1445  // or (options[, cb]) where options.port is explicitly set as undefined or
1446  // null, bind to an arbitrary unused port
1447  if (args.length === 0 || typeof args[0] === 'function' ||
1448      (typeof options.port === 'undefined' && 'port' in options) ||
1449      options.port === null) {
1450    options.port = 0;
1451  }
1452  // ([port][, host][, backlog][, cb]) where port is specified
1453  // or (options[, cb]) where options.port is specified
1454  // or if options.port is normalized as 0 before
1455  let backlog;
1456  if (typeof options.port === 'number' || typeof options.port === 'string') {
1457    validatePort(options.port, 'options.port');
1458    backlog = options.backlog || backlogFromArgs;
1459    // start TCP server listening on host:port
1460    if (options.host) {
1461      lookupAndListen(this, options.port | 0, options.host, backlog,
1462                      options.exclusive, flags);
1463    } else { // Undefined host, listens on unspecified address
1464      // Default addressType 4 will be used to search for master server
1465      listenInCluster(this, null, options.port | 0, 4,
1466                      backlog, undefined, options.exclusive);
1467    }
1468    return this;
1469  }
1470
1471  // (path[, backlog][, cb]) or (options[, cb])
1472  // where path or options.path is a UNIX domain socket or Windows pipe
1473  if (options.path && isPipeName(options.path)) {
1474    const pipeName = this._pipeName = options.path;
1475    backlog = options.backlog || backlogFromArgs;
1476    listenInCluster(this, pipeName, -1, -1,
1477                    backlog, undefined, options.exclusive);
1478
1479    if (!this._handle) {
1480      // Failed and an error shall be emitted in the next tick.
1481      // Therefore, we directly return.
1482      return this;
1483    }
1484
1485    let mode = 0;
1486    if (options.readableAll === true)
1487      mode |= PipeConstants.UV_READABLE;
1488    if (options.writableAll === true)
1489      mode |= PipeConstants.UV_WRITABLE;
1490    if (mode !== 0) {
1491      const err = this._handle.fchmod(mode);
1492      if (err) {
1493        this._handle.close();
1494        this._handle = null;
1495        throw errnoException(err, 'uv_pipe_chmod');
1496      }
1497    }
1498    return this;
1499  }
1500
1501  if (!(('port' in options) || ('path' in options))) {
1502    throw new ERR_INVALID_ARG_VALUE('options', options,
1503                                    'must have the property "port" or "path"');
1504  }
1505
1506  throw new ERR_INVALID_OPT_VALUE('options', options);
1507};
1508
1509function lookupAndListen(self, port, address, backlog, exclusive, flags) {
1510  if (dns === undefined) dns = require('dns');
1511  dns.lookup(address, function doListen(err, ip, addressType) {
1512    if (err) {
1513      self.emit('error', err);
1514    } else {
1515      addressType = ip ? addressType : 4;
1516      listenInCluster(self, ip, port, addressType,
1517                      backlog, undefined, exclusive, flags);
1518    }
1519  });
1520}
1521
1522ObjectDefineProperty(Server.prototype, 'listening', {
1523  get: function() {
1524    return !!this._handle;
1525  },
1526  configurable: true,
1527  enumerable: true
1528});
1529
1530Server.prototype.address = function() {
1531  if (this._handle && this._handle.getsockname) {
1532    const out = {};
1533    const err = this._handle.getsockname(out);
1534    if (err) {
1535      throw errnoException(err, 'address');
1536    }
1537    return out;
1538  } else if (this._pipeName) {
1539    return this._pipeName;
1540  }
1541  return null;
1542};
1543
1544function onconnection(err, clientHandle) {
1545  const handle = this;
1546  const self = handle[owner_symbol];
1547
1548  debug('onconnection');
1549
1550  if (err) {
1551    self.emit('error', errnoException(err, 'accept'));
1552    return;
1553  }
1554
1555  if (self.maxConnections && self._connections >= self.maxConnections) {
1556    clientHandle.close();
1557    return;
1558  }
1559
1560  const socket = new Socket({
1561    handle: clientHandle,
1562    allowHalfOpen: self.allowHalfOpen,
1563    pauseOnCreate: self.pauseOnConnect,
1564    readable: true,
1565    writable: true
1566  });
1567
1568  self._connections++;
1569  socket.server = self;
1570  socket._server = self;
1571
1572  DTRACE_NET_SERVER_CONNECTION(socket);
1573  self.emit('connection', socket);
1574}
1575
1576/**
1577 * Gets the number of concurrent connections on the server
1578 * @param {Function} cb
1579 * @returns {Server}
1580 */
1581
1582Server.prototype.getConnections = function(cb) {
1583  const self = this;
1584
1585  function end(err, connections) {
1586    defaultTriggerAsyncIdScope(self[async_id_symbol],
1587                               process.nextTick,
1588                               cb,
1589                               err,
1590                               connections);
1591  }
1592
1593  if (!this._usingWorkers) {
1594    end(null, this._connections);
1595    return this;
1596  }
1597
1598  // Poll workers
1599  let left = this._workers.length;
1600  let total = this._connections;
1601
1602  function oncount(err, count) {
1603    if (err) {
1604      left = -1;
1605      return end(err);
1606    }
1607
1608    total += count;
1609    if (--left === 0) return end(null, total);
1610  }
1611
1612  for (let n = 0; n < this._workers.length; n++) {
1613    this._workers[n].getConnections(oncount);
1614  }
1615
1616  return this;
1617};
1618
1619
1620Server.prototype.close = function(cb) {
1621  if (typeof cb === 'function') {
1622    if (!this._handle) {
1623      this.once('close', function close() {
1624        cb(new ERR_SERVER_NOT_RUNNING());
1625      });
1626    } else {
1627      this.once('close', cb);
1628    }
1629  }
1630
1631  if (this._handle) {
1632    this._handle.close();
1633    this._handle = null;
1634  }
1635
1636  if (this._usingWorkers) {
1637    let left = this._workers.length;
1638    const onWorkerClose = () => {
1639      if (--left !== 0) return;
1640
1641      this._connections = 0;
1642      this._emitCloseIfDrained();
1643    };
1644
1645    // Increment connections to be sure that, even if all sockets will be closed
1646    // during polling of workers, `close` event will be emitted only once.
1647    this._connections++;
1648
1649    // Poll workers
1650    for (let n = 0; n < this._workers.length; n++)
1651      this._workers[n].close(onWorkerClose);
1652  } else {
1653    this._emitCloseIfDrained();
1654  }
1655
1656  return this;
1657};
1658
1659Server.prototype._emitCloseIfDrained = function() {
1660  debug('SERVER _emitCloseIfDrained');
1661
1662  if (this._handle || this._connections) {
1663    debug('SERVER handle? %j   connections? %d',
1664          !!this._handle, this._connections);
1665    return;
1666  }
1667
1668  defaultTriggerAsyncIdScope(this[async_id_symbol],
1669                             process.nextTick,
1670                             emitCloseNT,
1671                             this);
1672};
1673
1674
1675function emitCloseNT(self) {
1676  debug('SERVER: emit close');
1677  self.emit('close');
1678}
1679
1680
1681Server.prototype[EventEmitter.captureRejectionSymbol] = function(
1682  err, event, sock) {
1683
1684  switch (event) {
1685    case 'connection':
1686      sock.destroy(err);
1687      break;
1688    default:
1689      this.emit('error', err);
1690  }
1691};
1692
1693
1694// Legacy alias on the C++ wrapper object. This is not public API, so we may
1695// want to runtime-deprecate it at some point. There's no hurry, though.
1696ObjectDefineProperty(TCP.prototype, 'owner', {
1697  get() { return this[owner_symbol]; },
1698  set(v) { return this[owner_symbol] = v; }
1699});
1700
1701ObjectDefineProperty(Socket.prototype, '_handle', {
1702  get() { return this[kHandle]; },
1703  set(v) { return this[kHandle] = v; }
1704});
1705
1706Server.prototype._setupWorker = function(socketList) {
1707  this._usingWorkers = true;
1708  this._workers.push(socketList);
1709  socketList.once('exit', (socketList) => {
1710    const index = ArrayPrototypeIndexOf(this._workers, socketList);
1711    this._workers.splice(index, 1);
1712  });
1713};
1714
1715Server.prototype.ref = function() {
1716  this._unref = false;
1717
1718  if (this._handle)
1719    this._handle.ref();
1720
1721  return this;
1722};
1723
1724Server.prototype.unref = function() {
1725  this._unref = true;
1726
1727  if (this._handle)
1728    this._handle.unref();
1729
1730  return this;
1731};
1732
1733let _setSimultaneousAccepts;
1734let warnSimultaneousAccepts = true;
1735
1736if (isWindows) {
1737  let simultaneousAccepts;
1738
1739  _setSimultaneousAccepts = function(handle) {
1740    if (warnSimultaneousAccepts) {
1741      process.emitWarning(
1742        'net._setSimultaneousAccepts() is deprecated and will be removed.',
1743        'DeprecationWarning', 'DEP0121');
1744      warnSimultaneousAccepts = false;
1745    }
1746    if (handle === undefined) {
1747      return;
1748    }
1749
1750    if (simultaneousAccepts === undefined) {
1751      simultaneousAccepts = (process.env.NODE_MANY_ACCEPTS &&
1752                             process.env.NODE_MANY_ACCEPTS !== '0');
1753    }
1754
1755    if (handle._simultaneousAccepts !== simultaneousAccepts) {
1756      handle.setSimultaneousAccepts(!!simultaneousAccepts);
1757      handle._simultaneousAccepts = simultaneousAccepts;
1758    }
1759  };
1760} else {
1761  _setSimultaneousAccepts = function() {
1762    if (warnSimultaneousAccepts) {
1763      process.emitWarning(
1764        'net._setSimultaneousAccepts() is deprecated and will be removed.',
1765        'DeprecationWarning', 'DEP0121');
1766      warnSimultaneousAccepts = false;
1767    }
1768  };
1769}
1770
1771module.exports = {
1772  _createServerHandle: createServerHandle,
1773  _normalizeArgs: normalizeArgs,
1774  _setSimultaneousAccepts,
1775  get BlockList() {
1776    BlockList = BlockList ?? require('internal/blocklist').BlockList;
1777    return BlockList;
1778  },
1779  get SocketAddress() {
1780    SocketAddress =
1781      SocketAddress ?? require('internal/socketaddress').SocketAddress;
1782    return SocketAddress;
1783  },
1784  connect,
1785  createConnection: connect,
1786  createServer,
1787  isIP: isIP,
1788  isIPv4: isIPv4,
1789  isIPv6: isIPv6,
1790  Server,
1791  Socket,
1792  Stream: Socket, // Legacy naming
1793};
1794