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.

1108 lines
34 KiB

  1. #include "inetdown.h"
  2. //----------------------------------------------------------------------------
  3. // Globals
  4. //----------------------------------------------------------------------------
  5. //#define TEST 1
  6. HINTERNET hInternet;
  7. HANDLE hDownloadThread;
  8. HANDLE hMaxDownloadSem;
  9. DWORD dwThreadID;
  10. LPSTR ppAccept[] = {"*/*",NULL};
  11. DWORD dwBegin_Time = 0;
  12. DWORD dwEnd_Time;
  13. DWORD dwTot_Time;
  14. DWORD dwNum_Opens = 1;
  15. DWORD dwBuf_Size = BUF_SIZE;
  16. DWORD dwBytes_Read = 0;
  17. DWORD dwMax_Simul_Downloads = URLMAX;
  18. DWORD dwInternet_Open_Flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_EXISTING_CONNECT;
  19. DWORD dwInternet_Connect_Flags = 0;
  20. BOOL bDelim = FALSE;
  21. BOOL g_bSingleThreaded = FALSE;
  22. DWORD g_dwMainThreadID = 0;
  23. DWORD g_iDownloads = 0;
  24. char *pFilename = NULL;
  25. char *pInFile = NULL;
  26. char *g_pRunStr = NULL;
  27. char *g_pTestName = NULL;
  28. char g_CmdLine[1024];
  29. BOOL g_bTimeFirstFile = TRUE;
  30. url_info_cache g_pUrlInfoCache;
  31. HANDLE g_hHeap;
  32. #ifdef DBG
  33. #define dprintf(args) _dprintf args
  34. INT _dprintf(TCHAR *fmt, ... )
  35. {
  36. INT ret;
  37. va_list marker;
  38. TCHAR szBuffer[256];
  39. if(TRUE) {
  40. va_start(marker, fmt);
  41. ret = vsprintf(szBuffer, fmt, marker);
  42. OutputDebugString(szBuffer);
  43. printf(szBuffer);
  44. }
  45. return ret;
  46. }
  47. #else
  48. #define dprintf(args)
  49. #endif
  50. //----------------------------------------------------------------------------
  51. //Procedure: generateInfo
  52. //Purpose: init globals
  53. //Arguments: none
  54. //RetVal: void
  55. //----------------------------------------------------------------------------
  56. void generateInfo()
  57. {
  58. g_iDownloads = 0;
  59. g_dwMainThreadID = GetCurrentThreadId();
  60. return;
  61. }
  62. //----------------------------------------------------------------------------
  63. // Procedure: getCachedUrlInfo
  64. // Purpose: Finds existing url_info struct from the cache if it exists
  65. // Arguments: szUrl
  66. // RetVal: url_info* or NULL based on whether it's there
  67. //----------------------------------------------------------------------------
  68. url_info *getCachedUrlInfo(TCHAR *szUrl)
  69. {
  70. url_info *temp = g_pUrlInfoCache.pHead;
  71. while(temp && (0 != lstrcmp(temp->pURLName,szUrl)))
  72. {
  73. temp = temp->pNext;
  74. }
  75. return temp;
  76. }
  77. //----------------------------------------------------------------------------
  78. // Procedure: getUrlInfo
  79. // Purpose: Sets pUrlInfo member of the outQ struct
  80. // Arguments: outQ, szUrl
  81. // RetVal: TRUE or FALSE based on error
  82. //----------------------------------------------------------------------------
  83. BOOL getUrlInfo(outQ *pOutQ, TCHAR *szUrl)
  84. {
  85. URL_COMPONENTS urlc;
  86. BOOL fRet = FALSE;
  87. if(pOutQ->pURLInfo = getCachedUrlInfo(szUrl))
  88. {
  89. //Use existing url_info from cache
  90. return TRUE;
  91. }
  92. pOutQ->pURLInfo = HeapAlloc(g_hHeap,0,sizeof(url_info));
  93. if(!pOutQ->pURLInfo)
  94. return FALSE;
  95. pOutQ->pURLInfo->pURLName = HeapAlloc(g_hHeap,0,(1+lstrlen(szUrl))*sizeof(TCHAR));
  96. if(!pOutQ->pURLInfo->pURLName)
  97. {
  98. HeapFree(g_hHeap,0,pOutQ->pURLInfo);
  99. return FALSE;
  100. }
  101. lstrcpy(pOutQ->pURLInfo->pURLName,szUrl);
  102. //Add to head of url_info cache
  103. pOutQ->pURLInfo->pNext = g_pUrlInfoCache.pHead;
  104. g_pUrlInfoCache.pHead = pOutQ->pURLInfo;
  105. urlc.dwStructSize = sizeof(URL_COMPONENTS);
  106. urlc.lpszScheme=pOutQ->pURLInfo->szRScheme;
  107. urlc.dwSchemeLength= MAX_SCHEME_LENGTH;
  108. urlc.nScheme = INTERNET_SCHEME_UNKNOWN;
  109. urlc.lpszHostName=pOutQ->pURLInfo->szRHost;
  110. urlc.dwHostNameLength=INTERNET_MAX_HOST_NAME_LENGTH;
  111. urlc.lpszUserName=NULL;
  112. urlc.dwUserNameLength=0;
  113. urlc.lpszPassword=NULL;
  114. urlc.dwPasswordLength=0;
  115. urlc.lpszExtraInfo = NULL;
  116. urlc.dwExtraInfoLength = 0;
  117. urlc.lpszUrlPath=pOutQ->pURLInfo->szRPath;
  118. urlc.dwUrlPathLength=INTERNET_MAX_PATH_LENGTH;
  119. urlc.nPort = 0;
  120. if (InternetCrackUrl(pOutQ->pURLInfo->pURLName,0,0,&urlc))
  121. {
  122. fRet = TRUE;
  123. pOutQ->pURLInfo->nScheme = urlc.nScheme;
  124. pOutQ->pURLInfo->nPort = urlc.nPort;
  125. // For now, we will only support HTTP
  126. if((pOutQ->pURLInfo->nScheme != INTERNET_SERVICE_HTTP) && (pOutQ->pURLInfo->nScheme != INTERNET_SCHEME_HTTPS))
  127. fRet = FALSE;
  128. }
  129. return fRet;
  130. }
  131. //----------------------------------------------------------------------------
  132. // Procedure: fillOutQ
  133. // Purpose: fills the OutQ will URLs to be downloaded
  134. // Arguments: OutQ to be filled
  135. // RetVal: the start of the Queue or NULL on error
  136. //----------------------------------------------------------------------------
  137. outQ* fillOutQ(outQ *pOutQ, TCHAR *URLName)
  138. {
  139. outQ *pStartOutQ;
  140. pStartOutQ = pOutQ;
  141. if(pOutQ) {
  142. //go to first free outQ as opposed to adding to front (not concerned w/time)
  143. while(pOutQ->pNext != NULL)
  144. {
  145. pOutQ = pOutQ->pNext;
  146. }
  147. pOutQ->pNext = HeapAlloc(g_hHeap,0, sizeof(outQ));
  148. if (!pOutQ->pNext)
  149. {
  150. dprintf(("HeapAlloc Failed!\n"));
  151. return NULL;
  152. }
  153. pOutQ = pOutQ->pNext;
  154. pOutQ->pNext = NULL;
  155. }
  156. else
  157. {
  158. pStartOutQ = pOutQ = HeapAlloc(g_hHeap,0, sizeof(outQ));
  159. if (!pOutQ)
  160. {
  161. dprintf(("HeapAlloc Failed!\n"));
  162. return NULL;
  163. }
  164. pOutQ->pNext = NULL;
  165. }
  166. //keep track of the number of downloads
  167. g_iDownloads++;
  168. if(!getUrlInfo(pOutQ,URLName))
  169. {
  170. dprintf(("getUrlInfo failed!\n"));
  171. return NULL;
  172. }
  173. return pStartOutQ;
  174. }
  175. //----------------------------------------------------------------------------
  176. // Procedure: freeOutQMem
  177. // Purpose: frees the memory held in the given outQ
  178. // Arguments: outQ to be freed
  179. // RetVal: none
  180. //----------------------------------------------------------------------------
  181. void freeOutQMem(outQ *pOutQ)
  182. {
  183. outQ *pLastOutQ;
  184. while(pOutQ)
  185. {
  186. pLastOutQ = pOutQ;
  187. pOutQ = pOutQ->pNext;
  188. HeapFree(g_hHeap,0,pLastOutQ);
  189. }
  190. return;
  191. }
  192. //----------------------------------------------------------------------------
  193. // Procedure: callOpenRequest
  194. // Purpose: calls HttpOpenRequest
  195. // Arguments: outQ
  196. // RetVal: none
  197. //----------------------------------------------------------------------------
  198. void callOpenRequest(outQ *pOutQ)
  199. {
  200. INT iError = 0;
  201. DWORD dwAdded_Connect_Flags = 0;
  202. if(lstrcmpi(pOutQ->pURLInfo->szRScheme, "https") == 0)
  203. {
  204. dwAdded_Connect_Flags = INTERNET_FLAG_SECURE;
  205. }
  206. if(pOutQ->hInetReq = HttpOpenRequest(
  207. pOutQ->hInetCon, //connection
  208. NULL, //verb
  209. pOutQ->pURLInfo->szRPath, //object
  210. NULL, //version
  211. NULL, //referrer
  212. ppAccept, //accept headers
  213. dwInternet_Open_Flags | dwAdded_Connect_Flags, //flags
  214. (DWORD) pOutQ)) //context
  215. {
  216. //it was synchronous (usual)
  217. dprintf(("callOpenRequest: Sync TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, LDG_STARTING));
  218. pOutQ->iStatus = LDG_STARTING;
  219. callSendRequest(pOutQ);
  220. return;
  221. }
  222. else
  223. {
  224. if((iError = GetLastError()) != ERROR_IO_PENDING){
  225. dprintf((" Error on HttpOpenRequest[%d]\n", iError));
  226. g_iDownloads--;
  227. if(g_iDownloads == 0)
  228. {
  229. if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_DONE, (WPARAM) pOutQ, 0))
  230. {
  231. iError = GetLastError();
  232. dprintf(("error on PostThreadMessage[%d]\n", iError));
  233. }
  234. }
  235. return;
  236. }
  237. dprintf(("callOpenRequest: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, REQUEST_OPENED));
  238. pOutQ->iStatus = REQUEST_OPENED;
  239. return;
  240. }
  241. }
  242. //----------------------------------------------------------------------------
  243. // Procedure: callSendRequest
  244. // Purpose: calls HttpSendRequest
  245. // Arguments: outQ
  246. // RetVal: none
  247. //----------------------------------------------------------------------------
  248. void callSendRequest(outQ *pOutQ)
  249. {
  250. INT iError = 0;
  251. if(HttpSendRequest(pOutQ->hInetReq, NULL, 0, NULL, 0))
  252. {
  253. //it was synchronous
  254. dprintf(("callSendRequest: Sync TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, LDG_START));
  255. pOutQ->iStatus = LDG_START;
  256. callReadFile(pOutQ);
  257. return;
  258. }
  259. else
  260. {
  261. if((iError = GetLastError()) != ERROR_IO_PENDING)
  262. {
  263. dprintf((" Error on HttpSendRequest[%d]\n", iError));
  264. g_iDownloads--;
  265. if(g_iDownloads == 0)
  266. {
  267. if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_DONE, (WPARAM) pOutQ, 0))
  268. {
  269. iError = GetLastError();
  270. dprintf(("error on PostThreadMessage[%d]\n", iError));
  271. }
  272. }
  273. return;
  274. }
  275. //it was async (usual)
  276. dprintf(("callSendRequest: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, LDG_START));
  277. pOutQ->iStatus = LDG_START;
  278. return;
  279. }
  280. }
  281. //----------------------------------------------------------------------------
  282. // Procedure: callReadFile
  283. // Purpose: calls InternetReadFile
  284. // Arguments: outQ
  285. // RetVal: none
  286. //----------------------------------------------------------------------------
  287. void callReadFile(outQ *pOutQ)
  288. {
  289. #ifndef TEST
  290. INT iError;
  291. INTERNET_BUFFERS IB;
  292. BOOL bRC;
  293. static TCHAR buf[BUF_SIZE];
  294. switch (pOutQ->iStatus)
  295. {
  296. case LDG_START:
  297. dprintf(("callReadFile: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, LDG_LDG));
  298. pOutQ->iStatus = LDG_LDG;
  299. break;
  300. case LDG_RDY:
  301. if(pOutQ->lNumRead == 0)
  302. {
  303. // should wait for 0 bytes read so data will cache.
  304. dprintf(("callReadFile: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, LDG_DONE));
  305. pOutQ->iStatus = LDG_DONE;
  306. dprintf(("%s downloaded\n", pOutQ->pURLInfo->pURLName));
  307. g_iDownloads--;
  308. //post msg if last download for exit
  309. if(g_iDownloads == 0)
  310. {
  311. dwEnd_Time = GetTickCount();
  312. if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_DONE, (WPARAM) pOutQ, 0))
  313. {
  314. iError = GetLastError();
  315. dprintf(("error on PostThreadMessage[%d]\n", iError));
  316. return;
  317. }
  318. }
  319. InternetCloseHandle(pOutQ->hInetReq);
  320. InternetCloseHandle(pOutQ->hInetCon);
  321. if(!ReleaseSemaphore(hMaxDownloadSem,1,NULL))
  322. {
  323. dprintf((" ReleaseSemaphore failed!\n"));
  324. return;
  325. }
  326. return;
  327. }
  328. dprintf((" '%s':Rd = %d\n", pOutQ->pURLInfo->pURLName, pOutQ->lNumRead));
  329. dwBytes_Read += pOutQ->lNumRead;
  330. break;
  331. }
  332. //Should insert timing test here
  333. if(dwBegin_Time == 0)
  334. {
  335. if(!g_bTimeFirstFile)
  336. g_bTimeFirstFile = TRUE;
  337. else
  338. dwBegin_Time = GetTickCount();
  339. }
  340. IB.dwStructSize = sizeof (INTERNET_BUFFERS);
  341. IB.Next = 0;
  342. IB.lpcszHeader = 0;
  343. IB.dwHeadersLength = 0;
  344. IB.dwHeadersTotal = 0;
  345. IB.lpvBuffer = buf;
  346. IB.dwBufferLength = dwBuf_Size;
  347. IB.dwBufferTotal = 0;
  348. IB.dwOffsetLow = 0;
  349. IB.dwOffsetHigh = 0;
  350. bRC = InternetReadFileEx(pOutQ->hInetReq, &IB, IRF_NO_WAIT, 0);
  351. pOutQ->lNumRead = IB.dwBufferLength;
  352. if(bRC)
  353. {
  354. //it was synchronous
  355. dprintf(("callReadFile: Sync TID=%x pOutQ=%x Read=%d iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->lNumRead, pOutQ->iStatus, LDG_RDY));
  356. pOutQ->iStatus = LDG_RDY;
  357. callReadFile(pOutQ);
  358. return;
  359. }
  360. else
  361. {
  362. dprintf(("callReadFile: TID=%x pOutQ=%x Read=%d iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->lNumRead, pOutQ->iStatus, LDG_RDY));
  363. if(GetLastError() != ERROR_IO_PENDING)
  364. {
  365. g_iDownloads--;
  366. if(g_iDownloads == 0)
  367. {
  368. if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_DONE, (WPARAM) pOutQ, 0))
  369. {
  370. iError = GetLastError();
  371. dprintf(("error on PostThreadMessage[%d]\n", iError));
  372. return;
  373. }
  374. }
  375. dprintf(("Error on InternetRead"));
  376. return;
  377. }
  378. if((pOutQ->lNumRead == 0) && (pOutQ->iStatus == LDG_LDG)) //vmr
  379. pOutQ->iStatus = LDG_RDY;
  380. }
  381. #else // ifndef TEST =======================================================================
  382. INT iError;
  383. INTERNET_BUFFERS IB;
  384. BOOL bRC;
  385. BYTE Buf[8192];
  386. pOutQ->pBuf = Buf;
  387. //Should insert timing test here
  388. if(dwBegin_Time == 0)
  389. {
  390. if(!g_bTimeFirstFile)
  391. g_bTimeFirstFile = TRUE;
  392. else
  393. dwBegin_Time = GetTickCount();
  394. }
  395. IB.dwStructSize = sizeof (INTERNET_BUFFERS);
  396. IB.Next = 0;
  397. IB.lpcszHeader = 0;
  398. IB.dwHeadersLength = 0;
  399. IB.dwHeadersTotal = 0;
  400. IB.lpvBuffer = &Buf;
  401. IB.dwBufferLength = dwBuf_Size;
  402. IB.dwBufferTotal = 0;
  403. IB.dwOffsetLow = 0;
  404. IB.dwOffsetHigh = 0;
  405. bRC = InternetReadFileEx(pOutQ->hInetReq, &IB, IRF_NO_WAIT, 0);
  406. pOutQ->lNumRead = IB.dwBufferLength;
  407. if(bRC)
  408. {
  409. //it was synchronous
  410. dprintf(("callReadFile: Sync TID=%x pOutQ=%x Read=%d iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->lNumRead, pOutQ->iStatus, LDG_RDY));
  411. pOutQ->iStatus = LDG_RDY;
  412. if(pOutQ->lNumRead == 0)
  413. {
  414. pOutQ->iStatus = LDG_DONE;
  415. dprintf(("%s downloaded\n", pOutQ->pURLInfo->pURLName));
  416. InternetCloseHandle(pOutQ->hInetReq);
  417. InternetCloseHandle(pOutQ->hInetCon);
  418. //post msg if last download for exit
  419. g_iDownloads--;
  420. if(g_iDownloads == 0)
  421. {
  422. dwEnd_Time = GetTickCount();
  423. if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_DONE, (WPARAM) pOutQ, 0))
  424. {
  425. iError = GetLastError();
  426. dprintf(("error on PostThreadMessage[%d]\n", iError));
  427. return;
  428. }
  429. }
  430. if(!ReleaseSemaphore(hMaxDownloadSem,1,NULL))
  431. {
  432. dprintf((" ReleaseSemaphore failed!\n"));
  433. return;
  434. }
  435. }
  436. else
  437. {
  438. dprintf((" '%s':Rd = %d\n", pOutQ->pURLInfo->pURLName, pOutQ->lNumRead));
  439. dwBytes_Read += pOutQ->lNumRead;
  440. callReadFile(pOutQ);
  441. }
  442. }
  443. else
  444. {
  445. dprintf(("callReadFile: TID=%x pOutQ=%x Read=%d iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->lNumRead, pOutQ->iStatus, LDG_RDY));
  446. if(GetLastError() != ERROR_IO_PENDING)
  447. {
  448. g_iDownloads--;
  449. if(g_iDownloads == 0)
  450. {
  451. if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_DONE, (WPARAM) pOutQ, 0))
  452. {
  453. iError = GetLastError();
  454. dprintf(("error on PostThreadMessage[%d]\n", iError));
  455. return;
  456. }
  457. }
  458. dprintf(("Error on InternetRead"));
  459. return;
  460. }
  461. if((pOutQ->lNumRead == 0) && (pOutQ->iStatus == LDG_LDG)) //vmr
  462. pOutQ->iStatus = LDG_RDY;
  463. }
  464. return;
  465. #endif // ifndef TEST
  466. }
  467. //----------------------------------------------------------------------------
  468. // Procedure: inetCallBackFn
  469. // Purpose: callback function used for all the async wininet calls
  470. // simply makes calls to do the actual processing of this callback.
  471. // Arguments: hInet HINTERNET for the callback
  472. // dwContext the outQ
  473. // dwInternewStatus Status of the callback
  474. // lpStatusInfo Holds connection handle
  475. // dwStatusInfoLen Not used
  476. //----------------------------------------------------------------------------
  477. VOID CALLBACK inetCallBackFn(HINTERNET hInet,
  478. DWORD dwContext,
  479. DWORD dwInternetStatus,
  480. LPVOID lpStatusInfo,
  481. DWORD dwStatusInfoLen) {
  482. INT iError;
  483. outQ *pOutQ = (outQ *)(dwContext);
  484. //First check outQ's state
  485. //Should post messages to other thread to do calls
  486. switch(pOutQ->iStatus)
  487. {
  488. case CONNECTED:
  489. //should not be called in normal async behavior
  490. if(!pOutQ->hInetCon)
  491. {
  492. pOutQ->hInetCon = *((HINTERNET *)(lpStatusInfo));
  493. }
  494. dprintf(("inetCallBackFn: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, REQUEST_OPENING));
  495. pOutQ->iStatus = REQUEST_OPENING;
  496. if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_OPEN_REQUEST, (WPARAM) pOutQ, 0))
  497. {
  498. iError = GetLastError();
  499. dprintf(("error on PostThreadMessage[%d]\n", iError));
  500. return;
  501. }
  502. break;
  503. case REQUEST_OPENED:
  504. //should not be called in normal async behavior
  505. if(!pOutQ->hInetReq)
  506. {
  507. pOutQ->hInetReq = *((HINTERNET *)(lpStatusInfo));
  508. }
  509. dprintf(("inetCallBackFn: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, LDG_STARTING));
  510. pOutQ->iStatus = LDG_STARTING;
  511. if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_SEND_REQUEST, (WPARAM) pOutQ, 0))
  512. {
  513. iError = GetLastError();
  514. dprintf(("error on PostThreadMessage[%d]\n", iError));
  515. return;
  516. }
  517. break;
  518. case LDG_LDG:
  519. /// if(dwInternetStatus == INTERNET_STATUS_REQUEST_COMPLETE)
  520. if(dwInternetStatus == INTERNET_STATUS_REQUEST_COMPLETE &&
  521. pOutQ->lNumRead != 0)
  522. {
  523. dprintf(("inetCallBackFn: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, LDG_RDY));
  524. pOutQ->iStatus = LDG_RDY;
  525. }
  526. else
  527. return;
  528. case LDG_START:
  529. case LDG_RDY:
  530. /// if(dwInternetStatus == INTERNET_STATUS_REQUEST_COMPLETE ||
  531. /// dwInternetStatus == INTERNET_STATUS_REQUEST_SENT) // vmr
  532. if(dwInternetStatus == INTERNET_STATUS_REQUEST_COMPLETE)
  533. {
  534. if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_READ_FILE, (WPARAM) pOutQ, 0))
  535. {
  536. iError = GetLastError();
  537. dprintf(("error on PostThreadMessage[%d]\n", iError));
  538. return;
  539. }
  540. }
  541. break;
  542. case CONNECTING:
  543. case REQUEST_OPENING:
  544. case LDG_STARTING:
  545. case LDG_DONE:
  546. return;
  547. default:
  548. dprintf(("Bad iStatus=%d\n", pOutQ->iStatus));
  549. return;
  550. }
  551. return;
  552. }
  553. //----------------------------------------------------------------------------
  554. //----------------------------------------------------------------------------
  555. BOOL DoInit(void)
  556. {
  557. hMaxDownloadSem = CreateSemaphore(NULL,dwMax_Simul_Downloads,dwMax_Simul_Downloads, NULL);
  558. if(!hMaxDownloadSem) {
  559. dprintf((" *** CreateSem failed!\n"));
  560. return FALSE;
  561. }
  562. hInternet = InternetOpen(
  563. NULL, //referrer
  564. PRE_CONFIG_INTERNET_ACCESS, //access type
  565. NULL, //proxy
  566. 0, //proxy bypass
  567. #ifndef TEST
  568. INTERNET_FLAG_ASYNC); //flags
  569. #else
  570. 0);
  571. #endif
  572. if(!hInternet)
  573. {
  574. dprintf((" *** InternetOpen failed!\n"));
  575. return FALSE;
  576. }
  577. #ifndef TEST
  578. if(InternetSetStatusCallback(hInternet, inetCallBackFn) < 0)
  579. {
  580. dprintf((" setCallback Failed!\n"));
  581. return FALSE;
  582. }
  583. #endif
  584. return TRUE;
  585. }
  586. //----------------------------------------------------------------------------
  587. //----------------------------------------------------------------------------
  588. BOOL DoConnect(outQ *pOutQ)
  589. {
  590. INT iError;
  591. DWORD dwAdded_Connect_Flags = 0;
  592. if(lstrcmpi(pOutQ->pURLInfo->szRScheme, "https") == 0)
  593. {
  594. dwAdded_Connect_Flags = INTERNET_FLAG_SECURE;
  595. }
  596. pOutQ->hInetCon = InternetConnect(hInternet, //handle from internetOpen
  597. pOutQ->pURLInfo->szRHost, //name of the server
  598. pOutQ->pURLInfo->nPort, //name of the port
  599. NULL, //username
  600. NULL, //password
  601. pOutQ->pURLInfo->nScheme, //service
  602. dwInternet_Connect_Flags | dwAdded_Connect_Flags, //service specific flags
  603. (DWORD) (pOutQ)); //context
  604. if(pOutQ->hInetCon)
  605. {
  606. //it was synchronous (usually)
  607. dprintf(("DoConnect: Sync connect TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, REQUEST_OPENING));
  608. pOutQ->iStatus = REQUEST_OPENING;
  609. if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_OPEN_REQUEST, (WPARAM) pOutQ, 0))
  610. {
  611. iError = GetLastError();
  612. dprintf(("error on PostThreadMessage[%d]\n", iError));
  613. return FALSE;
  614. }
  615. }
  616. else
  617. {
  618. if(GetLastError() != ERROR_IO_PENDING)
  619. {
  620. dprintf((" InternetConnect error\n"));
  621. return FALSE;
  622. }
  623. dprintf(("DoConnect: Async connect TID=%x pOutQ=%x iStatus=%ld ->%ld->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, CONNECTED));
  624. pOutQ->iStatus = CONNECTED;
  625. }
  626. return TRUE;
  627. }
  628. //----------------------------------------------------------------------------
  629. // Procedure: DownloadThread
  630. // Purpose: Opens internet connection and downloads URL. Saves
  631. // URL to pOutQ (one chunk at a time).
  632. // Arguments: outQ
  633. // Return Val: TRUE or FALSE based on error
  634. //----------------------------------------------------------------------------
  635. DWORD DownloadThread(LPDWORD lpdwParam)
  636. {
  637. outQ *pOutQ = (outQ *) lpdwParam;
  638. BOOL bRC = TRUE;
  639. if(bRC = DoInit()) // create throttle semaphore, do InternetOpen & InternetSetStatusCallback
  640. {
  641. while(pOutQ)
  642. {
  643. //Only allow MAXURL downloads at one time
  644. if(WaitForSingleObject(hMaxDownloadSem, TIMEOUT) == WAIT_TIMEOUT)
  645. {
  646. dprintf(("timeout on Sem\n"));
  647. printf("Error: timeout on throttle semaphore\n");
  648. }
  649. pOutQ->iStatus = CONNECTING;
  650. pOutQ->iPriority = LOW;
  651. dprintf(("DownloadThread: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, CONNECTING));
  652. if(!(bRC = DoConnect(pOutQ)))
  653. break;
  654. pOutQ = pOutQ->pNext;
  655. }
  656. }
  657. return((DWORD)bRC);
  658. }
  659. //==================================================================
  660. void Display_Usage(char **argv)
  661. {
  662. printf("\nUsage: %s -fURLname [options]\n", argv[0]);
  663. printf("\n -iInputFileName [options]\n");
  664. printf("\n\t options:\n");
  665. printf("\t\t -c - cache reads (flags ^= INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE)\n");
  666. printf("\t\t -c1 - force reload and cache reads (flags ^= INTERNET_FLAG_DONT_CACHE)\n");
  667. printf("\t\t (flags default = INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_EXISTING_CONNECT\n");
  668. printf("\t\t -k - keep alive (flags |= INTERNET_FLAG_KEEP_CONNECTION)\n");
  669. printf("\t\t -l - read buffer length\n");
  670. printf("\t\t -m - maximum number of simultaneous downloads\n");
  671. printf("\t\t -n## - number of times to download\n");
  672. printf("\t\t -o - set INTERNET_FLAG_NO_COOKIES\n");
  673. printf("\t\t -x - don't time first download\n");
  674. printf("\t\t -s - run test in single threaded mode\n");
  675. printf("\t\t -z - comma delimited format\n");
  676. printf("\t\t -tStr - test name string (used on results output with -z)\n");
  677. printf("\t\t -rStr - run# string (used on results output with -z)\n");
  678. }
  679. //==================================================================
  680. BOOL Process_Command_Line(int argcIn, char **argvIn)
  681. {
  682. BOOL bRC = TRUE;
  683. int argc = argcIn;
  684. char **argv = argvIn;
  685. DWORD dwLen = 0;
  686. *g_CmdLine = '\0';
  687. argv++; argc--;
  688. while( argc > 0 && argv[0][0] == '-' )
  689. {
  690. switch (argv[0][1])
  691. {
  692. case 'c':
  693. if(argv[0][2] == '1')
  694. dwInternet_Open_Flags ^= INTERNET_FLAG_DONT_CACHE; // force reload & cache file
  695. else
  696. dwInternet_Open_Flags ^= INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE; // cache file
  697. break;
  698. case 'k':
  699. dwInternet_Open_Flags |= INTERNET_FLAG_KEEP_CONNECTION;
  700. break;
  701. case 'f':
  702. pFilename = &argv[0][2];
  703. break;
  704. case 'i':
  705. pInFile = &argv[0][2];
  706. break;
  707. case 'n':
  708. dwNum_Opens = atoi(&argv[0][2]);
  709. break;
  710. case 'l':
  711. dwBuf_Size = atoi(&argv[0][2]);
  712. break;
  713. case 'm':
  714. dwMax_Simul_Downloads = atoi(&argv[0][2]);
  715. break;
  716. case 'o':
  717. dwInternet_Open_Flags |= INTERNET_FLAG_NO_COOKIES;
  718. break;
  719. case 'r':
  720. g_pRunStr = &argv[0][2];
  721. break;
  722. case 's':
  723. g_bSingleThreaded = TRUE;
  724. break;
  725. case 't':
  726. g_pTestName = &argv[0][2];
  727. break;
  728. case 'x':
  729. g_bTimeFirstFile = FALSE;
  730. break;
  731. case 'z':
  732. bDelim = TRUE;
  733. break;
  734. default:
  735. Display_Usage(argvIn);
  736. bRC = FALSE;
  737. }
  738. if(bRC)
  739. {
  740. dwLen += lstrlen(argv[0]) + 1; // length of arg and space
  741. if(dwLen < ((sizeof(g_CmdLine)/sizeof(g_CmdLine[0]))-1))
  742. {
  743. lstrcat(g_CmdLine, ",");
  744. lstrcat(g_CmdLine, argv[0]);
  745. }
  746. }
  747. argv++; argc--;
  748. }
  749. if(!pFilename && !pInFile)
  750. {
  751. Display_Usage(argvIn);
  752. bRC = FALSE;
  753. }
  754. return(bRC);
  755. }
  756. //----------------------------------------------------------------------------
  757. //----------------------------------------------------------------------------
  758. outQ *FillURLQueue(void)
  759. {
  760. outQ *pOutQ = NULL;
  761. DWORD dwCnt = 0;
  762. char szName[INTERNET_MAX_URL_LENGTH+1];
  763. if(pFilename)
  764. {
  765. while(dwCnt++ < dwNum_Opens)
  766. {
  767. if((dwInternet_Open_Flags & (INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE)) == (INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE)) // Not Cached
  768. lstrcpy(szName, pFilename);
  769. else
  770. wsprintf(szName, "%s.%d", pFilename, dwCnt);
  771. pOutQ = fillOutQ(pOutQ, szName);
  772. if(!pOutQ)
  773. {
  774. dprintf(("error filling outQ!\n"));
  775. return NULL;
  776. }
  777. }
  778. }
  779. else if(pInFile) // Process input file
  780. {
  781. FILE *fp;
  782. while(dwCnt++ < dwNum_Opens)
  783. {
  784. if((fp = fopen(pInFile, "r")) == NULL)
  785. {
  786. dprintf(("error opening file\n"));
  787. return NULL;
  788. }
  789. while(fgets(szName, INTERNET_MAX_URL_LENGTH, fp) != NULL)
  790. {
  791. if(szName[0] != '#')
  792. {
  793. szName[strlen(szName) - sizeof(char)] = '\0';
  794. pOutQ = fillOutQ(pOutQ, szName);
  795. if(!pOutQ)
  796. {
  797. dprintf(("error filling outQ!\n"));
  798. return NULL;
  799. }
  800. }
  801. }
  802. fclose(fp);
  803. }
  804. }
  805. return(pOutQ);
  806. }
  807. //----------------------------------------------------------------------------
  808. //----------------------------------------------------------------------------
  809. BOOL ProcessMessage(MSG msg, outQ *pOutQ, outQ *pMsgOutQ)
  810. {
  811. float fKB;
  812. float fSec;
  813. float fKBSec;
  814. switch(msg.message)
  815. {
  816. case DOWNLOAD_DONE:
  817. dwTot_Time = dwEnd_Time - dwBegin_Time;
  818. if(dwTot_Time == 0)
  819. dwTot_Time = 1;
  820. fKB = ((float)dwBytes_Read)/1024;
  821. fSec = ((float)dwTot_Time)/1000;
  822. fKBSec = fKB / fSec;
  823. if(!bDelim)
  824. {
  825. dprintf(("TID=%X, %ld bytes in %ld real milliseconds = %2.0f KB/sec\r\n", GetCurrentThreadId(), dwBytes_Read, dwTot_Time, fKBSec));
  826. printf("\r\nDownloaded: %s\r\n", pOutQ->pURLInfo->pURLName);
  827. printf("%ld Reads, %ld Downloads, %ld Byte Read Buffer, %s, %s\r\n",
  828. dwNum_Opens, dwMax_Simul_Downloads, dwBuf_Size, (dwInternet_Open_Flags & INTERNET_FLAG_DONT_CACHE) ?"Not Cached" :"Cached", (dwInternet_Open_Flags & INTERNET_FLAG_KEEP_CONNECTION) ?"KeepAlive" : "!KeepAlive");
  829. printf("Read %ld Bytes in %ld Milliseconds = %2.0f KB/Sec\r\n", dwBytes_Read, dwTot_Time, fKBSec);
  830. }
  831. else
  832. {
  833. printf("%s, %s, %ld, %ld, %2.0f %s\r\n",
  834. g_pTestName ?g_pTestName :"wininet",
  835. g_pRunStr ?g_pRunStr :"1",
  836. dwTot_Time,
  837. dwBytes_Read,
  838. fKBSec,
  839. g_CmdLine
  840. );
  841. }
  842. InternetCloseHandle(hInternet);
  843. CloseHandle(hDownloadThread);
  844. freeOutQMem(pOutQ);
  845. return TRUE;
  846. case DOWNLOAD_OPEN_REQUEST:
  847. dprintf(("main: DOWNLOAD_OPEN_REQUEST msg\n"));
  848. callOpenRequest(pMsgOutQ);
  849. break;
  850. case DOWNLOAD_SEND_REQUEST:
  851. dprintf(("main: DOWNLOAD_SEND_REQUEST msg\n"));
  852. callSendRequest(pMsgOutQ);
  853. break;
  854. case DOWNLOAD_READ_FILE:
  855. dprintf(("main: DOWNLOAD_READ_FILE msg\n"));
  856. callReadFile(pMsgOutQ);
  857. break;
  858. default:
  859. dprintf(("no match for message\n"));
  860. }
  861. return FALSE;
  862. }
  863. //----------------------------------------------------------------------------
  864. // Function: Main
  865. // Purpose: main entry procedure
  866. // Args: none
  867. // RetVal: TRUE or FALSE based on error
  868. //----------------------------------------------------------------------------
  869. __cdecl main(INT argc, TCHAR *argv[])
  870. {
  871. outQ *pOutQ = NULL;
  872. outQ *pMsgOutQ = NULL;
  873. outQ *pQ = NULL;
  874. MSG msg;
  875. INT retVal;
  876. DWORD dwResult;
  877. HANDLE *pObjs = &hMaxDownloadSem;
  878. g_hHeap = HeapCreate(0,1000000,0);
  879. if(!g_hHeap)
  880. return(FALSE);
  881. if(!Process_Command_Line(argc, argv))
  882. return FALSE;
  883. generateInfo();
  884. g_pUrlInfoCache.pHead = NULL;
  885. if(!(pOutQ = FillURLQueue()))
  886. return(FALSE);
  887. if(g_bSingleThreaded)
  888. {
  889. if(!DoInit()) // create throttle semaphore, do InternetOpen & InternetSetStatusCallback
  890. return FALSE;
  891. pQ = pOutQ;
  892. }
  893. else
  894. {
  895. hDownloadThread = CreateThread(NULL,
  896. 0,
  897. (LPTHREAD_START_ROUTINE)DownloadThread,
  898. (LPVOID)pOutQ,
  899. 0,
  900. &dwThreadID );
  901. if (!hDownloadThread) {
  902. dprintf(("Could not create Thread\n"));
  903. return FALSE;
  904. }
  905. }
  906. while(TRUE)
  907. {
  908. if(g_bSingleThreaded)
  909. {
  910. dwResult = MsgWaitForMultipleObjects(1, pObjs, FALSE, INFINITE, QS_ALLINPUT);
  911. if(dwResult == (WAIT_OBJECT_0 + 1))
  912. {
  913. MSG msg;
  914. while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  915. {
  916. if(msg.message == WM_QUIT)
  917. return(FALSE);
  918. pMsgOutQ = (outQ *) msg.wParam;
  919. ProcessMessage(msg, pOutQ, pMsgOutQ);
  920. if(msg.message == DOWNLOAD_DONE)
  921. return(TRUE);
  922. }
  923. }
  924. else
  925. {
  926. // Semaphore is signaled so do next connect/download
  927. if(pQ != NULL) // If there are still more downloads to do
  928. {
  929. pQ->iStatus = CONNECTING;
  930. pQ->iPriority = LOW;
  931. dprintf(("Download Main: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pQ, pQ->iStatus, CONNECTING));
  932. if(!DoConnect(pQ))
  933. break;
  934. pQ = pQ->pNext;
  935. }
  936. }
  937. }
  938. else
  939. {
  940. retVal = GetMessage(&msg, NULL, 0, 0);
  941. if(retVal == -1)
  942. {
  943. dprintf(("error on GetMessage\n"));
  944. break;
  945. }
  946. if(retVal == FALSE)
  947. {
  948. msg.message = DOWNLOAD_DONE;
  949. }
  950. pMsgOutQ = (outQ *) msg.wParam;
  951. ProcessMessage(msg, pOutQ, pMsgOutQ);
  952. if(msg.message == DOWNLOAD_DONE)
  953. return(TRUE);
  954. }
  955. }
  956. dprintf(("exiting abnormally\n"));
  957. return(FALSE);
  958. }