├── .eslintrc.json
├── .gitattributes
├── .github
└── workflows
│ └── build-test-coverage.yml
├── .gitignore
├── .npmignore
├── .travis.yml
├── CONTRIBUTING.md
├── Gruntfile.js
├── LICENSE
├── README.md
├── babel.config.json
├── examples
├── example.js
├── example2.js
└── example_win_de_v6.js
├── index.js
├── lib
├── builder
│ ├── factory.js
│ ├── linux.js
│ ├── mac.js
│ └── win.js
├── parser
│ ├── base.js
│ ├── factory.js
│ ├── linux.js
│ ├── mac.js
│ └── win.js
├── ping-pcap.js
├── ping-promise.js
└── ping-sys.js
├── package-lock.json
├── package.json
└── test
├── fixture
├── answer.json
├── linux
│ ├── .gitdirectory
│ └── en
│ │ ├── sample1.txt
│ │ ├── sample2.txt
│ │ ├── sample3.txt
│ │ ├── v6_sample1.txt
│ │ └── v6_sample2.txt
├── macos
│ ├── .gitdirectory
│ └── en
│ │ ├── sample1.txt
│ │ └── sample2.txt
└── window
│ ├── .gitdirectory
│ ├── de
│ └── v6_sample.txt
│ ├── en
│ └── sample1.txt
│ ├── fr
│ ├── sample1.txt
│ └── sample2.txt
│ ├── ja
│ ├── sample1.txt
│ └── sample2.txt
│ ├── ru
│ └── sample1.txt
│ └── zh
│ ├── sample1.txt
│ ├── sample2.txt
│ └── sample3.txt
├── load-fixture-path.js
└── test-ping.js
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "globals": {
3 | "__dirname": false,
4 | "__filename": false,
5 | "arguments": false,
6 | "Buffer": false,
7 | "clearImmediate": false,
8 | "clearInterval": false,
9 | "clearTimeout": false,
10 | "console": false,
11 | "exports": true,
12 | "GLOBAL": false,
13 | "global": false,
14 | "Intl": false,
15 | "module": false,
16 | "process": false,
17 | "require": false,
18 | "root": false,
19 | "setImmediate": false,
20 | "setInterval": false,
21 | "setTimeout": false,
22 | "addEventListener": false,
23 | "alert": false,
24 | "AnalyserNode": false,
25 | "AnimationEvent": false,
26 | "applicationCache": false,
27 | "ApplicationCache": false,
28 | "ApplicationCacheErrorEvent": false,
29 | "atob": false,
30 | "Attr": false,
31 | "Audio": false,
32 | "AudioBuffer": false,
33 | "AudioBufferSourceNode": false,
34 | "AudioContext": false,
35 | "AudioDestinationNode": false,
36 | "AudioListener": false,
37 | "AudioNode": false,
38 | "AudioParam": false,
39 | "AudioProcessingEvent": false,
40 | "AutocompleteErrorEvent": false,
41 | "BarProp": false,
42 | "BatteryManager": false,
43 | "BeforeUnloadEvent": false,
44 | "BiquadFilterNode": false,
45 | "Blob": false,
46 | "blur": false,
47 | "btoa": false,
48 | "Cache": false,
49 | "caches": false,
50 | "CacheStorage": false,
51 | "cancelAnimationFrame": false,
52 | "CanvasGradient": false,
53 | "CanvasPattern": false,
54 | "CanvasRenderingContext2D": false,
55 | "CDATASection": false,
56 | "ChannelMergerNode": false,
57 | "ChannelSplitterNode": false,
58 | "CharacterData": false,
59 | "clientInformation": false,
60 | "ClientRect": false,
61 | "ClientRectList": false,
62 | "ClipboardEvent": false,
63 | "close": false,
64 | "closed": false,
65 | "CloseEvent": false,
66 | "Comment": false,
67 | "CompositionEvent": false,
68 | "confirm": false,
69 | "ConvolverNode": false,
70 | "crypto": false,
71 | "Crypto": false,
72 | "CryptoKey": false,
73 | "CSS": false,
74 | "CSSFontFaceRule": false,
75 | "CSSImportRule": false,
76 | "CSSKeyframeRule": false,
77 | "CSSKeyframesRule": false,
78 | "CSSMediaRule": false,
79 | "CSSPageRule": false,
80 | "CSSRule": false,
81 | "CSSRuleList": false,
82 | "CSSStyleDeclaration": false,
83 | "CSSStyleRule": false,
84 | "CSSStyleSheet": false,
85 | "CSSSupportsRule": false,
86 | "CSSUnknownRule": false,
87 | "CSSViewportRule": false,
88 | "CustomEvent": false,
89 | "DataTransfer": false,
90 | "DataTransferItem": false,
91 | "DataTransferItemList": false,
92 | "Debug": false,
93 | "defaultStatus": false,
94 | "defaultstatus": false,
95 | "DelayNode": false,
96 | "DeviceMotionEvent": false,
97 | "DeviceOrientationEvent": false,
98 | "devicePixelRatio": false,
99 | "dispatchEvent": false,
100 | "document": false,
101 | "Document": false,
102 | "DocumentFragment": false,
103 | "DocumentType": false,
104 | "DOMError": false,
105 | "DOMException": false,
106 | "DOMImplementation": false,
107 | "DOMParser": false,
108 | "DOMSettableTokenList": false,
109 | "DOMStringList": false,
110 | "DOMStringMap": false,
111 | "DOMTokenList": false,
112 | "DragEvent": false,
113 | "DynamicsCompressorNode": false,
114 | "Element": false,
115 | "ElementTimeControl": false,
116 | "ErrorEvent": false,
117 | "event": false,
118 | "Event": false,
119 | "EventSource": false,
120 | "EventTarget": false,
121 | "external": false,
122 | "fetch": false,
123 | "File": false,
124 | "FileError": false,
125 | "FileList": false,
126 | "FileReader": false,
127 | "find": false,
128 | "focus": false,
129 | "FocusEvent": false,
130 | "FontFace": false,
131 | "FormData": false,
132 | "frameElement": false,
133 | "frames": false,
134 | "GainNode": false,
135 | "Gamepad": false,
136 | "GamepadButton": false,
137 | "GamepadEvent": false,
138 | "getComputedStyle": false,
139 | "getSelection": false,
140 | "HashChangeEvent": false,
141 | "Headers": false,
142 | "history": false,
143 | "History": false,
144 | "HTMLAllCollection": false,
145 | "HTMLAnchorElement": false,
146 | "HTMLAppletElement": false,
147 | "HTMLAreaElement": false,
148 | "HTMLAudioElement": false,
149 | "HTMLBaseElement": false,
150 | "HTMLBlockquoteElement": false,
151 | "HTMLBodyElement": false,
152 | "HTMLBRElement": false,
153 | "HTMLButtonElement": false,
154 | "HTMLCanvasElement": false,
155 | "HTMLCollection": false,
156 | "HTMLContentElement": false,
157 | "HTMLDataListElement": false,
158 | "HTMLDetailsElement": false,
159 | "HTMLDialogElement": false,
160 | "HTMLDirectoryElement": false,
161 | "HTMLDivElement": false,
162 | "HTMLDListElement": false,
163 | "HTMLDocument": false,
164 | "HTMLElement": false,
165 | "HTMLEmbedElement": false,
166 | "HTMLFieldSetElement": false,
167 | "HTMLFontElement": false,
168 | "HTMLFormControlsCollection": false,
169 | "HTMLFormElement": false,
170 | "HTMLFrameElement": false,
171 | "HTMLFrameSetElement": false,
172 | "HTMLHeadElement": false,
173 | "HTMLHeadingElement": false,
174 | "HTMLHRElement": false,
175 | "HTMLHtmlElement": false,
176 | "HTMLIFrameElement": false,
177 | "HTMLImageElement": false,
178 | "HTMLInputElement": false,
179 | "HTMLIsIndexElement": false,
180 | "HTMLKeygenElement": false,
181 | "HTMLLabelElement": false,
182 | "HTMLLayerElement": false,
183 | "HTMLLegendElement": false,
184 | "HTMLLIElement": false,
185 | "HTMLLinkElement": false,
186 | "HTMLMapElement": false,
187 | "HTMLMarqueeElement": false,
188 | "HTMLMediaElement": false,
189 | "HTMLMenuElement": false,
190 | "HTMLMetaElement": false,
191 | "HTMLMeterElement": false,
192 | "HTMLModElement": false,
193 | "HTMLObjectElement": false,
194 | "HTMLOListElement": false,
195 | "HTMLOptGroupElement": false,
196 | "HTMLOptionElement": false,
197 | "HTMLOptionsCollection": false,
198 | "HTMLOutputElement": false,
199 | "HTMLParagraphElement": false,
200 | "HTMLParamElement": false,
201 | "HTMLPictureElement": false,
202 | "HTMLPreElement": false,
203 | "HTMLProgressElement": false,
204 | "HTMLQuoteElement": false,
205 | "HTMLScriptElement": false,
206 | "HTMLSelectElement": false,
207 | "HTMLShadowElement": false,
208 | "HTMLSourceElement": false,
209 | "HTMLSpanElement": false,
210 | "HTMLStyleElement": false,
211 | "HTMLTableCaptionElement": false,
212 | "HTMLTableCellElement": false,
213 | "HTMLTableColElement": false,
214 | "HTMLTableElement": false,
215 | "HTMLTableRowElement": false,
216 | "HTMLTableSectionElement": false,
217 | "HTMLTemplateElement": false,
218 | "HTMLTextAreaElement": false,
219 | "HTMLTitleElement": false,
220 | "HTMLTrackElement": false,
221 | "HTMLUListElement": false,
222 | "HTMLUnknownElement": false,
223 | "HTMLVideoElement": false,
224 | "IDBCursor": false,
225 | "IDBCursorWithValue": false,
226 | "IDBDatabase": false,
227 | "IDBEnvironment": false,
228 | "IDBFactory": false,
229 | "IDBIndex": false,
230 | "IDBKeyRange": false,
231 | "IDBObjectStore": false,
232 | "IDBOpenDBRequest": false,
233 | "IDBRequest": false,
234 | "IDBTransaction": false,
235 | "IDBVersionChangeEvent": false,
236 | "Image": false,
237 | "ImageBitmap": false,
238 | "ImageData": false,
239 | "indexedDB": false,
240 | "innerHeight": false,
241 | "innerWidth": false,
242 | "InputEvent": false,
243 | "InputMethodContext": false,
244 | "KeyboardEvent": false,
245 | "length": false,
246 | "localStorage": false,
247 | "location": false,
248 | "Location": false,
249 | "locationbar": false,
250 | "matchMedia": false,
251 | "MediaElementAudioSourceNode": false,
252 | "MediaEncryptedEvent": false,
253 | "MediaError": false,
254 | "MediaKeyError": false,
255 | "MediaKeyEvent": false,
256 | "MediaKeyMessageEvent": false,
257 | "MediaKeys": false,
258 | "MediaKeySession": false,
259 | "MediaKeyStatusMap": false,
260 | "MediaKeySystemAccess": false,
261 | "MediaList": false,
262 | "MediaQueryList": false,
263 | "MediaQueryListEvent": false,
264 | "MediaSource": false,
265 | "MediaStreamAudioDestinationNode": false,
266 | "MediaStreamAudioSourceNode": false,
267 | "MediaStreamEvent": false,
268 | "MediaStreamTrack": false,
269 | "menubar": false,
270 | "MessageChannel": false,
271 | "MessageEvent": false,
272 | "MessagePort": false,
273 | "MIDIAccess": false,
274 | "MIDIConnectionEvent": false,
275 | "MIDIInput": false,
276 | "MIDIInputMap": false,
277 | "MIDIMessageEvent": false,
278 | "MIDIOutput": false,
279 | "MIDIOutputMap": false,
280 | "MIDIPort": false,
281 | "MimeType": false,
282 | "MimeTypeArray": false,
283 | "MouseEvent": false,
284 | "moveBy": false,
285 | "moveTo": false,
286 | "MutationEvent": false,
287 | "MutationObserver": false,
288 | "MutationRecord": false,
289 | "name": false,
290 | "NamedNodeMap": false,
291 | "navigator": false,
292 | "Navigator": false,
293 | "Node": false,
294 | "NodeFilter": false,
295 | "NodeIterator": false,
296 | "NodeList": false,
297 | "Notification": false,
298 | "OfflineAudioCompletionEvent": false,
299 | "OfflineAudioContext": false,
300 | "offscreenBuffering": false,
301 | "onbeforeunload": true,
302 | "onblur": true,
303 | "onerror": true,
304 | "onfocus": true,
305 | "onload": true,
306 | "onresize": true,
307 | "onunload": true,
308 | "open": false,
309 | "openDatabase": false,
310 | "opener": false,
311 | "opera": false,
312 | "Option": false,
313 | "OscillatorNode": false,
314 | "outerHeight": false,
315 | "outerWidth": false,
316 | "PageTransitionEvent": false,
317 | "pageXOffset": false,
318 | "pageYOffset": false,
319 | "parent": false,
320 | "Path2D": false,
321 | "performance": false,
322 | "Performance": false,
323 | "PerformanceEntry": false,
324 | "PerformanceMark": false,
325 | "PerformanceMeasure": false,
326 | "PerformanceNavigation": false,
327 | "PerformanceResourceTiming": false,
328 | "PerformanceTiming": false,
329 | "PeriodicWave": false,
330 | "Permissions": false,
331 | "PermissionStatus": false,
332 | "personalbar": false,
333 | "Plugin": false,
334 | "PluginArray": false,
335 | "PopStateEvent": false,
336 | "postMessage": false,
337 | "print": false,
338 | "ProcessingInstruction": false,
339 | "ProgressEvent": false,
340 | "prompt": false,
341 | "PushManager": false,
342 | "PushSubscription": false,
343 | "RadioNodeList": false,
344 | "Range": false,
345 | "ReadableByteStream": false,
346 | "ReadableStream": false,
347 | "removeEventListener": false,
348 | "Request": false,
349 | "requestAnimationFrame": false,
350 | "resizeBy": false,
351 | "resizeTo": false,
352 | "Response": false,
353 | "RTCIceCandidate": false,
354 | "RTCSessionDescription": false,
355 | "screen": false,
356 | "Screen": false,
357 | "screenLeft": false,
358 | "ScreenOrientation": false,
359 | "screenTop": false,
360 | "screenX": false,
361 | "screenY": false,
362 | "ScriptProcessorNode": false,
363 | "scroll": false,
364 | "scrollbars": false,
365 | "scrollBy": false,
366 | "scrollTo": false,
367 | "scrollX": false,
368 | "scrollY": false,
369 | "SecurityPolicyViolationEvent": false,
370 | "Selection": false,
371 | "self": false,
372 | "ServiceWorker": false,
373 | "ServiceWorkerContainer": false,
374 | "ServiceWorkerRegistration": false,
375 | "sessionStorage": false,
376 | "ShadowRoot": false,
377 | "SharedWorker": false,
378 | "showModalDialog": false,
379 | "speechSynthesis": false,
380 | "SpeechSynthesisEvent": false,
381 | "SpeechSynthesisUtterance": false,
382 | "status": false,
383 | "statusbar": false,
384 | "stop": false,
385 | "Storage": false,
386 | "StorageEvent": false,
387 | "styleMedia": false,
388 | "StyleSheet": false,
389 | "StyleSheetList": false,
390 | "SubtleCrypto": false,
391 | "SVGAElement": false,
392 | "SVGAltGlyphDefElement": false,
393 | "SVGAltGlyphElement": false,
394 | "SVGAltGlyphItemElement": false,
395 | "SVGAngle": false,
396 | "SVGAnimateColorElement": false,
397 | "SVGAnimatedAngle": false,
398 | "SVGAnimatedBoolean": false,
399 | "SVGAnimatedEnumeration": false,
400 | "SVGAnimatedInteger": false,
401 | "SVGAnimatedLength": false,
402 | "SVGAnimatedLengthList": false,
403 | "SVGAnimatedNumber": false,
404 | "SVGAnimatedNumberList": false,
405 | "SVGAnimatedPathData": false,
406 | "SVGAnimatedPoints": false,
407 | "SVGAnimatedPreserveAspectRatio": false,
408 | "SVGAnimatedRect": false,
409 | "SVGAnimatedString": false,
410 | "SVGAnimatedTransformList": false,
411 | "SVGAnimateElement": false,
412 | "SVGAnimateMotionElement": false,
413 | "SVGAnimateTransformElement": false,
414 | "SVGAnimationElement": false,
415 | "SVGCircleElement": false,
416 | "SVGClipPathElement": false,
417 | "SVGColor": false,
418 | "SVGColorProfileElement": false,
419 | "SVGColorProfileRule": false,
420 | "SVGComponentTransferFunctionElement": false,
421 | "SVGCSSRule": false,
422 | "SVGCursorElement": false,
423 | "SVGDefsElement": false,
424 | "SVGDescElement": false,
425 | "SVGDiscardElement": false,
426 | "SVGDocument": false,
427 | "SVGElement": false,
428 | "SVGElementInstance": false,
429 | "SVGElementInstanceList": false,
430 | "SVGEllipseElement": false,
431 | "SVGEvent": false,
432 | "SVGExternalResourcesRequired": false,
433 | "SVGFEBlendElement": false,
434 | "SVGFEColorMatrixElement": false,
435 | "SVGFEComponentTransferElement": false,
436 | "SVGFECompositeElement": false,
437 | "SVGFEConvolveMatrixElement": false,
438 | "SVGFEDiffuseLightingElement": false,
439 | "SVGFEDisplacementMapElement": false,
440 | "SVGFEDistantLightElement": false,
441 | "SVGFEDropShadowElement": false,
442 | "SVGFEFloodElement": false,
443 | "SVGFEFuncAElement": false,
444 | "SVGFEFuncBElement": false,
445 | "SVGFEFuncGElement": false,
446 | "SVGFEFuncRElement": false,
447 | "SVGFEGaussianBlurElement": false,
448 | "SVGFEImageElement": false,
449 | "SVGFEMergeElement": false,
450 | "SVGFEMergeNodeElement": false,
451 | "SVGFEMorphologyElement": false,
452 | "SVGFEOffsetElement": false,
453 | "SVGFEPointLightElement": false,
454 | "SVGFESpecularLightingElement": false,
455 | "SVGFESpotLightElement": false,
456 | "SVGFETileElement": false,
457 | "SVGFETurbulenceElement": false,
458 | "SVGFilterElement": false,
459 | "SVGFilterPrimitiveStandardAttributes": false,
460 | "SVGFitToViewBox": false,
461 | "SVGFontElement": false,
462 | "SVGFontFaceElement": false,
463 | "SVGFontFaceFormatElement": false,
464 | "SVGFontFaceNameElement": false,
465 | "SVGFontFaceSrcElement": false,
466 | "SVGFontFaceUriElement": false,
467 | "SVGForeignObjectElement": false,
468 | "SVGGElement": false,
469 | "SVGGeometryElement": false,
470 | "SVGGlyphElement": false,
471 | "SVGGlyphRefElement": false,
472 | "SVGGradientElement": false,
473 | "SVGGraphicsElement": false,
474 | "SVGHKernElement": false,
475 | "SVGICCColor": false,
476 | "SVGImageElement": false,
477 | "SVGLangSpace": false,
478 | "SVGLength": false,
479 | "SVGLengthList": false,
480 | "SVGLinearGradientElement": false,
481 | "SVGLineElement": false,
482 | "SVGLocatable": false,
483 | "SVGMarkerElement": false,
484 | "SVGMaskElement": false,
485 | "SVGMatrix": false,
486 | "SVGMetadataElement": false,
487 | "SVGMissingGlyphElement": false,
488 | "SVGMPathElement": false,
489 | "SVGNumber": false,
490 | "SVGNumberList": false,
491 | "SVGPaint": false,
492 | "SVGPathElement": false,
493 | "SVGPathSeg": false,
494 | "SVGPathSegArcAbs": false,
495 | "SVGPathSegArcRel": false,
496 | "SVGPathSegClosePath": false,
497 | "SVGPathSegCurvetoCubicAbs": false,
498 | "SVGPathSegCurvetoCubicRel": false,
499 | "SVGPathSegCurvetoCubicSmoothAbs": false,
500 | "SVGPathSegCurvetoCubicSmoothRel": false,
501 | "SVGPathSegCurvetoQuadraticAbs": false,
502 | "SVGPathSegCurvetoQuadraticRel": false,
503 | "SVGPathSegCurvetoQuadraticSmoothAbs": false,
504 | "SVGPathSegCurvetoQuadraticSmoothRel": false,
505 | "SVGPathSegLinetoAbs": false,
506 | "SVGPathSegLinetoHorizontalAbs": false,
507 | "SVGPathSegLinetoHorizontalRel": false,
508 | "SVGPathSegLinetoRel": false,
509 | "SVGPathSegLinetoVerticalAbs": false,
510 | "SVGPathSegLinetoVerticalRel": false,
511 | "SVGPathSegList": false,
512 | "SVGPathSegMovetoAbs": false,
513 | "SVGPathSegMovetoRel": false,
514 | "SVGPatternElement": false,
515 | "SVGPoint": false,
516 | "SVGPointList": false,
517 | "SVGPolygonElement": false,
518 | "SVGPolylineElement": false,
519 | "SVGPreserveAspectRatio": false,
520 | "SVGRadialGradientElement": false,
521 | "SVGRect": false,
522 | "SVGRectElement": false,
523 | "SVGRenderingIntent": false,
524 | "SVGScriptElement": false,
525 | "SVGSetElement": false,
526 | "SVGStopElement": false,
527 | "SVGStringList": false,
528 | "SVGStylable": false,
529 | "SVGStyleElement": false,
530 | "SVGSVGElement": false,
531 | "SVGSwitchElement": false,
532 | "SVGSymbolElement": false,
533 | "SVGTests": false,
534 | "SVGTextContentElement": false,
535 | "SVGTextElement": false,
536 | "SVGTextPathElement": false,
537 | "SVGTextPositioningElement": false,
538 | "SVGTitleElement": false,
539 | "SVGTransform": false,
540 | "SVGTransformable": false,
541 | "SVGTransformList": false,
542 | "SVGTRefElement": false,
543 | "SVGTSpanElement": false,
544 | "SVGUnitTypes": false,
545 | "SVGURIReference": false,
546 | "SVGUseElement": false,
547 | "SVGViewElement": false,
548 | "SVGViewSpec": false,
549 | "SVGVKernElement": false,
550 | "SVGZoomAndPan": false,
551 | "SVGZoomEvent": false,
552 | "Text": false,
553 | "TextDecoder": false,
554 | "TextEncoder": false,
555 | "TextEvent": false,
556 | "TextMetrics": false,
557 | "TextTrack": false,
558 | "TextTrackCue": false,
559 | "TextTrackCueList": false,
560 | "TextTrackList": false,
561 | "TimeEvent": false,
562 | "TimeRanges": false,
563 | "toolbar": false,
564 | "top": false,
565 | "Touch": false,
566 | "TouchEvent": false,
567 | "TouchList": false,
568 | "TrackEvent": false,
569 | "TransitionEvent": false,
570 | "TreeWalker": false,
571 | "UIEvent": false,
572 | "URL": false,
573 | "URLSearchParams": false,
574 | "ValidityState": false,
575 | "VTTCue": false,
576 | "WaveShaperNode": false,
577 | "WebGLActiveInfo": false,
578 | "WebGLBuffer": false,
579 | "WebGLContextEvent": false,
580 | "WebGLFramebuffer": false,
581 | "WebGLProgram": false,
582 | "WebGLRenderbuffer": false,
583 | "WebGLRenderingContext": false,
584 | "WebGLShader": false,
585 | "WebGLShaderPrecisionFormat": false,
586 | "WebGLTexture": false,
587 | "WebGLUniformLocation": false,
588 | "WebSocket": false,
589 | "WheelEvent": false,
590 | "window": false,
591 | "Window": false,
592 | "Worker": false,
593 | "XDomainRequest": false,
594 | "XMLDocument": false,
595 | "XMLHttpRequest": false,
596 | "XMLHttpRequestEventTarget": false,
597 | "XMLHttpRequestProgressEvent": false,
598 | "XMLHttpRequestUpload": false,
599 | "XMLSerializer": false,
600 | "XPathEvaluator": false,
601 | "XPathException": false,
602 | "XPathExpression": false,
603 | "XPathNamespace": false,
604 | "XPathNSResolver": false,
605 | "XPathResult": false,
606 | "XSLTProcessor": false,
607 | "define": false,
608 | "$": false,
609 | "jQuery": false
610 | },
611 | "env": {
612 | "node": true,
613 | "browser": true,
614 | "amd": true,
615 | "mocha": true,
616 | "jasmine": false,
617 | "es6": false,
618 | "jquery": true
619 | },
620 | "rules": {
621 | "no-alert": 1,
622 | "no-array-constructor": 2,
623 | "no-bitwise": 0,
624 | "no-caller": 2,
625 | "no-case-declarations": 2,
626 | "no-catch-shadow": 0,
627 | "no-class-assign": 0,
628 | "no-cond-assign": [2, "always"],
629 | "no-confusing-arrow": [
630 | 2,
631 | {
632 | "allowParens": true
633 | }
634 | ],
635 | "no-console": 0,
636 | "no-const-assign": 2,
637 | "no-constant-condition": 1,
638 | "no-continue": 0,
639 | "no-control-regex": 2,
640 | "no-debugger": 2,
641 | "no-delete-var": 2,
642 | "no-div-regex": 0,
643 | "no-dupe-class-members": 2,
644 | "no-dupe-keys": 2,
645 | "no-dupe-args": 2,
646 | "no-duplicate-case": 2,
647 | "no-duplicate-imports": 2,
648 | "no-else-return": 2,
649 | "no-empty": 2,
650 | "no-empty-character-class": 2,
651 | "no-empty-function": "off",
652 | "no-empty-pattern": "error",
653 | "no-eq-null": 0,
654 | "no-eval": 2,
655 | "no-ex-assign": 2,
656 | "no-extend-native": 2,
657 | "no-extra-bind": 2,
658 | "no-extra-boolean-cast": 0,
659 | "no-extra-label": 2,
660 | "no-extra-parens": [2, "functions"],
661 | "no-extra-semi": 2,
662 | "no-fallthrough": 2,
663 | "no-floating-decimal": 2,
664 | "no-func-assign": 2,
665 | "no-implicit-coercion": 0,
666 | "no-implicit-globals": 0,
667 | "no-implied-eval": 2,
668 | "no-inline-comments": 0,
669 | "no-inner-declarations": 2,
670 | "no-invalid-regexp": 2,
671 | "no-invalid-this": 0,
672 | "no-irregular-whitespace": 2,
673 | "no-iterator": 2,
674 | "no-label-var": 0,
675 | "no-labels": [
676 | 2,
677 | {
678 | "allowLoop": false,
679 | "allowSwitch": false
680 | }
681 | ],
682 | "no-lone-blocks": 2,
683 | "no-lonely-if": 0,
684 | "no-loop-func": 2,
685 | "no-mixed-requires": [2, false],
686 | "no-mixed-spaces-and-tabs": [2, false],
687 | "linebreak-style": 0,
688 | "no-multi-spaces": 2,
689 | "no-multi-str": 2,
690 | "no-multiple-empty-lines": [
691 | 2,
692 | {
693 | "max": 2,
694 | "maxEOF": 1
695 | }
696 | ],
697 | "no-native-reassign": 2,
698 | "no-negated-condition": "off",
699 | "no-negated-in-lhs": 2,
700 | "no-nested-ternary": 2,
701 | "no-new": 2,
702 | "no-new-func": 2,
703 | "no-new-object": 2,
704 | "no-new-require": 0,
705 | "no-new-symbol": 2,
706 | "no-new-wrappers": 2,
707 | "no-obj-calls": 2,
708 | "no-octal": 2,
709 | "no-octal-escape": 2,
710 | "no-param-reassign": [
711 | 2,
712 | {
713 | "props": true
714 | }
715 | ],
716 | "no-path-concat": 2,
717 | "no-plusplus": 0,
718 | "no-process-env": 0,
719 | "no-process-exit": 0,
720 | "no-proto": 2,
721 | "no-redeclare": 2,
722 | "no-regex-spaces": 2,
723 | "no-restricted-globals": 0,
724 | "no-restricted-imports": 0,
725 | "no-restricted-modules": 0,
726 | "no-restricted-syntax": "off",
727 | "no-return-assign": 2,
728 | "no-script-url": 2,
729 | "no-self-assign": 2,
730 | "no-self-compare": 2,
731 | "no-sequences": 2,
732 | "no-shadow": 2,
733 | "no-shadow-restricted-names": 2,
734 | "no-whitespace-before-property": 2,
735 | "no-spaced-func": 2,
736 | "no-sparse-arrays": 2,
737 | "no-sync": 0,
738 | "no-ternary": 0,
739 | "no-trailing-spaces": 2,
740 | "no-this-before-super": 0,
741 | "no-throw-literal": 2,
742 | "no-undef": 2,
743 | "no-undef-init": 2,
744 | "no-undefined": 0,
745 | "no-unexpected-multiline": 0,
746 | "no-underscore-dangle": [
747 | 0,
748 | {
749 | "allowAfterThis": true
750 | }
751 | ],
752 | "no-unmodified-loop-condition": 0,
753 | "no-unneeded-ternary": [
754 | 2,
755 | {
756 | "defaultAssignment": false
757 | }
758 | ],
759 | "no-unreachable": 2,
760 | "no-unused-expressions": 2,
761 | "no-unused-labels": 2,
762 | "no-unused-vars": [
763 | 2,
764 | {
765 | "vars": "local",
766 | "args": "after-used"
767 | }
768 | ],
769 | "no-use-before-define": 2,
770 | "no-useless-call": 0,
771 | "no-useless-concat": 2,
772 | "no-useless-constructor": 2,
773 | "no-useless-escape": 2,
774 | "no-void": 0,
775 | "no-var": 0,
776 | "no-warning-comments": [
777 | 0,
778 | {
779 | "terms": ["todo", "fixme", "xxx"],
780 | "location": "start"
781 | }
782 | ],
783 | "no-with": 2,
784 | "no-magic-numbers": "off",
785 | "array-bracket-spacing": [2, "never"],
786 | "array-callback-return": 2,
787 | "arrow-body-style": [2, "as-needed"],
788 | "arrow-parens": 0,
789 | "arrow-spacing": [
790 | 2,
791 | {
792 | "before": true,
793 | "after": true
794 | }
795 | ],
796 | "accessor-pairs": 0,
797 | "block-scoped-var": 2,
798 | "block-spacing": 2,
799 | "brace-style": [
800 | 2,
801 | "1tbs",
802 | {
803 | "allowSingleLine": true
804 | }
805 | ],
806 | "callback-return": [0, ["cb", "callback", "next"]],
807 | "camelcase": [
808 | 2,
809 | {
810 | "properties": "never"
811 | }
812 | ],
813 | "comma-dangle": [2, "always-multiline"],
814 | "comma-spacing": [
815 | 2,
816 | {
817 | "before": false,
818 | "after": true
819 | }
820 | ],
821 | "comma-style": [2, "last"],
822 | "complexity": [0, 11],
823 | "computed-property-spacing": [2, "never"],
824 | "consistent-return": 2,
825 | "consistent-this": 0,
826 | "constructor-super": 0,
827 | "curly": [2, "multi-line"],
828 | "default-case": 2,
829 | "dot-location": 0,
830 | "dot-notation": [
831 | 2,
832 | {
833 | "allowKeywords": true
834 | }
835 | ],
836 | "eol-last": 2,
837 | "eqeqeq": 2,
838 | "func-names": 0,
839 | "func-style": [0, "declaration"],
840 | "generator-star-spacing": 0,
841 | "global-require": "off",
842 | "guard-for-in": 2,
843 | "handle-callback-err": [2, "err"],
844 | "id-length": 0,
845 | "indent": [
846 | 2,
847 | 4,
848 | {
849 | "SwitchCase": 1,
850 | "VariableDeclarator": 1
851 | }
852 | ],
853 | "init-declarations": 0,
854 | "key-spacing": [
855 | 2,
856 | {
857 | "beforeColon": false,
858 | "afterColon": true
859 | }
860 | ],
861 | "keyword-spacing": [
862 | 2,
863 | {
864 | "before": true,
865 | "after": true,
866 | "overrides": {
867 | "return": {
868 | "after": true
869 | },
870 | "throw": {
871 | "after": true
872 | },
873 | "case": {
874 | "after": true
875 | }
876 | }
877 | }
878 | ],
879 | "lines-around-comment": 0,
880 | "max-depth": [0, 4],
881 | "max-len": [
882 | 2,
883 | 120,
884 | 4,
885 | {
886 | "ignoreUrls": true
887 | }
888 | ],
889 | "max-nested-callbacks": 0,
890 | "max-params": [0, 3],
891 | "max-statements": [0, 10],
892 | "max-statements-per-line": "off",
893 | "new-cap": [
894 | 2,
895 | {
896 | "newIsCap": true
897 | }
898 | ],
899 | "new-parens": 0,
900 | "newline-after-var": 0,
901 | "newline-before-return": 0,
902 | "newline-per-chained-call": [
903 | 0,
904 | {
905 | "ignoreChainWithDepth": 3
906 | }
907 | ],
908 | "object-curly-spacing": [2, "never"],
909 | "object-shorthand": [0, "always"],
910 | "one-var": [2, "never"],
911 | "one-var-declaration-per-line": [2, "always"],
912 | "operator-assignment": 0,
913 | "operator-linebreak": 0,
914 | "padded-blocks": [2, "never"],
915 | "prefer-arrow-callback": 0,
916 | "prefer-const": 2,
917 | "prefer-object-spread": 0,
918 | "prefer-reflect": 0,
919 | "prefer-rest-params": 2,
920 | "prefer-spread": 0,
921 | "prefer-template": 0,
922 | "quote-props": [
923 | 2,
924 | "as-needed",
925 | {
926 | "keywords": false,
927 | "unnecessary": true,
928 | "numbers": false
929 | }
930 | ],
931 | "quotes": [2, "single", "avoid-escape"],
932 | "radix": 2,
933 | "id-match": 0,
934 | "id-blacklist": 0,
935 | "require-jsdoc": 2,
936 | "require-yield": 0,
937 | "semi": [2, "always"],
938 | "semi-spacing": [
939 | 2,
940 | {
941 | "before": false,
942 | "after": true
943 | }
944 | ],
945 | "sort-vars": 0,
946 | "sort-imports": 0,
947 | "space-before-blocks": 2,
948 | "space-before-function-paren": [
949 | 2,
950 | {
951 | "anonymous": "always",
952 | "named": "never"
953 | }
954 | ],
955 | "space-in-parens": [2, "never"],
956 | "space-infix-ops": 2,
957 | "space-unary-ops": [
958 | 0,
959 | {
960 | "words": true,
961 | "nonwords": false
962 | }
963 | ],
964 | "spaced-comment": [
965 | 2,
966 | "always",
967 | {
968 | "exceptions": ["-", "+"],
969 | "markers": ["=", "!"]
970 | }
971 | ],
972 | "strict": [2, "global"],
973 | "template-curly-spacing": 2,
974 | "use-isnan": 2,
975 | "valid-jsdoc": [
976 | 0,
977 | {
978 | "prefer": {
979 | "return": "returns"
980 | }
981 | }
982 | ],
983 | "valid-typeof": 2,
984 | "vars-on-top": 0,
985 | "wrap-iife": [2, "outside"],
986 | "wrap-regex": 0,
987 | "yield-star-spacing": [2, "after"],
988 | "yoda": [2, "never"],
989 | "jsdoc/no-undefined-types": 0,
990 | "jsdoc/require-returns": 0,
991 | "jsdoc/check-tag-names": 0,
992 | "jsdoc/check-types": 0,
993 | "jsdoc/check-alignment": 0,
994 | "jsdoc/require-property": 0,
995 | "jsdoc/require-param": 0,
996 | "prefer-destructuring": 0
997 | },
998 | "parserOptions": {
999 | "ecmaFeatures": {
1000 | "globalReturn": true,
1001 | "jsx": true,
1002 | "generators": false,
1003 | "objectLiteralDuplicateProperties": false,
1004 | "modules": false
1005 | },
1006 | "ecmaVersion": 5,
1007 | "sourceType": "script"
1008 | },
1009 | "parser": "@babel/eslint-parser",
1010 | "extends": ["eslint-config-eslint", "eslint-config-airbnb", "plugin:jsdoc/recommended"],
1011 | "plugins": []
1012 | }
1013 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text eol=lf
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.github/workflows/build-test-coverage.yml:
--------------------------------------------------------------------------------
1 | name: CICD Build / Test / Coverage
2 |
3 | on:
4 | push:
5 | branches: [ "master" ]
6 | pull_request:
7 | branches: [ "master" ]
8 |
9 | jobs:
10 | buildTestCoverage:
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | matrix:
15 | node-version: [14.x, 16.x, 18.x]
16 |
17 | steps:
18 | - uses: actions/checkout@v3
19 |
20 | - name: Use Node.js ${{ matrix.node-version }}
21 | uses: actions/setup-node@v3
22 | with:
23 | node-version: ${{ matrix.node-version }}
24 |
25 | - name: Install dependencies
26 | run: |
27 | npm ci
28 |
29 | - name: Lint & Test
30 | run: |
31 | npm run lint
32 | npm run test
33 |
34 | - name: Covergae
35 | run: |
36 | npm run coverage
37 |
38 | - name: Code Coverage Report
39 | uses: irongut/CodeCoverageSummary@v1.3.0
40 | with:
41 | filename: dist/coverage/cobertura-coverage.xml
42 | badge: true
43 | fail_below_min: true
44 | format: markdown
45 | hide_branch_rate: false
46 | hide_complexity: true
47 | indicators: true
48 | output: both
49 | thresholds: '60 80'
50 |
51 | - name: Add Coverage PR Comment
52 | uses: marocchino/sticky-pull-request-comment@v2
53 | if: github.event_name == 'pull_request'
54 | with:
55 | recreate: true
56 | path: code-coverage-results.md
57 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | lib-cov
2 | *.seed
3 | *.log
4 | *.csv
5 | *.dat
6 | *.out
7 | *.pid
8 | *.gz
9 | *.tgz
10 |
11 | pids
12 | logs
13 | results
14 |
15 | node_modules
16 | npm-debug.log
17 | dist/
18 | .nyc_output/
19 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | test/*
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 17
4 | - 16
5 | - 15
6 | - lts/*
7 |
8 | script:
9 | - grunt test
10 | after_success:
11 | - grunt coverage
12 | - grunt coveralls
13 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | We welcome patches and features. There are however a few things that are
4 | required before your pull request can be merged.
5 |
6 | # Tests
7 |
8 | ## How to write a new test case
9 |
10 | As output from system ping varied on languages and OS, our parser may fail
11 | on new languages or OS. To improve the correctness and coverage for this
12 | module, we need to gather output from those system pings.
13 |
14 | ### Upload a fixture about system ping
15 |
16 | Suppose you are using `macos` in language `en`, you have a problem for running
17 | our module. Please upload a capture of your system ping in folder
18 | `test/fixture/$OS/$LANGUAGE`. In this case, the name of folder will be
19 | `test/fixture/macos/en`
20 |
21 | ### Write expected answer in answer.json
22 |
23 | NOTE: we recommend to use [this online editor][1] for editing the content for
24 | `answer.json`
25 |
26 | To verify the correctness of our module on your new fixture, please provide
27 | the expected answer in `test/fixture/answer.json`.
28 |
29 | Format of the key name is `$OS_$LANGUAGE_$FILENAME`. In our case, this is
30 | `macos_en_sample1`.
31 |
32 | Value of that key should be the result from our command.
33 |
34 | ```
35 | {
36 | "host": "google.com",
37 | "numeric_host": "172.217.24.46",
38 | "alive": true,
39 | "output": "PING google.com (172.217.24.46): 56 data bytes\n64 bytes from 172.217.24.46: icmp_seq=0 ttl=54 time=5.371 ms\n64 bytes from 172.217.24.46: icmp_seq=1 ttl=54 time=4.269 ms\n64 bytes from 172.217.24.46: icmp_seq=2 ttl=54 time=4.970 ms\n64 bytes from 172.217.24.46: icmp_seq=3 ttl=54 time=5.228 ms\n\n--- google.com ping statistics ---\n4 packets transmitted, 4 packets received, 0.0% packet loss\nround-trip min/avg/max/stddev = 4.269/4.960/5.371/0.424 ms\n",
40 | "time": 5.371,
41 | "times": [
42 | 5.371,
43 | 4.269,
44 | 4.97,
45 | 5.228
46 | ],
47 | "min": 4.269,
48 | "max": 4.96,
49 | "avg": 5.371,
50 | "packageLoss": 0.0
51 | "stddev": 0.424
52 | }
53 | ```
54 |
55 | ## Running test cases
56 |
57 | We trust tested codes. Please run below command for testing before sending
58 | a pull request
59 |
60 | ```
61 | $ grunt test
62 | ```
63 |
64 | ## Running ipv6 test cases
65 |
66 | As #67 introduces ipv6 mechanism, fixture file names with `v6` will enable v6.
67 | Please refer to window/de/v6_sample.txt for an example
68 |
69 | [1]: https://jsoneditoronline.org
70 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function (grunt) {
4 | grunt.initConfig({
5 | eslint: {
6 | src: ['lib/*.js', 'lib/**/*.js'],
7 | options: {
8 | overrideConfigFile: '.eslintrc.json',
9 | },
10 | },
11 | mochaTest: {
12 | src: ['test/test-*.js'],
13 | options: {
14 | reporter: 'dot',
15 | },
16 | },
17 | nyc_mocha: {
18 | src: ['test/test-*.js'],
19 | options: {
20 | nyc: {
21 | coverage: {
22 | dir: 'dist/coverage',
23 | reporter: ['text', 'html', 'lcov', 'cobertura'],
24 | },
25 | },
26 | mocha: {
27 | color: true,
28 | opts: ['--reporter', 'dot'],
29 | },
30 | },
31 | },
32 | coveralls: {
33 | src: 'dist/coverage/*.info',
34 | options: {},
35 | },
36 | });
37 |
38 | grunt.loadNpmTasks('grunt-eslint');
39 | grunt.loadNpmTasks('grunt-mocha-test');
40 | grunt.loadNpmTasks('grunt-nyc-mocha');
41 | grunt.loadNpmTasks('grunt-coveralls');
42 | grunt.registerTask('test', ['eslint', 'mochaTest']);
43 | grunt.registerTask('coverage', ['nyc_mocha']);
44 | };
45 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 | Copyright (c) 2016 Daniel Zelisko
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NODE-PING 
2 |
3 | a ping wrapper for nodejs
4 |
5 | @last-modified: 2023-03-11
6 |
7 | # License MIT
8 |
9 | (C) Daniel Zelisko
10 |
11 | http://github.com/danielzzz/node-ping
12 |
13 | # Description
14 |
15 | node-ping is a simple wrapper for the system ping utility
16 |
17 | # Installation
18 |
19 | npm install ping
20 |
21 | # Usage
22 |
23 | Below are examples extracted from `examples`
24 |
25 | ## Tradition calls
26 |
27 | ```js
28 | var ping = require('ping');
29 |
30 | var hosts = ['192.168.1.1', 'google.com', 'yahoo.com'];
31 | hosts.forEach(function(host){
32 | ping.sys.probe(host, function(isAlive){
33 | var msg = isAlive ? 'host ' + host + ' is alive' : 'host ' + host + ' is dead';
34 | console.log(msg);
35 | });
36 | });
37 | ```
38 |
39 | ## Tradition calls with configuration
40 |
41 | ```js
42 | var cfg = {
43 | timeout: 10,
44 | // WARNING: -i 2 may not work in other platform like windows
45 | extra: ['-i', '2'],
46 | };
47 |
48 | hosts.forEach(function(host){
49 | ping.sys.probe(host, function(isAlive){
50 | var msg = isAlive ? 'host ' + host + ' is alive' : 'host ' + host + ' is dead';
51 | console.log(msg);
52 | }, cfg);
53 | });
54 | ```
55 |
56 | ## Promise wrapper
57 |
58 | ```js
59 | var ping = require('ping');
60 |
61 | var hosts = ['192.168.1.1', 'google.com', 'yahoo.com'];
62 |
63 | hosts.forEach(function (host) {
64 | ping.promise.probe(host)
65 | .then(function (res) {
66 | console.log(res);
67 | });
68 | });
69 | ```
70 |
71 | ## Promise Wrapper with configurable ping options
72 |
73 | ```js
74 | hosts.forEach(function (host) {
75 | // WARNING: -i 2 argument may not work in other platform like windows
76 | ping.promise.probe(host, {
77 | timeout: 10,
78 | extra: ['-i', '2'],
79 | }).then(function (res) {
80 | console.log(res);
81 | });
82 | });
83 | ```
84 |
85 |
86 | ## Async-Await
87 | ```js
88 | var ping = require('ping');
89 |
90 | var hosts = ['192.168.1.1', 'google.com', 'yahoo.com'];
91 |
92 | for(let host of hosts){
93 | let res = await ping.promise.probe(host);
94 | console.log(res);
95 | }
96 | ```
97 |
98 | ## Async-Await with configurable ping options
99 | ```js
100 | var ping = require('ping');
101 |
102 | var hosts = ['192.168.1.1', 'google.com', 'yahoo.com'];
103 |
104 | for(let host of hosts){
105 | // WARNING: -i 2 argument may not work in other platform like windows
106 | let res = await ping.promise.probe(host, {
107 | timeout: 10,
108 | extra: ['-i', '2'],
109 | });
110 | console.log(res);
111 | }
112 | ```
113 | ### Support configuration
114 |
115 | Below is the possible configuration
116 |
117 | ```js
118 | /**
119 | * Cross platform config representation
120 | * @typedef {Object} PingConfig
121 | * @property {boolean} numeric - Map IP address to hostname or not
122 | * @property {number} timeout - Timeout in seconds for each ping request.
123 | * Behaviour varies between platforms. Check platform ping documentation for more information.
124 | * @property {number} deadline - Specify a timeout, in seconds, before ping exits regardless of
125 | how many packets have been sent or received. In this case ping
126 | does not stop after count packet are sent, it waits either for
127 | deadline expire or until count probes are answered or for some
128 | error notification from network. This option is only available on linux and mac.
129 | * @property {number} min_reply - Exit after sending number of ECHO_REQUEST
130 | * @property {boolean} v6 - Ping via ipv6 or not. Default is false
131 | * @property {string} sourceAddr - source address for sending the ping
132 | * @property {number} packetSize - Specifies the number of data bytes to be sent
133 | Default: Linux / MAC: 56 Bytes, Windows: 32 Bytes
134 | * @property {string[]} extra - Optional options does not provided
135 | */
136 | ```
137 |
138 | ### Output specification
139 |
140 | * For callback based implementation:
141 |
142 | ```js
143 | /**
144 | * Callback after probing given host
145 | * @callback probeCallback
146 | * @param {boolean} isAlive - Whether target is alive or not
147 | * @param {Object} error - Null if no error occurs
148 | */
149 | ```
150 |
151 | * For promise based implementation
152 |
153 | ```js
154 | /**
155 | * Parsed response
156 | * @typedef {object} PingResponse
157 | * @param {string} inputHost - The input IP address or HOST
158 | * @param {string} host - Parsed host from system command's output
159 | * @param {string} numeric_host - Target IP address
160 | * @param {boolean} alive - True for existed host
161 | * @param {string} output - Raw stdout from system ping
162 | * @param {number} time - Time (float) in ms for first successful ping response
163 | * @param {Array} times - Array of Time (float) in ms for each ping response
164 | * @param {string} min - Minimum time for collection records
165 | * @param {string} max - Maximum time for collection records
166 | * @param {string} avg - Average time for collection records
167 | * @param {string} packetLoss - Packet Losses in percent (100% -> "100.000")
168 | * @param {string} stddev - Standard deviation time for collected records
169 | */
170 | ```
171 |
172 | #### Note
173 |
174 | * Since `ping` in this module relies on the `ping` from underlying platform,
175 | arguments in `PingConfig.extra` will definitely be varied across different
176 | platforms.
177 |
178 | * However, `numeric`, `timeout` and `min_reply` have been abstracted. Values for
179 | them are expected to be cross platform.
180 |
181 | * By setting `numeric`, `timeout` or `min_reply` to false, you can run `ping`
182 | without corresponding arguments.
183 |
184 | # FAQ
185 |
186 | * It does not work with busybox's ping implemetation [#89](https://github.com/danielzzz/node-ping/issues/89)
187 |
188 | Try to install package `iputils`. For example, running `apk add iputils`
189 |
190 | * For questions regarding to the implementation of `timeout`, and `deadline`, please checkout discussions in
191 | [#101](https://github.com/danielzzz/node-ping/issues/101)
192 |
193 | * For questions regarding to the defintions of `host`, `inputHost`, and `numeric_host`, please checkout
194 | discussions in [#133](https://github.com/danielzzz/node-ping/issues/133)
195 |
196 | # Contributing
197 |
198 | Before opening a pull request please make sure your changes follow the
199 | [contribution guidelines][1].
200 |
201 | [1]: https://github.com/danielzzz/node-ping/blob/master/CONTRIBUTING.md
202 |
203 |
204 | # Contributors
205 |
206 |
207 |
208 |
209 | Made with [contrib.rocks](https://contrib.rocks).
210 |
--------------------------------------------------------------------------------
/babel.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "targets": {
7 | "edge": "17",
8 | "firefox": "60",
9 | "chrome": "67",
10 | "safari": "11.1"
11 | },
12 | "useBuiltIns": "usage",
13 | "corejs": "3.6.5"
14 | }
15 | ]
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/examples/example.js:
--------------------------------------------------------------------------------
1 | // -------- example -----------------------
2 |
3 | 'use strict';
4 |
5 | var ping = require('../index');
6 |
7 | var hosts = ['192.168.1.1', 'google.com', 'yahoo.com'];
8 | hosts.forEach(function (host) {
9 | // Running with default config
10 | ping.sys.probe(host, function (isAlive) {
11 | var msg = isAlive ?
12 | 'host ' + host + ' is alive' : 'host ' + host + ' is dead';
13 | console.log(msg);
14 | });
15 |
16 | // Running with custom config
17 | ping.sys.probe(host, function (isAlive) {
18 | var msg = isAlive ?
19 | 'host ' + host + ' is alive' : 'host ' + host + ' is dead';
20 | console.log(msg);
21 | }, {extra: ['-i', '2']});
22 |
23 | // Running ping with some default argument gone
24 | ping.sys.probe(host, function (isAlive) {
25 | var msg = isAlive ?
26 | 'host ' + host + ' is alive' : 'host ' + host + ' is dead';
27 | console.log(msg);
28 | }, {extra: ['-i', '2'], timeout: false});
29 | });
30 |
31 |
--------------------------------------------------------------------------------
/examples/example2.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var ping = require('../index');
4 |
5 | var hosts = ['192.168.1.1', 'google.com', 'yahoo.com'];
6 |
7 | // Running with default config
8 | hosts.forEach(function (host) {
9 | ping.promise.probe(host)
10 | .then(function (res) {
11 | console.log(res);
12 | });
13 | });
14 |
15 | // Running with custom config
16 | hosts.forEach(function (host) {
17 | // WARNING: -i 2 argument may not work in other platform like window
18 | ping.promise.probe(host, {
19 | timeout: 10,
20 | extra: ['-i', '2'],
21 | })
22 | .then(function (res) {
23 | console.log(res);
24 | });
25 | });
26 |
27 | // Running ping with some default argument gone
28 | hosts.forEach(function (host) {
29 | // WARNING: -i 2 argument may not work in other platform like window
30 | ping.promise.probe(host, {
31 | timeout: false,
32 | // Below extra arguments may not work in platforms other than linux
33 | extra: ['-i', '2'],
34 | })
35 | .then(function (res) {
36 | console.log(res);
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/examples/example_win_de_v6.js:
--------------------------------------------------------------------------------
1 | // -------- example -----------------------
2 |
3 | 'use strict';
4 |
5 | var ping = require('../index');
6 |
7 | var hosts = ['google.de']; // , '192.168.1.1', 'google.com', 'yahoo.com'];
8 |
9 | // Running with custom config
10 | hosts.forEach(function (host) {
11 | ping.promise.probe(host, {
12 | // v6: true,
13 | min_reply: 2,
14 | sourceAddr: 'your NIC\'s IPv6 address',
15 | // sourceAddr: false,
16 | })
17 | .then(function (res) {
18 | console.log('\n');
19 | console.log(res);
20 | });
21 |
22 | // Running ping with some default argument gone
23 | ping.sys.probe(host, function (isAlive) {
24 | var msg = isAlive ?
25 | 'host ' + host + ' is alive' : 'host ' + host + ' is dead';
26 | console.log('\n');
27 | console.log(msg);
28 | }, {
29 | timeout: false,
30 | // v6: true,
31 | min_reply: 2,
32 | sourceAddr: 'your NIC\'s IPv6 address',
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var ping = {};
2 |
3 | ping.sys = require('./lib/ping-sys');
4 | //ping.pcap = require('./lib/ping-pcap');
5 | ping.promise = require("./lib/ping-promise");
6 |
7 | module.exports = ping;
8 |
--------------------------------------------------------------------------------
/lib/builder/factory.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('util');
4 |
5 | // Our library
6 | var linuxBuilder = require('./linux');
7 | var macBuilder = require('./mac');
8 | var winBuilder = require('./win');
9 |
10 | /**
11 | * A factory creates argument builders for different platform
12 | * @constructor
13 | */
14 | function factory() {}
15 |
16 | /**
17 | * Check out linux platform
18 | */
19 | factory.isLinux = function (p) {
20 | var platforms = [
21 | 'aix',
22 | 'android',
23 | 'linux',
24 | ];
25 |
26 | return platforms.indexOf(p) >= 0;
27 | };
28 |
29 | /**
30 | * Check out macos platform
31 | */
32 | factory.isMacOS = function (p) {
33 | var platforms = [
34 | 'darwin',
35 | 'freebsd',
36 | ];
37 |
38 | return platforms.indexOf(p) >= 0;
39 | };
40 |
41 | /**
42 | * Check out window platform
43 | */
44 | factory.isWindow = function (p) {
45 | return p && p.match(/^win/) !== null;
46 | };
47 |
48 | /**
49 | * Check whether given platform is supported
50 | * @param {string} p - Name of the platform
51 | * @return {bool} - True or False
52 | */
53 | factory.isPlatformSupport = function (p) {
54 | return this.isWindow(p) || this.isLinux(p) || this.isMacOS(p);
55 | };
56 |
57 | /**
58 | * Return a path to the ping executable in the system
59 | * @param {string} platform - Name of the platform
60 | * @param {bool} v6 - Ping via ipv6 or not
61 | * @return {string} - Executable path for system command ping
62 | * @throw if given platform is not supported
63 | */
64 | factory.getExecutablePath = function (platform, v6) {
65 | if (!this.isPlatformSupport(platform)) {
66 | throw new Error(util.format('Platform |%s| is not support', platform));
67 | }
68 |
69 | var ret = null;
70 |
71 | if (platform === 'aix') {
72 | ret = '/usr/sbin/ping';
73 | } else if (factory.isLinux(platform)) {
74 | ret = v6 ? 'ping6' : 'ping';
75 | } else if (factory.isWindow(platform)) {
76 | ret = process.env.SystemRoot + '/system32/ping.exe';
77 | } else if (factory.isMacOS(platform)) {
78 | ret = v6 ? '/sbin/ping6' : '/sbin/ping';
79 | }
80 |
81 | return ret;
82 | };
83 |
84 | /**
85 | * Create a builder
86 | * @param {string} platform - Name of the platform
87 | * @return {object} - Argument builder
88 | * @throw if given platform is not supported
89 | */
90 | factory.createBuilder = function (platform) {
91 | if (!this.isPlatformSupport(platform)) {
92 | throw new Error(util.format('Platform |%s| is not support', platform));
93 | }
94 |
95 | var ret = null;
96 |
97 | if (factory.isLinux(platform)) {
98 | ret = linuxBuilder;
99 | } else if (factory.isWindow(platform)) {
100 | ret = winBuilder;
101 | } else if (factory.isMacOS(platform)) {
102 | ret = macBuilder;
103 | }
104 |
105 | return ret;
106 | };
107 |
108 | module.exports = factory;
109 |
--------------------------------------------------------------------------------
/lib/builder/linux.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * A builder builds command line arguments for ping in linux environment
5 | * @module lib/builder/linux
6 | */
7 | var util = require('util');
8 |
9 | var builder = {};
10 |
11 | /**
12 | * Cross platform config representation
13 | * @typedef {Object} PingConfig
14 | * @property {boolean} numeric - Map IP address to hostname or not
15 | * @property {number} timeout - Time to wait for a response, in seconds.
16 | * The option affects only timeout in absence of any responses,
17 | * otherwise ping waits for two RTTs.
18 | * @property {number} deadline - Specify a timeout, in seconds,
19 | * before ping exits regardless of how many packets have been sent or received.
20 | * In this case ping does not stop after count packet are sent,
21 | * it waits either for deadline expire or until count probes are answered
22 | * or for some error notification from network.
23 | * This option is only available on linux and mac.
24 | * @property {number} min_reply - Exit after sending number of ECHO_REQUEST
25 | * @property {boolean} v6 - Use IPv4 (default) or IPv6
26 | * @property {string} sourceAddr - source address for sending the ping
27 | * @property {number} packetSize - Specifies the number of data bytes to be sent
28 | * Default: Linux / MAC: 56 Bytes,
29 | * Window: 32 Bytes
30 | * @property {string[]} extra - Optional options does not provided
31 | */
32 |
33 | var defaultConfig = {
34 | numeric: true,
35 | timeout: 2,
36 | deadline: false,
37 | min_reply: 1,
38 | v6: false,
39 | sourceAddr: '',
40 | packetSize: 56,
41 | extra: [],
42 | };
43 |
44 | /**
45 | * Get the finalized array of command line arguments
46 | * @param {string} target - hostname or ip address
47 | * @param {PingConfig} [config] - Configuration object for cmd line argument
48 | * @return {string[]} - Command line argument according to the configuration
49 | */
50 | builder.getCommandArguments = function (target, config) {
51 | var _config = config || {};
52 |
53 | // Empty argument
54 | var ret = [];
55 |
56 | // Make every key in config has been setup properly
57 | var keys = ['numeric', 'timeout', 'deadline', 'min_reply', 'v6',
58 | 'sourceAddr', 'extra', 'packetSize'];
59 | keys.forEach(function (k) {
60 | // Falsy value will be overridden without below checking
61 | if (typeof(_config[k]) !== 'boolean') {
62 | _config[k] = _config[k] || defaultConfig[k];
63 | }
64 | });
65 |
66 | if (_config.numeric) {
67 | ret.push('-n');
68 | }
69 |
70 | if (_config.timeout) {
71 | ret = ret.concat([
72 | '-W',
73 | util.format('%d', _config.timeout),
74 | ]);
75 | }
76 |
77 | if (_config.deadline) {
78 | ret = ret.concat([
79 | '-w',
80 | util.format('%d', _config.deadline),
81 | ]);
82 | }
83 |
84 | if (_config.min_reply) {
85 | ret = ret.concat([
86 | '-c',
87 | util.format('%d', _config.min_reply),
88 | ]);
89 | }
90 |
91 | if (_config.sourceAddr) {
92 | ret = ret.concat([
93 | '-I',
94 | util.format('%s', _config.sourceAddr),
95 | ]);
96 | }
97 |
98 | if (_config.packetSize) {
99 | ret = ret.concat([
100 | '-s',
101 | util.format('%d', _config.packetSize),
102 | ]);
103 | }
104 |
105 | if (_config.extra) {
106 | ret = ret.concat(_config.extra);
107 | }
108 |
109 | ret.push(target);
110 |
111 | return ret;
112 | };
113 |
114 | /**
115 | * Compute an option object for child_process.spawn
116 | * @return {object} - Refer to document of child_process.spawn
117 | */
118 | builder.getSpawnOptions = function () {
119 | return {
120 | shell: false,
121 | env: Object.assign({}, process.env, {LANG: 'C'}),
122 | };
123 | };
124 |
125 | module.exports = builder;
126 |
--------------------------------------------------------------------------------
/lib/builder/mac.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * A builder builds command line arguments for ping in mac environment
5 | * @module lib/builder/mac
6 | */
7 | var util = require('util');
8 |
9 | var builder = {};
10 |
11 | /**
12 | * Cross platform config representation
13 | * @typedef {Object} PingConfig
14 | * @property {boolean} numeric - Map IP address to hostname or not
15 | * @property {number} timeout - Time to wait for a response, in seconds.
16 | * The option affects only timeout in absence of any responses,
17 | * otherwise ping waits for two RTTs.
18 | * @property {number} deadline - Specify a timeout, in seconds,
19 | * before ping exits regardless of how many packets have been sent or received.
20 | * In this case ping does not stop after count packet are sent,
21 | * it waits either for deadline expire or until count probes are answered
22 | * or for some error notification from network.
23 | * This option is only available on linux and mac.
24 | * @property {number} min_reply - Exit after sending number of ECHO_REQUEST
25 | * @property {boolean} v6 - Use IPv4 (default) or IPv6
26 | * @property {string} sourceAddr - source address for sending the ping
27 | * @property {number} packetSize - Specifies the number of data bytes to be sent
28 | * Default: Linux / MAC: 56 Bytes,
29 | * Window: 32 Bytes
30 | * @property {string[]} extra - Optional options does not provided
31 | */
32 |
33 | var defaultConfig = {
34 | numeric: true,
35 | timeout: 2,
36 | deadline: false,
37 | min_reply: 1,
38 | v6: false,
39 | sourceAddr: '',
40 | packetSize: 56,
41 | extra: [],
42 | };
43 |
44 | /**
45 | * Get the finalized array of command line arguments
46 | * @param {string} target - hostname or ip address
47 | * @param {PingConfig} [config] - Configuration object for cmd line argument
48 | * @return {string[]} - Command line argument according to the configuration
49 | * @throws If there are errors on building arguments with given inputs
50 | */
51 | builder.getCommandArguments = function (target, config) {
52 | var _config = config || {};
53 |
54 | // Empty argument
55 | var ret = [];
56 |
57 | // Make every key in config has been setup properly
58 | var keys = ['numeric', 'timeout', 'deadline', 'min_reply', 'v6',
59 | 'sourceAddr', 'extra', 'packetSize'];
60 | keys.forEach(function (k) {
61 | // Falsy value will be overridden without below checking
62 | if (typeof(_config[k]) !== 'boolean') {
63 | _config[k] = _config[k] || defaultConfig[k];
64 | }
65 | });
66 |
67 | if (_config.numeric) {
68 | ret.push('-n');
69 | }
70 |
71 | if (_config.timeout) {
72 | // XXX: There is no timeout option on mac's ping6
73 | if (config.v6) {
74 | throw new Error('There is no timeout option on ping6');
75 | }
76 |
77 | ret = ret.concat([
78 | '-W',
79 | util.format('%d', _config.timeout * 1000),
80 | ]);
81 | }
82 |
83 | if (_config.deadline) {
84 | ret = ret.concat([
85 | '-t',
86 | util.format('%d', _config.deadline),
87 | ]);
88 | }
89 |
90 | if (_config.min_reply) {
91 | ret = ret.concat([
92 | '-c',
93 | util.format('%d', _config.min_reply),
94 | ]);
95 | }
96 |
97 | if (_config.sourceAddr) {
98 | ret = ret.concat([
99 | '-S',
100 | util.format('%s', _config.sourceAddr),
101 | ]);
102 | }
103 |
104 | if (_config.packetSize) {
105 | ret = ret.concat([
106 | '-s',
107 | util.format('%d', _config.packetSize),
108 | ]);
109 | }
110 |
111 | if (_config.extra) {
112 | ret = ret.concat(_config.extra);
113 | }
114 |
115 | ret.push(target);
116 |
117 | return ret;
118 | };
119 |
120 | /**
121 | * Compute an option object for child_process.spawn
122 | * @return {object} - Refer to document of child_process.spawn
123 | */
124 | builder.getSpawnOptions = function () {
125 | return {};
126 | };
127 |
128 |
129 | module.exports = builder;
130 |
--------------------------------------------------------------------------------
/lib/builder/win.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * A builder builds command line arguments for ping in window environment
5 | * @module lib/builder/win
6 | */
7 | var util = require('util');
8 |
9 | var builder = {};
10 |
11 | /**
12 | * Cross platform config representation
13 | * @typedef {Object} PingConfig
14 | * @property {boolean} numeric - Map IP address to hostname or not
15 | * @property {number} timeout - Timeout in seconds for each ping request
16 | * @property {number} min_reply - Exit after sending number of ECHO_REQUEST
17 | * @property {boolean} v6 - Use IPv4 (default) or IPv6
18 | * @property {string} sourceAddr - source address for sending the ping
19 | * @property {number} packetSize - Specifies the number of data bytes to be sent
20 | * Default: Linux / MAC: 56 Bytes,
21 | * Window: 32 Bytes
22 | * @property {string[]} extra - Optional options does not provided
23 | */
24 |
25 | var defaultConfig = {
26 | numeric: true,
27 | timeout: 5,
28 | min_reply: 1,
29 | v6: false,
30 | sourceAddr: '',
31 | packetSize: 32,
32 | extra: [],
33 | };
34 |
35 | /**
36 | * Get the finalized array of command line arguments
37 | * @param {string} target - hostname or ip address
38 | * @param {PingConfig} [config] - Configuration object for cmd line argument
39 | * @return {string[]} - Command line argument according to the configuration
40 | */
41 | builder.getCommandArguments = function (target, config) {
42 | var _config = config || {};
43 |
44 | // Empty argument
45 | var ret = [];
46 |
47 | // Make every key in config has been setup properly
48 | var keys = [
49 | 'numeric', 'timeout', 'min_reply', 'v6', 'sourceAddr', 'extra',
50 | 'packetSize',
51 | ];
52 | keys.forEach(function (k) {
53 | // Falsy value will be overrided without below checking
54 | if (typeof(_config[k]) !== 'boolean') {
55 | _config[k] = _config[k] || defaultConfig[k];
56 | }
57 | });
58 |
59 | ret.push(_config.v6 ? '-6' : '-4');
60 |
61 | if (!_config.numeric) {
62 | ret.push('-a');
63 | }
64 |
65 | if (_config.timeout) {
66 | // refs #56: Unit problem
67 | // Our timeout is in second while timeout in window is in milliseconds
68 | // so we need to convert our units accordingly
69 | ret = ret.concat([
70 | '-w',
71 | util.format('%d', _config.timeout * 1000),
72 | ]);
73 | }
74 |
75 | if (_config.deadline) {
76 | throw new Error('There is no deadline option on windows');
77 | }
78 |
79 | if (_config.min_reply) {
80 | ret = ret.concat([
81 | '-n',
82 | util.format('%d', _config.min_reply),
83 | ]);
84 | }
85 |
86 | if (_config.sourceAddr) {
87 | ret = ret.concat([
88 | '-S',
89 | util.format('%s', _config.sourceAddr),
90 | ]);
91 | }
92 |
93 | if (_config.packetSize) {
94 | ret = ret.concat([
95 | '-l',
96 | util.format('%d', _config.packetSize),
97 | ]);
98 | }
99 |
100 | if (_config.extra) {
101 | ret = ret.concat(_config.extra);
102 | }
103 |
104 | ret.push(target);
105 |
106 | return ret;
107 | };
108 |
109 | /**
110 | * Compute an option object for child_process.spawn
111 | * @return {object} - Refer to document of child_process.spawn
112 | */
113 | builder.getSpawnOptions = function () {
114 | return {
115 | windowsHide: true,
116 | };
117 | };
118 |
119 | module.exports = builder;
120 |
--------------------------------------------------------------------------------
/lib/parser/base.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /* eslint no-unused-vars: 0 */
4 |
5 | /**
6 | * Parsed response
7 | * @typedef {object} PingResponse
8 | * @param {string} inputHost - The input IP address or HOST
9 | * @param {string} host - The input IP address or HOST
10 | * @param {string} numeric_host - Target IP address
11 | * @param {boolean} alive - True for existed host
12 | * @param {string} output - Raw stdout from system ping
13 | * @param {number} time - Time (float) in ms for first successful ping response
14 | * @param {string} min - Minimum time for collection records
15 | * @param {string} max - Maximum time for collection records
16 | * @param {string} avg - Average time for collection records
17 | * @param {number} packetLoss - Packet Losses in percent (number)
18 | * @param {string} stddev - Standard deviation time for collected records
19 | */
20 |
21 | /**
22 | * @constructor
23 | * @param {string} addr - Hostname or ip addres
24 | * @param {PingConfig} config - Config object in probe()
25 | */
26 | function parser(addr, config) {
27 | // Initial state is 0
28 | this._state = 0;
29 |
30 | // Initial cache value
31 | this._response = {
32 | inputHost: addr,
33 | host: 'unknown',
34 | alive: false,
35 | output: 'unknown',
36 | time: 'unknown',
37 | times: [],
38 | min: 'unknown',
39 | max: 'unknown',
40 | avg: 'unknown',
41 | stddev: 'unknown',
42 | packetLoss: 'unknown',
43 | };
44 |
45 | // Initial times storage for ping time
46 | this._times = [];
47 |
48 | // Initial lines storage for ping output
49 | this._lines = [];
50 |
51 | // strip string regexp
52 | this._stripRegex = /[ ]*\r?\n?$/g;
53 |
54 | // Ping Config
55 | this._pingConfig = config || {};
56 | }
57 |
58 | /**
59 | * Enum for parser states
60 | * @readonly
61 | * @enum {number}
62 | */
63 | parser.prototype.STATES = {
64 | INIT: 0,
65 | HEADER: 1,
66 | BODY: 2,
67 | FOOTER: 3,
68 | END: 4,
69 | };
70 |
71 | /**
72 | * Change state of this parser
73 | * @param {number} state - parser.STATES
74 | * @return {this} - This instance
75 | */
76 | parser.prototype._changeState = function (state) {
77 | // var states = Object.values(this.STATES); // If minimum engine version can be raised to >=7.0.0 in package.json
78 | var states = Object.keys(this.STATES).map(function (key) { return this.STATES[key]; }, this);
79 | if (states.indexOf(state) < 0) {
80 | throw new Error('Unknown state');
81 | }
82 |
83 | this._state = state;
84 |
85 | return this;
86 | };
87 |
88 | /**
89 | * Process output's header
90 | * @param {string} line - A line from system ping
91 | */
92 | parser.prototype._processHeader = function (line) {
93 | throw new Error('Subclass should implement this method');
94 | };
95 |
96 | /**
97 | * Process output's body
98 | * @param {string} line - A line from system ping
99 | */
100 | parser.prototype._processBody = function (line) {
101 | throw new Error('Subclass should implement this method');
102 | };
103 |
104 | /**
105 | * Process output's footer
106 | * @param {string} line - A line from system ping
107 | */
108 | parser.prototype._processFooter = function (line) {
109 | throw new Error('Subclass should implement this method');
110 | };
111 |
112 | /**
113 | * Process a line from system ping
114 | * @param {string} line - A line from system ping
115 | * @return {this} - This instance
116 | */
117 | parser.prototype.eat = function (line) {
118 | var headerStates = [this.STATES.INIT, this.STATES.HEADER];
119 |
120 | // Store lines
121 | this._lines.push(line);
122 |
123 | // Strip all space \r\n at the end
124 | var _line = line.replace(this._stripRegex, '');
125 |
126 | if (_line.length === 0) {
127 | // Do nothing if this is an empty line
128 | } else if (headerStates.indexOf(this._state) >= 0) {
129 | this._processHeader(_line);
130 | } else if (this._state === this.STATES.BODY) {
131 | this._processBody(_line);
132 | } else if (this._state === this.STATES.FOOTER) {
133 | this._processFooter(_line);
134 | } else if (this._state === this.STATES.END) {
135 | // Do nothing
136 | } else {
137 | throw new Error('Unknown state');
138 | }
139 |
140 | return this;
141 | };
142 |
143 | /**
144 | * Get results after parsing certain lines from system ping
145 | * @return {PingResponse} - Response from parsing ping output
146 | */
147 | parser.prototype.getResult = function () {
148 | var ret = Object.assign({}, this._response);
149 |
150 | // Concat output
151 | ret.output = this._lines.join('\n');
152 |
153 | // Determine alive
154 | ret.alive = this._times.length > 0;
155 |
156 | // Update time at first successful line
157 | if (ret.alive) {
158 | this._response.time = this._times[0];
159 | ret.time = this._response.time;
160 | this._response.times = this._times;
161 | ret.times = this._response.times;
162 | }
163 |
164 | // Get stddev
165 | if (ret.stddev === 'unknown' && ret.alive) {
166 | var numberOfSamples = this._times.length;
167 |
168 | var sumOfAllSquareDifferences = this._times.reduce(
169 | function (memory, time) {
170 | var differenceFromMean = time - ret.avg;
171 | var squaredDifference = differenceFromMean * differenceFromMean;
172 | return memory + squaredDifference;
173 | },
174 | 0
175 | );
176 | var variances = sumOfAllSquareDifferences / numberOfSamples;
177 |
178 | ret.stddev = Math.round(Math.sqrt(variances) * 1000) / 1000;
179 | }
180 |
181 | // Fix min, avg, max, stddev up to 3 decimal points
182 | ['min', 'avg', 'max', 'stddev', 'packetLoss'].forEach(function (key) {
183 | var v = ret[key];
184 | if (typeof v === 'number') {
185 | ret[key] = v.toFixed(3);
186 | }
187 | });
188 |
189 | return ret;
190 | };
191 |
192 | module.exports = parser;
193 |
--------------------------------------------------------------------------------
/lib/parser/factory.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('util');
4 |
5 | var builderFactory = require('../builder/factory');
6 | var WinParser = require('./win');
7 | var MacParser = require('./mac');
8 | var LinuxParser = require('./linux');
9 |
10 | /**
11 | * A factory creates a parser for parsing output from system ping
12 | * @constructor
13 | */
14 | function factory() {}
15 |
16 | /**
17 | * Create a parser for a given platform
18 | * @param {string} addr - Hostname or ip addres
19 | * @param {string} platform - Name of the platform
20 | * @param {PingConfig} [config] - Config object in probe()
21 | * @return {object} - Parser
22 | * @throw if given platform is not supported
23 | */
24 | factory.createParser = function (addr, platform, config) {
25 | // Avoid function reassignment
26 | var _config = config || {};
27 |
28 | if (!builderFactory.isPlatformSupport(platform)) {
29 | throw new Error(util.format('Platform |%s| is not support', platform));
30 | }
31 |
32 | var ret = null;
33 | if (builderFactory.isWindow(platform)) {
34 | ret = new WinParser(addr, _config);
35 | } else if (builderFactory.isMacOS(platform)) {
36 | ret = new MacParser(addr, _config);
37 | } else if (builderFactory.isLinux(platform)) {
38 | ret = new LinuxParser(addr, _config);
39 | }
40 |
41 | return ret;
42 | };
43 |
44 | module.exports = factory;
45 |
--------------------------------------------------------------------------------
/lib/parser/linux.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('util');
4 | var base = require('./base');
5 | var MacParser = require('./mac');
6 |
7 | /**
8 | * @constructor
9 | * @param {string} addr - Hostname or ip addres
10 | * @param {PingConfig} config - Config object in probe()
11 | */
12 | function LinuxParser(addr, config) {
13 | base.call(this, addr, config);
14 | }
15 |
16 | util.inherits(LinuxParser, base);
17 |
18 | /**
19 | * Process output's body
20 | * @param {string} line - A line from system ping
21 | */
22 | LinuxParser.prototype._processHeader = function (line) {
23 | // Get host and numeric_host
24 | var tokens = line.split(' ');
25 | var isProbablyIPv4 = tokens[1].indexOf('(') === -1;
26 |
27 | if (isProbablyIPv4) {
28 | this._response.host = tokens[1];
29 | this._response.numeric_host = tokens[2].slice(1, -1);
30 | } else {
31 | // Normalise into either a 2 or 3 element array
32 | var foundAddresses = tokens
33 | .slice(1, -3)
34 | .join('')
35 | .match(/([^\s()]+)/g);
36 | this._response.host = foundAddresses.shift();
37 | this._response.numeric_host = foundAddresses.pop();
38 | }
39 |
40 | this._changeState(this.STATES.BODY);
41 | };
42 |
43 | /**
44 | * Process output's body
45 | * @param {string} line - A line from system ping
46 | */
47 | LinuxParser.prototype._processBody = function (line) {
48 | // Reuse mac parser implementation
49 | MacParser.prototype._processBody.call(this, line);
50 | };
51 |
52 | /**
53 | * Process output's footer
54 | * @param {string} line - A line from system ping
55 | */
56 | LinuxParser.prototype._processFooter = function (line) {
57 | // Reuse mac parser implementation
58 | MacParser.prototype._processFooter.call(this, line);
59 | };
60 |
61 | module.exports = LinuxParser;
62 |
--------------------------------------------------------------------------------
/lib/parser/mac.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('util');
4 | var base = require('./base');
5 |
6 | /**
7 | * @constructor
8 | * @param {string} addr - Hostname or ip addres
9 | * @param {PingConfig} config - Config object in probe()
10 | */
11 | function MacParser(addr, config) {
12 | base.call(this, addr, config);
13 | }
14 |
15 | util.inherits(MacParser, base);
16 |
17 | /**
18 | * Process output's header
19 | * @param {string} line - A line from system ping
20 | */
21 | MacParser.prototype._processHeader = function (line) {
22 | // Get host and numeric_host
23 | var tokens = line.split(' ');
24 |
25 | this._response.host = tokens[1];
26 | this._response.numeric_host = tokens[2].slice(1, -2);
27 |
28 | this._changeState(this.STATES.BODY);
29 | };
30 |
31 | /**
32 | * Process output's body
33 | * @param {string} line - A line from system ping
34 | */
35 | MacParser.prototype._processBody = function (line) {
36 | // XXX: Assume there is at least 3 '=' can be found
37 | var count = (line.match(/=/g) || []).length;
38 | if (count >= 3) {
39 | var regExp = /([0-9.]+)[ ]*ms/;
40 | var match = regExp.exec(line);
41 | this._times.push(parseFloat(match[1], 10));
42 | }
43 |
44 | // Change state if it see a '---'
45 | if (line.indexOf('---') >= 0) {
46 | this._changeState(this.STATES.FOOTER);
47 | }
48 | };
49 |
50 | /**
51 | * Process output's footer
52 | * @param {string} line - A line from system ping
53 | */
54 | MacParser.prototype._processFooter = function (line) {
55 | var packetLoss = line.match(/ ([\d.]+)%/);
56 | if (packetLoss) {
57 | this._response.packetLoss = parseFloat(packetLoss[1], 10);
58 | }
59 |
60 | // XXX: Assume number of keywords '/' more than 3
61 | var count = (line.match(/[/]/g) || []).length;
62 | if (count >= 3) {
63 | var regExp = /([0-9.]+)/g;
64 | // XXX: Assume min avg max stddev
65 | var m1 = regExp.exec(line);
66 | var m2 = regExp.exec(line);
67 | var m3 = regExp.exec(line);
68 | var m4 = regExp.exec(line);
69 |
70 | if (m1 && m2 && m3 && m4) {
71 | this._response.min = parseFloat(m1[1], 10);
72 | this._response.avg = parseFloat(m2[1], 10);
73 | this._response.max = parseFloat(m3[1], 10);
74 | this._response.stddev = parseFloat(m4[1], 10);
75 | this._changeState(this.STATES.END);
76 | }
77 |
78 | this._changeState(this.STATES.END);
79 | }
80 | };
81 |
82 | module.exports = MacParser;
83 |
--------------------------------------------------------------------------------
/lib/parser/win.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('util');
4 | var base = require('./base');
5 |
6 | /**
7 | * @constructor
8 | * @param {string} addr - Hostname or ip addres
9 | * @param {PingConfig} config - Config object in probe()
10 | */
11 | function WinParser(addr, config) {
12 | base.call(this, addr, config);
13 | this._ipv4Regex = /^([0-9]{1,3}\.){3}[0-9]{1,3}$/;
14 | }
15 |
16 | util.inherits(WinParser, base);
17 |
18 | /**
19 | * Process output's header
20 | * @param {string} line - A line from system ping
21 | */
22 | WinParser.prototype._processHeader = function (line) {
23 | // XXX: Expect to find [****] when pinging domain like google.com
24 | // Read fixture/win/**/* for the detail
25 | var isPingNumeric = line.indexOf('[') === -1;
26 |
27 | // Get host and numeric_host
28 | var tokens = line.split(' ');
29 |
30 | if (isPingNumeric) {
31 | // For those missing [***], get the first token which match IPV4 regex
32 | this._response.host = tokens.find(
33 | function (t) {
34 | return this._ipv4Regex.test(t);
35 | },
36 | this
37 | );
38 | this._response.numeric_host = this._response.host;
39 | } else {
40 | // For those has [***], anchor with such token
41 | var numericHost = tokens.find(
42 | function (t) {
43 | return t.indexOf('[') !== -1;
44 | },
45 | this
46 | );
47 | var numericHostIndex = tokens.indexOf(numericHost);
48 | var match = /\[(.*)\]/.exec(numericHost);
49 |
50 | if (match) {
51 | // Capture IP inside [] only. refs #71
52 | this._response.numeric_host = match[1];
53 | } else {
54 | // Otherwise, just mark as NA to indicate an error
55 | this._response.numeric_host = 'NA';
56 | }
57 | this._response.host = tokens[numericHostIndex - 1];
58 | }
59 |
60 | this._changeState(this.STATES.BODY);
61 | };
62 |
63 | /**
64 | * Process ipv6 output's body
65 | * @param {string} line - A line from system ping
66 | */
67 | WinParser.prototype._processIPV6Body = function (line) {
68 | var tokens = line.split(' ');
69 | var dataFields = tokens.filter(function (token) {
70 | var isDataField = token.indexOf('=') >= 0 || token.indexOf('<') >= 0;
71 | return isDataField;
72 | });
73 |
74 | // refs #65: Support system like french which has an extra space
75 | dataFields = dataFields.map(function (dataField) {
76 | var ret = dataField;
77 | var dataFieldIndex = tokens.indexOf(dataField);
78 | var nextIndex = dataFieldIndex + 1;
79 |
80 | // Append the missing *ms*
81 | if (nextIndex < tokens.length) {
82 | if (tokens[nextIndex] === 'ms') {
83 | ret += 'ms';
84 | }
85 | }
86 |
87 | return ret;
88 | });
89 |
90 | var expectDataFieldInReplyLine = 1;
91 | if (dataFields.length >= expectDataFieldInReplyLine) {
92 | // XXX: Assume time will alaways get keyword ms for all language
93 | var timeKVP = dataFields.find(function (dataField) {
94 | return dataField.search(/(ms|мс)/i) >= 0;
95 | });
96 | var regExp = /([0-9.]+)/;
97 | var match = regExp.exec(timeKVP);
98 |
99 | this._times.push(parseFloat(match[1], 10));
100 | }
101 | };
102 |
103 | /**
104 | * Process ipv4 output's body
105 | * @param {string} line - A line from system ping
106 | */
107 | WinParser.prototype._processIPV4Body = function (line) {
108 | var tokens = line.split(' ');
109 | var byteTimeTTLFields = tokens.filter(function (token) {
110 | var isDataField = token.indexOf('=') >= 0 || token.indexOf('<') >= 0;
111 | return isDataField;
112 | });
113 |
114 | var expectDataFieldInReplyLine = 3;
115 | var isReplyLine = byteTimeTTLFields.length >= expectDataFieldInReplyLine;
116 | if (isReplyLine) {
117 | var packetSize = this._pingConfig.packetSize;
118 | var byteField = byteTimeTTLFields.find(function (dataField) {
119 | var packetSizeToken = util.format('=%d', packetSize);
120 | var isByteField = dataField.indexOf(packetSizeToken) >= 0;
121 | return isByteField;
122 | });
123 |
124 | // XXX: Assume time field will always be next of byte field
125 | var byteFieldIndex = byteTimeTTLFields.indexOf(byteField);
126 | var timeFieldIndex = byteFieldIndex + 1;
127 | var timeKVP = byteTimeTTLFields[timeFieldIndex];
128 |
129 | var regExp = /([0-9.]+)/;
130 | var match = regExp.exec(timeKVP);
131 |
132 | this._times.push(parseFloat(match[1], 10));
133 | }
134 | };
135 |
136 | /**
137 | * Process output's body
138 | * @param {string} line - A line from system ping
139 | */
140 | WinParser.prototype._processBody = function (line) {
141 | var isPingSummaryLineShown = line.slice(-1) === ':';
142 | if (isPingSummaryLineShown) {
143 | this._changeState(this.STATES.FOOTER);
144 | return;
145 | }
146 |
147 | var isIPV6 = this._pingConfig.v6;
148 | if (isIPV6) {
149 | this._processIPV6Body(line);
150 | } else {
151 | this._processIPV4Body(line);
152 | }
153 | };
154 |
155 | /**
156 | * Process output's footer
157 | * @param {string} line - A line from system ping
158 | */
159 | WinParser.prototype._processFooter = function (line) {
160 | var packetLoss = line.match(/([\d.]+)%/);
161 | if (packetLoss) {
162 | this._response.packetLoss = parseFloat(packetLoss[1], 10);
163 | }
164 |
165 | // XXX: Assume there is a keyword ms
166 | if (line.search(/(ms|мсек)/i) >= 0) {
167 | // XXX: Assume the ordering is Min Max Avg
168 | var regExp = /([0-9.]+)/g;
169 | var m1 = regExp.exec(line);
170 | var m2 = regExp.exec(line);
171 | var m3 = regExp.exec(line);
172 |
173 | if (m1 && m2 && m3) {
174 | this._response.min = parseFloat(m1[1], 10);
175 | this._response.max = parseFloat(m2[1], 10);
176 | this._response.avg = parseFloat(m3[1], 10);
177 | this._changeState(this.STATES.END);
178 | }
179 | }
180 | };
181 |
182 | module.exports = WinParser;
183 |
--------------------------------------------------------------------------------
/lib/ping-pcap.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | /**
4 | * LICENSE MIT
5 | * (C) Daniel Zelisko
6 | * http://github.com/danielzzz/node-ping
7 | *
8 | * A poor man's ping for node.js
9 | * It uses UDP_scanning (as node is not able to generate iCPM packets)
10 | * http://en.wikipedia.org/wiki/Port_scanner#UDP_scanning
11 | * it may not work correct for hosts that silently drop UDP traffic on their firewall
12 | * you need at pcap version 0.1.9 or higher
13 | *
14 | */
15 |
16 | var sys = require("util"),
17 | pcap = require('pcap');
18 |
19 | var addr = process.argv[3] || 'localhost';
20 | setInterval(function() {probe(addr)}, 1000);
21 |
22 |
23 | function probe(addr) {
24 | sys.puts('sending a probe to ' + addr);
25 | var dgram = require('dgram');
26 | var message = new Buffer("Some bytes");
27 | var client = dgram.createSocket("udp4");
28 | client.send(message, 0, message.length, 21111, addr);
29 | client.close();
30 | }
31 |
32 | // create a pcap session
33 | pcap_session = pcap.createSession(process.argv[2] || 'eth0', "");
34 |
35 |
36 | // listen for packets, decode them, and feed the simple printer
37 | pcap_session.addListener('packet', function (raw_packet) {
38 | var packet = pcap.decode.packet(raw_packet);
39 | if (packet.link && packet.link.ip && packet.link.ip.saddr==addr) {
40 | packet.link && packet.link.ip && sys.puts(packet.link.ip.saddr + " is alive");
41 | }
42 | });
43 |
44 | //-------- example ------------------------
45 |
46 |
47 |
--------------------------------------------------------------------------------
/lib/ping-promise.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * LICENSE MIT
5 | * (C) Daniel Zelisko
6 | * http://github.com/danielzzz/node-ping
7 | *
8 | * a simple wrapper for ping
9 | * Now with support of not only english Windows.
10 | *
11 | */
12 |
13 | // System library
14 | var util = require('util');
15 | var net = require('net');
16 | var cp = require('child_process');
17 | var os = require('os');
18 |
19 | // Our library
20 | var builderFactory = require('./builder/factory');
21 | var parserFactory = require('./parser/factory');
22 |
23 | /**
24 | * Refer to probe()
25 | */
26 | function _probe(addr, config) {
27 | // Do not reassign function argument
28 | var _config = config || {};
29 | if (_config.v6 === undefined) {
30 | _config.v6 = net.isIPv6(addr);
31 | }
32 |
33 | // Convert callback base system command to promise base
34 | return new Promise(function (resolve, reject) {
35 | // Spawn a ping process
36 | var ping = null;
37 | var platform = os.platform();
38 | try {
39 | var argumentBuilder = builderFactory.createBuilder(platform);
40 | var pingExecutablePath = builderFactory.getExecutablePath(platform, _config.v6);
41 | var pingArgs = argumentBuilder.getCommandArguments(addr, _config);
42 | var spawnOptions = argumentBuilder.getSpawnOptions();
43 | ping = cp.spawn(pingExecutablePath, pingArgs, spawnOptions);
44 | } catch (err) {
45 | reject(err);
46 | return;
47 | }
48 |
49 | // Initial parser
50 | var parser = parserFactory.createParser(addr, platform, _config);
51 |
52 | // Register events from system ping
53 | ping.once('error', function () {
54 | var err = new Error(
55 | util.format(
56 | 'ping.probe: %s. %s',
57 | 'there was an error while executing the ping program. ',
58 | 'Check the path or permissions...'
59 | )
60 | );
61 | reject(err);
62 | });
63 |
64 | // Cache all lines from the system ping
65 | var outstring = [];
66 | ping.stdout.on('data', function (data) {
67 | outstring.push(String(data));
68 | });
69 | ping.stderr.on('data', function (data) {
70 | outstring.push(String(data));
71 | });
72 |
73 | // Parse lines we have on closing system ping
74 | ping.once('close', function () {
75 | // Merge lines we have and split it by \n
76 | var lines = outstring.join('').split('\n');
77 |
78 | // Parse line one by one
79 | lines.forEach(parser.eat, parser);
80 |
81 | // Get result
82 | var ret = parser.getResult();
83 |
84 | resolve(ret);
85 | });
86 | });
87 | }
88 |
89 | /**
90 | * Class::PromisePing
91 | * @param {string} addr - Hostname or ip addres
92 | * @param {PingConfig} config - Configuration for command ping
93 | * @return {Promise}
94 | */
95 | function probe(addr, config) {
96 | try {
97 | var probePromise = _probe(addr, config);
98 | return probePromise;
99 | } catch (error) {
100 | var errorPromise = Promise.reject(error);
101 | return errorPromise;
102 | }
103 | }
104 |
105 | exports.probe = probe;
106 |
--------------------------------------------------------------------------------
/lib/ping-sys.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * LICENSE MIT
5 | * (C) Daniel Zelisko
6 | * http://github.com/danielzzz/node-ping
7 | *
8 | * a simple wrapper for ping
9 | * Now with support of not only english Windows.
10 | *
11 | */
12 |
13 | // Promise implementation
14 | var ping = require('./ping-promise');
15 |
16 | // TODO:
17 | // 1. Port round trip time to this callback
18 | // 2. However, it may breaks backward compatability
19 | // 3. Need discussion
20 | /**
21 | * Callback after probing given host
22 | * @callback probeCallback
23 | * @param {boolean} isAlive - Whether target is alive or not
24 | * @param {Object} error - Null if no error occurs
25 | */
26 |
27 | /**
28 | * Class::Ping construtor
29 | * @param {string} addr - Hostname or ip addres
30 | * @param {probeCallback} cb - Callback
31 | * @param {PingConfig} config - Configuration for command ping
32 | */
33 | function probe(addr, cb, config) {
34 | // Do not reassign function parameter
35 | var _config = config || {};
36 |
37 | return ping.probe(addr, _config).then(function (res) {
38 | cb(res.alive, null);
39 | }).catch(function (err) {
40 | cb(null, err);
41 | });
42 | }
43 |
44 | exports.probe = probe;
45 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "danielzzz (http://daniel.zelisko.net)",
3 | "scripts": {
4 | "test": "grunt test",
5 | "lint": "grunt eslint",
6 | "coverage": "grunt coverage"
7 | },
8 | "contributors": [
9 | "Mond Wan ",
10 | "dougluce ",
11 | "weihua44",
12 | "GermanBluefox",
13 | "mabukar",
14 | "microacup ",
15 | "Andrew Fadeev",
16 | "Joshua Pruitt ",
17 | "Stephan van Rooij (http://svrooij.nl)",
18 | "Krispin Schulz (http://kr1sp1n.io)",
19 | "Kathy Hill",
20 | "mrMuppet",
21 | "Adam Heath (http://www.adamheath.me)",
22 | "BlessJah ",
23 | "jritsema"
24 | ],
25 | "name": "ping",
26 | "description": "a simple wrapper for ping",
27 | "version": "0.4.4",
28 | "homepage": "http://github.com/danielzzz/node-ping",
29 | "license": "MIT",
30 | "repository": {
31 | "type": "git",
32 | "url": "git://github.com/danielzzz/node-ping.git"
33 | },
34 | "engines": {
35 | "node": ">=4.0.0"
36 | },
37 | "devDependencies": {
38 | "@babel/cli": "^7.17.10",
39 | "@babel/core": "^7.18.2",
40 | "@babel/eslint-parser": "^7.18.2",
41 | "@babel/preset-env": "^7.18.2",
42 | "@types/glob": "^8.1.0",
43 | "chai": "4.2.0",
44 | "coveralls": "^3.1.1",
45 | "eslint": "^8.16.0",
46 | "eslint-config-airbnb": "^19.0.4",
47 | "eslint-config-eslint": "^7.0.0",
48 | "eslint-plugin-import": "^2.26.0",
49 | "eslint-plugin-jsdoc": "^39.3.2",
50 | "eslint-plugin-jsx-a11y": "^6.5.1",
51 | "eslint-plugin-node": "^11.1.0",
52 | "eslint-plugin-react": "^7.30.0",
53 | "eslint-plugin-react-hooks": "^4.5.0",
54 | "glob": "^7.2.3",
55 | "grunt": "^1.5.3",
56 | "grunt-coveralls": "^2.0.0",
57 | "grunt-eslint": "^24.0.0",
58 | "grunt-mocha-test": "^0.13.3",
59 | "grunt-nyc-mocha": "^1.1.0",
60 | "mocha": "^10.0.0",
61 | "nyc": "^15.1.0",
62 | "sinon": "9.2.2"
63 | },
64 | "main": "index.js",
65 | "files": [
66 | "index.js",
67 | "lib/**/*",
68 | "lib/*"
69 | ]
70 | }
71 |
--------------------------------------------------------------------------------
/test/fixture/answer.json:
--------------------------------------------------------------------------------
1 | {
2 | "macos_en_sample1": {
3 | "inputHost": "whatever",
4 | "host": "google.com",
5 | "numeric_host": "172.217.24.46",
6 | "alive": true,
7 | "output": "PING google.com (172.217.24.46): 56 data bytes\n64 bytes from 172.217.24.46: icmp_seq=0 ttl=54 time=5.371 ms\n64 bytes from 172.217.24.46: icmp_seq=1 ttl=54 time=4.269 ms\n64 bytes from 172.217.24.46: icmp_seq=2 ttl=54 time=4.970 ms\n64 bytes from 172.217.24.46: icmp_seq=3 ttl=54 time=5.228 ms\n\n--- google.com ping statistics ---\n4 packets transmitted, 4 packets received, 0.0% packet loss\nround-trip min/avg/max/stddev = 4.269/4.960/5.371/0.424 ms\n",
8 | "time": 5.371,
9 | "times": [
10 | 5.371,
11 | 4.269,
12 | 4.97,
13 | 5.228
14 | ],
15 | "min": "4.269",
16 | "max": "5.371",
17 | "avg": "4.960",
18 | "packetLoss": "0.000",
19 | "stddev": "0.424"
20 | },
21 | "macos_en_sample2": {
22 | "inputHost": "whatever",
23 | "host": "1.1.1.1",
24 | "numeric_host": "1.1.1.1",
25 | "alive": false,
26 | "output": "PING 1.1.1.1 (1.1.1.1): 56 data bytes\nping: permission denied (are you root?)\n",
27 | "time": "unknown",
28 | "times": [],
29 | "min": "unknown",
30 | "max": "unknown",
31 | "avg": "unknown",
32 | "packetLoss": "unknown",
33 | "stddev": "unknown"
34 | },
35 | "linux_en_sample1": {
36 | "inputHost": "whatever",
37 | "host": "localhost",
38 | "numeric_host": "127.0.0.1",
39 | "alive": true,
40 | "output": "PING localhost (127.0.0.1) 56(84) bytes of data.\n64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.022 ms\n64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.027 ms\n64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.029 ms\n64 bytes from localhost (127.0.0.1): icmp_seq=4 ttl=64 time=0.030 ms\n\n--- localhost ping statistics ---\n4 packets transmitted, 4 received, 0% packet loss, time 2999ms\nrtt min/avg/max/mdev = 0.022/0.027/0.030/0.003 ms\n",
41 | "time": 0.022,
42 | "times": [
43 | 0.022,
44 | 0.027,
45 | 0.029,
46 | 0.03
47 | ],
48 | "min": "0.022",
49 | "max": "0.030",
50 | "avg": "0.027",
51 | "stddev": "0.003",
52 | "packetLoss": "0.000"
53 | },
54 | "linux_en_sample2": {
55 | "inputHost": "whatever",
56 | "host": "10.48.249.8",
57 | "numeric_host": "10.48.249.8",
58 | "alive": true,
59 | "output": "PING 10.48.249.8 (10.48.249.8) 56(84) bytes of data.\n64 bytes from 10.48.249.8: icmp_seq=1 ttl=64 time=2.98 ms\n64 bytes from 10.48.249.8: icmp_seq=2 ttl=64 time=0.890 ms\n64 bytes from 10.48.249.8: icmp_seq=3 ttl=64 time=0.711 ms\n64 bytes from 10.48.249.8: icmp_seq=4 ttl=64 time=0.863 ms\n64 bytes from 10.48.249.8: icmp_seq=5 ttl=64 time=1.20 ms\nping: sendmsg: Network is unreachable\nping: sendmsg: Network is unreachable\nping: sendmsg: Network is unreachable\n64 bytes from 10.48.249.8: icmp_seq=14 ttl=64 time=797 ms\n64 bytes from 10.48.249.8: icmp_seq=15 ttl=64 time=3.86 ms\n64 bytes from 10.48.249.8: icmp_seq=16 ttl=64 time=1.62 ms\n64 bytes from 10.48.249.8: icmp_seq=17 ttl=64 time=0.702 ms\n64 bytes from 10.48.249.8: icmp_seq=18 ttl=64 time=0.783 ms\n64 bytes from 10.48.249.8: icmp_seq=19 ttl=64 time=0.646 ms\n\n--- 10.48.249.8 ping statistics ---\n19 packets transmitted, 11 received, 42% packet loss, time 18195ms\nrtt min/avg/max/mdev = 0.646/73.819/797.744/228.927 ms\n",
60 | "time": 2.98,
61 | "times": [
62 | 2.98,
63 | 0.89,
64 | 0.711,
65 | 0.863,
66 | 1.2,
67 | 797,
68 | 3.86,
69 | 1.62,
70 | 0.702,
71 | 0.783,
72 | 0.646
73 | ],
74 | "min": "0.646",
75 | "max": "797.744",
76 | "avg": "73.819",
77 | "packetLoss": "42.000",
78 | "stddev": "228.927"
79 | },
80 | "linux_en_sample3": {
81 | "inputHost": "whatever",
82 | "host": "10.48.249.150",
83 | "numeric_host": "10.48.249.150",
84 | "alive": false,
85 | "output": "PING 10.48.249.150 (10.48.249.150) 56(84) bytes of data.\nFrom 10.48.249.95 icmp_seq=1 Destination Host Unreachable\nFrom 10.48.249.95 icmp_seq=2 Destination Host Unreachable\nFrom 10.48.249.95 icmp_seq=3 Destination Host Unreachable\n\n--- 10.48.249.150 ping statistics ---\n5 packets transmitted, 0 received, +3 errors, 100% packet loss, time 4079ms\n",
86 | "time": "unknown",
87 | "times": [],
88 | "min": "unknown",
89 | "max": "unknown",
90 | "avg": "unknown",
91 | "packetLoss": "100.000",
92 | "stddev": "unknown"
93 | },
94 | "linux_en_v6_sample1": {
95 | "inputHost": "whatever",
96 | "host": "2606:4700:4700::1111",
97 | "numeric_host": "2606:4700:4700::1111",
98 | "alive": true,
99 | "output": "PING 2606:4700:4700::1111(2606:4700:4700::1111) 56 data bytes\n64 bytes from 2606:4700:4700::1111: icmp_seq=1 ttl=57 time=0.672 ms\n64 bytes from 2606:4700:4700::1111: icmp_seq=2 ttl=57 time=1.00 ms\n\n--- 2606:4700:4700::1111 ping statistics ---\n2 packets transmitted, 2 received, 0% packet loss, time 1000ms\nrtt min/avg/max/mdev = 0.672/0.840/1.009/0.170 ms\n",
100 | "time": 0.672,
101 | "times": [
102 | 0.672,
103 | 1.00
104 | ],
105 | "min": "0.672",
106 | "max": "1.009",
107 | "avg": "0.840",
108 | "packetLoss": "0.000",
109 | "stddev": "0.170"
110 | },
111 | "linux_en_v6_sample2": {
112 | "inputHost": "whatever",
113 | "host": "one.one.one.one",
114 | "numeric_host": "2606:4700:4700::1111",
115 | "alive": true,
116 | "output": "PING one.one.one.one(one.one.one.one (2606:4700:4700::1111)) 56 data bytes\n64 bytes from one.one.one.one (2606:4700:4700::1111): icmp_seq=1 ttl=60 time=1.66 ms\n64 bytes from one.one.one.one (2606:4700:4700::1111): icmp_seq=2 ttl=60 time=1.42 ms\n\n--- one.one.one.one ping statistics ---\n2 packets transmitted, 2 received, 0% packet loss, time 1001ms\nrtt min/avg/max/mdev = 1.429/1.546/1.663/0.117 ms\n",
117 | "time": 1.66,
118 | "times": [
119 | 1.66,
120 | 1.42
121 | ],
122 | "min": "1.429",
123 | "max": "1.663",
124 | "avg": "1.546",
125 | "packetLoss": "0.000",
126 | "stddev": "0.117"
127 | },
128 | "window_en_sample1": {
129 | "inputHost": "whatever",
130 | "host": "www.some-domain.com",
131 | "numeric_host": "127.0.0.1",
132 | "alive": true,
133 | "output": "Pinging www.some-domain.com [127.0.0.1] with 32 bytes of\nReply from 127.0.0.1: bytes=32 time=564ms TTL=237\nReply from 127.0.0.1: bytes=32 time=555ms TTL=237\nReply from 127.0.0.1: bytes=32 time=554ms TTL=237\nReply from 127.0.0.1: bytes=32 time=548ms TTL=237\n\nPing statistics for 127.0.0.1:\n Packets: Sent = 4, Received = 4, Lost = 0 (0% loss)\n Approximate round trip times in milli-seconds:\n Minimum = 548ms, Maximum = 564ms, Average = 555ms\n",
134 | "time": 564,
135 | "times": [
136 | 564,
137 | 555,
138 | 554,
139 | 548
140 | ],
141 | "min": "548.000",
142 | "max": "564.000",
143 | "avg": "555.000",
144 | "stddev": "5.723",
145 | "packetLoss": "0.000",
146 | "stddev": "5.723"
147 | },
148 | "window_fr_sample1": {
149 | "inputHost": "whatever",
150 | "host": "127.0.0.1",
151 | "numeric_host": "127.0.0.1",
152 | "alive": true,
153 | "output": "Envoi d’une requete 'Ping' 127.0.0.1 avec 32 octets de donnees :\nReponse de 127.0.0.1 : octets=32 temps<1ms TTL=128\nReponse de 127.0.0.1 : octets=32 temps<1ms TTL=128\nReponse de 127.0.0.1 : octets=32 temps<1ms TTL=128\nReponse de 127.0.0.1 : octets=32 temps<1ms TTL=128\n\nStatistiques Ping pour 127.0.0.1:\nPaquets : envoyes = 4, recus = 4, perdus = 0 (perte 0%),\nDuree approximative des boucles en millisecondes :\nMinimum = 0ms, Maximum = 0ms, Moyenne = 0ms\n",
154 | "time": 1,
155 | "times": [
156 | 1,
157 | 1,
158 | 1,
159 | 1
160 | ],
161 | "min": "0.000",
162 | "max": "0.000",
163 | "avg": "0.000",
164 | "stddev": "1.000",
165 | "packetLoss": "0.000"
166 | },
167 | "window_fr_sample2": {
168 | "inputHost": "whatever",
169 | "host": "8.8.8.8",
170 | "numeric_host": "8.8.8.8",
171 | "alive": true,
172 | "output": "Envoi d’une requete 'Ping' 8.8.8.8 avec 32 octets de donnees :\nReponse de 8.8.8.8 : octets=32 temps=6 ms TTL=58\nReponse de 8.8.8.8 : octets=32 temps=6 ms TTL=58\nReponse de 8.8.8.8 : octets=32 temps=6 ms TTL=58\nReponse de 8.8.8.8 : octets=32 temps=6 ms TTL=58\n\nStatistiques Ping pour 8.8.8.8:\nPaquets : envoyes = 4, recus = 4, perdus = 0 (perte 0%),\nDuree approximative des boucles en millisecondes :\nMinimum = 6ms, Maximum = 6ms, Moyenne = 6ms\n",
173 | "time": 6,
174 | "times": [
175 | 6,
176 | 6,
177 | 6,
178 | 6
179 | ],
180 | "min": "6.000",
181 | "max": "6.000",
182 | "avg": "6.000",
183 | "stddev": "0.000",
184 | "packetLoss": "0.000"
185 | },
186 | "window_ja_sample1": {
187 | "inputHost": "whatever",
188 | "host": "google.com",
189 | "numeric_host": "216.58.197.142",
190 | "alive": true,
191 | "output": "google.com [216.58.197.142]に ping を送信しています 32 バイトのデータ:\n216.58.197.142 からの応答: バイト数 =32 時間 =7ms TTL=55\n216.58.197.142 からの応答: バイト数 =32 時間 =5ms TTL=55\n216.58.197.142 からの応答: バイト数 =32 時間 =4ms TTL=55\n216.58.197.142 からの応答: バイト数 =32 時間 =4ms TTL=55\n\n216.58.197.142 の ping 統計:\n パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、\nラウンド トリップの概算時間 (ミリ秒):\n 最小 = 4ms、最大 = 7ms、平均 = 5ms\n",
192 | "time": 7,
193 | "times": [
194 | 7,
195 | 5,
196 | 4,
197 | 4
198 | ],
199 | "min": "4.000",
200 | "max": "7.000",
201 | "avg": "5.000",
202 | "stddev": "1.225",
203 | "packetLoss": "0.000"
204 | },
205 | "window_ja_sample2": {
206 | "inputHost": "whatever",
207 | "host": "8.8.8.8",
208 | "numeric_host": "8.8.8.8",
209 | "alive": true,
210 | "output": "8.8.8.8 に ping を送信しています 32 バイトのデータ:\n8.8.8.8 からの応答: バイト数 =32 時間 =4ms TTL=58\n8.8.8.8 からの応答: バイト数 =32 時間 =4ms TTL=58\n8.8.8.8 からの応答: バイト数 =32 時間 =5ms TTL=58\n8.8.8.8 からの応答: バイト数 =32 時間 =6ms TTL=58\n\n8.8.8.8 の ping 統計:\n パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、\nラウンド トリップの概算時間 (ミリ秒):\n 最小 = 4ms、最大 = 6ms、平均 = 4ms\n",
211 | "time": 4,
212 | "times": [
213 | 4,
214 | 4,
215 | 5,
216 | 6
217 | ],
218 | "min": "4.000",
219 | "max": "6.000",
220 | "avg": "4.000",
221 | "stddev": "1.118",
222 | "packetLoss": "0.000"
223 | },
224 | "window_zh_sample1": {
225 | "inputHost": "whatever",
226 | "host": "google.com",
227 | "numeric_host": "216.58.203.14",
228 | "alive": true,
229 | "output": "Ping google.com [216.58.203.14] (使用 32 位元組的資料):\n回覆自 216.58.203.14: 位元組=32 時間=2ms TTL=54\n回覆自 216.58.203.14: 位元組=32 時間=2ms TTL=54\n回覆自 216.58.203.14: 位元組=32 時間=3ms TTL=54\n回覆自 216.58.203.14: 位元組=32 時間=3ms TTL=54\n\n216.58.203.14 的 Ping 統計資料:\n 封包: 已傳送 = 4,已收到 = 4, 已遺失 = 0 (0% 遺失),\n 大約的來回時間 (毫秒):\n 最小值 = 2ms,最大值 = 3ms,平均 = 2ms\n",
230 | "time": 2,
231 | "times": [
232 | 2,
233 | 2,
234 | 3,
235 | 3
236 | ],
237 | "min": "2.000",
238 | "max": "3.000",
239 | "avg": "2.000",
240 | "stddev": "0.707",
241 | "packetLoss": "0.000"
242 | },
243 | "window_zh_sample2": {
244 | "inputHost": "whatever",
245 | "host": "google.com",
246 | "numeric_host": "216.58.203.14",
247 | "alive": true,
248 | "output": "\nPing google.com [216.58.203.14] (使用 32 位元組的資料):\n回覆自 216.58.203.14: 位元組=32 時間=2ms TTL=54\n回覆自 216.58.203.14: 位元組=32 時間=2ms TTL=54\n回覆自 216.58.203.14: 位元組=32 時間=3ms TTL=54\n回覆自 216.58.203.14: 位元組=32 時間=3ms TTL=54\n\n216.58.203.14 的 Ping 統計資料:\n 封包: 已傳送 = 4,已收到 = 4, 已遺失 = 0 (0% 遺失),\n 大約的來回時間 (毫秒):\n 最小值 = 2ms,最大值 = 3ms,平均 = 2ms\n",
249 | "time": 2,
250 | "times": [
251 | 2,
252 | 2,
253 | 3,
254 | 3
255 | ],
256 | "min": "2.000",
257 | "max": "3.000",
258 | "avg": "2.000",
259 | "stddev": "0.707",
260 | "packetLoss": "0.000"
261 | },
262 | "window_zh_sample3": {
263 | "inputHost": "whatever",
264 | "host": "127.0.0.1",
265 | "numeric_host": "127.0.0.1",
266 | "alive": true,
267 | "output": "\nPing 127.0.0.1 (使用 32 位元組的資料):\n回覆自 127.0.0.1: 位元組=32 時間<1ms TTL=128\n回覆自 127.0.0.1: 位元組=32 時間<1ms TTL=128\n回覆自 127.0.0.1: 位元組=32 時間<1ms TTL=128\n回覆自 127.0.0.1: 位元組=32 時間<1ms TTL=128\n\n127.0.0.1 的 Ping 統計資料:\n 封包: 已傳送 = 4,已收到 = 4, 已遺失 = 0 (0% 遺失),\n 大約的來回時間 (毫秒):\n 最小值 = 0ms,最大值 = 0ms,平均 = 0ms\n",
268 | "time": 1,
269 | "times": [
270 | 1,
271 | 1,
272 | 1,
273 | 1
274 | ],
275 | "min": "0.000",
276 | "max": "0.000",
277 | "avg": "0.000",
278 | "stddev": "1.000",
279 | "packetLoss": "0.000"
280 | },
281 | "window_ru_sample1": {
282 | "inputHost": "whatever",
283 | "host": "8.8.8.8",
284 | "numeric_host": "8.8.8.8",
285 | "alive": true,
286 | "output": "Обмен пакетами с 8.8.8.8 по с 32 байтами данных:\nОтвет от 8.8.8.8: число байт=32 время=37мс TTL=55\nОтвет от 8.8.8.8: число байт=32 время=33мс TTL=55\nОтвет от 8.8.8.8: число байт=32 время=38мс TTL=55\nОтвет от 8.8.8.8: число байт=32 время=34мс TTL=55\n\nСтатистика Ping для 8.8.8.8:\n Пакетов: отправлено = 4, получено = 4, потеряно = 0\n (0% потерь)\nПриблизительное время приема-передачи в мс:\n Минимальное = 33мсек, Максимальное = 38 мсек, Среднее = 35 мсек",
287 | "time": 37,
288 | "times": [
289 | 37,
290 | 33,
291 | 38,
292 | 34
293 | ],
294 | "min": "33.000",
295 | "max": "38.000",
296 | "avg": "35.000",
297 | "stddev": "2.121",
298 | "packetLoss": "0.000"
299 | },
300 | "window_de_v6_sample": {
301 | "inputHost": "whatever",
302 | "host": "google.de",
303 | "alive": true,
304 | "output": "Ping wird ausgeführt für google.de [2a00:1450:4001:810::2003] von 3001:4cb0:0:f282:ddf1:bec9:1e0:bfa9 mit 32 Bytes Daten:\nAntwort von 2a00:1450:4001:810::2003: Zeit=11ms\nAntwort von 2a00:1450:4001:810::2003: Zeit=11ms\nAntwort von 2a00:1450:4001:810::2003: Zeit=18ms\nAntwort von 2a00:1450:4001:810::2003: Zeit=11ms\n\nPing-Statistik für 2a00:1450:4001:810::2003:\n Pakete: Gesendet = 4, Empfangen = 4, Verloren = 0\n (0% Verlust),\nCa. Zeitangaben in Millisek.:\n Minimum = 11ms, Maximum = 18ms, Mittelwert = 12ms\n",
305 | "time": 11,
306 | "times": [
307 | 11,
308 | 11,
309 | 18,
310 | 11
311 | ],
312 | "min": "11.000",
313 | "max": "18.000",
314 | "avg": "12.000",
315 | "packetLoss": "0.000",
316 | "stddev": "3.122",
317 | "numeric_host": "2a00:1450:4001:810::2003" }
318 | }
319 |
--------------------------------------------------------------------------------
/test/fixture/linux/.gitdirectory:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danielzzz/node-ping/e4aafb594c2f5a738174a4bc604f2dae9ed84a31/test/fixture/linux/.gitdirectory
--------------------------------------------------------------------------------
/test/fixture/linux/en/sample1.txt:
--------------------------------------------------------------------------------
1 | PING localhost (127.0.0.1) 56(84) bytes of data.
2 | 64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.022 ms
3 | 64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.027 ms
4 | 64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.029 ms
5 | 64 bytes from localhost (127.0.0.1): icmp_seq=4 ttl=64 time=0.030 ms
6 |
7 | --- localhost ping statistics ---
8 | 4 packets transmitted, 4 received, 0% packet loss, time 2999ms
9 | rtt min/avg/max/mdev = 0.022/0.027/0.030/0.003 ms
10 |
--------------------------------------------------------------------------------
/test/fixture/linux/en/sample2.txt:
--------------------------------------------------------------------------------
1 | PING 10.48.249.8 (10.48.249.8) 56(84) bytes of data.
2 | 64 bytes from 10.48.249.8: icmp_seq=1 ttl=64 time=2.98 ms
3 | 64 bytes from 10.48.249.8: icmp_seq=2 ttl=64 time=0.890 ms
4 | 64 bytes from 10.48.249.8: icmp_seq=3 ttl=64 time=0.711 ms
5 | 64 bytes from 10.48.249.8: icmp_seq=4 ttl=64 time=0.863 ms
6 | 64 bytes from 10.48.249.8: icmp_seq=5 ttl=64 time=1.20 ms
7 | ping: sendmsg: Network is unreachable
8 | ping: sendmsg: Network is unreachable
9 | ping: sendmsg: Network is unreachable
10 | 64 bytes from 10.48.249.8: icmp_seq=14 ttl=64 time=797 ms
11 | 64 bytes from 10.48.249.8: icmp_seq=15 ttl=64 time=3.86 ms
12 | 64 bytes from 10.48.249.8: icmp_seq=16 ttl=64 time=1.62 ms
13 | 64 bytes from 10.48.249.8: icmp_seq=17 ttl=64 time=0.702 ms
14 | 64 bytes from 10.48.249.8: icmp_seq=18 ttl=64 time=0.783 ms
15 | 64 bytes from 10.48.249.8: icmp_seq=19 ttl=64 time=0.646 ms
16 |
17 | --- 10.48.249.8 ping statistics ---
18 | 19 packets transmitted, 11 received, 42% packet loss, time 18195ms
19 | rtt min/avg/max/mdev = 0.646/73.819/797.744/228.927 ms
20 |
--------------------------------------------------------------------------------
/test/fixture/linux/en/sample3.txt:
--------------------------------------------------------------------------------
1 | PING 10.48.249.150 (10.48.249.150) 56(84) bytes of data.
2 | From 10.48.249.95 icmp_seq=1 Destination Host Unreachable
3 | From 10.48.249.95 icmp_seq=2 Destination Host Unreachable
4 | From 10.48.249.95 icmp_seq=3 Destination Host Unreachable
5 |
6 | --- 10.48.249.150 ping statistics ---
7 | 5 packets transmitted, 0 received, +3 errors, 100% packet loss, time 4079ms
8 |
--------------------------------------------------------------------------------
/test/fixture/linux/en/v6_sample1.txt:
--------------------------------------------------------------------------------
1 | PING 2606:4700:4700::1111(2606:4700:4700::1111) 56 data bytes
2 | 64 bytes from 2606:4700:4700::1111: icmp_seq=1 ttl=57 time=0.672 ms
3 | 64 bytes from 2606:4700:4700::1111: icmp_seq=2 ttl=57 time=1.00 ms
4 |
5 | --- 2606:4700:4700::1111 ping statistics ---
6 | 2 packets transmitted, 2 received, 0% packet loss, time 1000ms
7 | rtt min/avg/max/mdev = 0.672/0.840/1.009/0.170 ms
8 |
--------------------------------------------------------------------------------
/test/fixture/linux/en/v6_sample2.txt:
--------------------------------------------------------------------------------
1 | PING one.one.one.one(one.one.one.one (2606:4700:4700::1111)) 56 data bytes
2 | 64 bytes from one.one.one.one (2606:4700:4700::1111): icmp_seq=1 ttl=60 time=1.66 ms
3 | 64 bytes from one.one.one.one (2606:4700:4700::1111): icmp_seq=2 ttl=60 time=1.42 ms
4 |
5 | --- one.one.one.one ping statistics ---
6 | 2 packets transmitted, 2 received, 0% packet loss, time 1001ms
7 | rtt min/avg/max/mdev = 1.429/1.546/1.663/0.117 ms
8 |
--------------------------------------------------------------------------------
/test/fixture/macos/.gitdirectory:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danielzzz/node-ping/e4aafb594c2f5a738174a4bc604f2dae9ed84a31/test/fixture/macos/.gitdirectory
--------------------------------------------------------------------------------
/test/fixture/macos/en/sample1.txt:
--------------------------------------------------------------------------------
1 | PING google.com (172.217.24.46): 56 data bytes
2 | 64 bytes from 172.217.24.46: icmp_seq=0 ttl=54 time=5.371 ms
3 | 64 bytes from 172.217.24.46: icmp_seq=1 ttl=54 time=4.269 ms
4 | 64 bytes from 172.217.24.46: icmp_seq=2 ttl=54 time=4.970 ms
5 | 64 bytes from 172.217.24.46: icmp_seq=3 ttl=54 time=5.228 ms
6 |
7 | --- google.com ping statistics ---
8 | 4 packets transmitted, 4 packets received, 0.0% packet loss
9 | round-trip min/avg/max/stddev = 4.269/4.960/5.371/0.424 ms
10 |
--------------------------------------------------------------------------------
/test/fixture/macos/en/sample2.txt:
--------------------------------------------------------------------------------
1 | PING 1.1.1.1 (1.1.1.1): 56 data bytes
2 | ping: permission denied (are you root?)
3 |
--------------------------------------------------------------------------------
/test/fixture/window/.gitdirectory:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danielzzz/node-ping/e4aafb594c2f5a738174a4bc604f2dae9ed84a31/test/fixture/window/.gitdirectory
--------------------------------------------------------------------------------
/test/fixture/window/de/v6_sample.txt:
--------------------------------------------------------------------------------
1 | Ping wird ausgeführt für google.de [2a00:1450:4001:810::2003] von 3001:4cb0:0:f282:ddf1:bec9:1e0:bfa9 mit 32 Bytes Daten:
2 | Antwort von 2a00:1450:4001:810::2003: Zeit=11ms
3 | Antwort von 2a00:1450:4001:810::2003: Zeit=11ms
4 | Antwort von 2a00:1450:4001:810::2003: Zeit=18ms
5 | Antwort von 2a00:1450:4001:810::2003: Zeit=11ms
6 |
7 | Ping-Statistik für 2a00:1450:4001:810::2003:
8 | Pakete: Gesendet = 4, Empfangen = 4, Verloren = 0
9 | (0% Verlust),
10 | Ca. Zeitangaben in Millisek.:
11 | Minimum = 11ms, Maximum = 18ms, Mittelwert = 12ms
12 |
--------------------------------------------------------------------------------
/test/fixture/window/en/sample1.txt:
--------------------------------------------------------------------------------
1 | Pinging www.some-domain.com [127.0.0.1] with 32 bytes of
2 | Reply from 127.0.0.1: bytes=32 time=564ms TTL=237
3 | Reply from 127.0.0.1: bytes=32 time=555ms TTL=237
4 | Reply from 127.0.0.1: bytes=32 time=554ms TTL=237
5 | Reply from 127.0.0.1: bytes=32 time=548ms TTL=237
6 |
7 | Ping statistics for 127.0.0.1:
8 | Packets: Sent = 4, Received = 4, Lost = 0 (0% loss)
9 | Approximate round trip times in milli-seconds:
10 | Minimum = 548ms, Maximum = 564ms, Average = 555ms
11 |
--------------------------------------------------------------------------------
/test/fixture/window/fr/sample1.txt:
--------------------------------------------------------------------------------
1 | Envoi d’une requete 'Ping' 127.0.0.1 avec 32 octets de donnees :
2 | Reponse de 127.0.0.1 : octets=32 temps<1ms TTL=128
3 | Reponse de 127.0.0.1 : octets=32 temps<1ms TTL=128
4 | Reponse de 127.0.0.1 : octets=32 temps<1ms TTL=128
5 | Reponse de 127.0.0.1 : octets=32 temps<1ms TTL=128
6 |
7 | Statistiques Ping pour 127.0.0.1:
8 | Paquets : envoyes = 4, recus = 4, perdus = 0 (perte 0%),
9 | Duree approximative des boucles en millisecondes :
10 | Minimum = 0ms, Maximum = 0ms, Moyenne = 0ms
11 |
--------------------------------------------------------------------------------
/test/fixture/window/fr/sample2.txt:
--------------------------------------------------------------------------------
1 | Envoi d’une requete 'Ping' 8.8.8.8 avec 32 octets de donnees :
2 | Reponse de 8.8.8.8 : octets=32 temps=6 ms TTL=58
3 | Reponse de 8.8.8.8 : octets=32 temps=6 ms TTL=58
4 | Reponse de 8.8.8.8 : octets=32 temps=6 ms TTL=58
5 | Reponse de 8.8.8.8 : octets=32 temps=6 ms TTL=58
6 |
7 | Statistiques Ping pour 8.8.8.8:
8 | Paquets : envoyes = 4, recus = 4, perdus = 0 (perte 0%),
9 | Duree approximative des boucles en millisecondes :
10 | Minimum = 6ms, Maximum = 6ms, Moyenne = 6ms
11 |
--------------------------------------------------------------------------------
/test/fixture/window/ja/sample1.txt:
--------------------------------------------------------------------------------
1 | google.com [216.58.197.142]に ping を送信しています 32 バイトのデータ:
2 | 216.58.197.142 からの応答: バイト数 =32 時間 =7ms TTL=55
3 | 216.58.197.142 からの応答: バイト数 =32 時間 =5ms TTL=55
4 | 216.58.197.142 からの応答: バイト数 =32 時間 =4ms TTL=55
5 | 216.58.197.142 からの応答: バイト数 =32 時間 =4ms TTL=55
6 |
7 | 216.58.197.142 の ping 統計:
8 | パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、
9 | ラウンド トリップの概算時間 (ミリ秒):
10 | 最小 = 4ms、最大 = 7ms、平均 = 5ms
11 |
--------------------------------------------------------------------------------
/test/fixture/window/ja/sample2.txt:
--------------------------------------------------------------------------------
1 | 8.8.8.8 に ping を送信しています 32 バイトのデータ:
2 | 8.8.8.8 からの応答: バイト数 =32 時間 =4ms TTL=58
3 | 8.8.8.8 からの応答: バイト数 =32 時間 =4ms TTL=58
4 | 8.8.8.8 からの応答: バイト数 =32 時間 =5ms TTL=58
5 | 8.8.8.8 からの応答: バイト数 =32 時間 =6ms TTL=58
6 |
7 | 8.8.8.8 の ping 統計:
8 | パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、
9 | ラウンド トリップの概算時間 (ミリ秒):
10 | 最小 = 4ms、最大 = 6ms、平均 = 4ms
11 |
--------------------------------------------------------------------------------
/test/fixture/window/ru/sample1.txt:
--------------------------------------------------------------------------------
1 | Обмен пакетами с 8.8.8.8 по с 32 байтами данных:
2 | Ответ от 8.8.8.8: число байт=32 время=37мс TTL=55
3 | Ответ от 8.8.8.8: число байт=32 время=33мс TTL=55
4 | Ответ от 8.8.8.8: число байт=32 время=38мс TTL=55
5 | Ответ от 8.8.8.8: число байт=32 время=34мс TTL=55
6 |
7 | Статистика Ping для 8.8.8.8:
8 | Пакетов: отправлено = 4, получено = 4, потеряно = 0
9 | (0% потерь)
10 | Приблизительное время приема-передачи в мс:
11 | Минимальное = 33мсек, Максимальное = 38 мсек, Среднее = 35 мсек
--------------------------------------------------------------------------------
/test/fixture/window/zh/sample1.txt:
--------------------------------------------------------------------------------
1 | Ping google.com [216.58.203.14] (使用 32 位元組的資料):
2 | 回覆自 216.58.203.14: 位元組=32 時間=2ms TTL=54
3 | 回覆自 216.58.203.14: 位元組=32 時間=2ms TTL=54
4 | 回覆自 216.58.203.14: 位元組=32 時間=3ms TTL=54
5 | 回覆自 216.58.203.14: 位元組=32 時間=3ms TTL=54
6 |
7 | 216.58.203.14 的 Ping 統計資料:
8 | 封包: 已傳送 = 4,已收到 = 4, 已遺失 = 0 (0% 遺失),
9 | 大約的來回時間 (毫秒):
10 | 最小值 = 2ms,最大值 = 3ms,平均 = 2ms
11 |
--------------------------------------------------------------------------------
/test/fixture/window/zh/sample2.txt:
--------------------------------------------------------------------------------
1 |
2 | Ping google.com [216.58.203.14] (使用 32 位元組的資料):
3 | 回覆自 216.58.203.14: 位元組=32 時間=2ms TTL=54
4 | 回覆自 216.58.203.14: 位元組=32 時間=2ms TTL=54
5 | 回覆自 216.58.203.14: 位元組=32 時間=3ms TTL=54
6 | 回覆自 216.58.203.14: 位元組=32 時間=3ms TTL=54
7 |
8 | 216.58.203.14 的 Ping 統計資料:
9 | 封包: 已傳送 = 4,已收到 = 4, 已遺失 = 0 (0% 遺失),
10 | 大約的來回時間 (毫秒):
11 | 最小值 = 2ms,最大值 = 3ms,平均 = 2ms
12 |
--------------------------------------------------------------------------------
/test/fixture/window/zh/sample3.txt:
--------------------------------------------------------------------------------
1 |
2 | Ping 127.0.0.1 (使用 32 位元組的資料):
3 | 回覆自 127.0.0.1: 位元組=32 時間<1ms TTL=128
4 | 回覆自 127.0.0.1: 位元組=32 時間<1ms TTL=128
5 | 回覆自 127.0.0.1: 位元組=32 時間<1ms TTL=128
6 | 回覆自 127.0.0.1: 位元組=32 時間<1ms TTL=128
7 |
8 | 127.0.0.1 的 Ping 統計資料:
9 | 封包: 已傳送 = 4,已收到 = 4, 已遺失 = 0 (0% 遺失),
10 | 大約的來回時間 (毫秒):
11 | 最小值 = 0ms,最大值 = 0ms,平均 = 0ms
12 |
--------------------------------------------------------------------------------
/test/load-fixture-path.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var path = require('path');
4 | var glob = require('glob');
5 |
6 | /**
7 | * Check out linux platform
8 | */
9 | function isLinux(p) {
10 | var platforms = ['aix', 'android', 'linux'];
11 |
12 | return platforms.indexOf(p) >= 0;
13 | }
14 |
15 | /**
16 | * Check out macos platform
17 | */
18 | function isMacOS(p) {
19 | var platforms = ['darwin', 'freebsd'];
20 |
21 | return platforms.indexOf(p) >= 0;
22 | }
23 |
24 | /**
25 | * Check out window platform
26 | */
27 | function isWindow(p) {
28 | return p && p.match(/^win/) !== null;
29 | }
30 |
31 | module.exports = function (platform) {
32 | var dirname = null;
33 |
34 | if (isLinux(platform)) {
35 | dirname = 'linux';
36 | } else if (isMacOS(platform)) {
37 | dirname = 'macos';
38 | } else if (isWindow(platform)) {
39 | dirname = 'window';
40 | }
41 |
42 | var currentDirectory = path.dirname(__filename);
43 |
44 | var targetDirectory = [currentDirectory, 'fixture'];
45 | if (dirname) {
46 | targetDirectory.push(dirname);
47 | }
48 | targetDirectory = targetDirectory.concat(['**', '*.txt']);
49 | targetDirectory = path.posix.join.apply(path.posix, targetDirectory);
50 |
51 | return glob.sync(targetDirectory);
52 | };
53 |
--------------------------------------------------------------------------------
/test/test-ping.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var expect = require('chai').expect;
4 | var sinon = require('sinon');
5 | var os = require('os');
6 | var cp = require('child_process');
7 | var fs = require('fs');
8 | var path = require('path');
9 | var util = require('util');
10 | var events = require('events');
11 |
12 | var loadFixturePath = require('./load-fixture-path');
13 | var ping = require('..');
14 |
15 | // Some constants
16 | var ANSWER = require('./fixture/answer.json');
17 |
18 | var PLATFORMS = [
19 | 'window',
20 | 'darwin',
21 | 'freebsd',
22 | // 'aix',
23 | 'android',
24 | 'linux',
25 | ];
26 | var PLATFORM_TO_EXTRA_ARGUMENTS = {
27 | window: ['-n', '2'],
28 | darwin: ['-c', '2'],
29 | freebsd: ['-c', '2'],
30 | android: ['-c', '2'],
31 | linux: ['-c', '2'],
32 | };
33 |
34 | var pathToAnswerKey = function (p) {
35 | var basename = path.posix.basename(p, '.txt');
36 | var dirname = path.posix.basename(path.posix.dirname(p));
37 | var osname = path.posix.basename(path.posix.dirname(path.posix.dirname(p)));
38 |
39 | return [osname, dirname, basename].join('_');
40 | };
41 |
42 | var mockOutSpawn = function (fp) {
43 | return function () {
44 | var fakeProcessEventEmitter = new events.EventEmitter();
45 | var stdoutEmitter = new events.EventEmitter();
46 | var stderrEmitter = new events.EventEmitter();
47 |
48 | fakeProcessEventEmitter.stdout = stdoutEmitter;
49 | fakeProcessEventEmitter.stderr = stderrEmitter;
50 |
51 | var s = fs.createReadStream(fp);
52 | s.on('data', function (fileContentsBuffer) {
53 | var fileContents = String(fileContentsBuffer);
54 | var lines = fileContents.split('\n');
55 | var normalizedLines = lines.map((line) => `${line}\n`);
56 | normalizedLines.forEach((line) => {
57 | var isSystemPingErrorMessage = line.startsWith('ping: ');
58 | // eslint-disable-next-line max-len
59 | // eslint-disable-next-line node/no-unsupported-features/node-builtins, no-buffer-constructor, node/no-deprecated-api
60 | var str2Buffer = Buffer.from ? (string) => Buffer.from(string, 'utf8') : (string) => new Buffer(string);
61 | var lineBuffer = str2Buffer(line);
62 |
63 | if (isSystemPingErrorMessage) {
64 | stderrEmitter.emit('data', lineBuffer);
65 | } else {
66 | stdoutEmitter.emit('data', lineBuffer);
67 | }
68 | });
69 | });
70 | s.on('close', function () {
71 | fakeProcessEventEmitter.emit('close', 0);
72 | });
73 |
74 | return fakeProcessEventEmitter;
75 | };
76 | };
77 |
78 | var createTestCase = function (platform, pingExecution) {
79 | var stubs = [];
80 |
81 | describe(util.format('On %s platform', platform), function () {
82 | var fixturePaths = loadFixturePath(platform);
83 |
84 | before(function () {
85 | stubs.push(
86 | sinon.stub(os, 'platform').callsFake(function () {
87 | return platform;
88 | })
89 | );
90 | });
91 |
92 | after(function () {
93 | stubs.forEach(function (stub) {
94 | stub.restore();
95 | });
96 | });
97 |
98 | describe('runs with default config', function () {
99 | fixturePaths.forEach(function (fp) {
100 | it(util.format('Using |%s|', pathToAnswerKey(fp)), function () {
101 | return pingExecution(fp);
102 | });
103 | });
104 | });
105 |
106 | describe('runs with custom config', function () {
107 | fixturePaths.forEach(function (fp) {
108 | it(util.format('Using |%s|', pathToAnswerKey(fp)), function () {
109 | return pingExecution(fp, {
110 | timeout: 10,
111 | extra: PLATFORM_TO_EXTRA_ARGUMENTS[platform],
112 | });
113 | });
114 | });
115 | });
116 |
117 | describe('runs with custom config with default gone', function () {
118 | fixturePaths.forEach(function (fp) {
119 | it(util.format('Using |%s|', pathToAnswerKey(fp)), function () {
120 | return pingExecution(fp, {
121 | timeout: false,
122 | extra: PLATFORM_TO_EXTRA_ARGUMENTS[platform],
123 | });
124 | });
125 | });
126 | });
127 | });
128 | };
129 |
130 | describe('ping timeout and deadline options', function () {
131 | describe('on linux platform', function () {
132 | beforeEach(function () {
133 | this.platformStub = sinon.stub(os, 'platform').callsFake(function () {
134 | return 'linux';
135 | });
136 | const fixturePath = path.join(__dirname, 'fixture', 'linux', 'en', 'sample1.txt');
137 | this.spawnStub = sinon.stub(cp, 'spawn').callsFake(mockOutSpawn(fixturePath));
138 | });
139 |
140 | afterEach(function () {
141 | this.platformStub.restore();
142 | this.spawnStub.restore();
143 | });
144 |
145 | it('are forwarded to the ping binary', function () {
146 | return ping.promise
147 | .probe('whatever', {
148 | timeout: 47,
149 | deadline: 83,
150 | })
151 | .then(
152 | function () {
153 | const spawnArgs = this.spawnStub.getCalls()[0].args;
154 | const pingArgs = spawnArgs[1];
155 | expect(pingArgs[pingArgs.indexOf('-W') + 1]).to.equal('47');
156 | expect(pingArgs[pingArgs.indexOf('-w') + 1]).to.equal('83');
157 | }.bind(this)
158 | );
159 | });
160 | });
161 |
162 | describe('on windows platform', function () {
163 | beforeEach(function () {
164 | this.platformStub = sinon.stub(os, 'platform').callsFake(function () {
165 | return 'window';
166 | });
167 | const fixturePath = path.join(__dirname, 'fixture', 'window', 'en', 'sample1.txt');
168 | this.spawnStub = sinon.stub(cp, 'spawn').callsFake(mockOutSpawn(fixturePath));
169 | });
170 |
171 | afterEach(function () {
172 | this.platformStub.restore();
173 | this.spawnStub.restore();
174 | });
175 |
176 | it('results in an error as deadline is not supported', function () {
177 | return ping.promise
178 | .probe('whatever', {
179 | timeout: 47,
180 | deadline: 83,
181 | })
182 | .then(function () {
183 | throw new Error('deadline should result in an error');
184 | })
185 | .catch(function () {});
186 | });
187 | });
188 |
189 | describe('on mac platform', function () {
190 | beforeEach(function () {
191 | this.platformStub = sinon.stub(os, 'platform').callsFake(function () {
192 | return 'freebsd';
193 | });
194 | const fixturePath = path.join(__dirname, 'fixture', 'macos', 'en', 'sample1.txt');
195 | this.spawnStub = sinon.stub(cp, 'spawn').callsFake(mockOutSpawn(fixturePath));
196 | });
197 |
198 | afterEach(function () {
199 | this.platformStub.restore();
200 | this.spawnStub.restore();
201 | });
202 |
203 | it('are forwarded to the ping binary', function () {
204 | return ping.promise
205 | .probe('whatever', {
206 | timeout: 47,
207 | deadline: 83,
208 | })
209 | .then(
210 | function () {
211 | const spawnArgs = this.spawnStub.getCalls()[0].args;
212 | const pingArgs = spawnArgs[1];
213 | expect(pingArgs[pingArgs.indexOf('-W') + 1]).to.equal('47000');
214 | expect(pingArgs[pingArgs.indexOf('-t') + 1]).to.equal('83');
215 | }.bind(this)
216 | );
217 | });
218 | });
219 | });
220 |
221 | describe('Ping in callback mode', function () {
222 | var pingExecution = function (fp, args) {
223 | return new Promise(function (resolve, reject) {
224 | var stub = sinon.stub(cp, 'spawn').callsFake(mockOutSpawn(fp));
225 |
226 | var cb = function (isAlive, err) {
227 | if (err) {
228 | reject(err);
229 | } else {
230 | resolve(isAlive);
231 | }
232 | };
233 |
234 | var _args = args;
235 | if (fp.includes('v6')) {
236 | _args = _args || {};
237 | _args.v6 = true;
238 | }
239 |
240 | ping.sys.probe('whatever', cb, _args);
241 |
242 | stub.restore();
243 | }).then(function (data) {
244 | var answerKey = pathToAnswerKey(fp);
245 | var actualIsAlive = data;
246 | var expectIsAlive = ANSWER[answerKey].alive;
247 | expect(actualIsAlive).to.equal(expectIsAlive);
248 | });
249 | };
250 |
251 | PLATFORMS.forEach(function (platform) {
252 | createTestCase(platform, pingExecution);
253 | });
254 | });
255 |
256 | describe('Ping in promise mode', function () {
257 | var pingExecution = function (fp, args) {
258 | var stub = sinon.stub(cp, 'spawn').callsFake(mockOutSpawn(fp));
259 |
260 | var ret = null;
261 | var _args = args;
262 | if (fp.includes('v6')) {
263 | _args = _args || {};
264 | _args.v6 = true;
265 | }
266 | ret = ping.promise.probe('whatever', _args);
267 |
268 | stub.restore();
269 |
270 | return ret.then(function (data) {
271 | var answerKey = pathToAnswerKey(fp);
272 | var actualData = data;
273 | var expectData = ANSWER[answerKey];
274 | var trimTraillingNewlineActualOutput = actualData.output.trim();
275 | var trimTraillingNewlineExpectOutput = expectData.output.trim();
276 | actualData.output = trimTraillingNewlineActualOutput;
277 | expectData.output = trimTraillingNewlineExpectOutput;
278 | expect(actualData).to.deep.equal(expectData);
279 | });
280 | };
281 |
282 | PLATFORMS.forEach(function (platform) {
283 | createTestCase(platform, pingExecution);
284 | });
285 | });
286 |
287 | describe('Ping ipv6 on MAC OS', function () {
288 | var platform = 'darwin';
289 | var stubs = [];
290 |
291 | before(function () {
292 | stubs.push(
293 | sinon.stub(os, 'platform').callsFake(function () {
294 | return platform;
295 | })
296 | );
297 | });
298 |
299 | after(function () {
300 | stubs.forEach(function (stub) {
301 | stub.restore();
302 | });
303 | });
304 |
305 | describe('With timeout setting', function () {
306 | var fixturePaths = loadFixturePath(platform);
307 |
308 | fixturePaths.forEach(function (fp) {
309 | it('Should raise an error', function (done) {
310 | var stub = sinon.stub(cp, 'spawn').callsFake(mockOutSpawn(fp));
311 |
312 | var ret = ping.promise.probe('whatever', {
313 | v6: true,
314 | timeout: 10,
315 | });
316 |
317 | stub.restore();
318 |
319 | ret.then(function () {
320 | done(new Error('It should not be success'));
321 | }).catch(function (err) {
322 | expect(err.message).to.be.a('string');
323 | expect(err.message).to.include('no timeout option');
324 | done();
325 | });
326 | });
327 | });
328 | });
329 | });
330 |
331 | describe('Ping in promise mode with unknown exception', function () {
332 | var pingExecution = function (fp, args) {
333 | var unknownException = new Error('Unknown error!');
334 | var stub = sinon.stub(cp, 'spawn').throws(unknownException);
335 |
336 | var ret = null;
337 | var _args = args;
338 | if (fp.includes('v6')) {
339 | _args = _args || {};
340 | _args.v6 = true;
341 | }
342 | ret = ping.promise.probe('whatever', _args);
343 |
344 | stub.restore();
345 |
346 | return ret.catch(function (err) {
347 | expect(err.message).to.be.a('string');
348 | expect(err.message).to.include('Unknown error!');
349 | });
350 | };
351 |
352 | PLATFORMS.forEach(function (platform) {
353 | createTestCase(platform, pingExecution);
354 | });
355 | });
356 |
--------------------------------------------------------------------------------