Leaked source code of windows server 2003
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.

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