tcpie 9.0.1 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,12 +1,13 @@
1
1
  # tcpie
2
- [![](https://img.shields.io/npm/v/tcpie.svg?style=flat)](https://www.npmjs.org/package/tcpie) [![](https://img.shields.io/npm/dm/tcpie.svg)](https://www.npmjs.org/package/tcpie)
2
+ [![](https://img.shields.io/npm/v/tcpie.svg?style=flat)](https://www.npmjs.org/package/tcpie) [![](https://img.shields.io/npm/dm/tcpie.svg)](https://www.npmjs.org/package/tcpie) [![](https://packagephobia.com/badge?p=tcpie)](https://packagephobia.com/result?p=tcpie)
3
+
3
4
  > Ping any TCP port
4
5
 
5
6
  tcpie is a tool to measure latency and verify the reliabilty of a TCP connection. It does so by initiating a handshake followed by an immediately termination of the socket. While many existing tools require raw socket access, tcpie runs fine in user space. An API for use as a module is also provided.
6
7
 
7
8
  ## CLI
9
+
8
10
  ### Installation
9
- Install [Node.js](https://nodejs.org) and then do:
10
11
  ```
11
12
  $ npm i -g tcpie
12
13
  ```
@@ -24,52 +25,27 @@ connected to google.com:443 seq=5 srcport=59057 time=10.4 ms
24
25
  5 handshakes attempted, 5 succeeded, 0% failed
25
26
  rtt min/avg/max/stdev = 10.012/10.970/12.854/1.190 ms
26
27
  ```
27
- ## Usage
28
- ```
29
- Usage: tcpie [options] host[:port]|url [port|22]
30
-
31
- Options:
32
-
33
- -v, --version output version
34
- -c, --count <n> number of connects (default: infinite)
35
- -i, --interval <n> wait n seconds between connects (default: 1)
36
- -t, --timeout <n> connection timeout in seconds (default: 3)
37
- -T, --timestamp add timestamps to output
38
- -f, --flood flood mode, connect as fast as possible
39
- -C, --no-color disable color output
40
-
41
- Examples:
42
28
 
43
- $ tcpie google.com
44
- $ tcpie -i .1 8.8.8.8:53
45
- $ tcpie -c5 -t.05 aspmx.l.google.com 25
46
- $ tcpie -i.2 https://google.com
29
+ ## API
47
30
 
48
- ```
49
-
50
- ## Module API
51
- ### Installation
52
- ```
53
- $ npm i tcpie
54
- ```
55
- ### Example
31
+ ### Usage
56
32
  ```js
57
- const tcpie = require('tcpie');
58
- const pie = tcpie('google.com', 443, {count: 10, interval: 500, timeout: 2000});
33
+ import {tcpie} from "tcpie";
34
+ const pie = tcpie("google.com", 443, {count: 10, interval: 500, timeout: 2000});
59
35
 
60
- pie.on('connect', function(stats) {
61
- console.info('connect', stats);
62
- }).on('error', function(err, stats) {
36
+ pie.on("connect", function(stats) {
37
+ console.info("connect", stats);
38
+ }).on("error", function(err, stats) {
63
39
  console.error(err, stats);
64
- }).on('timeout', function(stats) {
65
- console.info('timeout', stats);
66
- }).on('end', function(stats) {
40
+ }).on("timeout", function(stats) {
41
+ console.info("timeout", stats);
42
+ }).on("end", function(stats) {
67
43
  console.info(stats);
68
44
  // -> {
69
45
  // -> sent: 10,
70
46
  // -> success: 10,
71
47
  // -> failed: 0,
72
- // -> target: { host: 'google.com', port: 443 }
48
+ // -> target: { host: "google.com", port: 443 }
73
49
  // -> }
74
50
  }).start();
75
51
  ```
package/bin/tcpie.js ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ import {createRequire} from 'module';const require = createRequire(import.meta.url);
3
+ var vt=Object.create;var k=Object.defineProperty;var xt=Object.getOwnPropertyDescriptor;var Ot=Object.getOwnPropertyNames;var wt=Object.getPrototypeOf,It=Object.prototype.hasOwnProperty;var tt=(t,o)=>()=>(o||t((o={exports:{}}).exports,o),o.exports);var Ct=(t,o,e,s)=>{if(o&&typeof o=="object"||typeof o=="function")for(let n of Ot(o))!It.call(t,n)&&n!==e&&k(t,n,{get:()=>o[n],enumerable:!(s=xt(o,n))||s.enumerable});return t};var ot=(t,o,e)=>(e=t!=null?vt(wt(t)):{},Ct(o||!t||!t.__esModule?k(e,"default",{value:t,enumerable:!0}):e,t));var it=tt((Xt,rt)=>{(function(){"use strict";function t(o){if(!Array.isArray(o))throw new TypeError("stdev()::invalid input argument. Must provide an array.");var e=o.length,s=0,n=0,c=0,i=0;if(e<2)return 0;for(var N=0;N<e;N++)s+=1,i=o[N]-n,n+=i/s,c+=i*(o[N]-n);return Math.sqrt(c/(s-1))}rt.exports=t})()});var pt=tt((eo,lt)=>{"use strict";function Ft(t,o){var e=t;o.slice(0,-1).forEach(function(n){e=e[n]||{}});var s=o[o.length-1];return s in e}function ft(t){return typeof t=="number"||/^0x[0-9a-f]+$/i.test(t)?!0:/^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(t)}function ut(t,o){return o==="constructor"&&typeof t[o]=="function"||o==="__proto__"}lt.exports=function(t,o){o||(o={});var e={bools:{},strings:{},unknownFn:null};typeof o.unknown=="function"&&(e.unknownFn=o.unknown),typeof o.boolean=="boolean"&&o.boolean?e.allBools=!0:[].concat(o.boolean).filter(Boolean).forEach(function(r){e.bools[r]=!0});var s={};function n(r){return s[r].some(function(m){return e.bools[m]})}Object.keys(o.alias||{}).forEach(function(r){s[r]=[].concat(o.alias[r]),s[r].forEach(function(m){s[m]=[r].concat(s[r].filter(function(w){return m!==w}))})}),[].concat(o.string).filter(Boolean).forEach(function(r){e.strings[r]=!0,s[r]&&[].concat(s[r]).forEach(function(m){e.strings[m]=!0})});var c=o.default||{},i={_:[]};function N(r,m){return e.allBools&&/^--[^=]+$/.test(m)||e.strings[r]||e.bools[r]||s[r]}function P(r,m,w){for(var u=r,S=0;S<m.length-1;S++){var x=m[S];if(ut(u,x))return;u[x]===void 0&&(u[x]={}),(u[x]===Object.prototype||u[x]===Number.prototype||u[x]===String.prototype)&&(u[x]={}),u[x]===Array.prototype&&(u[x]=[]),u=u[x]}var I=m[m.length-1];ut(u,I)||((u===Object.prototype||u===Number.prototype||u===String.prototype)&&(u={}),u===Array.prototype&&(u=[]),u[I]===void 0||e.bools[I]||typeof u[I]=="boolean"?u[I]=w:Array.isArray(u[I])?u[I].push(w):u[I]=[u[I],w])}function _(r,m,w){if(!(w&&e.unknownFn&&!N(r,w)&&e.unknownFn(w)===!1)){var u=!e.strings[r]&&ft(m)?Number(m):m;P(i,r.split("."),u),(s[r]||[]).forEach(function(S){P(i,S.split("."),u)})}}Object.keys(e.bools).forEach(function(r){_(r,c[r]===void 0?!1:c[r])});var y=[];t.indexOf("--")!==-1&&(y=t.slice(t.indexOf("--")+1),t=t.slice(0,t.indexOf("--")));for(var h=0;h<t.length;h++){var f=t[h],p,T;if(/^--.+=/.test(f)){var j=f.match(/^--([^=]+)=([\s\S]*)$/);p=j[1];var V=j[2];e.bools[p]&&(V=V!=="false"),_(p,V,f)}else if(/^--no-.+/.test(f))p=f.match(/^--no-(.+)/)[1],_(p,!1,f);else if(/^--.+/.test(f))p=f.match(/^--(.+)/)[1],T=t[h+1],T!==void 0&&!/^(-|--)[^-]/.test(T)&&!e.bools[p]&&!e.allBools&&(!s[p]||!n(p))?(_(p,T,f),h+=1):/^(true|false)$/.test(T)?(_(p,T==="true",f),h+=1):_(p,e.strings[p]?"":!0,f);else if(/^-[^-]+/.test(f)){for(var $=f.slice(1,-1).split(""),L=!1,b=0;b<$.length;b++){if(T=f.slice(b+2),T==="-"){_($[b],T,f);continue}if(/[A-Za-z]/.test($[b])&&T[0]==="="){_($[b],T.slice(1),f),L=!0;break}if(/[A-Za-z]/.test($[b])&&/-?\d+(\.\d*)?(e-?\d+)?$/.test(T)){_($[b],T,f),L=!0;break}if($[b+1]&&$[b+1].match(/\W/)){_($[b],f.slice(b+2),f),L=!0;break}else _($[b],e.strings[$[b]]?"":!0,f)}p=f.slice(-1)[0],!L&&p!=="-"&&(t[h+1]&&!/^(-|--)[^-]/.test(t[h+1])&&!e.bools[p]&&(!s[p]||!n(p))?(_(p,t[h+1],f),h+=1):t[h+1]&&/^(true|false)$/.test(t[h+1])?(_(p,t[h+1]==="true",f),h+=1):_(p,e.strings[p]?"":!0,f))}else if((!e.unknownFn||e.unknownFn(f)!==!1)&&i._.push(e.strings._||!ft(f)?f:Number(f)),o.stopEarly){i._.push.apply(i._,t.slice(h+1));break}}return Object.keys(c).forEach(function(r){Ft(i,r.split("."))||(P(i,r.split("."),c[r]),(s[r]||[]).forEach(function(m){P(i,m.split("."),c[r])}))}),o["--"]?i["--"]=y.slice():y.forEach(function(r){i._.push(r)}),i}});var et=!0;function nt(){et=!1}function q(t,o,e){return et?`\x1B[${o}m${t}\x1B[${e}m`:t}var C=t=>q(t,31,39),K=t=>q(t,32,39),st=t=>q(t,33,39);var Tt=ot(it(),1);import{isIP as Dt}from"node:net";import{lookup as Ut}from"node:dns";import M,{exit as R,argv as Yt,stdin as J,stdout as Q,stderr as yt}from"node:process";import gt from"node:events";import Nt from"node:net";import At from"node:util";var A=function(t,o,e){if(!(this instanceof A))return new A;if(typeof t!="string")throw new Error("host is required");o===void 0&&(o=80),this.host=t,this.port=o,this.opts={interval:1e3,timeout:3e3,count:1/0,...e},this.stats={sent:0,success:0,failed:0}};At.inherits(A,gt.EventEmitter);A.prototype.start=function t(o){return o||(this.stats.sent=0,this.stats.success=0,this.stats.failed=0),this._next=setTimeout(t.bind(this,!0),this.opts.interval),this._done=!1,this._abort=!1,this._socket=new Nt.Socket,this._startTime=performance.now(),this._socket.setTimeout(this.opts.timeout),this._socket.on("timeout",()=>{this._done||(this._done=!0,this.stats.sent++,this.stats.failed++,this.emit("timeout",H(this,this)),this._socket.destroy(),B(this))}),this._socket.on("error",e=>{this._done||(this._done=!0,this.stats.sent++,this.stats.failed++,this.emit("error",e,H(this,this)),this._socket.destroy(),B(this))}),this._socket.connect(this.port,this.host,()=>{this._done||(this._done=!0,this.stats.sent++,this.stats.success++,this.stats.rtt=performance.now()-this._startTime,this.emit("connect",H(this,this)),this._socket.end(),B(this))}),this};A.prototype.stop=function(){return this._abort=!0,this._socket.end(),B(this),this};function ct(...t){return new A(...t)}function H(t,o){let e=t.stats;return e.target={host:t.host,port:t.port},e.socket={localAddress:o.localAddress,localPort:o.localPort,remoteAddress:o.remoteAddress,remotePort:o.remotePort},e}function B(t){(t._abort||t.stats.failed+t.stats.success>=t.opts.count)&&(t._next&&clearTimeout(t._next),t.emit("end",{sent:t.stats.sent,success:t.stats.success,failed:t.stats.failed,target:{host:t.host,port:t.port}}))}var Et=ot(pt(),1);import{readFileSync as St}from"node:fs";var W;function at(t,o="tcp"){if(typeof t!="string")throw new Error("expected a 'string'");W||(W=JSON.parse(St(new URL("services.json",import.meta.url))));let e=W[t.toLowerCase()];if(!e)return null;let s=e.ports.find(n=>/\w+$/.exec(n)[0]===o);return s?{port:Number(/^\d+/.exec(s)[0]),protocol:/\w+$/.exec(s)[0],description:e.description}:null}import z from"node:process";import Mt from"node:os";import mt from"node:tty";function E(t,o=globalThis.Deno?globalThis.Deno.args:z.argv){let e=t.startsWith("-")?"":t.length===1?"-":"--",s=o.indexOf(e+t),n=o.indexOf("--");return s!==-1&&(n===-1||s<n)}var{env:a}=z,G;E("no-color")||E("no-colors")||E("color=false")||E("color=never")?G=0:(E("color")||E("colors")||E("color=true")||E("color=always"))&&(G=1);function Pt(){if("FORCE_COLOR"in a)return a.FORCE_COLOR==="true"?1:a.FORCE_COLOR==="false"?0:a.FORCE_COLOR.length===0?1:Math.min(Number.parseInt(a.FORCE_COLOR,10),3)}function Lt(t){return t===0?!1:{level:t,hasBasic:!0,has256:t>=2,has16m:t>=3}}function Bt(t,{streamIsTTY:o,sniffFlags:e=!0}={}){let s=Pt();s!==void 0&&(G=s);let n=e?G:s;if(n===0)return 0;if(e){if(E("color=16m")||E("color=full")||E("color=truecolor"))return 3;if(E("color=256"))return 2}if("TF_BUILD"in a&&"AGENT_NAME"in a)return 1;if(t&&!o&&n===void 0)return 0;let c=n||0;if(a.TERM==="dumb")return c;if(z.platform==="win32"){let i=Mt.release().split(".");return Number(i[0])>=10&&Number(i[2])>=10586?Number(i[2])>=14931?3:2:1}if("CI"in a)return"GITHUB_ACTIONS"in a?3:["TRAVIS","CIRCLECI","APPVEYOR","GITLAB_CI","BUILDKITE","DRONE"].some(i=>i in a)||a.CI_NAME==="codeship"?1:c;if("TEAMCITY_VERSION"in a)return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(a.TEAMCITY_VERSION)?1:0;if(a.COLORTERM==="truecolor"||a.TERM==="xterm-kitty")return 3;if("TERM_PROGRAM"in a){let i=Number.parseInt((a.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(a.TERM_PROGRAM){case"iTerm.app":return i>=3?3:2;case"Apple_Terminal":return 2}}return/-256(color)?$/i.test(a.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(a.TERM)||"COLORTERM"in a?1:c}function dt(t,o={}){let e=Bt(t,{streamIsTTY:t&&t.isTTY,...o});return Lt(e)}var Gt={stdout:dt({isTTY:mt.isatty(1)}),stderr:dt({isTTY:mt.isatty(2)})},ht=Gt;var l=(0,Et.default)(Yt.slice(2),{boolean:["color","C","timestamp","T","flood","f","version","v"]}),Vt="10.0.0",qt=1,D=3,Kt=0,Ht=22,Wt=[""," Usage: tcpie [options] host[:port]|url [port|22]",""," Options:",""," -v, --version output version"," -c, --count <n> number of connects (default: infinite)"," -i, --interval <n> wait n seconds between connects (default: 1)"," -t, --timeout <n> connection timeout in seconds (default: 3)"," -T, --timestamp add timestamps to output"," -f, --flood flood mode, connect as fast as possible"," -C, --no-color disable color output",""," Examples:",""," $ tcpie google.com"," $ tcpie -i .1 8.8.8.8:53"," $ tcpie -c5 -t.05 aspmx.l.google.com 25"," $ tcpie -i.2 https://google.com","",""].join(`
4
+ `);l.v&&(console.info(Vt),R(0));(!l._.length||l._.length>2||l._[1]&&Number.isNaN(parseInt(l._[1])))&&Rt();var d=l._[0],F={},O=parseInt(l._[1]),X=!1,Y=[],v;typeof d!="string"&&Rt();var U=/^(.+):(\d+)$/.exec(d);U&&U.length===3&&!O&&(d=U[1],O=U[2]);if(/.+:\/\/.+/.test(d)){let{protocol:t,hostname:o,port:e}=new URL(d),s=t.replace(":","");d=o,O=e??at(s).port,O||(g(C("ERROR:"),`Unknown protocol '${s}'`),R(1)),d||(g(C("ERROR:"),`Missing host in '${d}'`),R(1))}O||(O=Ht);(l.count||l.c)&&(F.count=parseInt(l.count||l.c));(l.interval||l.i)&&(F.interval=$t(l.interval||l.i));(l.timeout||l.t)&&(F.timeout=$t(l.timeout||l.t));(l.flood||l.f)&&(F.interval=0);(l.C||!ht.stdout)&&nt();Dt(d)?(bt(d,d,O),_t(d,O,F)):Ut(d,(t,o)=>{t?(t.code==="ENOTFOUND"?g(C("ERROR:"),`Host '${d}' not found`):g(C("ERROR:"),t.code,t.syscall||""),R(1)):(bt(d,o,O),_t(d,O,F))});function _t(t,o,e){let s=ct(t,o,e);s.on("error",(n,c)=>{v=c,g(C("error connecting to",`${c.target.host}:${c.target.port}`),`seq=${c.sent}`,`error=${C(n.code)}`)}).on("connect",n=>{v=n,Y.push(n.rtt),g(K("connected to",`${n.target.host}:${n.target.port}`),`seq=${n.sent}`,n.socket.localPort!==void 0?`srcport=${n.socket.localPort}`:"",`time=${zt(n.rtt.toFixed(qt))}`)}).on("timeout",n=>{v=n,g(C("timeout connecting to",`${n.target.host}:${n.target.port}`),`seq=${n.sent}`,n.socket.localPort&&`srcport=${n.socket.localPort}`)}),J.isTTY?(J.setRawMode(!0),J.on("data",n=>{let c=[3,4,26,28];for(let i=0;i<n.length;i++)c.includes(n[i])&&Z()})):(M.on("SIGINT",R),M.on("SIGQUIT",R),M.on("SIGTERM",R),M.on("SIGTSTP",R)),M.on("exit",Z),s.on("end",Z).start()}function bt(t,o,e){g("TCPIE",t,`(${o})`,"port",String(e))}function Z(){let t=0,o=1/0,e=0,s,n;if(X&&R(v.success===0&&1||0),v&&v.sent>0){for(let c of Y)c<=o&&(o=c.toFixed(D)),c>=e&&(e=c.toFixed(D)),t+=c;s=(t/Y.length).toFixed(D),n=(0,Tt.default)(Y).toFixed(D),o===1/0&&(o="0"),Number.isNaN(s)&&(s="0"),X=!0,g(`
5
+ ---`,d,"tcpie statistics","---",`
6
+ ${v.sent}`,"handshakes attempted,",v.success||"0","succeeded,",`${(v.failed/v.sent*100).toFixed(Kt)}% failed`,`
7
+ rtt min/avg/max/stdev =`,`${o}/${s}/${e}/${n}`,"ms"),R(v.success===0&&1||0)}else R(1)}function zt(t){return t>=150?`${C(t)} ms`:t>=75?`${st(t)} ms`:`${K(t)} ms`}function g(...t){t=t.filter(Boolean),(l.timeout||l.T)&&t[0][0]!==`
8
+ `&&t.unshift(Jt()),t.push(`
9
+ `),(Q._type==="pipe"&&X?yt:Q).write(t.join(" "))}function Rt(){Q.write(Wt),R(1)}function $t(t){return parseFloat(t)*1e3}function Jt(){let t=new Date,o=t.getFullYear(),e=t.getMonth()+1,s=t.getDate(),n=t.getHours(),c=t.getMinutes(),i=t.getSeconds();return e<10&&(e=`0${e}`),s<10&&(s=`0${s}`),n<10&&(n=`0${n}`),c<10&&(c=`0${c}`),i<10&&(i=`0${i}`),`${o}-${e}-${s} ${n}:${c}:${i}`}
package/index.js CHANGED
@@ -1,22 +1,18 @@
1
- "use strict";
2
-
3
- const events = require("events");
4
- const net = require("net");
5
- const util = require("util");
1
+ import events from "node:events";
2
+ import net from "node:net";
3
+ import util from "node:util";
6
4
 
7
5
  const Tcpie = function(host, port, opts) {
8
6
  if (!(this instanceof Tcpie)) return new Tcpie();
9
7
  if (typeof host !== "string") throw new Error("host is required");
10
- if (typeof port === "undefined") port = 80;
8
+ if (port === undefined) port = 80;
11
9
 
12
10
  this.host = host;
13
11
  this.port = port;
14
12
 
15
- this.opts = Object.assign({
16
- interval: 1000,
13
+ this.opts = {interval: 1000,
17
14
  timeout: 3000,
18
- count: Infinity
19
- }, opts);
15
+ count: Infinity, ...opts};
20
16
 
21
17
  this.stats = {
22
18
  sent: 0,
@@ -38,7 +34,7 @@ Tcpie.prototype.start = function start(subsequent) {
38
34
  this._done = false;
39
35
  this._abort = false;
40
36
  this._socket = new net.Socket();
41
- this._startTime = now();
37
+ this._startTime = performance.now();
42
38
 
43
39
  this._socket.setTimeout(this.opts.timeout);
44
40
  this._socket.on("timeout", () => {
@@ -68,7 +64,7 @@ Tcpie.prototype.start = function start(subsequent) {
68
64
  this._done = true;
69
65
  this.stats.sent++;
70
66
  this.stats.success++;
71
- this.stats.rtt = (now() - this._startTime) / 1e6;
67
+ this.stats.rtt = (performance.now() - this._startTime);
72
68
  this.emit("connect", addDetails(this, this));
73
69
  this._socket.end();
74
70
  checkEnd(this);
@@ -85,9 +81,9 @@ Tcpie.prototype.stop = function stop() {
85
81
  return this;
86
82
  };
87
83
 
88
- module.exports = function(host, port, opts) {
89
- return new Tcpie(host, port, opts);
90
- };
84
+ export function tcpie(...args) {
85
+ return new Tcpie(...args);
86
+ }
91
87
 
92
88
  // add details to stats object
93
89
  function addDetails(that, socket) {
@@ -124,9 +120,3 @@ function checkEnd(that) {
124
120
  });
125
121
  }
126
122
  }
127
-
128
- // get current timestamp in nanoseconds
129
- function now() {
130
- const hrtime = process.hrtime();
131
- return hrtime[0] * 1e9 + hrtime[1];
132
- }
package/package.json CHANGED
@@ -1,46 +1,34 @@
1
1
  {
2
2
  "name": "tcpie",
3
- "version": "9.0.1",
3
+ "version": "10.0.0",
4
4
  "description": "Ping any TCP port",
5
- "author": "silverwind <me@silverwind.io> (https://github.com/silverwind)",
5
+ "author": "silverwind <me@silverwind.io>",
6
6
  "repository": "silverwind/tcpie",
7
7
  "license": "BSD-2-Clause",
8
- "main": "index.js",
9
- "bin": "tcpie.js",
10
- "scripts": {
11
- "test": "make test"
12
- },
8
+ "exports": "./index.js",
9
+ "bin": "./bin/tcpie.js",
10
+ "type": "module",
11
+ "sideEffects": false,
13
12
  "engines": {
14
- "node": ">=10"
13
+ "node": ">=16"
15
14
  },
16
15
  "files": [
17
- "index.js",
18
- "tcpie.js"
19
- ],
20
- "keywords": [
21
- "tcp",
22
- "port",
23
- "socket",
24
- "ping",
25
- "network",
26
- "networking",
27
- "connect",
28
- "connection",
29
- "test",
30
- "testing"
16
+ "./index.js",
17
+ "./bin/tcpie.js"
31
18
  ],
32
19
  "dependencies": {
33
- "chalk": "4.0.0",
34
20
  "compute-stdev": "1.0.0",
35
- "epipebomb": "1.0.0",
36
- "minimist": "1.2.5",
37
- "port-numbers": "6.0.0"
21
+ "glowie": "1.0.1",
22
+ "minimist": "1.2.8",
23
+ "port-numbers": "7.0.0",
24
+ "supports-color": "9.3.1"
38
25
  },
39
26
  "devDependencies": {
40
- "eslint": "7.1.0",
41
- "eslint-config-silverwind": "13.4.2",
42
- "jest": "26.0.1",
43
- "updates": "10.2.13",
44
- "versions": "8.2.10"
27
+ "eslint": "8.43.0",
28
+ "eslint-config-silverwind": "73.0.4",
29
+ "updates": "14.2.8",
30
+ "versions": "11.0.1",
31
+ "vitest": "0.32.2",
32
+ "vitest-config-silverwind": "1.0.0"
45
33
  }
46
34
  }
package/LICENSE DELETED
@@ -1,22 +0,0 @@
1
- Copyright (c) silverwind
2
- All rights reserved.
3
-
4
- Redistribution and use in source and binary forms, with or without
5
- modification, are permitted provided that the following conditions are met:
6
-
7
- 1. Redistributions of source code must retain the above copyright notice, this
8
- list of conditions and the following disclaimer.
9
- 2. Redistributions in binary form must reproduce the above copyright notice,
10
- this list of conditions and the following disclaimer in the documentation
11
- and/or other materials provided with the distribution.
12
-
13
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17
- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/tcpie.js DELETED
@@ -1,245 +0,0 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
-
4
- const pkg = require("./package.json");
5
-
6
- // avoid EPIPE on partially consumed streams
7
- require("epipebomb")();
8
-
9
- const chalk = require("chalk");
10
- const net = require("net");
11
- const dns = require("dns");
12
- const stdev = require("compute-stdev");
13
- const tcpie = require(".");
14
-
15
- const args = require("minimist")(process.argv.slice(2), {
16
- boolean: [
17
- "color", "C",
18
- "timestamp", "T",
19
- "flood", "f",
20
- "version", "v"
21
- ]
22
- });
23
-
24
- const DIGITS_LINE = 1;
25
- const DIGITS_STATS = 3;
26
- const DIGITS_PERC = 0;
27
- const DEFAULT_PORT = 22;
28
-
29
- const usage = [
30
- "",
31
- " Usage: tcpie [options] host[:port]|url [port|22]",
32
- "",
33
- " Options:",
34
- "",
35
- " -v, --version output version",
36
- " -c, --count <n> number of connects (default: infinite)",
37
- " -i, --interval <n> wait n seconds between connects (default: 1)",
38
- " -t, --timeout <n> connection timeout in seconds (default: 3)",
39
- " -T, --timestamp add timestamps to output",
40
- " -f, --flood flood mode, connect as fast as possible",
41
- " -C, --no-color disable color output",
42
- "",
43
- " Examples:",
44
- "",
45
- " $ tcpie google.com",
46
- " $ tcpie -i .1 8.8.8.8:53",
47
- " $ tcpie -c5 -t.05 aspmx.l.google.com 25",
48
- " $ tcpie -i.2 https://google.com",
49
- "",
50
- ""
51
- ].join("\n");
52
-
53
- if (args.v) {
54
- process.stdout.write(`${pkg.version}\n`);
55
- process.exit(0);
56
- }
57
-
58
- if (!args._.length || args._.length > 2 || (args._[1] && isNaN(parseInt(args._[1])))) {
59
- help();
60
- }
61
-
62
- let host = args._[0];
63
- const opts = {};
64
- let port = parseInt(args._[1]);
65
- let printed = false;
66
- const rtts = [];
67
- let stats;
68
-
69
- if (typeof host !== "string") {
70
- help();
71
- }
72
-
73
- // host:port syntax
74
- const matches = /^(.+):(\d+)$/.exec(host);
75
- if (matches && matches.length === 3 && !port) {
76
- host = matches[1];
77
- port = matches[2];
78
- }
79
-
80
- // url syntax
81
- if (/.+:\/\/.+/.test(host)) {
82
- const url = require("url").parse(host);
83
- const proto = url.protocol.replace(":", "");
84
- host = url.host;
85
- port = url.port || require("port-numbers").getPort(proto).port;
86
- if (!port) {
87
- writeLine(chalk.red("ERROR:"), `Unknown protocol '${proto}'`);
88
- process.exit(1);
89
- }
90
- if (!host) {
91
- writeLine(chalk.red("ERROR:"), `Missing host in '${host}'`);
92
- }
93
- }
94
-
95
- if (!port) port = DEFAULT_PORT;
96
- if (args.count || args.c) opts.count = parseInt(args.count || args.c);
97
- if (args.interval || args.i) opts.interval = secondsToMs(args.interval || args.i);
98
- if (args.timeout || args.t) opts.timeout = secondsToMs(args.timeout || args.t);
99
- if (args.flood || args.f) opts.interval = 0;
100
- if (args.C) chalk.enabled = false;
101
-
102
- // Do a DNS lookup and start the connects
103
- if (!net.isIP(host)) {
104
- dns.lookup(host, (err, address) => {
105
- if (!err) {
106
- printStart(host, address, port);
107
- run(host, port, opts);
108
- } else {
109
- if (err.code === "ENOTFOUND") writeLine(chalk.red("ERROR:"), `Host '${host}' not found`);
110
- else writeLine(chalk.red("ERROR:"), err.code, err.syscall || "");
111
- process.exit(1);
112
- }
113
- });
114
- } else {
115
- printStart(host, host, port);
116
- run(host, port, opts);
117
- }
118
-
119
- function run(host, port, opts) {
120
- const pie = tcpie(host, port, opts);
121
-
122
- pie.on("error", (err, data) => {
123
- stats = data;
124
- writeLine(
125
- chalk.red("error connecting to", `${data.target.host}:${data.target.port}`),
126
- `seq=${data.sent}`,
127
- `error=${chalk.red(err.code)}`
128
- );
129
- }).on("connect", data => {
130
- stats = data;
131
- rtts.push(data.rtt);
132
- writeLine(
133
- chalk.green("connected to", `${data.target.host}:${data.target.port}`),
134
- `seq=${data.sent}`,
135
- (data.socket.localPort !== undefined) ? `srcport=${data.socket.localPort}` : "",
136
- `time=${colorRTT(data.rtt.toFixed(DIGITS_LINE))}`,
137
- );
138
- }).on("timeout", data => {
139
- stats = data;
140
- writeLine(
141
- chalk.red("timeout connecting to", `${data.target.host}:${data.target.port}`),
142
- `seq=${data.sent}`,
143
- data.socket.localPort && `srcport=${data.socket.localPort}`
144
- );
145
- });
146
-
147
- if (process.stdin.isTTY) {
148
- process.stdin.setRawMode(true);
149
- process.stdin.on("data", bytes => {
150
- // http://nemesis.lonestar.org/reference/telecom/codes/ascii.html
151
- const exitCodes = [
152
- 3, // SIGINT
153
- 4, // EOF
154
- 26, // SIGTSTP
155
- 28, // SIGQUIT
156
- ];
157
- for (let i = 0; i < bytes.length; i++) {
158
- if (exitCodes.includes(bytes[i])) printEnd();
159
- }
160
- });
161
- } else {
162
- process.on("SIGINT", process.exit);
163
- process.on("SIGQUIT", process.exit);
164
- process.on("SIGTERM", process.exit);
165
- process.on("SIGTSTP", process.exit);
166
- }
167
-
168
- process.on("exit", printEnd);
169
- pie.on("end", printEnd).start();
170
- }
171
-
172
- function printStart(host, address, port) {
173
- writeLine(pkg.name.toUpperCase(), host, `(${address})`, "port", String(port));
174
- }
175
-
176
- function printEnd() {
177
- let sum = 0, min = Infinity, max = 0, avg, dev;
178
-
179
- if (printed) process.exit(stats.success === 0 && 1 || 0);
180
-
181
- if (stats && stats.sent > 0) {
182
- rtts.forEach(rtt => {
183
- if (rtt <= min) min = rtt.toFixed(DIGITS_STATS);
184
- if (rtt >= max) max = rtt.toFixed(DIGITS_STATS);
185
- sum += rtt;
186
- });
187
-
188
- avg = (sum / rtts.length).toFixed(DIGITS_STATS);
189
- dev = stdev(rtts).toFixed(DIGITS_STATS);
190
-
191
- if (min === Infinity) min = "0";
192
- if (isNaN(avg)) avg = "0";
193
-
194
- printed = true;
195
-
196
- writeLine(
197
- "\n---", host, `${pkg.name} statistics`, "---",
198
- `\n${stats.sent}`, "handshakes attempted,", stats.success || "0", "succeeded,",
199
- `${((stats.failed / stats.sent) * 100).toFixed(DIGITS_PERC)}% failed`,
200
- "\nrtt min/avg/max/stdev =", `${min}/${avg}/${max}/${dev}`, "ms"
201
- );
202
-
203
- process.exit(stats.success === 0 && 1 || 0);
204
- } else {
205
- process.exit(1);
206
- }
207
- }
208
-
209
- function colorRTT(rtt) {
210
- return `${chalk[rtt >= 150 ? "red" : rtt >= 75 ? "yellow" : "green"](rtt)} ms`;
211
- }
212
-
213
- function writeLine(...arg) {
214
- arg = arg.filter(string => Boolean(string));
215
- if ((args.timeout || args.T) && arg[0][0] !== "\n") arg.unshift(timestamp());
216
- arg.push("\n");
217
- const stream = (process.stdout._type === "pipe" && printed) ? process.stderr : process.stdout;
218
- stream.write(arg.join(" "));
219
- }
220
-
221
- function help() {
222
- process.stdout.write(usage);
223
- process.exit(1);
224
- }
225
-
226
- function secondsToMs(s) {
227
- return (parseFloat(s) * 1000);
228
- }
229
-
230
- function timestamp() {
231
- const now = new Date();
232
- const year = now.getFullYear();
233
- let month = now.getMonth() + 1;
234
- let day = now.getDate();
235
- let hrs = now.getHours();
236
- let mins = now.getMinutes();
237
- let secs = now.getSeconds();
238
-
239
- if (month < 10) month = `0${month}`;
240
- if (day < 10) day = `0${day}`;
241
- if (hrs < 10) hrs = `0${hrs}`;
242
- if (mins < 10) mins = `0${mins}`;
243
- if (secs < 10) secs = `0${secs}`;
244
- return `${year}-${month}-${day} ${hrs}:${mins}:${secs}`;
245
- }