• 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  ArrayPrototypePush,
28  Boolean,
29  FunctionPrototypeBind,
30  FunctionPrototypeCall,
31  MathMax,
32  Number,
33  NumberIsNaN,
34  NumberParseInt,
35  ObjectDefineProperty,
36  ObjectSetPrototypeOf,
37  Symbol,
38  ObjectCreate,
39  SymbolAsyncDispose,
40} = primordials;
41
42const EventEmitter = require('events');
43const stream = require('stream');
44let debug = require('internal/util/debuglog').debuglog('net', (fn) => {
45  debug = fn;
46});
47const {
48  kReinitializeHandle,
49  isIP,
50  isIPv4,
51  isIPv6,
52  normalizedArgsSymbol,
53  makeSyncWrite,
54} = require('internal/net');
55const assert = require('internal/assert');
56const {
57  UV_EADDRINUSE,
58  UV_EINVAL,
59  UV_ENOTCONN,
60  UV_ECANCELED,
61} = internalBinding('uv');
62
63const { Buffer } = require('buffer');
64const { guessHandleType } = internalBinding('util');
65const { ShutdownWrap } = internalBinding('stream_wrap');
66const {
67  TCP,
68  TCPConnectWrap,
69  constants: TCPConstants,
70} = internalBinding('tcp_wrap');
71const {
72  Pipe,
73  PipeConnectWrap,
74  constants: PipeConstants,
75} = internalBinding('pipe_wrap');
76const {
77  newAsyncId,
78  defaultTriggerAsyncIdScope,
79  symbols: { async_id_symbol, owner_symbol },
80} = require('internal/async_hooks');
81const {
82  writevGeneric,
83  writeGeneric,
84  onStreamRead,
85  kAfterAsyncWrite,
86  kHandle,
87  kUpdateTimer,
88  setStreamTimeout,
89  kBuffer,
90  kBufferCb,
91  kBufferGen,
92} = require('internal/stream_base_commons');
93const {
94  codes: {
95    ERR_INVALID_ADDRESS_FAMILY,
96    ERR_INVALID_ARG_TYPE,
97    ERR_INVALID_ARG_VALUE,
98    ERR_INVALID_FD_TYPE,
99    ERR_INVALID_IP_ADDRESS,
100    ERR_INVALID_HANDLE_TYPE,
101    ERR_SERVER_ALREADY_LISTEN,
102    ERR_SERVER_NOT_RUNNING,
103    ERR_SOCKET_CLOSED,
104    ERR_SOCKET_CLOSED_BEFORE_CONNECTION,
105    ERR_MISSING_ARGS,
106  },
107  aggregateErrors,
108  errnoException,
109  exceptionWithHostPort,
110  genericNodeError,
111  uvExceptionWithHostPort,
112} = require('internal/errors');
113const { isUint8Array } = require('internal/util/types');
114const { queueMicrotask } = require('internal/process/task_queues');
115const { kEmptyObject, promisify } = require('internal/util');
116const {
117  validateAbortSignal,
118  validateBoolean,
119  validateFunction,
120  validateInt32,
121  validateNumber,
122  validatePort,
123  validateString,
124} = require('internal/validators');
125const kLastWriteQueueSize = Symbol('lastWriteQueueSize');
126const {
127  DTRACE_NET_SERVER_CONNECTION,
128  DTRACE_NET_STREAM_END,
129} = require('internal/dtrace');
130const { getOptionValue } = require('internal/options');
131
132// Lazy loaded to improve startup performance.
133let cluster;
134let dns;
135let BlockList;
136let SocketAddress;
137let autoSelectFamilyDefault = getOptionValue('--enable-network-family-autoselection');
138let autoSelectFamilyAttemptTimeoutDefault = 250;
139
140const { clearTimeout, setTimeout } = require('timers');
141const { kTimeout } = require('internal/timers');
142
143const DEFAULT_IPV4_ADDR = '0.0.0.0';
144const DEFAULT_IPV6_ADDR = '::';
145
146const isWindows = process.platform === 'win32';
147
148const noop = () => {};
149
150const kPerfHooksNetConnectContext = Symbol('kPerfHooksNetConnectContext');
151
152let netClientSocketChannel;
153let netServerSocketChannel;
154function lazyChannels() {
155  // TODO(joyeecheung): support diagnostics channels in the snapshot.
156  // For now it is fine to create them lazily when there isn't a snapshot to
157  // build. If users need the channels they would have to create them first
158  // before invoking any built-ins that would publish to these channels
159  // anyway.
160  if (netClientSocketChannel === undefined) {
161    const dc = require('diagnostics_channel');
162    netClientSocketChannel = dc.channel('net.client.socket');
163    netServerSocketChannel = dc.channel('net.server.socket');
164  }
165}
166
167const {
168  hasObserver,
169  startPerf,
170  stopPerf,
171} = require('internal/perf/observe');
172const { getDefaultHighWaterMark } = require('internal/streams/state');
173
174function getFlags(ipv6Only) {
175  return ipv6Only === true ? TCPConstants.UV_TCP_IPV6ONLY : 0;
176}
177
178function createHandle(fd, is_server) {
179  validateInt32(fd, 'fd', 0);
180  const type = guessHandleType(fd);
181  if (type === 'PIPE') {
182    return new Pipe(
183      is_server ? PipeConstants.SERVER : PipeConstants.SOCKET,
184    );
185  }
186
187  if (type === 'TCP') {
188    return new TCP(
189      is_server ? TCPConstants.SERVER : TCPConstants.SOCKET,
190    );
191  }
192
193  throw new ERR_INVALID_FD_TYPE(type);
194}
195
196
197function getNewAsyncId(handle) {
198  return (!handle || typeof handle.getAsyncId !== 'function') ?
199    newAsyncId() : handle.getAsyncId();
200}
201
202
203function isPipeName(s) {
204  return typeof s === 'string' && toNumber(s) === false;
205}
206
207/**
208 * Creates a new TCP or IPC server
209 * @param {{
210 *   allowHalfOpen?: boolean;
211 *   pauseOnConnect?: boolean;
212 *   }} [options]
213 * @param {Function} [connectionListener]
214 * @returns {Server}
215 */
216
217function createServer(options, connectionListener) {
218  return new Server(options, connectionListener);
219}
220
221
222// Target API:
223//
224// let s = net.connect({port: 80, host: 'google.com'}, function() {
225//   ...
226// });
227//
228// There are various forms:
229//
230// connect(options, [cb])
231// connect(port, [host], [cb])
232// connect(path, [cb]);
233//
234function connect(...args) {
235  const normalized = normalizeArgs(args);
236  const options = normalized[0];
237  debug('createConnection', normalized);
238  const socket = new Socket(options);
239  lazyChannels();
240  if (netClientSocketChannel.hasSubscribers) {
241    netClientSocketChannel.publish({
242      socket,
243    });
244  }
245  if (options.timeout) {
246    socket.setTimeout(options.timeout);
247  }
248
249  return socket.connect(normalized);
250}
251
252function getDefaultAutoSelectFamily() {
253  return autoSelectFamilyDefault;
254}
255
256function setDefaultAutoSelectFamily(value) {
257  validateBoolean(value, 'value');
258  autoSelectFamilyDefault = value;
259}
260
261function getDefaultAutoSelectFamilyAttemptTimeout() {
262  return autoSelectFamilyAttemptTimeoutDefault;
263}
264
265function setDefaultAutoSelectFamilyAttemptTimeout(value) {
266  validateInt32(value, 'value', 1);
267
268  if (value < 10) {
269    value = 10;
270  }
271
272  autoSelectFamilyAttemptTimeoutDefault = value;
273}
274
275// Returns an array [options, cb], where options is an object,
276// cb is either a function or null.
277// Used to normalize arguments of Socket.prototype.connect() and
278// Server.prototype.listen(). Possible combinations of parameters:
279//   (options[...][, cb])
280//   (path[...][, cb])
281//   ([port][, host][...][, cb])
282// For Socket.prototype.connect(), the [...] part is ignored
283// For Server.prototype.listen(), the [...] part is [, backlog]
284// but will not be handled here (handled in listen())
285function normalizeArgs(args) {
286  let arr;
287
288  if (args.length === 0) {
289    arr = [{}, null];
290    arr[normalizedArgsSymbol] = true;
291    return arr;
292  }
293
294  const arg0 = args[0];
295  let options = {};
296  if (typeof arg0 === 'object' && arg0 !== null) {
297    // (options[...][, cb])
298    options = arg0;
299  } else if (isPipeName(arg0)) {
300    // (path[...][, cb])
301    options.path = arg0;
302  } else {
303    // ([port][, host][...][, cb])
304    options.port = arg0;
305    if (args.length > 1 && typeof args[1] === 'string') {
306      options.host = args[1];
307    }
308  }
309
310  const cb = args[args.length - 1];
311  if (typeof cb !== 'function')
312    arr = [options, null];
313  else
314    arr = [options, cb];
315
316  arr[normalizedArgsSymbol] = true;
317  return arr;
318}
319
320
321// Called when creating new Socket, or when re-using a closed Socket
322function initSocketHandle(self) {
323  self._undestroy();
324  self._sockname = null;
325
326  // Handle creation may be deferred to bind() or connect() time.
327  if (self._handle) {
328    self._handle[owner_symbol] = self;
329    self._handle.onread = onStreamRead;
330    self[async_id_symbol] = getNewAsyncId(self._handle);
331
332    let userBuf = self[kBuffer];
333    if (userBuf) {
334      const bufGen = self[kBufferGen];
335      if (bufGen !== null) {
336        userBuf = bufGen();
337        if (!isUint8Array(userBuf))
338          return;
339        self[kBuffer] = userBuf;
340      }
341      self._handle.useUserBuffer(userBuf);
342    }
343  }
344}
345
346function closeSocketHandle(self, isException, isCleanupPending = false) {
347  if (self._handle) {
348    self._handle.close(() => {
349      debug('emit close');
350      self.emit('close', isException);
351      if (isCleanupPending) {
352        self._handle.onread = noop;
353        self._handle = null;
354        self._sockname = null;
355      }
356    });
357  }
358}
359
360const kBytesRead = Symbol('kBytesRead');
361const kBytesWritten = Symbol('kBytesWritten');
362const kSetNoDelay = Symbol('kSetNoDelay');
363const kSetKeepAlive = Symbol('kSetKeepAlive');
364const kSetKeepAliveInitialDelay = Symbol('kSetKeepAliveInitialDelay');
365
366function Socket(options) {
367  if (!(this instanceof Socket)) return new Socket(options);
368  if (options?.objectMode) {
369    throw new ERR_INVALID_ARG_VALUE(
370      'options.objectMode',
371      options.objectMode,
372      'is not supported',
373    );
374  } else if (options?.readableObjectMode || options?.writableObjectMode) {
375    throw new ERR_INVALID_ARG_VALUE(
376      `options.${
377        options.readableObjectMode ? 'readableObjectMode' : 'writableObjectMode'
378      }`,
379      options.readableObjectMode || options.writableObjectMode,
380      'is not supported',
381    );
382  }
383  if (typeof options?.keepAliveInitialDelay !== 'undefined') {
384    validateNumber(
385      options?.keepAliveInitialDelay, 'options.keepAliveInitialDelay',
386    );
387
388    if (options.keepAliveInitialDelay < 0) {
389      options.keepAliveInitialDelay = 0;
390    }
391  }
392
393  this.connecting = false;
394  // Problem with this is that users can supply their own handle, that may not
395  // have _handle.getAsyncId(). In this case an[async_id_symbol] should
396  // probably be supplied by async_hooks.
397  this[async_id_symbol] = -1;
398  this._hadError = false;
399  this[kHandle] = null;
400  this._parent = null;
401  this._host = null;
402  this[kLastWriteQueueSize] = 0;
403  this[kTimeout] = null;
404  this[kBuffer] = null;
405  this[kBufferCb] = null;
406  this[kBufferGen] = null;
407  this._closeAfterHandlingError = false;
408
409  if (typeof options === 'number')
410    options = { fd: options }; // Legacy interface.
411  else
412    options = { ...options };
413
414  // Default to *not* allowing half open sockets.
415  options.allowHalfOpen = Boolean(options.allowHalfOpen);
416  // For backwards compat do not emit close on destroy.
417  options.emitClose = false;
418  options.autoDestroy = true;
419  // Handle strings directly.
420  options.decodeStrings = false;
421  stream.Duplex.call(this, options);
422
423  if (options.handle) {
424    this._handle = options.handle; // private
425    this[async_id_symbol] = getNewAsyncId(this._handle);
426  } else if (options.fd !== undefined) {
427    const { fd } = options;
428    let err;
429
430    // createHandle will throw ERR_INVALID_FD_TYPE if `fd` is not
431    // a valid `PIPE` or `TCP` descriptor
432    this._handle = createHandle(fd, false);
433
434    err = this._handle.open(fd);
435
436    // While difficult to fabricate, in some architectures
437    // `open` may return an error code for valid file descriptors
438    // which cannot be opened. This is difficult to test as most
439    // un-openable fds will throw on `createHandle`
440    if (err)
441      throw errnoException(err, 'open');
442
443    this[async_id_symbol] = this._handle.getAsyncId();
444
445    if ((fd === 1 || fd === 2) &&
446        (this._handle instanceof Pipe) && isWindows) {
447      // Make stdout and stderr blocking on Windows
448      err = this._handle.setBlocking(true);
449      if (err)
450        throw errnoException(err, 'setBlocking');
451
452      this._writev = null;
453      this._write = makeSyncWrite(fd);
454      // makeSyncWrite adjusts this value like the original handle would, so
455      // we need to let it do that by turning it into a writable, own
456      // property.
457      ObjectDefineProperty(this._handle, 'bytesWritten', {
458        __proto__: null,
459        value: 0, writable: true,
460      });
461    }
462  }
463
464  const onread = options.onread;
465  if (onread !== null && typeof onread === 'object' &&
466      (isUint8Array(onread.buffer) || typeof onread.buffer === 'function') &&
467      typeof onread.callback === 'function') {
468    if (typeof onread.buffer === 'function') {
469      this[kBuffer] = true;
470      this[kBufferGen] = onread.buffer;
471    } else {
472      this[kBuffer] = onread.buffer;
473    }
474    this[kBufferCb] = onread.callback;
475  }
476
477  this[kSetNoDelay] = Boolean(options.noDelay);
478  this[kSetKeepAlive] = Boolean(options.keepAlive);
479  this[kSetKeepAliveInitialDelay] = ~~(options.keepAliveInitialDelay / 1000);
480
481  // Shut down the socket when we're finished with it.
482  this.on('end', onReadableStreamEnd);
483
484  initSocketHandle(this);
485
486  this._pendingData = null;
487  this._pendingEncoding = '';
488
489  // If we have a handle, then start the flow of data into the
490  // buffer.  if not, then this will happen when we connect
491  if (this._handle && options.readable !== false) {
492    if (options.pauseOnCreate) {
493      // Stop the handle from reading and pause the stream
494      this._handle.reading = false;
495      this._handle.readStop();
496      this.readableFlowing = false;
497    } else if (!options.manualStart) {
498      this.read(0);
499    }
500  }
501
502  // Reserve properties
503  this.server = null;
504  this._server = null;
505
506  // Used after `.destroy()`
507  this[kBytesRead] = 0;
508  this[kBytesWritten] = 0;
509}
510ObjectSetPrototypeOf(Socket.prototype, stream.Duplex.prototype);
511ObjectSetPrototypeOf(Socket, stream.Duplex);
512
513// Refresh existing timeouts.
514Socket.prototype._unrefTimer = function _unrefTimer() {
515  for (let s = this; s !== null; s = s._parent) {
516    if (s[kTimeout])
517      s[kTimeout].refresh();
518  }
519};
520
521
522// The user has called .end(), and all the bytes have been
523// sent out to the other side.
524Socket.prototype._final = function(cb) {
525  // If still connecting - defer handling `_final` until 'connect' will happen
526  if (this.pending) {
527    debug('_final: not yet connected');
528    return this.once('connect', () => this._final(cb));
529  }
530
531  if (!this._handle)
532    return cb();
533
534  debug('_final: not ended, call shutdown()');
535
536  const req = new ShutdownWrap();
537  req.oncomplete = afterShutdown;
538  req.handle = this._handle;
539  req.callback = cb;
540  const err = this._handle.shutdown(req);
541
542  if (err === 1 || err === UV_ENOTCONN)  // synchronous finish
543    return cb();
544  else if (err !== 0)
545    return cb(errnoException(err, 'shutdown'));
546};
547
548function afterShutdown() {
549  const self = this.handle[owner_symbol];
550
551  debug('afterShutdown destroyed=%j', self.destroyed);
552
553  this.callback();
554}
555
556// Provide a better error message when we call end() as a result
557// of the other side sending a FIN.  The standard 'write after end'
558// is overly vague, and makes it seem like the user's code is to blame.
559function writeAfterFIN(chunk, encoding, cb) {
560  if (!this.writableEnded) {
561    return stream.Duplex.prototype.write.call(this, chunk, encoding, cb);
562  }
563
564  if (typeof encoding === 'function') {
565    cb = encoding;
566    encoding = null;
567  }
568
569  const er = genericNodeError(
570    'This socket has been ended by the other party',
571    { code: 'EPIPE' },
572  );
573  if (typeof cb === 'function') {
574    defaultTriggerAsyncIdScope(this[async_id_symbol], process.nextTick, cb, er);
575  }
576  this.destroy(er);
577
578  return false;
579}
580
581Socket.prototype.setTimeout = setStreamTimeout;
582
583
584Socket.prototype._onTimeout = function() {
585  const handle = this._handle;
586  const lastWriteQueueSize = this[kLastWriteQueueSize];
587  if (lastWriteQueueSize > 0 && handle) {
588    // `lastWriteQueueSize !== writeQueueSize` means there is
589    // an active write in progress, so we suppress the timeout.
590    const { writeQueueSize } = handle;
591    if (lastWriteQueueSize !== writeQueueSize) {
592      this[kLastWriteQueueSize] = writeQueueSize;
593      this._unrefTimer();
594      return;
595    }
596  }
597  debug('_onTimeout');
598  this.emit('timeout');
599};
600
601
602Socket.prototype.setNoDelay = function(enable) {
603  // Backwards compatibility: assume true when `enable` is omitted
604  enable = Boolean(enable === undefined ? true : enable);
605
606  if (!this._handle) {
607    this[kSetNoDelay] = enable;
608    return this;
609  }
610
611  if (this._handle.setNoDelay && enable !== this[kSetNoDelay]) {
612    this[kSetNoDelay] = enable;
613    this._handle.setNoDelay(enable);
614  }
615
616  return this;
617};
618
619
620Socket.prototype.setKeepAlive = function(enable, initialDelayMsecs) {
621  enable = Boolean(enable);
622  const initialDelay = ~~(initialDelayMsecs / 1000);
623
624  if (!this._handle) {
625    this[kSetKeepAlive] = enable;
626    this[kSetKeepAliveInitialDelay] = initialDelay;
627    return this;
628  }
629
630  if (!this._handle.setKeepAlive) {
631    return this;
632  }
633
634  if (enable !== this[kSetKeepAlive] ||
635      (
636        enable &&
637        this[kSetKeepAliveInitialDelay] !== initialDelay
638      )
639  ) {
640    this[kSetKeepAlive] = enable;
641    this[kSetKeepAliveInitialDelay] = initialDelay;
642    this._handle.setKeepAlive(enable, initialDelay);
643  }
644
645  return this;
646};
647
648
649Socket.prototype.address = function() {
650  return this._getsockname();
651};
652
653
654ObjectDefineProperty(Socket.prototype, '_connecting', {
655  __proto__: null,
656  get: function() {
657    return this.connecting;
658  },
659});
660
661ObjectDefineProperty(Socket.prototype, 'pending', {
662  __proto__: null,
663  get() {
664    return !this._handle || this.connecting;
665  },
666  configurable: true,
667});
668
669
670ObjectDefineProperty(Socket.prototype, 'readyState', {
671  __proto__: null,
672  get: function() {
673    if (this.connecting) {
674      return 'opening';
675    } else if (this.readable && this.writable) {
676      return 'open';
677    } else if (this.readable && !this.writable) {
678      return 'readOnly';
679    } else if (!this.readable && this.writable) {
680      return 'writeOnly';
681    }
682    return 'closed';
683  },
684});
685
686
687ObjectDefineProperty(Socket.prototype, 'bufferSize', {
688  __proto__: null,
689  get: function() {
690    if (this._handle) {
691      return this.writableLength;
692    }
693  },
694});
695
696ObjectDefineProperty(Socket.prototype, kUpdateTimer, {
697  __proto__: null,
698  get: function() {
699    return this._unrefTimer;
700  },
701});
702
703
704function tryReadStart(socket) {
705  // Not already reading, start the flow
706  debug('Socket._handle.readStart');
707  socket._handle.reading = true;
708  const err = socket._handle.readStart();
709  if (err)
710    socket.destroy(errnoException(err, 'read'));
711}
712
713// Just call handle.readStart until we have enough in the buffer
714Socket.prototype._read = function(n) {
715  debug(
716    '_read - n', n,
717    'isConnecting?', !!this.connecting,
718    'hasHandle?', !!this._handle,
719  );
720
721  if (this.connecting || !this._handle) {
722    debug('_read wait for connection');
723    this.once('connect', () => this._read(n));
724  } else if (!this._handle.reading) {
725    tryReadStart(this);
726  }
727};
728
729
730Socket.prototype.end = function(data, encoding, callback) {
731  stream.Duplex.prototype.end.call(this,
732                                   data, encoding, callback);
733  DTRACE_NET_STREAM_END(this);
734  return this;
735};
736
737Socket.prototype.resetAndDestroy = function() {
738  if (this._handle) {
739    if (!(this._handle instanceof TCP))
740      throw new ERR_INVALID_HANDLE_TYPE();
741    if (this.connecting) {
742      debug('reset wait for connection');
743      this.once('connect', () => this._reset());
744    } else {
745      this._reset();
746    }
747  } else {
748    this.destroy(new ERR_SOCKET_CLOSED());
749  }
750  return this;
751};
752
753Socket.prototype.pause = function() {
754  if (this[kBuffer] && !this.connecting && this._handle &&
755      this._handle.reading) {
756    this._handle.reading = false;
757    if (!this.destroyed) {
758      const err = this._handle.readStop();
759      if (err)
760        this.destroy(errnoException(err, 'read'));
761    }
762  }
763  return stream.Duplex.prototype.pause.call(this);
764};
765
766
767Socket.prototype.resume = function() {
768  if (this[kBuffer] && !this.connecting && this._handle &&
769      !this._handle.reading) {
770    tryReadStart(this);
771  }
772  return stream.Duplex.prototype.resume.call(this);
773};
774
775
776Socket.prototype.read = function(n) {
777  if (this[kBuffer] && !this.connecting && this._handle &&
778      !this._handle.reading) {
779    tryReadStart(this);
780  }
781  return stream.Duplex.prototype.read.call(this, n);
782};
783
784
785// Called when the 'end' event is emitted.
786function onReadableStreamEnd() {
787  if (!this.allowHalfOpen) {
788    this.write = writeAfterFIN;
789  }
790}
791
792
793Socket.prototype.destroySoon = function() {
794  if (this.writable)
795    this.end();
796
797  if (this.writableFinished)
798    this.destroy();
799  else
800    this.once('finish', this.destroy);
801};
802
803
804Socket.prototype._destroy = function(exception, cb) {
805  debug('destroy');
806
807  this.connecting = false;
808
809  for (let s = this; s !== null; s = s._parent) {
810    clearTimeout(s[kTimeout]);
811  }
812
813  debug('close');
814  if (this._handle) {
815    if (this !== process.stderr)
816      debug('close handle');
817    const isException = exception ? true : false;
818    // `bytesRead` and `kBytesWritten` should be accessible after `.destroy()`
819    this[kBytesRead] = this._handle.bytesRead;
820    this[kBytesWritten] = this._handle.bytesWritten;
821
822    if (this.resetAndClosing) {
823      this.resetAndClosing = false;
824      const err = this._handle.reset(() => {
825        debug('emit close');
826        this.emit('close', isException);
827      });
828      if (err)
829        this.emit('error', errnoException(err, 'reset'));
830    } else if (this._closeAfterHandlingError) {
831      // Enqueue closing the socket as a microtask, so that the socket can be
832      // accessible when an `error` event is handled in the `next tick queue`.
833      queueMicrotask(() => closeSocketHandle(this, isException, true));
834    } else {
835      closeSocketHandle(this, isException);
836    }
837
838    if (!this._closeAfterHandlingError) {
839      this._handle.onread = noop;
840      this._handle = null;
841      this._sockname = null;
842    }
843    cb(exception);
844  } else {
845    cb(exception);
846    process.nextTick(emitCloseNT, this);
847  }
848
849  if (this._server) {
850    debug('has server');
851    this._server._connections--;
852    if (this._server._emitCloseIfDrained) {
853      this._server._emitCloseIfDrained();
854    }
855  }
856};
857
858Socket.prototype._reset = function() {
859  debug('reset connection');
860  this.resetAndClosing = true;
861  return this.destroy();
862};
863
864Socket.prototype._getpeername = function() {
865  if (!this._handle || !this._handle.getpeername || this.connecting) {
866    return this._peername || {};
867  } else if (!this._peername) {
868    const out = {};
869    const err = this._handle.getpeername(out);
870    if (err) return out;
871    this._peername = out;
872  }
873  return this._peername;
874};
875
876function protoGetter(name, callback) {
877  ObjectDefineProperty(Socket.prototype, name, {
878    __proto__: null,
879    configurable: false,
880    enumerable: true,
881    get: callback,
882  });
883}
884
885protoGetter('bytesRead', function bytesRead() {
886  return this._handle ? this._handle.bytesRead : this[kBytesRead];
887});
888
889protoGetter('remoteAddress', function remoteAddress() {
890  return this._getpeername().address;
891});
892
893protoGetter('remoteFamily', function remoteFamily() {
894  return this._getpeername().family;
895});
896
897protoGetter('remotePort', function remotePort() {
898  return this._getpeername().port;
899});
900
901
902Socket.prototype._getsockname = function() {
903  if (!this._handle || !this._handle.getsockname) {
904    return {};
905  } else if (!this._sockname) {
906    this._sockname = {};
907    // FIXME(bnoordhuis) Throw when the return value is not 0?
908    this._handle.getsockname(this._sockname);
909  }
910  return this._sockname;
911};
912
913
914protoGetter('localAddress', function localAddress() {
915  return this._getsockname().address;
916});
917
918
919protoGetter('localPort', function localPort() {
920  return this._getsockname().port;
921});
922
923protoGetter('localFamily', function localFamily() {
924  return this._getsockname().family;
925});
926
927Socket.prototype[kAfterAsyncWrite] = function() {
928  this[kLastWriteQueueSize] = 0;
929};
930
931Socket.prototype._writeGeneric = function(writev, data, encoding, cb) {
932  // If we are still connecting, then buffer this for later.
933  // The Writable logic will buffer up any more writes while
934  // waiting for this one to be done.
935  if (this.connecting) {
936    this._pendingData = data;
937    this._pendingEncoding = encoding;
938    this.once('connect', function connect() {
939      this.off('close', onClose);
940      this._writeGeneric(writev, data, encoding, cb);
941    });
942    function onClose() {
943      cb(new ERR_SOCKET_CLOSED_BEFORE_CONNECTION());
944    }
945    this.once('close', onClose);
946    return;
947  }
948  this._pendingData = null;
949  this._pendingEncoding = '';
950
951  if (!this._handle) {
952    cb(new ERR_SOCKET_CLOSED());
953    return false;
954  }
955
956  this._unrefTimer();
957
958  let req;
959  if (writev)
960    req = writevGeneric(this, data, cb);
961  else
962    req = writeGeneric(this, data, encoding, cb);
963  if (req.async)
964    this[kLastWriteQueueSize] = req.bytes;
965};
966
967
968Socket.prototype._writev = function(chunks, cb) {
969  this._writeGeneric(true, chunks, '', cb);
970};
971
972
973Socket.prototype._write = function(data, encoding, cb) {
974  this._writeGeneric(false, data, encoding, cb);
975};
976
977
978// Legacy alias. Having this is probably being overly cautious, but it doesn't
979// really hurt anyone either. This can probably be removed safely if desired.
980protoGetter('_bytesDispatched', function _bytesDispatched() {
981  return this._handle ? this._handle.bytesWritten : this[kBytesWritten];
982});
983
984protoGetter('bytesWritten', function bytesWritten() {
985  let bytes = this._bytesDispatched;
986  const data = this._pendingData;
987  const encoding = this._pendingEncoding;
988  const writableBuffer = this.writableBuffer;
989
990  if (!writableBuffer)
991    return undefined;
992
993  for (const el of writableBuffer) {
994    bytes += el.chunk instanceof Buffer ?
995      el.chunk.length :
996      Buffer.byteLength(el.chunk, el.encoding);
997  }
998
999  if (ArrayIsArray(data)) {
1000    // Was a writev, iterate over chunks to get total length
1001    for (let i = 0; i < data.length; i++) {
1002      const chunk = data[i];
1003
1004      if (data.allBuffers || chunk instanceof Buffer)
1005        bytes += chunk.length;
1006      else
1007        bytes += Buffer.byteLength(chunk.chunk, chunk.encoding);
1008    }
1009  } else if (data) {
1010    // Writes are either a string or a Buffer.
1011    if (typeof data !== 'string')
1012      bytes += data.length;
1013    else
1014      bytes += Buffer.byteLength(data, encoding);
1015  }
1016
1017  return bytes;
1018});
1019
1020
1021function checkBindError(err, port, handle) {
1022  // EADDRINUSE may not be reported until we call listen() or connect().
1023  // To complicate matters, a failed bind() followed by listen() or connect()
1024  // will implicitly bind to a random port. Ergo, check that the socket is
1025  // bound to the expected port before calling listen() or connect().
1026  //
1027  // FIXME(bnoordhuis) Doesn't work for pipe handles, they don't have a
1028  // getsockname() method. Non-issue for now, the cluster module doesn't
1029  // really support pipes anyway.
1030  if (err === 0 && port > 0 && handle.getsockname) {
1031    const out = {};
1032    err = handle.getsockname(out);
1033    if (err === 0 && port !== out.port) {
1034      debug(`checkBindError, bound to ${out.port} instead of ${port}`);
1035      err = UV_EADDRINUSE;
1036    }
1037  }
1038  return err;
1039}
1040
1041
1042function internalConnect(
1043  self, address, port, addressType, localAddress, localPort, flags) {
1044  // TODO return promise from Socket.prototype.connect which
1045  // wraps _connectReq.
1046
1047  assert(self.connecting);
1048
1049  let err;
1050
1051  if (localAddress || localPort) {
1052    if (addressType === 4) {
1053      localAddress = localAddress || DEFAULT_IPV4_ADDR;
1054      err = self._handle.bind(localAddress, localPort);
1055    } else { // addressType === 6
1056      localAddress = localAddress || DEFAULT_IPV6_ADDR;
1057      err = self._handle.bind6(localAddress, localPort, flags);
1058    }
1059    debug('connect: binding to localAddress: %s and localPort: %d (addressType: %d)',
1060          localAddress, localPort, addressType);
1061
1062    err = checkBindError(err, localPort, self._handle);
1063    if (err) {
1064      const ex = exceptionWithHostPort(err, 'bind', localAddress, localPort);
1065      self.destroy(ex);
1066      return;
1067    }
1068  }
1069
1070  debug('connect: attempting to connect to %s:%d (addressType: %d)', address, port, addressType);
1071
1072  if (addressType === 6 || addressType === 4) {
1073    const req = new TCPConnectWrap();
1074    req.oncomplete = afterConnect;
1075    req.address = address;
1076    req.port = port;
1077    req.localAddress = localAddress;
1078    req.localPort = localPort;
1079
1080    if (addressType === 4)
1081      err = self._handle.connect(req, address, port);
1082    else
1083      err = self._handle.connect6(req, address, port);
1084  } else {
1085    const req = new PipeConnectWrap();
1086    req.address = address;
1087    req.oncomplete = afterConnect;
1088
1089    err = self._handle.connect(req, address);
1090  }
1091
1092  if (err) {
1093    const sockname = self._getsockname();
1094    let details;
1095
1096    if (sockname) {
1097      details = sockname.address + ':' + sockname.port;
1098    }
1099
1100    const ex = exceptionWithHostPort(err, 'connect', address, port, details);
1101    self.destroy(ex);
1102  } else if ((addressType === 6 || addressType === 4) && hasObserver('net')) {
1103    startPerf(self, kPerfHooksNetConnectContext, { type: 'net', name: 'connect', detail: { host: address, port } });
1104  }
1105}
1106
1107
1108function internalConnectMultiple(context, canceled) {
1109  clearTimeout(context[kTimeout]);
1110  const self = context.socket;
1111
1112  // All connections have been tried without success, destroy with error
1113  if (canceled || context.current === context.addresses.length) {
1114    self.destroy(aggregateErrors(context.errors));
1115    return;
1116  }
1117
1118  assert(self.connecting);
1119
1120  const current = context.current++;
1121  const handle = current === 0 ? self._handle : new TCP(TCPConstants.SOCKET);
1122  const { localPort, port, flags } = context;
1123  const { address, family: addressType } = context.addresses[current];
1124  let localAddress;
1125  let err;
1126
1127  if (localPort) {
1128    if (addressType === 4) {
1129      localAddress = DEFAULT_IPV4_ADDR;
1130      err = handle.bind(localAddress, localPort);
1131    } else { // addressType === 6
1132      localAddress = DEFAULT_IPV6_ADDR;
1133      err = handle.bind6(localAddress, localPort, flags);
1134    }
1135
1136    debug('connect/multiple: binding to localAddress: %s and localPort: %d (addressType: %d)',
1137          localAddress, localPort, addressType);
1138
1139    err = checkBindError(err, localPort, handle);
1140    if (err) {
1141      ArrayPrototypePush(context.errors, exceptionWithHostPort(err, 'bind', localAddress, localPort));
1142      internalConnectMultiple(context);
1143      return;
1144    }
1145  }
1146
1147  debug('connect/multiple: attempting to connect to %s:%d (addressType: %d)', address, port, addressType);
1148
1149  const req = new TCPConnectWrap();
1150  req.oncomplete = FunctionPrototypeBind(afterConnectMultiple, undefined, context, current);
1151  req.address = address;
1152  req.port = port;
1153  req.localAddress = localAddress;
1154  req.localPort = localPort;
1155
1156  ArrayPrototypePush(self.autoSelectFamilyAttemptedAddresses, `${address}:${port}`);
1157
1158  if (addressType === 4) {
1159    err = handle.connect(req, address, port);
1160  } else {
1161    err = handle.connect6(req, address, port);
1162  }
1163
1164  if (err) {
1165    const sockname = self._getsockname();
1166    let details;
1167
1168    if (sockname) {
1169      details = sockname.address + ':' + sockname.port;
1170    }
1171
1172    ArrayPrototypePush(context.errors, exceptionWithHostPort(err, 'connect', address, port, details));
1173    internalConnectMultiple(context);
1174    return;
1175  }
1176
1177  if (current < context.addresses.length - 1) {
1178    debug('connect/multiple: setting the attempt timeout to %d ms', context.timeout);
1179
1180    // If the attempt has not returned an error, start the connection timer
1181    context[kTimeout] = setTimeout(internalConnectMultipleTimeout, context.timeout, context, req, handle);
1182  }
1183}
1184
1185Socket.prototype.connect = function(...args) {
1186  let normalized;
1187  // If passed an array, it's treated as an array of arguments that have
1188  // already been normalized (so we don't normalize more than once). This has
1189  // been solved before in https://github.com/nodejs/node/pull/12342, but was
1190  // reverted as it had unintended side effects.
1191  if (ArrayIsArray(args[0]) && args[0][normalizedArgsSymbol]) {
1192    normalized = args[0];
1193  } else {
1194    normalized = normalizeArgs(args);
1195  }
1196  const options = normalized[0];
1197  const cb = normalized[1];
1198
1199  // options.port === null will be checked later.
1200  if (options.port === undefined && options.path == null)
1201    throw new ERR_MISSING_ARGS(['options', 'port', 'path']);
1202
1203  if (this.write !== Socket.prototype.write)
1204    this.write = Socket.prototype.write;
1205
1206  if (this.destroyed) {
1207    this._handle = null;
1208    this._peername = null;
1209    this._sockname = null;
1210  }
1211
1212  const { path } = options;
1213  const pipe = !!path;
1214  debug('pipe', pipe, path);
1215
1216  if (!this._handle) {
1217    this._handle = pipe ?
1218      new Pipe(PipeConstants.SOCKET) :
1219      new TCP(TCPConstants.SOCKET);
1220    initSocketHandle(this);
1221  }
1222
1223  if (cb !== null) {
1224    this.once('connect', cb);
1225  }
1226
1227  this._unrefTimer();
1228
1229  this.connecting = true;
1230
1231  if (pipe) {
1232    validateString(path, 'options.path');
1233    defaultTriggerAsyncIdScope(
1234      this[async_id_symbol], internalConnect, this, path,
1235    );
1236  } else {
1237    lookupAndConnect(this, options);
1238  }
1239  return this;
1240};
1241
1242Socket.prototype[kReinitializeHandle] = function reinitializeHandle(handle) {
1243  this._handle?.close();
1244
1245  this._handle = handle;
1246  this._handle[owner_symbol] = this;
1247
1248  initSocketHandle(this);
1249};
1250
1251function socketToDnsFamily(family) {
1252  switch (family) {
1253    case 'IPv4':
1254      return 4;
1255    case 'IPv6':
1256      return 6;
1257  }
1258
1259  return family;
1260}
1261
1262function lookupAndConnect(self, options) {
1263  const { localAddress, localPort } = options;
1264  const host = options.host || 'localhost';
1265  let { port, autoSelectFamilyAttemptTimeout, autoSelectFamily } = options;
1266
1267  if (localAddress && !isIP(localAddress)) {
1268    throw new ERR_INVALID_IP_ADDRESS(localAddress);
1269  }
1270
1271  if (localPort) {
1272    validateNumber(localPort, 'options.localPort');
1273  }
1274
1275  if (typeof port !== 'undefined') {
1276    if (typeof port !== 'number' && typeof port !== 'string') {
1277      throw new ERR_INVALID_ARG_TYPE('options.port',
1278                                     ['number', 'string'], port);
1279    }
1280    validatePort(port);
1281  }
1282  port |= 0;
1283
1284
1285  if (autoSelectFamily != null) {
1286    validateBoolean(autoSelectFamily, 'options.autoSelectFamily');
1287  } else {
1288    autoSelectFamily = autoSelectFamilyDefault;
1289  }
1290
1291  if (autoSelectFamilyAttemptTimeout != null) {
1292    validateInt32(autoSelectFamilyAttemptTimeout, 'options.autoSelectFamilyAttemptTimeout', 1);
1293
1294    if (autoSelectFamilyAttemptTimeout < 10) {
1295      autoSelectFamilyAttemptTimeout = 10;
1296    }
1297  } else {
1298    autoSelectFamilyAttemptTimeout = autoSelectFamilyAttemptTimeoutDefault;
1299  }
1300
1301  // If host is an IP, skip performing a lookup
1302  const addressType = isIP(host);
1303  if (addressType) {
1304    defaultTriggerAsyncIdScope(self[async_id_symbol], process.nextTick, () => {
1305      if (self.connecting)
1306        defaultTriggerAsyncIdScope(
1307          self[async_id_symbol],
1308          internalConnect,
1309          self, host, port, addressType, localAddress, localPort,
1310        );
1311    });
1312    return;
1313  }
1314
1315  if (options.lookup != null)
1316    validateFunction(options.lookup, 'options.lookup');
1317
1318  if (dns === undefined) dns = require('dns');
1319  const dnsopts = {
1320    family: socketToDnsFamily(options.family),
1321    hints: options.hints || 0,
1322  };
1323
1324  if (!isWindows &&
1325      dnsopts.family !== 4 &&
1326      dnsopts.family !== 6 &&
1327      dnsopts.hints === 0) {
1328    dnsopts.hints = dns.ADDRCONFIG;
1329  }
1330
1331  debug('connect: find host', host);
1332  debug('connect: dns options', dnsopts);
1333  self._host = host;
1334  const lookup = options.lookup || dns.lookup;
1335
1336  if (dnsopts.family !== 4 && dnsopts.family !== 6 && !localAddress && autoSelectFamily) {
1337    debug('connect: autodetecting');
1338
1339    dnsopts.all = true;
1340    defaultTriggerAsyncIdScope(self[async_id_symbol], function() {
1341      lookupAndConnectMultiple(
1342        self,
1343        async_id_symbol,
1344        lookup,
1345        host,
1346        options,
1347        dnsopts,
1348        port,
1349        localPort,
1350        autoSelectFamilyAttemptTimeout,
1351      );
1352    });
1353
1354    return;
1355  }
1356
1357  defaultTriggerAsyncIdScope(self[async_id_symbol], function() {
1358    lookup(host, dnsopts, function emitLookup(err, ip, addressType) {
1359      self.emit('lookup', err, ip, addressType, host);
1360
1361      // It's possible we were destroyed while looking this up.
1362      // XXX it would be great if we could cancel the promise returned by
1363      // the look up.
1364      if (!self.connecting) return;
1365
1366      if (err) {
1367        // net.createConnection() creates a net.Socket object and immediately
1368        // calls net.Socket.connect() on it (that's us). There are no event
1369        // listeners registered yet so defer the error event to the next tick.
1370        process.nextTick(connectErrorNT, self, err);
1371      } else if (!isIP(ip)) {
1372        err = new ERR_INVALID_IP_ADDRESS(ip);
1373        process.nextTick(connectErrorNT, self, err);
1374      } else if (addressType !== 4 && addressType !== 6) {
1375        err = new ERR_INVALID_ADDRESS_FAMILY(addressType,
1376                                             options.host,
1377                                             options.port);
1378        process.nextTick(connectErrorNT, self, err);
1379      } else {
1380        self._unrefTimer();
1381        defaultTriggerAsyncIdScope(
1382          self[async_id_symbol],
1383          internalConnect,
1384          self, ip, port, addressType, localAddress, localPort,
1385        );
1386      }
1387    });
1388  });
1389}
1390
1391function lookupAndConnectMultiple(self, async_id_symbol, lookup, host, options, dnsopts, port, localPort, timeout) {
1392  defaultTriggerAsyncIdScope(self[async_id_symbol], function emitLookup() {
1393    lookup(host, dnsopts, function emitLookup(err, addresses) {
1394      // It's possible we were destroyed while looking this up.
1395      // XXX it would be great if we could cancel the promise returned by
1396      // the look up.
1397      if (!self.connecting) {
1398        return;
1399      } else if (err) {
1400        self.emit('lookup', err, undefined, undefined, host);
1401
1402        // net.createConnection() creates a net.Socket object and immediately
1403        // calls net.Socket.connect() on it (that's us). There are no event
1404        // listeners registered yet so defer the error event to the next tick.
1405        process.nextTick(connectErrorNT, self, err);
1406        return;
1407      }
1408
1409      // Filter addresses by only keeping the one which are either IPv4 or IPV6.
1410      // The first valid address determines which group has preference on the
1411      // alternate family sorting which happens later.
1412      const validIps = [[], []];
1413      let destinations;
1414      for (let i = 0, l = addresses.length; i < l; i++) {
1415        const address = addresses[i];
1416        const { address: ip, family: addressType } = address;
1417        self.emit('lookup', err, ip, addressType, host);
1418
1419        if (isIP(ip) && (addressType === 4 || addressType === 6)) {
1420          if (!destinations) {
1421            destinations = addressType === 6 ? { 6: 0, 4: 1 } : { 4: 0, 6: 1 };
1422          }
1423
1424          ArrayPrototypePush(validIps[destinations[addressType]], address);
1425        }
1426      }
1427
1428      // When no AAAA or A records are available, fail on the first one
1429      if (!validIps[0].length && !validIps[1].length) {
1430        const { address: firstIp, family: firstAddressType } = addresses[0];
1431
1432        if (!isIP(firstIp)) {
1433          err = new ERR_INVALID_IP_ADDRESS(firstIp);
1434          process.nextTick(connectErrorNT, self, err);
1435        } else if (firstAddressType !== 4 && firstAddressType !== 6) {
1436          err = new ERR_INVALID_ADDRESS_FAMILY(firstAddressType,
1437                                               options.host,
1438                                               options.port);
1439          process.nextTick(connectErrorNT, self, err);
1440        }
1441
1442        return;
1443      }
1444
1445      // Sort addresses alternating families
1446      const toAttempt = [];
1447      for (let i = 0, l = MathMax(validIps[0].length, validIps[1].length); i < l; i++) {
1448        if (i in validIps[0]) {
1449          ArrayPrototypePush(toAttempt, validIps[0][i]);
1450        }
1451        if (i in validIps[1]) {
1452          ArrayPrototypePush(toAttempt, validIps[1][i]);
1453        }
1454      }
1455
1456      self.autoSelectFamilyAttemptedAddresses = [];
1457
1458      const context = {
1459        socket: self,
1460        addresses: toAttempt,
1461        current: 0,
1462        port,
1463        localPort,
1464        timeout,
1465        [kTimeout]: null,
1466        errors: [],
1467      };
1468
1469      self._unrefTimer();
1470      defaultTriggerAsyncIdScope(self[async_id_symbol], internalConnectMultiple, context);
1471    });
1472  });
1473}
1474
1475function connectErrorNT(self, err) {
1476  self.destroy(err);
1477}
1478
1479
1480Socket.prototype.ref = function() {
1481  if (!this._handle) {
1482    this.once('connect', this.ref);
1483    return this;
1484  }
1485
1486  if (typeof this._handle.ref === 'function') {
1487    this._handle.ref();
1488  }
1489
1490  return this;
1491};
1492
1493
1494Socket.prototype.unref = function() {
1495  if (!this._handle) {
1496    this.once('connect', this.unref);
1497    return this;
1498  }
1499
1500  if (typeof this._handle.unref === 'function') {
1501    this._handle.unref();
1502  }
1503
1504  return this;
1505};
1506
1507
1508function afterConnect(status, handle, req, readable, writable) {
1509  const self = handle[owner_symbol];
1510
1511  // Callback may come after call to destroy
1512  if (self.destroyed) {
1513    return;
1514  }
1515
1516  debug('afterConnect');
1517
1518  assert(self.connecting);
1519  self.connecting = false;
1520  self._sockname = null;
1521
1522  if (status === 0) {
1523    if (self.readable && !readable) {
1524      self.push(null);
1525      self.read();
1526    }
1527    if (self.writable && !writable) {
1528      self.end();
1529    }
1530    self._unrefTimer();
1531
1532    if (self[kSetNoDelay] && self._handle.setNoDelay) {
1533      self._handle.setNoDelay(true);
1534    }
1535
1536    if (self[kSetKeepAlive] && self._handle.setKeepAlive) {
1537      self._handle.setKeepAlive(true, self[kSetKeepAliveInitialDelay]);
1538    }
1539
1540    self.emit('connect');
1541    self.emit('ready');
1542
1543    // Start the first read, or get an immediate EOF.
1544    // this doesn't actually consume any bytes, because len=0.
1545    if (readable && !self.isPaused())
1546      self.read(0);
1547    if (self[kPerfHooksNetConnectContext] && hasObserver('net')) {
1548      stopPerf(self, kPerfHooksNetConnectContext);
1549    }
1550  } else {
1551    let details;
1552    if (req.localAddress && req.localPort) {
1553      details = req.localAddress + ':' + req.localPort;
1554    }
1555    const ex = exceptionWithHostPort(status,
1556                                     'connect',
1557                                     req.address,
1558                                     req.port,
1559                                     details);
1560    if (details) {
1561      ex.localAddress = req.localAddress;
1562      ex.localPort = req.localPort;
1563    }
1564    self.destroy(ex);
1565  }
1566}
1567
1568function afterConnectMultiple(context, current, status, handle, req, readable, writable) {
1569  // Make sure another connection is not spawned
1570  clearTimeout(context[kTimeout]);
1571
1572  // One of the connection has completed and correctly dispatched but after timeout, ignore this one
1573  if (status === 0 && current !== context.current - 1) {
1574    debug('connect/multiple: ignoring successful but timedout connection to %s:%s', req.address, req.port);
1575    handle.close();
1576    return;
1577  }
1578
1579  const self = context.socket;
1580
1581
1582  // Some error occurred, add to the list of exceptions
1583  if (status !== 0) {
1584    let details;
1585    if (req.localAddress && req.localPort) {
1586      details = req.localAddress + ':' + req.localPort;
1587    }
1588    const ex = exceptionWithHostPort(status,
1589                                     'connect',
1590                                     req.address,
1591                                     req.port,
1592                                     details);
1593    if (details) {
1594      ex.localAddress = req.localAddress;
1595      ex.localPort = req.localPort;
1596    }
1597
1598    ArrayPrototypePush(context.errors, ex);
1599
1600    // Try the next address
1601    internalConnectMultiple(context, status === UV_ECANCELED);
1602    return;
1603  }
1604
1605  // One of the connection has completed and correctly dispatched but after timeout, ignore this one
1606  if (status === 0 && current !== context.current - 1) {
1607    debug('connect/multiple: ignoring successful but timedout connection to %s:%s', req.address, req.port);
1608    handle.close();
1609    return;
1610  }
1611
1612  if (context.current > 1 && self[kReinitializeHandle]) {
1613    self[kReinitializeHandle](handle);
1614    handle = self._handle;
1615  }
1616
1617  if (hasObserver('net')) {
1618    startPerf(
1619      self,
1620      kPerfHooksNetConnectContext,
1621      { type: 'net', name: 'connect', detail: { host: req.address, port: req.port } },
1622    );
1623  }
1624
1625  afterConnect(status, handle, req, readable, writable);
1626}
1627
1628function internalConnectMultipleTimeout(context, req, handle) {
1629  debug('connect/multiple: connection to %s:%s timed out', req.address, req.port);
1630  req.oncomplete = undefined;
1631  handle.close();
1632  internalConnectMultiple(context);
1633}
1634
1635function addAbortSignalOption(self, options) {
1636  if (options?.signal === undefined) {
1637    return;
1638  }
1639  validateAbortSignal(options.signal, 'options.signal');
1640  const { signal } = options;
1641  const onAborted = () => {
1642    self.close();
1643  };
1644  if (signal.aborted) {
1645    process.nextTick(onAborted);
1646  } else {
1647    signal.addEventListener('abort', onAborted);
1648    self.once('close', () => signal.removeEventListener('abort', onAborted));
1649  }
1650}
1651
1652function Server(options, connectionListener) {
1653  if (!(this instanceof Server))
1654    return new Server(options, connectionListener);
1655
1656  EventEmitter.call(this);
1657
1658  if (typeof options === 'function') {
1659    connectionListener = options;
1660    options = kEmptyObject;
1661    this.on('connection', connectionListener);
1662  } else if (options == null || typeof options === 'object') {
1663    options = { ...options };
1664
1665    if (typeof connectionListener === 'function') {
1666      this.on('connection', connectionListener);
1667    }
1668  } else {
1669    throw new ERR_INVALID_ARG_TYPE('options', 'Object', options);
1670  }
1671  if (typeof options.keepAliveInitialDelay !== 'undefined') {
1672    validateNumber(
1673      options.keepAliveInitialDelay, 'options.keepAliveInitialDelay',
1674    );
1675
1676    if (options.keepAliveInitialDelay < 0) {
1677      options.keepAliveInitialDelay = 0;
1678    }
1679  }
1680  if (typeof options.highWaterMark !== 'undefined') {
1681    validateNumber(
1682      options.highWaterMark, 'options.highWaterMark',
1683    );
1684
1685    if (options.highWaterMark < 0) {
1686      options.highWaterMark = getDefaultHighWaterMark();
1687    }
1688  }
1689
1690  this._connections = 0;
1691
1692  this[async_id_symbol] = -1;
1693  this._handle = null;
1694  this._usingWorkers = false;
1695  this._workers = [];
1696  this._unref = false;
1697
1698  this.allowHalfOpen = options.allowHalfOpen || false;
1699  this.pauseOnConnect = !!options.pauseOnConnect;
1700  this.noDelay = Boolean(options.noDelay);
1701  this.keepAlive = Boolean(options.keepAlive);
1702  this.keepAliveInitialDelay = ~~(options.keepAliveInitialDelay / 1000);
1703  this.highWaterMark = options.highWaterMark ?? getDefaultHighWaterMark();
1704}
1705ObjectSetPrototypeOf(Server.prototype, EventEmitter.prototype);
1706ObjectSetPrototypeOf(Server, EventEmitter);
1707
1708
1709function toNumber(x) { return (x = Number(x)) >= 0 ? x : false; }
1710
1711// Returns handle if it can be created, or error code if it can't
1712function createServerHandle(address, port, addressType, fd, flags) {
1713  let err = 0;
1714  // Assign handle in listen, and clean up if bind or listen fails
1715  let handle;
1716
1717  let isTCP = false;
1718  if (typeof fd === 'number' && fd >= 0) {
1719    try {
1720      handle = createHandle(fd, true);
1721    } catch (e) {
1722      // Not a fd we can listen on.  This will trigger an error.
1723      debug('listen invalid fd=%d:', fd, e.message);
1724      return UV_EINVAL;
1725    }
1726
1727    err = handle.open(fd);
1728    if (err)
1729      return err;
1730
1731    assert(!address && !port);
1732  } else if (port === -1 && addressType === -1) {
1733    handle = new Pipe(PipeConstants.SERVER);
1734    if (isWindows) {
1735      const instances = NumberParseInt(process.env.NODE_PENDING_PIPE_INSTANCES);
1736      if (!NumberIsNaN(instances)) {
1737        handle.setPendingInstances(instances);
1738      }
1739    }
1740  } else {
1741    handle = new TCP(TCPConstants.SERVER);
1742    isTCP = true;
1743  }
1744
1745  if (address || port || isTCP) {
1746    debug('bind to', address || 'any');
1747    if (!address) {
1748      // Try binding to ipv6 first
1749      err = handle.bind6(DEFAULT_IPV6_ADDR, port, flags);
1750      if (err) {
1751        handle.close();
1752        // Fallback to ipv4
1753        return createServerHandle(DEFAULT_IPV4_ADDR, port);
1754      }
1755    } else if (addressType === 6) {
1756      err = handle.bind6(address, port, flags);
1757    } else {
1758      err = handle.bind(address, port);
1759    }
1760  }
1761
1762  if (err) {
1763    handle.close();
1764    return err;
1765  }
1766
1767  return handle;
1768}
1769
1770function setupListenHandle(address, port, addressType, backlog, fd, flags) {
1771  debug('setupListenHandle', address, port, addressType, backlog, fd);
1772
1773  // If there is not yet a handle, we need to create one and bind.
1774  // In the case of a server sent via IPC, we don't need to do this.
1775  if (this._handle) {
1776    debug('setupListenHandle: have a handle already');
1777  } else {
1778    debug('setupListenHandle: create a handle');
1779
1780    let rval = null;
1781
1782    // Try to bind to the unspecified IPv6 address, see if IPv6 is available
1783    if (!address && typeof fd !== 'number') {
1784      rval = createServerHandle(DEFAULT_IPV6_ADDR, port, 6, fd, flags);
1785
1786      if (typeof rval === 'number') {
1787        rval = null;
1788        address = DEFAULT_IPV4_ADDR;
1789        addressType = 4;
1790      } else {
1791        address = DEFAULT_IPV6_ADDR;
1792        addressType = 6;
1793      }
1794    }
1795
1796    if (rval === null)
1797      rval = createServerHandle(address, port, addressType, fd, flags);
1798
1799    if (typeof rval === 'number') {
1800      const error = uvExceptionWithHostPort(rval, 'listen', address, port);
1801      process.nextTick(emitErrorNT, this, error);
1802      return;
1803    }
1804    this._handle = rval;
1805  }
1806
1807  this[async_id_symbol] = getNewAsyncId(this._handle);
1808  this._handle.onconnection = onconnection;
1809  this._handle[owner_symbol] = this;
1810
1811  // Use a backlog of 512 entries. We pass 511 to the listen() call because
1812  // the kernel does: backlogsize = roundup_pow_of_two(backlogsize + 1);
1813  // which will thus give us a backlog of 512 entries.
1814  const err = this._handle.listen(backlog || 511);
1815
1816  if (err) {
1817    const ex = uvExceptionWithHostPort(err, 'listen', address, port);
1818    this._handle.close();
1819    this._handle = null;
1820    defaultTriggerAsyncIdScope(this[async_id_symbol],
1821                               process.nextTick,
1822                               emitErrorNT,
1823                               this,
1824                               ex);
1825    return;
1826  }
1827
1828  // Generate connection key, this should be unique to the connection
1829  this._connectionKey = addressType + ':' + address + ':' + port;
1830
1831  // Unref the handle if the server was unref'ed prior to listening
1832  if (this._unref)
1833    this.unref();
1834
1835  defaultTriggerAsyncIdScope(this[async_id_symbol],
1836                             process.nextTick,
1837                             emitListeningNT,
1838                             this);
1839}
1840
1841Server.prototype._listen2 = setupListenHandle;  // legacy alias
1842
1843function emitErrorNT(self, err) {
1844  self.emit('error', err);
1845}
1846
1847
1848function emitListeningNT(self) {
1849  // Ensure handle hasn't closed
1850  if (self._handle)
1851    self.emit('listening');
1852}
1853
1854
1855function listenInCluster(server, address, port, addressType,
1856                         backlog, fd, exclusive, flags, options) {
1857  exclusive = !!exclusive;
1858
1859  if (cluster === undefined) cluster = require('cluster');
1860
1861  if (cluster.isPrimary || exclusive) {
1862    // Will create a new handle
1863    // _listen2 sets up the listened handle, it is still named like this
1864    // to avoid breaking code that wraps this method
1865    server._listen2(address, port, addressType, backlog, fd, flags);
1866    return;
1867  }
1868
1869  const serverQuery = {
1870    address: address,
1871    port: port,
1872    addressType: addressType,
1873    fd: fd,
1874    flags,
1875    backlog,
1876    ...options,
1877  };
1878  // Get the primary's server handle, and listen on it
1879  cluster._getServer(server, serverQuery, listenOnPrimaryHandle);
1880
1881  function listenOnPrimaryHandle(err, handle) {
1882    err = checkBindError(err, port, handle);
1883
1884    if (err) {
1885      const ex = exceptionWithHostPort(err, 'bind', address, port);
1886      return server.emit('error', ex);
1887    }
1888
1889    // Reuse primary's server handle
1890    server._handle = handle;
1891    // _listen2 sets up the listened handle, it is still named like this
1892    // to avoid breaking code that wraps this method
1893    server._listen2(address, port, addressType, backlog, fd, flags);
1894  }
1895}
1896
1897
1898Server.prototype.listen = function(...args) {
1899  const normalized = normalizeArgs(args);
1900  let options = normalized[0];
1901  const cb = normalized[1];
1902
1903  if (this._handle) {
1904    throw new ERR_SERVER_ALREADY_LISTEN();
1905  }
1906
1907  if (cb !== null) {
1908    this.once('listening', cb);
1909  }
1910  const backlogFromArgs =
1911    // (handle, backlog) or (path, backlog) or (port, backlog)
1912    toNumber(args.length > 1 && args[1]) ||
1913    toNumber(args.length > 2 && args[2]);  // (port, host, backlog)
1914
1915  options = options._handle || options.handle || options;
1916  const flags = getFlags(options.ipv6Only);
1917  // (handle[, backlog][, cb]) where handle is an object with a handle
1918  if (options instanceof TCP) {
1919    this._handle = options;
1920    this[async_id_symbol] = this._handle.getAsyncId();
1921    listenInCluster(this, null, -1, -1, backlogFromArgs);
1922    return this;
1923  }
1924  addAbortSignalOption(this, options);
1925  // (handle[, backlog][, cb]) where handle is an object with a fd
1926  if (typeof options.fd === 'number' && options.fd >= 0) {
1927    listenInCluster(this, null, null, null, backlogFromArgs, options.fd);
1928    return this;
1929  }
1930
1931  // ([port][, host][, backlog][, cb]) where port is omitted,
1932  // that is, listen(), listen(null), listen(cb), or listen(null, cb)
1933  // or (options[, cb]) where options.port is explicitly set as undefined or
1934  // null, bind to an arbitrary unused port
1935  if (args.length === 0 || typeof args[0] === 'function' ||
1936      (typeof options.port === 'undefined' && 'port' in options) ||
1937      options.port === null) {
1938    options.port = 0;
1939  }
1940  // ([port][, host][, backlog][, cb]) where port is specified
1941  // or (options[, cb]) where options.port is specified
1942  // or if options.port is normalized as 0 before
1943  let backlog;
1944  if (typeof options.port === 'number' || typeof options.port === 'string') {
1945    validatePort(options.port, 'options.port');
1946    backlog = options.backlog || backlogFromArgs;
1947    // start TCP server listening on host:port
1948    if (options.host) {
1949      lookupAndListen(this, options.port | 0, options.host, backlog,
1950                      options.exclusive, flags);
1951    } else { // Undefined host, listens on unspecified address
1952      // Default addressType 4 will be used to search for primary server
1953      listenInCluster(this, null, options.port | 0, 4,
1954                      backlog, undefined, options.exclusive);
1955    }
1956    return this;
1957  }
1958
1959  // (path[, backlog][, cb]) or (options[, cb])
1960  // where path or options.path is a UNIX domain socket or Windows pipe
1961  if (options.path && isPipeName(options.path)) {
1962    const pipeName = this._pipeName = options.path;
1963    backlog = options.backlog || backlogFromArgs;
1964    listenInCluster(this,
1965                    pipeName,
1966                    -1,
1967                    -1,
1968                    backlog,
1969                    undefined,
1970                    options.exclusive,
1971                    undefined,
1972                    {
1973                      readableAll: options.readableAll,
1974                      writableAll: options.writableAll,
1975                    });
1976
1977    if (!this._handle) {
1978      // Failed and an error shall be emitted in the next tick.
1979      // Therefore, we directly return.
1980      return this;
1981    }
1982
1983    let mode = 0;
1984    if (options.readableAll === true)
1985      mode |= PipeConstants.UV_READABLE;
1986    if (options.writableAll === true)
1987      mode |= PipeConstants.UV_WRITABLE;
1988    if (mode !== 0) {
1989      const err = this._handle.fchmod(mode);
1990      if (err) {
1991        this._handle.close();
1992        this._handle = null;
1993        throw errnoException(err, 'uv_pipe_chmod');
1994      }
1995    }
1996    return this;
1997  }
1998
1999  if (!(('port' in options) || ('path' in options))) {
2000    throw new ERR_INVALID_ARG_VALUE('options', options,
2001                                    'must have the property "port" or "path"');
2002  }
2003
2004  throw new ERR_INVALID_ARG_VALUE('options', options);
2005};
2006
2007function lookupAndListen(self, port, address, backlog, exclusive, flags) {
2008  if (dns === undefined) dns = require('dns');
2009  dns.lookup(address, function doListen(err, ip, addressType) {
2010    if (err) {
2011      self.emit('error', err);
2012    } else {
2013      addressType = ip ? addressType : 4;
2014      listenInCluster(self, ip, port, addressType,
2015                      backlog, undefined, exclusive, flags);
2016    }
2017  });
2018}
2019
2020ObjectDefineProperty(Server.prototype, 'listening', {
2021  __proto__: null,
2022  get: function() {
2023    return !!this._handle;
2024  },
2025  configurable: true,
2026  enumerable: true,
2027});
2028
2029Server.prototype.address = function() {
2030  if (this._handle && this._handle.getsockname) {
2031    const out = {};
2032    const err = this._handle.getsockname(out);
2033    if (err) {
2034      throw errnoException(err, 'address');
2035    }
2036    return out;
2037  } else if (this._pipeName) {
2038    return this._pipeName;
2039  }
2040  return null;
2041};
2042
2043function onconnection(err, clientHandle) {
2044  const handle = this;
2045  const self = handle[owner_symbol];
2046
2047  debug('onconnection');
2048
2049  if (err) {
2050    self.emit('error', errnoException(err, 'accept'));
2051    return;
2052  }
2053
2054  if (self.maxConnections && self._connections >= self.maxConnections) {
2055    if (clientHandle.getsockname || clientHandle.getpeername) {
2056      const data = ObjectCreate(null);
2057      if (clientHandle.getsockname) {
2058        const localInfo = ObjectCreate(null);
2059        clientHandle.getsockname(localInfo);
2060        data.localAddress = localInfo.address;
2061        data.localPort = localInfo.port;
2062        data.localFamily = localInfo.family;
2063      }
2064      if (clientHandle.getpeername) {
2065        const remoteInfo = ObjectCreate(null);
2066        clientHandle.getpeername(remoteInfo);
2067        data.remoteAddress = remoteInfo.address;
2068        data.remotePort = remoteInfo.port;
2069        data.remoteFamily = remoteInfo.family;
2070      }
2071      self.emit('drop', data);
2072    } else {
2073      self.emit('drop');
2074    }
2075    clientHandle.close();
2076    return;
2077  }
2078
2079  const socket = new Socket({
2080    handle: clientHandle,
2081    allowHalfOpen: self.allowHalfOpen,
2082    pauseOnCreate: self.pauseOnConnect,
2083    readable: true,
2084    writable: true,
2085    readableHighWaterMark: self.highWaterMark,
2086    writableHighWaterMark: self.highWaterMark,
2087  });
2088
2089  if (self.noDelay && clientHandle.setNoDelay) {
2090    socket[kSetNoDelay] = true;
2091    clientHandle.setNoDelay(true);
2092  }
2093  if (self.keepAlive && clientHandle.setKeepAlive) {
2094    socket[kSetKeepAlive] = true;
2095    socket[kSetKeepAliveInitialDelay] = self.keepAliveInitialDelay;
2096    clientHandle.setKeepAlive(true, self.keepAliveInitialDelay);
2097  }
2098
2099  self._connections++;
2100  socket.server = self;
2101  socket._server = self;
2102
2103  DTRACE_NET_SERVER_CONNECTION(socket);
2104  self.emit('connection', socket);
2105  lazyChannels();
2106  if (netServerSocketChannel.hasSubscribers) {
2107    netServerSocketChannel.publish({
2108      socket,
2109    });
2110  }
2111}
2112
2113/**
2114 * Gets the number of concurrent connections on the server
2115 * @param {Function} cb
2116 * @returns {Server}
2117 */
2118
2119Server.prototype.getConnections = function(cb) {
2120  const self = this;
2121
2122  function end(err, connections) {
2123    defaultTriggerAsyncIdScope(self[async_id_symbol],
2124                               process.nextTick,
2125                               cb,
2126                               err,
2127                               connections);
2128  }
2129
2130  if (!this._usingWorkers) {
2131    end(null, this._connections);
2132    return this;
2133  }
2134
2135  // Poll workers
2136  let left = this._workers.length;
2137  let total = this._connections;
2138
2139  function oncount(err, count) {
2140    if (err) {
2141      left = -1;
2142      return end(err);
2143    }
2144
2145    total += count;
2146    if (--left === 0) return end(null, total);
2147  }
2148
2149  for (let n = 0; n < this._workers.length; n++) {
2150    this._workers[n].getConnections(oncount);
2151  }
2152
2153  return this;
2154};
2155
2156
2157Server.prototype.close = function(cb) {
2158  if (typeof cb === 'function') {
2159    if (!this._handle) {
2160      this.once('close', function close() {
2161        cb(new ERR_SERVER_NOT_RUNNING());
2162      });
2163    } else {
2164      this.once('close', cb);
2165    }
2166  }
2167
2168  if (this._handle) {
2169    this._handle.close();
2170    this._handle = null;
2171  }
2172
2173  if (this._usingWorkers) {
2174    let left = this._workers.length;
2175    const onWorkerClose = () => {
2176      if (--left !== 0) return;
2177
2178      this._connections = 0;
2179      this._emitCloseIfDrained();
2180    };
2181
2182    // Increment connections to be sure that, even if all sockets will be closed
2183    // during polling of workers, `close` event will be emitted only once.
2184    this._connections++;
2185
2186    // Poll workers
2187    for (let n = 0; n < this._workers.length; n++)
2188      this._workers[n].close(onWorkerClose);
2189  } else {
2190    this._emitCloseIfDrained();
2191  }
2192
2193  return this;
2194};
2195
2196Server.prototype[SymbolAsyncDispose] = async function() {
2197  if (!this._handle) {
2198    return;
2199  }
2200  return FunctionPrototypeCall(promisify(this.close), this);
2201};
2202
2203Server.prototype._emitCloseIfDrained = function() {
2204  debug('SERVER _emitCloseIfDrained');
2205
2206  if (this._handle || this._connections) {
2207    debug('SERVER handle? %j   connections? %d',
2208          !!this._handle, this._connections);
2209    return;
2210  }
2211
2212  defaultTriggerAsyncIdScope(this[async_id_symbol],
2213                             process.nextTick,
2214                             emitCloseNT,
2215                             this);
2216};
2217
2218
2219function emitCloseNT(self) {
2220  debug('SERVER: emit close');
2221  self.emit('close');
2222}
2223
2224
2225Server.prototype[EventEmitter.captureRejectionSymbol] = function(
2226  err, event, sock) {
2227
2228  switch (event) {
2229    case 'connection':
2230      sock.destroy(err);
2231      break;
2232    default:
2233      this.emit('error', err);
2234  }
2235};
2236
2237
2238// Legacy alias on the C++ wrapper object. This is not public API, so we may
2239// want to runtime-deprecate it at some point. There's no hurry, though.
2240ObjectDefineProperty(TCP.prototype, 'owner', {
2241  __proto__: null,
2242  get() { return this[owner_symbol]; },
2243  set(v) { return this[owner_symbol] = v; },
2244});
2245
2246ObjectDefineProperty(Socket.prototype, '_handle', {
2247  __proto__: null,
2248  get() { return this[kHandle]; },
2249  set(v) { return this[kHandle] = v; },
2250});
2251
2252Server.prototype._setupWorker = function(socketList) {
2253  this._usingWorkers = true;
2254  this._workers.push(socketList);
2255  socketList.once('exit', (socketList) => {
2256    const index = ArrayPrototypeIndexOf(this._workers, socketList);
2257    this._workers.splice(index, 1);
2258  });
2259};
2260
2261Server.prototype.ref = function() {
2262  this._unref = false;
2263
2264  if (this._handle)
2265    this._handle.ref();
2266
2267  return this;
2268};
2269
2270Server.prototype.unref = function() {
2271  this._unref = true;
2272
2273  if (this._handle)
2274    this._handle.unref();
2275
2276  return this;
2277};
2278
2279let _setSimultaneousAccepts;
2280let warnSimultaneousAccepts = true;
2281
2282if (isWindows) {
2283  let simultaneousAccepts;
2284
2285  _setSimultaneousAccepts = function(handle) {
2286    if (warnSimultaneousAccepts) {
2287      process.emitWarning(
2288        'net._setSimultaneousAccepts() is deprecated and will be removed.',
2289        'DeprecationWarning', 'DEP0121');
2290      warnSimultaneousAccepts = false;
2291    }
2292    if (handle === undefined) {
2293      return;
2294    }
2295
2296    if (simultaneousAccepts === undefined) {
2297      simultaneousAccepts = (process.env.NODE_MANY_ACCEPTS &&
2298                             process.env.NODE_MANY_ACCEPTS !== '0');
2299    }
2300
2301    if (handle._simultaneousAccepts !== simultaneousAccepts) {
2302      handle.setSimultaneousAccepts(!!simultaneousAccepts);
2303      handle._simultaneousAccepts = simultaneousAccepts;
2304    }
2305  };
2306} else {
2307  _setSimultaneousAccepts = function() {
2308    if (warnSimultaneousAccepts) {
2309      process.emitWarning(
2310        'net._setSimultaneousAccepts() is deprecated and will be removed.',
2311        'DeprecationWarning', 'DEP0121');
2312      warnSimultaneousAccepts = false;
2313    }
2314  };
2315}
2316
2317module.exports = {
2318  _createServerHandle: createServerHandle,
2319  _normalizeArgs: normalizeArgs,
2320  _setSimultaneousAccepts,
2321  get BlockList() {
2322    BlockList ??= require('internal/blocklist').BlockList;
2323    return BlockList;
2324  },
2325  get SocketAddress() {
2326    SocketAddress ??= require('internal/socketaddress').SocketAddress;
2327    return SocketAddress;
2328  },
2329  connect,
2330  createConnection: connect,
2331  createServer,
2332  isIP: isIP,
2333  isIPv4: isIPv4,
2334  isIPv6: isIPv6,
2335  Server,
2336  Socket,
2337  Stream: Socket, // Legacy naming
2338  getDefaultAutoSelectFamily,
2339  setDefaultAutoSelectFamily,
2340  getDefaultAutoSelectFamilyAttemptTimeout,
2341  setDefaultAutoSelectFamilyAttemptTimeout,
2342};
2343