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.

1442 lines
48 KiB

  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (C) 2000 Microsoft Corporation. All Rights Reserved.
  7. //
  8. // Module:
  9. // RMTest.c
  10. //
  11. // Abstract:
  12. // This sample shows how to send and receive data using the
  13. // RMcast driver
  14. // This sample is post-Windows 2000 only.
  15. //
  16. // Usage:
  17. // RMTest.exe -i:int -a:IP
  18. // -i:int Capture on this interface
  19. // This is a zero based index of the
  20. // local interfaces
  21. // -a:IP Use this MCast address
  22. //
  23. // Build:
  24. // cl RMTest.c ws2_32.lib
  25. //
  26. // OR
  27. //
  28. // nmake.exe
  29. //
  30. // Author:
  31. // Mohammad Shabbir Alam
  32. //
  33. #include <nt.h>
  34. #include <ntrtl.h>
  35. #include <nturtl.h>
  36. #include <windef.h>
  37. #include <winbase.h>
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <winsock2.h>
  41. #include <wsahelp.h>
  42. #include <wsasetup.h>
  43. #include <mstcpip.h>
  44. #include <ws2tcpip.h>
  45. #include <ws2spi.h>
  46. #include <wsahelp.h>
  47. #include <sys\timeb.h>
  48. #include "wsRm.h"
  49. //
  50. // Globals
  51. //
  52. #define SOCK_RMCAST SOCK_RDM
  53. struct _timeb StartTime, CurrentTime, PreviousTime;
  54. //
  55. // User-definable variables
  56. //
  57. BOOL gSetWinsockInfo = FALSE;
  58. BOOL gClearWinsockInfo = FALSE;
  59. BOOL gReceiver = FALSE;
  60. DWORD gInterface = 0;
  61. LONG gRateKbitsPerSec = 56;
  62. LONG gMinPktSize = 500;
  63. LONG gMaxPktSize = 100000;
  64. LONG gNumSends = 10000;
  65. LONG gStatusInterval = 100;
  66. LONG gMCastTtl = MAX_MCAST_TTL;
  67. ULONG gLateJoinerPercentage = 0;
  68. BOOLEAN gfSetMCastTtl = FALSE;
  69. BOOLEAN gListenOnAllInterfaces = FALSE;
  70. BOOLEAN gUseSpecifiedInterface = FALSE;
  71. BOOLEAN gSetLateJoiner = FALSE;
  72. BOOLEAN gSetLingerTime = FALSE;
  73. USHORT gLingerTime = 0;
  74. ULONG gMCastGroupAddr = 0;
  75. USHORT gMCastGroupPort = 0;
  76. ULONG gAfdBufferSize = 0;
  77. BOOLEAN gfSetAfdBufferSize = FALSE;
  78. BOOLEAN gfEnumerateProts = FALSE;
  79. BOOLEAN gfVerifyData = FALSE;
  80. // FEC vars:
  81. USHORT gFECBlockSize = 255; // Default
  82. UCHAR gFECGroupSize = 0;
  83. USHORT gFECProActive = 0;
  84. BOOLEAN gfFECOnDemand = FALSE;
  85. int
  86. GetInterface(
  87. int num,
  88. ULONG *pIpAddress,
  89. BOOL fPrintInterfaces
  90. );
  91. //
  92. // Function: usage
  93. //
  94. // Description:
  95. // Prints usage information.
  96. //
  97. void usage(char *progname)
  98. {
  99. WSADATA wsd;
  100. // Load Winsock
  101. //
  102. if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
  103. {
  104. fprintf(stderr, "WSAStartup() failed: %d\n", GetLastError());
  105. ExitProcess(-1);
  106. }
  107. fprintf (stdout, "usage: %s [-l] [-i:Interface] [-a:MCastIP] [-p:Port] [-r:Rate] ...\n", progname);
  108. fprintf (stdout, " -a:MCastIP Use this MCast address (default is 231.7.8.9)\n");
  109. fprintf (stdout, " -b:BufferSize Override Afd's buffer size\n");
  110. fprintf (stdout, " -e Enumerate all protocols known to Winsock\n");
  111. fprintf (stdout, " -j:LateJoiner Percentage of Window available for LateJoiner\n");
  112. fprintf (stdout, " -min:MinPacketSize must be >= 4, default = 500\n");
  113. fprintf (stdout, " -max:MaxPacketSize must be <= 10 Mb, default = 100000\n\n");
  114. fprintf (stdout, " -p:MCastPort Port # (default is 0)\n");
  115. fprintf (stdout, " -s:StatusInterval Number of messages between status\n\n");
  116. fprintf (stdout, " -L[:a] Listen for RMcast packets (otherwise we are sender)\n");
  117. fprintf (stdout, " -- option a means listen on all interfaces\n\n");
  118. fprintf (stdout, " -v:VerifyData Verify data integrity on the receiver (receiver only)\n");
  119. fprintf (stdout, " -F:FECGroupSize Use FEC, <= 128, & power of 2 (sender only)\n");
  120. fprintf (stdout, " -Fo OnDemand FEC (FEC must be set) (sender only)\n");
  121. fprintf (stdout, " -Fp:ProactivePkts Pro-active FEC (FEC must be set) (sender only)\n");
  122. fprintf (stdout, " -n:NumSends Number of sends, default = 10000 (sender only)\n");
  123. fprintf (stdout, " -r:Rate Send Rate in Kbits/Sec, default=56 (sender only)\n");
  124. fprintf (stdout, " -g:LingerTime LingerTime in seconds (sender only)\n");
  125. fprintf (stdout, " -t:TTL Send MCast Ttl, default = max = %d (sender only)\n",
  126. MAX_MCAST_TTL);
  127. fprintf (stdout, " -i:Interface Interface for Send/Capture, default=0\n");
  128. fprintf (stdout, " Available interfaces:\n");
  129. GetInterface (0, NULL, TRUE);
  130. WSACleanup();
  131. ExitProcess(-1);
  132. }
  133. //
  134. // Function: ValidateArgs
  135. //
  136. // Description:
  137. // This function parses the command line arguments and
  138. // sets global variables to indicate how the app should act.
  139. //
  140. void ValidateArgs(int argc, char **argv)
  141. {
  142. int i;
  143. char *ptr;
  144. for(i=1; i < argc; i++)
  145. {
  146. if (strlen(argv[i]) < 2) // Must have '-' or '/' preceding option!
  147. continue;
  148. if ((argv[i][0] == '-') || (argv[i][0] == '/'))
  149. {
  150. switch (tolower(argv[i][1]))
  151. {
  152. case 'a': // Use this MCast address
  153. if (gMCastGroupAddr = inet_addr (&argv[i][3]))
  154. {
  155. break;
  156. }
  157. usage(argv[0]);
  158. case 'b': // Afd's internal buffer size
  159. gAfdBufferSize = atoi(&argv[i][3]);
  160. gfSetAfdBufferSize = TRUE;
  161. break;
  162. case 'e':
  163. gfEnumerateProts = TRUE;
  164. break;
  165. case 'i': // interface number
  166. gInterface = atoi(&argv[i][3]);
  167. gUseSpecifiedInterface = TRUE;
  168. break;
  169. case 'j': // Late Joiner %
  170. gSetLateJoiner = TRUE;
  171. gLateJoinerPercentage = atoi(&argv[i][3]);
  172. break;
  173. case 'f':
  174. if ((tolower (argv[i][2]) == ':') &&
  175. ((gFECGroupSize = (UCHAR) atoi (&argv[i][3])) <= 128))
  176. {
  177. break;
  178. }
  179. if ((tolower (argv[i][2]) == 'p') &&
  180. ((gFECProActive = (UCHAR) atoi (&argv[i][4])) <= 128))
  181. {
  182. break;
  183. }
  184. if (tolower (argv[i][2]) == 'o')
  185. {
  186. gfFECOnDemand = TRUE;
  187. break;
  188. }
  189. usage(argv[0]);
  190. case 'g':
  191. gLingerTime = (USHORT) atoi (&argv[i][3]);
  192. gSetLingerTime = TRUE;
  193. break;
  194. case 'l':
  195. gReceiver = TRUE; // we are receiver, otherwise we would have been sender by default
  196. if (((argv[i][2]) == ':') &&
  197. (tolower (argv[i][3]) == 'a'))
  198. {
  199. gListenOnAllInterfaces = TRUE;
  200. }
  201. break;
  202. case 'm':
  203. if ((tolower (argv[i][2]) == 'i') &&
  204. ((gMinPktSize = atoi (&argv[i][5])) >= 4))
  205. {
  206. break;
  207. }
  208. if ((tolower (argv[i][2]) == 'a') &&
  209. ((gMaxPktSize = atoi (&argv[i][5])) <= 10*1000*1000))
  210. {
  211. break;
  212. }
  213. usage(argv[0]);
  214. case 'n':
  215. gNumSends = atoi (&argv[i][3]);
  216. break;
  217. case 'p': // interface number
  218. gMCastGroupPort = (USHORT) atoi (&argv[i][3]);
  219. break;
  220. case 'r':
  221. if (gRateKbitsPerSec = atoi (&argv[i][3]))
  222. {
  223. break;
  224. }
  225. usage(argv[0]);
  226. case 's':
  227. if (gStatusInterval = atoi(&argv[i][3]))
  228. {
  229. break;
  230. }
  231. usage(argv[0]);
  232. case 't':
  233. if ((gMCastTtl = atoi(&argv[i][3])) <= MAX_MCAST_TTL)
  234. {
  235. gfSetMCastTtl = TRUE;
  236. break;
  237. }
  238. usage(argv[0]);
  239. case 'v':
  240. gfVerifyData = TRUE;
  241. break;
  242. case 'x':
  243. gSetWinsockInfo = TRUE;
  244. break;
  245. case 'y':
  246. gClearWinsockInfo = TRUE;
  247. break;
  248. default:
  249. usage(argv[0]);
  250. }
  251. }
  252. }
  253. //
  254. // Check FEC parameters
  255. //
  256. if ((gFECGroupSize || gFECProActive || gfFECOnDemand) &&
  257. ((!gFECGroupSize) || !(gFECProActive || gfFECOnDemand)))
  258. {
  259. usage(argv[0]);
  260. }
  261. return;
  262. }
  263. //
  264. // Function: GetInterface
  265. //
  266. // Description:
  267. // This function retrieves a zero based index and returns
  268. // the IP interface corresponding to that.
  269. //
  270. int
  271. GetInterface(
  272. int InterfaceNum,
  273. ULONG *pIpAddress,
  274. BOOL fPrintInterfaces
  275. )
  276. {
  277. SOCKET s;
  278. SOCKET_ADDRESS_LIST *slist=NULL;
  279. char buf[2048];
  280. DWORD dwBytesRet;
  281. int i, ret;
  282. s = WSASocket(AF_INET, SOCK_RAW, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);
  283. if (s == INVALID_SOCKET)
  284. {
  285. fprintf(stderr, "WSASocket() failed: %d\n", WSAGetLastError());
  286. return -1;
  287. }
  288. ret = WSAIoctl (s, SIO_ADDRESS_LIST_QUERY, NULL, 0, buf, 2048, &dwBytesRet, NULL, NULL);
  289. if (ret == SOCKET_ERROR)
  290. {
  291. fprintf(stderr, "WSAIoctl(SIO_ADDRESS_LIST_QUERY) failed: %d\n",
  292. WSAGetLastError());
  293. closesocket(s);
  294. return -1;
  295. }
  296. slist = (SOCKET_ADDRESS_LIST *)buf;
  297. closesocket(s);
  298. if (fPrintInterfaces)
  299. {
  300. // Just print all local IP interfaces.
  301. for(i=0; i < slist->iAddressCount ;i++)
  302. {
  303. fprintf(stdout, " %-2d ........ [%s]\n", i,
  304. inet_ntoa(((SOCKADDR_IN *)slist->Address[i].lpSockaddr)->sin_addr));
  305. }
  306. }
  307. else
  308. {
  309. if (InterfaceNum >= slist->iAddressCount)
  310. {
  311. return -1;
  312. }
  313. *pIpAddress = (ULONG) ((SOCKADDR_IN *)slist->Address[InterfaceNum].lpSockaddr)->sin_addr.s_addr;
  314. }
  315. return 0;
  316. }
  317. // --------------------------------------------------------------
  318. // ****************************************************************
  319. #define RMCAST_PARAM_KEY \
  320. L"System\\CurrentControlSet\\Services\\RMCast\\Parameters"
  321. #define RMCAST_WINSOCK_KEY \
  322. L"System\\CurrentControlSet\\Services\\RMCast\\Parameters\\Winsock"
  323. #define WINSOCK_PARAMS_KEY \
  324. L"System\\CurrentControlSet\\Services\\WinSock\\Parameters"
  325. #define RMCAST_TRANSPORT \
  326. L"RMCast"
  327. DWORD
  328. SetHelperDllRegInfo(
  329. )
  330. {
  331. DWORD status;
  332. DWORD NameLength, mappingSize, Type;
  333. HKEY hKey = NULL;
  334. LPBYTE mapping = NULL;
  335. WCHAR *wshDllPath = L"%SystemRoot%\\system32\\wshrm.dll";
  336. ULONG sockAddrLength = sizeof(SOCKADDR_IN);
  337. WCHAR *pTransports;
  338. HANDLE hWshRm;
  339. PWSH_GET_WINSOCK_MAPPING pMapFunc = NULL;
  340. system ("sc create RMCast binPath= %SystemRoot%\\system32\\drivers\\RMCast.sys type= kernel");
  341. //
  342. // First, create the keys in HKLM / System / CurrentControlSet / Services / RMCast
  343. //
  344. status = RegCreateKeyExW (HKEY_LOCAL_MACHINE, // hkey
  345. RMCAST_PARAM_KEY, // lpSubKey
  346. 0, // reserved
  347. NULL, // lpclass
  348. REG_OPTION_NON_VOLATILE, // options
  349. KEY_ALL_ACCESS, // samDesired
  350. NULL, // lpSecurityAttributes
  351. &hKey, // phkResult
  352. NULL); // lpdwDisposition
  353. if (status != NO_ERROR)
  354. {
  355. return (status);
  356. }
  357. RegCloseKey(hKey);
  358. status = RegCreateKeyExW (HKEY_LOCAL_MACHINE, // hkey
  359. RMCAST_WINSOCK_KEY, // lpSubKey
  360. 0, // reserved
  361. NULL, // lpclass
  362. REG_OPTION_NON_VOLATILE, // options
  363. KEY_ALL_ACCESS, // samDesired
  364. NULL, // lpSecurityAttributes
  365. &hKey, // phkResult
  366. NULL); // lpdwDisposition
  367. if (status != NO_ERROR)
  368. {
  369. return (status);
  370. }
  371. RegCloseKey(hKey);
  372. if (!(hWshRm = LoadLibrary ("wshrm.dll")) ||
  373. !(pMapFunc = (PWSH_GET_WINSOCK_MAPPING) GetProcAddress (hWshRm, "WSHGetWinsockMapping")))
  374. {
  375. if (hWshRm)
  376. {
  377. printf ("FAILed to find proc -- WSHGetWinsockMapping -- in wshrm.dll\n");
  378. FreeLibrary (hWshRm);
  379. }
  380. else
  381. {
  382. printf ("FAILed to load wshrm.dll\n");
  383. }
  384. return (ERROR_NOT_ENOUGH_MEMORY);
  385. }
  386. //
  387. // Get the winsock mapping data.
  388. //
  389. mappingSize = (*pMapFunc) ((PWINSOCK_MAPPING) mapping, 0);
  390. mapping = LocalAlloc(LMEM_FIXED, mappingSize);
  391. if (mapping == NULL)
  392. {
  393. FreeLibrary (hWshRm);
  394. return (ERROR_NOT_ENOUGH_MEMORY);
  395. }
  396. mappingSize = (*pMapFunc) ((PWINSOCK_MAPPING) mapping, mappingSize);
  397. FreeLibrary (hWshRm);
  398. //
  399. // Open the RMCast winsock parameters registry key
  400. //
  401. status = RegOpenKeyExW (HKEY_LOCAL_MACHINE,
  402. RMCAST_WINSOCK_KEY,
  403. 0,
  404. KEY_WRITE,
  405. &hKey);
  406. if (status != ERROR_SUCCESS)
  407. {
  408. LocalFree (mapping);
  409. return (status);
  410. }
  411. //
  412. // Write the required values
  413. //
  414. status = RegSetValueExW (hKey,
  415. L"Mapping",
  416. 0,
  417. REG_BINARY,
  418. (CONST BYTE *) mapping,
  419. mappingSize);
  420. LocalFree (mapping);
  421. if (status != ERROR_SUCCESS)
  422. {
  423. RegCloseKey(hKey);
  424. return (status);
  425. }
  426. status = RegSetValueExW (hKey,
  427. L"HelperDllName",
  428. 0,
  429. REG_EXPAND_SZ,
  430. (CONST BYTE *) wshDllPath,
  431. (lstrlenW(wshDllPath) + 1) * sizeof(WCHAR));
  432. if (status != ERROR_SUCCESS)
  433. {
  434. RegCloseKey(hKey);
  435. return (status);
  436. }
  437. status = RegSetValueExW (hKey,
  438. L"MinSockaddrLength",
  439. 0,
  440. REG_DWORD,
  441. (CONST BYTE *) &sockAddrLength,
  442. sizeof(DWORD));
  443. if (status != ERROR_SUCCESS)
  444. {
  445. RegCloseKey(hKey);
  446. return (status);
  447. }
  448. status = RegSetValueExW (hKey,
  449. L"MaxSockaddrLength",
  450. 0,
  451. REG_DWORD,
  452. (CONST BYTE *) &sockAddrLength,
  453. sizeof(DWORD));
  454. RegCloseKey (hKey);
  455. if (status != ERROR_SUCCESS)
  456. {
  457. return (status);
  458. }
  459. //
  460. // Now, set the Winsock parameter key
  461. //
  462. status = RegOpenKeyExW (HKEY_LOCAL_MACHINE,
  463. WINSOCK_PARAMS_KEY,
  464. 0,
  465. MAXIMUM_ALLOWED,
  466. &hKey);
  467. if (status != ERROR_SUCCESS)
  468. {
  469. return (status);
  470. }
  471. mapping = NULL;
  472. mappingSize = 0;
  473. status = RegQueryValueExW (hKey,
  474. L"Transports",
  475. NULL,
  476. &Type,
  477. mapping,
  478. &mappingSize);
  479. NameLength = (wcslen (RMCAST_TRANSPORT) + 1) * sizeof(WCHAR);
  480. if ((status == ERROR_MORE_DATA) ||
  481. ((status == ERROR_SUCCESS) && (mappingSize)))
  482. {
  483. mapping = LocalAlloc(LMEM_FIXED, (mappingSize+NameLength));
  484. if (mapping == NULL)
  485. {
  486. RegCloseKey (hKey);
  487. return (ERROR_NOT_ENOUGH_MEMORY);
  488. }
  489. //
  490. // Append the RMCast entry to the Transports key
  491. //
  492. status = RegQueryValueExW (hKey,
  493. L"Transports",
  494. NULL,
  495. &Type,
  496. mapping,
  497. &mappingSize);
  498. pTransports = (WCHAR *) &mapping[mappingSize-sizeof(WCHAR)];
  499. wcscpy (pTransports, RMCAST_TRANSPORT);
  500. pTransports [wcslen(RMCAST_TRANSPORT)] = 0;
  501. pTransports [wcslen(RMCAST_TRANSPORT)+1] = 0;
  502. }
  503. else
  504. {
  505. status = ERROR_MORE_DATA;
  506. }
  507. if ((status != ERROR_SUCCESS) ||
  508. (Type != REG_MULTI_SZ))
  509. {
  510. if (mapping)
  511. {
  512. LocalFree (mapping);
  513. }
  514. RegCloseKey (hKey);
  515. return (status);
  516. }
  517. status = RegSetValueExW (hKey,
  518. L"Transports",
  519. 0,
  520. REG_MULTI_SZ,
  521. mapping,
  522. (mappingSize+NameLength));
  523. LocalFree (mapping);
  524. RegCloseKey (hKey);
  525. return (status);
  526. }
  527. DWORD
  528. ClearHelperDllRegInfo(
  529. )
  530. {
  531. DWORD status;
  532. HKEY hKey = NULL;
  533. DWORD remainingSize, mappingSize, Type, RMNameLength = wcslen (RMCAST_TRANSPORT) + 1;
  534. LPBYTE mapping = NULL;
  535. DWORD CurStrLenPlusOne;
  536. WCHAR *pTransports;
  537. //
  538. // Remove the RMCast transport from the Winsock parameter key
  539. //
  540. status = RegOpenKeyExW (HKEY_LOCAL_MACHINE,
  541. WINSOCK_PARAMS_KEY,
  542. 0,
  543. MAXIMUM_ALLOWED,
  544. &hKey);
  545. if (status != ERROR_SUCCESS)
  546. {
  547. return (status);
  548. }
  549. mapping = NULL;
  550. mappingSize = 0;
  551. status = RegQueryValueExW (hKey,
  552. L"Transports",
  553. NULL,
  554. &Type,
  555. mapping,
  556. &mappingSize);
  557. if ((status == ERROR_MORE_DATA) ||
  558. ((status == ERROR_SUCCESS) && (mappingSize)))
  559. {
  560. mapping = LocalAlloc(LMEM_FIXED, mappingSize);
  561. if (mapping == NULL)
  562. {
  563. RegCloseKey (hKey);
  564. return (ERROR_NOT_ENOUGH_MEMORY);
  565. }
  566. status = RegQueryValueExW (hKey,
  567. L"Transports",
  568. NULL,
  569. &Type,
  570. mapping,
  571. &mappingSize);
  572. }
  573. else
  574. {
  575. status = ERROR_MORE_DATA;
  576. }
  577. if ((status != ERROR_SUCCESS) ||
  578. (Type != REG_MULTI_SZ))
  579. {
  580. if (mapping)
  581. {
  582. LocalFree (mapping);
  583. }
  584. RegCloseKey (hKey);
  585. return (status);
  586. }
  587. pTransports = (WCHAR *) mapping;
  588. remainingSize = mappingSize;
  589. while (*pTransports != L'\0')
  590. {
  591. CurStrLenPlusOne = wcslen(pTransports) + 1;
  592. if (CurStrLenPlusOne > remainingSize)
  593. {
  594. status = ERROR_INVALID_DATA;
  595. break;
  596. }
  597. remainingSize -= (CurStrLenPlusOne * sizeof (WCHAR)); // Decrement the amount of buffer unparsed
  598. // If this string is RMCast
  599. if ((CurStrLenPlusOne == RMNameLength) &&
  600. (_wcsicmp( pTransports, RMCAST_TRANSPORT) == 0))
  601. {
  602. // Remove this string from the list
  603. mappingSize -= (RMNameLength * sizeof(WCHAR));
  604. MoveMemory (pTransports , pTransports + RMNameLength , remainingSize);
  605. }
  606. else
  607. {
  608. pTransports += CurStrLenPlusOne; // Move to the next string
  609. }
  610. } // while: the transport list has not been completely parsed.
  611. status = RegSetValueExW (hKey,
  612. L"Transports",
  613. 0,
  614. REG_MULTI_SZ,
  615. mapping,
  616. mappingSize);
  617. LocalFree (mapping);
  618. RegCloseKey (hKey);
  619. return (status);
  620. }
  621. // ****************************************************************
  622. ULONGLONG TotalBytes = 0;
  623. ULONGLONG DataBytes = 0;
  624. ULONG
  625. GetSenderStats(
  626. SOCKET s,
  627. LONG count
  628. )
  629. {
  630. ULONG BufferLength;
  631. RM_SENDER_STATS RmSenderStats;
  632. time_t DiffTotalSecs, DiffTotalMSecs;
  633. time_t DiffPreviousSecs, DiffPreviousMSecs;
  634. ULONG ret;
  635. // Add 1 below to MSsecs to avoid div by 0
  636. DiffTotalSecs = CurrentTime.time - StartTime.time;
  637. DiffTotalMSecs = (1 + CurrentTime.millitm - StartTime.millitm) + (1000 * DiffTotalSecs);
  638. DiffPreviousSecs = CurrentTime.time - PreviousTime.time;
  639. DiffPreviousMSecs = (1 + CurrentTime.millitm - PreviousTime.millitm) + (1000 * DiffPreviousSecs);
  640. BufferLength = sizeof(RM_SENDER_STATS);
  641. memset (&RmSenderStats, 0, BufferLength);
  642. ret = getsockopt (s, IPPROTO_RM, RM_SENDER_STATISTICS, (char *)&RmSenderStats, &BufferLength);
  643. if (ret != ERROR_SUCCESS)
  644. {
  645. fprintf (stderr, "GetSenderStats: Failed to retrieve sender stats!\n");
  646. return (ret);
  647. }
  648. fprintf (stdout, "MessagesSent=<%d>, Interval=[%d.%d / %d.%d]\n",
  649. count, DiffPreviousSecs, DiffPreviousMSecs, DiffTotalSecs, DiffTotalMSecs);
  650. fprintf (stdout, "\tDataBytesSent=<%I64d>, Rate= %d Kbits / Sec\n",
  651. RmSenderStats.DataBytesSent, (ULONG) ((RmSenderStats.DataBytesSent*BITS_PER_BYTE) / DiffTotalMSecs));
  652. fprintf (stdout, "\tTotalBytesSent=<%I64d>, Rate= %d Kbits / Sec\n",
  653. RmSenderStats.TotalBytesSent, ((RmSenderStats.TotalBytesSent*BITS_PER_BYTE)/DiffTotalMSecs));
  654. fprintf (stdout, "\tNaksReceived=<%I64d>\n", RmSenderStats.NaksReceived);
  655. fprintf (stdout, "\tNaksReceivedTooLate=<%I64d>\n", RmSenderStats.NaksReceivedTooLate);
  656. fprintf (stdout, "\tNumOutstandingNaks=<%I64d>\n", RmSenderStats.NumOutstandingNaks);
  657. fprintf (stdout, "\tNumNaksAfterRData=<%I64d>\n", RmSenderStats.NumNaksAfterRData);
  658. fprintf (stdout, "\tRepairPacketsSent=<%I64d>\n", RmSenderStats.RepairPacketsSent);
  659. fprintf (stdout, "\tBufferSpaceAvailable=<%I64d> bytes\n\n", RmSenderStats.BufferSpaceAvailable);
  660. fprintf (stdout, "\tLeadingEdgeSeqId=<%I64d>\n", RmSenderStats.LeadingEdgeSeqId);
  661. fprintf (stdout, "\tTrailingEdgeSeqId=<%I64d>\n", RmSenderStats.TrailingEdgeSeqId);
  662. fprintf (stdout, "\tSequences in Window=<%I64d>\n", (RmSenderStats.LeadingEdgeSeqId-RmSenderStats.TrailingEdgeSeqId+1));
  663. fprintf (stdout, "\tRateKBitsPerSecLast=<%I64d>\n", RmSenderStats.RateKBitsPerSecLast);
  664. fprintf (stdout, "\tRateKBitsPerSecOverall=<%I64d>\n", RmSenderStats.RateKBitsPerSecOverall);
  665. fprintf (stdout, "\n\tDataBytesSent in last interval=<%I64d>, Rate= %d Kbits / Sec\n",
  666. (RmSenderStats.DataBytesSent-DataBytes),
  667. (ULONG) (BITS_PER_BYTE * (RmSenderStats.DataBytesSent-DataBytes) / DiffPreviousMSecs));
  668. fprintf (stdout, "\tTotalBytesSent in last interval=<%I64d>, Rate= %d Kbits / Sec\n\n",
  669. (RmSenderStats.TotalBytesSent-TotalBytes),
  670. (ULONG) (BITS_PER_BYTE * (RmSenderStats.TotalBytesSent-TotalBytes)/DiffPreviousMSecs));
  671. TotalBytes = RmSenderStats.TotalBytesSent;
  672. DataBytes = RmSenderStats.DataBytesSent;
  673. fflush (stdout);
  674. return (ERROR_SUCCESS);
  675. }
  676. ULONG
  677. GetReceiverStats(
  678. SOCKET s,
  679. LONG count
  680. )
  681. {
  682. ULONG BufferLength;
  683. RM_RECEIVER_STATS RmReceiverStats;
  684. time_t DiffTotalSecs, DiffTotalMSecs;
  685. time_t DiffPreviousSecs, DiffPreviousMSecs;
  686. ULONG ret;
  687. // Add 1 below to MSsecs to avoid div by 0
  688. DiffTotalSecs = CurrentTime.time - StartTime.time;
  689. DiffTotalMSecs = (1 + CurrentTime.millitm - StartTime.millitm) + (1000 * DiffTotalSecs);
  690. DiffPreviousSecs = CurrentTime.time - PreviousTime.time;
  691. DiffPreviousMSecs = (1 + CurrentTime.millitm - PreviousTime.millitm) + (1000 * DiffPreviousSecs);
  692. BufferLength = sizeof(RM_RECEIVER_STATS);
  693. memset (&RmReceiverStats, 0, BufferLength);
  694. ret = getsockopt (s, IPPROTO_RM, RM_RECEIVER_STATISTICS, (char *)&RmReceiverStats, &BufferLength);
  695. if (ret != ERROR_SUCCESS)
  696. {
  697. fprintf (stderr, "GetReceiverStats: Failed to retrieve Receiver stats, ret=<%d>, LastError=<%x>!\n",
  698. ret, GetLastError());
  699. return (ret);
  700. }
  701. fprintf (stdout, "MessagesRcvd=<%d>, Interval=[%d.%d / %d.%d]\n",
  702. count, DiffPreviousSecs, DiffPreviousMSecs, DiffTotalSecs, DiffTotalMSecs);
  703. fprintf (stdout, "\n\tDataBytesReceived in last interval=<%I64d>, Rate= %d Kbits / Sec\n",
  704. (RmReceiverStats.DataBytesReceived-DataBytes),
  705. (ULONG) (BITS_PER_BYTE * (RmReceiverStats.DataBytesReceived-DataBytes) / DiffPreviousMSecs));
  706. fprintf (stdout, "\tTotalBytesReceived in last interval=<%I64d>, Rate= %d Kbits / Sec\n\n",
  707. (RmReceiverStats.TotalBytesReceived-TotalBytes),
  708. (ULONG) (BITS_PER_BYTE * (RmReceiverStats.TotalBytesReceived-TotalBytes)/DiffPreviousMSecs));
  709. fprintf (stdout, "\tTotalDataBytesRcvd=<%I64d>, Rate= %d Kbits / Sec\n",
  710. RmReceiverStats.DataBytesReceived, (ULONG) ((RmReceiverStats.DataBytesReceived*BITS_PER_BYTE) / DiffTotalMSecs));
  711. fprintf (stdout, "\tTotalBytesReceived=<%I64d>, Rate= %d Kbits / Sec\n",
  712. RmReceiverStats.TotalBytesReceived, ((RmReceiverStats.TotalBytesReceived*BITS_PER_BYTE)/DiffTotalMSecs));
  713. fprintf (stdout, "\tRateKBitsPerSecLast=<%I64d>\n", RmReceiverStats.RateKBitsPerSecLast);
  714. fprintf (stdout, "\tRateKBitsPerSecOverall=<%I64d>\n", RmReceiverStats.RateKBitsPerSecOverall);
  715. fprintf (stdout, "\tNumODataPacketsReceived=<%I64d>\n", RmReceiverStats.NumODataPacketsReceived);
  716. fprintf (stdout, "\tNumRDataPacketsReceived=<%I64d>\n", RmReceiverStats.NumRDataPacketsReceived);
  717. fprintf (stdout, "\tNumDuplicateDataPackets=<%I64d>\n", RmReceiverStats.NumDuplicateDataPackets);
  718. fprintf (stdout, "\tLeadingEdgeSeqId=<%I64d>\n", RmReceiverStats.LeadingEdgeSeqId);
  719. fprintf (stdout, "\tTrailingEdgeSeqId=<%I64d>\n", RmReceiverStats.TrailingEdgeSeqId);
  720. fprintf (stdout, "\tSequences in Window=<%I64d>\n\n", (RmReceiverStats.LeadingEdgeSeqId-RmReceiverStats.TrailingEdgeSeqId+1));
  721. fprintf (stdout, "\tFirstNakSequenceNumber=<%I64d>\n", RmReceiverStats.FirstNakSequenceNumber);
  722. fprintf (stdout, "\tNumPendingNaks=<%I64d>\n", RmReceiverStats.NumPendingNaks);
  723. fprintf (stdout, "\tNumOutstandingNaks=<%I64d>\n", RmReceiverStats.NumOutstandingNaks);
  724. fprintf (stdout, "\tNumDataPacketsBuffered=<%I64d>\n", RmReceiverStats.NumDataPacketsBuffered);
  725. fprintf (stdout, "\tTotalSelectiveNaksSent=<%I64d>\n", RmReceiverStats.TotalSelectiveNaksSent);
  726. fprintf (stdout, "\tTotalParityNaksSent=<%I64d>\n\n", RmReceiverStats.TotalParityNaksSent);
  727. TotalBytes = RmReceiverStats.TotalBytesReceived;
  728. DataBytes = RmReceiverStats.DataBytesReceived;
  729. fflush (stdout);
  730. return (ERROR_SUCCESS);
  731. }
  732. // --------------------------------------------------------------
  733. EnumerateProtocols(
  734. )
  735. {
  736. #define BUFFER_SIZE 10*1024
  737. INT NumProts, err = NO_ERROR;
  738. CHAR pBuffer[BUFFER_SIZE];
  739. WSAPROTOCOL_INFOW* pwpiProtoInfo = (WSAPROTOCOL_INFOW *) pBuffer;
  740. WSAPROTOCOL_INFOW* pwpiInfo = pwpiProtoInfo;
  741. DWORD dwBuffSize = BUFFER_SIZE;
  742. if (NumProts = WSCEnumProtocols (NULL, pwpiProtoInfo, &dwBuffSize, &err))
  743. {
  744. // Print all protocols
  745. printf ("WSHEnumProtocols returned <%d>:\n", NumProts);
  746. for (err = 0; err < NumProts; err++)
  747. {
  748. printf ("\t[%d]:\tType=<%x>, ProtocolId=<%x>, Flags=<%x>\n",
  749. err, pwpiInfo->iSocketType, pwpiInfo->iProtocol, pwpiInfo->dwServiceFlags1);
  750. pwpiInfo++;
  751. }
  752. }
  753. else
  754. {
  755. printf ("WSCEnumProtocols failed: <%d>, dwBuffSize=<%d>\n", err, dwBuffSize);
  756. }
  757. }
  758. // --------------------------------------------------------------
  759. //
  760. // Function: main
  761. //
  762. // Description:
  763. // This function loads Winsock, parses the command line, and
  764. // begins receiving packets. Once a packet is received they
  765. // are decoded. Because we are receiving IP datagrams, the
  766. // receive call will return whole datagrams.
  767. //
  768. int __cdecl
  769. main(int argc, char **argv)
  770. {
  771. SOCKET s, sockR;
  772. WSADATA wsd;
  773. SOCKADDR_IN SrcSockAddr;
  774. SOCKADDR_IN SAMulticast;
  775. SOCKADDR_IN SASender;
  776. WSA_SETUP_DISPOSITION disposition;
  777. ULONG IpAddress;
  778. LONG ret;
  779. LONG count, Length, BufferInfo;
  780. char *TestBuffer=NULL;
  781. char value;
  782. struct linger LingerData;
  783. RM_SEND_WINDOW RmWindow;
  784. RM_FEC_INFO RmFEC;
  785. time_t DiffSecs, DiffMSecs;
  786. LONG Flags, BytesRead;
  787. WSABUF WsaBuf;
  788. // Parse the command line
  789. //
  790. gMCastGroupAddr = inet_addr ("231.7.8.9");
  791. ValidateArgs(argc, argv);
  792. if (gClearWinsockInfo)
  793. {
  794. //
  795. // First, stop the service and delete the RMCast registry keys
  796. //
  797. system ("sc stop RMCast");
  798. system ("sc delete RMCast");
  799. ret = ClearHelperDllRegInfo ();
  800. if (ret == ERROR_SUCCESS)
  801. {
  802. fprintf (stdout, "ClearHelperDllRegInfo returned <%x>\n", ret);
  803. //
  804. // Poke winsock to update the Winsock2 config
  805. //
  806. ret = MigrateWinsockConfiguration (&disposition, NULL, 0);
  807. if (ret != ERROR_SUCCESS)
  808. {
  809. fprintf (stderr, "MigrateWinsockConfiguration FAILed <%x>\n", ret);
  810. }
  811. }
  812. else
  813. {
  814. fprintf (stderr, "ClearHelperDllRegInfo FAILed <%x>\n", ret);
  815. }
  816. if (ret != ERROR_SUCCESS)
  817. {
  818. return -1;
  819. }
  820. return 0;
  821. }
  822. if (gSetWinsockInfo)
  823. {
  824. //
  825. // First, clear any Registry keys that may still be lying around
  826. // from any previous installation
  827. //
  828. ret = ClearHelperDllRegInfo ();
  829. //
  830. // Now, rewrite the keys afresh
  831. //
  832. ret = SetHelperDllRegInfo ();
  833. if (ret == ERROR_SUCCESS)
  834. {
  835. fprintf (stdout, "SetHelperDllRegInfo returned <%x>\n", ret);
  836. //
  837. // Poke winsock to update the Winsock2 config
  838. //
  839. ret = MigrateWinsockConfiguration (&disposition, NULL, 0);
  840. if (ret != ERROR_SUCCESS)
  841. {
  842. fprintf (stderr, "MigrateWinsockConfiguration FAILed <%x>\n", ret);
  843. }
  844. }
  845. else
  846. {
  847. fprintf (stderr, "SetHelperDllRegInfo FAILed <%x>\n", ret);
  848. }
  849. if (ret != ERROR_SUCCESS)
  850. {
  851. return -1;
  852. }
  853. return 0;
  854. }
  855. ret = 0;
  856. //
  857. // Now, check for validity of the parameters
  858. //
  859. if (gMinPktSize > gMaxPktSize)
  860. {
  861. fprintf (stderr, "ERROR in parameter specification: MinPktSize=%d > MaxPktSize=%d\n",
  862. gMinPktSize, gMaxPktSize);
  863. ret = -1;
  864. }
  865. if (ret)
  866. {
  867. return (ret);
  868. }
  869. // Load Winsock
  870. //
  871. if (WSAStartup (MAKEWORD(2,2), &wsd) != 0)
  872. {
  873. fprintf(stderr, "WSAStartup() failed: %d\n", GetLastError());
  874. return -1;
  875. }
  876. if (gfEnumerateProts)
  877. {
  878. EnumerateProtocols();
  879. }
  880. TestBuffer = (char *)HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BYTE) * gMaxPktSize);
  881. if (!TestBuffer)
  882. {
  883. fprintf(stderr, "HeapAlloc() for %d bytes failed: ERROR=%d\n", gMaxPktSize, GetLastError());
  884. WSACleanup();
  885. return -1;
  886. }
  887. if (gReceiver)
  888. {
  889. memset (TestBuffer, '#', gMaxPktSize);
  890. }
  891. else
  892. {
  893. value = 0;
  894. for (count = 0; count < gMaxPktSize; count++)
  895. {
  896. TestBuffer[count] = value++;
  897. }
  898. }
  899. // Create an RMCast socket
  900. if (INVALID_SOCKET == (s = WSASocket(AF_INET,
  901. SOCK_RMCAST,
  902. IPPROTO_RM,
  903. NULL,
  904. 0,
  905. (WSA_FLAG_MULTIPOINT_C_LEAF |
  906. WSA_FLAG_MULTIPOINT_D_LEAF))))
  907. {
  908. fprintf(stderr, "socket() failed: %d\n", WSAGetLastError());
  909. HeapFree(GetProcessHeap(), 0, TestBuffer);
  910. WSACleanup();
  911. return -1;
  912. }
  913. fprintf(stdout, "socket SUCCEEDED, s=<%d>\n", s);
  914. SAMulticast.sin_family = AF_INET;
  915. SAMulticast.sin_port = htons (gMCastGroupPort);
  916. SAMulticast.sin_addr.s_addr = gMCastGroupAddr;
  917. if (gReceiver)
  918. {
  919. fprintf(stdout, "We are Receiver!\n");
  920. if (bind (s, (SOCKADDR *) &SAMulticast, sizeof(SAMulticast)))
  921. {
  922. fprintf(stderr, "bind to (%s:%d) FAILed, status=<%x>\n",
  923. inet_ntoa(SAMulticast.sin_addr), ntohs(SAMulticast.sin_port), WSAGetLastError());
  924. }
  925. else
  926. {
  927. fprintf (stdout, "Bind to <%s> succeeded! ...\n", inet_ntoa(SAMulticast.sin_addr));
  928. if (gListenOnAllInterfaces)
  929. {
  930. count = 0;
  931. while (0 == GetInterface (count, &IpAddress, FALSE))
  932. {
  933. SrcSockAddr.sin_addr.s_addr = IpAddress;
  934. fprintf (stdout, "\t[%d] Listening on <%s>\n", count, inet_ntoa(SrcSockAddr.sin_addr));
  935. setsockopt (s, IPPROTO_RM, RM_ADD_RECEIVE_IF, (char *)&IpAddress, sizeof(IpAddress));
  936. count++;
  937. }
  938. }
  939. else if (gUseSpecifiedInterface)
  940. {
  941. //
  942. // Set an interface to receive IP packets on
  943. //
  944. if (0 == GetInterface (gInterface, &IpAddress, FALSE))
  945. {
  946. SrcSockAddr.sin_addr.s_addr = IpAddress;
  947. fprintf (stdout, "\t[%d] Interface is <%s>\n", gInterface, inet_ntoa(SrcSockAddr.sin_addr));
  948. setsockopt (s, IPPROTO_RM, RM_ADD_RECEIVE_IF, (char *)&IpAddress, sizeof(IpAddress));
  949. }
  950. else
  951. {
  952. fprintf (stderr, "Unable to obtain an interface from GetInterface\n");
  953. }
  954. }
  955. // listen on the socket
  956. if (listen (s, 1))
  957. {
  958. fprintf(stderr, "listen() FAILed, status=<%x>\n", WSAGetLastError());
  959. }
  960. else
  961. {
  962. fprintf (stdout, "Listen succeeded! ...\n");
  963. // join an RMCast session
  964. Length = sizeof (SOCKADDR);
  965. sockR = accept (s, (SOCKADDR *) &SASender, &Length);
  966. if (sockR == INVALID_SOCKET)
  967. {
  968. fprintf(stderr, "accept() failed: %d\n", WSAGetLastError());
  969. }
  970. else
  971. {
  972. fprintf(stdout, "Accept succeeded! s=<%d>, sockR=<%d>, Sender=<%s>\n",
  973. s, sockR, inet_ntoa(SASender.sin_addr));
  974. // start receiving data
  975. // memset (TestBuffer, '@', gMaxPktSize);
  976. WsaBuf.buf = TestBuffer;
  977. WsaBuf.len = gMaxPktSize;
  978. count = 0;
  979. Length = gMinPktSize;
  980. _ftime (&StartTime);
  981. while (TRUE)
  982. {
  983. * ((PULONG) TestBuffer) = 0;
  984. Flags = BytesRead = 0;
  985. /*
  986. ret = recv (sockR, TestBuffer, gMaxPktSize, 0);
  987. if ((ret==0) || (ret == SOCKET_ERROR))
  988. */
  989. ret = WSARecv (sockR, // socket
  990. &WsaBuf, // lpBuffers
  991. 1, // dwBufferCount
  992. &BytesRead, // lpNumberOfBytesRecvd
  993. &Flags, // lpFlags
  994. NULL, // lpOverlapped
  995. NULL); // lpCompletionRoutine
  996. if (ret)
  997. {
  998. fprintf(stderr, "WSARecv() FAILed==><%d>, ret=<%d>, count=<%d> BytesRead=<%d>\n",
  999. WSAGetLastError(), ret, count, BytesRead);
  1000. break;
  1001. }
  1002. if (Flags)
  1003. {
  1004. fprintf(stdout, "[%d : %d] WARNING: BytesRead=<%d>, LastError=<%d>, Flags=<%x>\n",
  1005. count, Length, BytesRead, WSAGetLastError(), Flags);
  1006. }
  1007. TotalBytes += BytesRead;
  1008. _ftime (&CurrentTime);
  1009. if (!count++)
  1010. {
  1011. PreviousTime = StartTime = CurrentTime;
  1012. }
  1013. if (!(count % gStatusInterval))
  1014. {
  1015. if (ERROR_SUCCESS == GetReceiverStats (sockR, count))
  1016. {
  1017. PreviousTime = CurrentTime;
  1018. }
  1019. }
  1020. if (BytesRead != Length)
  1021. {
  1022. fprintf(stderr, "OUT-OF-ORDER: Expecting <%d>, received <%d>\n",
  1023. Length, BytesRead);
  1024. fflush (stdout);
  1025. }
  1026. else if (BytesRead != * ((PLONG) TestBuffer))
  1027. {
  1028. fprintf(stderr, "BAD-DATA ? First ULONG=<%d>, BytesRead=<%d>\n",
  1029. * ((PULONG) TestBuffer), BytesRead);
  1030. fflush (stdout);
  1031. }
  1032. else if (gfVerifyData)
  1033. {
  1034. value = TestBuffer[4];
  1035. for (BufferInfo = 5; BufferInfo < BytesRead; BufferInfo++)
  1036. {
  1037. if (++value != TestBuffer[BufferInfo])
  1038. {
  1039. fprintf (stderr, "\tCORRUPT buffer! Count=<%d>, Offset=<%d/%d> -- ActualValue=<%x>!=<%x>\n",
  1040. count, BufferInfo, BytesRead, TestBuffer[BufferInfo], value);
  1041. fflush (stdout);
  1042. break;
  1043. }
  1044. }
  1045. }
  1046. Length = BytesRead+1;
  1047. if (Length > gMaxPktSize)
  1048. {
  1049. Length = gMinPktSize;
  1050. }
  1051. }
  1052. fprintf (stdout, "************************ Final Stats ***************************\n");
  1053. GetReceiverStats (sockR, count);
  1054. closesocket(sockR);
  1055. }
  1056. }
  1057. }
  1058. }
  1059. else
  1060. {
  1061. fprintf(stdout, "We are Sender!\n");
  1062. // Bind the socket socket
  1063. SrcSockAddr.sin_family = AF_INET;
  1064. SrcSockAddr.sin_port = htons(0); // let system pick the port #
  1065. SrcSockAddr.sin_addr.s_addr = 0; // set default interface = 0 for now
  1066. if (bind (s, (SOCKADDR *)&SrcSockAddr, sizeof(SrcSockAddr)))
  1067. {
  1068. fprintf(stderr, "bind(%s:%d) FAILed: %d\n",
  1069. inet_ntoa(SrcSockAddr.sin_addr), ntohs(SrcSockAddr.sin_port), WSAGetLastError());
  1070. }
  1071. else
  1072. {
  1073. fprintf (stdout, "Bind succeeded! ...\n");
  1074. if (gfSetAfdBufferSize)
  1075. {
  1076. if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *) &gAfdBufferSize, sizeof (gAfdBufferSize)) < 0)
  1077. {
  1078. fprintf (stderr, "SO_SNDBUF FAILed -- <%x>\n", WSAGetLastError());
  1079. }
  1080. else
  1081. {
  1082. fprintf (stdout, "SO_SNDBUF SUCCEEDed\n");
  1083. }
  1084. }
  1085. //
  1086. // Set an interface to send IP packets on
  1087. //
  1088. if (gUseSpecifiedInterface)
  1089. {
  1090. if (0 == GetInterface (gInterface, &IpAddress, FALSE))
  1091. {
  1092. SrcSockAddr.sin_addr.s_addr = IpAddress;
  1093. fprintf (stdout, "Interface <%d> is <%s>\n", gInterface,inet_ntoa(SrcSockAddr.sin_addr));
  1094. setsockopt (s, IPPROTO_RM, RM_SET_SEND_IF, (char *)&IpAddress, sizeof(IpAddress));
  1095. }
  1096. else
  1097. {
  1098. fprintf (stderr, "Unable to obtain an interface from GetInterface\n");
  1099. }
  1100. }
  1101. //
  1102. // Check if we need to set the Linger time
  1103. //
  1104. if (gSetLingerTime)
  1105. {
  1106. LingerData.l_onoff = 1;
  1107. LingerData.l_linger = gLingerTime;
  1108. if (setsockopt (s, SOL_SOCKET, SO_LINGER, (char *) &LingerData, sizeof (struct linger)) < 0)
  1109. {
  1110. fprintf (stderr, "SO_LINGER FAILed -- <%x>\n", WSAGetLastError());
  1111. }
  1112. else
  1113. {
  1114. fprintf (stdout, "SO_LINGER SUCCEEDed, Lingertime=<%d>\n", (ULONG) gLingerTime);
  1115. }
  1116. }
  1117. //
  1118. // Set the transmission rate and window size
  1119. //
  1120. RmWindow.RateKbitsPerSec = gRateKbitsPerSec;
  1121. RmWindow.WindowSizeInMSecs = 0;
  1122. RmWindow.WindowSizeInBytes = 0;
  1123. // RmWindow.WindowSizeInBytes = 50*1000*1000;
  1124. ret = setsockopt (s, IPPROTO_RM, RM_RATE_WINDOW_SIZE, (char *)&RmWindow, sizeof(RM_SEND_WINDOW));
  1125. //
  1126. // Now, query the transmission rate and window size (to verify that it got set)
  1127. //
  1128. RmWindow.RateKbitsPerSec = 0;
  1129. Length = sizeof(RM_SEND_WINDOW);
  1130. ret = getsockopt (s, IPPROTO_RM, RM_RATE_WINDOW_SIZE, (char *)&RmWindow, &Length);
  1131. fprintf (stdout, "Rate= %d Kb/sec, WindowSize = %d msecs = %d bytes\n",
  1132. RmWindow.RateKbitsPerSec, RmWindow.WindowSizeInMSecs, RmWindow.WindowSizeInBytes);
  1133. //
  1134. // Set the FEC info if desired
  1135. //
  1136. if (gFECGroupSize)
  1137. {
  1138. RmFEC.FECBlockSize = gFECBlockSize;
  1139. RmFEC.FECGroupSize = gFECGroupSize;
  1140. RmFEC.FECProActivePackets = gFECProActive;
  1141. RmFEC.fFECOnDemandParityEnabled = gfFECOnDemand;
  1142. ret = setsockopt (s, IPPROTO_RM, RM_USE_FEC, (char *)&RmFEC, sizeof(RM_FEC_INFO));
  1143. fprintf (stdout, "RM_USE_FEC: ret = <%x>, gFECGroupSize=<%x>, Pro:OnD=<%x:%x>\n",
  1144. ret, gFECGroupSize, gFECProActive, gfFECOnDemand);
  1145. RmFEC.FECBlockSize = 0;
  1146. RmFEC.FECGroupSize = 0;
  1147. RmFEC.FECProActivePackets = 0;
  1148. RmFEC.fFECOnDemandParityEnabled = 0;
  1149. Length = sizeof(RM_FEC_INFO);
  1150. ret = getsockopt (s, IPPROTO_RM, RM_USE_FEC, (char *)&RmFEC, &Length);
  1151. fprintf (stdout, "ret=<%x>, BlockSize= %d, GroupSize = %d, ProActive = %d, OnDemand = %s\n",
  1152. ret, RmFEC.FECBlockSize, RmFEC.FECGroupSize, RmFEC.FECProActivePackets,
  1153. (RmFEC.fFECOnDemandParityEnabled ? "ENabled" : "DISabled"));
  1154. }
  1155. //
  1156. // Set the Late joiner option
  1157. //
  1158. if (gSetLateJoiner)
  1159. {
  1160. ret = setsockopt (s, IPPROTO_RM, RM_LATEJOIN, (char *)&gLateJoinerPercentage, sizeof(ULONG));
  1161. }
  1162. if (gfSetMCastTtl)
  1163. {
  1164. //
  1165. // Set the MCast packet Ttl
  1166. //
  1167. ret = setsockopt (s, IPPROTO_RM, RM_SET_MCAST_TTL, (char *)&gMCastTtl, sizeof(ULONG));
  1168. }
  1169. //
  1170. // Set the Send-Window Advance-rate
  1171. //
  1172. Length = 20;
  1173. ret = setsockopt (s, IPPROTO_RM, RM_SEND_WINDOW_ADV_RATE, (char *)&Length, sizeof(ULONG));
  1174. //
  1175. // Query the Send-Window Advance-rate
  1176. //
  1177. Length= sizeof(ULONG);
  1178. BufferInfo = 0;
  1179. ret = getsockopt (s, IPPROTO_RM, RM_SEND_WINDOW_ADV_RATE, (char *)&BufferInfo, &Length);
  1180. fprintf (stdout, "ret=<%d>, Length=<%d>, WindowAdvRate=<%d>\n", ret, Length, BufferInfo);
  1181. if (connect (s, (SOCKADDR *)&SAMulticast, sizeof(SAMulticast)))
  1182. {
  1183. fprintf(stderr, "connect to (%s:%d) FAILed, status=<%x>\n",
  1184. inet_ntoa(SAMulticast.sin_addr), ntohs(SAMulticast.sin_port), WSAGetLastError());
  1185. }
  1186. else
  1187. {
  1188. fprintf (stdout, "Connect to <%s> succeeded! ...\n", inet_ntoa(SAMulticast.sin_addr));
  1189. _ftime (&StartTime);
  1190. PreviousTime = StartTime;
  1191. //
  1192. // Now, send the rest of the data
  1193. //
  1194. Length = gMinPktSize;
  1195. count = 0;
  1196. while (count < gNumSends)
  1197. {
  1198. * ((PULONG) TestBuffer) = Length;
  1199. // fprintf (stdout, "\tSending %d/%d Length=<%d>\n", count, gNumSends, Length);
  1200. ret = send (s, TestBuffer, Length, 0);
  1201. if (ret == SOCKET_ERROR)
  1202. {
  1203. fprintf(stderr, "[%d]th sendto() failed: %d, Length=<%d>\n",
  1204. (count+1), WSAGetLastError(), Length);
  1205. fflush (stdout);
  1206. break;
  1207. }
  1208. Length++;
  1209. if (Length > gMaxPktSize)
  1210. {
  1211. Length = gMinPktSize;
  1212. }
  1213. _ftime (&CurrentTime);
  1214. count++;
  1215. if (!(count % gStatusInterval))
  1216. {
  1217. if (ERROR_SUCCESS == GetSenderStats (s, count))
  1218. {
  1219. PreviousTime = CurrentTime;
  1220. }
  1221. }
  1222. }
  1223. // fprintf (stdout, "Calling shutdown!\n");
  1224. // shutdown (s, SD_SEND);
  1225. fprintf (stdout, "\nWaiting 10 seconds for receivers to finish receiving ...\n");
  1226. Sleep (10*1000); // 10 seconds for any receivers to finish receiving data!
  1227. fprintf (stdout, "************************ Final Stats ***************************\n");
  1228. GetSenderStats (s, count);
  1229. }
  1230. }
  1231. }
  1232. HeapFree (GetProcessHeap(), 0, TestBuffer);
  1233. closesocket(s);
  1234. WSACleanup();
  1235. return 0;
  1236. }