cnping.c (19047B)
1//Copyright (c) 2011-2019 <>< Charles Lohr - Under the MIT/x11 or NewBSD License you choose. 2 3#include <stdio.h> 4#include <stdlib.h> 5#include <math.h> 6#include <errno.h> 7#include <string.h> 8#if defined( WINDOWS ) || defined( WIN32 ) 9#ifdef _MSC_VER 10#define strdup _strdup 11#endif 12#include <windows.h> 13#else 14 #ifdef __FreeBSD__ 15 #include <sys/types.h> 16 #include <netinet/in.h> 17 #endif 18#include <sys/socket.h> 19#include <netinet/ip.h> 20#include <netinet/ip_icmp.h> 21#include <arpa/inet.h> 22#include <sys/select.h> 23#include <netdb.h> 24#endif 25 26#ifndef CNFGOGL 27#define CNFGOGL 28#endif 29 30#define CNFG_IMPLEMENTATION 31#include "rawdraw/os_generic.h" 32#include "rawdraw/CNFG.h" 33#include "ping.h" 34#include "error_handling.h" 35#include "httping.h" 36 37// #### Cross-plattform debugging #### 38// Windows does not print to Console, use DebugView from SysInternals to 39// see the output. (Setup: Computer -> Connect Local; Capture -> Capture Win32) 40// Warning: Debugging on Windows can slow cnping down and lead to wrong measurements! 41//#define DEBUG 42#ifdef DEBUG 43 char msgbuf[1024]; 44 #ifdef WIN32 45 #define debug(...) \ 46 snprintf(msgbuf, sizeof(msgbuf), __VA_ARGS__); \ 47 OutputDebugString(msgbuf); 48 #else 49 #define debug(...) printf(__VA_ARGS__); 50 #endif 51#else 52 // Let the compiler parse it to catch errors. Compiler will optimize away. 53 #define debug(...) \ 54 do { if (0) fprintf(stderr, __VA_ARGS__); } while (0); 55#endif 56 57unsigned frames = 0; 58unsigned long iframeno = 0; 59short screenx, screeny; 60const char * pinghost; 61float GuiYScaleFactor; 62int GuiYscaleFactorIsConstant; 63double globmaxtime, globmintime = 1e20; 64double globinterval, globlast; 65uint64_t globalrx; 66uint64_t globallost; 67// Ping Data. Will be overwritten with random bytes when !DEBUG 68uint8_t pattern[8] = {0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF}; 69 70#define PINGCYCLEWIDTH 8192 71#define TIMEOUT 4 72 73double PingSendTimes[PINGCYCLEWIDTH]; 74double PingRecvTimes[PINGCYCLEWIDTH]; 75int current_cycle = 0; 76 77int ExtraPingSize; 78int in_histogram_mode, in_frame_mode = 1; 79void HandleGotPacket( int seqno, int timeout ); 80 81#if defined( WINDOWS ) || defined( WIN32 ) 82WSADATA wsaData; 83#endif 84 85 86#define MAX_HISTO_MARKS (TIMEOUT*10000) 87uint64_t hist_counts[MAX_HISTO_MARKS]; 88 89void HandleNewPacket( int seqno ) 90{ 91 double Now = OGGetAbsoluteTime(); 92 PingSendTimes[seqno] = Now; 93 PingRecvTimes[seqno] = 0; 94 static int timeoutmark; 95 96 while( Now - PingSendTimes[timeoutmark] > TIMEOUT ) 97 { 98 if( PingRecvTimes[timeoutmark] < PingSendTimes[timeoutmark] ) 99 { 100 HandleGotPacket( timeoutmark, 1 ); 101 } 102 timeoutmark++; 103 if( timeoutmark >= PINGCYCLEWIDTH ) timeoutmark = 0; 104 } 105} 106 107void HandleGotPacket( int seqno, int timeout ) 108{ 109 double Now = OGGetAbsoluteTime(); 110 111 if( timeout ) 112 { 113 if( PingRecvTimes[seqno] < -0.5 ) return; 114 115 globallost++; 116 PingRecvTimes[seqno] = -1; 117 hist_counts[MAX_HISTO_MARKS-1]++; 118 return; 119 } 120 121 if( PingRecvTimes[seqno] >= PingSendTimes[seqno] ) return; 122 if( PingSendTimes[seqno] < 1 ) return; 123 if( Now - PingSendTimes[seqno] > TIMEOUT ) return; 124 125 PingRecvTimes[seqno] = OGGetAbsoluteTime(); 126 double Delta = PingRecvTimes[seqno] - PingSendTimes[seqno]; 127 if( Delta > globmaxtime ) { globmaxtime = Delta; } 128 if( Delta < globmintime ) { globmintime = Delta; } 129 int slot = Delta * 10000; 130 if( slot >= MAX_HISTO_MARKS ) slot = MAX_HISTO_MARKS-1; 131 if( slot < 0 ) slot = 0; 132 hist_counts[slot]++; 133 134 if( globlast > 0.5 ) 135 { 136 if( Now - globlast > globinterval ) globinterval = Now - globlast; 137 } 138 globlast = Now; 139 globalrx++; 140} 141 142 143void HTTPingCallbackStart( int seqno ) 144{ 145 current_cycle = seqno; 146 HandleNewPacket( seqno ); 147} 148 149void HTTPingCallbackGot( int seqno ) 150{ 151 HandleGotPacket( seqno, 0 ); 152} 153 154void display(uint8_t *buf, int bytes) 155{ 156 int reqid = (buf[0] << 24) | (buf[1]<<16) | (buf[2]<<8) | (buf[3]); 157 debug("Received ping: reqid=%d\n", reqid); 158 reqid &= (PINGCYCLEWIDTH-1); 159 if( memcmp( buf+4, pattern, sizeof(pattern) ) != 0 ) return; 160 debug("Memcmp OK, checked %ld bytes, first values being %x %x %x %x\n", 161 (long int) sizeof(pattern), pattern[0], pattern[1], pattern[2], pattern[3]) 162 HandleGotPacket( reqid, 0 ); 163} 164 165int load_ping_packet( uint8_t * buffer, int bufflen ) 166{ 167 buffer[0] = current_cycle >> 24; 168 buffer[1] = current_cycle >> 16; 169 buffer[2] = current_cycle >> 8; 170 buffer[3] = current_cycle >> 0; 171 172 memcpy( buffer+4, pattern, sizeof(pattern) ); 173 174 if( ping_failed_to_send ) 175 { 176 PingSendTimes[(current_cycle+PINGCYCLEWIDTH-1)&(PINGCYCLEWIDTH-1)] = 0; //Unset ping send. 177 } 178 179 HandleNewPacket( current_cycle&(PINGCYCLEWIDTH-1) ); 180 181 current_cycle++; 182 183 return 12 + ExtraPingSize; 184} 185 186void * PingListen( void * r ) 187{ 188 listener(); 189 ERRM( "Fault on listen.\n" ); 190 exit( -2 ); 191} 192 193void * PingSend( void * r ) 194{ 195 do_pinger( ); 196 ERRM( "Fault on ping.\n" ); 197 exit( -1 ); 198} 199 200 201 202 203void HandleKey( int keycode, int bDown ) 204{ 205 switch( keycode ) 206 { 207 208#if defined( WIN32 ) || defined( WINDOWS ) 209 case 'r': 210 { 211 char lpFilename[1024]; 212 char lpDirectory[1024]; 213 GetCurrentDirectory( 1023, lpDirectory ); 214 GetModuleFileNameA( GetModuleHandle(0), lpFilename, 1023 ); 215 216 CreateProcessA( lpFilename, GetCommandLine(), 0, 0, 1, 0, 0, lpDirectory, 0, 0 ); 217 exit( 0 ); 218 break; 219 } 220#endif 221 case 'f': 222 if( bDown ) in_frame_mode = !in_frame_mode; 223 if( !in_frame_mode ) in_histogram_mode = 1; 224 break; 225 case 'm': 226 if( bDown ) in_histogram_mode = !in_histogram_mode; 227 if( !in_histogram_mode ) in_frame_mode = 1; 228 break; 229 case 'c': 230 memset( hist_counts, 0, sizeof( hist_counts ) ); 231 globmaxtime = 0; 232 globmintime = 1e20; 233 globinterval = 0; 234 globlast = 0; 235 globalrx = 0; 236 globallost = 0; 237 break; 238 case 'q': 239 exit(0); 240 break; 241 242 } 243} 244void HandleButton( int x, int y, int button, int bDown ){} 245void HandleMotion( int x, int y, int mask ){} 246void HandleDestroy() { exit(0); } 247 248 249double GetWindMaxPingTime( void ) 250{ 251 int i; 252 double maxtime = 0; 253 254 for( i = 0; i < screenx; i++ ) 255 { 256 int index = ((current_cycle - i - 1) + PINGCYCLEWIDTH) & (PINGCYCLEWIDTH-1); 257 double st = PingSendTimes[index]; 258 double rt = PingRecvTimes[index]; 259 260 double dt = 0; 261 262 if( rt > st ) 263 { 264 dt = rt - st; 265 dt *= 1000; 266 if( dt > maxtime ) maxtime = dt; 267 } 268 } 269 270 return maxtime; 271} 272 273void DrawMainText( const char * stbuf ) 274{ 275 int x, y; 276 CNFGColor( 0x000000ff ); 277 for( x = -1; x < 2; x++ ) for( y = -1; y < 2; y++ ) 278 { 279 CNFGPenX = 10+x; CNFGPenY = 10+y; 280 CNFGDrawText( stbuf, 2 ); 281 } 282 CNFGColor( 0xffffffff ); 283 CNFGPenX = 10; CNFGPenY = 10; 284 CNFGDrawText( stbuf, 2 ); 285} 286 287void DrawFrameHistogram() 288{ 289 int i; 290// double Now = OGGetAbsoluteTime(); 291 const int colwid = 50; 292 int categories = (screenx-50)/colwid; 293 int maxpingslot = ( globmaxtime*10000.0 ); 294 int minpingslot = ( globmintime*10000.0 ); 295 int slots = maxpingslot-minpingslot; 296 297 if( categories <= 2 ) 298 { 299 goto nodata; 300 } 301 else 302 { 303 int skips = ( (slots)/categories ) + 1; 304 int slotsmax = maxpingslot / skips + 1; 305 int slotsmin = minpingslot / skips; 306 slots = slotsmax - slotsmin; 307 if( slots <= 0 ) goto nodata; 308 309 uint64_t samples[slots+2]; 310 int ssmsMIN[slots+2]; 311 int ssmsMAX[slots+2]; 312 int samp = minpingslot - 1; 313 314 if( slots <= 1 ) goto nodata; 315 316 memset( samples, 0, sizeof( samples ) ); 317 if( samp < 0 ) samp = 0; 318 319 uint64_t highestchart = 0; 320 int tslot = 0; 321 for( i = slotsmin; i <= slotsmax; i++ ) 322 { 323 int j; 324 uint64_t total = 0; 325 ssmsMIN[tslot] = samp; 326 for( j = 0; j < skips; j++ ) 327 { 328 total += hist_counts[samp++]; 329 } 330 331 ssmsMAX[tslot] = samp; 332 if( total > highestchart ) highestchart = total; 333 samples[tslot++] = total; 334 } 335 336 if( highestchart <= 0 ) 337 { 338 goto nodata; 339 } 340 341 int rslots = 0; 342 for( i = 0; i < slots+1; i++ ) 343 { 344 if( samples[i] ) rslots = i; 345 } 346 rslots++; 347 348 for( i = 0; i < rslots; i++ ) 349 { 350 CNFGColor( 0x33cc33ff ); 351 int top = 30; 352 uint64_t samps = samples[i]; 353 int bottom = screeny - 50; 354 int height = samps?(samps * (bottom-top) / highestchart + 1):0; 355 int startx = (i+1) * (screenx-50) / rslots; 356 int endx = (i+2) * (screenx-50) / rslots; 357 358 if( !in_frame_mode ) 359 { 360 CNFGTackRectangle( startx, bottom-height, endx, bottom + 1 ); 361 CNFGColor( 0x000000ff ); 362 } 363 else 364 { 365 CNFGColor( 0x8080ffff ); 366 } 367 CNFGTackSegment( startx, bottom+1, endx, bottom+1 ); 368 369 CNFGTackSegment( startx, bottom-height, startx, bottom+1 ); 370 CNFGTackSegment( endx, bottom-height, endx, bottom+1 ); 371 372 CNFGTackSegment( startx, bottom-height, endx, bottom-height ); 373 char stbuf[1024]; 374 int log10 = 1; 375 int64_t ll = samps; 376 while( ll >= 10 ) 377 { 378 ll /= 10; 379 log10++; 380 } 381 382 if( !in_frame_mode ) 383 { 384 CNFGColor( 0xffffffff ); 385 } 386 else 387 { 388 CNFGColor( 0x8080ffff ); 389 } 390 391 392 CNFGPenX = startx + (8-log10) * 4; CNFGPenY = bottom+3; 393#ifdef WIN32 394 sprintf( stbuf, "%I64u", samps ); 395#else 396 sprintf( stbuf, "%lu", samps ); 397#endif 398 CNFGDrawText( stbuf, 2 ); 399 400 CNFGPenX = startx; CNFGPenY = bottom+14; 401 sprintf( stbuf, "%5.1fms\n%5.1fms", ssmsMIN[i]/10.0, ssmsMAX[i]/10.0 ); 402 CNFGDrawText( stbuf, 2 ); 403 } 404 char stt[1024]; 405#ifdef WIN32 406 snprintf( stt, 1024, "Host: %s\nHistorical max %9.2fms\nBiggest interval%9.2fms\nHistorical packet loss %I64u/%I64u = %6.3f%%", 407#else 408 snprintf( stt, 1024, "Host: %s\nHistorical max %9.2fms\nBiggest interval%9.2fms\nHistorical packet loss %lu/%lu = %6.3f%%", 409#endif 410 pinghost, globmaxtime*1000.0, globinterval*1000.0, globallost, globalrx, globallost*100.0/(globalrx+globallost) ); 411 if( !in_frame_mode ) 412 DrawMainText( stt ); 413 return; 414 } 415nodata: 416 DrawMainText( "No data.\n" ); 417 return; 418} 419 420 421void DrawFrame( void ) 422{ 423 int i; 424 425 double now = OGGetAbsoluteTime(); 426 427 double totaltime = 0; 428 int totalcountok = 0; 429 int totalcountloss = 0; 430 double mintime = 10000; 431 double maxtime = 0; 432 double stddev = 0; 433 double last = -1; 434 double loss = 100.00; 435 double windmaxtime = GetWindMaxPingTime(); 436 437 for( i = 0; i < screenx; i++ ) 438 { 439 int index = ((current_cycle - i - 1) + PINGCYCLEWIDTH) & (PINGCYCLEWIDTH-1); 440 double st = PingSendTimes[index]; 441 double rt = PingRecvTimes[index]; 442 443 double dt = 0; 444 445 if( rt > st ) // ping received 446 { 447 CNFGColor( 0xffffffff ); 448 dt = rt - st; 449 dt *= 1000; 450 totaltime += dt; 451 if( dt < mintime ) mintime = dt; 452 if( dt > maxtime ) maxtime = dt; 453 totalcountok++; 454 if( last < 0) 455 last = dt; 456 } 457 else if (st != 0) // ping sent but not received 458 { 459 CNFGColor( 0xff0000ff ); 460 dt = now - st; 461 dt *= 1000; 462 if( i > 5 ) totalcountloss++; //Get a freebie on the first 5. 463 } 464 else // no ping sent for this point in time (after startup) 465 { 466 CNFGColor( 0x000000ff ); 467 dt = 99 * 1000; // assume 99s to fill screen black 468 } 469 470 if (!GuiYscaleFactorIsConstant) 471 { 472 GuiYScaleFactor = (screeny - 50) / windmaxtime; 473 } 474 475 int h = dt*GuiYScaleFactor; 476 int top = screeny - h; 477 if( top < 0 ) top = 0; 478 CNFGTackSegment( i, screeny-1, i, top ); 479 } 480 481 double avg = totaltime / totalcountok; 482 loss = (double) totalcountloss / (totalcountok + totalcountloss) * 100; 483 484 for( i = 0; i < screenx; i++ ) 485 { 486 int index = ((current_cycle - i - 1) + PINGCYCLEWIDTH) & (PINGCYCLEWIDTH-1); 487 double st = PingSendTimes[index]; 488 double rt = PingRecvTimes[index]; 489 490 double dt = 0; 491 if( rt > st ) 492 { 493 dt = rt - st; 494 dt *= 1000; 495 stddev += (dt-avg)*(dt-avg); 496 } 497 } 498 499 stddev /= totalcountok; 500 501 stddev = sqrt(stddev); 502 503 int avg_gui = avg*GuiYScaleFactor; 504 int stddev_gui = stddev*GuiYScaleFactor; 505 506 CNFGColor( 0x00ff00ff ); 507 508 509 int l = avg_gui; 510 CNFGTackSegment( 0, screeny-l, screenx, screeny - l ); 511 l = (avg_gui) + (stddev_gui); 512 CNFGTackSegment( 0, screeny-l, screenx, screeny - l ); 513 l = (avg_gui) - (stddev_gui); 514 CNFGTackSegment( 0, screeny-l, screenx, screeny - l ); 515 516 char stbuf[2048]; 517 char * sptr = &stbuf[0]; 518 519 sptr += sprintf( sptr, 520 "Last:%6.2f ms Host: %s\n" 521 "Min :%6.2f ms\n" 522 "Max :%6.2f ms Historical max: %5.2f ms\n" 523 "Avg :%6.2f ms Biggest interval: %5.2f ms\n" 524#ifdef WIN32 525 "Std :%6.2f ms Historical loss: %I64u/%I64u %5.3f%%\n" 526#else 527 "Std :%6.2f ms Historical loss: %lu/%lu %5.3f%%\n" 528#endif 529 "Loss:%6.1f %%", last, pinghost, mintime, maxtime, globmaxtime*1000, avg, globinterval*1000.0, stddev, 530 globallost, globalrx+globallost, globallost*100.0f/(globalrx+globallost), loss ); 531 532 DrawMainText( stbuf ); 533 OGUSleep( 1000 ); 534} 535 536#ifdef WIN32 537 538const char * glargv[10]; 539int glargc = 0; 540 541int RegString( int write, char * data, DWORD len ) 542{ 543 HKEY hKey; 544 if( RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\cnping", 0, NULL, 545 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS) 546 { 547 if( write ) 548 { 549 RegSetValueExA( hKey, "history", 0, REG_SZ, (uint8_t*)data, len ); 550 return 0; 551 } 552 else 553 { 554 DWORD type; 555 if( RegGetValueA( hKey, "", "history", 0x02, &type, data, &len ) == ERROR_SUCCESS ) 556 { 557 return 0; 558 } 559 return -16; 560 } 561 562 RegCloseKey( hKey ); 563 } 564 else 565 { 566 return -15; 567 } 568} 569 570INT_PTR CALLBACK TextEntry( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) 571{ 572 573 switch( uMsg ) 574 { 575 case WM_INITDIALOG: 576 SetDlgItemText(hwndDlg, 4, "0.02"); 577 SetDlgItemText(hwndDlg, 5, "0" ); 578 579 char data[1024]; 580 if( !RegString( 0, data, sizeof( data ) ) ) 581 { 582 SetDlgItemText(hwndDlg, 3, data); 583 } 584 585 return 0; 586 case WM_COMMAND: 587 switch( wParam>>24 ) 588 { 589 case 4: case 3: return 0; //keyboard input 590 case 1: case 2: return 0; //focus changed. 591 case 0: 592 { 593 int id = wParam & 0xffffff; 594 if( id == 8 || id == 2 ) 595 { 596 exit( -1 ); 597 } 598 599 char Address[128]; GetDlgItemText(hwndDlg, 3, Address, sizeof(Address)); 600 char Period[128]; GetDlgItemText(hwndDlg, 4, Period, sizeof(Period)); 601 char Extra[128]; GetDlgItemText(hwndDlg, 5, Extra, sizeof(Extra)); 602 char Scaling[128]; GetDlgItemText(hwndDlg, 6, Scaling, sizeof(Scaling)); 603 604 if( strlen( Address ) ) 605 { 606 RegString( 1, Address, strlen( Address ) ); 607 608 glargc = 2; 609 glargv[1] = strdup( Address ); 610 if( strlen( Period ) ) 611 { 612 glargc = 3; 613 glargv[2] = strdup( Period ); 614 if( strlen( Extra ) ) 615 { 616 glargc = 4; 617 glargv[3] = strdup( Extra ); 618 if( strlen( Scaling ) ) 619 { 620 glargc = 5; 621 glargv[4] = strdup( Scaling ); 622 } 623 } 624 } 625 } 626 EndDialog(hwndDlg, 0); 627 return 0; //User pressed enter. 628 } 629 } 630/* return 0; 631 case WM_CTLCOLORBTN: 632 //printf( "ctr %p %p %p\n", uMsg, wParam, lParam ); 633 //return 0; 634 case 32: case 512: case 132: case 24: case 70: 635 case 127: case 783: case 28: case 134: case 6: case 7: 636 case 8: case 312: case 15: case 71: case 133: case 307: 637 case 20: case 310: case 33: 638 return 0; 639*/ 640 } 641 return 0; 642} 643#endif 644int main( int argc, const char ** argv ) 645{ 646 char title[1024]; 647 int i; 648 double ThisTime; 649 double LastFPSTime = OGGetAbsoluteTime(); 650 double LastFrameTime = OGGetAbsoluteTime(); 651 double SecToWait; 652 double frameperiodseconds; 653 const char * device = NULL; 654 655#ifdef WIN32 656 ShowWindow (GetConsoleWindow(), SW_HIDE); 657#endif 658 659 srand( (uintmax_t)(OGGetAbsoluteTime()*100000) ); 660 #ifndef DEBUG 661 for( i = 0; i < sizeof( pattern ); i++ ) 662 { 663 pattern[i] = rand(); 664 } 665 #endif 666 CNFGBGColor = 0x000080ff; 667#ifdef WIN32 668 if( argc < 2 ) 669 { 670 DialogBox(0, "IPDialog", 0, TextEntry ); 671 argc = glargc; 672 argv = glargv; 673 } 674#endif 675 676 pingperiodseconds = 0.02; 677 ExtraPingSize = 0; 678 title[0] = 0; 679 GuiYScaleFactor = 0; 680 681 //We need to process all the unmarked parameters. 682 int argcunmarked = 1; 683 int displayhelp = 0; 684 685 for( i = 1; i < argc; i++ ) 686 { 687 const char * thisargv = argv[i]; 688 if( thisargv[0] == '-' ) 689 { 690 int np = ++i; 691 if( np >= argc ) 692 { 693 displayhelp = 1; 694 break; 695 } 696 const char * nextargv = argv[np]; 697 //Parameter-based field. 698 switch( thisargv[1] ) 699 { 700 case 'h': pinghost = nextargv; break; 701 case 'p': pingperiodseconds = atof( nextargv ); break; 702 case 's': ExtraPingSize = atoi( nextargv ); break; 703 case 'y': GuiYScaleFactor = atof( nextargv ); break; 704 case 't': sprintf(title, "%s", nextargv); break; 705 case 'm': in_histogram_mode = 1; break; 706 case 'I': device = nextargv; break; 707 default: displayhelp = 1; break; 708 } 709 } 710 else 711 { 712 //Unmarked fields 713 switch( argcunmarked++ ) 714 { 715 case 1: pinghost = thisargv; break; 716 case 2: pingperiodseconds = atof( thisargv ); break; 717 case 3: ExtraPingSize = atoi( thisargv ); break; 718 case 4: GuiYScaleFactor = atof( thisargv ); break; 719 case 5: sprintf(title, "%s", thisargv ); break; 720 default: displayhelp = 1; 721 } 722 } 723 } 724 725 if( title[0] == 0 ) 726 { 727 sprintf( title, "%s - cnping "VERSION, pinghost ); 728 } 729 730 if( GuiYScaleFactor > 0 ) 731 { 732 GuiYscaleFactorIsConstant = 1; 733 } 734 735 if( !pinghost ) 736 { 737 displayhelp = 1; 738 } 739 740 if( displayhelp ) 741 { 742 ERRM( "cnping "VERSION" Usage: cnping [host] [period] [extra size] [y-axis scaling] [window title]\n" 743 " (-h) [host] -- domain, IP address of ping target for ICMP or http host, i.e. http://google.com\n" 744 " (-p) [period] -- period in seconds (optional), default 0.02 \n" 745 " (-s) [extra size] -- ping packet extra size (above 12), optional, default = 0 \n" 746 " (-y) [const y-axis scaling] -- use a fixed scaling factor instead of auto scaling (optional)\n" 747 " (-t) [window title] -- the title of the window (optional)\n" 748 " (-I) [interface] -- Sets source interface (i.e. eth0)\n"); 749 return -1; 750 } 751 752#if defined( WIN32 ) || defined( WINDOWS ) 753 if(device) 754 { 755 ERRM("Error: Device option is not implemented on your platform. PRs welcome.\n"); 756 exit( -1 ); 757 } 758 759 if( WSAStartup(MAKEWORD(2,2), &wsaData) ) 760 { 761 ERRM( "Fault in WSAStartup\n" ); 762 exit( -2 ); 763 } 764 CNFGSetup( title, 320, 155 ); 765#else 766 CNFGSetupWMClass( title, 320, 155, "cnping", "cnping" ); 767#endif 768 769 770 if( memcmp( pinghost, "http://", 7 ) == 0 ) 771 { 772 StartHTTPing( pinghost+7, pingperiodseconds, device ); 773 } 774 else 775 { 776 char* protoEnd = strstr( pinghost, "://" ); 777 if ( protoEnd ) 778 { 779 int protoSize = protoEnd - pinghost; 780 char protoBuffer[protoSize + 1]; 781 memcpy( protoBuffer, pinghost, protoSize ); 782 protoBuffer[protoSize] = '\0'; 783 ERRM( "Protocol \"%s\" is not supported\n", protoBuffer ); 784 exit( -1 ); 785 } 786 787 ping_setup( pinghost, device ); 788 OGCreateThread( PingSend, 0 ); 789 OGCreateThread( PingListen, 0 ); 790 } 791 792 793 frameperiodseconds = fmin(.2, fmax(.03, pingperiodseconds)); 794 795 while(1) 796 { 797 iframeno++; 798 CNFGHandleInput(); 799 800 CNFGClearFrame(); 801 CNFGColor( 0xffffffff ); 802 CNFGGetDimensions( &screenx, &screeny ); 803 804 if( in_frame_mode ) 805 { 806 DrawFrame(); 807 } 808 809 if( in_histogram_mode ) 810 { 811 DrawFrameHistogram(); 812 } 813 814 CNFGPenX = 100; CNFGPenY = 100; 815 CNFGColor( 0xff0000ff ); 816 CNFGDrawText( errbuffer, 3 ); 817 818 819 frames++; 820 CNFGSwapBuffers(); 821 822 ThisTime = OGGetAbsoluteTime(); 823 if( ThisTime > LastFPSTime + 1 ) 824 { 825 frames = 0; 826 LastFPSTime+=1; 827 } 828 829 SecToWait = frameperiodseconds - ( ThisTime - LastFrameTime ); 830 LastFrameTime += frameperiodseconds; 831 //printf("iframeno = %d; SecToWait = %f; pingperiodseconds = %f; frameperiodseconds = %f \n", iframeno, SecToWait, pingperiodseconds, frameperiodseconds); 832 if( SecToWait > 0 ) 833 OGUSleep( (int)( SecToWait * 1000000 ) ); 834 } 835 836 return(0); 837} 838