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.

599 lines
15 KiB

  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <tchar.h>
  5. #include <winsock.h>
  6. #include <bits.h>
  7. #include <iphlpapi.h>
  8. #include <iptypes.h>
  9. #define WINSOCK_PORT 4000
  10. struct BITS_INTERNAL_STATS
  11. {
  12. UINT64 BytesTransferred;
  13. UINT64 BlocksTransferred;
  14. DWORD LastBlockSize;
  15. float LastServerSpeed;
  16. float AverageServerSpeed;
  17. float LastInterfaceSpeed;
  18. float AverageInterfaceSpeed;
  19. DWORD InterfaceId;
  20. };
  21. long g_PollInterval = 200;
  22. long g_SendSize = 1000;
  23. long g_ReceiveSize = 1000;
  24. long g_Time = 10 * 60;
  25. long g_StartTime;
  26. long g_WinsockBusyTime = 10;
  27. long g_WinsockFreeTime = 30;
  28. TCHAR * g_WinsockServer;
  29. SOCKET g_conn;
  30. long g_TotalSent = 0;
  31. long g_TotalReceived = 0;
  32. TCHAR * g_Url;
  33. BG_JOB_PRIORITY g_Priority = BG_JOB_PRIORITY_NORMAL;
  34. IBackgroundCopyJob * g_job;
  35. HANDLE g_StartEvent;
  36. volatile BOOL g_Halt;
  37. TCHAR * g_OutputFileName;
  38. FILE * g_OutputFile = NULL;
  39. MIB_IFROW g_InitialNetStats;
  40. DWORD g_NetworkAdapterIndex = 0;
  41. HANDLE g_BitsThread;
  42. HANDLE g_WinsockThread;
  43. void CollectWinsockStats();
  44. void CollectBitsStats();
  45. void CleanupWinsock();
  46. void EnumerateAdapters();
  47. //------------------------------------------------------
  48. void Usage()
  49. {
  50. printf(
  51. "parameters:\n"
  52. " -p <msec> to poll every <msec> milliseconds\n"
  53. " -server <name> to specify the Winsock server name or IP address\n"
  54. " -ss <size> to send <size> bytes per winsock request\n"
  55. " -sr <size> to receive <size> bytes per winsock request\n"
  56. " -wb <sec> winsock thread's busy time\n"
  57. " -wf <sec> winsock thread's free time\n"
  58. " -t <secs> number of seconds to run test\n"
  59. " -netindex <index> network adapter index to monitor\n"
  60. " -url <url> URL to transfer\n"
  61. );
  62. }
  63. long GetLongArg( int & i, int & argc, TCHAR * argv[], TCHAR * msg )
  64. {
  65. ++i;
  66. if (i < argc)
  67. {
  68. return _ttol( argv[i] );
  69. }
  70. else
  71. {
  72. _tprintf(msg);
  73. exit(1);
  74. }
  75. }
  76. TCHAR * GetStringArg( int & i, int & argc, TCHAR * argv[], TCHAR * msg )
  77. {
  78. ++i;
  79. if (i < argc)
  80. {
  81. return argv[i];
  82. }
  83. else
  84. {
  85. _tprintf(msg);
  86. exit(1);
  87. }
  88. }
  89. BG_JOB_PRIORITY GetPriority( int & i, int & argc, TCHAR * argv[], TCHAR * msg )
  90. {
  91. TCHAR * val = GetStringArg( i, argc, argv, msg );
  92. if (0 == _tcsicmp( val, _T("low")))
  93. {
  94. return BG_JOB_PRIORITY_LOW;
  95. }
  96. else if (0 == _tcsicmp( val, _T("normal")))
  97. {
  98. return BG_JOB_PRIORITY_NORMAL;
  99. }
  100. else if (0 == _tcsicmp( val, _T("high")))
  101. {
  102. return BG_JOB_PRIORITY_HIGH;
  103. }
  104. else if (0 == _tcsicmp( val, _T("foreground")))
  105. {
  106. return BG_JOB_PRIORITY_FOREGROUND;
  107. }
  108. else
  109. {
  110. _tprintf(msg);
  111. exit(1);
  112. }
  113. }
  114. void ParseCmdLine( int argc, wchar_t * argv[] )
  115. {
  116. int i = 1;
  117. while (i < argc)
  118. {
  119. if (0 == _tcsicmp( argv[i], _T("-p")))
  120. {
  121. g_PollInterval = GetLongArg( i, argc, argv, _T("-p must be followed by a number in milliseconds\n") );
  122. }
  123. else if (0 == _tcsicmp( argv[i], _T("-server")))
  124. {
  125. g_WinsockServer = GetStringArg( i, argc, argv, _T("-server must be followed by a server name \n"));
  126. }
  127. else if (0 == _tcsicmp( argv[i], _T("-ss")))
  128. {
  129. g_SendSize = GetLongArg( i, argc, argv, _T("-ss must be followed by a number of bytes\n"));
  130. }
  131. else if (0 == _tcsicmp( argv[i], _T("-sr")))
  132. {
  133. g_ReceiveSize = GetLongArg( i, argc, argv, _T("-sr must be followed by a number of bytes") );
  134. }
  135. else if (0 == _tcsicmp( argv[i], _T("-wb")))
  136. {
  137. g_WinsockBusyTime = GetLongArg( i, argc, argv, _T("-wb must be followed by a number of seconds\n"));
  138. }
  139. else if (0 == _tcsicmp( argv[i], _T("-wf")))
  140. {
  141. g_WinsockFreeTime = GetLongArg( i, argc, argv, _T("-wf must be followed by a number of seconds\n"));
  142. }
  143. else if (0 == _tcsicmp( argv[i], _T("-t")))
  144. {
  145. g_Time = GetLongArg( i, argc, argv, _T("-t must be followed by a time in seconds\n"));
  146. }
  147. else if (0 == _tcsicmp( argv[i], _T("-netindex")))
  148. {
  149. g_NetworkAdapterIndex = GetLongArg( i, argc, argv, _T("-netindex must be followed by a network adapter index\n"));
  150. }
  151. else if (0 == _tcsicmp( argv[i], _T("-f")))
  152. {
  153. g_OutputFileName = GetStringArg( i, argc, argv, _T("-f must be followed by a file name\n"));
  154. }
  155. else if (0 == _tcsicmp( argv[i], _T("-pri")))
  156. {
  157. g_Priority = GetPriority( i, argc, argv, _T("-pri must be followed by a priority\n"));
  158. }
  159. else if (0 == _tcsicmp( argv[i], _T("-url")))
  160. {
  161. g_Url = GetStringArg( i, argc, argv, _T("-url must be followed by an URL\n"));
  162. }
  163. else if (0 == _tcsicmp( argv[i], _T("-enum")))
  164. {
  165. EnumerateAdapters();
  166. }
  167. else if (0 == _tcsicmp( argv[i], _T("-?")))
  168. {
  169. Usage();
  170. exit(1);
  171. }
  172. else
  173. {
  174. printf("'%S' is not a recognized option", argv[i]);
  175. exit(1);
  176. }
  177. ++i;
  178. }
  179. }
  180. void PrepareCommon()
  181. {
  182. g_StartEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  183. if (!g_StartEvent)
  184. {
  185. printf("unable to create event\n");
  186. exit(1);
  187. }
  188. g_Halt = FALSE;
  189. if (g_OutputFileName)
  190. {
  191. g_OutputFile = _tfopen( g_OutputFileName, _T("w"));
  192. if (!g_OutputFile)
  193. {
  194. printf("unable to open output file\n");
  195. exit(1);
  196. }
  197. }
  198. else
  199. {
  200. g_OutputFile = stdout;
  201. }
  202. }
  203. void CleanupCommon()
  204. {
  205. if (g_OutputFileName)
  206. {
  207. fclose( g_OutputFile );
  208. }
  209. }
  210. DWORD WINAPI BitsThreadProc( PVOID arg );
  211. void PrepareBits()
  212. {
  213. IBackgroundCopyManager * mgr = NULL;
  214. HRESULT hr;
  215. hr = CoInitialize( NULL );
  216. if (FAILED(hr))
  217. {
  218. printf("unable to inti COM %x\n", hr);
  219. exit(1);
  220. }
  221. hr = CoCreateInstance(
  222. __uuidof(BackgroundCopyManager),
  223. NULL, // no aggregation
  224. CLSCTX_ALL,
  225. __uuidof(IBackgroundCopyManager),
  226. (LPVOID *) &mgr );
  227. if (FAILED(hr))
  228. {
  229. printf("unable to create BITS manager %x\n", hr);
  230. exit(1);
  231. }
  232. GUID guid;
  233. hr = mgr->CreateJob( L"perf test", BG_JOB_TYPE_DOWNLOAD, &guid, &g_job );
  234. if (FAILED(hr))
  235. {
  236. printf("unable to create BITS job %x\n", hr);
  237. exit(1);
  238. }
  239. hr = g_job->AddFile( g_Url, L"c:\\temp\\download.dat" );
  240. if (FAILED(hr))
  241. {
  242. printf("unable to create add file to job %x\n", hr);
  243. exit(1);
  244. }
  245. hr = g_job->SetPriority( g_Priority );
  246. if (FAILED(hr))
  247. {
  248. printf("unable to set job priority %x\n", hr);
  249. exit(1);
  250. }
  251. }
  252. void CleanupBits()
  253. {
  254. g_job->Cancel();
  255. }
  256. DWORD WINAPI WinsockThreadProc( PVOID arg );
  257. void PrepareWinsock()
  258. {
  259. char * AsciiServer = (char *) malloc( 1 +_tcslen( g_WinsockServer ));
  260. for (int i = _tcslen( g_WinsockServer ); i >= 0; --i)
  261. {
  262. AsciiServer[i] = char(g_WinsockServer[i]);
  263. }
  264. //
  265. // Get the IP address of the server.
  266. //
  267. ULONG addr = inet_addr( AsciiServer );
  268. if (addr == -1)
  269. {
  270. struct hostent *pHostEntry = gethostbyname( AsciiServer );
  271. if (pHostEntry == 0)
  272. {
  273. printf("unable to resolve the address of %s: %d\n", AsciiServer, WSAGetLastError() );
  274. exit(1);
  275. }
  276. addr = *(unsigned long *)pHostEntry->h_addr;
  277. }
  278. struct sockaddr_in dest;
  279. dest.sin_addr.s_addr = addr;
  280. dest.sin_family = AF_INET;
  281. dest.sin_port = WINSOCK_PORT;
  282. //
  283. // Connect to the server.
  284. //
  285. SOCKET s = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
  286. if (s == INVALID_SOCKET)
  287. {
  288. printf("unable to create socket, %d\n", WSAGetLastError());
  289. exit(1);
  290. }
  291. if (SOCKET_ERROR == connect( s, (sockaddr *)&dest, sizeof(dest)))
  292. {
  293. printf("unable to connect, %d\n", WSAGetLastError());
  294. exit(1);
  295. }
  296. printf("winsock connected to server\n");
  297. g_InitialNetStats.dwIndex = g_NetworkAdapterIndex;
  298. if (g_NetworkAdapterIndex)
  299. {
  300. DWORD err = GetIfEntry( &g_InitialNetStats );
  301. if (err)
  302. {
  303. printf("unable to collect stats from network %d: %d\n", g_NetworkAdapterIndex, err);
  304. exit(1);
  305. }
  306. }
  307. DWORD id;
  308. HANDLE h = CreateThread( NULL, 0, WinsockThreadProc, PVOID(s), 0, &id);
  309. if (!h)
  310. {
  311. printf("unable to create socket thread %d\n", GetLastError());
  312. exit(1);
  313. }
  314. }
  315. DWORD WINAPI WinsockThreadProc( PVOID arg )
  316. {
  317. SOCKET s = SOCKET(arg);
  318. char * buf = (char *) malloc( max( g_SendSize, g_ReceiveSize ));
  319. printf("2: winsock thread ready to start...\n");
  320. WaitForSingleObject( g_StartEvent, INFINITE );
  321. //
  322. // Send and receive data forever, with duty cycle governed by the -wb and -wf parameters.
  323. //
  324. DWORD Sizes[2];
  325. Sizes[0] = g_SendSize;
  326. Sizes[1] = g_ReceiveSize;
  327. do
  328. {
  329. printf("sending...\n");
  330. long StartTime = GetTickCount();
  331. while (long(GetTickCount()) - StartTime < (g_WinsockBusyTime * 1000) && g_Halt == FALSE)
  332. {
  333. if (SOCKET_ERROR == send(s, (char *) Sizes, sizeof(Sizes), 0))
  334. {
  335. printf("unable to send, %d\n", WSAGetLastError());
  336. }
  337. if (SOCKET_ERROR == send(s, buf, g_SendSize, 0))
  338. {
  339. printf("unable to send, %d\n", WSAGetLastError());
  340. }
  341. g_TotalSent += g_SendSize + sizeof(Sizes);
  342. long Received = 0;
  343. do
  344. {
  345. int bytes = recv(s, buf, g_ReceiveSize - Received, 0);
  346. if (bytes == 0)
  347. {
  348. printf("server closed the socket connection\n");
  349. break;
  350. }
  351. Received += bytes;
  352. g_TotalReceived += bytes;
  353. }
  354. while ( Received < g_ReceiveSize );
  355. }
  356. printf("2: waiting...\n");
  357. Sleep( g_WinsockFreeTime * 1000 );
  358. }
  359. while ( !g_Halt );
  360. printf("2: winsock thread exiting\n");
  361. return 0;
  362. }
  363. void CleanupWinsock()
  364. {
  365. }
  366. char * JobStateStringOf( BG_JOB_STATE state )
  367. {
  368. switch (state)
  369. {
  370. case BG_JOB_STATE_QUEUED : return "queued";
  371. case BG_JOB_STATE_CONNECTING : return "connecting";
  372. case BG_JOB_STATE_TRANSFERRING : return "transferring";
  373. case BG_JOB_STATE_TRANSFERRED : return "FINISHED";
  374. case BG_JOB_STATE_TRANSIENT_ERROR : return "trans-error";
  375. case BG_JOB_STATE_ERROR : return "ERROR";
  376. case BG_JOB_STATE_SUSPENDED : return "SUSPENDED";
  377. case BG_JOB_STATE_ACKNOWLEDGED : return "ACKNOWLEDGED";
  378. case BG_JOB_STATE_CANCELLED : return "CANCELLED";
  379. default: return "(unknown state)";
  380. }
  381. }
  382. void CollectStats()
  383. {
  384. HRESULT hr;
  385. BG_JOB_STATE state;
  386. BG_JOB_PROGRESS progress;
  387. hr = g_job->GetState( &state );
  388. if (hr)
  389. {
  390. printf("unable to get job state %x\n", hr);
  391. return;
  392. }
  393. hr = g_job->GetProgress( &progress );
  394. if (hr)
  395. {
  396. printf("unable to get job progress %x\n", hr);
  397. return;
  398. }
  399. //
  400. // Get net card stats.
  401. //
  402. MIB_IFROW net = {0};
  403. long InOctets = -1, OutOctets = -1;
  404. if (g_NetworkAdapterIndex != 0)
  405. {
  406. net.dwIndex = g_NetworkAdapterIndex;
  407. if (!GetIfEntry( &net ))
  408. {
  409. InOctets = net.dwInOctets - g_InitialNetStats.dwInOctets;
  410. OutOctets = net.dwOutOctets - g_InitialNetStats.dwOutOctets;
  411. }
  412. }
  413. printf("%d, BITS, %s, %I64u, sockets, %d , %d",
  414. GetTickCount() - g_StartTime,
  415. JobStateStringOf( state ), progress.BytesTransferred,
  416. g_TotalSent, g_TotalReceived );
  417. if (g_NetworkAdapterIndex != 0)
  418. {
  419. printf(", net, %d , %d , %d", InOctets, OutOctets, InOctets+OutOctets);
  420. }
  421. putchar('\n');
  422. }
  423. void RunTest()
  424. {
  425. g_job->Resume();
  426. SetEvent( g_StartEvent );
  427. g_StartTime = GetTickCount();
  428. do
  429. {
  430. CollectStats();
  431. Sleep( g_PollInterval );
  432. }
  433. while ( long(GetTickCount()) - g_StartTime < (g_Time * 1000 ));
  434. g_Halt = TRUE;
  435. }
  436. void __cdecl wmain (int argc, wchar_t *argv[])
  437. {
  438. DWORD err;
  439. WSADATA WsaData = {0};
  440. if ((err = WSAStartup(0x0101, &WsaData)) != NO_ERROR)
  441. {
  442. printf("unable to init winsock: %d\n", err);
  443. }
  444. ParseCmdLine( argc, argv );
  445. PrepareCommon();
  446. PrepareWinsock();
  447. PrepareBits();
  448. Sleep(1000);
  449. RunTest();
  450. CleanupBits();
  451. CleanupWinsock();
  452. CleanupCommon();
  453. }
  454. char * AdapterTypeStringOf( DWORD Type )
  455. {
  456. switch (Type)
  457. {
  458. case MIB_IF_TYPE_ETHERNET: return "Ethernet";
  459. case MIB_IF_TYPE_PPP: return "PPP dial-up";
  460. case MIB_IF_TYPE_SLIP: return "SLIP dial-up";
  461. case MIB_IF_TYPE_TOKENRING : return "Token-ring";
  462. default: return "(unknown type)";
  463. }
  464. }
  465. void EnumerateAdapters()
  466. {
  467. PIP_ADAPTER_INFO buf = 0;
  468. DWORD s;
  469. DWORD size = 0;
  470. s = GetAdaptersInfo( NULL, &size );
  471. if (s != ERROR_BUFFER_OVERFLOW)
  472. {
  473. printf("unable to enum adapters: %d\n", s);
  474. exit(1);
  475. }
  476. buf = (PIP_ADAPTER_INFO) malloc( size );
  477. if (!buf)
  478. {
  479. printf("out of memory\n");
  480. exit(1);
  481. }
  482. s = GetAdaptersInfo( buf, &size );
  483. if (s)
  484. {
  485. printf("unable to enum adapters: %d\n", s);
  486. exit(1);
  487. }
  488. while (buf)
  489. {
  490. printf("%d: %s %s '%s' ",
  491. buf->Index,
  492. AdapterTypeStringOf( buf->Type),
  493. buf->IpAddressList.IpAddress.String,
  494. buf->Description);
  495. buf = buf->Next;
  496. }
  497. exit(1);
  498. }