#include "inetdown.h" //---------------------------------------------------------------------------- // Globals //---------------------------------------------------------------------------- //#define TEST 1 HINTERNET hInternet; HANDLE hDownloadThread; HANDLE hMaxDownloadSem; DWORD dwThreadID; LPSTR ppAccept[] = {"*/*",NULL}; DWORD dwBegin_Time = 0; DWORD dwEnd_Time; DWORD dwTot_Time; DWORD dwNum_Opens = 1; DWORD dwBuf_Size = BUF_SIZE; DWORD dwBytes_Read = 0; DWORD dwMax_Simul_Downloads = URLMAX; DWORD dwInternet_Open_Flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_EXISTING_CONNECT; DWORD dwInternet_Connect_Flags = 0; BOOL bDelim = FALSE; BOOL g_bSingleThreaded = FALSE; DWORD g_dwMainThreadID = 0; DWORD g_iDownloads = 0; char *pFilename = NULL; char *pInFile = NULL; char *g_pRunStr = NULL; char *g_pTestName = NULL; char g_CmdLine[1024]; BOOL g_bTimeFirstFile = TRUE; url_info_cache g_pUrlInfoCache; HANDLE g_hHeap; #ifdef DBG #define dprintf(args) _dprintf args INT _dprintf(TCHAR *fmt, ... ) { INT ret; va_list marker; TCHAR szBuffer[256]; if(TRUE) { va_start(marker, fmt); ret = vsprintf(szBuffer, fmt, marker); OutputDebugString(szBuffer); printf(szBuffer); } return ret; } #else #define dprintf(args) #endif //---------------------------------------------------------------------------- //Procedure: generateInfo //Purpose: init globals //Arguments: none //RetVal: void //---------------------------------------------------------------------------- void generateInfo() { g_iDownloads = 0; g_dwMainThreadID = GetCurrentThreadId(); return; } //---------------------------------------------------------------------------- // Procedure: getCachedUrlInfo // Purpose: Finds existing url_info struct from the cache if it exists // Arguments: szUrl // RetVal: url_info* or NULL based on whether it's there //---------------------------------------------------------------------------- url_info *getCachedUrlInfo(TCHAR *szUrl) { url_info *temp = g_pUrlInfoCache.pHead; while(temp && (0 != lstrcmp(temp->pURLName,szUrl))) { temp = temp->pNext; } return temp; } //---------------------------------------------------------------------------- // Procedure: getUrlInfo // Purpose: Sets pUrlInfo member of the outQ struct // Arguments: outQ, szUrl // RetVal: TRUE or FALSE based on error //---------------------------------------------------------------------------- BOOL getUrlInfo(outQ *pOutQ, TCHAR *szUrl) { URL_COMPONENTS urlc; BOOL fRet = FALSE; if(pOutQ->pURLInfo = getCachedUrlInfo(szUrl)) { //Use existing url_info from cache return TRUE; } pOutQ->pURLInfo = HeapAlloc(g_hHeap,0,sizeof(url_info)); if(!pOutQ->pURLInfo) return FALSE; pOutQ->pURLInfo->pURLName = HeapAlloc(g_hHeap,0,(1+lstrlen(szUrl))*sizeof(TCHAR)); if(!pOutQ->pURLInfo->pURLName) { HeapFree(g_hHeap,0,pOutQ->pURLInfo); return FALSE; } lstrcpy(pOutQ->pURLInfo->pURLName,szUrl); //Add to head of url_info cache pOutQ->pURLInfo->pNext = g_pUrlInfoCache.pHead; g_pUrlInfoCache.pHead = pOutQ->pURLInfo; urlc.dwStructSize = sizeof(URL_COMPONENTS); urlc.lpszScheme=pOutQ->pURLInfo->szRScheme; urlc.dwSchemeLength= MAX_SCHEME_LENGTH; urlc.nScheme = INTERNET_SCHEME_UNKNOWN; urlc.lpszHostName=pOutQ->pURLInfo->szRHost; urlc.dwHostNameLength=INTERNET_MAX_HOST_NAME_LENGTH; urlc.lpszUserName=NULL; urlc.dwUserNameLength=0; urlc.lpszPassword=NULL; urlc.dwPasswordLength=0; urlc.lpszExtraInfo = NULL; urlc.dwExtraInfoLength = 0; urlc.lpszUrlPath=pOutQ->pURLInfo->szRPath; urlc.dwUrlPathLength=INTERNET_MAX_PATH_LENGTH; urlc.nPort = 0; if (InternetCrackUrl(pOutQ->pURLInfo->pURLName,0,0,&urlc)) { fRet = TRUE; pOutQ->pURLInfo->nScheme = urlc.nScheme; pOutQ->pURLInfo->nPort = urlc.nPort; // For now, we will only support HTTP if((pOutQ->pURLInfo->nScheme != INTERNET_SERVICE_HTTP) && (pOutQ->pURLInfo->nScheme != INTERNET_SCHEME_HTTPS)) fRet = FALSE; } return fRet; } //---------------------------------------------------------------------------- // Procedure: fillOutQ // Purpose: fills the OutQ will URLs to be downloaded // Arguments: OutQ to be filled // RetVal: the start of the Queue or NULL on error //---------------------------------------------------------------------------- outQ* fillOutQ(outQ *pOutQ, TCHAR *URLName) { outQ *pStartOutQ; pStartOutQ = pOutQ; if(pOutQ) { //go to first free outQ as opposed to adding to front (not concerned w/time) while(pOutQ->pNext != NULL) { pOutQ = pOutQ->pNext; } pOutQ->pNext = HeapAlloc(g_hHeap,0, sizeof(outQ)); if (!pOutQ->pNext) { dprintf(("HeapAlloc Failed!\n")); return NULL; } pOutQ = pOutQ->pNext; pOutQ->pNext = NULL; } else { pStartOutQ = pOutQ = HeapAlloc(g_hHeap,0, sizeof(outQ)); if (!pOutQ) { dprintf(("HeapAlloc Failed!\n")); return NULL; } pOutQ->pNext = NULL; } //keep track of the number of downloads g_iDownloads++; if(!getUrlInfo(pOutQ,URLName)) { dprintf(("getUrlInfo failed!\n")); return NULL; } return pStartOutQ; } //---------------------------------------------------------------------------- // Procedure: freeOutQMem // Purpose: frees the memory held in the given outQ // Arguments: outQ to be freed // RetVal: none //---------------------------------------------------------------------------- void freeOutQMem(outQ *pOutQ) { outQ *pLastOutQ; while(pOutQ) { pLastOutQ = pOutQ; pOutQ = pOutQ->pNext; HeapFree(g_hHeap,0,pLastOutQ); } return; } //---------------------------------------------------------------------------- // Procedure: callOpenRequest // Purpose: calls HttpOpenRequest // Arguments: outQ // RetVal: none //---------------------------------------------------------------------------- void callOpenRequest(outQ *pOutQ) { INT iError = 0; DWORD dwAdded_Connect_Flags = 0; if(lstrcmpi(pOutQ->pURLInfo->szRScheme, "https") == 0) { dwAdded_Connect_Flags = INTERNET_FLAG_SECURE; } if(pOutQ->hInetReq = HttpOpenRequest( pOutQ->hInetCon, //connection NULL, //verb pOutQ->pURLInfo->szRPath, //object NULL, //version NULL, //referrer ppAccept, //accept headers dwInternet_Open_Flags | dwAdded_Connect_Flags, //flags (DWORD) pOutQ)) //context { //it was synchronous (usual) dprintf(("callOpenRequest: Sync TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, LDG_STARTING)); pOutQ->iStatus = LDG_STARTING; callSendRequest(pOutQ); return; } else { if((iError = GetLastError()) != ERROR_IO_PENDING){ dprintf((" Error on HttpOpenRequest[%d]\n", iError)); g_iDownloads--; if(g_iDownloads == 0) { if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_DONE, (WPARAM) pOutQ, 0)) { iError = GetLastError(); dprintf(("error on PostThreadMessage[%d]\n", iError)); } } return; } dprintf(("callOpenRequest: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, REQUEST_OPENED)); pOutQ->iStatus = REQUEST_OPENED; return; } } //---------------------------------------------------------------------------- // Procedure: callSendRequest // Purpose: calls HttpSendRequest // Arguments: outQ // RetVal: none //---------------------------------------------------------------------------- void callSendRequest(outQ *pOutQ) { INT iError = 0; if(HttpSendRequest(pOutQ->hInetReq, NULL, 0, NULL, 0)) { //it was synchronous dprintf(("callSendRequest: Sync TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, LDG_START)); pOutQ->iStatus = LDG_START; callReadFile(pOutQ); return; } else { if((iError = GetLastError()) != ERROR_IO_PENDING) { dprintf((" Error on HttpSendRequest[%d]\n", iError)); g_iDownloads--; if(g_iDownloads == 0) { if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_DONE, (WPARAM) pOutQ, 0)) { iError = GetLastError(); dprintf(("error on PostThreadMessage[%d]\n", iError)); } } return; } //it was async (usual) dprintf(("callSendRequest: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, LDG_START)); pOutQ->iStatus = LDG_START; return; } } //---------------------------------------------------------------------------- // Procedure: callReadFile // Purpose: calls InternetReadFile // Arguments: outQ // RetVal: none //---------------------------------------------------------------------------- void callReadFile(outQ *pOutQ) { #ifndef TEST INT iError; INTERNET_BUFFERS IB; BOOL bRC; static TCHAR buf[BUF_SIZE]; switch (pOutQ->iStatus) { case LDG_START: dprintf(("callReadFile: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, LDG_LDG)); pOutQ->iStatus = LDG_LDG; break; case LDG_RDY: if(pOutQ->lNumRead == 0) { // should wait for 0 bytes read so data will cache. dprintf(("callReadFile: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, LDG_DONE)); pOutQ->iStatus = LDG_DONE; dprintf(("%s downloaded\n", pOutQ->pURLInfo->pURLName)); g_iDownloads--; //post msg if last download for exit if(g_iDownloads == 0) { dwEnd_Time = GetTickCount(); if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_DONE, (WPARAM) pOutQ, 0)) { iError = GetLastError(); dprintf(("error on PostThreadMessage[%d]\n", iError)); return; } } InternetCloseHandle(pOutQ->hInetReq); InternetCloseHandle(pOutQ->hInetCon); if(!ReleaseSemaphore(hMaxDownloadSem,1,NULL)) { dprintf((" ReleaseSemaphore failed!\n")); return; } return; } dprintf((" '%s':Rd = %d\n", pOutQ->pURLInfo->pURLName, pOutQ->lNumRead)); dwBytes_Read += pOutQ->lNumRead; break; } //Should insert timing test here if(dwBegin_Time == 0) { if(!g_bTimeFirstFile) g_bTimeFirstFile = TRUE; else dwBegin_Time = GetTickCount(); } IB.dwStructSize = sizeof (INTERNET_BUFFERS); IB.Next = 0; IB.lpcszHeader = 0; IB.dwHeadersLength = 0; IB.dwHeadersTotal = 0; IB.lpvBuffer = buf; IB.dwBufferLength = dwBuf_Size; IB.dwBufferTotal = 0; IB.dwOffsetLow = 0; IB.dwOffsetHigh = 0; bRC = InternetReadFileEx(pOutQ->hInetReq, &IB, IRF_NO_WAIT, 0); pOutQ->lNumRead = IB.dwBufferLength; if(bRC) { //it was synchronous dprintf(("callReadFile: Sync TID=%x pOutQ=%x Read=%d iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->lNumRead, pOutQ->iStatus, LDG_RDY)); pOutQ->iStatus = LDG_RDY; callReadFile(pOutQ); return; } else { dprintf(("callReadFile: TID=%x pOutQ=%x Read=%d iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->lNumRead, pOutQ->iStatus, LDG_RDY)); if(GetLastError() != ERROR_IO_PENDING) { g_iDownloads--; if(g_iDownloads == 0) { if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_DONE, (WPARAM) pOutQ, 0)) { iError = GetLastError(); dprintf(("error on PostThreadMessage[%d]\n", iError)); return; } } dprintf(("Error on InternetRead")); return; } if((pOutQ->lNumRead == 0) && (pOutQ->iStatus == LDG_LDG)) //vmr pOutQ->iStatus = LDG_RDY; } #else // ifndef TEST ======================================================================= INT iError; INTERNET_BUFFERS IB; BOOL bRC; BYTE Buf[8192]; pOutQ->pBuf = Buf; //Should insert timing test here if(dwBegin_Time == 0) { if(!g_bTimeFirstFile) g_bTimeFirstFile = TRUE; else dwBegin_Time = GetTickCount(); } IB.dwStructSize = sizeof (INTERNET_BUFFERS); IB.Next = 0; IB.lpcszHeader = 0; IB.dwHeadersLength = 0; IB.dwHeadersTotal = 0; IB.lpvBuffer = &Buf; IB.dwBufferLength = dwBuf_Size; IB.dwBufferTotal = 0; IB.dwOffsetLow = 0; IB.dwOffsetHigh = 0; bRC = InternetReadFileEx(pOutQ->hInetReq, &IB, IRF_NO_WAIT, 0); pOutQ->lNumRead = IB.dwBufferLength; if(bRC) { //it was synchronous dprintf(("callReadFile: Sync TID=%x pOutQ=%x Read=%d iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->lNumRead, pOutQ->iStatus, LDG_RDY)); pOutQ->iStatus = LDG_RDY; if(pOutQ->lNumRead == 0) { pOutQ->iStatus = LDG_DONE; dprintf(("%s downloaded\n", pOutQ->pURLInfo->pURLName)); InternetCloseHandle(pOutQ->hInetReq); InternetCloseHandle(pOutQ->hInetCon); //post msg if last download for exit g_iDownloads--; if(g_iDownloads == 0) { dwEnd_Time = GetTickCount(); if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_DONE, (WPARAM) pOutQ, 0)) { iError = GetLastError(); dprintf(("error on PostThreadMessage[%d]\n", iError)); return; } } if(!ReleaseSemaphore(hMaxDownloadSem,1,NULL)) { dprintf((" ReleaseSemaphore failed!\n")); return; } } else { dprintf((" '%s':Rd = %d\n", pOutQ->pURLInfo->pURLName, pOutQ->lNumRead)); dwBytes_Read += pOutQ->lNumRead; callReadFile(pOutQ); } } else { dprintf(("callReadFile: TID=%x pOutQ=%x Read=%d iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->lNumRead, pOutQ->iStatus, LDG_RDY)); if(GetLastError() != ERROR_IO_PENDING) { g_iDownloads--; if(g_iDownloads == 0) { if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_DONE, (WPARAM) pOutQ, 0)) { iError = GetLastError(); dprintf(("error on PostThreadMessage[%d]\n", iError)); return; } } dprintf(("Error on InternetRead")); return; } if((pOutQ->lNumRead == 0) && (pOutQ->iStatus == LDG_LDG)) //vmr pOutQ->iStatus = LDG_RDY; } return; #endif // ifndef TEST } //---------------------------------------------------------------------------- // Procedure: inetCallBackFn // Purpose: callback function used for all the async wininet calls // simply makes calls to do the actual processing of this callback. // Arguments: hInet HINTERNET for the callback // dwContext the outQ // dwInternewStatus Status of the callback // lpStatusInfo Holds connection handle // dwStatusInfoLen Not used //---------------------------------------------------------------------------- VOID CALLBACK inetCallBackFn(HINTERNET hInet, DWORD dwContext, DWORD dwInternetStatus, LPVOID lpStatusInfo, DWORD dwStatusInfoLen) { INT iError; outQ *pOutQ = (outQ *)(dwContext); //First check outQ's state //Should post messages to other thread to do calls switch(pOutQ->iStatus) { case CONNECTED: //should not be called in normal async behavior if(!pOutQ->hInetCon) { pOutQ->hInetCon = *((HINTERNET *)(lpStatusInfo)); } dprintf(("inetCallBackFn: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, REQUEST_OPENING)); pOutQ->iStatus = REQUEST_OPENING; if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_OPEN_REQUEST, (WPARAM) pOutQ, 0)) { iError = GetLastError(); dprintf(("error on PostThreadMessage[%d]\n", iError)); return; } break; case REQUEST_OPENED: //should not be called in normal async behavior if(!pOutQ->hInetReq) { pOutQ->hInetReq = *((HINTERNET *)(lpStatusInfo)); } dprintf(("inetCallBackFn: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, LDG_STARTING)); pOutQ->iStatus = LDG_STARTING; if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_SEND_REQUEST, (WPARAM) pOutQ, 0)) { iError = GetLastError(); dprintf(("error on PostThreadMessage[%d]\n", iError)); return; } break; case LDG_LDG: /// if(dwInternetStatus == INTERNET_STATUS_REQUEST_COMPLETE) if(dwInternetStatus == INTERNET_STATUS_REQUEST_COMPLETE && pOutQ->lNumRead != 0) { dprintf(("inetCallBackFn: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, LDG_RDY)); pOutQ->iStatus = LDG_RDY; } else return; case LDG_START: case LDG_RDY: /// if(dwInternetStatus == INTERNET_STATUS_REQUEST_COMPLETE || /// dwInternetStatus == INTERNET_STATUS_REQUEST_SENT) // vmr if(dwInternetStatus == INTERNET_STATUS_REQUEST_COMPLETE) { if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_READ_FILE, (WPARAM) pOutQ, 0)) { iError = GetLastError(); dprintf(("error on PostThreadMessage[%d]\n", iError)); return; } } break; case CONNECTING: case REQUEST_OPENING: case LDG_STARTING: case LDG_DONE: return; default: dprintf(("Bad iStatus=%d\n", pOutQ->iStatus)); return; } return; } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- BOOL DoInit(void) { hMaxDownloadSem = CreateSemaphore(NULL,dwMax_Simul_Downloads,dwMax_Simul_Downloads, NULL); if(!hMaxDownloadSem) { dprintf((" *** CreateSem failed!\n")); return FALSE; } hInternet = InternetOpen( NULL, //referrer PRE_CONFIG_INTERNET_ACCESS, //access type NULL, //proxy 0, //proxy bypass #ifndef TEST INTERNET_FLAG_ASYNC); //flags #else 0); #endif if(!hInternet) { dprintf((" *** InternetOpen failed!\n")); return FALSE; } #ifndef TEST if(InternetSetStatusCallback(hInternet, inetCallBackFn) < 0) { dprintf((" setCallback Failed!\n")); return FALSE; } #endif return TRUE; } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- BOOL DoConnect(outQ *pOutQ) { INT iError; DWORD dwAdded_Connect_Flags = 0; if(lstrcmpi(pOutQ->pURLInfo->szRScheme, "https") == 0) { dwAdded_Connect_Flags = INTERNET_FLAG_SECURE; } pOutQ->hInetCon = InternetConnect(hInternet, //handle from internetOpen pOutQ->pURLInfo->szRHost, //name of the server pOutQ->pURLInfo->nPort, //name of the port NULL, //username NULL, //password pOutQ->pURLInfo->nScheme, //service dwInternet_Connect_Flags | dwAdded_Connect_Flags, //service specific flags (DWORD) (pOutQ)); //context if(pOutQ->hInetCon) { //it was synchronous (usually) dprintf(("DoConnect: Sync connect TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, REQUEST_OPENING)); pOutQ->iStatus = REQUEST_OPENING; if(!PostThreadMessage(g_dwMainThreadID, DOWNLOAD_OPEN_REQUEST, (WPARAM) pOutQ, 0)) { iError = GetLastError(); dprintf(("error on PostThreadMessage[%d]\n", iError)); return FALSE; } } else { if(GetLastError() != ERROR_IO_PENDING) { dprintf((" InternetConnect error\n")); return FALSE; } dprintf(("DoConnect: Async connect TID=%x pOutQ=%x iStatus=%ld ->%ld->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, CONNECTED)); pOutQ->iStatus = CONNECTED; } return TRUE; } //---------------------------------------------------------------------------- // Procedure: DownloadThread // Purpose: Opens internet connection and downloads URL. Saves // URL to pOutQ (one chunk at a time). // Arguments: outQ // Return Val: TRUE or FALSE based on error //---------------------------------------------------------------------------- DWORD DownloadThread(LPDWORD lpdwParam) { outQ *pOutQ = (outQ *) lpdwParam; BOOL bRC = TRUE; if(bRC = DoInit()) // create throttle semaphore, do InternetOpen & InternetSetStatusCallback { while(pOutQ) { //Only allow MAXURL downloads at one time if(WaitForSingleObject(hMaxDownloadSem, TIMEOUT) == WAIT_TIMEOUT) { dprintf(("timeout on Sem\n")); printf("Error: timeout on throttle semaphore\n"); } pOutQ->iStatus = CONNECTING; pOutQ->iPriority = LOW; dprintf(("DownloadThread: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pOutQ, pOutQ->iStatus, CONNECTING)); if(!(bRC = DoConnect(pOutQ))) break; pOutQ = pOutQ->pNext; } } return((DWORD)bRC); } //================================================================== void Display_Usage(char **argv) { printf("\nUsage: %s -fURLname [options]\n", argv[0]); printf("\n -iInputFileName [options]\n"); printf("\n\t options:\n"); printf("\t\t -c - cache reads (flags ^= INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE)\n"); printf("\t\t -c1 - force reload and cache reads (flags ^= INTERNET_FLAG_DONT_CACHE)\n"); printf("\t\t (flags default = INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_EXISTING_CONNECT\n"); printf("\t\t -k - keep alive (flags |= INTERNET_FLAG_KEEP_CONNECTION)\n"); printf("\t\t -l - read buffer length\n"); printf("\t\t -m - maximum number of simultaneous downloads\n"); printf("\t\t -n## - number of times to download\n"); printf("\t\t -o - set INTERNET_FLAG_NO_COOKIES\n"); printf("\t\t -x - don't time first download\n"); printf("\t\t -s - run test in single threaded mode\n"); printf("\t\t -z - comma delimited format\n"); printf("\t\t -tStr - test name string (used on results output with -z)\n"); printf("\t\t -rStr - run# string (used on results output with -z)\n"); } //================================================================== BOOL Process_Command_Line(int argcIn, char **argvIn) { BOOL bRC = TRUE; int argc = argcIn; char **argv = argvIn; DWORD dwLen = 0; *g_CmdLine = '\0'; argv++; argc--; while( argc > 0 && argv[0][0] == '-' ) { switch (argv[0][1]) { case 'c': if(argv[0][2] == '1') dwInternet_Open_Flags ^= INTERNET_FLAG_DONT_CACHE; // force reload & cache file else dwInternet_Open_Flags ^= INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE; // cache file break; case 'k': dwInternet_Open_Flags |= INTERNET_FLAG_KEEP_CONNECTION; break; case 'f': pFilename = &argv[0][2]; break; case 'i': pInFile = &argv[0][2]; break; case 'n': dwNum_Opens = atoi(&argv[0][2]); break; case 'l': dwBuf_Size = atoi(&argv[0][2]); break; case 'm': dwMax_Simul_Downloads = atoi(&argv[0][2]); break; case 'o': dwInternet_Open_Flags |= INTERNET_FLAG_NO_COOKIES; break; case 'r': g_pRunStr = &argv[0][2]; break; case 's': g_bSingleThreaded = TRUE; break; case 't': g_pTestName = &argv[0][2]; break; case 'x': g_bTimeFirstFile = FALSE; break; case 'z': bDelim = TRUE; break; default: Display_Usage(argvIn); bRC = FALSE; } if(bRC) { dwLen += lstrlen(argv[0]) + 1; // length of arg and space if(dwLen < ((sizeof(g_CmdLine)/sizeof(g_CmdLine[0]))-1)) { lstrcat(g_CmdLine, ","); lstrcat(g_CmdLine, argv[0]); } } argv++; argc--; } if(!pFilename && !pInFile) { Display_Usage(argvIn); bRC = FALSE; } return(bRC); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- outQ *FillURLQueue(void) { outQ *pOutQ = NULL; DWORD dwCnt = 0; char szName[INTERNET_MAX_URL_LENGTH+1]; if(pFilename) { while(dwCnt++ < dwNum_Opens) { if((dwInternet_Open_Flags & (INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE)) == (INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE)) // Not Cached lstrcpy(szName, pFilename); else wsprintf(szName, "%s.%d", pFilename, dwCnt); pOutQ = fillOutQ(pOutQ, szName); if(!pOutQ) { dprintf(("error filling outQ!\n")); return NULL; } } } else if(pInFile) // Process input file { FILE *fp; while(dwCnt++ < dwNum_Opens) { if((fp = fopen(pInFile, "r")) == NULL) { dprintf(("error opening file\n")); return NULL; } while(fgets(szName, INTERNET_MAX_URL_LENGTH, fp) != NULL) { if(szName[0] != '#') { szName[strlen(szName) - sizeof(char)] = '\0'; pOutQ = fillOutQ(pOutQ, szName); if(!pOutQ) { dprintf(("error filling outQ!\n")); return NULL; } } } fclose(fp); } } return(pOutQ); } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- BOOL ProcessMessage(MSG msg, outQ *pOutQ, outQ *pMsgOutQ) { float fKB; float fSec; float fKBSec; switch(msg.message) { case DOWNLOAD_DONE: dwTot_Time = dwEnd_Time - dwBegin_Time; if(dwTot_Time == 0) dwTot_Time = 1; fKB = ((float)dwBytes_Read)/1024; fSec = ((float)dwTot_Time)/1000; fKBSec = fKB / fSec; if(!bDelim) { dprintf(("TID=%X, %ld bytes in %ld real milliseconds = %2.0f KB/sec\r\n", GetCurrentThreadId(), dwBytes_Read, dwTot_Time, fKBSec)); printf("\r\nDownloaded: %s\r\n", pOutQ->pURLInfo->pURLName); printf("%ld Reads, %ld Downloads, %ld Byte Read Buffer, %s, %s\r\n", 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"); printf("Read %ld Bytes in %ld Milliseconds = %2.0f KB/Sec\r\n", dwBytes_Read, dwTot_Time, fKBSec); } else { printf("%s, %s, %ld, %ld, %2.0f %s\r\n", g_pTestName ?g_pTestName :"wininet", g_pRunStr ?g_pRunStr :"1", dwTot_Time, dwBytes_Read, fKBSec, g_CmdLine ); } InternetCloseHandle(hInternet); CloseHandle(hDownloadThread); freeOutQMem(pOutQ); return TRUE; case DOWNLOAD_OPEN_REQUEST: dprintf(("main: DOWNLOAD_OPEN_REQUEST msg\n")); callOpenRequest(pMsgOutQ); break; case DOWNLOAD_SEND_REQUEST: dprintf(("main: DOWNLOAD_SEND_REQUEST msg\n")); callSendRequest(pMsgOutQ); break; case DOWNLOAD_READ_FILE: dprintf(("main: DOWNLOAD_READ_FILE msg\n")); callReadFile(pMsgOutQ); break; default: dprintf(("no match for message\n")); } return FALSE; } //---------------------------------------------------------------------------- // Function: Main // Purpose: main entry procedure // Args: none // RetVal: TRUE or FALSE based on error //---------------------------------------------------------------------------- __cdecl main(INT argc, TCHAR *argv[]) { outQ *pOutQ = NULL; outQ *pMsgOutQ = NULL; outQ *pQ = NULL; MSG msg; INT retVal; DWORD dwResult; HANDLE *pObjs = &hMaxDownloadSem; g_hHeap = HeapCreate(0,1000000,0); if(!g_hHeap) return(FALSE); if(!Process_Command_Line(argc, argv)) return FALSE; generateInfo(); g_pUrlInfoCache.pHead = NULL; if(!(pOutQ = FillURLQueue())) return(FALSE); if(g_bSingleThreaded) { if(!DoInit()) // create throttle semaphore, do InternetOpen & InternetSetStatusCallback return FALSE; pQ = pOutQ; } else { hDownloadThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)DownloadThread, (LPVOID)pOutQ, 0, &dwThreadID ); if (!hDownloadThread) { dprintf(("Could not create Thread\n")); return FALSE; } } while(TRUE) { if(g_bSingleThreaded) { dwResult = MsgWaitForMultipleObjects(1, pObjs, FALSE, INFINITE, QS_ALLINPUT); if(dwResult == (WAIT_OBJECT_0 + 1)) { MSG msg; while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if(msg.message == WM_QUIT) return(FALSE); pMsgOutQ = (outQ *) msg.wParam; ProcessMessage(msg, pOutQ, pMsgOutQ); if(msg.message == DOWNLOAD_DONE) return(TRUE); } } else { // Semaphore is signaled so do next connect/download if(pQ != NULL) // If there are still more downloads to do { pQ->iStatus = CONNECTING; pQ->iPriority = LOW; dprintf(("Download Main: TID=%x pOutQ=%x iStatus=%ld ->%ld\r\n", GetCurrentThreadId(), pQ, pQ->iStatus, CONNECTING)); if(!DoConnect(pQ)) break; pQ = pQ->pNext; } } } else { retVal = GetMessage(&msg, NULL, 0, 0); if(retVal == -1) { dprintf(("error on GetMessage\n")); break; } if(retVal == FALSE) { msg.message = DOWNLOAD_DONE; } pMsgOutQ = (outQ *) msg.wParam; ProcessMessage(msg, pOutQ, pMsgOutQ); if(msg.message == DOWNLOAD_DONE) return(TRUE); } } dprintf(("exiting abnormally\n")); return(FALSE); }