1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/other-licenses/nsis/Contrib/InetBgDL/InetBgDL.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,672 @@ 1.4 +// 1.5 +// Copyright (C) Anders Kjersem. Licensed under the zlib/libpng license 1.6 +// 1.7 + 1.8 +#include "InetBgDL.h" 1.9 + 1.10 +#define USERAGENT _T("NSIS InetBgDL (Mozilla)") 1.11 + 1.12 +#define STATUS_COMPLETEDALL 0 1.13 +#define STATUS_INITIAL 202 1.14 +#define STATUS_CONNECTING STATUS_INITIAL //102 1.15 +#define STATUS_DOWNLOADING STATUS_INITIAL 1.16 +#define STATUS_ERR_GETLASTERROR 418 //HTTP: I'm a teapot: Win32 error code in $3 1.17 +#define STATUS_ERR_LOCALFILEWRITEERROR 450 //HTTP: MS parental control extension 1.18 +#define STATUS_ERR_CANCELLED 499 1.19 + 1.20 +typedef DWORD FILESIZE_T; // Limit to 4GB for now... 1.21 +#define FILESIZE_UNKNOWN (-1) 1.22 + 1.23 +#define MAX_STRLEN 1024 1.24 + 1.25 +HINSTANCE g_hInst; 1.26 +NSIS::stack_t*g_pLocations = NULL; 1.27 +HANDLE g_hThread = NULL; 1.28 +HANDLE g_hGETStartedEvent = NULL; 1.29 +volatile UINT g_FilesTotal = 0; 1.30 +volatile UINT g_FilesCompleted = 0; 1.31 +volatile UINT g_Status = STATUS_INITIAL; 1.32 +volatile FILESIZE_T g_cbCurrXF; 1.33 +volatile FILESIZE_T g_cbCurrTot = FILESIZE_UNKNOWN; 1.34 +CRITICAL_SECTION g_CritLock; 1.35 +UINT g_N_CCH; 1.36 +PTSTR g_N_Vars; 1.37 +TCHAR g_ServerIP[128] = { _T('\0') }; 1.38 + 1.39 +DWORD g_ConnectTimeout = 0; 1.40 +DWORD g_ReceiveTimeout = 0; 1.41 + 1.42 +#define NSISPI_INITGLOBALS(N_CCH, N_Vars) do { \ 1.43 + g_N_CCH = N_CCH; \ 1.44 + g_N_Vars = N_Vars; \ 1.45 + } while(0) 1.46 + 1.47 +#define ONELOCKTORULETHEMALL 1.48 +#ifdef ONELOCKTORULETHEMALL 1.49 +#define TaskLock_AcquireExclusive() EnterCriticalSection(&g_CritLock) 1.50 +#define TaskLock_ReleaseExclusive() LeaveCriticalSection(&g_CritLock) 1.51 +#define StatsLock_AcquireExclusive() TaskLock_AcquireExclusive() 1.52 +#define StatsLock_ReleaseExclusive() TaskLock_ReleaseExclusive() 1.53 +#define StatsLock_AcquireShared() StatsLock_AcquireExclusive() 1.54 +#define StatsLock_ReleaseShared() StatsLock_ReleaseExclusive() 1.55 +#endif 1.56 + 1.57 +PTSTR NSIS_SetRegStr(UINT Reg, LPCTSTR Value) 1.58 +{ 1.59 + PTSTR s = g_N_Vars + (Reg * g_N_CCH); 1.60 + lstrcpy(s, Value); 1.61 + return s; 1.62 +} 1.63 +#define NSIS_SetRegStrEmpty(r) NSIS_SetRegStr(r, _T("")) 1.64 +void NSIS_SetRegUINT(UINT Reg, UINT Value) 1.65 +{ 1.66 + TCHAR buf[32]; 1.67 + wsprintf(buf, _T("%u"), Value); 1.68 + NSIS_SetRegStr(Reg, buf); 1.69 +} 1.70 +#define StackFreeItem(pI) GlobalFree(pI) 1.71 +NSIS::stack_t* StackPopItem(NSIS::stack_t**ppST) 1.72 +{ 1.73 + if (*ppST) 1.74 + { 1.75 + NSIS::stack_t*pItem = *ppST; 1.76 + *ppST = pItem->next; 1.77 + return pItem; 1.78 + } 1.79 + return NULL; 1.80 +} 1.81 + 1.82 +void Reset() 1.83 +{ 1.84 + // The g_hGETStartedEvent event is used to make sure that the Get() call will 1.85 + // acquire the lock before the Reset() call acquires the lock. 1.86 + if (g_hGETStartedEvent) { 1.87 + TRACE(_T("InetBgDl: waiting on g_hGETStartedEvent\n")); 1.88 + WaitForSingleObject(g_hGETStartedEvent, INFINITE); 1.89 + CloseHandle(g_hGETStartedEvent); 1.90 + g_hGETStartedEvent = NULL; 1.91 + } 1.92 + 1.93 + TaskLock_AcquireExclusive(); 1.94 +#ifndef ONELOCKTORULETHEMALL 1.95 + StatsLock_AcquireExclusive(); 1.96 +#endif 1.97 + g_FilesTotal = 0; // This causes the Task thread to exit the transfer loop 1.98 + if (g_hThread) 1.99 + { 1.100 + TRACE(_T("InetBgDl: waiting on g_hThread\n")); 1.101 + if (WAIT_OBJECT_0 != WaitForSingleObject(g_hThread, 10 * 1000)) 1.102 + { 1.103 + TRACE(_T("InetBgDl: terminating g_hThread\n")); 1.104 + TerminateThread(g_hThread, ERROR_OPERATION_ABORTED); 1.105 + } 1.106 + CloseHandle(g_hThread); 1.107 + g_hThread = NULL; 1.108 + } 1.109 + g_FilesTotal = 0; 1.110 + g_FilesCompleted = 0; 1.111 + g_Status = STATUS_INITIAL; 1.112 +#ifndef ONELOCKTORULETHEMALL 1.113 + StatsLock_ReleaseExclusive(); 1.114 +#endif 1.115 + for (NSIS::stack_t*pTmpTast,*pTask = g_pLocations; pTask ;) 1.116 + { 1.117 + pTmpTast = pTask; 1.118 + pTask = pTask->next; 1.119 + StackFreeItem(pTmpTast); 1.120 + } 1.121 + g_pLocations = NULL; 1.122 + TaskLock_ReleaseExclusive(); 1.123 +} 1.124 + 1.125 +UINT_PTR __cdecl NSISPluginCallback(UINT Event) 1.126 +{ 1.127 + switch(Event) 1.128 + { 1.129 + case NSPIM_UNLOAD: 1.130 + Reset(); 1.131 + break; 1.132 + } 1.133 + return NULL; 1.134 +} 1.135 + 1.136 +void __stdcall InetStatusCallback(HINTERNET hInternet, DWORD_PTR dwContext, 1.137 + DWORD dwInternetStatus, 1.138 + LPVOID lpvStatusInformation, 1.139 + DWORD dwStatusInformationLength) 1.140 +{ 1.141 + if (dwInternetStatus == INTERNET_STATUS_NAME_RESOLVED) { 1.142 + // The documentation states the IP address is a PCTSTR but it is usually a 1.143 + // PCSTR and only sometimes a PCTSTR. 1.144 + StatsLock_AcquireExclusive(); 1.145 + wsprintf(g_ServerIP, _T("%S"), lpvStatusInformation); 1.146 + if (wcslen(g_ServerIP) == 1) 1.147 + { 1.148 + wsprintf(g_ServerIP, _T("%s"), lpvStatusInformation); 1.149 + } 1.150 + StatsLock_ReleaseExclusive(); 1.151 + } 1.152 + 1.153 +#if defined(PLUGIN_DEBUG) 1.154 + switch (dwInternetStatus) 1.155 + { 1.156 + case INTERNET_STATUS_RESOLVING_NAME: 1.157 + TRACE(_T("InetBgDl: INTERNET_STATUS_RESOLVING_NAME (%d), name=%s\n"), 1.158 + dwStatusInformationLength, lpvStatusInformation); 1.159 + break; 1.160 + case INTERNET_STATUS_NAME_RESOLVED: 1.161 + TRACE(_T("InetBgDl: INTERNET_STATUS_NAME_RESOLVED (%d), resolved name=%s\n"), 1.162 + dwStatusInformationLength, g_ServerIP); 1.163 + break; 1.164 + case INTERNET_STATUS_CONNECTING_TO_SERVER: 1.165 + TRACE(_T("InetBgDl: INTERNET_STATUS_CONNECTING_TO_SERVER (%d)\n"), 1.166 + dwStatusInformationLength); 1.167 + break; 1.168 + case INTERNET_STATUS_CONNECTED_TO_SERVER: 1.169 + TRACE(_T("InetBgDl: INTERNET_STATUS_CONNECTED_TO_SERVER (%d)\n"), 1.170 + dwStatusInformationLength); 1.171 + break; 1.172 + case INTERNET_STATUS_SENDING_REQUEST: 1.173 + TRACE(_T("InetBgDl: INTERNET_STATUS_SENDING_REQUEST (%d)\n"), 1.174 + dwStatusInformationLength); 1.175 + break; 1.176 + case INTERNET_STATUS_REQUEST_SENT: 1.177 + TRACE(_T("InetBgDl: INTERNET_STATUS_REQUEST_SENT (%d), bytes sent=%d\n"), 1.178 + dwStatusInformationLength, lpvStatusInformation); 1.179 + break; 1.180 + case INTERNET_STATUS_RECEIVING_RESPONSE: 1.181 + TRACE(_T("InetBgDl: INTERNET_STATUS_RECEIVING_RESPONSE (%d)\n"), 1.182 + dwStatusInformationLength); 1.183 + break; 1.184 + case INTERNET_STATUS_RESPONSE_RECEIVED: 1.185 + TRACE(_T("InetBgDl: INTERNET_STATUS_RESPONSE_RECEIVED (%d)\n"), 1.186 + dwStatusInformationLength); 1.187 + break; 1.188 + case INTERNET_STATUS_CTL_RESPONSE_RECEIVED: 1.189 + TRACE(_T("InetBgDl: INTERNET_STATUS_CTL_RESPONSE_RECEIVED (%d)\n"), 1.190 + dwStatusInformationLength); 1.191 + break; 1.192 + case INTERNET_STATUS_PREFETCH: 1.193 + TRACE(_T("InetBgDl: INTERNET_STATUS_PREFETCH (%d)\n"), 1.194 + dwStatusInformationLength); 1.195 + break; 1.196 + case INTERNET_STATUS_CLOSING_CONNECTION: 1.197 + TRACE(_T("InetBgDl: INTERNET_STATUS_CLOSING_CONNECTION (%d)\n"), 1.198 + dwStatusInformationLength); 1.199 + break; 1.200 + case INTERNET_STATUS_CONNECTION_CLOSED: 1.201 + TRACE(_T("InetBgDl: INTERNET_STATUS_CONNECTION_CLOSED (%d)\n"), 1.202 + dwStatusInformationLength); 1.203 + break; 1.204 + case INTERNET_STATUS_HANDLE_CREATED: 1.205 + TRACE(_T("InetBgDl: INTERNET_STATUS_HANDLE_CREATED (%d)\n"), 1.206 + dwStatusInformationLength); 1.207 + break; 1.208 + case INTERNET_STATUS_HANDLE_CLOSING: 1.209 + TRACE(_T("InetBgDl: INTERNET_STATUS_HANDLE_CLOSING (%d)\n"), 1.210 + dwStatusInformationLength); 1.211 + break; 1.212 + case INTERNET_STATUS_DETECTING_PROXY: 1.213 + TRACE(_T("InetBgDl: INTERNET_STATUS_DETECTING_PROXY (%d)\n"), 1.214 + dwStatusInformationLength); 1.215 + break; 1.216 + case INTERNET_STATUS_REQUEST_COMPLETE: 1.217 + TRACE(_T("InetBgDl: INTERNET_STATUS_REQUEST_COMPLETE (%d)\n"), 1.218 + dwStatusInformationLength); 1.219 + break; 1.220 + case INTERNET_STATUS_REDIRECT: 1.221 + TRACE(_T("InetBgDl: INTERNET_STATUS_REDIRECT (%d), new url=%s\n"), 1.222 + dwStatusInformationLength, lpvStatusInformation); 1.223 + break; 1.224 + case INTERNET_STATUS_INTERMEDIATE_RESPONSE: 1.225 + TRACE(_T("InetBgDl: INTERNET_STATUS_INTERMEDIATE_RESPONSE (%d)\n"), 1.226 + dwStatusInformationLength); 1.227 + break; 1.228 + case INTERNET_STATUS_USER_INPUT_REQUIRED: 1.229 + TRACE(_T("InetBgDl: INTERNET_STATUS_USER_INPUT_REQUIRED (%d)\n"), 1.230 + dwStatusInformationLength); 1.231 + break; 1.232 + case INTERNET_STATUS_STATE_CHANGE: 1.233 + TRACE(_T("InetBgDl: INTERNET_STATUS_STATE_CHANGE (%d)\n"), 1.234 + dwStatusInformationLength); 1.235 + break; 1.236 + case INTERNET_STATUS_COOKIE_SENT: 1.237 + TRACE(_T("InetBgDl: INTERNET_STATUS_COOKIE_SENT (%d)\n"), 1.238 + dwStatusInformationLength); 1.239 + break; 1.240 + case INTERNET_STATUS_COOKIE_RECEIVED: 1.241 + TRACE(_T("InetBgDl: INTERNET_STATUS_COOKIE_RECEIVED (%d)\n"), 1.242 + dwStatusInformationLength); 1.243 + break; 1.244 + case INTERNET_STATUS_PRIVACY_IMPACTED: 1.245 + TRACE(_T("InetBgDl: INTERNET_STATUS_PRIVACY_IMPACTED (%d)\n"), 1.246 + dwStatusInformationLength); 1.247 + break; 1.248 + case INTERNET_STATUS_P3P_HEADER: 1.249 + TRACE(_T("InetBgDl: INTERNET_STATUS_P3P_HEADER (%d)\n"), 1.250 + dwStatusInformationLength); 1.251 + break; 1.252 + case INTERNET_STATUS_P3P_POLICYREF: 1.253 + TRACE(_T("InetBgDl: INTERNET_STATUS_P3P_POLICYREF (%d)\n"), 1.254 + dwStatusInformationLength); 1.255 + break; 1.256 + case INTERNET_STATUS_COOKIE_HISTORY: 1.257 + TRACE(_T("InetBgDl: INTERNET_STATUS_COOKIE_HISTORY (%d)\n"), 1.258 + dwStatusInformationLength); 1.259 + break; 1.260 + default: 1.261 + TRACE(_T("InetBgDl: Unknown Status %d\n"), dwInternetStatus); 1.262 + break; 1.263 + } 1.264 +#endif 1.265 +} 1.266 + 1.267 +DWORD CALLBACK TaskThreadProc(LPVOID ThreadParam) 1.268 +{ 1.269 + NSIS::stack_t *pURL,*pFile; 1.270 + HINTERNET hInetSes = NULL, hInetFile = NULL; 1.271 + DWORD cbio = sizeof(DWORD); 1.272 + HANDLE hLocalFile; 1.273 + bool completedFile = false; 1.274 +startnexttask: 1.275 + hLocalFile = INVALID_HANDLE_VALUE; 1.276 + pFile = NULL; 1.277 + TaskLock_AcquireExclusive(); 1.278 + // Now that we've acquired the lock, we can set the event to indicate this. 1.279 + // SetEvent will likely never fail, but if it does we should set it to NULL 1.280 + // to avoid anyone waiting on it. 1.281 + if (!SetEvent(g_hGETStartedEvent)) { 1.282 + CloseHandle(g_hGETStartedEvent); 1.283 + g_hGETStartedEvent = NULL; 1.284 + } 1.285 + pURL = g_pLocations; 1.286 + if (pURL) 1.287 + { 1.288 + pFile = pURL->next; 1.289 + g_pLocations = pFile->next; 1.290 + } 1.291 +#ifndef ONELOCKTORULETHEMALL 1.292 + StatsLock_AcquireExclusive(); 1.293 +#endif 1.294 + if (completedFile) 1.295 + { 1.296 + ++g_FilesCompleted; 1.297 + } 1.298 + completedFile = false; 1.299 + g_cbCurrXF = 0; 1.300 + g_cbCurrTot = FILESIZE_UNKNOWN; 1.301 + if (!pURL) 1.302 + { 1.303 + if (g_FilesTotal) 1.304 + { 1.305 + if (g_FilesTotal == g_FilesCompleted) 1.306 + { 1.307 + g_Status = STATUS_COMPLETEDALL; 1.308 + } 1.309 + } 1.310 + g_hThread = NULL; 1.311 + } 1.312 +#ifndef ONELOCKTORULETHEMALL 1.313 + StatsLock_ReleaseExclusive(); 1.314 +#endif 1.315 + TaskLock_ReleaseExclusive(); 1.316 + 1.317 + if (!pURL) 1.318 + { 1.319 + if (0) 1.320 + { 1.321 +diegle: 1.322 + DWORD gle = GetLastError(); 1.323 + //TODO? if (ERROR_INTERNET_EXTENDED_ERROR==gle) InternetGetLastResponseInfo(...) 1.324 + g_Status = STATUS_ERR_GETLASTERROR; 1.325 + } 1.326 + if (hInetSes) 1.327 + { 1.328 + InternetCloseHandle(hInetSes); 1.329 + } 1.330 + if (INVALID_HANDLE_VALUE != hLocalFile) 1.331 + { 1.332 + CloseHandle(hLocalFile); 1.333 + } 1.334 + StackFreeItem(pURL); 1.335 + StackFreeItem(pFile); 1.336 + return 0; 1.337 + } 1.338 + 1.339 + if (!hInetSes) 1.340 + { 1.341 + hInetSes = InternetOpen(USERAGENT, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); 1.342 + if (!hInetSes) 1.343 + { 1.344 + TRACE(_T("InetBgDl: InternetOpen failed with gle=%u\n"), 1.345 + GetLastError()); 1.346 + goto diegle; 1.347 + } 1.348 + InternetSetStatusCallback(hInetSes, (INTERNET_STATUS_CALLBACK)InetStatusCallback); 1.349 + 1.350 + //msdn.microsoft.com/library/default.asp?url=/workshop/components/offline/offline.asp#Supporting Offline Browsing in Applications and Components 1.351 + ULONG longOpt; 1.352 + DWORD cbio = sizeof(ULONG); 1.353 + if (InternetQueryOption(hInetSes, INTERNET_OPTION_CONNECTED_STATE, &longOpt, &cbio)) 1.354 + { 1.355 + if (INTERNET_STATE_DISCONNECTED_BY_USER&longOpt) 1.356 + { 1.357 + INTERNET_CONNECTED_INFO ci = {INTERNET_STATE_CONNECTED, 0}; 1.358 + InternetSetOption(hInetSes, INTERNET_OPTION_CONNECTED_STATE, &ci, sizeof(ci)); 1.359 + } 1.360 + } 1.361 + 1.362 + // Change the default connect timeout if specified. 1.363 + if(g_ConnectTimeout > 0) 1.364 + { 1.365 + InternetSetOption(hInetSes, INTERNET_OPTION_CONNECT_TIMEOUT, 1.366 + &g_ConnectTimeout, sizeof(g_ConnectTimeout)); 1.367 + } 1.368 + 1.369 + // Change the default receive timeout if specified. 1.370 + if (g_ReceiveTimeout) 1.371 + { 1.372 + InternetSetOption(hInetSes, INTERNET_OPTION_RECEIVE_TIMEOUT, 1.373 + &g_ReceiveTimeout, sizeof(DWORD)); 1.374 + } 1.375 + } 1.376 + 1.377 + DWORD ec = ERROR_SUCCESS; 1.378 + hLocalFile = CreateFile(pFile->text, GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_DELETE,NULL,CREATE_ALWAYS, 0, NULL); 1.379 + if (INVALID_HANDLE_VALUE == hLocalFile) 1.380 + { 1.381 + TRACE(_T("InetBgDl: CreateFile file handle invalid\n")); 1.382 + goto diegle; 1.383 + } 1.384 + 1.385 + const DWORD IOURedirFlags = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | 1.386 + INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS; 1.387 + const DWORD IOUCacheFlags = INTERNET_FLAG_RESYNCHRONIZE | 1.388 + INTERNET_FLAG_NO_CACHE_WRITE | 1.389 + INTERNET_FLAG_PRAGMA_NOCACHE | 1.390 + INTERNET_FLAG_RELOAD; 1.391 + const DWORD IOUCookieFlags = INTERNET_FLAG_NO_COOKIES; 1.392 + DWORD IOUFlags = IOURedirFlags | IOUCacheFlags | IOUCookieFlags | 1.393 + INTERNET_FLAG_NO_UI | INTERNET_FLAG_EXISTING_CONNECT; 1.394 + 1.395 + TCHAR *hostname = (TCHAR*) GlobalAlloc(GPTR, MAX_STRLEN * sizeof(TCHAR)), 1.396 + *urlpath = (TCHAR*) GlobalAlloc(GPTR, MAX_STRLEN * sizeof(TCHAR)), 1.397 + *extrainfo = (TCHAR*) GlobalAlloc(GPTR, MAX_STRLEN * sizeof(TCHAR)); 1.398 + 1.399 + URL_COMPONENTS uc = { sizeof(URL_COMPONENTS), NULL, 0, (INTERNET_SCHEME)0, 1.400 + hostname, MAX_STRLEN, (INTERNET_PORT)0, NULL, 0, 1.401 + NULL, 0, urlpath, MAX_STRLEN, extrainfo, MAX_STRLEN}; 1.402 + uc.dwHostNameLength = uc.dwUrlPathLength = uc.dwExtraInfoLength = MAX_STRLEN; 1.403 + 1.404 + if (!InternetCrackUrl(pURL->text, 0, ICU_ESCAPE, &uc)) 1.405 + { 1.406 + // Bad url or param passed in 1.407 + TRACE(_T("InetBgDl: InternetCrackUrl false with url=%s, gle=%u\n"), 1.408 + pURL->text, GetLastError()); 1.409 + goto diegle; 1.410 + } 1.411 + 1.412 + TRACE(_T("InetBgDl: scheme_id=%d, hostname=%s, port=%d, urlpath=%s, extrainfo=%s\n"), 1.413 + uc.nScheme, hostname, uc.nPort, urlpath, extrainfo); 1.414 + 1.415 + // Only http and https are supported 1.416 + if (uc.nScheme != INTERNET_SCHEME_HTTP && 1.417 + uc.nScheme != INTERNET_SCHEME_HTTPS) 1.418 + { 1.419 + TRACE(_T("InetBgDl: only http and https is supported, aborting...\n")); 1.420 + goto diegle; 1.421 + } 1.422 + 1.423 + TRACE(_T("InetBgDl: calling InternetOpenUrl with url=%s\n"), pURL->text); 1.424 + hInetFile = InternetOpenUrl(hInetSes, pURL->text, 1.425 + NULL, 0, IOUFlags | 1.426 + (uc.nScheme == INTERNET_SCHEME_HTTPS ? 1.427 + INTERNET_FLAG_SECURE : 0), 1); 1.428 + if (!hInetFile) 1.429 + { 1.430 + TRACE(_T("InetBgDl: InternetOpenUrl failed with gle=%u\n"), 1.431 + GetLastError()); 1.432 + goto diegle; 1.433 + } 1.434 + 1.435 + // Get the file length via the Content-Length header 1.436 + FILESIZE_T cbThisFile; 1.437 + cbio = sizeof(cbThisFile); 1.438 + if (!HttpQueryInfo(hInetFile, 1.439 + HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, 1.440 + &cbThisFile, &cbio, NULL)) 1.441 + { 1.442 + cbThisFile = FILESIZE_UNKNOWN; 1.443 + } 1.444 + TRACE(_T("InetBgDl: file size=%d bytes\n"), cbThisFile); 1.445 + 1.446 + // Setup a buffer of size 256KiB to store the downloaded data. 1.447 + const UINT cbBufXF = 262144; 1.448 + // Use a 4MiB read buffer for the connection. 1.449 + // Bigger buffers will be faster. 1.450 + // cbReadBufXF should be a multiple of cbBufXF. 1.451 + const UINT cbReadBufXF = 4194304; 1.452 + BYTE bufXF[cbBufXF]; 1.453 + 1.454 + // Up the default internal buffer size from 4096 to internalReadBufferSize. 1.455 + DWORD internalReadBufferSize = cbReadBufXF; 1.456 + if (!InternetSetOption(hInetFile, INTERNET_OPTION_READ_BUFFER_SIZE, 1.457 + &internalReadBufferSize, sizeof(DWORD))) 1.458 + { 1.459 + TRACE(_T("InetBgDl: InternetSetOption failed to set read buffer size to %u bytes, gle=%u\n"), 1.460 + internalReadBufferSize, GetLastError()); 1.461 + 1.462 + // Maybe it's too big, try half of the optimal value. If that fails just 1.463 + // use the default. 1.464 + internalReadBufferSize /= 2; 1.465 + if (!InternetSetOption(hInetFile, INTERNET_OPTION_READ_BUFFER_SIZE, 1.466 + &internalReadBufferSize, sizeof(DWORD))) 1.467 + { 1.468 + TRACE(_T("InetBgDl: InternetSetOption failed to set read buffer size ") \ 1.469 + _T("to %u bytes (using default read buffer size), gle=%u\n"), 1.470 + internalReadBufferSize, GetLastError()); 1.471 + } 1.472 + } 1.473 + 1.474 + for(;;) 1.475 + { 1.476 + DWORD cbio = 0, cbXF = 0; 1.477 + BOOL retXF = InternetReadFile(hInetFile, bufXF, cbBufXF, &cbio); 1.478 + if (!retXF) 1.479 + { 1.480 + ec = GetLastError(); 1.481 + TRACE(_T("InetBgDl: InternetReadFile failed, gle=%u\n"), ec); 1.482 + break; 1.483 + } 1.484 + 1.485 + if (0 == cbio) 1.486 + { 1.487 + ASSERT(ERROR_SUCCESS == ec); 1.488 + // EOF or broken connection? 1.489 + // TODO: Can InternetQueryDataAvailable detect this? 1.490 + 1.491 + TRACE(_T("InetBgDl: InternetReadFile true with 0 cbio, cbThisFile=%d, gle=%u\n"), 1.492 + cbThisFile, GetLastError()); 1.493 + // If we haven't transferred all of the file, and we know how big the file 1.494 + // is, and we have no more data to read from the HTTP request, then set a 1.495 + // broken pipe error. Reading without StatsLock is ok in this thread. 1.496 + if (FILESIZE_UNKNOWN != cbThisFile && g_cbCurrXF != cbThisFile) 1.497 + { 1.498 + TRACE(_T("InetBgDl: downloaded file size of %d bytes doesn't equal ") \ 1.499 + _T("expected file size of %d bytes\n"), g_cbCurrXF, cbThisFile); 1.500 + ec = ERROR_BROKEN_PIPE; 1.501 + } 1.502 + break; 1.503 + } 1.504 + 1.505 + // Check if we canceled the download 1.506 + if (0 == g_FilesTotal) 1.507 + { 1.508 + TRACE(_T("InetBgDl: 0 == g_FilesTotal, aborting transfer loop...\n")); 1.509 + ec = ERROR_CANCELLED; 1.510 + break; 1.511 + } 1.512 + 1.513 + cbXF = cbio; 1.514 + if (cbXF) 1.515 + { 1.516 + retXF = WriteFile(hLocalFile, bufXF, cbXF, &cbio, NULL); 1.517 + if (!retXF || cbXF != cbio) 1.518 + { 1.519 + ec = GetLastError(); 1.520 + break; 1.521 + } 1.522 + 1.523 + StatsLock_AcquireExclusive(); 1.524 + if (FILESIZE_UNKNOWN != cbThisFile) { 1.525 + g_cbCurrTot = cbThisFile; 1.526 + } 1.527 + g_cbCurrXF += cbXF; 1.528 + StatsLock_ReleaseExclusive(); 1.529 + } 1.530 + } 1.531 + 1.532 + TRACE(_T("InetBgDl: TaskThreadProc completed %s, ec=%u\n"), pURL->text, ec); 1.533 + InternetCloseHandle(hInetFile); 1.534 + if (ERROR_SUCCESS == ec) 1.535 + { 1.536 + if (INVALID_HANDLE_VALUE != hLocalFile) 1.537 + { 1.538 + CloseHandle(hLocalFile); 1.539 + hLocalFile = INVALID_HANDLE_VALUE; 1.540 + } 1.541 + StackFreeItem(pURL); 1.542 + StackFreeItem(pFile); 1.543 + ++completedFile; 1.544 + } 1.545 + else 1.546 + { 1.547 + TRACE(_T("InetBgDl: failed with ec=%u\n"), ec); 1.548 + SetLastError(ec); 1.549 + goto diegle; 1.550 + } 1.551 + goto startnexttask; 1.552 +} 1.553 + 1.554 +NSISPIEXPORTFUNC Get(HWND hwndNSIS, UINT N_CCH, TCHAR*N_Vars, NSIS::stack_t**ppST, NSIS::xparams_t*pX) 1.555 +{ 1.556 + pX->RegisterPluginCallback(g_hInst, NSISPluginCallback); 1.557 + for (;;) 1.558 + { 1.559 + NSIS::stack_t*pURL = StackPopItem(ppST); 1.560 + if (!pURL) 1.561 + { 1.562 + break; 1.563 + } 1.564 + 1.565 + if (lstrcmpi(pURL->text, _T("/connecttimeout")) == 0) 1.566 + { 1.567 + NSIS::stack_t*pConnectTimeout = StackPopItem(ppST); 1.568 + g_ConnectTimeout = _tcstol(pConnectTimeout->text, NULL, 10) * 1000; 1.569 + continue; 1.570 + } 1.571 + else if (lstrcmpi(pURL->text, _T("/receivetimeout")) == 0) 1.572 + { 1.573 + NSIS::stack_t*pReceiveTimeout = StackPopItem(ppST); 1.574 + g_ReceiveTimeout = _tcstol(pReceiveTimeout->text, NULL, 10) * 1000; 1.575 + continue; 1.576 + } 1.577 + else if (lstrcmpi(pURL->text, _T("/reset")) == 0) 1.578 + { 1.579 + StackFreeItem(pURL); 1.580 + Reset(); 1.581 + continue; 1.582 + } 1.583 + else if (lstrcmpi(pURL->text, _T("/end")) == 0) 1.584 + { 1.585 +freeurlandexit: 1.586 + StackFreeItem(pURL); 1.587 + break; 1.588 + } 1.589 + 1.590 + NSIS::stack_t*pFile = StackPopItem(ppST); 1.591 + if (!pFile) 1.592 + { 1.593 + goto freeurlandexit; 1.594 + } 1.595 + 1.596 + TaskLock_AcquireExclusive(); 1.597 + 1.598 + pFile->next = NULL; 1.599 + pURL->next = pFile; 1.600 + NSIS::stack_t*pTasksTail = g_pLocations; 1.601 + while(pTasksTail && pTasksTail->next) pTasksTail = pTasksTail->next; 1.602 + if (pTasksTail) 1.603 + { 1.604 + pTasksTail->next = pURL; 1.605 + } 1.606 + else 1.607 + { 1.608 + g_pLocations = pURL; 1.609 + } 1.610 + 1.611 + if (!g_hThread) 1.612 + { 1.613 + DWORD tid; 1.614 + if (g_hGETStartedEvent) { 1.615 + CloseHandle(g_hGETStartedEvent); 1.616 + } 1.617 + g_hGETStartedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 1.618 + g_hThread = CreateThread(NULL, 0, TaskThreadProc, NULL, 0, &tid); 1.619 + } 1.620 + 1.621 + if (!g_hThread) 1.622 + { 1.623 + goto freeurlandexit; 1.624 + } 1.625 + 1.626 +#ifndef ONELOCKTORULETHEMALL 1.627 + StatsLock_AcquireExclusive(); 1.628 +#endif 1.629 + ++g_FilesTotal; 1.630 +#ifndef ONELOCKTORULETHEMALL 1.631 + StatsLock_ReleaseExclusive(); 1.632 +#endif 1.633 + TaskLock_ReleaseExclusive(); 1.634 + } 1.635 +} 1.636 + 1.637 +NSISPIEXPORTFUNC GetStats(HWND hwndNSIS, UINT N_CCH, TCHAR*N_Vars, NSIS::stack_t**ppST, NSIS::xparams_t*pX) 1.638 +{ 1.639 + NSISPI_INITGLOBALS(N_CCH, N_Vars); 1.640 + StatsLock_AcquireShared(); 1.641 + NSIS_SetRegUINT(0, g_Status); 1.642 + NSIS_SetRegUINT(1, g_FilesCompleted); 1.643 + NSIS_SetRegUINT(2, g_FilesTotal - g_FilesCompleted); 1.644 + NSIS_SetRegUINT(3, g_cbCurrXF); 1.645 + NSIS_SetRegStrEmpty(4); 1.646 + if (FILESIZE_UNKNOWN != g_cbCurrTot) 1.647 + { 1.648 + NSIS_SetRegUINT(4, g_cbCurrTot); 1.649 + } 1.650 + NSIS_SetRegStr(5, g_ServerIP); 1.651 + StatsLock_ReleaseShared(); 1.652 +} 1.653 + 1.654 +EXTERN_C BOOL WINAPI _DllMainCRTStartup(HMODULE hInst, UINT Reason, LPVOID pCtx) 1.655 +{ 1.656 + if (DLL_PROCESS_ATTACH==Reason) 1.657 + { 1.658 + g_hInst=hInst; 1.659 + InitializeCriticalSection(&g_CritLock); 1.660 + } 1.661 + return TRUE; 1.662 +} 1.663 + 1.664 +BOOL WINAPI DllMain(HINSTANCE hInst, ULONG Reason, LPVOID pCtx) 1.665 +{ 1.666 + return _DllMainCRTStartup(hInst, Reason, pCtx); 1.667 +} 1.668 + 1.669 +// For some reason VC6++ doesn't like wcsicmp and swprintf. 1.670 +// If you use them, you get a linking error about _main 1.671 +// as an unresolved external. 1.672 +int main(int argc, char**argv) 1.673 +{ 1.674 + return 0; 1.675 +}