[
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"monthly\"\n\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Build cnping\n\non:\n  push:\n  pull_request:\n  workflow_dispatch:\n\njobs:\n  Build-for-Linux:\n    runs-on: ubuntu-latest\n      \n    steps:\n    - uses: actions/checkout@v6\n      with:\n        submodules: recursive\n    - name: Install dependencies\n      run: |\n        sudo apt-get update\n        sudo apt-get install -y \\\n           debhelper-compat \\\n           libglvnd-dev \\\n           libx11-dev \\\n           libxext-dev \\\n           libxinerama-dev \\\n           mesa-common-dev \\\n           make \\\n           build-essential \\\n           binutils-mingw-w64-i686 \\\n           gcc-mingw-w64-i686 \\\n           g++-mingw-w64-i686 \\\n           devscripts \\\n           appstream \\\n           imagemagick \\\n           desktop-file-utils\n\n    - name: Build\n      run: make cnping cnping.exe\n        \n    - uses: actions/upload-artifact@v7\n      with:\n        name: cnping-exe\n        path: \"*.exe\"\n\n    - name: Build deb\n      run: debuild --no-sign\n      \n    - uses: actions/upload-artifact@v7\n      with:\n        name: cnping-debian\n        path: |\n          /home/runner/work/cnping/*.deb\n          /home/runner/work/cnping/*.ddeb\n          \n    - name: Validate AppStream data\n      run: appstreamcli validate freedesktop/com.github.cntools.cnping.metainfo.xml\n    - name: Validate desktop file\n      run: desktop-file-validate freedesktop/com.github.cntools.cnping.desktop\n      \n#  Build-RPM-for-Fedora:\n#    runs-on: ubuntu-latest\n#    container: dreua/ ...\n#    steps:\n#    - name: RPM Build\n#      run: /cnping/cnping-build\n#    - uses: actions/upload-artifact@v7\n#      with:\n#        name: cnping-fedora-rpm\n#        path: /github/home/rpmbuild/**/*.rpm\n"
  },
  {
    "path": ".gitignore",
    "content": "*.o\n*.exe\ncnping\ncnping-mousey\nsearchnet\ntags\n\ndebian/.debhelper\ndebian/cnping\ndebian/cnping.substvars\ndebian/debhelper-build-stamp\ndebian/files\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"rawdraw\"]\n\tpath = rawdraw\n\turl = https://github.com/cntools/rawdraw\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: c\ndist: bionic\n\nbefore_install:\n- sudo apt-get -qq update\n- sudo apt-get install -y make libxinerama-dev libxext-dev libx11-dev build-essential\n  binutils-mingw-w64-i686 gcc-mingw-w64-i686 g++-mingw-w64-i686 mesa-common-dev libglvnd-dev\nscript: make cnping cnping.exe\n  \ndeploy:\n  provider: releases\n  api_key:\n    secure: \"iGexfXEEUlID8jiIFaly4RcWBS1iFiT2jTtwLEExz0tBMxZuvpvS+MfZMtXt3YTI1NsbY/B/1tfO2CueEfIWW/d8mmCxf1E/VerfxA1j0NgRc3br6L1nFxbkwEiHtsHO5sYf4QGlqgzipfW2u/cp4nO8pme4jGStMTSZxyTSJPAuWT+4qiyDeay4QGLkigplW9570xKVgejX0hBm7zuw7R8QdnRvIftyvvbQiRqnLoYPPDc1PSOxLfdfNTAoUikbMuOkiN1XI3s3mytTYKCiUa3Zxj1BS35AEPCxaQoOr0iyY+jBFZrwdvPOTAD8VsAGRzjvQ0NldnuIZlXJnFAvtwjxRIIS2rPaLqC79lphaw2j0564tDY0p+j1MhVBt1wjAkRg/Dh2R1SzcO3baxJH6MHKCGS1lUxkUgW0kBoKaIw/DzfnXHx5EsJPbyLeksyLf8XzYCTPMaVJEQK30b0TM5OOEcwCrtAjwX9IiIXAgZiGyw7E4CuKWU+RfZRee8IvhF0qs5DIn0yiCmvYIMYZvX9rL6mm1Wn1Hb7+o4bxHzMmuFmo9HJfgYOzoIhBmr3Q1DIbH/UHcqeFWrP/Dz47easv3GRSbnXcbyh8G0d7mFheO+9JdAnoGBzr1Ig5Eeq0Q1ppjP7jCQuPJQ9EP3uJHStQlIVJse95PZD+TyP8LW4=\"\n  file: \n    - cnping.exe\n  skip_cleanup: true\n  on:\n    tags: true\n    repo: cntools/cnping\n    branch: master\n  draft: true\n"
  },
  {
    "path": "LICENSE",
    "content": "//Rawdraw and CNPing may be licensed feely under the MIT-x11\n//or NewBSD Licenses.  You choose!\n\n"
  },
  {
    "path": "LICENSE.BSD-3-Clause",
    "content": "BSD 3-Clause License\n\nCopyright (c) 2018 Charles Lohr\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    (1) Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer. \n\n    (2) Redistributions in binary form must reproduce the above copyright\n    notice, this list of conditions and the following disclaimer in\n    the documentation and/or other materials provided with the\n    distribution.  \n    \n    (3)The name of the author may not be used to\n    endorse or promote products derived from this software without\n    specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\nINDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\nSTRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE. \n"
  },
  {
    "path": "LICENSE.MIT",
    "content": "MIT License\n\nCopyright (c) 2018 Charles Lohr\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "CFLAGS ?= -s -Os -I/opt/X11/include -Wall\nLDFLAGS ?= -s -L/opt/X11/lib/\nCC? = gcc\n\nICONSPATH = freedesktop/icons/hicolor/\nAPPNAME = com.github.cntools.cnping\n\nall : cnping\n\n#CFLAGS := $(CFLAGS) -DCNFGOGL\n#LDFLAGS := $(LDFLAGS) -lGL\n\nclean :\n\trm -rf *.o *~ cnping cnping.exe cnping_mac searchnet\n\trm -rf rawdraw/*.o\n\n\n# Windows\n\n#MINGW32 := /usr/bin/i686-w64-mingw32-\nMINGW32 ?= i686-w64-mingw32-\n\n# If you don't need admin privileges\nADMINFLAGS := $(ADMINFLAGS) -DWIN_USE_NO_ADMIN_PING\n\n# Add git version to CFLAGS\nGIT_VERSION := \"$(shell git describe --abbrev=4 --dirty --always --tags)\"\nCFLAGS += -DVERSION=\\\"$(GIT_VERSION)\\\"\n\ncnping-wingdi.exe : cnping.c ping.c httping.c resources.o\n\t$(MINGW32)gcc -g -fno-ident -mwindows -m32 $(CFLAGS) -o $@ $^  -lgdi32 -lws2_32 -s -D_WIN32_WINNT=0x0600 -DWIN32 -liphlpapi -DMINGW_BUILD $(ADMINFLAGS)\n\ncnping.exe : cnping.c ping.c httping.c resolve.c resources.o\n\t$(MINGW32)gcc -g -fno-ident -mwindows -m32 -DCNFGOGL $(CFLAGS) -o $@ $^  -lgdi32 -lws2_32 -s -D_WIN32_WINNT=0x0600 -DWIN32 -liphlpapi -lopengl32 -DMINGW_BUILD $(ADMINFLAGS)\n\nresources.o : resources.rc\n\t$(MINGW32)windres resources.rc -o resources.o $(ADMINFLAGS)\n\n\n# Unix\n\ncnping : cnping.c ping.c httping.c resolve.c\n\t$(CC) $(CFLAGS) -o $@ $^ -lX11 -lm -lpthread -lGL $(LDFLAGS)\n\ncnping_ogl : cnping.c ping.c httping.c resolve.c\n\t$(CC) $(CFLAGS) -o $@ $^ -DCNFGOGL $(CFLAGS) -lX11 -lm -lpthread $(LDFLAGS) -lGL\n\ncnping_mac : cnping.c ping.c httping.c resolve.c\n\t$(CC) -o cnping $^ -x objective-c -framework Cocoa -framework QuartzCore -lm -lpthread -DOSX\n\nsearchnet : ping.c searchnet.c resolve.c\n\t$(CC) $(CFLAGS) -o $@ $^ -lpthread\n\nlinuxinstall : cnping\n\trm -f /usr/local/bin/cnping\n\tcp cnping /usr/local/bin/\n\tcp -r $(ICONSPATH) /usr/local/share/icons\n\tcp freedesktop/${APPNAME}.desktop /usr/local/share/applications\n\tcp freedesktop/${APPNAME}.metainfo.xml /usr/local/share/metainfo\n\tsetcap cap_net_raw+ep /usr/local/bin/cnping\n#\tsudo chmod +t /usr/local/bin/cnping  #One option - set the stuid bit.\n#\tsudo install cnping /usr/local/bin/  #Another option - using install.\n\n# minimal linux install, may be useful for development\nminlinuxinstall : cnping\n\tsudo rm -f /usr/local/bin/cnping\n\tsudo cp cnping /usr/local/bin/\n\tsudo setcap cap_net_raw+ep /usr/local/bin/cnping\n\n\n\n# this target requires imagemagick\nupdateicons : ${ICONSPATH}scalable/apps/${APPNAME}.svg\n\tconvert $^ -resize 16x16 ${ICONSPATH}16x16/apps/${APPNAME}.png\n\tconvert $^ -resize 32x32 ${ICONSPATH}32x32/apps/${APPNAME}.png\n\tconvert $^ -resize 48x48 ${ICONSPATH}48x48/apps/${APPNAME}.png\n\tconvert $^ -resize 256x256 ${ICONSPATH}256x256/apps/${APPNAME}.png\n\tconvert $^ -resize 1024x1024 ${ICONSPATH}1024x1024/apps/${APPNAME}.png\n\n# after creating the ico file use GIMP to compress it:\n# Image-> Mode -> Indexed...\n# Choose \"Generate optimum palette\"\n# Maximum number of colors: 3 (may change if the icon changes)\n# \"Convert\"\n# File -> Export As\n# Check \"Compressed (PNG)\" in every resolution\n# \"Export\"\ncnping.ico: ${ICONSPATH}scalable/apps/${APPNAME}.svg\n\tconvert $^ -density 300 -define icon:auto-resize=256,64,16 -background none $@\n\n"
  },
  {
    "path": "README.md",
    "content": "cnping\n======\n\nMinimal Graphical IPV4 Ping/HTTP Ping Tool.  (also comes with searchnet, like nmap but smaller and simpler).  It uses rawdraw so it is OS independent.\n```\nUsage: cnping [host] [period] [extra size] [y-axis scaling] [window title]\n\n\t [host]                 -- domain or IP address of ICMP ping target, or http://[host] i.e. http://google.com\n\t [period]               -- period in seconds (optional), default 0.02\n\t [extra size]           -- ping packet extra size (above 12), optional, default = 0\n\t [const y-axis scaling] -- use a fixed scaling factor instead of auto scaling (optional)\n\t [window title]         -- the title of the window (optional)\n```\n<IMG SRC=https://i.imgur.com/Yj5coKN.gif>\n\nIf an http host is listed, the default request is ```HEAD /favicon.ico HTTP/1.1``` since this is usually a very fast, easy operation for the server.  If a specific file or uri is requested, that will be requested instead, i.e. http://github.com/cnlohr will request ```HEAD /cnlohr HTTP/1.1```.\n\nIf a regular hostname is requested instead, ICMP (regular ping) will be used.\n\nThis allows cnping to be operated in environments where ICMP is prohibited by local computer or network policies.\n\n## Installation\n\n### Ubuntu\n\n```\nsudo apt install libxinerama-dev libxext-dev libx11-dev build-essential mesa-common-dev libglvnd-dev\ngit clone https://github.com/cntools/cnping.git\ncd cnping/\ngit submodule update --init --recursive\nmake linuxinstall\n```\n\n'linuxinstall' builds the tool, copies it to your /usr/local/bin folder, and sets the cap_net_raw capability allowing it to create raw sockets without being root.\n\n```\nsudo cp cnping /usr/local/bin/\nsudo setcap cap_net_raw+ep /usr/local/bin/cnping\n```\n\nNote that if only http pinging is requested, you do not need cap_net_raw or root access.\n\n### Windows\n\nA Windows-exe can be cross compiled on Linux, just install the necessary dependencies and compile it:\n\n```\nsudo apt install binutils-mingw-w64-i686 gcc-mingw-w64-i686 g++-mingw-w64-i686\nmake cnping.exe\n```\n\n### Other distributions\n\nSee our Wiki page for information on more distributions, e.g. Arch, Void, Gentoo or Fedora: [Binary packages and distributions](https://github.com/cntools/cnping/wiki/Binary-packages-and-distributions)\n"
  },
  {
    "path": "cnping.1",
    "content": ".TH CNPING 1 \"Dec 2020\" \"version 1.0\" \"User Manuals\"\n.SH \"NAME\"\ncnping \\- Minimal Graphical IPv4 Ping/HTTP Ping Tool\n.SH \"SYNOPSIS\"\n.B cnping cnping [host] [period] [extra size] [y-axis scaling] [window title]\n.SH \"DESCRIPTION\"\n.B cnping\nis a minimal graphical real time IPv4 ping tool written in C.\nIt can send pings via ICMP (regular ping) or HTTP which is useful \nin case ICMP is prohibited. Responses are displayed as vertical bars \nin a graphical window. Red bars indicate a response was not (yet) \nreceived, white bars indicate the response was received with a height \nrelative to the round trip time. Additional statistics are displayed \nas an overlay.\n.SH \"OPTIONS\"\nAll options can be passed either positional or as flags.\n.IP -h\ndomain, IP address of ping target for ICMP or http host, i.e. http://google.com\n\n.IP -p\nperiod in seconds (optional), default 0.02 \n\n.IP -s\nping packet extra size (above 12), optional, default = 0 \n\n.IP -y\nuse a fixed scaling factor instead of auto scaling (optional)\n\n.IP -t\nthe title of the window (optional)\n\n.SH \"GUI\"\n.IP q\nquit\n\n.IP m\ntoggle histogram mode\n\n.IP f\ntoggle histogram frame mode\n\n.IP c\nreset histogram data\n\n.SH \"AUTHOR\"\nCharles Lohr <TODO Email>\n.SH COPYRIGHT\nCopyright \\(co 2018-2020 Charles Lohr\n.br\n.SH LICENSE\nRawdraw and CNPing may be licensed feely under the MIT-x11\nor NewBSD Licenses. You choose!\n\n"
  },
  {
    "path": "cnping.c",
    "content": "//Copyright (c) 2011-2019 <>< Charles Lohr - Under the MIT/x11 or NewBSD License you choose.\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <math.h>\n#include <errno.h>\n#include <string.h>\n#if defined( WINDOWS ) || defined( WIN32 )\n#ifdef _MSC_VER\n#define strdup _strdup\n#endif\n#include <windows.h>\n#else\n  #ifdef __FreeBSD__\n    #include <sys/types.h>\n    #include <netinet/in.h>\n  #endif\n#include <sys/socket.h>\n#include <netinet/ip.h>\n#include <netinet/ip_icmp.h>\n#include <arpa/inet.h>\n#include <sys/select.h>\n#include <netdb.h>\n#endif\n\n#ifndef CNFGOGL\n#define CNFGOGL\n#endif\n\n#define CNFG_IMPLEMENTATION\n#include \"rawdraw/os_generic.h\"\n#include \"rawdraw/CNFG.h\"\n#include \"ping.h\"\n#include \"error_handling.h\"\n#include \"httping.h\"\n\n// #### Cross-plattform debugging ####\n// Windows does not print to Console, use DebugView from SysInternals to\n// see the output. (Setup: Computer -> Connect Local; Capture -> Capture Win32)\n// Warning: Debugging on Windows can slow cnping down and lead to wrong measurements!\n//#define DEBUG\n#ifdef DEBUG\n\tchar msgbuf[1024];\n\t#ifdef WIN32\n\t\t#define debug(...) \\\n\t\t\tsnprintf(msgbuf, sizeof(msgbuf), __VA_ARGS__); \\\n\t\t\tOutputDebugString(msgbuf);\n\t#else\n\t\t#define debug(...) printf(__VA_ARGS__);\n\t#endif\n#else\n\t// Let the compiler parse it to catch errors. Compiler will optimize away.\n\t#define debug(...) \\\n\t\t\tdo { if (0) fprintf(stderr, __VA_ARGS__); } while (0);\n#endif\n\nunsigned frames = 0;\nunsigned long iframeno = 0;\nshort screenx, screeny;\nconst char * pinghost;\nfloat GuiYScaleFactor;\nint GuiYscaleFactorIsConstant;\ndouble globmaxtime, globmintime = 1e20;\ndouble globinterval, globlast;\nuint64_t globalrx;\nuint64_t globallost;\n// Ping Data. Will be overwritten with random bytes when !DEBUG\nuint8_t pattern[8] = {0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF};\n\n#define PINGCYCLEWIDTH 8192\n#define TIMEOUT 4\n\ndouble PingSendTimes[PINGCYCLEWIDTH];\ndouble PingRecvTimes[PINGCYCLEWIDTH];\nint current_cycle = 0;\n\nint ExtraPingSize;\nint in_histogram_mode, in_frame_mode = 1;\nvoid HandleGotPacket( int seqno, int timeout );\n\n#if defined( WINDOWS ) || defined( WIN32 )\nWSADATA wsaData;\n#endif\n\n\n#define MAX_HISTO_MARKS (TIMEOUT*10000)\nuint64_t hist_counts[MAX_HISTO_MARKS];\n\nvoid HandleNewPacket( int seqno )\n{\n\tdouble Now = OGGetAbsoluteTime();\n\tPingSendTimes[seqno] = Now;\n\tPingRecvTimes[seqno] = 0;\n\tstatic int timeoutmark;\n\n\twhile( Now - PingSendTimes[timeoutmark] > TIMEOUT )\n\t{\n\t\tif( PingRecvTimes[timeoutmark] < PingSendTimes[timeoutmark] )\n\t\t{\n\t\t\tHandleGotPacket( timeoutmark, 1 );\n\t\t}\n\t\ttimeoutmark++;\n\t\tif( timeoutmark >= PINGCYCLEWIDTH ) timeoutmark = 0;\n\t}\n}\n\nvoid HandleGotPacket( int seqno, int timeout )\n{\n\tdouble Now = OGGetAbsoluteTime();\n\n\tif( timeout )\n\t{\n\t\tif( PingRecvTimes[seqno] < -0.5 ) return;\n\n\t\tgloballost++;\n\t\tPingRecvTimes[seqno] = -1;\n\t\thist_counts[MAX_HISTO_MARKS-1]++;\n\t\treturn;\n\t}\n\n\tif( PingRecvTimes[seqno] >= PingSendTimes[seqno] ) return;\n\tif( PingSendTimes[seqno] < 1 )  return;\n\tif( Now - PingSendTimes[seqno] > TIMEOUT ) return;\n\n\tPingRecvTimes[seqno] = OGGetAbsoluteTime();\n\tdouble Delta = PingRecvTimes[seqno] - PingSendTimes[seqno];\n\tif( Delta > globmaxtime ) { globmaxtime = Delta; }\n\tif( Delta < globmintime ) { globmintime = Delta; }\n\tint slot = Delta * 10000;\n\tif( slot >= MAX_HISTO_MARKS ) slot = MAX_HISTO_MARKS-1;\n\tif( slot < 0 ) slot = 0;\n\thist_counts[slot]++;\n\n\tif( globlast > 0.5 )\n\t{\n\t\tif( Now - globlast > globinterval ) globinterval = Now - globlast;\n\t}\n\tgloblast = Now;\n\tglobalrx++;\n}\n\n\nvoid HTTPingCallbackStart( int seqno )\n{\n\tcurrent_cycle = seqno;\n\tHandleNewPacket( seqno );\n}\n\nvoid HTTPingCallbackGot( int seqno )\n{\n\tHandleGotPacket( seqno, 0 );\n}\n\nvoid display(uint8_t *buf, int bytes)\n{\n\tint reqid = (buf[0] << 24) | (buf[1]<<16) | (buf[2]<<8) | (buf[3]);\n\tdebug(\"Received ping: reqid=%d\\n\", reqid);\n\treqid &= (PINGCYCLEWIDTH-1);\n\tif( memcmp( buf+4, pattern, sizeof(pattern) ) != 0 ) return;\n\tdebug(\"Memcmp OK, checked %ld bytes, first values being %x %x %x %x\\n\",\n\t\t  (long int) sizeof(pattern), pattern[0], pattern[1], pattern[2], pattern[3])\n\tHandleGotPacket( reqid, 0 );\n}\n\nint load_ping_packet( uint8_t * buffer, int bufflen )\n{\n\tbuffer[0] = current_cycle >> 24;\n\tbuffer[1] = current_cycle >> 16;\n\tbuffer[2] = current_cycle >> 8;\n\tbuffer[3] = current_cycle >> 0;\n\n\tmemcpy( buffer+4, pattern, sizeof(pattern) );\n\n\tif( ping_failed_to_send )\n\t{\n\t\tPingSendTimes[(current_cycle+PINGCYCLEWIDTH-1)&(PINGCYCLEWIDTH-1)] = 0; //Unset ping send.\n\t}\n\n\tHandleNewPacket( current_cycle&(PINGCYCLEWIDTH-1) );\n\n\tcurrent_cycle++;\n\n\treturn 12 + ExtraPingSize;\n}\n\nvoid * PingListen( void * r )\n{\n\tlistener();\n\tERRM( \"Fault on listen.\\n\" );\n\texit( -2 );\n}\n\nvoid * PingSend( void * r )\n{\n\tdo_pinger( );\n\tERRM( \"Fault on ping.\\n\" );\n\texit( -1 );\n}\n\n\n\n\nvoid HandleKey( int keycode, int bDown )\n{\n\tswitch( keycode )\n\t{\n\n#if defined( WIN32 ) || defined( WINDOWS )\n\t\tcase 'r':\n\t\t{\n\t\t\tchar   lpFilename[1024];\n\t\t\tchar   lpDirectory[1024];\n\t\t\tGetCurrentDirectory( 1023, lpDirectory );\n\t\t\tGetModuleFileNameA( GetModuleHandle(0), lpFilename, 1023 );\n\n\t\t\tCreateProcessA( lpFilename, GetCommandLine(), 0, 0, 1, 0, 0, lpDirectory, 0, 0 );\n\t\t\texit( 0 );\n\t\t\tbreak;\n\t\t}\n#endif\n\t\tcase 'f':\n\t\t\tif( bDown ) in_frame_mode = !in_frame_mode;\n\t\t\tif( !in_frame_mode ) in_histogram_mode = 1;\n\t\t\tbreak;\n\t\tcase 'm': \n\t\t\tif( bDown ) in_histogram_mode = !in_histogram_mode;\n\t\t\tif( !in_histogram_mode ) in_frame_mode = 1;\n\t\t\tbreak;\n\t\tcase 'c':\n\t\t\tmemset( hist_counts, 0, sizeof( hist_counts ) );\n\t\t\tglobmaxtime = 0;\n\t\t\tglobmintime = 1e20;\n\t\t\tglobinterval = 0;\n\t\t\tgloblast = 0;\n\t\t\tglobalrx = 0;\n\t\t\tgloballost = 0;\n\t\t\tbreak;\n\t\tcase 'q':\n\t\t\texit(0);\n\t\t\tbreak;\n\n\t}\n}\nvoid HandleButton( int x, int y, int button, int bDown ){}\nvoid HandleMotion( int x, int y, int mask ){}\nvoid HandleDestroy() { exit(0); }\n\n\ndouble GetWindMaxPingTime( void )\n{\n\tint i;\n\tdouble maxtime = 0;\n\n\tfor( i = 0; i < screenx; i++ )\n\t{\n\t\tint index = ((current_cycle - i - 1) + PINGCYCLEWIDTH) & (PINGCYCLEWIDTH-1);\n\t\tdouble st = PingSendTimes[index];\n\t\tdouble rt = PingRecvTimes[index];\n\n\t\tdouble dt = 0;\n\n\t\tif( rt > st )\n\t\t{\n\t\t\tdt = rt - st;\n\t\t\tdt *= 1000;\n\t\t\tif( dt > maxtime ) maxtime = dt;\n\t\t}\n\t}\n\n\treturn maxtime;\n}\n\nvoid DrawMainText( const char * stbuf )\n{\n\tint x, y;\n\tCNFGColor( 0x000000ff );\n\tfor( x = -1; x < 2; x++ ) for( y = -1; y < 2; y++ )\n\t{\n\t\tCNFGPenX = 10+x; CNFGPenY = 10+y;\n\t\tCNFGDrawText( stbuf, 2 );\n\t}\n\tCNFGColor( 0xffffffff );\n\tCNFGPenX = 10; CNFGPenY = 10;\n\tCNFGDrawText( stbuf, 2 );\n}\n\nvoid DrawFrameHistogram()\n{\n\tint i;\n//\tdouble Now = OGGetAbsoluteTime();\n\tconst int colwid = 50;\n\tint categories = (screenx-50)/colwid;\n\tint maxpingslot = ( globmaxtime*10000.0 );\n\tint minpingslot = ( globmintime*10000.0 );\n\tint slots = maxpingslot-minpingslot;\n\n\tif( categories <= 2 )\n\t{\n\t\tgoto nodata;\n\t}\n\telse\n\t{\n\t\tint skips = ( (slots)/categories ) + 1;\n\t\tint slotsmax = maxpingslot / skips + 1;\n\t\tint slotsmin = minpingslot / skips;\n\t\tslots = slotsmax - slotsmin;\n\t\tif( slots <= 0 ) goto nodata;\n\n\t\tuint64_t samples[slots+2];\n\t\tint      ssmsMIN[slots+2];\n\t\tint      ssmsMAX[slots+2];\n\t\tint samp = minpingslot - 1;\n\n\t\tif( slots <= 1 ) goto nodata;\n\n\t\tmemset( samples, 0, sizeof( samples ) );\n\t\tif( samp < 0 ) samp = 0;\n\n\t\tuint64_t highestchart = 0;\n\t\tint tslot = 0;\n\t\tfor( i = slotsmin; i <= slotsmax; i++ )\n\t\t{\n\t\t\tint j;\n\t\t\tuint64_t total = 0;\n\t\t\tssmsMIN[tslot] = samp;\n\t\t\tfor( j = 0; j < skips; j++ )\n\t\t\t{\n\t\t\t\ttotal += hist_counts[samp++];\n\t\t\t}\n\n\t\t\tssmsMAX[tslot] = samp;\n\t\t\tif( total > highestchart ) highestchart = total;\n\t\t\tsamples[tslot++] = total;\n\t\t}\n\n\t\tif( highestchart <= 0 )\n\t\t{\n\t\t\tgoto nodata;\n\t\t}\n\n\t\tint rslots = 0;\n\t\tfor( i = 0; i < slots+1; i++ )\n\t\t{\n\t\t\tif( samples[i] ) rslots = i;\n\t\t}\n\t\trslots++;\n\n\t\tfor( i = 0; i < rslots; i++ )\n\t\t{\n\t\t\tCNFGColor( 0x33cc33ff );\n\t\t\tint top = 30;\n\t\t\tuint64_t samps = samples[i];\n\t\t\tint bottom = screeny - 50;\n\t\t\tint height = samps?(samps * (bottom-top) / highestchart + 1):0;\n\t\t\tint startx = (i+1) * (screenx-50) / rslots;\n\t\t\tint endx = (i+2) * (screenx-50) / rslots;\n\n\t\t\tif( !in_frame_mode )\n\t\t\t{\n\t\t\t\tCNFGTackRectangle( startx, bottom-height, endx, bottom + 1 );\n\t\t\t\tCNFGColor( 0x000000ff );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tCNFGColor( 0x8080ffff );\n\t\t\t}\n\t\t\tCNFGTackSegment( startx, bottom+1, endx, bottom+1 );\n\n\t\t\tCNFGTackSegment( startx, bottom-height, startx, bottom+1 );\n\t\t\tCNFGTackSegment( endx,   bottom-height, endx,   bottom+1 );\n\n\t\t\tCNFGTackSegment( startx, bottom-height, endx, bottom-height );\n\t\t\tchar stbuf[1024];\n\t\t\tint log10 = 1;\n\t\t\tint64_t ll = samps;\n\t\t\twhile( ll >= 10 )\n\t\t\t{\n\t\t\t\tll /= 10;\n\t\t\t\tlog10++;\n\t\t\t}\n\n\t\t\tif( !in_frame_mode )\n\t\t\t{\n\t\t\t\tCNFGColor( 0xffffffff );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tCNFGColor( 0x8080ffff );\n\t\t\t}\n\n\n\t\t\tCNFGPenX = startx + (8-log10) * 4; CNFGPenY = bottom+3;\n#ifdef WIN32\n\t\t\tsprintf( stbuf, \"%I64u\", samps );\n#else\n\t\t\tsprintf( stbuf, \"%lu\", samps );\n#endif\n\t\t\tCNFGDrawText( stbuf, 2 );\n\n\t\t\tCNFGPenX = startx; CNFGPenY = bottom+14;\n\t\t\tsprintf( stbuf, \"%5.1fms\\n%5.1fms\", ssmsMIN[i]/10.0, ssmsMAX[i]/10.0 );\n\t\t\tCNFGDrawText( stbuf, 2 );\n\t\t}\n\t\tchar stt[1024];\n#ifdef WIN32\n\t\tsnprintf( stt, 1024, \"Host: %s\\nHistorical max  %9.2fms\\nBiggest interval%9.2fms\\nHistorical packet loss %I64u/%I64u = %6.3f%%\",\n#else\n\t\tsnprintf( stt, 1024, \"Host: %s\\nHistorical max  %9.2fms\\nBiggest interval%9.2fms\\nHistorical packet loss %lu/%lu = %6.3f%%\",\n#endif\n\t\t\tpinghost, globmaxtime*1000.0, globinterval*1000.0, globallost, globalrx, globallost*100.0/(globalrx+globallost) );\n\t\tif( !in_frame_mode )\n\t\t\tDrawMainText( stt );\n\t\treturn;\n\t}\nnodata:\n\tDrawMainText( \"No data.\\n\" );\n\treturn;\n}\n\n\nvoid DrawFrame( void )\n{\n\tint i;\n\n\tdouble now = OGGetAbsoluteTime();\n\n\tdouble totaltime = 0;\n\tint totalcountok = 0;\n\tint totalcountloss = 0;\n\tdouble mintime = 10000;\n\tdouble maxtime = 0;\n\tdouble stddev = 0;\n\tdouble last = -1;\n\tdouble loss = 100.00;\n\tdouble windmaxtime = GetWindMaxPingTime();\n\n\tfor( i = 0; i < screenx; i++ )\n\t{\n\t\tint index = ((current_cycle - i - 1) + PINGCYCLEWIDTH) & (PINGCYCLEWIDTH-1);\n\t\tdouble st = PingSendTimes[index];\n\t\tdouble rt = PingRecvTimes[index];\n\n\t\tdouble dt = 0;\n\n\t\tif( rt > st ) // ping received\n\t\t{\n\t\t\tCNFGColor( 0xffffffff );\n\t\t\tdt = rt - st;\n\t\t\tdt *= 1000;\n\t\t\ttotaltime += dt;\n\t\t\tif( dt < mintime ) mintime = dt;\n\t\t\tif( dt > maxtime ) maxtime = dt;\n\t\t\ttotalcountok++;\n\t\t\tif( last < 0)\n\t\t\t\tlast = dt;\n\t\t}\n\t\telse if (st != 0) // ping sent but not received\n\t\t{\n\t\t\tCNFGColor( 0xff0000ff );\n\t\t\tdt = now - st;\n\t\t\tdt *= 1000;\n\t\t\tif( i > 5 ) totalcountloss++; //Get a freebie on the first 5.\n\t\t}\n\t\telse // no ping sent for this point in time (after startup)\n\t\t{\n\t\t\tCNFGColor( 0x000000ff );\n\t\t\tdt = 99 * 1000; // assume 99s to fill screen black\n\t\t}\n\n\t\tif (!GuiYscaleFactorIsConstant)\n\t\t{\n\t\t\tGuiYScaleFactor =  (screeny - 50) / windmaxtime;\n\t\t}\n\n\t\tint h = dt*GuiYScaleFactor;\n\t\tint top = screeny - h;\n\t\tif( top < 0 ) top = 0;\n\t\tCNFGTackSegment( i, screeny-1, i, top );\n\t}\n\n\tdouble avg = totaltime / totalcountok;\n\tloss = (double) totalcountloss / (totalcountok + totalcountloss) * 100;\n\n\tfor( i = 0; i < screenx; i++ )\n\t{\n\t\tint index = ((current_cycle - i - 1) + PINGCYCLEWIDTH) & (PINGCYCLEWIDTH-1);\n\t\tdouble st = PingSendTimes[index];\n\t\tdouble rt = PingRecvTimes[index];\n\n\t\tdouble dt = 0;\n\t\tif( rt > st )\n\t\t{\n\t\t\tdt = rt - st;\n\t\t\tdt *= 1000;\n\t\t\tstddev += (dt-avg)*(dt-avg);\n\t\t}\n\t}\n\n\tstddev /= totalcountok;\n\n\tstddev = sqrt(stddev);\n\n\tint avg_gui    = avg*GuiYScaleFactor;\n\tint stddev_gui = stddev*GuiYScaleFactor;\n\n\tCNFGColor( 0x00ff00ff );\n\n\n\tint l = avg_gui;\n\tCNFGTackSegment( 0, screeny-l, screenx, screeny - l );\n\tl = (avg_gui) + (stddev_gui);\n\tCNFGTackSegment( 0, screeny-l, screenx, screeny - l );\n\tl = (avg_gui) - (stddev_gui);\n\tCNFGTackSegment( 0, screeny-l, screenx, screeny - l );\n\n\tchar stbuf[2048];\n\tchar * sptr = &stbuf[0];\n\n\tsptr += sprintf( sptr, \n\t\t\"Last:%6.2f ms    Host: %s\\n\"\n\t\t\"Min :%6.2f ms\\n\"\n\t\t\"Max :%6.2f ms    Historical max:   %5.2f ms\\n\"\n\t\t\"Avg :%6.2f ms    Biggest interval: %5.2f ms\\n\"\n#ifdef WIN32\n\t\t\"Std :%6.2f ms    Historical loss:  %I64u/%I64u %5.3f%%\\n\"\n#else\n\t\t\"Std :%6.2f ms    Historical loss:  %lu/%lu %5.3f%%\\n\"\n#endif\n\t\t\"Loss:%6.1f %%\", last, pinghost, mintime, maxtime, globmaxtime*1000, avg, globinterval*1000.0, stddev,\n\t\tgloballost, globalrx+globallost, globallost*100.0f/(globalrx+globallost), loss );\n\n\tDrawMainText( stbuf );\n\tOGUSleep( 1000 );\n}\n\n#ifdef WIN32\n\nconst char * glargv[10];\nint glargc = 0;\n\nint RegString( int write, char * data, DWORD len )\n{\n\tHKEY hKey;\n\tif( RegCreateKeyExA(HKEY_CURRENT_USER, \"Software\\\\cnping\", 0, NULL,\t   \n\t\tREG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS)\n\t{\n\t\tif( write )\n\t\t{\n\t\t\tRegSetValueExA( hKey, \"history\", 0, REG_SZ, (uint8_t*)data, len );\n\t\t\treturn 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tDWORD type;\n\t\t\tif( RegGetValueA( hKey, \"\", \"history\", 0x02, &type, data, &len ) == ERROR_SUCCESS )\n\t\t\t{\t\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn -16;\n\t\t}\n\n\t\tRegCloseKey( hKey );\n\t}\n\telse\n\t{\n\t\treturn -15;\n\t}\n}\n\nINT_PTR CALLBACK TextEntry( HWND   hwndDlg, UINT   uMsg, WPARAM wParam, LPARAM lParam )\n{\n\n\tswitch( uMsg )\n\t{\n\tcase WM_INITDIALOG:\n\t\tSetDlgItemText(hwndDlg, 4, \"0.02\");\n\t\tSetDlgItemText(hwndDlg, 5, \"0\" );\n\n\t\tchar data[1024];\n\t\tif( !RegString( 0, data, sizeof( data ) ) )\n\t\t{\n\t\t\tSetDlgItemText(hwndDlg, 3, data);\n\t\t}\n\n\t\treturn 0;\n\tcase WM_COMMAND:\n\t\tswitch( wParam>>24 )\n\t\t{\n\t\t\tcase 4: case 3: return 0; //keyboard input\n\t\t\tcase 1: case 2: return 0; //focus changed.\n\t\t\tcase 0:\n\t\t\t{\n\t\t\t\tint id = wParam & 0xffffff;\n\t\t\t\tif( id == 8 || id == 2 )\n\t\t\t\t{\n\t\t\t\t\texit( -1 );\n\t\t\t\t}\n\n\t\t\t\tchar Address[128]; GetDlgItemText(hwndDlg, 3, Address, sizeof(Address));\n\t\t\t\tchar Period[128];  GetDlgItemText(hwndDlg, 4, Period, sizeof(Period));\n\t\t\t\tchar Extra[128];   GetDlgItemText(hwndDlg, 5, Extra, sizeof(Extra));\n\t\t\t\tchar Scaling[128]; GetDlgItemText(hwndDlg, 6, Scaling, sizeof(Scaling));\n\t\t\t\n\t\t\t\tif( strlen( Address ) )\n\t\t\t\t{\n\t\t\t\t\tRegString( 1, Address, strlen( Address ) );\n\n\t\t\t\t\tglargc = 2;\n\t\t\t\t\tglargv[1] = strdup( Address );\n\t\t\t\t\tif( strlen( Period ) )\n\t\t\t\t\t{\n\t\t\t\t\t\tglargc = 3;\n\t\t\t\t\t\tglargv[2] = strdup( Period );\n\t\t\t\t\t\tif( strlen( Extra ) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tglargc = 4;\n\t\t\t\t\t\t\tglargv[3] = strdup( Extra );\n\t\t\t\t\t\t\tif( strlen( Scaling ) )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tglargc = 5;\n\t\t\t\t\t\t\t\tglargv[4] = strdup( Scaling );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tEndDialog(hwndDlg, 0);\n\t\t\t\treturn 0; //User pressed enter.\n\t\t\t}\n\t\t}\n/*\t\treturn 0;\n\tcase WM_CTLCOLORBTN:\n\t\t//printf( \"ctr %p %p %p\\n\", uMsg, wParam, lParam );\n\t\t//return 0;\n\tcase 32: case 512: case 132: case 24: case 70:\n\tcase 127: case 783: case 28: case 134: case 6: case 7:\n\tcase 8: case 312: case 15: case 71: case 133: case 307:\n\tcase 20: case 310: case 33:\n\t\treturn 0;\n*/\n\t}\n\treturn 0;\n}\n#endif\nint main( int argc, const char ** argv )\n{\n\tchar title[1024];\n\tint i;\n\tdouble ThisTime;\n\tdouble LastFPSTime = OGGetAbsoluteTime();\n\tdouble LastFrameTime = OGGetAbsoluteTime();\n\tdouble SecToWait;\n\tdouble frameperiodseconds;\n\tconst char * device = NULL;\n\n#ifdef WIN32\n\tShowWindow (GetConsoleWindow(), SW_HIDE);\n#endif\n\n\tsrand( (uintmax_t)(OGGetAbsoluteTime()*100000) );\n\t#ifndef DEBUG\n\tfor( i = 0; i < sizeof( pattern ); i++ )\n\t{\n\t\tpattern[i] = rand();\n\t}\n\t#endif\n\tCNFGBGColor = 0x000080ff;\n#ifdef WIN32\n\tif( argc < 2 )\n\t{\n\t\tDialogBox(0, \"IPDialog\", 0, TextEntry );\n\t\targc = glargc;\n\t\targv = glargv;\n\t}\n#endif\n\n\tpingperiodseconds = 0.02;\n\tExtraPingSize = 0;\n\ttitle[0] = 0;\n\tGuiYScaleFactor = 0;\n\n\t//We need to process all the unmarked parameters.\n\tint argcunmarked = 1;\n\tint displayhelp = 0;\n\n\tfor( i = 1; i < argc; i++ )\n\t{\n\t\tconst char * thisargv = argv[i];\n\t\tif( thisargv[0] == '-' )\n\t\t{\n\t\t\tint np = ++i;\n\t\t\tif( np >= argc )\n\t\t\t{\n\t\t\t\tdisplayhelp = 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst char * nextargv = argv[np];\n\t\t\t//Parameter-based field.\n\t\t\tswitch( thisargv[1] )\n\t\t\t{\n\t\t\t\tcase 'h': pinghost = nextargv; break;\n\t\t\t\tcase 'p': pingperiodseconds = atof( nextargv ); break;\n\t\t\t\tcase 's': ExtraPingSize = atoi( nextargv ); break;\n\t\t\t\tcase 'y': GuiYScaleFactor = atof( nextargv ); break;\n\t\t\t\tcase 't': sprintf(title, \"%s\", nextargv); break;\n\t\t\t\tcase 'm': in_histogram_mode = 1; break;\n\t\t\t\tcase 'I': device = nextargv; break;\n\t\t\t\tdefault: displayhelp = 1; break;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t//Unmarked fields\n\t\t\tswitch( argcunmarked++ )\n\t\t\t{\n\t\t\t\tcase 1: pinghost = thisargv; break;\n\t\t\t\tcase 2: pingperiodseconds = atof( thisargv ); break;\n\t\t\t\tcase 3: ExtraPingSize = atoi( thisargv ); break;\n\t\t\t\tcase 4: GuiYScaleFactor = atof( thisargv ); break;\n\t\t\t\tcase 5: sprintf(title, \"%s\", thisargv ); break;\n\t\t\t\tdefault: displayhelp = 1;\n\t\t\t}\n\t\t}\n\t}\n\n\tif( title[0] == 0 )\n\t{\n\t\tsprintf( title, \"%s - cnping \"VERSION, pinghost );\n\t}\n\n\tif( GuiYScaleFactor > 0 )\n\t{\n\t\tGuiYscaleFactorIsConstant = 1;\n\t}\n\n\tif( !pinghost )\n\t{\n\t\tdisplayhelp = 1;\n\t}\n\n\tif( displayhelp )\n\t{\n\t\tERRM( \"cnping \"VERSION\" Usage: cnping [host] [period] [extra size] [y-axis scaling] [window title]\\n\"\n\t\t\t\"   (-h) [host]                 -- domain, IP address of ping target for ICMP or http host, i.e. http://google.com\\n\"\n\t\t\t\"   (-p) [period]               -- period in seconds (optional), default 0.02 \\n\"\n\t\t\t\"   (-s) [extra size]           -- ping packet extra size (above 12), optional, default = 0 \\n\"\n\t\t\t\"   (-y) [const y-axis scaling] -- use a fixed scaling factor instead of auto scaling (optional)\\n\"\n\t\t\t\"   (-t) [window title]         -- the title of the window (optional)\\n\"\n\t\t\t\"   (-I) [interface]            -- Sets source interface (i.e. eth0)\\n\");\n\t\treturn -1;\n\t}\n\n#if defined( WIN32 ) || defined( WINDOWS )\n\tif(device)\n\t{\n\t\tERRM(\"Error: Device option is not implemented on your platform. PRs welcome.\\n\");\n\t\texit( -1 );\n\t}\n\t\n\tif( WSAStartup(MAKEWORD(2,2), &wsaData) )\n\t{\n\t\tERRM( \"Fault in WSAStartup\\n\" );\n\t\texit( -2 );\n\t}\n\tCNFGSetup( title, 320, 155 );\n#else\n\tCNFGSetupWMClass( title, 320, 155, \"cnping\", \"cnping\" );\n#endif\n \n\n\tif( memcmp( pinghost, \"http://\", 7 ) == 0 )\n\t{\n\t\tStartHTTPing( pinghost+7, pingperiodseconds, device );\n\t}\n\telse\n\t{\n\t\tchar* protoEnd = strstr( pinghost, \"://\" );\n\t\tif ( protoEnd )\n\t\t{\n\t\t\tint protoSize = protoEnd - pinghost;\n\t\t\tchar protoBuffer[protoSize + 1];\n\t\t\tmemcpy( protoBuffer, pinghost, protoSize );\n\t\t\tprotoBuffer[protoSize] = '\\0';\n\t\t\tERRM( \"Protocol \\\"%s\\\" is not supported\\n\", protoBuffer );\n\t\t\texit( -1 );\n\t\t}\n\n\t\tping_setup( pinghost, device );\n\t\tOGCreateThread( PingSend, 0 );\n\t\tOGCreateThread( PingListen, 0 );\n\t}\n\n\n\tframeperiodseconds = fmin(.2, fmax(.03, pingperiodseconds));\n\n\twhile(1)\n\t{\n\t\tiframeno++;\n\t\tCNFGHandleInput();\n\n\t\tCNFGClearFrame();\n\t\tCNFGColor( 0xffffffff );\n\t\tCNFGGetDimensions( &screenx, &screeny );\n\n\t\tif( in_frame_mode )\n\t\t{\n\t\t\tDrawFrame();\n\t\t}\n\n\t\tif( in_histogram_mode )\n\t\t{\n\t\t\tDrawFrameHistogram();\n\t\t}\n\n\t\tCNFGPenX = 100; CNFGPenY = 100;\n\t\tCNFGColor( 0xff0000ff );\n\t\tCNFGDrawText( errbuffer, 3 );\n\n\n\t\tframes++;\n\t\tCNFGSwapBuffers();\n\n\t\tThisTime = OGGetAbsoluteTime();\n\t\tif( ThisTime > LastFPSTime + 1 )\n\t\t{\n\t\t\tframes = 0;\n\t\t\tLastFPSTime+=1;\n\t\t}\n\n\t\tSecToWait = frameperiodseconds - ( ThisTime - LastFrameTime );\n\t\tLastFrameTime += frameperiodseconds;\n\t\t//printf(\"iframeno = %d; SecToWait = %f; pingperiodseconds = %f; frameperiodseconds = %f \\n\", iframeno, SecToWait, pingperiodseconds, frameperiodseconds);\n\t\tif( SecToWait > 0 )\n\t\t\tOGUSleep( (int)( SecToWait * 1000000 ) );\n\t}\n\n\treturn(0);\n}\n\n"
  },
  {
    "path": "debian/changelog",
    "content": "cnping (1.0.0) unstable; urgency=medium\n\n  * Initial Release.\n\n -- Charles Lohr <lohr85@gmail.com>  Sun, 04 Dec 2022 14:05:43 +0100\n"
  },
  {
    "path": "debian/control",
    "content": "Source: cnping\nSection: net\nPriority: optional\nMaintainer: Charles Lohr <lohr85@gmail.com>\nBuild-Depends: debhelper-compat (= 12),\n               libglvnd-dev,\n               libx11-dev,\n               libxext-dev,\n               libxinerama-dev,\n               mesa-common-dev\nStandards-Version: 4.6.1\nHomepage: https://github.com/cntools/cnping/\nVCS-Browser: https://github.com/cntools/cnping/\nVCS-Git: https://github.com/cntools/cnping.git\n\nPackage: cnping\nArchitecture: any\nDepends: libcap2-bin, ${misc:Depends}, ${shlibs:Depends}\nDescription: Minimal Graphical IP Ping Tool\n cnping is a minimal graphical real time IP ping tool written in C.\n It can send pings via ICMP (regular ping) or HTTP which is useful in case ICMP\n is prohibited. Responses are displayed as vertical bars in a graphical window.\n Red bars indicate a response was not (yet) received, white bars indicate the\n response was received with a height relative to the round trip time.\n Additional statistics are displayed as an overlay.\n .\n cnping uses rawdraw so it is OS independent and very light weight.\n"
  },
  {
    "path": "debian/copyright",
    "content": "Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/\nUpstream-Name: cnping\nUpstream-Contact: Charles Lohr <lohr85@gmail.com>\nSource: https://github.com/cntools/cnping/\n\nFiles: *\nCopyright: 2022 Charles Lohr <lohr85@gmail.com>\nLicense: BSD-3-Clause or MIT\n\nFiles: debian/*\nCopyright: 2022 Charles Lohr <lohr85@gmail.com>\nLicense: GPL-3.0+\n\nLicense: GPL-3.0+\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n .\n This package is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n GNU General Public License for more details.\n .\n You should have received a copy of the GNU General Public License\n along with this program. If not, see <https://www.gnu.org/licenses/>.\n .\n On Debian systems, the complete text of the GNU General\n Public License version 3 can be found in \"/usr/share/common-licenses/GPL-3\".\n\nLicense: BSD-3-Clause\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n\n     (1) Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n\n     (2) Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in\n     the documentation and/or other materials provided with the\n     distribution.\n\n     (3)The name of the author may not be used to\n     endorse or promote products derived from this software without\n     specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\n INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n POSSIBILITY OF SUCH DAMAGE.\n\n\nLicense: MIT\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n"
  },
  {
    "path": "debian/install",
    "content": "cnping /usr/bin/\nfreedesktop/com.github.cntools.cnping.desktop /usr/share/applications/\nfreedesktop/com.github.cntools.cnping.metainfo.xml /usr/share/metainfo/\nfreedesktop/icons/hicolor /usr/share/icons\n"
  },
  {
    "path": "debian/postinst",
    "content": "#!/bin/sh\n\nset -e\n\nPROGRAM=$(dpkg-divert --truename /usr/bin/cnping)\n\nif [ \"$1\" = configure ]; then\n    # If we have setcap installed, try setting cap_net_raw+ep,\n    # which allows us to install our binaries without the setuid\n    # bit.\n    if command -v setcap > /dev/null; then\n        if setcap cap_net_raw+ep $PROGRAM; then\n            chmod u-s $PROGRAM\n        else\n            echo \"Setcap failed on $PROGRAM, falling back to setuid\" >&2\n            chmod u+s $PROGRAM\n        fi\n    else\n        echo \"Setcap is not installed, falling back to setuid\" >&2\n        chmod u+s $PROGRAM\n    fi\nfi\n\n#DEBHELPER#\n\nexit 0\n"
  },
  {
    "path": "debian/rules",
    "content": "#!/usr/bin/make -f\n\n%:\n\tdh $@\n"
  },
  {
    "path": "debian/source/format",
    "content": "3.0 (native)\n"
  },
  {
    "path": "error_handling.h",
    "content": "#ifndef _ERROR_HANDLING\n#define _ERROR_HANDLING\n\nextern char errbuffer[1024];\n\n#ifdef WIN32\n\n#ifndef _MSC_VER\n#define ERRM(x...) { sprintf( errbuffer, x ); MessageBox( 0, errbuffer, \"cnping\", 0 ); }\n#define ERRMB(x...) { sprintf( errbuffer, x ); }\n#else\n#define ERRM(...) { sprintf( errbuffer, __VA_ARGS__ ); MessageBox( 0, errbuffer, \"cnping\", 0 ); }\n#define ERRMB(...) { sprintf( errbuffer, __VA_ARGS__ ); }\n#endif\n\n#else\n\n#define ERRM(x...) { fprintf( stderr, x ); }\n#define ERRMB(x...) { sprintf( errbuffer, x);  fprintf( stderr, x ); }\n\n#endif\n\n\n#endif\n"
  },
  {
    "path": "freedesktop/com.github.cntools.cnping.desktop",
    "content": "[Desktop Entry]\nVersion=1.0\nName=cnping\nComment=Minimal Graphical IP Ping/HTTP Ping Tool\nType=Application\nIcon=com.github.cntools.cnping\nCategories=Network;\nKeywords=ping;\nStartupWMClass=cnping\n\n# cnping is meant to be started from command line, let's give users a hint.\nExec=bash -c \"cnping ; bash\"\nTerminal=true\n\n"
  },
  {
    "path": "freedesktop/com.github.cntools.cnping.metainfo.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<component type=\"desktop-application\">\n  <id>com.github.cntools.cnping</id>\n  <name>cnping</name>\n  <summary>Minimal Graphical IPv4 Ping/HTTP Ping Tool</summary>\n  <launchable type=\"desktop-id\">com.github.cntools.cnping.desktop</launchable>\n  <metadata_license>CC0-1.0</metadata_license>\n  <content_rating type=\"oars-1.1\"/>\n  <description>\n    <p>\n        cnping is a minimal graphical real time IPv4 ping tool written in C.\nIt can send pings via ICMP (regular ping) or HTTP which is useful \nin case ICMP is prohibited. Responses are displayed as vertical bars \nin a graphical window. Red bars indicate a response was not (yet) \nreceived, white bars indicate the response was received with a height \nrelative to the round trip time. Additional statistics are displayed \nas an overlay.\n    </p>\n    <p>\n        cnping uses rawdraw so it is OS independent and very light weight.\n    </p>\n  </description>\n  <url type=\"homepage\">https://github.com/cntools/cnping</url>\n  <screenshots>\n    <screenshot type=\"default\">\n      <image>https://i.imgur.com/Yj5coKN.gif</image>\n      <caption/>\n    </screenshot>\n  </screenshots>\n  <releases><!-- add new versions on top -->\n    <release date=\"2019-10-04\" version=\"1.0.0\"/>\n  </releases>\n  <project_license>MIT or BSD-3-Clause</project_license>\n  <url type=\"bugtracker\">https://github.com/cntools/cnping/issues</url>\n</component>\n"
  },
  {
    "path": "httping.c",
    "content": "#include \"httping.h\"\n#include <errno.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"resolve.h\"\n\n#ifndef TCC\n#include <unistd.h>\n#include <sys/types.h>\n#else\n#include \"tccheader.h\"\n#endif\n\n#if defined( WIN32 ) || defined( WINDOWS )\n\t#ifdef TCC\n\t#else\n\t#include <ws2tcpip.h>\n\t#endif\n\t#define SOL_TCP IPPROTO_TCP\n#else\n\t#include <sys/socket.h>\n\t#include <netinet/in.h>\n\t#include <netinet/tcp.h>\n\t#include <netdb.h>\n#endif\n\n#include \"rawdraw/os_generic.h\"\n#include \"error_handling.h\"\n\n#ifndef MSG_NOSIGNAL\n\t#define MSG_NOSIGNAL 0\n#endif\n\n#define HTTPTIMEOUT 3.0\n\n//Callbacks (when started/received)\nvoid HTTPingCallbackStart( int seqno );\nvoid HTTPingCallbackGot( int seqno );\n\n//Don't dynamically allocate resources here, since execution may be stopped arbitrarily.\nvoid DoHTTPing( const char * addy, double minperiod, int * seqnoptr, volatile double * timeouttime, int * socketptr, volatile int * getting_host_by_name, const char * device)\n{\n#if defined(WIN32) || defined(WINDOWS)\n\t(void) device; // option is not available for windows. Suppress unused warning.\n\n\tWSADATA wsaData;\n\tint r =\tWSAStartup(MAKEWORD(2,2), &wsaData);\n\tif( r )\n\t{\n\t\tERRM( \"Fault in WSAStartup\\n\" );\n\t\texit( -2 );\n\t}\n#endif\n\tstruct sockaddr_in6 serveraddr;\n\tsocklen_t serveraddr_len;\n\tint serverresolve;\n\tint httpsock;\n\tint addylen = strlen(addy);\n\tchar hostname[addylen+1];\n\tmemcpy( hostname, addy, addylen + 1 );\n\tchar * eportmarker = strchr( hostname, ':' );\n\tchar * eurl = strchr( hostname, '/' );\n\n\tint portno = 80;\n\n\tif( eportmarker )\n\t{\n\t\tportno = atoi( eportmarker+1 );\n\t\t*eportmarker = 0;\n\t}\n\telse\n\t{\n\t\tif( eurl )\n\t\t\t*eurl = 0;\n\t}\n\n\t/* gethostbyname: get the server's DNS entry */\n\tserveraddr_len = sizeof(serveraddr);\n\t*getting_host_by_name = 1;\n\tserverresolve = resolveName((struct sockaddr*) &serveraddr, &serveraddr_len, hostname, AF_UNSPEC);\n\t*getting_host_by_name = 0;\n\n\tif (serverresolve != 1) {\n\t\tERRMB(\"ERROR, no such host as \\\"%s\\\"\\n\", hostname);\n\t\tgoto fail;\n\t}\n\n\t/* build the server's Internet address */\n\tserveraddr.sin6_port = htons(portno);\n\nreconnect:\n\t*socketptr = httpsock = socket(serveraddr.sin6_family, SOCK_STREAM, 0);\n\tif (httpsock < 0)\n\t{\n\t\tERRMB( \"Error opening socket\\n\" );\n\t\treturn;\n\t}\n\n\tint sockVal = 1;\n\t// using char* for sockVal for windows\n\tif (setsockopt(httpsock, SOL_TCP, TCP_NODELAY, (char*) &sockVal, 4) != 0)\n\t{\n\t\tERRM( \"Error: Failed to set TCP_NODELAY\\n\");\n\t\t// not a critical error, we can continue\n\t}\n\n#if !defined( WIN32 ) && !defined( WINDOWS )\n\tif(device)\n\t{\n\t\tif( setsockopt(httpsock, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) +1) != 0)\n\t\t{\n\t\t\tERRM(\"Error: Failed to set Device option.\\n\");\n\t\t\texit( -1 );\n\t\t}\n\t}\n#endif // not windows\n\n\t/* connect: create a connection with the server */\n\tif (connect(httpsock, (struct sockaddr*)&serveraddr, serveraddr_len) < 0)\n\t{\n\t\tERRMB( \"%s: ERROR connecting: %s (%d)\\n\", hostname, strerror(errno), errno );\n\t\tgoto fail;\n\t}\n\n#ifdef __APPLE__\n\tint opt = 1;\n\tsetsockopt(httpsock, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt));\n#endif\n\n\terrbuffer[0] = 0;\n\n\twhile( 1 )\n\t{\n\t\tchar buf[8192];\n\n\t\tint n = sprintf( buf, \"HEAD %s HTTP/1.1\\r\\nConnection: keep-alive\\r\\nHost: %s\\r\\n\\r\\n\", eurl?eurl:\"/favicon.ico\", hostname );\n\n\t\t(*seqnoptr) ++;\n\t\tHTTPingCallbackStart( *seqnoptr );\n\n\t\tint rs = send( httpsock, buf, n, MSG_NOSIGNAL );\n\t\tdouble starttime = *timeouttime = OGGetAbsoluteTime();\n\t\tint breakout = 0;\n\t\tif( rs != n ) breakout = 1;\n\t\tint endstate = 0;\n\t\twhile( !breakout )\n\t\t{\n#ifdef WIN32\n\t\t\tn = recv( httpsock, buf, sizeof(buf)-1, 0);\n#else\n\t\t\tn = recv( httpsock, buf, sizeof(buf)-1, MSG_PEEK);\n\t\t\tif( n > 0 ) n = read( httpsock, buf, sizeof(buf)-1);\n\t\t\telse if( n == 0 ) break; //FIN received\n#endif\n\n\t\t\t\n\t\t\tif( n < 0 ) return;\n\t\t\t\n\t\t\tint i;\n\t\t\tfor( i = 0; i < n; i++ )\n\t\t\t{\n\t\t\t\tchar c = buf[i];\n\t\t\t\tswitch( endstate )\n\t\t\t\t{\n\t\t\t\tcase 0: if( c == '\\r' ) endstate++; break;\n\t\t\t\tcase 1: if( c == '\\n' ) endstate++; else endstate = 0; break;\n\t\t\t\tcase 2: if( c == '\\r' ) endstate++; else endstate = 0; break;\n\t\t\t\tcase 3: if( c == '\\n' && i == n-1) breakout = 1; else endstate = 0; break;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t*timeouttime = OGGetAbsoluteTime();\n\n\t\tHTTPingCallbackGot( *seqnoptr );\n\n\t\tdouble delay_time = minperiod - (*timeouttime - starttime);\n\t\tif( delay_time > 0 )\n\t\t\tusleep( (int)(delay_time * 1000000) );\n\t\tif( !breakout ) {\n#ifdef WIN32\n\t\t\tclosesocket( httpsock );\n#else\n\t\t\tclose( httpsock );\n#endif\n\t\t\tgoto reconnect;\n\t\t}\n\t}\nfail:\n\treturn;\n}\n\n\nstruct HTTPPingLaunch\n{\n\tconst char * addy;\n\tdouble minperiod;\n\tconst char * device;\n\n\tvolatile double timeout_time;\n\tvolatile int failed;\n\tint seqno;\n\tint socket;\n\tvolatile int getting_host_by_name;\n};\n\nstatic void * DeployPing( void * v )\n{\n\tstruct HTTPPingLaunch *hpl = (struct HTTPPingLaunch*)v;\n\thpl->socket = 0;\n\thpl->getting_host_by_name = 0;\n\tDoHTTPing( hpl->addy, hpl->minperiod, &hpl->seqno, &hpl->timeout_time, &hpl->socket, &hpl->getting_host_by_name, hpl->device );\n\thpl->failed = 1;\n\treturn 0;\n}\n\n\nstatic void * PingRunner( void * v )\n{\n\tstruct HTTPPingLaunch *hpl = (struct HTTPPingLaunch*)v;\n\thpl->seqno = 0;\n\twhile( 1 )\n\t{\n\t\thpl->timeout_time = OGGetAbsoluteTime();\n\t\tog_thread_t thd = OGCreateThread( DeployPing, hpl );\n\t\twhile( 1 )\n\t\t{\n\t\t\tdouble Now = OGGetAbsoluteTime();\n\t\t\tdouble usl = hpl->timeout_time - Now + HTTPTIMEOUT;\n\t\t\tif( usl > 0 ) usleep( (int)(usl*1000000 + 1000));\n\t\t\telse usleep( 10000 );\n\n\t\t\tif( hpl->timeout_time + HTTPTIMEOUT < Now && !hpl->getting_host_by_name ) //Can't terminate in the middle of a gethostbyname operation otherwise bad things can happen.\n\t\t\t{\n\t\t\t\tif( hpl->socket )\n\t\t\t\t{\n#ifdef WIN32\n\t\t\t\t\tclosesocket( hpl->socket );\n#else\n\t\t\t\t\tclose( hpl->socket );\n#endif\n\t\t\t\t}\n\n\t\t\t\tOGCancelThread( thd );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn 0;\n}\n\nint StartHTTPing( const char * addy, double minperiod, const char * device)\n{\n\tstruct HTTPPingLaunch *hpl = malloc( sizeof( struct HTTPPingLaunch ) );\n\thpl->addy = addy;\n\thpl->minperiod = minperiod;\n\thpl->device = device;\n\tOGCreateThread( PingRunner, hpl );\n\treturn 0;\n}\n\n\n\n"
  },
  {
    "path": "httping.h",
    "content": "#ifndef _HTTPING_H\n#define _HTTPING_H\n\n//Callbacks (when started/received)\nvoid HTTPingCallbackStart( int seqno );\nvoid HTTPingCallbackGot( int seqno );\n\n//addy should be google.com/blah or something like that.  Do not include prefixing http://.  Port numbers OK.\nint StartHTTPing( const char * addy, double minperiod, const char * device);\n\n#endif\n\n"
  },
  {
    "path": "ping.c",
    "content": "//Copyright 2017 <>< C. Lohr, under the MIT/x11 License\n//Rewritten from Sean Walton and Macmillan Publishers.\n//Most of it was rewritten but the header was never updated.\n//Now I finished the job.\n\n#include <string.h>\n#include <fcntl.h>\n#include <errno.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <assert.h>\n#include \"ping.h\"\n#include \"error_handling.h\"\n#include \"resolve.h\"\n\n#ifdef TCC\n#include \"tccheader.h\"\n#endif\n\nint ping_failed_to_send;\nfloat pingperiodseconds;\nint precise_ping;\nstruct sockaddr_in6 psaddr;\nsocklen_t psaddr_len;\nint using_regular_ping;\n\n#ifdef WIN_USE_NO_ADMIN_PING\n\n#ifdef TCC\n\t//...\n#else\n#include <inaddr.h>\n#include <ws2tcpip.h>\n#include <ipexport.h>\n#include <icmpapi.h>\n#include <windows.h>\n#endif\n\n#include \"rawdraw/os_generic.h\"\n\n\n\n#define MAX_PING_SIZE 16384\n#define PINGTHREADS 100\n\n#if !defined( MINGW_BUILD ) && !defined( TCC )\n\t#pragma comment(lib, \"Ws2_32.lib\")\n\t#pragma comment(lib, \"iphlpapi.lib\")\n#endif\n\nstatic og_sema_t s_disp;\nstatic og_sema_t s_ping;\n\nvoid ping_setup(const char * strhost, const char * device)\n{\n\t// resolve host\n\tpsaddr_len = sizeof(psaddr);\n\tif( strhost )\n\t\tresolveName((struct sockaddr*) &psaddr, &psaddr_len, strhost, AF_INET); // only resolve ipv4 on windows\n\telse\n\t\tpsaddr.sin6_family = AF_INET;\n\n\ts_disp = OGCreateSema();\n\ts_ping = OGCreateSema();\n\t//This function is executed first.\n}\n\nvoid listener()\n{\n\tstatic uint8_t listth;\n\tif( listth ) return;\n\tlistth = 1;\n\n\tOGUnlockSema( s_disp );\n\t//Normally needs to call display(buf + 28, bytes - 28 ); on successful ping.\n\t//This function is executed as a thread after setup.\n\t//Really, we just use the s_disp semaphore to make sure we only launch disp's at correct times.\n\n\twhile(1) { OGSleep( 100000 ); }\n\treturn;\n}\n\nstatic HANDLE pinghandles[PINGTHREADS];\n\nstatic void * pingerthread( void * v )\n{\n\tuint8_t ping_payload[MAX_PING_SIZE];\n\n\tHANDLE ih = *((HANDLE*)v);\n\n\tint timeout_ms = pingperiodseconds * (PINGTHREADS-1) * 1000;\n\twhile(1)\n\t{\n\t\tOGLockSema( s_ping );\n\t\tint rl = load_ping_packet( ping_payload, sizeof( ping_payload ) );\n\t\tstruct repl_t\n\t\t{\n\t\t\tICMP_ECHO_REPLY rply;\n\t\t\tuint8_t err_data[16384];\n\t\t} repl;\n\n\t\tDWORD res = IcmpSendEcho( ih,\n\t\t\t((struct sockaddr_in*) &psaddr)->sin_addr.s_addr, ping_payload, rl,\n\t\t\t0, &repl, sizeof( repl ),\n\t\t\ttimeout_ms );\n\t\tint err;\n\t\tif( !res ) err = GetLastError();\n\t\tOGLockSema( s_disp );\n\n\t\tif( !res )\n\t\t{\n\t\t\tif( err == 11050 )\n\t\t\t{\n\t\t\t\tprintf( \"GENERAL FAILURE\\n\" );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tprintf( \"ERROR: %d\\n\", err );\n\t\t\t}\n\t\t}\n\t\tif( res )\n\t\t{\n\t\t\tdisplay( repl.rply.Data, rl );\n\t\t}\n\t\tOGUnlockSema( s_disp );\n\t}\n\treturn 0;\n}\n\nvoid singleping(struct sockaddr *addr, socklen_t addr_len )\n{\n\tint i;\n\t(void) addr;\n\t(void) addr_len;\n\n\tif( psaddr.sin6_family != AF_INET )\n\t{\n\t\t// ipv6 ICMP Ping is not supported on windows\n\t\tERRM( \"ERROR: ipv6 ICMP Ping is not supported on windows\\n\" );\n\t\texit( -1 );\n\t}\n\n\tstatic int did_init_threads = 0;\n\tif( !did_init_threads )\n\t{\n\t\tdid_init_threads = 1;\n\t\t//Launch pinger threads\n\t\tfor( i = 0; i < PINGTHREADS; i++ )\n\t\t{\n\t\t\tHANDLE ih = pinghandles[i] = IcmpCreateFile();\n\t\t\tif( ih == INVALID_HANDLE_VALUE )\n\t\t\t{\n\t\t\t\tERRM( \"Cannot create ICMP thread %d\\n\", i );\n\t\t\t\texit( 0 );\n\t\t\t}\n\n\t\t\tOGCreateThread( pingerthread, &pinghandles[i] );\n\t\t}\n\t}\n\t//This function is executed as a thread after setup.\n\n\tif( i >= PINGTHREADS-1 ) i = 0;\n\telse i++;\n\tOGUnlockSema( s_ping );\n}\n\nvoid ping(struct sockaddr *addr, socklen_t addr_len )\n{\n\tint i;\n\t(void) addr;\n\t(void) addr_len;\n\n\tusing_regular_ping = 1;\n\n\tif( psaddr.sin6_family != AF_INET )\n\t{\n\t\t// ipv6 ICMP Ping is not supported on windows\n\t\tERRM( \"ERROR: ipv6 ICMP Ping is not supported on windows\\n\" );\n\t\texit( -1 );\n\t}\n\n\t//Launch pinger threads\n\tfor( i = 0; i < PINGTHREADS; i++ )\n\t{\n\t\tHANDLE ih = pinghandles[i] = IcmpCreateFile();\n\t\tif( ih == INVALID_HANDLE_VALUE )\n\t\t{\n\t\t\tERRM( \"Cannot create ICMP thread %d\\n\", i );\n\t\t\texit( 0 );\n\t\t}\n\n\t\tOGCreateThread( pingerthread, &pinghandles[i] );\n\t}\n\t//This function is executed as a thread after setup.\n\n\twhile(1)\n\t{\n\t\tif( i >= PINGTHREADS-1 ) i = 0;\n\t\telse i++;\n\t\tOGUnlockSema( s_ping );\n\t\tOGUSleep( (int)(pingperiodseconds * 1000000) );\n\t}\n}\n\n\n\n#else // ! WIN_USE_NO_ADMIN_PING\n\n//The normal way to do it - only problem is Windows needs admin privs.\n\n\n#ifdef WIN32\n\t#include <winsock2.h>\n\t#define SOL_IP\t\t0\n\t#define F_SETFL\t\t4\n\t#define ICMP_ECHO\t8\n\t#define IP_TTL\t\t2\n\t#define O_NONBLOCK   04000\n#ifndef MINGW_BUILD\n\t#pragma comment(lib, \"Ws2_32.lib\")\n#endif\n\t#include <windows.h>\n\t#include <winsock2.h>\n\t#include <ws2tcpip.h>\n\t#include <stdint.h>\n#else // ! WIN32\n\t#ifdef __FreeBSD__\n\t\t#include <netinet/in.h>\n\t#endif\n\t#include <unistd.h>\n\t#include <sys/socket.h>\n\t#include <resolv.h>\n\t#include <netdb.h>\n\t#if defined(__APPLE__) || defined(__FreeBSD__)\n\t\t#ifndef SOL_IP\n\t\t\t#define SOL_IP IPPROTO_IP\n\t\t#endif\n\t#endif\n\t#include <netinet/ip.h>\n\t#include <netinet/ip_icmp.h>\n\t#include <netinet/icmp6.h>\n#endif\n\n#include \"rawdraw/os_generic.h\"\n\n#if defined WIN32 || defined __APPLE__\nstruct icmphdr\n{\n\tuint8_t\t\ttype;\n\tuint8_t\t\tcode;\n\tuint16_t\tchecksum;\n\tunion\n\t{\n\t\tstruct\n\t\t{\n\t\t\tuint16_t\tid;\n\t\t\tuint16_t\tsequence;\n\t\t} echo;\n\t\tuint32_t\tgateway;\n\t\tstruct\n\t\t{\n\t\t\tuint16_t\t__unused;\n\t\t\tuint16_t\tmtu;\n\t\t} frag;\n\t} un;\n};\n#endif\n\n\n#define PACKETSIZE\t65536\n\nstruct packet\n{\n#ifdef __FreeBSD__\n\tstruct icmp hdr;\n\tunsigned char msg[PACKETSIZE-sizeof(struct icmp)];\n#else\n\tstruct icmphdr hdr;\n\tunsigned char msg[PACKETSIZE-sizeof(struct icmphdr)];\n#endif\n};\n\nint sd;\nint pid=-1;\n\nuint16_t checksum( const unsigned char * start, uint16_t len )\n{\n\tuint16_t i;\n\tconst uint16_t * wptr = (uint16_t*) start;\n\tuint32_t csum = 0;\n\tfor (i=1;i<len;i+=2)\n\t\tcsum += (uint32_t)(*(wptr++));\n\tif( len & 1 )  //See if there's an odd number of bytes?\n\t\tcsum += *(uint8_t*)wptr;\n\tif (csum>>16)\n\t\tcsum = (csum & 0xFFFF)+(csum >> 16);\n\t//csum = (csum>>8) | ((csum&0xff)<<8);\n\treturn ~csum;\n}\n\n// setsockopt TTL to 255\nvoid setTTL(int sock)\n{\n\tconst int val=255;\n\n\tassert(psaddr.sin6_family == AF_INET || psaddr.sin6_family == AF_INET6);\n\n\tif ( setsockopt(sd, (psaddr.sin6_family == AF_INET) ? SOL_IP : SOL_IPV6, IP_TTL, &val, sizeof(val)) != 0)\n\t{\n\t\tERRM(\"Error: Failed to set TTL option.  Are you root?  Or can do sock_raw sockets?\\n\");\n\t\texit( -1 );\n\t}\n}\n\n// 0 = failed, 1 = this is a ICMP Response\nint isICMPResponse(unsigned char* buf, int bytes)\n{\n\tassert(psaddr.sin6_family == AF_INET || psaddr.sin6_family == AF_INET6);\n\n\tif( bytes == -1 ) return 0;\n\n\tif( psaddr.sin6_family == AF_INET ) // ipv4 compare\n\t{\n\t\tif( buf[9] != IPPROTO_ICMP ) return 0;\n\t\tif( buf[20] !=  ICMP_ECHOREPLY ) return 0;\n\n\t}\n\telse if( psaddr.sin6_family == AF_INET6 ) // ipv6 compare\n\t{\n\t\tif( buf[0] != ICMP6_ECHO_REPLY ) return 0;\n\t}\n\n\treturn 1;\n}\n\nint createSocket()\n{\n\tif( psaddr.sin6_family == AF_INET )\n\t{\n\t\treturn socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);\n\t}\n\telse if( psaddr.sin6_family == AF_INET6 )\n\t{\n\t\treturn socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);\n\t}\n\n\t// invalid af_family\n\treturn -1;\n}\n\nvoid listener()\n{\n#ifndef WIN32\n\tint sd = createSocket();\n\n\tsetTTL(sd);\n#endif\n\n\tstruct sockaddr_in6 addr;\n\tunsigned char buf[66000];\n#ifdef WIN32\n\tSetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);\n#endif\n\tfor (;;)\n\t{\n\t\tsocklen_t addrlenval=sizeof(addr);\n\t\tint bytes;\n\n#ifdef WIN32\n\t\tWSAPOLLFD fda[1];\n\t\tfda[0].fd = sd;\n\t\tfda[0].events = POLLIN;\n\t\tWSAPoll(fda, 1, 10);\n#endif\n\t\tkeep_retry_quick:\n\n\t\tbytes = recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr*)&addr, &addrlenval );\n\t\tif( !isICMPResponse(buf, bytes) ) continue;\n\n\t\t// compare the sender\n\t\tif( using_regular_ping && memcmp(&addr, &psaddr, addrlenval) != 0 ) continue;\n\n\t\t// sizeof(packet.hdr) + 20\n\t\tint offset = 0;\n\t\tif(addr.sin6_family == AF_INET) // ipv4\n\t\t{\n#ifdef __FreeBSD__\n\t\t\toffset = 48;\n#else\n\t\t\toffset = 28;\n#endif\n\t\t}\n\t\telse // ipv6\n\t\t{\n\t\t\toffset = 8;\n\t\t}\n\n\t\tif ( bytes > 0 )\n\t\t\tdisplay(buf + offset, bytes - offset );\n\t\telse\n\t\t{\n\t\t\tERRM(\"Error: recvfrom failed\");\n\t\t}\n\n\t\tgoto keep_retry_quick;\n\t}\n\n\tERRM( \"Fault on listen().\\n\" );\n\texit( 0 );\n}\n\nvoid singleping(struct sockaddr *addr, socklen_t addr_len )\n{\n\tint cnt=1;\n\n#ifdef WIN32\n\t{\n\t\t//Setup windows socket for nonblocking io.\n\t\tunsigned long iMode = 1;\n\t\tioctlsocket(sd, FIONBIO, &iMode);\n\t}\n#else\n\tif ( fcntl(sd, F_SETFL, O_NONBLOCK) != 0 )\n\t\tERRM(\"Warning: Request nonblocking I/O failed.\");\n#endif\n\n\tdouble stime = OGGetAbsoluteTime();\n\n\tstruct packet pckt;\n\n\t{\n\t\tint rsize = load_ping_packet( pckt.msg, sizeof( pckt.msg ) );\n\t\tmemset( &pckt.hdr, 0, sizeof( pckt.hdr ) ); //This needs to be here, but I don't know why, since I think the struct is fully populated.\n#ifdef __FreeBSD__\n\t\tpckt.hdr.icmp_code = 0;\n\t\tpckt.hdr.icmp_type = ICMP_ECHO;\n\t\tpckt.hdr.icmp_id = pid;\n\t\tpckt.hdr.icmp_seq = cnt++;\n\t\tpckt.hdr.icmp_cksum = checksum((const unsigned char *)&pckt, sizeof( pckt.hdr ) + rsize );\n#else\n\t\tpckt.hdr.code = 0;\n\t\tpckt.hdr.type = (psaddr.sin6_family == AF_INET) ? ICMP_ECHO : ICMP6_ECHO_REQUEST;\n\t\tpckt.hdr.un.echo.id = pid;\n\t\tpckt.hdr.un.echo.sequence = cnt++;\n\t\tpckt.hdr.checksum = checksum((const unsigned char *)&pckt, sizeof( pckt.hdr ) + rsize );\n#endif\n\n\t\tint sr = sendto(sd, (char*)&pckt, sizeof( pckt.hdr ) + rsize , 0, addr, addr_len);\n\n\t\tif( sr <= 0 )\n\t\t{\n\t\t\tping_failed_to_send = 1;\n\t\t\tif( using_regular_ping )\n\t\t\t{\n\t\t\t\tERRMB(\"Ping send failed:\\n%s (%d)\\n\", strerror(errno), errno);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tping_failed_to_send = 0;\n\t\t}\n\t} \n}\n\nvoid ping(struct sockaddr *addr, socklen_t addr_len )\n{\n\tint cnt=1;\n\n\tusing_regular_ping = 1;\n#ifdef WIN32\n\t{\n\t\t//Setup windows socket for nonblocking io.\n\t\tunsigned long iMode = 1;\n\t\tioctlsocket(sd, FIONBIO, &iMode);\n\t}\n#else\n\tif ( fcntl(sd, F_SETFL, O_NONBLOCK) != 0 )\n\t\tERRM(\"Warning: Request nonblocking I/O failed.\");\n#endif\n\n\tdouble stime = OGGetAbsoluteTime();\n\n\tstruct packet pckt;\n\tdo\n\t{\n\t\tint rsize = load_ping_packet( pckt.msg, sizeof( pckt.msg ) );\n\t\tmemset( &pckt.hdr, 0, sizeof( pckt.hdr ) ); //This needs to be here, but I don't know why, since I think the struct is fully populated.\n#ifdef __FreeBSD__\n\t\tpckt.hdr.icmp_code = 0;\n\t\tpckt.hdr.icmp_type = ICMP_ECHO;\n\t\tpckt.hdr.icmp_id = pid;\n\t\tpckt.hdr.icmp_seq = cnt++;\n\t\tpckt.hdr.icmp_cksum = checksum((const unsigned char *)&pckt, sizeof( pckt.hdr ) + rsize );\n#else\n\t\tpckt.hdr.code = 0;\n\t\tpckt.hdr.type = (psaddr.sin6_family == AF_INET) ? ICMP_ECHO : ICMP6_ECHO_REQUEST;\n\t\tpckt.hdr.un.echo.id = pid;\n\t\tpckt.hdr.un.echo.sequence = cnt++;\n\t\tpckt.hdr.checksum = checksum((const unsigned char *)&pckt, sizeof( pckt.hdr ) + rsize );\n#endif\n\n\t\tint sr = sendto(sd, (char*)&pckt, sizeof( pckt.hdr ) + rsize , 0, addr, addr_len);\n\n\t\tif( sr <= 0 )\n\t\t{\n\t\t\tping_failed_to_send = 1;\n\t\t\tif( using_regular_ping )\n\t\t\t{\n\t\t\t\tERRMB(\"Ping send failed:\\n%s (%d)\\n\", strerror(errno), errno);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tping_failed_to_send = 0;\n\t\t}\n\n\t\tif( precise_ping )\n\t\t{\n\t\t\tdouble ctime;\n\t\t\tdo\n\t\t\t{\n\t\t\t\tctime = OGGetAbsoluteTime();\n\t\t\t\tif( pingperiodseconds >= 1000 ) stime = ctime;\n\t\t\t} while( ctime < stime + pingperiodseconds );\n\t\t\tstime += pingperiodseconds;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif( pingperiodseconds > 0 )\n\t\t\t{\n\t\t\t\tuint32_t dlw = 1000000.0*pingperiodseconds;\n\t\t\t\tOGUSleep( dlw );\n\t\t\t}\n\t\t}\n\t} \twhile( pingperiodseconds >= 0 );\n\t//close( sd ); //Hacky, we don't close here because SD doesn't come from here, rather from ping_setup.  We may want to run this multiple times.\n}\n\nvoid ping_setup(const char * strhost, const char * device)\n{\n\tpid = getpid();\n\n#ifdef WIN32\n\tWSADATA wsaData;\n\tint r =\tWSAStartup(MAKEWORD(2,2), &wsaData);\n\tif( r )\n\t{\n\t\tERRM( \"Fault in WSAStartup\\n\" );\n\t\texit( -2 );\n\t}\n#endif\n\n\n#ifdef WIN32\n\tsd = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, 0, 0, WSA_FLAG_OVERLAPPED);\n\t{\n\t\tint lttl = 0xff;\n\t\tif (setsockopt(sd, IPPROTO_IP, IP_TTL, (const char*)&lttl, sizeof(lttl)) == SOCKET_ERROR)\n\t\t{\n\t\t\tprintf( \"Warning: No IP_TTL.\\n\" );\n\t\t}\n\t}\n#else\n\t// resolve host\n\tpsaddr_len = sizeof(psaddr);\n\n\tif( strhost )\n\t\tresolveName((struct sockaddr*) &psaddr, &psaddr_len, strhost, AF_UNSPEC);\n\telse\n\t\tpsaddr.sin6_family = AF_INET;\n\n\tsd = createSocket();\n\n\tsetTTL(sd);\n\n\tif(device)\n\t{\n\t\tif( setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) +1) != 0)\n\t\t{\n\t\t\tERRM(\"Error: Failed to set Device option.  Are you root?  Or can do sock_raw sockets?\\n\");\n\t\t\texit( -1 );\n\t\t}\n\t}\n\n#endif\n\tif ( sd < 0 )\n\t{\n\t\tERRM(\"Error: Could not create raw socket\\n\");\n\t\texit(0);\n\t}\n\n}\n\n#endif // WIN_USE_NO_ADMIN_PING\n\n\nvoid do_pinger( )\n{\n\tping((struct sockaddr*) &psaddr, psaddr_len );\n}\n\n// used by the ERRMB makro from error_handling.h\nchar errbuffer[1024];\n\n"
  },
  {
    "path": "ping.h",
    "content": "#ifndef _PING_H\n#define _PING_H\n\n#include <stdint.h>\n#ifdef WIN32\n\ttypedef int socklen_t;\n\tstruct sockaddr;\n#else\n\t#include <sys/socket.h>\n#endif\n\nunsigned short checksum(const unsigned char *b, uint16_t len);\n\n//Callback (when received)\nvoid display(uint8_t *buf, int bytes);\n\n//Callback (before sending)\n//return value = # of bytes to send in ping message.\nint load_ping_packet( uint8_t  * buffer, int buffersize );\n\nvoid listener();\nvoid ping(struct sockaddr *addr, socklen_t addr_len );\nvoid do_pinger( );\n\nvoid singleping(struct sockaddr *addr, socklen_t addr_len ); // If using this, must call ping_setup( 0, 0); to begin.\n\n//If pingperiodseconds = -1, run ping/do_pinger once and exit.\nextern float pingperiodseconds;\nextern int precise_ping; //if 0, use minimal CPU, but ping send-outs are only approximate, if 1, spinlock until precise time for ping is hit.\nextern int ping_failed_to_send;\nvoid ping_setup(const char * strhost, const char * device);\n\n\n#endif\n\n"
  },
  {
    "path": "resolve.c",
    "content": "#include \"resolve.h\"\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"error_handling.h\"\n\n#ifdef WIN32\n\t#include <ws2tcpip.h>\n#else // !WIN32\n\t#include <arpa/inet.h> // inet_pton (parsing ipv4 and ipv6 notation)\n\n\t#include <sys/types.h>\n\t#include <sys/socket.h>\n\t#include <netdb.h>\n#endif\n\nint resolveName(struct sockaddr* addr, socklen_t* addr_len, const char* hostname, int family)\n{\n\tint result;\n\tstruct addrinfo* res = NULL;\n\n\t// zero addr\n\tmemset(addr, 0, *addr_len);\n\n\t// try to parse ipv4\n\tif(family == AF_UNSPEC || family == AF_INET) {\n\t\tresult = inet_pton(AF_INET, hostname, &((struct sockaddr_in*) addr)->sin_addr);\n\t\tif(result == 1)\n\t\t{\n\t\t\taddr->sa_family = AF_INET;\n\t\t\t*addr_len = sizeof(struct sockaddr_in);\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\t// try to parse ipv6\n\tif(family == AF_UNSPEC || family == AF_INET6) {\n\t\tresult = inet_pton(AF_INET6, hostname, &((struct sockaddr_in6*) addr)->sin6_addr);\n\t\tif(result == 1)\n\t\t{\n\t\t\taddr->sa_family = AF_INET6;\n\t\t\t*addr_len = sizeof(struct sockaddr_in6);\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\t// try to resolve DNS\n\tstruct addrinfo hints;\n\tmemset(&hints, 0, sizeof(struct addrinfo));\n\thints.ai_family = family; // AF_UNSPEC, AF_INET, AF_INET6\n\thints.ai_socktype = 0; // 0 = any, SOCK_STREAM, SOCK_DGRAM\n\thints.ai_protocol = 0; // 0 = any\n\thints.ai_flags = 0; // no flags\n\n\tresult = getaddrinfo(hostname, NULL, &hints, &res);\n\tif( result != 0)\n\t{\n\t\tERRM( \"Error: cannot resolve hostname %s: %s\\n\", hostname, gai_strerror(result) );\n\t\texit( -1 );\n\t}\n\n\tif(res->ai_addrlen > *addr_len)\n\t{\n\t\t// error - this should not happen\n\t\tERRM( \"Error addr is to short. required length: %d, available length: %d\", res->ai_addrlen, *addr_len );\n\t\tfreeaddrinfo(res);\n\t\texit( -1 );\n\t}\n\tmemcpy(addr, res->ai_addr, res->ai_addrlen);\n\t*addr_len = res->ai_addrlen;\n\n\tfreeaddrinfo(res);\n\treturn 1;\n}\n"
  },
  {
    "path": "resolve.h",
    "content": "#ifndef _RESOLVE_H\n#define _RESOLVE_H\n\n#ifdef WIN32\n\ttypedef int socklen_t;\n\tstruct sockaddr;\n#else\n\t#include <sys/socket.h>\n#endif\n\n// try to parse hostname\n//  * as dot notation (1.1.1.1)\n//  * as ipv6 notation (abcd:ef00::1)\n//  * as hostname (resolve DNS)\n// returns 1 on success\n// family can be used to force ipv4 or ipv6. Use AF_UNSPEC (allow both), AF_INET or AF_INET6 to force ipv4 or ipv6\nint resolveName(struct sockaddr* addr, socklen_t* addr_len, const char* hostname, int family);\n\n#endif\n"
  },
  {
    "path": "resources.rc",
    "content": "#ifndef WIN_USE_NO_ADMIN_PING\n1 24 \"uac.manifest\"\n#endif\n\n#include <windows.h>\n\nLANGUAGE 9, SUBLANG_DEFAULT\nIPDialog DIALOG 10, 10, 340, 100\nSTYLE WS_CAPTION | WS_SYSMENU | WS_THICKFRAME\nCAPTION \"cnping\"\nBEGIN\n    LTEXT           \"Usage: cnping [host] [period] [extra size] [y-axis scaling]\",                        0, 90, 0, 300, 20, SS_LEFT\n    LTEXT           \"[host]                 -- domain or IP address of icmp ping, or http://host\",        0, 90, 15, 300, 20, SS_LEFT\n    LTEXT           \"[period]               -- period in seconds (optional), default is 0.02\",            0, 90, 30, 300, 20, SS_LEFT\n    LTEXT           \"[extra size]           -- ping packet extra size (above 12), optional, default = 0\", 0, 90, 45, 300, 10, SS_LEFT\n    LTEXT           \"[const y-axis scaling] -- use a fixed scaling factor instead of auto scaling\",       0, 90, 60, 300, 10, SS_LEFT\n    EDITTEXT        3, 1, 15, 88, 12\n    EDITTEXT        4, 1, 30, 88, 12\n    EDITTEXT        5, 1, 45, 88, 12\n    EDITTEXT        6, 1, 60, 88, 12\n    PUSHBUTTON      \"&Ping\", 7, 25, 80, 100, 10\n    PUSHBUTTON      \"&Close\", 8, 175, 80, 100, 10\nEND\n\nMAIN_ICON ICON \"cnping.ico\"\n"
  },
  {
    "path": "searchnet.c",
    "content": "#include <stdio.h>\n#include \"ping.h\"\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include \"resolve.h\"\n#include \"rawdraw/os_generic.h\"\n\nuint32_t my_random_key;\nuint8_t send_id[4];\n\nextern float pingperiodseconds;\n\nvoid * PingListen( void * r )\n{\n\tlistener();\n\tprintf( \"Fault on listen.\\n\" );\n\texit( -2 );\n}\n\nvoid display(uint8_t *buf, int bytes)\n{\n\tuint32_t reqid = ((uint32_t)buf[0+1] << 24) | (buf[1+1]<<16) | (buf[2+1]<<8) | (buf[3+1]);\n\n\tif( reqid != my_random_key ) return;\n\n\tprintf( \"%d.%d.%d.%d\\n\", buf[4+1], buf[5+1], buf[6+1], buf[7+1] );\n}\n\nint load_ping_packet( uint8_t * buffer, int bufflen )\n{\n\tbuffer[0+1] = my_random_key >> 24;\n\tbuffer[1+1] = my_random_key >> 16;\n\tbuffer[2+1] = my_random_key >> 8;\n\tbuffer[3+1] = my_random_key >> 0;\n\n\tbuffer[4+1] = send_id[0];\n\tbuffer[5+1] = send_id[1];\n\tbuffer[6+1] = send_id[2];\n\tbuffer[7+1] = send_id[3];\n\n\treturn 12;\n}\n\n\nint main( int argc, char ** argv )\n{\n\tuint32_t offset;\n\tint mask;\n\tin_addr_t base;\n\tchar dispip[32];\n\tfloat speed;\n\n\tping_setup( 0, 0);\n\tOGCreateThread( PingListen, 0 );\n\tsrand( ((int)(OGGetAbsoluteTime()*10000)) );\n\tmy_random_key = rand();\n\n\tif( argc != 4 )\n\t{\n\t\tfprintf( stderr, \"Usage: [searchnet IP net] [mask (single #, i.e. 24)] [speed (in seconds per attempt)]\\n\" );\n\t\treturn -1;\n\t}\n\n\tbase = ntohl(inet_addr( argv[1] ));\n\tmask = 1<<(32-atoi(argv[2]));\n\tspeed = atof(argv[3]);\n\n\tbase &= ~(mask-1);\n\tprintf( \"Base: %08x / Mask: %08x\\n\", base, mask );\n\tfor( offset = 0; offset < mask; offset++ )\n\t{\n\t\tuint32_t cur = base + offset;\n\t\tsprintf( dispip, \"%d.%d.%d.%d\", (cur>>24)&0xff, (cur>>16)&0xff, (cur>>8)&0xff, (cur)&0xff );\n\t\tsend_id[0] = (cur>>24)&0xff;\n\t\tsend_id[1] = (cur>>16)&0xff;\n\t\tsend_id[2] = (cur>>8)&0xff;\n\t\tsend_id[3] = (cur)&0xff;\n//\t\tprintf( \"Pinging: %s\\n\", dispip );\n\t\tpingperiodseconds = -1;\n\n\t\tstruct sockaddr_in6 psaddr;\n\t\tsocklen_t psaddr_len = sizeof(psaddr);\n\t\tresolveName((struct sockaddr*) &psaddr, &psaddr_len, dispip, AF_UNSPEC);\n\t\tsingleping((struct sockaddr*) &psaddr, psaddr_len );\n\n\t\tOGUSleep( (int)(speed * 1000000) );\n\t}\n\n\treturn 0;\n}\n\n"
  },
  {
    "path": "uac.manifest",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<!-- This is no longer needed if you compile with WIN_USE_NO_ADMIN_PING.  It is only required for raw packet access -->\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n  <assemblyIdentity version=\"1.0.0.0\" processorArchitecture=\"X86\" name=\"cnping\" type=\"win32\"/>\n  <trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n    <security>\n      <requestedPrivileges>\n        <requestedExecutionLevel level=\"requireAdministrator\" uiAccess=\"false\"/>\n      </requestedPrivileges>\n    </security>\n  </trustInfo>\n</assembly>\n"
  }
]