| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 |
- /**
- * @fileOverview
- * A simple promises-based check to see if a TCP port is already in use.
- */
- 'use strict';
- // define the exports first to avoid cyclic dependencies.
- exports.check = check;
- exports.waitUntilFreeOnHost = waitUntilFreeOnHost;
- exports.waitUntilFree = waitUntilFree;
- exports.waitUntilUsedOnHost = waitUntilUsedOnHost;
- exports.waitUntilUsed = waitUntilUsed;
- exports.waitForStatus = waitForStatus;
- var is = require('is2');
- var net = require('net');
- var util = require('util');
- var debug = require('debug')('tcp-port-used');
- // Global Values
- var TIMEOUT = 2000;
- var RETRYTIME = 250;
- function getDeferred() {
- var resolve, reject, promise = new Promise(function(res, rej) {
- resolve = res;
- reject = rej;
- });
- return {
- resolve: resolve,
- reject: reject,
- promise: promise
- };
- }
- /**
- * Creates an options object from all the possible arguments
- * @private
- * @param {Number} port a valid TCP port number
- * @param {String} host The DNS name or IP address.
- * @param {Boolean} status The desired in use status to wait for: false === not in use, true === in use
- * @param {Number} retryTimeMs the retry interval in milliseconds - defaultis is 200ms
- * @param {Number} timeOutMs the amount of time to wait until port is free default is 1000ms
- * @return {Object} An options object with all the above parameters as properties.
- */
- function makeOptionsObj(port, host, inUse, retryTimeMs, timeOutMs) {
- var opts = {};
- opts.port = port;
- opts.host = host;
- opts.inUse = inUse;
- opts.retryTimeMs = retryTimeMs;
- opts.timeOutMs = timeOutMs;
- return opts;
- }
- /**
- * Checks if a TCP port is in use by creating the socket and binding it to the
- * target port. Once bound, successfully, it's assume the port is availble.
- * After the socket is closed or in error, the promise is resolved.
- * Note: you have to be super user to correctly test system ports (0-1023).
- * @param {Number|Object} port The port you are curious to see if available. If an object, must have the parameters as properties.
- * @param {String} [host] May be a DNS name or IP address. Default '127.0.0.1'
- * @return {Object} A deferred Q promise.
- *
- * Example usage:
- *
- * var tcpPortUsed = require('tcp-port-used');
- * tcpPortUsed.check(22, '127.0.0.1')
- * .then(function(inUse) {
- * debug('Port 22 usage: '+inUse);
- * }, function(err) {
- * console.error('Error on check: '+util.inspect(err));
- * });
- */
- function check(port, host) {
- var deferred = getDeferred();
- var inUse = true;
- var client;
- var opts;
- if (!is.obj(port)) {
- opts = makeOptionsObj(port, host);
- } else {
- opts = port;
- }
- if (!is.port(opts.port)) {
- debug('Error invalid port: '+util.inspect(opts.port));
- deferred.reject(new Error('invalid port: '+util.inspect(opts.port)));
- return deferred.promise;
- }
- if (is.nullOrUndefined(opts.host)) {
- debug('set host address to default 127.0.0.1');
- opts.host = '127.0.0.1';
- }
- function cleanUp() {
- if (client) {
- client.removeAllListeners('connect');
- client.removeAllListeners('error');
- client.end();
- client.destroy();
- client.unref();
- }
- //debug('listeners removed from client socket');
- }
- function onConnectCb() {
- //debug('check - promise resolved - in use');
- deferred.resolve(inUse);
- cleanUp();
- }
- function onErrorCb(err) {
- if (err.code !== 'ECONNREFUSED') {
- //debug('check - promise rejected, error: '+err.message);
- deferred.reject(err);
- } else {
- //debug('ECONNREFUSED');
- inUse = false;
- //debug('check - promise resolved - not in use');
- deferred.resolve(inUse);
- }
- cleanUp();
- }
- client = new net.Socket();
- client.once('connect', onConnectCb);
- client.once('error', onErrorCb);
- client.connect({port: opts.port, host: opts.host}, function() {});
- return deferred.promise;
- }
- /**
- * Creates a deferred promise and fulfills it only when the socket's usage
- * equals status in terms of 'in use' (false === not in use, true === in use).
- * Will retry on an interval specified in retryTimeMs. Note: you have to be
- * super user to correctly test system ports (0-1023).
- * @param {Number|Object} port a valid TCP port number, if an object, has all the parameters described as properties.
- * @param {String} host The DNS name or IP address.
- * @param {Boolean} status The desired in use status to wait for false === not in use, true === in use
- * @param {Number} [retryTimeMs] the retry interval in milliseconds - defaultis is 200ms
- * @param {Number} [timeOutMs] the amount of time to wait until port is free default is 1000ms
- * @return {Object} A deferred promise from the Q library.
- *
- * Example usage:
- *
- * var tcpPortUsed = require('tcp-port-used');
- * tcpPortUsed.waitForStatus(44204, 'some.host.com', true, 500, 4000)
- * .then(function() {
- * console.log('Port 44204 is now in use.');
- * }, function(err) {
- * console.log('Error: ', error.message);
- * });
- */
- function waitForStatus(port, host, inUse, retryTimeMs, timeOutMs) {
- var deferred = getDeferred();
- var timeoutId;
- var timedout = false;
- var retryId;
- // the first arument may be an object, if it is not, make an object
- var opts;
- if (is.obj(port)) {
- opts = port;
- } else {
- opts = makeOptionsObj(port, host, inUse, retryTimeMs, timeOutMs);
- }
- //debug('opts:'+util.inspect(opts);
- if (!is.bool(opts.inUse)) {
- deferred.reject(new Error('inUse must be a boolean'));
- return deferred.promise;
- }
- if (!is.positiveInt(opts.retryTimeMs)) {
- opts.retryTimeMs = RETRYTIME;
- debug('set retryTime to default '+RETRYTIME+'ms');
- }
- if (!is.positiveInt(opts.timeOutMs)) {
- opts.timeOutMs = TIMEOUT;
- debug('set timeOutMs to default '+TIMEOUT+'ms');
- }
- function cleanUp() {
- if (timeoutId) {
- clearTimeout(timeoutId);
- }
- if (retryId) {
- clearTimeout(retryId);
- }
- }
- function timeoutFunc() {
- timedout = true;
- cleanUp();
- deferred.reject(new Error('timeout'));
- }
- timeoutId = setTimeout(timeoutFunc, opts.timeOutMs);
- function doCheck() {
- check(opts.port, opts.host)
- .then(function(inUse) {
- if (timedout) {
- return;
- }
- //debug('doCheck inUse: '+inUse);
- //debug('doCheck opts.inUse: '+opts.inUse);
- if (inUse === opts.inUse) {
- deferred.resolve();
- cleanUp();
- return;
- } else {
- retryId = setTimeout(function() { doCheck(); }, opts.retryTimeMs);
- return;
- }
- }, function(err) {
- if (timedout) {
- return;
- }
- deferred.reject(err);
- cleanUp();
- });
- }
- doCheck();
- return deferred.promise;
- }
- /**
- * Creates a deferred promise and fulfills it only when the socket is free.
- * Will retry on an interval specified in retryTimeMs.
- * Note: you have to be super user to correctly test system ports (0-1023).
- * @param {Number} port a valid TCP port number
- * @param {String} [host] The hostname or IP address of where the socket is.
- * @param {Number} [retryTimeMs] the retry interval in milliseconds - defaultis is 100ms.
- * @param {Number} [timeOutMs] the amount of time to wait until port is free. Default 300ms.
- * @return {Object} A deferred promise from the q library.
- *
- * Example usage:
- *
- * var tcpPortUsed = require('tcp-port-used');
- * tcpPortUsed.waitUntilFreeOnHost(44203, 'some.host.com', 500, 4000)
- * .then(function() {
- * console.log('Port 44203 is now free.');
- * }, function(err) {
- * console.loh('Error: ', error.message);
- * });
- */
- function waitUntilFreeOnHost(port, host, retryTimeMs, timeOutMs) {
- // the first arument may be an object, if it is not, make an object
- var opts;
- if (is.obj(port)) {
- opts = port;
- opts.inUse = false;
- } else {
- opts = makeOptionsObj(port, host, false, retryTimeMs, timeOutMs);
- }
- return waitForStatus(opts);
- }
- /**
- * For compatibility with previous version of the module, that did not provide
- * arguements for hostnames. The host is set to the localhost '127.0.0.1'.
- * @param {Number|Object} port a valid TCP port number. If an object, must contain all the parameters as properties.
- * @param {Number} [retryTimeMs] the retry interval in milliseconds - defaultis is 100ms.
- * @param {Number} [timeOutMs] the amount of time to wait until port is free. Default 300ms.
- * @return {Object} A deferred promise from the q library.
- *
- * Example usage:
- *
- * var tcpPortUsed = require('tcp-port-used');
- * tcpPortUsed.waitUntilFree(44203, 500, 4000)
- * .then(function() {
- * console.log('Port 44203 is now free.');
- * }, function(err) {
- * console.loh('Error: ', error.message);
- * });
- */
- function waitUntilFree(port, retryTimeMs, timeOutMs) {
- // the first arument may be an object, if it is not, make an object
- var opts;
- if (is.obj(port)) {
- opts = port;
- opts.host = '127.0.0.1';
- opts.inUse = false;
- } else {
- opts = makeOptionsObj(port, '127.0.0.1', false, retryTimeMs, timeOutMs);
- }
- return waitForStatus(opts);
- }
- /**
- * Creates a deferred promise and fulfills it only when the socket is used.
- * Will retry on an interval specified in retryTimeMs.
- * Note: you have to be super user to correctly test system ports (0-1023).
- * @param {Number|Object} port a valid TCP port number. If an object, must contain all the parameters as properties.
- * @param {Number} [retryTimeMs] the retry interval in milliseconds - defaultis is 500ms
- * @param {Number} [timeOutMs] the amount of time to wait until port is free
- * @return {Object} A deferred promise from the q library.
- *
- * Example usage:
- *
- * var tcpPortUsed = require('tcp-port-used');
- * tcpPortUsed.waitUntilUsedOnHost(44204, 'some.host.com', 500, 4000)
- * .then(function() {
- * console.log('Port 44204 is now in use.');
- * }, function(err) {
- * console.log('Error: ', error.message);
- * });
- */
- function waitUntilUsedOnHost(port, host, retryTimeMs, timeOutMs) {
- // the first arument may be an object, if it is not, make an object
- var opts;
- if (is.obj(port)) {
- opts = port;
- opts.inUse = true;
- } else {
- opts = makeOptionsObj(port, host, true, retryTimeMs, timeOutMs);
- }
- return waitForStatus(opts);
- }
- /**
- * For compatibility to previous version of module which did not have support
- * for host addresses. This function works only for localhost.
- * @param {Number} port a valid TCP port number. If an Object, must contain all the parameters as properties.
- * @param {Number} [retryTimeMs] the retry interval in milliseconds - defaultis is 500ms
- * @param {Number} [timeOutMs] the amount of time to wait until port is free
- * @return {Object} A deferred promise from the q library.
- *
- * Example usage:
- *
- * var tcpPortUsed = require('tcp-port-used');
- * tcpPortUsed.waitUntilUsed(44204, 500, 4000)
- * .then(function() {
- * console.log('Port 44204 is now in use.');
- * }, function(err) {
- * console.log('Error: ', error.message);
- * });
- */
- function waitUntilUsed(port, retryTimeMs, timeOutMs) {
- // the first arument may be an object, if it is not, make an object
- var opts;
- if (is.obj(port)) {
- opts = port;
- opts.host = '127.0.0.1';
- opts.inUse = true;
- } else {
- opts = makeOptionsObj(port, '127.0.0.1', true, retryTimeMs, timeOutMs);
- }
- return waitUntilUsedOnHost(opts);
- }
|