├── .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 ![Workflow Status](https://github.com/danielzzz/node-ping/actions/workflows/build-test-coverage.yml/badge.svg) 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 | --------------------------------------------------------------------------------