Socket
Socket
Sign inDemoInstall

pick-port

Package Overview
Dependencies
2
Maintainers
2
Versions
10
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.0.0 to 2.0.1

2

lib/index.d.ts

@@ -1,2 +0,2 @@

export type Type = 'udp' | 'tcp';
export type Type = 'tcp' | 'udp';
export declare function pickPort({ type, ip, minPort, maxPort, reserveTimeout, }: {

@@ -3,0 +3,0 @@ type: Type;

@@ -5,2 +5,3 @@ "use strict";

const net = require("node:net");
const crypto = require("node:crypto");
const Logger_1 = require("./Logger");

@@ -40,7 +41,5 @@ const tcp_1 = require("./tcp");

// Take a random port in the range.
// NOTE: Use last reserved port as initial value since it will be incremented
// at the end of the loop below.
let port = lastReservedPort === undefined
? Math.floor(Math.random() * (maxPort + 1 - minPort)) + minPort
: lastReservedPort;
// NOTE: Use last reserved port (if any) as initial value since it will be
// incremented at the end of the loop below.
let port = lastReservedPort ?? crypto.randomInt(minPort, maxPort + 1);
let retries = maxPort - minPort + 1;

@@ -52,6 +51,9 @@ while (--retries >= 0) {

}
const hash = generateHash(type, ip, port);
// If current port is reserved, try next one.
if (isReserved(type, ip, port)) {
if (isReserved(hash)) {
continue;
}
// Optimistically reserve the port.
reserve(hash);
try {

@@ -68,8 +70,10 @@ switch (type) {

}
reserve(type, ip, port, reserveTimeout);
logger.debug(`pickPort() | got available port [type:${type}, ip:${ip}, port:${port}]`);
lastReservedPort = port;
logger.debug(`pickPort() | got available port [type:${type}, ip:${ip}, port:${port}]`);
// Unreserve the reserved port after given timeout.
setTimeout(() => unreserve(hash), reserveTimeout * 1000);
return port;
}
catch (error) {
unreserve(hash);
if (error.code === 'EADDRINUSE') {

@@ -89,13 +93,19 @@ logger.debug(`pickPort() | port in use [type:${type}, ip:${ip}, port:${port}]`);

exports.pickPort = pickPort;
function reserve(type, ip, port, reserveTimeout) {
const hash = generateHash(type, ip, port);
function generateHash(type, ip, port) {
return `${type}:${ip}:${port}`;
}
function reserve(hash) {
if (isReserved(hash)) {
throw new Error(`reserve() | hash '${hash}' is already reserved`);
}
reserved.add(hash);
setTimeout(() => reserved.delete(hash), reserveTimeout * 1000);
}
function isReserved(type, ip, port) {
const hash = generateHash(type, ip, port);
function unreserve(hash) {
if (!isReserved(hash)) {
throw new Error(`unreserve() | hash '${hash}' is not reserved`);
}
reserved.delete(hash);
}
function isReserved(hash) {
return reserved.has(hash);
}
function generateHash(type, ip, port) {
return `${type}:${ip}:${port}`;
}

@@ -70,8 +70,9 @@ "use strict";

});
expect([port1, port2]).toEqual(expect.arrayContaining([minPort, maxPort]));
// No more ports available during 1 second so this should reject.
expect([port1, port2]).toEqual(expect.arrayContaining([2001, 2002]));
// No more ports available during reserve time second so this should
// reject.
await expect((0, __1.pickPort)({ type, ip, minPort, maxPort, reserveTimeout })).rejects.toThrow();
// However it should work if a separate range is given.
await expect((0, __1.pickPort)({ type, ip, minPort: 3001, maxPort: 3002, reserveTimeout })).resolves.toBeNumber();
// After 1 second, ports should be available again.
// After reserve time, ports should be available again.
await new Promise(resolve => setTimeout(resolve, reserveTimeout * 1000));

@@ -81,2 +82,33 @@ await expect((0, __1.pickPort)({ type, ip, minPort, maxPort, reserveTimeout })).resolves.toBeNumber();

}, 4000);
test('pick N ports at the same time succeeds', async () => {
for (const type of allTypes) {
const ip = '127.0.0.1';
const minPort = 3001;
const maxPort = 3003;
const reserveTimeout = 1;
await expect(Promise.all([
(0, __1.pickPort)({
type,
ip,
minPort,
maxPort,
reserveTimeout,
}),
(0, __1.pickPort)({
type,
ip,
minPort,
maxPort,
reserveTimeout,
}),
(0, __1.pickPort)({
type,
ip,
minPort,
maxPort,
reserveTimeout,
}),
])).resolves.toEqual(expect.arrayContaining([3001, 3002, 3003]));
}
}, 2000);
/**

@@ -83,0 +115,0 @@ * Not all reported IPs are bindable. Verify it by binding on them in a random

{
"name": "pick-port",
"version": "2.0.0",
"version": "2.0.1",
"description": "Get a free TCP or UDP port for the given IP address",

@@ -12,3 +12,3 @@ "author": "José Luis Millán <jmillan@aliax.net> (https://github.com/jmillan)",

"type": "git",
"url": "https://github.com/versatica/pick-port.git"
"url": "git+https://github.com/versatica/pick-port.git"
},

@@ -71,3 +71,3 @@ "bugs": {

"@types/jest": "^29.5.11",
"@types/node": "^20.10.8",
"@types/node": "^20.11.0",
"@typescript-eslint/eslint-plugin": "^6.18.1",

@@ -77,4 +77,4 @@ "@typescript-eslint/parser": "^6.18.1",

"eslint-config-prettier": "^9.1.0",
"eslint-plugin-jest": "^27.6.1",
"eslint-plugin-prettier": "^5.1.2",
"eslint-plugin-jest": "^27.6.2",
"eslint-plugin-prettier": "^5.1.3",
"jest": "^29.7.0",

@@ -81,0 +81,0 @@ "jest-extended": "^4.0.2",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc