cnping

Minimal Graphical Ping Tool
git clone https://git.sinitax.com/cnlohr/cnping
Log | Files | Refs | Submodules | README | LICENSE | sfeed.txt

commit 9e7b717ad682914732a40da40f4f2c7f987ad3aa
parent 5c42452616a85c6877f5502a828dc82f61212a80
Author: Viknet <viknet@icloud.com>
Date:   Sat, 28 Jul 2018 13:46:20 +0300

Merge pull request #1 from cnlohr/master

Update tree
Diffstat:
M.gitignore | 1+
ACNFGCocoaCGDriver.m | 361+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MCNFGXDriver.c | 22+++++++++-------------
MLICENSE | 21+--------------------
MMakefile | 21++++++++++++---------
MREADME.md | 37+++++++++++++++++++++++++------------
Dcnping-mousey.c | 453-------------------------------------------------------------------------------
Mcnping.c | 613++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Mcnping.exe | 0
Aerror_handling.h | 24++++++++++++++++++++++++
Ahttping.c | 232+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahttping.h | 12++++++++++++
Mos_generic.c | 2+-
Mos_generic.h | 4++--
Mping.c | 265+++++++++++++++++++++++++++++++++----------------------------------------------
Mping.h | 20+++++---------------
Mresources.rc | 2+-
Msearchnet.c | 11+----------
18 files changed, 1190 insertions(+), 911 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -3,3 +3,4 @@ cnping cnping-mousey searchnet +tags diff --git a/CNFGCocoaCGDriver.m b/CNFGCocoaCGDriver.m @@ -0,0 +1,361 @@ +//Copyright (c) 2017 <>< David Chapman - Under the MIT/x11 or NewBSD License you choose. +//Copyright (C) 2017 Viknet, MIT/x11 License or NewBSD License you choose. + +#import <Cocoa/Cocoa.h> +#import <Foundation/Foundation.h> + +#define RGB2Color(RGB) (RGB&0xFF)/256., ((RGB>>8)&0xFF)/256., ((RGB>>16)&0xFF)/256. + +#include "CNFGFunctions.h" + +id app_menubar, app_appMenuItem, app_appMenu, app_appName, app_quitMenuItem, app_quitTitle, app_quitMenuItem, app_window; +NSView *app_imageView; +CGColorSpaceRef colorSpace; +CGContextRef bufferContext; +uint32_t *bufferData; + +NSAutoreleasePool *app_pool; +int app_sw=0, app_sh=0; +NSRect frameRect; +int app_mouseX=0, app_mouseY=0; +BOOL inFullscreen = false; + +uint32_t CNFGColor( uint32_t RGB ) +{ + CNFGLastColor = RGB; + unsigned char red = RGB & 0xFF; + unsigned char grn = ( RGB >> 8 ) & 0xFF; + unsigned char blu = ( RGB >> 16 ) & 0xFF; + CGContextSetRGBStrokeColor(bufferContext, RGB2Color(RGB), 1.0); + CGContextSetRGBFillColor(bufferContext, RGB2Color(RGB), 1.0); + return CNFGLastColor; +} + +void CNFGTackPixel( short x, short y ) +{ + y = app_sh - y - 1; + if( x < 0 || y < 0 || x >= app_sw || y >= app_sh ) return; + bufferData[x + app_sw * y] = CNFGLastColor; +} + +// void CNFGTackSegment( short x1, short y1, short x2, short y2 ) +// { +// y1 = app_sh - y1 - 1; +// y2 = app_sh - y2 - 1; +// CGContextBeginPath(bufferContext); +// CGContextMoveToPoint(bufferContext, x1, y1); +// CGContextAddLineToPoint(bufferContext, x2, y2); +// CGContextStrokePath(bufferContext); +// } + +void CNFGTackSegment( short x1, short y1, short x2, short y2 ) +{ + short tx, ty; + float slope, lp; + + short dx = x2 - x1; + short dy = y2 - y1; + + if( dx < 0 ) dx = -dx; + if( dy < 0 ) dy = -dy; + + if( dx > dy ) + { + short minx = (x1 < x2)?x1:x2; + short maxx = (x1 < x2)?x2:x1; + short miny = (x1 < x2)?y1:y2; + short maxy = (x1 < x2)?y2:y1; + float thisy = miny; + slope = (float)(maxy-miny) / (float)(maxx-minx); + + for( tx = minx; tx <= maxx; tx++ ) + { + ty = thisy; + if( tx < 0 || ty < 0 || ty >= app_sh ) continue; + if( tx >= app_sw ) break; + bufferData[ty * app_sw + tx] = CNFGLastColor; + thisy += slope; + } + } + else + { + short minx = (y1 < y2)?x1:x2; + short maxx = (y1 < y2)?x2:x1; + short miny = (y1 < y2)?y1:y2; + short maxy = (y1 < y2)?y2:y1; + float thisx = minx; + slope = (float)(maxx-minx) / (float)(maxy-miny); + + for( ty = miny; ty <= maxy; ty++ ) + { + tx = thisx; + if( ty < 0 || tx < 0 || tx >= app_sw ) continue; + if( ty >= app_sh ) break; + bufferData[ty * app_sw + tx] = CNFGLastColor; + thisx += slope; + } + } +} + +void CNFGTackRectangle( short x1, short y1, short x2, short y2 ) +{ + CGContextFillRect(bufferContext, CGRectMake (x1, app_sh - y1 - 1, x2, app_sh - y2 - 1 )); +} + +void CNFGTackPoly( RDPoint * points, int verts ) +{ + if (verts==0) return; + CGContextBeginPath(bufferContext); + CGContextMoveToPoint(bufferContext, points[0].x, app_sh - points[0].y - 1); + for (int i=1; i<verts; i++){ + CGContextAddLineToPoint(bufferContext, points[i].x, app_sh - points[i].y - 1); + } + CGContextFillPath(bufferContext); +} + +@interface MyView : NSView +@end +@implementation MyView +- (id)initWithFrame:(NSRect)frame { + self = [super initWithFrame:frame]; + if (self) + { + [self setWantsLayer:YES]; + [self setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawOnSetNeedsDisplay]; + // [self setLayerContentsPlacement: NSViewLayerContentsPlacementCenter]; + } + return self; +} + +- (BOOL) wantsUpdateLayer +{ + return YES; +} +- (void) updateLayer +{ + CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bufferData, 4*app_sw*app_sh, NULL); + CGImageRef frameImage = CGImageCreate(app_sw, app_sh, 8, 32, 4*app_sw, colorSpace, kCGBitmapByteOrderDefault, provider, NULL, false, kCGRenderingIntentDefault); + + [app_imageView.layer setContents:(id)frameImage]; + + CGImageRelease(frameImage); + CGDataProviderRelease(provider); +} +@end + +CGContextRef createBitmapContext (int pixelsWide, + int pixelsHigh) +{ + int bitmapBytesPerRow = (pixelsWide * 4); + + CGContextRef context = CGBitmapContextCreate (NULL, + pixelsWide, + pixelsHigh, + 8, + bitmapBytesPerRow, + colorSpace, + kCGImageAlphaNoneSkipLast); + bufferData = CGBitmapContextGetData(context); + CGContextSetInterpolationQuality(context, kCGInterpolationNone); + // CGContextSetShouldAntialias(context, NO); + // CGContextSetLineWidth(context, 0.5); + + return context; +} + +void initApp(){ + [NSApplication sharedApplication]; + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + app_menubar = [[NSMenu new] autorelease]; + app_appMenuItem = [[NSMenuItem new] autorelease]; + [app_menubar addItem:app_appMenuItem]; + [NSApp setMainMenu:app_menubar]; + app_appMenu = [[NSMenu new] autorelease]; + app_appName = [[NSProcessInfo processInfo] processName]; + app_quitTitle = [@"Quit " stringByAppendingString:app_appName]; + app_quitMenuItem = [[[NSMenuItem alloc] initWithTitle:app_quitTitle + action:@selector(terminate:) keyEquivalent:@"q"] autorelease]; + [app_appMenu addItem:app_quitMenuItem]; + [app_appMenuItem setSubmenu:app_appMenu]; + app_imageView = [MyView new]; + colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear); +} + +void CNFGSetupFullscreen( const char * WindowName, int screen_number ) +{ + inFullscreen = YES; + initApp(); + + NSDictionary *fullScreenOptions = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithInt: + (NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock) ], + NSFullScreenModeApplicationPresentationOptions, nil]; + [app_imageView enterFullScreenMode:[[NSScreen screens] objectAtIndex:screen_number] withOptions:fullScreenOptions]; + frameRect = [app_imageView frame]; + CGSize app_imageSize = frameRect.size; + app_sw = app_imageSize.width; app_sh = app_imageSize.height; + bufferContext = createBitmapContext (app_sw, app_sh); + [NSApp finishLaunching]; + [NSApp updateWindows]; + app_pool = [NSAutoreleasePool new]; +} + +void CNFGSetup( const char * WindowName, int sw, int sh ) +{ + app_sw=sw; app_sh=sh; + frameRect = NSMakeRect(0, 0, app_sw, app_sh); + + initApp(); + + app_window = [[[NSWindow alloc] + initWithContentRect:frameRect + styleMask: + NSWindowStyleMaskBorderless | + NSWindowStyleMaskResizable | + NSWindowStyleMaskTitled | + NSWindowStyleMaskClosable | + NSWindowStyleMaskMiniaturizable + backing:NSBackingStoreBuffered defer:NO] + autorelease]; + + NSString *title = [[[NSString alloc] initWithCString: WindowName encoding: NSUTF8StringEncoding] autorelease]; + [app_window setTitle:title]; + [app_window setContentView:app_imageView]; + [app_window cascadeTopLeftFromPoint:NSMakePoint(20,20)]; + [app_window makeKeyAndOrderFront:nil]; + [NSApp activateIgnoringOtherApps:YES]; + bufferContext = createBitmapContext (app_sw, app_sh); + [NSApp finishLaunching]; + [NSApp updateWindows]; + app_pool = [NSAutoreleasePool new]; +} + +#define XK_Left 0xff51 /* Move left, left arrow */ +#define XK_Up 0xff52 /* Move up, up arrow */ +#define XK_Right 0xff53 /* Move right, right arrow */ +#define XK_Down 0xff54 /* Move down, down arrow */ +#define KEY_UNDEFINED 255 +#define KEY_LEFT_MOUSE 0 + +static int keycode(key) +{ + if (key < 256) return key; + switch(key) { + case 63232: return XK_Up; + case 63233: return XK_Down; + case 63234: return XK_Left; + case 63235: return XK_Right; + } + return KEY_UNDEFINED; +} + +void CNFGHandleInput() +{ + [app_pool release]; + app_pool = [NSAutoreleasePool new]; + // Quit if no open windows left + if ([[NSApp windows] count] == 0) [NSApp terminate: nil]; + + //---------------------- + // Peek at the next event + //---------------------- + NSDate *app_currDate = [NSDate new]; + // If we have events, handle them! + NSEvent *event; + for (;(event = [NSApp + nextEventMatchingMask:NSEventMaskAny + untilDate:app_currDate + inMode:NSDefaultRunLoopMode + dequeue:YES]);) + { + NSPoint local_point; + NSEventType type = [event type]; + switch (type) + { + case NSEventTypeKeyDown: + for (int i=0; i<[event.characters length]; i++) { + unichar ch = [event.characters characterAtIndex: i]; + HandleKey(keycode(ch), 1); + } + break; + + case NSEventTypeKeyUp: + for (int i=0; i<[event.characters length]; i++) { + unichar ch = [event.characters characterAtIndex: i]; + HandleKey(keycode(ch), 0); + } + break; + + case NSEventTypeMouseMoved: + case NSEventTypeLeftMouseDragged: + case NSEventTypeRightMouseDragged: + case NSEventTypeOtherMouseDragged: + if (inFullscreen){ + local_point = [NSEvent mouseLocation]; + } else { + if ([event window] == nil) break; + NSPoint event_location = event.locationInWindow; + local_point = [app_imageView convertPoint:event_location fromView:nil]; + } + app_mouseX = fmax(fmin(local_point.x, app_sw), 0); + // Y coordinate must be inversed? + app_mouseY = fmax(fmin(app_sh - local_point.y, app_sh), 0); + HandleMotion(app_mouseX, app_mouseY, [NSEvent pressedMouseButtons]); + break; + + case NSEventTypeLeftMouseDown: + case NSEventTypeRightMouseDown: + case NSEventTypeOtherMouseDown: + // Button number start from 1? + HandleButton(app_mouseX, app_mouseY, event.buttonNumber+1, 1); + break; + + case NSEventTypeLeftMouseUp: + case NSEventTypeRightMouseUp: + case NSEventTypeOtherMouseUp: + HandleButton(app_mouseX, app_mouseY, event.buttonNumber+1, 0); + break; + + default: + break; + } + [NSApp sendEvent:event]; + } + [app_currDate release]; +} + +void CNFGGetDimensions( short * x, short * y ) +{ + frameRect = [app_window frame]; + CGSize app_imageSize = frameRect.size; + if (app_imageSize.width != app_sw || app_imageSize.height != app_sh) + { + app_sw = app_imageSize.width; + app_sh = app_imageSize.height; + if (bufferContext != NULL) + CGContextRelease(bufferContext); + bufferContext = createBitmapContext (app_sw, app_sh); + } + *x = app_sw; + *y = app_sh; +} + +void CNFGClearFrame() +{ + CGContextSetRGBFillColor(bufferContext, RGB2Color(CNFGBGColor), 1.0); + CGContextFillRect(bufferContext, CGRectMake (0, 0, app_sw, app_sh )); +} + +void CNFGSwapBuffers() +{ + [app_imageView setNeedsDisplay:YES]; +} + +void CNFGUpdateScreenWithBitmap( unsigned long * data, int w, int h ) +{ + CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, data, 4*w*h, NULL); + CGImageRef bitmap = CGImageCreate(w, h, 8, 32, 4*w, colorSpace, kCGBitmapByteOrderDefault, provider, NULL, false, kCGRenderingIntentDefault); + CGContextDrawImage(bufferContext, frameRect, bitmap); + CGImageRelease(bitmap); + CGDataProviderRelease(provider); +} diff --git a/CNFGXDriver.c b/CNFGXDriver.c @@ -1,5 +1,5 @@ //Copyright (c) 2011, 2017 <>< Charles Lohr - Under the MIT/x11 or NewBSD License you choose. -//portions from +//portions from //http://www.xmission.com/~georgeps/documentation/tutorials/Xlib_Beginner.html //#define HAS_XINERAMA @@ -128,8 +128,8 @@ void CNFGSetupFullscreen( const char * WindowName, int screen_no ) CNFGWindow = XCreateWindow(CNFGDisplay, XRootWindow(CNFGDisplay, screen), xpos, ypos, CNFGWinAtt.width, CNFGWinAtt.height, - 0, CNFGWinAtt.depth, InputOutput, CNFGVisual, - CWBorderPixel | CWEventMask | CWOverrideRedirect | CWSaveUnder, + 0, CNFGWinAtt.depth, InputOutput, CNFGVisual, + CWBorderPixel | CWEventMask | CWOverrideRedirect | CWSaveUnder, &setwinattr); XMapWindow(CNFGDisplay, CNFGWindow); @@ -173,7 +173,7 @@ void CNFGSetup( const char * WindowName, int w, int h ) #ifdef CNFGOGL int attribs[] = { GLX_RGBA, - GLX_DOUBLEBUFFER, + GLX_DOUBLEBUFFER, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, @@ -214,10 +214,9 @@ void CNFGHandleInput() XEvent report; int bKeyDirection = 1; - int r; while( XPending( CNFGDisplay ) ) { - r=XNextEvent( CNFGDisplay, &report ); + XNextEvent( CNFGDisplay, &report ); bKeyDirection = 1; switch (report.type) @@ -251,7 +250,8 @@ void CNFGHandleInput() exit( 0 ); break; default: - printf( "Event: %d\n", report.type ); + //printf( "Event: %d\n", report.type ); + break; } } } @@ -262,8 +262,6 @@ void CNFGUpdateScreenWithBitmap( unsigned long * data, int w, int h ) static XImage *xi; static int depth; static int lw, lh; - static unsigned char * lbuffer; - int r, ls; if( !xi ) { @@ -281,9 +279,6 @@ void CNFGUpdateScreenWithBitmap( unsigned long * data, int w, int h ) lw = w; lh = h; } - - ls = lw * lh; - XPutImage(CNFGDisplay, CNFGWindow, CNFGWindowGC, xi, 0, 0, 0, 0, w, h ); } @@ -323,7 +318,7 @@ uint32_t CNFGColor( uint32_t RGB ) void CNFGClearFrame() { XGetWindowAttributes( CNFGDisplay, CNFGWindow, &CNFGWinAtt ); - XSetForeground(CNFGDisplay, CNFGGC, CNFGColor(CNFGBGColor) ); + XSetForeground(CNFGDisplay, CNFGGC, CNFGColor(CNFGBGColor) ); XFillRectangle(CNFGDisplay, CNFGPixmap, CNFGGC, 0, 0, CNFGWinAtt.width, CNFGWinAtt.height ); } @@ -338,6 +333,7 @@ void CNFGSwapBuffers() void CNFGTackSegment( short x1, short y1, short x2, short y2 ) { XDrawLine( CNFGDisplay, CNFGPixmap, CNFGGC, x1, y1, x2, y2 ); + XDrawPoint( CNFGDisplay, CNFGPixmap, CNFGGC, x1, y1 ); } void CNFGTackPixel( short x1, short y1 ) diff --git a/LICENSE b/LICENSE @@ -1,22 +1,3 @@ -//The myping tool is licensed under the below license. -//The rest of rawdraw and CNPing may be licensed feely under the MIT-x11 +//Rawdraw and CNPing may be licensed feely under the MIT-x11 //or NewBSD Licenses. You choose! -/* myping.c - * - * Copyright (c) 2000 Sean Walton and Macmillan Publishers. Use may be in - * whole or in part in accordance to the General Public License (GPL). - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. -*/ - diff --git a/Makefile b/Makefile @@ -1,6 +1,6 @@ -all : cnping searchnet cnping-mousey +all : cnping searchnet -CFLAGS:=$(CFLAGS) -g -Os -I/opt/X11/include +CFLAGS:=$(CFLAGS) -g -Os -I/opt/X11/include -Wall CXXFLAGS:=$(CFLAGS) LDFLAGS:=-g -L/opt/X11/lib/ @@ -10,23 +10,26 @@ LDFLAGS:=-g -L/opt/X11/lib/ #MINGW32:=/usr/bin/i686-w64-mingw32- MINGW32:=i686-w64-mingw32- -cnping.exe : cnping.c CNFGFunctions.c CNFGWinDriver.c os_generic.c ping.c +cnping.exe : cnping.c CNFGFunctions.c CNFGWinDriver.c os_generic.c ping.c httping.c $(MINGW32)windres resources.rc -o resources.o - $(MINGW32)gcc -g -mwindows -m32 $(CFLAGS) resources.o -o $@ $^ -lgdi32 -lws2_32 -s -D_WIN32_WINNT=0x0600 -DWIN32 + $(MINGW32)gcc -g -fno-ident -mwindows -m32 $(CFLAGS) resources.o -o $@ $^ -lgdi32 -lws2_32 -s -D_WIN32_WINNT=0x0600 -DWIN32 -cnping : cnping.o CNFGFunctions.o CNFGXDriver.o os_generic.o ping.o +cnping : cnping.o CNFGFunctions.o CNFGXDriver.o os_generic.o ping.o httping.o gcc $(CFLAGS) -o $@ $^ -lX11 -lm -lpthread $(LDFLAGS) -cnping-mousey : cnping-mousey.o CNFGFunctions.o CNFGXDriver.o os_generic.o ping.o - gcc $(CFLAGS) -o $@ $^ -lX11 -lm -lpthread $(LDFLAGS) +cnping_mac : cnping.c CNFGFunctions.c CNFGCocoaCGDriver.m os_generic.c ping.c httping.o + gcc -o cnping $^ -x objective-c -framework Cocoa -framework QuartzCore -lm -lpthread searchnet : os_generic.o ping.o searchnet.o gcc $(CFLAGS) -o $@ $^ -lpthread linuxinstall : cnping + sudo rm -f /usr/local/bin/cnping sudo cp cnping /usr/local/bin/ - sudo chmod +s /usr/local/bin/cnping + sudo setcap cap_net_raw+ep /usr/local/bin/cnping +# sudo chmod +t /usr/local/bin/cnping #One option - set the stuid bit. +# sudo install cnping /usr/local/bin/ #Another option - using install. clean : - rm -rf *.o *~ cnping cnping.exe cnping-mousey searchnet + rm -rf *.o *~ cnping cnping.exe cnping_mac searchnet diff --git a/README.md b/README.md @@ -1,31 +1,44 @@ cnping ====== -Minimal Graphical IPV4 Ping Tool. (also comes with searchnet, like nmap but smaller and simpler). It uses rawdraw so it is OS independent. - -Usage: cnping [host] [period] [extra size] [y-axis scaling] - - [host] -- domain or IP address of ping target - [period] -- period in seconds (optional), default 0.02 - [extra size] -- ping packet extra size (above 12), optional, default = 0 - [const y-axis scaling] -- use a fixed scaling factor instead of auto scaling (optional) +Minimal Graphical IPV4 Ping/HTTP Ping Tool. (also comes with searchnet, like nmap but smaller and simpler). It uses rawdraw so it is OS independent. +``` +Usage: cnping [host] [period] [extra size] [y-axis scaling] [window title] + [host] -- domain or IP address of ICMP ping target, or http://[host] i.e. http://google.com + [period] -- period in seconds (optional), default 0.02 + [extra size] -- ping packet extra size (above 12), optional, default = 0 + [const y-axis scaling] -- use a fixed scaling factor instead of auto scaling (optional) + [window title] -- the title of the window (optional) +``` Picture: <IMG SRC=cnping.png> -To build on ubuntu, please run: +If 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```. + +If a regular hostname is requested instead, ICMP (regular ping) will be used. + +This allows cnping to be operated in environments where ICMP is prohibited by local computer or network policies. + +## Installation: + +### Ubuntu: ``` sudo apt install libxinerama-dev libxext-dev libx11-dev build-essential make linuxinstall ``` -'linuxinstall' builds the tool and copies it to your usr/local/bin folder, and sets the sticky bit allowing it to run as though it were root, allowing it to create raw sockets. +'linuxinstall' builds the tool and copies it to your usr/local/bin folder, and sets the sticky bit or appropriate permissions allowing it to run as though it were root, allowing it to create raw sockets. ``` - sudo cp cnping /usr/local/bin/ - sudo chmod +s /usr/local/bin/cnping +sudo cp cnping /usr/local/bin/ +sudo chmod +s /usr/local/bin/cnping ``` +Note that if only http pinging is requested, you do not need root access. + +### Archlinux: + [cnping-git](https://aur.archlinux.org/packages/cnping-git/) in the [Arch User Repository](https://wiki.archlinux.org/index.php/Arch_User_Repository) diff --git a/cnping-mousey.c b/cnping-mousey.c @@ -1,453 +0,0 @@ -//Copyright (c) 2011-2014 <>< Charles Lohr - Under the MIT/x11 or NewBSD License you choose. - -#include <stdio.h> -#include <stdlib.h> -#include <math.h> -#include <errno.h> -#include <string.h> -#ifdef WIN32 -#include <windows.h> -#else -#include <sys/socket.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#include <arpa/inet.h> -#include <sys/select.h> -#include <netdb.h> -#endif -#include "CNFGFunctions.h" -#include "os_generic.h" -#include "ping.h" - -unsigned frames = 0; -unsigned long iframeno = 0; -short screenx, screeny; -const char * pinghost; -float pingperiod; -extern int precise_ping; -uint8_t pattern[8]; - -int notemode = 0; - -#define PINGCYCLEWIDTH 1024 -#define TIMEOUT 4 - -double PingSendTimes[PINGCYCLEWIDTH]; -double PingRecvTimes[PINGCYCLEWIDTH]; -int current_cycle = 0; - -int ExtraPingSize = 0; - -void display(uint8_t *buf, int bytes) -{ - int reqid = (buf[0] << 24) | (buf[1]<<16) | (buf[2]<<8) | (buf[3]); - reqid &= (PINGCYCLEWIDTH-1); - - double STime = PingSendTimes[reqid]; - double LRTime = PingRecvTimes[reqid]; - - if( memcmp( buf+4, pattern, 8 ) != 0 ) return; - if( LRTime > STime ) return; - if( STime < 1 ) return; - - //Otherwise this is a legit packet. - - PingRecvTimes[reqid] = OGGetAbsoluteTime(); -} - -int load_ping_packet( uint8_t * buffer, int bufflen ) -{ - buffer[0] = current_cycle >> 24; - buffer[1] = current_cycle >> 16; - buffer[2] = current_cycle >> 8; - buffer[3] = current_cycle >> 0; - - memcpy( buffer+4, pattern, 8 ); - - PingSendTimes[current_cycle&(PINGCYCLEWIDTH-1)] = OGGetAbsoluteTime(); - PingRecvTimes[current_cycle&(PINGCYCLEWIDTH-1)] = 0; - - current_cycle++; - - return 12 + ExtraPingSize; -} - -void * PingListen( void * r ) -{ - listener(); - printf( "Fault on listen.\n" ); - exit( -2 ); -} - -void * PingSend( void * r ) -{ - do_pinger( pinghost ); - printf( "Fault on ping.\n" ); - exit( -1 ); -} - -double lastnote; -double lastnoteupdown = 0; - -void HandleKey( int keycode, int bDown ) -{ - double note; - if( keycode == 'n' && bDown ) - { - notemode = !notemode; - } - note = -1; - - switch( keycode ) - { - case 'a': note = 0; break; - case 'w': note = 1; break; - case 's': note = 2; break; - case 'e': note = 3; break; - case 'd': note = 4; break; - case 'f': note = 5; break; - case 't': note = 6; break; - case 'g': note = 7; break; - case 'y': note = 8; break; - case 'h': note = 9; break; - case 'u': note = 10; break; - case 'j': note = 11; break; - case 'k': note = 12; break; - case 'o': note = 13; break; - case 'l': note = 14; break; - case 'p': note = 15; break; - case ';': note = 16; break; - case '\'': note = 17; break; - } - - if( note >= 0 ) - { - double per = (2.0 / pow(2.0, (note/12.0) ) ) * (1/440.); - if( bDown ) - { - printf( "%f\n", note ); - pingperiod = per; - lastnoteupdown = 0; - lastnote = note; - } - else - { - if( note == lastnote ) - lastnoteupdown = OGGetAbsoluteTime(); - } - } -} -void HandleButton( int x, int y, int button, int bDown ){} -void HandleMotion( int x, int y, int mask ) -{ - if( mask ) - { - float per = (2.0 / pow(2.0, x / 120.0)) * 0.02; - if( !notemode ) - { - pingperiod = per; - } - - if( y > 0 ) - ExtraPingSize = y*2; - - } -} - -void DrawFrame( void ) -{ - int i, x, y; - - double now = OGGetAbsoluteTime(); - - double totaltime = 0; - int totalcountok = 0; - double mintime = 100; - double maxtime = 0; - double stddev = 0; - double last = -1; - - precise_ping = 1; - - for( i = 0; i < screenx; i++ ) - { - int index = ((current_cycle - i - 1) + PINGCYCLEWIDTH) & (PINGCYCLEWIDTH-1); - double st = PingSendTimes[index]; - double rt = PingRecvTimes[index]; - - double dt = 0; - - if( rt > st ) - { - CNFGColor( 0xffffff ); - dt = rt - st; - dt *= 1000; - totaltime += dt; - if( dt < mintime ) mintime = dt; - if( dt > maxtime ) maxtime = dt; - totalcountok++; - } - else - { - CNFGColor( 0xff ); - dt = now - st; - dt *= 1000; - - } - - if( last < 0 && rt > st ) - last = dt; - int h = dt*10; - int top = screeny - h; - if( top < 0 ) top = 0; - CNFGTackSegment( i, screeny-1, i, top ); - } - - double avg = totaltime / totalcountok; - - for( i = 0; i < screenx; i++ ) - { - int index = ((current_cycle - i - 1) + PINGCYCLEWIDTH) & (PINGCYCLEWIDTH-1); - double st = PingSendTimes[index]; - double rt = PingRecvTimes[index]; - - double dt = 0; - if( rt > st ) - { - dt = rt - st; - dt *= 1000; - stddev += (dt-avg)*(dt-avg); - } - } - - stddev /= totalcountok; - - stddev = sqrt(stddev); - - CNFGColor( 0xff00 ); - int l = avg*10; - CNFGTackSegment( 0, screeny-l, screenx, screeny - l ); - l = (avg + stddev)*10; - CNFGTackSegment( 0, screeny-l, screenx, screeny - l ); - l = (avg - stddev)*10; - CNFGTackSegment( 0, screeny-l, screenx, screeny - l ); - - char stbuf[1024]; - char * sptr = &stbuf[0]; - sptr += sprintf( sptr, "Last: %5.2f ms\n", last ); - sptr += sprintf( sptr, "Min : %5.2f ms\n", mintime ); - sptr += sprintf( sptr, "Max : %5.2f ms\n", maxtime ); - sptr += sprintf( sptr, "Avg : %5.2f ms\n", avg ); - sptr += sprintf( sptr, "Std : %5.2f ms\n", stddev ); - sptr += sprintf( sptr, "EPS : %d / PP: %.2f ms\n", ExtraPingSize, pingperiod*1000.0 ); - sptr += sprintf( sptr, "Notemode: %d\n", notemode ); - - CNFGColor( 0x00 ); - for( x = -1; x < 2; x++ ) for( y = -1; y < 2; y++ ) - { - CNFGPenX = 10+x; CNFGPenY = 10+y; - CNFGDrawText( stbuf, 2 ); - } - CNFGColor( 0xffffff ); - CNFGPenX = 10; CNFGPenY = 10; - CNFGDrawText( stbuf, 2 ); - OGUSleep( 10000 ); -} - -#ifdef WIN32 -int mymain( int argc, const char ** argv ) -#else -int main( int argc, const char ** argv ) -#endif -{ - char title[1024]; - int i, x, y, r; - double ThisTime; - double LastFPSTime = OGGetAbsoluteTime(); - double LastFrameTime = OGGetAbsoluteTime(); - double SecToWait; - int linesegs = 0; -// struct in_addr dst; - struct addrinfo *result; - - srand( (int)(OGGetAbsoluteTime()*100000) ); - - for( i = 0; i < sizeof( pattern ); i++ ) - { - pattern[i] = rand(); - } - CNFGBGColor = 0x800000; - CNFGDialogColor = 0x444444; - for( i = 0; i < PINGCYCLEWIDTH; i++ ) - { - PingSendTimes[i] = 0; - PingRecvTimes[i] = 0; - } - - if( argc < 2 ) - { - ERRM( "Usage: cnping-mousey [host] [ping period in seconds (optional) default 0.02] [ping packet extra size (above 12), default = 0]\n" ); - return -1; - } - - if( argc > 3 ) - { - ExtraPingSize = atoi( argv[3] ); - printf( "Extra ping size added: %d\n", ExtraPingSize ); - } - - sprintf( title, "%s - cnping-mousey", argv[1] ); - CNFGSetup( title, 300, 115 ); - - ping_setup(); - - pinghost = argv[1]; - pingperiod = (argc>=3)?atof( argv[2] ):.02; - - OGCreateThread( PingSend, 0 ); - OGCreateThread( PingListen, 0 ); - - while(1) - { - int i, pos; - float f; - iframeno++; - RDPoint pto[3]; - - - if( notemode && lastnoteupdown > 0 && OGGetAbsoluteTime() - lastnoteupdown > .05 ) - { - pingperiod = 1000; - } - CNFGHandleInput(); - - CNFGClearFrame(); - CNFGColor( 0xFFFFFF ); - CNFGGetDimensions( &screenx, &screeny ); - - DrawFrame(); - - frames++; - CNFGSwapBuffers(); - - ThisTime = OGGetAbsoluteTime(); - if( ThisTime > LastFPSTime + 1 ) - { - frames = 0; - linesegs = 0; - LastFPSTime+=1; - } - - SecToWait = .030 - ( ThisTime - LastFrameTime ); - LastFrameTime += .030; - if( SecToWait > 0 ) - OGUSleep( (int)( SecToWait * 1000000 ) ); - } - - return(0); -} - -#ifdef WIN32 - -//from: http://alter.org.ua/docs/win/args/ - PCHAR* - CommandLineToArgvA( - PCHAR CmdLine, - int* _argc - ) - { - PCHAR* argv; - PCHAR _argv; - ULONG len; - ULONG argc; - CHAR a; - ULONG i, j; - - BOOLEAN in_QM; - BOOLEAN in_TEXT; - BOOLEAN in_SPACE; - - len = strlen(CmdLine); - i = ((len+2)/2)*sizeof(PVOID) + sizeof(PVOID); - - argv = (PCHAR*)GlobalAlloc(GMEM_FIXED, - i + (len+2)*sizeof(CHAR)); - - _argv = (PCHAR)(((PUCHAR)argv)+i); - - argc = 0; - argv[argc] = _argv; - in_QM = FALSE; - in_TEXT = FALSE; - in_SPACE = TRUE; - i = 0; - j = 0; - - while( a = CmdLine[i] ) { - if(in_QM) { - if(a == '\"') { - in_QM = FALSE; - } else { - _argv[j] = a; - j++; - } - } else { - switch(a) { - case '\"': - in_QM = TRUE; - in_TEXT = TRUE; - if(in_SPACE) { - argv[argc] = _argv+j; - argc++; - } - in_SPACE = FALSE; - break; - case ' ': - case '\t': - case '\n': - case '\r': - if(in_TEXT) { - _argv[j] = '\0'; - j++; - } - in_TEXT = FALSE; - in_SPACE = TRUE; - break; - default: - in_TEXT = TRUE; - if(in_SPACE) { - argv[argc] = _argv+j; - argc++; - } - _argv[j] = a; - j++; - in_SPACE = FALSE; - break; - } - } - i++; - } - _argv[j] = '\0'; - argv[argc] = NULL; - - (*_argc) = argc; - return argv; - } - - -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) -{ - int argc; - char cts[8192]; - sprintf( cts, "%s %s", GetCommandLine(), lpCmdLine ); - - ShowWindow (GetConsoleWindow(), SW_HIDE); - char ** argv = CommandLineToArgvA( - cts, - &argc - ); -// MessageBox( 0, argv[1], "X", 0 ); - return mymain( argc-1, (const char**)argv ); -} - -#endif diff --git a/cnping.c b/cnping.c @@ -6,6 +6,9 @@ #include <errno.h> #include <string.h> #ifdef WIN32 +#ifdef _MSC_VER +#define strdup _strdup +#endif #include <windows.h> #else #include <sys/socket.h> @@ -18,6 +21,8 @@ #include "CNFGFunctions.h" #include "os_generic.h" #include "ping.h" +#include "error_handling.h" +#include "httping.h" unsigned frames = 0; unsigned long iframeno = 0; @@ -25,11 +30,14 @@ short screenx, screeny; const char * pinghost; float GuiYScaleFactor; int GuiYscaleFactorIsConstant; - +double globmaxtime, globmintime = 1e20; +double globinterval, globlast; +uint64_t globalrx; +uint64_t globallost; uint8_t pattern[8]; -#define PINGCYCLEWIDTH 2048 +#define PINGCYCLEWIDTH 8192 #define TIMEOUT 4 double PingSendTimes[PINGCYCLEWIDTH]; @@ -37,22 +45,83 @@ double PingRecvTimes[PINGCYCLEWIDTH]; int current_cycle = 0; int ExtraPingSize; +int in_histogram_mode, in_frame_mode = 1; +void HandleGotPacket( int seqno, int timeout ); -void display(uint8_t *buf, int bytes) +#define MAX_HISTO_MARKS (TIMEOUT*10000) +uint64_t hist_counts[MAX_HISTO_MARKS]; + +void HandleNewPacket( int seqno ) { - int reqid = (buf[0] << 24) | (buf[1]<<16) | (buf[2]<<8) | (buf[3]); - reqid &= (PINGCYCLEWIDTH-1); + double Now = OGGetAbsoluteTime(); + PingSendTimes[seqno] = Now; + PingRecvTimes[seqno] = 0; + static int timeoutmark; - double STime = PingSendTimes[reqid]; - double LRTime = PingRecvTimes[reqid]; + while( Now - PingSendTimes[timeoutmark] > TIMEOUT ) + { + if( PingRecvTimes[timeoutmark] < PingSendTimes[timeoutmark] ) + { + HandleGotPacket( timeoutmark, 1 ); + } + timeoutmark++; + if( timeoutmark >= PINGCYCLEWIDTH ) timeoutmark = 0; + } +} - if( memcmp( buf+4, pattern, 8 ) != 0 ) return; - if( LRTime > STime ) return; - if( STime < 1 ) return; +void HandleGotPacket( int seqno, int timeout ) +{ + double Now = OGGetAbsoluteTime(); + + if( timeout ) + { + if( PingRecvTimes[seqno] < -0.5 ) return; + + globallost++; + PingRecvTimes[seqno] = -1; + hist_counts[MAX_HISTO_MARKS-1]++; + return; + } + + if( PingRecvTimes[seqno] >= PingSendTimes[seqno] ) return; + if( PingSendTimes[seqno] < 1 ) return; + if( Now - PingSendTimes[seqno] > TIMEOUT ) return; - //Otherwise this is a legit packet. + PingRecvTimes[seqno] = OGGetAbsoluteTime(); + double Delta = PingRecvTimes[seqno] - PingSendTimes[seqno]; + if( Delta > globmaxtime ) { globmaxtime = Delta; } + if( Delta < globmintime ) { globmintime = Delta; } + int slot = Delta * 10000; + if( slot >= MAX_HISTO_MARKS ) slot = MAX_HISTO_MARKS-1; + if( slot < 0 ) slot = 0; + hist_counts[slot]++; - PingRecvTimes[reqid] = OGGetAbsoluteTime(); + if( globlast > 0.5 ) + { + if( Now - globlast > globinterval ) globinterval = Now - globlast; + } + globlast = Now; + globalrx++; +} + + +void HTTPingCallbackStart( int seqno ) +{ + current_cycle = seqno; + HandleNewPacket( seqno ); +} + +void HTTPingCallbackGot( int seqno ) +{ + HandleGotPacket( seqno, 0 ); +} + +void display(uint8_t *buf, int bytes) +{ + int reqid = (buf[0] << 24) | (buf[1]<<16) | (buf[2]<<8) | (buf[3]); + reqid &= (PINGCYCLEWIDTH-1); + if( memcmp( buf+4, pattern, 8 ) != 0 ) return; + HandleGotPacket( reqid, 0 ); } int load_ping_packet( uint8_t * buffer, int bufflen ) @@ -64,8 +133,12 @@ int load_ping_packet( uint8_t * buffer, int bufflen ) memcpy( buffer+4, pattern, 8 ); - PingSendTimes[current_cycle&(PINGCYCLEWIDTH-1)] = OGGetAbsoluteTime(); - PingRecvTimes[current_cycle&(PINGCYCLEWIDTH-1)] = 0; + if( ping_failed_to_send ) + { + PingSendTimes[(current_cycle+PINGCYCLEWIDTH-1)&(PINGCYCLEWIDTH-1)] = 0; //Unset ping send. + } + + HandleNewPacket( current_cycle&(PINGCYCLEWIDTH-1) ); current_cycle++; @@ -89,12 +162,39 @@ void * PingSend( void * r ) -void HandleKey( int keycode, int bDown ){} +void HandleKey( int keycode, int bDown ) +{ + switch( keycode ) + { + case 'f': + if( bDown ) in_frame_mode = !in_frame_mode; + if( !in_frame_mode ) in_histogram_mode = 1; + break; + case 'm': + if( bDown ) in_histogram_mode = !in_histogram_mode; + if( !in_histogram_mode ) in_frame_mode = 1; + break; + case 'c': + memset( hist_counts, 0, sizeof( hist_counts ) ); + globmaxtime = 0; + globmintime = 1e20; + globinterval = 0; + globlast = 0; + globalrx = 0; + globallost = 0; + break; + case 'q': + exit(0); + break; + + } +} void HandleButton( int x, int y, int button, int bDown ){} void HandleMotion( int x, int y, int mask ){} void HandleDestroy() { exit(0); } -double GetGlobMaxPingTime( void ) + +double GetWindMaxPingTime( void ) { int i; double maxtime = 0; @@ -118,12 +218,159 @@ double GetGlobMaxPingTime( void ) return maxtime; } +void DrawMainText( const char * stbuf ) +{ + int x, y; + CNFGColor( 0x00 ); + for( x = -1; x < 2; x++ ) for( y = -1; y < 2; y++ ) + { + CNFGPenX = 10+x; CNFGPenY = 10+y; + CNFGDrawText( stbuf, 2 ); + } + CNFGColor( 0xffffff ); + CNFGPenX = 10; CNFGPenY = 10; + CNFGDrawText( stbuf, 2 ); +} + +void DrawFrameHistogram() +{ + int i; +// double Now = OGGetAbsoluteTime(); + const int colwid = 50; + int categories = (screenx-50)/colwid; + int maxpingslot = ( globmaxtime*10000.0 ); + int minpingslot = ( globmintime*10000.0 ); + int slots = maxpingslot-minpingslot; + + if( categories <= 2 ) + { + goto nodata; + } + else + { + int skips = ( (slots)/categories ) + 1; + int slotsmax = maxpingslot / skips + 1; + int slotsmin = minpingslot / skips; + slots = slotsmax - slotsmin; + if( slots <= 0 ) goto nodata; + + uint64_t samples[slots+2]; + int ssmsMIN[slots+2]; + int ssmsMAX[slots+2]; + int samp = minpingslot - 1; + + if( slots <= 1 ) goto nodata; + + memset( samples, 0, sizeof( samples ) ); + if( samp < 0 ) samp = 0; + + uint64_t highestchart = 0; + int tslot = 0; + for( i = slotsmin; i <= slotsmax; i++ ) + { + int j; + uint64_t total = 0; + ssmsMIN[tslot] = samp; + for( j = 0; j < skips; j++ ) + { + total += hist_counts[samp++]; + } + + ssmsMAX[tslot] = samp; + if( total > highestchart ) highestchart = total; + samples[tslot++] = total; + } + + if( highestchart <= 0 ) + { + goto nodata; + } + + int rslots = 0; + for( i = 0; i < slots+1; i++ ) + { + if( samples[i] ) rslots = i; + } + rslots++; + + for( i = 0; i < rslots; i++ ) + { + CNFGColor( 0x33cc33 ); + int top = 30; + uint64_t samps = samples[i]; + int bottom = screeny - 50; + int height = samps?(samps * (bottom-top) / highestchart + 1):0; + int startx = (i+1) * (screenx-50) / rslots; + int endx = (i+2) * (screenx-50) / rslots; + + if( !in_frame_mode ) + { + CNFGTackRectangle( startx, bottom-height, endx, bottom + 1 ); + CNFGColor( 0x00 ); + } + else + { + CNFGColor( 0x8080ff ); + } + CNFGTackSegment( startx, bottom+1, endx, bottom+1 ); + + CNFGTackSegment( startx, bottom-height, startx, bottom+1 ); + CNFGTackSegment( endx, bottom-height, endx, bottom+1 ); + + CNFGTackSegment( startx, bottom-height, endx, bottom-height ); + char stbuf[1024]; + int log10 = 1; + int64_t ll = samps; + while( ll >= 10 ) + { + ll /= 10; + log10++; + } + + if( !in_frame_mode ) + { + CNFGColor( 0xffffff ); + } + else + { + CNFGColor( 0x8080ff ); + } + + + CNFGPenX = startx + (8-log10) * 4; CNFGPenY = bottom+3; +#ifdef WIN32 + sprintf( stbuf, "%I64u", samps ); +#else + sprintf( stbuf, "%lu", samps ); +#endif + CNFGDrawText( stbuf, 2 ); + + CNFGPenX = startx; CNFGPenY = bottom+14; + sprintf( stbuf, "%5.1fms\n%5.1fms", ssmsMIN[i]/10.0, ssmsMAX[i]/10.0 ); + CNFGDrawText( stbuf, 2 ); + } + char stt[1024]; +#ifdef WIN32 + snprintf( stt, 1024, "Host: %s\nHistorical max %9.2fms\nBiggest interval%9.2fms\nHistorical packet loss %I64u/%I64u = %6.3f%%", +#else + snprintf( stt, 1024, "Host: %s\nHistorical max %9.2fms\nBiggest interval%9.2fms\nHistorical packet loss %lu/%lu = %6.3f%%", +#endif + pinghost, globmaxtime*1000.0, globinterval*1000.0, globallost, globalrx, globallost*100.0/(globalrx+globallost) ); + if( !in_frame_mode ) + DrawMainText( stt ); + return; + } +nodata: + DrawMainText( "No data.\n" ); + return; +} + + void DrawFrame( void ) { - int i, x, y; + int i; double now = OGGetAbsoluteTime(); - double globmaxtime = GetGlobMaxPingTime(); double totaltime = 0; int totalcountok = 0; @@ -133,6 +380,7 @@ void DrawFrame( void ) double stddev = 0; double last = -1; double loss = 100.00; + double windmaxtime = GetWindMaxPingTime(); for( i = 0; i < screenx; i++ ) { @@ -159,7 +407,7 @@ void DrawFrame( void ) CNFGColor( 0xff ); dt = now - st; dt *= 1000; - totalcountloss++; + if( i > 5 ) totalcountloss++; //Get a freebie on the first 5. } else // no ping sent for this point in time (after startup) { @@ -169,7 +417,7 @@ void DrawFrame( void ) if (!GuiYscaleFactorIsConstant) { - GuiYScaleFactor = (screeny - 50) / globmaxtime; + GuiYScaleFactor = (screeny - 50) / windmaxtime; } int h = dt*GuiYScaleFactor; @@ -213,23 +461,23 @@ void DrawFrame( void ) l = (avg_gui) - (stddev_gui); CNFGTackSegment( 0, screeny-l, screenx, screeny - l ); - char stbuf[1024]; + char stbuf[2048]; char * sptr = &stbuf[0]; - sptr += sprintf( sptr, "Last: %5.2f ms\n", last ); - sptr += sprintf( sptr, "Min : %5.2f ms\n", mintime ); - sptr += sprintf( sptr, "Max : %5.2f ms\n", maxtime ); - sptr += sprintf( sptr, "Avg : %5.2f ms\n", avg ); - sptr += sprintf( sptr, "Std : %5.2f ms\n", stddev ); - sptr += sprintf( sptr, "Loss: %5.1f %%\n", loss ); - CNFGColor( 0x00 ); - for( x = -1; x < 2; x++ ) for( y = -1; y < 2; y++ ) - { - CNFGPenX = 10+x; CNFGPenY = 10+y; - CNFGDrawText( stbuf, 2 ); - } - CNFGColor( 0xffffff ); - CNFGPenX = 10; CNFGPenY = 10; - CNFGDrawText( stbuf, 2 ); + + sptr += sprintf( sptr, + "Last:%6.2f ms Host: %s\n" + "Min :%6.2f ms\n" + "Max :%6.2f ms Historical max: %5.2f ms\n" + "Avg :%6.2f ms Biggest interval: %5.2f ms\n" +#ifdef WIN32 + "Std :%6.2f ms Historical loss: %I64u/%I64u %5.3f%%\n" +#else + "Std :%6.2f ms Historical loss: %lu/%lu %5.3f%%\n" +#endif + "Loss:%6.1f %%", last, pinghost, mintime, maxtime, globmaxtime*1000, avg, globinterval*1000.0, stddev, + globallost, globalrx, globallost*100.0f/(globalrx+globallost), loss ); + + DrawMainText( stbuf ); OGUSleep( 1000 ); } @@ -238,21 +486,11 @@ void DrawFrame( void ) const char * glargv[10]; int glargc = 0; -INT_PTR CALLBACK TextEntry( HWND hwndDlg, - UINT uMsg, - WPARAM wParam, - LPARAM lParam ) +INT_PTR CALLBACK TextEntry( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { -// printf( "%d %d %d\n", uMsg, wParam, lParam ); switch( uMsg ) { - //case IDC_SAVESETS: - // GetDlgItemText(DLG_SETS, IDC_SETS1, stringVariable, sizeof(stringVariable)); -// case 31: -// printf( "Exit\n" ); -// exit( 0 ); -// return 0; case WM_INITDIALOG: SetDlgItemText(hwndDlg, 4, "0.02"); SetDlgItemText(hwndDlg, 5, "0" ); @@ -295,19 +533,11 @@ INT_PTR CALLBACK TextEntry( HWND hwndDlg, } } } - -// printf( "+++%s\n", stringVariable ); -// printf( "Commit %p/%d\n", lParam, id ); EndDialog(hwndDlg, 0); return 0; //User pressed enter. } } - -//case IDC_SAVESETS: http://www.cplusplus.com/forum/beginner/19843/ -//GetDlgItemText(DLG_SETS, IDC_SETS1, stringVariable, sizeof(stringVariable)); - - //printf( "cmd %p %p %p\n", uMsg, wParam, lParam ); - return 0; +/* return 0; case WM_CTLCOLORBTN: //printf( "ctr %p %p %p\n", uMsg, wParam, lParam ); //return 0; @@ -316,25 +546,24 @@ INT_PTR CALLBACK TextEntry( HWND hwndDlg, case 8: case 312: case 15: case 71: case 133: case 307: case 20: case 310: case 33: return 0; +*/ } - //MessageBox( 0, "XXX", "cnping", 0 ); - //printf( "XXX %d %d %d\n", uMsg, wParam, lParam ); return 0; } -int mymain( int argc, const char ** argv ) -#else -int main( int argc, const char ** argv ) #endif +int main( int argc, const char ** argv ) { char title[1024]; - int i, x, y, r; + int i; double ThisTime; double LastFPSTime = OGGetAbsoluteTime(); double LastFrameTime = OGGetAbsoluteTime(); double SecToWait; - int linesegs = 0; -// struct in_addr dst; - struct addrinfo *result; + double frameperiodseconds; + +#ifdef WIN32 + ShowWindow (GetConsoleWindow(), SW_HIDE); +#endif srand( (int)(OGGetAbsoluteTime()*100000) ); @@ -344,92 +573,138 @@ int main( int argc, const char ** argv ) } CNFGBGColor = 0x800000; CNFGDialogColor = 0x444444; - for( i = 0; i < PINGCYCLEWIDTH; i++ ) - { - PingSendTimes[i] = 0; - PingRecvTimes[i] = 0; - } - #ifdef WIN32 if( argc < 2 ) { - int ret = DialogBox(0, "IPDialog", 0, TextEntry ); + DialogBox(0, "IPDialog", 0, TextEntry ); argc = glargc; argv = glargv; } #endif - - if( argc < 2 ) + pingperiodseconds = 0.02; + ExtraPingSize = 0; + title[0] = 0; + GuiYScaleFactor = 0; + + //We need to process all the unmarked parameters. + int argcunmarked = 1; + int displayhelp = 0; + + for( i = 1; i < argc; i++ ) { -#ifdef WIN32 - ERRM( "Need at least a host address to ping.\n" ); -#else - ERRM( "Usage: cnping [host] [period] [extra size] [y-axis scaling]\n" - - " [host] -- domain or IP address of ping target \n" - " [period] -- period in seconds (optional), default 0.02 \n" - " [extra size] -- ping packet extra size (above 12), optional, default = 0 \n" - " [const y-axis scaling] -- use a fixed scaling factor instead of auto scaling (optional)\n"); -#endif - return -1; + const char * thisargv = argv[i]; + if( thisargv[0] == '-' ) + { + int np = ++i; + if( np >= argc ) + { + displayhelp = 1; + break; + } + const char * nextargv = argv[np]; + //Parameter-based field. + switch( thisargv[1] ) + { + case 'h': pinghost = nextargv; break; + case 'p': pingperiodseconds = atof( nextargv ); break; + case 's': ExtraPingSize = atoi( nextargv ); break; + case 'y': GuiYScaleFactor = atof( nextargv ); break; + case 't': sprintf(title, "%s", nextargv); break; + case 'm': in_histogram_mode = 1; break; + default: displayhelp = 1; break; + } + } + else + { + //Unmarked fields + switch( argcunmarked++ ) + { + case 1: pinghost = thisargv; break; + case 2: pingperiodseconds = atof( thisargv ); break; + case 3: ExtraPingSize = atoi( thisargv ); break; + case 4: GuiYScaleFactor = atof( thisargv ); break; + case 5: sprintf(title, "%s", thisargv ); break; + default: displayhelp = 1; + } + } } - - if( argc > 2 ) + if( title[0] == 0 ) { - pingperiod = atof( argv[2] ); - printf( "Extra ping period: %f\n", pingperiod ); + sprintf( title, "%s - cnping", pinghost ); } - else + + if( GuiYScaleFactor > 0 ) { - pingperiod = 0.02; + GuiYscaleFactorIsConstant = 1; } - if( argc > 3 ) + if( !pinghost ) { - ExtraPingSize = atoi( argv[3] ); - printf( "Extra ping size: %d\n", ExtraPingSize ); + displayhelp = 1; } - else + + if( displayhelp ) { - ExtraPingSize = 0; + #ifdef WIN32 + ERRM( "Need at least a host address to ping.\n" ); + #else + ERRM( "Usage: cnping [host] [period] [extra size] [y-axis scaling] [window title]\n" + " (-h) [host] -- domain, IP address of ping target for ICMP or http host, i.e. http://google.com\n" + " (-p) [period] -- period in seconds (optional), default 0.02 \n" + " (-s) [extra size] -- ping packet extra size (above 12), optional, default = 0 \n" + " (-y) [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"); + #endif + return -1; } + + CNFGSetup( title, 320, 155 ); - if( argc > 4 ) + if( memcmp( pinghost, "http://", 7 ) == 0 ) { - GuiYScaleFactor = atof( argv[4] ); - GuiYscaleFactorIsConstant = 1; - printf( "GuiYScaleFactor: %f\n", GuiYScaleFactor ); + StartHTTPing( pinghost+7, pingperiodseconds ); } else { - printf( "GuiYScaleFactor: %s\n", "dynamic" ); + ping_setup(); + OGCreateThread( PingSend, 0 ); + OGCreateThread( PingListen, 0 ); } - pinghost = argv[1]; - sprintf( title, "%s - cnping", pinghost ); - CNFGSetup( title, 320, 155 ); - - ping_setup(); - - OGCreateThread( PingSend, 0 ); - OGCreateThread( PingListen, 0 ); + frameperiodseconds = fmin(.2, fmax(.03, pingperiodseconds)); while(1) { - int i, pos; - float f; iframeno++; - RDPoint pto[3]; - CNFGHandleInput(); CNFGClearFrame(); CNFGColor( 0xFFFFFF ); CNFGGetDimensions( &screenx, &screeny ); - DrawFrame(); + if( in_frame_mode ) + { + DrawFrame(); + } + + if( in_histogram_mode ) + { + DrawFrameHistogram(); + } + + CNFGPenX = 100; CNFGPenY = 100; + CNFGColor( 0xff ); + if( ping_failed_to_send ) + { + CNFGDrawText( "Could not send ping.\nIs target reachable?\nDo you have sock_raw to privileges?", 3 ); + } + else + { + CNFGDrawText( errbuffer, 3 ); + } + frames++; CNFGSwapBuffers(); @@ -438,12 +713,12 @@ int main( int argc, const char ** argv ) if( ThisTime > LastFPSTime + 1 ) { frames = 0; - linesegs = 0; LastFPSTime+=1; } - SecToWait = .030 - ( ThisTime - LastFrameTime ); - LastFrameTime += .030; + SecToWait = frameperiodseconds - ( ThisTime - LastFrameTime ); + LastFrameTime += frameperiodseconds; + //printf("iframeno = %d; SecToWait = %f; pingperiodseconds = %f; frameperiodseconds = %f \n", iframeno, SecToWait, pingperiodseconds, frameperiodseconds); if( SecToWait > 0 ) OGUSleep( (int)( SecToWait * 1000000 ) ); } @@ -451,107 +726,3 @@ int main( int argc, const char ** argv ) return(0); } -#ifdef WIN32 - -//from: http://alter.org.ua/docs/win/args/ - PCHAR* - CommandLineToArgvA( - PCHAR CmdLine, - int* _argc - ) - { - PCHAR* argv; - PCHAR _argv; - ULONG len; - ULONG argc; - CHAR a; - ULONG i, j; - - BOOLEAN in_QM; - BOOLEAN in_TEXT; - BOOLEAN in_SPACE; - - len = strlen(CmdLine); - i = ((len+2)/2)*sizeof(PVOID) + sizeof(PVOID); - - argv = (PCHAR*)GlobalAlloc(GMEM_FIXED, - i + (len+2)*sizeof(CHAR)); - - _argv = (PCHAR)(((PUCHAR)argv)+i); - - argc = 0; - argv[argc] = _argv; - in_QM = FALSE; - in_TEXT = FALSE; - in_SPACE = TRUE; - i = 0; - j = 0; - - while( a = CmdLine[i] ) { - if(in_QM) { - if(a == '\"') { - in_QM = FALSE; - } else { - _argv[j] = a; - j++; - } - } else { - switch(a) { - case '\"': - in_QM = TRUE; - in_TEXT = TRUE; - if(in_SPACE) { - argv[argc] = _argv+j; - argc++; - } - in_SPACE = FALSE; - break; - case ' ': - case '\t': - case '\n': - case '\r': - if(in_TEXT) { - _argv[j] = '\0'; - j++; - } - in_TEXT = FALSE; - in_SPACE = TRUE; - break; - default: - in_TEXT = TRUE; - if(in_SPACE) { - argv[argc] = _argv+j; - argc++; - } - _argv[j] = a; - j++; - in_SPACE = FALSE; - break; - } - } - i++; - } - _argv[j] = '\0'; - argv[argc] = NULL; - - (*_argc) = argc; - return argv; - } - - -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) -{ - int argc; - char cts[8192]; - sprintf( cts, "%s %s", GetCommandLine(), lpCmdLine ); - - ShowWindow (GetConsoleWindow(), SW_HIDE); - char ** argv = CommandLineToArgvA( - cts, - &argc - ); -// MessageBox( 0, argv[1], "X", 0 ); - return mymain( argc-1, (const char**)argv ); -} - -#endif diff --git a/cnping.exe b/cnping.exe Binary files differ. diff --git a/error_handling.h b/error_handling.h @@ -0,0 +1,24 @@ +#ifndef _ERROR_HANDLING +#define _ERROR_HANDLING + +extern char errbuffer[1024]; + +#ifdef WIN32 + +#ifndef _MSC_VER +#define ERRM(x...) { sprintf( errbuffer, x ); MessageBox( 0, errbuffer, "cnping", 0 ); } +#define ERRMB(x...) { sprintf( errbuffer, x ); } +#else +#define ERRM(...) { sprintf( errbuffer, __VA_ARGS__ ); MessageBox( 0, errbuffer, "cnping", 0 ); } +#define ERRMB(...) { sprintf( errbuffer, __VA_ARGS__ ); } +#endif + +#else + +#define ERRM(x...) { fprintf( stderr, x ); } +#define ERRMB(x...) { sprintf( errbuffer, x); fprintf( stderr, x ); } + +#endif + + +#endif diff --git a/httping.c b/httping.c @@ -0,0 +1,232 @@ +#include "httping.h" +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> + +#ifdef WIN32 + #include <winsock2.h> +#else + #include <sys/socket.h> + #include <netinet/in.h> + #include <netdb.h> +#endif + +#include "os_generic.h" +#include "error_handling.h" + +#ifndef MSG_NOSIGNAL + #define MSG_NOSIGNAL 0 +#endif + +#define HTTPTIMEOUT 3.0 + +//Callbacks (when started/received) +void HTTPingCallbackStart( int seqno ); +void HTTPingCallbackGot( int seqno ); + +//Don't dynamically allocate resources here, since execution may be stopped arbitrarily. +void DoHTTPing( const char * addy, double minperiod, int * seqnoptr, volatile double * timeouttime, int * socketptr, volatile int * getting_host_by_name ) +{ + struct sockaddr_in serveraddr; + struct hostent *server; + int httpsock; + int addylen = strlen(addy); + char hostname[addylen+1]; + memcpy( hostname, addy, addylen + 1 ); + char * eportmarker = strchr( hostname, ':' ); + char * eurl = strchr( hostname, '/' ); + + int portno = 80; + + (*seqnoptr) ++; + HTTPingCallbackStart( *seqnoptr ); + + if( eportmarker ) + { + portno = atoi( eportmarker+1 ); + *eportmarker = 0; + } + else + { + if( eurl ) + *eurl = 0; + } + + /* gethostbyname: get the server's DNS entry */ + *getting_host_by_name = 1; + server = gethostbyname(hostname); + *getting_host_by_name = 0; + if (server == NULL) { + ERRMB("ERROR, no such host as %s\n", hostname); + goto fail; + } + + /* build the server's Internet address */ + memset((char *) &serveraddr, 0, sizeof(serveraddr)); + serveraddr.sin_family = AF_INET; + memcpy((char *)&serveraddr.sin_addr.s_addr, (char *)server->h_addr, server->h_length); + serveraddr.sin_port = htons(portno); + +reconnect: + *socketptr = httpsock = socket(AF_INET, SOCK_STREAM, 0); + if (httpsock < 0) + { + ERRMB( "Error opening socket\n" ); + return; + } + + /* connect: create a connection with the server */ + if (connect(httpsock, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0) + { + ERRMB( "%s: ERROR connecting\n", hostname ); + goto fail; + } + +#ifdef __APPLE__ + int opt = 1; + setsockopt(httpsock, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); +#endif + + errbuffer[0] = 0; + + while( 1 ) + { + char buf[8192]; + + int n = sprintf( buf, "HEAD %s HTTP/1.1\r\nConnection: keep-alive\r\n\r\n", eurl?eurl:"/favicon.ico" ); + int rs = send( httpsock, buf, n, MSG_NOSIGNAL ); + double starttime = *timeouttime = OGGetAbsoluteTime(); + int breakout = 0; + if( rs != n ) breakout = 1; + int endstate = 0; + while( !breakout ) + { +#ifdef WIN32 + n = recv( httpsock, buf, sizeof(buf)-1, 0); +#else + n = recv( httpsock, buf, sizeof(buf)-1, MSG_PEEK); + if( n > 0 ) n = read( httpsock, buf, sizeof(buf)-1); + else if( n == 0 ) break; //FIN received +#endif + + + if( n < 0 ) return; + + int i; + for( i = 0; i < n; i++ ) + { + char c = buf[i]; + switch( endstate ) + { + case 0: if( c == '\r' ) endstate++; break; + case 1: if( c == '\n' ) endstate++; else endstate = 0; break; + case 2: if( c == '\r' ) endstate++; else endstate = 0; break; + case 3: if( c == '\n' && i == n-1) breakout = 1; else endstate = 0; break; + } + } + } + *timeouttime = OGGetAbsoluteTime(); + + HTTPingCallbackGot( *seqnoptr ); + + double delay_time = minperiod - (*timeouttime - starttime); + if( delay_time > 0 ) + usleep( (int)(delay_time * 1000000) ); + (*seqnoptr) ++; + HTTPingCallbackStart( *seqnoptr ); + if( !breakout ) { +#ifdef WIN32 + closesocket( httpsock ); +#else + close( httpsock ); +#endif + goto reconnect; + } + } +fail: + return; +} + + +struct HTTPPingLaunch +{ + const char * addy; + double minperiod; + + volatile double timeout_time; + volatile int failed; + int seqno; + int socket; + volatile int getting_host_by_name; +}; + +static void * DeployPing( void * v ) +{ + struct HTTPPingLaunch *hpl = (struct HTTPPingLaunch*)v; + hpl->socket = 0; + hpl->getting_host_by_name = 0; + DoHTTPing( hpl->addy, hpl->minperiod, &hpl->seqno, &hpl->timeout_time, &hpl->socket, &hpl->getting_host_by_name ); + hpl->failed = 1; + return 0; +} + + +static void * PingRunner( void * v ) +{ + struct HTTPPingLaunch *hpl = (struct HTTPPingLaunch*)v; + hpl->seqno = 0; + while( 1 ) + { + hpl->timeout_time = OGGetAbsoluteTime(); + og_thread_t thd = OGCreateThread( DeployPing, hpl ); + while( 1 ) + { + double Now = OGGetAbsoluteTime(); + double usl = hpl->timeout_time - Now + HTTPTIMEOUT; + if( usl > 0 ) usleep( (int)(usl*1000000 + 1000)); + else usleep( 10000 ); + + if( 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. + { + if( hpl->socket ) + { +#ifdef WIN32 + closesocket( hpl->socket ); +#else + close( hpl->socket ); +#endif + } + + OGCancelThread( thd ); + break; + } + } + } + return 0; +} + +int StartHTTPing( const char * addy, double minperiod ) +{ + +#ifdef WIN32 + WSADATA wsaData; + int r = WSAStartup(MAKEWORD(2,2), &wsaData); + if( r ) + { + ERRM( "Fault in WSAStartup\n" ); + exit( -2 ); + } +#endif + + struct HTTPPingLaunch *hpl = malloc( sizeof( struct HTTPPingLaunch ) ); + hpl->addy = addy; + hpl->minperiod = minperiod; + OGCreateThread( PingRunner, hpl ); + return 0; +} + + + diff --git a/httping.h b/httping.h @@ -0,0 +1,12 @@ +#ifndef _HTTPING_H +#define _HTTPING_H + +//Callbacks (when started/received) +void HTTPingCallbackStart( int seqno ); +void HTTPingCallbackGot( int seqno ); + +//addy should be google.com/blah or something like that. Do not include prefixing http://. Port numbers OK. +int StartHTTPing( const char * addy, double minperiod ); + +#endif + diff --git a/os_generic.c b/os_generic.c @@ -1,6 +1,5 @@ #include "os_generic.h" - #ifdef USE_WINDOWS #include <windows.h> @@ -56,6 +55,7 @@ void * OGJoinThread( og_thread_t ot ) { WaitForSingleObject( ot, INFINITE ); CloseHandle( ot ); + return 0; } void OGCancelThread( og_thread_t ot ) diff --git a/os_generic.h b/os_generic.h @@ -1,7 +1,7 @@ #ifndef _OS_GENERIC_H #define _OS_GENERIC_H -#ifdef WIN32 +#if defined( WIN32 ) || defined (WINDOWS) || defined( _WIN32) #define USE_WINDOWS #endif @@ -25,7 +25,7 @@ og_thread_t OGCreateThread( void * (routine)( void * ), void * parameter ); void * OGJoinThread( og_thread_t ot ); void OGCancelThread( og_thread_t ot ); -//Always a recrusive mutex. +//Always a recursive mutex. og_mutex_t OGCreateMutex(); void OGLockMutex( og_mutex_t om ); void OGUnlockMutex( og_mutex_t om ); diff --git a/ping.c b/ping.c @@ -1,155 +1,122 @@ -/* myping.c - * - * Copyright (c) 2000 Sean Walton and Macmillan Publishers. Use may be in - * whole or in part in accordance to the General Public License (GPL). - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. -*/ - -/*****************************************************************************/ -/*** ping.c ***/ -/*** ***/ -/*** Use the ICMP protocol to request "echo" from destination. ***/ -/*****************************************************************************/ +//Copyright 2017 <>< C. Lohr, under the MIT/x11 License +//Rewritten from Sean Walton and Macmillan Publishers. +//Most of it was rewritten but the header was never updated. +//Now I finished the job. #include <string.h> #include <fcntl.h> #include <errno.h> +#include <stdio.h> +#include <stdlib.h> #include "ping.h" #include "os_generic.h" -#ifdef WIN32 -#include <winsock2.h> -#define SOL_IP 0 -#define F_SETFL 4 -#define ICMP_ECHO 8 -#define IP_TTL 2 -# define O_NONBLOCK 04000 - -#ifndef _MSC_VER -void bzero(void *location,__LONG32 count); -#else -#pragma comment(lib, "Ws2_32.lib") -void bzero(void * loc, int len) -{ - memset(loc, 0, len); -} -#endif -void usleep(int x) { - Sleep(x / 1000); -} -#include <windows.h> -#include <stdio.h> -#include <winsock2.h> -#include <ws2tcpip.h> -#include <stdint.h> +#include "error_handling.h" + +#ifdef WIN32 + #include <winsock2.h> + #define SOL_IP 0 + #define F_SETFL 4 + #define ICMP_ECHO 8 + #define IP_TTL 2 + #define O_NONBLOCK 04000 + #pragma comment(lib, "Ws2_32.lib") + #include <windows.h> + #include <winsock2.h> + #include <ws2tcpip.h> + #include <stdint.h> #else -#include <unistd.h> -#include <sys/socket.h> -#include <resolv.h> -#include <netdb.h> -#ifdef __APPLE__ -#ifndef SOL_IP -#define SOL_IP IPPROTO_IP + #include <unistd.h> + #include <sys/socket.h> + #include <resolv.h> + #include <netdb.h> + #ifdef __APPLE__ + #ifndef SOL_IP + #define SOL_IP IPPROTO_IP + #endif + #endif + #include <netinet/ip.h> + #include <netinet/ip_icmp.h> #endif -#endif -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#endif -#include <stdlib.h> #if defined WIN32 || defined __APPLE__ -struct icmphdr { - uint8_t type; - uint8_t code; - uint16_t checksum; - union { - struct { - uint16_t id; - uint16_t sequence; - } echo; - uint32_t gateway; - struct { - uint16_t __unused; - uint16_t mtu; - } frag; - } un; +struct icmphdr +{ + uint8_t type; + uint8_t code; + uint16_t checksum; + union + { + struct + { + uint16_t id; + uint16_t sequence; + } echo; + uint32_t gateway; + struct + { + uint16_t __unused; + uint16_t mtu; + } frag; + } un; }; #endif -float pingperiod; +float pingperiodseconds; int precise_ping; -#define PACKETSIZE 1500 +#define PACKETSIZE 65536 + struct packet { struct icmphdr hdr; - char msg[PACKETSIZE-sizeof(struct icmphdr)]; + unsigned char msg[PACKETSIZE-sizeof(struct icmphdr)]; }; int sd; int pid=-1; -struct protoent *proto=NULL; +int ping_failed_to_send; struct sockaddr_in psaddr; -/*--------------------------------------------------------------------*/ -/*--- checksum - standard 1s complement checksum ---*/ -/*--------------------------------------------------------------------*/ -unsigned short checksum(void *b, int len) -{ unsigned short *buf = b; - unsigned int sum=0; - unsigned short result; - - for ( sum = 0; len > 1; len -= 2 ) - sum += *buf++; - if ( len == 1 ) - sum += *(unsigned char*)buf; - sum = (sum >> 16) + (sum & 0xFFFF); - sum += (sum >> 16); - result = ~sum; - return result; +uint16_t checksum( const unsigned char * start, uint16_t len ) +{ + uint16_t i; + const uint16_t * wptr = (uint16_t*) start; + uint32_t csum = 0; + for (i=1;i<len;i+=2) + csum += (uint32_t)(*(wptr++)); + if( len & 1 ) //See if there's an odd number of bytes? + csum += *(uint8_t*)wptr; + if (csum>>16) + csum = (csum & 0xFFFF)+(csum >> 16); + //csum = (csum>>8) | ((csum&0xff)<<8); + return ~csum; } - -/*--------------------------------------------------------------------*/ -/*--- listener - separate process to listen for and collect messages--*/ -/*--------------------------------------------------------------------*/ -void listener(void) +void listener() { #ifndef WIN32 const int val=255; - int sd = socket(PF_INET, SOCK_RAW, proto->p_proto); + int sd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); if ( setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0) { - ERRM("Erro: could not set TTL option\n"); + ERRM("Error: could not set TTL option - did you forget to run as root or sticky bit cnping?\n"); exit( -1 ); } - #endif struct sockaddr_in addr; - unsigned char buf[8192]; + unsigned char buf[66000]; #ifdef WIN32 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); #endif for (;;) { - int i; - int bytes, len=sizeof(addr); + socklen_t addrlenval=sizeof(addr); + int bytes; - bzero(buf, sizeof(buf)); #ifdef WIN32 WSAPOLLFD fda[1]; fda[0].fd = sd; @@ -157,8 +124,9 @@ void listener(void) WSAPoll(fda, 1, 10); #endif keep_retry_quick: - bytes = recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr*)&addr, &len); - if (bytes == -1) continue; + + bytes = recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr*)&addr, &addrlenval ); + if( bytes == -1 ) continue; if( buf[20] != 0 ) continue; //Make sure ping response. if( buf[9] != 1 ) continue; //ICMP if( addr.sin_addr.s_addr != psaddr.sin_addr.s_addr ) continue; @@ -166,35 +134,25 @@ void listener(void) if ( bytes > 0 ) display(buf + 28, bytes - 28 ); else - perror("recvfrom"); + { + ERRM("Error: recvfrom failed"); + } goto keep_retry_quick; } - printf( "Fault on listen.\n" ); - exit(0); + ERRM( "Fault on listen.\n" ); + exit( 0 ); } -/*--------------------------------------------------------------------*/ -/*--- ping - Create message and send it. ---*/ -/*--------------------------------------------------------------------*/ void ping(struct sockaddr_in *addr ) { + int cnt=1; #ifdef WIN32 - const char val=255; -#else - const int val=255; -#endif - int i, cnt=1; - struct packet pckt; - struct sockaddr_in r_addr; -#ifdef WIN32 { - //this /was/ recommended. + //Setup windows socket for nonblocking io. unsigned long iMode = 1; ioctlsocket(sd, FIONBIO, &iMode); - - } #else if ( fcntl(sd, F_SETFL, O_NONBLOCK) != 0 ) @@ -203,24 +161,28 @@ void ping(struct sockaddr_in *addr ) double stime = OGGetAbsoluteTime(); + struct packet pckt; do - { int len=sizeof(r_addr); + { + int rsize = load_ping_packet( pckt.msg, sizeof( pckt.msg ) ); + memset( &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. -// printf("Msg #%d\n", cnt); -// if ( recvfrom(sd, &pckt, sizeof(pckt), 0, (struct sockaddr*)&r_addr, &len) > 0 ) - { - //printf("***Got message!***\n"); - } - bzero(&pckt, sizeof(pckt)); + pckt.hdr.code = 0; pckt.hdr.type = ICMP_ECHO; pckt.hdr.un.echo.id = pid; - int rsize = load_ping_packet( pckt.msg, sizeof( pckt.msg ) ); pckt.hdr.un.echo.sequence = cnt++; - pckt.hdr.checksum = checksum(&pckt, sizeof(pckt) - sizeof( pckt.msg ) + rsize ); + pckt.hdr.checksum = checksum((const unsigned char *)&pckt, sizeof( pckt.hdr ) + rsize ); - if ( sendto(sd, (char*)&pckt, sizeof(pckt) - sizeof( pckt.msg ) + rsize , 0, (struct sockaddr*)addr, sizeof(*addr)) <= 0 ) - perror("sendto"); + int sr = sendto(sd, (char*)&pckt, sizeof( pckt.hdr ) + rsize , 0, (struct sockaddr*)addr, sizeof(*addr)); + if( sr <= 0 ) + { + ping_failed_to_send = 1; + } + else + { + ping_failed_to_send = 0; + } if( precise_ping ) { @@ -228,32 +190,27 @@ void ping(struct sockaddr_in *addr ) do { ctime = OGGetAbsoluteTime(); - if( pingperiod >= 1000 ) stime = ctime; - } while( ctime < stime + pingperiod ); - stime += pingperiod; + if( pingperiodseconds >= 1000 ) stime = ctime; + } while( ctime < stime + pingperiodseconds ); + stime += pingperiodseconds; } else { - if( pingperiod > 0 ) + if( pingperiodseconds > 0 ) { - uint32_t dlw = 1000000.0*pingperiod; - usleep( dlw ); + uint32_t dlw = 1000000.0*pingperiodseconds; + OGUSleep( dlw ); } } - } while( pingperiod >= 0 ); + } while( pingperiodseconds >= 0 ); //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. } void ping_setup() { pid = getpid(); - proto = getprotobyname("ICMP"); #ifdef WIN32 -/* - WSADATA wsaData; - int r = WSAStartup(0x0202, &wsaData ); -*/ WSADATA wsaData; int r = WSAStartup(MAKEWORD(2,2), &wsaData); if( r ) @@ -268,19 +225,19 @@ void ping_setup() sd = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, 0, 0, WSA_FLAG_OVERLAPPED); { int lttl = 0xff; - if (setsockopt(sd, IPPROTO_IP, IP_TTL, (const char*)&lttl, - sizeof(lttl)) == SOCKET_ERROR) { + if (setsockopt(sd, IPPROTO_IP, IP_TTL, (const char*)&lttl, sizeof(lttl)) == SOCKET_ERROR) + { printf( "Warning: No IP_TTL.\n" ); } } #else const int val=255; - sd = socket(PF_INET, SOCK_RAW, proto->p_proto); + sd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); if ( setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0) { - ERRM("Error: Failed to set TTL option\n"); + ERRM("Error: Failed to set TTL option. Are you root? Or can do sock_raw sockets?\n"); exit( -1 ); } @@ -298,7 +255,7 @@ void do_pinger( const char * strhost ) struct hostent *hname; hname = gethostbyname(strhost); - bzero(&psaddr, sizeof(psaddr)); + memset(&psaddr, 0, sizeof(psaddr)); psaddr.sin_family = hname->h_addrtype; psaddr.sin_port = 0; psaddr.sin_addr.s_addr = *(long*)hname->h_addr; diff --git a/ping.h b/ping.h @@ -5,7 +5,7 @@ struct sockaddr_in; -unsigned short checksum(void *b, int len); +unsigned short checksum(const unsigned char *b, uint16_t len); //Callback (when received) void display(uint8_t *buf, int bytes); @@ -14,26 +14,16 @@ void display(uint8_t *buf, int bytes); //return value = # of bytes to send in ping message. int load_ping_packet( uint8_t * buffer, int buffersize ); -void listener(void); +void listener(); void ping(struct sockaddr_in *addr ); void do_pinger( const char * strhost ); -//If pingperiod = -1, run ping/do_pinger once and exit. -extern float pingperiod; +//If pingperiodseconds = -1, run ping/do_pinger once and exit. +extern float pingperiodseconds; extern 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. - +extern int ping_failed_to_send; void ping_setup(); -#ifdef WIN32 - -extern char errbuffer[1024]; -#define ERRM(x...) { sprintf( errbuffer, x ); MessageBox( 0, errbuffer, "cnping", 0 ); } - -#else - -#define ERRM(x...) fprintf( stderr, x ); - -#endif #endif diff --git a/resources.rc b/resources.rc @@ -8,7 +8,7 @@ STYLE WS_CAPTION | WS_SYSMENU CAPTION "cnping" BEGIN LTEXT "Usage: cnping [host] [period] [extra size] [y-axis scaling]", 0, 60, 0, 300, 20, SS_LEFT - LTEXT "[host] -- domain or IP address of ping target", 0, 60, 15, 300, 20, SS_LEFT + LTEXT "[host] -- domain or IP address of icmp ping, or http://host", 0, 60, 15, 300, 20, SS_LEFT LTEXT "[period] -- period in seconds (optional), default is 0.02", 0, 60, 30, 300, 20, SS_LEFT LTEXT "[extra size] -- ping packet extra size (above 12), optional, default = 0", 0, 60, 45, 300, 10, SS_LEFT LTEXT "[const y-axis scaling] -- use a fixed scaling factor instead of auto scaling", 0, 60, 60, 300, 10, SS_LEFT diff --git a/searchnet.c b/searchnet.c @@ -19,17 +19,8 @@ void * PingListen( void * r ) void display(uint8_t *buf, int bytes) { - int i; uint32_t reqid = ((uint32_t)buf[0+1] << 24) | (buf[1+1]<<16) | (buf[2+1]<<8) | (buf[3+1]); -/* for( i = 0; i < bytes; i++ ) - { - printf( "%02x ", buf[i] ); - } - printf( "\n" ); - printf( "REQ: %08x %08x\n", reqid, my_random_key ); -/// printf( "%d.%d.%d.%d\n", buf[4], buf[5], buf[6], buf[7] ); -*/ if( reqid != my_random_key ) return; printf( "%d.%d.%d.%d\n", buf[4+1], buf[5+1], buf[6+1], buf[7+1] ); @@ -85,7 +76,7 @@ int main( int argc, char ** argv ) send_id[2] = (cur>>8)&0xff; send_id[3] = (cur)&0xff; // printf( "Pinging: %s\n", dispip ); - pingperiod = -1; + pingperiodseconds = -1; do_pinger( dispip ); OGUSleep( (int)(speed * 1000000) );