|
|
#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); }
|