11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci// Copyright Joyent, Inc. and other Node contributors.
31cb0ef41Sopenharmony_ci//
41cb0ef41Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a
51cb0ef41Sopenharmony_ci// copy of this software and associated documentation files (the
61cb0ef41Sopenharmony_ci// "Software"), to deal in the Software without restriction, including
71cb0ef41Sopenharmony_ci// without limitation the rights to use, copy, modify, merge, publish,
81cb0ef41Sopenharmony_ci// distribute, sublicense, and/or sell copies of the Software, and to permit
91cb0ef41Sopenharmony_ci// persons to whom the Software is furnished to do so, subject to the
101cb0ef41Sopenharmony_ci// following conditions:
111cb0ef41Sopenharmony_ci//
121cb0ef41Sopenharmony_ci// The above copyright notice and this permission notice shall be included
131cb0ef41Sopenharmony_ci// in all copies or substantial portions of the Software.
141cb0ef41Sopenharmony_ci//
151cb0ef41Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
161cb0ef41Sopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
171cb0ef41Sopenharmony_ci// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
181cb0ef41Sopenharmony_ci// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
191cb0ef41Sopenharmony_ci// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
201cb0ef41Sopenharmony_ci// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
211cb0ef41Sopenharmony_ci// USE OR OTHER DEALINGS IN THE SOFTWARE.
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ciconst common = require('../common');
241cb0ef41Sopenharmony_ciconst assert = require('assert');
251cb0ef41Sopenharmony_ciconst cluster = require('cluster');
261cb0ef41Sopenharmony_ciconst dgram = require('dgram');
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci// Without an explicit bind, send() causes an implicit bind, which always
291cb0ef41Sopenharmony_ci// generate a unique per-socket ephemeral port. An explicit bind to a port
301cb0ef41Sopenharmony_ci// number causes all sockets bound to that number to share a port.
311cb0ef41Sopenharmony_ci//
321cb0ef41Sopenharmony_ci// The 2 workers that call bind() will share a port, the two workers that do
331cb0ef41Sopenharmony_ci// not will not share a port, so primary will see 3 unique source ports.
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci// Note that on Windows, clustered dgram is not supported. Since explicit
361cb0ef41Sopenharmony_ci// binding causes the dgram to be clustered, don't fork the workers that bind.
371cb0ef41Sopenharmony_ci// This is a useful test, still, because it demonstrates that by avoiding
381cb0ef41Sopenharmony_ci// clustering, client (ephemeral, implicitly bound) dgram sockets become
391cb0ef41Sopenharmony_ci// supported while using cluster, though servers still cause the primary
401cb0ef41Sopenharmony_ci// to error with ENOTSUP.
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ciif (cluster.isPrimary) {
431cb0ef41Sopenharmony_ci  let messages = 0;
441cb0ef41Sopenharmony_ci  const ports = {};
451cb0ef41Sopenharmony_ci  const pids = [];
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci  const target = dgram.createSocket('udp4');
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci  const done = common.mustCall(function() {
501cb0ef41Sopenharmony_ci    cluster.disconnect();
511cb0ef41Sopenharmony_ci    target.close();
521cb0ef41Sopenharmony_ci  });
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci  target.on('message', function(buf, rinfo) {
551cb0ef41Sopenharmony_ci    if (pids.includes(buf.toString()))
561cb0ef41Sopenharmony_ci      return;
571cb0ef41Sopenharmony_ci    pids.push(buf.toString());
581cb0ef41Sopenharmony_ci    messages++;
591cb0ef41Sopenharmony_ci    ports[rinfo.port] = true;
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci    if (common.isWindows && messages === 2) {
621cb0ef41Sopenharmony_ci      assert.strictEqual(Object.keys(ports).length, 2);
631cb0ef41Sopenharmony_ci      done();
641cb0ef41Sopenharmony_ci    }
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci    if (!common.isWindows && messages === 4) {
671cb0ef41Sopenharmony_ci      assert.strictEqual(Object.keys(ports).length, 3);
681cb0ef41Sopenharmony_ci      done();
691cb0ef41Sopenharmony_ci    }
701cb0ef41Sopenharmony_ci  });
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci  target.on('listening', function() {
731cb0ef41Sopenharmony_ci    cluster.fork({ PORT: target.address().port });
741cb0ef41Sopenharmony_ci    cluster.fork({ PORT: target.address().port });
751cb0ef41Sopenharmony_ci    if (!common.isWindows) {
761cb0ef41Sopenharmony_ci      cluster.fork({ BOUND: 'y', PORT: target.address().port });
771cb0ef41Sopenharmony_ci      cluster.fork({ BOUND: 'y', PORT: target.address().port });
781cb0ef41Sopenharmony_ci    }
791cb0ef41Sopenharmony_ci  });
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci  target.bind({ port: 0, exclusive: true });
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci  return;
841cb0ef41Sopenharmony_ci}
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ciconst source = dgram.createSocket('udp4');
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_cisource.on('close', function() {
891cb0ef41Sopenharmony_ci  clearInterval(interval);
901cb0ef41Sopenharmony_ci});
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ciif (process.env.BOUND === 'y') {
931cb0ef41Sopenharmony_ci  source.bind(0);
941cb0ef41Sopenharmony_ci} else {
951cb0ef41Sopenharmony_ci  // Cluster doesn't know about exclusive sockets, so it won't close them. This
961cb0ef41Sopenharmony_ci  // is expected, its the same situation for timers, outgoing tcp connections,
971cb0ef41Sopenharmony_ci  // etc, which also keep workers alive after disconnect was requested.
981cb0ef41Sopenharmony_ci  source.unref();
991cb0ef41Sopenharmony_ci}
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ciassert(process.env.PORT);
1021cb0ef41Sopenharmony_ciconst buf = Buffer.from(process.pid.toString());
1031cb0ef41Sopenharmony_ciconst interval = setInterval(() => {
1041cb0ef41Sopenharmony_ci  source.send(buf, process.env.PORT, '127.0.0.1');
1051cb0ef41Sopenharmony_ci}, 1).unref();
106