Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3931 lines
129 KiB

  1. //
  2. // QTCP.C version 1.0.3
  3. //
  4. // This program tests the quality of a network connection in terms of
  5. // variation in latency (jitter). It is based on TTCP, a public domain
  6. // program, written for BSD. The version of TTCP upon which this was
  7. // based has been contributed to by:
  8. //
  9. // T.C. Slattery, USNA (18 Dec 84)
  10. // Mike Muuss and T. Slattery (16 Oct 85)
  11. // Silicon Graphics, Inc. (1989)
  12. //
  13. // QTCP is written by Yoram Bernet ([email protected])
  14. // further development work by John Holmes ([email protected])
  15. //
  16. // QTCP user level code may be used to provide rough jitter measurements,
  17. // which indicate both operating system and network jitter. However, QTCP
  18. // is intended to be used in conjunction with kernel timestamping for precise
  19. // jitter measurements. The kernel component timestmp.sys should be installed
  20. // when running on Win2000 (beta-3 or later).
  21. //
  22. // timestmp.sys is written by Shreedhar Madhavapeddi ([email protected])
  23. //
  24. //
  25. // Distribution Status -
  26. // Public Domain. Distribution Unlimited.
  27. //
  28. // Version History -
  29. // 0.8:
  30. // - adaptation of TTCP by Yoram Bernet -- core functionality
  31. // 0.9: (6/15/99)
  32. // - first version by John Holmes -- bug fixes and new features
  33. // - fixed all compile warnings
  34. // - added -v option to set up RSVP connection without sending data
  35. // - added -y option to skip confirmation of continues
  36. // - fixed line length error in log files
  37. // - fixed service type string to display properly
  38. // - added best effort and no service service types (BE & NS)
  39. // - added version string print upon execution
  40. // 0.9.1: (6/17/99)
  41. // - check for hardware clock reset using correlation coefficient
  42. // - fixed incorrect clock skew in .sta file
  43. // - fixed -v option to keep socket open until user carriage returns
  44. // - added local statistics to clock skew computation for better estimate
  45. // - added -k option to prevent using local statistics for clock skew
  46. // - fixed maximum latency computation
  47. // 0.9.2: (6/23/99)
  48. // - fixed peak rate in flowspec so no shaping happens in CL servicetype
  49. // - added -e option to force shaping
  50. // - fixed error in allocating size of log array with bufsize <= 1500 bytes
  51. // - fixed not exiting on receiver
  52. // - fixed access violation if no filename specified on receiver
  53. // - changed dummy log entries to be off by default
  54. // - added -F option to convert raw file to log file
  55. // 0.9.3: (6/29/99)
  56. // - improved low transmission speed at high packet/second rates by changing
  57. // default # async buffers from 3 to 32
  58. // - fixed user mode timestamps to use NtQueryPerformanceCounter()
  59. // - added -u option to use usermode timestamps in log generation
  60. // 0.9.4: (7/8/99)
  61. // - cleaned up source (chopped up main into a bunch of functions to improve readability)
  62. // - fixed default buffer size to be 1472 bytes, so whole packet is 1500 bytes.
  63. // - rewrote i/o code to use callbacks for asynch i/o in order to improve throughput
  64. // - doing the right thing if not getting kernel-mode timestamps
  65. // - added ability to run for a specified amount of time with -n##s paramater
  66. // - added dynamic resizing of log array on receiver to prevent access violations
  67. // with mismatched parameters
  68. // - fixed devious bug in the GrowLogArray routine
  69. // - fixed total time reported for long runs (use UINT64 instead of DWORD)
  70. // - fixed problem with -F option specified on empty but extant file
  71. // - added RSVPMonitor Thread to watch for RSVP-err messages on receiver and
  72. // early abort by sender
  73. // - removed -a option as it is now obsolete
  74. // - revised usage screen to make more clear what pertains to sender and what
  75. // pertains to receiver
  76. // - fixed crash if receiver terminates before transmitter finishes
  77. // 0.9.5: (7/15/99)
  78. // - re-added error checking on WriteFileEx and ReadFileEx routines
  79. // 0.9.6: (7/20/99)
  80. // - changed default filler data in buffer so that it is less compressible to
  81. // better account for links that compress data before sending
  82. // - added -i option to use more compressible data
  83. // 0.9.7: (7/24/99)
  84. // - put back a thread to watch for 'q' on receiver to quit properly before sender's done
  85. // - added control channel to better handle RSVP timeouts, early aborts, etc.
  86. // - if no calibrations are specified, we calibrate based on all buffers
  87. // - gracefully exit if LogRecord runs out of memory, saving all logs we've got so far
  88. // - changed default behavior so raw file is dumped with no normalization whatsoever.
  89. // - improved the way anomalous points are caught in clock-skew calc
  90. // 0.9.8: (7/28/99)
  91. // - fixed field assignments & file opening problem on converting raw file to log.
  92. // - changed latency to be written to file to signed and fixed normalization routine for
  93. // cases when clocks are orders of magnitude different (underflow error)
  94. // - added absolute deviation as goodness of fit measure
  95. // - added routine to look for clock jumps and fix for them (with -k3 option)
  96. // 0.9.9: (8/4/99)
  97. // - changed format of .sta file to include more useful information and test params
  98. // - changed Logging scheme so that we are limited by disk space instead of memory
  99. // (now using a memory mapped file for the log, so the theoretical limit has gone from
  100. // less than 2GB to 18EB, but we won't ever get that in practice on normal disks)
  101. // - added -ni option to run indefinitely
  102. // - added -R##B option to specify tokenrate in bytes
  103. // - made default not to show dropped packets at console (it only causes more drops)
  104. // - added -q## option to log only every nth packet
  105. // 1.0.0: (8/6/99)
  106. // - fixed bug where if a new qtcp receiver is started immediately after a previous
  107. // instance, it will think "theend" packets are normal packets and AV
  108. // - added check for the piix4 timer chip and an appropriate warning
  109. // - using precise incorrect value in FixWackyTimestamps function
  110. // - added -A option (aggregate data processing of all .sta files in a directory)
  111. // 1.0.1: (8/6/99)
  112. // - fixed incorrect calculation of send rate with dropped packets
  113. // 1.0.2: (8/23/99)
  114. // - improved clock skip detection algorithm
  115. // - fixed a bug in control channel communication of TokenRate
  116. // - fixed problem with forceshape option when rate is specified in bytes
  117. // 1.0.3: (8/26/99)
  118. // - fixed SENDERS NO_SENDERS bug
  119. // - added summary over time to aggregate stats option
  120. // - changed .sta file format to include number of drops
  121. // - fixed shaping in best effort servicetype
  122. // ToDo:
  123. // - add histogram to output in .sta file and on console
  124. // - add ability to run w/o control channel connection
  125. // - mark control channel traffic as higher priority
  126. // - add more aggregate stats (time varying statistics) -- maybe fourier xform
  127. #ifndef lint
  128. static char RCSid[] = "qtcp.c $Revision: 1.0.3 $";
  129. #endif
  130. #include <malloc.h>
  131. #include <stdio.h>
  132. #include <stdlib.h>
  133. #include <nt.h>
  134. #include <ntrtl.h>
  135. #include <nturtl.h>
  136. #include <windows.h>
  137. #include <io.h>
  138. #include <signal.h>
  139. #include <ctype.h>
  140. #include <sys/types.h>
  141. #include <winsock2.h>
  142. #include <qossp.h>
  143. #include <winbase.h>
  144. #include <time.h>
  145. #include <shlwapi.h>
  146. #if defined(_AMD64_)
  147. #include <math.h>
  148. #endif
  149. #include "ioctl.h"
  150. #define CONTROL_PORT 7239
  151. CHAR *VERSION_STRING = "1.0.3";
  152. #define MAX_STRING 255
  153. INT64 MAX_INT64=9223372036854775807;
  154. HANDLE hRSVPMonitor;
  155. DWORD idRSVPMonitor;
  156. INT64 g_BadHalAdjustment = 46869688; // this is the value on a piix4 chip
  157. SYSTEM_INFO g_si;
  158. char g_szErr[255];
  159. CRITICAL_SECTION g_csLogRecord;
  160. EXCEPTION_RECORD g_erec;
  161. BOOL g_fOtherSideFinished = FALSE;
  162. BOOL g_fReadyForXmit = FALSE;
  163. SOCKET fd;
  164. SOCKET g_sockControl = INVALID_SOCKET;
  165. struct sockaddr_in sinhim;
  166. struct sockaddr_in sinme;
  167. short port = 5003; // UDP port number
  168. char *host; // ptr to name of host
  169. char szHisAddr[MAX_STRING];
  170. char szMyAddr[MAX_STRING];
  171. int trans; // 0=receive, !0=transmit mode
  172. int normalize = 0; // dump raw file after normalizing
  173. char *Name = NULL; // Name of file for logs
  174. HANDLE hRawFile = NULL;
  175. HANDLE hLogFile = NULL;
  176. HANDLE hStatFile = NULL;
  177. HANDLE hDriver = NULL; // handle to the timestmp.sys driver
  178. WSADATA WsaData;
  179. WSAEVENT QoSEvents;
  180. SYSTEMTIME systimeStart;
  181. INT64 timeStart;
  182. INT64 time0;
  183. INT64 time1;
  184. INT64 timeElapsed;
  185. CHAR* TheEnd = "TheEnd";
  186. CHAR* ControlledLoad = "CL";
  187. CHAR* Guaranteed = "GR";
  188. CHAR* BestEffort = "BE";
  189. CHAR* NoTraffic = "NT";
  190. LPCTSTR DriverName = TEXT("\\\\.\\Timestmp");
  191. BOOL fWackySender = FALSE;
  192. BOOL fWackyReceiver = FALSE;
  193. typedef struct {
  194. HANDLE hSocket;
  195. INT TokenRate;
  196. INT MaxSDUSize;
  197. INT BucketSize;
  198. INT MinPolicedSize;
  199. SERVICETYPE dwServiceType;
  200. CHAR *szServiceType;
  201. INT buflen; // length of buffer
  202. INT nbuf; // number of buffers to send
  203. INT64 calibration;
  204. BOOLEAN UserStamps; // By default, we use kernel mode timestamping, if available
  205. BOOLEAN SkipConfirm; // By default, we wait for user confirmation at certain times
  206. BOOLEAN RESVonly; // By default, we send data after getting the resv
  207. int SkewFitMode; // by default, 0 = no fit, 1 = chisq, 2 = chisq w/outlier removal
  208. // 3 = abs dev
  209. BOOLEAN Wait; // By default, we wait for a QoS reservation
  210. BOOLEAN Dummy; // insert dummy rows in log by default
  211. BOOLEAN PrintDrops; // report dropped packets on console
  212. BOOLEAN ForceShape; // by default, we do not force shaping on CL flows
  213. BOOLEAN RateInBytes; // KB by default
  214. BOOLEAN AggregateStats; // by default, we do not do this
  215. BOOLEAN ConvertOnly; // by default, we act normally and do not go around converting files
  216. BOOLEAN NoSenderTimestamps;
  217. BOOLEAN NoReceiverTimestamps;
  218. BOOLEAN TimedRun; // true if we're running for a specified amount of time
  219. BOOLEAN RunForever; // run until the person pushes 'q'
  220. BOOLEAN nBufUnspecified; // true if the user has not specified the -n parameter
  221. BOOLEAN RandomFiller;// by default, we use random, incompressible filler data
  222. int LoggingPeriod; // by default, 1 (log every packet)
  223. } QTCPPARAMS, *PQTCPPARAMS;
  224. QTCPPARAMS g_params;
  225. typedef struct {
  226. BOOL Done; // done if true
  227. int nWritesInProgress; // number of writes outstanding
  228. int nReadsInProgress; // number of reads outstanding
  229. int nBuffersSent; // number of buffers sent to the device
  230. int nBuffersReceived; // number of buffers received from network
  231. int nBytesTransferred; // number of bytes written to device
  232. } QTCPSTATE, *PQTCPSTATE;
  233. QTCPSTATE g_state;
  234. typedef struct {
  235. OVERLAPPED Overlapped;
  236. PVOID pBuffer;
  237. DWORD BytesWritten;
  238. } IOREQ, *PIOREQ;
  239. #define MAX_PENDING_IO_REQS 64 // number of simultaneous async calls.
  240. // This format is used for the buffer
  241. // transmitted on the wire.
  242. typedef struct _BUFFER_FORMAT{
  243. INT64 TimeSentUser;
  244. INT64 TimeReceivedUser;
  245. INT64 TimeSent;
  246. INT64 TimeReceived;
  247. INT64 Latency;
  248. INT BufferSize;
  249. INT SequenceNumber;
  250. } BUFFER_FORMAT, *PBUFFER_FORMAT;
  251. // This format is used for the scheduling record
  252. // written based on the received buffers.
  253. typedef struct _LOG_RECORD{
  254. INT64 TimeSentUser;
  255. INT64 TimeReceivedUser;
  256. INT64 TimeSent;
  257. INT64 TimeReceived;
  258. INT64 Latency;
  259. INT BufferSize;
  260. INT SequenceNumber;
  261. } LOG_RECORD, *PLOG_RECORD;
  262. // The LOG structure is a data abstraction for a log of LOG_RECORDS that uses memory
  263. // mapped files to have a theoretical storage limit of 18EB. It uses two buffers in memory
  264. // along with a watcher thread so that there is no delay when switching from one bit to
  265. // the next.
  266. typedef struct {
  267. INT64 nBuffersLogged;
  268. PBYTE pbMapView; // view of file in Get/SetLogElement functions
  269. INT64 qwMapViewOffset; // offset of Get/Set view in file (rounded down to allocation)
  270. char *szStorageFile; // the name of the mapped file on disk (so we can delete it)
  271. HANDLE hStorageFile; // the memory mapped file on disk
  272. HANDLE hFileMapping; // the file mapping object for our storage file
  273. INT64 qwFileSize; // the size of the storage file in bytes
  274. } LOG, *PLOG;
  275. LOG g_log;
  276. // The STATS structure keeps a record of overall statistics for the qtcp run
  277. typedef struct {
  278. char szStaFile[MAX_PATH];
  279. char szSender[MAX_STRING];
  280. char szReceiver[MAX_STRING];
  281. int nBuffers;
  282. int nTokenRate;
  283. int nBytesPerBuffer;
  284. double sendrate;
  285. double recvrate;
  286. double median;
  287. double mean;
  288. double var;
  289. double kurt;
  290. double skew;
  291. double abdev;
  292. FILETIME time;
  293. int nDrops;
  294. } STATS, *PSTATS;
  295. INT64 totalBuffers;
  296. INT anomalies = 0;
  297. INT SequenceNumber = 0;
  298. INT LastSequenceNumber = -1;
  299. #define bcopy(s, d, c) memcpy((u_char *)(d), (u_char *)(s), (c))
  300. #define bzero(d, l) memset((d), '\0', (l))
  301. #define SENDER 1
  302. #define RECEIVER 0
  303. #define SECONDS_BETWEEN_HELLOS 120
  304. // control messages
  305. #define MSGCH_DELIMITER '!'
  306. #define MSGST_RSVPERR "RSVPERR"
  307. #define MSGST_ABORT "ABORT"
  308. #define MSGST_ERROR "ERROR"
  309. #define MSGST_DONE "DONE"
  310. #define MSGST_HELLO "HELLO"
  311. #define MSGST_RATE "RATE"
  312. #define MSGST_SIZE "SIZE"
  313. #define MSGST_NUM "NUM"
  314. #define MSGST_READY "READY"
  315. #define MSGST_VER "VER"
  316. // -------------------
  317. // Function prototypes
  318. // -------------------
  319. VOID
  320. SetDefaults();
  321. VOID
  322. Usage();
  323. BOOLEAN
  324. GoodParams();
  325. VOID
  326. SetupLogs();
  327. VOID
  328. SetupSockets();
  329. SOCKET
  330. OpenQoSSocket();
  331. INT
  332. SetQoSSocket(
  333. SOCKET fd,
  334. BOOL Sending);
  335. VOID
  336. WaitForQoS(
  337. BOOL Sender,
  338. SOCKET fd);
  339. ULONG
  340. GetRsvpStatus(
  341. DWORD dwTimeout,
  342. SOCKET fd);
  343. VOID
  344. PrintRSVPStatus(
  345. ULONG code);
  346. VOID
  347. DoTransmit();
  348. VOID WINAPI
  349. TransmitCompletionRoutine(
  350. DWORD dwErrorCode,
  351. DWORD dwNumberOfBytesTransferred,
  352. LPOVERLAPPED pOverlapped);
  353. VOID WINAPI
  354. DelimiterSendCompletion(
  355. DWORD dwErrorCode,
  356. DWORD dwNumberOfBytesTransferred,
  357. LPOVERLAPPED pOverlapped);
  358. VOID
  359. FillBuffer(
  360. CHAR *Cp,
  361. INT Cnt);
  362. INT
  363. TimeStamp(
  364. CHAR *Cp,
  365. INT Cnt);
  366. VOID
  367. DoReceive();
  368. VOID WINAPI
  369. RecvCompletionRoutine(
  370. DWORD dwErrorCode,
  371. DWORD dwNumberOfBytesTransferred,
  372. LPOVERLAPPED pOverlapped);
  373. VOID
  374. LogRecord(CHAR * Buffer);
  375. BOOL CreateLog(PLOG plog, INT64 c);
  376. BOOL GetLogEntry(PLOG plog, PLOG_RECORD prec, INT64 i);
  377. BOOL DestroyLog(PLOG plog);
  378. BOOL SetLogEntry(PLOG plog, PLOG_RECORD prec, INT64 i);
  379. BOOL AddLogEntry(PLOG plog, PLOG_RECORD prec);
  380. UINT64
  381. GetUserTime();
  382. DWORD
  383. MyCreateFile(
  384. IN PCHAR Name,
  385. IN PCHAR Extension,
  386. OUT HANDLE *File);
  387. void AggregateStats();
  388. int IndexOfStatRecWith(int rate, int size, INT64 time, PSTATS pStats, int cStats);
  389. BOOL GetStatsFromFile(PSTATS pstats);
  390. VOID
  391. DoStatsFromFile();
  392. DWORD
  393. OpenRawFile(
  394. IN PCHAR Name,
  395. OUT HANDLE *File);
  396. INT64 ReadSchedulingRecords(HANDLE file);
  397. VOID
  398. DoStats();
  399. VOID
  400. WriteSchedulingRecords(
  401. HANDLE File,
  402. BOOLEAN InsertDummyRows);
  403. void AdvancedStats();
  404. VOID
  405. GenericStats();
  406. VOID
  407. CheckForLostPackets();
  408. VOID
  409. WriteStats(
  410. UCHAR * HoldingBuffer,
  411. INT Count);
  412. VOID
  413. NormalizeTimeStamps();
  414. VOID
  415. ClockSkew(
  416. DOUBLE * Slope,
  417. DOUBLE * Offset);
  418. BOOLEAN
  419. AnomalousPoint(
  420. DOUBLE x,
  421. DOUBLE y);
  422. VOID
  423. AdjustForClockSkew(
  424. DOUBLE Slope,
  425. DOUBLE Offset);
  426. BOOL FixWackyTimestamps();
  427. // monitor threads
  428. DWORD WINAPI RSVPMonitor (LPVOID lpvThreadParm);
  429. DWORD WINAPI KeyboardMonitor (LPVOID lpvThreadParm);
  430. DWORD WINAPI ControlSocketMonitor(LPVOID lpvThreadParm);
  431. DWORD WINAPI LogWatcher(LPVOID lpvThreadParm);
  432. // utilities
  433. int SendControlMessage(SOCKET sock, char * szMsg);
  434. void ErrorExit(char *msg, DWORD dwErrorNumber);
  435. UINT64 GetBadHalAdjustment();
  436. //int compare( const void *arg1, const void *arg2 );
  437. int __cdecl compare(const void *elem1, const void *elem2 ) ;
  438. void medfit(double x[], double y[], int N, double *a, double *b, double *abdev);
  439. double mode(const double data[], const int N);
  440. void RemoveDuplicates(int rg[], int * pN);
  441. void RemoveDuplicatesI64(INT64 rg[], int * pN);
  442. #define RoundUp(val, unit) (val + (val % unit))
  443. #define InRange(val, low, high) ((val >= low) && (val < high)) ? TRUE:FALSE
  444. void PrintFlowspec(LPFLOWSPEC lpfs);
  445. VOID __cdecl
  446. main(INT argc,CHAR **argv)
  447. {
  448. int error;
  449. char *stopstring;
  450. char szBuf[MAX_STRING];
  451. BOOL b;
  452. ULONG bytesreturned;
  453. printf("qtcp version %s\n\n",VERSION_STRING);
  454. if (GetBadHalAdjustment() == (UINT64)g_BadHalAdjustment) {
  455. printf("WARNING: This machine has a timer whose frequency matches that of the piix4\n");
  456. printf(" chip. There is a known bug in the HAL for this timer that causes the\n");
  457. printf(" timer to jump forward about 4.7 seconds every once in a while.\n");
  458. printf(" If you notice large jumps in the timestamps from this machine, try\n");
  459. printf(" running with the -k3 option to attempt to correct for the timer bug.\n\n");
  460. }
  461. srand( (unsigned)time( NULL ) ); // seed the random number generator
  462. timeStart = GetUserTime();
  463. GetSystemInfo(&g_si);
  464. error = WSAStartup( 0x0101, &WsaData );
  465. if (error == SOCKET_ERROR) {
  466. printf("qtcp: WSAStartup failed %ld:", WSAGetLastError());
  467. }
  468. if (argc < 2) Usage();
  469. Name = malloc(MAX_STRING);
  470. bzero(Name,MAX_STRING);
  471. SetDefaults();
  472. argv++; argc--;
  473. while( argc>0 && argv[0][0] == '-' ) {
  474. switch (argv[0][1]) {
  475. case 'B':
  476. g_params.BucketSize = atoi(&argv[0][2]);
  477. break;
  478. case 'm':
  479. g_params.MinPolicedSize = atoi(&argv[0][2]);
  480. break;
  481. case 'M':
  482. g_params.MaxSDUSize = atoi(&argv[0][2]);
  483. break;
  484. case 'R':
  485. g_params.TokenRate = (int)strtod(&argv[0][2],&stopstring);
  486. if (*stopstring == 0) { // normal run
  487. g_params.RateInBytes = FALSE;
  488. break;
  489. }
  490. if (*stopstring == 'B') { // rate is in bytes / sec, not kbytes/sec
  491. g_params.RateInBytes = TRUE;
  492. break;
  493. }
  494. else {
  495. Usage();
  496. break;
  497. }
  498. case 'S':
  499. g_params.szServiceType = &argv[0][2];
  500. if(!strncmp(g_params.szServiceType, ControlledLoad, 2)){
  501. g_params.dwServiceType = SERVICETYPE_CONTROLLEDLOAD;
  502. break;
  503. }
  504. if(!strncmp(g_params.szServiceType, Guaranteed, 2)){
  505. g_params.dwServiceType = SERVICETYPE_GUARANTEED;
  506. break;
  507. }
  508. if(!strncmp(g_params.szServiceType, BestEffort, 2)){
  509. g_params.dwServiceType = SERVICETYPE_BESTEFFORT;
  510. g_params.Wait = FALSE;
  511. break;
  512. }
  513. if(!strncmp(g_params.szServiceType, NoTraffic, 2)){
  514. g_params.dwServiceType = SERVICETYPE_NOTRAFFIC;
  515. g_params.Wait = FALSE;
  516. break;
  517. }
  518. fprintf(stderr, "Invalid service type (not CL or GR).\n");
  519. fprintf(stderr, "Using GUARANTEED service.\n");
  520. break;
  521. case 'e':
  522. g_params.ForceShape = TRUE;
  523. break;
  524. case 'W':
  525. g_params.Wait = FALSE;
  526. break;
  527. case 't':
  528. trans = 1;
  529. break;
  530. case 'f':
  531. strcpy(Name,&argv[0][2]);
  532. break;
  533. case 'F':
  534. strcpy(Name,&argv[0][2]);
  535. g_params.ConvertOnly = TRUE;
  536. break;
  537. case 'A':
  538. strcpy(Name,&argv[0][2]);
  539. g_params.AggregateStats = TRUE;
  540. break;
  541. case 'r':
  542. trans = 0;
  543. break;
  544. case 'n':
  545. g_params.nbuf = (INT)strtod(&argv[0][2],&stopstring);
  546. if (*stopstring == 0) { // normal run
  547. g_params.nBufUnspecified = FALSE;
  548. break;
  549. }
  550. if (*stopstring == 'i') { // run for an infinite time
  551. g_params.RunForever = TRUE;
  552. break;
  553. }
  554. if (*stopstring == 's') { // run for a specified time
  555. g_params.TimedRun = TRUE;
  556. printf("Running for %d seconds\n",g_params.nbuf);
  557. break;
  558. }
  559. else {
  560. Usage();
  561. break;
  562. }
  563. case 'c':
  564. g_params.calibration = atoi(&argv[0][2]);
  565. break;
  566. case 'k':
  567. g_params.SkewFitMode = atoi(&argv[0][2]);
  568. if (g_params.SkewFitMode < 0 || g_params.SkewFitMode > 3)
  569. ErrorExit("Invalid Skew Fit Mode",g_params.SkewFitMode);
  570. break;
  571. case 'l':
  572. g_params.buflen = atoi(&argv[0][2]);
  573. break;
  574. case 'p':
  575. port = (short)atoi(&argv[0][2]);
  576. break;
  577. case 'd':
  578. g_params.Dummy = TRUE;
  579. break;
  580. case 'N':
  581. normalize = 1;
  582. break;
  583. case 'P':
  584. g_params.PrintDrops = TRUE;
  585. break;
  586. case 'v':
  587. g_params.RESVonly = TRUE;
  588. break;
  589. case 'y':
  590. g_params.SkipConfirm = TRUE;
  591. break;
  592. case 'u':
  593. g_params.UserStamps = TRUE;
  594. break;
  595. case 'i':
  596. g_params.RandomFiller = FALSE;
  597. break;
  598. case 'q':
  599. g_params.LoggingPeriod = atoi(&argv[0][2]);
  600. break;
  601. default:
  602. Usage();
  603. }
  604. argv++;
  605. argc--;
  606. }
  607. //
  608. // Make an ioctl to Timestmp driver, if its exists about the
  609. // port to timestamp on.
  610. //
  611. printf("Trying to open %s\n", DriverName);
  612. hDriver = CreateFile(DriverName,
  613. GENERIC_READ | GENERIC_WRITE,
  614. FILE_SHARE_READ | FILE_SHARE_WRITE,
  615. 0, // Default security
  616. OPEN_EXISTING,
  617. 0,
  618. 0); // No template
  619. if(hDriver == INVALID_HANDLE_VALUE) {
  620. printf("Timestmp.sys CreateFile- Error %ld - Maybe its not INSTALLED\n", GetLastError());
  621. // Otherwise, print success and close the driver
  622. } else {
  623. printf("Timestmp.sys - CreateFile Success.\n");
  624. b = DeviceIoControl(
  625. hDriver, // handle to a device, file, or directory
  626. IOCTL_TIMESTMP_REGISTER_PORT, // control code of operation to perform
  627. &port, // pointer to buffer to supply input data
  628. 2, //nInBufferSize, // size, in bytes, of input buffer
  629. NULL, //lpOutBuffer, // pointer to buffer to receive output data
  630. 0, //nOutBufferSize, // size, in bytes, of output buffer
  631. &bytesreturned, // pointer to variable to receive byte count
  632. NULL // pointer to overlapped structure
  633. );
  634. printf("IOCTL performed\n");
  635. if (!b) {
  636. printf("IOCTL FAILED!\n", GetLastError());
  637. // Close the driver
  638. CloseHandle(hDriver);
  639. } else {
  640. printf("IOCTL succeeded!\n");
  641. }
  642. }
  643. // get the host address if we're the sender
  644. if(trans) {
  645. if(argc != 1)
  646. Usage();
  647. host = malloc(strlen(argv[0]) + 1);
  648. strcpy(host,argv[0]);
  649. }
  650. // first, we see if this is a conversion -- if it is, just jump right in, else go on
  651. if (g_params.ConvertOnly) {
  652. DoStatsFromFile();
  653. exit(0);
  654. }
  655. // see if we're supposed to do stat aggregation
  656. if (g_params.AggregateStats) {
  657. AggregateStats();
  658. exit(0);
  659. }
  660. // Do argument sanity tests & set default values if not already set
  661. if (!GoodParams()) exit(1);
  662. // Spawn off the control socket monitor thread
  663. CreateThread(NULL, 0, ControlSocketMonitor, (LPVOID)host, 0, NULL);
  664. // Get the sockets ready, set for QoS, and wait for a connection
  665. SetupSockets();
  666. // Check for a RESV only session
  667. if (g_params.RESVonly) { // keep socket open and hang out
  668. fprintf(stdout, "RSVP connection established. Press return to quit.\n");
  669. while(TRUE){
  670. if(getchar())
  671. break;
  672. }
  673. exit(0);
  674. }
  675. // start up the RSVPMonitor and keyboard monitor threads to watch for wackiness
  676. hRSVPMonitor = CreateThread(NULL,0,RSVPMonitor,NULL,0,&idRSVPMonitor);
  677. CreateThread(NULL,0,KeyboardMonitor,NULL,0,NULL);
  678. // wait for the control channel to be set up, if it's not already
  679. while (g_sockControl == INVALID_SOCKET) Sleep(50);
  680. if (!trans) { // we want to make sure these are not initialized, so we don't put wrong values in .sta
  681. g_params.buflen = 0;
  682. g_params.nbuf = 2048; // it's ok to init this because it's not saved in .sta
  683. g_params.TokenRate = 0;
  684. }
  685. totalBuffers = g_params.nbuf + g_params.calibration;
  686. // Tell the receiver the important parameters
  687. if (trans) {
  688. if (g_params.RunForever) totalBuffers = 2048;
  689. sprintf(szBuf, "%s %d", MSGST_NUM, totalBuffers);
  690. SendControlMessage(g_sockControl, szBuf);
  691. sprintf(szBuf, "%s %d", MSGST_SIZE, g_params.buflen);
  692. SendControlMessage(g_sockControl, szBuf);
  693. if (g_params.RateInBytes) sprintf(szBuf, "%s %d", MSGST_RATE, g_params.TokenRate);
  694. else sprintf(szBuf, "%s %d", MSGST_RATE, 1000 * g_params.TokenRate);
  695. SendControlMessage(g_sockControl, szBuf);
  696. }
  697. while (!g_fReadyForXmit) Sleep(50);
  698. // If we're the receiver, set up the log buffer and files
  699. if((Name != NULL) && !trans){
  700. SetupLogs();
  701. }
  702. // Let the user know what's up
  703. if(trans){
  704. fprintf(stdout, "qtcp TRANSMITTER\n");
  705. if (g_params.calibration)
  706. fprintf(stdout, "\tSending %d calibration buffers.\n", g_params.calibration);
  707. fprintf(stdout, "\tSending %d buffers of length %d.\n", g_params.nbuf, g_params.buflen);
  708. fprintf(stdout, "\tDestination address (port) is %s (%d).\n", argv[0], port);
  709. if (g_params.RateInBytes)
  710. fprintf(stdout, "\tToken rate is %d bytes/sec.\n", g_params.TokenRate);
  711. else
  712. fprintf(stdout, "\tToken rate is %d Kbytes/sec.\n", g_params.TokenRate);
  713. fprintf(stdout, "\tBucket size is %d bytes.\n", g_params.BucketSize);
  714. }
  715. else{
  716. fprintf(stdout, "qtcp RECEIVER\n");
  717. if (g_params.calibration)
  718. fprintf(stdout, "\tPrepared to receive %d calibration buffers.\n", g_params.calibration);
  719. if (!g_params.nBufUnspecified) {
  720. fprintf(stdout, "\tPrepared to receive %d buffers.\n", g_params.nbuf);
  721. }
  722. }
  723. // Do the actual communication
  724. time0 = GetUserTime();
  725. if (trans)
  726. DoTransmit();
  727. else
  728. DoReceive();
  729. time1 = GetUserTime();
  730. timeElapsed = (time1 - time0)/10000;
  731. // tell the other guy we're done
  732. SendControlMessage(g_sockControl, MSGST_DONE);
  733. // get to a new line
  734. printf("\n");
  735. // put some stats on the transmitter console
  736. if (trans) {
  737. printf("Sent %ld bytes in %I64d milliseconds = %I64d KBps\n",
  738. g_state.nBytesTransferred, timeElapsed, g_state.nBytesTransferred/timeElapsed);
  739. }
  740. // wait for the other side to tell us it's done.
  741. while (!g_fOtherSideFinished) Sleep(50);
  742. // let the user know if timestmp.sys was installed
  743. if (g_params.NoSenderTimestamps && g_params.NoReceiverTimestamps)
  744. printf("WARNING: No kernel-level timestamps detected on sender or receiver\n\tUsing user-mode timestamps.\n");
  745. else if (g_params.NoSenderTimestamps)
  746. printf("WARNING: No kernel-level timestamps detected on sender\n\tUsing user-mode timestamps.\n");
  747. else if (g_params.NoReceiverTimestamps)
  748. printf("WARNING: No kernel-level timestamps detected on receiver\n Using user-mode timestamps.\n");
  749. // Close down the sockets
  750. if (closesocket((SOCKET)g_params.hSocket) != 0)
  751. fprintf(stderr,"closesocket failed: %d\n",WSAGetLastError());
  752. if(timeElapsed <= 100){
  753. fprintf(stdout,
  754. "qtcp %s:Time interval too short for valid measurement!\n",
  755. trans?"-t":"-r");
  756. }
  757. // Close files & exit
  758. if(!trans && Name != NULL){
  759. if (g_log.nBuffersLogged) {
  760. DoStats();
  761. } else {
  762. printf("ERROR: no buffers logged due to errors.\n");
  763. }
  764. CloseHandle(hRawFile);
  765. CloseHandle(hLogFile);
  766. CloseHandle(hStatFile);
  767. DestroyLog(&g_log);
  768. }
  769. if (WSACleanup() != 0)
  770. fprintf(stderr,"WSACleanup failed: %d\n",WSAGetLastError());
  771. printf("\n");
  772. _exit(0);
  773. } // main()
  774. VOID SetDefaults()
  775. {
  776. g_params.hSocket = NULL;
  777. g_params.TokenRate = 100;
  778. g_params.MaxSDUSize = QOS_NOT_SPECIFIED;
  779. g_params.BucketSize = QOS_NOT_SPECIFIED;
  780. g_params.MinPolicedSize = QOS_NOT_SPECIFIED;
  781. g_params.dwServiceType = SERVICETYPE_GUARANTEED;
  782. g_params.szServiceType = "GR";
  783. g_params.buflen = 1472; /* length of buffer */
  784. g_params.nbuf = 2 * 1024; /* number of buffers to send */
  785. g_params.calibration = 0;
  786. g_params.UserStamps = FALSE; // By default, we use kernel mode timestamping, if available
  787. g_params.SkipConfirm = FALSE; // By default, we wait for user confirmation at certain times
  788. g_params.SkewFitMode = 2; // by default, we use absolute deviation
  789. g_params.Wait = TRUE; // By default, we wait for a QoS reservation
  790. g_params.Dummy = FALSE; // insert dummy rows in log by default
  791. g_params.PrintDrops = FALSE; // report dropped packets on console
  792. g_params.ForceShape = FALSE; // by default, we do not force shaping on CL flows
  793. g_params.RateInBytes = FALSE; // KB by default
  794. g_params.ConvertOnly = FALSE; // by default, we act normally and do not go around converting files
  795. g_params.AggregateStats = FALSE;
  796. g_params.NoSenderTimestamps = FALSE;
  797. g_params.NoReceiverTimestamps = FALSE;
  798. g_params.TimedRun = FALSE; // by default, we run for a number of packets
  799. g_params.RunForever = FALSE; // by default, we run fora number of packets
  800. g_params.nBufUnspecified = TRUE;
  801. g_params.RandomFiller = TRUE; // by default, we use random filler to prevent compression
  802. g_params.LoggingPeriod = 1;
  803. } // SetDefaults()
  804. VOID Usage()
  805. {
  806. fprintf(stderr,"Usage: qtcp [-options] -t host\n");
  807. fprintf(stderr," qtcp [-options] -r\n");
  808. fprintf(stderr," -t options:\n");
  809. fprintf(stderr," -B## TokenBucket size signaled to network and to traffic control\n");
  810. fprintf(stderr," (default is equal to buffer size)\n");
  811. fprintf(stderr," -m## MinPolicedSize signaled to network and to traffic control\n");
  812. fprintf(stderr," (default is equal to buffer size)\n");
  813. fprintf(stderr," -R## TokenRate in kilobytes per second (default is 100 KBPS)\n");
  814. fprintf(stderr," -R##B TokenRate in bytes per second\n");
  815. fprintf(stderr," -e Force shaping to TokenRate.\n");
  816. fprintf(stderr," -M MaxSDUSize to be used in signaling messages (default is buffer\n");
  817. fprintf(stderr," size\n");
  818. fprintf(stderr," -l## length of buffers to transmit (default is 1472 bytes)\n");
  819. fprintf(stderr," -n## number of source bufs written to network (default is 2048 bytes)\n");
  820. fprintf(stderr," -n##s numbef of seconds to send buffers for (numbef of buffers will\n");
  821. fprintf(stderr," be calculated based on other parameters\n");
  822. fprintf(stderr," -ni run indefinitely (will stop when 'q' is pressed on either)\n");
  823. fprintf(stderr," -c## Specifies number of calibration packets to be sent\n");
  824. fprintf(stderr," Calibration packets will be sent immediately\n");
  825. fprintf(stderr," After calibration packets are sent, n additional\n");
  826. fprintf(stderr," packets will be sent. This option is useful if you want to\n");
  827. fprintf(stderr," change network conditions after a set calibration phase\n");
  828. fprintf(stderr," -y skip confirmation message after calibration phase\n");
  829. fprintf(stderr," -p## port number to send to or listen at (default 5003)\n");
  830. fprintf(stderr," -i use more compressible buffer data\n");
  831. fprintf(stderr," -r options:\n");
  832. fprintf(stderr," -f\"filename\" Name prefix to be used in generating log file and\n");
  833. fprintf(stderr," statistics summary. (no file generated by default)\n");
  834. fprintf(stderr," -c## Specifies number of buffers to use in clock-skew calibration\n");
  835. fprintf(stderr," -k0 do not calculate clock skew\n");
  836. fprintf(stderr," -k1 use chi squared as goodness of fit\n");
  837. fprintf(stderr," -k2 use absolute deviation as goodness of fit (default)\n");
  838. fprintf(stderr," -k3 use abs dev and check for clock jumps\n");
  839. fprintf(stderr," -d suppress insertion of dummy log records for lost packets.\n");
  840. fprintf(stderr," -N Normalize before dumping raw file (default is after)\n");
  841. fprintf(stderr," -P enables console reporting of dropped packets\n");
  842. fprintf(stderr," -u use user mode timestamps instead of kernel timestamps in logs\n");
  843. fprintf(stderr," -q## log only every ##th packet\n");
  844. fprintf(stderr," common options:\n");
  845. fprintf(stderr," -S\"service type\" (CL or GR -- GR is default)\n");
  846. fprintf(stderr," -W Suppress waiting for QoS reservation\n");
  847. fprintf(stderr," -v Set up QoS reservation only, send no data\n");
  848. fprintf(stderr," -F\"filename\" Name prefix of raw file to be converted to log file\n");
  849. fprintf(stderr," -A\"path\" Path to directory for aggregate statistics computation\n");
  850. WSACleanup();
  851. exit(1);
  852. } // Usage()
  853. BOOLEAN GoodParams()
  854. {
  855. BOOLEAN ok = TRUE;
  856. if(g_params.buflen < sizeof(BUFFER_FORMAT)){
  857. printf("Buffer size too small for record!\n");
  858. ok = FALSE;
  859. }
  860. // Unless otherwise specified, min policed size will be equal to
  861. // buflen.
  862. if(g_params.MinPolicedSize == QOS_NOT_SPECIFIED){
  863. g_params.MinPolicedSize = g_params.buflen;
  864. }
  865. // Same goes for bucket size
  866. if(g_params.BucketSize == QOS_NOT_SPECIFIED){
  867. g_params.BucketSize = g_params.buflen;
  868. }
  869. // And for MaxSDU
  870. if(g_params.MaxSDUSize == QOS_NOT_SPECIFIED){
  871. g_params.MaxSDUSize = g_params.buflen;
  872. }
  873. // If the bucket size is smaller than the buffer size,
  874. // and this is a sender, then warn the user because
  875. // data will be discarded
  876. if((g_params.BucketSize < g_params.buflen) && trans){
  877. printf("Token bucket size is smaller than buffer size!\n");
  878. ok = FALSE;
  879. }
  880. if(g_params.MaxSDUSize < g_params.buflen){
  881. printf("MaxSDU cannot be less than buffer size!\n");
  882. ok = FALSE;
  883. }
  884. if(g_params.buflen < 5){
  885. g_params.buflen = 5; // send more than the sentinel size
  886. }
  887. if(g_params.TimedRun) {
  888. if (g_params.RateInBytes)
  889. g_params.nbuf = g_params.nbuf * g_params.TokenRate / g_params.buflen;
  890. else
  891. g_params.nbuf = g_params.nbuf * g_params.TokenRate * 1000 / g_params.buflen;
  892. printf("Using %d buffers\n",g_params.nbuf);
  893. }
  894. return ok;
  895. } // GoodParams()
  896. VOID SetupLogs()
  897. {
  898. CreateLog(&g_log, totalBuffers);
  899. // set up logging files
  900. if(ERROR_SUCCESS != MyCreateFile(Name,".raw",&hRawFile)){
  901. fprintf(stderr, "WARNING: Could not create raw file.\n");
  902. }
  903. if(ERROR_SUCCESS == MyCreateFile(Name,".log", &hLogFile)){
  904. fprintf(stdout,"Logging per-packet data to %s.log.\n",Name);
  905. }
  906. else{
  907. fprintf(stderr, "WARNING: Could not create log file.\n");
  908. }
  909. if(ERROR_SUCCESS == MyCreateFile(Name, ".sta", &hStatFile)){
  910. fprintf(stdout,"Writing statistics sumary to %s.sta\n",Name);
  911. }
  912. else{
  913. fprintf(stderr,"Could not create statistics file.\n");
  914. }
  915. } // SetupLogs()
  916. VOID SetupSockets()
  917. {
  918. struct hostent *addr;
  919. ULONG addr_tmp;
  920. char szAddr[MAX_STRING];
  921. int dwAddrSize, dwError;
  922. // Set address and port parameters
  923. if(trans) {
  924. bzero((char *)&sinhim, sizeof(sinhim));
  925. if (atoi(host) > 0 ) {
  926. sinhim.sin_family = AF_INET;
  927. sinhim.sin_addr.s_addr = inet_addr(host);
  928. }
  929. else{
  930. if ((addr=gethostbyname(host)) == NULL){
  931. printf("ERROR: bad hostname\n");
  932. WSACleanup();
  933. exit(1);
  934. }
  935. sinhim.sin_family = addr->h_addrtype;
  936. bcopy(addr->h_addr,(char*)&addr_tmp, addr->h_length);
  937. sinhim.sin_addr.s_addr = addr_tmp;
  938. }
  939. sinhim.sin_port = htons(port);
  940. sinme.sin_port = 0; /* free choice */
  941. }
  942. else{
  943. sinme.sin_port = htons(port);
  944. }
  945. sinme.sin_family = AF_INET;
  946. // Open socket for QoS traffic
  947. fd = OpenQoSSocket();
  948. if((fd == (UINT_PTR)NULL) || (fd == INVALID_SOCKET)){
  949. fprintf(stderr,"Failed to open QoS socket!\n");
  950. exit(1);
  951. }
  952. // Prepare to get QoS notifications
  953. if((QoSEvents = WSACreateEvent()) == WSA_INVALID_EVENT){
  954. fprintf(stderr,
  955. "Failed to create an event for QoS notifications %ld\n",
  956. WSAGetLastError());
  957. exit(1);
  958. }
  959. if(WSAEventSelect(fd, QoSEvents, FD_QOS) == SOCKET_ERROR){
  960. fprintf(stderr,
  961. "Unable to get notifications for QoS events. %ld\n",
  962. WSAGetLastError());
  963. }
  964. if(trans){
  965. // Set QoS on sending traffic
  966. if(SetQoSSocket(fd, TRUE)){
  967. exit(1);
  968. }
  969. fprintf(stdout, "Initiated QoS connection. Waiting for receiver.\n");
  970. WaitForQoS(SENDER, fd);
  971. }
  972. else{ // we're the receiver, so bind and wait
  973. if(bind(fd, (PSOCKADDR)&sinme, sizeof(sinme)) < 0){
  974. printf("bind() failed: %ld\n", GetLastError( ));
  975. }
  976. if(SetQoSSocket(fd, FALSE)){
  977. exit(1);
  978. }
  979. fprintf(stdout, "Waiting for QoS sender to initiate QoS connection.\n");
  980. WaitForQoS(RECEIVER, fd);
  981. }
  982. // set some options
  983. // none to set!
  984. g_params.hSocket = (HANDLE)fd;
  985. } // SetupSockets()
  986. SOCKET
  987. OpenQoSSocket(
  988. )
  989. {
  990. INT bufferSize = 0;
  991. INT numProtocols;
  992. LPWSAPROTOCOL_INFO installedProtocols, qosProtocol;
  993. INT i;
  994. SOCKET fd;
  995. BOOLEAN QoSInstalled = FALSE;
  996. // Call WSAEnumProtocols to determine buffer size required
  997. numProtocols = WSAEnumProtocols(NULL, NULL, &bufferSize);
  998. if((numProtocols != SOCKET_ERROR) && (WSAGetLastError() != WSAENOBUFS)){
  999. printf("Failed to enumerate protocols!\n");
  1000. return((UINT_PTR)NULL);
  1001. }
  1002. else{
  1003. // Enumerate the protocols, find the QoS enabled one
  1004. installedProtocols = (LPWSAPROTOCOL_INFO)malloc(bufferSize);
  1005. numProtocols = WSAEnumProtocols(NULL,
  1006. (LPVOID)installedProtocols,
  1007. &bufferSize);
  1008. if(numProtocols == SOCKET_ERROR){
  1009. printf("Failed to enumerate protocols!\n");
  1010. return((UINT_PTR)NULL);
  1011. }
  1012. else{
  1013. qosProtocol = installedProtocols;
  1014. for(i=0; i<numProtocols; i++){
  1015. if((qosProtocol->dwServiceFlags1 & XP1_QOS_SUPPORTED)&&
  1016. (qosProtocol->dwServiceFlags1 & XP1_CONNECTIONLESS) &&
  1017. (qosProtocol->iAddressFamily == AF_INET)){
  1018. QoSInstalled = TRUE;
  1019. break;
  1020. }
  1021. qosProtocol++;
  1022. }
  1023. }
  1024. // Now open the socket.
  1025. if (!QoSInstalled) {
  1026. fprintf(stderr,"ERROR: No QoS protocols installed on this machine\n");
  1027. exit(1);
  1028. }
  1029. fd = WSASocket(0,
  1030. SOCK_DGRAM,
  1031. 0,
  1032. qosProtocol,
  1033. 0,
  1034. WSA_FLAG_OVERLAPPED);
  1035. free(installedProtocols);
  1036. return(fd);
  1037. }
  1038. } // OpenQoSSocket()
  1039. INT
  1040. SetQoSSocket(
  1041. SOCKET fd,
  1042. BOOL Sending)
  1043. {
  1044. QOS qos;
  1045. INT status;
  1046. LPFLOWSPEC flowSpec;
  1047. INT dummy;
  1048. INT receiverServiceType = Sending?
  1049. SERVICETYPE_NOTRAFFIC:
  1050. g_params.dwServiceType;
  1051. qos.ProviderSpecific.len = 0;
  1052. qos.ProviderSpecific.buf = 0;
  1053. // receiving flowspec is either NO_TRAFFIC (on a sender) or all
  1054. // defaults except for the service type (on a receiver)
  1055. flowSpec = &qos.ReceivingFlowspec;
  1056. flowSpec->TokenRate = QOS_NOT_SPECIFIED;
  1057. flowSpec->TokenBucketSize = QOS_NOT_SPECIFIED;
  1058. flowSpec->PeakBandwidth = QOS_NOT_SPECIFIED;
  1059. flowSpec->Latency = QOS_NOT_SPECIFIED;
  1060. flowSpec->DelayVariation = QOS_NOT_SPECIFIED;
  1061. flowSpec->ServiceType = receiverServiceType;
  1062. flowSpec->MaxSduSize = QOS_NOT_SPECIFIED;
  1063. flowSpec->MinimumPolicedSize = QOS_NOT_SPECIFIED;
  1064. // now do the sending flowspec
  1065. flowSpec = &qos.SendingFlowspec;
  1066. if(Sending){
  1067. if (g_params.RateInBytes)
  1068. flowSpec->TokenRate = g_params.TokenRate;
  1069. else
  1070. flowSpec->TokenRate = g_params.TokenRate * 1000;
  1071. flowSpec->TokenBucketSize = g_params.BucketSize;
  1072. if (g_params.ForceShape) {
  1073. if (g_params.RateInBytes)
  1074. flowSpec->PeakBandwidth = g_params.TokenRate;
  1075. else
  1076. flowSpec->PeakBandwidth = g_params.TokenRate * 1000;
  1077. }
  1078. else
  1079. flowSpec->PeakBandwidth = QOS_NOT_SPECIFIED;
  1080. flowSpec->Latency = QOS_NOT_SPECIFIED;
  1081. flowSpec->DelayVariation = QOS_NOT_SPECIFIED;
  1082. flowSpec->ServiceType = g_params.dwServiceType;
  1083. if (g_params.ForceShape && flowSpec->ServiceType == SERVICETYPE_BESTEFFORT )
  1084. flowSpec->ServiceType = SERVICETYPE_GUARANTEED | SERVICE_NO_QOS_SIGNALING;
  1085. flowSpec->MaxSduSize = g_params.MaxSDUSize;
  1086. flowSpec->MinimumPolicedSize = g_params.MinPolicedSize;
  1087. printf("Sending Flowspec\n");
  1088. PrintFlowspec(&qos.SendingFlowspec);
  1089. status = WSAConnect(fd,
  1090. (PSOCKADDR)&sinhim,
  1091. sizeof(sinhim),
  1092. NULL,
  1093. NULL,
  1094. &qos,
  1095. NULL);
  1096. if(status){
  1097. printf("SetQoS failed on socket: %ld\n", WSAGetLastError());
  1098. }
  1099. }
  1100. else{
  1101. flowSpec->TokenRate = QOS_NOT_SPECIFIED;
  1102. flowSpec->TokenBucketSize = QOS_NOT_SPECIFIED;
  1103. flowSpec->PeakBandwidth = QOS_NOT_SPECIFIED;
  1104. flowSpec->Latency = QOS_NOT_SPECIFIED;
  1105. flowSpec->DelayVariation = QOS_NOT_SPECIFIED;
  1106. flowSpec->ServiceType = SERVICETYPE_NOTRAFFIC;
  1107. flowSpec->MaxSduSize = QOS_NOT_SPECIFIED;
  1108. flowSpec->MinimumPolicedSize = QOS_NOT_SPECIFIED;
  1109. status = WSAIoctl(fd,
  1110. SIO_SET_QOS,
  1111. &qos,
  1112. sizeof(QOS),
  1113. NULL,
  1114. 0,
  1115. &dummy,
  1116. NULL,
  1117. NULL);
  1118. if(status){
  1119. printf("SetQoS failed on socket: %ld\n", WSAGetLastError());
  1120. }
  1121. }
  1122. return(status);
  1123. } // SetQoSSocket()
  1124. VOID
  1125. WaitForQoS(
  1126. BOOL Sender,
  1127. SOCKET fd)
  1128. {
  1129. ULONG status;
  1130. if(!g_params.Wait){
  1131. // For best effort, we don't do anything QoS... Return
  1132. // right away. In this case, the sender should be started
  1133. // after the reciever, since there is no synchronization
  1134. // via rsvp and data could be missed.
  1135. fprintf(stdout, "WARNING: Not waiting for QoS reservation.\n");
  1136. return;
  1137. }
  1138. while(TRUE){
  1139. // get the statuscode, waiting for as long as it takes
  1140. status = GetRsvpStatus(WSA_INFINITE,fd);
  1141. switch (status) {
  1142. case WSA_QOS_RECEIVERS: // at least one RESV has arrived
  1143. if (Sender)
  1144. fprintf(stdout, "QoS reservation installed for %s service.\n", g_params.szServiceType);
  1145. break;
  1146. case WSA_QOS_SENDERS: // at least one PATH has arrived
  1147. if (!Sender)
  1148. fprintf(stdout, "QoS sender detected using %s service.\n", g_params.szServiceType);
  1149. break;
  1150. default:
  1151. PrintRSVPStatus(status);
  1152. break;
  1153. }
  1154. // if we received one of the coveted status codes, break out
  1155. // altogether. otherwise wait and see if we get another batch
  1156. // of indications.
  1157. if( ((status == WSA_QOS_RECEIVERS) && Sender) ||
  1158. ((status == WSA_QOS_SENDERS) && !Sender) ) {
  1159. break;
  1160. }
  1161. }
  1162. } // WaitForQoS()
  1163. ULONG
  1164. GetRsvpStatus(
  1165. DWORD dwTimeout,
  1166. SOCKET fd)
  1167. {
  1168. LPQOS qos;
  1169. UCHAR qosBuffer[500];
  1170. LPRSVP_STATUS_INFO rsvpStatus;
  1171. INT bytesReturned;
  1172. qos = (LPQOS)qosBuffer;
  1173. qos->ProviderSpecific.len = sizeof(RSVP_STATUS_INFO);
  1174. qos->ProviderSpecific.buf = (PUCHAR)(qos+1);
  1175. // wait for notification that a QoS event has occured
  1176. WSAWaitForMultipleEvents(1,
  1177. &QoSEvents,
  1178. FALSE,
  1179. dwTimeout,
  1180. TRUE);
  1181. // loop through all qos events
  1182. WSAIoctl(fd,
  1183. SIO_GET_QOS,
  1184. NULL,
  1185. 0,
  1186. qosBuffer,
  1187. sizeof(qosBuffer),
  1188. &bytesReturned,
  1189. NULL,
  1190. NULL);
  1191. rsvpStatus = (LPRSVP_STATUS_INFO)qos->ProviderSpecific.buf;
  1192. return rsvpStatus->StatusCode;
  1193. } // GetRsvpStatus
  1194. VOID
  1195. PrintRSVPStatus(ULONG code)
  1196. {
  1197. switch (code) {
  1198. case WSA_QOS_RECEIVERS: // at least one RESV has arrived
  1199. printf("WSA_QOS_RECEIVERS\n");
  1200. break;
  1201. case WSA_QOS_SENDERS: // at least one PATH has arrived
  1202. printf("WSA_QOS_SENDERS\n");
  1203. break;
  1204. case WSA_QOS_REQUEST_CONFIRMED: // Reserve has been confirmed
  1205. printf("WSA_QOS_REQUEST_CONFIRMED\n");
  1206. break;
  1207. case WSA_QOS_ADMISSION_FAILURE: // error due to lack of resources
  1208. printf("WSA_QOS_ADMISSION_FAILURE\n");
  1209. break;
  1210. case WSA_QOS_POLICY_FAILURE: // rejected for admin reasons
  1211. printf("WSA_QOS_POLICY_FAILURE\n");
  1212. break;
  1213. case WSA_QOS_BAD_STYLE: // unknown or conflicting style
  1214. printf("WSA_QOS_BAD_STYLE\n");
  1215. break;
  1216. case WSA_QOS_BAD_OBJECT: // problem with some part of the
  1217. // filterspec/providerspecific
  1218. // buffer in general
  1219. printf("WSA_QOS_BAD_OBJECT\n");
  1220. break;
  1221. case WSA_QOS_TRAFFIC_CTRL_ERROR: // problem with some part of the
  1222. // flowspec
  1223. printf("WSA_QOS_TRAFFIC_CTRL_ERROR\n");
  1224. break;
  1225. case WSA_QOS_GENERIC_ERROR: // general error
  1226. printf("WSA_QOS_GENERIC_ERROR\n");
  1227. break;
  1228. default:
  1229. printf("Unknown RSVP StatusCode %lu\n", code);
  1230. break;
  1231. }
  1232. } // PrintRSVPStatus
  1233. VOID
  1234. DoTransmit()
  1235. {
  1236. IOREQ IOReq[MAX_PENDING_IO_REQS] = { 0 };
  1237. INT i;
  1238. BOOL ret;
  1239. BOOL fOk;
  1240. g_state.nBytesTransferred = 0;
  1241. g_state.nBuffersSent = 0;
  1242. g_state.nWritesInProgress = 0;
  1243. // fill up the initial buffers and send them on their way
  1244. for (i=0; i<MAX_PENDING_IO_REQS; i++) {
  1245. IOReq[i].pBuffer = malloc(g_params.buflen);
  1246. FillBuffer(IOReq[i].pBuffer,g_params.buflen);
  1247. TimeStamp(IOReq[i].pBuffer,g_params.buflen);
  1248. IOReq[i].Overlapped.Internal = 0;
  1249. IOReq[i].Overlapped.InternalHigh = 0;
  1250. IOReq[i].Overlapped.Offset = 0;
  1251. IOReq[i].Overlapped.OffsetHigh = 0;
  1252. IOReq[i].Overlapped.hEvent = NULL;
  1253. if (g_state.nBuffersSent < totalBuffers) {
  1254. WriteFileEx(g_params.hSocket,
  1255. IOReq[i].pBuffer,
  1256. g_params.buflen,
  1257. &IOReq[i].Overlapped,
  1258. TransmitCompletionRoutine);
  1259. g_state.nWritesInProgress++;
  1260. g_state.nBuffersSent++;
  1261. }
  1262. }
  1263. // now loop until an error happens or we're done writing to the socket
  1264. while (g_state.nWritesInProgress > 0) {
  1265. SleepEx(INFINITE, TRUE);
  1266. }
  1267. // send the end of transmission delimiters
  1268. for (i=0; i<MAX_PENDING_IO_REQS; i++) {
  1269. strncpy(IOReq[i].pBuffer,TheEnd,strlen(TheEnd));
  1270. fOk = WriteFileEx(g_params.hSocket,
  1271. IOReq[i].pBuffer,
  1272. strlen(TheEnd),
  1273. &IOReq[i].Overlapped,
  1274. DelimiterSendCompletion);
  1275. g_state.nWritesInProgress++;
  1276. if (!fOk) {
  1277. printf("WriteFileEx() failed: %lu\n",GetLastError());
  1278. }
  1279. }
  1280. // wait for all the delimiters to be sent
  1281. while (g_state.nWritesInProgress > 0) {
  1282. SleepEx(INFINITE, TRUE);
  1283. }
  1284. // free up the used memory
  1285. for (i=0; i<MAX_PENDING_IO_REQS; i++) {
  1286. free(IOReq[i].pBuffer);
  1287. }
  1288. } // DoTransmit()
  1289. VOID WINAPI
  1290. TransmitCompletionRoutine(
  1291. DWORD dwErrorCode,
  1292. DWORD dwNumberOfBytesTransferred,
  1293. LPOVERLAPPED pOverlapped)
  1294. {
  1295. PIOREQ pIOReq = (PIOREQ) pOverlapped;
  1296. BOOL fOk;
  1297. if (dwErrorCode == ERROR_REQUEST_ABORTED) {
  1298. g_state.Done = TRUE;
  1299. }
  1300. else if (dwErrorCode != NO_ERROR) {
  1301. printf("ERROR: Write completed abnormally: %u\n",dwErrorCode);
  1302. }
  1303. g_state.nWritesInProgress--;
  1304. g_state.nBytesTransferred += dwNumberOfBytesTransferred;
  1305. // check to make sure we're not done
  1306. if (g_state.Done)
  1307. return;
  1308. // give some indication of life
  1309. if(!(g_state.nBuffersSent % 100)){
  1310. fprintf(stdout, ".");
  1311. }
  1312. // if there are more buffers to go, send one
  1313. if (g_state.nBuffersSent < totalBuffers || g_params.RunForever) {
  1314. // see if this was the last of the calibration buffers (if we want confirmation)
  1315. if (g_params.SkipConfirm == FALSE) {
  1316. if (g_params.calibration && (g_state.nBuffersSent == g_params.calibration)) {
  1317. printf("\nCalibration complete. Type 'c' to continue.\n");
  1318. while(TRUE){
  1319. if(getchar() == 'c'){
  1320. break;
  1321. }
  1322. }
  1323. }
  1324. }
  1325. // fill in the buffer with new values
  1326. FillBuffer(pIOReq->pBuffer,g_params.buflen);
  1327. TimeStamp(pIOReq->pBuffer,g_params.buflen);
  1328. // send a request to write the new buffer
  1329. fOk = WriteFileEx(g_params.hSocket,
  1330. pIOReq->pBuffer,
  1331. g_params.buflen,
  1332. pOverlapped,
  1333. TransmitCompletionRoutine);
  1334. if (!fOk) {
  1335. printf("WriteFileEx() failed: %lu\n",GetLastError());
  1336. }
  1337. g_state.nWritesInProgress++;
  1338. g_state.nBuffersSent++;
  1339. }
  1340. } // TransmitCompletionRoutine()
  1341. VOID WINAPI
  1342. DelimiterSendCompletion(
  1343. DWORD dwErrorCode,
  1344. DWORD dwNumberOfBytesTransferred,
  1345. LPOVERLAPPED pOverlapped)
  1346. {
  1347. g_state.nWritesInProgress--;
  1348. } // DelimiterSendCompletion()
  1349. VOID
  1350. FillBuffer(
  1351. CHAR *Cp,
  1352. INT Cnt)
  1353. {
  1354. PBUFFER_FORMAT buf = (PBUFFER_FORMAT) Cp;
  1355. CHAR c = 0;
  1356. // Fill with a background pattern
  1357. if (g_params.RandomFiller) { // incompressible
  1358. while(Cnt-- > 0) {
  1359. c = rand() % 0x5F;
  1360. c += 0x20;
  1361. *Cp++ = c;
  1362. }
  1363. }
  1364. else { // compressible
  1365. while(Cnt-- > 0){
  1366. while(!isprint((c&0x7F))) c++;
  1367. *Cp++ = (c++&0x7F);
  1368. }
  1369. }
  1370. buf->TimeSent = -1;
  1371. buf->TimeReceived = -1;
  1372. } // FillBuffer()
  1373. INT
  1374. TimeStamp(
  1375. CHAR *Cp,
  1376. INT Cnt)
  1377. {
  1378. PBUFFER_FORMAT record;
  1379. LARGE_INTEGER timeSent;
  1380. INT64 time;
  1381. record = (BUFFER_FORMAT *)Cp;
  1382. // Stamp with length and sequence number
  1383. if(Cnt < sizeof(BUFFER_FORMAT)){
  1384. printf("ERROR: Buffer length smaller than record size!\n");
  1385. return(0);
  1386. }
  1387. else{
  1388. time = GetUserTime();
  1389. record->TimeSentUser = time;
  1390. record->BufferSize = Cnt;
  1391. record->SequenceNumber = SequenceNumber++;
  1392. }
  1393. return 1;
  1394. } // TimeStamp()
  1395. VOID
  1396. DoReceive()
  1397. {
  1398. IOREQ IOReq[MAX_PENDING_IO_REQS] = { 0 };
  1399. INT i;
  1400. BOOL ret;
  1401. // set the start state
  1402. g_state.Done = FALSE;
  1403. g_state.nBytesTransferred = 0;
  1404. g_state.nBuffersReceived = 0;
  1405. g_state.nReadsInProgress = 0;
  1406. // fill up the initial buffers and send them on their way
  1407. for (i=0; i<MAX_PENDING_IO_REQS; i++) {
  1408. IOReq[i].pBuffer = malloc(g_params.buflen);
  1409. IOReq[i].Overlapped.Internal = 0;
  1410. IOReq[i].Overlapped.InternalHigh = 0;
  1411. IOReq[i].Overlapped.Offset = 0;
  1412. IOReq[i].Overlapped.OffsetHigh = 0;
  1413. IOReq[i].Overlapped.hEvent = NULL;
  1414. if (g_state.nBuffersReceived < totalBuffers) {
  1415. ReadFileEx(g_params.hSocket,
  1416. IOReq[i].pBuffer,
  1417. g_params.buflen,
  1418. &IOReq[i].Overlapped,
  1419. RecvCompletionRoutine);
  1420. g_state.nReadsInProgress++;
  1421. }
  1422. }
  1423. InitializeCriticalSection(&g_csLogRecord);
  1424. // now loop until an error happens or we're done writing to the socket
  1425. while ((g_state.nReadsInProgress > 0) && !g_state.Done) {
  1426. SleepEx(5000, TRUE);
  1427. if (g_state.Done)
  1428. break;
  1429. }
  1430. DeleteCriticalSection(&g_csLogRecord);
  1431. // cancel the other pending reads
  1432. CancelIo(g_params.hSocket);
  1433. // free up the used memory
  1434. for (i=0; i<MAX_PENDING_IO_REQS; i++) {
  1435. free(IOReq[i].pBuffer);
  1436. }
  1437. } // DoReceive()
  1438. VOID WINAPI
  1439. RecvCompletionRoutine(
  1440. DWORD dwErrorCode,
  1441. DWORD dwNumberOfBytesTransferred,
  1442. LPOVERLAPPED pOverlapped)
  1443. {
  1444. PIOREQ pIOReq = (PIOREQ) pOverlapped;
  1445. BOOL fOk;
  1446. static BOOL fLastWasError = FALSE;
  1447. g_state.nReadsInProgress--;
  1448. g_state.nBytesTransferred += dwNumberOfBytesTransferred;
  1449. if (dwNumberOfBytesTransferred == 0) { // an error occurred
  1450. if (!fLastWasError) {
  1451. printf("ERROR in RecvCompletionRoutine: code=%d, lasterr=%d\n",
  1452. dwErrorCode, GetLastError());
  1453. printf("\tReceived no data. Telling sender to abort...\n");
  1454. SendControlMessage(g_sockControl, MSGST_ERROR);
  1455. }
  1456. fLastWasError = TRUE;
  1457. }
  1458. else fLastWasError = FALSE;
  1459. // if this is the first packet we've received, save the system time
  1460. if (g_state.nBuffersReceived == 0) {
  1461. GetSystemTime(&systimeStart);
  1462. }
  1463. // give some indication of life
  1464. if(!(g_state.nBuffersReceived % 100)){
  1465. fprintf(stdout, ".");
  1466. }
  1467. // end of transmission delimiter? if so, set the total buffers to the number got
  1468. if(!(strncmp(pIOReq->pBuffer, TheEnd, 6))) {
  1469. totalBuffers = g_state.nBuffersReceived;
  1470. g_state.Done = TRUE;
  1471. }
  1472. // check to see if someone's set our done flag (if they have, leave)
  1473. if (g_state.Done)
  1474. return;
  1475. // if not, then the buffer should hold a scheduling record.
  1476. if(dwNumberOfBytesTransferred>0 && dwNumberOfBytesTransferred <= sizeof(BUFFER_FORMAT)) {
  1477. printf("Buffer too small for scheduling record\n");
  1478. printf("\tOnly %d bytes read.\n", dwNumberOfBytesTransferred);
  1479. }
  1480. // Log the record, but don't log more than one at a time (lock on this call)
  1481. if (dwNumberOfBytesTransferred >= sizeof(BUFFER_FORMAT) &&
  1482. g_state.nBuffersReceived % g_params.LoggingPeriod == 0) {
  1483. EnterCriticalSection(&g_csLogRecord);
  1484. LogRecord(pIOReq->pBuffer);
  1485. LeaveCriticalSection(&g_csLogRecord);
  1486. }
  1487. // if there are more buffers (or if we don't know how many are coming), ask for one
  1488. if ((g_state.nBuffersReceived < totalBuffers) || g_params.nBufUnspecified) {
  1489. // send a request to read the next buffer
  1490. fOk = ReadFileEx(g_params.hSocket,
  1491. pIOReq->pBuffer,
  1492. g_params.buflen,
  1493. pOverlapped,
  1494. RecvCompletionRoutine);
  1495. if (!fOk) {
  1496. printf("ReadFileEx() failed: %lu\n",GetLastError());
  1497. }
  1498. g_state.nReadsInProgress++;
  1499. g_state.nBuffersReceived++;
  1500. }
  1501. } // RecvCompletionRoutine()
  1502. void LogRecord(char * Buffer)
  1503. {
  1504. // This function copies the recieved record to the scheduling array.
  1505. // The contents of the array are processed and written to file once
  1506. // reception is complete.
  1507. PBUFFER_FORMAT inRecord = (PBUFFER_FORMAT)Buffer;
  1508. LOG_RECORD outRecord;
  1509. INT64 time;
  1510. SYSTEMTIME CurrentTime;
  1511. time = GetUserTime();
  1512. outRecord.TimeSentUser = inRecord->TimeSentUser;
  1513. outRecord.TimeReceivedUser = time;
  1514. outRecord.TimeSent = inRecord->TimeSent;
  1515. outRecord.TimeReceived = inRecord->TimeReceived;
  1516. outRecord.BufferSize = inRecord->BufferSize;
  1517. outRecord.SequenceNumber = inRecord->SequenceNumber;
  1518. if (inRecord->TimeSent == -1) {
  1519. outRecord.TimeSent = outRecord.TimeSentUser;
  1520. g_params.NoSenderTimestamps = TRUE;
  1521. }
  1522. if (inRecord->TimeReceived == -1) {
  1523. outRecord.TimeReceived = outRecord.TimeReceivedUser;
  1524. g_params.NoReceiverTimestamps = TRUE;
  1525. }
  1526. if(g_params.UserStamps){
  1527. outRecord.TimeSent = outRecord.TimeSentUser;
  1528. outRecord.TimeReceived = outRecord.TimeReceivedUser;
  1529. }
  1530. outRecord.Latency = outRecord.TimeReceived - outRecord.TimeSent;
  1531. AddLogEntry(&g_log, &outRecord);
  1532. if(g_params.PrintDrops){
  1533. if(inRecord->SequenceNumber != LastSequenceNumber + g_params.LoggingPeriod){
  1534. GetLocalTime(&CurrentTime);
  1535. printf("\n%4d/%02d/%02d %02d:%02d:%02d:%04d: ",
  1536. CurrentTime.wYear,
  1537. CurrentTime.wMonth,
  1538. CurrentTime.wDay,
  1539. CurrentTime.wHour,
  1540. CurrentTime.wMinute,
  1541. CurrentTime.wSecond,
  1542. CurrentTime.wMilliseconds);
  1543. printf("Dropped %d packets after packet %d.\n",
  1544. inRecord->SequenceNumber - LastSequenceNumber,
  1545. LastSequenceNumber);
  1546. }
  1547. LastSequenceNumber = inRecord->SequenceNumber;
  1548. }
  1549. return;
  1550. } // LogRecord()
  1551. BOOL CreateLog(PLOG plog, INT64 c) {
  1552. // sets up a log structure that can hold c entries
  1553. char szTempFile[MAX_PATH];
  1554. char szTempPath[MAX_PATH];
  1555. SYSTEM_INFO si;
  1556. DWORD dwFileSizeHigh;
  1557. DWORD dwFileSizeLow;
  1558. INT64 qwFileSize;
  1559. // get some system info
  1560. GetSystemInfo(&si);
  1561. // allocate logging array
  1562. plog->nBuffersLogged = 0;
  1563. plog->pbMapView = NULL;
  1564. plog->qwMapViewOffset = -1;
  1565. // set up the temporary storage file for logging
  1566. GetTempPath(MAX_PATH, szTempPath);
  1567. GetTempFileName(szTempPath, "qtc", 0, szTempFile);
  1568. plog->szStorageFile = malloc(strlen(szTempFile) + 1);
  1569. strcpy(plog->szStorageFile, szTempFile);
  1570. plog->hStorageFile = CreateFile(szTempFile, GENERIC_READ | GENERIC_WRITE, 0,
  1571. NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
  1572. if (plog->hStorageFile == INVALID_HANDLE_VALUE)
  1573. ErrorExit("Could not create temp storage file",GetLastError());
  1574. // create the memory mapping kernel object
  1575. qwFileSize = c * sizeof(LOG_RECORD);
  1576. dwFileSizeHigh = (DWORD) (qwFileSize >> 32);
  1577. dwFileSizeLow = (DWORD) (qwFileSize & 0xFFFFFFFF);
  1578. plog->qwFileSize = qwFileSize;
  1579. plog->hFileMapping = CreateFileMapping(plog->hStorageFile, NULL, PAGE_READWRITE,
  1580. dwFileSizeHigh,dwFileSizeLow,NULL);
  1581. if (plog->hFileMapping == NULL)
  1582. ErrorExit("Could not create mapping for temp storage file",GetLastError());
  1583. return TRUE;
  1584. }
  1585. BOOL DestroyLog(PLOG plog) {
  1586. DWORD dwError;
  1587. // destroys the log and all associated data
  1588. dwError = CloseHandle(plog->hFileMapping);
  1589. if (!dwError) printf("Error in DestroyLog:CloseHandle(FileMapping) %d\n",GetLastError());
  1590. dwError = CloseHandle(plog->hStorageFile);
  1591. if (!dwError) printf("Error in DestroyLog:CloseHandle(StorageFile) %d\n",GetLastError());
  1592. dwError = UnmapViewOfFile(plog->pbMapView);
  1593. if (!dwError) printf("Error in DestroyLog:UnmapViewOfFile(plog->pbMapView) %d\n",GetLastError());
  1594. dwError = DeleteFile(plog->szStorageFile);
  1595. if (!dwError) printf("Error in DestroyLog:DeleteFile(StroageFile) %d\n",GetLastError());
  1596. free(plog->szStorageFile);
  1597. return FALSE;
  1598. }
  1599. void PrintLogRecord(PLOG_RECORD prec) {
  1600. char szBuf[MAX_STRING];
  1601. sprintf(szBuf,"%d: %I64u - %I64u (%I64d)",
  1602. prec->SequenceNumber,prec->TimeSent,prec->TimeReceived,prec->Latency);
  1603. puts(szBuf);
  1604. }
  1605. BOOL ExtendLog(PLOG plog) {
  1606. // makes the log bigger by some fixed constant
  1607. HANDLE hNewFileMapping;
  1608. INT64 qwNewFileSize;
  1609. UnmapViewOfFile(plog->pbMapView);
  1610. qwNewFileSize = plog->qwFileSize + g_si.dwAllocationGranularity * sizeof(LOG_RECORD);
  1611. hNewFileMapping = CreateFileMapping(plog->hStorageFile, NULL, PAGE_READWRITE,
  1612. (DWORD)(qwNewFileSize >> 32), (DWORD)(qwNewFileSize & 0xFFFFFFFF), NULL);
  1613. if (hNewFileMapping == NULL) {
  1614. ErrorExit("Could not create mapping for temp storage file",GetLastError());
  1615. return FALSE;
  1616. }
  1617. plog->qwFileSize = qwNewFileSize;
  1618. CloseHandle(plog->hFileMapping);
  1619. plog->hFileMapping = hNewFileMapping;
  1620. plog->qwMapViewOffset = -1;
  1621. return TRUE;
  1622. }
  1623. BOOL GetLogEntry(PLOG plog, PLOG_RECORD prec, INT64 i) {
  1624. // fills prec with the (0 indexed) i'th log in plog
  1625. // returns TRUE if it was successful, FALSE otherwise
  1626. INT64 qwT;
  1627. PLOG_RECORD entry;
  1628. // first, check to see if this is within the range of our file
  1629. if ((INT64)((i+1)*sizeof(LOG_RECORD)) > plog->qwFileSize) {
  1630. // too high, so we return false
  1631. return FALSE;
  1632. }
  1633. // we have to round down to the nearest allocation boundary
  1634. qwT = sizeof(LOG_RECORD) * i; // offset within file
  1635. qwT /= g_si.dwAllocationGranularity; // in allocation granularity units
  1636. // check to see if we do not already have this mapped in memory
  1637. if (plog->qwMapViewOffset != qwT * g_si.dwAllocationGranularity) {
  1638. if (plog->pbMapView != NULL) UnmapViewOfFile(plog->pbMapView);
  1639. plog->qwMapViewOffset = qwT * g_si.dwAllocationGranularity; // offset of lower allocation bound
  1640. if (plog->qwFileSize < (INT64)g_si.dwAllocationGranularity) {
  1641. // file is smaller than allocation granularity
  1642. plog->qwMapViewOffset = 0;
  1643. plog->pbMapView = MapViewOfFile(plog->hFileMapping, FILE_MAP_WRITE, 0, 0, 0);
  1644. }
  1645. else if (plog->qwFileSize - plog->qwMapViewOffset < g_si.dwAllocationGranularity) {
  1646. // we're within an allocation granularity of the end of the file
  1647. plog->pbMapView = MapViewOfFile(plog->hFileMapping, FILE_MAP_WRITE,
  1648. (DWORD)(plog->qwMapViewOffset >> 32),
  1649. (DWORD)(plog->qwMapViewOffset & 0xFFFFFFFF),
  1650. (DWORD)(plog->qwFileSize - plog->qwMapViewOffset));
  1651. }
  1652. else {
  1653. // we're just somewhere in the file with space around us
  1654. plog->pbMapView = MapViewOfFile(plog->hFileMapping, FILE_MAP_WRITE,
  1655. (DWORD)(plog->qwMapViewOffset >> 32),
  1656. (DWORD)(plog->qwMapViewOffset & 0xFFFFFFFF),
  1657. RoundUp(g_si.dwAllocationGranularity,sizeof(LOG_RECORD)));
  1658. }
  1659. if (plog->pbMapView == NULL)
  1660. ErrorExit("GetLogEntry could not MapViewOfFile",GetLastError());
  1661. }
  1662. qwT = sizeof(LOG_RECORD) * i;
  1663. entry = (PLOG_RECORD)(plog->pbMapView + (qwT - plog->qwMapViewOffset));
  1664. CopyMemory(prec, entry, sizeof(LOG_RECORD));
  1665. return TRUE;
  1666. }
  1667. BOOL SetLogEntry(PLOG plog, PLOG_RECORD prec, INT64 i) {
  1668. // fills log entry i with the data pointed to by prec
  1669. // returns TRUE if it was successful, FALSE otherwise
  1670. INT64 qwT;
  1671. PLOG_RECORD entry;
  1672. // first, check to see if this is within the range of our file
  1673. if ((INT64)((i+1)*sizeof(LOG_RECORD)) > plog->qwFileSize) {
  1674. // we need to make our mapping bigger
  1675. ExtendLog(plog);
  1676. }
  1677. // we have to round down to the nearest allocation boundary
  1678. qwT = sizeof(LOG_RECORD) * i; // offset within file
  1679. qwT /= g_si.dwAllocationGranularity; // in allocation granularity units
  1680. // check to see if we do not already have this mapped in memory
  1681. if (plog->qwMapViewOffset != qwT * g_si.dwAllocationGranularity) {
  1682. if (plog->pbMapView != NULL) UnmapViewOfFile(plog->pbMapView);
  1683. plog->qwMapViewOffset = qwT * g_si.dwAllocationGranularity; // offset of lower allocation bound
  1684. if (plog->qwFileSize < (INT64)g_si.dwAllocationGranularity) {
  1685. // file is smaller than allocation granularity
  1686. plog->qwMapViewOffset = 0;
  1687. plog->pbMapView = MapViewOfFile(plog->hFileMapping, FILE_MAP_WRITE, 0, 0, 0);
  1688. }
  1689. else if (plog->qwFileSize - plog->qwMapViewOffset < g_si.dwAllocationGranularity) {
  1690. // we're within an allocation granularity of the end of the file
  1691. plog->pbMapView = MapViewOfFile(plog->hFileMapping, FILE_MAP_WRITE,
  1692. (DWORD)(plog->qwMapViewOffset >> 32),
  1693. (DWORD)(plog->qwMapViewOffset & 0xFFFFFFFF),
  1694. (DWORD)(plog->qwFileSize - plog->qwMapViewOffset));
  1695. }
  1696. else {
  1697. // we're just somewhere in the file with space around us
  1698. plog->pbMapView = MapViewOfFile(plog->hFileMapping, FILE_MAP_WRITE,
  1699. (DWORD)(plog->qwMapViewOffset >> 32),
  1700. (DWORD)(plog->qwMapViewOffset & 0xFFFFFFFF),
  1701. RoundUp(g_si.dwAllocationGranularity,sizeof(LOG_RECORD)));
  1702. }
  1703. if (plog->pbMapView == NULL)
  1704. ErrorExit("SetLogEntry could not MapViewOfFile",GetLastError());
  1705. }
  1706. qwT = sizeof(LOG_RECORD) * i;
  1707. entry = (PLOG_RECORD)(plog->pbMapView + (qwT - plog->qwMapViewOffset));
  1708. CopyMemory(entry, prec, sizeof(LOG_RECORD));
  1709. return TRUE;
  1710. }
  1711. BOOL AddLogEntry(PLOG plog, PLOG_RECORD prec) {
  1712. PLOG_RECORD entry;
  1713. // adds the data pointed to by prec to the end of the log
  1714. // returns TRUE if it was successful, FALSE otherwise
  1715. SetLogEntry(plog, prec, plog->nBuffersLogged);
  1716. plog->nBuffersLogged++;
  1717. return TRUE;
  1718. }
  1719. UINT64
  1720. GetUserTime()
  1721. { // This function returns the performance counter time in units of 100ns
  1722. LARGE_INTEGER count, freq;
  1723. NtQueryPerformanceCounter(&count,&freq);
  1724. // make sure we have hardware performance counting
  1725. if(freq.QuadPart == 0) {
  1726. NtQuerySystemTime(&count);
  1727. return (UINT64)count.QuadPart;
  1728. }
  1729. return (UINT64)((10000000 * count.QuadPart) / freq.QuadPart);
  1730. } // GetUserTime()
  1731. UINT64
  1732. GetBadHalAdjustment() {
  1733. // this function returns the amount the hal timer in a machine with
  1734. // an intel chipset with the piix4 timer chip will jump forward in the case of
  1735. // repeated garbage returned fom the piix4 (bug #347410) so we can correct it out
  1736. // in the FixWackyTimestamps routine
  1737. LARGE_INTEGER freq;
  1738. UINT64 diff;
  1739. QueryPerformanceFrequency(&freq);
  1740. // so we want to find how much it is increased in 100ns intervals if we increase
  1741. // byte 3 by 1.
  1742. diff = 0x01000000;
  1743. diff *= 10000000;
  1744. diff /= (UINT64)freq.QuadPart;
  1745. return diff;
  1746. }
  1747. DWORD
  1748. MyCreateFile(
  1749. IN PCHAR Name,
  1750. IN PCHAR Extension,
  1751. OUT HANDLE *File)
  1752. {
  1753. HANDLE hFile;
  1754. UCHAR * fileName;
  1755. fileName = malloc(strlen(Name) + 5);
  1756. bzero(fileName,strlen(Name) + 5);
  1757. strncpy(fileName, Name, strlen(Name));
  1758. if (strlen(Extension)==4) {
  1759. strcat(fileName,Extension);
  1760. }
  1761. else
  1762. return !ERROR_SUCCESS;
  1763. hFile = CreateFile(fileName,
  1764. GENERIC_WRITE | GENERIC_READ,
  1765. 0,
  1766. NULL,
  1767. CREATE_ALWAYS,
  1768. FILE_ATTRIBUTE_NORMAL,
  1769. NULL);
  1770. *File = hFile;
  1771. return(INVALID_HANDLE_VALUE == hFile ? (!(ERROR_SUCCESS)) : ERROR_SUCCESS);
  1772. } // MyCreateFile()
  1773. void AggregateStats() {
  1774. // this will go through the directory specified in Name and aggregate stats from
  1775. // all the .sta files therein. it will then output the results of the aggregation
  1776. // in a file within that directory called stats.qtc
  1777. char szDirPath[3 * MAX_PATH];
  1778. char szSearchString[3 * MAX_PATH];
  1779. WIN32_FIND_DATA FileData; // Data structure describes the file found
  1780. HANDLE hSearch; // Search handle returned by FindFirstFile
  1781. PCHAR rgszStaFiles[1000]; // an array of the names of the .sta files
  1782. int cStaFiles = 0, i,j,k,l; // keeps track of how many of the .sta files there are
  1783. STATS * pStats;
  1784. int rgSizes[1000], cSizes = 0;
  1785. int rgRates[1000], cRates = 0;
  1786. char szAggFile[3 * MAX_PATH];
  1787. char szLineBuf[1000];
  1788. STATS statsT;
  1789. FILE *pfile;
  1790. FILETIME rgtime[1000];
  1791. SYSTEMTIME st;
  1792. ULARGE_INTEGER uliT;
  1793. int ctime = 0;
  1794. int cSpecs = 0;
  1795. PathCanonicalize(szDirPath,Name);
  1796. if (szDirPath[strlen(szDirPath) - 1] == '"') szDirPath[strlen(szDirPath) - 1] = 0;
  1797. if (!PathIsDirectory(szDirPath)) {
  1798. printf("Path (%s) is not a directory\n",szDirPath);
  1799. ErrorExit("Invalid Path for aggregate stats", -1);
  1800. }
  1801. // so now szDirPath is the path to the directory we want to go through
  1802. // and we begin our search for .sta files
  1803. sprintf(szSearchString,"%s\\*.sta",szDirPath);
  1804. hSearch = FindFirstFile (szSearchString, &FileData);
  1805. if (hSearch == INVALID_HANDLE_VALUE) {
  1806. ErrorExit("No .sta files found.",GetLastError());
  1807. }
  1808. do {
  1809. rgszStaFiles[cStaFiles] = malloc(sizeof(char) * 3 * MAX_PATH);
  1810. // check to see if it's a good .sta file
  1811. sprintf(statsT.szStaFile,"%s\\%s", szDirPath, FileData.cFileName);
  1812. if (GetStatsFromFile(&statsT)) {
  1813. // if it's good, include it
  1814. strcpy(rgszStaFiles[cStaFiles], FileData.cFileName);
  1815. cStaFiles++;
  1816. }
  1817. } while (FindNextFile(hSearch, &FileData));
  1818. if (GetLastError() != ERROR_NO_MORE_FILES) {
  1819. ErrorExit("Problem in FindNextFile()",GetLastError());
  1820. }
  1821. // open the stats file
  1822. sprintf(szAggFile,"%s\\stats.qtc",szDirPath);
  1823. pfile = fopen(szAggFile,"w+");
  1824. if (pfile == NULL) printf("Could not open file for aggregate stats: %s\n",szAggFile);
  1825. pStats = malloc(cStaFiles * sizeof(STATS));
  1826. ZeroMemory(pStats, cStaFiles * sizeof(STATS));
  1827. for (i=0; i<cStaFiles; i++) {
  1828. sprintf(pStats[i].szStaFile, "%s\\%s", szDirPath, rgszStaFiles[i]);
  1829. GetStatsFromFile(&(pStats[i]));
  1830. }
  1831. // at this point our pStats array is loaded up, so we can go to work
  1832. for (i=0; i<cStaFiles; i++) {
  1833. rgSizes[i] = pStats[i].nBytesPerBuffer;
  1834. rgRates[i] = pStats[i].nTokenRate;
  1835. rgtime[i] = pStats[i].time;
  1836. }
  1837. // now sort them and get out the dupliates
  1838. cSizes = cRates = ctime = cStaFiles;
  1839. RemoveDuplicates(rgSizes, &cSizes);
  1840. RemoveDuplicates(rgRates, &cRates);
  1841. RemoveDuplicatesI64((INT64 *)rgtime, &ctime);
  1842. // --- do the stats by by time ---
  1843. fprintf(pfile, "Latency Characteristics at varying times\n");
  1844. fprintf(pfile, " Latency Characteristics (microseconds) Rates (Bps) Buffers\n");
  1845. fprintf(pfile, " Time (UTC) Median StDev Mean Skew Kurt Send Receive Received Dropped\n");
  1846. for (i=0; i<cRates; i++) {
  1847. for (j=0; j<cSizes; j++) {
  1848. // print the flowspec
  1849. if (IndexOfStatRecWith(rgRates[i],rgSizes[j],-1,pStats,cStaFiles) != -1) {
  1850. fprintf(pfile, "FLOWSPEC %d: %dB buffers at %d Bps\n",
  1851. cSpecs++, rgSizes[j], rgRates[i]);
  1852. for (k=0; k<ctime; k++) {
  1853. // check to see if there is something with these params and print it
  1854. ZeroMemory(&uliT, sizeof(ULARGE_INTEGER));
  1855. CopyMemory(&uliT, &rgtime[k], sizeof(ULARGE_INTEGER));
  1856. l = IndexOfStatRecWith(rgRates[i],rgSizes[j],uliT.QuadPart,pStats,cStaFiles);
  1857. if (l > 0) {
  1858. FileTimeToSystemTime(&pStats[l].time, &st);
  1859. fprintf(pfile,"%02hu/%02hu/%04hu %2hu:%02hu.%02hu.%03hu: %10.1lf %10.1lf %10.1lf %8.2lf %8.2lf %10.1lf %10.1lf %10d %10d\n",
  1860. st.wMonth, st.wDay, st.wYear, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds,
  1861. pStats[l].median, sqrt((double)pStats[l].var), pStats[l].mean,
  1862. pStats[l].skew, pStats[l].kurt, pStats[l].sendrate, pStats[l].recvrate,
  1863. pStats[l].nBuffers, pStats[l].nDrops);
  1864. }
  1865. }
  1866. fprintf(pfile,"\n");
  1867. }
  1868. }
  1869. }
  1870. fprintf(pfile, "Latency Characteristics by flowspec\n");
  1871. // --- do the stats by flowspec ---
  1872. // now write the file, line by line, to szLineBuf, then to the file
  1873. // median
  1874. fprintf(pfile,"Median Latency (microseconds)\n");
  1875. fprintf(pfile," ");
  1876. for (i=0; i<cSizes; i++)
  1877. fprintf(pfile,"%9dB ",rgSizes[i]);
  1878. fprintf(pfile,"\n");
  1879. for (i=0; i<cRates; i++) {
  1880. fprintf(pfile,"%7dBps ",rgRates[i]);
  1881. for (j=0; j<cSizes; j++) {
  1882. k = IndexOfStatRecWith(rgRates[i],rgSizes[j],-1,pStats,cStaFiles);
  1883. if (k != -1) {
  1884. fprintf(pfile,"%10.1lf ",pStats[k].median);
  1885. }
  1886. else {
  1887. fprintf(pfile," ");
  1888. }
  1889. }
  1890. fprintf(pfile,"\n");
  1891. }
  1892. fprintf(pfile,"\n");
  1893. // mean
  1894. fprintf(pfile,"Mean Latency (microseconds)\n");
  1895. fprintf(pfile," ");
  1896. for (i=0; i<cSizes; i++)
  1897. fprintf(pfile,"%9dB ",rgSizes[i]);
  1898. fprintf(pfile,"\n");
  1899. for (i=0; i<cRates; i++) {
  1900. fprintf(pfile,"%7dBps ",rgRates[i]);
  1901. for (j=0; j<cSizes; j++) {
  1902. k = IndexOfStatRecWith(rgRates[i],rgSizes[j],-1,pStats,cStaFiles);
  1903. if (k != -1) {
  1904. fprintf(pfile,"%10.2lf ",pStats[k].mean);
  1905. }
  1906. else {
  1907. fprintf(pfile," ");
  1908. }
  1909. }
  1910. fprintf(pfile,"\n");
  1911. }
  1912. fprintf(pfile,"\n");
  1913. // variance
  1914. fprintf(pfile,"Latency Standard Deviation\n");
  1915. fprintf(pfile," ");
  1916. for (i=0; i<cSizes; i++)
  1917. fprintf(pfile,"%9dB ",rgSizes[i]);
  1918. fprintf(pfile,"\n");
  1919. for (i=0; i<cRates; i++) {
  1920. fprintf(pfile,"%7dBps ",rgRates[i]);
  1921. for (j=0; j<cSizes; j++) {
  1922. k = IndexOfStatRecWith(rgRates[i],rgSizes[j],-1,pStats,cStaFiles);
  1923. if (k != -1) {
  1924. fprintf(pfile,"%10.2lf ",sqrt((double)pStats[k].var));
  1925. }
  1926. else {
  1927. fprintf(pfile," ");
  1928. }
  1929. }
  1930. fprintf(pfile,"\n");
  1931. }
  1932. fprintf(pfile,"\n");
  1933. // skew
  1934. fprintf(pfile,"Latency Skew\n");
  1935. fprintf(pfile," ");
  1936. for (i=0; i<cSizes; i++)
  1937. fprintf(pfile,"%9dB ",rgSizes[i]);
  1938. fprintf(pfile,"\n");
  1939. for (i=0; i<cRates; i++) {
  1940. fprintf(pfile,"%7dBps ",rgRates[i]);
  1941. for (j=0; j<cSizes; j++) {
  1942. k = IndexOfStatRecWith(rgRates[i],rgSizes[j],-1,pStats,cStaFiles);
  1943. if (k != -1) {
  1944. fprintf(pfile,"%10.2lf ",pStats[k].skew);
  1945. }
  1946. else {
  1947. fprintf(pfile," ");
  1948. }
  1949. }
  1950. fprintf(pfile,"\n");
  1951. }
  1952. fprintf(pfile,"\n");
  1953. // kurtosis
  1954. fprintf(pfile,"Latency Kurtosis\n");
  1955. fprintf(pfile," ");
  1956. for (i=0; i<cSizes; i++)
  1957. fprintf(pfile,"%9dB ",rgSizes[i]);
  1958. fprintf(pfile,"\n");
  1959. for (i=0; i<cRates; i++) {
  1960. fprintf(pfile,"%7dBps ",rgRates[i]);
  1961. for (j=0; j<cSizes; j++) {
  1962. k = IndexOfStatRecWith(rgRates[i],rgSizes[j],-1,pStats,cStaFiles);
  1963. if (k != -1) {
  1964. fprintf(pfile,"%10.2lf ",pStats[k].kurt);
  1965. }
  1966. else {
  1967. fprintf(pfile," ");
  1968. }
  1969. }
  1970. fprintf(pfile,"\n");
  1971. }
  1972. fprintf(pfile,"\n");
  1973. // send rate
  1974. fprintf(pfile,"Send Rate (Bps)\n");
  1975. fprintf(pfile," ");
  1976. for (i=0; i<cSizes; i++)
  1977. fprintf(pfile,"%9dB ",rgSizes[i]);
  1978. fprintf(pfile,"\n");
  1979. for (i=0; i<cRates; i++) {
  1980. fprintf(pfile,"%7dBps ",rgRates[i]);
  1981. for (j=0; j<cSizes; j++) {
  1982. k = IndexOfStatRecWith(rgRates[i],rgSizes[j],-1,pStats,cStaFiles);
  1983. if (k != -1) {
  1984. fprintf(pfile,"%10.1lf ",pStats[k].sendrate);
  1985. }
  1986. else {
  1987. fprintf(pfile," ");
  1988. }
  1989. }
  1990. fprintf(pfile,"\n");
  1991. }
  1992. fprintf(pfile,"\n");
  1993. // recv rate
  1994. fprintf(pfile,"Receive Rate (Bps)\n");
  1995. fprintf(pfile," ");
  1996. for (i=0; i<cSizes; i++)
  1997. fprintf(pfile,"%9dB ",rgSizes[i]);
  1998. fprintf(pfile,"\n");
  1999. for (i=0; i<cRates; i++) {
  2000. fprintf(pfile,"%7dBps ",rgRates[i]);
  2001. for (j=0; j<cSizes; j++) {
  2002. k = IndexOfStatRecWith(rgRates[i],rgSizes[j],-1,pStats,cStaFiles);
  2003. if (k != -1) {
  2004. fprintf(pfile,"%10.1lf ",pStats[k].recvrate);
  2005. }
  2006. else {
  2007. fprintf(pfile," ");
  2008. }
  2009. }
  2010. fprintf(pfile,"\n");
  2011. }
  2012. fprintf(pfile,"\n");
  2013. // show the file to the screen, just for kicks
  2014. rewind(pfile);
  2015. while (fgets(szLineBuf, 1000, pfile) != NULL)
  2016. printf("%s", szLineBuf);
  2017. // we're done, so we free up the memory we used
  2018. printf("Saved aggregate stats to %s\n",szAggFile);
  2019. fclose(pfile);
  2020. for (i=0; i<cStaFiles; i++) {
  2021. free(rgszStaFiles[i]);
  2022. }
  2023. free(pStats);
  2024. }
  2025. int IndexOfStatRecWith(int rate, int size, INT64 time, PSTATS pStats, int cStats) {
  2026. // returns an index into pStats that has the requested values for rate and size
  2027. // if there are more than one, returns arbitrary match
  2028. // returns -1 if no suitable entry is found.
  2029. int i;
  2030. ULARGE_INTEGER uliT;
  2031. for (i=0; i<cStats; i++) {
  2032. if (rate == -1 || pStats[i].nTokenRate == rate) {
  2033. if (size == -1 || pStats[i].nBytesPerBuffer == size) {
  2034. CopyMemory(&uliT, &(pStats[i].time), sizeof(ULARGE_INTEGER));
  2035. if (time == -1 || uliT.QuadPart == (UINT64)time) {
  2036. return i;
  2037. }
  2038. }
  2039. }
  2040. }
  2041. return -1;
  2042. }
  2043. BOOL GetStatsFromFile(PSTATS pstats) {
  2044. // this function gets the overall statistics from the .sta file it's pointed to
  2045. // it returns true if successful, false otherwise
  2046. PCHAR szBuf = NULL;
  2047. double T1,T2,T3;
  2048. int nT1,nT2,nT3,nT4,nT5,nT6;
  2049. HANDLE hFile;
  2050. DWORD dwFileSize;
  2051. DWORD dwRead;
  2052. int nFields;
  2053. SYSTEMTIME st;
  2054. szBuf = malloc(sizeof(CHAR) * 1000);
  2055. if (!szBuf) return FALSE;
  2056. ZeroMemory(szBuf,1000);
  2057. // open the file
  2058. hFile = CreateFile(pstats->szStaFile,GENERIC_READ, FILE_SHARE_READ, NULL,
  2059. OPEN_EXISTING, 0, NULL);
  2060. dwFileSize = GetFileSize(hFile, NULL);
  2061. if (dwFileSize == 0) return FALSE;
  2062. // read the whole file into szBuf
  2063. ReadFile(hFile, szBuf, dwFileSize, &dwRead, NULL);
  2064. // close the file
  2065. CloseHandle(hFile);
  2066. // parse the buffer
  2067. nFields = sscanf(szBuf,
  2068. "Sender: %s Receiver: %s\n" \
  2069. "First packet received: %hu:%hu.%hu.%hu %hu/%hu/%hu (UTC)\n" \
  2070. "Buffer size: %d\tTokenrate: %d\n" \
  2071. "Received %d packets.\n" \
  2072. "Logged %d records.\n" \
  2073. "Received %d bytes in %d milliseconds = %d KBps\n" \
  2074. "Clock skew is %lf microseconds per second.\n " \
  2075. "\tbased on %d calibration points\n" \
  2076. "Overall send rate: %lf Bytes/s\n" \
  2077. "Overall recv rate: %lf Bytes/s\n" \
  2078. "Latency Statistics (microsecond units): median: %lf\n" \
  2079. "\tMean: %lf\tStdev: %lf\tAbDev: %lf\n" \
  2080. "\tVariance: %lf\tSkew: %lf\t Kurtosis: %lf \n" \
  2081. "Dropped %d packets\n",
  2082. pstats->szSender, pstats->szReceiver,
  2083. &(st.wHour), &(st.wMinute), &(st.wSecond), &(st.wMilliseconds),
  2084. &(st.wDay), &(st.wMonth), &(st.wYear),
  2085. &(pstats->nBytesPerBuffer), &(pstats->nTokenRate),
  2086. &(pstats->nBuffers), &nT2, &nT3, &nT4, &nT5, &T1, &nT6, &(pstats->sendrate),
  2087. &(pstats->recvrate), &(pstats->median),
  2088. &(pstats->mean),&T2,&(pstats->abdev),
  2089. &(pstats->var),&(pstats->skew),&(pstats->kurt),
  2090. &(pstats->nDrops));
  2091. if (nFields != 28 && nFields != 27) { // see if they ran without clock skew calc
  2092. nFields = sscanf(szBuf,
  2093. "Sender: %s Receiver: %s\n" \
  2094. "First packet received: %hu:%hu.%hu.%hu %hu/%hu/%hu (UTC)\n" \
  2095. "Buffer size: %d\tTokenrate: %d\n" \
  2096. "Received %d packets.\n" \
  2097. "Logged %d records.\n" \
  2098. "Received %d bytes in %d milliseconds = %d KBps\n" \
  2099. "Overall send rate: %lf Bytes/s\n" \
  2100. "Overall recv rate: %lf Bytes/s\n" \
  2101. "Latency Statistics (microsecond units): median: %lf\n" \
  2102. "\tMean: %lf\tStdev: %lf\tAbDev: %lf\n" \
  2103. "\tVariance: %lf\tSkew: %lf\t Kurtosis: %lf \n" \
  2104. "Dropped %d packets\n",
  2105. pstats->szSender, pstats->szReceiver,
  2106. &(st.wHour), &(st.wMinute), &(st.wSecond), &(st.wMilliseconds),
  2107. &(st.wDay), &(st.wMonth), &(st.wYear),
  2108. &(pstats->nBytesPerBuffer), &(pstats->nTokenRate),
  2109. &nT1, &nT2, &nT3, &nT4, &nT5, &(pstats->sendrate),
  2110. &(pstats->recvrate), &(pstats->median),
  2111. &(pstats->mean),&T2,&(pstats->abdev),
  2112. &(pstats->var),&(pstats->skew),&(pstats->kurt),
  2113. &(pstats->nDrops));
  2114. if (nFields != 26 && nFields != 25) return FALSE;
  2115. }
  2116. // assemble a FILETIME structure from the date & time
  2117. if (!SystemTimeToFileTime(&st,&pstats->time)) {
  2118. return FALSE;
  2119. }
  2120. free(szBuf);
  2121. return TRUE;
  2122. }
  2123. VOID
  2124. DoStatsFromFile()
  2125. {
  2126. DOUBLE slope = 0;
  2127. DOUBLE offset = 0;
  2128. printf("Logging stats from file.\n");
  2129. if (Name == NULL) {
  2130. fprintf(stderr, "ERROR: you must specify a file to convert\n");
  2131. }
  2132. if(MyCreateFile(Name, ".log", &hLogFile) != ERROR_SUCCESS) {
  2133. fprintf(stderr, "ERROR: could not create log file\n");
  2134. exit(1);
  2135. }
  2136. if(OpenRawFile(Name, &hRawFile) != ERROR_SUCCESS) {
  2137. fprintf(stderr, "ERROR: could not open raw file\n");
  2138. exit(1);
  2139. }
  2140. ReadSchedulingRecords(hRawFile);
  2141. if (g_params.calibration == 0)
  2142. g_params.calibration = g_log.nBuffersLogged;
  2143. NormalizeTimeStamps();
  2144. // here we check for wacky timestamps on the sender and receiver
  2145. if (g_params.SkewFitMode == 3)
  2146. FixWackyTimestamps();
  2147. if (g_params.SkewFitMode) {
  2148. ClockSkew(&slope, &offset);
  2149. AdjustForClockSkew(slope,offset);
  2150. NormalizeTimeStamps();
  2151. }
  2152. if(hLogFile != INVALID_HANDLE_VALUE) {
  2153. WriteSchedulingRecords(hLogFile, g_params.Dummy);
  2154. }
  2155. printf("Done stats from file.\n");
  2156. } // DoStatsFromFile()
  2157. DWORD
  2158. OpenRawFile(
  2159. IN PCHAR Name,
  2160. OUT HANDLE *File
  2161. )
  2162. {
  2163. HANDLE hFile;
  2164. UCHAR * logName;
  2165. logName = malloc(strlen(Name) + 4);
  2166. strncpy(logName, Name, strlen(Name));
  2167. logName[strlen(Name)+0] = '.';
  2168. logName[strlen(Name)+1] = 'r';
  2169. logName[strlen(Name)+2] = 'a';
  2170. logName[strlen(Name)+3] = 'w';
  2171. logName[strlen(Name)+4] = (UCHAR)NULL;
  2172. hFile = CreateFile(logName,
  2173. GENERIC_READ,
  2174. 0,
  2175. NULL,
  2176. OPEN_EXISTING ,
  2177. FILE_ATTRIBUTE_NORMAL,
  2178. NULL);
  2179. *File = hFile;
  2180. return(INVALID_HANDLE_VALUE == hFile ? (!(ERROR_SUCCESS)) : ERROR_SUCCESS);
  2181. } // OpenRawFile()
  2182. INT64 ReadSchedulingRecords(HANDLE File)
  2183. {
  2184. char szTempFile[MAX_PATH];
  2185. char szTempPath[MAX_PATH];
  2186. LOG_RECORD currentRecord;
  2187. CHAR lineBuf[MAX_STRING];
  2188. CHAR nextChar[2] = {0,0};
  2189. DWORD readBytes = 0;
  2190. INT assignedFields;
  2191. if (!File || (File == INVALID_HANDLE_VALUE)) {
  2192. fprintf(stderr,"ERROR: Invalid File\n");
  2193. return 0;
  2194. }
  2195. CreateLog(&g_log, 2048);
  2196. // loop through the file, reading in line after line
  2197. do
  2198. {
  2199. // get the next line of characters
  2200. bzero(lineBuf, MAX_STRING);
  2201. ZeroMemory(lineBuf, MAX_STRING);
  2202. do {
  2203. ReadFile(File,nextChar,1,&readBytes,NULL);
  2204. if (readBytes == 0) {
  2205. if (g_log.nBuffersLogged == 0) {
  2206. fprintf(stderr,"ERROR: no logs read\n");
  2207. exit(1);
  2208. }
  2209. break;
  2210. }
  2211. strcat(lineBuf,nextChar);
  2212. } while (*nextChar != '\n');
  2213. // parse line and add it to the log
  2214. assignedFields = sscanf(lineBuf,
  2215. "%I64u:%I64u:%I64u:%d:%d\n",
  2216. &(currentRecord.TimeSent),
  2217. &(currentRecord.TimeReceived),
  2218. &(currentRecord.Latency),
  2219. &(currentRecord.BufferSize),
  2220. &(currentRecord.SequenceNumber));
  2221. if ((assignedFields != 5) && (assignedFields != EOF))
  2222. printf("ERROR: parsing the log gave bad field assignments on record %d\n",
  2223. g_log.nBuffersLogged);
  2224. if (assignedFields == EOF) break;
  2225. AddLogEntry(&g_log, &currentRecord);
  2226. }
  2227. while (readBytes != 0);
  2228. printf("read %d records\n",g_log.nBuffersLogged);
  2229. return g_log.nBuffersLogged; // return the number of records read
  2230. } // ReadSchedulingRecords()
  2231. VOID
  2232. DoStats()
  2233. {
  2234. DOUBLE slope = 0;
  2235. DOUBLE offset = 0;
  2236. GenericStats();
  2237. if(!normalize){
  2238. if(hRawFile != INVALID_HANDLE_VALUE){
  2239. WriteSchedulingRecords(hRawFile, FALSE);
  2240. }
  2241. }
  2242. NormalizeTimeStamps();
  2243. if(normalize){
  2244. if(hRawFile != INVALID_HANDLE_VALUE){
  2245. WriteSchedulingRecords(hRawFile, FALSE);
  2246. }
  2247. }
  2248. if(!g_params.calibration) { // if we have nothing specified, calibrate on all buffers
  2249. g_params.calibration = g_state.nBuffersReceived;
  2250. }
  2251. // here we check for wacky timestamps on the sender and receiver
  2252. if (g_params.SkewFitMode == 3)
  2253. FixWackyTimestamps();
  2254. if(g_params.SkewFitMode) {
  2255. ClockSkew(&slope, &offset);
  2256. AdjustForClockSkew(slope, offset);
  2257. NormalizeTimeStamps();
  2258. }
  2259. // we calculate these stats on the normalized / skew adjusted data
  2260. AdvancedStats();
  2261. CheckForLostPackets();
  2262. if(hLogFile != INVALID_HANDLE_VALUE){
  2263. WriteSchedulingRecords(hLogFile, g_params.Dummy);
  2264. }
  2265. printf("\n");
  2266. }
  2267. VOID
  2268. WriteSchedulingRecords(
  2269. HANDLE File,
  2270. BOOLEAN InsertDummyRows)
  2271. {
  2272. LOG_RECORD scheduleRecord;
  2273. CHAR formattingBuffer[MAX_STRING];
  2274. INT dwWritten;
  2275. INT64 records = g_log.nBuffersLogged;
  2276. INT wrote;
  2277. INT i;
  2278. INT64 maxLatency = (INT64)0;
  2279. if(!File || (File == INVALID_HANDLE_VALUE)){
  2280. return;
  2281. }
  2282. while(records){
  2283. GetLogEntry(&g_log, &scheduleRecord, g_log.nBuffersLogged - records);
  2284. ZeroMemory(formattingBuffer,MAX_STRING);
  2285. wrote = sprintf(formattingBuffer,
  2286. "%020I64u:%020I64u:%010I64d:%10d:%10d\n",
  2287. scheduleRecord.TimeSent,
  2288. scheduleRecord.TimeReceived,
  2289. scheduleRecord.Latency,
  2290. scheduleRecord.BufferSize,
  2291. scheduleRecord.SequenceNumber);
  2292. WriteFile(File, formattingBuffer, wrote, &dwWritten, NULL);
  2293. records--;
  2294. }
  2295. } // WriteSchedulingRecords()
  2296. VOID
  2297. GenericStats()
  2298. {
  2299. INT bytesWritten;
  2300. UCHAR holdingBuffer[MAX_STRING];
  2301. INT count;
  2302. // say who the sender and receiver are
  2303. count = sprintf(holdingBuffer, "Sender: %s Receiver: %s\n",szHisAddr, szMyAddr);
  2304. WriteStats(holdingBuffer, count);
  2305. printf("%s",holdingBuffer);
  2306. // say when we received the first packet
  2307. count = sprintf(holdingBuffer, "First packet received: %02u:%02u.%02u.%03u %02u/%02u/%04u (UTC)\n",
  2308. systimeStart.wHour, systimeStart.wMinute, systimeStart.wSecond,
  2309. systimeStart.wMilliseconds, systimeStart.wDay, systimeStart.wMonth, systimeStart.wYear);
  2310. WriteStats(holdingBuffer, count);
  2311. printf("%s",holdingBuffer);
  2312. // write the test params to the .sta file
  2313. bzero(holdingBuffer, MAX_STRING);
  2314. count = _snprintf(holdingBuffer, MAX_STRING -1,
  2315. "Buffer size: %d\tTokenrate: %d\n",
  2316. g_params.buflen, g_params.TokenRate);
  2317. WriteStats(holdingBuffer, count);
  2318. printf("%s",holdingBuffer);
  2319. // write some generic results
  2320. bzero(holdingBuffer, MAX_STRING);
  2321. count = _snprintf(holdingBuffer,
  2322. MAX_STRING-1, // leave room for NULL
  2323. "Received %u packets.\n",
  2324. g_state.nBuffersReceived);
  2325. WriteStats(holdingBuffer, count);
  2326. printf("%s",holdingBuffer);
  2327. bzero(holdingBuffer, MAX_STRING);
  2328. count = _snprintf(holdingBuffer,
  2329. MAX_STRING-1, // leave room for NULL
  2330. "Logged %I64u records.\n",
  2331. g_log.nBuffersLogged);
  2332. WriteStats(holdingBuffer, count);
  2333. printf("%s",holdingBuffer);
  2334. bzero(holdingBuffer, MAX_STRING);
  2335. count = _snprintf(holdingBuffer,
  2336. MAX_STRING-1, // room for NULL
  2337. "Received %ld bytes in %I64d milliseconds = %I64d KBps\n",
  2338. g_state.nBytesTransferred,
  2339. timeElapsed,
  2340. g_state.nBytesTransferred/timeElapsed);
  2341. WriteStats(holdingBuffer, count);
  2342. printf("%s",holdingBuffer);
  2343. } // GenericStats()
  2344. void AdvancedStats() {
  2345. // write some more interesting stats to the .sta file
  2346. char szBuf[MAX_STRING];
  2347. INT64 i,n;
  2348. int count;
  2349. INT64 FirstTime,LastTime;
  2350. double rate, median, mean, var, abdev, skew, kurt, sdev, ep = 0.0, s, p;
  2351. LOG_RECORD rec;
  2352. double * sortedLatencies;
  2353. // overall send rate
  2354. GetLogEntry(&g_log, &rec, 0);
  2355. FirstTime = rec.TimeSent;
  2356. GetLogEntry(&g_log, &rec, g_log.nBuffersLogged - 1);
  2357. LastTime = rec.TimeSent;
  2358. rate = (rec.SequenceNumber * g_params.buflen)/((double)(LastTime - FirstTime)/10000000.0);
  2359. count = sprintf(szBuf, "Overall send rate: %.3f Bytes/s\n",rate);
  2360. WriteStats(szBuf, count);
  2361. printf("%s",szBuf);
  2362. GetLogEntry(&g_log, &rec, 0);
  2363. FirstTime = rec.TimeReceived;
  2364. GetLogEntry(&g_log, &rec, g_log.nBuffersLogged - 1);
  2365. LastTime = rec.TimeReceived;
  2366. rate = (g_state.nBytesTransferred)/((double)(LastTime - FirstTime)/10000000.0);
  2367. count = sprintf(szBuf, "Overall recv rate: %.3f Bytes/s\n",rate);
  2368. WriteStats(szBuf, count);
  2369. printf("%s",szBuf);
  2370. // now show mean, variance, avdev, etc of latency.
  2371. s = 0.0;
  2372. n = g_log.nBuffersLogged;
  2373. sortedLatencies = malloc(sizeof(double) * (UINT)n);
  2374. for (i=0; i < n; i++) { // first pass, we get mean
  2375. GetLogEntry(&g_log, &rec, i);
  2376. s += (double)rec.Latency/10.0;
  2377. sortedLatencies[i] = (double)rec.Latency/10.0;
  2378. }
  2379. qsort(sortedLatencies,(UINT)n,sizeof(double),compare);
  2380. median = (n & 1) ? sortedLatencies[(n-1)/2] : 0.5*(sortedLatencies[n/2] + sortedLatencies[n/2 - 1]);
  2381. free(sortedLatencies);
  2382. mean = s / n;
  2383. abdev = var = skew = kurt = 0.0;
  2384. for (i=0; i<n; i++) { // second pass, we get 1st,2nd,3rd,4th moments of deviation from mean
  2385. GetLogEntry(&g_log, &rec, i);
  2386. abdev += fabs(s=(double)rec.Latency/10.0 - mean);
  2387. ep += s;
  2388. var += (p = s*s);
  2389. skew += (p *= s);
  2390. kurt += (p *= s);
  2391. }
  2392. abdev /= n;
  2393. var = (var - ep*ep/n) / (n-1);
  2394. sdev = sqrt(var);
  2395. if (var) { // if var=0, no skew/kurtosis defined
  2396. skew /= (n*var*sdev);
  2397. kurt = kurt / (n*var*var) - 3.0;
  2398. }
  2399. count = sprintf(szBuf, "Latency Statistics (microsecond units): median: %.1lf\n",median);
  2400. WriteStats(szBuf, count);
  2401. printf("%s",szBuf);
  2402. count = sprintf(szBuf, "\tMean: %6.2lf\tStdev: %6.2lf\tAbDev: %6.2lf\n",mean,sdev,abdev);
  2403. WriteStats(szBuf, count);
  2404. printf("%s",szBuf);
  2405. count = sprintf(szBuf, "\tVariance: %6.2lf\tSkew: %6.2lf\tKurtosis: %6.2lf\n",var,skew,kurt);
  2406. WriteStats(szBuf, count);
  2407. printf("%s",szBuf);
  2408. }
  2409. VOID
  2410. CheckForLostPackets()
  2411. {
  2412. LOG_RECORD currentRecord;
  2413. INT currentSequenceNumber = 0;
  2414. INT bytesWritten;
  2415. UCHAR holdingBuffer[MAX_STRING];
  2416. INT count;
  2417. INT64 nLost = 0;
  2418. INT i;
  2419. for(i=0; i<g_log.nBuffersLogged; i++){
  2420. GetLogEntry(&g_log, &currentRecord, i);
  2421. if(currentRecord.SequenceNumber != currentSequenceNumber){
  2422. nLost += currentRecord.SequenceNumber - currentSequenceNumber;
  2423. currentSequenceNumber = currentRecord.SequenceNumber;
  2424. }
  2425. currentSequenceNumber += g_params.LoggingPeriod;
  2426. }
  2427. count = sprintf(holdingBuffer, "Dropped %I64u packets\n", nLost);
  2428. WriteStats(holdingBuffer, count);
  2429. } // CheckForLostPackets()
  2430. VOID
  2431. WriteStats(
  2432. UCHAR * HoldingBuffer,
  2433. INT Count)
  2434. {
  2435. INT bytesWritten;
  2436. if(Count < 0){
  2437. Count = MAX_STRING;
  2438. }
  2439. WriteFile(hStatFile,
  2440. HoldingBuffer,
  2441. Count,
  2442. &bytesWritten,
  2443. NULL);
  2444. } // WriteStats()
  2445. VOID
  2446. NormalizeTimeStamps()
  2447. {
  2448. LOG_RECORD currentRecord;
  2449. INT bytesWritten;
  2450. UCHAR holdingBuffer[MAX_STRING];
  2451. INT count;
  2452. INT i;
  2453. UINT64 timeSent;
  2454. UINT64 timeReceived;
  2455. UINT64 smaller;
  2456. INT64 constantDelay = MAX_INT64;
  2457. INT64 currentDelay;
  2458. UINT64 base = 0xFFFFFFFFFFFFFFFF;
  2459. for(i=0; i<g_log.nBuffersLogged; i++){
  2460. GetLogEntry(&g_log, &currentRecord, i);
  2461. currentDelay = currentRecord.TimeReceived - currentRecord.TimeSent;
  2462. constantDelay = (currentDelay < constantDelay) ? currentDelay : constantDelay;
  2463. }
  2464. // now subtract off the constant delay off
  2465. for(i=0; i<g_log.nBuffersLogged; i++){
  2466. GetLogEntry(&g_log, &currentRecord, i);
  2467. currentRecord.TimeReceived -= constantDelay;
  2468. currentRecord.Latency = currentRecord.TimeReceived - currentRecord.TimeSent;
  2469. SetLogEntry(&g_log, &currentRecord, i);
  2470. }
  2471. for (i=0; i<g_log.nBuffersLogged; i++) {
  2472. GetLogEntry(&g_log, &currentRecord, i);
  2473. smaller = (currentRecord.TimeReceived < currentRecord.TimeSent) ?
  2474. currentRecord.TimeReceived : currentRecord.TimeSent;
  2475. base = (base < smaller)?base:smaller; // find the smallest timestamp
  2476. }
  2477. // now we can subtract the base off of the send & receive times
  2478. for (i=0; i<g_log.nBuffersLogged; i++) {
  2479. GetLogEntry(&g_log, &currentRecord, i);
  2480. currentRecord.TimeSent -= base;
  2481. currentRecord.TimeReceived -= base;
  2482. SetLogEntry(&g_log, &currentRecord, i);
  2483. }
  2484. } // NormalizeTimeStamps()
  2485. VOID
  2486. ClockSkew(
  2487. DOUBLE * Slope,
  2488. DOUBLE * Offset) {
  2489. // If there is a calibration period, we can estimate clock skew between
  2490. // sender and receiver. See comments under AdjustForClockSkew. We use
  2491. // calculus to determine the best-fit slope.
  2492. INT i;
  2493. LOG_RECORD currentRecord;
  2494. DOUBLE N;
  2495. DOUBLE slope;
  2496. DOUBLE offset;
  2497. UCHAR holdingBuffer[MAX_STRING];
  2498. INT count;
  2499. double *x, *y, abdev;
  2500. double devpercent;
  2501. // We find the clock skew using medfit, a function which fits to minimum absolute deviation
  2502. N = (double) g_params.calibration;
  2503. x = malloc(sizeof(double) * (UINT)N);
  2504. y = malloc(sizeof(double) * (UINT)N);
  2505. for (i = 0; i<N; i++) {
  2506. GetLogEntry(&g_log,&currentRecord,i);
  2507. x[i] = (DOUBLE)currentRecord.TimeSent;
  2508. y[i] = (DOUBLE)currentRecord.Latency;
  2509. }
  2510. medfit(x, y, (INT)N, &offset, &slope, &abdev);
  2511. // Now write out our findings.
  2512. bzero(holdingBuffer, MAX_STRING);
  2513. count = _snprintf(holdingBuffer,
  2514. MAX_STRING-1, // leave room for NULL
  2515. "Clock skew is %f microseconds per second.\n " \
  2516. "\tbased on %d calibration points\n",
  2517. 100000*slope, g_params.calibration);
  2518. WriteStats(holdingBuffer, count);
  2519. printf("%s",holdingBuffer);
  2520. for (i = 0,devpercent = 0.0; i<N; i++) {
  2521. devpercent += y[i];
  2522. }
  2523. devpercent /= N;
  2524. devpercent = 100 * abdev / devpercent;
  2525. printf("\tfit resulted in avg. absolute deviation of %f percent from mean\n",devpercent);
  2526. free(x);
  2527. free(y);
  2528. *Slope = slope;
  2529. *Offset = offset;
  2530. } // ClockSkew()
  2531. BOOLEAN
  2532. AnomalousPoint(
  2533. DOUBLE x,
  2534. DOUBLE y)
  2535. {
  2536. // here we simply keep a buffer of the past 10 calls and if this one
  2537. // falls out of a few standard deviations of the 8 inner points, we deem it anomalous
  2538. static DOUBLE buf[10];
  2539. DOUBLE sortedbuf[10];
  2540. DOUBLE mean = 0;
  2541. DOUBLE sum = 0;
  2542. DOUBLE sumsqdev = 0;
  2543. DOUBLE median = 0;
  2544. DOUBLE sdev = 0;
  2545. DOUBLE N;
  2546. static int curIndex = 0;
  2547. int i;
  2548. static INT64 submittedPoints;
  2549. buf[curIndex % 10] = y;
  2550. curIndex++;
  2551. submittedPoints++;
  2552. if (g_params.SkewFitMode != 4)
  2553. return FALSE;
  2554. if (submittedPoints >= 10) {
  2555. sum = 0;
  2556. sumsqdev = 0;
  2557. // sort them into sortedbuf
  2558. for (i=0; i<10; i++) sortedbuf[i] = buf[i];
  2559. qsort(sortedbuf, 10, sizeof(DOUBLE), compare);
  2560. // use only the inner 8 points in the calculation of mean & var
  2561. for (i = 1; i < 9; i++) {
  2562. sum += sortedbuf[i];
  2563. }
  2564. N = 8.0; // using only 8 points
  2565. mean = sum / N;
  2566. for (i = 1; i < 9; i++) {
  2567. sumsqdev += ((sortedbuf[i] - mean) * (sortedbuf[i] - mean));
  2568. }
  2569. sdev = sqrt(sumsqdev / N);
  2570. if (fabs(y - mean) < 2.5 * sdev) {
  2571. return FALSE;
  2572. }
  2573. else {
  2574. anomalies++;
  2575. return TRUE;
  2576. }
  2577. }
  2578. return TRUE;
  2579. } // AnomalousPoint()
  2580. VOID
  2581. AdjustForClockSkew(
  2582. DOUBLE Slope,
  2583. DOUBLE Offset)
  2584. {
  2585. //
  2586. // When measuring very low jitter, clock drift between machines
  2587. // introduces noise in the form of a monotonically increasing
  2588. // skew between sending and receiving clock. This effect can be
  2589. // filtered out by finding the best-fit slope for all samples
  2590. // taken during the calibration period, then using this slope to
  2591. // normalize the entire run. This routine normalizes using the
  2592. // slope determined in the routine ClockSkew.
  2593. //
  2594. INT i;
  2595. LOG_RECORD currentRecord;
  2596. INT64 minLatency = MAX_INT64;
  2597. INT64 x;
  2598. DOUBLE mXPlusB;
  2599. for(i=0; i < g_log.nBuffersLogged; i++){
  2600. GetLogEntry(&g_log, &currentRecord, i);
  2601. mXPlusB = (currentRecord.TimeSent*Slope) + Offset; // offset is not necessary
  2602. currentRecord.TimeReceived -= (INT64)mXPlusB;
  2603. currentRecord.Latency -= (INT64)mXPlusB;
  2604. SetLogEntry(&g_log, &currentRecord, i);
  2605. //
  2606. // find the minimum latency value
  2607. //
  2608. minLatency = (currentRecord.Latency < minLatency)?
  2609. currentRecord.Latency:
  2610. minLatency;
  2611. }
  2612. for(i=0; i < g_log.nBuffersLogged; i++){
  2613. GetLogEntry(&g_log, &currentRecord, i);
  2614. currentRecord.Latency -= minLatency;
  2615. currentRecord.TimeReceived -= minLatency;
  2616. SetLogEntry(&g_log, &currentRecord, i);
  2617. }
  2618. } // AdjustForClockSkew()
  2619. #define WACKY 2.5
  2620. BOOL FixWackyTimestamps() {
  2621. // This routine will look over the sender & receiver timestamps and try to see if there
  2622. // are any non-clock skew related irregularities (such as one of them bumping it's clock
  2623. // a fixed amount every once-in-a-while) and try to remove them.
  2624. INT64 *sendstamps, *recvstamps;
  2625. double *sendgaps, *recvgaps;
  2626. double *sortedsendgaps, *sortedrecvgaps;
  2627. double sendmean, sendsdev, sendsum, sendsumsqdev;
  2628. double recvmean, recvsdev, recvsum, recvsumsqdev;
  2629. double mediansendgap, medianrecvgap;
  2630. double modesendgap, moderecvgap;
  2631. double meansendwackiness, sdevsendwackiness, sumsendwackiness, sumsqdevsendwackiness;
  2632. double meanrecvwackiness, sdevrecvwackiness, sumrecvwackiness, sumsqdevrecvwackiness;
  2633. double fractionaldevofsendwackiness, fractionaldevofrecvwackiness;
  2634. double normalsendgapmean, normalrecvgapmean;
  2635. double trimmeansendgap, trimmeanrecvgap;
  2636. BOOL *fWackoSend, *fWackoRecv;
  2637. int cWackoSend, cWackoRecv;
  2638. BOOL *fMaybeWackoSend, *fMaybeWackoRecv;
  2639. int i,N;
  2640. LOG_RECORD currentRecord;
  2641. const double FixThreshold = 0.1;
  2642. double CumulativeFixMagnitude = 0.0;
  2643. N = (int)g_log.nBuffersLogged;
  2644. cWackoSend = cWackoRecv = 0;
  2645. // fill our arrays.
  2646. sendstamps = malloc(sizeof(INT64) * N);
  2647. recvstamps = malloc(sizeof(INT64) * N);
  2648. sendgaps = malloc(sizeof(double) * N);
  2649. recvgaps = malloc(sizeof(double) * N);
  2650. sortedsendgaps = malloc(sizeof(double) *N);
  2651. sortedrecvgaps = malloc(sizeof(double) *N);
  2652. fWackoRecv = malloc(sizeof(BOOL) * N);
  2653. fWackoSend = malloc(sizeof(BOOL) * N);
  2654. fMaybeWackoSend = malloc(sizeof(BOOL) * N);
  2655. fMaybeWackoRecv = malloc(sizeof(BOOL) * N);
  2656. for (i=0; i<N; i++) {
  2657. GetLogEntry(&g_log, &currentRecord, i);
  2658. sendstamps[i] = currentRecord.TimeSent;
  2659. recvstamps[i] = currentRecord.TimeReceived;
  2660. fWackoSend[i] = FALSE;
  2661. fMaybeWackoSend[i] = FALSE;
  2662. fWackoRecv[i] = FALSE;
  2663. fMaybeWackoRecv[i] = FALSE;
  2664. }
  2665. // First, check for wacky timestamps. This is a multistep process:
  2666. // 1. Calculate the interpacket gaps on both sender & receiver.
  2667. for (i=1; i<N; i++) {
  2668. sendgaps[i] = (double) (sendstamps[i] - sendstamps[i-1]);
  2669. recvgaps[i] = (double) (recvstamps[i] - recvstamps[i-1]);
  2670. }
  2671. // 2. We will define wacky as being at least WACKY standard deviations away from the
  2672. // mean.
  2673. sendsum = recvsum = 0.0;
  2674. for (i=1; i<N; i++) {
  2675. sendsum += sendgaps[i];
  2676. recvsum += recvgaps[i];
  2677. }
  2678. sendmean = sendsum / N;
  2679. recvmean = recvsum / N;
  2680. sendsumsqdev = recvsumsqdev = 0.0;
  2681. for (i=1; i<N; i++) {
  2682. sendsumsqdev += ((sendgaps[i] - sendmean) * (sendgaps[i] - sendmean));
  2683. recvsumsqdev += ((recvgaps[i] - recvmean) * (recvgaps[i] - recvmean));
  2684. }
  2685. sendsdev = sqrt(sendsumsqdev / N);
  2686. recvsdev = sqrt(recvsumsqdev / N);
  2687. for (i=1; i<N; i++) {
  2688. if ((sendgaps[i] < sendmean - WACKY*sendsdev) ||
  2689. (sendgaps[i] > sendmean + WACKY*sendsdev)) {
  2690. fMaybeWackoSend[i] = fWackoSend[i] = TRUE;
  2691. }
  2692. if ((recvgaps[i] < recvmean - WACKY*recvsdev) ||
  2693. (recvgaps[i] > recvmean + WACKY*recvsdev)) {
  2694. fMaybeWackoRecv[i] = fWackoRecv[i] = TRUE;
  2695. }
  2696. }
  2697. // 3. Check to see if any wacky points are unpaired (that is, a wacky point in the
  2698. // sending timestamps is not matched with an equally wacky point in the receiving
  2699. // timestamps).
  2700. for (i=1; i<N; i++) {
  2701. if (fMaybeWackoSend[i] && fMaybeWackoRecv[i]) {
  2702. // I should check to make sure they're equally wacky, but i'm not currently
  2703. fMaybeWackoSend[i] = fWackoSend[i] = FALSE;
  2704. fMaybeWackoRecv[i] = fWackoRecv[i] = FALSE;
  2705. }
  2706. }
  2707. // 4. Check to see if any wacky unpaired points are solitary (that is, they are not
  2708. // surrounded by other wacky points).
  2709. for (i=1; i<N-1; i++) {
  2710. if (fMaybeWackoSend[i]) {
  2711. if (fMaybeWackoSend[i-1] || fMaybeWackoSend[i+1]) {
  2712. fWackoSend[i] = FALSE;
  2713. }
  2714. }
  2715. if (fMaybeWackoRecv[i]) {
  2716. if (fMaybeWackoRecv[i-1] || fMaybeWackoRecv[i+1]) {
  2717. fWackoRecv[i] = FALSE;
  2718. }
  2719. }
  2720. }
  2721. if (fMaybeWackoSend[N-1] && fMaybeWackoSend[N-2]) fWackoSend[N-1] = FALSE;
  2722. if (fMaybeWackoRecv[N-1] && fMaybeWackoRecv[N-2]) fWackoRecv[N-1] = FALSE;
  2723. // 5. If we find a point that meets all these criteria, label it wacky and add it to
  2724. // our list of wacky points.
  2725. for (i=1; i<N; i++) {
  2726. fMaybeWackoSend[i] = fWackoSend[i];
  2727. fMaybeWackoRecv[i] = fWackoRecv[i];
  2728. }
  2729. // Now we find out the stats for the sends & receivees to use as the baseline
  2730. sendsum = recvsum = 0.0;
  2731. cWackoSend = cWackoRecv = 0;
  2732. for (i=1; i<N; i++) {
  2733. sortedsendgaps[i] = sendgaps[i];
  2734. sortedrecvgaps[i] = recvgaps[i];
  2735. if (!fWackoSend[i]) {
  2736. sendsum += sendgaps[i];
  2737. cWackoSend++;
  2738. }
  2739. if (!fWackoRecv[i]) {
  2740. recvsum += recvgaps[i];
  2741. cWackoRecv++;
  2742. }
  2743. }
  2744. normalsendgapmean = sendsum / cWackoSend;
  2745. normalrecvgapmean = recvsum / cWackoRecv;
  2746. qsort(sortedsendgaps, N, sizeof(double), compare);
  2747. qsort(sortedrecvgaps, N, sizeof(double), compare);
  2748. if (N & 1) { // odd N
  2749. mediansendgap = sortedsendgaps[(N+1) / 2];
  2750. medianrecvgap = sortedrecvgaps[(N+1) / 2];
  2751. } else { // even N
  2752. i = N/2;
  2753. mediansendgap = 0.5 * (sortedsendgaps[i] + sortedsendgaps[i+1]);
  2754. medianrecvgap = 0.5 * (sortedrecvgaps[i] + sortedrecvgaps[i+1]);
  2755. }
  2756. sendsum = recvsum = 0.0;
  2757. for (i=(int)(0.05*N); i<(int)(0.85*N); i++) { // find the 80% trimmean (bottom heavy)
  2758. sendsum += sortedsendgaps[i];
  2759. recvsum += sortedrecvgaps[i];
  2760. }
  2761. trimmeansendgap = sendsum / (0.80 * N);
  2762. trimmeanrecvgap = recvsum / (0.80 * N);
  2763. modesendgap = mode(sendgaps, N);
  2764. moderecvgap = mode(recvgaps, N);
  2765. // 6. we have to check to see if the wackiness at each wacky point is about equal to what
  2766. // we think it ought to be, based on the timer clock
  2767. for (i=1; i<N; i++) {
  2768. if (fWackoSend[i]) {
  2769. if (!InRange(sendgaps[i] - g_BadHalAdjustment,
  2770. mediansendgap - sendsdev, mediansendgap + sendsdev)) {
  2771. fWackoSend[i] = FALSE;
  2772. cWackoSend--;
  2773. }
  2774. }
  2775. if (fWackoRecv[i]) {
  2776. if (!InRange(recvgaps[i] - g_BadHalAdjustment,
  2777. medianrecvgap - recvsdev, medianrecvgap + recvsdev)) {
  2778. fWackoRecv[i] = FALSE;
  2779. cWackoRecv--;
  2780. }
  2781. }
  2782. }
  2783. // Now we want to correct for the wacky timestamps, so we see if the wacky points are all
  2784. // equally wacky. If they are, we're psyched and we simply subtract off the wackiness
  2785. // from the wacky points and all points after them. (Wackiness is cumulative!)
  2786. cWackoSend = cWackoRecv = 0;
  2787. sumsendwackiness = sumrecvwackiness = sumsqdevsendwackiness = sumsqdevrecvwackiness = 0.0;
  2788. for (i=1; i<N; i++) {
  2789. if (fWackoSend[i]) {
  2790. sumsendwackiness += (sendgaps[i] - trimmeansendgap);
  2791. cWackoSend++;
  2792. }
  2793. if (fWackoRecv[i]) {
  2794. sumrecvwackiness += (recvgaps[i] - trimmeanrecvgap);
  2795. cWackoRecv++;
  2796. }
  2797. }
  2798. meansendwackiness = sumsendwackiness / cWackoSend;
  2799. meanrecvwackiness = sumrecvwackiness / cWackoRecv;
  2800. for (i=1; i<N; i++) {
  2801. if (fWackoSend[i])
  2802. sumsqdevsendwackiness += ((sendgaps[i]-trimmeansendgap-meansendwackiness) * (sendgaps[i]-normalsendgapmean-meansendwackiness));
  2803. if (fWackoRecv[i])
  2804. sumsqdevrecvwackiness += ((recvgaps[i]-trimmeanrecvgap-meanrecvwackiness) * (recvgaps[i]-normalrecvgapmean-meanrecvwackiness));
  2805. }
  2806. sdevsendwackiness = sqrt(sumsqdevsendwackiness / cWackoSend);
  2807. sdevrecvwackiness = sqrt(sumsqdevrecvwackiness / cWackoRecv);
  2808. // so if the fractional deviation is less than some set amount, we apply the fix
  2809. fractionaldevofsendwackiness = sdevsendwackiness / meansendwackiness;
  2810. fractionaldevofrecvwackiness = sdevrecvwackiness / meanrecvwackiness;
  2811. if (cWackoSend && (fractionaldevofsendwackiness < FixThreshold)) {
  2812. // apply fix to send timestamps
  2813. CumulativeFixMagnitude = 0.0;
  2814. cWackoSend = 0;
  2815. for (i=0; i<N; i++) {
  2816. if (fWackoSend[i]) {
  2817. fWackySender = TRUE;
  2818. CumulativeFixMagnitude += g_BadHalAdjustment;
  2819. cWackoSend++;
  2820. }
  2821. sendstamps[i] -= (INT64)CumulativeFixMagnitude;
  2822. }
  2823. }
  2824. if (cWackoRecv && (fractionaldevofrecvwackiness < FixThreshold)) {
  2825. // apply fix to recv timestamps
  2826. CumulativeFixMagnitude = 0.0;
  2827. cWackoRecv = 0;
  2828. for (i=0; i<N; i++) {
  2829. if (fWackoRecv[i]) {
  2830. fWackyReceiver = TRUE;
  2831. CumulativeFixMagnitude += g_BadHalAdjustment;
  2832. cWackoRecv++;
  2833. }
  2834. recvstamps[i] -= (INT64)CumulativeFixMagnitude;
  2835. }
  2836. }
  2837. // set the globals to reflect our "fixed" values
  2838. for (i=0; i<N; i++) {
  2839. if (fWackySender) {
  2840. GetLogEntry(&g_log, &currentRecord, i);
  2841. currentRecord.TimeSent = sendstamps[i];
  2842. SetLogEntry(&g_log, &currentRecord, i);
  2843. }
  2844. if (fWackyReceiver) {
  2845. GetLogEntry(&g_log, &currentRecord, i);
  2846. currentRecord.TimeReceived = recvstamps[i];
  2847. SetLogEntry(&g_log, &currentRecord, i);
  2848. }
  2849. }
  2850. if (fWackySender || fWackyReceiver) {
  2851. printf("WARNING: I noticed some oddities among the timestamps on the");
  2852. if (fWackySender) printf(" sender");
  2853. if (fWackySender && fWackyReceiver) printf(" and");
  2854. if (fWackyReceiver) printf(" receiver");
  2855. printf(".\n");
  2856. if (fWackySender) {
  2857. printf("\t%d of them on the order of %fms each on the sender.\n",
  2858. cWackoSend, meansendwackiness / 10000); }
  2859. if (fWackyReceiver) {
  2860. printf("\t%d of them on the order of %fms each on the receiver.\n",
  2861. cWackoRecv, meanrecvwackiness / 10000); }
  2862. printf("\tThey are caused by a malfunctioning clock on the afflicted machine.\n");
  2863. printf("\tI have tried to compensate for them in the .log file.\n");
  2864. NormalizeTimeStamps(); // we have to renormalize now
  2865. }
  2866. return FALSE;
  2867. }
  2868. DWORD WINAPI RSVPMonitor (LPVOID lpvThreadParm) {
  2869. DWORD dwResult = 0;
  2870. ULONG status;
  2871. BOOLEAN confirmed = FALSE;
  2872. UINT64 ui64LastHi = 0,ui64Now = 0;
  2873. FILETIME filetime;
  2874. ULARGE_INTEGER ulargeint;
  2875. BOOLEAN fResvGood = FALSE;
  2876. // don't do anything until the control socket is established
  2877. while (g_sockControl == INVALID_SOCKET) {
  2878. Sleep(10);
  2879. }
  2880. while(TRUE){
  2881. // send a HELLO message every once in a while
  2882. GetSystemTimeAsFileTime(&filetime);
  2883. memcpy(&ulargeint, &filetime, sizeof(FILETIME));
  2884. ui64Now = ulargeint.QuadPart;
  2885. if (ui64LastHi + 10000000*SECONDS_BETWEEN_HELLOS < ui64Now) {
  2886. SendControlMessage(g_sockControl,MSGST_HELLO);
  2887. ui64LastHi = ui64Now;
  2888. }
  2889. // get the RSVP statuscode, waiting for as long as it takes
  2890. status = GetRsvpStatus(WSA_INFINITE,fd);
  2891. if (g_state.Done) {
  2892. ExitThread(1);
  2893. }
  2894. switch (status) {
  2895. case WSA_QOS_TRAFFIC_CTRL_ERROR: // sad if we get this
  2896. printf("RSVP-ERR: Reservation rejected by traffic control on server. Aborting.\n");
  2897. SendControlMessage(g_sockControl,MSGST_RSVPERR);
  2898. g_state.Done = TRUE;
  2899. exit(1);
  2900. break;
  2901. case WSA_QOS_REQUEST_CONFIRMED: // happy if we get this
  2902. if (!confirmed) {
  2903. printf("RSVP: Reservation confirmed\n");
  2904. confirmed = TRUE;
  2905. fResvGood = TRUE;
  2906. }
  2907. break;
  2908. case WSA_QOS_SENDERS:
  2909. if (!fResvGood && !trans) {
  2910. printf("\nRSVP Monitor: WSA_QOS_SENDERS at t=%I64ds\n",
  2911. (GetUserTime() - timeStart) / 10000000);
  2912. fResvGood = TRUE;
  2913. }
  2914. break;
  2915. case WSA_QOS_RECEIVERS:
  2916. if (!fResvGood && trans) {
  2917. printf("\nRSVP Monitor: WSA_QOS_RECEIVERS at t=%I64ds\n",
  2918. (GetUserTime() - timeStart) / 10000000);
  2919. fResvGood = TRUE;
  2920. }
  2921. break;
  2922. case WSA_QOS_NO_SENDERS: // the sender is now gone, so we stop
  2923. if (fResvGood && !trans) {
  2924. printf("\nRSVP Monitor: WSA_QOS_NO_SENDERS at t=%I64ds\n",
  2925. (GetUserTime() - timeStart) / 10000000);
  2926. fResvGood = FALSE;
  2927. }
  2928. break;
  2929. case WSA_QOS_NO_RECEIVERS: // means the sender is done, so he should exit
  2930. if (fResvGood && trans) {
  2931. printf("\nRSVP Monitor: WSA_QOS_NO_RECEIVERS at t=%I64ds\n",
  2932. (GetUserTime() - timeStart) / 10000000);
  2933. fResvGood = FALSE;
  2934. }
  2935. break;
  2936. default:
  2937. break;
  2938. }
  2939. Sleep(1000); // check at most once per second
  2940. }
  2941. return dwResult;
  2942. } // RSVPMonitor()
  2943. DWORD WINAPI KeyboardMonitor(LPVOID lpvThreadParm) {
  2944. DWORD dwResult = 0;
  2945. char ch;
  2946. while (TRUE) {
  2947. ch = (CHAR) getchar();
  2948. switch (ch) {
  2949. case 'q':
  2950. SendControlMessage(g_sockControl,MSGST_DONE);
  2951. g_state.Done = TRUE;
  2952. ExitThread(1);
  2953. break;
  2954. }
  2955. }
  2956. return 0;
  2957. }
  2958. DWORD WINAPI ControlSocketMonitor(LPVOID lpvThreadParm) {
  2959. DWORD dwResult = 0;
  2960. DWORD dwError, cbBuf = 0;
  2961. DWORD dwAddrSize = MAX_STRING;
  2962. char szAddr[MAX_STRING];
  2963. char szBuf[MAX_STRING],szCommand[MAX_STRING], *pchStart, *pchEnd;
  2964. int cch;
  2965. char szT[MAX_STRING];
  2966. char szT2[MAX_STRING];
  2967. char * szHost;
  2968. BOOL fSender;
  2969. SOCKET sockControl, sockListen;
  2970. SOCKADDR_IN sinmeControl, sinhimControl;
  2971. PHOSTENT phostent;
  2972. UINT64 ui64LastHello = 0;
  2973. BOOL fDone = FALSE;
  2974. BOOL fGotRate=FALSE, fGotSize=FALSE, fGotNum=FALSE;
  2975. BOOL fSentReady =FALSE;
  2976. // find out if we're the sender or receiver
  2977. if (lpvThreadParm == NULL) fSender = FALSE;
  2978. else fSender = TRUE;
  2979. // if sender, copy the host address into our local host string
  2980. if (fSender) {
  2981. szHost = malloc(strlen((char *)lpvThreadParm) + 1);
  2982. strcpy(szHost, (const char *)lpvThreadParm);
  2983. }
  2984. // set up a control socket
  2985. if (fSender) {
  2986. sockControl = socket(AF_INET, SOCK_STREAM, 0);
  2987. }
  2988. else {
  2989. sockListen = socket(AF_INET, SOCK_STREAM, 0);
  2990. }
  2991. // bind properly
  2992. sinmeControl.sin_family = AF_INET;
  2993. sinmeControl.sin_addr.s_addr = INADDR_ANY;
  2994. sinhimControl.sin_family = AF_INET;
  2995. if (fSender) {
  2996. sinmeControl.sin_port = 0;
  2997. // set up the sinhim structure
  2998. if (atoi(szHost) > 0 ) {
  2999. sinhimControl.sin_addr.s_addr = inet_addr(szHost);
  3000. }
  3001. else{
  3002. if ((phostent=gethostbyname(szHost)) == NULL) {
  3003. ErrorExit("bad host name",WSAGetLastError());
  3004. }
  3005. sinhimControl.sin_family = phostent->h_addrtype;
  3006. memcpy(&(sinhimControl.sin_addr.s_addr), phostent->h_addr, phostent->h_length);
  3007. }
  3008. sinhimControl.sin_port = htons(CONTROL_PORT);
  3009. dwError = bind(sockControl,(SOCKADDR*)&sinmeControl,sizeof(sinmeControl));
  3010. }
  3011. else { // receiver
  3012. sinmeControl.sin_port = htons(CONTROL_PORT);
  3013. dwError = bind(sockListen,(SOCKADDR*)&sinmeControl,sizeof(sinmeControl));
  3014. }
  3015. if (dwError == SOCKET_ERROR)
  3016. ErrorExit("bind failed",WSAGetLastError());
  3017. // now connect the socket
  3018. sinhimControl.sin_family = AF_INET;
  3019. if (fSender) {
  3020. // if we're the sender, keep trying to connect until we get through
  3021. dwAddrSize = MAX_STRING;
  3022. dwError = WSAAddressToString((SOCKADDR *)&(sinhimControl),
  3023. sizeof(SOCKADDR_IN),
  3024. NULL,
  3025. szAddr,
  3026. &dwAddrSize);
  3027. if (dwError == SOCKET_ERROR)
  3028. ErrorExit("WSAAddressToString failed", WSAGetLastError());
  3029. else
  3030. strcpy(szHisAddr,szAddr);
  3031. while (TRUE) {
  3032. dwError = connect(sockControl,(SOCKADDR*)&sinhimControl,sizeof(sinhimControl));
  3033. if (!dwError) {
  3034. printf("control socket: connected to %s\n",szAddr);
  3035. break;
  3036. }
  3037. dwError = WSAGetLastError();
  3038. if (dwError != WSAECONNREFUSED) {
  3039. ErrorExit("connect() failed",dwError);
  3040. }
  3041. Sleep(500); // wait a half second between attempts
  3042. }
  3043. }
  3044. else {
  3045. // if we're the receiver, listen / accept
  3046. if (listen(sockListen, SOMAXCONN) == SOCKET_ERROR) {
  3047. ErrorExit("listen() failed", WSAGetLastError());
  3048. }
  3049. sockControl = accept(sockListen, (SOCKADDR*)&sinhimControl, &dwAddrSize);
  3050. // once we've accepted, close the listen socket
  3051. closesocket(sockListen);
  3052. if ((INT_PTR)sockControl < 0) {
  3053. ErrorExit("accept() failed",WSAGetLastError());
  3054. }
  3055. dwAddrSize = MAX_STRING;
  3056. dwError = WSAAddressToString((SOCKADDR *)&(sinhimControl),
  3057. sizeof(SOCKADDR_IN),
  3058. NULL,
  3059. szAddr,
  3060. &dwAddrSize);
  3061. if (dwError == SOCKET_ERROR)
  3062. ErrorExit("WSAAddressToString failed", WSAGetLastError());
  3063. else
  3064. strcpy(szHisAddr, szAddr);
  3065. printf("control socket: accepted connection from %s\n",szAddr);
  3066. }
  3067. // set our global control socket variable
  3068. g_sockControl = sockControl;
  3069. // record my name
  3070. dwAddrSize = sizeof(SOCKADDR_IN);
  3071. getsockname(sockControl,(SOCKADDR *)&(sinmeControl),&dwAddrSize);
  3072. dwAddrSize = MAX_STRING;
  3073. dwError = WSAAddressToString((SOCKADDR *)&(sinmeControl),
  3074. sizeof(SOCKADDR_IN), NULL, szAddr, &dwAddrSize);
  3075. if (dwError == SOCKET_ERROR)
  3076. ErrorExit("WSAAddressToString failed", WSAGetLastError());
  3077. else
  3078. strcpy(szMyAddr, szAddr);
  3079. // exchange version information
  3080. sprintf(szBuf, "%s %s", MSGST_VER, VERSION_STRING);
  3081. SendControlMessage(sockControl, szBuf);
  3082. // now that we're all set, do the actual work of the control socket
  3083. while (!fDone) {
  3084. ZeroMemory(szBuf,MAX_STRING);
  3085. dwError = cbBuf = recv(sockControl, szBuf, MAX_STRING, 0);
  3086. pchStart = szBuf;
  3087. pchEnd = szBuf + cbBuf;
  3088. if (dwError == 0) { // the connection's been gracefully closed
  3089. fDone = TRUE;
  3090. closesocket(sockControl);
  3091. g_fOtherSideFinished=TRUE;
  3092. ExitThread(0);
  3093. }
  3094. if (dwError == SOCKET_ERROR) {
  3095. dwError = WSAGetLastError();
  3096. if (dwError == WSAECONNRESET) {
  3097. printf("\ncontrol socket: connection reset by peer");
  3098. printf("\n\t%I64us since last HELLO packet received",
  3099. (GetUserTime() - ui64LastHello)/10000000);
  3100. printf("\n\t%I64us since start",
  3101. (GetUserTime() - timeStart)/10000000);
  3102. g_state.Done = TRUE;
  3103. fDone = TRUE;
  3104. g_fOtherSideFinished = TRUE;
  3105. closesocket(sockControl);
  3106. ExitThread(1);
  3107. }
  3108. else {
  3109. printf("\ncontrol socket: error in recv: %d\n",dwError);
  3110. g_state.Done = TRUE;
  3111. fDone = TRUE;
  3112. g_fOtherSideFinished = TRUE;
  3113. closesocket(sockControl);
  3114. ExitThread(1);
  3115. }
  3116. continue;
  3117. }
  3118. while (pchStart < pchEnd) {
  3119. ZeroMemory(szCommand,MAX_STRING);
  3120. // consume the first command and act on it
  3121. if (pchEnd > szBuf + cbBuf) break;
  3122. pchEnd = strchr(pchStart, MSGCH_DELIMITER);
  3123. if (pchEnd == NULL) break;
  3124. strncpy(szCommand,pchStart,pchEnd - pchStart);
  3125. if (strcmp(szCommand,MSGST_HELLO) == 0) {
  3126. // update last hello time
  3127. ui64LastHello = GetUserTime();
  3128. // i should do something like set a timer here that sleeps until a certain timeout
  3129. // passes, at which point it aborts our transfer
  3130. }
  3131. if (strcmp(szCommand,MSGST_ERROR) == 0) {
  3132. // the other guy's had an error, so we stop and tell him to abort
  3133. g_fOtherSideFinished = TRUE;
  3134. g_state.Done = TRUE;
  3135. fDone = TRUE;
  3136. SendControlMessage(sockControl,MSGST_ABORT);
  3137. closesocket(sockControl);
  3138. ExitThread(1);
  3139. }
  3140. if (strcmp(szCommand,MSGST_ABORT) == 0) {
  3141. // we're told to abort, so do so
  3142. g_fOtherSideFinished = TRUE;
  3143. g_state.Done = TRUE;
  3144. fDone = TRUE;
  3145. closesocket(sockControl);
  3146. ExitThread(1);
  3147. }
  3148. if (strcmp(szCommand,MSGST_DONE) == 0) {
  3149. // we're told the other guy's done, so therefore are we
  3150. closesocket(sockControl);
  3151. g_fOtherSideFinished = TRUE;
  3152. g_state.Done = TRUE;
  3153. fDone = TRUE;
  3154. ExitThread(1);
  3155. }
  3156. if (strcmp(szCommand,MSGST_RSVPERR) == 0) {
  3157. // we're told the other guy got an rsvp error, so we abort the whole program
  3158. closesocket(sockControl);
  3159. g_fOtherSideFinished = TRUE;
  3160. g_state.Done = TRUE;
  3161. fDone = TRUE;
  3162. exit(1);
  3163. }
  3164. if (strncmp(szCommand,MSGST_SIZE,4) == 0) {
  3165. // the sender is telling us how big the buffers are
  3166. sscanf(szCommand,"%s %d",szT, &g_params.buflen);
  3167. fGotSize = TRUE;
  3168. }
  3169. if (strncmp(szCommand,MSGST_RATE,4) == 0) {
  3170. // the sender is telling us how fast the buffers are coming
  3171. sscanf(szCommand, "%s %d",szT, &g_params.TokenRate);
  3172. fGotRate = TRUE;
  3173. }
  3174. if (strncmp(szCommand,MSGST_NUM,3) == 0) {
  3175. // the sender is telling us how many buffers it's sending
  3176. sscanf(szCommand, "%s %d",szT, &g_params.nbuf);
  3177. totalBuffers = g_params.nbuf;
  3178. fGotNum = TRUE;
  3179. }
  3180. if (strncmp(szCommand,MSGST_VER,3) == 0) {
  3181. sscanf(szCommand, "%s %s",szT, szT2);
  3182. if (strcmp(szT2,VERSION_STRING) != 0) {
  3183. printf("WARNING: remote machine using different version of qtcp: %s vs. %s\n",
  3184. szT2,VERSION_STRING);
  3185. }
  3186. }
  3187. if (trans) {
  3188. if (strcmp(szCommand,MSGST_READY) == 0) {
  3189. g_fReadyForXmit = TRUE;
  3190. }
  3191. }
  3192. else {
  3193. if (!fSentReady && fGotRate && fGotSize && fGotNum) {
  3194. SendControlMessage(sockControl, MSGST_READY);
  3195. fSentReady = TRUE;
  3196. g_fReadyForXmit = TRUE;
  3197. }
  3198. }
  3199. pchStart = pchEnd + 1;
  3200. pchEnd = szBuf + cbBuf;
  3201. }
  3202. }
  3203. return 0;
  3204. }
  3205. int SendControlMessage(SOCKET sock, char * szMsg) {
  3206. int iResult;
  3207. char szBuf[MAX_STRING];
  3208. sprintf(szBuf,"%s%c",szMsg,MSGCH_DELIMITER);
  3209. iResult = send (sock, szBuf, strlen(szBuf), 0);
  3210. if (iResult == SOCKET_ERROR) {
  3211. return WSAGetLastError();
  3212. }
  3213. return iResult;
  3214. }
  3215. void ErrorExit(char *msg, DWORD dwErrorNumber) {
  3216. fprintf(stderr,"ERROR: %d\n",dwErrorNumber);
  3217. if (msg != NULL)
  3218. fprintf(stderr,"\t%s\n",msg);
  3219. else {
  3220. switch(dwErrorNumber) {
  3221. case WSAEFAULT:
  3222. fprintf(stderr,"\tWSAEFAULT: Buffer too small to contain name\n");
  3223. break;
  3224. case WSAEINVAL:
  3225. fprintf(stderr,"\tWSAEINVAL: Invalid socket address\n");
  3226. break;
  3227. case WSANOTINITIALISED:
  3228. fprintf(stderr,"\tWSANOTINITIALIZED: WSA Not initialized\n");
  3229. break;
  3230. default:
  3231. fprintf(stderr,"\tUnknown error\n");
  3232. break;
  3233. }
  3234. }
  3235. SendControlMessage(g_sockControl, MSGST_ABORT);
  3236. DestroyLog(&g_log);
  3237. WSACleanup();
  3238. exit(1);
  3239. _exit(1);
  3240. }
  3241. // some math utility functions
  3242. // comparison for doubles (to use in qsort)
  3243. int __cdecl compare( const void *arg1, const void *arg2 )
  3244. {
  3245. DOUBLE dTemp;
  3246. DOUBLE d1 = * (DOUBLE *) arg1;
  3247. DOUBLE d2 = * (DOUBLE *) arg2;
  3248. dTemp = d1 - d2;
  3249. if (dTemp < 0) return -1;
  3250. if (dTemp == 0) return 0;
  3251. else
  3252. return 1;
  3253. }
  3254. // comparison for ints (to use in qsort)
  3255. int __cdecl compareint( const void *arg1, const void *arg2 )
  3256. {
  3257. int nTemp;
  3258. int n1 = * (int *) arg1;
  3259. int n2 = * (int *) arg2;
  3260. nTemp = n1 - n2;
  3261. if (nTemp < 0) return -1;
  3262. if (nTemp == 0) return 0;
  3263. else
  3264. return 1;
  3265. }
  3266. // comparison for int64s (to use in qsort)
  3267. int __cdecl compareI64( const void *arg1, const void *arg2 )
  3268. {
  3269. INT64 nTemp;
  3270. INT64 n1 = * (INT64 *) arg1;
  3271. INT64 n2 = * (INT64 *) arg2;
  3272. nTemp = n1 - n2;
  3273. if (nTemp < 0) return -1;
  3274. if (nTemp == 0) return 0;
  3275. else return 1;
  3276. }
  3277. #define EPS 1.0e-7
  3278. // sum up error function for given value of b
  3279. double rofunc(double b, int N, double yt[], double xt[], double * paa, double * pabdevt) {
  3280. int i;
  3281. double *pfT;
  3282. double d, sum=0.0;
  3283. double aa = *paa;
  3284. double abdevt = *pabdevt;
  3285. pfT = malloc(sizeof(double) * N);
  3286. for (i = 0; i < N; i++) pfT[i] = yt[i]-b*xt[i];
  3287. qsort(pfT, N, sizeof(DOUBLE), compare);
  3288. if (N & 1) { // odd N
  3289. aa = pfT[(N+1) / 2];
  3290. }
  3291. else {
  3292. i = N / 2;
  3293. aa = 0.5 * (pfT[i] + pfT[i+1]);
  3294. }
  3295. abdevt = 0.0;
  3296. for (i = 0; i<N; i++) {
  3297. d = yt[i] - (b*xt[i]+aa);
  3298. abdevt += fabs(d);
  3299. if (yt[i] != 0.0) d /= fabs(yt[i]);
  3300. if (fabs(d) > EPS) sum += (d >= 0.0 ? xt[i]: -xt[i]);
  3301. }
  3302. *paa = aa;
  3303. *pabdevt = abdevt;
  3304. free(pfT);
  3305. return sum;
  3306. }
  3307. #define SIGN(a,b) ((b) >= 0 ? fabs(a) : fabs(-a))
  3308. void medfit(double x[], double y[], int N, double *a, double *b, double *abdev) {
  3309. // fit y = a + bx to least absolute deviation. abdev is mean absolute deviation.
  3310. // incoming, a and b are treated as starting guesses
  3311. int i;
  3312. double *xt = x;
  3313. double *yt = y;
  3314. double sx, sy, sxy, sxx, chisq;
  3315. double del, sigb;
  3316. double bb, b1, b2, aa, abdevt, f, f1, f2, temp;
  3317. sx = sy = sxy = sxx = chisq = 0.0;
  3318. // we find chisq fit to use as starting guess
  3319. for (i=0; i<N; i++) {
  3320. sx += x[i];
  3321. sy += y[i];
  3322. sxy += x[i]*y[i];
  3323. sxx += x[i]*x[i];
  3324. }
  3325. del = N*sxx - sx*sx;
  3326. aa = (sxx*sy-sx*sxy) / del;
  3327. bb = (N*sxy - sx*sy) / del;
  3328. // do the absolute deviation fit, if we're supposed to.
  3329. if (g_params.SkewFitMode == 2) {
  3330. for (i=0; i<N; i++)
  3331. chisq += (temp=y[i]-(aa+bb*x[i]), temp*temp);
  3332. sigb = sqrt(chisq/del);
  3333. b1 = bb;
  3334. f1 = rofunc(b1, N, yt, xt, &aa, &abdevt);
  3335. // guess the bracket as 3 sigma away in downhill direction from f1
  3336. b2 = bb + SIGN(3.0 * sigb, f1);
  3337. f2 = rofunc(b2, N, yt, xt, &aa, &abdevt);
  3338. if (b2 == b1) {
  3339. *a = aa;
  3340. *b = bb;
  3341. *abdev = abdevt / N;
  3342. return;
  3343. }
  3344. // Bracketing
  3345. while ((f1*f2) > 0.0) {
  3346. if (fabs(f1) < fabs(f2))
  3347. f1 = rofunc(b1 += 1.6*(b1-b2),N,yt,xt,&aa,&abdevt);
  3348. else
  3349. f2 = rofunc(b2 += 1.6*(b2-b1),N,yt,xt,&aa,&abdevt);
  3350. }
  3351. sigb = 0.000001 * sigb; // refine
  3352. while (fabs(b2 - b1) > sigb) {
  3353. bb = b1 + 0.5 * (b2 - b1);
  3354. if (bb == b1 || bb == b2) break;
  3355. f = rofunc(bb, N, yt, xt, &aa, &abdevt);
  3356. if (f*f1 >= 0.0) {
  3357. f1 = f;
  3358. b1 = bb;
  3359. } else {
  3360. f2 = f;
  3361. b2 = bb;
  3362. }
  3363. }
  3364. }
  3365. *a = aa;
  3366. *b = bb;
  3367. *abdev = abdevt / N;
  3368. }
  3369. double mode(const double data[], const int N) {
  3370. // finds and returns the mode of the N points in data
  3371. double * sorted;
  3372. double mode, cur=0;
  3373. int cMode, cCur;
  3374. int i;
  3375. sorted = malloc(N * sizeof(double));
  3376. for (i=0; i<N; i++) sorted[i] = data[i];
  3377. qsort(sorted, N, sizeof(double), compare);
  3378. mode = sorted[0];
  3379. cMode = cCur = 0;
  3380. for (i=0; i<N; i++) {
  3381. if (cCur > cMode) {
  3382. mode = cur;
  3383. cMode = cCur;
  3384. }
  3385. if (sorted[i] == mode) {
  3386. cMode++;
  3387. } else {
  3388. if (sorted[i] == cur) cCur++;
  3389. else {
  3390. cur = sorted[i];
  3391. cCur = 1;
  3392. }
  3393. }
  3394. }
  3395. free(sorted);
  3396. return mode;
  3397. }
  3398. void RemoveDuplicates(int rg[], int * pN) {
  3399. // this removes duplicates from the array passed in and returns it with *pN = #remaining
  3400. // it makes no guarantees about elements after rg[#remaining]
  3401. int *pNewArray;
  3402. int cNew;
  3403. int i;
  3404. qsort(rg,*pN,sizeof(int),compareint);
  3405. pNewArray = malloc(sizeof(int) * *pN);
  3406. pNewArray[0] = rg[0];
  3407. cNew = 1;
  3408. for (i=1; i<*pN; i++) {
  3409. if (rg[i] != pNewArray[cNew - 1]) {
  3410. pNewArray[cNew++] = rg[i];
  3411. }
  3412. }
  3413. *pN = cNew;
  3414. for (i=0; i<cNew; i++)
  3415. rg[i] = pNewArray[i];
  3416. }
  3417. void RemoveDuplicatesI64(INT64 rg[], int * pN) {
  3418. // this removes duplicates from the array passed in and returns it with *pN = #remaining
  3419. // it makes no guarantees about elements after rg[#remaining]
  3420. INT64 *pNewArray;
  3421. int cNew;
  3422. int i;
  3423. qsort(rg,*pN,sizeof(INT64),compareI64);
  3424. pNewArray = malloc(sizeof(INT64) * *pN);
  3425. pNewArray[0] = rg[0];
  3426. cNew = 1;
  3427. for (i=1; i<*pN; i++) {
  3428. if (rg[i] != pNewArray[cNew - 1]) {
  3429. pNewArray[cNew++] = rg[i];
  3430. }
  3431. }
  3432. *pN = cNew;
  3433. for (i=0; i<cNew; i++)
  3434. rg[i] = pNewArray[i];
  3435. }
  3436. void PrintFlowspec(LPFLOWSPEC lpfs) {
  3437. printf("TokenRate: %lu bytes/sec\n",lpfs->TokenRate);
  3438. printf("TokenBucketSize: %lu bytes\n",lpfs->TokenBucketSize);
  3439. printf("PeakBandwidth: %lu bytes/sec\n",lpfs->PeakBandwidth);
  3440. printf("Latency: %lu microseconds\n",lpfs->Latency);
  3441. printf("DelayVariation: %lu microseconds\n",lpfs->DelayVariation);
  3442. printf("ServiceType: %X\n",lpfs->ServiceType);
  3443. printf("MaxSduSize: %lu bytes\n",lpfs->MaxSduSize);
  3444. printf("MinimumPolicedSize: %lu bytes\n",lpfs->MinimumPolicedSize);
  3445. }