├── .gitignore ├── README.md ├── package.json ├── LICENSE ├── test └── findPort.test.js └── lib └── findPort.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # find-port 2 | 3 | find an unused port in your localhost 4 | 5 | ```js 6 | var findPort = require('find-port') 7 | 8 | // scan a range 9 | findPort('127.0.0.1', 8000, 8003, function(ports) { 10 | console.log(ports) 11 | }) 12 | 13 | // scan explicitly 14 | findPort('127.0.0.1', [8000, 8011], function(ports) { 15 | console.log(ports) 16 | }) 17 | ``` 18 | 19 | - Since version 2.0.0 a local interface must be specified 20 | - This module is not designed to scan remote ports only local ones. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "find-port", 3 | "version": "3.0.0", 4 | "description": "find an unused port in your localhost", 5 | "main": "lib/findPort.js", 6 | "scripts": { 7 | "test": "npx mocha" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/kessler/find-port" 12 | }, 13 | "keywords": [ 14 | "port", 15 | "scanner", 16 | "portscanner", 17 | "net", 18 | "tcp" 19 | ], 20 | "author": "Yaniv Kessler", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/kessler/find-port/issues" 24 | }, 25 | "dependencies": { 26 | "async": "^3.2.3" 27 | }, 28 | "devDependencies": { 29 | "mocha": "^10.0.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Yaniv Kessler 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /test/findPort.test.js: -------------------------------------------------------------------------------- 1 | var findPort = require('../lib/findPort.js') 2 | var http = require('http') 3 | var assert = require('assert') 4 | 5 | describe('findPort', function () { 6 | 7 | var server; 8 | 9 | beforeEach(function (done) { 10 | server = http.createServer(function (request, response) { 11 | response.end() 12 | }) 13 | 14 | server.on('listening', done) 15 | 16 | server.listen(9000, '127.0.0.1') 17 | }) 18 | 19 | afterEach(function() { 20 | server.close() 21 | }) 22 | 23 | it('throws an error if callback is missing with one argument', function () { 24 | assert.throws(function () { 25 | findPort('127.0.0.1', 9000) 26 | }) 27 | }) 28 | 29 | it('throws an error if callback is missing with two arguments', function () { 30 | assert.throws(function () { 31 | findPort('127.0.0.1', 9000, 9002) 32 | }) 33 | }) 34 | 35 | it('finds unused ports in a range', function (done) { 36 | 37 | findPort('127.0.0.1', 9000, 9003, function(err, ports) { 38 | if (err) return done(err) 39 | assert.deepEqual(ports, [9001, 9002, 9003]) 40 | done() 41 | }) 42 | }) 43 | 44 | it('finds unused ports in an array', function (done) { 45 | 46 | findPort('127.0.0.1', [9000, 9003], function(err, ports) { 47 | if (err) return done(err) 48 | assert.deepEqual(ports, [9003]) 49 | done() 50 | }) 51 | }) 52 | }) -------------------------------------------------------------------------------- /lib/findPort.js: -------------------------------------------------------------------------------- 1 | var net = require('net') 2 | var async = require('async') 3 | var util = require('util') 4 | 5 | module.exports = function(host, start, endOrCallback, callback) { 6 | 7 | if (typeof endOrCallback === 'function') { 8 | callback = endOrCallback 9 | endOrCallback = 0 10 | } 11 | 12 | if (typeof callback !== 'function') { 13 | throw new Error('missing callback') 14 | } 15 | 16 | var ports 17 | 18 | if (Array.isArray(start)) { 19 | ports = start 20 | } else { 21 | ports = [] 22 | for (var i = start; i <= endOrCallback; i++) { 23 | ports.push(i) 24 | } 25 | } 26 | 27 | async.filter(ports, probe, callback) 28 | 29 | function probe(port, callback) { 30 | 31 | var server = net.createServer().listen(port, host) 32 | 33 | var calledOnce = false 34 | 35 | var timeoutRef = setTimeout(function() { 36 | calledOnce = true 37 | callback(null, false) 38 | }, 2000) 39 | 40 | timeoutRef.unref() 41 | 42 | var connected = false 43 | 44 | server.on('listening', function() { 45 | clearTimeout(timeoutRef) 46 | 47 | if (server) { 48 | server.close() 49 | } 50 | 51 | if (!calledOnce) { 52 | calledOnce = true 53 | callback(null, true) 54 | } 55 | }) 56 | 57 | server.on('error', function(err) { 58 | clearTimeout(timeoutRef) 59 | 60 | var result = true 61 | if (err.code === 'EADDRINUSE' || err.code === 'EACCES') { 62 | result = false 63 | } 64 | 65 | if (!calledOnce) { 66 | calledOnce = true 67 | callback(null, result) 68 | } 69 | }) 70 | } 71 | } 72 | --------------------------------------------------------------------------------